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