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