reindent-20030715
[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;
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;
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   done:
722     if (lnames.namelist_val)
723         free(lnames.namelist_val);
724     if (lids.idlist_val)
725         free(lids.idlist_val);
726     if (ids.idlist_val)
727         free(ids.idlist_val);
728
729     return (rcode);
730 }
731
732 ListEntries(as)
733      struct cmd_syndesc *as;
734 {
735     afs_int32 code = 0;
736     afs_int32 flag, startindex, nentries, nextstartindex;
737     struct prlistentries *entriesp = 0, *e;
738     afs_int32 i;
739
740     flag = PRUSERS;
741     if (as->parms[1].items)
742         flag = PRGROUPS;
743     if (as->parms[0].items)
744         flag |= PRUSERS;
745
746     printf("Name                          ID  Owner Creator\n");
747     for (startindex = 0; startindex != -1; startindex = nextstartindex) {
748         code =
749             pr_ListEntries(flag, startindex, &nentries, &entriesp,
750                            &nextstartindex);
751         if (code) {
752             com_err(whoami, code, "; unable to list entries\n");
753             if (entriesp)
754                 free(entriesp);
755             break;
756         }
757
758         /* Now display each of the entries we read */
759         for (i = 0, e = entriesp; i < nentries; i++, e++) {
760             printf("%-25s %6d %6d %7d \n", e->name, e->id, e->owner,
761                    e->creator);
762         }
763         if (entriesp)
764             free(entriesp);
765     }
766     return code;
767 }
768
769 ChownGroup(as)
770      register struct cmd_syndesc *as;
771 {
772     register afs_int32 code;
773     char *name;
774     char *owner;
775
776     name = as->parms[0].items->data;
777     owner = as->parms[1].items->data;
778     code = pr_ChangeEntry(name, "", 0, owner);
779     if (code)
780         com_err(whoami, code, "; unable to change owner of %s to %s", name,
781                 owner);
782     return code;
783 }
784
785 ChangeName(as)
786      register struct cmd_syndesc *as;
787 {
788     register afs_int32 code;
789     char *oldname;
790     char *newname;
791
792     oldname = as->parms[0].items->data;
793     newname = as->parms[1].items->data;
794     code = pr_ChangeEntry(oldname, newname, 0, "");
795     if (code)
796         com_err(whoami, code, "; unable to change name of %s to %s", oldname,
797                 newname);
798     return code;
799 }
800
801 ListMax(as)
802      register struct cmd_syndesc *as;
803 {
804     register afs_int32 code;
805     afs_int32 maxUser, maxGroup;
806
807     code = pr_ListMaxUserId(&maxUser);
808     if (code)
809         com_err(whoami, code, "getting maximum user id");
810     else {
811         code = pr_ListMaxGroupId(&maxGroup);
812         if (code)
813             com_err(whoami, code, "getting maximum group id");
814         else {
815             printf("Max user id is %d and max group id is %d.\n", maxUser,
816                    maxGroup);
817         }
818     }
819     return code;
820 }
821
822 SetMax(as)
823      register struct cmd_syndesc *as;
824 {
825     register afs_int32 code;
826     afs_int32 maxid;
827
828     code = 0;
829     if (as->parms[1].items) {
830         /* set user max */
831         code = util_GetInt32(as->parms[1].items->data, &maxid);
832         if (code) {
833             com_err(whoami, code, "because id was: '%s'",
834                     as->parms[1].items->data);
835         } else {
836             code = pr_SetMaxUserId(maxid);
837             if (code)
838                 com_err(whoami, code, "so couldn't set Max User Id to %d",
839                         maxid);
840         }
841     }
842     if (as->parms[0].items) {
843         /* set group max */
844         code = util_GetInt32(as->parms[0].items->data, &maxid);
845         if (code) {
846             com_err(whoami, code, "because id was: '%s'",
847                     as->parms[0].items->data);
848         } else {
849             code = pr_SetMaxGroupId(maxid);
850             if (code)
851                 com_err(whoami, code, "so couldn't set Max Group Id to %d",
852                         maxid);
853         }
854     }
855     if (!as->parms[0].items && !as->parms[1].items) {
856         code = PRBADARG;
857         printf("Must specify at least one of group or user.\n");
858     }
859     return code;
860 }
861
862 SetFields(as)
863      register struct cmd_syndesc *as;
864 {
865     register afs_int32 code;
866     idlist ids;
867     namelist names;
868     int i;
869     afs_int32 mask, flags, ngroups, nusers;
870
871     if (GetNameOrId(as, &ids, &names))
872         return PRBADARG;
873
874     mask = 0;
875     nusers = 0;
876     if (as->parms[1].items) {   /* privacy bits */
877         char *access = as->parms[1].items->data;
878         int new;
879
880         if (strpbrk(access, "76543210") != 0) { /* all octal digits */
881             sscanf(access, "%lo", &flags);
882         } else {                /* interpret flag bit names */
883             if (strlen(access) != 5) {
884               form_error:
885                 printf("Access bits must be of the form 'somar', not %s\n",
886                        access);
887                 return PRBADARG;
888             }
889             if (strpbrk(access, "somar-") == 0)
890                 goto form_error;
891             flags = 0;
892             for (i = 0; i < 5; i++) {
893                 if (access[i] == flags_upcase[i])
894                     new = 2;
895                 else if (access[i] == flags_dncase[i])
896                     new = 1;
897                 else if (access[i] == '-')
898                     new = 0;
899                 else {
900                     printf
901                         ("Access bits out of order or illegal:\n  must be a combination of letters from '%s' or '%s' or hyphen, not %s\n",
902                          flags_upcase, flags_dncase, access);
903                     return PRBADARG;
904                 }
905                 flags <<= flags_shift[i];
906                 if (flags_shift[i] == 1) {
907                     if (new)
908                         flags |= 1;
909                 } else
910                     flags |= new;
911             }
912         }
913         mask |= PR_SF_ALLBITS;
914     }
915     if (as->parms[2].items) {   /* limitgroups */
916         code = util_GetInt32(as->parms[2].items->data, &ngroups);
917         if (code) {
918             com_err(whoami, code, "because ngroups was: '%s'",
919                     as->parms[2].items->data);
920             return code;
921         }
922         mask |= PR_SF_NGROUPS;
923     }
924 #if FOREIGN
925     if (as->parms[3].items) {   /* limitgroups */
926         code = util_GetInt32(as->parms[3].items->data, &nusers);
927         if (code) {
928             com_err(whoami, code, "because nusers was: '%s'",
929                     as->parms[3].items->data);
930             return code;
931         }
932         mask |= PR_SF_NUSERS;
933     }
934 #endif
935
936     for (i = 0; i < ids.idlist_len; i++) {
937         afs_int32 id = ids.idlist_val[i];
938         char *name = names.namelist_val[i];
939         if (id == ANONYMOUSID)
940             continue;
941         code = pr_SetFieldsEntry(id, mask, flags, ngroups, nusers);
942         if (code) {
943             com_err(whoami, code, "; unable to set fields for %s (id: %d)",
944                     name, id);
945             return code;
946         }
947     }
948     if (ids.idlist_val)
949         free(ids.idlist_val);
950     if (names.namelist_val)
951         free(names.namelist_val);
952     return 0;
953 }
954
955 ListOwned(as)
956      register struct cmd_syndesc *as;
957 {
958     register afs_int32 code;
959     idlist ids;
960     namelist names;
961     namelist list;
962     int i, j;
963     afs_int32 more;
964
965     if (GetNameOrId(as, &ids, &names))
966         return PRBADARG;
967
968     for (i = 0; i < ids.idlist_len; i++) {
969         afs_int32 oid = ids.idlist_val[i];
970         char *name = names.namelist_val[i];
971
972         if (oid == ANONYMOUSID)
973             continue;
974
975         if (oid)
976             printf("Groups owned by %s (id: %d) are:\n", name, oid);
977         else
978             printf("Orphaned groups are:\n");
979         more = 0;
980         do {
981             list.namelist_val = 0;
982             list.namelist_len = 0;
983             code = pr_ListOwned(oid, &list, &more);
984             if (code) {
985                 com_err(whoami, code,
986                         "; unable to get owner list for %s (id: %d)", name,
987                         oid);
988                 break;
989             }
990
991             for (j = 0; j < list.namelist_len; j++)
992                 printf("  %s\n", list.namelist_val[j]);
993             if (list.namelist_val)
994                 free(list.namelist_val);
995         } while (more);
996     }
997
998     if (ids.idlist_val)
999         free(ids.idlist_val);
1000     if (names.namelist_val)
1001         free(names.namelist_val);
1002     return 0;
1003 }
1004
1005 static void
1006 add_std_args(ts)
1007      register struct cmd_syndesc *ts;
1008 {
1009     char test_help[AFSDIR_PATH_MAX];
1010
1011     sprintf(test_help, "use config file in %s", AFSDIR_SERVER_ETC_DIRPATH);
1012
1013     cmd_Seek(ts, 16);
1014     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1015     cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL, "run unauthenticated");
1016     cmd_AddParm(ts, "-test", CMD_FLAG, CMD_OPTIONAL | CMD_HIDE, test_help);
1017     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
1018                 "Continue oper despite reasonable errors");
1019 }
1020
1021 /*
1022 static void add_NameOrId_args (ts)
1023   register struct cmd_syndesc *ts;
1024 {
1025     cmd_AddParm(ts,"-name",CMD_LIST,CMD_OPTIONAL,"user or group name");
1026     cmd_AddParm(ts,"-id",CMD_LIST,CMD_OPTIONAL,"user or group id");
1027 }
1028 */
1029
1030 #include "AFS_component_version_number.c"
1031
1032 int
1033 main(argc, argv)
1034      int argc;
1035      char **argv;
1036 {
1037     register afs_int32 code;
1038     register struct cmd_syndesc *ts;
1039 #if defined(SUPERGROUPS)
1040     char line[2048];
1041     char *cp, *lastp;
1042     int parsec;
1043     char *parsev[CMD_MAXPARMS];
1044     char *savec;
1045 #endif
1046 #ifdef WIN32
1047     WSADATA WSAjunk;
1048 #endif
1049
1050 #ifdef WIN32
1051     WSAStartup(0x0101, &WSAjunk);
1052 #endif
1053
1054 #ifdef  AFS_AIX32_ENV
1055     /*
1056      * The following signal action for AIX is necessary so that in case of a 
1057      * crash (i.e. core is generated) we can include the user's data section 
1058      * in the core dump. Unfortunately, by default, only a partial core is
1059      * generated which, in many cases, isn't too useful.
1060      */
1061     struct sigaction nsa;
1062
1063     sigemptyset(&nsa.sa_mask);
1064     nsa.sa_handler = SIG_DFL;
1065     nsa.sa_flags = SA_FULLDUMP;
1066     sigaction(SIGSEGV, &nsa, NULL);
1067 #endif
1068
1069     ts = cmd_CreateSyntax("creategroup", CreateGroup, 0,
1070                           "create a new group");
1071     cmd_AddParm(ts, "-name", CMD_LIST, 0, "group name");
1072     cmd_AddParm(ts, "-owner", CMD_SINGLE, CMD_OPTIONAL, "owner of the group");
1073     cmd_AddParm(ts, "-id", CMD_LIST, CMD_OPTIONAL,
1074                 "id (negated) for the group");
1075     add_std_args(ts);
1076     cmd_CreateAlias(ts, "cg");
1077
1078     ts = cmd_CreateSyntax("createuser", CreateUser, 0, "create a new user");
1079     cmd_AddParm(ts, "-name", CMD_LIST, 0, "user name");
1080     cmd_AddParm(ts, "-id", CMD_LIST, CMD_OPTIONAL, "user id");
1081     add_std_args(ts);
1082     cmd_CreateAlias(ts, "cu");
1083
1084     ts = cmd_CreateSyntax("adduser", AddToGroup, 0, "add a user to a group");
1085     cmd_AddParm(ts, "-user", CMD_LIST, 0, "user name");
1086     cmd_AddParm(ts, "-group", CMD_LIST, 0, "group name");
1087     add_std_args(ts);
1088
1089     ts = cmd_CreateSyntax("removeuser", RemoveFromGroup, 0,
1090                           "remove a user from a group");
1091     cmd_AddParm(ts, "-user", CMD_LIST, 0, "user name");
1092     cmd_AddParm(ts, "-group", CMD_LIST, 0, "group name");
1093     add_std_args(ts);
1094
1095     ts = cmd_CreateSyntax("membership", ListMembership, 0,
1096                           "list membership of a user or group");
1097     cmd_AddParm(ts, "-nameorid", CMD_LIST, 0, "user or group name or id");
1098     add_std_args(ts);
1099     cmd_CreateAlias(ts, "groups");
1100
1101     ts = cmd_CreateSyntax("delete", Delete, 0,
1102                           "delete a user or group from database");
1103     cmd_AddParm(ts, "-nameorid", CMD_LIST, 0, "user or group name or id");
1104     add_std_args(ts);
1105
1106     ts = cmd_CreateSyntax("examine", CheckEntry, 0, "examine an entry");
1107     cmd_AddParm(ts, "-nameorid", CMD_LIST, 0, "user or group name or id");
1108     add_std_args(ts);
1109     cmd_CreateAlias(ts, "check");
1110
1111     ts = cmd_CreateSyntax("chown", ChownGroup, 0,
1112                           "change ownership of a group");
1113     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "group name");
1114     cmd_AddParm(ts, "-owner", CMD_SINGLE, 0, "new owner");
1115     add_std_args(ts);
1116
1117     ts = cmd_CreateSyntax("rename", ChangeName, 0, "rename user or group");
1118     cmd_AddParm(ts, "-oldname", CMD_SINGLE, 0, "old name");
1119     cmd_AddParm(ts, "-newname", CMD_SINGLE, 0, "new name");
1120     add_std_args(ts);
1121     cmd_CreateAlias(ts, "chname");
1122
1123     ts = cmd_CreateSyntax("listmax", ListMax, 0, "list max id");
1124     add_std_args(ts);
1125
1126     ts = cmd_CreateSyntax("setmax", SetMax, 0, "set max id");
1127     cmd_AddParm(ts, "-group", CMD_SINGLE, CMD_OPTIONAL, "group max");
1128     cmd_AddParm(ts, "-user", CMD_SINGLE, CMD_OPTIONAL, "user max");
1129     add_std_args(ts);
1130
1131     ts = cmd_CreateSyntax("setfields", SetFields, 0,
1132                           "set fields for an entry");
1133     cmd_AddParm(ts, "-nameorid", CMD_LIST, 0, "user or group name or id");
1134     cmd_AddParm(ts, "-access", CMD_SINGLE, CMD_OPTIONAL, "set privacy flags");
1135     cmd_AddParm(ts, "-groupquota", CMD_SINGLE, CMD_OPTIONAL,
1136                 "set limit on group creation");
1137 #if FOREIGN
1138     cmd_AddParm(ts, "-userquota", CMD_SINGLE, CMD_OPTIONAL,
1139                 "set limit on foreign user creation");
1140 #endif
1141     add_std_args(ts);
1142
1143     ts = cmd_CreateSyntax("listowned", ListOwned, 0,
1144                           "list groups owned by an entry or zero id gets orphaned groups");
1145     cmd_AddParm(ts, "-nameorid", CMD_LIST, 0, "user or group name or id");
1146     add_std_args(ts);
1147
1148     ts = cmd_CreateSyntax("listentries", ListEntries, 0,
1149                           "list users/groups in the protection database");
1150     cmd_AddParm(ts, "-users", CMD_FLAG, CMD_OPTIONAL, "list user entries");
1151     cmd_AddParm(ts, "-groups", CMD_FLAG, CMD_OPTIONAL, "list group entries");
1152     add_std_args(ts);
1153
1154 #if defined(SUPERGROUPS)
1155
1156     ts = cmd_CreateSyntax("interactive", Interactive, 0,
1157                           "enter interactive mode");
1158     add_std_args(ts);
1159     cmd_CreateAlias(ts, "in");
1160
1161     ts = cmd_CreateSyntax("quit", Quit, 0, "exit program");
1162     add_std_args(ts);
1163
1164     ts = cmd_CreateSyntax("source", Source, 0, "read commands from file");
1165     cmd_AddParm(ts, "-file", CMD_SINGLE, 0, "filename");
1166     add_std_args(ts);
1167
1168     ts = cmd_CreateSyntax("sleep", Sleep, 0, "pause for a bit");
1169     cmd_AddParm(ts, "-delay", CMD_SINGLE, 0, "seconds");
1170     add_std_args(ts);
1171
1172 #endif /* SUPERGROUPS */
1173
1174     cmd_SetBeforeProc(GetGlobals, 0);
1175
1176 #if defined(SUPERGROUPS)
1177     finished = 1;
1178     if (code = cmd_Dispatch(argc, argv)) {
1179         CleanUp(0);
1180         exit(1);
1181     }
1182     source = stdin;
1183     while (!finished) {
1184         if (isatty(fileno(source)))
1185             fprintf(stderr, "pts> ");
1186         if (!fgets(line, sizeof line, source)) {
1187             if (!popsource())
1188                 break;
1189             continue;
1190         }
1191         lastp = 0;
1192         for (cp = line; *cp; ++cp)
1193             if (!isspace(*cp))
1194                 lastp = 0;
1195             else if (!lastp)
1196                 lastp = cp;
1197         if (lastp)
1198             *lastp = 0;
1199         if (!*line)
1200             continue;
1201         code =
1202             cmd_ParseLine(line, parsev, &parsec,
1203                           sizeof(parsev) / sizeof(*parsev));
1204         if (code) {
1205             com_err(whoami, code, "parsing line: <%s>", line);
1206             exit(2);
1207         }
1208         savec = parsev[0];
1209         parsev[0] = argv[0];
1210         code = cmd_Dispatch(parsec, parsev);
1211         parsev[0] = savec;
1212         cmd_FreeArgv(parsev);
1213     }
1214     CleanUp(0);
1215     exit(0);
1216
1217 #else /* SUPERGROUPS */
1218
1219     cmd_SetAfterProc(CleanUp, 0);
1220     code = cmd_Dispatch(argc, argv);
1221     exit(code != 0);
1222 #endif /* SUPERGROUPS */
1223 }