remove / add / attempt to stop remove didn't work.
[samba.git] / source3 / smbd / groupname.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Groupname handling
5    Copyright (C) Jeremy Allison 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 /* 
23  * UNIX gid and Local or Domain SID resolution.  This module resolves
24  * only those entries in the map files, it is *NOT* responsible for
25  * resolving UNIX groups not listed: that is an entirely different
26  * matter, altogether...
27  */
28
29 /*
30  *
31  *
32
33  format of the file is:
34
35  unixname       NT Group name
36  unixname       Domain Admins (well-known Domain Group)
37  unixname       DOMAIN_NAME\NT Group name
38  unixname       OTHER_DOMAIN_NAME\NT Group name
39  unixname       DOMAIN_NAME\Domain Admins (well-known Domain Group)
40  ....
41
42  if the DOMAIN_NAME\ component is left off, then your own domain is assumed.
43
44  *
45  *
46  */
47
48
49 #include "includes.h"
50 extern int DEBUGLEVEL;
51
52 extern fstring global_sam_name;
53
54 /* we can map either local aliases or domain groups */
55 typedef enum 
56 {
57         GROUP_LOCAL,
58         GROUP_DOMAIN
59
60 } GROUP_TYPE;
61
62 /**************************************************************************
63  Groupname map functionality. The code loads a groupname map file and
64  (currently) loads it into a linked list. This is slow and memory
65  hungry, but can be changed into a more efficient storage format
66  if the demands on it become excessive.
67 ***************************************************************************/
68
69 typedef struct group_name_info
70 {
71    char *nt_name;
72    char *nt_domain;
73    char *unix_name;
74
75    DOM_SID sid;
76    gid_t  unix_gid;
77
78 } GROUP_NAME_INFO;
79
80 typedef struct name_map
81 {
82         ubi_slNode next;
83         GROUP_NAME_INFO grp;
84
85 } name_map_entry;
86
87 static ubi_slList groupname_map_list;
88 static ubi_slList aliasname_map_list;
89
90 static void delete_name_entry(name_map_entry *gmep)
91 {
92         if (gmep->grp.nt_name)
93         {
94                 free(gmep->grp.nt_name);
95         }
96         if (gmep->grp.nt_domain)
97         {
98                 free(gmep->grp.nt_domain);
99         }
100         if (gmep->grp.unix_name)
101         {
102                 free(gmep->grp.unix_name);
103         }
104         free((char*)gmep);
105 }
106
107 /**************************************************************************
108  Delete all the entries in the name map list.
109 ***************************************************************************/
110
111 static void delete_map_list(ubi_slList *map_list)
112 {
113         name_map_entry *gmep;
114
115         while ((gmep = (name_map_entry *)ubi_slRemHead(map_list )) != NULL)
116         {
117                 delete_name_entry(gmep);
118         }
119 }
120
121
122 /**************************************************************************
123  makes a group sid out of a domain sid and a _unix_ gid.
124 ***************************************************************************/
125 static BOOL make_mydomain_sid(GROUP_NAME_INFO *grp, GROUP_TYPE type)
126 {
127         uint32 tmp_rid;
128         DOM_SID sid;
129         uint8  tmp_type;
130
131         DEBUG(10,("make_mydomain_sid\n"));
132
133         if (!map_domain_name_to_sid(&grp->sid, &(grp->nt_domain)))
134         {
135                 DEBUG(0,("make_mydomain_sid: unknown domain %s\n",
136                           grp->nt_domain));
137                 return False;
138         }
139
140         if (strequal(grp->nt_domain, global_sam_name) &&
141             lookup_wk_group_name(grp->nt_name, &sid, &tmp_type))
142         {
143                 sid_copy(&grp->sid, &sid);
144                 return True;
145         }
146         else
147         {
148                 if (type == GROUP_DOMAIN)
149                 {
150                         tmp_rid = pwdb_gid_to_group_rid(grp->unix_gid);
151                 }
152                 else
153                 {
154                         tmp_rid = pwdb_gid_to_alias_rid(grp->unix_gid);
155                 }
156                 return sid_append_rid(&(grp->sid), tmp_rid);
157         }
158 }
159
160 /**************************************************************************
161  makes a group sid out of an nt domain, nt group name or a unix group name.
162 ***************************************************************************/
163 static BOOL unix_name_to_group_info(GROUP_NAME_INFO *grp, GROUP_TYPE type)
164 {
165         struct group *gptr = NULL;
166
167         /*
168          * Attempt to get the unix gid_t for this name.
169          */
170
171         DEBUG(5,("unix_name_to_group_info: unix_name:%s\n", grp->unix_name));
172
173         gptr = (struct group *)getgrnam(grp->unix_name);
174         if (gptr == NULL)
175         {
176                 DEBUG(0,("unix_name_to_group_info: getgrnam for group %s\
177 failed. Error was %s.\n", grp->unix_name, strerror(errno) ));
178                 return False;
179         }
180
181         grp->unix_gid = (gid_t)gptr->gr_gid;
182
183         DEBUG(5,("unix_name_to_group_info: unix gid:%d\n", grp->unix_gid));
184
185         /*
186          * Now map the name to an NT SID+RID.
187          */
188
189         if (grp->nt_domain != NULL && !strequal(grp->nt_domain, global_sam_name))
190         {
191                 /* Must add client-call lookup code here, to 
192                  * resolve remote domain's sid and the group's rid,
193                  * in that domain.
194                  *
195                  * NOTE: it is _incorrect_ to put code here that assumes
196                  * that we can call pwdb_gid_to_group_rid() or _alias_rid():
197                  * it is a totally different domain for which we are *NOT*
198                  * responsible.
199                  * for foriegn domains for which we are *NOT* the PDC, all
200                  * we can be responsible for is the unix * gid_t to which
201                  * the foriegn SID+rid maps to, on this _local_ machine.  
202                  */
203
204                 if (!map_domain_name_to_sid(&grp->sid, &(grp->nt_domain)))
205                 {
206                         DEBUG(0,("unix_name_to_group_info: no known sid for %s\n",
207                                   grp->nt_domain));
208                         return False;
209                 }
210
211                 DEBUG(0,("unix_name_to_group_info: cannot resolve domain %s\n",
212                           grp->nt_domain));
213
214                 return False;
215         }
216         else
217         {
218                 return make_mydomain_sid(grp, type);
219         }
220 }
221
222 static BOOL make_name_entry(name_map_entry **new_ep,
223                 char *nt_domain, char *nt_group, char *unix_group,
224                 GROUP_TYPE type)
225 {
226         /*
227          * Create the list entry and add it onto the list.
228          */
229
230         DEBUG(5,("make_name_entry:%s,%s,%s\n", nt_domain, nt_group, unix_group));
231
232         (*new_ep) = (name_map_entry *)malloc(sizeof(name_map_entry));
233         if ((*new_ep) == NULL)
234         {
235                 DEBUG(0,("make_name_entry: malloc fail for name_map_entry.\n"));
236                 return False;
237         } 
238
239         ZERO_STRUCTP(*new_ep);
240
241         (*new_ep)->grp.nt_name   = strdup(nt_group  );
242         (*new_ep)->grp.nt_domain = strdup(nt_domain );
243         (*new_ep)->grp.unix_name = strdup(unix_group);
244
245         if ((*new_ep)->grp.nt_name   == NULL ||
246             (*new_ep)->grp.unix_name == NULL)
247         {
248                 DEBUG(0,("make_name_entry: malloc fail for names in name_map_entry.\n"));
249                 delete_name_entry((*new_ep));
250                 return False;
251         }
252
253         /*
254          * look up the group names, make the Group-SID and unix gid
255          */
256  
257         if (!unix_name_to_group_info(&(*new_ep)->grp, type))
258         {
259                 delete_name_entry((*new_ep));
260                 return False;
261         }
262
263         return True;
264 }
265
266 /**************************************************************************
267  Load a name map file. Sets last accessed timestamp.
268 ***************************************************************************/
269 static void load_name_map(GROUP_TYPE type)
270 {
271         static time_t groupmap_file_last_modified = (time_t)0;
272         static time_t aliasmap_file_last_modified = (time_t)0;
273         static BOOL initialised_group = False;
274         static BOOL initialised_alias = False;
275         char *groupname_map_file = lp_groupname_map();
276         char *aliasname_map_file = lp_aliasname_map();
277
278         SMB_STRUCT_STAT st;
279         FILE *fp;
280         char *s;
281         pstring buf;
282         name_map_entry *new_ep;
283
284         time_t *file_last_modified;
285         int    *initialised;
286         char   *map_file;
287         ubi_slList *map_list;
288
289         if (type == GROUP_DOMAIN)
290         {
291                 file_last_modified = &groupmap_file_last_modified;
292                 initialised        = &initialised_group;
293                 map_file           = groupname_map_file;
294                 map_list           = &groupname_map_list;
295         }
296         else
297         {
298                 file_last_modified = &aliasmap_file_last_modified;
299                 initialised        = &initialised_alias;
300                 map_file           = aliasname_map_file;
301                 map_list           = &aliasname_map_list;
302         }
303
304         DEBUG(10,("load_name_map : %s\n", map_file));
305
306         if (!(*initialised))
307         {
308                 ubi_slInitList(map_list);
309                 (*initialised) = True;
310         }
311
312         if (!*map_file)
313         {
314                 return;
315         }
316
317         if (sys_stat(map_file, &st) != 0)
318         {
319                 DEBUG(0, ("load_name_map: Unable to stat file %s. Error was %s\n",
320                            map_file, strerror(errno) ));
321                 return;
322         }
323
324         /*
325          * Check if file has changed.
326          */
327         if (st.st_mtime <= (*file_last_modified))
328         {
329                 return;
330         }
331
332         (*file_last_modified) = st.st_mtime;
333
334         /*
335          * Load the file.
336          */
337
338         fp = fopen(map_file,"r");
339         if (!fp)
340         {
341                 DEBUG(0,("load_name_map: can't open name map %s. Error was %s\n",
342                           map_file, strerror(errno)));
343                 return;
344         }
345
346         /*
347          * Throw away any previous list.
348          */
349         delete_map_list(map_list);
350
351         DEBUG(4,("load_name_map: Scanning name map %s\n",map_file));
352
353         while ((s = fgets_slash(buf, sizeof(buf), fp)) != NULL)
354         {
355                 pstring unixname;
356                 pstring nt_name;
357                 fstring nt_domain;
358                 fstring nt_group;
359                 char *p;
360
361                 DEBUG(10,("Read line |%s|\n", s));
362
363                 memset(nt_name, 0, sizeof(nt_name));
364
365                 if (!*s || strchr("#;",*s))
366                         continue;
367
368                 if (!next_token(&s,unixname, "\t\n\r=", sizeof(unixname)))
369                         continue;
370
371                 if (!next_token(&s,nt_name, "\t\n\r=", sizeof(nt_name)))
372                         continue;
373
374                 trim_string(unixname, " ", " ");
375                 trim_string(nt_name, " ", " ");
376
377                 if (!*nt_name)
378                         continue;
379
380                 if (!*unixname)
381                         continue;
382
383                 DEBUG(5,("unixname = %s, ntname = %s.\n",
384                           unixname, nt_name));
385
386                 p = strchr(nt_name, '\\');
387
388                 if (p == NULL)
389                 {
390                         memset(nt_domain, 0, sizeof(nt_domain));
391                         fstrcpy(nt_group, nt_name);
392                 }
393                 else
394                 {
395                         *p = 0;
396                         p++;
397                         fstrcpy(nt_domain, nt_name);
398                         fstrcpy(nt_group , p);
399                 }
400
401                 if (make_name_entry(&new_ep, nt_domain, nt_name, unixname, type))
402                 {
403                         ubi_slAddHead(map_list, (ubi_slNode *)new_ep);
404                 }
405         }
406
407         DEBUG(10,("load_name_map: Added %ld entries to name map.\n",
408         ubi_slCount(map_list)));
409
410         fclose(fp);
411 }
412
413 /***********************************************************
414  Lookup by SID
415 ************************************************************/
416 static BOOL map_sid(GROUP_TYPE type, ubi_slList *map_list,
417                 DOM_SID *psid, gid_t *gid, char *ntname, char *ntdomain)
418 {
419         name_map_entry *gmep;
420
421         /*
422          * Initialize and load if not already loaded.
423          */
424         load_name_map(type);
425
426         for (gmep = (name_map_entry *)ubi_slFirst(map_list);
427              gmep != NULL;
428              gmep = (name_map_entry *)ubi_slNext(gmep ))
429         {
430                 if (sid_equal(&gmep->grp.sid, psid))
431                 {
432                         if (gid != NULL)
433                         {
434                                 *gid = gmep->grp.unix_gid;
435                         }
436                         if (ntname != NULL)
437                         {
438                                 fstrcpy(ntname, gmep->grp.nt_name);
439                         }
440                         if (ntdomain != NULL)
441                         {
442                                 fstrcpy(ntdomain, gmep->grp.nt_domain);
443                         }
444                         DEBUG(7,("map_sid: Mapping unix group %s to nt group %s.\n",
445                                gmep->grp.unix_name, gmep->grp.nt_name ));
446                         return True;
447                 }
448         }
449
450         return False;
451 }
452
453 /***********************************************************
454  Lookup nt name.
455 ************************************************************/
456 static BOOL map_ntname(GROUP_TYPE type, ubi_slList *map_list,
457                 char *ntname, char *ntdomain, DOM_SID *psid,
458                 char *unixname, gid_t *gid)
459 {
460         name_map_entry *gmep;
461
462         /*
463          * Initialize and load if not already loaded.
464          */
465         load_name_map(type);
466
467         for (gmep = (name_map_entry *)ubi_slFirst(&map_list);
468              gmep != NULL;
469              gmep = (name_map_entry *)ubi_slNext(gmep ))
470         {
471                 if (strequal(gmep->grp.nt_name  , ntname) &&
472                     strequal(gmep->grp.nt_domain, ntdomain))
473                 {
474                         if (psid != NULL)
475                         {
476                                 *psid = gmep->grp.sid;
477                         }
478                         if (gid != NULL)
479                         {
480                                 *gid = gmep->grp.unix_gid;
481                         }
482                         if (unixname != NULL)
483                         {
484                                 fstrcpy(unixname, gmep->grp.unix_name);
485                         }
486                         DEBUG(7,("map_ntname: Mapping unix group %s to nt group %s.\n",
487                                gmep->grp.unix_name, gmep->grp.nt_name ));
488                         return True;
489                 }
490         }
491
492         return False;
493 }
494
495 /***********************************************************
496  Lookup unix name.
497 ************************************************************/
498 static BOOL map_unixname(GROUP_TYPE type, ubi_slList *map_list,
499                 char *unixname, DOM_SID *psid, char *ntname, char *ntdomain)
500 {
501         name_map_entry *gmep;
502
503         /*
504          * Initialize and load if not already loaded.
505          */
506         load_name_map(type);
507
508         for (gmep = (name_map_entry *)ubi_slFirst(&map_list);
509              gmep != NULL;
510              gmep = (name_map_entry *)ubi_slNext(gmep ))
511         {
512                 if (strequal(gmep->grp.unix_name, unixname))
513                 {
514                         if (psid != NULL)
515                         {
516                                 *psid = gmep->grp.sid;
517                         }
518                         if (ntname != NULL)
519                         {
520                                 fstrcpy(ntname, gmep->grp.nt_name);
521                         }
522                         if (ntdomain != NULL)
523                         {
524                                 fstrcpy(ntdomain, gmep->grp.nt_domain);
525                         }
526                         DEBUG(7,("map_unixname: Mapping unix group %s to nt group %s.\n",
527                                gmep->grp.unix_name, gmep->grp.nt_name ));
528                         return True;
529                 }
530         }
531
532         return False;
533 }
534
535 /***********************************************************
536  Lookup by gid_t.
537 ************************************************************/
538 static BOOL map_gid(GROUP_TYPE type, ubi_slList *map_list,
539                 gid_t gid, DOM_SID *psid, char *ntname, char *ntdomain)
540 {
541         name_map_entry *gmep;
542
543         /*
544          * Initialize and load if not already loaded.
545          */
546         load_name_map(type);
547
548         for (gmep = (name_map_entry *)ubi_slFirst(&map_list);
549              gmep != NULL;
550              gmep = (name_map_entry *)ubi_slNext(gmep ))
551         {
552                 if (gmep->grp.unix_gid == gid)
553                 {
554                         if (psid != NULL)
555                         {
556                                 *psid = gmep->grp.sid;
557                         }
558                         if (ntname != NULL)
559                         {
560                                 fstrcpy(ntname, gmep->grp.nt_name);
561                         }
562                         if (ntdomain != NULL)
563                         {
564                                 fstrcpy(ntdomain, gmep->grp.nt_domain);
565                         }
566                         DEBUG(7,("map_gid: Mapping unix group %s to nt group %s.\n",
567                                gmep->grp.unix_name, gmep->grp.nt_name ));
568                         return True;
569                 }
570         }
571
572         return False;
573 }
574
575 /***********************************************************
576  *
577  * Call four functions to resolve unix group ids and either
578  * local group SIDs or domain group SIDs listed in the local group
579  * or domain group map files.
580  *
581  * Note that it is *NOT* the responsibility of these functions to
582  * resolve entries that are not in the map files.
583  *
584  * Any SID can be in the map files (i.e from any Domain).
585  *
586  ***********************************************************/
587
588 /***********************************************************
589  Lookup a Group entry by sid.
590 ************************************************************/
591 BOOL map_group_sid(DOM_SID *psid, gid_t *gid, char *group_name, char *nt_domain)
592 {
593         return map_sid(GROUP_DOMAIN, &groupname_map_list, psid, gid, group_name, nt_domain);
594 }
595
596 /***********************************************************
597  Lookup an Alias SID entry by name.
598 ************************************************************/
599 BOOL map_alias_sid(DOM_SID *psid, gid_t *gid, char *alias_name, char *nt_domain)
600 {
601         return map_sid(GROUP_LOCAL, &aliasname_map_list, psid, gid, alias_name, nt_domain);
602 }
603
604 /***********************************************************
605  Lookup a UNIX Group entry by name.
606 ************************************************************/
607 BOOL map_unix_group_name(char *group_name, DOM_SID *psid, char *ntgroup_name, char *nt_domain)
608 {
609         return map_unixname(GROUP_DOMAIN, &groupname_map_list, group_name, psid, ntgroup_name, nt_domain);
610 }
611
612 /***********************************************************
613  Lookup a UNIX Alias entry by name.
614 ************************************************************/
615 BOOL map_unix_alias_name(char *alias_name, DOM_SID *psid, char *ntalias_name, char *nt_domain)
616 {
617         return map_unixname(GROUP_LOCAL, &aliasname_map_list, alias_name, psid, ntalias_name, nt_domain);
618 }
619
620 /***********************************************************
621  Lookup a Group entry
622 ************************************************************/
623 BOOL map_nt_group_name(char *ntgroup_name, char *nt_domain, DOM_SID *psid, char *group_name, gid_t *gid)
624 {
625         return map_ntname(GROUP_DOMAIN, &groupname_map_list, ntgroup_name, nt_domain, psid, group_name, gid);
626 }
627
628 /***********************************************************
629  Lookup an Alias name entry 
630 ************************************************************/
631 BOOL map_nt_alias_name(char *ntalias_name, char *nt_domain, DOM_SID *psid, char *alias_name, gid_t *gid)
632 {
633         return map_ntname(GROUP_LOCAL, &aliasname_map_list, ntalias_name, nt_domain, psid, alias_name, gid);
634 }
635
636 /***********************************************************
637  Lookup an Alias SID entry by gid_t.
638 ************************************************************/
639 BOOL map_alias_gid(gid_t gid, DOM_SID *psid, char *nt_als_name, char *nt_domain)
640 {
641         return map_gid(GROUP_LOCAL, &aliasname_map_list, gid, psid, nt_als_name, nt_domain);
642 }
643
644 /***********************************************************
645  Lookup a Group SID entry by gid_t.
646 ************************************************************/
647 BOOL map_group_gid( gid_t gid, DOM_SID *psid, char *nt_grp_name, char *nt_domain)
648 {
649         return map_gid(GROUP_DOMAIN, &groupname_map_list, gid, psid, nt_grp_name, nt_domain);
650 }
651