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