jean-f. sent me some S-1-3-0,1,2,3 SIDs and names. S-1-3 doesn't exist.
[kai/samba.git] / source / rpc_server / srv_sid.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 /*
61  * some useful sids
62  */
63
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 */
71
72 extern pstring global_myworkgroup;
73 /* extern fstring global_member_dom_name; */
74
75 static struct sid_name_map_info
76 {
77         DOM_SID *sid;
78         char *name;
79
80 }
81 sid_name_map[] =
82 {
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 },
92         { NULL                 , NULL      }
93 };
94
95 /****************************************************************************
96  Read the machine SID from a file.
97 ****************************************************************************/
98
99 static BOOL read_sid_from_file(int fd, char *sid_file)
100 {   
101   fstring fline;
102     
103   memset(fline, '\0', sizeof(fline));
104
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) ));
108     return False;
109   }
110
111   /*
112    * Convert to the machine SID.
113    */
114
115   fline[sizeof(fline)-1] = '\0';
116   if (!string_to_sid( &global_sam_sid, fline)) {
117     DEBUG(0,("unable to generate machine SID.\n"));
118     return False;
119   }
120
121   return True;
122 }
123
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)
129 {
130         POLICY_HND pol;
131         fstring srv_name;
132         struct cli_state cli;
133         BOOL res = True;
134         DOM_SID sid3;
135         DOM_SID sid5;
136         fstring dom3;
137         fstring dom5;
138
139         if (!cli_connect_serverlist(&cli, lp_passwordserver()))
140         {
141                 DEBUG(0,("get_member_domain_sid: unable to initialize client connection.\n"));
142                 return False;
143         }
144
145         /*
146          * Ok - we have an anonymous connection to the IPC$ share.
147          * Now start the NT Domain stuff :-).
148          */
149
150         fstrcpy(dom3, "");
151         fstrcpy(dom5, "");
152         ZERO_STRUCT(sid3);
153         ZERO_STRUCT(sid5);
154
155         fstrcpy(srv_name, "\\\\");
156         fstrcat(srv_name, global_myname);
157         strupper(srv_name);
158
159         /* open LSARPC session. */
160         res = res ? cli_nt_session_open(&cli, PIPE_LSARPC) : False;
161
162         /* lookup domain controller; receive a policy handle */
163         res = res ? do_lsa_open_policy(&cli, srv_name, &pol, False) : False;
164
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;
167
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;
170
171         /* close policy handle */
172         res = res ? do_lsa_close(&cli, &pol) : False;
173
174         /* close the session */
175         cli_nt_session_close(&cli);
176         cli_ulogoff(&cli);
177         cli_shutdown(&cli);
178
179         if (res)
180         {
181                 pstring sid;
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));
187
188                 if (!strequal(dom3, global_myworkgroup) ||
189                     !strequal(dom5, global_myworkgroup))
190                 {
191                         DEBUG(0,("get_member_domain_sid: %s is a DC for %s not %s\n",
192                                   cli.desthost, dom5, global_myworkgroup));
193                         res = False;
194                 }
195         }
196         else
197         {
198                 DEBUG(5,("lsa query info failed\n"));
199         }
200         if (!res)
201         {
202                 DEBUG(0,("get_member_domain_sid: unable to obtain Domain member SID\n"));
203         }
204         else
205         {
206                 /* this is a _lot_ of trouble to go to for just this info: */
207                 global_member_sid = sid5;
208         }
209
210         return res;
211 }
212
213 /****************************************************************************
214  creates some useful well known sids
215 ****************************************************************************/
216 void generate_wellknown_sids(void)
217 {
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"   );
225 }
226
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)
232 {
233         int fd;
234         int i;
235         char *p;
236         pstring sid_file;
237         fstring sid_string;
238         SMB_STRUCT_STAT st;
239         uchar raw_sid_data[12];
240
241         pstrcpy(sid_file, lp_smb_passwd_file());
242         p = strrchr(sid_file, '/');
243         if (p != NULL) {
244                 *++p = '\0';
245         }
246
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)));
251                         return False;
252                 }
253         }
254
255         pstrcat(sid_file, "MACHINE.SID");
256     
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) ));
260                 return False;
261         } 
262   
263         /*
264          * Check if the file contains data.
265          */
266         
267         if (sys_fstat( fd, &st) < 0) {
268                 DEBUG(0,("unable to stat file %s. Error was %s\n",
269                          sid_file, strerror(errno) ));
270                 close(fd);
271                 return False;
272         } 
273   
274         if (st.st_size > 0) {
275                 /*
276                  * We have a valid SID - read it.
277                  */
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) ));
281                         close(fd);
282                         return False;
283                 }
284                 close(fd);
285                 return True;
286         } 
287   
288         /*
289          * Generate the new sid data & turn it into a string.
290          */
291         generate_random_buffer( raw_sid_data, 12, True);
292                 
293         fstrcpy( sid_string, "S-1-5-21");
294         for( i = 0; i < 3; i++) {
295                 fstring tmp_string;
296                 slprintf( tmp_string, sizeof(tmp_string) - 1, "-%u", IVAL(raw_sid_data, i*4));
297                 fstrcat( sid_string, tmp_string);
298         }
299         
300         fstrcat(sid_string, "\n");
301         
302         /*
303          * Ensure our new SID is valid.
304          */
305         
306         if (!string_to_sid( &global_sam_sid, sid_string)) {
307                 DEBUG(0,("unable to generate machine SID.\n"));
308                 return False;
309         } 
310   
311         /*
312          * Do an exclusive blocking lock on the file.
313          */
314         
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) ));
318                 close(fd);
319                 return False;
320         } 
321   
322         /*
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,
326          * use their data.
327          */
328         
329         if (sys_fstat( fd, &st) < 0) {
330                 DEBUG(0,("unable to stat file %s. Error was %s\n",
331                          sid_file, strerror(errno) ));
332                 close(fd);
333                 return False;
334         } 
335   
336         if (st.st_size > 0) {
337                 /*
338                  * Unlock as soon as possible to reduce
339                  * contention on the exclusive lock.
340                  */ 
341                 do_file_lock( fd, 60, F_UNLCK);
342                 
343                 /*
344                  * We have a valid SID - read it.
345                  */
346                 
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) ));
350                         close(fd);
351                         return False;
352                 }
353                 close(fd);
354                 return True;
355         } 
356         
357         /*
358          * The file is still empty and we have an exlusive lock on it.
359          * Write out out SID data into the file.
360          */
361         
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) ));
365                 close(fd);
366                 return False;
367         } 
368         
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) ));
372                 close(fd);
373                 return False;
374         } 
375         
376         /*
377          * Unlock & exit.
378          */
379         
380         do_file_lock( fd, 60, F_UNLCK);
381         close(fd);
382         return True;
383 }   
384
385 /**************************************************************************
386  turns a domain name into a SID.
387
388  *** side-effect: if the domain name is NULL, it is set to our domain ***
389
390 ***************************************************************************/
391 BOOL map_domain_name_to_sid(DOM_SID *sid, char **nt_domain)
392 {
393         fstring sid_str;
394         sid_to_string(sid_str, sid);
395         DEBUG(5,("map_domain_name_to_sid: %s\n", sid_str));
396
397         if (nt_domain == NULL)
398         {
399                 *sid = global_sam_sid;
400                 return True;
401         }
402
403         if ((*nt_domain) == NULL)
404         {
405                 DEBUG(5,("map_domain_name_to_sid: overriding NULL name to %s\n",
406                           global_sam_name));
407                 (*nt_domain) = strdup(global_sam_name);
408                 *sid = global_sam_sid;
409                 return True;
410         }
411
412         if (strequal((*nt_domain), global_sam_name))
413         {
414                 *sid = global_sam_sid;
415                 return True;
416         }
417
418         DEBUG(0,("map_domain_name_to_sid: mapping to %s NOT IMPLEMENTED\n",
419                   (*nt_domain)));
420         return False;
421 }
422
423 /**************************************************************************
424  turns a domain SID into a name.
425
426 ***************************************************************************/
427 BOOL map_domain_sid_to_name(DOM_SID *sid, char *nt_domain)
428 {
429         fstring sid_str;
430         int i = 0;
431         sid_to_string(sid_str, sid);
432
433         DEBUG(5,("map_domain_sid_to_name: %s\n", sid_str));
434
435         if (nt_domain == NULL)
436         {
437                 return False;
438         }
439
440         while (sid_name_map[i].sid != NULL)
441         {
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))
445                 {
446                         fstrcpy(nt_domain, sid_name_map[i].name);
447                         DEBUG(5,("found %s\n", nt_domain));
448                         return True;
449                 }
450                 i++;
451         }
452
453         DEBUG(0,("map_domain_sid_to_name: mapping NOT IMPLEMENTED\n"));
454
455         return False;
456 }
457
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)
463 {
464         fstring full_name;
465         char *p;
466
467         if (fullname == NULL || domain == NULL || name == NULL)
468         {
469                 return False;
470         }
471
472         if (fullname[0] == '\\')
473         {
474                 fullname++;
475         }
476         fstrcpy(full_name, fullname);
477         p = strchr(full_name+1, '\\');
478
479         if (p == NULL)
480         {
481                 *p = 0;
482                 fstrcpy(domain, full_name);
483                 fstrcpy(name, p+1);
484         }
485         else
486         {
487                 fstrcpy(domain, global_sam_name);
488                 fstrcpy(name, full_name);
489         }
490
491         DEBUG(5,("name '%s' split into '\\%s\\%s'\n", fullname, domain, name));
492         return True;
493 }