static long MakeMultiChannelCall(struct rx_connection *conn, int each, long expectedCode, long codes[]) { long code; int i; struct multiChannel mc; memset(&mc, 0, sizeof(mc)); mc.conn = conn; for (i = 0; i < RX_MAXCALLS; i++) { codes[i] = RXKST_PROCESSRUNNING; mc.changes[i] = each; } mc.codes = codes; code = rxi_GetCallNumberVector(conn, mc.callNumbers); if (code) return code; mc.done = 0; code = CallSimultaneously(RX_MAXCALLS, &mc, UniChannelCall); if (((expectedCode == RXKST_INCFAILED) || (expectedCode == -1)) && ((code == expectedCode) || (code == -3))); /* strange cases */ else if (code != expectedCode) { afs_com_err(whoami, code, "problem making multichannel call, expected '%s'", ((expectedCode == 0) ? "no error" : (char *)afs_error_message(expectedCode))); } return code; }
static long UniChannelCall(int index, opaque rock) { struct multiChannel *mc = (struct multiChannel *)rock; long code; afs_int32 callNumbers[RX_MAXCALLS]; int unchanged; code = 0; unchanged = 1; while (!mc->done && unchanged) { int i; code = FastCall(mc->conn); if (code) break; code = rxi_GetCallNumberVector(mc->conn, callNumbers); if (code) break; unchanged = 0; for (i = 0; i < RX_MAXCALLS; i++) { if (callNumbers[i] > mc->callNumbers[i]) { mc->callNumbers[i] = callNumbers[i]; mc->changes[i]--; /* may go negative */ } if (mc->changes[i] > 0) unchanged++; } } mc->codes[index] = code; mc->done++; return code; }
int rxkad_GetResponse(struct rx_securityClass *aobj, struct rx_connection *aconn, struct rx_packet *apacket) { struct rxkad_cprivate *tcp; char *tp; int v2; /* whether server is old style or v2 */ afs_int32 challengeID; rxkad_level level; char *response; int responseSize, missing; struct rxkad_v2ChallengeResponse r_v2; struct rxkad_oldChallengeResponse r_old; tcp = (struct rxkad_cprivate *)aobj->privateData; if (!(tcp->type & rxkad_client)) return RXKADINCONSISTENCY; v2 = (rx_Contiguous(apacket) > sizeof(struct rxkad_oldChallenge)); tp = rx_DataOf(apacket); if (v2) { /* v2 challenge */ struct rxkad_v2Challenge *c_v2; if (rx_GetDataSize(apacket) < sizeof(struct rxkad_v2Challenge)) return RXKADPACKETSHORT; c_v2 = (struct rxkad_v2Challenge *)tp; challengeID = ntohl(c_v2->challengeID); level = ntohl(c_v2->level); } else { /* old format challenge */ struct rxkad_oldChallenge *c_old; if (rx_GetDataSize(apacket) < sizeof(struct rxkad_oldChallenge)) return RXKADPACKETSHORT; c_old = (struct rxkad_oldChallenge *)tp; challengeID = ntohl(c_old->challengeID); level = ntohl(c_old->level); } if (level > tcp->level) return RXKADLEVELFAIL; INC_RXKAD_STATS(challenges[rxkad_LevelIndex(tcp->level)]); if (v2) { int i; afs_uint32 xor[2]; memset((void *)&r_v2, 0, sizeof(r_v2)); r_v2.version = htonl(RXKAD_CHALLENGE_PROTOCOL_VERSION); r_v2.spare = 0; (void)rxkad_SetupEndpoint(aconn, &r_v2.encrypted.endpoint); (void)rxi_GetCallNumberVector(aconn, r_v2.encrypted.callNumbers); for (i = 0; i < RX_MAXCALLS; i++) { if (r_v2.encrypted.callNumbers[i] < 0) return RXKADINCONSISTENCY; r_v2.encrypted.callNumbers[i] = htonl(r_v2.encrypted.callNumbers[i]); } r_v2.encrypted.incChallengeID = htonl(challengeID + 1); r_v2.encrypted.level = htonl((afs_int32) tcp->level); r_v2.kvno = htonl(tcp->kvno); r_v2.ticketLen = htonl(tcp->ticketLen); r_v2.encrypted.endpoint.cksum = rxkad_CksumChallengeResponse(&r_v2); memcpy((void *)xor, (void *)tcp->ivec, 2 * sizeof(afs_int32)); fc_cbc_encrypt(&r_v2.encrypted, &r_v2.encrypted, sizeof(r_v2.encrypted), tcp->keysched, xor, ENCRYPT); response = (char *)&r_v2; responseSize = sizeof(r_v2); } else { memset((void *)&r_old, 0, sizeof(r_old)); r_old.encrypted.incChallengeID = htonl(challengeID + 1); r_old.encrypted.level = htonl((afs_int32) tcp->level); r_old.kvno = htonl(tcp->kvno); r_old.ticketLen = htonl(tcp->ticketLen); fc_ecb_encrypt(&r_old.encrypted, &r_old.encrypted, tcp->keysched, ENCRYPT); response = (char *)&r_old; responseSize = sizeof(r_old); } if (RX_MAX_PACKET_DATA_SIZE < responseSize + tcp->ticketLen) return RXKADPACKETSHORT; /* not enough space */ rx_computelen(apacket, missing); missing = responseSize + tcp->ticketLen - missing; if (missing > 0) if (rxi_AllocDataBuf(apacket, missing, RX_PACKET_CLASS_SEND) > 0) return RXKADPACKETSHORT; /* not enough space */ /* copy response and ticket into packet */ rx_packetwrite(apacket, 0, responseSize, response); rx_packetwrite(apacket, responseSize, tcp->ticketLen, tcp->ticket); rx_SetDataSize(apacket, responseSize + tcp->ticketLen); return 0; }
static long RunCallTest(struct clientParms *parms, long host, struct rx_securityClass *sc, long si) { long code; #ifndef rx_GetPacketCksum code = RXKST_BADARGS; afs_com_err(whoami, code, "Older versions of Rx don't support Get/Set callNumber Vector procedures: can't run this CallTest"); return code; #else int i, ch; struct rx_connection *conn; long firstCall; afs_int32 callNumbers[RX_MAXCALLS]; long codes[RX_MAXCALLS]; long retCode = 0; /* ret. if nothing fatal goes wrong */ conn = rx_NewConnection(host, htons(RXKST_SERVICEPORT), RXKST_SERVICEID, sc, si); if (!conn) return RXKST_NEWCONNFAILED; /* First check the basic behaviour of call number handling */ code = rxi_GetCallNumberVector(conn, callNumbers); if (code) return code; for (i = 0; i < RX_MAXCALLS; i++) { if (callNumbers[i] != 0) { fprintf(stderr, "Connection's initial call numbers not zero. call[%d] = %d\n", i, callNumbers[i]); return RXKST_BADCALLNUMBERS; } } code = FastCall(conn); if (code) return code; code = rxi_GetCallNumberVector(conn, callNumbers); if (code) return code; firstCall = callNumbers[0]; code = FastCall(conn); if (code) return code; code = rxi_GetCallNumberVector(conn, callNumbers); if (code) return code; if ((callNumbers[0] != firstCall + 1) && ((firstCall == 1) || (firstCall == 2))) { /* The call number after the first call should be one or, more likely, * two (if the call is still DALLYing). Between first and second call, * the call number should have incremented by one. */ fprintf(stderr, "Connection's first channel call number not one. call[%d] = %d\n", 0, callNumbers[0]); return RXKST_BADCALLNUMBERS; } for (i = 1; i < RX_MAXCALLS; i++) { if (callNumbers[i] != 0) { fprintf(stderr, "Connection's other channel call numbers not zero. call[%d] = %d\n", i, callNumbers[i]); return RXKST_BADCALLNUMBERS; } } code = MakeMultiChannelCall(conn, 1, 0, codes); if (code) return code; /* Now try to resend a call that's already been executed by finding a * non-zero call number on a channel other than zero and decrementing it by * one. This should appear to the server as a retransmitted call. Since * this is behaving as a broken client different strange behaviors may be * exhibited by different servers. If the response packet to the original * call is discarded by the time the "retransmitted" call arrives (perhaps * due to high server or client load) there is no way for the server to * respond at all. Further, it seems, that under some cases the connection * will be kept alive indefinitely even though the server has discarded the * "retransmitted" call and is making no effort to reexecute the call. To * handle these, accept either a timeout (-1) or and INCFAILED error here, * also set the connenction HardDeadTime to punt after a reasonable * interval. */ /* short dead time since may we expect some trouble */ rx_SetConnHardDeadTime(conn, 30); code = rxi_GetCallNumberVector(conn, callNumbers); if (code) return code; for (ch = 1; ch < RX_MAXCALLS; ch++) if (callNumbers[ch] > 1) { callNumbers[ch]--; code = rxi_SetCallNumberVector(conn, callNumbers); if (code) return code; break; } if (ch >= RX_MAXCALLS) /* didn't find any? all DALLYing? */ return RXKST_BADCALLNUMBERS; code = MakeMultiChannelCall(conn, 1, RXKST_INCFAILED, codes); code = CheckCallFailure(conn, codes, code, "retransmitted call"); if (code && !retCode) retCode = code; /* Get a fresh connection, becasue if the above failed as it should the * connection is dead. */ rx_DestroyConnection(conn); conn = rx_NewConnection(host, htons(RXKST_SERVICEPORT), RXKST_SERVICEID, sc, si); if (!conn) return RXKST_NEWCONNFAILED; /* Similarly, but decrement call number by two which should be completely * unmistakeable as a broken or malicious client. */ /* short dead time since may we expect some trouble */ rx_SetConnHardDeadTime(conn, 30); code = MakeMultiChannelCall(conn, 2, 0, codes); if (code) return code; code = rxi_GetCallNumberVector(conn, callNumbers); if (code) return code; for (ch = 1; ch < RX_MAXCALLS; ch++) if (callNumbers[ch] > 2) { callNumbers[ch] -= 2; code = rxi_SetCallNumberVector(conn, callNumbers); break; } if (ch >= RX_MAXCALLS) /* didn't find any? all DALLYing? */ return RXKST_BADCALLNUMBERS; code = MakeMultiChannelCall(conn, 1, -1, codes); code = CheckCallFailure(conn, codes, code, "duplicate call"); if (code && !retCode) retCode = code; rx_DestroyConnection(conn); conn = rx_NewConnection(host, htons(RXKST_SERVICEPORT), RXKST_SERVICEID, sc, si); if (!conn) return RXKST_NEWCONNFAILED; /* Next, without waiting for the server to discard its state, we will check * to see if the Challenge/Response protocol correctly informs the server * of the client's callNumber state. We do this by artificially increasing * the call numbers of a new connection for all channels beyond zero, * making a call on channel zero, then resetting the call number for the * unused channels back to zero, then making calls on all channels. */ code = rxi_GetCallNumberVector(conn, callNumbers); if (code) return code; for (i = 0; i < RX_MAXCALLS; i++) { if (callNumbers[i] != 0) return RXKST_BADCALLNUMBERS; callNumbers[i] = 51; /* an arbitrary value... */ } code = rxi_SetCallNumberVector(conn, callNumbers); if (code) return code; code = FastCall(conn); /* use channel 0 */ if (code) return code; code = rxi_GetCallNumberVector(conn, callNumbers); if (code) return code; if (callNumbers[0] != 52) return RXKST_BADCALLNUMBERS; for (i = 1; i < RX_MAXCALLS; i++) { if (callNumbers[i] != 51) return RXKST_BADCALLNUMBERS; callNumbers[i] = 37; /* back up a ways */ } code = rxi_SetCallNumberVector(conn, callNumbers); if (code) return code; /* now try calls on all channels... */ code = MakeMultiChannelCall(conn, 1, -1, codes); code = CheckCallFailure(conn, codes, code, "alternate channel call replay"); if (code && !retCode) retCode = code; rx_DestroyConnection(conn); return retCode; #endif /* rx_GetPacketCksum */ }