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