2 Unix SMB/Netbios implementation.
4 Samba utility functions
5 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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.
25 extern int DEBUGLEVEL;
27 extern pstring global_myname;
30 * This is set on startup - it defines the SID for this
31 * machine, and therefore the SAM database for which it is
35 DOM_SID global_sam_sid;
38 * This is the name associated with the SAM database for
39 * which this machine is responsible. In the case of a PDC
40 * or PDC, this name is the same as the workgroup. In the
41 * case of "security = domain" mode, this is the same as
42 * the name of the server (global_myname).
45 fstring global_sam_name;
48 * This is obtained on startup - it defines the SID for which
49 * this machine is a member. It is therefore only set, and
50 * used, in "security = domain" mode.
53 DOM_SID global_member_sid;
56 * note the lack of a "global_member_name" - this is because
57 * this is the same as "global_myworkgroup".
60 extern fstring global_myworkgroup;
61 /* fstring global_member_dom_name; */
67 DOM_SID global_sid_S_1_5_20; /* local well-known domain */
68 DOM_SID global_sid_S_1_1; /* everyone */
69 DOM_SID global_sid_S_1_3; /* Creator Owner */
70 DOM_SID global_sid_S_1_5; /* NT Authority */
72 static struct sid_name_map_info
80 { &global_sid_S_1_5_20, "BUILTIN" },
81 { &global_sid_S_1_1 , "Everyone" },
82 { &global_sid_S_1_3 , "Creator Owner" },
83 { &global_sid_S_1_5 , "NT Authority" },
84 { &global_sam_sid , global_sam_name },
85 { &global_member_sid , global_myworkgroup },
89 /****************************************************************************
90 Read the machine SID from a file.
91 ****************************************************************************/
93 static BOOL read_sid_from_file(int fd, char *sid_file)
98 memset(fline, '\0', sizeof(fline));
100 if (read(fd, fline, sizeof(fline) -1 ) < 0) {
101 DEBUG(0,("unable to read file %s. Error was %s\n",
102 sid_file, strerror(errno) ));
107 * Convert to the machine SID.
110 fline[sizeof(fline)-1] = '\0';
111 if (!string_to_sid( &global_sam_sid, fline)) {
112 DEBUG(0,("unable to generate machine SID.\n"));
116 sid_to_string(sid_str, &global_sam_sid);
117 DEBUG(5,("read_sid_from_file: sid %s\n", sid_str));
122 /****************************************************************************
123 sets up the name associated with the SAM database for which we are responsible
124 ****************************************************************************/
125 void get_sam_domain_name(void)
127 switch (lp_server_role())
129 case ROLE_DOMAIN_PDC:
130 case ROLE_DOMAIN_BDC:
132 /* we are PDC (or BDC) for a Domain */
133 fstrcpy(global_sam_name, lp_workgroup());
136 case ROLE_DOMAIN_MEMBER:
138 /* we are a "PDC", but FOR LOCAL SAM DATABASE ONLY */
139 fstrcpy(global_sam_name, global_myname);
144 /* no domain role, probably due to "security = share" */
145 memset(global_sam_name, 0, sizeof(global_sam_name));
151 /****************************************************************************
152 obtain the sid from the PDC.
153 ****************************************************************************/
154 BOOL get_member_domain_sid(void)
156 switch (lp_server_role())
158 case ROLE_DOMAIN_NONE:
160 ZERO_STRUCT(global_member_sid);
163 case ROLE_DOMAIN_PDC:
165 sid_copy(&global_member_sid, &global_sam_sid);
170 /* member or BDC, we're going for connection to PDC */
175 return get_domain_sids(NULL, &global_member_sid, lp_passwordserver());
178 /****************************************************************************
179 obtain the sid from the PDC. do some verification along the way...
180 ****************************************************************************/
181 BOOL get_domain_sids(DOM_SID *sid3, DOM_SID *sid5, char *servers)
186 struct cli_state cli;
191 if (sid3 == NULL && sid5 == NULL)
193 /* don't waste my time... */
197 if (!cli_connect_serverlist(&cli, servers))
199 DEBUG(0,("get_member_domain_sid: unable to initialise client connection.\n"));
204 * Ok - we have an anonymous connection to the IPC$ share.
205 * Now start the NT Domain stuff :-).
219 fstrcpy(srv_name, "\\\\");
220 fstrcat(srv_name, global_myname);
223 /* open LSARPC session. */
224 res = res ? cli_nt_session_open(&cli, PIPE_LSARPC, &nt_pipe_fnum) : False;
226 /* lookup domain controller; receive a policy handle */
227 res = res ? lsa_open_policy(&cli, nt_pipe_fnum, srv_name, &pol, False) : False;
231 /* send client info query, level 3. receive domain name and sid */
232 res = res ? lsa_query_info_pol(&cli, nt_pipe_fnum, &pol, 3, dom3, sid3) : False;
237 /* send client info query, level 5. receive domain name and sid */
238 res = res ? lsa_query_info_pol(&cli, nt_pipe_fnum, &pol, 5, dom5, sid5) : False;
241 /* close policy handle */
242 res = res ? lsa_close(&cli, nt_pipe_fnum, &pol) : False;
244 /* close the session */
245 cli_nt_session_close(&cli, nt_pipe_fnum);
252 DEBUG(2,("LSA Query Info Policy\n"));
255 sid_to_string(sid, sid3);
256 DEBUG(2,("Domain Member - Domain: %s SID: %s\n", dom3, sid));
260 sid_to_string(sid, sid5);
261 DEBUG(2,("Domain Controller - Domain: %s SID: %s\n", dom5, sid));
266 DEBUG(1,("lsa query info failed\n"));
272 /****************************************************************************
273 creates some useful well known sids
274 ****************************************************************************/
275 void generate_wellknown_sids(void)
277 string_to_sid(&global_sid_S_1_5_20, "S-1-5-32");
278 string_to_sid(&global_sid_S_1_1 , "S-1-1" );
279 string_to_sid(&global_sid_S_1_3 , "S-1-3" );
280 string_to_sid(&global_sid_S_1_5 , "S-1-5" );
283 /****************************************************************************
284 Generate the global machine sid. Look for the DOMAINNAME.SID file first, if
285 not found then look in smb.conf and use it to create the DOMAINNAME.SID file.
286 ****************************************************************************/
287 BOOL generate_sam_sid(char *domain_name)
293 pstring machine_sid_file;
297 uchar raw_sid_data[12];
299 pstrcpy(sid_file, lp_smb_passwd_file());
301 if (sid_file[0] == 0)
303 DEBUG(0,("cannot find smb passwd file\n"));
307 p = strrchr(sid_file, '/');
313 if (!directory_exist(sid_file, NULL)) {
314 if (dos_mkdir(sid_file, 0700) != 0) {
315 DEBUG(0,("can't create private directory %s : %s\n",
316 sid_file, strerror(errno)));
321 pstrcpy(machine_sid_file, sid_file);
322 pstrcat(machine_sid_file, "MACHINE.SID");
324 slprintf(file_name, sizeof(file_name)-1, "%s.SID", domain_name);
326 pstrcat(sid_file, file_name);
328 if (file_exist(machine_sid_file, NULL))
330 if (file_exist(sid_file, NULL))
332 DEBUG(0,("both %s and %s exist when only one should, unable to continue\n",
333 machine_sid_file, sid_file));
336 if (file_rename(machine_sid_file, sid_file))
338 DEBUG(0,("could not rename %s to %s. Error was %s\n",
339 machine_sid_file, sid_file, strerror(errno)));
344 if ((fd = sys_open(sid_file, O_RDWR | O_CREAT, 0644)) == -1) {
345 DEBUG(0,("unable to open or create file %s. Error was %s\n",
346 sid_file, strerror(errno) ));
351 * Check if the file contains data.
354 if (sys_fstat( fd, &st) < 0) {
355 DEBUG(0,("unable to stat file %s. Error was %s\n",
356 sid_file, strerror(errno) ));
361 if (st.st_size > 0) {
363 * We have a valid SID - read it.
365 if (!read_sid_from_file( fd, sid_file)) {
366 DEBUG(0,("unable to read file %s. Error was %s\n",
367 sid_file, strerror(errno) ));
376 * Generate the new sid data & turn it into a string.
378 generate_random_buffer( raw_sid_data, 12, True);
380 fstrcpy( sid_string, "S-1-5-21");
381 for( i = 0; i < 3; i++) {
383 slprintf( tmp_string, sizeof(tmp_string) - 1, "-%u", IVAL(raw_sid_data, i*4));
384 fstrcat( sid_string, tmp_string);
387 fstrcat(sid_string, "\n");
390 * Ensure our new SID is valid.
393 if (!string_to_sid( &global_sam_sid, sid_string)) {
394 DEBUG(0,("unable to generate machine SID.\n"));
399 * Do an exclusive blocking lock on the file.
402 if (!do_file_lock( fd, 60, F_WRLCK)) {
403 DEBUG(0,("unable to lock file %s. Error was %s\n",
404 sid_file, strerror(errno) ));
410 * At this point we have a blocking lock on the SID
411 * file - check if in the meantime someone else wrote
412 * SID data into the file. If so - they were here first,
416 if (sys_fstat( fd, &st) < 0) {
417 DEBUG(0,("unable to stat file %s. Error was %s\n",
418 sid_file, strerror(errno) ));
423 if (st.st_size > 0) {
425 * Unlock as soon as possible to reduce
426 * contention on the exclusive lock.
428 do_file_lock( fd, 60, F_UNLCK);
431 * We have a valid SID - read it.
434 if (!read_sid_from_file( fd, sid_file)) {
435 DEBUG(0,("unable to read file %s. Error was %s\n",
436 sid_file, strerror(errno) ));
445 * The file is still empty and we have an exlusive lock on it.
446 * Write out out SID data into the file.
449 if (fchmod(fd, 0644) < 0) {
450 DEBUG(0,("unable to set correct permissions on file %s. \
451 Error was %s\n", sid_file, strerror(errno) ));
456 if (write( fd, sid_string, strlen(sid_string)) != strlen(sid_string)) {
457 DEBUG(0,("unable to write file %s. Error was %s\n",
458 sid_file, strerror(errno) ));
467 do_file_lock( fd, 60, F_UNLCK);
472 /**************************************************************************
473 turns a domain name into a SID.
475 *** side-effect: if the domain name is NULL, it is set to our domain ***
477 ***************************************************************************/
478 BOOL map_domain_name_to_sid(DOM_SID *sid, char **nt_domain)
482 if (nt_domain == NULL)
484 sid_copy(sid, &global_sam_sid);
488 if ((*nt_domain) == NULL)
490 DEBUG(5,("map_domain_name_to_sid: overriding NULL name to %s\n",
492 (*nt_domain) = strdup(global_sam_name);
493 sid_copy(sid, &global_sam_sid);
497 if ((*nt_domain)[0] == 0)
500 (*nt_domain) = strdup(global_sam_name);
501 DEBUG(5,("map_domain_name_to_sid: overriding blank name to %s\n",
503 sid_copy(sid, &global_sam_sid);
507 DEBUG(5,("map_domain_name_to_sid: %s\n", (*nt_domain)));
509 while (sid_name_map[i].name != NULL)
511 DEBUG(5,("compare: %s\n", sid_name_map[i].name));
512 if (strequal(sid_name_map[i].name, (*nt_domain)))
515 sid_copy(sid, sid_name_map[i].sid);
516 sid_to_string(sid_str, sid_name_map[i].sid);
517 DEBUG(5,("found %s\n", sid_str));
523 DEBUG(0,("map_domain_name_to_sid: mapping to %s NOT IMPLEMENTED\n",
528 /**************************************************************************
529 turns a domain SID into a name.
531 ***************************************************************************/
532 BOOL map_domain_sid_to_name(DOM_SID *sid, char *nt_domain)
536 sid_to_string(sid_str, sid);
538 DEBUG(5,("map_domain_sid_to_name: %s\n", sid_str));
540 if (nt_domain == NULL)
545 while (sid_name_map[i].sid != NULL)
547 sid_to_string(sid_str, sid_name_map[i].sid);
548 DEBUG(5,("compare: %s\n", sid_str));
549 if (sid_equal(sid_name_map[i].sid, sid))
551 fstrcpy(nt_domain, sid_name_map[i].name);
552 DEBUG(5,("found %s\n", nt_domain));
558 DEBUG(0,("map_domain_sid_to_name: mapping NOT IMPLEMENTED\n"));
563 /**************************************************************************
564 splits a name of format \DOMAIN\name or name into its two components.
565 sets the DOMAIN name to global_sam_name if it has not been specified.
566 ***************************************************************************/
567 BOOL split_domain_name(const char *fullname, char *domain, char *name)
572 if (fullname == NULL || domain == NULL || name == NULL)
577 if (fullname[0] == '\\')
581 fstrcpy(full_name, fullname);
582 p = strchr(full_name+1, '\\');
587 fstrcpy(domain, full_name);
592 fstrcpy(domain, global_sam_name);
593 fstrcpy(name, full_name);
596 DEBUG(10,("name '%s' split into domain:%s and nt name:%s'\n", fullname, domain, name));