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