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