1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-27 03:21:53 +03:00
samba-mirror/source3/rpc_server/srv_sid.c

494 lines
12 KiB
C
Raw Normal View History

/*
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 02139, 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 */
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 */
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" },
{ &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" },
{ &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" );
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" );
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;
}