17a99442c1d69779666cbc3223c58361a55c1d7e
[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     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     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     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             if (id < 0) {
344                 code = PRBADARG;
345                 afs_com_err(whoami, code, "because user id %d was not positive",
346                         id);
347                 return code;
348             }
349             idi = idi->next;
350         } else
351             id = 0;
352
353         code = pr_CreateUser(namei->data, &id);
354         if (code) {
355             if (id)
356                 afs_com_err(whoami, code,
357                         "; unable to create user %s with id %d %s",
358                         namei->data, id, (force ? "(ignored)" : ""));
359             else
360                 afs_com_err(whoami, code, "; unable to create user %s %s",
361                         namei->data, (force ? "(ignored)" : ""));
362             if (!force)
363                 return code;
364         }
365         printf("User %s has id %d\n", namei->data, id);
366         namei = namei->next;
367     }
368     return 0;
369 }
370
371
372 #ifdef notdef
373 static int
374 GetNameOrId(struct cmd_syndesc *as, struct idlist *lids, struct namelist *lnames)
375 {
376     afs_int32 code = 0;
377     int n = 0;
378     struct cmd_item *i;
379     int goodCount;
380
381     if (!(as->parms[0].items || as->parms[1].items)) {
382         afs_com_err(whoami, 0, "must specify either a name or an id.");
383         return -1;
384     }
385     if (as->parms[0].items && as->parms[1].items) {
386         afs_com_err(whoami, 0, "can't specify both a name and id.");
387         return -1;
388     }
389
390     goodCount = 0;
391     lids->idlist_len = 0;
392     lids->idlist_val = 0;
393
394     if (as->parms[0].items) {   /* name */
395         struct namelist names;  /* local copy, if not ret. names */
396         struct namelist *nl;
397
398         names.namelist_val = 0; /* so it gets freed later if needed */
399         if (lnames)
400             nl = lnames;
401         else
402             nl = &names;
403
404         n = 0;                  /* count names */
405         for (i = as->parms[0].items; i; i = i->next)
406             n++;
407         nl->namelist_val = (prname *) malloc(n * PR_MAXNAMELEN);
408         nl->namelist_len = n;
409         n = 0;
410         for (i = as->parms[0].items; i; i = i->next)
411             strncpy(nl->namelist_val[n++], i->data, PR_MAXNAMELEN);
412
413         code = pr_NameToId(nl, lids);
414         if (code)
415             afs_com_err(whoami, code, "so couldn't look up names");
416         else {
417             for (n = 0; n < lids->idlist_len; n++) {
418                 if ((lids->idlist_val[n] == ANONYMOUSID)) {
419                     afs_com_err(whoami, PRNOENT, "so couldn't look up id for %s",
420                             nl->namelist_val[n]);
421                 } else
422                     goodCount++;
423             }
424             /* treat things as working if any of the lookups worked */
425             if (goodCount == 0)
426                 code = PRNOENT;
427         }
428
429         if (names.namelist_val)
430             free(names.namelist_val);
431     } else if (as->parms[1].items) {    /* id */
432         n = 0;
433         for (i = as->parms[1].items; i; i = i->next)
434             n++;
435         lids->idlist_val = (afs_int32 *) malloc(n * sizeof(afs_int32));
436         lids->idlist_len = n;
437         n = 0;
438         for (i = as->parms[1].items; i; i = i->next) {
439             code = util_GetInt32(i->data, &lids->idlist_val[n]);
440             if (code)
441                 afs_com_err(whoami, code =
442                         PRNOENT, "because a bogus id '%s' was specified",
443                         i->data);
444             n++;
445         }
446         if (!code && lnames) {
447             lnames->namelist_val = 0;
448             lnames->namelist_len = 0;
449             code = pr_IdToName(lids, lnames);
450             if (code)
451                 afs_com_err(whoami, code, "translating ids");
452         }
453     }
454     if (code) {
455         if (lids->idlist_val)
456             free(lids->idlist_val);
457         return -1;
458     }
459     return 0;
460 }
461 #endif
462
463
464 static int
465 GetNameOrId(struct cmd_syndesc *as, struct idlist *lids,
466             struct namelist *lnames)
467 {
468     afs_int32 code = 0;
469     int n = 0, nd = 0, nm = 0, id, x;
470     struct cmd_item *i;
471     struct namelist names, tnames;      /* local copy, if not ret. names */
472     struct idlist ids, tids;    /* local copy, if not ret. ids */
473     int goodCount = 0;
474
475     for (i = as->parms[0].items; i; i = i->next)
476         n++;
477     lids->idlist_val = (afs_int32 *) malloc(n * sizeof(afs_int32));
478     lids->idlist_len = n;
479     ids.idlist_val = (afs_int32 *) malloc(n * sizeof(afs_int32));
480     ids.idlist_len = n;
481     names.namelist_val = (prname *) malloc(n * PR_MAXNAMELEN);
482     names.namelist_len = n;
483     if (lnames) {
484         lnames->namelist_val = (prname *) malloc(n * PR_MAXNAMELEN);
485         lnames->namelist_len = 0;
486     }
487     for (i = as->parms[0].items; i; i = i->next) {
488         tnames.namelist_val = (prname *) malloc(PR_MAXNAMELEN);
489         strncpy(tnames.namelist_val[0], i->data, PR_MAXNAMELEN);
490         tnames.namelist_len = 1;
491         tids.idlist_len = 0;
492         tids.idlist_val = 0;
493         code = pr_NameToId(&tnames, &tids);
494         if ((!code && (tids.idlist_val[0] != 32766))
495             || (code = util_GetInt32(i->data, &id))) {
496             /* Assume it's a name instead */
497             strncpy(names.namelist_val[nm++], i->data, PR_MAXNAMELEN);
498         } else {
499             ids.idlist_val[nd++] = id;
500         }
501         free(tnames.namelist_val);
502     }
503     names.namelist_len = nm;
504     ids.idlist_len = nd;
505     tids.idlist_len = nd = nm = 0;
506     tids.idlist_val = 0;
507     code = pr_NameToId(&names, &tids);
508     if (code)
509         afs_com_err(whoami, code, "so couldn't look up names");
510     else {
511         for (n = 0; n < tids.idlist_len; n++) {
512             if ((tids.idlist_val[n] == ANONYMOUSID)) {
513                 afs_com_err(whoami, PRNOENT, "so couldn't look up id for %s",
514                         names.namelist_val[n]);
515             } else
516                 goodCount++;
517             lids->idlist_val[nd] = tids.idlist_val[n];
518             if (lnames)
519                 strcpy(lnames->namelist_val[nd], names.namelist_val[n]);
520             nd++;
521         }
522     }
523     for (x = 0; x < ids.idlist_len; x++) {
524         lids->idlist_val[nd + x] = ids.idlist_val[x];
525     }
526     lids->idlist_len = nd + x;
527     if (!code && lnames) {
528         tnames.namelist_val = 0;
529         tnames.namelist_len = 0;
530         code = pr_IdToName(&ids, &tnames);
531         if (code)
532             afs_com_err(whoami, code, "translating ids");
533         else
534             goodCount++;
535         if (lnames) {
536             for (x = 0; x < ids.idlist_len; x++)
537                 strcpy(lnames->namelist_val[nd + x], tnames.namelist_val[x]);
538             lnames->namelist_len = nd + x;
539         }
540     }
541     /* treat things as working if any of the lookups worked */
542     if (goodCount == 0)
543         code = PRNOENT;
544     if (code) {
545         if (lids->idlist_val)
546             free(lids->idlist_val);
547         return -1;
548     }
549     return 0;
550 }
551
552
553 static int
554 AddToGroup(struct cmd_syndesc *as, void *arock)
555 {
556     afs_int32 code;
557     struct cmd_item *u, *g;
558
559     for (u = as->parms[0].items; u; u = u->next) {
560         for (g = as->parms[1].items; g; g = g->next) {
561             code = pr_AddToGroup(u->data, g->data);
562             if (code) {
563                 afs_com_err(whoami, code,
564                         "; unable to add user %s to group %s %s", u->data,
565                         g->data, (force ? "(ignored)" : ""));
566                 if (!force)
567                     return code;
568             }
569         }
570     }
571     return 0;
572 }
573
574 static int
575 RemoveFromGroup(struct cmd_syndesc *as, void *arock)
576 {
577     afs_int32 code;
578     struct cmd_item *u, *g;
579
580     for (u = as->parms[0].items; u; u = u->next) {
581         for (g = as->parms[1].items; g; g = g->next) {
582             code = pr_RemoveUserFromGroup(u->data, g->data);
583             if (code) {
584                 afs_com_err(whoami, code,
585                         "; unable to remove user %s from group %s %s",
586                         u->data, g->data, (force ? "(ignored)" : ""));
587                 if (!force)
588                     return code;
589             }
590         }
591     }
592     return 0;
593 }
594
595 static int
596 ListMembership(struct cmd_syndesc *as, void *arock)
597 {
598     afs_int32 code;
599     idlist ids;
600     namelist names;
601     int i;
602     namelist list;
603     int j;
604
605     if (GetNameOrId(as, &ids, &names))
606         return PRBADARG;
607
608     for (i = 0; i < ids.idlist_len; i++) {
609         afs_int32 id = ids.idlist_val[i];
610         char *name = names.namelist_val[i];
611
612         if (id == ANONYMOUSID)
613             continue;           /* bad entry */
614
615         list.namelist_val = 0;
616         list.namelist_len = 0;
617         if (as->parms[2].items) {       /* -expandgroups */
618             code = pr_IDListExpandedMembers(id, &list);
619             if (!code)
620                 printf("Expanded ");
621         } else {
622             code = pr_IDListMembers(id, &list);
623         }
624         if (code) {
625             afs_com_err(whoami, code, "; unable to get membership of %s (id: %d)",
626                     name, id);
627             continue;
628         }
629         if (id < 0)
630             printf("Members of %s (id: %d) are:\n", name, id);
631         else
632             printf("Groups %s (id: %d) is a member of:\n", name, id);
633
634         for (j = 0; j < list.namelist_len; j++)
635             printf("  %s\n", list.namelist_val[j]);
636         if (list.namelist_val)
637             free(list.namelist_val);
638         if (as->parms[1].items && id < 0) {     /* -supergroups */
639             list.namelist_val = 0;
640             list.namelist_len = 0;
641             code = pr_ListSuperGroups(ids.idlist_val[i], &list);
642             if (code == RXGEN_OPCODE) {
643                 continue; /* server does not support supergroups */
644             } else if (code != 0) {
645                 afs_com_err(whoami, code,
646                             "; unable to get supergroups of %s (id: %d)",
647                             name, id);
648                 continue;
649             }
650             printf("Groups %s (id: %d) is a member of:\n", name, id);
651             for (j = 0; j < list.namelist_len; j++)
652                 printf("  %s\n", list.namelist_val[j]);
653             if (list.namelist_val)
654                 free(list.namelist_val);
655         }
656     }
657     if (ids.idlist_val)
658         free(ids.idlist_val);
659     if (names.namelist_val)
660         free(names.namelist_val);
661     return 0;
662 }
663
664 static int
665 Delete(struct cmd_syndesc *as, void *arock)
666 {
667     afs_int32 code;
668     idlist ids;
669     namelist names;
670     int i;
671
672     if (GetNameOrId(as, &ids, &names))
673         return PRBADARG;
674
675     for (i = 0; i < ids.idlist_len; i++) {
676         afs_int32 id = ids.idlist_val[i];
677         char *name = names.namelist_val[i];
678
679         if (id == ANONYMOUSID)
680             continue;
681
682         code = pr_DeleteByID(id);
683         if (code) {
684             afs_com_err(whoami, code, "deleting %s (id: %d) %s", name, id,
685                     (force ? "(ignored)" : ""));
686             if (!force)
687                 return code;
688         }
689     }
690     if (ids.idlist_val)
691         free(ids.idlist_val);
692     if (names.namelist_val)
693         free(names.namelist_val);
694     return 0;
695 }
696
697 /* access bit translation info */
698
699 char *flags_upcase = "SOMA ";   /* legal all access values */
700 char *flags_dncase = "s mar";   /* legal member acces values */
701 int flags_shift[5] = { 2, 1, 2, 2, 1 }; /* bits for each */
702
703 static int
704 CheckEntry(struct cmd_syndesc *as, void *arock)
705 {
706     afs_int32 code;
707     afs_int32 rcode = 1;
708     int i, flag = 0, admin = 0;
709     namelist lnames, names;
710     idlist ids;
711     idlist lids;
712     struct prcheckentry aentry;
713
714     if (GetNameOrId(as, &ids, &names))
715         return PRBADARG;
716
717     lids.idlist_len = 2;
718     lids.idlist_val = (afs_int32 *) malloc(sizeof(afs_int32) * 2);
719     lnames.namelist_len = 0;
720     lnames.namelist_val = 0;
721
722     for (i = 0; i < ids.idlist_len; i++) {
723         afs_int32 id = ids.idlist_val[i];
724
725         if (id == ANONYMOUSID)
726             continue;
727
728         rcode = 0;
729         code = pr_ListEntry(id, &aentry);
730         if (code) {
731             rcode = code;
732             afs_com_err(whoami, code, "; unable to find entry for (id: %d)", id);
733             continue;
734         }
735
736         lids.idlist_val[0] = aentry.owner;
737         lids.idlist_val[1] = aentry.creator;
738         code = pr_IdToName(&lids, &lnames);
739         if (code) {
740             rcode = code;
741             afs_com_err(whoami, code,
742                     "translating owner (%d) and creator (%d) ids",
743                     aentry.owner, aentry.creator);
744             continue;
745         }
746         printf("Name: %s, id: %d, owner: %s, creator: %s,\n", aentry.name,
747                aentry.id, lnames.namelist_val[0], lnames.namelist_val[1]);
748         printf("  membership: %d", aentry.count);
749         {
750             char access[6];
751             afs_int32 flags = aentry.flags;
752             int j, s, new;
753             char c;
754             access[5] = 0;      /* null-terminate the string */
755             for (j = 4; j >= 0; j--) {
756                 s = flags_shift[j];
757                 if (s == 1)
758                     new = flags & 1;
759                 else
760                     new = flags & 3;
761                 if (new == 0)
762                     c = '-';
763                 else if (new == 1) {
764                     c = flags_dncase[j];
765                     if (c == ' ')
766                         c = flags_upcase[j];
767                 } else if (new == 2)
768                     c = flags_upcase[j];
769                 else
770                     c = 'X';
771                 access[j] = c;
772                 flags >>= s;
773             }
774             printf(", flags: %s", access);
775         }
776         if (aentry.id == SYSADMINID)
777             admin = 1;
778         else if (!pr_IsAMemberOf(aentry.name, "system:administrators", &flag)) {
779             if (flag)
780                 admin = 1;
781         }
782         if (admin)
783             printf(", group quota: unlimited");
784         else
785             printf(", group quota: %d", aentry.ngroups);
786 #if FOREIGN
787         printf(", foreign user quota=%d", aentry.nusers);
788 #endif
789         printf(".\n");
790     }
791
792     if (lnames.namelist_val)
793         free(lnames.namelist_val);
794     if (lids.idlist_val)
795         free(lids.idlist_val);
796     if (ids.idlist_val)
797         free(ids.idlist_val);
798
799     return (rcode);
800 }
801
802 static int
803 ListEntries(struct cmd_syndesc *as, void *arock)
804 {
805     afs_int32 code = 0;
806     afs_int32 flag, startindex, nentries, nextstartindex;
807     struct prlistentries *entriesp = 0, *e;
808     afs_int32 i;
809
810     flag = PRUSERS;
811     if (as->parms[1].items)
812         flag = PRGROUPS;
813     if (as->parms[0].items)
814         flag |= PRUSERS;
815
816     printf("Name                          ID  Owner Creator\n");
817     for (startindex = 0; startindex != -1; startindex = nextstartindex) {
818         code =
819             pr_ListEntries(flag, startindex, &nentries, &entriesp,
820                            &nextstartindex);
821         if (code) {
822             afs_com_err(whoami, code, "; unable to list entries");
823             if (entriesp)
824                 free(entriesp);
825             break;
826         }
827
828         /* Now display each of the entries we read */
829         for (i = 0, e = entriesp; i < nentries; i++, e++) {
830             printf("%-25s %6d %6d %7d \n", e->name, e->id, e->owner,
831                    e->creator);
832         }
833         if (entriesp)
834             free(entriesp);
835     }
836     return code;
837 }
838
839 static int
840 ChownGroup(struct cmd_syndesc *as, void *arock)
841 {
842     afs_int32 code;
843     char *name;
844     char *owner;
845
846     name = as->parms[0].items->data;
847     owner = as->parms[1].items->data;
848     code = pr_ChangeEntry(name, "", 0, owner);
849     if (code)
850         afs_com_err(whoami, code, "; unable to change owner of %s to %s", name,
851                 owner);
852     return code;
853 }
854
855 static int
856 ChangeName(struct cmd_syndesc *as, void *arock)
857 {
858     afs_int32 code;
859     char *oldname;
860     char *newname;
861
862     oldname = as->parms[0].items->data;
863     newname = as->parms[1].items->data;
864     code = pr_ChangeEntry(oldname, newname, 0, "");
865     if (code)
866         afs_com_err(whoami, code, "; unable to change name of %s to %s", oldname,
867                 newname);
868     return code;
869 }
870
871 static int
872 ListMax(struct cmd_syndesc *as, void *arock)
873 {
874     afs_int32 code;
875     afs_int32 maxUser, maxGroup;
876
877     code = pr_ListMaxUserId(&maxUser);
878     if (code)
879         afs_com_err(whoami, code, "getting maximum user id");
880     else {
881         code = pr_ListMaxGroupId(&maxGroup);
882         if (code)
883             afs_com_err(whoami, code, "getting maximum group id");
884         else {
885             printf("Max user id is %d and max group id is %d.\n", maxUser,
886                    maxGroup);
887         }
888     }
889     return code;
890 }
891
892 static int
893 SetMaxCommand(struct cmd_syndesc *as, void *arock)
894 {
895     afs_int32 code;
896     afs_int32 maxid;
897
898     code = 0;
899     if (as->parms[1].items) {
900         /* set user max */
901         code = util_GetInt32(as->parms[1].items->data, &maxid);
902         if (code) {
903             afs_com_err(whoami, code, "because id was: '%s'",
904                     as->parms[1].items->data);
905         } else {
906             code = pr_SetMaxUserId(maxid);
907             if (code)
908                 afs_com_err(whoami, code, "so couldn't set Max User Id to %d",
909                         maxid);
910         }
911     }
912     if (as->parms[0].items) {
913         /* set group max */
914         code = util_GetInt32(as->parms[0].items->data, &maxid);
915         if (code) {
916             afs_com_err(whoami, code, "because id was: '%s'",
917                     as->parms[0].items->data);
918         } else {
919             code = pr_SetMaxGroupId(maxid);
920             if (code)
921                 afs_com_err(whoami, code, "so couldn't set Max Group Id to %d",
922                         maxid);
923         }
924     }
925     if (!as->parms[0].items && !as->parms[1].items) {
926         code = PRBADARG;
927         printf("Must specify at least one of group or user.\n");
928     }
929     return code;
930 }
931
932 static int
933 SetFields(struct cmd_syndesc *as, void *arock)
934 {
935     afs_int32 code;
936     idlist ids;
937     namelist names;
938     int i;
939     afs_int32 mask, flags=0, ngroups, nusers;
940
941     if (GetNameOrId(as, &ids, &names))
942         return PRBADARG;
943
944     mask = 0;
945     nusers = 0;
946     ngroups = 0;
947
948     if (as->parms[1].items) {   /* privacy bits */
949         char *access = as->parms[1].items->data;
950         int new;
951
952         if (strpbrk(access, "76543210") != 0) { /* all octal digits */
953             sscanf(access, "%lo", (long unsigned int *) &flags);
954         } else {                /* interpret flag bit names */
955             if (strlen(access) != 5) {
956               form_error:
957                 printf("Access bits must be of the form 'somar', not %s\n",
958                        access);
959                 return PRBADARG;
960             }
961             if (strpbrk(access, "somar-") == 0)
962                 goto form_error;
963             flags = 0;
964             for (i = 0; i < 5; i++) {
965                 if (access[i] == flags_upcase[i])
966                     new = 2;
967                 else if (access[i] == flags_dncase[i])
968                     new = 1;
969                 else if (access[i] == '-')
970                     new = 0;
971                 else {
972                     printf
973                         ("Access bits out of order or illegal:\n  must be a combination of letters from '%s' or '%s' or hyphen, not %s\n",
974                          flags_upcase, flags_dncase, access);
975                     return PRBADARG;
976                 }
977                 flags <<= flags_shift[i];
978                 if (flags_shift[i] == 1) {
979                     if (new)
980                         flags |= 1;
981                 } else
982                     flags |= new;
983             }
984         }
985         mask |= PR_SF_ALLBITS;
986     }
987     if (as->parms[2].items) {   /* limitgroups */
988         code = util_GetInt32(as->parms[2].items->data, &ngroups);
989         if (code) {
990             afs_com_err(whoami, code, "because ngroups was: '%s'",
991                     as->parms[2].items->data);
992             return code;
993         }
994         mask |= PR_SF_NGROUPS;
995     }
996 #if FOREIGN
997     if (as->parms[3].items) {   /* limitgroups */
998         code = util_GetInt32(as->parms[3].items->data, &nusers);
999         if (code) {
1000             afs_com_err(whoami, code, "because nusers was: '%s'",
1001                     as->parms[3].items->data);
1002             return code;
1003         }
1004         mask |= PR_SF_NUSERS;
1005     }
1006 #endif
1007
1008     for (i = 0; i < ids.idlist_len; i++) {
1009         afs_int32 id = ids.idlist_val[i];
1010         char *name = names.namelist_val[i];
1011         if (id == ANONYMOUSID)
1012             continue;
1013         code = pr_SetFieldsEntry(id, mask, flags, ngroups, nusers);
1014         if (code) {
1015             afs_com_err(whoami, code, "; unable to set fields for %s (id: %d)",
1016                     name, id);
1017             return code;
1018         }
1019     }
1020     if (ids.idlist_val)
1021         free(ids.idlist_val);
1022     if (names.namelist_val)
1023         free(names.namelist_val);
1024     return 0;
1025 }
1026
1027 static int
1028 ListOwned(struct cmd_syndesc *as, void *arock)
1029 {
1030     afs_int32 code;
1031     idlist ids;
1032     namelist names;
1033     namelist list;
1034     int i, j;
1035     afs_int32 more;
1036
1037     if (GetNameOrId(as, &ids, &names))
1038         return PRBADARG;
1039
1040     for (i = 0; i < ids.idlist_len; i++) {
1041         afs_int32 oid = ids.idlist_val[i];
1042         char *name = names.namelist_val[i];
1043
1044         if (oid == ANONYMOUSID)
1045             continue;
1046
1047         if (oid)
1048             printf("Groups owned by %s (id: %d) are:\n", name, oid);
1049         else
1050             printf("Orphaned groups are:\n");
1051         more = 0;
1052         do {
1053             list.namelist_val = 0;
1054             list.namelist_len = 0;
1055             code = pr_ListOwned(oid, &list, &more);
1056             if (code) {
1057                 afs_com_err(whoami, code,
1058                         "; unable to get owner list for %s (id: %d)", name,
1059                         oid);
1060                 break;
1061             }
1062
1063             for (j = 0; j < list.namelist_len; j++)
1064                 printf("  %s\n", list.namelist_val[j]);
1065             if (list.namelist_val)
1066                 free(list.namelist_val);
1067         } while (more);
1068     }
1069
1070     if (ids.idlist_val)
1071         free(ids.idlist_val);
1072     if (names.namelist_val)
1073         free(names.namelist_val);
1074     return 0;
1075 }
1076
1077 static void
1078 add_std_args(struct cmd_syndesc *ts)
1079 {
1080     char test_help[AFSDIR_PATH_MAX];
1081
1082     sprintf(test_help, "use config file in %s", AFSDIR_SERVER_ETC_DIRPATH);
1083
1084     cmd_Seek(ts, 16);
1085     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1086     cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL, "run unauthenticated");
1087     cmd_AddParm(ts, "-test", CMD_FLAG, CMD_OPTIONAL | CMD_HIDE, test_help);
1088     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
1089                 "Continue oper despite reasonable errors");
1090     cmd_AddParm(ts, "-localauth", CMD_FLAG, CMD_OPTIONAL,
1091                 "use local authentication");
1092     cmd_AddParm(ts, "-auth", CMD_FLAG, CMD_OPTIONAL,
1093                 "use user's authentication (default)");
1094     cmd_AddParm(ts, "-encrypt", CMD_FLAG, CMD_OPTIONAL,
1095                 "encrypt commands");
1096 }
1097
1098 /*
1099 static void add_NameOrId_args (ts)
1100   struct cmd_syndesc *ts;
1101 {
1102     cmd_AddParm(ts,"-name",CMD_LIST,CMD_OPTIONAL,"user or group name");
1103     cmd_AddParm(ts,"-id",CMD_LIST,CMD_OPTIONAL,"user or group id");
1104 }
1105 */
1106
1107 #include "AFS_component_version_number.c"
1108
1109 int
1110 main(int argc, char **argv)
1111 {
1112     afs_int32 code;
1113     struct cmd_syndesc *ts;
1114
1115     char line[2048];
1116     char *cp, *lastp;
1117     int parsec;
1118     char *parsev[CMD_MAXPARMS];
1119     char *savec;
1120     struct authstate state;
1121
1122 #ifdef WIN32
1123     WSADATA WSAjunk;
1124 #endif
1125
1126 #ifdef WIN32
1127     WSAStartup(0x0101, &WSAjunk);
1128 #endif
1129
1130 #ifdef  AFS_AIX32_ENV
1131     /*
1132      * The following signal action for AIX is necessary so that in case of a
1133      * crash (i.e. core is generated) we can include the user's data section
1134      * in the core dump. Unfortunately, by default, only a partial core is
1135      * generated which, in many cases, isn't too useful.
1136      */
1137     struct sigaction nsa;
1138
1139     sigemptyset(&nsa.sa_mask);
1140     nsa.sa_handler = SIG_DFL;
1141     nsa.sa_flags = SA_FULLDUMP;
1142     sigaction(SIGSEGV, &nsa, NULL);
1143 #endif
1144
1145     memset(&state, 0, sizeof(state));
1146     state.sec = 1; /* default is auth */
1147
1148     ts = cmd_CreateSyntax("creategroup", CreateGroup, NULL,
1149                           "create a new group");
1150     cmd_AddParm(ts, "-name", CMD_LIST, 0, "group name");
1151     cmd_AddParm(ts, "-owner", CMD_SINGLE, CMD_OPTIONAL, "owner of the group");
1152     cmd_AddParm(ts, "-id", CMD_LIST, CMD_OPTIONAL,
1153                 "id (negated) for the group");
1154     add_std_args(ts);
1155     cmd_CreateAlias(ts, "cg");
1156
1157     ts = cmd_CreateSyntax("createuser", CreateUser, NULL, "create a new user");
1158     cmd_AddParm(ts, "-name", CMD_LIST, 0, "user name");
1159     cmd_AddParm(ts, "-id", CMD_LIST, CMD_OPTIONAL, "user id");
1160     add_std_args(ts);
1161     cmd_CreateAlias(ts, "cu");
1162
1163     ts = cmd_CreateSyntax("adduser", AddToGroup, NULL, "add a user to a group");
1164     cmd_AddParm(ts, "-user", CMD_LIST, 0, "user name");
1165     cmd_AddParm(ts, "-group", CMD_LIST, 0, "group name");
1166     add_std_args(ts);
1167
1168     ts = cmd_CreateSyntax("removeuser", RemoveFromGroup, NULL,
1169                           "remove a user from a group");
1170     cmd_AddParm(ts, "-user", CMD_LIST, 0, "user name");
1171     cmd_AddParm(ts, "-group", CMD_LIST, 0, "group name");
1172     add_std_args(ts);
1173
1174     ts = cmd_CreateSyntax("membership", ListMembership, NULL,
1175                           "list membership of a user or group");
1176     cmd_AddParm(ts, "-nameorid", CMD_LIST, 0, "user or group name or id");
1177     cmd_AddParm(ts, "-supergroups", CMD_FLAG, CMD_OPTIONAL, "show supergroups");
1178     cmd_AddParm(ts, "-expandgroups", CMD_FLAG, CMD_OPTIONAL, "expand super and sub group membership");
1179     add_std_args(ts);
1180     cmd_CreateAlias(ts, "groups");
1181
1182     ts = cmd_CreateSyntax("delete", Delete, NULL,
1183                           "delete a user or group from database");
1184     cmd_AddParm(ts, "-nameorid", CMD_LIST, 0, "user or group name or id");
1185     add_std_args(ts);
1186
1187     ts = cmd_CreateSyntax("examine", CheckEntry, NULL, "examine an entry");
1188     cmd_AddParm(ts, "-nameorid", CMD_LIST, 0, "user or group name or id");
1189     add_std_args(ts);
1190     cmd_CreateAlias(ts, "check");
1191
1192     ts = cmd_CreateSyntax("chown", ChownGroup, NULL,
1193                           "change ownership of a group");
1194     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "group name");
1195     cmd_AddParm(ts, "-owner", CMD_SINGLE, 0, "new owner");
1196     add_std_args(ts);
1197
1198     ts = cmd_CreateSyntax("rename", ChangeName, NULL, "rename user or group");
1199     cmd_AddParm(ts, "-oldname", CMD_SINGLE, 0, "old name");
1200     cmd_AddParm(ts, "-newname", CMD_SINGLE, 0, "new name");
1201     add_std_args(ts);
1202     cmd_CreateAlias(ts, "chname");
1203
1204     ts = cmd_CreateSyntax("listmax", ListMax, NULL, "list max id");
1205     add_std_args(ts);
1206
1207     ts = cmd_CreateSyntax("setmax", SetMaxCommand, NULL, "set max id");
1208     cmd_AddParm(ts, "-group", CMD_SINGLE, CMD_OPTIONAL, "group max");
1209     cmd_AddParm(ts, "-user", CMD_SINGLE, CMD_OPTIONAL, "user max");
1210     add_std_args(ts);
1211
1212     ts = cmd_CreateSyntax("setfields", SetFields, NULL,
1213                           "set fields for an entry");
1214     cmd_AddParm(ts, "-nameorid", CMD_LIST, 0, "user or group name or id");
1215     cmd_AddParm(ts, "-access", CMD_SINGLE, CMD_OPTIONAL, "set privacy flags");
1216     cmd_AddParm(ts, "-groupquota", CMD_SINGLE, CMD_OPTIONAL,
1217                 "set limit on group creation");
1218 #if FOREIGN
1219     cmd_AddParm(ts, "-userquota", CMD_SINGLE, CMD_OPTIONAL,
1220                 "set limit on foreign user creation");
1221 #endif
1222     add_std_args(ts);
1223
1224     ts = cmd_CreateSyntax("listowned", ListOwned, NULL,
1225                           "list groups owned by an entry or zero id gets orphaned groups");
1226     cmd_AddParm(ts, "-nameorid", CMD_LIST, 0, "user or group name or id");
1227     add_std_args(ts);
1228
1229     ts = cmd_CreateSyntax("listentries", ListEntries, NULL,
1230                           "list users/groups in the protection database");
1231     cmd_AddParm(ts, "-users", CMD_FLAG, CMD_OPTIONAL, "list user entries");
1232     cmd_AddParm(ts, "-groups", CMD_FLAG, CMD_OPTIONAL, "list group entries");
1233     add_std_args(ts);
1234
1235     ts = cmd_CreateSyntax("interactive", pts_Interactive, NULL,
1236                           "enter interactive mode");
1237     add_std_args(ts);
1238     cmd_CreateAlias(ts, "in");
1239
1240     ts = cmd_CreateSyntax("quit", pts_Quit, NULL, "exit program");
1241     add_std_args(ts);
1242
1243     ts = cmd_CreateSyntax("source", pts_Source, NULL, "read commands from file");
1244     cmd_AddParm(ts, "-file", CMD_SINGLE, 0, "filename");
1245     add_std_args(ts);
1246
1247     ts = cmd_CreateSyntax("sleep", pts_Sleep, NULL, "pause for a bit");
1248     cmd_AddParm(ts, "-delay", CMD_SINGLE, 0, "seconds");
1249     add_std_args(ts);
1250
1251     cmd_SetBeforeProc(GetGlobals, &state);
1252
1253     finished = 1;
1254     source = NULL;
1255     if ((code = cmd_Dispatch(argc, argv))) {
1256         CleanUp(NULL, NULL);
1257         exit(1);
1258     }
1259     while (source && !finished) {
1260         if (isatty(fileno(source)))
1261             fprintf(stderr, "pts> ");
1262         if (!fgets(line, sizeof line, source)) {
1263             if (!popsource())
1264                 break;
1265             continue;
1266         }
1267         lastp = 0;
1268         for (cp = line; *cp; ++cp)
1269             if (!isspace(*cp))
1270                 lastp = 0;
1271             else if (!lastp)
1272                 lastp = cp;
1273         if (lastp)
1274             *lastp = 0;
1275         if (!*line)
1276             continue;
1277         code =
1278             cmd_ParseLine(line, parsev, &parsec,
1279                           sizeof(parsev) / sizeof(*parsev));
1280         if (code) {
1281             afs_com_err(whoami, code, "parsing line: <%s>", line);
1282             exit(2);
1283         }
1284         savec = parsev[0];
1285         parsev[0] = argv[0];
1286         code = cmd_Dispatch(parsec, parsev);
1287         parsev[0] = savec;
1288         cmd_FreeArgv(parsev);
1289     }
1290     CleanUp(NULL, NULL);
1291     exit(0);
1292 }