1996-05-04 07:50:46 +00:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
Username handling
1998-01-22 13:27:43 +00:00
Copyright ( C ) Andrew Tridgell 1992 - 1998
1996-05-04 07:50:46 +00:00
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 .
*/
# include "includes.h"
extern int DEBUGLEVEL ;
1998-06-10 19:45:13 +00:00
/* internal functions */
1998-04-13 19:24:06 +00:00
static struct passwd * uname_string_combinations ( char * s , struct passwd * ( * fn ) ( char * ) , int N ) ;
static struct passwd * uname_string_combinations2 ( char * s , int offset , struct passwd * ( * fn ) ( char * ) , int N ) ;
1996-05-04 07:50:46 +00:00
/****************************************************************************
1998-06-10 19:45:13 +00:00
get a users home directory .
1996-05-04 07:50:46 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * get_home_dir ( char * user )
{
static struct passwd * pass ;
1998-06-10 19:45:13 +00:00
pass = Get_Pwnam ( user , False ) ;
1996-05-04 07:50:46 +00:00
if ( ! pass ) return ( NULL ) ;
return ( pass - > pw_dir ) ;
}
/*******************************************************************
map a username from a dos name to a unix name by looking in the username
1998-06-10 19:45:13 +00:00
map . Note that this modifies the name in place .
This is the main function that should be called * once * on
any incoming or new username - in order to canonicalize the name .
This is being done to de - couple the case conversions from the user mapping
function . Previously , the map_username was being called
every time Get_Pwnam was called .
1998-06-12 03:08:23 +00:00
Returns True if username was changed , false otherwise .
1996-05-04 07:50:46 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-06-12 03:08:23 +00:00
BOOL map_username ( char * user )
1996-05-04 07:50:46 +00:00
{
static BOOL initialised = False ;
static fstring last_from , last_to ;
FILE * f ;
char * mapfile = lp_username_map ( ) ;
1998-06-12 03:08:23 +00:00
char * s ;
pstring buf ;
1998-07-07 16:58:29 +00:00
BOOL mapped_user = False ;
1996-05-04 07:50:46 +00:00
1998-06-12 03:08:23 +00:00
if ( ! * user )
return False ;
1996-05-04 07:50:46 +00:00
1998-06-12 03:08:23 +00:00
if ( ! * mapfile )
return False ;
1998-06-10 19:45:13 +00:00
1996-05-04 07:50:46 +00:00
if ( ! initialised ) {
* last_from = * last_to = 0 ;
initialised = True ;
}
1998-06-10 19:45:13 +00:00
if ( strequal ( user , last_to ) )
1998-06-12 03:08:23 +00:00
return False ;
1996-05-04 07:50:46 +00:00
if ( strequal ( user , last_from ) ) {
DEBUG ( 3 , ( " Mapped user %s to %s \n " , user , last_to ) ) ;
1997-09-26 18:55:29 +00:00
fstrcpy ( user , last_to ) ;
1998-06-12 03:08:23 +00:00
return True ;
1996-05-04 07:50:46 +00:00
}
f = fopen ( mapfile , " r " ) ;
if ( ! f ) {
DEBUG ( 0 , ( " can't open username map %s \n " , mapfile ) ) ;
1998-06-12 03:08:23 +00:00
return False ;
1996-05-04 07:50:46 +00:00
}
DEBUG ( 4 , ( " Scanning username map %s \n " , mapfile ) ) ;
1998-06-12 03:08:23 +00:00
while ( ( s = fgets_slash ( buf , sizeof ( buf ) , f ) ) ! = NULL ) {
1996-05-04 07:50:46 +00:00
char * unixname = s ;
char * dosname = strchr ( unixname , ' = ' ) ;
1998-06-10 19:45:13 +00:00
BOOL return_if_mapped = False ;
1996-05-04 07:50:46 +00:00
1998-06-12 03:08:23 +00:00
if ( ! dosname )
continue ;
1996-05-04 07:50:46 +00:00
* dosname + + = 0 ;
1998-06-12 03:08:23 +00:00
while ( isspace ( * unixname ) )
unixname + + ;
1998-06-10 19:45:13 +00:00
if ( ' ! ' = = * unixname ) {
return_if_mapped = True ;
1997-12-03 04:20:39 +00:00
unixname + + ;
1998-06-12 03:08:23 +00:00
while ( * unixname & & isspace ( * unixname ) )
unixname + + ;
1997-12-03 04:20:39 +00:00
}
1998-06-12 03:08:23 +00:00
if ( ! * unixname | | strchr ( " #; " , * unixname ) )
continue ;
1996-05-04 07:50:46 +00:00
{
int l = strlen ( unixname ) ;
while ( l & & isspace ( unixname [ l - 1 ] ) ) {
1998-06-10 19:45:13 +00:00
unixname [ l - 1 ] = 0 ;
l - - ;
1996-05-04 07:50:46 +00:00
}
}
if ( strchr ( dosname , ' * ' ) | | user_in_list ( user , dosname ) ) {
DEBUG ( 3 , ( " Mapped user %s to %s \n " , user , unixname ) ) ;
1998-07-07 16:58:29 +00:00
mapped_user = True ;
1998-06-10 19:45:13 +00:00
fstrcpy ( last_from , user ) ;
1996-05-04 07:50:46 +00:00
sscanf ( unixname , " %s " , user ) ;
1998-06-10 19:45:13 +00:00
fstrcpy ( last_to , user ) ;
if ( return_if_mapped ) {
fclose ( f ) ;
1998-06-12 03:08:23 +00:00
return True ;
1997-12-03 04:20:39 +00:00
}
1996-05-04 07:50:46 +00:00
}
}
fclose ( f ) ;
1998-06-12 03:08:23 +00:00
/*
1998-07-07 16:58:29 +00:00
* Setup the last_from and last_to as an optimization so
* that we don ' t scan the file again for the same user .
1998-06-12 03:08:23 +00:00
*/
fstrcpy ( last_from , user ) ;
fstrcpy ( last_to , user ) ;
1998-07-07 16:58:29 +00:00
return mapped_user ;
1996-05-04 07:50:46 +00:00
}
/****************************************************************************
1998-06-10 19:45:13 +00:00
Get_Pwnam wrapper
1996-05-04 07:50:46 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct passwd * _Get_Pwnam ( char * s )
{
struct passwd * ret ;
ret = getpwnam ( s ) ;
if ( ret )
{
1998-07-31 03:33:25 +00:00
# ifdef HAVE_GETPWANAM
1996-05-04 07:50:46 +00:00
struct passwd_adjunct * pwret ;
pwret = getpwanam ( s ) ;
if ( pwret )
{
free ( ret - > pw_passwd ) ;
ret - > pw_passwd = pwret - > pwa_passwd ;
}
# endif
}
return ( ret ) ;
}
/****************************************************************************
a wrapper for getpwnam ( ) that tries with all lower and all upper case
if the initial name fails . Also tried with first letter capitalised
1998-06-10 19:45:13 +00:00
Note that this can change user !
1996-05-04 07:50:46 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct passwd * Get_Pwnam ( char * user , BOOL allow_change )
{
fstring user2 ;
1997-09-19 17:12:08 +00:00
int last_char ;
int usernamelevel = lp_usernamelevel ( ) ;
1996-05-04 07:50:46 +00:00
struct passwd * ret ;
if ( ! user | | ! ( * user ) )
return ( NULL ) ;
StrnCpy ( user2 , user , sizeof ( user2 ) - 1 ) ;
if ( ! allow_change ) {
user = & user2 [ 0 ] ;
}
ret = _Get_Pwnam ( user ) ;
if ( ret ) return ( ret ) ;
strlower ( user ) ;
ret = _Get_Pwnam ( user ) ;
if ( ret ) return ( ret ) ;
strupper ( user ) ;
ret = _Get_Pwnam ( user ) ;
if ( ret ) return ( ret ) ;
/* try with first letter capitalised */
if ( strlen ( user ) > 1 )
strlower ( user + 1 ) ;
ret = _Get_Pwnam ( user ) ;
if ( ret ) return ( ret ) ;
1997-09-19 17:12:08 +00:00
/* try with last letter capitalised */
strlower ( user ) ;
last_char = strlen ( user ) - 1 ;
user [ last_char ] = toupper ( user [ last_char ] ) ;
ret = _Get_Pwnam ( user ) ;
if ( ret ) return ( ret ) ;
/* try all combinations up to usernamelevel */
strlower ( user ) ;
ret = uname_string_combinations ( user , _Get_Pwnam , usernamelevel ) ;
if ( ret ) return ( ret ) ;
1996-05-04 07:50:46 +00:00
if ( allow_change )
1997-09-26 18:55:29 +00:00
fstrcpy ( user , user2 ) ;
1996-05-04 07:50:46 +00:00
return ( NULL ) ;
}
/****************************************************************************
1998-06-13 03:04:00 +00:00
check if a user is in a netgroup user list
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL user_in_netgroup_list ( char * user , char * ngname )
{
1998-07-29 03:08:05 +00:00
# ifdef HAVE_NETGROUP
1998-06-13 03:04:00 +00:00
static char * mydomain = NULL ;
if ( mydomain = = NULL )
yp_get_default_domain ( & mydomain ) ;
if ( mydomain = = NULL )
{
DEBUG ( 5 , ( " Unable to get default yp domain \n " ) ) ;
}
else
{
DEBUG ( 5 , ( " looking for user %s of domain %s in netgroup %s \n " ,
user , mydomain , ngname ) ) ;
DEBUG ( 5 , ( " innetgr is %s \n " ,
innetgr ( ngname , NULL , user , mydomain )
? " TRUE " : " FALSE " ) ) ;
if ( innetgr ( ngname , NULL , user , mydomain ) )
return ( True ) ;
}
1998-07-29 03:08:05 +00:00
# endif /* HAVE_NETGROUP */
1998-06-13 03:04:00 +00:00
return False ;
}
/****************************************************************************
check if a user is in a UNIX user list
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL user_in_group_list ( char * user , char * gname )
{
1998-07-29 03:08:05 +00:00
# ifdef HAVE_GETGRNAM
1998-06-13 03:04:00 +00:00
struct group * gptr ;
char * * member ;
struct passwd * pass = Get_Pwnam ( user , False ) ;
if ( pass )
{
gptr = getgrgid ( pass - > pw_gid ) ;
if ( gptr & & strequal ( gptr - > gr_name , gname ) )
return ( True ) ;
}
gptr = ( struct group * ) getgrnam ( gname ) ;
if ( gptr )
{
member = gptr - > gr_mem ;
while ( member & & * member )
{
if ( strequal ( * member , user ) )
return ( True ) ;
member + + ;
}
}
# endif /* HAVE_GETGRNAM */
return False ;
}
/****************************************************************************
check if a user is in a user list - can check combinations of UNIX
and netgroup lists .
1996-05-04 07:50:46 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL user_in_list ( char * user , char * list )
{
pstring tok ;
char * p = list ;
while ( next_token ( & p , tok , LIST_SEP ) )
1998-06-13 03:04:00 +00:00
{
/*
* Check raw username .
*/
if ( strequal ( user , tok ) )
return ( True ) ;
1996-05-04 07:50:46 +00:00
1998-06-13 03:04:00 +00:00
/*
* Now check to see if any combination
* of UNIX and netgroups has been specified .
*/
1996-05-04 07:50:46 +00:00
1998-06-13 03:04:00 +00:00
if ( * tok = = ' @ ' )
{
/*
* Old behaviour . Check netgroup list
* followed by UNIX list .
*/
if ( user_in_netgroup_list ( user , & tok [ 1 ] ) )
return True ;
if ( user_in_group_list ( user , & tok [ 1 ] ) )
return True ;
}
else if ( * tok = = ' + ' )
{
if ( tok [ 1 ] = = ' & ' )
{
/*
* Search UNIX list followed by netgroup .
*/
if ( user_in_group_list ( user , & tok [ 2 ] ) )
return True ;
if ( user_in_netgroup_list ( user , & tok [ 2 ] ) )
return True ;
}
else
{
/*
* Just search UNIX list .
*/
if ( user_in_group_list ( user , & tok [ 1 ] ) )
return True ;
}
}
else if ( * tok = = ' & ' )
{
if ( tok [ 1 ] = = ' & ' )
{
/*
* Search netgroup list followed by UNIX list .
*/
if ( user_in_netgroup_list ( user , & tok [ 2 ] ) )
return True ;
if ( user_in_group_list ( user , & tok [ 2 ] ) )
return True ;
}
else
{
/*
* Just search netgroup list .
*/
if ( user_in_netgroup_list ( user , & tok [ 1 ] ) )
return True ;
}
1996-05-04 07:50:46 +00:00
}
1998-06-13 03:04:00 +00:00
}
1996-05-04 07:50:46 +00:00
return ( False ) ;
}
1997-09-19 17:12:08 +00:00
/* The functions below have been taken from password.c and slightly modified */
/****************************************************************************
apply a function to upper / lower case combinations
of a string and return true if one of them returns true .
try all combinations with N uppercase letters .
offset is the first char to try and change ( start with 0 )
it assumes the string starts lowercased
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-04-13 19:24:06 +00:00
static struct passwd * uname_string_combinations2 ( char * s , int offset , struct passwd * ( * fn ) ( char * ) , int N )
1997-09-19 17:12:08 +00:00
{
int len = strlen ( s ) ;
int i ;
struct passwd * ret ;
# ifdef PASSWORD_LENGTH
len = MIN ( len , PASSWORD_LENGTH ) ;
# endif
if ( N < = 0 | | offset > = len )
return ( fn ( s ) ) ;
1996-05-04 07:50:46 +00:00
1997-09-19 17:12:08 +00:00
for ( i = offset ; i < ( len - ( N - 1 ) ) ; i + + )
{
char c = s [ i ] ;
if ( ! islower ( c ) ) continue ;
s [ i ] = toupper ( c ) ;
ret = uname_string_combinations2 ( s , i + 1 , fn , N - 1 ) ;
if ( ret ) return ( ret ) ;
s [ i ] = c ;
}
return ( NULL ) ;
}
/****************************************************************************
apply a function to upper / lower case combinations
of a string and return true if one of them returns true .
try all combinations with up to N uppercase letters .
offset is the first char to try and change ( start with 0 )
it assumes the string starts lowercased
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-04-13 19:24:06 +00:00
static struct passwd * uname_string_combinations ( char * s , struct passwd * ( * fn ) ( char * ) , int N )
1997-09-19 17:12:08 +00:00
{
int n ;
struct passwd * ret ;
for ( n = 1 ; n < = N ; n + + )
{
ret = uname_string_combinations2 ( s , 0 , fn , n ) ;
if ( ret ) return ( ret ) ;
}
return ( NULL ) ;
}