cleaning up conflicts between group code not yet committed and
[samba.git] / source3 / 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_3;    /* */
67 DOM_SID global_sid_S_1_5;    /* NT Authority */
68
69 extern pstring global_myworkgroup;
70 /* extern fstring global_member_dom_name; */
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   , "don't know" },
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     
97   memset(fline, '\0', sizeof(fline));
98
99   if (read(fd, fline, sizeof(fline) -1 ) < 0) {
100     DEBUG(0,("unable to read file %s. Error was %s\n",
101            sid_file, strerror(errno) ));
102     return False;
103   }
104
105   /*
106    * Convert to the machine SID.
107    */
108
109   fline[sizeof(fline)-1] = '\0';
110   if (!string_to_sid( &global_sam_sid, fline)) {
111     DEBUG(0,("unable to generate machine SID.\n"));
112     return False;
113   }
114
115   return True;
116 }
117
118 /****************************************************************************
119  Generate the global machine sid. Look for the MACHINE.SID file first, if
120  not found then look in smb.conf and use it to create the MACHINE.SID file.
121 ****************************************************************************/
122 BOOL get_member_domain_sid(void)
123 {
124         POLICY_HND pol;
125         fstring srv_name;
126         struct cli_state cli;
127         BOOL res = True;
128         DOM_SID sid3;
129         DOM_SID sid5;
130         fstring dom3;
131         fstring dom5;
132
133         if (!cli_connect_serverlist(&cli, lp_passwordserver()))
134         {
135                 DEBUG(0,("get_member_domain_sid: unable to initialize client connection.\n"));
136                 return False;
137         }
138
139         /*
140          * Ok - we have an anonymous connection to the IPC$ share.
141          * Now start the NT Domain stuff :-).
142          */
143
144         fstrcpy(dom3, "");
145         fstrcpy(dom5, "");
146         ZERO_STRUCT(sid3);
147         ZERO_STRUCT(sid5);
148
149         fstrcpy(srv_name, "\\\\");
150         fstrcat(srv_name, global_myname);
151         strupper(srv_name);
152
153         /* open LSARPC session. */
154         res = res ? cli_nt_session_open(&cli, PIPE_LSARPC) : False;
155
156         /* lookup domain controller; receive a policy handle */
157         res = res ? do_lsa_open_policy(&cli, srv_name, &pol, False) : False;
158
159         /* send client info query, level 3.  receive domain name and sid */
160         res = res ? do_lsa_query_info_pol(&cli, &pol, 3, dom3, &sid3) : False;
161
162         /* send client info query, level 5.  receive domain name and sid */
163         res = res ? do_lsa_query_info_pol(&cli, &pol, 5, dom5, &sid5) : False;
164
165         /* close policy handle */
166         res = res ? do_lsa_close(&cli, &pol) : False;
167
168         /* close the session */
169         cli_nt_session_close(&cli);
170         cli_ulogoff(&cli);
171         cli_shutdown(&cli);
172
173         if (res)
174         {
175                 pstring sid;
176                 DEBUG(5,("LSA Query Info Policy\n"));
177                 sid_to_string(sid, &sid3);
178                 DEBUG(5,("Domain Member     - Domain: %s SID: %s\n", dom3, sid));
179                 sid_to_string(sid, &sid5);
180                 DEBUG(5,("Domain Controller - Domain: %s SID: %s\n", dom5, sid));
181
182                 if (!strequal(dom3, global_myworkgroup) ||
183                     !strequal(dom5, global_myworkgroup))
184                 {
185                         DEBUG(0,("get_member_domain_sid: %s is a DC for %s not %s\n",
186                                   cli.desthost, dom5, global_myworkgroup));
187                         res = False;
188                 }
189         }
190         else
191         {
192                 DEBUG(5,("lsa query info failed\n"));
193         }
194         if (!res)
195         {
196                 DEBUG(0,("get_member_domain_sid: unable to obtain Domain member SID\n"));
197         }
198         else
199         {
200                 /* this is a _lot_ of trouble to go to for just this info: */
201                 global_member_sid = sid5;
202         }
203
204         return res;
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  Generate the global machine sid. Look for the MACHINE.SID file first, if
220  not found then look in smb.conf and use it to create the MACHINE.SID file.
221 ****************************************************************************/
222 BOOL generate_sam_sid(void)
223 {
224         int fd;
225         int i;
226         char *p;
227         pstring sid_file;
228         fstring sid_string;
229         SMB_STRUCT_STAT st;
230         uchar raw_sid_data[12];
231
232         pstrcpy(sid_file, lp_smb_passwd_file());
233         p = strrchr(sid_file, '/');
234         if (p != NULL) {
235                 *++p = '\0';
236         }
237
238         if (!directory_exist(sid_file, NULL)) {
239                 if (dos_mkdir(sid_file, 0700) != 0) {
240                         DEBUG(0,("can't create private directory %s : %s\n",
241                                  sid_file, strerror(errno)));
242                         return False;
243                 }
244         }
245
246         pstrcat(sid_file, "MACHINE.SID");
247     
248         if ((fd = open(sid_file, O_RDWR | O_CREAT, 0644)) == -1) {
249                 DEBUG(0,("unable to open or create file %s. Error was %s\n",
250                          sid_file, strerror(errno) ));
251                 return False;
252         } 
253   
254         /*
255          * Check if the file contains data.
256          */
257         
258         if (sys_fstat( fd, &st) < 0) {
259                 DEBUG(0,("unable to stat file %s. Error was %s\n",
260                          sid_file, strerror(errno) ));
261                 close(fd);
262                 return False;
263         } 
264   
265         if (st.st_size > 0) {
266                 /*
267                  * We have a valid SID - read it.
268                  */
269                 if (!read_sid_from_file( fd, sid_file)) {
270                         DEBUG(0,("unable to read file %s. Error was %s\n",
271                                  sid_file, strerror(errno) ));
272                         close(fd);
273                         return False;
274                 }
275                 close(fd);
276                 return True;
277         } 
278   
279         /*
280          * Generate the new sid data & turn it into a string.
281          */
282         generate_random_buffer( raw_sid_data, 12, True);
283                 
284         fstrcpy( sid_string, "S-1-5-21");
285         for( i = 0; i < 3; i++) {
286                 fstring tmp_string;
287                 slprintf( tmp_string, sizeof(tmp_string) - 1, "-%u", IVAL(raw_sid_data, i*4));
288                 fstrcat( sid_string, tmp_string);
289         }
290         
291         fstrcat(sid_string, "\n");
292         
293         /*
294          * Ensure our new SID is valid.
295          */
296         
297         if (!string_to_sid( &global_sam_sid, sid_string)) {
298                 DEBUG(0,("unable to generate machine SID.\n"));
299                 return False;
300         } 
301   
302         /*
303          * Do an exclusive blocking lock on the file.
304          */
305         
306         if (!do_file_lock( fd, 60, F_WRLCK)) {
307                 DEBUG(0,("unable to lock file %s. Error was %s\n",
308                          sid_file, strerror(errno) ));
309                 close(fd);
310                 return False;
311         } 
312   
313         /*
314          * At this point we have a blocking lock on the SID
315          * file - check if in the meantime someone else wrote
316          * SID data into the file. If so - they were here first,
317          * use their data.
318          */
319         
320         if (sys_fstat( fd, &st) < 0) {
321                 DEBUG(0,("unable to stat file %s. Error was %s\n",
322                          sid_file, strerror(errno) ));
323                 close(fd);
324                 return False;
325         } 
326   
327         if (st.st_size > 0) {
328                 /*
329                  * Unlock as soon as possible to reduce
330                  * contention on the exclusive lock.
331                  */ 
332                 do_file_lock( fd, 60, F_UNLCK);
333                 
334                 /*
335                  * We have a valid SID - read it.
336                  */
337                 
338                 if (!read_sid_from_file( fd, sid_file)) {
339                         DEBUG(0,("unable to read file %s. Error was %s\n",
340                                  sid_file, strerror(errno) ));
341                         close(fd);
342                         return False;
343                 }
344                 close(fd);
345                 return True;
346         } 
347         
348         /*
349          * The file is still empty and we have an exlusive lock on it.
350          * Write out out SID data into the file.
351          */
352         
353         if (fchmod(fd, 0644) < 0) {
354                 DEBUG(0,("unable to set correct permissions on file %s. \
355 Error was %s\n", sid_file, strerror(errno) ));
356                 close(fd);
357                 return False;
358         } 
359         
360         if (write( fd, sid_string, strlen(sid_string)) != strlen(sid_string)) {
361                 DEBUG(0,("unable to write file %s. Error was %s\n",
362                          sid_file, strerror(errno) ));
363                 close(fd);
364                 return False;
365         } 
366         
367         /*
368          * Unlock & exit.
369          */
370         
371         do_file_lock( fd, 60, F_UNLCK);
372         close(fd);
373         return True;
374 }   
375
376 /**************************************************************************
377  turns a domain name into a SID.
378
379  *** side-effect: if the domain name is NULL, it is set to our domain ***
380
381 ***************************************************************************/
382 BOOL map_domain_name_to_sid(DOM_SID *sid, char **nt_domain)
383 {
384         fstring sid_str;
385         sid_to_string(sid_str, sid);
386         DEBUG(5,("map_domain_name_to_sid: %s\n", sid_str));
387
388         if (nt_domain == NULL)
389         {
390                 *sid = global_sam_sid;
391                 return True;
392         }
393
394         if ((*nt_domain) == NULL)
395         {
396                 DEBUG(5,("map_domain_name_to_sid: overriding NULL name to %s\n",
397                           global_sam_name));
398                 (*nt_domain) = strdup(global_sam_name);
399                 *sid = global_sam_sid;
400                 return True;
401         }
402
403         if (strequal((*nt_domain), global_sam_name))
404         {
405                 *sid = global_sam_sid;
406                 return True;
407         }
408
409         DEBUG(0,("map_domain_name_to_sid: mapping to %s NOT IMPLEMENTED\n",
410                   (*nt_domain)));
411         return False;
412 }
413
414 /**************************************************************************
415  turns a domain SID into a name.
416
417 ***************************************************************************/
418 BOOL map_domain_sid_to_name(DOM_SID *sid, char *nt_domain)
419 {
420         fstring sid_str;
421         int i = 0;
422         sid_to_string(sid_str, sid);
423
424         DEBUG(5,("map_domain_sid_to_name: %s\n", sid_str));
425
426         if (nt_domain == NULL)
427         {
428                 return False;
429         }
430
431         while (sid_name_map[i].sid != NULL)
432         {
433                 sid_to_string(sid_str, sid_name_map[i].sid);
434                 DEBUG(5,("compare: %s\n", sid_str));
435                 if (sid_equal(sid_name_map[i].sid, sid))
436                 {
437                         fstrcpy(nt_domain, sid_name_map[i].name);
438                         DEBUG(5,("found %s\n", nt_domain));
439                         return True;
440                 }
441                 i++;
442         }
443
444         DEBUG(0,("map_domain_sid_to_name: mapping NOT IMPLEMENTED\n"));
445
446         return False;
447 }
448
449 /**************************************************************************
450  splits a name of format \DOMAIN\name into its two components.
451  sets the DOMAIN name to global_sam_name if it has not been specified.
452 ***************************************************************************/
453 BOOL split_domain_name(char *fullname, char *domain, char *name)
454 {
455         fstring full_name;
456         char *p;
457
458         if (fullname == NULL || domain == NULL || name == NULL)
459         {
460                 return False;
461         }
462
463         if (fullname[0] == '\\')
464         {
465                 fullname++;
466         }
467         fstrcpy(full_name, fullname);
468         p = strchr(full_name+1, '\\');
469
470         if (p == NULL)
471         {
472                 *p = 0;
473                 fstrcpy(domain, full_name);
474                 fstrcpy(name, p+1);
475         }
476         else
477         {
478                 fstrcpy(domain, global_sam_name);
479                 fstrcpy(name, full_name);
480         }
481
482         DEBUG(5,("name '%s' split into '\\%s\\%s'\n", fullname, domain, name));
483         return True;
484 }