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