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