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