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