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