2 * Copyright 2000, International Business Machines Corporation and others.
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
10 /* Test ktc related calls as well as some file access stuff. */
12 #include <sys/types.h>
16 #include <arpa/inet.h>
17 #include <afs/prs_fs.h>
18 #include <afs/param.h>
20 #include <afs/com_err.h>
21 #include <afs/cellconfig.h>
28 static char *whoami = "test_interim_ktc";
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];
38 static char remoteTester[MAXKTCNAMELEN];
39 static char remoteTesterPassword[32];
40 static long remoteTesterId;
42 static void PrintPrincipal (stream, p)
44 struct ktc_principal *p;
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);
53 static void PrintAuthentication (stream, s, t, c)
55 struct ktc_principal *s, *c;
59 unsigned long now = time(0);
60 char bob[KA_TIMESTR_LEN];
62 lifetime = (unsigned long)t->endTime - (unsigned long)t->startTime;
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",
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);
89 fprintf (stream, "from %d to %d is %d seconds\n", t->startTime,
90 t->endTime, lifetime);
91 fprintf (stream, "Lifetime is odd\n");
95 static int CheckUnixUID (server, token, client)
96 struct ktc_principal *server;
97 struct ktc_token *token;
98 struct ktc_principal *client;
101 struct ktc_token ntoken;
102 struct ktc_principal nclient;
106 code = ktc_SetToken (server, token, client, 0);
108 com_err (whoami, code, "using SetToken to set vice id");
111 sprintf (name_buf, "Unix UID %d", getuid());
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);
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);
131 static int CheckAFSId (server, token, client)
132 struct ktc_principal *server;
133 struct ktc_token *token;
134 struct ktc_principal *client;
137 struct ktc_token ntoken;
138 struct ktc_principal nclient;
143 viceId = atoi((client->name) + 7);
144 code = ktc_SetToken (server, token, client, 0);
146 com_err (whoami, code, "using SetToken to set vice id to %d", viceId);
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");
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);
171 #include <afs/venus.h>
173 /* Stolen from auth/comktc.c: U_CellSetLocalTokens */
174 /* Try various Auth2 style pioctl calls with kvno == 999 */
176 static int CheckAuth2 (server)
177 struct ktc_principal *server;
181 struct ViceIoctl buffer; /*pioctl() communication block*/
182 struct ktc_principal client;
183 struct ktc_token token;
186 struct EncryptedSecretToken {
189 typedef struct EncryptedSecretToken EncryptedSecretToken;
193 struct ktc_encryptionKey HandShakeKey;
198 typedef struct ClearToken ClearToken;
200 /* venus buffer for using the new interface to set/get venus tokens */
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*/
211 EncryptedSecretToken sToken;
215 cellID = server->cell;
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 */
226 /* Then invent secret token */
227 for (i = 0; i < sizeof(sToken); i++)
228 sToken.data[i] = random() & 0xff;
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));
237 /* Copy in the Primary ID flag and the cell name */
239 fprintf(stderr, "U_CellSetLocalTokens: using isPrimary=%d, cellName='%s'\n",
240 primaryFlag, cellID);
242 inbuff.isPrimary = primaryFlag;
243 strcpy(inbuff.cellName, cellID);
245 /* Place our inbuff in the standard PIOCTL buffer and go for it. */
246 buffer.in = (char *)&inbuff;
248 buffer.in_size = sizeof(inbuff);
250 code = pioctl(0, _VICEIOCTL(3), &buffer, 1);
252 com_err (whoami, errno, "setting old-style token");
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");
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);
281 /* Stolen from the "fs" command. */
286 static void ListCellsCmd ()
293 struct ViceIoctl blob;
295 for(i=0;i<1000;i++) {
297 blob.out_size = MAXSIZE;
298 blob.in_size = sizeof(long);
301 bcopy(&i, space, sizeof(long));
302 code = pioctl(0, VIOCGETCELL, &blob, 1);
304 if (errno == EDOM) break; /* done with the list */
306 com_err (whoami, code, "getting cell list");
310 cellname = space+8*sizeof(long);
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;
317 tcp = hostutil_GetNameByINet(clear);
319 tcp = inet_ntoa(clear);
325 if (nCells < CELLSTOKEEP) {
326 strncpy (cellNameList[nCells++], cellname, MAXKTCREALMLEN);
332 /* Stolen from the fs command */
337 struct AclEntry *pluslist;
338 struct AclEntry *minuslist;
342 struct AclEntry *next;
347 char *AclToString(acl)
350 static char mydata[MAXSIZE];
351 char tstring[MAXSIZE];
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);
358 for(tp = acl->minuslist;tp;tp=tp->next) {
359 sprintf(tstring, "%s %d\n", tp->name, tp->rights);
360 strcat(mydata, tstring);
365 char *SkipLine (astr)
366 register char *astr; {
367 while (*astr !='\n') astr++;
372 struct Acl *ParseAcl (astr)
375 int nplus, nminus, i, trights;
377 struct AclEntry *first, *last, *tl;
379 sscanf(astr, "%d", &nplus);
380 astr = SkipLine(astr);
381 sscanf(astr, "%d", &nminus);
382 astr = SkipLine(astr);
384 ta = (struct Acl *) malloc (sizeof (struct Acl));
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;
398 if (last) last->next = tl;
401 ta->pluslist = first;
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;
413 if (last) last->next = tl;
416 ta->minuslist = first;
422 struct AclEntry *alist;
424 register struct AclEntry *tp, *np;
425 for (tp = alist; tp; tp = np) {
432 struct AclEntry **ae;
434 struct AclEntry **lp;
435 struct AclEntry *te, *ne;
439 for(te = *ae;te;te=ne) {
440 if (te->rights == 0) {
454 static int AddTester(pathname)
458 struct ViceIoctl blob;
462 blob.out_size = MAXSIZE;
465 code = pioctl(pathname, VIOCGETAL, &blob, 1);
467 com_err (whoami, errno, "getting acl for %s", pathname);
470 if (verbose > 1) printf ("old acl for %s is %s\n", pathname, space);
471 al = ParseAcl(space);
473 { struct AclEntry *tlist;
475 /* clean acl up a bit */
476 ZapList (al->minuslist);
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;
486 al->nplus -= PruneList(&al->pluslist);
488 tlist = (struct AclEntry *) malloc(sizeof (struct AclEntry));
490 strcpy (tlist->name, tester);
491 tlist->next = al->pluslist;
492 al->pluslist = tlist;
498 printf ("before:\n");
499 sprintf (tmp, "fs la %s", pathname);
503 blob.in = AclToString(al);
505 blob.in_size = 1+strlen(blob.in);
506 code = pioctl(pathname, VIOCSETAL, &blob, 1);
508 com_err (whoami, errno, "setting acl on %s to %s", pathname, blob.in);
514 sprintf (tmp, "fs la %s", pathname);
520 /* Free this cell for reuse */
521 static void FreeUnusedCell ()
523 struct ktc_principal client, server;
524 struct ktc_token token;
527 strcpy (server.name, "afs");
528 strcpy (server.instance, "");
529 strcpy (server.cell, cellNameList[unusedCell]);
531 token.ticketLen = MINKTCTICKETLEN;
533 code = ktc_SetToken (&server, &token, &client, 0);
535 com_err (whoami, code, "freeing cell");
540 static int TryAuthenticating (name, password, viceId, cell)
548 struct ktc_principal server, client;
549 struct ktc_token token;
551 unsigned long now = time(0);
553 code = ka_UserAuthenticate (name, "", cell, password, 0, &reason);
555 fprintf (stderr, "unable to authenticate as %s because %s\n",
559 strcpy (server.name, "afs");
560 strcpy (server.instance, "");
561 strcpy (server.cell, cell);
562 code = ktc_GetToken (&server, &token, sizeof(token), &client);
564 com_err (whoami, code,
565 "so couldn't get %s's afs token in %s", name, cell);
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);
574 lifetime = token.endTime - token.startTime;
575 if ((lifetime & 1) == 0) {
576 fprintf (stderr, "*** Old style KTC (in cell %s) ***\n", cell);
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);
585 "' should have gotten AFS ID %d for %s@%s\n",
591 fprintf (stdout, "%s@%s using ", name, cell);
592 PrintAuthentication (stdout, &server, &token, &client);
597 static long CheckAFSTickets ()
600 struct ktc_principal client, server;
601 struct ktc_token token;
602 struct ktc_principal nclient;
603 struct ktc_token ntoken;
607 char *tdpath = "./tester_dir";
608 char *tfpath = "./tester_dir/touch";
610 unsigned long now = time(0);
612 strcpy (server.name, "afs");
613 strcpy (server.instance, "");
614 strcpy (server.cell, ka_LocalCell());
615 code = ktc_GetToken (&server, &token, sizeof(token), &client);
617 com_err (whoami, code, "so couldn't get afs token");
621 code = mkdir (tdpath, 0777);
622 if (code && (errno != EEXIST)) {
623 com_err (whoami, errno, "making test dir %s", tdpath);
626 fd = open(tfpath, O_WRONLY + O_CREAT + O_TRUNC, 0777);
628 com_err (whoami, errno, "making test file %s", tfpath);
633 com_err (whoami, errno, "failed to close %s after create", tfpath);
637 code = AddTester (tdpath);
638 if (code) goto failed;
642 if (TryAuthenticating (tester, testerPassword, testerId, server.cell))
644 code = ktc_GetToken (&server, &ntoken, sizeof(ntoken), &nclient);
646 com_err (whoami, code, "getting new local afs token");
650 if (remoteTesterId) { /* make sure remote cells work also */
651 if (TryAuthenticating
652 (remoteTester, remoteTesterPassword, remoteTesterId, cell))
656 ktc_ForgetToken (&server); /* switch to unauthenticated */
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");
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);
675 /* as tester we should have read but not write */
676 code = ktc_SetToken (&server, &ntoken, &nclient, 0);
678 com_err (whoami, code, "restoring new local afs token");
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);
686 fd = open (tfpath, O_RDONLY, 0);
688 com_err (whoami, errno, "failed to open %s for read", tfpath);
693 com_err (whoami, errno, "failed to close %s after open", tfpath);
698 /* go back to original privileges */
699 code = ktc_SetToken (&server, &token, &client, 0);
701 com_err (whoami, code, "so couldn't set afs token in new pag");
704 if (unlink (tfpath) || rmdir (tdpath)) {
705 com_err (whoami, errno, "removing test dir %s", tdpath);
721 struct ktc_principal client, server;
722 struct ktc_token token;
723 struct ktc_principal nclient, nnclient;
724 struct ktc_token ntoken;
727 int printToken = 0; /* just print afs @ remoteCell */
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();
740 strcpy (tester, "tester");
741 strcpy (testerPassword, "xxx");
743 remoteTesterId = 0; /* don't try this */
745 /* parse arguments */
748 int arglen = strlen(argv[i]);
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));
767 fprintf (stderr, "unexpected arg '%s'\n", arg);
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);
775 /* get list of cells */
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);
783 com_err (whoami, code, "expanding cell %s", cell);
787 strcpy (server.name, "afs");
788 strcpy (server.instance, "");
789 strcpy (server.cell, cell);
791 code = ktc_GetToken (&server, &token, sizeof(token), &client);
793 com_err (whoami, code, "so couldn't get afs token");
796 PrintAuthentication (stdout, &server, &token, &client);
797 } else { /* dummy up a token */
798 token.startTime = time(0);
799 token.endTime = token.startTime + 3600;
801 token.ticketLen = 48;
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;
811 fprintf (stderr, "All cells have tokens\n");
814 if (verbose) printf ("Using unused cell %s\n", cellNameList[unusedCell]);
816 /* First check for various pathological cases */
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");
825 strcpy (server.cell, cellNameList[unusedCell]);
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");
833 ntoken.ticketLen = token.ticketLen;
835 code = ktc_SetToken (&server, &ntoken, &client, 0);
837 com_err (whoami, code, "calling SetToken with zero expiration time");
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);
845 com_err (whoami, code, "calling SetToken with bogus client cell");
848 bcopy (&token, &ntoken, sizeof(ntoken));
849 if (token.kvno == 999) ntoken.kvno = 99;
851 /* Now check out SetToken parsing of specially formed names */
853 strcpy (nclient.instance, "");
854 /* cell is uniformly ignored */
856 sprintf (nclient.name, "AFS ID %d", viceId);
857 if (CheckAFSId (&server, &ntoken, &nclient)) goto failed;
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;
863 sprintf (nclient.name, "AFS ID %d", -44444);
864 if (CheckAFSId (&server, &ntoken, &nclient)) goto failed;
866 sprintf (nclient.name, "AFS ID %d", 0x7fffffff);
867 if (CheckAFSId (&server, &ntoken, &nclient)) goto failed;
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;
876 if (CheckUnixUID (&server, &ntoken, &nclient)) goto failed;
878 /* make sure simulated auth2 tokens still does something reasonable */
879 if (CheckAuth2 (&server)) goto failed;
883 code = CheckAFSTickets(); /* returns in new PAG */