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