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