Added init_nt_time function which initialises an NTTIME to -1.
[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 static struct sid_name_map_info
73 {
74         DOM_SID *sid;
75         char *name;
76
77 }
78 sid_name_map[] =
79 {
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 },
86         { NULL                , NULL      }
87 };
88
89 /****************************************************************************
90  Read the machine SID from a file.
91 ****************************************************************************/
92
93 static BOOL read_sid_from_file(int fd, char *sid_file)
94 {   
95   fstring fline;
96         fstring sid_str;
97     
98   memset(fline, '\0', sizeof(fline));
99
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) ));
103     return False;
104   }
105
106   /*
107    * Convert to the machine SID.
108    */
109
110   fline[sizeof(fline)-1] = '\0';
111   if (!string_to_sid( &global_sam_sid, fline)) {
112     DEBUG(0,("unable to generate machine SID.\n"));
113     return False;
114   }
115
116         sid_to_string(sid_str, &global_sam_sid);
117         DEBUG(5,("read_sid_from_file: sid %s\n", sid_str));
118
119   return True;
120 }
121
122 /****************************************************************************
123  sets up the name associated with the SAM database for which we are responsible
124 ****************************************************************************/
125 void get_sam_domain_name(void)
126 {
127         switch (lp_server_role())
128         {
129                 case ROLE_DOMAIN_PDC:
130                 case ROLE_DOMAIN_BDC:
131                 {
132                         /* we are PDC (or BDC) for a Domain */
133                         fstrcpy(global_sam_name, lp_workgroup());
134                         break;
135                 }
136                 case ROLE_DOMAIN_MEMBER:
137                 {
138                         /* we are a "PDC", but FOR LOCAL SAM DATABASE ONLY */
139                         fstrcpy(global_sam_name, global_myname);
140                         break;
141                 }
142                 default:
143                 {
144                         /* no domain role, probably due to "security = share" */
145                         memset(global_sam_name, 0, sizeof(global_sam_name));
146                         break;
147                 }
148         }
149 }
150
151 /****************************************************************************
152  obtain the sid from the PDC.
153 ****************************************************************************/
154 BOOL get_member_domain_sid(void)
155 {
156         switch (lp_server_role())
157         {
158                 case ROLE_DOMAIN_NONE:
159                 {
160                         ZERO_STRUCT(global_member_sid);
161                         return True;
162                 }
163                 case ROLE_DOMAIN_PDC:
164                 {
165                         sid_copy(&global_member_sid, &global_sam_sid);
166                         return True;
167                 }
168                 default:
169                 {
170                         /* member or BDC, we're going for connection to PDC */
171                         break;
172                 }
173         }
174
175         return get_domain_sids(NULL, &global_member_sid, lp_passwordserver());
176 }
177
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)
182 {
183         uint16 nt_pipe_fnum;
184         POLICY_HND pol;
185         fstring srv_name;
186         struct cli_state cli;
187         BOOL res = True;
188         fstring dom3;
189         fstring dom5;
190
191         if (sid3 == NULL && sid5 == NULL)
192         {
193                 /* don't waste my time... */
194                 return False;
195         }
196
197         if (!cli_connect_serverlist(&cli, servers))
198         {
199                 DEBUG(0,("get_member_domain_sid: unable to initialise client connection.\n"));
200                 return False;
201         }
202
203         /*
204          * Ok - we have an anonymous connection to the IPC$ share.
205          * Now start the NT Domain stuff :-).
206          */
207
208         fstrcpy(dom3, "");
209         fstrcpy(dom5, "");
210         if (sid3 != NULL)
211         {
212                 ZERO_STRUCTP(sid3);
213         }
214         if (sid5 != NULL)
215         {
216                 ZERO_STRUCTP(sid5);
217         }
218
219         fstrcpy(srv_name, "\\\\");
220         fstrcat(srv_name, global_myname);
221         strupper(srv_name);
222
223         /* open LSARPC session. */
224         res = res ? cli_nt_session_open(&cli, PIPE_LSARPC, &nt_pipe_fnum) : False;
225
226         /* lookup domain controller; receive a policy handle */
227         res = res ? lsa_open_policy(&cli, nt_pipe_fnum, srv_name, &pol, False) : False;
228
229         if (sid3 != NULL)
230         {
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;
233         }
234
235         if (sid5 != NULL)
236         {
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;
239         }
240
241         /* close policy handle */
242         res = res ? lsa_close(&cli, nt_pipe_fnum, &pol) : False;
243
244         /* close the session */
245         cli_nt_session_close(&cli, nt_pipe_fnum);
246         cli_ulogoff(&cli);
247         cli_shutdown(&cli);
248
249         if (res)
250         {
251                 pstring sid;
252                 DEBUG(2,("LSA Query Info Policy\n"));
253                 if (sid3 != NULL)
254                 {
255                         sid_to_string(sid, sid3);
256                         DEBUG(2,("Domain Member     - Domain: %s SID: %s\n", dom3, sid));
257                 }
258                 if (sid5 != NULL)
259                 {
260                         sid_to_string(sid, sid5);
261                         DEBUG(2,("Domain Controller - Domain: %s SID: %s\n", dom5, sid));
262                 }
263         }
264         else
265         {
266                 DEBUG(1,("lsa query info failed\n"));
267         }
268
269         return res;
270 }
271
272 /****************************************************************************
273  creates some useful well known sids
274 ****************************************************************************/
275 void generate_wellknown_sids(void)
276 {
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"   );
281 }
282
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)
288 {
289         int fd;
290         int i;
291         char *p;
292         pstring sid_file;
293         pstring machine_sid_file;
294         fstring sid_string;
295         fstring file_name;
296         SMB_STRUCT_STAT st;
297         uchar raw_sid_data[12];
298
299         pstrcpy(sid_file, lp_smb_passwd_file());
300
301         if (sid_file[0] == 0)
302         {
303                 DEBUG(0,("cannot find smb passwd file\n"));
304                 return False;
305         }
306
307         p = strrchr(sid_file, '/');
308         if (p != NULL)
309         {
310                 *++p = '\0';
311         }
312
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)));
317                         return False;
318                 }
319         }
320
321         pstrcpy(machine_sid_file, sid_file);
322         pstrcat(machine_sid_file, "MACHINE.SID");
323
324         slprintf(file_name, sizeof(file_name)-1, "%s.SID", domain_name);
325         strupper(file_name);
326         pstrcat(sid_file, file_name);
327     
328         if (file_exist(machine_sid_file, NULL))
329         {
330                 if (file_exist(sid_file, NULL))
331                 {
332                         DEBUG(0,("both %s and %s exist when only one should, unable to continue\n",
333                                   machine_sid_file, sid_file));
334                         return False;
335                 }
336                 if (file_rename(machine_sid_file, sid_file))
337                 {
338                         DEBUG(0,("could not rename %s to %s.  Error was %s\n",
339                                   machine_sid_file, sid_file, strerror(errno)));
340                         return False;
341                 }
342         }
343         
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) ));
347                 return False;
348         } 
349   
350         /*
351          * Check if the file contains data.
352          */
353         
354         if (sys_fstat( fd, &st) < 0) {
355                 DEBUG(0,("unable to stat file %s. Error was %s\n",
356                          sid_file, strerror(errno) ));
357                 close(fd);
358                 return False;
359         } 
360   
361         if (st.st_size > 0) {
362                 /*
363                  * We have a valid SID - read it.
364                  */
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) ));
368                         close(fd);
369                         return False;
370                 }
371                 close(fd);
372                 return True;
373         } 
374   
375         /*
376          * Generate the new sid data & turn it into a string.
377          */
378         generate_random_buffer( raw_sid_data, 12, True);
379                 
380         fstrcpy( sid_string, "S-1-5-21");
381         for( i = 0; i < 3; i++) {
382                 fstring tmp_string;
383                 slprintf( tmp_string, sizeof(tmp_string) - 1, "-%u", IVAL(raw_sid_data, i*4));
384                 fstrcat( sid_string, tmp_string);
385         }
386         
387         fstrcat(sid_string, "\n");
388         
389         /*
390          * Ensure our new SID is valid.
391          */
392         
393         if (!string_to_sid( &global_sam_sid, sid_string)) {
394                 DEBUG(0,("unable to generate machine SID.\n"));
395                 return False;
396         } 
397   
398         /*
399          * Do an exclusive blocking lock on the file.
400          */
401         
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) ));
405                 close(fd);
406                 return False;
407         } 
408   
409         /*
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,
413          * use their data.
414          */
415         
416         if (sys_fstat( fd, &st) < 0) {
417                 DEBUG(0,("unable to stat file %s. Error was %s\n",
418                          sid_file, strerror(errno) ));
419                 close(fd);
420                 return False;
421         } 
422   
423         if (st.st_size > 0) {
424                 /*
425                  * Unlock as soon as possible to reduce
426                  * contention on the exclusive lock.
427                  */ 
428                 do_file_lock( fd, 60, F_UNLCK);
429                 
430                 /*
431                  * We have a valid SID - read it.
432                  */
433                 
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) ));
437                         close(fd);
438                         return False;
439                 }
440                 close(fd);
441                 return True;
442         } 
443         
444         /*
445          * The file is still empty and we have an exlusive lock on it.
446          * Write out out SID data into the file.
447          */
448         
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) ));
452                 close(fd);
453                 return False;
454         } 
455         
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) ));
459                 close(fd);
460                 return False;
461         } 
462         
463         /*
464          * Unlock & exit.
465          */
466         
467         do_file_lock( fd, 60, F_UNLCK);
468         close(fd);
469         return True;
470 }   
471
472 /**************************************************************************
473  turns a domain name into a SID.
474
475  *** side-effect: if the domain name is NULL, it is set to our domain ***
476
477 ***************************************************************************/
478 BOOL map_domain_name_to_sid(DOM_SID *sid, char **nt_domain)
479 {
480         int i = 0;
481
482         if (nt_domain == NULL)
483         {
484                 sid_copy(sid, &global_sam_sid);
485                 return True;
486         }
487
488         if ((*nt_domain) == NULL)
489         {
490                 DEBUG(5,("map_domain_name_to_sid: overriding NULL name to %s\n",
491                           global_sam_name));
492                 (*nt_domain) = strdup(global_sam_name);
493                 sid_copy(sid, &global_sam_sid);
494                 return True;
495         }
496
497         if ((*nt_domain)[0] == 0)
498         {
499                 free(*nt_domain);
500                 (*nt_domain) = strdup(global_sam_name);
501                 DEBUG(5,("map_domain_name_to_sid: overriding blank name to %s\n",
502                           (*nt_domain)));
503                 sid_copy(sid, &global_sam_sid);
504                 return True;
505         }
506
507         DEBUG(5,("map_domain_name_to_sid: %s\n", (*nt_domain)));
508
509         while (sid_name_map[i].name != NULL)
510         {
511                 DEBUG(5,("compare: %s\n", sid_name_map[i].name));
512                 if (strequal(sid_name_map[i].name, (*nt_domain)))
513                 {
514                         fstring sid_str;
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));
518                         return True;
519                 }
520                 i++;
521         }
522
523         DEBUG(0,("map_domain_name_to_sid: mapping to %s NOT IMPLEMENTED\n",
524                   (*nt_domain)));
525         return False;
526 }
527
528 /**************************************************************************
529  turns a domain SID into a name.
530
531 ***************************************************************************/
532 BOOL map_domain_sid_to_name(DOM_SID *sid, char *nt_domain)
533 {
534         fstring sid_str;
535         int i = 0;
536         sid_to_string(sid_str, sid);
537
538         DEBUG(5,("map_domain_sid_to_name: %s\n", sid_str));
539
540         if (nt_domain == NULL)
541         {
542                 return False;
543         }
544
545         while (sid_name_map[i].sid != NULL)
546         {
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))
550                 {
551                         fstrcpy(nt_domain, sid_name_map[i].name);
552                         DEBUG(5,("found %s\n", nt_domain));
553                         return True;
554                 }
555                 i++;
556         }
557
558         DEBUG(0,("map_domain_sid_to_name: mapping NOT IMPLEMENTED\n"));
559
560         return False;
561 }
562
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)
568 {
569         fstring full_name;
570         char *p;
571
572         if (fullname == NULL || domain == NULL || name == NULL)
573         {
574                 return False;
575         }
576
577         if (fullname[0] == '\\')
578         {
579                 fullname++;
580         }
581         fstrcpy(full_name, fullname);
582         p = strchr(full_name+1, '\\');
583
584         if (p != NULL)
585         {
586                 *p = 0;
587                 fstrcpy(domain, full_name);
588                 fstrcpy(name, p+1);
589         }
590         else
591         {
592                 fstrcpy(domain, global_sam_name);
593                 fstrcpy(name, full_name);
594         }
595
596         DEBUG(10,("name '%s' split into domain:%s and nt name:%s'\n", fullname, domain, name));
597         return True;
598 }