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