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