dbservers: Don't cast returns from malloc()
[openafs.git] / src / kauth / test / test_interim_ktc.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 /* Test ktc related calls as well as some file access stuff. */
11
12 #include <afsconfig.h>
13 #include <afs/param.h>
14
15 #include <sys/types.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <sys/file.h>
19 #include <arpa/inet.h>
20 #include <afs/prs_fs.h>
21
22 #include <afs/stds.h>
23 #include <afs/com_err.h>
24 #include <afs/cellconfig.h>
25 #include <afs/auth.h>
26 #include <afs/afs_consts.h>
27 #include "kautils.h"
28
29
30 extern int errno;
31
32 static char *whoami = "test_interim_ktc";
33 static verbose = 1;
34 #define CELLSTOKEEP 50
35 static char cell[MAXKTCREALMLEN];
36 static char cellNameList[CELLSTOKEEP][MAXKTCREALMLEN];
37 static int nCells = 0;
38 static int unusedCell;
39 static char tester[MAXKTCNAMELEN];
40 static char testerPassword[32];
41 static long testerId;
42 static char remoteTester[MAXKTCNAMELEN];
43 static char remoteTesterPassword[32];
44 static long remoteTesterId;
45
46 static void
47 PrintPrincipal(stream, p)
48      FILE *stream;
49      struct ktc_principal *p;
50 {
51     if (!verbose)
52         return;
53     fprintf(stream, "%s", p->name);
54     if (strlen(p->instance))
55         fprintf(stream, ".%s", p->instance);
56     if (strlen(p->cell) && (strcmp(p->cell, ka_LocalCell()) != 0))
57         fprintf(stream, "@%s", p->cell);
58 }
59
60 static void
61 PrintAuthentication(stream, s, t, c)
62      FILE *stream;
63      struct ktc_principal *s, *c;
64      struct ktc_token *t;
65 {
66     long lifetime;
67     unsigned long now = time(0);
68     char bob[KA_TIMESTR_LEN];
69
70     lifetime = (unsigned long)t->endTime - (unsigned long)t->startTime;
71
72     fprintf(stream, "Ticket for '");
73     PrintPrincipal(stream, s);
74     fprintf(stream, "'\n");
75     ka_timestr(t->endTime, bob, KA_TIMESTR_LEN);
76     fprintf(stream, "  good for %d seconds till %s", lifetime, bob);
77
78     /* Allow one second grace, so the even/odd lifetime doesn't appear as an
79      * error.  If it is way off complain loudly. */
80     if (now + KTC_TIME_UNCERTAINTY < t->startTime)
81         fprintf(stream, " [FUTURE]\n");
82     else if (now + 1 < t->startTime)
83         fprintf(stream, " [ahead]\n");
84     else if (now >= t->endTime + KTC_TIME_UNCERTAINTY)
85         fprintf(stream, " [EXPIRED]\n");
86     else if (now >= t->endTime)
87         fprintf(stream, " [behind]\n");
88     else
89         fprintf(stream, "\n");
90     fprintf(stream, "  for user '");
91     PrintPrincipal(stream, c);
92     fprintf(stream, "'\n");
93     fprintf(stream, "  session key='");
94     ka_PrintBytes(&t->sessionKey, sizeof(t->sessionKey));
95     fprintf(stream, "'\n");
96     fprintf(stream, "  kvno=%d, ticket is %d bytes long.\n", t->kvno,
97             t->ticketLen);
98     if (lifetime & 1) {
99         fprintf(stream, "from %d to %d is %d seconds\n", t->startTime,
100                 t->endTime, lifetime);
101         fprintf(stream, "Lifetime is odd\n");
102     }
103 }
104
105 static int
106 CheckUnixUID(server, token, client)
107      struct ktc_principal *server;
108      struct ktc_token *token;
109      struct ktc_principal *client;
110 {
111     long code;
112     struct ktc_token ntoken;
113     struct ktc_principal nclient;
114     long lifetime;
115     char name_buf[24];
116
117     code = ktc_SetToken(server, token, client, 0);
118     if (code) {
119         afs_com_err(whoami, code, "using SetToken to set vice id");
120         return 1;
121     }
122     sprintf(name_buf, "Unix UID %d", getuid());
123
124     code = ktc_GetToken(server, &ntoken, sizeof(ntoken), &nclient);
125     if (code || (strcmp(nclient.name, name_buf) != 0)
126         || strlen(nclient.instance)) {
127         fprintf(stderr, "GetToken returned bad client: '");
128         PrintPrincipal(stderr, &nclient);
129         fprintf(stderr, "'\n");
130         afs_com_err(whoami, code, "should have gotten '%s'", name_buf);
131         return 1;
132     }
133     lifetime =
134         (unsigned long)ntoken.endTime - (unsigned long)ntoken.startTime;
135     if ((lifetime & 1) == 1) {
136         afs_com_err(whoami, code, "GetToken returned even lifetime (%d)",
137                 lifetime);
138         return 1;
139     }
140     return 0;
141 }
142
143 static int
144 CheckAFSId(server, token, client)
145      struct ktc_principal *server;
146      struct ktc_token *token;
147      struct ktc_principal *client;
148 {
149     long code;
150     struct ktc_token ntoken;
151     struct ktc_principal nclient;
152     long lifetime;
153     char name_buf[24];
154     long viceId;
155
156     viceId = atoi((client->name) + 7);
157     code = ktc_SetToken(server, token, client, 0);
158     if (code) {
159         afs_com_err(whoami, code, "using SetToken to set vice id to %d", viceId);
160         return 1;
161     }
162     code = ktc_GetToken(server, &ntoken, sizeof(ntoken), &nclient);
163     if ((strncmp(nclient.name, "AFS ID ", 7) != 0)
164         || (strlen(nclient.name) < 8) || (atoi(nclient.name + 7) != viceId)
165         || strlen(nclient.instance)) {
166         fprintf(stderr, "GetToken returned bad client: '");
167         PrintPrincipal(stderr, &nclient);
168         fprintf(stderr, "' should have gotten '");
169         PrintPrincipal(stderr, client);
170         fprintf(stderr, "'\n");
171         afs_com_err(whoami, code, "didn't preserve AFS ID");
172         return 1;
173     }
174     lifetime =
175         (unsigned long)ntoken.endTime - (unsigned long)ntoken.startTime;
176     if ((lifetime & 1) == 0) {
177         afs_com_err(whoami, code, "GetToken returned even lifetime (%d)",
178                 lifetime);
179         return 1;
180     }
181     return 0;
182 }
183
184 #include <afs/venus.h>
185
186 /* Stolen from auth/comktc.c: U_CellSetLocalTokens */
187 /* Try various Auth2 style pioctl calls with kvno == 999 */
188
189 static int
190 CheckAuth2(server)
191      struct ktc_principal *server;
192 {
193     long code;
194     int i;
195     struct ViceIoctl buffer;    /*pioctl() communication block */
196     struct ktc_principal client;
197     struct ktc_token token;
198     long lifetime;
199
200     struct EncryptedSecretToken {
201         char data[56];
202     };
203     typedef struct EncryptedSecretToken EncryptedSecretToken;
204
205     struct ClearToken {
206         long AuthHandle;
207         struct ktc_encryptionKey HandShakeKey;
208         long ViceId;
209         long BeginTimestamp;
210         long EndTimestamp;
211     };
212     typedef struct ClearToken ClearToken;
213
214     /* venus buffer for using the new interface to set/get venus tokens */
215     typedef struct {
216         int sTokenSize;         /*Size in bytes of secret token */
217         EncryptedSecretToken stoken;    /*Secret token */
218         int cTokenSize;         /*Size in bytes of clear token */
219         ClearToken ctoken;      /*Clear token */
220         int isPrimary;          /*Is this the primary ID? */
221         char cellName[64];      /*Cell in which tokens are valid */
222     } venusbuff;
223     venusbuff inbuff;
224     ClearToken cToken;
225     EncryptedSecretToken sToken;
226     char *cellID;
227     int primaryFlag;
228
229     cellID = server->cell;
230     primaryFlag = 0;
231
232     /* First build a plausible clear token (code from old auth(2) server */
233     cToken.AuthHandle = -1;     /* not in use right now */
234     for (i = 0; i < sizeof(struct ktc_encryptionKey); i++)
235         cToken.HandShakeKey.data[i] = random() & 0xff;
236     cToken.BeginTimestamp = 0;
237     cToken.EndTimestamp = time(0) + 60 * 60 * 25;       /* valid for 25 hours */
238     cToken.ViceId = 123;
239
240     /* Then invent secret token */
241     for (i = 0; i < sizeof(sToken); i++)
242         sToken.data[i] = random() & 0xff;
243
244
245     /*Copy in the sizes and bodies of the secret and clear tokens */
246     inbuff.sTokenSize = sizeof(EncryptedSecretToken);
247     memcpy((char *)&inbuff.stoken, &sToken, sizeof(EncryptedSecretToken));
248     inbuff.cTokenSize = sizeof(ClearToken);
249     memcpy((char *)&inbuff.ctoken, &cToken, sizeof(ClearToken));
250
251     /* Copy in the Primary ID flag and the cell name */
252 #if DB_CELLS
253     fprintf(stderr,
254             "U_CellSetLocalTokens: using isPrimary=%d, cellName='%s'\n",
255             primaryFlag, cellID);
256 #endif /* DB_CELLS */
257     inbuff.isPrimary = primaryFlag;
258     strcpy(inbuff.cellName, cellID);
259
260     /* Place our inbuff in the standard PIOCTL buffer and go for it. */
261     buffer.in = (char *)&inbuff;
262     buffer.out = 0;
263     buffer.in_size = sizeof(inbuff);
264     buffer.out_size = 0;
265     code = pioctl(0, _VICEIOCTL(3), &buffer, 1);
266     if (code) {
267         afs_com_err(whoami, errno, "setting old-style token");
268         return 1;
269     }
270
271     /* now get it back and see if it's OK */
272     code = ktc_GetToken(server, &token, sizeof(token), &client);
273     if ((strcmp(client.name, "AFS ID 123") != 0) || strlen(client.instance)
274         || (strcmp(client.cell, cellID) != 0)) {
275         fprintf(stderr, "GetToken returned bad client: '");
276         PrintPrincipal(stderr, &client);
277         fprintf(stderr, "'\n");
278         return 1;
279     }
280     if ((token.kvno != 999) || (token.startTime != 0)
281         || (token.endTime != cToken.EndTimestamp)
282         || (token.ticketLen != sizeof(sToken))
283         ||
284         (memcmp
285          (&cToken.HandShakeKey, &token.sessionKey,
286           sizeof(struct ktc_encryptionKey)) != 0)
287         || (memcmp(&sToken, token.ticket, sizeof(sToken)) != 0)) {
288         fprintf(stdout, "Auth2 token was bad\n");
289         PrintAuthentication(stdout, server, &token, &client);
290         return 1;
291     }
292
293     return 0;
294
295 }
296
297 /* Stolen from the "fs" command. */
298
299 #define MAXNAME 100
300
301 static void
302 ListCellsCmd()
303 {
304     long code;
305     long i, j;
306     char *tcp;
307     long clear;
308     char space[AFS_PIOCTL_MAXSIZE];
309     struct ViceIoctl blob;
310
311     for (i = 0; i < 1000; i++) {
312         char *cellname;
313         blob.out_size = AFS_PIOCTL_MAXSIZE;
314         blob.in_size = sizeof(long);
315         blob.in = space;
316         blob.out = space;
317         memcpy(space, &i, sizeof(long));
318         code = pioctl(0, VIOCGETCELL, &blob, 1);
319         if (code < 0) {
320             if (errno == EDOM)
321                 break;          /* done with the list */
322             else {
323                 afs_com_err(whoami, code, "getting cell list");
324                 exit(1);
325             }
326         }
327         cellname = space + 8 * sizeof(long);
328         if (verbose > 1) {
329             printf("Cell %s on hosts", cellname);
330             for (j = 0; j < 8; j++) {
331                 memcpy(&clear, space + j * sizeof(long), sizeof(long));
332                 if (clear == 0)
333                     break;
334 #if SLOW
335                 tcp = hostutil_GetNameByINet(clear);
336 #else
337                 tcp = inet_ntoa(clear);
338 #endif
339                 printf(" %s", tcp);
340             }
341             printf(".\n");
342         }
343         if (nCells < CELLSTOKEEP) {
344             strncpy(cellNameList[nCells++], cellname, MAXKTCREALMLEN);
345         }
346     }
347     return;
348 }
349
350 /* Stolen from the fs command */
351
352 struct Acl {
353     int nplus;
354     int nminus;
355     struct AclEntry *pluslist;
356     struct AclEntry *minuslist;
357 };
358
359 struct AclEntry {
360     struct AclEntry *next;
361     char name[MAXNAME];
362     long rights;
363 };
364
365 char *
366 AclToString(acl)
367      struct Acl *acl;
368 {
369     static char mydata[AFS_PIOCTL_MAXSIZE];
370     char tstring[AFS_PIOCTL_MAXSIZE];
371     struct AclEntry *tp;
372     sprintf(mydata, "%d\n%d\n", acl->nplus, acl->nminus);
373     for (tp = acl->pluslist; tp; tp = tp->next) {
374         sprintf(tstring, "%s %d\n", tp->name, tp->rights);
375         strcat(mydata, tstring);
376     }
377     for (tp = acl->minuslist; tp; tp = tp->next) {
378         sprintf(tstring, "%s %d\n", tp->name, tp->rights);
379         strcat(mydata, tstring);
380     }
381     return mydata;
382 }
383
384 char *
385 SkipLine(astr)
386      char *astr;
387 {
388     while (*astr != '\n')
389         astr++;
390     astr++;
391     return astr;
392 }
393
394 struct Acl *
395 ParseAcl(astr)
396      char *astr;
397 {
398     int nplus, nminus, i, trights;
399     char tname[MAXNAME];
400     struct AclEntry *first, *last, *tl;
401     struct Acl *ta;
402     sscanf(astr, "%d", &nplus);
403     astr = SkipLine(astr);
404     sscanf(astr, "%d", &nminus);
405     astr = SkipLine(astr);
406
407     ta = malloc(sizeof(struct Acl));
408     ta->nplus = nplus;
409     ta->nminus = nminus;
410
411     last = 0;
412     first = 0;
413     for (i = 0; i < nplus; i++) {
414         sscanf(astr, "%100s %d", tname, &trights);
415         astr = SkipLine(astr);
416         tl = malloc(sizeof(struct AclEntry));
417         if (!first)
418             first = tl;
419         strcpy(tl->name, tname);
420         tl->rights = trights;
421         tl->next = 0;
422         if (last)
423             last->next = tl;
424         last = tl;
425     }
426     ta->pluslist = first;
427
428     last = 0;
429     first = 0;
430     for (i = 0; i < nminus; i++) {
431         sscanf(astr, "%100s %d", tname, &trights);
432         astr = SkipLine(astr);
433         tl = malloc(sizeof(struct AclEntry));
434         if (!first)
435             first = tl;
436         strcpy(tl->name, tname);
437         tl->rights = trights;
438         tl->next = 0;
439         if (last)
440             last->next = tl;
441         last = tl;
442     }
443     ta->minuslist = first;
444
445     return ta;
446 }
447
448 ZapList(alist)
449      struct AclEntry *alist;
450 {
451     struct AclEntry *tp, *np;
452     for (tp = alist; tp; tp = np) {
453         np = tp->next;
454         free(tp);
455     }
456 }
457
458 int
459 PruneList(ae)
460      struct AclEntry **ae;
461 {
462     struct AclEntry **lp;
463     struct AclEntry *te, *ne;
464     long ctr;
465     ctr = 0;
466     lp = ae;
467     for (te = *ae; te; te = ne) {
468         if (te->rights == 0) {
469             *lp = te->next;
470             ne = te->next;
471             free(te);
472             ctr++;
473         } else {
474             ne = te->next;
475             lp = &te->next;
476         }
477     }
478     return ctr;
479 }
480
481 static int
482 AddTester(pathname)
483      char *pathname;
484 {
485     long code;
486     struct ViceIoctl blob;
487     struct Acl *al;
488     char space[AFS_PIOCTL_MAXSIZE];
489
490     blob.out_size = AFS_PIOCTL_MAXSIZE;
491     blob.in_size = 0;
492     blob.out = space;
493     code = pioctl(pathname, VIOCGETAL, &blob, 1);
494     if (code) {
495         afs_com_err(whoami, errno, "getting acl for %s", pathname);
496         return 1;
497     }
498     if (verbose > 1)
499         printf("old acl for %s is %s\n", pathname, space);
500     al = ParseAcl(space);
501
502     {
503         struct AclEntry *tlist;
504         struct AclEntry *ae;
505         /* clean acl up a bit */
506         ZapList(al->minuslist);
507         al->minuslist = 0;
508         al->nminus = 0;
509         for (ae = al->pluslist; ae; ae = ae->next) {
510             if ((strcmp(ae->name, tester) == 0) ||
511                 /* punt useless entries (like system:anyuser) */
512                 !(ae->
513                   rights & (PRSFS_INSERT | PRSFS_DELETE | PRSFS_WRITE |
514                             PRSFS_LOCK | PRSFS_ADMINISTER)))
515                 ae->rights = 0;
516         }
517         al->nplus -= PruneList(&al->pluslist);
518
519         tlist = malloc(sizeof(struct AclEntry));
520         tlist->rights = 9;
521         strcpy(tlist->name, tester);
522         tlist->next = al->pluslist;
523         al->pluslist = tlist;
524         al->nplus++;
525     }
526
527     if (verbose > 1) {
528         char tmp[100];
529         printf("before:\n");
530         sprintf(tmp, "fs la %s", pathname);
531         system(tmp);
532     }
533
534     blob.in = AclToString(al);
535     blob.out_size = 0;
536     blob.in_size = 1 + strlen(blob.in);
537     code = pioctl(pathname, VIOCSETAL, &blob, 1);
538     if (code) {
539         afs_com_err(whoami, errno, "setting acl on %s to %s", pathname, blob.in);
540         return 1;
541     }
542     if (verbose > 1) {
543         char tmp[100];
544         printf("after:\n");
545         sprintf(tmp, "fs la %s", pathname);
546         system(tmp);
547     }
548     return 0;
549 }
550
551 /* Free this cell for reuse */
552 static void
553 FreeUnusedCell()
554 {
555     struct ktc_principal client, server;
556     struct ktc_token token;
557     long code;
558
559     strcpy(server.name, "afs");
560     strcpy(server.instance, "");
561     strcpy(server.cell, cellNameList[unusedCell]);
562
563     token.ticketLen = MINKTCTICKETLEN;
564     token.endTime = 0;
565     code = ktc_SetToken(&server, &token, &client, 0);
566     if (code) {
567         afs_com_err(whoami, code, "freeing cell");
568         exit(1);
569     }
570 }
571
572 static int
573 TryAuthenticating(name, password, viceId, cell)
574      char *name;
575      char *password;
576      long viceId;
577      char *cell;
578 {
579     long code;
580     char *reason;
581     struct ktc_principal server, client;
582     struct ktc_token token;
583     long lifetime;
584     unsigned long now = time(0);
585
586     code = ka_UserAuthenticate(name, "", cell, password, 0, &reason);
587     if (code) {
588         fprintf(stderr, "unable to authenticate as %s because %s\n", name,
589                 reason);
590         return 1;
591     }
592     strcpy(server.name, "afs");
593     strcpy(server.instance, "");
594     strcpy(server.cell, cell);
595     code = ktc_GetToken(&server, &token, sizeof(token), &client);
596     if (code) {
597         afs_com_err(whoami, code, "so couldn't get %s's afs token in %s", name,
598                 cell);
599         return code;
600     }
601     if (code = tkt_CheckTimes(token.startTime, token.endTime, now) != 2) {
602         fprintf(stdout, "Bad times on afs ticket\n");
603         PrintAuthentication(stdout, &server, &token, &client);
604         return code;
605     }
606
607     lifetime = token.endTime - token.startTime;
608     if ((lifetime & 1) == 0) {
609         fprintf(stderr, "*** Old style KTC (in cell %s) ***\n", cell);
610     } else {
611         char tmp[24];
612         sprintf(tmp, "AFS ID %d", viceId);
613         if ((strcmp(client.name, tmp) != 0) || strlen(client.instance)) {
614             fprintf(stderr, "GetToken returned bad client: '");
615             PrintPrincipal(stderr, &client);
616             fprintf(stderr, "' should have gotten AFS ID %d for %s@%s\n",
617                     viceId, name, cell);
618             return 1;
619         }
620     }
621     if (verbose) {
622         fprintf(stdout, "%s@%s using ", name, cell);
623         PrintAuthentication(stdout, &server, &token, &client);
624     }
625     return 0;
626 }
627
628 static long
629 CheckAFSTickets()
630 {
631     long code;
632     struct ktc_principal client, server;
633     struct ktc_token token;
634     struct ktc_principal nclient;
635     struct ktc_token ntoken;
636     long lifetime;
637     long exitCode = 0;
638     char *reason;
639     char *tdpath = "./tester_dir";
640     char *tfpath = "./tester_dir/touch";
641     int fd;
642     unsigned long now = time(0);
643
644     strcpy(server.name, "afs");
645     strcpy(server.instance, "");
646     strcpy(server.cell, ka_LocalCell());
647     code = ktc_GetToken(&server, &token, sizeof(token), &client);
648     if (code) {
649         afs_com_err(whoami, code, "so couldn't get afs token");
650         return code;
651     }
652
653     code = mkdir(tdpath, 0777);
654     if (code && (errno != EEXIST)) {
655         afs_com_err(whoami, errno, "making test dir %s", tdpath);
656         return code;
657     }
658     fd = open(tfpath, O_WRONLY + O_CREAT + O_TRUNC, 0777);
659     if (fd == -1) {
660         afs_com_err(whoami, errno, "making test file %s", tfpath);
661         goto failed;
662     }
663     code = close(fd);
664     if (code) {
665         afs_com_err(whoami, errno, "failed to close %s after create", tfpath);
666         goto failed;
667     }
668
669     code = AddTester(tdpath);
670     if (code)
671         goto failed;
672
673     setpag();
674
675     if (TryAuthenticating(tester, testerPassword, testerId, server.cell))
676         goto failed;
677     code = ktc_GetToken(&server, &ntoken, sizeof(ntoken), &nclient);
678     if (code) {
679         afs_com_err(whoami, code, "getting new local afs token");
680         goto failed;
681     }
682
683     if (remoteTesterId) {       /* make sure remote cells work also */
684         if (TryAuthenticating
685             (remoteTester, remoteTesterPassword, remoteTesterId, cell))
686             goto failed;
687     }
688
689     ktc_ForgetToken(&server);   /* switch to unauthenticated */
690
691     /* check to see if remote ticket disappears also. */
692     {
693         struct ktc_principal remote;
694         strcpy(remote.name, "afs");
695         strcpy(remote.instance, "");
696         strcpy(remote.cell, cell);
697         code = ktc_GetToken(&remote, 0, 0, 0);
698         if (code == KTC_NOENT)
699             fprintf(stdout, "*** Using interim KTC ***\n");
700         else
701             fprintf(stdout, "Using kernel ticket cache\n");
702     }
703
704     code = open(tfpath, O_RDONLY, 0);   /* check for read access */
705     if (!((code == -1) && ((errno == ENOENT) || (errno == EACCES)))) {
706         afs_com_err(whoami, errno, "didn't fail to open %s for read", tfpath);
707         goto failed;
708     }
709
710     /* as tester we should have read but not write */
711     code = ktc_SetToken(&server, &ntoken, &nclient, 0);
712     if (code) {
713         afs_com_err(whoami, code, "restoring new local afs token");
714         goto failed;
715     }
716     code = open(tfpath, O_RDWR + O_TRUNC, 0);
717     if ((code != -1) || (errno != EACCES)) {
718         afs_com_err(whoami, errno, "didn't fail to open %s for write", tfpath);
719         goto failed;
720     }
721     fd = open(tfpath, O_RDONLY, 0);
722     if (fd == -1) {
723         afs_com_err(whoami, errno, "failed to open %s for read", tfpath);
724         goto failed;
725     }
726     code = close(fd);
727     if (code) {
728         afs_com_err(whoami, errno, "failed to close %s after open", tfpath);
729         goto failed;
730     }
731
732   finish:
733     /* go back to original privileges */
734     code = ktc_SetToken(&server, &token, &client, 0);
735     if (code) {
736         afs_com_err(whoami, code, "so couldn't set afs token in new pag");
737         exit(1);
738     }
739     if (unlink(tfpath) || rmdir(tdpath)) {
740         afs_com_err(whoami, errno, "removing test dir %s", tdpath);
741         return 1;
742     }
743     return exitCode;
744
745   failed:
746     exitCode = 1;
747     goto finish;
748 }
749
750 main(argc, argv)
751      int argc;
752      char *argv[];
753 {
754     int i;
755     long code;
756     struct ktc_principal client, server;
757     struct ktc_token token;
758     struct ktc_principal nclient, nnclient;
759     struct ktc_token ntoken;
760     long lifetime;
761     long viceId;
762     int printToken = 0;         /* just print afs @ remoteCell */
763
764     srandom(1);
765
766     /* Initialize afs_com_err error code hacking */
767     initialize_U_error_table();
768     initialize_KA_error_table();
769     initialize_RXK_error_table();
770     initialize_KTC_error_table();
771     initialize_ACFG_error_table();
772
773     /* set defaults */
774     strcpy(cell, "");
775     strcpy(tester, "tester");
776     strcpy(testerPassword, "xxx");
777     testerId = 1031;
778     remoteTesterId = 0;         /* don't try this */
779
780     /* parse arguments */
781     i = 1;
782     while (i < argc) {
783         int arglen = strlen(argv[i]);
784         char arg[256];
785         lcstring(arg, argv[i], sizeof(arg));
786 #define IsArg(a) (strncmp (arg,a, arglen) == 0)
787         if (IsArg("-quiet"))
788             verbose--;
789         else if (IsArg("-verbose"))
790             verbose++;
791         else if (IsArg("-printtoken"))
792             printToken++;
793         else if (IsArg("-remotecell"))
794             strncpy(cell, argv[++i], sizeof(cell));
795         else if (IsArg("-testid"))
796             testerId = atoi(argv[++i]);
797         else if (IsArg("-tester"))
798             strncpy(tester, argv[++i], sizeof(tester));
799         else if (IsArg("-testpassword"))
800             strncpy(testerPassword, argv[++i], sizeof(testerPassword));
801         else if (IsArg("-remotetestid"))
802             remoteTesterId = atoi(argv[++i]);
803         else if (IsArg("-remotetester"))
804             strncpy(remoteTester, argv[++i], sizeof(tester));
805         else if (IsArg("-remotetestpassword"))
806             strncpy(remoteTesterPassword, argv[++i],
807                     sizeof(remoteTesterPassword));
808         else {
809             fprintf(stderr, "unexpected arg '%s'\n", arg);
810           usage:
811             fprintf(stderr,
812                     "Usage is: '%s [-quiet] [-verbose] [-remotecell <cellname>] [-testid <AFS ID>] [-tester <name>] -testpassword <pass> [-remotetestid <AFS ID> -remotetester <name> -remotetestpassword <pass>]\n",
813                     whoami);
814             exit(1);
815         }
816         i++;
817     }
818
819     /* get list of cells */
820     ListCellsCmd();
821
822     /* expand requested cell name */
823     code = ka_CellConfig(AFSCONF_CLIENTNAME);
824     if (code)
825         afs_com_err(whoami, code, "calling cell config");
826     code = ka_ExpandCell(cell, cell, 0);
827     if (code) {
828         afs_com_err(whoami, code, "expanding cell %s", cell);
829         exit(1);
830     }
831
832     strcpy(server.name, "afs");
833     strcpy(server.instance, "");
834     strcpy(server.cell, cell);
835     if (printToken) {
836         code = ktc_GetToken(&server, &token, sizeof(token), &client);
837         if (code) {
838             afs_com_err(whoami, code, "so couldn't get afs token");
839             exit(1);
840         }
841         PrintAuthentication(stdout, &server, &token, &client);
842     } else {                    /* dummy up a token */
843         token.startTime = time(0);
844         token.endTime = token.startTime + 3600;
845         token.kvno = 1;
846         token.ticketLen = 48;
847     }
848
849     /* find a cell w/o tokens */
850     for (i = 0; i < nCells; i++) {
851         strcpy(server.cell, cellNameList[i]);
852         code = ktc_GetToken(&server, &ntoken, sizeof(ntoken), &nclient);
853         if ((code == KTC_NOENT) || ((code == 0) && (ntoken.endTime == 0)))
854             goto unused_cell_found;
855     }
856     fprintf(stderr, "All cells have tokens\n");
857   unused_cell_found:
858     unusedCell = i;
859     if (verbose)
860         printf("Using unused cell %s\n", cellNameList[unusedCell]);
861
862     /* First check for various pathological cases */
863
864     strcpy(server.cell, "foo.bar.baz");
865     memcpy(&ntoken, &token, sizeof(ntoken));
866     code = ktc_SetToken(&server, &ntoken, &client, 0);
867     if (code != KTC_NOCELL) {
868         afs_com_err(whoami, code,
869                 "should have gotten bad pioctl error calling SetToken with bogus cell name");
870         goto failed;
871     }
872     strcpy(server.cell, cellNameList[unusedCell]);
873
874     ntoken.ticketLen = 0;
875     code = ktc_SetToken(&server, &ntoken, &client, 0);
876     if ((code != KTC_TOOBIG) && (code != KTC_PIOCTLFAIL)) {
877         afs_com_err(whoami, code,
878                 "should have gotten error calling SetToken with zero ticket length");
879         goto failed;
880     }
881     ntoken.ticketLen = token.ticketLen;
882     ntoken.endTime = 0;
883     code = ktc_SetToken(&server, &ntoken, &client, 0);
884     if (code) {
885         afs_com_err(whoami, code, "calling SetToken with zero expiration time");
886         goto failed;
887     }
888     strcpy(nclient.name, "foo");
889     strcpy(nclient.instance, "bar");
890     strcpy(nclient.cell, "foo.bar.baz");
891     code = ktc_SetToken(&server, &ntoken, &nclient, 0);
892     if (code) {
893         afs_com_err(whoami, code, "calling SetToken with bogus client cell");
894         goto failed;
895     }
896     memcpy(&ntoken, &token, sizeof(ntoken));
897     if (token.kvno == 999)
898         ntoken.kvno = 99;
899
900     /* Now check out SetToken parsing of specially formed names */
901
902     strcpy(nclient.instance, "");
903     /* cell is uniformly ignored */
904     viceId = 123;
905     sprintf(nclient.name, "AFS ID %d", viceId);
906     if (CheckAFSId(&server, &ntoken, &nclient))
907         goto failed;
908     ntoken.endTime--;
909     if (CheckAFSId(&server, &ntoken, &nclient))
910         goto failed;
911     sprintf(nclient.name, "AFS ID 0%d", viceId);
912     if (CheckAFSId(&server, &ntoken, &nclient))
913         goto failed;
914 #if 1
915     sprintf(nclient.name, "AFS ID %d", -44444);
916     if (CheckAFSId(&server, &ntoken, &nclient))
917         goto failed;
918 #endif
919     sprintf(nclient.name, "AFS ID %d", 0x7fffffff);
920     if (CheckAFSId(&server, &ntoken, &nclient))
921         goto failed;
922
923     sprintf(nclient.name, "AFS ID ");
924     if (CheckUnixUID(&server, &ntoken, &nclient))
925         goto failed;
926     sprintf(nclient.name, "AFS ID 10x");
927     if (CheckUnixUID(&server, &ntoken, &nclient))
928         goto failed;
929     sprintf(nclient.name, "foobar");
930     if (CheckUnixUID(&server, &ntoken, &nclient))
931         goto failed;
932     ntoken.endTime--;
933     if (CheckUnixUID(&server, &ntoken, &nclient))
934         goto failed;
935
936     /* make sure simulated auth2 tokens still does something reasonable */
937     if (CheckAuth2(&server))
938         goto failed;
939
940     FreeUnusedCell();
941
942     code = CheckAFSTickets();   /* returns in new PAG */
943     if (code)
944         exit(1);
945
946     rx_Finalize();
947
948     printf("All OK\n");
949     exit(0);
950
951   failed:
952     FreeUnusedCell();
953     exit(1);
954 }