Use calloc, rather than malloc/memset
[openafs.git] / src / ptserver / testpt.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 #include <afs/opr.h>
15
16 #include <ctype.h>
17 #include <math.h>
18
19 #ifdef AFS_NT40_ENV
20 #include <WINNT/afsevent.h>
21 #endif
22
23 #include <rx/rx.h>
24 #include <rx/xdr.h>
25 #include <afs/rxgen_consts.h>
26 #include <afs/cmd.h>
27 #include <afs/auth.h>
28 #include <afs/cellconfig.h>
29 #include <afs/afsutil.h>
30 #include <afs/com_err.h>
31
32 #include "ptclient.h"
33 #include "pterror.h"
34 #include "ptuser.h"
35 #include "ptprototypes.h"
36
37 static char *whoami = "testpr";
38 static struct afsconf_dir *conf;        /* cell info, set by MyBeforeProc */
39 static char conf_dir[100];
40 static char lcell[MAXCELLCHARS];
41
42 int
43 ListUsedIds(struct cmd_syndesc *as, void *arock)
44 {
45     afs_int32 code;
46     namelist lnames;
47     idlist lids;
48     int i, j;
49     int group = 0;              /* check groups */
50     int unused = 0;             /* print unused */
51     int number = 100;           /* check 100 ids */
52     afs_int32 startId = 1;
53     afs_int32 maxId;
54     int range;
55
56     if (as->parms[0].items)
57         startId = atoi(as->parms[0].items->data);
58     if (as->parms[1].items)
59         number = atoi(as->parms[1].items->data);
60     if (as->parms[2].items)
61         unused = 1;
62
63     code = pr_Initialize(1, conf_dir, NULL);
64     if (code) {
65         afs_com_err(whoami, code, "initializing pruser");
66         exit(1);
67     }
68     if (startId < 0) {
69         group = 1;
70         code = pr_ListMaxGroupId(&maxId);
71         if (code) {
72           bad_max:
73             afs_com_err(whoami, code, "getting maximum id");
74             exit(2);
75         }
76         if (startId < maxId) {
77             fprintf(stderr, "Max group id is only %d.\n", maxId);
78             exit(3);
79         }
80     } else {
81         code = pr_ListMaxUserId(&maxId);
82         if (code)
83             goto bad_max;
84         if (startId > maxId) {
85             fprintf(stderr, "Max user id is only %d.\n", maxId);
86             exit(3);
87         }
88     }
89     range = abs(startId - maxId);
90     if (range < 0)
91         range = -range;
92     range++;                    /* number that can be printed */
93     if (range < number) {
94         fprintf(stderr, "Only %d ids to be checked.\n", range);
95         number = range;
96     }
97
98     printf("Checking for %d %sused ids starting at %d.\n", number,
99            (unused ? "un" : ""), startId);
100 #define NUM 100
101     lids.idlist_val = (afs_int32 *) malloc(sizeof(afs_int32) * NUM);
102     lnames.namelist_len = 0;
103     lnames.namelist_val = 0;
104     while (number) {
105         if (number < NUM)
106             i = number;
107         else
108             i = NUM;
109         for (j = 0; j < i; j++) {
110             lids.idlist_val[j] = startId;
111             if (group)
112                 startId--;
113             else
114                 startId++;
115         }
116         lids.idlist_len = i;
117         code = pr_IdToName(&lids, &lnames);
118         if (code) {
119             afs_com_err(whoami, code, "converting id to name");
120             exit(2);
121         }
122         for (j = 0; j < lnames.namelist_len; j++) {
123             if (lids.idlist_val[j] == atoi(lnames.namelist_val[j])) {
124                 if (unused)
125                     printf("%s is free\n", lnames.namelist_val[j]);
126             } else {
127                 if (!unused)
128                     printf("%s is id %d\n", lnames.namelist_val[j],
129                            lids.idlist_val[j]);
130             }
131         }
132         number -= i;
133     }
134     if (lids.idlist_val)
135         free(lids.idlist_val);
136     if (lnames.namelist_val)
137         free(lnames.namelist_val);
138     return 0;
139 }
140
141 /* TestManyMembers - called with a number N.  Try creating N users and N groups
142  * and put all the users on one of the groups and one of the users on all the
143  * groups.  Also put many users on many groups.
144  *
145  * To keep track of this create an NxN matrix of membership and fill it in with
146  * a function that looks like a quarter of a circle.  That makes the first
147  * group contain every user and the first user be a member of every group. */
148
149 int verbose;
150 char callerName[PR_MAXNAMELEN];
151 afs_int32 callerId;
152 afs_int32 lastGroup;            /* id of last group created */
153 afs_int32 ownerUser;            /* first created user */
154 char ownerUserName[PR_MAXNAMELEN];      /*  " " " name */
155 int steepDropOff;               /* precentage decreate in GroupLimit */
156 char *createPrefix;             /* prefix for naming users&groups */
157 extern struct ubik_client *pruclient;   /* initialized by pr_Initialize */
158
159 /* These variables form the state if this test */
160 int number;                     /* max number of members */
161 char *population;               /* matrix of memberships */
162 afs_int32 *users;               /* ids of users */
163 afs_int32 *groups;              /* ids of groups */
164 afs_int32 *groupOwners;         /* ids of owners of groups */
165
166 /* statistics */
167 int nUsers, nGroups, nAdds, nRems, nUDels, nGDels;
168
169 int
170 IdCmp(const void *a, const void *b)
171 {
172     if (*(afs_int32 *)a > *(afs_int32 *)b) {
173         return 1;
174     } else if (*(afs_int32 *)a == *(afs_int32 *)b) {
175         return 0;
176     } else /* (*a < *b) */ {
177         return -1;
178     }
179 }
180
181 static int
182 sqr(int n)
183 {
184     return n * n;
185 }
186
187 static int
188 GetGroupLimit(int N, int x)
189 {
190     int y;
191
192     if ((x >= N) || (x < 0)) {
193         printf("GetGroupLimit: input value out of range %d (%d)\n", x, N);
194         exit(10);
195     }
196     if (steepDropOff) {         /* Use exponential decrease */
197         int i;
198         y = N;
199         for (i = 0; i < x; i++) {
200             y = (y * steepDropOff) / 100;       /* parameter is a percentage */
201             if (y == 0) {
202                 y = 1;          /* with a floor of 1 */
203                 break;
204             }
205         }
206     } else {                    /* Use a circle's third quadrant */
207         y = sqr(N - 1) - sqr(N - 1 - x);
208         y = (int)(sqrt((double)y) + 0.5);       /* round off */
209         y = N - y;
210     }
211     if ((y > N) || (y < 1)) {
212         printf("filling value out of range: %d (%d) => %d\n", x, N, y);
213         exit(11);
214     }
215     return y;
216 }
217
218 void
219 CreateUser(int u)
220 {
221     afs_int32 code;
222     char name[16];
223     afs_int32 id;
224
225     sprintf(name, "%s%d", createPrefix, u);
226     id = 0;
227     code = pr_CreateUser(name, &id);
228     if (code) {
229         if (code == PREXIST) {
230             code = pr_Delete(name);
231             if (code == 0) {
232                 nUDels++;
233                 code = pr_CreateUser(name, &id);
234                 if (code == 0) {
235                     if (verbose)
236                         printf("RE-");
237                     goto done;
238                 }
239             }
240         }
241         afs_com_err(whoami, code, "couldn't create %s", name);
242         exit(12);
243     }
244   done:
245     if (verbose)
246         printf("Creating user %s (%di)\n", name, id);
247     users[u] = id;
248     nUsers++;
249
250     if (ownerUser == 0) {
251         ownerUser = id;
252         strcpy(ownerUserName, name);
253     }
254 }
255
256 void
257 CreateGroup(int g)
258 {
259     afs_int32 code;
260     char name[16];
261     afs_int32 id = 0;
262     afs_int32 owner = 0;
263     char *ownerName = NULL;
264     int ownerType;              /* type of ownership */
265     static char *lastGroupPrefix;       /* prefix used for type==2 */
266
267     /* At least 50 groups should be owned by another group to test long owner
268      * chains during deletion.  Also let's create some long owners of owners
269      * lists.  */
270     ownerType = random() % 3;
271
272     if (!ownerUser)
273         ownerType = 0;
274     if (!lastGroup)
275         ownerType = 0;
276     switch (ownerType) {
277     case 0:
278         owner = callerId;
279         ownerName = callerName;
280         break;
281     case 1:
282         owner = ownerUser;
283         ownerName = ownerUserName;
284         break;
285     case 2:
286         owner = lastGroup;
287         ownerName = lastGroupPrefix;
288         break;
289     }
290
291     sprintf(name, "%s:%s%d", ownerName, createPrefix, g);
292     code = ubik_PR_NewEntry(pruclient, 0, name, PRGRP, owner, &id);
293     if (code) {
294         if (code == PREXIST) {
295             code = pr_Delete(name);
296             if (code == 0) {
297                 nGDels++;
298                 code =
299                     ubik_PR_NewEntry(pruclient, 0, name, PRGRP, owner,
300                               &id);
301                 if (code == 0) {
302                     if (verbose)
303                         printf("RE-");
304                     goto done;
305                 }
306             }
307         }
308         afs_com_err(whoami, code, "couldn't create %s w/ owner=%d", name, owner);
309         exit(13);
310     }
311   done:
312     if (verbose)
313         printf("Creating group %s (%di)\n", name, id);
314     groups[g] = id;
315     groupOwners[g] = owner;
316     nGroups++;
317     if (!lastGroup || (ownerType == 2)) {
318         lastGroup = id;
319         lastGroupPrefix = ownerName;
320     }
321 }
322
323 int
324 DeleteRandomId(afs_int32 *list)
325 {
326     afs_int32 code;
327     afs_int32 id;
328     int j, k;
329     int m;
330
331     k = random();               /* random starting point */
332     for (j = 0; j < number; j++) {      /* find an undeleted id */
333         m = (k + j) % number;
334         if ((id = list[m])) {
335             code = ubik_PR_Delete(pruclient, 0, id);
336             if (code) {
337                 afs_com_err(whoami, code, "Couldn't delete %di", id);
338                 exit(22);
339             }
340             list[m] = 0;
341             if (list == users)
342                 nUDels++;
343             else
344                 nGDels++;
345             return 0;
346         }
347     }
348     return -1;                  /* none left */
349 }
350
351 void
352 AddUser(int u, int g)
353 {
354     afs_int32 code;
355     afs_int32 ui, gi;
356
357     if (users[u] == 0)          /* create if necessary */
358         CreateUser(u);
359     if (groups[g] == 0)         /* create group if necessary */
360         CreateGroup(g);
361     ui = users[u];
362     gi = groups[g];
363     code = ubik_PR_AddToGroup(pruclient, 0, ui, gi);
364     if (code) {
365         afs_com_err(whoami, code, "couldn't add %d to %d", ui, gi);
366         exit(14);
367     }
368     if (verbose)
369         printf("Adding user (%di) to group (%di)\n", ui, gi);
370     population[u * number + g]++;
371     nAdds++;
372 }
373
374 void
375 RemUser(int u, int g)
376 {
377     afs_int32 code;
378     afs_int32 ui, gi;
379
380     ui = users[u];
381     gi = groups[g];
382     code = ubik_PR_RemoveFromGroup(pruclient, 0, ui, gi);
383     if (code) {
384         afs_com_err(whoami, code, "couldn't remove %d from %d", ui, gi);
385         exit(14);
386     }
387     if (verbose)
388         printf("Removing user (%di) from group (%di)\n", ui, gi);
389     population[u * number + g]--;
390     nRems++;
391 }
392
393 int
394 TestManyMembers(struct cmd_syndesc *as, void *arock)
395 {
396     char *filled;               /* users filled up */
397     char *cleaned;              /* users cleaned up */
398
399     int nFilled, nCleaned;
400     int u, g, i, j, n;
401     int seed;                   /* random number generator seed */
402
403     afs_int32 *glist;           /* membership list */
404
405     afs_int32 code;
406
407     code = pr_Initialize(1, conf_dir, NULL);
408     if (code) {
409         afs_com_err(whoami, code, "initializing pruser");
410         exit(1);
411     }
412     /* get name of person running command */
413     {
414         struct ktc_principal afs, user;
415         struct ktc_token token;
416
417         strcpy(afs.name, "afs");
418         strcpy(afs.instance, "");
419         code = afsconf_GetLocalCell(conf, afs.cell, sizeof(afs.cell));
420         if (code)
421             exit(2);
422         code = ktc_GetToken(&afs, &token, sizeof(token), &user);
423         if (code) {
424             afs_com_err(whoami, code, "getting afs tokens");
425             exit(3);
426         }
427         if (strlen(user.instance) > 0) {
428             fprintf(stderr, "can't handle non-null instance %s.%s\n",
429                     user.name, user.cell);
430             exit(4);
431         }
432         if (strncmp(user.name, "AFS ID ", 7) == 0) {
433             callerId = atoi(user.name + 7);
434             code = pr_SIdToName(callerId, callerName);
435             if (code) {
436                 afs_com_err(whoami, code, "call get name for id %d", callerId);
437                 exit(6);
438             }
439         } else {
440             strcpy(callerName, user.name);
441             code = pr_SNameToId(callerName, &callerId);
442             if ((code == 0) && (callerId == ANONYMOUSID))
443                 code = PRNOENT;
444         }
445 #if 0                           /* don't create user */
446         if (code == PRNOENT) {
447             callerId = 0;
448             code = pr_CreateUser(callerName, &callerId);
449             if (code) {
450                 afs_com_err(whoami, code, "can't create caller %s", callerName);
451                 exit(5);
452             }
453             printf("Creating caller %s (%di)\n", callerName, callerId);
454         }
455         /* else */
456 #endif
457         if (code) {
458             afs_com_err(whoami, code, "can't find caller %s", callerName);
459             exit(6);
460         } else
461             printf("Assuming caller is %s (%di)\n", callerName, callerId);
462     }
463
464     /* Parse arguments */
465     if (as->parms[0].items)
466         number = atoi(as->parms[0].items->data);
467     if (as->parms[1].items) {
468         steepDropOff = atoi(as->parms[1].items->data);
469         if ((steepDropOff < 0) || (steepDropOff > 100)) {
470             fprintf(stderr,
471                     "Illegal value for dropoff: %d, must be between 0 and 100, inclusive.\n",
472                     steepDropOff);
473             exit(7);
474         }
475     } else
476         steepDropOff = 0;       /* use quadratic dropoff */
477     if (as->parms[2].items)
478         createPrefix = as->parms[2].items->data;
479     else
480         createPrefix = "u";
481     if (as->parms[3].items)
482         verbose = 1;
483     else
484         verbose = 0;
485     if (as->parms[4].items)
486         seed = atoi(as->parms[4].items->data);
487     else
488         seed = 1;
489
490     srandom(seed);
491
492     users = calloc(number, sizeof(afs_int32));
493     groups = calloc(number, sizeof(afs_int32));
494     filled = calloc(number, sizeof(char));
495     cleaned = calloc(number, sizeof(char));
496     population = calloc(sqr(number), sizeof(char));
497
498     nFilled = 0;
499     nCleaned = 0;
500
501     ownerUser = lastGroup = 0;
502     groupOwners = (afs_int32 *) malloc(number * sizeof(afs_int32));
503     nUsers = nGroups = nAdds = nRems = nUDels = nGDels = 0;
504
505     while ((nFilled < number) || (nCleaned < number)) {
506         /* pick a user at random, using  */
507         u = random() % number;
508         if (!filled[u]) {
509             n = GetGroupLimit(number, u);       /* get group limit for that user */
510             g = random() % (n + 1);     /* pick a random group */
511             if (g == n) {       /* in a few cases create any user */
512                 n = number;     /* in the whole range */
513                 g = random() % n;
514             }
515             for (i = 0; i < n; i++) {   /* rotate until unused one found */
516                 j = (g + i) % n;
517                 if (!population[u * number + j]) {
518                     /* add this user/group membership */
519                     AddUser(u, j);
520                     goto added;
521                 }
522             }
523             filled[u]++;
524             nFilled++;
525           added:;
526         }
527         if (!cleaned[u]) {
528             int base;
529             if (filled[u]) {    /* only clean above GroupLimit */
530                 base = GetGroupLimit(number, u);
531                 n = number - base;
532                 if (n == 0)
533                     goto iscleaned;
534                 g = random() % n;
535             } else {
536                 base = 0;
537                 n = number;     /* pick a group from the whole range */
538                 g = random() % 2 * n;   /* at random for removal */
539                 if (g >= n)
540                     goto remed; /* but half the time do nothing */
541             }
542             for (i = 0; i < n; i++) {   /* rotate until used one found */
543                 j = (g + i) % n + base;
544                 if (population[u * number + j]) {
545                     /* remove this user/group membership */
546                     RemUser(u, j);
547                     goto remed;
548                 }
549             }
550             if (filled[u]) {    /* track finished ones */
551               iscleaned:
552                 cleaned[u]++;
553                 nCleaned++;
554             }
555           remed:;
556         }
557     }
558
559     /* check the membership list of all users for correctness */
560     printf("Starting check of memberships\n");
561     glist = (afs_int32 *) malloc(number * sizeof(afs_int32));
562     for (u = 0; u < number; u++) {
563         afs_int32 ui = users[u];
564         if (ui) {
565             int i;
566             int ng;             /* number groups */
567             int over;
568             int (*proc)(struct ubik_client *, afs_int32, afs_int32, prlist *,
569                         afs_int32 *);
570             prlist alist;
571
572             alist.prlist_len = 0;
573             alist.prlist_val = 0;
574             if (random() & 4) {
575                 proc = ubik_PR_ListElements;
576             } else {
577                 proc = ubik_PR_GetCPS;
578             }
579             code = (*proc)(pruclient, 0, ui, &alist, &over);
580             if (code) {
581                 afs_com_err(whoami, code,
582                         "getting membership list of (%di) using %s", ui,
583                         (proc == ubik_PR_ListElements?"ListElements":"GetCPS"));
584                 exit(24);
585             }
586             if (over) {
587                 fprintf(stderr, "membership list for id %di too long\n", ui);
588             }
589             ng = 0;
590             for (i = 0; i < number; i++)
591                 if (population[u * number + i])
592                     glist[ng++] = groups[i];
593             qsort(glist, ng, sizeof(afs_int32), IdCmp);
594             if (ng != (alist.prlist_len - ((proc == ubik_PR_GetCPS) ? 3 : 0))) {
595                 fprintf(stderr,
596                         "Membership list for %di of unexpected length: was %d but expected %d\n",
597                         ui, alist.prlist_len, ng);
598                 exit(20);
599             }
600             /* all the extra entries for the CPS should be at the end. */
601             code = 0;
602             for (i = 0; i < ng; i++)
603                 if (alist.prlist_val[i] != glist[i]) {
604                     fprintf(stderr,
605                             "membership for %di not correct: was %di but expected %di\n",
606                             ui, alist.prlist_val[i], glist[i]);
607                     code++;
608                 }
609             if (code)
610                 exit(21);
611             if (proc == ubik_PR_GetCPS) {
612                 if ((alist.prlist_val[i /* =ng */ ] != AUTHUSERID) ||
613                     (alist.prlist_val[++i] != ANYUSERID)
614                     || (alist.prlist_val[++i] != ui)) {
615                     fprintf(stderr, "CPS doesn't have extra entries\n");
616                     exit(27);
617                 }
618             }
619             if (alist.prlist_val)
620                 free(alist.prlist_val);
621
622             /* User 0 is a member of all groups all of which should also be on
623              * the owner list of the caller or the ownerUser, although there
624              * may also be others.  Check this. */
625             if (u == 0) {
626                 prlist callerList;
627                 prlist ownerList;
628                 prlist lastGroupList;
629                 int i, j, k, l;
630
631                 if (ng != number) {
632                     fprintf(stderr, "User 0 not a member of all groups\n");
633                     exit(26);
634                 }
635 #define GETOWNED(xlist,xid) \
636   (xlist).prlist_val = 0; (xlist).prlist_len = 0; \
637   code = ubik_PR_ListOwned(pruclient, 0, (xid), &(xlist), &over); \
638   if (code) { \
639       afs_com_err (whoami, code, "getting owner list of (%di)", (xid)); \
640       exit (23); } \
641   if (over) \
642       { fprintf (stderr, "membership of id %di too long\n", (xid)); }
643
644                 GETOWNED(callerList, callerId);
645                 GETOWNED(ownerList, ownerUser);
646
647                 /* look for every entry in glist, in all the owner lists */
648                 for (i = j = k = l = 0; i < number; i++) {
649                     while ((j < callerList.prlist_len)
650                            && (callerList.prlist_val[j] < glist[i]))
651                         j++;
652                     while ((k < ownerList.prlist_len)
653                            && (ownerList.prlist_val[k] < glist[i]))
654                         k++;
655 #define PRLISTCMP(l,i) \
656   (((l).prlist_len == 0) || (glist[i] != (l).prlist_val[(i)]))
657                     if (PRLISTCMP(callerList, j) && PRLISTCMP(ownerList, k)) {
658                         for (l = 0; l < number; l++) {
659                             if (groups[l] == glist[i]) {
660                                 if ((groupOwners[l] != callerId)
661                                     && (groupOwners[l] != ownerUser)) {
662                                     GETOWNED(lastGroupList, groupOwners[l]);
663                                     if ((lastGroupList.prlist_len != 1)
664                                         || (lastGroupList.prlist_val[0] !=
665                                             glist[i])) {
666                                         fprintf(stderr,
667                                                 "Group (%di) not on any owner list\n",
668                                                 glist[i]);
669                                         exit(25);
670                                     }
671                                 }
672                                 goto foundLast;
673                             }
674                         }
675                         fprintf(stderr, "unexpected group %di\n", glist[i]);
676                       foundLast:;
677                     }
678                 }
679                 if (callerList.prlist_val)
680                     free(callerList.prlist_val);
681                 if (ownerList.prlist_val)
682                     free(ownerList.prlist_val);
683                 if (lastGroupList.prlist_val)
684                     free(lastGroupList.prlist_val);
685             }
686         }
687     }
688
689     /* cleanup by deleting all the users and groups */
690     printf("Starting deletion of users and groups\n");
691     for (i = 0; i < number; i++) {
692         DeleteRandomId(users);
693         DeleteRandomId(groups);
694     }
695
696     printf
697         ("Created/deleted %d/%d users and %d/%d groups; added %d and removed %d.\n",
698          nUsers, nUDels, nGroups, nGDels, nAdds, nRems);
699     return 0;
700 }
701
702 /* from ka_ConvertBytes included here to avoid circularity */
703 /* Converts a byte string to ascii.  Return the number of unconverted bytes. */
704
705 static int
706 ka_ConvertBytes(char *ascii,            /* output buffer */
707                 int alen,               /* buffer length */
708                 char bs[],              /* byte string */
709                 int bl)                 /* number of bytes */
710 {
711     int i;
712     unsigned char c;
713
714     alen--;                     /* make room for termination */
715     for (i = 0; i < bl; i++) {
716         c = bs[i];
717         if (alen <= 0)
718             return bl - i;
719         if (isalnum(c) || ispunct(c))
720             (*ascii++ = c), alen--;
721         else {
722             if (alen <= 3)
723                 return bl - i;
724             *ascii++ = '\\';
725             *ascii++ = (c >> 6) + '0';
726             *ascii++ = (c >> 3 & 7) + '0';
727             *ascii++ = (c & 7) + '0';
728             alen -= 4;
729         }
730     }
731     *ascii = 0;                 /* terminate string */
732     return 0;
733 }
734
735 /* This runs various tests on the server.  It creates, then deletes, a bunch of
736  * users and groups, so it would be safest to run it on a test database.
737  *
738  * These are the things I check for:
739  *   User names longer than PR_MAXNAMELEN - strlen(cellname).
740  *   Group names longer than PR_MAXNAMELEN.
741  *   User names containing all legal 8-bit ascii characters.  This excludes
742  *     only ':', '@', and '\n'.
743  *   Group names as above, but at least one colon is required, and the owner
744  *     must be correct.
745  */
746
747 int
748 TestPrServ(struct cmd_syndesc *as, void *arock)
749 {
750     afs_int32 id;
751     char name[PR_MAXNAMELEN + 1];
752     char creator[PR_MAXNAMELEN];        /* our name */
753     struct prcheckentry ent;
754     afs_int32 code;
755     int i, j;
756     int maxLen = PR_MAXNAMELEN - 1 - strlen(lcell) - 1;
757
758     code = pr_Initialize(1, conf_dir, NULL);
759     if (code) {
760         afs_com_err(whoami, code, "initializing pruser");
761         exit(1);
762     }
763
764     for (i = 0; i < maxLen; i++)
765         name[i] = 'a';
766     name[i] = 'a';              /* too long a name... */
767     name[i + 1] = 0;
768     id = 0;
769     code = pr_CreateUser(name, &id);
770     if ((code != RXGEN_CC_MARSHAL) && (code != PRBADNAM)) {
771         afs_com_err(whoami, code, "succeeded creating %s", name);
772         exit(2);
773     }
774     name[i] = 0;
775     id = 0;
776     code = pr_CreateUser(name, &id);
777     if (code == PREXIST) {
778         fprintf(stderr, "group already exists, skipping\n");
779         pr_SNameToId(name, &id);
780     } else if (code) {
781         afs_com_err(whoami, code, "failed creating %s", name);
782         exit(3);
783     }
784     if ((code = pr_ListEntry(id, &ent))
785         || (code = pr_SIdToName(ent.creator, creator))) {
786         afs_com_err(whoami, code, "getting creator's name");
787         exit(5);
788     }
789     code = pr_DeleteByID(id);
790     if (code) {
791         afs_com_err(whoami, code, "deleting %s", name);
792         exit(6);
793     }
794     /* now make sure the illegal chars are detected */
795     {
796         char *illegalChars;
797         for (illegalChars = "@:\n"; *illegalChars; illegalChars++) {
798             name[10] = *illegalChars;
799             id = 0;
800             code = pr_CreateUser(name, &id);
801             if (code != PRBADNAM) {
802                 afs_com_err(whoami, code, "succeeded creating %s", name);
803                 exit(8);
804             }
805         }
806     }
807
808     for (i = 1; i <= 255;) {    /* for all 8-bit ascii... */
809         j = 0;                  /* build a new name */
810         while ((j < maxLen) && (i <= 255)) {
811             if (!((i == ':') || (i == '@') || (i == '\n')))
812                 name[j++] = i;
813             i++;
814         }
815         name[j] = 0;            /* terminate string */
816         id = 0;
817         code = pr_CreateUser(name, &id);
818         if (code == PREXIST) {
819             fprintf(stderr, "user already exists, skipping\n");
820             pr_SNameToId(name, &id);
821         } else if (code) {
822             char ascii[BUFSIZ];
823             ka_ConvertBytes(ascii, sizeof(ascii), name, strlen(name));
824             afs_com_err(whoami, code, "failed creating %s", ascii);
825             exit(4);
826         }
827         code = pr_DeleteByID(id);
828         if (code) {
829             afs_com_err(whoami, code, "deleting %s", name);
830             exit(7);
831         }
832     }
833
834     /* now check group names */
835     strcpy(name, creator);
836     strcat(name, ":abcdefghijklmnopqrstuvwxyz");
837     name[0] = 1;                /* bash the owner name */
838     id = 0;
839     code = pr_CreateGroup(name, creator, &id);
840     if (code != PRNOENT) {      /* owner doesn't exist */
841         afs_com_err(whoami, code, "succeeded creating %s", name);
842         exit(9);
843     }
844     name[0] = creator[0];       /* fix owner */
845     /* Make sure the illegal chars are detected */
846     {
847         char *illegalChars;
848         for (illegalChars = ":@\n"; *illegalChars; illegalChars++) {
849             name[strlen(creator) + 10] = *illegalChars;
850             id = 0;
851             code = pr_CreateGroup(name, creator, &id);
852             if (code != PRBADNAM) {
853                 afs_com_err(whoami, code, "succeeded creating %s", name);
854                 exit(10);
855             }
856         }
857     }
858     for (i = 1; i <= 255;) {    /* for all 8-bit ascii... */
859         j = strlen(creator) + 1;        /* build a new name */
860         while ((j < PR_MAXNAMELEN - 1) && (i <= 255)) {
861             if (!((i == ':') || (i == '@') || (i == '\n')))
862                 name[j++] = i;
863             i++;
864         }
865         name[j] = 0;            /* terminate string */
866         id = 0;
867         code = pr_CreateGroup(name, creator, &id);
868         if (code == PREXIST) {
869             fprintf(stderr, "group already exists, skipping\n");
870             pr_SNameToId(name, &id);
871         } else if (code) {
872             char ascii[BUFSIZ];
873             ka_ConvertBytes(ascii, sizeof(ascii), name, strlen(name));
874             afs_com_err(whoami, code, "failed creating %s", ascii);
875             exit(4);
876         }
877         code = pr_DeleteByID(id);
878         if (code) {
879             afs_com_err(whoami, code, "deleting %s", name);
880             exit(7);
881         }
882     }
883
884     printf("All OK\n");
885     return 0;
886 }
887
888 static char tmp_conf_dir[128] = "";
889 static char tmp_conf_file[128] = "";
890 static char tmp_cell_file[128] = "";
891 static char tmp_noauth_file[128] = "";
892
893 static int
894 MyAfterProc(struct cmd_syndesc *as, void *arock)
895 {
896     if (strlen(tmp_conf_file))
897         unlink(tmp_conf_file);
898     if (strlen(tmp_cell_file))
899         unlink(tmp_cell_file);
900     if (strlen(tmp_noauth_file))
901         unlink(tmp_noauth_file);
902     if (strlen(tmp_conf_dir))
903         rmdir(tmp_conf_dir);
904     return 0;
905 }
906
907 static int
908 MyBeforeProc(struct cmd_syndesc *as, void *arock)
909 {
910     afs_int32 code;
911     int i;
912     char *cdir = 0;
913     int noAuth = 0;
914     struct cmd_item *serverList = 0;
915     struct afsconf_dir *local_conf = 0; /* so we can default stuff nicely */
916     struct afsconf_cell cellinfo;
917
918     if (as->parms[12].items) {  /* if conf dir specified */
919         cdir = as->parms[12].items->data;
920         if (as->parms[13].items || as->parms[14].items || as->parms[15].items) {
921             printf("Can't specify conf dir and other cell parameters\n");
922             return AFSCONF_SYNTAX;
923         }
924     }
925
926     /* if we need to default cell name or cell servers, get local conf info */
927
928     if (!(local_conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH))
929         && !(local_conf = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH))) {
930         printf("** Can't local configuration!\n");
931         return AFSCONF_NOCELL;
932     }
933
934     if (as->parms[13].items) {  /* if cell name specified */
935         lcstring(lcell, as->parms[13].items->data, sizeof(lcell));
936         code = afsconf_GetCellInfo(local_conf, lcell, 0, &cellinfo);
937         if (code == 0)
938             strncpy(lcell, cellinfo.name, sizeof(lcell));
939     } else {
940         code = afsconf_GetLocalCell(local_conf, lcell, sizeof(lcell));
941         if (code)
942             return code;
943     }
944
945     if (as->parms[14].items) {  /* noauth flag */
946         noAuth = 1;
947     }
948
949     if (as->parms[15].items) {  /* servers list */
950         serverList = as->parms[15].items;
951         for (i = 0; serverList; i++, serverList = serverList->next) {
952             struct hostent *th;
953             if (i >= MAXHOSTSPERCELL)
954                 return AFSCONF_FULL;
955             strncpy(cellinfo.hostName[i], serverList->data, MAXHOSTCHARS);
956             th = gethostbyname(cellinfo.hostName[i]);
957             if (!th)
958                 return UBADHOST;
959             memcpy(&cellinfo.hostAddr[i].sin_addr, th->h_addr,
960                    sizeof(afs_int32));
961             cellinfo.hostAddr[i].sin_family = AF_INET;
962             cellinfo.hostAddr[i].sin_port = 0;
963 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
964             cellinfo.hostAddr[i].sin_len = sizeof(struct sockaddr_in);
965 #endif
966         }
967         cellinfo.numServers = i;
968         strcpy(cellinfo.name, lcell);
969     } else {
970         code = afsconf_GetCellInfo(local_conf, lcell, 0, &cellinfo);
971         if (code)
972             return code;
973     }
974
975     if (local_conf)
976         afsconf_Close(local_conf);
977
978     if (cdir == 0) {
979         FILE *f;
980
981         sprintf(tmp_conf_dir, "%s/afsconf.%lu", gettmpdir(),
982                 (unsigned long)getpid());
983         code = mkdir(tmp_conf_dir, 0777);
984         if ((code < 0) && (errno != EEXIST)) {
985             afs_com_err(whoami, errno, "can't create temporary afsconf dir: %s",
986                     cdir);
987             return errno;
988         }
989
990         strcompose(tmp_conf_file, 128, tmp_conf_dir, "/",
991                    AFSDIR_CELLSERVDB_FILE, NULL);
992         f = fopen(tmp_conf_file, "w");
993         if (f == 0) {
994           cantcreate:
995             afs_com_err(whoami, errno, "can't create conf file %s",
996                     tmp_conf_file);
997             return errno;
998         }
999         fprintf(f, ">%s\n", lcell);
1000         for (i = 0; i < cellinfo.numServers; i++) {
1001             unsigned char *tp =
1002                 (unsigned char *)&cellinfo.hostAddr[i].sin_addr;
1003             fprintf(f, "%d.%d.%d.%d\t#%s\n", tp[0], tp[1], tp[2], tp[3],
1004                     cellinfo.hostName[i]);
1005         }
1006         if (fclose(f) == EOF) {
1007           cantclose:
1008             afs_com_err(whoami, errno, "can't write to conf file %s",
1009                     tmp_conf_file);
1010             return errno;
1011         }
1012
1013         strcompose(tmp_cell_file, 128, tmp_conf_dir, "/",
1014                    AFSDIR_THISCELL_FILE, NULL);
1015         f = fopen(tmp_cell_file, "w");
1016         if (f == 0)
1017             goto cantcreate;
1018         fprintf(f, "%s", lcell);
1019         if (fclose(f) == EOF)
1020             goto cantclose;
1021
1022         strcompose(tmp_noauth_file, 128, tmp_conf_dir, "/",
1023                    AFSDIR_NOAUTH_FILE, NULL);
1024         if (noAuth) {
1025             code = creat(tmp_noauth_file, 0777);
1026             if (code && (errno != EEXIST))
1027                 return errno;
1028         } else {                /* make sure file doesn't exist */
1029             code = unlink(tmp_noauth_file);
1030             if (code && (errno != ENOENT))
1031                 return errno;
1032         }
1033     }
1034
1035     strncpy(conf_dir, tmp_conf_dir, sizeof(conf_dir));
1036     conf = afsconf_Open(conf_dir);
1037     if (conf == 0)
1038         return AFSCONF_NOTFOUND;
1039     return 0;
1040 }
1041
1042 static void
1043 add_std_args(struct cmd_syndesc *ts)
1044 {
1045     cmd_Seek(ts, 12);
1046     cmd_AddParm(ts, "-confdir", CMD_SINGLE, CMD_OPTIONAL,
1047                 "AFS Conf dir pathname");
1048     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "Cell name");
1049     cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL, "Don't authenticate");
1050     cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL, "Server config");
1051 }
1052
1053 int
1054 osi_audit(void)
1055 {
1056 /* OK, this REALLY sucks bigtime, but I can't tell who is calling
1057  * afsconf_CheckAuth easily, and only *SERVERS* should be calling osi_audit
1058  * anyway.  It's gonna give somebody fits to debug, I know, I know.
1059  */
1060     return 0;
1061 }
1062
1063 #include "AFS_component_version_number.c"
1064
1065 int
1066 main(int argc, char *argv[])
1067 {
1068     afs_int32 code;
1069     struct cmd_syndesc *ts;     /* ptr to parsed command line syntax */
1070
1071     whoami = argv[0];
1072     initialize_CMD_error_table();
1073     initialize_ACFG_error_table();
1074     initialize_KTC_error_table();
1075     initialize_U_error_table();
1076     initialize_PT_error_table();
1077     initialize_RXK_error_table();
1078
1079 #ifdef AFS_NT40_ENV
1080     /* initialize winsock */
1081     if (afs_winsockInit() < 0) {
1082         fprintf(stderr, "%s: couldn't initialize winsock. \n", whoami);
1083         exit(1);
1084     }
1085 #endif
1086
1087     cmd_SetBeforeProc(MyBeforeProc, NULL);
1088     cmd_SetAfterProc(MyAfterProc, NULL);
1089
1090     ts = cmd_CreateSyntax("usedIds", ListUsedIds, NULL,
1091                           "Find used (or unused) user (or group) ids");
1092     cmd_AddParm(ts, "-startId", CMD_SINGLE, CMD_OPTIONAL,
1093                 "id to start checking");
1094     cmd_AddParm(ts, "-number", CMD_SINGLE, CMD_OPTIONAL,
1095                 "number of ids to check");
1096     cmd_AddParm(ts, "-unused", CMD_FLAG, CMD_OPTIONAL, "print unused ids");
1097     add_std_args(ts);
1098
1099     ts = cmd_CreateSyntax("initcmd", TestPrServ, NULL, "test the prserver");
1100     add_std_args(ts);
1101
1102     ts = cmd_CreateSyntax("testmanymembers", TestManyMembers, NULL,
1103                           "test creating users and groups w/ many members");
1104     cmd_AddParm(ts, "-number", CMD_SINGLE, 0,
1105                 "number of users/groups to create");
1106     cmd_AddParm(ts, "-dropoff", CMD_SINGLE, CMD_OPTIONAL,
1107                 "precentage for exponential dropoff");
1108     cmd_AddParm(ts, "-prefix", CMD_SINGLE, CMD_OPTIONAL, "naming prefix");
1109     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL, "show progress");
1110     cmd_AddParm(ts, "-seed", CMD_SINGLE, CMD_OPTIONAL, "random number seed");
1111     add_std_args(ts);
1112     cmd_CreateAlias(ts, "mm");
1113
1114
1115     code = cmd_Dispatch(argc, argv);
1116     if (code)
1117         afs_com_err(whoami, code, "calling cmd_Dispatch");
1118     exit(code);
1119 }