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