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