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