BIG patch...
[amitay/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 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         const 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, const char *sid, enum SID_NAME_USE sid_name_use,
297                        const char *nt_name, const char *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         pdb_add_group_mapping_entry(&map);
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
504 BOOL get_group_map_from_sid(DOM_SID sid, GROUP_MAP *map, BOOL with_priv)
505 {
506         TDB_DATA kbuf, dbuf;
507         pstring key;
508         fstring string_sid;
509         int ret;
510         int i;
511         PRIVILEGE_SET *set;
512         
513         if(!init_group_mapping()) {
514                 DEBUG(0,("failed to initialize group mapping"));
515                 return(False);
516         }
517
518         /* the key is the SID, retrieving is direct */
519
520         sid_to_string(string_sid, &sid);
521         slprintf(key, sizeof(key), "%s%s", GROUP_PREFIX, string_sid);
522
523         kbuf.dptr = key;
524         kbuf.dsize = strlen(key)+1;
525                 
526         dbuf = tdb_fetch(tdb, kbuf);
527         if (!dbuf.dptr)
528                 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  Return the sid and the type of the unix group.
566 ****************************************************************************/
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)
591                         continue;
592
593                 fstrcpy(string_sid, kbuf.dptr+strlen(GROUP_PREFIX));
594
595                 string_to_sid(&map->sid, string_sid);
596                 
597                 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddffd",
598                                  &map->gid, &map->sid_name_use, &map->nt_name, &map->comment, &map->systemaccount);
599
600                 set=&map->priv_set;
601                 ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "d", &set->count);
602                 set->set = NULL;
603                 if (set->count) {
604                         set->set=(LUID_ATTR *)smb_xmalloc(set->count*sizeof(LUID_ATTR));
605                 }
606
607                 for (i=0; i<set->count; i++)
608                         ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "ddd", 
609                                         &(set->set[i].luid.low), &(set->set[i].luid.high), &(set->set[i].attr));
610
611                 SAFE_FREE(dbuf.dptr);
612                 if (ret != dbuf.dsize){
613                         free_privilege(set);
614                         continue;
615                 }
616
617                 if (gid==map->gid) {
618                         if (!with_priv)
619                                 free_privilege(&map->priv_set);
620                         return True;
621                 }
622                 
623                 free_privilege(set);
624         }
625
626         return False;
627 }
628
629 /****************************************************************************
630  Return the sid and the type of the unix group.
631 ****************************************************************************/
632
633 BOOL get_group_map_from_ntname(char *name, GROUP_MAP *map, BOOL with_priv)
634 {
635         TDB_DATA kbuf, dbuf, newkey;
636         fstring string_sid;
637         int ret;
638         int i;
639         PRIVILEGE_SET *set;
640
641         if(!init_group_mapping()) {
642                 DEBUG(0,("get_group_map_from_ntname:failed to initialize group mapping"));
643                 return(False);
644         }
645
646         /* we need to enumerate the TDB to find the name */
647
648         for (kbuf = tdb_firstkey(tdb); 
649              kbuf.dptr; 
650              newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
651
652                 if (strncmp(kbuf.dptr, GROUP_PREFIX, strlen(GROUP_PREFIX)) != 0) continue;
653                 
654                 dbuf = tdb_fetch(tdb, kbuf);
655                 if (!dbuf.dptr)
656                         continue;
657
658                 fstrcpy(string_sid, kbuf.dptr+strlen(GROUP_PREFIX));
659
660                 string_to_sid(&map->sid, string_sid);
661                 
662                 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddffd",
663                                  &map->gid, &map->sid_name_use, &map->nt_name, &map->comment, &map->systemaccount);
664
665                 set=&map->priv_set;
666                 ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "d", &set->count);
667         
668                 set->set=(LUID_ATTR *)malloc(set->count*sizeof(LUID_ATTR));
669                 if (set->set==NULL) {
670                         DEBUG(0,("get_group_map_from_ntname: could not allocate memory for privileges\n"));
671                         return False;
672                 }
673
674                 for (i=0; i<set->count; i++)
675                         ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "ddd", 
676                                         &(set->set[i].luid.low), &(set->set[i].luid.high), &(set->set[i].attr));
677
678                 SAFE_FREE(dbuf.dptr);
679                 if (ret != dbuf.dsize) {
680                         free_privilege(set);
681                         continue;
682                 }
683
684                 if (StrCaseCmp(name, map->nt_name)==0) {
685                         if (!with_priv)
686                                 free_privilege(&map->priv_set);
687                         return True;
688                 }
689
690                 free_privilege(set);
691         }
692
693         return False;
694 }
695
696 /****************************************************************************
697  Remove a group mapping entry.
698 ****************************************************************************/
699
700 BOOL group_map_remove(DOM_SID sid)
701 {
702         TDB_DATA kbuf, dbuf;
703         pstring key;
704         fstring string_sid;
705         
706         if(!init_group_mapping()) {
707                 DEBUG(0,("failed to initialize group mapping"));
708                 return(False);
709         }
710
711         /* the key is the SID, retrieving is direct */
712
713         sid_to_string(string_sid, &sid);
714         slprintf(key, sizeof(key), "%s%s", GROUP_PREFIX, string_sid);
715
716         kbuf.dptr = key;
717         kbuf.dsize = strlen(key)+1;
718                 
719         dbuf = tdb_fetch(tdb, kbuf);
720         if (!dbuf.dptr)
721                 return False;
722         
723         SAFE_FREE(dbuf.dptr);
724
725         if(tdb_delete(tdb, kbuf) != TDB_SUCCESS)
726                 return False;
727
728         return True;
729 }
730
731 /****************************************************************************
732  Enumerate the group mapping.
733 ****************************************************************************/
734
735 BOOL enum_group_mapping(enum SID_NAME_USE sid_name_use, GROUP_MAP **rmap,
736                         int *num_entries, BOOL unix_only, BOOL with_priv)
737 {
738         TDB_DATA kbuf, dbuf, newkey;
739         fstring string_sid;
740         fstring group_type;
741         GROUP_MAP map;
742         GROUP_MAP *mapt;
743         int ret;
744         int entries=0;
745         int i;
746         PRIVILEGE_SET *set;
747
748         if(!init_group_mapping()) {
749                 DEBUG(0,("failed to initialize group mapping"));
750                 return(False);
751         }
752
753         *num_entries=0;
754         *rmap=NULL;
755
756         for (kbuf = tdb_firstkey(tdb); 
757              kbuf.dptr; 
758              newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
759
760                 if (strncmp(kbuf.dptr, GROUP_PREFIX, strlen(GROUP_PREFIX)) != 0)
761                         continue;
762                 
763                 dbuf = tdb_fetch(tdb, kbuf);
764                 if (!dbuf.dptr)
765                         continue;
766
767                 fstrcpy(string_sid, kbuf.dptr+strlen(GROUP_PREFIX));
768                                 
769                 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddffd",
770                                  &map.gid, &map.sid_name_use, &map.nt_name, &map.comment, &map.systemaccount);
771
772                 set=&map.priv_set;
773                 init_privilege(set);
774                 
775                 ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "d", &set->count);
776         
777                 if (set->count!=0) {
778                         set->set=(LUID_ATTR *)malloc(set->count*sizeof(LUID_ATTR));
779                         if (set->set==NULL) {
780                                 DEBUG(0,("enum_group_mapping: could not allocate memory for privileges\n"));
781                                 return False;
782                         }
783                 }
784
785                 for (i=0; i<set->count; i++)
786                         ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "ddd", 
787                                         &(set->set[i].luid.low), &(set->set[i].luid.high), &(set->set[i].attr));
788
789                 SAFE_FREE(dbuf.dptr);
790                 if (ret != dbuf.dsize) {
791                         DEBUG(11,("enum_group_mapping: error in memory size\n"));
792                         free_privilege(set);
793                         continue;
794                 }
795
796                 /* list only the type or everything if UNKNOWN */
797                 if (sid_name_use!=SID_NAME_UNKNOWN  && sid_name_use!=map.sid_name_use) {
798                         DEBUG(11,("enum_group_mapping: group %s is not of the requested type\n", map.nt_name));
799                         free_privilege(set);
800                         continue;
801                 }
802                 
803                 if (unix_only==ENUM_ONLY_MAPPED && map.gid==-1) {
804                         DEBUG(11,("enum_group_mapping: group %s is non mapped\n", map.nt_name));
805                         free_privilege(set);
806                         continue;
807                 }
808
809                 string_to_sid(&map.sid, string_sid);
810                 
811                 decode_sid_name_use(group_type, map.sid_name_use);
812                 DEBUG(11,("enum_group_mapping: returning group %s of type %s\n", map.nt_name ,group_type));
813
814                 mapt=(GROUP_MAP *)Realloc((*rmap), (entries+1)*sizeof(GROUP_MAP));
815                 if (!mapt) {
816                         DEBUG(0,("enum_group_mapping: Unable to enlarge group map!\n"));
817                         SAFE_FREE(*rmap);
818                         free_privilege(set);
819                         return False;
820                 }
821                 else
822                         (*rmap) = mapt;
823
824                 mapt[entries].gid = map.gid;
825                 sid_copy( &mapt[entries].sid, &map.sid);
826                 mapt[entries].sid_name_use = map.sid_name_use;
827                 fstrcpy(mapt[entries].nt_name, map.nt_name);
828                 fstrcpy(mapt[entries].comment, map.comment);
829                 mapt[entries].systemaccount=map.systemaccount;
830                 mapt[entries].priv_set.count=set->count;
831                 mapt[entries].priv_set.control=set->control;
832                 mapt[entries].priv_set.set=set->set;
833                 if (!with_priv)
834                         free_privilege(&(mapt[entries].priv_set));
835
836                 entries++;
837         }
838
839         *num_entries=entries;
840         return True;
841 }
842
843
844 /****************************************************************************
845 convert a privilege string to a privilege array
846 ****************************************************************************/
847 void convert_priv_from_text(PRIVILEGE_SET *se_priv, char *privilege)
848 {
849         pstring tok;
850         const char *p = privilege;
851         int i;
852         LUID_ATTR set;
853
854         /* By default no privilege */
855         init_privilege(se_priv);
856         
857         if (privilege==NULL)
858                 return;
859
860         while(next_token(&p, tok, " ", sizeof(tok)) ) {
861                 for (i=0; i<=PRIV_ALL_INDEX; i++) {
862                         if (StrCaseCmp(privs[i].priv, tok)==0) {
863                                 set.attr=0;
864                                 set.luid.high=0;
865                                 set.luid.low=privs[i].se_priv;
866                                 add_privilege(se_priv, set);
867                         }
868                 }               
869         }
870 }
871
872 /****************************************************************************
873 convert a privilege array to a privilege string
874 ****************************************************************************/
875 void convert_priv_to_text(PRIVILEGE_SET *se_priv, char *privilege)
876 {
877         int i,j;
878
879         if (privilege==NULL)
880                 return;
881
882         ZERO_STRUCTP(privilege);
883
884         if (check_empty_privilege(se_priv)) {
885                 fstrcat(privilege, "No privilege");
886                 return;
887         }
888
889         for(i=0; i<se_priv->count; i++) {
890                 j=1;
891                 while (privs[j].se_priv!=se_priv->set[i].luid.low && j<=PRIV_ALL_INDEX) {
892                         j++;
893                 }
894
895                 fstrcat(privilege, privs[j].priv);
896                 fstrcat(privilege, " ");
897         }
898 }
899
900
901 /*
902  *
903  * High level functions
904  * better to use them than the lower ones.
905  *
906  * we are checking if the group is in the mapping file
907  * and if the group is an existing unix group
908  *
909  */
910
911 /* get a domain group from it's SID */
912
913 BOOL get_domain_group_from_sid(DOM_SID sid, GROUP_MAP *map, BOOL with_priv)
914 {
915         struct group *grp;
916
917         if(!init_group_mapping()) {
918                 DEBUG(0,("failed to initialize group mapping"));
919                 return(False);
920         }
921
922         DEBUG(10, ("get_domain_group_from_sid\n"));
923
924         /* if the group is NOT in the database, it CAN NOT be a domain group */
925         if(!pdb_getgrsid(map, sid, with_priv))
926                 return False;
927
928         DEBUG(10, ("get_domain_group_from_sid: SID found in the TDB\n"));
929
930         /* if it's not a domain group, continue */
931         if (map->sid_name_use!=SID_NAME_DOM_GRP) {
932                 if (with_priv)
933                         free_privilege(&map->priv_set);
934                 return False;
935         }
936
937         DEBUG(10, ("get_domain_group_from_sid: SID is a domain group\n"));
938         
939         if (map->gid==-1) {
940                 if (with_priv)
941                         free_privilege(&map->priv_set);
942                 return False;
943         }
944
945         DEBUG(10, ("get_domain_group_from_sid: SID is mapped to gid:%d\n",map->gid));
946
947         if ( (grp=getgrgid(map->gid)) == NULL) {
948                 DEBUG(10, ("get_domain_group_from_sid: gid DOESN'T exist in UNIX security\n"));
949                 if (with_priv)
950                         free_privilege(&map->priv_set);
951                 return False;
952         }
953
954         DEBUG(10, ("get_domain_group_from_sid: gid exists in UNIX security\n"));
955
956         return True;
957 }
958
959
960 /* get a local (alias) group from it's SID */
961
962 BOOL get_local_group_from_sid(DOM_SID sid, GROUP_MAP *map, BOOL with_priv)
963 {
964         struct group *grp;
965
966         if(!init_group_mapping()) {
967                 DEBUG(0,("failed to initialize group mapping"));
968                 return(False);
969         }
970
971         /* The group is in the mapping table */
972         if(pdb_getgrsid(map, sid, with_priv)) {
973                 if (map->sid_name_use!=SID_NAME_ALIAS) {
974                         if (with_priv)
975                                 free_privilege(&map->priv_set);
976                         return False;
977                 }
978                 
979                 if (map->gid==-1) {
980                         if (with_priv)
981                                 free_privilege(&map->priv_set);
982                         return False;
983                 }
984
985                 if ( (grp=getgrgid(map->gid)) == NULL) {
986                         if (with_priv)
987                                 free_privilege(&map->priv_set);
988                         return False;
989                 }
990         } else {
991                 /* the group isn't in the mapping table.
992                  * make one based on the unix information */
993                 uint32 alias_rid;
994
995                 sid_peek_rid(&sid, &alias_rid);
996                 map->gid=pdb_group_rid_to_gid(alias_rid);
997
998                 if ((grp=getgrgid(map->gid)) == NULL)
999                         return False;
1000
1001                 map->sid_name_use=SID_NAME_ALIAS;
1002                 map->systemaccount=PR_ACCESS_FROM_NETWORK;
1003
1004                 fstrcpy(map->nt_name, grp->gr_name);
1005                 fstrcpy(map->comment, "Local Unix Group");
1006
1007                 init_privilege(&map->priv_set);
1008
1009                 sid_copy(&map->sid, &sid);
1010         }
1011
1012         return True;
1013 }
1014
1015 /* get a builtin group from it's SID */
1016
1017 BOOL get_builtin_group_from_sid(DOM_SID sid, GROUP_MAP *map, BOOL with_priv)
1018 {
1019         struct group *grp;
1020
1021         if(!init_group_mapping()) {
1022                 DEBUG(0,("failed to initialize group mapping"));
1023                 return(False);
1024         }
1025
1026         if(!pdb_getgrsid(map, sid, with_priv))
1027                 return False;
1028
1029         if (map->sid_name_use!=SID_NAME_WKN_GRP) {
1030                 if (with_priv)
1031                         free_privilege(&map->priv_set);
1032                 return False;
1033         }
1034
1035         if (map->gid==-1) {
1036                 if (with_priv)
1037                         free_privilege(&map->priv_set);
1038                 return False;
1039         }
1040
1041         if ( (grp=getgrgid(map->gid)) == NULL) {
1042                 if (with_priv)
1043                         free_privilege(&map->priv_set);
1044                 return False;
1045         }
1046
1047         return True;
1048 }
1049
1050
1051
1052 /****************************************************************************
1053 Returns a GROUP_MAP struct based on the gid.
1054 ****************************************************************************/
1055 BOOL get_group_from_gid(gid_t gid, GROUP_MAP *map, BOOL with_priv)
1056 {
1057         struct group *grp;
1058
1059         if(!init_group_mapping()) {
1060                 DEBUG(0,("failed to initialize group mapping"));
1061                 return(False);
1062         }
1063
1064         if ( (grp=getgrgid(gid)) == NULL)
1065                 return False;
1066
1067         /*
1068          * make a group map from scratch if doesn't exist.
1069          */
1070         if (!pdb_getgrgid(map, gid, with_priv)) {
1071                 map->gid=gid;
1072                 map->sid_name_use=SID_NAME_ALIAS;
1073                 map->systemaccount=PR_ACCESS_FROM_NETWORK;
1074                 init_privilege(&map->priv_set);
1075
1076                 /* interim solution until we have a last RID allocated */
1077
1078                 sid_copy(&map->sid, get_global_sam_sid());
1079                 sid_append_rid(&map->sid, pdb_gid_to_group_rid(gid));
1080
1081                 fstrcpy(map->nt_name, grp->gr_name);
1082                 fstrcpy(map->comment, "Local Unix Group");
1083         }
1084         
1085         return True;
1086 }
1087
1088
1089
1090
1091 /****************************************************************************
1092  Get the member users of a group and
1093  all the users who have that group as primary.
1094             
1095  give back an array of uid
1096  return the grand number of users
1097
1098
1099  TODO: sort the list and remove duplicate. JFM.
1100
1101 ****************************************************************************/
1102         
1103 BOOL get_uid_list_of_group(gid_t gid, uid_t **uid, int *num_uids)
1104 {
1105         struct group *grp;
1106         struct passwd *pwd;
1107         int i=0;
1108         char *gr;
1109         uid_t *u;
1110  
1111         if(!init_group_mapping()) {
1112                 DEBUG(0,("failed to initialize group mapping"));
1113                 return(False);
1114         }
1115
1116         *num_uids = 0;
1117         *uid=NULL;
1118         
1119         if ( (grp=getgrgid(gid)) == NULL)
1120                 return False;
1121
1122         gr = grp->gr_mem[0];
1123         DEBUG(10, ("getting members\n"));
1124         
1125         while (gr && (*gr != (char)'\0')) {
1126                 u = Realloc((*uid), sizeof(uid_t)*(*num_uids+1));
1127                 if (!u) {
1128                         DEBUG(0,("get_uid_list_of_group: unable to enlarge uid list!\n"));
1129                         return False;
1130                 }
1131                 else (*uid) = u;
1132
1133                 if( (pwd=getpwnam_alloc(gr)) !=NULL) {
1134                         (*uid)[*num_uids]=pwd->pw_uid;
1135                         (*num_uids)++;
1136                 }
1137                 passwd_free(&pwd);
1138                 gr = grp->gr_mem[++i];
1139         }
1140         DEBUG(10, ("got [%d] members\n", *num_uids));
1141
1142         setpwent();
1143         while ((pwd=getpwent()) != NULL) {
1144                 if (pwd->pw_gid==gid) {
1145                         u = Realloc((*uid), sizeof(uid_t)*(*num_uids+1));
1146                         if (!u) {
1147                                 DEBUG(0,("get_uid_list_of_group: unable to enlarge uid list!\n"));
1148                                 return False;
1149                         }
1150                         else (*uid) = u;
1151                         (*uid)[*num_uids]=pwd->pw_uid;
1152
1153                         (*num_uids)++;
1154                 }
1155         }
1156         endpwent();
1157         DEBUG(10, ("got primary groups, members: [%d]\n", *num_uids));
1158
1159         return True;
1160 }
1161
1162 /****************************************************************************
1163  Create a UNIX group on demand.
1164 ****************************************************************************/
1165
1166 int smb_create_group(char *unix_group, gid_t *new_gid)
1167 {
1168         pstring add_script;
1169         int ret;
1170         int fd = 0;
1171
1172         pstrcpy(add_script, lp_addgroup_script());
1173         if (! *add_script) return -1;
1174         pstring_sub(add_script, "%g", unix_group);
1175         ret = smbrun(add_script, (new_gid!=NULL) ? &fd : NULL);
1176         DEBUG(3,("smb_create_group: Running the command `%s' gave %d\n",add_script,ret));
1177         if (ret != 0)
1178                 return ret;
1179
1180         if (fd != 0) {
1181                 fstring output;
1182
1183                 *new_gid = 0;
1184                 if (read(fd, output, sizeof(output)) > 0) {
1185                         *new_gid = (gid_t)strtoul(output, NULL, 10);
1186                 }
1187                 close(fd);
1188
1189                 if (*new_gid == 0) {
1190                         /* The output was garbage. We assume nobody
1191                            will create group 0 via smbd. Now we try to
1192                            get the group via getgrnam. */
1193
1194                         struct group *grp = getgrnam(unix_group);
1195                         if (grp != NULL)
1196                                 *new_gid = grp->gr_gid;
1197                         else
1198                                 return 1;
1199                 }
1200         }
1201
1202         return ret;
1203 }
1204
1205 /****************************************************************************
1206  Delete a UNIX group on demand.
1207 ****************************************************************************/
1208
1209 int smb_delete_group(char *unix_group)
1210 {
1211         pstring del_script;
1212         int ret;
1213
1214         pstrcpy(del_script, lp_delgroup_script());
1215         if (! *del_script) return -1;
1216         pstring_sub(del_script, "%g", unix_group);
1217         ret = smbrun(del_script,NULL);
1218         DEBUG(3,("smb_delete_group: Running the command `%s' gave %d\n",del_script,ret));
1219         return ret;
1220 }
1221
1222 /****************************************************************************
1223  Set a user's primary UNIX group.
1224 ****************************************************************************/
1225 int smb_set_primary_group(const char *unix_group, const char* unix_user)
1226 {
1227         pstring add_script;
1228         int ret;
1229
1230         pstrcpy(add_script, lp_setprimarygroup_script());
1231         if (! *add_script) return -1;
1232         all_string_sub(add_script, "%g", unix_group, sizeof(add_script));
1233         all_string_sub(add_script, "%u", unix_user, sizeof(add_script));
1234         ret = smbrun(add_script,NULL);
1235         DEBUG(3,("smb_set_primary_group: "
1236                  "Running the command `%s' gave %d\n",add_script,ret));
1237         return ret;
1238 }
1239
1240 /****************************************************************************
1241  Add a user to a UNIX group.
1242 ****************************************************************************/
1243
1244 int smb_add_user_group(char *unix_group, char *unix_user)
1245 {
1246         pstring add_script;
1247         int ret;
1248
1249         pstrcpy(add_script, lp_addusertogroup_script());
1250         if (! *add_script) return -1;
1251         pstring_sub(add_script, "%g", unix_group);
1252         pstring_sub(add_script, "%u", unix_user);
1253         ret = smbrun(add_script,NULL);
1254         DEBUG(3,("smb_add_user_group: Running the command `%s' gave %d\n",add_script,ret));
1255         return ret;
1256 }
1257
1258 /****************************************************************************
1259  Delete a user from a UNIX group
1260 ****************************************************************************/
1261
1262 int smb_delete_user_group(const char *unix_group, const char *unix_user)
1263 {
1264         pstring del_script;
1265         int ret;
1266
1267         pstrcpy(del_script, lp_deluserfromgroup_script());
1268         if (! *del_script) return -1;
1269         pstring_sub(del_script, "%g", unix_group);
1270         pstring_sub(del_script, "%u", unix_user);
1271         ret = smbrun(del_script,NULL);
1272         DEBUG(3,("smb_delete_user_group: Running the command `%s' gave %d\n",del_script,ret));
1273         return ret;
1274 }