joe-beuhler-patches-20031122
[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 /*
11  *                      (3) add new pts commands:
12  *
13  *                          Interactive - allow the pts command
14  *                                        to be run interactively.
15  *                          Quit        - quit interactive mode.
16  *                          Source      - allow input to come from a file(s).
17  *                          Sleep       - pause for a specified number
18  *                                        of seconds.
19  *
20  */
21
22 #include <afsconfig.h>
23 #include <afs/param.h>
24
25 RCSID
26     ("$Header$");
27
28 #include <stdio.h>
29 #include <string.h>
30 #ifdef  AFS_AIX32_ENV
31 #include <signal.h>
32 #endif
33 #include <ctype.h>
34 #include <sys/types.h>
35 #include <errno.h>
36 #include <afs/cmd.h>
37 #ifdef AFS_NT40_ENV
38 #include <winsock2.h>
39 #include <WINNT/afsevent.h>
40 #else
41 #include <netinet/in.h>
42 #endif
43 #include <afs/cellconfig.h>
44 #include <rx/rx.h>
45 #include <rx/xdr.h>
46 #include "ptclient.h"
47 #include "pterror.h"
48 #include <afs/afsutil.h>
49
50 #undef FOREIGN
51
52 char *whoami;
53 int force = 0;
54
55 #if defined(SUPERGROUPS)
56
57 /*
58  *  Add new pts commands:
59  *
60  *      Interactive - allow the pts command to be run interactively.
61  *      Quit        - quit interactive mode.
62  *      Source      - allow input to come from a file(s).
63  *      Sleep       - pause for a specified number of seconds.
64  */
65
66 static int finished;
67 static FILE *source;
68 extern struct ubik_client *pruclient;
69
70 struct sourcestack {
71     struct sourcestack *s_next;
72     FILE *s_file;
73 } *shead;
74
75 int
76 Interactive(as)
77      register struct cmd_syndesc *as;
78 {
79     finished = 0;
80     return 0;
81 }
82
83 int
84 Quit(as)
85      register struct cmd_syndesc *as;
86 {
87     finished = 1;
88     return 0;
89 }
90
91 int
92 Source(as)
93      register struct cmd_syndesc *as;
94 {
95     FILE *fd;
96     struct sourcestack *sp;
97
98     finished = 0;
99     if (!as->parms[0].items) {
100 /* can this happen? */
101         return 1;
102     }
103     fd = fopen(as->parms[0].items->data, "r");
104     if (!fd) {
105         perror(as->parms[0].items->data);
106         return errno;
107     }
108     sp = (struct sourcestack *)malloc(sizeof *sp);
109     if (!sp) {
110         return errno ? errno : ENOMEM;
111     } else {
112         sp->s_next = shead;
113         sp->s_file = source;
114         shead = sp;
115         source = fd;
116     }
117     return 0;
118 }
119
120 int
121 Sleep(as)
122      register struct cmd_syndesc *as;
123 {
124     int delay;
125     if (!as->parms[0].items) {
126 /* can this happen? */
127         return 1;
128     }
129     delay = atoi(as->parms[0].items->data);
130     IOMGR_Sleep(delay);
131 }
132
133 int
134 popsource()
135 {
136     register struct sourcestack *sp;
137     if (!(sp = shead))
138         return 0;
139     if (source != stdin)
140         fclose(source);
141     source = sp->s_file;
142     shead = sp->s_next;
143     free((char *)sp);
144     return 1;
145 }
146
147 #endif /* SUPERGROUPS */
148
149 int
150 osi_audit()
151 {
152 /* OK, this REALLY sucks bigtime, but I can't tell who is calling
153  * afsconf_CheckAuth easily, and only *SERVERS* should be calling osi_audit
154  * anyway.  It's gonna give somebody fits to debug, I know, I know.
155  */
156     return 0;
157 }
158
159 int
160 GetGlobals(as)
161      register struct cmd_syndesc *as;
162 {
163     register afs_int32 code;
164     char *cell;
165     afs_int32 sec = 1;
166
167     whoami = as->a0name;
168
169     if (!strcmp(as->name, "help"))
170         return 0;
171     if (as->parms[16].items)
172         cell = as->parms[16].items->data;
173     else
174         cell = 0;
175     if (as->parms[17].items)
176         sec = 0;
177
178     if (as->parms[18].items) {  /* testing? */
179         code = pr_Initialize(sec, AFSDIR_SERVER_ETC_DIRPATH, cell);
180     } else {
181         code = pr_Initialize(sec, AFSDIR_CLIENT_ETC_DIRPATH, cell);
182     }
183     if (code) {
184         com_err(whoami, code, "while initializing");
185         return code;
186     }
187     if (as->parms[19].items)
188         force = 1;
189     return code;
190 }
191
192 int
193 CleanUp(as)
194      register struct cmd_syndesc *as;
195 {
196 #if defined(SUPERGROUPS)
197     if (as && !strcmp(as->name, "help"))
198         return 0;
199     if (pruclient) {
200         /* Need to shutdown the ubik_client & other connections */
201         pr_End();
202         rx_Finalize();
203     }
204 #else
205     if (!strcmp(as->name, "help"))
206         return 0;
207     /* Need to shutdown the ubik_client & other connections */
208     pr_End();
209     rx_Finalize();
210 #endif /* SUPERGROUPS */
211
212     return 0;
213 }
214
215 CreateGroup(as)
216      register struct cmd_syndesc *as;
217 {
218     register afs_int32 code;
219     afs_int32 id;
220     char *owner;
221     struct cmd_item *namei;
222     struct cmd_item *idi;
223
224     namei = as->parms[0].items;
225     idi = as->parms[2].items;
226     if (as->parms[1].items)
227         owner = as->parms[1].items->data;
228     else
229         owner = NULL;
230
231     while (namei) {
232         if (idi) {
233             code = util_GetInt32(idi->data, &id);
234             if (code) {
235                 com_err(whoami, code, "because group id was: '%s'",
236                         idi->data);
237                 return code;
238             }
239             if (id >= 0) {
240                 code = PRBADARG;
241                 com_err(whoami, code, "because group id %d was not negative",
242                         id);
243                 return code;
244             }
245 #if defined(SUPERGROUPS)
246             if (id == 0) {
247                 printf("0 isn't a valid user id; aborting\n");
248                 return EINVAL;
249             }
250 #endif
251             idi = idi->next;
252         } else
253             id = 0;
254
255         code = pr_CreateGroup(namei->data, owner, &id);
256         if (code) {
257             if (owner || id)
258                 com_err(whoami, code,
259                         "; unable to create group %s with id %d%s%s%s%s",
260                         namei->data, id, owner ? " owned by '" : "",
261                         owner ? owner : "", owner ? "'" : "",
262                         (force ? " (ignored)" : ""));
263             else
264                 com_err(whoami, code, "; unable to create group %s %s",
265                         namei->data, (force ? "(ignored)" : ""));
266             if (!force)
267                 return code;
268         }
269         printf("group %s has id %d\n", namei->data, id);
270         namei = namei->next;
271     }
272     return 0;
273 }
274
275 CreateUser(as)
276      register struct cmd_syndesc *as;
277 {
278     register afs_int32 code;
279     afs_int32 id;
280     struct cmd_item *namei;
281     struct cmd_item *idi;
282
283     namei = as->parms[0].items;
284     idi = as->parms[1].items;
285
286     while (namei) {
287         if (idi) {
288             code = util_GetInt32(idi->data, &id);
289             if (code) {
290                 com_err(whoami, code, "because id was: '%s'", idi->data);
291                 return code;
292             }
293             if (id == 0) {
294                 printf("0 isn't a valid user id; aborting\n");
295                 return EINVAL;
296             }
297             idi = idi->next;
298         } else
299             id = 0;
300
301         code = pr_CreateUser(namei->data, &id);
302         if (code) {
303             if (id)
304                 com_err(whoami, code,
305                         "; unable to create user %s with id %d %s",
306                         namei->data, id, (force ? "(ignored)" : ""));
307             else
308                 com_err(whoami, code, "; unable to create user %s %s",
309                         namei->data, (force ? "(ignored)" : ""));
310             if (!force)
311                 return code;
312         }
313         printf("User %s has id %d\n", namei->data, id);
314         namei = namei->next;
315     }
316     return 0;
317 }
318
319
320 #ifdef notdef
321 int
322 GetNameOrId(as, lids, lnames)
323      register struct cmd_syndesc *as;
324      struct idlist *lids;
325      struct namelist *lnames;
326 {
327     register afs_int32 code = 0;
328     int n = 0;
329     struct cmd_item *i;
330     int goodCount;
331
332     if (!(as->parms[0].items || as->parms[1].items)) {
333         com_err(whoami, 0, "must specify either a name or an id.");
334         return -1;
335     }
336     if (as->parms[0].items && as->parms[1].items) {
337         com_err(whoami, 0, "can't specify both a name and id.");
338         return -1;
339     }
340
341     goodCount = 0;
342     lids->idlist_len = 0;
343     lids->idlist_val = 0;
344
345     if (as->parms[0].items) {   /* name */
346         struct namelist names;  /* local copy, if not ret. names */
347         struct namelist *nl;
348
349         names.namelist_val = 0; /* so it gets freed later if needed */
350         if (lnames)
351             nl = lnames;
352         else
353             nl = &names;
354
355         n = 0;                  /* count names */
356         for (i = as->parms[0].items; i; i = i->next)
357             n++;
358         nl->namelist_val = (prname *) malloc(n * PR_MAXNAMELEN);
359         nl->namelist_len = n;
360         n = 0;
361         for (i = as->parms[0].items; i; i = i->next)
362             strncpy(nl->namelist_val[n++], i->data, PR_MAXNAMELEN);
363
364         code = pr_NameToId(nl, lids);
365         if (code)
366             com_err(whoami, code, "so couldn't look up names");
367         else {
368             for (n = 0; n < lids->idlist_len; n++) {
369                 if ((lids->idlist_val[n] == ANONYMOUSID)) {
370                     com_err(whoami, PRNOENT, "so couldn't look up id for %s",
371                             nl->namelist_val[n]);
372                 } else
373                     goodCount++;
374             }
375             /* treat things as working if any of the lookups worked */
376             if (goodCount == 0)
377                 code = PRNOENT;
378         }
379
380         if (names.namelist_val)
381             free(names.namelist_val);
382     } else if (as->parms[1].items) {    /* id */
383         n = 0;
384         for (i = as->parms[1].items; i; i = i->next)
385             n++;
386         lids->idlist_val = (afs_int32 *) malloc(n * sizeof(afs_int32));
387         lids->idlist_len = n;
388         n = 0;
389         for (i = as->parms[1].items; i; i = i->next) {
390             code = util_GetInt32(i->data, &lids->idlist_val[n]);
391             if (code)
392                 com_err(whoami, code =
393                         PRNOENT, "because a bogus id '%s' was specified",
394                         i->data);
395             n++;
396         }
397         if (!code && lnames) {
398             lnames->namelist_val = 0;
399             lnames->namelist_len = 0;
400             code = pr_IdToName(lids, lnames);
401             if (code)
402                 com_err(whoami, code, "translating ids");
403         }
404     }
405     if (code) {
406         if (lids->idlist_val)
407             free(lids->idlist_val);
408         return -1;
409     }
410     return 0;
411 }
412 #endif
413
414
415 int
416 GetNameOrId(as, lids, lnames)
417      register struct cmd_syndesc *as;
418      struct idlist *lids;
419      struct namelist *lnames;
420 {
421     register afs_int32 code = 0;
422     int n = 0, nd = 0, nm = 0, id, x;
423     struct cmd_item *i;
424     struct namelist names, tnames;      /* local copy, if not ret. names */
425     struct idlist ids, tids;    /* local copy, if not ret. ids */
426     int goodCount = 0;
427
428     for (i = as->parms[0].items; i; i = i->next)
429         n++;
430     lids->idlist_val = (afs_int32 *) malloc(n * sizeof(afs_int32));
431     lids->idlist_len = n;
432     ids.idlist_val = (afs_int32 *) malloc(n * sizeof(afs_int32));
433     ids.idlist_len = n;
434     names.namelist_val = (prname *) malloc(n * PR_MAXNAMELEN);
435     names.namelist_len = n;
436     if (lnames) {
437         lnames->namelist_val = (prname *) malloc(n * PR_MAXNAMELEN);
438         lnames->namelist_len = 0;
439     }
440     for (i = as->parms[0].items; i; i = i->next) {
441         tnames.namelist_val = (prname *) malloc(PR_MAXNAMELEN);
442         strncpy(tnames.namelist_val[0], i->data, PR_MAXNAMELEN);
443         tnames.namelist_len = 1;
444         tids.idlist_len = 0;
445         tids.idlist_val = 0;
446         code = pr_NameToId(&tnames, &tids);
447         if ((!code && (tids.idlist_val[0] != 32766))
448             || (code = util_GetInt32(i->data, &id))) {
449             /* Assume it's a name instead */
450             strncpy(names.namelist_val[nm++], i->data, PR_MAXNAMELEN);
451         } else {
452             ids.idlist_val[nd++] = id;
453         }
454         free(tnames.namelist_val);
455     }
456     names.namelist_len = nm;
457     ids.idlist_len = nd;
458     tids.idlist_len = nd = nm = 0;
459     tids.idlist_val = 0;
460     code = pr_NameToId(&names, &tids);
461     if (code)
462         com_err(whoami, code, "so couldn't look up names");
463     else {
464         for (n = 0; n < tids.idlist_len; n++) {
465             if ((tids.idlist_val[n] == ANONYMOUSID)) {
466                 com_err(whoami, PRNOENT, "so couldn't look up id for %s",
467                         names.namelist_val[n]);
468             } else
469                 goodCount++;
470             lids->idlist_val[nd] = tids.idlist_val[n];
471             if (lnames)
472                 strcpy(lnames->namelist_val[nd], names.namelist_val[n]);
473             nd++;
474         }
475     }
476     for (x = 0; x < ids.idlist_len; x++) {
477         lids->idlist_val[nd + x] = ids.idlist_val[x];
478     }
479     lids->idlist_len = nd + x;
480     if (!code && lnames) {
481         tnames.namelist_val = 0;
482         tnames.namelist_len = 0;
483         code = pr_IdToName(&ids, &tnames);
484         if (code)
485             com_err(whoami, code, "translating ids");
486         else
487             goodCount++;
488         if (lnames) {
489             for (x = 0; x < ids.idlist_len; x++)
490                 strcpy(lnames->namelist_val[nd + x], tnames.namelist_val[x]);
491             lnames->namelist_len = nd + x;
492         }
493     }
494     /* treat things as working if any of the lookups worked */
495     if (goodCount == 0)
496         code = PRNOENT;
497     if (code) {
498         if (lids->idlist_val)
499             free(lids->idlist_val);
500         return -1;
501     }
502     return 0;
503 }
504
505
506 AddToGroup(as)
507      register struct cmd_syndesc *as;
508 {
509     register afs_int32 code;
510     struct cmd_item *u, *g;
511
512     for (u = as->parms[0].items; u; u = u->next) {
513         for (g = as->parms[1].items; g; g = g->next) {
514             code = pr_AddToGroup(u->data, g->data);
515             if (code) {
516                 com_err(whoami, code,
517                         "; unable to add user %s to group %s %s", u->data,
518                         g->data, (force ? "(ignored)" : ""));
519                 if (!force)
520                     return code;
521             }
522         }
523     }
524     return 0;
525 }
526
527 RemoveFromGroup(as)
528      register struct cmd_syndesc *as;
529 {
530     register afs_int32 code;
531     struct cmd_item *u, *g;
532
533     for (u = as->parms[0].items; u; u = u->next) {
534         for (g = as->parms[1].items; g; g = g->next) {
535             code = pr_RemoveUserFromGroup(u->data, g->data);
536             if (code) {
537                 com_err(whoami, code,
538                         "; unable to remove user %s from group %s %s",
539                         u->data, g->data, (force ? "(ignored)" : ""));
540                 if (!force)
541                     return code;
542             }
543         }
544     }
545     return 0;
546 }
547
548 ListMembership(as)
549      register struct cmd_syndesc *as;
550 {
551     register afs_int32 code;
552     idlist ids;
553     namelist names;
554     int i;
555     namelist list;
556     int j;
557
558     if (GetNameOrId(as, &ids, &names))
559         return PRBADARG;
560
561     for (i = 0; i < ids.idlist_len; i++) {
562         afs_int32 id = ids.idlist_val[i];
563         char *name = names.namelist_val[i];
564
565         if (id == ANONYMOUSID)
566             continue;           /* bad entry */
567
568         list.namelist_val = 0;
569         list.namelist_len = 0;
570         code = pr_IDListMembers(ids.idlist_val[i], &list);
571         if (code) {
572             com_err(whoami, code, "; unable to get membership of %s (id: %d)",
573                     name, id);
574             continue;
575         }
576         if (id < 0)
577             printf("Members of %s (id: %d) are:\n", name, id);
578         else
579             printf("Groups %s (id: %d) is a member of:\n", name, id);
580
581         for (j = 0; j < list.namelist_len; j++)
582             printf("  %s\n", list.namelist_val[j]);
583         if (list.namelist_val)
584             free(list.namelist_val);
585     }
586     if (ids.idlist_val)
587         free(ids.idlist_val);
588     if (names.namelist_val)
589         free(names.namelist_val);
590     return 0;
591 }
592
593 Delete(as)
594      register struct cmd_syndesc *as;
595 {
596     register afs_int32 code;
597     idlist ids;
598     namelist names;
599     int i;
600
601     if (GetNameOrId(as, &ids, &names))
602         return PRBADARG;
603
604     for (i = 0; i < ids.idlist_len; i++) {
605         afs_int32 id = ids.idlist_val[i];
606         char *name = names.namelist_val[i];
607
608         if (id == ANONYMOUSID)
609             continue;
610
611         code = pr_DeleteByID(id);
612         if (code) {
613             com_err(whoami, code, "deleting %s (id: %d) %s", name, id,
614                     (force ? "(ignored)" : ""));
615             if (!force)
616                 return code;
617         }
618     }
619     if (ids.idlist_val)
620         free(ids.idlist_val);
621     if (names.namelist_val)
622         free(names.namelist_val);
623     return 0;
624 }
625
626 /* access bit translation info */
627
628 char *flags_upcase = "SOMA ";   /* legal all access values */
629 char *flags_dncase = "s mar";   /* legal member acces values */
630 int flags_shift[5] = { 2, 1, 2, 2, 1 }; /* bits for each */
631
632 CheckEntry(as)
633      register struct cmd_syndesc *as;
634 {
635     register afs_int32 code;
636     afs_int32 rcode = 1;
637     int i, flag = 0, admin = 0;
638     namelist lnames, names;
639     idlist ids;
640     idlist lids;
641     struct prcheckentry aentry;
642
643     if (GetNameOrId(as, &ids, &names))
644         return PRBADARG;
645
646     lids.idlist_len = 2;
647     lids.idlist_val = (afs_int32 *) malloc(sizeof(afs_int32) * 2);
648     lnames.namelist_len = 0;
649     lnames.namelist_val = 0;
650
651     for (i = 0; i < ids.idlist_len; i++) {
652         afs_int32 id = ids.idlist_val[i];
653
654         if (id == ANONYMOUSID)
655             continue;
656
657         rcode = 0;
658         code = pr_ListEntry(id, &aentry);
659         if (code) {
660             rcode = code;
661             com_err(whoami, code, "; unable to find entry for (id: %d)", id);
662             continue;
663         }
664
665         lids.idlist_val[0] = aentry.owner;
666         lids.idlist_val[1] = aentry.creator;
667         code = pr_IdToName(&lids, &lnames);
668         if (code) {
669             rcode = code;
670             com_err(whoami, code,
671                     "translating owner (%d) and creator (%d) ids",
672                     aentry.owner, aentry.creator);
673             continue;
674         }
675         printf("Name: %s, id: %d, owner: %s, creator: %s,\n", aentry.name,
676                aentry.id, lnames.namelist_val[0], lnames.namelist_val[1]);
677         printf("  membership: %d", aentry.count);
678         {
679             char access[6];
680             afs_int32 flags = aentry.flags;
681             int j, s, new;
682             char c;
683             access[5] = 0;      /* null-terminate the string */
684             for (j = 4; j >= 0; j--) {
685                 s = flags_shift[j];
686                 if (s == 1)
687                     new = flags & 1;
688                 else
689                     new = flags & 3;
690                 if (new == 0)
691                     c = '-';
692                 else if (new == 1) {
693                     c = flags_dncase[j];
694                     if (c == ' ')
695                         c = flags_upcase[j];
696                 } else if (new == 2)
697                     c = flags_upcase[j];
698                 else
699                     c = 'X';
700                 access[j] = c;
701                 flags >>= s;
702             }
703             printf(", flags: %s", access);
704         }
705         if (aentry.id == SYSADMINID)
706             admin = 1;
707         else if (!pr_IsAMemberOf(aentry.name, "system:administrators", &flag)) {
708             if (flag)
709                 admin = 1;
710         }
711         if (admin)
712             printf(", group quota: unlimited");
713         else
714             printf(", group quota: %d", aentry.ngroups);
715 #if FOREIGN
716         printf(", foreign user quota=%d", aentry.nusers);
717 #endif
718         printf(".\n");
719     }
720
721     if (lnames.namelist_val)
722         free(lnames.namelist_val);
723     if (lids.idlist_val)
724         free(lids.idlist_val);
725     if (ids.idlist_val)
726         free(ids.idlist_val);
727
728     return (rcode);
729 }
730
731 ListEntries(as)
732      struct cmd_syndesc *as;
733 {
734     afs_int32 code = 0;
735     afs_int32 flag, startindex, nentries, nextstartindex;
736     struct prlistentries *entriesp = 0, *e;
737     afs_int32 i;
738
739     flag = PRUSERS;
740     if (as->parms[1].items)
741         flag = PRGROUPS;
742     if (as->parms[0].items)
743         flag |= PRUSERS;
744
745     printf("Name                          ID  Owner Creator\n");
746     for (startindex = 0; startindex != -1; startindex = nextstartindex) {
747         code =
748             pr_ListEntries(flag, startindex, &nentries, &entriesp,
749                            &nextstartindex);
750         if (code) {
751             com_err(whoami, code, "; unable to list entries\n");
752             if (entriesp)
753                 free(entriesp);
754             break;
755         }
756
757         /* Now display each of the entries we read */
758         for (i = 0, e = entriesp; i < nentries; i++, e++) {
759             printf("%-25s %6d %6d %7d \n", e->name, e->id, e->owner,
760                    e->creator);
761         }
762         if (entriesp)
763             free(entriesp);
764     }
765     return code;
766 }
767
768 ChownGroup(as)
769      register struct cmd_syndesc *as;
770 {
771     register afs_int32 code;
772     char *name;
773     char *owner;
774
775     name = as->parms[0].items->data;
776     owner = as->parms[1].items->data;
777     code = pr_ChangeEntry(name, "", 0, owner);
778     if (code)
779         com_err(whoami, code, "; unable to change owner of %s to %s", name,
780                 owner);
781     return code;
782 }
783
784 ChangeName(as)
785      register struct cmd_syndesc *as;
786 {
787     register afs_int32 code;
788     char *oldname;
789     char *newname;
790
791     oldname = as->parms[0].items->data;
792     newname = as->parms[1].items->data;
793     code = pr_ChangeEntry(oldname, newname, 0, "");
794     if (code)
795         com_err(whoami, code, "; unable to change name of %s to %s", oldname,
796                 newname);
797     return code;
798 }
799
800 ListMax(as)
801      register struct cmd_syndesc *as;
802 {
803     register afs_int32 code;
804     afs_int32 maxUser, maxGroup;
805
806     code = pr_ListMaxUserId(&maxUser);
807     if (code)
808         com_err(whoami, code, "getting maximum user id");
809     else {
810         code = pr_ListMaxGroupId(&maxGroup);
811         if (code)
812             com_err(whoami, code, "getting maximum group id");
813         else {
814             printf("Max user id is %d and max group id is %d.\n", maxUser,
815                    maxGroup);
816         }
817     }
818     return code;
819 }
820
821 SetMax(as)
822      register struct cmd_syndesc *as;
823 {
824     register afs_int32 code;
825     afs_int32 maxid;
826
827     code = 0;
828     if (as->parms[1].items) {
829         /* set user max */
830         code = util_GetInt32(as->parms[1].items->data, &maxid);
831         if (code) {
832             com_err(whoami, code, "because id was: '%s'",
833                     as->parms[1].items->data);
834         } else {
835             code = pr_SetMaxUserId(maxid);
836             if (code)
837                 com_err(whoami, code, "so couldn't set Max User Id to %d",
838                         maxid);
839         }
840     }
841     if (as->parms[0].items) {
842         /* set group max */
843         code = util_GetInt32(as->parms[0].items->data, &maxid);
844         if (code) {
845             com_err(whoami, code, "because id was: '%s'",
846                     as->parms[0].items->data);
847         } else {
848             code = pr_SetMaxGroupId(maxid);
849             if (code)
850                 com_err(whoami, code, "so couldn't set Max Group Id to %d",
851                         maxid);
852         }
853     }
854     if (!as->parms[0].items && !as->parms[1].items) {
855         code = PRBADARG;
856         printf("Must specify at least one of group or user.\n");
857     }
858     return code;
859 }
860
861 SetFields(as)
862      register struct cmd_syndesc *as;
863 {
864     register afs_int32 code;
865     idlist ids;
866     namelist names;
867     int i;
868     afs_int32 mask, flags, ngroups, nusers;
869
870     if (GetNameOrId(as, &ids, &names))
871         return PRBADARG;
872
873     mask = 0;
874     nusers = 0;
875     if (as->parms[1].items) {   /* privacy bits */
876         char *access = as->parms[1].items->data;
877         int new;
878
879         if (strpbrk(access, "76543210") != 0) { /* all octal digits */
880             sscanf(access, "%lo", &flags);
881         } else {                /* interpret flag bit names */
882             if (strlen(access) != 5) {
883               form_error:
884                 printf("Access bits must be of the form 'somar', not %s\n",
885                        access);
886                 return PRBADARG;
887             }
888             if (strpbrk(access, "somar-") == 0)
889                 goto form_error;
890             flags = 0;
891             for (i = 0; i < 5; i++) {
892                 if (access[i] == flags_upcase[i])
893                     new = 2;
894                 else if (access[i] == flags_dncase[i])
895                     new = 1;
896                 else if (access[i] == '-')
897                     new = 0;
898                 else {
899                     printf
900                         ("Access bits out of order or illegal:\n  must be a combination of letters from '%s' or '%s' or hyphen, not %s\n",
901                          flags_upcase, flags_dncase, access);
902                     return PRBADARG;
903                 }
904                 flags <<= flags_shift[i];
905                 if (flags_shift[i] == 1) {
906                     if (new)
907                         flags |= 1;
908                 } else
909                     flags |= new;
910             }
911         }
912         mask |= PR_SF_ALLBITS;
913     }
914     if (as->parms[2].items) {   /* limitgroups */
915         code = util_GetInt32(as->parms[2].items->data, &ngroups);
916         if (code) {
917             com_err(whoami, code, "because ngroups was: '%s'",
918                     as->parms[2].items->data);
919             return code;
920         }
921         mask |= PR_SF_NGROUPS;
922     }
923 #if FOREIGN
924     if (as->parms[3].items) {   /* limitgroups */
925         code = util_GetInt32(as->parms[3].items->data, &nusers);
926         if (code) {
927             com_err(whoami, code, "because nusers was: '%s'",
928                     as->parms[3].items->data);
929             return code;
930         }
931         mask |= PR_SF_NUSERS;
932     }
933 #endif
934
935     for (i = 0; i < ids.idlist_len; i++) {
936         afs_int32 id = ids.idlist_val[i];
937         char *name = names.namelist_val[i];
938         if (id == ANONYMOUSID)
939             continue;
940         code = pr_SetFieldsEntry(id, mask, flags, ngroups, nusers);
941         if (code) {
942             com_err(whoami, code, "; unable to set fields for %s (id: %d)",
943                     name, id);
944             return code;
945         }
946     }
947     if (ids.idlist_val)
948         free(ids.idlist_val);
949     if (names.namelist_val)
950         free(names.namelist_val);
951     return 0;
952 }
953
954 ListOwned(as)
955      register struct cmd_syndesc *as;
956 {
957     register afs_int32 code;
958     idlist ids;
959     namelist names;
960     namelist list;
961     int i, j;
962     afs_int32 more;
963
964     if (GetNameOrId(as, &ids, &names))
965         return PRBADARG;
966
967     for (i = 0; i < ids.idlist_len; i++) {
968         afs_int32 oid = ids.idlist_val[i];
969         char *name = names.namelist_val[i];
970
971         if (oid == ANONYMOUSID)
972             continue;
973
974         if (oid)
975             printf("Groups owned by %s (id: %d) are:\n", name, oid);
976         else
977             printf("Orphaned groups are:\n");
978         more = 0;
979         do {
980             list.namelist_val = 0;
981             list.namelist_len = 0;
982             code = pr_ListOwned(oid, &list, &more);
983             if (code) {
984                 com_err(whoami, code,
985                         "; unable to get owner list for %s (id: %d)", name,
986                         oid);
987                 break;
988             }
989
990             for (j = 0; j < list.namelist_len; j++)
991                 printf("  %s\n", list.namelist_val[j]);
992             if (list.namelist_val)
993                 free(list.namelist_val);
994         } while (more);
995     }
996
997     if (ids.idlist_val)
998         free(ids.idlist_val);
999     if (names.namelist_val)
1000         free(names.namelist_val);
1001     return 0;
1002 }
1003
1004 static void
1005 add_std_args(ts)
1006      register struct cmd_syndesc *ts;
1007 {
1008     char test_help[AFSDIR_PATH_MAX];
1009
1010     sprintf(test_help, "use config file in %s", AFSDIR_SERVER_ETC_DIRPATH);
1011
1012     cmd_Seek(ts, 16);
1013     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1014     cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL, "run unauthenticated");
1015     cmd_AddParm(ts, "-test", CMD_FLAG, CMD_OPTIONAL | CMD_HIDE, test_help);
1016     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
1017                 "Continue oper despite reasonable errors");
1018 }
1019
1020 /*
1021 static void add_NameOrId_args (ts)
1022   register struct cmd_syndesc *ts;
1023 {
1024     cmd_AddParm(ts,"-name",CMD_LIST,CMD_OPTIONAL,"user or group name");
1025     cmd_AddParm(ts,"-id",CMD_LIST,CMD_OPTIONAL,"user or group id");
1026 }
1027 */
1028
1029 #include "AFS_component_version_number.c"
1030
1031 int
1032 main(argc, argv)
1033      int argc;
1034      char **argv;
1035 {
1036     register afs_int32 code;
1037     register struct cmd_syndesc *ts;
1038 #if defined(SUPERGROUPS)
1039     char line[2048];
1040     char *cp, *lastp;
1041     int parsec;
1042     char *parsev[CMD_MAXPARMS];
1043     char *savec;
1044 #endif
1045 #ifdef WIN32
1046     WSADATA WSAjunk;
1047 #endif
1048
1049 #ifdef WIN32
1050     WSAStartup(0x0101, &WSAjunk);
1051 #endif
1052
1053 #ifdef  AFS_AIX32_ENV
1054     /*
1055      * The following signal action for AIX is necessary so that in case of a 
1056      * crash (i.e. core is generated) we can include the user's data section 
1057      * in the core dump. Unfortunately, by default, only a partial core is
1058      * generated which, in many cases, isn't too useful.
1059      */
1060     struct sigaction nsa;
1061
1062     sigemptyset(&nsa.sa_mask);
1063     nsa.sa_handler = SIG_DFL;
1064     nsa.sa_flags = SA_FULLDUMP;
1065     sigaction(SIGSEGV, &nsa, NULL);
1066 #endif
1067
1068     ts = cmd_CreateSyntax("creategroup", CreateGroup, 0,
1069                           "create a new group");
1070     cmd_AddParm(ts, "-name", CMD_LIST, 0, "group name");
1071     cmd_AddParm(ts, "-owner", CMD_SINGLE, CMD_OPTIONAL, "owner of the group");
1072     cmd_AddParm(ts, "-id", CMD_LIST, CMD_OPTIONAL,
1073                 "id (negated) for the group");
1074     add_std_args(ts);
1075     cmd_CreateAlias(ts, "cg");
1076
1077     ts = cmd_CreateSyntax("createuser", CreateUser, 0, "create a new user");
1078     cmd_AddParm(ts, "-name", CMD_LIST, 0, "user name");
1079     cmd_AddParm(ts, "-id", CMD_LIST, CMD_OPTIONAL, "user id");
1080     add_std_args(ts);
1081     cmd_CreateAlias(ts, "cu");
1082
1083     ts = cmd_CreateSyntax("adduser", AddToGroup, 0, "add a user to a group");
1084     cmd_AddParm(ts, "-user", CMD_LIST, 0, "user name");
1085     cmd_AddParm(ts, "-group", CMD_LIST, 0, "group name");
1086     add_std_args(ts);
1087
1088     ts = cmd_CreateSyntax("removeuser", RemoveFromGroup, 0,
1089                           "remove a user from a group");
1090     cmd_AddParm(ts, "-user", CMD_LIST, 0, "user name");
1091     cmd_AddParm(ts, "-group", CMD_LIST, 0, "group name");
1092     add_std_args(ts);
1093
1094     ts = cmd_CreateSyntax("membership", ListMembership, 0,
1095                           "list membership of a user or group");
1096     cmd_AddParm(ts, "-nameorid", CMD_LIST, 0, "user or group name or id");
1097     add_std_args(ts);
1098     cmd_CreateAlias(ts, "groups");
1099
1100     ts = cmd_CreateSyntax("delete", Delete, 0,
1101                           "delete a user or group from database");
1102     cmd_AddParm(ts, "-nameorid", CMD_LIST, 0, "user or group name or id");
1103     add_std_args(ts);
1104
1105     ts = cmd_CreateSyntax("examine", CheckEntry, 0, "examine an entry");
1106     cmd_AddParm(ts, "-nameorid", CMD_LIST, 0, "user or group name or id");
1107     add_std_args(ts);
1108     cmd_CreateAlias(ts, "check");
1109
1110     ts = cmd_CreateSyntax("chown", ChownGroup, 0,
1111                           "change ownership of a group");
1112     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "group name");
1113     cmd_AddParm(ts, "-owner", CMD_SINGLE, 0, "new owner");
1114     add_std_args(ts);
1115
1116     ts = cmd_CreateSyntax("rename", ChangeName, 0, "rename user or group");
1117     cmd_AddParm(ts, "-oldname", CMD_SINGLE, 0, "old name");
1118     cmd_AddParm(ts, "-newname", CMD_SINGLE, 0, "new name");
1119     add_std_args(ts);
1120     cmd_CreateAlias(ts, "chname");
1121
1122     ts = cmd_CreateSyntax("listmax", ListMax, 0, "list max id");
1123     add_std_args(ts);
1124
1125     ts = cmd_CreateSyntax("setmax", SetMax, 0, "set max id");
1126     cmd_AddParm(ts, "-group", CMD_SINGLE, CMD_OPTIONAL, "group max");
1127     cmd_AddParm(ts, "-user", CMD_SINGLE, CMD_OPTIONAL, "user max");
1128     add_std_args(ts);
1129
1130     ts = cmd_CreateSyntax("setfields", SetFields, 0,
1131                           "set fields for an entry");
1132     cmd_AddParm(ts, "-nameorid", CMD_LIST, 0, "user or group name or id");
1133     cmd_AddParm(ts, "-access", CMD_SINGLE, CMD_OPTIONAL, "set privacy flags");
1134     cmd_AddParm(ts, "-groupquota", CMD_SINGLE, CMD_OPTIONAL,
1135                 "set limit on group creation");
1136 #if FOREIGN
1137     cmd_AddParm(ts, "-userquota", CMD_SINGLE, CMD_OPTIONAL,
1138                 "set limit on foreign user creation");
1139 #endif
1140     add_std_args(ts);
1141
1142     ts = cmd_CreateSyntax("listowned", ListOwned, 0,
1143                           "list groups owned by an entry or zero id gets orphaned groups");
1144     cmd_AddParm(ts, "-nameorid", CMD_LIST, 0, "user or group name or id");
1145     add_std_args(ts);
1146
1147     ts = cmd_CreateSyntax("listentries", ListEntries, 0,
1148                           "list users/groups in the protection database");
1149     cmd_AddParm(ts, "-users", CMD_FLAG, CMD_OPTIONAL, "list user entries");
1150     cmd_AddParm(ts, "-groups", CMD_FLAG, CMD_OPTIONAL, "list group entries");
1151     add_std_args(ts);
1152
1153 #if defined(SUPERGROUPS)
1154
1155     ts = cmd_CreateSyntax("interactive", Interactive, 0,
1156                           "enter interactive mode");
1157     add_std_args(ts);
1158     cmd_CreateAlias(ts, "in");
1159
1160     ts = cmd_CreateSyntax("quit", Quit, 0, "exit program");
1161     add_std_args(ts);
1162
1163     ts = cmd_CreateSyntax("source", Source, 0, "read commands from file");
1164     cmd_AddParm(ts, "-file", CMD_SINGLE, 0, "filename");
1165     add_std_args(ts);
1166
1167     ts = cmd_CreateSyntax("sleep", Sleep, 0, "pause for a bit");
1168     cmd_AddParm(ts, "-delay", CMD_SINGLE, 0, "seconds");
1169     add_std_args(ts);
1170
1171 #endif /* SUPERGROUPS */
1172
1173     cmd_SetBeforeProc(GetGlobals, 0);
1174
1175 #if defined(SUPERGROUPS)
1176     finished = 1;
1177     if (code = cmd_Dispatch(argc, argv)) {
1178         CleanUp(0);
1179         exit(1);
1180     }
1181     source = stdin;
1182     while (!finished) {
1183         if (isatty(fileno(source)))
1184             fprintf(stderr, "pts> ");
1185         if (!fgets(line, sizeof line, source)) {
1186             if (!popsource())
1187                 break;
1188             continue;
1189         }
1190         lastp = 0;
1191         for (cp = line; *cp; ++cp)
1192             if (!isspace(*cp))
1193                 lastp = 0;
1194             else if (!lastp)
1195                 lastp = cp;
1196         if (lastp)
1197             *lastp = 0;
1198         if (!*line)
1199             continue;
1200         code =
1201             cmd_ParseLine(line, parsev, &parsec,
1202                           sizeof(parsev) / sizeof(*parsev));
1203         if (code) {
1204             com_err(whoami, code, "parsing line: <%s>", line);
1205             exit(2);
1206         }
1207         savec = parsev[0];
1208         parsev[0] = argv[0];
1209         code = cmd_Dispatch(parsec, parsev);
1210         parsev[0] = savec;
1211         cmd_FreeArgv(parsev);
1212     }
1213     CleanUp(0);
1214     exit(0);
1215
1216 #else /* SUPERGROUPS */
1217
1218     cmd_SetAfterProc(CleanUp, 0);
1219     code = cmd_Dispatch(argc, argv);
1220     exit(code != 0);
1221 #endif /* SUPERGROUPS */
1222 }