Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
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 */

}