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