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 /* RX Authentication Stress test: client side code. */
12 #include <afsconfig.h>
13 #include <afs/param.h>
19 #include <afs/com_err.h>
20 #include <afs/afsutil.h>
23 #include <des_prototypes.h>
25 #include "stress_internal.h"
26 #ifdef AFS_PTHREAD_ENV
28 #define FT_ApproxTime() (int)time(0)
36 GetServer(const char *aname)
41 th = gethostbyname(aname);
43 fprintf(stderr, "host %s not found\n", aname);
46 memcpy(&addr, th->h_addr, sizeof(addr));
51 GetToken(long *versionP, struct ktc_encryptionKey *session,
52 int *ticketLenP, char *ticket, char *cell)
54 struct ktc_principal sname;
55 struct ktc_token ttoken;
58 strcpy(sname.cell, cell);
59 sname.instance[0] = 0;
60 strcpy(sname.name, "afs");
61 code = ktc_GetToken(&sname, &ttoken, sizeof(ttoken), NULL);
65 *versionP = ttoken.kvno;
66 *ticketLenP = ttoken.ticketLen;
67 memcpy(ticket, ttoken.ticket, ttoken.ticketLen);
68 memcpy(session, &ttoken.sessionKey, sizeof(struct ktc_encryptionKey));
73 GetTicket(long *versionP, struct ktc_encryptionKey *session,
74 int *ticketLenP, char *ticket, char *cell)
78 /* create random session key, using key for seed to good random */
79 des_init_random_number_generator(ktc_to_cblock(&serviceKey));
80 code = des_random_key(ktc_to_cblock(session));
84 /* now create the actual ticket */
87 tkt_MakeTicket(ticket, ticketLenP, &serviceKey, RXKST_CLIENT_NAME,
88 RXKST_CLIENT_INST, cell,
89 /*start,end */ 0, 0xffffffff, session, /*host */ 0,
90 RXKST_SERVER_NAME, RXKST_SERVER_NAME);
91 /* parms were buffer, ticketlen, key to seal ticket with, principal name,
92 * instance and cell, start time, end time, session key to seal in ticket,
93 * inet host, server name and server instance */
96 *versionP = serviceKeyVersion;
100 struct rx_connection *conn;
101 u_long sendLen; /* parameters for call to Copious */
103 u_long *fastCalls; /* number of calls to perform */
105 u_long *copiousCalls;
109 Copious(struct client *c, char *buf, u_long buflen)
112 struct rx_call *call;
114 long inlen = c->sendLen;
115 long outlen = c->recvLen;
121 for (i = 0; i < inlen; i++)
122 mysum += (d++ & 0xff);
124 call = rx_NewCall(c->conn);
125 code = StartRXKST_Copious(call, inlen, mysum, outlen);
131 while (xfer < inlen) {
135 for (i = 0; i < tlen; i++)
136 buf[i] = (d++ & 0xff);
137 n = rx_Write(call, buf, tlen);
142 code = RXKST_WRITESHORT;
150 while (xfer < outlen) {
151 tlen = outlen - xfer;
154 n = rx_Read(call, buf, tlen);
159 code = RXKST_READSHORT;
162 for (i = 0; i < tlen; i++)
169 code = EndRXKST_Copious(call, &outsum);
170 code = rx_EndCall(call, code);
173 if (outsum != mysum) {
174 return RXKST_BADOUTPUTSUM;
180 DoClient(int index, opaque rock)
182 struct client *c = (struct client *)rock;
188 for (i = 0; i < c->fastCalls[index]; i++) {
189 code = RXKST_Fast(c->conn, n, &inc_n);
193 return RXKST_INCFAILED;
197 for (i = 0; i < c->slowCalls[index]; i++) {
200 code = RXKST_Slow(c->conn, 1, &ntime);
203 now = FT_ApproxTime();
204 if ((ntime < now - maxSkew) || (ntime > now + maxSkew))
205 return RXKST_TIMESKEW;
208 if (c->copiousCalls[index] > 0) {
209 u_long buflen = 10000;
210 char *buf = osi_Alloc(buflen);
211 for (i = 0; i < c->copiousCalls[index]; i++) {
212 code = Copious(c, buf, buflen);
216 osi_Free(buf, buflen);
225 long exitCode; /* is PROCESSRUNNING until exit */
228 long (*proc) (int, opaque);
231 #ifdef AFS_PTHREAD_ENV
232 static pthread_once_t workerOnce = PTHREAD_ONCE_INIT;
233 static pthread_mutex_t workerLock;
234 static pthread_cond_t workerCV;
238 pthread_mutex_init(&workerLock, NULL);
239 pthread_cond_init(&workerCV, NULL);
242 static struct worker *workers;
245 DoWorker(void * rock)
247 struct worker *w = rock;
249 code = (*w->proc) (w->index, w->rock);
250 #ifdef AFS_PTHREAD_ENV
251 pthread_mutex_lock(&workerLock);
254 #ifdef AFS_PTHREAD_ENV
255 pthread_mutex_unlock(&workerLock);
257 #ifdef AFS_PTHREAD_ENV
258 pthread_cond_signal(&workerCV);
260 LWP_NoYieldSignal(&workers);
262 return (void *)(intptr_t)code;
265 #define MAX_CTHREADS 25
268 CallSimultaneously(u_int threads, opaque rock, long (*proc)(int, opaque))
272 #ifdef AFS_PTHREAD_ENV
273 pthread_once(&workerOnce, WorkerInit);
277 for (i = 0; i < threads; i++) {
279 #ifdef AFS_PTHREAD_ENV
284 assert(i < MAX_CTHREADS);
285 w = osi_Alloc(sizeof(struct worker));
286 memset(w, 0, sizeof(*w));
290 w->exitCode = RXKST_PROCESSRUNNING;
293 #ifdef AFS_PTHREAD_ENV
295 pthread_attr_t tattr;
297 code = pthread_attr_init(&tattr);
299 afs_com_err(whoami, code,
300 "can't pthread_attr_init worker process");
305 pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
307 afs_com_err(whoami, code,
308 "can't pthread_attr_setdetachstate worker process");
312 code = pthread_create(&pid, &tattr, DoWorker, (void *)w);
316 LWP_CreateProcess(DoWorker, 16000, LWP_NORMAL_PRIORITY,
317 (opaque) w, "Worker Process", &pid);
320 afs_com_err(whoami, code, "can't create worker process");
324 code = 0; /* last non-zero code encountered */
325 #ifdef AFS_PTHREAD_ENV
326 pthread_mutex_lock(&workerLock);
329 struct worker *w, *prevW, *nextW;
331 for (w = workers; w; w = nextW) {
333 if (w->exitCode != RXKST_PROCESSRUNNING) {
339 prevW->next = w->next;
342 osi_Free(w, sizeof(*w));
343 continue; /* don't bump prevW */
347 #ifdef AFS_PTHREAD_ENV
349 pthread_cond_wait(&workerCV, &workerLock);
352 LWP_WaitProcess(&workers);
355 #ifdef AFS_PTHREAD_ENV
356 pthread_mutex_unlock(&workerLock);
362 DivideUpCalls(u_long calls, u_int threads, u_long threadCalls[])
365 for (i = 0; i < threads; i++) {
366 threadCalls[i] = calls / (threads - i);
367 calls -= threadCalls[i];
375 gettimeofday(&tv, NULL);
376 return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
380 RunLoadTest(struct clientParms *parms, struct rx_connection *conn)
384 u_long fastCalls[MAX_CTHREADS];
385 u_long slowCalls[MAX_CTHREADS];
386 u_long copiousCalls[MAX_CTHREADS];
387 double start, interval;
389 DivideUpCalls(parms->fastCalls, parms->threads, fastCalls);
390 DivideUpCalls(parms->slowCalls, parms->threads, slowCalls);
391 DivideUpCalls(parms->copiousCalls, parms->threads, copiousCalls);
393 memset(&c, 0, sizeof(c));
395 c.sendLen = parms->sendLen;
396 c.recvLen = parms->recvLen;
397 c.fastCalls = fastCalls;
398 c.slowCalls = slowCalls;
399 c.copiousCalls = copiousCalls;
402 code = CallSimultaneously(parms->threads, &c, DoClient);
404 afs_com_err(whoami, code, "in DoClient");
407 interval = ftime() - start;
409 if (parms->printTiming) {
411 parms->fastCalls + parms->slowCalls + parms->copiousCalls;
412 int t = (interval / totalCalls) * 1000.0 + 0.5;
413 if (totalCalls > 0) {
414 printf("For %lu calls: %d msec/call\n", totalCalls, t);
416 if (parms->copiousCalls > 0) {
417 long n = parms->sendLen + parms->recvLen;
420 kbps = (double)(parms->copiousCalls * n) / (interval * 1000.0);
423 ("For %lu copious calls, %lu send + %lu recv = %lu bytes each: %d kbytes/sec\n",
424 parms->copiousCalls, parms->sendLen, parms->recvLen, n, b);
431 RepeatLoadTest(struct clientParms *parms, struct rx_connection *conn)
436 if (parms->repeatInterval == 0) {
437 if (parms->repeatCount == 0)
438 parms->repeatCount = 1;
440 if (parms->repeatCount == 0)
441 parms->repeatCount = 0x7fffffff;
444 if (parms->printTiming) {
447 (parms->fastCalls ? 1 : 0) + (parms->slowCalls ? 1 : 0) +
448 (parms->copiousCalls ? 1 : 0);
451 "Combined timings of several types of calls may not be meaningful.\n");
453 /* do timings of copious calls by default */
454 parms->copiousCalls = 10;
457 for (count = 0; count < parms->repeatCount; count++) {
458 code = RunLoadTest(parms, conn);
461 if (parms->repeatInterval) {
462 u_long i = parms->repeatInterval;
463 u_long now = time(0);
464 u_long next = (now + i - 1) / i * i; /* round up to next interval */
466 #ifdef AFS_PTHREAD_ENV
469 IOMGR_Sleep(next - now);
478 /* For backward compatibility, don't try to use the CallNumber stuff unless
479 * we're compiling against the new Rx. */
481 #ifdef rx_GetPacketCksum
483 struct multiChannel {
484 struct rx_connection *conn;
487 int changes[RX_MAXCALLS];
488 afs_int32 callNumbers[RX_MAXCALLS];
490 #define BIG_PRIME 1257056893 /* 0x4AED2A7d */
491 static u_long sequence = 0;
494 FastCall(struct rx_connection *conn)
497 u_long n = (sequence = sequence * BIG_PRIME + BIG_PRIME);
500 code = RXKST_Fast(conn, n, &inc_n);
504 return RXKST_INCFAILED;
509 UniChannelCall(int index, opaque rock)
511 struct multiChannel *mc = (struct multiChannel *)rock;
513 afs_int32 callNumbers[RX_MAXCALLS];
518 while (!mc->done && unchanged) {
520 code = FastCall(mc->conn);
523 code = rxi_GetCallNumberVector(mc->conn, callNumbers);
527 for (i = 0; i < RX_MAXCALLS; i++) {
528 if (callNumbers[i] > mc->callNumbers[i]) {
529 mc->callNumbers[i] = callNumbers[i];
530 mc->changes[i]--; /* may go negative */
532 if (mc->changes[i] > 0)
536 mc->codes[index] = code;
542 MakeMultiChannelCall(struct rx_connection *conn, int each,
543 long expectedCode, long codes[])
547 struct multiChannel mc;
549 memset(&mc, 0, sizeof(mc));
551 for (i = 0; i < RX_MAXCALLS; i++) {
552 codes[i] = RXKST_PROCESSRUNNING;
553 mc.changes[i] = each;
556 code = rxi_GetCallNumberVector(conn, mc.callNumbers);
560 code = CallSimultaneously(RX_MAXCALLS, &mc, UniChannelCall);
561 if (((expectedCode == RXKST_INCFAILED) || (expectedCode == -1)) && ((code == expectedCode) || (code == -3))); /* strange cases */
562 else if (code != expectedCode) {
563 afs_com_err(whoami, code,
564 "problem making multichannel call, expected '%s'",
566 ? "no error" : (char *)afs_error_message(expectedCode)));
572 CheckCallFailure(struct rx_connection *conn, long codes[], long code,
576 fprintf(stderr, "Failed to detect %s\n", msg);
577 return RXKST_NODUPLICATECALL;
582 for (i = 0; i < RX_MAXCALLS; i++)
583 if (!((codes[i] == 0) || (codes[i] == code) || (codes[i] == -3)))
588 fprintf(stderr, "%s produced these errors:\n", msg);
589 for (i = 0; i < RX_MAXCALLS; i++) {
590 assert(codes[i] != RXKST_PROCESSRUNNING);
593 fprintf(stderr, " %d no error\n", i);
595 fprintf(stderr, " %d %s\n", i, afs_error_message(codes[i]));
599 sprintf(buf, "connection dead following %s", msg);
600 code = FastCall(conn);
602 afs_com_err(whoami, code, "%s", buf);
609 #endif /* rx_GetPacketCksum */
612 RunCallTest(struct clientParms *parms, long host,
613 struct rx_securityClass *sc, long si)
617 #ifndef rx_GetPacketCksum
619 code = RXKST_BADARGS;
620 afs_com_err(whoami, code,
621 "Older versions of Rx don't support Get/Set callNumber Vector procedures: can't run this CallTest");
627 struct rx_connection *conn;
629 afs_int32 callNumbers[RX_MAXCALLS];
630 long codes[RX_MAXCALLS];
631 long retCode = 0; /* ret. if nothing fatal goes wrong */
634 rx_NewConnection(host, htons(RXKST_SERVICEPORT), RXKST_SERVICEID, sc,
637 return RXKST_NEWCONNFAILED;
639 /* First check the basic behaviour of call number handling */
641 code = rxi_GetCallNumberVector(conn, callNumbers);
644 for (i = 0; i < RX_MAXCALLS; i++) {
645 if (callNumbers[i] != 0) {
647 "Connection's initial call numbers not zero. call[%d] = %d\n",
649 return RXKST_BADCALLNUMBERS;
652 code = FastCall(conn);
655 code = rxi_GetCallNumberVector(conn, callNumbers);
658 firstCall = callNumbers[0];
659 code = FastCall(conn);
662 code = rxi_GetCallNumberVector(conn, callNumbers);
665 if ((callNumbers[0] != firstCall + 1)
666 && ((firstCall == 1) || (firstCall == 2))) {
667 /* The call number after the first call should be one or, more likely,
668 * two (if the call is still DALLYing). Between first and second call,
669 * the call number should have incremented by one. */
671 "Connection's first channel call number not one. call[%d] = %d\n",
673 return RXKST_BADCALLNUMBERS;
675 for (i = 1; i < RX_MAXCALLS; i++) {
676 if (callNumbers[i] != 0) {
678 "Connection's other channel call numbers not zero. call[%d] = %d\n",
680 return RXKST_BADCALLNUMBERS;
683 code = MakeMultiChannelCall(conn, 1, 0, codes);
687 /* Now try to resend a call that's already been executed by finding a
688 * non-zero call number on a channel other than zero and decrementing it by
689 * one. This should appear to the server as a retransmitted call. Since
690 * this is behaving as a broken client different strange behaviors may be
691 * exhibited by different servers. If the response packet to the original
692 * call is discarded by the time the "retransmitted" call arrives (perhaps
693 * due to high server or client load) there is no way for the server to
694 * respond at all. Further, it seems, that under some cases the connection
695 * will be kept alive indefinitely even though the server has discarded the
696 * "retransmitted" call and is making no effort to reexecute the call. To
697 * handle these, accept either a timeout (-1) or and INCFAILED error here,
698 * also set the connenction HardDeadTime to punt after a reasonable
701 /* short dead time since may we expect some trouble */
702 rx_SetConnHardDeadTime(conn, 30);
703 code = rxi_GetCallNumberVector(conn, callNumbers);
706 for (ch = 1; ch < RX_MAXCALLS; ch++)
707 if (callNumbers[ch] > 1) {
709 code = rxi_SetCallNumberVector(conn, callNumbers);
714 if (ch >= RX_MAXCALLS) /* didn't find any? all DALLYing? */
715 return RXKST_BADCALLNUMBERS;
716 code = MakeMultiChannelCall(conn, 1, RXKST_INCFAILED, codes);
717 code = CheckCallFailure(conn, codes, code, "retransmitted call");
718 if (code && !retCode)
721 /* Get a fresh connection, becasue if the above failed as it should the
722 * connection is dead. */
723 rx_DestroyConnection(conn);
725 rx_NewConnection(host, htons(RXKST_SERVICEPORT), RXKST_SERVICEID, sc,
728 return RXKST_NEWCONNFAILED;
730 /* Similarly, but decrement call number by two which should be completely
731 * unmistakeable as a broken or malicious client. */
733 /* short dead time since may we expect some trouble */
734 rx_SetConnHardDeadTime(conn, 30);
735 code = MakeMultiChannelCall(conn, 2, 0, codes);
738 code = rxi_GetCallNumberVector(conn, callNumbers);
741 for (ch = 1; ch < RX_MAXCALLS; ch++)
742 if (callNumbers[ch] > 2) {
743 callNumbers[ch] -= 2;
744 code = rxi_SetCallNumberVector(conn, callNumbers);
747 if (ch >= RX_MAXCALLS) /* didn't find any? all DALLYing? */
748 return RXKST_BADCALLNUMBERS;
749 code = MakeMultiChannelCall(conn, 1, -1, codes);
750 code = CheckCallFailure(conn, codes, code, "duplicate call");
751 if (code && !retCode)
754 rx_DestroyConnection(conn);
756 rx_NewConnection(host, htons(RXKST_SERVICEPORT), RXKST_SERVICEID, sc,
759 return RXKST_NEWCONNFAILED;
761 /* Next, without waiting for the server to discard its state, we will check
762 * to see if the Challenge/Response protocol correctly informs the server
763 * of the client's callNumber state. We do this by artificially increasing
764 * the call numbers of a new connection for all channels beyond zero,
765 * making a call on channel zero, then resetting the call number for the
766 * unused channels back to zero, then making calls on all channels. */
768 code = rxi_GetCallNumberVector(conn, callNumbers);
771 for (i = 0; i < RX_MAXCALLS; i++) {
772 if (callNumbers[i] != 0)
773 return RXKST_BADCALLNUMBERS;
774 callNumbers[i] = 51; /* an arbitrary value... */
776 code = rxi_SetCallNumberVector(conn, callNumbers);
779 code = FastCall(conn); /* use channel 0 */
782 code = rxi_GetCallNumberVector(conn, callNumbers);
785 if (callNumbers[0] != 52)
786 return RXKST_BADCALLNUMBERS;
787 for (i = 1; i < RX_MAXCALLS; i++) {
788 if (callNumbers[i] != 51)
789 return RXKST_BADCALLNUMBERS;
790 callNumbers[i] = 37; /* back up a ways */
792 code = rxi_SetCallNumberVector(conn, callNumbers);
795 /* now try calls on all channels... */
796 code = MakeMultiChannelCall(conn, 1, -1, codes);
798 CheckCallFailure(conn, codes, code, "alternate channel call replay");
799 if (code && !retCode)
802 rx_DestroyConnection(conn);
805 #endif /* rx_GetPacketCksum */
809 #ifdef rx_GetPacketCksum
813 u_long epoch; /* connection to attack */
815 int client; /* TRUE => client side */
816 u_long newEpoch; /* conn to direct challenges to */
818 u_long counts[RX_N_PACKET_TYPES];
822 #define IO_REDIRECTCHALLENGE 2
825 HandleIncoming(struct rx_packet *p, struct sockaddr_in *addr)
827 int client; /* packet sent by client */
828 u_char type; /* packet type */
830 if (incomingOps.op == IO_NOOP)
833 client = ((p->header.flags & RX_CLIENT_INITIATED) != RX_CLIENT_INITIATED);
834 if ((p->header.epoch != incomingOps.epoch)
835 || ((p->header.cid ^ incomingOps.cid) & RX_CIDMASK)
836 || (client != incomingOps.client))
838 type = p->header.type;
839 if ((type <= 0) || (type >= RX_N_PACKET_TYPES))
841 incomingOps.counts[type]++;
843 switch (incomingOps.op) {
848 case IO_REDIRECTCHALLENGE:
849 if (p->header.type != RX_PACKET_TYPE_CHALLENGE)
851 p->header.epoch = incomingOps.newEpoch;
852 p->header.cid = incomingOps.newCid;
853 /* Now set up to watch for the corresponding challenge. */
854 incomingOps.epoch = incomingOps.newEpoch;
855 incomingOps.cid = incomingOps.newCid;
856 incomingOps.op = IO_COUNT;
860 fprintf(stderr, "Unknown incoming op %d\n", incomingOps.op);
868 u_long epoch; /* connection to attack */
870 int client; /* TRUE => client side */
871 u_long counts[RX_N_PACKET_TYPES];
875 #define OO_ZEROCKSUM 2
876 #define OO_MUNGCKSUM 3
879 HandleOutgoing(struct rx_packet *p, struct sockaddr_in *addr)
881 int client; /* packet sent by client */
882 u_char type; /* packet type */
884 if (outgoingOps.op == OO_NOOP)
887 client = ((p->header.flags & RX_CLIENT_INITIATED) == RX_CLIENT_INITIATED);
888 if ((p->header.epoch != outgoingOps.epoch)
889 || ((p->header.cid ^ outgoingOps.cid) & RX_CIDMASK)
890 || (client != outgoingOps.client))
892 type = p->header.type;
893 if ((type <= 0) || (type >= RX_N_PACKET_TYPES))
895 outgoingOps.counts[type]++;
897 switch (outgoingOps.op) {
900 /* counting always happens above if not noop */
904 if (p->header.type != RX_PACKET_TYPE_DATA)
906 if (rx_GetPacketCksum(p) == 0) {
907 /* probably, a retransmitted packet */
908 fprintf(stderr, "Packet cksum already zero\n");
911 rx_SetPacketCksum(p, 0);
916 if (p->header.type != RX_PACKET_TYPE_DATA)
918 cksum = rx_GetPacketCksum(p);
920 fprintf(stderr, "Packet cksum already zero\n");
923 rx_SetPacketCksum(p, cksum ^ 8);
927 fprintf(stderr, "Unknown outgoing op %d\n", outgoingOps.op);
933 #ifdef AFS_PTHREAD_ENV
934 static pthread_once_t slowCallOnce = PTHREAD_ONCE_INIT;
935 static pthread_mutex_t slowCallLock;
936 static pthread_cond_t slowCallCV;
940 pthread_mutex_init(&slowCallLock, NULL);
941 pthread_cond_init(&slowCallCV, NULL);
944 static long slowCallCode;
946 SlowCall(void * rock)
948 struct rx_connection *conn = rock;
953 #ifdef AFS_PTHREAD_ENV
954 pthread_mutex_lock(&slowCallLock);
956 slowCallCode = RXKST_PROCESSRUNNING;
957 #ifdef AFS_PTHREAD_ENV
958 pthread_cond_signal(&slowCallCV);
960 LWP_NoYieldSignal(&slowCallCode);
962 slowCallCode = RXKST_Slow(conn, 1, &ntime);
964 now = FT_ApproxTime();
965 if ((ntime < now - maxSkew) || (ntime > now + maxSkew))
966 slowCallCode = RXKST_TIMESKEW;
968 temp_rc = slowCallCode;
969 #ifdef AFS_PTHREAD_ENV
970 pthread_cond_signal(&slowCallCV);
971 pthread_mutex_unlock(&slowCallLock);
973 LWP_NoYieldSignal(&slowCallCode);
975 return (void *)(intptr_t)temp_rc;
978 #endif /* rx_GetPacketCksum */
981 RunHijackTest(struct clientParms *parms, long host,
982 struct rx_securityClass *sc, long si)
985 #ifndef rx_GetPacketCksum
987 code = RXKST_BADARGS;
988 afs_com_err(whoami, code,
989 "Older versions of Rx don't export packet tracing routines: can't run this HijackTest");
995 struct rx_connection *conn = 0;
996 struct rx_connection *otherConn = 0;
997 #ifdef AFS_PTHREAD_ENV
1002 int nResp; /* otherConn responses seen */
1005 #ifdef AFS_PTHREAD_ENV
1006 pthread_once(&slowCallOnce, SlowCallInit);
1008 rx_justReceived = HandleIncoming;
1009 rx_almostSent = HandleOutgoing;
1011 incomingOps.op = IO_NOOP;
1012 outgoingOps.op = OO_NOOP;
1014 #define HIJACK_CONN(conn) \
1015 { if (conn) rx_DestroyConnection (conn); \
1016 (conn) = rx_NewConnection(host, htons(RXKST_SERVICEPORT), \
1017 RXKST_SERVICEID, sc, si); \
1018 if (!(conn)) return RXKST_NEWCONNFAILED; \
1019 outgoingOps.client = 1; \
1020 outgoingOps.epoch = (conn)->epoch; \
1021 outgoingOps.cid = (conn)->cid; }
1025 /* First try switching from no packet cksum to sending packet cksum between
1026 * calls, and see if server complains. */
1028 outgoingOps.op = OO_ZEROCKSUM;
1029 code = FastCall(conn);
1031 afs_com_err(whoami, code, "doing FastCall with ZEROCKSUM");
1034 /* The server thinks we're an old style client. Now start sending cksums.
1035 * Server shouldn't care. */
1036 outgoingOps.op = OO_NOOP;
1037 code = FastCall(conn);
1039 afs_com_err(whoami, code, "doing FastCall with non-ZEROCKSUM");
1042 /* The server now thinks we're a new style client, we can't go back now. */
1043 outgoingOps.op = OO_ZEROCKSUM;
1044 code = FastCall(conn);
1046 code = RXKST_NOBADCKSUM;
1047 if (code != RXKADSEALEDINCON) {
1048 afs_com_err(whoami, code, "doing FastCall with ZEROCKSUM");
1050 } else if (!conn->error) {
1051 code = RXKST_NOCONNERROR;
1052 afs_com_err(whoami, code, "doing FastCall with ZEROCKSUM");
1059 /* Now try modifying packet cksum to see if server complains. */
1061 outgoingOps.op = OO_MUNGCKSUM;
1062 code = FastCall(conn);
1064 code = RXKST_NOBADCKSUM;
1065 if (code != RXKADSEALEDINCON) {
1066 afs_com_err(whoami, code, "doing FastCall with ZEROCKSUM");
1068 } else if (!conn->error) {
1069 code = RXKST_NOCONNERROR;
1070 afs_com_err(whoami, code, "doing FastCall with ZEROCKSUM");
1075 /* Now make two connection and direct the first challenge on one connection
1076 * to the other connection to see if it generates a response. The
1077 * retransmitted challenge should allow the call on the first connection to
1078 * complete correctly. Part one is to attack a new connection, then attack
1079 * it after it has made a call. Part three, just for comparison, attacks a
1080 * otherConn while it is making a slow call (and thus has an active call).
1081 * Against this attack we have no defense so we expect a challenge in this
1082 * case, which the server will discard. */
1084 #define RedirectChallenge(conn,otherConn) \
1085 (incomingOps.epoch = (conn)->epoch, \
1086 incomingOps.cid = (conn)->cid, \
1087 incomingOps.client = 1, \
1088 incomingOps.newEpoch = (otherConn)->epoch, \
1089 incomingOps.newCid = (otherConn)->cid, \
1090 incomingOps.op = IO_REDIRECTCHALLENGE, \
1091 outgoingOps.epoch = (otherConn)->epoch, \
1092 outgoingOps.cid = (otherConn)->cid, \
1093 outgoingOps.client = 1, \
1094 outgoingOps.op = OO_COUNT, \
1095 outgoingOps.counts[RX_PACKET_TYPE_RESPONSE] = 0)
1098 HIJACK_CONN(otherConn)
1099 RedirectChallenge(conn, otherConn);
1101 code = FastCall(conn);
1104 assert(incomingOps.op == IO_COUNT); /* redirect code was triggered */
1105 if (outgoingOps.counts[RX_PACKET_TYPE_RESPONSE] > 0) {
1107 code = RXKST_CHALLENGEORACLE;
1108 afs_com_err(whoami, code, "misdirecting challenge");
1111 code = FastCall(otherConn); /* generate some activity here */
1114 nResp = outgoingOps.counts[RX_PACKET_TYPE_RESPONSE];
1116 code = FastCall(conn);
1119 if (outgoingOps.counts[RX_PACKET_TYPE_RESPONSE] > nResp)
1123 RedirectChallenge(conn, otherConn);
1124 /* otherConn was authenticated during part one */
1125 code = FastCall(conn);
1128 assert(incomingOps.op == IO_COUNT); /* redirect code was triggered */
1129 if (outgoingOps.counts[RX_PACKET_TYPE_RESPONSE] != 0)
1133 RedirectChallenge(conn, otherConn);
1134 /* otherConn is still authenticated */
1135 slowCallCode = RXKST_PROCESSCREATED;
1136 #ifdef AFS_PTHREAD_ENV
1138 pthread_attr_t tattr;
1140 code = pthread_attr_init(&tattr);
1142 afs_com_err(whoami, code,
1143 "can't pthread_attr_init slow call process");
1147 code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
1149 afs_com_err(whoami, code,
1150 "can't pthread_attr_setdetachstate slow call process");
1154 code = pthread_create(&pid, &tattr, SlowCall, (void *)otherConn);
1158 LWP_CreateProcess(SlowCall, 16000, LWP_NORMAL_PRIORITY,
1159 (opaque) otherConn, "Slow Call Process", &pid);
1162 afs_com_err(whoami, code, "can't create slow call process");
1165 #ifdef AFS_PTHREAD_ENV
1166 pthread_mutex_lock(&slowCallLock);
1167 while (slowCallCode == RXKST_PROCESSCREATED)
1168 pthread_cond_wait(&slowCallCV, &slowCallLock);
1170 while (slowCallCode == RXKST_PROCESSCREATED)
1171 LWP_WaitProcess(&slowCallCode); /* wait for process start */
1173 if (slowCallCode != RXKST_PROCESSRUNNING) {
1174 tmp_rc = slowCallCode;
1175 #ifdef AFS_PTHREAD_ENV
1176 pthread_mutex_unlock(&slowCallLock);
1178 return tmp_rc; /* make sure didn't fail immediately */
1180 assert(incomingOps.op == IO_REDIRECTCHALLENGE);
1181 code = FastCall(conn);
1184 assert(incomingOps.op == IO_COUNT); /* redirect code was triggered */
1185 #ifdef AFS_PTHREAD_ENV
1186 while (slowCallCode == RXKST_PROCESSRUNNING)
1187 pthread_cond_wait(&slowCallCV, &slowCallLock);
1188 pthread_mutex_unlock(&slowCallLock);
1190 while (slowCallCode == RXKST_PROCESSRUNNING)
1191 LWP_WaitProcess(&slowCallCode); /* wait for process finish */
1193 if (outgoingOps.counts[RX_PACKET_TYPE_RESPONSE] != 1)
1196 rx_justReceived = 0;
1198 rx_DestroyConnection(otherConn);
1199 rx_DestroyConnection(conn);
1202 #endif /* rx_GetPacketCksum */
1207 rxkst_StartClient(struct clientParms *parms)
1212 struct rx_securityClass *sc;
1214 whoami = parms->whoami; /* set this global variable */
1216 host = GetServer(parms->server);
1218 if (parms->authentication >= 0) {
1220 char ticket[MAXKTCTICKETLEN];
1222 struct ktc_encryptionKey Ksession;
1224 if (parms->useTokens)
1226 GetToken(&kvno, &Ksession, &ticketLen, ticket, parms->cell);
1229 GetTicket(&kvno, &Ksession, &ticketLen, ticket, parms->cell);
1233 /* next, we have ticket, kvno and session key, authenticate the conn */
1234 sc = (struct rx_securityClass *)
1235 rxkad_NewClientSecurityObject(parms->authentication, &Ksession,
1236 kvno, ticketLen, ticket);
1238 scIndex = RX_SECIDX_KAD;
1240 /* unauthenticated connection */
1241 sc = rxnull_NewClientSecurityObject();
1243 scIndex = RX_SECIDX_NULL;
1247 if (!code && parms->callTest) {
1248 code = RunCallTest(parms, host, sc, scIndex);
1250 if (!code && parms->hijackTest) {
1251 code = RunHijackTest(parms, host, sc, scIndex);
1254 && (parms->printTiming || parms->fastCalls || parms->slowCalls
1255 || parms->copiousCalls)) {
1256 struct rx_connection *conn;
1258 rx_NewConnection(host, htons(RXKST_SERVICEPORT), RXKST_SERVICEID,
1261 code = RepeatLoadTest(parms, conn);
1262 rx_DestroyConnection(conn);
1264 code = RXKST_NEWCONNFAILED;
1266 if (!code && parms->stopServer) {
1267 struct rx_connection *conn;
1269 rx_NewConnection(host, htons(RXKST_SERVICEPORT), RXKST_SERVICEID,
1272 code = RXKST_Kill(conn);
1274 afs_com_err(whoami, code, "trying to stop server");
1276 rx_DestroyConnection(conn);
1278 code = RXKST_NEWCONNFAILED;
1281 if (parms->printStats) {
1282 rx_PrintStats(stdout);
1288 afs_com_err(parms->whoami, code, "test fails");
1291 printf("Test Okay\n");