cleaning up: removing those horrible references to server list
[kai/samba.git] / source3 / lib / sids.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Samba utility functions
5    Copyright (C) Andrew Tridgell 1992-1998
6    
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.
11    
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.
16    
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.
20 */
21
22 #include "includes.h"
23
24
25 extern int DEBUGLEVEL;
26 extern pstring scope;
27 extern pstring global_myname;
28
29 /*
30  * This is set on startup - it defines the SID for this
31  * machine, and therefore the SAM database for which it is
32  * responsible.
33  */
34
35 DOM_SID global_sam_sid;
36
37 /*
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).
43  */
44
45 fstring global_sam_name; 
46
47 /*
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.
51  */
52
53 DOM_SID global_member_sid;
54
55 /*
56  * note the lack of a "global_member_name" - this is because
57  * this is the same as "global_myworkgroup".
58  */
59
60 extern fstring global_myworkgroup;
61 /* fstring global_member_dom_name; */
62
63 /*
64  * some useful sids
65  */
66
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 */
71
72 struct sid_map
73 {
74         DOM_SID *sid;
75         char *name;
76
77 };
78
79 struct sid_map static_sid_name_map[] =
80 {
81         { &global_sid_S_1_5_20, "BUILTIN" },
82         { &global_sid_S_1_1   , "Everyone" },
83         { &global_sid_S_1_3   , "Creator Owner" },
84         { &global_sid_S_1_5   , "NT Authority" },
85         { &global_sam_sid     , global_sam_name },
86         { &global_member_sid  , global_myworkgroup },
87         { NULL                , NULL      }
88 };
89
90 struct sid_map **sid_name_map = NULL;
91 uint32 num_maps = 0;
92
93 static struct sid_map *sid_map_dup(const struct sid_map *from)
94 {
95         if (from != NULL)
96         {
97                 struct sid_map *copy = (struct sid_map *)
98                                         malloc(sizeof(struct sid_map));
99                 if (copy != NULL)
100                 {
101                         ZERO_STRUCTP(copy);
102                         if (from->name != NULL)
103                         {
104                                 copy->name  = strdup(from->name );
105                         }
106                         if (from->sid != NULL)
107                         {
108                                 copy->sid = sid_dup(from->sid);
109                         }
110                 }
111                 return copy;
112         }
113         return NULL;
114 }
115
116 static void sid_map_free(struct sid_map *map)
117 {
118         if (map->name != NULL)
119         {
120                 free(map->name);
121         }
122         if (map->sid != NULL)
123         {
124                 free(map->sid);
125         }
126         free(map);
127 }
128
129 /****************************************************************************
130 free a sid map array
131 ****************************************************************************/
132 static void free_sidmap_array(uint32 num_entries, struct sid_map **entries)
133 {
134         void(*fn)(void*) = (void(*)(void*))&sid_map_free;
135         free_void_array(num_entries, (void**)entries, *fn);
136 }
137
138 /****************************************************************************
139 add a sid map state to the array
140 ****************************************************************************/
141 struct sid_map* add_sidmap_to_array(uint32 *len, struct sid_map ***array,
142                                 const struct sid_map *name)
143 {
144         void*(*fn)(const void*) = (void*(*)(const void*))&sid_map_dup;
145         return (struct sid_map*)add_copy_to_array(len,
146                              (void***)array, (const void*)name, *fn, False);
147                                 
148 }
149 /****************************************************************************
150  sets up the name associated with the SAM database for which we are responsible
151 ****************************************************************************/
152 void get_sam_domain_name(void)
153 {
154         switch (lp_server_role())
155         {
156                 case ROLE_DOMAIN_PDC:
157                 case ROLE_DOMAIN_BDC:
158                 {
159                         /* we are PDC (or BDC) for a Domain */
160                         fstrcpy(global_sam_name, lp_workgroup());
161                         break;
162                 }
163                 case ROLE_DOMAIN_MEMBER:
164                 {
165                         /* we are a "PDC", but FOR LOCAL SAM DATABASE ONLY */
166                         fstrcpy(global_sam_name, global_myname);
167                         break;
168                 }
169                 default:
170                 {
171                         /* no domain role, probably due to "security = share" */
172                         memset(global_sam_name, 0, sizeof(global_sam_name));
173                         break;
174                 }
175         }
176 }
177
178 /****************************************************************************
179  obtain the sid from the PDC.
180 ****************************************************************************/
181 BOOL get_member_domain_sid(void)
182 {
183         switch (lp_server_role())
184         {
185                 case ROLE_DOMAIN_NONE:
186                 {
187                         ZERO_STRUCT(global_member_sid);
188                         return True;
189                 }
190                 case ROLE_DOMAIN_PDC:
191                 {
192                         sid_copy(&global_member_sid, &global_sam_sid);
193                         return True;
194                 }
195                 default:
196                 {
197                         /* member or BDC, we're going for connection to PDC */
198                         break;
199                 }
200         }
201
202         return get_domain_sids(global_myname, NULL,
203                                &global_member_sid, lp_workgroup());
204 }
205
206
207 /****************************************************************************
208  creates some useful well known sids
209 ****************************************************************************/
210 void generate_wellknown_sids(void)
211 {
212         string_to_sid(&global_sid_S_1_5_20, "S-1-5-32");
213         string_to_sid(&global_sid_S_1_1   , "S-1-1"   );
214         string_to_sid(&global_sid_S_1_3   , "S-1-3"   );
215         string_to_sid(&global_sid_S_1_5   , "S-1-5"   );
216 }
217
218 /****************************************************************************
219  create a sid map table
220 ****************************************************************************/
221 BOOL create_sidmap_table(void)
222 {
223         int i;
224         char **doms = NULL;
225         uint32 num_doms = 0;
226
227         for (i = 0; static_sid_name_map[i].name != NULL; i++)
228         {
229                 add_sidmap_to_array(&num_maps, &sid_name_map,
230                                     &static_sid_name_map[i]);
231         }
232
233         enumtrustdoms(&doms, &num_doms);
234
235         for (i = 0; i < num_doms; i++)
236         {
237                 struct sid_map map;
238                 DOM_SID sid;
239
240                 map.name = doms[i];
241                 map.sid  = &sid;
242
243                 if (!read_sid(map.name, map.sid))
244                 {
245                         DEBUG(0,("Could not read Domain SID %s\n", map.name));
246                         return False;
247                 }
248                 add_sidmap_to_array(&num_maps, &sid_name_map, &map);
249         }
250
251
252         for (i = 0; i < num_maps; i++)
253         {
254                 fstring sidstr;
255                 sid_to_string(sidstr, sid_name_map[i]->sid);
256                 DEBUG(10,("Map:\tDomain:\t%s\tSID:\t%s\n",
257                          sid_name_map[i]->name, sidstr));
258         }
259
260
261         free_char_array(num_doms, doms);
262
263         return True;
264 }
265
266 /****************************************************************************
267  Generate the global machine sid. Look for the DOMAINNAME.SID file first, if
268  not found then look in smb.conf and use it to create the DOMAINNAME.SID file.
269 ****************************************************************************/
270 BOOL generate_sam_sid(char *domain_name, DOM_SID *sid)
271 {
272         char *p;
273         pstring sid_file;
274         pstring machine_sid_file;
275         fstring file_name;
276
277         pstrcpy(sid_file, lp_smb_passwd_file());
278
279         if (sid_file[0] == 0)
280         {
281                 DEBUG(0,("cannot find smb passwd file\n"));
282                 return False;
283         }
284
285         p = strrchr(sid_file, '/');
286         if (p != NULL)
287         {
288                 *++p = '\0';
289         }
290
291         if (!directory_exist(sid_file, NULL)) {
292                 if (mkdir(sid_file, 0700) != 0) {
293                         DEBUG(0,("can't create private directory %s : %s\n",
294                                  sid_file, strerror(errno)));
295                         return False;
296                 }
297         }
298
299         pstrcpy(machine_sid_file, sid_file);
300         pstrcat(machine_sid_file, "MACHINE.SID");
301
302         slprintf(file_name, sizeof(file_name)-1, "%s.SID", domain_name);
303         strupper(file_name);
304         pstrcat(sid_file, file_name);
305     
306         if (file_exist(machine_sid_file, NULL))
307         {
308                 if (file_exist(sid_file, NULL))
309                 {
310                         DEBUG(0,("both %s and %s exist when only one should, unable to continue\n",
311                                   machine_sid_file, sid_file));
312                         return False;
313                 }
314                 if (file_rename(machine_sid_file, sid_file))
315                 {
316                         DEBUG(0,("could not rename %s to %s.  Error was %s\n",
317                                   machine_sid_file, sid_file, strerror(errno)));
318                         return False;
319                 }
320         }
321         
322         /* attempt to read the SID from the file */
323         if (read_sid(domain_name, sid))
324         {
325                 return True;
326         }
327   
328         if (!create_new_sid(sid))
329         {
330                 return False;
331         }
332         /* attempt to read the SID from the file */
333         if (!write_sid(domain_name, sid))
334         {
335                 return True;
336         }
337   
338         /* during the attempt to write, someone else wrote? */
339
340         /* attempt to read the SID from the file */
341         if (read_sid(domain_name, sid))
342         {
343                 return True;
344         }
345   
346         return True;
347 }   
348
349 /**************************************************************************
350  turns a domain name into a SID.
351
352  *** side-effect: if the domain name is NULL, it is set to our domain ***
353
354 ***************************************************************************/
355 BOOL map_domain_name_to_sid(DOM_SID *sid, char **nt_domain)
356 {
357         int i = 0;
358
359         if (nt_domain == NULL)
360         {
361                 sid_copy(sid, &global_sam_sid);
362                 return True;
363         }
364
365         if ((*nt_domain) == NULL)
366         {
367                 DEBUG(5,("map_domain_name_to_sid: overriding NULL name to %s\n",
368                           global_sam_name));
369                 (*nt_domain) = strdup(global_sam_name);
370                 sid_copy(sid, &global_sam_sid);
371                 return True;
372         }
373
374         if ((*nt_domain)[0] == 0)
375         {
376                 free(*nt_domain);
377                 (*nt_domain) = strdup(global_sam_name);
378                 DEBUG(5,("map_domain_name_to_sid: overriding blank name to %s\n",
379                           (*nt_domain)));
380                 sid_copy(sid, &global_sam_sid);
381                 return True;
382         }
383
384         DEBUG(5,("map_domain_name_to_sid: %s\n", (*nt_domain)));
385
386         for (i = 0; sid_name_map[i]->name != NULL; i++)
387         {
388                 DEBUG(5,("compare: %s\n", sid_name_map[i]->name));
389                 if (strequal(sid_name_map[i]->name, (*nt_domain)))
390                 {
391                         fstring sid_str;
392                         sid_copy(sid, sid_name_map[i]->sid);
393                         sid_to_string(sid_str, sid_name_map[i]->sid);
394                         DEBUG(5,("found %s\n", sid_str));
395                         return True;
396                 }
397         }
398
399         DEBUG(0,("map_domain_name_to_sid: mapping to %s NOT IMPLEMENTED\n",
400                   (*nt_domain)));
401         return False;
402 }
403
404 /**************************************************************************
405  turns a domain SID into a name.
406
407 ***************************************************************************/
408 BOOL map_domain_sid_to_name(DOM_SID *sid, char *nt_domain)
409 {
410         fstring sid_str;
411         int i = 0;
412         sid_to_string(sid_str, sid);
413
414         DEBUG(5,("map_domain_sid_to_name: %s\n", sid_str));
415
416         if (nt_domain == NULL)
417         {
418                 return False;
419         }
420
421         for (i = 0; sid_name_map[i]->sid != NULL; i++)
422         {
423                 sid_to_string(sid_str, sid_name_map[i]->sid);
424                 DEBUG(5,("compare: %s\n", sid_str));
425                 if (sid_equal(sid_name_map[i]->sid, sid))
426                 {
427                         fstrcpy(nt_domain, sid_name_map[i]->name);
428                         DEBUG(5,("found %s\n", nt_domain));
429                         return True;
430                 }
431         }
432
433         DEBUG(0,("map_domain_sid_to_name: mapping NOT IMPLEMENTED\n"));
434
435         return False;
436 }
437 /**************************************************************************
438  turns a domain SID into a domain controller name.
439 ***************************************************************************/
440 BOOL map_domain_sid_to_any_dc(DOM_SID *sid, char *dc_name)
441 {
442         fstring domain;
443
444         if (!map_domain_sid_to_name(sid, domain))
445         {
446                 return False;
447         }
448
449         return get_any_dc_name(domain, dc_name);
450 }
451
452 /**************************************************************************
453  splits a name of format \DOMAIN\name or name into its two components.
454  sets the DOMAIN name to global_sam_name if it has not been specified.
455 ***************************************************************************/
456 BOOL split_domain_name(const char *fullname, char *domain, char *name)
457 {
458         fstring full_name;
459         char *p;
460
461         if (fullname == NULL || domain == NULL || name == NULL)
462         {
463                 return False;
464         }
465
466         if (fullname[0] == '\\')
467         {
468                 fullname++;
469         }
470         fstrcpy(full_name, fullname);
471         p = strchr(full_name+1, '\\');
472
473         if (p != NULL)
474         {
475                 *p = 0;
476                 fstrcpy(domain, full_name);
477                 fstrcpy(name, p+1);
478         }
479         else
480         {
481                 fstrcpy(domain, global_sam_name);
482                 fstrcpy(name, full_name);
483         }
484
485         DEBUG(10,("name '%s' split into domain:%s and nt name:%s'\n", fullname, domain, name));
486         return True;
487 }
488
489 /**************************************************************************
490  enumerates all trusted domains
491 ***************************************************************************/
492 BOOL enumtrustdoms(char ***doms, uint32 *num_entries)
493 {
494         fstring tmp;
495         char *tok;
496
497         /* add trusted domains */
498
499         tok = lp_trusted_domains();
500         if (next_token(&tok, tmp, NULL, sizeof(tmp)))
501         {
502                 do
503                 {
504                         fstring domain;
505                         split_at_first_component(tmp, domain, '=', NULL);
506                         add_chars_to_array(num_entries, doms, domain);
507
508                 } while (next_token(NULL, tmp, NULL, sizeof(tmp)));
509         }
510
511         return True;
512 }
513
514 /**************************************************************************
515  enumerates all domains for which the SAM server is responsible
516 ***************************************************************************/
517 BOOL enumdomains(char ***doms, uint32 *num_entries)
518 {
519         add_chars_to_array(num_entries, doms, global_sam_name);
520         add_chars_to_array(num_entries, doms, "Builtin");
521
522         return True;
523 }
524