cf8a68f4bff065d70404bacd67816391a4875c99
[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 = (afs_int32 *) malloc(number * sizeof(afs_int32));
493     groups = (afs_int32 *) malloc(number * sizeof(afs_int32));
494     filled = (char *)malloc(number * sizeof(char));
495     cleaned = (char *)malloc(number * sizeof(char));
496     population = (char *)malloc(sqr(number) * sizeof(char));
497
498     nFilled = 0;
499     memset(filled, 0, number);
500     nCleaned = 0;
501     memset(cleaned, 0, number);
502     memset(population, 0, sqr(number));
503     memset(users, 0, number * sizeof(afs_int32));
504     memset(groups, 0, number * sizeof(afs_int32));
505
506     ownerUser = lastGroup = 0;
507     groupOwners = (afs_int32 *) malloc(number * sizeof(afs_int32));
508     nUsers = nGroups = nAdds = nRems = nUDels = nGDels = 0;
509
510     while ((nFilled < number) || (nCleaned < number)) {
511         /* pick a user at random, using  */
512         u = random() % number;
513         if (!filled[u]) {
514             n = GetGroupLimit(number, u);       /* get group limit for that user */
515             g = random() % (n + 1);     /* pick a random group */
516             if (g == n) {       /* in a few cases create any user */
517                 n = number;     /* in the whole range */
518                 g = random() % n;
519             }
520             for (i = 0; i < n; i++) {   /* rotate until unused one found */
521                 j = (g + i) % n;
522                 if (!population[u * number + j]) {
523                     /* add this user/group membership */
524                     AddUser(u, j);
525                     goto added;
526                 }
527             }
528             filled[u]++;
529             nFilled++;
530           added:;
531         }
532         if (!cleaned[u]) {
533             int base;
534             if (filled[u]) {    /* only clean above GroupLimit */
535                 base = GetGroupLimit(number, u);
536                 n = number - base;
537                 if (n == 0)
538                     goto iscleaned;
539                 g = random() % n;
540             } else {
541                 base = 0;
542                 n = number;     /* pick a group from the whole range */
543                 g = random() % 2 * n;   /* at random for removal */
544                 if (g >= n)
545                     goto remed; /* but half the time do nothing */
546             }
547             for (i = 0; i < n; i++) {   /* rotate until used one found */
548                 j = (g + i) % n + base;
549                 if (population[u * number + j]) {
550                     /* remove this user/group membership */
551                     RemUser(u, j);
552                     goto remed;
553                 }
554             }
555             if (filled[u]) {    /* track finished ones */
556               iscleaned:
557                 cleaned[u]++;
558                 nCleaned++;
559             }
560           remed:;
561         }
562     }
563
564     /* check the membership list of all users for correctness */
565     printf("Starting check of memberships\n");
566     glist = (afs_int32 *) malloc(number * sizeof(afs_int32));
567     for (u = 0; u < number; u++) {
568         afs_int32 ui = users[u];
569         if (ui) {
570             int i;
571             int ng;             /* number groups */
572             int over;
573             int (*proc)(struct ubik_client *, afs_int32, afs_int32, prlist *,
574                         afs_int32 *);
575             prlist alist;
576
577             alist.prlist_len = 0;
578             alist.prlist_val = 0;
579             if (random() & 4) {
580                 proc = ubik_PR_ListElements;
581             } else {
582                 proc = ubik_PR_GetCPS;
583             }
584             code = (*proc)(pruclient, 0, ui, &alist, &over);
585             if (code) {
586                 afs_com_err(whoami, code,
587                         "getting membership list of (%di) using %s", ui,
588                         (proc == ubik_PR_ListElements?"ListElements":"GetCPS"));
589                 exit(24);
590             }
591             if (over) {
592                 fprintf(stderr, "membership list for id %di too long\n", ui);
593             }
594             ng = 0;
595             for (i = 0; i < number; i++)
596                 if (population[u * number + i])
597                     glist[ng++] = groups[i];
598             qsort(glist, ng, sizeof(afs_int32), IdCmp);
599             if (ng != (alist.prlist_len - ((proc == ubik_PR_GetCPS) ? 3 : 0))) {
600                 fprintf(stderr,
601                         "Membership list for %di of unexpected length: was %d but expected %d\n",
602                         ui, alist.prlist_len, ng);
603                 exit(20);
604             }
605             /* all the extra entries for the CPS should be at the end. */
606             code = 0;
607             for (i = 0; i < ng; i++)
608                 if (alist.prlist_val[i] != glist[i]) {
609                     fprintf(stderr,
610                             "membership for %di not correct: was %di but expected %di\n",
611                             ui, alist.prlist_val[i], glist[i]);
612                     code++;
613                 }
614             if (code)
615                 exit(21);
616             if (proc == ubik_PR_GetCPS) {
617                 if ((alist.prlist_val[i /* =ng */ ] != AUTHUSERID) ||
618                     (alist.prlist_val[++i] != ANYUSERID)
619                     || (alist.prlist_val[++i] != ui)) {
620                     fprintf(stderr, "CPS doesn't have extra entries\n");
621                     exit(27);
622                 }
623             }
624             if (alist.prlist_val)
625                 free(alist.prlist_val);
626
627             /* User 0 is a member of all groups all of which should also be on
628              * the owner list of the caller or the ownerUser, although there
629              * may also be others.  Check this. */
630             if (u == 0) {
631                 prlist callerList;
632                 prlist ownerList;
633                 prlist lastGroupList;
634                 int i, j, k, l;
635
636                 if (ng != number) {
637                     fprintf(stderr, "User 0 not a member of all groups\n");
638                     exit(26);
639                 }
640 #define GETOWNED(xlist,xid) \
641   (xlist).prlist_val = 0; (xlist).prlist_len = 0; \
642   code = ubik_PR_ListOwned(pruclient, 0, (xid), &(xlist), &over); \
643   if (code) { \
644       afs_com_err (whoami, code, "getting owner list of (%di)", (xid)); \
645       exit (23); } \
646   if (over) \
647       { fprintf (stderr, "membership of id %di too long\n", (xid)); }
648
649                 GETOWNED(callerList, callerId);
650                 GETOWNED(ownerList, ownerUser);
651
652                 /* look for every entry in glist, in all the owner lists */
653                 for (i = j = k = l = 0; i < number; i++) {
654                     while ((j < callerList.prlist_len)
655                            && (callerList.prlist_val[j] < glist[i]))
656                         j++;
657                     while ((k < ownerList.prlist_len)
658                            && (ownerList.prlist_val[k] < glist[i]))
659                         k++;
660 #define PRLISTCMP(l,i) \
661   (((l).prlist_len == 0) || (glist[i] != (l).prlist_val[(i)]))
662                     if (PRLISTCMP(callerList, j) && PRLISTCMP(ownerList, k)) {
663                         for (l = 0; l < number; l++) {
664                             if (groups[l] == glist[i]) {
665                                 if ((groupOwners[l] != callerId)
666                                     && (groupOwners[l] != ownerUser)) {
667                                     GETOWNED(lastGroupList, groupOwners[l]);
668                                     if ((lastGroupList.prlist_len != 1)
669                                         || (lastGroupList.prlist_val[0] !=
670                                             glist[i])) {
671                                         fprintf(stderr,
672                                                 "Group (%di) not on any owner list\n",
673                                                 glist[i]);
674                                         exit(25);
675                                     }
676                                 }
677                                 goto foundLast;
678                             }
679                         }
680                         fprintf(stderr, "unexpected group %di\n", glist[i]);
681                       foundLast:;
682                     }
683                 }
684                 if (callerList.prlist_val)
685                     free(callerList.prlist_val);
686                 if (ownerList.prlist_val)
687                     free(ownerList.prlist_val);
688                 if (lastGroupList.prlist_val)
689                     free(lastGroupList.prlist_val);
690             }
691         }
692     }
693
694     /* cleanup by deleting all the users and groups */
695     printf("Starting deletion of users and groups\n");
696     for (i = 0; i < number; i++) {
697         DeleteRandomId(users);
698         DeleteRandomId(groups);
699     }
700
701     printf
702         ("Created/deleted %d/%d users and %d/%d groups; added %d and removed %d.\n",
703          nUsers, nUDels, nGroups, nGDels, nAdds, nRems);
704     return 0;
705 }
706
707 /* from ka_ConvertBytes included here to avoid circularity */
708 /* Converts a byte string to ascii.  Return the number of unconverted bytes. */
709
710 static int
711 ka_ConvertBytes(char *ascii,            /* output buffer */
712                 int alen,               /* buffer length */
713                 char bs[],              /* byte string */
714                 int bl)                 /* number of bytes */
715 {
716     int i;
717     unsigned char c;
718
719     alen--;                     /* make room for termination */
720     for (i = 0; i < bl; i++) {
721         c = bs[i];
722         if (alen <= 0)
723             return bl - i;
724         if (isalnum(c) || ispunct(c))
725             (*ascii++ = c), alen--;
726         else {
727             if (alen <= 3)
728                 return bl - i;
729             *ascii++ = '\\';
730             *ascii++ = (c >> 6) + '0';
731             *ascii++ = (c >> 3 & 7) + '0';
732             *ascii++ = (c & 7) + '0';
733             alen -= 4;
734         }
735     }
736     *ascii = 0;                 /* terminate string */
737     return 0;
738 }
739
740 /* This runs various tests on the server.  It creates, then deletes, a bunch of
741  * users and groups, so it would be safest to run it on a test database.
742  *
743  * These are the things I check for:
744  *   User names longer than PR_MAXNAMELEN - strlen(cellname).
745  *   Group names longer than PR_MAXNAMELEN.
746  *   User names containing all legal 8-bit ascii characters.  This excludes
747  *     only ':', '@', and '\n'.
748  *   Group names as above, but at least one colon is required, and the owner
749  *     must be correct.
750  */
751
752 int
753 TestPrServ(struct cmd_syndesc *as, void *arock)
754 {
755     afs_int32 id;
756     char name[PR_MAXNAMELEN + 1];
757     char creator[PR_MAXNAMELEN];        /* our name */
758     struct prcheckentry ent;
759     afs_int32 code;
760     int i, j;
761     int maxLen = PR_MAXNAMELEN - 1 - strlen(lcell) - 1;
762
763     code = pr_Initialize(1, conf_dir, NULL);
764     if (code) {
765         afs_com_err(whoami, code, "initializing pruser");
766         exit(1);
767     }
768
769     for (i = 0; i < maxLen; i++)
770         name[i] = 'a';
771     name[i] = 'a';              /* too long a name... */
772     name[i + 1] = 0;
773     id = 0;
774     code = pr_CreateUser(name, &id);
775     if ((code != RXGEN_CC_MARSHAL) && (code != PRBADNAM)) {
776         afs_com_err(whoami, code, "succeeded creating %s", name);
777         exit(2);
778     }
779     name[i] = 0;
780     id = 0;
781     code = pr_CreateUser(name, &id);
782     if (code == PREXIST) {
783         fprintf(stderr, "group already exists, skipping\n");
784         pr_SNameToId(name, &id);
785     } else if (code) {
786         afs_com_err(whoami, code, "failed creating %s", name);
787         exit(3);
788     }
789     if ((code = pr_ListEntry(id, &ent))
790         || (code = pr_SIdToName(ent.creator, creator))) {
791         afs_com_err(whoami, code, "getting creator's name");
792         exit(5);
793     }
794     code = pr_DeleteByID(id);
795     if (code) {
796         afs_com_err(whoami, code, "deleting %s", name);
797         exit(6);
798     }
799     /* now make sure the illegal chars are detected */
800     {
801         char *illegalChars;
802         for (illegalChars = "@:\n"; *illegalChars; illegalChars++) {
803             name[10] = *illegalChars;
804             id = 0;
805             code = pr_CreateUser(name, &id);
806             if (code != PRBADNAM) {
807                 afs_com_err(whoami, code, "succeeded creating %s", name);
808                 exit(8);
809             }
810         }
811     }
812
813     for (i = 1; i <= 255;) {    /* for all 8-bit ascii... */
814         j = 0;                  /* build a new name */
815         while ((j < maxLen) && (i <= 255)) {
816             if (!((i == ':') || (i == '@') || (i == '\n')))
817                 name[j++] = i;
818             i++;
819         }
820         name[j] = 0;            /* terminate string */
821         id = 0;
822         code = pr_CreateUser(name, &id);
823         if (code == PREXIST) {
824             fprintf(stderr, "user already exists, skipping\n");
825             pr_SNameToId(name, &id);
826         } else if (code) {
827             char ascii[BUFSIZ];
828             ka_ConvertBytes(ascii, sizeof(ascii), name, strlen(name));
829             afs_com_err(whoami, code, "failed creating %s", ascii);
830             exit(4);
831         }
832         code = pr_DeleteByID(id);
833         if (code) {
834             afs_com_err(whoami, code, "deleting %s", name);
835             exit(7);
836         }
837     }
838
839     /* now check group names */
840     strcpy(name, creator);
841     strcat(name, ":abcdefghijklmnopqrstuvwxyz");
842     name[0] = 1;                /* bash the owner name */
843     id = 0;
844     code = pr_CreateGroup(name, creator, &id);
845     if (code != PRNOENT) {      /* owner doesn't exist */
846         afs_com_err(whoami, code, "succeeded creating %s", name);
847         exit(9);
848     }
849     name[0] = creator[0];       /* fix owner */
850     /* Make sure the illegal chars are detected */
851     {
852         char *illegalChars;
853         for (illegalChars = ":@\n"; *illegalChars; illegalChars++) {
854             name[strlen(creator) + 10] = *illegalChars;
855             id = 0;
856             code = pr_CreateGroup(name, creator, &id);
857             if (code != PRBADNAM) {
858                 afs_com_err(whoami, code, "succeeded creating %s", name);
859                 exit(10);
860             }
861         }
862     }
863     for (i = 1; i <= 255;) {    /* for all 8-bit ascii... */
864         j = strlen(creator) + 1;        /* build a new name */
865         while ((j < PR_MAXNAMELEN - 1) && (i <= 255)) {
866             if (!((i == ':') || (i == '@') || (i == '\n')))
867                 name[j++] = i;
868             i++;
869         }
870         name[j] = 0;            /* terminate string */
871         id = 0;
872         code = pr_CreateGroup(name, creator, &id);
873         if (code == PREXIST) {
874             fprintf(stderr, "group already exists, skipping\n");
875             pr_SNameToId(name, &id);
876         } else if (code) {
877             char ascii[BUFSIZ];
878             ka_ConvertBytes(ascii, sizeof(ascii), name, strlen(name));
879             afs_com_err(whoami, code, "failed creating %s", ascii);
880             exit(4);
881         }
882         code = pr_DeleteByID(id);
883         if (code) {
884             afs_com_err(whoami, code, "deleting %s", name);
885             exit(7);
886         }
887     }
888
889     printf("All OK\n");
890     return 0;
891 }
892
893 static char tmp_conf_dir[128] = "";
894 static char tmp_conf_file[128] = "";
895 static char tmp_cell_file[128] = "";
896 static char tmp_noauth_file[128] = "";
897
898 static int
899 MyAfterProc(struct cmd_syndesc *as, void *arock)
900 {
901     if (strlen(tmp_conf_file))
902         unlink(tmp_conf_file);
903     if (strlen(tmp_cell_file))
904         unlink(tmp_cell_file);
905     if (strlen(tmp_noauth_file))
906         unlink(tmp_noauth_file);
907     if (strlen(tmp_conf_dir))
908         rmdir(tmp_conf_dir);
909     return 0;
910 }
911
912 static int
913 MyBeforeProc(struct cmd_syndesc *as, void *arock)
914 {
915     afs_int32 code;
916     int i;
917     char *cdir = 0;
918     int noAuth = 0;
919     struct cmd_item *serverList = 0;
920     struct afsconf_dir *local_conf = 0; /* so we can default stuff nicely */
921     struct afsconf_cell cellinfo;
922
923     if (as->parms[12].items) {  /* if conf dir specified */
924         cdir = as->parms[12].items->data;
925         if (as->parms[13].items || as->parms[14].items || as->parms[15].items) {
926             printf("Can't specify conf dir and other cell parameters\n");
927             return AFSCONF_SYNTAX;
928         }
929     }
930
931     /* if we need to default cell name or cell servers, get local conf info */
932
933     if (!(local_conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH))
934         && !(local_conf = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH))) {
935         printf("** Can't local configuration!\n");
936         return AFSCONF_NOCELL;
937     }
938
939     if (as->parms[13].items) {  /* if cell name specified */
940         lcstring(lcell, as->parms[13].items->data, sizeof(lcell));
941         code = afsconf_GetCellInfo(local_conf, lcell, 0, &cellinfo);
942         if (code == 0)
943             strncpy(lcell, cellinfo.name, sizeof(lcell));
944     } else {
945         code = afsconf_GetLocalCell(local_conf, lcell, sizeof(lcell));
946         if (code)
947             return code;
948     }
949
950     if (as->parms[14].items) {  /* noauth flag */
951         noAuth = 1;
952     }
953
954     if (as->parms[15].items) {  /* servers list */
955         serverList = as->parms[15].items;
956         for (i = 0; serverList; i++, serverList = serverList->next) {
957             struct hostent *th;
958             if (i >= MAXHOSTSPERCELL)
959                 return AFSCONF_FULL;
960             strncpy(cellinfo.hostName[i], serverList->data, MAXHOSTCHARS);
961             th = gethostbyname(cellinfo.hostName[i]);
962             if (!th)
963                 return UBADHOST;
964             memcpy(&cellinfo.hostAddr[i].sin_addr, th->h_addr,
965                    sizeof(afs_int32));
966             cellinfo.hostAddr[i].sin_family = AF_INET;
967             cellinfo.hostAddr[i].sin_port = 0;
968 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
969             cellinfo.hostAddr[i].sin_len = sizeof(struct sockaddr_in);
970 #endif
971         }
972         cellinfo.numServers = i;
973         strcpy(cellinfo.name, lcell);
974     } else {
975         code = afsconf_GetCellInfo(local_conf, lcell, 0, &cellinfo);
976         if (code)
977             return code;
978     }
979
980     if (local_conf)
981         afsconf_Close(local_conf);
982
983     if (cdir == 0) {
984         FILE *f;
985
986         sprintf(tmp_conf_dir, "%s/afsconf.%lu", gettmpdir(),
987                 (unsigned long)getpid());
988         code = mkdir(tmp_conf_dir, 0777);
989         if ((code < 0) && (errno != EEXIST)) {
990             afs_com_err(whoami, errno, "can't create temporary afsconf dir: %s",
991                     cdir);
992             return errno;
993         }
994
995         strcompose(tmp_conf_file, 128, tmp_conf_dir, "/",
996                    AFSDIR_CELLSERVDB_FILE, NULL);
997         f = fopen(tmp_conf_file, "w");
998         if (f == 0) {
999           cantcreate:
1000             afs_com_err(whoami, errno, "can't create conf file %s",
1001                     tmp_conf_file);
1002             return errno;
1003         }
1004         fprintf(f, ">%s\n", lcell);
1005         for (i = 0; i < cellinfo.numServers; i++) {
1006             unsigned char *tp =
1007                 (unsigned char *)&cellinfo.hostAddr[i].sin_addr;
1008             fprintf(f, "%d.%d.%d.%d\t#%s\n", tp[0], tp[1], tp[2], tp[3],
1009                     cellinfo.hostName[i]);
1010         }
1011         if (fclose(f) == EOF) {
1012           cantclose:
1013             afs_com_err(whoami, errno, "can't write to conf file %s",
1014                     tmp_conf_file);
1015             return errno;
1016         }
1017
1018         strcompose(tmp_cell_file, 128, tmp_conf_dir, "/",
1019                    AFSDIR_THISCELL_FILE, NULL);
1020         f = fopen(tmp_cell_file, "w");
1021         if (f == 0)
1022             goto cantcreate;
1023         fprintf(f, "%s", lcell);
1024         if (fclose(f) == EOF)
1025             goto cantclose;
1026
1027         strcompose(tmp_noauth_file, 128, tmp_conf_dir, "/",
1028                    AFSDIR_NOAUTH_FILE, NULL);
1029         if (noAuth) {
1030             code = creat(tmp_noauth_file, 0777);
1031             if (code && (errno != EEXIST))
1032                 return errno;
1033         } else {                /* make sure file doesn't exist */
1034             code = unlink(tmp_noauth_file);
1035             if (code && (errno != ENOENT))
1036                 return errno;
1037         }
1038     }
1039
1040     strncpy(conf_dir, tmp_conf_dir, sizeof(conf_dir));
1041     conf = afsconf_Open(conf_dir);
1042     if (conf == 0)
1043         return AFSCONF_NOTFOUND;
1044     return 0;
1045 }
1046
1047 static void
1048 add_std_args(struct cmd_syndesc *ts)
1049 {
1050     cmd_Seek(ts, 12);
1051     cmd_AddParm(ts, "-confdir", CMD_SINGLE, CMD_OPTIONAL,
1052                 "AFS Conf dir pathname");
1053     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "Cell name");
1054     cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL, "Don't authenticate");
1055     cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL, "Server config");
1056 }
1057
1058 int
1059 osi_audit(void)
1060 {
1061 /* OK, this REALLY sucks bigtime, but I can't tell who is calling
1062  * afsconf_CheckAuth easily, and only *SERVERS* should be calling osi_audit
1063  * anyway.  It's gonna give somebody fits to debug, I know, I know.
1064  */
1065     return 0;
1066 }
1067
1068 #include "AFS_component_version_number.c"
1069
1070 int
1071 main(int argc, char *argv[])
1072 {
1073     afs_int32 code;
1074     struct cmd_syndesc *ts;     /* ptr to parsed command line syntax */
1075
1076     whoami = argv[0];
1077     initialize_CMD_error_table();
1078     initialize_ACFG_error_table();
1079     initialize_KTC_error_table();
1080     initialize_U_error_table();
1081     initialize_PT_error_table();
1082     initialize_RXK_error_table();
1083
1084 #ifdef AFS_NT40_ENV
1085     /* initialize winsock */
1086     if (afs_winsockInit() < 0) {
1087         fprintf(stderr, "%s: couldn't initialize winsock. \n", whoami);
1088         exit(1);
1089     }
1090 #endif
1091
1092     cmd_SetBeforeProc(MyBeforeProc, NULL);
1093     cmd_SetAfterProc(MyAfterProc, NULL);
1094
1095     ts = cmd_CreateSyntax("usedIds", ListUsedIds, NULL,
1096                           "Find used (or unused) user (or group) ids");
1097     cmd_AddParm(ts, "-startId", CMD_SINGLE, CMD_OPTIONAL,
1098                 "id to start checking");
1099     cmd_AddParm(ts, "-number", CMD_SINGLE, CMD_OPTIONAL,
1100                 "number of ids to check");
1101     cmd_AddParm(ts, "-unused", CMD_FLAG, CMD_OPTIONAL, "print unused ids");
1102     add_std_args(ts);
1103
1104     ts = cmd_CreateSyntax("initcmd", TestPrServ, NULL, "test the prserver");
1105     add_std_args(ts);
1106
1107     ts = cmd_CreateSyntax("testmanymembers", TestManyMembers, NULL,
1108                           "test creating users and groups w/ many members");
1109     cmd_AddParm(ts, "-number", CMD_SINGLE, 0,
1110                 "number of users/groups to create");
1111     cmd_AddParm(ts, "-dropoff", CMD_SINGLE, CMD_OPTIONAL,
1112                 "precentage for exponential dropoff");
1113     cmd_AddParm(ts, "-prefix", CMD_SINGLE, CMD_OPTIONAL, "naming prefix");
1114     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL, "show progress");
1115     cmd_AddParm(ts, "-seed", CMD_SINGLE, CMD_OPTIONAL, "random number seed");
1116     add_std_args(ts);
1117     cmd_CreateAlias(ts, "mm");
1118
1119
1120     code = cmd_Dispatch(argc, argv);
1121     if (code)
1122         afs_com_err(whoami, code, "calling cmd_Dispatch");
1123     exit(code);
1124 }