Removed 'extern int DEBUGLEVEL' as it is now in the smb.h header.
[kai/samba.git] / source3 / groupdb / mapping.c
1 /* 
2  *  Unix SMB/Netbios implementation.
3  *  Version 1.9.
4  *  RPC Pipe client / server routines
5  *  Copyright (C) Andrew Tridgell              1992-2000,
6  *  Copyright (C) Jean François Micouleau      1998-2001.
7  *  
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *  
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *  
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #include "includes.h"
24
25 extern DOM_SID global_sam_sid;
26
27 static TDB_CONTEXT *tdb; /* used for driver files */
28
29 #define DATABASE_VERSION 1
30 #define GROUP_PREFIX "UNIXGROUP/"
31
32 PRIVS privs[] = {
33         {SE_PRIV_NONE, "no_privs", "No privilege"},
34         {SE_PRIV_ADD_USERS, "add_users", "add users"},
35         {SE_PRIV_ADD_MACHINES, "add_computers", "add computers to domain"},
36         {SE_PRIV_PRINT_OPERATOR, "print_op", "printer operator"},
37         {SE_PRIV_ALL, "all_privs", "all privileges"}
38 };
39 /*
40 PRIVS privs[] = {
41         {  2, "SeCreateTokenPrivilege" },
42         {  3, "SeAssignPrimaryTokenPrivilege" },
43         {  4, "SeLockMemoryPrivilege" },
44         {  5, "SeIncreaseQuotaPrivilege" },
45         {  6, "SeMachineAccountPrivilege" },
46         {  7, "SeTcbPrivilege" },
47         {  8, "SeSecurityPrivilege" },
48         {  9, "SeTakeOwnershipPrivilege" },
49         { 10, "SeLoadDriverPrivilege" },
50         { 11, "SeSystemProfilePrivilege" },
51         { 12, "SeSystemtimePrivilege" },
52         { 13, "SeProfileSingleProcessPrivilege" },
53         { 14, "SeIncreaseBasePriorityPrivilege" },
54         { 15, "SeCreatePagefilePrivilege" },
55         { 16, "SeCreatePermanentPrivilege" },
56         { 17, "SeBackupPrivilege" },
57         { 18, "SeRestorePrivilege" },
58         { 19, "SeShutdownPrivilege" },
59         { 20, "SeDebugPrivilege" },
60         { 21, "SeAuditPrivilege" },
61         { 22, "SeSystemEnvironmentPrivilege" },
62         { 23, "SeChangeNotifyPrivilege" },
63         { 24, "SeRemoteShutdownPrivilege" },
64 };
65 */
66
67 #if 0
68 /****************************************************************************
69 check if the user has the required privilege.
70 ****************************************************************************/
71 static BOOL se_priv_access_check(NT_USER_TOKEN *token, uint32 privilege)
72 {
73         /* no token, no privilege */
74         if (token==NULL)
75                 return False;
76         
77         if ((token->privilege & privilege)==privilege)
78                 return True;
79         
80         return False;
81 }
82 #endif
83
84 /****************************************************************************
85 dump the mapping group mapping to a text file
86 ****************************************************************************/
87 char *decode_sid_name_use(fstring group, enum SID_NAME_USE name_use)
88 {       
89         static fstring group_type;
90
91         switch(name_use) {
92                 case SID_NAME_USER:
93                         fstrcpy(group_type,"User");
94                         break;
95                 case SID_NAME_DOM_GRP:
96                         fstrcpy(group_type,"Domain group");
97                         break;
98                 case SID_NAME_DOMAIN:
99                         fstrcpy(group_type,"Domain");
100                         break;
101                 case SID_NAME_ALIAS:
102                         fstrcpy(group_type,"Local group");
103                         break;
104                 case SID_NAME_WKN_GRP:
105                         fstrcpy(group_type,"Builtin group");
106                         break;
107                 case SID_NAME_DELETED:
108                         fstrcpy(group_type,"Deleted");
109                         break;
110                 case SID_NAME_INVALID:
111                         fstrcpy(group_type,"Invalid");
112                         break;
113                 case SID_NAME_UNKNOWN:
114                 default:
115                         fstrcpy(group_type,"Unknown type");
116                         break;
117         }
118         
119         fstrcpy(group, group_type);
120         return group_type;
121 }
122
123 /****************************************************************************
124 open the group mapping tdb
125 ****************************************************************************/
126 BOOL init_group_mapping(void)
127 {
128         static pid_t local_pid;
129         char *vstring = "INFO/version";
130
131         if (tdb && local_pid == sys_getpid()) return True;
132         tdb = tdb_open_log(lock_path("group_mapping.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
133         if (!tdb) {
134                 DEBUG(0,("Failed to open group mapping database\n"));
135                 return False;
136         }
137
138         local_pid = sys_getpid();
139
140         /* handle a Samba upgrade */
141         tdb_lock_bystring(tdb, vstring);
142         if (tdb_fetch_int(tdb, vstring) != DATABASE_VERSION) {
143                 tdb_traverse(tdb, (tdb_traverse_func)tdb_delete, NULL);
144                 tdb_store_int(tdb, vstring, DATABASE_VERSION);
145         }
146         tdb_unlock_bystring(tdb, vstring);
147
148
149         return True;
150 }
151
152 /****************************************************************************
153 ****************************************************************************/
154 BOOL add_mapping_entry(GROUP_MAP *map, int flag)
155 {
156         TDB_DATA kbuf, dbuf;
157         pstring key, buf;
158         fstring string_sid="";
159         int len;
160         
161         sid_to_string(string_sid, &map->sid);
162
163         len = tdb_pack(buf, sizeof(buf), "ddffd",
164                         map->gid, map->sid_name_use, map->nt_name, map->comment, map->privilege);
165
166         if (len > sizeof(buf)) return False;
167
168         slprintf(key, sizeof(key), "%s%s", GROUP_PREFIX, string_sid);
169
170         kbuf.dsize = strlen(key)+1;
171         kbuf.dptr = key;
172         dbuf.dsize = len;
173         dbuf.dptr = buf;
174         if (tdb_store(tdb, kbuf, dbuf, flag) != 0) return False;
175
176         return True;
177 }
178
179 /****************************************************************************
180 initialise first time the mapping list
181 ****************************************************************************/
182 BOOL add_initial_entry(gid_t gid, fstring sid, enum SID_NAME_USE sid_name_use,
183                               fstring nt_name, fstring comment, uint32 privilege)
184 {
185         GROUP_MAP map;
186
187         map.gid=gid;
188         string_to_sid(&map.sid, sid);
189         map.sid_name_use=sid_name_use;
190         fstrcpy(map.nt_name, nt_name);
191         fstrcpy(map.comment, comment);
192         map.privilege=privilege;
193
194         add_mapping_entry(&map, TDB_INSERT);
195
196         return True;
197 }
198
199 /****************************************************************************
200 initialise first time the mapping list
201 ****************************************************************************/
202 BOOL default_group_mapping(void)
203 {
204         DOM_SID sid_admins;
205         DOM_SID sid_users;
206         DOM_SID sid_guests;
207         fstring str_admins;
208         fstring str_users;
209         fstring str_guests;
210
211
212         /* Add the Wellknown groups */
213
214         add_initial_entry(-1, "S-1-5-32-544", SID_NAME_WKN_GRP, "Administrators", "", SE_PRIV_ALL);
215         add_initial_entry(-1, "S-1-5-32-545", SID_NAME_WKN_GRP, "Users", "", SE_PRIV_NONE);
216         add_initial_entry(-1, "S-1-5-32-546", SID_NAME_WKN_GRP, "Guests", "", SE_PRIV_NONE);
217         add_initial_entry(-1, "S-1-5-32-547", SID_NAME_WKN_GRP, "Power Users", "", SE_PRIV_NONE);
218
219         add_initial_entry(-1, "S-1-5-32-548", SID_NAME_WKN_GRP, "Account Operators", "", SE_PRIV_NONE);
220         add_initial_entry(-1, "S-1-5-32-549", SID_NAME_WKN_GRP, "System Operators", "", SE_PRIV_NONE);
221         add_initial_entry(-1, "S-1-5-32-550", SID_NAME_WKN_GRP, "Print Operators", "", SE_PRIV_PRINT_OPERATOR);
222         add_initial_entry(-1, "S-1-5-32-551", SID_NAME_WKN_GRP, "Backup Operators", "", SE_PRIV_NONE);
223
224         add_initial_entry(-1, "S-1-5-32-552", SID_NAME_WKN_GRP, "Replicators", "", SE_PRIV_NONE);
225
226         /* Add the defaults domain groups */
227
228         sid_copy(&sid_admins, &global_sam_sid);
229         sid_append_rid(&sid_admins, DOMAIN_GROUP_RID_ADMINS);
230         sid_to_string(str_admins, &sid_admins);
231         add_initial_entry(-1, str_admins, SID_NAME_DOM_GRP, "Domain Admins", "", SE_PRIV_ALL);
232
233         sid_copy(&sid_users,  &global_sam_sid);
234         sid_append_rid(&sid_users,  DOMAIN_GROUP_RID_USERS);
235         sid_to_string(str_users, &sid_users);
236         add_initial_entry(-1, str_users,  SID_NAME_DOM_GRP, "Domain Users",  "", SE_PRIV_NONE);
237
238         sid_copy(&sid_guests, &global_sam_sid);
239         sid_append_rid(&sid_guests, DOMAIN_GROUP_RID_GUESTS);
240         sid_to_string(str_guests, &sid_guests);
241         add_initial_entry(-1, str_guests, SID_NAME_DOM_GRP, "Domain Guests", "", SE_PRIV_NONE);
242
243         return True;
244 }
245
246
247 /****************************************************************************
248 return the sid and the type of the unix group
249 ****************************************************************************/
250 BOOL get_group_map_from_sid(DOM_SID sid, GROUP_MAP *map)
251 {
252         TDB_DATA kbuf, dbuf;
253         pstring key;
254         fstring string_sid;
255         int ret;
256         
257         /* the key is the SID, retrieving is direct */
258
259         sid_to_string(string_sid, &sid);
260         slprintf(key, sizeof(key), "%s%s", GROUP_PREFIX, string_sid);
261
262         kbuf.dptr = key;
263         kbuf.dsize = strlen(key)+1;
264                 
265         dbuf = tdb_fetch(tdb, kbuf);
266         if (!dbuf.dptr) return False;
267
268         ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddffd",
269                                 &map->gid, &map->sid_name_use, &map->nt_name, &map->comment, &map->privilege);
270
271         SAFE_FREE(dbuf.dptr);
272         if (ret != dbuf.dsize) {
273                 DEBUG(0,("get_group_map_from_sid: mapping TDB corrupted ?\n"));
274                 return False;
275         }
276
277         sid_copy(&map->sid, &sid);
278         
279         return True;
280 }
281
282
283 /****************************************************************************
284 return the sid and the type of the unix group
285 ****************************************************************************/
286 BOOL get_group_map_from_gid(gid_t gid, GROUP_MAP *map)
287 {
288         TDB_DATA kbuf, dbuf, newkey;
289         fstring string_sid;
290         int ret;
291
292         /* we need to enumerate the TDB to find the GID */
293
294         for (kbuf = tdb_firstkey(tdb); 
295              kbuf.dptr; 
296              newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
297
298                 if (strncmp(kbuf.dptr, GROUP_PREFIX, strlen(GROUP_PREFIX)) != 0) continue;
299                 
300                 dbuf = tdb_fetch(tdb, kbuf);
301                 if (!dbuf.dptr) continue;
302
303                 fstrcpy(string_sid, kbuf.dptr+strlen(GROUP_PREFIX));
304
305                 string_to_sid(&map->sid, string_sid);
306                 
307                 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddffd",
308                                  &map->gid, &map->sid_name_use, &map->nt_name, &map->comment, &map->privilege);
309
310                 SAFE_FREE(dbuf.dptr);
311                 if (ret != dbuf.dsize) continue;
312
313                 if (gid==map->gid)
314                         return True;
315         }
316
317         return False;
318 }
319
320 /****************************************************************************
321 return the sid and the type of the unix group
322 ****************************************************************************/
323 BOOL get_group_map_from_ntname(char *name, GROUP_MAP *map)
324 {
325         TDB_DATA kbuf, dbuf, newkey;
326         fstring string_sid;
327         int ret;
328
329         /* we need to enumerate the TDB to find the GID */
330
331         for (kbuf = tdb_firstkey(tdb); 
332              kbuf.dptr; 
333              newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
334
335                 if (strncmp(kbuf.dptr, GROUP_PREFIX, strlen(GROUP_PREFIX)) != 0) continue;
336                 
337                 dbuf = tdb_fetch(tdb, kbuf);
338                 if (!dbuf.dptr) continue;
339
340                 fstrcpy(string_sid, kbuf.dptr+strlen(GROUP_PREFIX));
341
342                 string_to_sid(&map->sid, string_sid);
343                 
344                 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddffd",
345                                  &map->gid, &map->sid_name_use, &map->nt_name, &map->comment, &map->privilege);
346
347                 SAFE_FREE(dbuf.dptr);
348                 if (ret != dbuf.dsize) continue;
349
350                 if (StrCaseCmp(name, map->nt_name)==0)
351                         return True;
352
353         }
354
355         return False;
356 }
357
358 /****************************************************************************
359 enumerate the group mapping
360 ****************************************************************************/
361 BOOL group_map_remove(DOM_SID sid)
362 {
363         TDB_DATA kbuf, dbuf;
364         pstring key;
365         fstring string_sid;
366         
367         /* the key is the SID, retrieving is direct */
368
369         sid_to_string(string_sid, &sid);
370         slprintf(key, sizeof(key), "%s%s", GROUP_PREFIX, string_sid);
371
372         kbuf.dptr = key;
373         kbuf.dsize = strlen(key)+1;
374                 
375         dbuf = tdb_fetch(tdb, kbuf);
376         if (!dbuf.dptr) return False;
377         
378         SAFE_FREE(dbuf.dptr);
379
380         if(tdb_delete(tdb, kbuf) != TDB_SUCCESS)
381                 return False;
382
383         return True;
384 }
385
386
387 /****************************************************************************
388 enumerate the group mapping
389 ****************************************************************************/
390 BOOL enum_group_mapping(enum SID_NAME_USE sid_name_use, GROUP_MAP **rmap,
391                         int *num_entries, BOOL unix_only)
392 {
393         TDB_DATA kbuf, dbuf, newkey;
394         fstring string_sid;
395         fstring group_type;
396         GROUP_MAP map;
397         GROUP_MAP *mapt;
398         int ret;
399         int entries=0;
400
401         *num_entries=0;
402         *rmap=NULL;
403
404         for (kbuf = tdb_firstkey(tdb); 
405              kbuf.dptr; 
406              newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
407
408                 if (strncmp(kbuf.dptr, GROUP_PREFIX, strlen(GROUP_PREFIX)) != 0)
409                         continue;
410                 
411                 dbuf = tdb_fetch(tdb, kbuf);
412                 if (!dbuf.dptr)
413                         continue;
414
415                 fstrcpy(string_sid, kbuf.dptr+strlen(GROUP_PREFIX));
416                                 
417                 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddffd",
418                                  &map.gid, &map.sid_name_use, &map.nt_name, &map.comment, &map.privilege);
419
420                 SAFE_FREE(dbuf.dptr);
421                 if (ret != dbuf.dsize)
422                         continue;
423
424                 /* list only the type or everything if UNKNOWN */
425                 if (sid_name_use!=SID_NAME_UNKNOWN  && sid_name_use!=map.sid_name_use)
426                         continue;
427
428                 if (unix_only==ENUM_ONLY_MAPPED && map.gid==-1)
429                         continue;
430
431                 string_to_sid(&map.sid, string_sid);
432                 
433                 decode_sid_name_use(group_type, map.sid_name_use);
434
435                 mapt=(GROUP_MAP *)Realloc((*rmap), (entries+1)*sizeof(GROUP_MAP));
436                 if (!mapt) {
437                         DEBUG(0,("enum_group_mapping: Unable to enlarge group map!\n"));
438                         SAFE_FREE(*rmap);
439                         return False;
440                 }
441                 else (*rmap) = mapt;
442
443                 mapt[entries].gid = map.gid;
444                 sid_copy( &mapt[entries].sid, &map.sid);
445                 mapt[entries].sid_name_use = map.sid_name_use;
446                 fstrcpy(mapt[entries].nt_name, map.nt_name);
447                 fstrcpy(mapt[entries].comment, map.comment);
448                 mapt[entries].privilege = map.privilege;
449
450                 entries++;
451         }
452
453         *num_entries=entries;
454         return True;
455 }
456
457
458 /****************************************************************************
459 convert a privilege list to a privilege value
460 ****************************************************************************/
461 void convert_priv_from_text(uint32 *se_priv, char *privilege)
462 {
463         pstring tok;
464         char *p = privilege;
465         int i;
466
467         /* By default no privilege */
468         (*se_priv)=0x0;
469
470         if (privilege==NULL)
471                 return;
472
473         while(next_token(&p, tok, " ", sizeof(tok)) ) {
474                 for (i=0; i<=PRIV_ALL_INDEX; i++) {
475                         if (StrCaseCmp(privs[i].priv, tok)==0)
476                                 (*se_priv)+=privs[i].se_priv;
477                 }               
478         }
479 }
480
481 /****************************************************************************
482 convert a privilege value to a privilege list
483 ****************************************************************************/
484 void convert_priv_to_text(uint32 se_priv, char *privilege)
485 {
486         int i;
487
488         if (privilege==NULL)
489                 return;
490
491         ZERO_STRUCTP(privilege);
492
493         if (se_priv==SE_PRIV_NONE) {
494                 fstrcat(privilege, privs[0].priv);
495                 return;
496         }
497
498         if (se_priv==SE_PRIV_ALL) {
499                 fstrcat(privilege, privs[PRIV_ALL_INDEX].priv);
500                 return;
501         }
502
503         for (i=1; privs[i].se_priv!=SE_PRIV_ALL; i++) {
504                 if ( (se_priv & privs[i].se_priv) == privs[i].se_priv) {
505                         fstrcat(privilege, privs[i].priv);
506                         fstrcat(privilege, " ");
507                 }
508         }
509 }
510
511
512 /*
513  *
514  * High level functions
515  * better to use them than the lower ones.
516  *
517  * we are checking if the group is in the mapping file
518  * and if the group is an existing unix group
519  *
520  */
521
522 /* get a domain group from it's SID */
523
524 BOOL get_domain_group_from_sid(DOM_SID sid, GROUP_MAP *map)
525 {
526         struct group *grp;
527
528         DEBUG(10, ("get_domain_group_from_sid\n"));
529
530         /* if the group is NOT in the database, it CAN NOT be a domain group */
531         if(!get_group_map_from_sid(sid, map))
532                 return False;
533
534         DEBUG(10, ("get_domain_group_from_sid: SID found in the TDB\n"));
535
536         /* if it's not a domain group, continue */
537         if (map->sid_name_use!=SID_NAME_DOM_GRP)
538                 return False;
539
540         DEBUG(10, ("get_domain_group_from_sid: SID is a domain group\n"));
541         
542         if (map->gid==-1)
543                 return False;
544
545         DEBUG(10, ("get_domain_group_from_sid: SID is mapped to gid:%d\n",map->gid));
546
547         if ( (grp=getgrgid(map->gid)) == NULL)
548                 return False;
549
550         DEBUG(10, ("get_domain_group_from_sid: gid exists in UNIX security\n"));
551
552         return True;
553 }
554
555
556 /* get a local (alias) group from it's SID */
557
558 BOOL get_local_group_from_sid(DOM_SID sid, GROUP_MAP *map)
559 {
560         struct group *grp;
561
562         /* The group is in the mapping table */
563         if(get_group_map_from_sid(sid, map)) {
564                 if (map->sid_name_use!=SID_NAME_ALIAS)
565                         return False;
566         
567                 if (map->gid==-1)
568                         return False;
569
570                 if ( (grp=getgrgid(map->gid)) == NULL)
571                         return False;
572         } else {
573                 /* the group isn't in the mapping table.
574                  * make one based on the unix information */
575                 uint32 alias_rid;
576
577                 sid_peek_rid(&sid, &alias_rid);
578                 map->gid=pdb_user_rid_to_gid(alias_rid);
579
580                 if ((grp=getgrgid(map->gid)) == NULL)
581                         return False;
582
583                 map->sid_name_use=SID_NAME_ALIAS;
584
585                 fstrcpy(map->nt_name, grp->gr_name);
586                 fstrcpy(map->comment, "Local Unix Group");
587
588                 map->privilege=SE_PRIV_NONE;
589
590                 sid_copy(&map->sid, &sid);
591         }
592
593         return True;
594 }
595
596 /* get a builtin group from it's SID */
597
598 BOOL get_builtin_group_from_sid(DOM_SID sid, GROUP_MAP *map)
599 {
600         struct group *grp;
601
602         if(!get_group_map_from_sid(sid, map))
603                 return False;
604
605         if (map->sid_name_use!=SID_NAME_WKN_GRP)
606                 return False;
607
608         if (map->gid==-1)
609                 return False;
610
611         if ( (grp=getgrgid(map->gid)) == NULL)
612                 return False;
613
614         return True;
615 }
616
617
618
619 /****************************************************************************
620 Returns a GROUP_MAP struct based on the gid.
621 ****************************************************************************/
622 BOOL get_group_from_gid(gid_t gid, GROUP_MAP *map)
623 {
624         struct group *grp;
625
626         if ( (grp=getgrgid(gid)) == NULL)
627                 return False;
628
629         /*
630          * make a group map from scratch if doesn't exist.
631          */
632         if (!get_group_map_from_gid(gid, map)) {
633                 map->gid=gid;
634                 map->sid_name_use=SID_NAME_ALIAS;
635                 map->privilege=SE_PRIV_NONE;
636
637                 sid_copy(&map->sid, &global_sam_sid);
638                 sid_append_rid(&map->sid, pdb_gid_to_group_rid(gid));
639
640                 fstrcpy(map->nt_name, grp->gr_name);
641                 fstrcpy(map->comment, "Local Unix Group");
642         }
643         
644         return True;
645 }
646
647
648
649
650 /****************************************************************************
651  Get the member users of a group and
652  all the users who have that group as primary.
653             
654  give back an array of uid
655  return the grand number of users
656
657
658  TODO: sort the list and remove duplicate. JFM.
659
660 ****************************************************************************/
661         
662 BOOL get_uid_list_of_group(gid_t gid, uid_t **uid, int *num_uids)
663 {
664         struct group *grp;
665         struct passwd *pwd;
666         int i=0;
667         char *gr;
668         uid_t *u;
669  
670         *num_uids = 0;
671         *uid=NULL;
672         
673         if ( (grp=getgrgid(gid)) == NULL)
674                 return False;
675
676         gr = grp->gr_mem[0];
677         DEBUG(10, ("getting members\n"));
678         
679         while (gr && (*gr != (char)'\0')) {
680                 u = Realloc((*uid), sizeof(uid_t)*(*num_uids+1));
681                 if (!u) {
682                         DEBUG(0,("get_uid_list_of_group: unable to enlarge uid list!\n"));
683                         return False;
684                 }
685                 else (*uid) = u;
686
687                 if( (pwd=getpwnam(gr)) !=NULL) {
688                         (*uid)[*num_uids]=pwd->pw_uid;
689                         (*num_uids)++;
690                 }
691                 gr = grp->gr_mem[++i];
692         }
693         DEBUG(10, ("got [%d] members\n", *num_uids));
694
695         setpwent();
696         while ((pwd=getpwent()) != NULL) {
697                 if (pwd->pw_gid==gid) {
698                         u = Realloc((*uid), sizeof(uid_t)*(*num_uids+1));
699                         if (!u) {
700                                 DEBUG(0,("get_uid_list_of_group: unable to enlarge uid list!\n"));
701                                 return False;
702                         }
703                         else (*uid) = u;
704                         (*uid)[*num_uids]=pwd->pw_uid;
705
706                         (*num_uids)++;
707                 }
708         }
709         endpwent();
710         DEBUG(10, ("got primary groups, members: [%d]\n", *num_uids));
711
712         return True;
713 }
714
715 /****************************************************************************
716  Create a UNIX group on demand.
717 ****************************************************************************/
718
719 int smb_create_group(char *unix_group)
720 {
721         pstring add_script;
722         int ret;
723
724         pstrcpy(add_script, lp_addgroup_script());
725         if (! *add_script) return -1;
726         pstring_sub(add_script, "%g", unix_group);
727         ret = smbrun(add_script,NULL);
728         DEBUG(3,("smb_create_group: Running the command `%s' gave %d\n",add_script,ret));
729         return ret;
730 }
731
732 /****************************************************************************
733  Delete a UNIX group on demand.
734 ****************************************************************************/
735
736 int smb_delete_group(char *unix_group)
737 {
738         pstring del_script;
739         int ret;
740
741         pstrcpy(del_script, lp_delgroup_script());
742         if (! *del_script) return -1;
743         pstring_sub(del_script, "%g", unix_group);
744         ret = smbrun(del_script,NULL);
745         DEBUG(3,("smb_delete_group: Running the command `%s' gave %d\n",del_script,ret));
746         return ret;
747 }
748
749 /****************************************************************************
750  Create a UNIX group on demand.
751 ****************************************************************************/
752
753 int smb_add_user_group(char *unix_group, char *unix_user)
754 {
755         pstring add_script;
756         int ret;
757
758         pstrcpy(add_script, lp_addusertogroup_script());
759         if (! *add_script) return -1;
760         pstring_sub(add_script, "%g", unix_group);
761         pstring_sub(add_script, "%u", unix_user);
762         ret = smbrun(add_script,NULL);
763         DEBUG(3,("smb_add_user_group: Running the command `%s' gave %d\n",add_script,ret));
764         return ret;
765 }
766
767 /****************************************************************************
768  Delete a UNIX group on demand.
769 ****************************************************************************/
770
771 int smb_delete_user_group(char *unix_group, char *unix_user)
772 {
773         pstring del_script;
774         int ret;
775
776         pstrcpy(del_script, lp_deluserfromgroup_script());
777         if (! *del_script) return -1;
778         pstring_sub(del_script, "%g", unix_group);
779         pstring_sub(del_script, "%u", unix_user);
780         ret = smbrun(del_script,NULL);
781         DEBUG(3,("smb_delete_user_group: Running the command `%s' gave %d\n",del_script,ret));
782         return ret;
783 }
784
785
786