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 <afsconfig.h>
19 #include <afs/param.h>
24 #include <afs/com_err.h>
25 #include <afs/cellconfig.h>
32 static char *whoami = "test_interim_ktc";
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];
42 static char remoteTester[MAXKTCNAMELEN];
43 static char remoteTesterPassword[32];
44 static long remoteTesterId;
46 static void PrintPrincipal (stream, p)
48 struct ktc_principal *p;
51 fprintf (stream, "%s", p->name);
52 if (strlen(p->instance)) fprintf (stream, ".%s", p->instance);
53 if (strlen(p->cell) && (strcmp (p->cell, ka_LocalCell()) != 0))
54 fprintf (stream, "@%s", p->cell);
57 static void PrintAuthentication (stream, s, t, c)
59 struct ktc_principal *s, *c;
63 unsigned long now = time(0);
64 char bob[KA_TIMESTR_LEN];
66 lifetime = (unsigned long)t->endTime - (unsigned long)t->startTime;
68 fprintf (stream, "Ticket for '");
69 PrintPrincipal (stream, s);
70 fprintf (stream, "'\n");
71 ka_timestr(t->endTime,bob,KA_TIMESTR_LEN);
72 fprintf (stream, " good for %d seconds till %s",
75 /* Allow one second grace, so the even/odd lifetime doesn't appear as an
76 * error. If it is way off complain loudly. */
77 if (now+KTC_TIME_UNCERTAINTY < t->startTime)
78 fprintf (stream, " [FUTURE]\n");
79 else if (now+1 < t->startTime) fprintf (stream, " [ahead]\n");
80 else if (now >= t->endTime+KTC_TIME_UNCERTAINTY)
81 fprintf (stream, " [EXPIRED]\n");
82 else if (now >= t->endTime) fprintf (stream, " [behind]\n");
83 else fprintf (stream, "\n");
84 fprintf (stream, " for user '");
85 PrintPrincipal (stream, c);
86 fprintf (stream, "'\n");
87 fprintf (stream, " session key='");
88 ka_PrintBytes (&t->sessionKey, sizeof(t->sessionKey));
89 fprintf (stream, "'\n");
90 fprintf (stream, " kvno=%d, ticket is %d bytes long.\n",
91 t->kvno, t->ticketLen);
93 fprintf (stream, "from %d to %d is %d seconds\n", t->startTime,
94 t->endTime, lifetime);
95 fprintf (stream, "Lifetime is odd\n");
99 static int CheckUnixUID (server, token, client)
100 struct ktc_principal *server;
101 struct ktc_token *token;
102 struct ktc_principal *client;
105 struct ktc_token ntoken;
106 struct ktc_principal nclient;
110 code = ktc_SetToken (server, token, client, 0);
112 com_err (whoami, code, "using SetToken to set vice id");
115 sprintf (name_buf, "Unix UID %d", getuid());
117 code = ktc_GetToken (server, &ntoken, sizeof(ntoken), &nclient);
118 if (code || (strcmp (nclient.name, name_buf) != 0) ||
119 strlen (nclient.instance)) {
120 fprintf (stderr, "GetToken returned bad client: '");
121 PrintPrincipal (stderr, &nclient);
122 fprintf (stderr, "'\n");
123 com_err (whoami, code, "should have gotten '%s'", name_buf);
126 lifetime = (unsigned long)ntoken.endTime - (unsigned long)ntoken.startTime;
127 if ((lifetime & 1) == 1) {
128 com_err (whoami, code,
129 "GetToken returned even lifetime (%d)", lifetime);
135 static int CheckAFSId (server, token, client)
136 struct ktc_principal *server;
137 struct ktc_token *token;
138 struct ktc_principal *client;
141 struct ktc_token ntoken;
142 struct ktc_principal nclient;
147 viceId = atoi((client->name) + 7);
148 code = ktc_SetToken (server, token, client, 0);
150 com_err (whoami, code, "using SetToken to set vice id to %d", viceId);
153 code = ktc_GetToken (server, &ntoken, sizeof(ntoken), &nclient);
154 if ((strncmp (nclient.name, "AFS ID ", 7) != 0) ||
155 (strlen (nclient.name) < 8) ||
156 (atoi (nclient.name + 7) != viceId) ||
157 strlen (nclient.instance)) {
158 fprintf (stderr, "GetToken returned bad client: '");
159 PrintPrincipal (stderr, &nclient);
160 fprintf (stderr, "' should have gotten '");
161 PrintPrincipal (stderr, client);
162 fprintf (stderr, "'\n");
163 com_err (whoami, code, "didn't preserve AFS ID");
166 lifetime = (unsigned long)ntoken.endTime - (unsigned long)ntoken.startTime;
167 if ((lifetime & 1) == 0) {
168 com_err (whoami, code,
169 "GetToken returned even lifetime (%d)", lifetime);
175 #include <afs/venus.h>
177 /* Stolen from auth/comktc.c: U_CellSetLocalTokens */
178 /* Try various Auth2 style pioctl calls with kvno == 999 */
180 static int CheckAuth2 (server)
181 struct ktc_principal *server;
185 struct ViceIoctl buffer; /*pioctl() communication block*/
186 struct ktc_principal client;
187 struct ktc_token token;
190 struct EncryptedSecretToken {
193 typedef struct EncryptedSecretToken EncryptedSecretToken;
197 struct ktc_encryptionKey HandShakeKey;
202 typedef struct ClearToken ClearToken;
204 /* venus buffer for using the new interface to set/get venus tokens */
206 int sTokenSize; /*Size in bytes of secret token*/
207 EncryptedSecretToken stoken; /*Secret token*/
208 int cTokenSize; /*Size in bytes of clear token*/
209 ClearToken ctoken; /*Clear token*/
210 int isPrimary; /*Is this the primary ID?*/
211 char cellName[64]; /*Cell in which tokens are valid*/
215 EncryptedSecretToken sToken;
219 cellID = server->cell;
222 /* First build a plausible clear token (code from old auth(2) server */
223 cToken.AuthHandle = -1; /* not in use right now */
224 for (i = 0; i < sizeof(struct ktc_encryptionKey); i++)
225 cToken.HandShakeKey.data[i] = random() & 0xff;
226 cToken.BeginTimestamp = 0;
227 cToken.EndTimestamp = time(0) + 60*60*25; /* valid for 25 hours */
230 /* Then invent secret token */
231 for (i = 0; i < sizeof(sToken); i++)
232 sToken.data[i] = random() & 0xff;
235 /*Copy in the sizes and bodies of the secret and clear tokens*/
236 inbuff.sTokenSize = sizeof(EncryptedSecretToken);
237 memcpy((char *)&inbuff.stoken, &sToken, sizeof(EncryptedSecretToken));
238 inbuff.cTokenSize = sizeof(ClearToken);
239 memcpy((char*)&inbuff.ctoken, &cToken, sizeof(ClearToken));
241 /* Copy in the Primary ID flag and the cell name */
243 fprintf(stderr, "U_CellSetLocalTokens: using isPrimary=%d, cellName='%s'\n",
244 primaryFlag, cellID);
246 inbuff.isPrimary = primaryFlag;
247 strcpy(inbuff.cellName, cellID);
249 /* Place our inbuff in the standard PIOCTL buffer and go for it. */
250 buffer.in = (char *)&inbuff;
252 buffer.in_size = sizeof(inbuff);
254 code = pioctl(0, _VICEIOCTL(3), &buffer, 1);
256 com_err (whoami, errno, "setting old-style token");
260 /* now get it back and see if it's OK */
261 code = ktc_GetToken (server, &token, sizeof(token), &client);
262 if ((strcmp (client.name, "AFS ID 123") != 0) ||
263 strlen (client.instance) ||
264 (strcmp (client.cell, cellID) != 0)) {
265 fprintf (stderr, "GetToken returned bad client: '");
266 PrintPrincipal (stderr, &client);
267 fprintf (stderr, "'\n");
270 if ((token.kvno != 999) ||
271 (token.startTime != 0) ||
272 (token.endTime != cToken.EndTimestamp) ||
273 (token.ticketLen != sizeof(sToken)) ||
274 (memcmp (&cToken.HandShakeKey, &token.sessionKey, sizeof(struct ktc_encryptionKey)) != 0) ||
275 (memcmp (&sToken, token.ticket, sizeof(sToken)) != 0)) {
276 fprintf (stdout, "Auth2 token was bad\n");
277 PrintAuthentication (stdout, server, &token, &client);
285 /* Stolen from the "fs" command. */
290 static void ListCellsCmd ()
297 struct ViceIoctl blob;
299 for(i=0;i<1000;i++) {
301 blob.out_size = MAXSIZE;
302 blob.in_size = sizeof(long);
305 memcpy(space, &i, sizeof(long));
306 code = pioctl(0, VIOCGETCELL, &blob, 1);
308 if (errno == EDOM) break; /* done with the list */
310 com_err (whoami, code, "getting cell list");
314 cellname = space+8*sizeof(long);
316 printf("Cell %s on hosts", cellname);
317 for (j=0; j < 8; j++) {
318 memcpy(&clear, space + j*sizeof(long), sizeof(long));
319 if (clear == 0) break;
321 tcp = hostutil_GetNameByINet(clear);
323 tcp = inet_ntoa(clear);
329 if (nCells < CELLSTOKEEP) {
330 strncpy (cellNameList[nCells++], cellname, MAXKTCREALMLEN);
336 /* Stolen from the fs command */
341 struct AclEntry *pluslist;
342 struct AclEntry *minuslist;
346 struct AclEntry *next;
351 char *AclToString(acl)
354 static char mydata[MAXSIZE];
355 char tstring[MAXSIZE];
357 sprintf(mydata, "%d\n%d\n", acl->nplus, acl->nminus);
358 for(tp = acl->pluslist;tp;tp=tp->next) {
359 sprintf(tstring, "%s %d\n", tp->name, tp->rights);
360 strcat(mydata, tstring);
362 for(tp = acl->minuslist;tp;tp=tp->next) {
363 sprintf(tstring, "%s %d\n", tp->name, tp->rights);
364 strcat(mydata, tstring);
369 char *SkipLine (astr)
370 register char *astr; {
371 while (*astr !='\n') astr++;
376 struct Acl *ParseAcl (astr)
379 int nplus, nminus, i, trights;
381 struct AclEntry *first, *last, *tl;
383 sscanf(astr, "%d", &nplus);
384 astr = SkipLine(astr);
385 sscanf(astr, "%d", &nminus);
386 astr = SkipLine(astr);
388 ta = (struct Acl *) malloc (sizeof (struct Acl));
394 for(i=0;i<nplus;i++) {
395 sscanf(astr, "%100s %d", tname, &trights);
396 astr = SkipLine(astr);
397 tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
398 if (!first) first = tl;
399 strcpy(tl->name, tname);
400 tl->rights = trights;
402 if (last) last->next = tl;
405 ta->pluslist = first;
409 for(i=0;i<nminus;i++) {
410 sscanf(astr, "%100s %d", tname, &trights);
411 astr = SkipLine(astr);
412 tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
413 if (!first) first = tl;
414 strcpy(tl->name, tname);
415 tl->rights = trights;
417 if (last) last->next = tl;
420 ta->minuslist = first;
426 struct AclEntry *alist;
428 register struct AclEntry *tp, *np;
429 for (tp = alist; tp; tp = np) {
436 struct AclEntry **ae;
438 struct AclEntry **lp;
439 struct AclEntry *te, *ne;
443 for(te = *ae;te;te=ne) {
444 if (te->rights == 0) {
458 static int AddTester(pathname)
462 struct ViceIoctl blob;
466 blob.out_size = MAXSIZE;
469 code = pioctl(pathname, VIOCGETAL, &blob, 1);
471 com_err (whoami, errno, "getting acl for %s", pathname);
474 if (verbose > 1) printf ("old acl for %s is %s\n", pathname, space);
475 al = ParseAcl(space);
477 { struct AclEntry *tlist;
479 /* clean acl up a bit */
480 ZapList (al->minuslist);
483 for (ae=al->pluslist; ae; ae = ae->next) {
484 if ((strcmp (ae->name, tester) == 0) ||
485 /* punt useless entries (like system:anyuser) */
486 !(ae->rights & (PRSFS_INSERT | PRSFS_DELETE |
487 PRSFS_WRITE | PRSFS_LOCK |
488 PRSFS_ADMINISTER))) ae->rights = 0;
490 al->nplus -= PruneList(&al->pluslist);
492 tlist = (struct AclEntry *) malloc(sizeof (struct AclEntry));
494 strcpy (tlist->name, tester);
495 tlist->next = al->pluslist;
496 al->pluslist = tlist;
502 printf ("before:\n");
503 sprintf (tmp, "fs la %s", pathname);
507 blob.in = AclToString(al);
509 blob.in_size = 1+strlen(blob.in);
510 code = pioctl(pathname, VIOCSETAL, &blob, 1);
512 com_err (whoami, errno, "setting acl on %s to %s", pathname, blob.in);
518 sprintf (tmp, "fs la %s", pathname);
524 /* Free this cell for reuse */
525 static void FreeUnusedCell ()
527 struct ktc_principal client, server;
528 struct ktc_token token;
531 strcpy (server.name, "afs");
532 strcpy (server.instance, "");
533 strcpy (server.cell, cellNameList[unusedCell]);
535 token.ticketLen = MINKTCTICKETLEN;
537 code = ktc_SetToken (&server, &token, &client, 0);
539 com_err (whoami, code, "freeing cell");
544 static int TryAuthenticating (name, password, viceId, cell)
552 struct ktc_principal server, client;
553 struct ktc_token token;
555 unsigned long now = time(0);
557 code = ka_UserAuthenticate (name, "", cell, password, 0, &reason);
559 fprintf (stderr, "unable to authenticate as %s because %s\n",
563 strcpy (server.name, "afs");
564 strcpy (server.instance, "");
565 strcpy (server.cell, cell);
566 code = ktc_GetToken (&server, &token, sizeof(token), &client);
568 com_err (whoami, code,
569 "so couldn't get %s's afs token in %s", name, cell);
572 if (code = tkt_CheckTimes (token.startTime, token.endTime, now) != 2) {
573 fprintf (stdout, "Bad times on afs ticket\n");
574 PrintAuthentication (stdout, &server, &token, &client);
578 lifetime = token.endTime - token.startTime;
579 if ((lifetime & 1) == 0) {
580 fprintf (stderr, "*** Old style KTC (in cell %s) ***\n", cell);
583 sprintf (tmp, "AFS ID %d", viceId);
584 if ((strcmp (client.name, tmp) != 0) ||
585 strlen (client.instance)) {
586 fprintf (stderr, "GetToken returned bad client: '");
587 PrintPrincipal (stderr, &client);
589 "' should have gotten AFS ID %d for %s@%s\n",
595 fprintf (stdout, "%s@%s using ", name, cell);
596 PrintAuthentication (stdout, &server, &token, &client);
601 static long CheckAFSTickets ()
604 struct ktc_principal client, server;
605 struct ktc_token token;
606 struct ktc_principal nclient;
607 struct ktc_token ntoken;
611 char *tdpath = "./tester_dir";
612 char *tfpath = "./tester_dir/touch";
614 unsigned long now = time(0);
616 strcpy (server.name, "afs");
617 strcpy (server.instance, "");
618 strcpy (server.cell, ka_LocalCell());
619 code = ktc_GetToken (&server, &token, sizeof(token), &client);
621 com_err (whoami, code, "so couldn't get afs token");
625 code = mkdir (tdpath, 0777);
626 if (code && (errno != EEXIST)) {
627 com_err (whoami, errno, "making test dir %s", tdpath);
630 fd = open(tfpath, O_WRONLY + O_CREAT + O_TRUNC, 0777);
632 com_err (whoami, errno, "making test file %s", tfpath);
637 com_err (whoami, errno, "failed to close %s after create", tfpath);
641 code = AddTester (tdpath);
642 if (code) goto failed;
646 if (TryAuthenticating (tester, testerPassword, testerId, server.cell))
648 code = ktc_GetToken (&server, &ntoken, sizeof(ntoken), &nclient);
650 com_err (whoami, code, "getting new local afs token");
654 if (remoteTesterId) { /* make sure remote cells work also */
655 if (TryAuthenticating
656 (remoteTester, remoteTesterPassword, remoteTesterId, cell))
660 ktc_ForgetToken (&server); /* switch to unauthenticated */
662 /* check to see if remote ticket disappears also. */
663 { struct ktc_principal remote;
664 strcpy (remote.name, "afs");
665 strcpy (remote.instance, "");
666 strcpy (remote.cell, cell);
667 code = ktc_GetToken (&remote, 0, 0, 0);
668 if (code == KTC_NOENT)
669 fprintf (stdout, "*** Using interim KTC ***\n");
670 else fprintf (stdout, "Using kernel ticket cache\n");
673 code = open (tfpath, O_RDONLY, 0); /* check for read access */
674 if (!((code == -1) && ((errno == ENOENT) || (errno == EACCES)))) {
675 com_err (whoami, errno, "didn't fail to open %s for read", tfpath);
679 /* as tester we should have read but not write */
680 code = ktc_SetToken (&server, &ntoken, &nclient, 0);
682 com_err (whoami, code, "restoring new local afs token");
685 code = open (tfpath, O_RDWR + O_TRUNC, 0);
686 if ((code != -1) || (errno != EACCES)) {
687 com_err (whoami, errno, "didn't fail to open %s for write", tfpath);
690 fd = open (tfpath, O_RDONLY, 0);
692 com_err (whoami, errno, "failed to open %s for read", tfpath);
697 com_err (whoami, errno, "failed to close %s after open", tfpath);
702 /* go back to original privileges */
703 code = ktc_SetToken (&server, &token, &client, 0);
705 com_err (whoami, code, "so couldn't set afs token in new pag");
708 if (unlink (tfpath) || rmdir (tdpath)) {
709 com_err (whoami, errno, "removing test dir %s", tdpath);
725 struct ktc_principal client, server;
726 struct ktc_token token;
727 struct ktc_principal nclient, nnclient;
728 struct ktc_token ntoken;
731 int printToken = 0; /* just print afs @ remoteCell */
735 /* Initialize com_err error code hacking */
736 initialize_U_error_table();
737 initialize_KA_error_table();
738 initialize_RXK_error_table();
739 initialize_KTC_error_table();
740 initialize_ACFG_error_table();
744 strcpy (tester, "tester");
745 strcpy (testerPassword, "xxx");
747 remoteTesterId = 0; /* don't try this */
749 /* parse arguments */
752 int arglen = strlen(argv[i]);
754 lcstring (arg, argv[i], sizeof(arg));
755 #define IsArg(a) (strncmp (arg,a, arglen) == 0)
756 if (IsArg("-quiet")) verbose--;
757 else if (IsArg("-verbose")) verbose++;
758 else if (IsArg("-printtoken")) printToken++;
759 else if (IsArg("-remotecell")) strncpy (cell, argv[++i], sizeof(cell));
760 else if (IsArg("-testid")) testerId = atoi (argv[++i]);
761 else if (IsArg("-tester")) strncpy (tester, argv[++i], sizeof(tester));
762 else if (IsArg("-testpassword"))
763 strncpy (testerPassword, argv[++i], sizeof(testerPassword));
764 else if (IsArg("-remotetestid")) remoteTesterId = atoi (argv[++i]);
765 else if (IsArg("-remotetester"))
766 strncpy (remoteTester, argv[++i], sizeof(tester));
767 else if (IsArg("-remotetestpassword"))
768 strncpy (remoteTesterPassword, argv[++i],
769 sizeof(remoteTesterPassword));
771 fprintf (stderr, "unexpected arg '%s'\n", arg);
773 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);
779 /* get list of cells */
782 /* expand requested cell name */
783 code = ka_CellConfig (AFSCONF_CLIENTNAME);
784 if (code) com_err (whoami, code, "calling cell config");
785 code = ka_ExpandCell (cell, cell, 0);
787 com_err (whoami, code, "expanding cell %s", cell);
791 strcpy (server.name, "afs");
792 strcpy (server.instance, "");
793 strcpy (server.cell, cell);
795 code = ktc_GetToken (&server, &token, sizeof(token), &client);
797 com_err (whoami, code, "so couldn't get afs token");
800 PrintAuthentication (stdout, &server, &token, &client);
801 } else { /* dummy up a token */
802 token.startTime = time(0);
803 token.endTime = token.startTime + 3600;
805 token.ticketLen = 48;
808 /* find a cell w/o tokens */
809 for (i=0; i<nCells; i++) {
810 strcpy (server.cell, cellNameList[i]);
811 code = ktc_GetToken (&server, &ntoken, sizeof(ntoken), &nclient);
812 if ((code == KTC_NOENT) || ((code == 0) && (ntoken.endTime == 0)))
813 goto unused_cell_found;
815 fprintf (stderr, "All cells have tokens\n");
818 if (verbose) printf ("Using unused cell %s\n", cellNameList[unusedCell]);
820 /* First check for various pathological cases */
822 strcpy (server.cell, "foo.bar.baz");
823 memcpy(&ntoken, &token, sizeof(ntoken));
824 code = ktc_SetToken (&server, &ntoken, &client, 0);
825 if (code != KTC_NOCELL) {
826 com_err (whoami, code, "should have gotten bad pioctl error calling SetToken with bogus cell name");
829 strcpy (server.cell, cellNameList[unusedCell]);
831 ntoken.ticketLen = 0;
832 code = ktc_SetToken (&server, &ntoken, &client, 0);
833 if ((code != KTC_TOOBIG) && (code != KTC_PIOCTLFAIL)) {
834 com_err (whoami, code, "should have gotten error calling SetToken with zero ticket length");
837 ntoken.ticketLen = token.ticketLen;
839 code = ktc_SetToken (&server, &ntoken, &client, 0);
841 com_err (whoami, code, "calling SetToken with zero expiration time");
844 strcpy (nclient.name, "foo");
845 strcpy (nclient.instance, "bar");
846 strcpy (nclient.cell, "foo.bar.baz");
847 code = ktc_SetToken (&server, &ntoken, &nclient, 0);
849 com_err (whoami, code, "calling SetToken with bogus client cell");
852 memcpy(&ntoken, &token, sizeof(ntoken));
853 if (token.kvno == 999) ntoken.kvno = 99;
855 /* Now check out SetToken parsing of specially formed names */
857 strcpy (nclient.instance, "");
858 /* cell is uniformly ignored */
860 sprintf (nclient.name, "AFS ID %d", viceId);
861 if (CheckAFSId (&server, &ntoken, &nclient)) goto failed;
863 if (CheckAFSId (&server, &ntoken, &nclient)) goto failed;
864 sprintf (nclient.name, "AFS ID 0%d", viceId);
865 if (CheckAFSId (&server, &ntoken, &nclient)) goto failed;
867 sprintf (nclient.name, "AFS ID %d", -44444);
868 if (CheckAFSId (&server, &ntoken, &nclient)) goto failed;
870 sprintf (nclient.name, "AFS ID %d", 0x7fffffff);
871 if (CheckAFSId (&server, &ntoken, &nclient)) goto failed;
873 sprintf (nclient.name, "AFS ID ");
874 if (CheckUnixUID (&server, &ntoken, &nclient)) goto failed;
875 sprintf (nclient.name, "AFS ID 10x");
876 if (CheckUnixUID (&server, &ntoken, &nclient)) goto failed;
877 sprintf (nclient.name, "foobar");
878 if (CheckUnixUID (&server, &ntoken, &nclient)) goto failed;
880 if (CheckUnixUID (&server, &ntoken, &nclient)) goto failed;
882 /* make sure simulated auth2 tokens still does something reasonable */
883 if (CheckAuth2 (&server)) goto failed;
887 code = CheckAFSTickets(); /* returns in new PAG */