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