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 30static TDB_CONTEXT *tdb; 31/* called when a session is created */ 32BOOL session_claim(user_struct *vuser) 33{ 34 int i = 0; 35 TDB_DATA data; 36 struct sockaddr sa; 37 struct in_addr *client_ip; 38 struct sessionid sessionid; 39 uint32 pid = (uint32)sys_getpid(); 40 TDB_DATA key; 41 fstring keystr; 42 char * hostname; 43 int tdb_store_flag; /* If using utmp, we do an inital 'lock hold' store, 44 but we don't need this if we are just using the 45 (unique) pid/vuid combination */ 46 47 vuser->session_keystr = NULL; 48 49 /* don't register sessions for the guest user - its just too 50 expensive to go through pam session code for browsing etc */ 51 if (vuser->guest) { 52 return True; 53 } 54 55 if (!tdb) { 56 tdb = tdb_open_log(lock_path("sessionid.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, 57 O_RDWR | O_CREAT, 0644); 58 if (!tdb) { 59 DEBUG(1,("session_claim: failed to open sessionid tdb\n")); 60 return False; 61 } 62 } 63 64 ZERO_STRUCT(sessionid); 65 66 data.dptr = NULL; 67 data.dsize = 0; 68 69 if (lp_utmp()) { 70 for (i=1;i<MAX_SESSION_ID;i++) { 71 slprintf(keystr, sizeof(keystr)-1, "ID/%d", i); 72 key.dptr = keystr; 73 key.dsize = strlen(keystr)+1; 74 75 if (tdb_store(tdb, key, data, TDB_INSERT) == 0) break; 76 } 77 78 if (i == MAX_SESSION_ID) { 79 DEBUG(1,("session_claim: out of session IDs (max is %d)\n", 80 MAX_SESSION_ID)); 81 return False; 82 } 83 slprintf(sessionid.id_str, sizeof(sessionid.id_str)-1, SESSION_UTMP_TEMPLATE, i); 84 tdb_store_flag = TDB_MODIFY; 85 } else 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 because 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 client_ip = client_inaddr(&sa); 121 122 if (!smb_pam_claim_session(sessionid.username, sessionid.id_str, sessionid.hostname)) { 123 DEBUG(1,("pam_session rejected the session for %s [%s]\n", 124 sessionid.username, sessionid.id_str)); 125 if (tdb_store_flag == TDB_MODIFY) { 126 tdb_delete(tdb, key); 127 } 128 return False; 129 } 130 131 data.dptr = (char *)&sessionid; 132 data.dsize = sizeof(sessionid); 133 if (tdb_store(tdb, key, data, tdb_store_flag) != 0) { 134 DEBUG(1,("session_claim: unable to create session id record\n")); 135 return False; 136 } 137 138 if (lp_utmp()) { 139 sys_utmp_claim(sessionid.username, sessionid.hostname, 140 client_ip, 141 sessionid.id_str, sessionid.id_num); 142 } 143 144 vuser->session_keystr = strdup(keystr); 145 if (!vuser->session_keystr) { 146 DEBUG(0, ("session_claim: strdup() failed for session_keystr\n")); 147 return False; 148 } 149 return True; 150} 151 152/* called when a session is destroyed */ 153void session_yield(user_struct *vuser) 154{ 155 TDB_DATA dbuf; 156 struct sessionid sessionid; 157 struct in_addr *client_ip; 158 TDB_DATA key; 159 160 if (!tdb) return; 161 162 if (!vuser->session_keystr) { 163 return; 164 } 165 166 key.dptr = vuser->session_keystr; 167 key.dsize = strlen(vuser->session_keystr)+1; 168 169 dbuf = tdb_fetch(tdb, key); 170 171 if (dbuf.dsize != sizeof(sessionid)) 172 return; 173 174 memcpy(&sessionid, dbuf.dptr, sizeof(sessionid)); 175 176 client_ip = interpret_addr2(sessionid.ip_addr); 177 178 SAFE_FREE(dbuf.dptr); 179 180 if (lp_utmp()) { 181 sys_utmp_yield(sessionid.username, sessionid.hostname, 182 client_ip, 183 sessionid.id_str, sessionid.id_num); 184 } 185 186 smb_pam_close_session(sessionid.username, sessionid.id_str, sessionid.hostname); 187 188 tdb_delete(tdb, key); 189} 190 191static BOOL session_traverse(int (*fn)(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *), void *state) 192{ 193 if (!tdb) { 194 DEBUG(3, ("No tdb opened\n")); 195 return False; 196 } 197 198 tdb_traverse(tdb, fn, state); 199 return True; 200} 201 202struct session_list { 203 int count; 204 struct sessionid *sessions; 205}; 206 207static int gather_sessioninfo(TDB_CONTEXT *stdb, TDB_DATA kbuf, TDB_DATA dbuf, 208 void *state) 209{ 210 struct session_list *sesslist = (struct session_list *) state; 211 const struct sessionid *current = (const struct sessionid *) dbuf.dptr; 212 213 sesslist->count += 1; 214 sesslist->sessions = REALLOC(sesslist->sessions, sesslist->count * 215 sizeof(struct sessionid)); 216 217 memcpy(&sesslist->sessions[sesslist->count - 1], current, 218 sizeof(struct sessionid)); 219 DEBUG(7,("gather_sessioninfo session from %s@%s\n", 220 current->username, current->remote_machine)); 221 return 0; 222} 223 224int list_sessions(struct sessionid **session_list) 225{ 226 struct session_list sesslist; 227 228 sesslist.count = 0; 229 sesslist.sessions = NULL; 230 231 if (!session_traverse(gather_sessioninfo, (void *) &sesslist)) { 232 DEBUG(3, ("Session traverse failed\n")); 233 SAFE_FREE(sesslist.sessions); 234 *session_list = NULL; 235 return 0; 236 } 237 238 *session_list = sesslist.sessions; 239 return sesslist.count; 240} 241 242