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