Create group mappings on the fly.
[ira/wip.git] / source3 / groupdb / mapping.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Andrew Tridgell              1992-2000,
5  *  Copyright (C) Jean François Micouleau      1998-2001.
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 static TDB_CONTEXT *tdb; /* used for driver files */
25
26 #define DATABASE_VERSION_V1 1 /* native byte format. */
27 #define DATABASE_VERSION_V2 2 /* le format. */
28
29 #define GROUP_PREFIX "UNIXGROUP/"
30
31 PRIVS privs[] = {
32         {SE_PRIV_NONE,           "no_privs",                  "No privilege"                    }, /* this one MUST be first */
33         {SE_PRIV_ADD_MACHINES,   "SeMachineAccountPrivilege", "Add workstations to the domain"  },
34         {SE_PRIV_SEC_PRIV,       "SeSecurityPrivilege",       "Manage the audit logs"           },
35         {SE_PRIV_TAKE_OWNER,     "SeTakeOwnershipPrivilege",  "Take ownership of file"          },
36         {SE_PRIV_ADD_USERS,      "SaAddUsers",                "Add users to the domain - Samba" },
37         {SE_PRIV_PRINT_OPERATOR, "SaPrintOp",                 "Add or remove printers - Samba"  },
38         {SE_PRIV_ALL,            "SaAllPrivs",                "all privileges"                  }
39 };
40 /*
41 PRIVS privs[] = {
42         {  2, "SeCreateTokenPrivilege" },
43         {  3, "SeAssignPrimaryTokenPrivilege" },
44         {  4, "SeLockMemoryPrivilege" },
45         {  5, "SeIncreaseQuotaPrivilege" },
46         {  6, "SeMachineAccountPrivilege" },
47         {  7, "SeTcbPrivilege" },
48         {  8, "SeSecurityPrivilege" },
49         {  9, "SeTakeOwnershipPrivilege" },
50         { 10, "SeLoadDriverPrivilege" },
51         { 11, "SeSystemProfilePrivilege" },
52         { 12, "SeSystemtimePrivilege" },
53         { 13, "SeProfileSingleProcessPrivilege" },
54         { 14, "SeIncreaseBasePriorityPrivilege" },
55         { 15, "SeCreatePagefilePrivilege" },
56         { 16, "SeCreatePermanentPrivilege" },
57         { 17, "SeBackupPrivilege" },
58         { 18, "SeRestorePrivilege" },
59         { 19, "SeShutdownPrivilege" },
60         { 20, "SeDebugPrivilege" },
61         { 21, "SeAuditPrivilege" },
62         { 22, "SeSystemEnvironmentPrivilege" },
63         { 23, "SeChangeNotifyPrivilege" },
64         { 24, "SeRemoteShutdownPrivilege" },
65         { 25, "SeUndockPrivilege" },
66         { 26, "SeSyncAgentPrivilege" },
67         { 27, "SeEnableDelegationPrivilege" },
68 };
69 */
70
71         /*
72          * Those are not really privileges like the other ones.
73          * They are handled in a special case and called
74          * system privileges.
75          *
76          * SeNetworkLogonRight
77          * SeUnsolicitedInputPrivilege
78          * SeBatchLogonRight
79          * SeServiceLogonRight
80          * SeInteractiveLogonRight
81          * SeDenyInteractiveLogonRight
82          * SeDenyNetworkLogonRight
83          * SeDenyBatchLogonRight
84          * SeDenyBatchLogonRight
85          */
86
87 #if 0
88 /****************************************************************************
89 check if the user has the required privilege.
90 ****************************************************************************/
91 static BOOL se_priv_access_check(NT_USER_TOKEN *token, uint32 privilege)
92 {
93         /* no token, no privilege */
94         if (token==NULL)
95                 return False;
96         
97         if ((token->privilege & privilege)==privilege)
98                 return True;
99         
100         return False;
101 }
102 #endif
103
104 /****************************************************************************
105 dump the mapping group mapping to a text file
106 ****************************************************************************/
107 char *decode_sid_name_use(fstring group, enum SID_NAME_USE name_use)
108 {       
109         static fstring group_type;
110
111         switch(name_use) {
112                 case SID_NAME_USER:
113                         fstrcpy(group_type,"User");
114                         break;
115                 case SID_NAME_DOM_GRP:
116                         fstrcpy(group_type,"Domain group");
117                         break;
118                 case SID_NAME_DOMAIN:
119                         fstrcpy(group_type,"Domain");
120                         break;
121                 case SID_NAME_ALIAS:
122                         fstrcpy(group_type,"Local group");
123                         break;
124                 case SID_NAME_WKN_GRP:
125                         fstrcpy(group_type,"Builtin group");
126                         break;
127                 case SID_NAME_DELETED:
128                         fstrcpy(group_type,"Deleted");
129                         break;
130                 case SID_NAME_INVALID:
131                         fstrcpy(group_type,"Invalid");
132                         break;
133                 case SID_NAME_UNKNOWN:
134                 default:
135                         fstrcpy(group_type,"Unknown type");
136                         break;
137         }
138         
139         fstrcpy(group, group_type);
140         return group_type;
141 }
142
143 /****************************************************************************
144 initialise first time the mapping list - called from init_group_mapping()
145 ****************************************************************************/
146 static BOOL default_group_mapping(void)
147 {
148         DOM_SID sid_admins;
149         DOM_SID sid_users;
150         DOM_SID sid_guests;
151         fstring str_admins;
152         fstring str_users;
153         fstring str_guests;
154         LUID_ATTR set;
155
156         PRIVILEGE_SET privilege_none;
157         PRIVILEGE_SET privilege_all;
158         PRIVILEGE_SET privilege_print_op;
159
160         init_privilege(&privilege_none);
161         init_privilege(&privilege_all);
162         init_privilege(&privilege_print_op);
163
164         set.attr=0;
165         set.luid.high=0;
166         set.luid.low=SE_PRIV_PRINT_OPERATOR;
167         add_privilege(&privilege_print_op, set);
168
169         add_all_privilege(&privilege_all);
170
171         /* Add the Wellknown groups */
172
173         add_initial_entry(-1, "S-1-5-32-544", SID_NAME_ALIAS, "Administrators", "", privilege_all, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
174         add_initial_entry(-1, "S-1-5-32-545", SID_NAME_ALIAS, "Users", "", privilege_none, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
175         add_initial_entry(-1, "S-1-5-32-546", SID_NAME_ALIAS, "Guests", "", privilege_none, PR_ACCESS_FROM_NETWORK);
176         add_initial_entry(-1, "S-1-5-32-547", SID_NAME_ALIAS, "Power Users", "", privilege_none, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
177
178         add_initial_entry(-1, "S-1-5-32-548", SID_NAME_ALIAS, "Account Operators", "", privilege_none, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
179         add_initial_entry(-1, "S-1-5-32-549", SID_NAME_ALIAS, "System Operators", "", privilege_none, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
180         add_initial_entry(-1, "S-1-5-32-550", SID_NAME_ALIAS, "Print Operators", "", privilege_print_op, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
181         add_initial_entry(-1, "S-1-5-32-551", SID_NAME_ALIAS, "Backup Operators", "", privilege_none, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
182
183         add_initial_entry(-1, "S-1-5-32-552", SID_NAME_ALIAS, "Replicators", "", privilege_none, PR_ACCESS_FROM_NETWORK);
184
185         /* Add the defaults domain groups */
186
187         sid_copy(&sid_admins, get_global_sam_sid());
188         sid_append_rid(&sid_admins, DOMAIN_GROUP_RID_ADMINS);
189         sid_to_string(str_admins, &sid_admins);
190         add_initial_entry(-1, str_admins, SID_NAME_DOM_GRP, "Domain Admins", "", privilege_all, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
191
192         sid_copy(&sid_users,  get_global_sam_sid());
193         sid_append_rid(&sid_users,  DOMAIN_GROUP_RID_USERS);
194         sid_to_string(str_users, &sid_users);
195         add_initial_entry(-1, str_users,  SID_NAME_DOM_GRP, "Domain Users",  "", privilege_none, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
196
197         sid_copy(&sid_guests, get_global_sam_sid());
198         sid_append_rid(&sid_guests, DOMAIN_GROUP_RID_GUESTS);
199         sid_to_string(str_guests, &sid_guests);
200         add_initial_entry(-1, str_guests, SID_NAME_DOM_GRP, "Domain Guests", "", privilege_none, PR_ACCESS_FROM_NETWORK);
201
202         return True;
203 }
204
205 /****************************************************************************
206  Open the group mapping tdb.
207 ****************************************************************************/
208
209 static BOOL init_group_mapping(void)
210 {
211         static pid_t local_pid;
212         char *vstring = "INFO/version";
213         int32 vers_id;
214         
215         if (tdb && local_pid == sys_getpid())
216                 return True;
217         tdb = tdb_open_log(lock_path("group_mapping.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
218         if (!tdb) {
219                 DEBUG(0,("Failed to open group mapping database\n"));
220                 return False;
221         }
222
223         local_pid = sys_getpid();
224
225         /* handle a Samba upgrade */
226         tdb_lock_bystring(tdb, vstring, 0);
227
228         /* Cope with byte-reversed older versions of the db. */
229         vers_id = tdb_fetch_int32(tdb, vstring);
230         if ((vers_id == DATABASE_VERSION_V1) || (IREV(vers_id) == DATABASE_VERSION_V1)) {
231                 /* Written on a bigendian machine with old fetch_int code. Save as le. */
232                 tdb_store_int32(tdb, vstring, DATABASE_VERSION_V2);
233                 vers_id = DATABASE_VERSION_V2;
234         }
235
236         if (vers_id != DATABASE_VERSION_V2) {
237                 tdb_traverse(tdb, tdb_traverse_delete_fn, NULL);
238                 tdb_store_int32(tdb, vstring, DATABASE_VERSION_V2);
239         }
240
241         tdb_unlock_bystring(tdb, vstring);
242
243         /* write a list of default groups */
244         if(!default_group_mapping())
245                 return False;
246
247         return True;
248 }
249
250 /****************************************************************************
251 ****************************************************************************/
252 BOOL add_mapping_entry(GROUP_MAP *map, int flag)
253 {
254         TDB_DATA kbuf, dbuf;
255         pstring key, buf;
256         fstring string_sid="";
257         int len;
258         int i;
259         PRIVILEGE_SET *set;
260
261         if(!init_group_mapping()) {
262                 DEBUG(0,("failed to initialize group mapping"));
263                 return(False);
264         }
265         
266         sid_to_string(string_sid, &map->sid);
267
268         len = tdb_pack(buf, sizeof(buf), "ddffd",
269                         map->gid, map->sid_name_use, map->nt_name, map->comment, map->systemaccount);
270
271         /* write the privilege list in the TDB database */
272
273         set=&map->priv_set;
274         len += tdb_pack(buf+len, sizeof(buf)-len, "d", set->count);
275         for (i=0; i<set->count; i++)
276                 len += tdb_pack(buf+len, sizeof(buf)-len, "ddd", 
277                                 set->set[i].luid.low, set->set[i].luid.high, set->set[i].attr);
278
279         if (len > sizeof(buf))
280                 return False;
281
282         slprintf(key, sizeof(key), "%s%s", GROUP_PREFIX, string_sid);
283
284         kbuf.dsize = strlen(key)+1;
285         kbuf.dptr = key;
286         dbuf.dsize = len;
287         dbuf.dptr = buf;
288         if (tdb_store(tdb, kbuf, dbuf, flag) != 0) return False;
289
290         return True;
291 }
292
293 /****************************************************************************
294 initialise first time the mapping list
295 ****************************************************************************/
296 BOOL add_initial_entry(gid_t gid, fstring sid, enum SID_NAME_USE sid_name_use,
297                               fstring nt_name, fstring comment, PRIVILEGE_SET priv_set, uint32 systemaccount)
298 {
299         GROUP_MAP map;
300
301         if(!init_group_mapping()) {
302                 DEBUG(0,("failed to initialize group mapping"));
303                 return(False);
304         }
305         
306         map.gid=gid;
307         string_to_sid(&map.sid, sid);
308         map.sid_name_use=sid_name_use;
309         fstrcpy(map.nt_name, nt_name);
310         fstrcpy(map.comment, comment);
311         map.systemaccount=systemaccount;
312
313         map.priv_set.count=priv_set.count;
314         map.priv_set.set=priv_set.set;
315
316         add_mapping_entry(&map, TDB_INSERT);
317
318         return True;
319 }
320
321 /****************************************************************************
322 initialise a privilege list
323 ****************************************************************************/
324 void init_privilege(PRIVILEGE_SET *priv_set)
325 {
326         priv_set->count=0;
327         priv_set->control=0;
328         priv_set->set=NULL;
329 }
330
331 /****************************************************************************
332 free a privilege list
333 ****************************************************************************/
334 BOOL free_privilege(PRIVILEGE_SET *priv_set)
335 {
336         if (priv_set->count==0) {
337                 DEBUG(100,("free_privilege: count=0, nothing to clear ?\n"));
338                 return False;
339         }
340
341         if (priv_set->set==NULL) {
342                 DEBUG(0,("free_privilege: list ptr is NULL, very strange !\n"));
343                 return False;
344         }
345
346         safe_free(priv_set->set);
347         priv_set->count=0;
348         priv_set->control=0;
349         priv_set->set=NULL;
350
351         return True;
352 }
353
354 /****************************************************************************
355 add a privilege to a privilege array
356 ****************************************************************************/
357 BOOL add_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
358 {
359         LUID_ATTR *new_set;
360
361         /* check if the privilege is not already in the list */
362         if (check_priv_in_privilege(priv_set, set))
363                 return False;
364
365         /* we can allocate memory to add the new privilege */
366
367         new_set=(LUID_ATTR *)Realloc(priv_set->set, (priv_set->count+1)*(sizeof(LUID_ATTR)));
368         if (new_set==NULL) {
369                 DEBUG(0,("add_privilege: could not Realloc memory to add a new privilege\n"));
370                 return False;
371         }
372
373         new_set[priv_set->count].luid.high=set.luid.high;
374         new_set[priv_set->count].luid.low=set.luid.low;
375         new_set[priv_set->count].attr=set.attr;
376         
377         priv_set->count++;
378         priv_set->set=new_set;
379         
380         return True;    
381 }
382
383 /****************************************************************************
384 add all the privileges to a privilege array
385 ****************************************************************************/
386 BOOL add_all_privilege(PRIVILEGE_SET *priv_set)
387 {
388         LUID_ATTR set;
389
390         set.attr=0;
391         set.luid.high=0;
392         
393         set.luid.low=SE_PRIV_ADD_USERS;
394         add_privilege(priv_set, set);
395
396         set.luid.low=SE_PRIV_ADD_MACHINES;
397         add_privilege(priv_set, set);
398
399         set.luid.low=SE_PRIV_PRINT_OPERATOR;
400         add_privilege(priv_set, set);
401         
402         return True;
403 }
404
405 /****************************************************************************
406 check if the privilege list is empty
407 ****************************************************************************/
408 BOOL check_empty_privilege(PRIVILEGE_SET *priv_set)
409 {
410         return (priv_set->count == 0);
411 }
412
413 /****************************************************************************
414 check if the privilege is in the privilege list
415 ****************************************************************************/
416 BOOL check_priv_in_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
417 {
418         int i;
419
420         /* if the list is empty, obviously we can't have it */
421         if (check_empty_privilege(priv_set))
422                 return False;
423
424         for (i=0; i<priv_set->count; i++) {
425                 LUID_ATTR *cur_set;
426
427                 cur_set=&priv_set->set[i];
428                 /* check only the low and high part. Checking the attr field has no meaning */
429                 if( (cur_set->luid.low==set.luid.low) && (cur_set->luid.high==set.luid.high) )
430                         return True;
431         }
432
433         return False;
434 }
435
436 /****************************************************************************
437 remove a privilege from a privilege array
438 ****************************************************************************/
439 BOOL remove_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
440 {
441         LUID_ATTR *new_set;
442         LUID_ATTR *old_set;
443         int i,j;
444
445         /* check if the privilege is in the list */
446         if (!check_priv_in_privilege(priv_set, set))
447                 return False;
448
449         /* special case if it's the only privilege in the list */
450         if (priv_set->count==1) {
451                 free_privilege(priv_set);
452                 init_privilege(priv_set);       
453         
454                 return True;
455         }
456
457         /* 
458          * the privilege is there, create a new list,
459          * and copy the other privileges
460          */
461
462         old_set=priv_set->set;
463
464         new_set=(LUID_ATTR *)malloc((priv_set->count-1)*(sizeof(LUID_ATTR)));
465         if (new_set==NULL) {
466                 DEBUG(0,("remove_privilege: could not malloc memory for new privilege list\n"));
467                 return False;
468         }
469
470         for (i=0, j=0; i<priv_set->count; i++) {
471                 if ((old_set[i].luid.low==set.luid.low) && 
472                     (old_set[i].luid.high==set.luid.high)) {
473                         continue;
474                 }
475                 
476                 new_set[j].luid.low=old_set[i].luid.low;
477                 new_set[j].luid.high=old_set[i].luid.high;
478                 new_set[j].attr=old_set[i].attr;
479
480                 j++;
481         }
482         
483         if (j!=priv_set->count-1) {
484                 DEBUG(0,("remove_privilege: mismatch ! difference is not -1\n"));
485                 DEBUGADD(0,("old count:%d, new count:%d\n", priv_set->count, j));
486                 safe_free(new_set);
487                 return False;
488         }
489                 
490         /* ok everything is fine */
491         
492         priv_set->count--;
493         priv_set->set=new_set;
494         
495         safe_free(old_set);
496         
497         return True;    
498 }
499
500 /****************************************************************************
501 return the sid and the type of the unix group
502 ****************************************************************************/
503 BOOL get_group_map_from_sid(DOM_SID sid, GROUP_MAP *map, BOOL with_priv)
504 {
505         TDB_DATA kbuf, dbuf;
506         pstring key;
507         fstring string_sid;
508         int ret;
509         int i;
510         PRIVILEGE_SET *set;
511         
512         if(!init_group_mapping()) {
513                 DEBUG(0,("failed to initialize group mapping"));
514                 return(False);
515         }
516
517         /* the key is the SID, retrieving is direct */
518
519         sid_to_string(string_sid, &sid);
520         slprintf(key, sizeof(key), "%s%s", GROUP_PREFIX, string_sid);
521
522         kbuf.dptr = key;
523         kbuf.dsize = strlen(key)+1;
524                 
525         dbuf = tdb_fetch(tdb, kbuf);
526         if (!dbuf.dptr) return False;
527
528         ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddffd",
529                                 &map->gid, &map->sid_name_use, &map->nt_name, &map->comment, &map->systemaccount);
530
531         set=&map->priv_set;
532         init_privilege(set);
533         ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "d", &set->count);
534
535         DEBUG(10,("get_group_map_from_sid: %d privileges\n", map->priv_set.count));
536
537         set->set = NULL;
538         if (set->count) {
539                 set->set=(LUID_ATTR *)smb_xmalloc(set->count*sizeof(LUID_ATTR));
540         }
541
542         for (i=0; i<set->count; i++)
543                 ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "ddd", 
544                                 &(set->set[i].luid.low), &(set->set[i].luid.high), &(set->set[i].attr));
545
546         SAFE_FREE(dbuf.dptr);
547         if (ret != dbuf.dsize) {
548                 DEBUG(0,("get_group_map_from_sid: group mapping TDB corrupted ?\n"));
549                 free_privilege(set);
550                 return False;
551         }
552
553         /* we don't want the privileges */
554         if (with_priv==MAPPING_WITHOUT_PRIV)
555                 free_privilege(set);
556
557         sid_copy(&map->sid, &sid);
558         
559         return True;
560 }
561
562
563 /****************************************************************************
564 return the sid and the type of the unix group
565 ****************************************************************************/
566 BOOL get_group_map_from_gid(gid_t gid, GROUP_MAP *map, BOOL with_priv)
567 {
568         TDB_DATA kbuf, dbuf, newkey;
569         fstring string_sid;
570         int ret;
571         int i;
572         PRIVILEGE_SET *set;
573
574         if(!init_group_mapping()) {
575                 DEBUG(0,("failed to initialize group mapping"));
576                 return(False);
577         }
578
579         /* we need to enumerate the TDB to find the GID */
580
581         for (kbuf = tdb_firstkey(tdb); 
582              kbuf.dptr; 
583              newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
584
585                 if (strncmp(kbuf.dptr, GROUP_PREFIX, strlen(GROUP_PREFIX)) != 0) continue;
586                 
587                 dbuf = tdb_fetch(tdb, kbuf);
588                 if (!dbuf.dptr) continue;
589
590                 fstrcpy(string_sid, kbuf.dptr+strlen(GROUP_PREFIX));
591
592                 string_to_sid(&map->sid, string_sid);
593                 
594                 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddffd",
595                                  &map->gid, &map->sid_name_use, &map->nt_name, &map->comment, &map->systemaccount);
596
597                 set=&map->priv_set;
598                 ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "d", &set->count);
599                 set->set = NULL;
600                 if (set->count) {
601                         set->set=(LUID_ATTR *)smb_xmalloc(set->count*sizeof(LUID_ATTR));
602                 }
603
604                 for (i=0; i<set->count; i++)
605                         ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "ddd", 
606                                         &(set->set[i].luid.low), &(set->set[i].luid.high), &(set->set[i].attr));
607
608                 SAFE_FREE(dbuf.dptr);
609                 if (ret != dbuf.dsize){
610                         free_privilege(set);
611                         continue;
612                 }
613
614                 if (gid==map->gid) {
615                         if (!with_priv)
616                                 free_privilege(&map->priv_set);
617                         return True;
618                 }
619                 
620                 free_privilege(set);
621         }
622
623         return False;
624 }
625
626 /****************************************************************************
627 return the sid and the type of the unix group
628 ****************************************************************************/
629 BOOL get_group_map_from_ntname(char *name, GROUP_MAP *map, BOOL with_priv)
630 {
631         TDB_DATA kbuf, dbuf, newkey;
632         fstring string_sid;
633         int ret;
634         int i;
635         PRIVILEGE_SET *set;
636
637         if(!init_group_mapping()) {
638                 DEBUG(0,("get_group_map_from_ntname:failed to initialize group mapping"));
639                 return(False);
640         }
641
642         /* we need to enumerate the TDB to find the name */
643
644         for (kbuf = tdb_firstkey(tdb); 
645              kbuf.dptr; 
646              newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
647
648                 if (strncmp(kbuf.dptr, GROUP_PREFIX, strlen(GROUP_PREFIX)) != 0) continue;
649                 
650                 dbuf = tdb_fetch(tdb, kbuf);
651                 if (!dbuf.dptr) continue;
652
653                 fstrcpy(string_sid, kbuf.dptr+strlen(GROUP_PREFIX));
654
655                 string_to_sid(&map->sid, string_sid);
656                 
657                 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddffd",
658                                  &map->gid, &map->sid_name_use, &map->nt_name, &map->comment, &map->systemaccount);
659
660                 set=&map->priv_set;
661                 ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "d", &set->count);
662         
663                 set->set=(LUID_ATTR *)malloc(set->count*sizeof(LUID_ATTR));
664                 if (set->set==NULL) {
665                         DEBUG(0,("get_group_map_from_ntname: could not allocate memory for privileges\n"));
666                         return False;
667                 }
668
669                 for (i=0; i<set->count; i++)
670                         ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "ddd", 
671                                         &(set->set[i].luid.low), &(set->set[i].luid.high), &(set->set[i].attr));
672
673                 SAFE_FREE(dbuf.dptr);
674                 if (ret != dbuf.dsize) {
675                         free_privilege(set);
676                         continue;
677                 }
678
679                 if (StrCaseCmp(name, map->nt_name)==0) {
680                         if (!with_priv)
681                                 free_privilege(&map->priv_set);
682                         return True;
683                 }
684
685                 free_privilege(set);
686         }
687
688         return False;
689 }
690
691 /****************************************************************************
692  remove a group mapping entry
693 ****************************************************************************/
694 BOOL group_map_remove(DOM_SID sid)
695 {
696         TDB_DATA kbuf, dbuf;
697         pstring key;
698         fstring string_sid;
699         
700         if(!init_group_mapping()) {
701                 DEBUG(0,("failed to initialize group mapping"));
702                 return(False);
703         }
704
705         /* the key is the SID, retrieving is direct */
706
707         sid_to_string(string_sid, &sid);
708         slprintf(key, sizeof(key), "%s%s", GROUP_PREFIX, string_sid);
709
710         kbuf.dptr = key;
711         kbuf.dsize = strlen(key)+1;
712                 
713         dbuf = tdb_fetch(tdb, kbuf);
714         if (!dbuf.dptr) return False;
715         
716         SAFE_FREE(dbuf.dptr);
717
718         if(tdb_delete(tdb, kbuf) != TDB_SUCCESS)
719                 return False;
720
721         return True;
722 }
723
724
725 /****************************************************************************
726 enumerate the group mapping
727 ****************************************************************************/
728 BOOL enum_group_mapping(enum SID_NAME_USE sid_name_use, GROUP_MAP **rmap,
729                         int *num_entries, BOOL unix_only, BOOL with_priv)
730 {
731         TDB_DATA kbuf, dbuf, newkey;
732         fstring string_sid;
733         fstring group_type;
734         GROUP_MAP map;
735         GROUP_MAP *mapt;
736         int ret;
737         int entries=0;
738         int i;
739         PRIVILEGE_SET *set;
740
741         if(!init_group_mapping()) {
742                 DEBUG(0,("failed to initialize group mapping"));
743                 return(False);
744         }
745
746         *num_entries=0;
747         *rmap=NULL;
748
749         for (kbuf = tdb_firstkey(tdb); 
750              kbuf.dptr; 
751              newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
752
753                 if (strncmp(kbuf.dptr, GROUP_PREFIX, strlen(GROUP_PREFIX)) != 0)
754                         continue;
755                 
756                 dbuf = tdb_fetch(tdb, kbuf);
757                 if (!dbuf.dptr)
758                         continue;
759
760                 fstrcpy(string_sid, kbuf.dptr+strlen(GROUP_PREFIX));
761                                 
762                 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddffd",
763                                  &map.gid, &map.sid_name_use, &map.nt_name, &map.comment, &map.systemaccount);
764
765                 set=&map.priv_set;
766                 init_privilege(set);
767                 
768                 ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "d", &set->count);
769         
770                 if (set->count!=0) {
771                         set->set=(LUID_ATTR *)malloc(set->count*sizeof(LUID_ATTR));
772                         if (set->set==NULL) {
773                                 DEBUG(0,("enum_group_mapping: could not allocate memory for privileges\n"));
774                                 return False;
775                         }
776                 }
777
778                 for (i=0; i<set->count; i++)
779                         ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "ddd", 
780                                         &(set->set[i].luid.low), &(set->set[i].luid.high), &(set->set[i].attr));
781
782                 SAFE_FREE(dbuf.dptr);
783                 if (ret != dbuf.dsize) {
784                         DEBUG(11,("enum_group_mapping: error in memory size\n"));
785                         free_privilege(set);
786                         continue;
787                 }
788
789                 /* list only the type or everything if UNKNOWN */
790                 if (sid_name_use!=SID_NAME_UNKNOWN  && sid_name_use!=map.sid_name_use) {
791                         DEBUG(11,("enum_group_mapping: group %s is not of the requested type\n", map.nt_name));
792                         free_privilege(set);
793                         continue;
794                 }
795                 
796                 if (unix_only==ENUM_ONLY_MAPPED && map.gid==-1) {
797                         DEBUG(11,("enum_group_mapping: group %s is non mapped\n", map.nt_name));
798                         free_privilege(set);
799                         continue;
800                 }
801
802                 string_to_sid(&map.sid, string_sid);
803                 
804                 decode_sid_name_use(group_type, map.sid_name_use);
805                 DEBUG(11,("enum_group_mapping: returning group %s of type %s\n", map.nt_name ,group_type));
806
807                 mapt=(GROUP_MAP *)Realloc((*rmap), (entries+1)*sizeof(GROUP_MAP));
808                 if (!mapt) {
809                         DEBUG(0,("enum_group_mapping: Unable to enlarge group map!\n"));
810                         SAFE_FREE(*rmap);
811                         free_privilege(set);
812                         return False;
813                 }
814                 else
815                         (*rmap) = mapt;
816
817                 mapt[entries].gid = map.gid;
818                 sid_copy( &mapt[entries].sid, &map.sid);
819                 mapt[entries].sid_name_use = map.sid_name_use;
820                 fstrcpy(mapt[entries].nt_name, map.nt_name);
821                 fstrcpy(mapt[entries].comment, map.comment);
822                 mapt[entries].systemaccount=map.systemaccount;
823                 mapt[entries].priv_set.count=set->count;
824                 mapt[entries].priv_set.control=set->control;
825                 mapt[entries].priv_set.set=set->set;
826                 if (!with_priv)
827                         free_privilege(&(mapt[entries].priv_set));
828
829                 entries++;
830         }
831
832         *num_entries=entries;
833         return True;
834 }
835
836
837 /****************************************************************************
838 convert a privilege string to a privilege array
839 ****************************************************************************/
840 void convert_priv_from_text(PRIVILEGE_SET *se_priv, char *privilege)
841 {
842         pstring tok;
843         char *p = privilege;
844         int i;
845         LUID_ATTR set;
846
847         /* By default no privilege */
848         init_privilege(se_priv);
849         
850         if (privilege==NULL)
851                 return;
852
853         while(next_token(&p, tok, " ", sizeof(tok)) ) {
854                 for (i=0; i<=PRIV_ALL_INDEX; i++) {
855                         if (StrCaseCmp(privs[i].priv, tok)==0) {
856                                 set.attr=0;
857                                 set.luid.high=0;
858                                 set.luid.low=privs[i].se_priv;
859                                 add_privilege(se_priv, set);
860                         }
861                 }               
862         }
863 }
864
865 /****************************************************************************
866 convert a privilege array to a privilege string
867 ****************************************************************************/
868 void convert_priv_to_text(PRIVILEGE_SET *se_priv, char *privilege)
869 {
870         int i,j;
871
872         if (privilege==NULL)
873                 return;
874
875         ZERO_STRUCTP(privilege);
876
877         if (check_empty_privilege(se_priv)) {
878                 fstrcat(privilege, "No privilege");
879                 return;
880         }
881
882         for(i=0; i<se_priv->count; i++) {
883                 j=1;
884                 while (privs[j].se_priv!=se_priv->set[i].luid.low && j<=PRIV_ALL_INDEX) {
885                         j++;
886                 }
887
888                 fstrcat(privilege, privs[j].priv);
889                 fstrcat(privilege, " ");
890         }
891 }
892
893
894 /*
895  *
896  * High level functions
897  * better to use them than the lower ones.
898  *
899  * we are checking if the group is in the mapping file
900  * and if the group is an existing unix group
901  *
902  */
903
904 /* get a domain group from it's SID */
905
906 BOOL get_domain_group_from_sid(DOM_SID sid, GROUP_MAP *map, BOOL with_priv)
907 {
908         struct group *grp;
909
910         if(!init_group_mapping()) {
911                 DEBUG(0,("failed to initialize group mapping"));
912                 return(False);
913         }
914
915         DEBUG(10, ("get_domain_group_from_sid\n"));
916
917         /* if the group is NOT in the database, it CAN NOT be a domain group */
918         if(!get_group_map_from_sid(sid, map, with_priv))
919                 return False;
920
921         DEBUG(10, ("get_domain_group_from_sid: SID found in the TDB\n"));
922
923         /* if it's not a domain group, continue */
924         if (map->sid_name_use!=SID_NAME_DOM_GRP) {
925                 if (with_priv)
926                         free_privilege(&map->priv_set);
927                 return False;
928         }
929
930         DEBUG(10, ("get_domain_group_from_sid: SID is a domain group\n"));
931         
932         if (map->gid==-1) {
933                 if (with_priv)
934                         free_privilege(&map->priv_set);
935                 return False;
936         }
937
938         DEBUG(10, ("get_domain_group_from_sid: SID is mapped to gid:%d\n",map->gid));
939
940         if ( (grp=getgrgid(map->gid)) == NULL) {
941                 DEBUG(10, ("get_domain_group_from_sid: gid DOESN'T exist in UNIX security\n"));
942                 if (with_priv)
943                         free_privilege(&map->priv_set);
944                 return False;
945         }
946
947         DEBUG(10, ("get_domain_group_from_sid: gid exists in UNIX security\n"));
948
949         return True;
950 }
951
952
953 /* get a local (alias) group from it's SID */
954
955 BOOL get_local_group_from_sid(DOM_SID sid, GROUP_MAP *map, BOOL with_priv)
956 {
957         struct group *grp;
958
959         if(!init_group_mapping()) {
960                 DEBUG(0,("failed to initialize group mapping"));
961                 return(False);
962         }
963
964         /* The group is in the mapping table */
965         if(get_group_map_from_sid(sid, map, with_priv)) {
966                 if (map->sid_name_use!=SID_NAME_ALIAS) {
967                         if (with_priv)
968                                 free_privilege(&map->priv_set);
969                         return False;
970                 }
971                 
972                 if (map->gid==-1) {
973                         if (with_priv)
974                                 free_privilege(&map->priv_set);
975                         return False;
976                 }
977
978                 if ( (grp=getgrgid(map->gid)) == NULL) {
979                         if (with_priv)
980                                 free_privilege(&map->priv_set);
981                         return False;
982                 }
983         } else {
984                 /* the group isn't in the mapping table.
985                  * make one based on the unix information */
986                 uint32 alias_rid;
987
988                 sid_peek_rid(&sid, &alias_rid);
989                 map->gid=pdb_group_rid_to_gid(alias_rid);
990
991                 if ((grp=getgrgid(map->gid)) == NULL)
992                         return False;
993
994                 map->sid_name_use=SID_NAME_ALIAS;
995                 map->systemaccount=PR_ACCESS_FROM_NETWORK;
996
997                 fstrcpy(map->nt_name, grp->gr_name);
998                 fstrcpy(map->comment, "Local Unix Group");
999
1000                 init_privilege(&map->priv_set);
1001
1002                 sid_copy(&map->sid, &sid);
1003         }
1004
1005         return True;
1006 }
1007
1008 /* get a builtin group from it's SID */
1009
1010 BOOL get_builtin_group_from_sid(DOM_SID sid, GROUP_MAP *map, BOOL with_priv)
1011 {
1012         struct group *grp;
1013
1014         if(!init_group_mapping()) {
1015                 DEBUG(0,("failed to initialize group mapping"));
1016                 return(False);
1017         }
1018
1019         if(!get_group_map_from_sid(sid, map, with_priv))
1020                 return False;
1021
1022         if (map->sid_name_use!=SID_NAME_WKN_GRP) {
1023                 if (with_priv)
1024                         free_privilege(&map->priv_set);
1025                 return False;
1026         }
1027
1028         if (map->gid==-1) {
1029                 if (with_priv)
1030                         free_privilege(&map->priv_set);
1031                 return False;
1032         }
1033
1034         if ( (grp=getgrgid(map->gid)) == NULL) {
1035                 if (with_priv)
1036                         free_privilege(&map->priv_set);
1037                 return False;
1038         }
1039
1040         return True;
1041 }
1042
1043
1044
1045 /****************************************************************************
1046 Returns a GROUP_MAP struct based on the gid.
1047 ****************************************************************************/
1048 BOOL get_group_from_gid(gid_t gid, GROUP_MAP *map, BOOL with_priv)
1049 {
1050         struct group *grp;
1051         fstring name;
1052         DOM_SID sid;
1053         fstring string_sid;
1054         PRIVILEGE_SET priv_set;
1055
1056         if(!init_group_mapping()) {
1057                 DEBUG(0,("failed to initialize group mapping"));
1058                 return(False);
1059         }
1060
1061         if (get_group_map_from_gid(gid, map, with_priv))
1062                 return True;
1063
1064         /* There is no mapping, create one on the fly. This is just
1065            interim, we need a RID allocator in the passdb backend. */
1066
1067         if ((grp=getgrgid(gid)) != NULL) {
1068                 slprintf(name, sizeof(name), "Group %s", grp->gr_name);
1069         } else {
1070                 slprintf(name, sizeof(name), "Group %d", gid);
1071         }
1072
1073         /* interim solution until we have a last RID allocated */
1074
1075         sid_copy(&sid, get_global_sam_sid());
1076         sid_append_rid(&sid, pdb_gid_to_group_rid(gid));
1077         sid_to_string(string_sid, &sid);
1078         init_privilege(&priv_set);
1079
1080         if (!add_initial_entry(gid, string_sid, SID_NAME_DOM_GRP,
1081                                name, "Local Unix Group",
1082                                priv_set, PR_ACCESS_FROM_NETWORK)) {
1083                 return False;
1084         }
1085         
1086         return get_group_map_from_gid(gid, map, with_priv);
1087 }
1088
1089
1090
1091
1092 /****************************************************************************
1093  Get the member users of a group and
1094  all the users who have that group as primary.
1095             
1096  give back an array of uid
1097  return the grand number of users
1098
1099
1100  TODO: sort the list and remove duplicate. JFM.
1101
1102 ****************************************************************************/
1103         
1104 BOOL get_uid_list_of_group(gid_t gid, uid_t **uid, int *num_uids)
1105 {
1106         struct group *grp;
1107         struct passwd *pwd;
1108         int i=0;
1109         char *gr;
1110         uid_t *u;
1111  
1112         if(!init_group_mapping()) {
1113                 DEBUG(0,("failed to initialize group mapping"));
1114                 return(False);
1115         }
1116
1117         *num_uids = 0;
1118         *uid=NULL;
1119         
1120         if ( (grp=getgrgid(gid)) == NULL)
1121                 return False;
1122
1123         gr = grp->gr_mem[0];
1124         DEBUG(10, ("getting members\n"));
1125         
1126         while (gr && (*gr != (char)'\0')) {
1127                 u = Realloc((*uid), sizeof(uid_t)*(*num_uids+1));
1128                 if (!u) {
1129                         DEBUG(0,("get_uid_list_of_group: unable to enlarge uid list!\n"));
1130                         return False;
1131                 }
1132                 else (*uid) = u;
1133
1134                 if( (pwd=getpwnam_alloc(gr)) !=NULL) {
1135                         (*uid)[*num_uids]=pwd->pw_uid;
1136                         (*num_uids)++;
1137                 }
1138                 passwd_free(&pwd);
1139                 gr = grp->gr_mem[++i];
1140         }
1141         DEBUG(10, ("got [%d] members\n", *num_uids));
1142
1143         setpwent();
1144         while ((pwd=getpwent()) != NULL) {
1145                 if (pwd->pw_gid==gid) {
1146                         u = Realloc((*uid), sizeof(uid_t)*(*num_uids+1));
1147                         if (!u) {
1148                                 DEBUG(0,("get_uid_list_of_group: unable to enlarge uid list!\n"));
1149                                 return False;
1150                         }
1151                         else (*uid) = u;
1152                         (*uid)[*num_uids]=pwd->pw_uid;
1153
1154                         (*num_uids)++;
1155                 }
1156         }
1157         endpwent();
1158         DEBUG(10, ("got primary groups, members: [%d]\n", *num_uids));
1159
1160         return True;
1161 }
1162
1163 /****************************************************************************
1164  Create a UNIX group on demand.
1165 ****************************************************************************/
1166
1167 int smb_create_group(char *unix_group, gid_t *new_gid)
1168 {
1169         pstring add_script;
1170         int ret;
1171         int fd = 0;
1172
1173         pstrcpy(add_script, lp_addgroup_script());
1174         if (! *add_script) return -1;
1175         pstring_sub(add_script, "%g", unix_group);
1176         ret = smbrun(add_script, (new_gid!=NULL) ? &fd : NULL);
1177         DEBUG(3,("smb_create_group: Running the command `%s' gave %d\n",add_script,ret));
1178         if (ret != 0)
1179                 return ret;
1180
1181         if (fd != 0) {
1182                 fstring output;
1183
1184                 *new_gid = 0;
1185                 if (read(fd, output, sizeof(output)) > 0) {
1186                         *new_gid = (gid_t)strtoul(output, NULL, 10);
1187                 }
1188                 close(fd);
1189
1190                 if (*new_gid == 0) {
1191                         /* The output was garbage. We assume nobody
1192                            will create group 0 via smbd. Now we try to
1193                            get the group via getgrnam. */
1194
1195                         struct group *grp = getgrnam(unix_group);
1196                         if (grp != NULL)
1197                                 *new_gid = grp->gr_gid;
1198                         else
1199                                 return 1;
1200                 }
1201         }
1202
1203         return ret;
1204 }
1205
1206 /****************************************************************************
1207  Delete a UNIX group on demand.
1208 ****************************************************************************/
1209
1210 int smb_delete_group(char *unix_group)
1211 {
1212         pstring del_script;
1213         int ret;
1214
1215         pstrcpy(del_script, lp_delgroup_script());
1216         if (! *del_script) return -1;
1217         pstring_sub(del_script, "%g", unix_group);
1218         ret = smbrun(del_script,NULL);
1219         DEBUG(3,("smb_delete_group: Running the command `%s' gave %d\n",del_script,ret));
1220         return ret;
1221 }
1222
1223 /****************************************************************************
1224  Set a user's primary UNIX group.
1225 ****************************************************************************/
1226 int smb_set_primary_group(const char *unix_group, const char* unix_user)
1227 {
1228         pstring add_script;
1229         int ret;
1230
1231         pstrcpy(add_script, lp_setprimarygroup_script());
1232         if (! *add_script) return -1;
1233         all_string_sub(add_script, "%g", unix_group, sizeof(add_script));
1234         all_string_sub(add_script, "%u", unix_user, sizeof(add_script));
1235         ret = smbrun(add_script,NULL);
1236         DEBUG(3,("smb_set_primary_group: "
1237                  "Running the command `%s' gave %d\n",add_script,ret));
1238         return ret;
1239 }
1240
1241 /****************************************************************************
1242  Add a user to a UNIX group.
1243 ****************************************************************************/
1244
1245 int smb_add_user_group(char *unix_group, char *unix_user)
1246 {
1247         pstring add_script;
1248         int ret;
1249
1250         pstrcpy(add_script, lp_addusertogroup_script());
1251         if (! *add_script) return -1;
1252         pstring_sub(add_script, "%g", unix_group);
1253         pstring_sub(add_script, "%u", unix_user);
1254         ret = smbrun(add_script,NULL);
1255         DEBUG(3,("smb_add_user_group: Running the command `%s' gave %d\n",add_script,ret));
1256         return ret;
1257 }
1258
1259 /****************************************************************************
1260  Delete a user from a UNIX group
1261 ****************************************************************************/
1262
1263 int smb_delete_user_group(const char *unix_group, const char *unix_user)
1264 {
1265         pstring del_script;
1266         int ret;
1267
1268         pstrcpy(del_script, lp_deluserfromgroup_script());
1269         if (! *del_script) return -1;
1270         pstring_sub(del_script, "%g", unix_group);
1271         pstring_sub(del_script, "%u", unix_user);
1272         ret = smbrun(del_script,NULL);
1273         DEBUG(3,("smb_delete_user_group: Running the command `%s' gave %d\n",del_script,ret));
1274         return ret;
1275 }