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