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