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