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