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".
64 DOM_SID global_sid_S_1_5_20; /* local well-known domain */
65 DOM_SID global_sid_S_1_1; /* everyone */
66 DOM_SID global_sid_S_1_5; /* NT Authority */
67 DOM_SID global_sid_S_1_3_0; /* Creator owner */
68 DOM_SID global_sid_S_1_3_1; /* Creator group */
69 DOM_SID global_sid_S_1_3_2; /* Creator owner server */
70 DOM_SID global_sid_S_1_3_3; /* Creator group server */
72 extern pstring global_myworkgroup;
73 /* extern fstring global_member_dom_name; */
75 static struct sid_name_map_info
83 { &global_sid_S_1_5_20, "BUILTIN" },
84 { &global_sid_S_1_1 , "Everyone" },
85 { &global_sid_S_1_3_0 , "Creator Owner" },
86 { &global_sid_S_1_3_1 , "Creator Group" },
87 { &global_sid_S_1_3_2 , "Creator Owner Server" },
88 { &global_sid_S_1_3_3 , "Creator Group Server" },
89 { &global_sid_S_1_5 , "NT Authority" },
90 { &global_sam_sid , global_sam_name },
91 { &global_member_sid , global_myworkgroup },
95 /****************************************************************************
96 Read the machine SID from a file.
97 ****************************************************************************/
99 static BOOL read_sid_from_file(int fd, char *sid_file)
103 memset(fline, '\0', sizeof(fline));
105 if (read(fd, fline, sizeof(fline) -1 ) < 0) {
106 DEBUG(0,("unable to read file %s. Error was %s\n",
107 sid_file, strerror(errno) ));
112 * Convert to the machine SID.
115 fline[sizeof(fline)-1] = '\0';
116 if (!string_to_sid( &global_sam_sid, fline)) {
117 DEBUG(0,("unable to generate machine SID.\n"));
124 /****************************************************************************
125 Generate the global machine sid. Look for the MACHINE.SID file first, if
126 not found then look in smb.conf and use it to create the MACHINE.SID file.
127 ****************************************************************************/
128 BOOL get_member_domain_sid(void)
132 struct cli_state cli;
139 if (!cli_connect_serverlist(&cli, lp_passwordserver()))
141 DEBUG(0,("get_member_domain_sid: unable to initialize client connection.\n"));
146 * Ok - we have an anonymous connection to the IPC$ share.
147 * Now start the NT Domain stuff :-).
155 fstrcpy(srv_name, "\\\\");
156 fstrcat(srv_name, global_myname);
159 /* open LSARPC session. */
160 res = res ? cli_nt_session_open(&cli, PIPE_LSARPC) : False;
162 /* lookup domain controller; receive a policy handle */
163 res = res ? do_lsa_open_policy(&cli, srv_name, &pol, False) : False;
165 /* send client info query, level 3. receive domain name and sid */
166 res = res ? do_lsa_query_info_pol(&cli, &pol, 3, dom3, &sid3) : False;
168 /* send client info query, level 5. receive domain name and sid */
169 res = res ? do_lsa_query_info_pol(&cli, &pol, 5, dom5, &sid5) : False;
171 /* close policy handle */
172 res = res ? do_lsa_close(&cli, &pol) : False;
174 /* close the session */
175 cli_nt_session_close(&cli);
182 DEBUG(5,("LSA Query Info Policy\n"));
183 sid_to_string(sid, &sid3);
184 DEBUG(5,("Domain Member - Domain: %s SID: %s\n", dom3, sid));
185 sid_to_string(sid, &sid5);
186 DEBUG(5,("Domain Controller - Domain: %s SID: %s\n", dom5, sid));
188 if (!strequal(dom3, global_myworkgroup) ||
189 !strequal(dom5, global_myworkgroup))
191 DEBUG(0,("get_member_domain_sid: %s is a DC for %s not %s\n",
192 cli.desthost, dom5, global_myworkgroup));
198 DEBUG(5,("lsa query info failed\n"));
202 DEBUG(0,("get_member_domain_sid: unable to obtain Domain member SID\n"));
206 /* this is a _lot_ of trouble to go to for just this info: */
207 global_member_sid = sid5;
213 /****************************************************************************
214 creates some useful well known sids
215 ****************************************************************************/
216 void generate_wellknown_sids(void)
218 string_to_sid(&global_sid_S_1_5_20, "S-1-5-32");
219 string_to_sid(&global_sid_S_1_1 , "S-1-1" );
220 string_to_sid(&global_sid_S_1_3_0 , "S-1-3-0" );
221 string_to_sid(&global_sid_S_1_3_1 , "S-1-3-1" );
222 string_to_sid(&global_sid_S_1_3_2 , "S-1-3-2" );
223 string_to_sid(&global_sid_S_1_3_3 , "S-1-3-3" );
224 string_to_sid(&global_sid_S_1_5 , "S-1-5" );
227 /****************************************************************************
228 Generate the global machine sid. Look for the MACHINE.SID file first, if
229 not found then look in smb.conf and use it to create the MACHINE.SID file.
230 ****************************************************************************/
231 BOOL generate_sam_sid(void)
239 uchar raw_sid_data[12];
241 pstrcpy(sid_file, lp_smb_passwd_file());
242 p = strrchr(sid_file, '/');
247 if (!directory_exist(sid_file, NULL)) {
248 if (dos_mkdir(sid_file, 0700) != 0) {
249 DEBUG(0,("can't create private directory %s : %s\n",
250 sid_file, strerror(errno)));
255 pstrcat(sid_file, "MACHINE.SID");
257 if ((fd = open(sid_file, O_RDWR | O_CREAT, 0644)) == -1) {
258 DEBUG(0,("unable to open or create file %s. Error was %s\n",
259 sid_file, strerror(errno) ));
264 * Check if the file contains data.
267 if (sys_fstat( fd, &st) < 0) {
268 DEBUG(0,("unable to stat file %s. Error was %s\n",
269 sid_file, strerror(errno) ));
274 if (st.st_size > 0) {
276 * We have a valid SID - read it.
278 if (!read_sid_from_file( fd, sid_file)) {
279 DEBUG(0,("unable to read file %s. Error was %s\n",
280 sid_file, strerror(errno) ));
289 * Generate the new sid data & turn it into a string.
291 generate_random_buffer( raw_sid_data, 12, True);
293 fstrcpy( sid_string, "S-1-5-21");
294 for( i = 0; i < 3; i++) {
296 slprintf( tmp_string, sizeof(tmp_string) - 1, "-%u", IVAL(raw_sid_data, i*4));
297 fstrcat( sid_string, tmp_string);
300 fstrcat(sid_string, "\n");
303 * Ensure our new SID is valid.
306 if (!string_to_sid( &global_sam_sid, sid_string)) {
307 DEBUG(0,("unable to generate machine SID.\n"));
312 * Do an exclusive blocking lock on the file.
315 if (!do_file_lock( fd, 60, F_WRLCK)) {
316 DEBUG(0,("unable to lock file %s. Error was %s\n",
317 sid_file, strerror(errno) ));
323 * At this point we have a blocking lock on the SID
324 * file - check if in the meantime someone else wrote
325 * SID data into the file. If so - they were here first,
329 if (sys_fstat( fd, &st) < 0) {
330 DEBUG(0,("unable to stat file %s. Error was %s\n",
331 sid_file, strerror(errno) ));
336 if (st.st_size > 0) {
338 * Unlock as soon as possible to reduce
339 * contention on the exclusive lock.
341 do_file_lock( fd, 60, F_UNLCK);
344 * We have a valid SID - read it.
347 if (!read_sid_from_file( fd, sid_file)) {
348 DEBUG(0,("unable to read file %s. Error was %s\n",
349 sid_file, strerror(errno) ));
358 * The file is still empty and we have an exlusive lock on it.
359 * Write out out SID data into the file.
362 if (fchmod(fd, 0644) < 0) {
363 DEBUG(0,("unable to set correct permissions on file %s. \
364 Error was %s\n", sid_file, strerror(errno) ));
369 if (write( fd, sid_string, strlen(sid_string)) != strlen(sid_string)) {
370 DEBUG(0,("unable to write file %s. Error was %s\n",
371 sid_file, strerror(errno) ));
380 do_file_lock( fd, 60, F_UNLCK);
385 /**************************************************************************
386 turns a domain name into a SID.
388 *** side-effect: if the domain name is NULL, it is set to our domain ***
390 ***************************************************************************/
391 BOOL map_domain_name_to_sid(DOM_SID *sid, char **nt_domain)
394 sid_to_string(sid_str, sid);
395 DEBUG(5,("map_domain_name_to_sid: %s\n", sid_str));
397 if (nt_domain == NULL)
399 *sid = global_sam_sid;
403 if ((*nt_domain) == NULL)
405 DEBUG(5,("map_domain_name_to_sid: overriding NULL name to %s\n",
407 (*nt_domain) = strdup(global_sam_name);
408 *sid = global_sam_sid;
412 if (strequal((*nt_domain), global_sam_name))
414 *sid = global_sam_sid;
418 DEBUG(0,("map_domain_name_to_sid: mapping to %s NOT IMPLEMENTED\n",
423 /**************************************************************************
424 turns a domain SID into a name.
426 ***************************************************************************/
427 BOOL map_domain_sid_to_name(DOM_SID *sid, char *nt_domain)
431 sid_to_string(sid_str, sid);
433 DEBUG(5,("map_domain_sid_to_name: %s\n", sid_str));
435 if (nt_domain == NULL)
440 while (sid_name_map[i].sid != NULL)
442 sid_to_string(sid_str, sid_name_map[i].sid);
443 DEBUG(5,("compare: %s\n", sid_str));
444 if (sid_equal(sid_name_map[i].sid, sid))
446 fstrcpy(nt_domain, sid_name_map[i].name);
447 DEBUG(5,("found %s\n", nt_domain));
453 DEBUG(0,("map_domain_sid_to_name: mapping NOT IMPLEMENTED\n"));
458 /**************************************************************************
459 splits a name of format \DOMAIN\name into its two components.
460 sets the DOMAIN name to global_sam_name if it has not been specified.
461 ***************************************************************************/
462 BOOL split_domain_name(char *fullname, char *domain, char *name)
467 if (fullname == NULL || domain == NULL || name == NULL)
472 if (fullname[0] == '\\')
476 fstrcpy(full_name, fullname);
477 p = strchr(full_name+1, '\\');
482 fstrcpy(domain, full_name);
487 fstrcpy(domain, global_sam_name);
488 fstrcpy(name, full_name);
491 DEBUG(5,("name '%s' split into '\\%s\\%s'\n", fullname, domain, name));