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