Updates from Samba HEAD:
[ira/wip.git] / source / utils / smbgroupedit.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Andrew Tridgell              1992-2000,
5  *  Copyright (C) Jean François Micouleau      1998-2001.
6  *  
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *  
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *  
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #include "includes.h"
23
24 extern pstring global_myname;
25 extern fstring global_myworkgroup;
26
27 /*
28  * Next two lines needed for SunOS and don't
29  * hurt anything else...
30  */
31 extern char *optarg;
32 extern int optind;
33
34 /*********************************************************
35  Print command usage on stderr and die.
36 **********************************************************/
37 static void usage(void)
38 {
39         if (getuid() == 0) {
40                 printf("smbgroupedit options\n");
41         } else {
42                 printf("You need to be root to use this tool!\n");
43         }
44         printf("options:\n");
45         printf("  -a group             create new group\n");
46         printf("    -n group           NT group name\n");
47         printf("    -p privilege       only local\n");
48         printf("    -d description     group description\n");
49         printf("  -v                   list groups\n");
50         printf("    -l                 long list (include details)\n");
51         printf("    -s                 short list (default)\n");
52         printf("  -c SID               change group\n");
53         printf("     -u unix group\n");
54         printf("     -d description    group description\n");
55         printf("  -r rid               RID of new group\n");
56         printf("  -x group             delete this group\n");
57         printf("\n");
58         printf("    -t[b|d|l]          type: builtin, domain, local \n");
59         exit(1);
60 }
61
62 /*********************************************************
63  Figure out if the input was an NT group or a SID string.  
64  Return the SID.
65 **********************************************************/
66 static BOOL get_sid_from_input(DOM_SID *sid, char *input) 
67 {
68         GROUP_MAP map;
69         
70         if (StrnCaseCmp( input, "S-", 2)) {
71                 /* Perhaps its the NT group name? */
72                 if (!get_group_map_from_ntname(input, &map, MAPPING_WITHOUT_PRIV)) {
73                         printf("NT Group %s doesn't exist in mapping DB\n", input);
74                         return False;
75                 } else {
76                         *sid = map.sid;
77                 }
78         } else {
79                 if (!string_to_sid(sid, input)) {
80                         printf("converting sid %s from a string failed!\n", input);
81                         return False;
82                 }
83         }
84         return True;
85 }
86
87 /*********************************************************
88  add a group.
89 **********************************************************/
90 static int addgroup(gid_t gid, enum SID_NAME_USE sid_type, char *ntgroup, char *ntcomment, char *privilege, uint32 rid)
91 {
92         PRIVILEGE_SET se_priv;
93         DOM_SID sid;
94         fstring string_sid;
95         fstring comment;
96
97         sid_copy(&sid, get_global_sam_sid());
98         sid_append_rid(&sid, rid);
99         
100         sid_to_string(string_sid, &sid);
101         
102         if (ntcomment==NULL)
103                 fstrcpy(comment, "Local Unix group");
104         else
105                 fstrcpy(comment, ntcomment);
106
107         init_privilege(&se_priv);
108         if (privilege!=NULL)
109                 convert_priv_from_text(&se_priv, privilege);
110
111         if(!add_initial_entry(gid, string_sid, sid_type, ntgroup,
112                               comment, se_priv, PR_ACCESS_FROM_NETWORK)) {
113                 printf("adding entry for group %s failed!\n", ntgroup);
114                 free_privilege(&se_priv);
115                 return -1;
116         }
117
118         free_privilege(&se_priv);
119         return 0;
120 }
121
122 /*********************************************************
123  Change a group.
124 **********************************************************/
125 static int changegroup(char *sid_string, char *group, enum SID_NAME_USE sid_type, char *ntgroup, char *groupdesc, char *privilege)
126 {
127         DOM_SID sid;
128         GROUP_MAP map;
129         gid_t gid;
130
131         if (!get_sid_from_input(&sid, sid_string)) {
132                 return -1;
133         }
134
135         /* Get the current mapping from the database */
136         if(!get_group_map_from_sid(sid, &map, MAPPING_WITH_PRIV)) {
137                 printf("This SID does not exist in the database\n");
138                 return -1;
139         }
140
141         /* If a new Unix group is specified, check and change */
142         if (group!=NULL) {
143                 gid=nametogid(group);
144                 if (gid==-1) {
145                         printf("The UNIX group does not exist\n");
146                         return -1;
147                 } else
148                         map.gid=gid;
149         }
150         
151         /*
152          * Allow changing of group type only between domain and local
153          * We disallow changing Builtin groups !!! (SID problem)
154          */ 
155         if (sid_type==SID_NAME_ALIAS 
156             || sid_type==SID_NAME_DOM_GRP 
157             || sid_type==SID_NAME_UNKNOWN) {
158                 if (map.sid_name_use==SID_NAME_ALIAS 
159                     || map.sid_name_use==SID_NAME_DOM_GRP
160                     || map.sid_name_use==SID_NAME_UNKNOWN) {
161                         map.sid_name_use=sid_type;
162                 } else {
163                         printf("cannot change group type to builtin\n");
164                 };
165         } else {
166                 printf("cannot change group type from builtin\n");
167         }
168
169         if (ntgroup!=NULL)
170                 fstrcpy(map.nt_name, ntgroup);
171
172         /* Change comment if new one */
173         if (groupdesc!=NULL)
174                 fstrcpy(map.comment, groupdesc);
175
176         /* Change the privilege if new one */
177         if (privilege!=NULL)
178                 convert_priv_from_text(&map.priv_set, privilege);
179
180         if (!add_mapping_entry(&map, TDB_REPLACE)) {
181                 printf("Count not update group database\n");
182                 free_privilege(&map.priv_set);
183                 return -1;
184         }
185         
186         free_privilege(&map.priv_set);
187         return 0;
188 }
189
190 /*********************************************************
191  Delete the group.
192 **********************************************************/
193 static int deletegroup(char *group)
194 {
195         DOM_SID sid;
196
197         if (!get_sid_from_input(&sid, group)) {
198                 return -1;
199         }
200
201         if(!group_map_remove(sid)) {
202                 printf("removing group %s from the mapping db failed!\n", group);
203                 return -1;
204         }
205
206         return 0;
207 }
208
209 /*********************************************************
210  List the groups.
211 **********************************************************/
212 static int listgroup(enum SID_NAME_USE sid_type, BOOL long_list)
213 {
214         int entries,i;
215         GROUP_MAP *map=NULL;
216         fstring string_sid;
217         fstring group_type;
218         fstring priv_text;
219
220         if (!long_list)
221                 printf("NT group (SID) -> Unix group\n");
222                 
223         if (!enum_group_mapping(sid_type, &map, &entries, ENUM_ALL_MAPPED, MAPPING_WITH_PRIV))
224                 return -1;
225         
226         for (i=0; i<entries; i++) {
227                 decode_sid_name_use(group_type, (map[i]).sid_name_use);
228                 sid_to_string(string_sid, &map[i].sid);
229                 convert_priv_to_text(&(map[i].priv_set), priv_text);
230                 free_privilege(&(map[i].priv_set));
231                 
232                 if (!long_list)
233                         printf("%s (%s) -> %s\n", map[i].nt_name, string_sid, gidtoname(map[i].gid));
234                 else {
235                         printf("%s\n", map[i].nt_name);
236                         printf("\tSID       : %s\n", string_sid);
237                         printf("\tUnix group: %s\n", gidtoname(map[i].gid));
238                         printf("\tGroup type: %s\n", group_type);
239                         printf("\tComment   : %s\n", map[i].comment);
240                         printf("\tPrivilege : %s\n\n", priv_text);
241                 }
242         }
243
244         return 0;
245 }
246
247 /*********************************************************
248  Start here.
249 **********************************************************/
250 int main (int argc, char **argv)
251 {
252         int ch;
253         BOOL add_group = False;
254         BOOL view_group = False;
255         BOOL change_group = False;
256         BOOL delete_group = False;
257         BOOL nt_group = False;
258         BOOL priv = False;
259         BOOL group_type = False;
260         BOOL long_list = False;
261
262         char *group = NULL;
263         char *sid = NULL;
264         char *ntgroup = NULL;
265         char *privilege = NULL;
266         char *groupt = NULL;
267         char *group_desc = NULL;
268
269         enum SID_NAME_USE sid_type;
270         uint32 rid = -1;
271
272         setup_logging("groupedit", True);
273
274         if (argc < 2) {
275                 usage();
276                 return 0;
277         }
278         
279         if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
280                 fprintf(stderr, "Can't load %s - run testparm to debug it\n", 
281                         dyn_CONFIGFILE);
282                 exit(1);
283         }
284
285         if (!*global_myname) {
286                 char *p;
287                 pstrcpy( global_myname, myhostname() );
288                 p = strchr_m(global_myname, '.' );
289                 if (p) 
290                         *p = 0;
291         }
292
293         strupper(global_myname);
294
295         fstrcpy(global_myworkgroup, lp_workgroup());
296         
297         if(!initialize_password_db(True)) {
298                 fprintf(stderr, "Can't setup password database vectors.\n");
299                 exit(1);
300         }
301         
302         if(get_global_sam_sid()==False) {
303                 fprintf(stderr, "Can not read machine SID\n");
304                 return 0;
305         }
306
307         while ((ch = getopt(argc, argv, "a:c:d:ln:p:r:st:u:vx:")) != EOF) {
308                 switch(ch) {
309                 case 'a':
310                         add_group = True;
311                         group=optarg;
312                         break;
313                 case 'c':
314                         change_group = True;
315                         sid=optarg;
316                         break;
317                 case 'd':
318                         group_desc=optarg;
319                         break;
320                 case 'l':
321                         long_list = True;
322                         break;
323                 case 'n':
324                         nt_group = True;
325                         ntgroup=optarg;
326                         break;
327                 case 'p':
328                         priv = True;
329                         privilege=optarg;
330                         break;
331                 case 'r':
332                         rid = atoi(optarg);
333                         break;
334                 case 's':
335                         long_list = False;
336                         break;
337                 case 't':
338                         group_type = True;
339                         groupt=optarg;
340                         break;
341                 case 'u':
342                         group=optarg;
343                         break;
344                 case 'v':
345                         view_group = True;
346                         break;
347                 case 'x':
348                         delete_group = True;
349                         group=optarg;
350                         break;
351                 /*default:
352                         usage();*/
353                 }
354         }
355         
356         
357         if (((add_group?1:0) + (view_group?1:0) + (change_group?1:0) + (delete_group?1:0)) > 1) {
358                 fprintf (stderr, "Incompatible options on command line!\n");
359                 usage();
360                 exit(1);
361         }
362
363         /* no option on command line -> list groups */  
364         if (((add_group?1:0) + (view_group?1:0) + (change_group?1:0) + (delete_group?1:0)) == 0)
365                 view_group = True;
366
367         
368         if (group_type==False)
369                 sid_type=SID_NAME_UNKNOWN;
370         else {
371                 switch (groupt[0]) {
372                         case 'l':
373                         case 'L':
374                                 sid_type=SID_NAME_ALIAS;
375                                 break;
376                         case 'd':
377                         case 'D':
378                                 sid_type=SID_NAME_DOM_GRP;
379                                 break;
380                         case 'b':
381                         case 'B':
382                                 sid_type=SID_NAME_WKN_GRP;
383                                 break;
384                         default:
385                                 sid_type=SID_NAME_UNKNOWN;
386                                 break;
387                 }
388         }
389
390         if (add_group) {
391                 gid_t gid=nametogid(group);
392                 if (gid==-1) {
393                         printf("unix group %s doesn't exist!\n", group);
394                         return -1;
395                 }
396
397                 if (rid == -1) {
398                         rid = pdb_gid_to_group_rid(gid);
399                 }
400                 return addgroup(gid, sid_type, ntgroup?ntgroup:group,
401                                 group_desc, privilege, rid);
402         }
403
404         if (view_group)
405                 return listgroup(sid_type, long_list);
406
407         if (delete_group)
408                 return deletegroup(group);
409         
410         if (change_group) {             
411                 return changegroup(sid, group, sid_type, ntgroup, group_desc, privilege);
412         }
413         
414         usage();
415
416         return 0;
417 }