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