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