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