Standardize License information
[openafs.git] / src / ptserver / pts.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #ifndef lint
11 #endif
12 #include <afs/param.h>
13 #include <stdio.h>
14 #include <string.h>
15 #ifdef  AFS_AIX32_ENV
16 #include <signal.h>
17 #endif
18 #include <ctype.h>
19 #include <sys/types.h>
20 #include <errno.h>
21 #include <afs/cmd.h>
22 #ifdef AFS_NT40_ENV
23 #include <winsock2.h>
24 #include <WINNT/afsevent.h>
25 #else
26 #include <netinet/in.h>
27 #endif
28 #include <afs/cellconfig.h>
29 #include <rx/rx.h>
30 #include <rx/xdr.h>
31 #include "ptclient.h"
32 #include "pterror.h"
33 #include <afs/afsutil.h>
34
35 #undef FOREIGN
36
37 char *whoami;
38 int force = 0;
39
40
41 int osi_audit()
42 {
43 /* OK, this REALLY sucks bigtime, but I can't tell who is calling
44  * afsconf_CheckAuth easily, and only *SERVERS* should be calling osi_audit
45  * anyway.  It's gonna give somebody fits to debug, I know, I know.
46  */
47 return 0;
48 }
49
50 int GetGlobals (as)
51   register struct cmd_syndesc *as;
52 {
53     register afs_int32 code;
54     char *cell;
55     afs_int32 sec = 1;
56
57     whoami = as->a0name;
58
59     if (!strcmp(as->name,"help")) return 0;
60     if (as->parms[16].items) 
61         cell = as->parms[16].items->data;
62     else cell = 0;
63     if (as->parms[17].items)
64         sec = 0;
65     
66     if (as->parms[18].items) {          /* testing? */
67         code = pr_Initialize(sec, AFSDIR_SERVER_ETC_DIRPATH, cell);
68     }
69     else {
70         code = pr_Initialize(sec, AFSDIR_CLIENT_ETC_DIRPATH, cell);
71     }
72     if (code) {
73         com_err (whoami, code, "Couldn't initialize");
74         return code;
75     }
76     if (as->parms[19].items)
77         force = 1;
78     return code;
79 }
80
81 void CleanUp (as)
82   register struct cmd_syndesc *as;
83 {
84     if (!strcmp(as->name,"help")) return;
85     /* Need to shutdown the ubik_client & other connections */
86     pr_End();
87     rx_Finalize();
88 }
89
90 CreateGroup (as)
91   register struct cmd_syndesc *as;
92 {
93     register afs_int32 code;
94     afs_int32 id;
95     char *owner;
96     struct cmd_item *namei;
97     struct cmd_item *idi;
98
99     namei = as->parms[0].items;
100     idi = as->parms[2].items;
101     if (as->parms[1].items)
102         owner = as->parms[1].items->data;
103     else owner = NULL;
104
105     while (namei) {
106         if (idi) {
107             code = util_GetInt32 (idi->data, &id);
108             if (code) {
109                 com_err (whoami, code,
110                          "because group id was: '%s'", idi->data);
111                 return code;
112             }
113             if (id >= 0) {
114                 code = PRBADARG;
115                 com_err (whoami, code,
116                          "because group id %d was not negative", id);
117                 return code;
118             }
119             idi = idi->next;
120         } else id = 0;
121
122         code = pr_CreateGroup (namei->data, owner, &id);
123         if (code) {
124             if (owner || id) 
125                 com_err (whoami, code,
126                          "; unable to create group %s with id %d owned by '%s' %s",
127                          namei->data, id, owner, (force?"(ignored)":""));
128             else com_err (whoami, code,
129                          "; unable to create group %s %s", namei->data, (force?"(ignored)":""));
130             if (!force)
131                 return code;
132         }
133         printf ("group %s has id %d\n", namei->data, id);
134         namei = namei->next;
135     }
136     return 0;
137 }
138
139 CreateUser (as)
140   register struct cmd_syndesc *as;
141 {
142     register afs_int32 code;
143     afs_int32 id;
144     struct cmd_item *namei;
145     struct cmd_item *idi;
146
147     namei = as->parms[0].items;
148     idi = as->parms[1].items;
149
150     while (namei) {
151         if (idi) {
152             code = util_GetInt32 (idi->data, &id);
153             if (code) {
154                 com_err (whoami, code, "because id was: '%s'", idi->data);
155                 return code;
156             }
157             if (id == 0) {
158                 printf ("0 isn't a valid user id; aborting\n");
159                 return EINVAL;
160             }
161             idi = idi->next;
162         } else id = 0;
163
164         code = pr_CreateUser (namei->data, &id);
165         if (code) {
166             if (id) com_err (whoami, code,
167                              "; unable to create user %s with id %d %s",
168                              namei->data, id, (force?"(ignored)":""));
169             else com_err (whoami, code,
170                           "; unable to create user %s %s", namei->data, (force?"(ignored)":""));
171             if (!force)
172                 return code;
173         }
174         printf ("User %s has id %d\n", namei->data, id);
175         namei = namei->next;
176     }
177     return 0;
178 }
179
180
181 #ifdef notdef
182 int GetNameOrId (as, lids, lnames)
183   register struct cmd_syndesc *as;
184   struct idlist *lids;
185   struct namelist *lnames;
186 {
187     register afs_int32 code = 0;
188     int n = 0;
189     struct cmd_item *i;
190     int goodCount;
191
192     if (!(as->parms[0].items || as->parms[1].items)) {
193         com_err (whoami, 0, "must specify either a name or an id.");
194         return -1;
195     }
196     if (as->parms[0].items && as->parms[1].items) {
197         com_err (whoami, 0, "can't specify both a name and id.");
198         return -1;
199     }
200
201     goodCount = 0;
202     lids->idlist_len = 0;
203     lids->idlist_val = 0;
204
205     if (as->parms[0].items) {           /* name */
206         struct namelist names;          /* local copy, if not ret. names */
207         struct namelist *nl;
208
209         names.namelist_val = 0;         /* so it gets freed later if needed */
210         if (lnames) nl = lnames;
211         else nl = &names;
212
213         n = 0;                          /* count names */
214         for (i=as->parms[0].items; i; i=i->next) n++;
215         nl->namelist_val = (prname *)malloc(n*PR_MAXNAMELEN);
216         nl->namelist_len = n;
217         n = 0;
218         for (i=as->parms[0].items; i; i=i->next)
219             strncpy (nl->namelist_val[n++], i->data, PR_MAXNAMELEN);
220
221         code = pr_NameToId (nl, lids);
222         if (code) com_err (whoami, code, "so couldn't look up names");
223         else {
224             for (n=0; n<lids->idlist_len; n++) {
225                 if ((lids->idlist_val[n] == ANONYMOUSID)) {
226                     com_err (whoami, PRNOENT,
227                              "so couldn't look up id for %s", nl->namelist_val[n]);
228                 }
229                 else goodCount++;
230             }
231             /* treat things as working if any of the lookups worked */
232             if (goodCount==0) code = PRNOENT;
233         }
234         
235         if (names.namelist_val) free (names.namelist_val);
236     }
237     else if (as->parms[1].items) {      /* id */
238         n = 0;
239         for (i=as->parms[1].items; i; i=i->next) n++;
240         lids->idlist_val = (afs_int32 *)malloc(n*sizeof(afs_int32));
241         lids->idlist_len = n;
242         n = 0;
243         for (i=as->parms[1].items; i; i=i->next) {
244             code = util_GetInt32 (i->data, &lids->idlist_val[n]);
245             if (code)
246                 com_err (whoami, code=PRNOENT,
247                          "because a bogus id '%s' was specified", i->data);
248             n++;
249         }
250         if (!code && lnames) {
251             lnames->namelist_val = 0;
252             lnames->namelist_len = 0;
253             code = pr_IdToName (lids, lnames);
254             if (code) com_err (whoami, code, "translating ids");
255         }
256     }
257     if (code) {
258         if (lids->idlist_val) free (lids->idlist_val);
259         return -1;
260     }
261     return 0;
262 }
263 #endif
264
265
266 int GetNameOrId (as, lids, lnames)
267   register struct cmd_syndesc *as;
268   struct idlist *lids;
269   struct namelist *lnames;
270 {
271     register afs_int32 code = 0;
272     int n = 0, nd = 0, nm = 0, id, x;
273     struct cmd_item *i;
274     struct namelist names, tnames;      /* local copy, if not ret. names */
275     struct idlist ids, tids;            /* local copy, if not ret. ids */
276     int goodCount = 0;
277
278     for (i = as->parms[0].items; i; i = i->next) n++;
279     lids->idlist_val = (afs_int32 *)malloc(n*sizeof(afs_int32));
280     lids->idlist_len = n;
281     ids.idlist_val = (afs_int32 *)malloc(n*sizeof(afs_int32));
282     ids.idlist_len = n;
283     names.namelist_val = (prname *)malloc(n*PR_MAXNAMELEN);
284     names.namelist_len = n;
285     if (lnames) {
286         lnames->namelist_val = (prname *)malloc(n*PR_MAXNAMELEN);
287         lnames->namelist_len = 0;
288     }
289     for (i=as->parms[0].items; i; i=i->next) {
290         tnames.namelist_val = (prname *)malloc(PR_MAXNAMELEN);
291         strncpy (tnames.namelist_val[0], i->data, PR_MAXNAMELEN);           
292         tnames.namelist_len = 1;
293         tids.idlist_len =  0;
294         tids.idlist_val = 0;
295         code = pr_NameToId(&tnames, &tids);
296         if ((!code && (tids.idlist_val[0] != 32766)) || (code = util_GetInt32 (i->data, &id))) {
297             /* Assume it's a name instead */
298             strncpy (names.namelist_val[nm++], i->data, PR_MAXNAMELEN);     
299         } else {
300             ids.idlist_val[nd++] = id;
301         }
302         free(tnames.namelist_val);
303     }
304     names.namelist_len = nm;
305     ids.idlist_len = nd;
306     tids.idlist_len = nd = nm = 0;
307     tids.idlist_val = 0;
308     code = pr_NameToId (&names, &tids);
309     if (code) com_err (whoami, code, "so couldn't look up names");
310     else {
311         for (n=0; n < tids.idlist_len; n++) {
312             if ((tids.idlist_val[n] == ANONYMOUSID)) {
313                 com_err (whoami, PRNOENT,
314                          "so couldn't look up id for %s", names.namelist_val[n]);
315             } else 
316                 goodCount++;
317             lids->idlist_val[nd] = tids.idlist_val[n];
318             if (lnames)
319                 strcpy(lnames->namelist_val[nd], names.namelist_val[n]);            
320             nd++;
321         }
322     }
323     for (x=0; x < ids.idlist_len; x++) {
324         lids->idlist_val[nd+x] = ids.idlist_val[x];
325     }
326     lids->idlist_len = nd+x;    
327     if (!code && lnames) {
328         tnames.namelist_val = 0;
329         tnames.namelist_len = 0;
330         code = pr_IdToName (&ids, &tnames);
331         if (code) com_err (whoami, code, "translating ids");
332         else goodCount++;
333         if (lnames) {
334             for (x=0; x < ids.idlist_len; x++)
335                 strcpy(lnames->namelist_val[nd+x], tnames.namelist_val[x]);         
336             lnames->namelist_len = nd+x;
337         }
338     }
339     /* treat things as working if any of the lookups worked */
340     if (goodCount==0) code = PRNOENT;
341     if (code) {
342         if (lids->idlist_val) free (lids->idlist_val);
343         return -1;
344     }
345     return 0;
346 }
347
348
349 AddToGroup(as)
350   register struct cmd_syndesc *as;
351 {
352     register afs_int32 code;
353     struct cmd_item *u, *g;
354
355     for (u=as->parms[0].items; u; u=u->next) {
356         for (g=as->parms[1].items; g; g=g->next) {
357             code = pr_AddToGroup (u->data, g->data);
358             if (code) {
359                 com_err (whoami, code,
360                          "; unable to add user %s to group %s %s",
361                          u->data, g->data, (force?"(ignored)":""));
362                 if (!force)
363                     return code;
364             }
365         }
366     }
367     return 0;
368 }
369
370 RemoveFromGroup (as)
371   register struct cmd_syndesc *as;
372 {
373     register afs_int32 code;
374     struct cmd_item *u, *g;
375
376     for (u=as->parms[0].items; u; u=u->next) {
377         for (g=as->parms[1].items; g; g=g->next) {
378             code = pr_RemoveUserFromGroup (u->data, g->data);
379             if (code) {
380                 com_err (whoami, code,
381                          "; unable to remove user %s from group %s %s",
382                          u->data, g->data, (force?"(ignored)":""));
383                 if (!force)
384                     return code;
385             }
386         }
387     }
388     return 0;
389 }
390
391 ListMembership (as)
392   register struct cmd_syndesc *as;
393 {
394     register afs_int32 code;
395     idlist ids;
396     namelist names;
397     int i;
398     namelist list;
399     int j;
400
401     if (GetNameOrId(as, &ids, &names)) return PRBADARG;
402
403     for (i=0; i<ids.idlist_len; i++) {
404         afs_int32 id = ids.idlist_val[i];
405         char *name = names.namelist_val[i];
406
407         if (id == ANONYMOUSID) continue;        /* bad entry */
408
409         list.namelist_val = 0;
410         list.namelist_len = 0;
411         code = pr_IDListMembers(ids.idlist_val[i],&list);
412         if (code) {
413             com_err (whoami, code,
414                      "; unable to get membership of %s (id: %d)", name, id);
415             continue;
416         }
417         if (id < 0) printf ("Members of %s (id: %d) are:\n", name, id);
418         else printf ("Groups %s (id: %d) is a member of:\n", name, id);
419
420         for (j=0; j<list.namelist_len; j++)
421             printf("  %s\n", list.namelist_val[j]);
422         if (list.namelist_val) free (list.namelist_val);
423     }
424     if (ids.idlist_val) free (ids.idlist_val);
425     if (names.namelist_val) free (names.namelist_val);
426     return 0;
427 }
428
429 Delete (as)
430   register struct cmd_syndesc *as;
431 {
432     register afs_int32 code;
433     idlist ids;
434     namelist names;
435     int i;
436
437     if (GetNameOrId (as, &ids, &names)) return PRBADARG;
438
439     for (i=0; i<ids.idlist_len; i++) {
440         afs_int32 id = ids.idlist_val[i];
441         char *name = names.namelist_val[i];
442
443         if (id == ANONYMOUSID) continue;
444
445         code = pr_DeleteByID (id);
446         if (code) {
447             com_err (whoami, code, "deleting %s (id: %d) %s", name, id, (force?"(ignored)":""));
448             if (!force)
449                 return code;
450         }
451     }
452     if (ids.idlist_val) free (ids.idlist_val);
453     if (names.namelist_val) free (names.namelist_val);
454     return 0;
455 }
456
457 /* access bit translation info */
458
459 char *flags_upcase = "SOMA ";           /* legal all access values */
460 char *flags_dncase = "s mar";           /* legal member acces values */
461 int   flags_shift[5] = {2,1,2,2,1};     /* bits for each */
462
463 CheckEntry (as)
464   register struct cmd_syndesc *as;
465 {
466     register afs_int32 code;
467     afs_int32 rcode = 1;
468     int i, flag = 0, admin = 0;
469     namelist lnames, names;
470     idlist ids;
471     idlist lids;
472     struct prcheckentry aentry;
473
474     if (GetNameOrId (as, &ids, &names)) return PRBADARG;
475
476     lids.idlist_len = 2;
477     lids.idlist_val = (afs_int32 *)malloc(sizeof(afs_int32)*2);
478     lnames.namelist_len = 0;
479     lnames.namelist_val = 0;
480
481     for (i=0; i<ids.idlist_len; i++) {
482         afs_int32 id = ids.idlist_val[i];
483
484         if (id == ANONYMOUSID) continue;
485
486         rcode = 0;
487         code = pr_ListEntry (id, &aentry);
488         if (code) {
489             rcode = code;
490             com_err (whoami, code, "; unable to find entry for (id: %d)", id);
491             continue;
492         }
493
494         lids.idlist_val[0] = aentry.owner;
495         lids.idlist_val[1] = aentry.creator;
496         code = pr_IdToName (&lids, &lnames);
497         if (code) {
498             rcode = code;
499             com_err (whoami, code,
500                      "translating owner (%d) and creator (%d) ids",
501                      aentry.owner, aentry.creator);
502             continue;
503         }
504         printf("Name: %s, id: %d, owner: %s, creator: %s,\n",
505                aentry.name, aentry.id,
506                lnames.namelist_val[0], lnames.namelist_val[1]);
507         printf ("  membership: %d", aentry.count);
508         {   char access[6];
509             afs_int32 flags = aentry.flags;
510             int  j, s, new;
511             char c;
512             access[5] = 0;      /* null-terminate the string */
513             for (j=4; j>=0; j--) {
514                 s = flags_shift[j];
515                 if (s == 1) new = flags & 1;
516                 else new = flags & 3;
517                 if (new == 0) c = '-';
518                 else if (new == 1) {
519                     c = flags_dncase[j];
520                     if (c == ' ') c = flags_upcase[j];
521                 } else if (new == 2) c = flags_upcase[j];
522                 else c = 'X';
523                 access[j] = c;
524                 flags >>= s;
525             }
526             printf(", flags: %s", access);
527         }
528         if (aentry.id == SYSADMINID) 
529             admin = 1;
530         else if (!pr_IsAMemberOf (aentry.name, "system:administrators", &flag)) {
531             if (flag)
532                 admin = 1;
533         }
534         if (admin)
535             printf (", group quota: unlimited");                    
536         else
537             printf (", group quota: %d", aentry.ngroups);
538 #if FOREIGN
539         printf (", foreign user quota=%d", aentry.nusers);
540 #endif
541         printf (".\n");
542     }
543
544   done:
545     if (lnames.namelist_val) free(lnames.namelist_val);
546     if (lids.idlist_val) free(lids.idlist_val);
547     if (ids.idlist_val) free(ids.idlist_val);
548
549     return(rcode);
550 }
551
552 ListEntries (as)
553   struct cmd_syndesc *as;
554 {
555   afs_int32 code=0;
556   afs_int32 flag, startindex, nentries, nextstartindex;
557   struct prlistentries *entriesp=0, *e;
558   afs_int32 i;
559
560   flag = PRUSERS;
561   if (as->parms[1].items) flag  = PRGROUPS;
562   if (as->parms[0].items) flag |= PRUSERS;
563   
564   printf("Name                          ID  Owner Creator\n");
565   for (startindex = 0; startindex!=-1; startindex=nextstartindex) {
566      code = pr_ListEntries(flag, startindex, &nentries, &entriesp, &nextstartindex);
567      if (code) {
568         com_err (whoami, code, "; unable to list entries\n");
569         if (entriesp) free(entriesp);
570         break;
571      }
572
573      /* Now display each of the entries we read */
574      for (i=0,e=entriesp; i<nentries; i++,e++) {
575         printf("%-25s %6d %6d %7d \n", e->name, e->id, e->owner, e->creator);
576      }
577      if (entriesp) free(entriesp);
578   }
579   return code;
580 }
581
582 ChownGroup (as)
583   register struct cmd_syndesc *as;
584 {
585     register afs_int32 code;
586     char *name;
587     char *owner;
588
589     name = as->parms[0].items->data;
590     owner = as->parms[1].items->data;
591     code = pr_ChangeEntry (name, "", 0, owner);
592     if (code) com_err (whoami, code,
593                        "; unable to change owner of %s to %s", name, owner);
594     return code;
595 }
596
597 ChangeName (as)
598   register struct cmd_syndesc *as;
599 {
600     register afs_int32 code;
601     char *oldname;
602     char *newname;
603
604     oldname = as->parms[0].items->data;
605     newname = as->parms[1].items->data;
606     code = pr_ChangeEntry (oldname, newname, 0, "");
607     if (code) com_err (whoami, code,
608                        "; unable to change name of %s to %s",
609                        oldname, newname);
610     return code;
611 }
612
613 ListMax (as)
614   register struct cmd_syndesc *as;
615 {
616     register afs_int32 code;
617     afs_int32 maxUser, maxGroup;
618
619     code = pr_ListMaxUserId (&maxUser);
620     if (code) 
621         com_err (whoami, code, "getting maximum user id");
622     else {
623         code = pr_ListMaxGroupId (&maxGroup);
624         if (code) com_err (whoami, code, "getting maximum group id");
625         else {
626             printf("Max user id is %d and max group id is %d.\n",
627                    maxUser, maxGroup);      
628         }
629     }
630     return code;
631 }
632
633 SetMax (as)
634   register struct cmd_syndesc *as;
635 {
636     register afs_int32 code;
637     afs_int32 maxid;
638
639     code = 0;
640     if (as->parms[1].items) {
641         /* set user max */
642         code = util_GetInt32 (as->parms[1].items->data, &maxid);
643         if (code) {
644             com_err (whoami, code,
645                      "because id was: '%s'", as->parms[1].items->data);
646         }
647         else {
648             code = pr_SetMaxUserId (maxid);
649             if (code)
650                 com_err (whoami, code,
651                          "so couldn't set Max User Id to %d", maxid);
652         }
653     }
654     if (as->parms[0].items) {
655         /* set group max */
656         code = util_GetInt32 (as->parms[0].items->data, &maxid);
657         if (code) {
658             com_err (whoami, code,
659                      "because id was: '%s'", as->parms[0].items->data);
660         }
661         else {
662             code = pr_SetMaxGroupId (maxid);
663             if (code)
664                 com_err (whoami, code,
665                          "so couldn't set Max Group Id to %d", maxid);
666         }
667     }
668     if (!as->parms[0].items && !as->parms[1].items) {
669         code = PRBADARG;
670         printf("Must specify at least one of group or user.\n");
671     }
672     return code;
673 }
674
675 SetFields (as)
676   register struct cmd_syndesc *as;
677 {
678     register afs_int32 code;
679     idlist ids;
680     namelist names;
681     int i;
682     afs_int32 mask, flags, ngroups, nusers;
683
684     if (GetNameOrId (as, &ids, &names)) return PRBADARG;
685
686     mask = 0;
687     nusers = 0;
688     if (as->parms[1].items) {           /* privacy bits */
689         char *access = as->parms[1].items->data;
690         int   new;
691
692         if (strpbrk (access, "76543210") != 0) { /* all octal digits */
693             sscanf (access, "%lo", &flags);
694         } else {                        /* interpret flag bit names */
695             if (strlen(access) != 5) {
696               form_error:
697                 printf ("Access bits must be of the form 'somar', not %s\n", access);
698                 return PRBADARG;
699             }
700             if (strpbrk(access, "somar-") == 0) goto form_error;
701             flags = 0;
702             for (i=0; i<5; i++) {
703                 if (access[i] == flags_upcase[i]) new = 2;
704                 else if (access[i] == flags_dncase[i]) new = 1;
705                 else if (access[i] == '-') new = 0;
706                 else {
707                     printf ("Access bits out of order or illegal:\n  must be a combination of letters from '%s' or '%s' or hyphen, not %s\n", flags_upcase, flags_dncase, access);
708                     return PRBADARG;
709                 }
710                 flags <<= flags_shift[i];
711                 if (flags_shift[i] == 1) {
712                     if (new) flags |= 1;
713                 }
714                 else flags |= new;
715             }
716         }
717         mask |= PR_SF_ALLBITS;
718     }
719     if (as->parms[2].items) {           /* limitgroups */
720         code = util_GetInt32 (as->parms[2].items->data, &ngroups);
721         if (code) {
722             com_err (whoami, code, "because ngroups was: '%s'",
723                      as->parms[2].items->data);
724             return code;
725         }
726         mask |= PR_SF_NGROUPS;
727     }
728 #if FOREIGN
729     if (as->parms[3].items) {           /* limitgroups */
730         code = util_GetInt32 (as->parms[3].items->data, &nusers);
731         if (code) {
732             com_err (whoami, code, "because nusers was: '%s'",
733                      as->parms[3].items->data);
734             return code;
735         }
736         mask |= PR_SF_NUSERS;
737     }
738 #endif
739
740     for (i=0; i<ids.idlist_len; i++) {
741         afs_int32 id = ids.idlist_val[i];
742         char *name = names.namelist_val[i];
743         if (id == ANONYMOUSID) continue;
744         code = pr_SetFieldsEntry (id, mask, flags, ngroups, nusers);
745         if (code) {
746             com_err (whoami, code,
747                      "; unable to set fields for %s (id: %d)", name, id);
748             return code;
749         }
750     }
751     if (ids.idlist_val) free (ids.idlist_val);
752     if (names.namelist_val) free (names.namelist_val);
753     return 0;
754 }           
755
756 ListOwned (as)
757   register struct cmd_syndesc *as;
758 {   register afs_int32 code;
759     idlist ids;
760     namelist names;
761     namelist list;
762     int i,j;
763     afs_int32 more;
764
765     if (GetNameOrId (as, &ids, &names)) return PRBADARG;
766
767     for (i=0; i<ids.idlist_len; i++) {
768         afs_int32 oid = ids.idlist_val[i];
769         char *name = names.namelist_val[i];
770
771         if (oid == ANONYMOUSID) continue;
772
773         if (oid) printf("Groups owned by %s (id: %d) are:\n", name, oid);
774         else printf ("Orphaned groups are:\n");
775         more = 0;
776         do {
777            list.namelist_val = 0;
778            list.namelist_len = 0;
779            code = pr_ListOwned(oid, &list, &more);
780            if (code) {
781               com_err (whoami, code,
782                        "; unable to get owner list for %s (id: %d)",
783                        name, oid);
784               break;
785            }
786
787            for (j=0; j<list.namelist_len; j++)
788               printf ("  %s\n", list.namelist_val[j]);
789            if (list.namelist_val) free(list.namelist_val);
790         } while (more);
791     }
792
793     if (ids.idlist_val) free (ids.idlist_val);
794     if (names.namelist_val) free (names.namelist_val);
795     return 0;
796 }
797
798 static void add_std_args (ts)
799   register struct cmd_syndesc *ts;
800 {
801     char test_help[AFSDIR_PATH_MAX];
802
803     sprintf(test_help, "use config file in %s", AFSDIR_SERVER_ETC_DIRPATH);
804
805     cmd_Seek(ts,16);
806     cmd_AddParm(ts,"-cell",CMD_SINGLE,CMD_OPTIONAL,"cell name");
807     cmd_AddParm(ts,"-noauth",CMD_FLAG,CMD_OPTIONAL,"run unauthenticated");
808     cmd_AddParm(ts,"-test", CMD_FLAG,CMD_OPTIONAL|CMD_HIDE, test_help);
809     cmd_AddParm(ts,"-force",CMD_FLAG,CMD_OPTIONAL,"Continue oper despite reasonable errors");
810 }
811
812 /*
813 static void add_NameOrId_args (ts)
814   register struct cmd_syndesc *ts;
815 {
816     cmd_AddParm(ts,"-name",CMD_LIST,CMD_OPTIONAL,"user or group name");
817     cmd_AddParm(ts,"-id",CMD_LIST,CMD_OPTIONAL,"user or group id");
818 }
819 */
820
821 #include "AFS_component_version_number.c"
822
823 int main (argc, argv)
824   int argc;
825   char **argv;
826 {
827     register afs_int32 code;
828     register struct cmd_syndesc *ts;
829
830 #ifdef  AFS_AIX32_ENV
831     /*
832      * The following signal action for AIX is necessary so that in case of a 
833      * crash (i.e. core is generated) we can include the user's data section 
834      * in the core dump. Unfortunately, by default, only a partial core is
835      * generated which, in many cases, isn't too useful.
836      */
837     struct sigaction nsa;
838     
839     sigemptyset(&nsa.sa_mask);
840     nsa.sa_handler = SIG_DFL;
841     nsa.sa_flags = SA_FULLDUMP;
842     sigaction(SIGSEGV, &nsa, NULL);
843 #endif
844
845     ts = cmd_CreateSyntax("creategroup",CreateGroup,0,"create a new group");
846     cmd_AddParm(ts,"-name",CMD_LIST,0,"group name");
847     cmd_AddParm(ts,"-owner",CMD_SINGLE,CMD_OPTIONAL,"owner of the group");
848     cmd_AddParm(ts,"-id",CMD_LIST,CMD_OPTIONAL,"id (negated) for the group");
849     add_std_args (ts);
850     cmd_CreateAlias(ts,"cg");
851
852     ts = cmd_CreateSyntax("createuser",CreateUser,0,"create a new user");
853     cmd_AddParm(ts,"-name",CMD_LIST,0,"user name");
854     cmd_AddParm(ts,"-id",CMD_LIST,CMD_OPTIONAL,"user id");
855     add_std_args (ts);
856     cmd_CreateAlias(ts,"cu");
857
858     ts = cmd_CreateSyntax("adduser",AddToGroup,0,"add a user to a group");
859     cmd_AddParm(ts, "-user",CMD_LIST,0,"user name");
860     cmd_AddParm(ts, "-group",CMD_LIST,0,"group name");
861     add_std_args (ts);
862
863     ts = cmd_CreateSyntax("removeuser",RemoveFromGroup,0,
864                           "remove a user from a group");
865     cmd_AddParm(ts,"-user",CMD_LIST,0,"user name");
866     cmd_AddParm(ts,"-group",CMD_LIST,0,"group name");
867     add_std_args (ts);
868
869     ts = cmd_CreateSyntax ("membership",ListMembership, 0,
870                            "list membership of a user or group");
871     cmd_AddParm(ts,"-nameorid",CMD_LIST,0,"user or group name or id");
872     add_std_args (ts);
873     cmd_CreateAlias(ts,"groups");
874
875     ts = cmd_CreateSyntax ("delete", Delete, 0,
876                            "delete a user or group from database");
877     cmd_AddParm(ts,"-nameorid",CMD_LIST,0,"user or group name or id");
878     add_std_args (ts);
879
880     ts = cmd_CreateSyntax ("examine", CheckEntry, 0, "examine an entry");
881     cmd_AddParm(ts,"-nameorid",CMD_LIST,0,"user or group name or id");
882     add_std_args (ts);
883     cmd_CreateAlias (ts, "check");
884
885     ts = cmd_CreateSyntax("chown",ChownGroup,0,"change ownership of a group");
886     cmd_AddParm(ts,"-name",CMD_SINGLE,0,"group name");
887     cmd_AddParm(ts,"-owner",CMD_SINGLE,0,"new owner");
888     add_std_args (ts);
889
890     ts = cmd_CreateSyntax("rename",ChangeName,0,"rename user or group");
891     cmd_AddParm(ts,"-oldname",CMD_SINGLE,0,"old name");
892     cmd_AddParm(ts,"-newname",CMD_SINGLE,0,"new name");
893     add_std_args (ts);
894     cmd_CreateAlias(ts, "chname");
895
896     ts = cmd_CreateSyntax("listmax",ListMax,0,"list max id");
897     add_std_args (ts);
898
899     ts = cmd_CreateSyntax("setmax",SetMax,0,"set max id");
900     cmd_AddParm(ts,"-group",CMD_SINGLE,CMD_OPTIONAL,"group max");
901     cmd_AddParm(ts,"-user",CMD_SINGLE,CMD_OPTIONAL,"user max");
902     add_std_args (ts);
903
904     ts = cmd_CreateSyntax("setfields",SetFields,0,"set fields for an entry");
905     cmd_AddParm(ts,"-nameorid",CMD_LIST,0,"user or group name or id");
906     cmd_AddParm (ts, "-access", CMD_SINGLE, CMD_OPTIONAL,
907                  "set privacy flags"); 
908     cmd_AddParm (ts, "-groupquota", CMD_SINGLE, CMD_OPTIONAL,
909                  "set limit on group creation"); 
910 #if FOREIGN
911     cmd_AddParm (ts, "-userquota", CMD_SINGLE, CMD_OPTIONAL,
912                  "set limit on foreign user creation"); 
913 #endif
914     add_std_args (ts);
915
916     ts = cmd_CreateSyntax
917         ("listowned", ListOwned, 0,
918          "list groups owned by an entry or zero id gets orphaned groups");
919     cmd_AddParm(ts,"-nameorid",CMD_LIST,0,"user or group name or id");
920     add_std_args (ts);
921     
922     ts = cmd_CreateSyntax
923         ("listentries", ListEntries, 0,
924          "list users/groups in the protection database");
925     cmd_AddParm(ts, "-users",  CMD_FLAG, CMD_OPTIONAL, "list user entries");
926     cmd_AddParm(ts, "-groups", CMD_FLAG, CMD_OPTIONAL, "list group entries");
927     add_std_args (ts);
928     
929     cmd_SetBeforeProc(GetGlobals,0);
930     cmd_SetAfterProc(CleanUp,0);
931     code = cmd_Dispatch(argc,argv);
932     exit (code != 0);
933 }
934