1998-11-12 19:07:00 +03:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
Samba utility functions
Copyright ( C ) Andrew Tridgell 1992 - 1998
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 ;
extern pstring scope ;
extern pstring global_myname ;
/*
* This is set on startup - it defines the SID for this
* machine , and therefore the SAM database for which it is
* responsible .
*/
DOM_SID global_sam_sid ;
/*
* This is the name associated with the SAM database for
* which this machine is responsible . In the case of a PDC
* or PDC , this name is the same as the workgroup . In the
* case of " security = domain " mode , this is the same as
* the name of the server ( global_myname ) .
*/
fstring global_sam_name ;
/*
* This is obtained on startup - it defines the SID for which
* this machine is a member . It is therefore only set , and
* used , in " security = domain " mode .
*/
DOM_SID global_member_sid ;
/*
* note the lack of a " global_member_name " - this is because
* this is the same as " global_myworkgroup " .
*/
/*
* some useful sids
*/
DOM_SID global_sid_S_1_5_20 ; /* local well-known domain */
DOM_SID global_sid_S_1_1 ; /* everyone */
DOM_SID global_sid_S_1_5 ; /* NT Authority */
1998-11-12 22:21:20 +03:00
DOM_SID global_sid_S_1_3_0 ; /* Creator owner */
DOM_SID global_sid_S_1_3_1 ; /* Creator group */
DOM_SID global_sid_S_1_3_2 ; /* Creator owner server */
DOM_SID global_sid_S_1_3_3 ; /* Creator group server */
1998-11-12 19:07:00 +03:00
extern pstring global_myworkgroup ;
/* extern fstring global_member_dom_name; */
static struct sid_name_map_info
{
DOM_SID * sid ;
char * name ;
}
sid_name_map [ ] =
{
{ & global_sid_S_1_5_20 , " BUILTIN " } ,
{ & global_sid_S_1_1 , " Everyone " } ,
1998-11-12 22:21:20 +03:00
{ & global_sid_S_1_3_0 , " Creator Owner " } ,
{ & global_sid_S_1_3_1 , " Creator Group " } ,
{ & global_sid_S_1_3_2 , " Creator Owner Server " } ,
{ & global_sid_S_1_3_3 , " Creator Group Server " } ,
1998-11-12 19:07:00 +03:00
{ & global_sid_S_1_5 , " NT Authority " } ,
{ & global_sam_sid , global_sam_name } ,
{ & global_member_sid , global_myworkgroup } ,
{ NULL , NULL }
} ;
/****************************************************************************
Read the machine SID from a file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL read_sid_from_file ( int fd , char * sid_file )
{
fstring fline ;
memset ( fline , ' \0 ' , sizeof ( fline ) ) ;
if ( read ( fd , fline , sizeof ( fline ) - 1 ) < 0 ) {
DEBUG ( 0 , ( " unable to read file %s. Error was %s \n " ,
sid_file , strerror ( errno ) ) ) ;
return False ;
}
/*
* Convert to the machine SID .
*/
fline [ sizeof ( fline ) - 1 ] = ' \0 ' ;
if ( ! string_to_sid ( & global_sam_sid , fline ) ) {
DEBUG ( 0 , ( " unable to generate machine SID. \n " ) ) ;
return False ;
}
return True ;
}
/****************************************************************************
Generate the global machine sid . Look for the MACHINE . SID file first , if
not found then look in smb . conf and use it to create the MACHINE . SID file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL get_member_domain_sid ( void )
{
POLICY_HND pol ;
fstring srv_name ;
struct cli_state cli ;
BOOL res = True ;
DOM_SID sid3 ;
DOM_SID sid5 ;
fstring dom3 ;
fstring dom5 ;
if ( ! cli_connect_serverlist ( & cli , lp_passwordserver ( ) ) )
{
DEBUG ( 0 , ( " get_member_domain_sid: unable to initialize client connection. \n " ) ) ;
return False ;
}
/*
* Ok - we have an anonymous connection to the IPC $ share .
* Now start the NT Domain stuff : - ) .
*/
fstrcpy ( dom3 , " " ) ;
fstrcpy ( dom5 , " " ) ;
ZERO_STRUCT ( sid3 ) ;
ZERO_STRUCT ( sid5 ) ;
fstrcpy ( srv_name , " \\ \\ " ) ;
fstrcat ( srv_name , global_myname ) ;
strupper ( srv_name ) ;
/* open LSARPC session. */
res = res ? cli_nt_session_open ( & cli , PIPE_LSARPC ) : False ;
/* lookup domain controller; receive a policy handle */
res = res ? do_lsa_open_policy ( & cli , srv_name , & pol , False ) : False ;
/* send client info query, level 3. receive domain name and sid */
res = res ? do_lsa_query_info_pol ( & cli , & pol , 3 , dom3 , & sid3 ) : False ;
/* send client info query, level 5. receive domain name and sid */
res = res ? do_lsa_query_info_pol ( & cli , & pol , 5 , dom5 , & sid5 ) : False ;
/* close policy handle */
res = res ? do_lsa_close ( & cli , & pol ) : False ;
/* close the session */
cli_nt_session_close ( & cli ) ;
cli_ulogoff ( & cli ) ;
cli_shutdown ( & cli ) ;
if ( res )
{
pstring sid ;
DEBUG ( 5 , ( " LSA Query Info Policy \n " ) ) ;
sid_to_string ( sid , & sid3 ) ;
DEBUG ( 5 , ( " Domain Member - Domain: %s SID: %s \n " , dom3 , sid ) ) ;
sid_to_string ( sid , & sid5 ) ;
DEBUG ( 5 , ( " Domain Controller - Domain: %s SID: %s \n " , dom5 , sid ) ) ;
if ( ! strequal ( dom3 , global_myworkgroup ) | |
! strequal ( dom5 , global_myworkgroup ) )
{
DEBUG ( 0 , ( " get_member_domain_sid: %s is a DC for %s not %s \n " ,
cli . desthost , dom5 , global_myworkgroup ) ) ;
res = False ;
}
}
else
{
DEBUG ( 5 , ( " lsa query info failed \n " ) ) ;
}
if ( ! res )
{
DEBUG ( 0 , ( " get_member_domain_sid: unable to obtain Domain member SID \n " ) ) ;
}
else
{
/* this is a _lot_ of trouble to go to for just this info: */
global_member_sid = sid5 ;
}
return res ;
}
/****************************************************************************
creates some useful well known sids
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void generate_wellknown_sids ( void )
{
string_to_sid ( & global_sid_S_1_5_20 , " S-1-5-32 " ) ;
string_to_sid ( & global_sid_S_1_1 , " S-1-1 " ) ;
1998-11-12 22:21:20 +03:00
string_to_sid ( & global_sid_S_1_3_0 , " S-1-3-0 " ) ;
string_to_sid ( & global_sid_S_1_3_1 , " S-1-3-1 " ) ;
string_to_sid ( & global_sid_S_1_3_2 , " S-1-3-2 " ) ;
string_to_sid ( & global_sid_S_1_3_3 , " S-1-3-3 " ) ;
1998-11-12 19:07:00 +03:00
string_to_sid ( & global_sid_S_1_5 , " S-1-5 " ) ;
}
/****************************************************************************
Generate the global machine sid . Look for the MACHINE . SID file first , if
not found then look in smb . conf and use it to create the MACHINE . SID file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL generate_sam_sid ( void )
{
int fd ;
int i ;
char * p ;
pstring sid_file ;
fstring sid_string ;
SMB_STRUCT_STAT st ;
uchar raw_sid_data [ 12 ] ;
pstrcpy ( sid_file , lp_smb_passwd_file ( ) ) ;
p = strrchr ( sid_file , ' / ' ) ;
if ( p ! = NULL ) {
* + + p = ' \0 ' ;
}
if ( ! directory_exist ( sid_file , NULL ) ) {
if ( dos_mkdir ( sid_file , 0700 ) ! = 0 ) {
DEBUG ( 0 , ( " can't create private directory %s : %s \n " ,
sid_file , strerror ( errno ) ) ) ;
return False ;
}
}
pstrcat ( sid_file , " MACHINE.SID " ) ;
if ( ( fd = open ( sid_file , O_RDWR | O_CREAT , 0644 ) ) = = - 1 ) {
DEBUG ( 0 , ( " unable to open or create file %s. Error was %s \n " ,
sid_file , strerror ( errno ) ) ) ;
return False ;
}
/*
* Check if the file contains data .
*/
if ( sys_fstat ( fd , & st ) < 0 ) {
DEBUG ( 0 , ( " unable to stat file %s. Error was %s \n " ,
sid_file , strerror ( errno ) ) ) ;
close ( fd ) ;
return False ;
}
if ( st . st_size > 0 ) {
/*
* We have a valid SID - read it .
*/
if ( ! read_sid_from_file ( fd , sid_file ) ) {
DEBUG ( 0 , ( " unable to read file %s. Error was %s \n " ,
sid_file , strerror ( errno ) ) ) ;
close ( fd ) ;
return False ;
}
close ( fd ) ;
return True ;
}
/*
* Generate the new sid data & turn it into a string .
*/
generate_random_buffer ( raw_sid_data , 12 , True ) ;
fstrcpy ( sid_string , " S-1-5-21 " ) ;
for ( i = 0 ; i < 3 ; i + + ) {
fstring tmp_string ;
slprintf ( tmp_string , sizeof ( tmp_string ) - 1 , " -%u " , IVAL ( raw_sid_data , i * 4 ) ) ;
fstrcat ( sid_string , tmp_string ) ;
}
fstrcat ( sid_string , " \n " ) ;
/*
* Ensure our new SID is valid .
*/
if ( ! string_to_sid ( & global_sam_sid , sid_string ) ) {
DEBUG ( 0 , ( " unable to generate machine SID. \n " ) ) ;
return False ;
}
/*
* Do an exclusive blocking lock on the file .
*/
if ( ! do_file_lock ( fd , 60 , F_WRLCK ) ) {
DEBUG ( 0 , ( " unable to lock file %s. Error was %s \n " ,
sid_file , strerror ( errno ) ) ) ;
close ( fd ) ;
return False ;
}
/*
* At this point we have a blocking lock on the SID
* file - check if in the meantime someone else wrote
* SID data into the file . If so - they were here first ,
* use their data .
*/
if ( sys_fstat ( fd , & st ) < 0 ) {
DEBUG ( 0 , ( " unable to stat file %s. Error was %s \n " ,
sid_file , strerror ( errno ) ) ) ;
close ( fd ) ;
return False ;
}
if ( st . st_size > 0 ) {
/*
* Unlock as soon as possible to reduce
* contention on the exclusive lock .
*/
do_file_lock ( fd , 60 , F_UNLCK ) ;
/*
* We have a valid SID - read it .
*/
if ( ! read_sid_from_file ( fd , sid_file ) ) {
DEBUG ( 0 , ( " unable to read file %s. Error was %s \n " ,
sid_file , strerror ( errno ) ) ) ;
close ( fd ) ;
return False ;
}
close ( fd ) ;
return True ;
}
/*
* The file is still empty and we have an exlusive lock on it .
* Write out out SID data into the file .
*/
if ( fchmod ( fd , 0644 ) < 0 ) {
DEBUG ( 0 , ( " unable to set correct permissions on file %s. \
Error was % s \ n " , sid_file, strerror(errno) ));
close ( fd ) ;
return False ;
}
if ( write ( fd , sid_string , strlen ( sid_string ) ) ! = strlen ( sid_string ) ) {
DEBUG ( 0 , ( " unable to write file %s. Error was %s \n " ,
sid_file , strerror ( errno ) ) ) ;
close ( fd ) ;
return False ;
}
/*
* Unlock & exit .
*/
do_file_lock ( fd , 60 , F_UNLCK ) ;
close ( fd ) ;
return True ;
}
/**************************************************************************
turns a domain name into a SID .
* * * side - effect : if the domain name is NULL , it is set to our domain * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL map_domain_name_to_sid ( DOM_SID * sid , char * * nt_domain )
{
fstring sid_str ;
sid_to_string ( sid_str , sid ) ;
DEBUG ( 5 , ( " map_domain_name_to_sid: %s \n " , sid_str ) ) ;
if ( nt_domain = = NULL )
{
* sid = global_sam_sid ;
return True ;
}
if ( ( * nt_domain ) = = NULL )
{
DEBUG ( 5 , ( " map_domain_name_to_sid: overriding NULL name to %s \n " ,
global_sam_name ) ) ;
( * nt_domain ) = strdup ( global_sam_name ) ;
* sid = global_sam_sid ;
return True ;
}
if ( strequal ( ( * nt_domain ) , global_sam_name ) )
{
* sid = global_sam_sid ;
return True ;
}
DEBUG ( 0 , ( " map_domain_name_to_sid: mapping to %s NOT IMPLEMENTED \n " ,
( * nt_domain ) ) ) ;
return False ;
}
/**************************************************************************
turns a domain SID into a name .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL map_domain_sid_to_name ( DOM_SID * sid , char * nt_domain )
{
fstring sid_str ;
int i = 0 ;
sid_to_string ( sid_str , sid ) ;
DEBUG ( 5 , ( " map_domain_sid_to_name: %s \n " , sid_str ) ) ;
if ( nt_domain = = NULL )
{
return False ;
}
while ( sid_name_map [ i ] . sid ! = NULL )
{
sid_to_string ( sid_str , sid_name_map [ i ] . sid ) ;
DEBUG ( 5 , ( " compare: %s \n " , sid_str ) ) ;
if ( sid_equal ( sid_name_map [ i ] . sid , sid ) )
{
fstrcpy ( nt_domain , sid_name_map [ i ] . name ) ;
DEBUG ( 5 , ( " found %s \n " , nt_domain ) ) ;
return True ;
}
i + + ;
}
DEBUG ( 0 , ( " map_domain_sid_to_name: mapping NOT IMPLEMENTED \n " ) ) ;
return False ;
}
/**************************************************************************
splits a name of format \ DOMAIN \ name into its two components .
sets the DOMAIN name to global_sam_name if it has not been specified .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL split_domain_name ( char * fullname , char * domain , char * name )
{
fstring full_name ;
char * p ;
if ( fullname = = NULL | | domain = = NULL | | name = = NULL )
{
return False ;
}
if ( fullname [ 0 ] = = ' \\ ' )
{
fullname + + ;
}
fstrcpy ( full_name , fullname ) ;
p = strchr ( full_name + 1 , ' \\ ' ) ;
if ( p = = NULL )
{
* p = 0 ;
fstrcpy ( domain , full_name ) ;
fstrcpy ( name , p + 1 ) ;
}
else
{
fstrcpy ( domain , global_sam_name ) ;
fstrcpy ( name , full_name ) ;
}
DEBUG ( 5 , ( " name '%s' split into ' \\ %s \\ %s' \n " , fullname , domain , name ) ) ;
return True ;
}