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