Make 'remote_machine' private to lib/substitute.c, and fix all the user to use
[samba.git] / source3 / smbd / session.c
1 /* 
2    Unix SMB/CIFS implementation.
3    session handling for utmp and PAM
4    Copyright (C) tridge@samba.org 2001
5    Copyright (C) abartlet@pcug.org.au 2001
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 /* a "session" is claimed when we do a SessionSetupX operation
23    and is yielded when the corresponding vuid is destroyed.
24
25    sessions are used to populate utmp and PAM session structures
26 */
27
28 #include "includes.h"
29
30 static TDB_CONTEXT *tdb;
31 /* called when a session is created */
32 BOOL session_claim(user_struct *vuser)
33 {
34         int i = 0;
35         TDB_DATA data;
36         struct sessionid sessionid;
37         uint32 pid = (uint32)sys_getpid();
38         TDB_DATA key;           
39         fstring keystr;
40         char * hostname;
41         int tdb_store_flag;  /* If using utmp, we do an inital 'lock hold' store,
42                                 but we don't need this if we are just using the 
43                                 (unique) pid/vuid combination */
44
45         vuser->session_keystr = NULL;
46
47         /* don't register sessions for the guest user - its just too
48            expensive to go through pam session code for browsing etc */
49         if (vuser->guest) {
50                 return True;
51         }
52
53         if (!tdb) {
54                 tdb = tdb_open_log(lock_path("sessionid.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, 
55                                O_RDWR | O_CREAT, 0644);
56                 if (!tdb) {
57                         DEBUG(1,("session_claim: failed to open sessionid tdb\n"));
58                         return False;
59                 }
60         }
61
62         ZERO_STRUCT(sessionid);
63
64         data.dptr = NULL;
65         data.dsize = 0;
66
67 #if WITH_UTMP
68         if (lp_utmp()) {
69                 for (i=1;i<MAX_SESSION_ID;i++) {
70                         slprintf(keystr, sizeof(keystr)-1, "ID/%d", i);
71                         key.dptr = keystr;
72                         key.dsize = strlen(keystr)+1;
73                         
74                         if (tdb_store(tdb, key, data, TDB_INSERT) == 0) break;
75                 }
76                 
77                 if (i == MAX_SESSION_ID) {
78                         DEBUG(1,("session_claim: out of session IDs (max is %d)\n", 
79                                  MAX_SESSION_ID));
80                         return False;
81                 }
82                 slprintf(sessionid.id_str, sizeof(sessionid.id_str)-1, SESSION_UTMP_TEMPLATE, i);
83                 tdb_store_flag = TDB_MODIFY;
84         } else
85 #endif
86         {
87                 slprintf(keystr, sizeof(keystr)-1, "ID/%lu/%u", 
88                          (long unsigned int)sys_getpid(), 
89                          vuser->vuid);
90                 slprintf(sessionid.id_str, sizeof(sessionid.id_str)-1, 
91                          SESSION_TEMPLATE, (long unsigned int)sys_getpid(), 
92                          vuser->vuid);
93
94                 key.dptr = keystr;
95                 key.dsize = strlen(keystr)+1;
96                         
97                 tdb_store_flag = TDB_REPLACE;
98         }
99
100         /* If 'hostname lookup' == yes, then do the DNS lookup.  This is
101            needed becouse utmp and PAM both expect DNS names 
102            
103            client_name() handles this case internally.
104         */
105
106         hostname = client_name();
107         if (strcmp(hostname, "UNKNOWN") == 0) {
108                 hostname = client_addr();
109         }
110
111         fstrcpy(sessionid.username, vuser->user.unix_name);
112         fstrcpy(sessionid.hostname, hostname);
113         sessionid.id_num = i;  /* Only valid for utmp sessions */
114         sessionid.pid = pid;
115         sessionid.uid = vuser->uid;
116         sessionid.gid = vuser->gid;
117         fstrcpy(sessionid.remote_machine, get_remote_machine_name());
118         fstrcpy(sessionid.ip_addr, client_addr());
119
120         if (!smb_pam_claim_session(sessionid.username, sessionid.id_str, sessionid.hostname)) {
121                 DEBUG(1,("pam_session rejected the session for %s [%s]\n",
122                                 sessionid.username, sessionid.id_str));
123                 if (tdb_store_flag == TDB_MODIFY) {
124                         tdb_delete(tdb, key);
125                 }
126                 return False;
127         }
128
129         data.dptr = (char *)&sessionid;
130         data.dsize = sizeof(sessionid);
131         if (tdb_store(tdb, key, data, tdb_store_flag) != 0) {
132                 DEBUG(1,("session_claim: unable to create session id record\n"));
133                 return False;
134         }
135
136 #if WITH_UTMP   
137         if (lp_utmp()) {
138                 sys_utmp_claim(sessionid.username, sessionid.hostname, 
139                                sessionid.id_str, sessionid.id_num);
140         }
141 #endif
142
143         vuser->session_keystr = strdup(keystr);
144         if (!vuser->session_keystr) {
145                 DEBUG(0, ("session_claim:  strdup() failed for session_keystr\n"));
146                 return False;
147         }
148         return True;
149 }
150
151 /* called when a session is destroyed */
152 void session_yield(user_struct *vuser)
153 {
154         TDB_DATA dbuf;
155         struct sessionid sessionid;
156         TDB_DATA key;           
157
158         if (!tdb) return;
159
160         if (!vuser->session_keystr) {
161                 return;
162         }
163
164         key.dptr = vuser->session_keystr;
165         key.dsize = strlen(vuser->session_keystr)+1;
166
167         dbuf = tdb_fetch(tdb, key);
168
169         if (dbuf.dsize != sizeof(sessionid))
170                 return;
171
172         memcpy(&sessionid, dbuf.dptr, sizeof(sessionid));
173
174         SAFE_FREE(dbuf.dptr);
175
176 #if WITH_UTMP   
177         if (lp_utmp()) {
178                 sys_utmp_yield(sessionid.username, sessionid.hostname, 
179                                sessionid.id_str, sessionid.id_num);
180         }
181 #endif
182
183         smb_pam_close_session(sessionid.username, sessionid.id_str, sessionid.hostname);
184
185         tdb_delete(tdb, key);
186 }
187
188 static BOOL session_traverse(int (*fn)(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *), void *state)
189 {
190         if (!tdb) {
191                 DEBUG(3, ("No tdb opened\n"));
192                 return False;
193         }
194
195         tdb_traverse(tdb, fn, state);
196         return True;
197 }
198
199 struct session_list {
200         int count;
201         struct sessionid *sessions;
202 };
203
204 static int gather_sessioninfo(TDB_CONTEXT *stdb, TDB_DATA kbuf, TDB_DATA dbuf,
205                               void *state)
206 {
207         struct session_list *sesslist = (struct session_list *) state;
208         const struct sessionid *current = (const struct sessionid *) dbuf.dptr;
209
210         sesslist->count += 1;
211         sesslist->sessions = REALLOC(sesslist->sessions, sesslist->count * 
212                                       sizeof(struct sessionid));
213
214         memcpy(&sesslist->sessions[sesslist->count - 1], current, 
215                sizeof(struct sessionid));
216         DEBUG(7,("gather_sessioninfo session from %s@%s\n", 
217                  current->username, current->remote_machine));
218         return 0;
219 }
220
221 int list_sessions(struct sessionid **session_list)
222 {
223         struct session_list sesslist;
224
225         sesslist.count = 0;
226         sesslist.sessions = NULL;
227         
228         if (!session_traverse(gather_sessioninfo, (void *) &sesslist)) {
229                 DEBUG(3, ("Session traverse failed\n"));
230                 SAFE_FREE(sesslist.sessions);
231                 *session_list = NULL;
232                 return 0;
233         }
234
235         *session_list = sesslist.sessions;
236         return sesslist.count;
237 }
238