2001-04-18 20:42:07 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2001-04-18 20:42:07 +04:00
session handling for utmp and PAM
Copyright ( C ) tridge @ samba . org 2001
Copyright ( C ) abartlet @ pcug . org . au 2001
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
/* a "session" is claimed when we do a SessionSetupX operation
and is yielded when the corresponding vuid is destroyed .
sessions are used to populate utmp and PAM session structures
*/
# include "includes.h"
static TDB_CONTEXT * tdb ;
/* called when a session is created */
2001-11-09 01:19:01 +03:00
BOOL session_claim ( user_struct * vuser )
2001-04-18 20:42:07 +04:00
{
2002-08-17 19:27:10 +04:00
int i = 0 ;
2001-04-18 20:42:07 +04:00
TDB_DATA data ;
2003-04-24 13:52:29 +04:00
struct sockaddr sa ;
struct in_addr * client_ip ;
2001-04-18 20:42:07 +04:00
struct sessionid sessionid ;
uint32 pid = ( uint32 ) sys_getpid ( ) ;
TDB_DATA key ;
fstring keystr ;
2001-04-22 11:20:24 +04:00
char * hostname ;
2002-08-17 19:27:10 +04:00
int tdb_store_flag ; /* If using utmp, we do an inital 'lock hold' store,
but we don ' t need this if we are just using the
( unique ) pid / vuid combination */
2001-04-18 20:42:07 +04:00
2002-08-17 19:27:10 +04:00
vuser - > session_keystr = NULL ;
2001-04-18 20:42:07 +04:00
/* don't register sessions for the guest user - its just too
expensive to go through pam session code for browsing etc */
2001-11-09 01:19:01 +03:00
if ( vuser - > guest ) {
2001-04-18 20:42:07 +04:00
return True ;
}
if ( ! tdb ) {
2004-02-12 08:24:02 +03:00
tdb = tdb_open_ex ( lock_path ( " sessionid.tdb " ) , 0 , TDB_CLEAR_IF_FIRST | TDB_DEFAULT ,
O_RDWR | O_CREAT , 0644 , smbd_tdb_log ) ;
2001-04-18 20:42:07 +04:00
if ( ! tdb ) {
DEBUG ( 1 , ( " session_claim: failed to open sessionid tdb \n " ) ) ;
return False ;
}
}
ZERO_STRUCT ( sessionid ) ;
data . dptr = NULL ;
data . dsize = 0 ;
2002-08-17 19:27:10 +04:00
if ( lp_utmp ( ) ) {
for ( i = 1 ; i < MAX_SESSION_ID ; i + + ) {
slprintf ( keystr , sizeof ( keystr ) - 1 , " ID/%d " , i ) ;
key . dptr = keystr ;
key . dsize = strlen ( keystr ) + 1 ;
if ( tdb_store ( tdb , key , data , TDB_INSERT ) = = 0 ) break ;
}
if ( i = = MAX_SESSION_ID ) {
DEBUG ( 1 , ( " session_claim: out of session IDs (max is %d) \n " ,
MAX_SESSION_ID ) ) ;
return False ;
}
slprintf ( sessionid . id_str , sizeof ( sessionid . id_str ) - 1 , SESSION_UTMP_TEMPLATE , i ) ;
tdb_store_flag = TDB_MODIFY ;
} else
{
slprintf ( keystr , sizeof ( keystr ) - 1 , " ID/%lu/%u " ,
( long unsigned int ) sys_getpid ( ) ,
vuser - > vuid ) ;
slprintf ( sessionid . id_str , sizeof ( sessionid . id_str ) - 1 ,
SESSION_TEMPLATE , ( long unsigned int ) sys_getpid ( ) ,
vuser - > vuid ) ;
2001-04-18 20:42:07 +04:00
key . dptr = keystr ;
key . dsize = strlen ( keystr ) + 1 ;
2002-08-17 19:27:10 +04:00
tdb_store_flag = TDB_REPLACE ;
2001-04-18 20:42:07 +04:00
}
2002-02-09 06:29:36 +03:00
/* If 'hostname lookup' == yes, then do the DNS lookup. This is
2003-05-14 04:46:43 +04:00
needed because utmp and PAM both expect DNS names
2002-03-23 12:00:27 +03:00
client_name ( ) handles this case internally .
*/
2001-11-19 07:27:39 +03:00
2002-03-23 12:00:27 +03:00
hostname = client_name ( ) ;
if ( strcmp ( hostname , " UNKNOWN " ) = = 0 ) {
2002-02-09 06:29:36 +03:00
hostname = client_addr ( ) ;
}
2001-04-22 11:20:24 +04:00
2001-04-18 20:42:07 +04:00
fstrcpy ( sessionid . username , vuser - > user . unix_name ) ;
2001-04-22 11:20:24 +04:00
fstrcpy ( sessionid . hostname , hostname ) ;
2002-08-17 19:27:10 +04:00
sessionid . id_num = i ; /* Only valid for utmp sessions */
2001-04-18 20:42:07 +04:00
sessionid . pid = pid ;
2001-08-22 23:11:55 +04:00
sessionid . uid = vuser - > uid ;
sessionid . gid = vuser - > gid ;
2002-08-17 19:27:10 +04:00
fstrcpy ( sessionid . remote_machine , get_remote_machine_name ( ) ) ;
2001-08-22 23:11:55 +04:00
fstrcpy ( sessionid . ip_addr , client_addr ( ) ) ;
2001-04-18 20:42:07 +04:00
2003-04-24 13:52:29 +04:00
client_ip = client_inaddr ( & sa ) ;
2001-05-01 01:05:58 +04:00
if ( ! smb_pam_claim_session ( sessionid . username , sessionid . id_str , sessionid . hostname ) ) {
DEBUG ( 1 , ( " pam_session rejected the session for %s [%s] \n " ,
sessionid . username , sessionid . id_str ) ) ;
2002-08-17 19:27:10 +04:00
if ( tdb_store_flag = = TDB_MODIFY ) {
tdb_delete ( tdb , key ) ;
}
2001-05-01 01:05:58 +04:00
return False ;
}
2001-08-22 23:11:55 +04:00
data . dptr = ( char * ) & sessionid ;
data . dsize = sizeof ( sessionid ) ;
2002-08-17 19:27:10 +04:00
if ( tdb_store ( tdb , key , data , tdb_store_flag ) ! = 0 ) {
2001-04-18 20:42:07 +04:00
DEBUG ( 1 , ( " session_claim: unable to create session id record \n " ) ) ;
return False ;
}
if ( lp_utmp ( ) ) {
sys_utmp_claim ( sessionid . username , sessionid . hostname ,
2003-04-24 13:52:29 +04:00
client_ip ,
2001-04-18 20:42:07 +04:00
sessionid . id_str , sessionid . id_num ) ;
}
2002-08-17 19:27:10 +04:00
vuser - > session_keystr = strdup ( keystr ) ;
if ( ! vuser - > session_keystr ) {
DEBUG ( 0 , ( " session_claim: strdup() failed for session_keystr \n " ) ) ;
return False ;
}
2001-04-18 20:42:07 +04:00
return True ;
}
/* called when a session is destroyed */
2001-11-09 01:19:01 +03:00
void session_yield ( user_struct * vuser )
2001-04-18 20:42:07 +04:00
{
2001-08-22 23:11:55 +04:00
TDB_DATA dbuf ;
2001-04-18 20:42:07 +04:00
struct sessionid sessionid ;
2003-04-28 13:19:09 +04:00
struct in_addr * client_ip ;
2003-04-24 13:52:29 +04:00
TDB_DATA key ;
2001-04-18 20:42:07 +04:00
if ( ! tdb ) return ;
2002-08-17 19:27:10 +04:00
if ( ! vuser - > session_keystr ) {
2001-04-18 20:42:07 +04:00
return ;
}
2002-08-17 19:27:10 +04:00
key . dptr = vuser - > session_keystr ;
key . dsize = strlen ( vuser - > session_keystr ) + 1 ;
2001-04-18 20:42:07 +04:00
2001-08-22 23:11:55 +04:00
dbuf = tdb_fetch ( tdb , key ) ;
if ( dbuf . dsize ! = sizeof ( sessionid ) )
2001-04-18 20:42:07 +04:00
return ;
2001-08-22 23:11:55 +04:00
memcpy ( & sessionid , dbuf . dptr , sizeof ( sessionid ) ) ;
2001-04-18 20:42:07 +04:00
2003-04-28 13:19:09 +04:00
client_ip = interpret_addr2 ( sessionid . ip_addr ) ;
2003-04-24 13:52:29 +04:00
2001-09-17 15:25:41 +04:00
SAFE_FREE ( dbuf . dptr ) ;
2001-04-24 03:07:31 +04:00
2001-04-18 20:42:07 +04:00
if ( lp_utmp ( ) ) {
sys_utmp_yield ( sessionid . username , sessionid . hostname ,
2003-04-28 13:19:09 +04:00
client_ip ,
2001-04-18 20:42:07 +04:00
sessionid . id_str , sessionid . id_num ) ;
}
2001-05-01 01:05:58 +04:00
smb_pam_close_session ( sessionid . username , sessionid . id_str , sessionid . hostname ) ;
2001-04-18 20:42:07 +04:00
tdb_delete ( tdb , key ) ;
}
2002-07-15 14:35:28 +04:00
static BOOL session_traverse ( int ( * fn ) ( TDB_CONTEXT * , TDB_DATA , TDB_DATA , void * ) , void * state )
2001-10-22 22:14:42 +04:00
{
2002-07-15 14:35:28 +04:00
if ( ! tdb ) {
DEBUG ( 3 , ( " No tdb opened \n " ) ) ;
return False ;
}
2001-10-22 22:14:42 +04:00
2002-07-15 14:35:28 +04:00
tdb_traverse ( tdb , fn , state ) ;
return True ;
2001-10-22 22:14:42 +04:00
}
2002-07-15 14:35:28 +04:00
struct session_list {
int count ;
struct sessionid * sessions ;
} ;
static int gather_sessioninfo ( TDB_CONTEXT * stdb , TDB_DATA kbuf , TDB_DATA dbuf ,
void * state )
{
struct session_list * sesslist = ( struct session_list * ) state ;
const struct sessionid * current = ( const struct sessionid * ) dbuf . dptr ;
sesslist - > count + = 1 ;
sesslist - > sessions = REALLOC ( sesslist - > sessions , sesslist - > count *
sizeof ( struct sessionid ) ) ;
memcpy ( & sesslist - > sessions [ sesslist - > count - 1 ] , current ,
sizeof ( struct sessionid ) ) ;
DEBUG ( 7 , ( " gather_sessioninfo session from %s@%s \n " ,
current - > username , current - > remote_machine ) ) ;
return 0 ;
}
2001-10-22 22:14:42 +04:00
2002-07-15 14:35:28 +04:00
int list_sessions ( struct sessionid * * session_list )
{
struct session_list sesslist ;
sesslist . count = 0 ;
sesslist . sessions = NULL ;
if ( ! session_traverse ( gather_sessioninfo , ( void * ) & sesslist ) ) {
DEBUG ( 3 , ( " Session traverse failed \n " ) ) ;
SAFE_FREE ( sesslist . sessions ) ;
* session_list = NULL ;
return 0 ;
}
2001-10-22 22:14:42 +04:00
2002-07-15 14:35:28 +04:00
* session_list = sesslist . sessions ;
return sesslist . count ;
}