#include <afsconfig.h>
#include <afs/param.h>
-RCSID("$Header$");
#include <afs/stds.h>
#include <sys/types.h>
+#if (defined(AFS_AIX_ENV) && defined(KERNEL) && !defined(UKERNEL)) || defined(AFS_AUX_ENV) || defined(AFS_SUN5_ENV)
+#include <sys/systm.h>
+#endif
#include <time.h>
#ifdef AFS_NT40_ENV
#include <winsock2.h>
#else
#include <netinet/in.h>
#endif
-#ifdef HAVE_STRING_H
#include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#endif
#include <rx/rx.h>
#include <rx/xdr.h>
#include <des.h>
#include <afs/afsutil.h>
+#include <des/stats.h>
#include "private_data.h"
#define XPRT_RXKAD_SERVER
* Currently only used by the AFS/DFS protocol translator to recognize
* Kerberos V5 tickets. The actual code to do that is provided externally.
*/
-afs_int32 (*rxkad_AlternateTicketDecoder)();
+afs_int32(*rxkad_AlternateTicketDecoder) (afs_int32, char *, afs_int32,
+ char *, char *, char *,
+ struct ktc_encryptionKey *,
+ afs_int32 *, afs_uint32 *,
+ afs_uint32 *);
static struct rx_securityOps rxkad_server_ops = {
rxkad_Close,
rxkad_NewConnection,
- rxkad_PreparePacket, /* once per packet creation */
- 0, /* send packet (once per retrans) */
+ rxkad_PreparePacket, /* once per packet creation */
+ 0, /* send packet (once per retrans) */
rxkad_CheckAuthentication,
rxkad_CreateChallenge,
rxkad_GetChallenge,
0,
rxkad_CheckResponse,
- rxkad_CheckPacket, /* check data packet */
+ rxkad_CheckPacket, /* check data packet */
rxkad_DestroyConnection,
rxkad_GetStats,
+ rxkad_SetConfiguration,
+ 0, /* spare 2 */
+ 0, /* spare 3 */
};
extern afs_uint32 rx_MyMaxSendSize;
#include <assert.h>
pthread_mutex_t rxkad_random_mutex;
-#define LOCK_RM assert(pthread_mutex_lock(&rxkad_random_mutex)==0);
-#define UNLOCK_RM assert(pthread_mutex_unlock(&rxkad_random_mutex)==0);
+#define LOCK_RM assert(pthread_mutex_lock(&rxkad_random_mutex)==0)
+#define UNLOCK_RM assert(pthread_mutex_unlock(&rxkad_random_mutex)==0)
#else
#define LOCK_RM
#define UNLOCK_RM
#endif /* AFS_PTHREAD_ENV */
-static void init_random_int32 ()
-{ struct timeval key;
+static void
+init_random_int32(void)
+{
+ struct timeval key;
- gettimeofday (&key, NULL);
- LOCK_RM
- fc_keysched (&key, random_int32_schedule);
- UNLOCK_RM
+ gettimeofday(&key, NULL);
+ LOCK_RM;
+ fc_keysched((struct ktc_encryptionKey*)&key, random_int32_schedule);
+ UNLOCK_RM;
}
-static afs_int32 get_random_int32 ()
-{ static struct timeval seed;
+static afs_int32
+get_random_int32(void)
+{
+ static struct timeval seed;
afs_int32 rc;
- LOCK_RM
- fc_ecb_encrypt (&seed, &seed, random_int32_schedule, ENCRYPT);
+ LOCK_RM;
+ fc_ecb_encrypt(&seed, &seed, random_int32_schedule, ENCRYPT);
rc = seed.tv_sec;
- UNLOCK_RM
+ UNLOCK_RM;
return rc;
}
the rx connection pointer passed to the RPC routine to obtain information
about the client. */
+/*
+ rxkad_level level; * minimum level *
+ char *get_key_rock; * rock for get_key implementor *
+ int (*get_key)(); * passed kvno & addr(key) to fill *
+ int (*user_ok)(); * passed name, inst, cell => bool *
+*/
+
struct rx_securityClass *
-rxkad_NewServerSecurityObject (level, get_key_rock, get_key, user_ok)
- rxkad_level level; /* minimum level */
- char *get_key_rock; /* rock for get_key implementor */
- int (*get_key)(); /* passed kvno & addr(key) to fill */
- int (*user_ok)(); /* passed name, inst, cell => bool */
-{ struct rx_securityClass *tsc;
- struct rxkad_sprivate *tsp;
+rxkad_NewServerSecurityObject(rxkad_level level, void *get_key_rock,
+ int (*get_key) (void *get_key_rock, int kvno,
+ struct ktc_encryptionKey *
+ serverKey),
+ int (*user_ok) (char *name, char *instance,
+ char *cell, afs_int32 kvno))
+{
+ struct rx_securityClass *tsc;
+ struct rxkad_sprivate *tsp;
int size;
- if (!get_key) return 0;
-
+ if (!get_key)
+ return 0;
+
size = sizeof(struct rx_securityClass);
- tsc = (struct rx_securityClass *) osi_Alloc (size);
+ tsc = (struct rx_securityClass *)osi_Alloc(size);
memset(tsc, 0, size);
- tsc->refCount = 1; /* caller has one reference */
+ tsc->refCount = 1; /* caller has one reference */
tsc->ops = &rxkad_server_ops;
size = sizeof(struct rxkad_sprivate);
- tsp = (struct rxkad_sprivate *) osi_Alloc (size);
+ tsp = (struct rxkad_sprivate *)osi_Alloc(size);
memset(tsp, 0, size);
- tsc->privateData = (char *) tsp;
+ tsc->privateData = (char *)tsp;
- tsp->type |= rxkad_server; /* so can identify later */
- tsp->level = level; /* level of encryption */
+ tsp->type |= rxkad_server; /* so can identify later */
+ tsp->level = level; /* level of encryption */
tsp->get_key_rock = get_key_rock;
- tsp->get_key = get_key; /* to get server ticket */
- tsp->user_ok = user_ok; /* to inform server of client id. */
- init_random_int32 ();
+ tsp->get_key = get_key; /* to get server ticket */
+ tsp->user_ok = user_ok; /* to inform server of client id. */
+ init_random_int32();
- LOCK_RXKAD_STATS
- rxkad_stats_serverObjects++;
- UNLOCK_RXKAD_STATS
+ INC_RXKAD_STATS(serverObjects);
return tsc;
}
/* server: called to tell if a connection authenticated properly */
-rxs_return_t rxkad_CheckAuthentication (aobj, aconn)
- struct rx_securityClass *aobj;
- struct rx_connection *aconn;
-{ struct rxkad_sconn *sconn;
+int
+rxkad_CheckAuthentication(struct rx_securityClass *aobj,
+ struct rx_connection *aconn)
+{
+ struct rxkad_sconn *sconn;
/* first make sure the object exists */
- if (!aconn->securityData) return RXKADINCONSISTENCY;
+ if (!aconn->securityData)
+ return RXKADINCONSISTENCY;
- sconn = (struct rxkad_sconn *) aconn->securityData;
+ sconn = (struct rxkad_sconn *)aconn->securityData;
return !sconn->authenticated;
}
/* server: put the current challenge in the connection structure for later use
by packet sender */
-rxs_return_t rxkad_CreateChallenge(aobj, aconn)
- struct rx_securityClass *aobj;
- struct rx_connection *aconn;
-{ struct rxkad_sconn *sconn;
+int
+rxkad_CreateChallenge(struct rx_securityClass *aobj,
+ struct rx_connection *aconn)
+{
+ struct rxkad_sconn *sconn;
struct rxkad_sprivate *tsp;
- sconn = (struct rxkad_sconn *) aconn->securityData;
- sconn->challengeID = get_random_int32 ();
- sconn->authenticated = 0; /* conn unauth. 'til we hear back */
+ sconn = (struct rxkad_sconn *)aconn->securityData;
+ sconn->challengeID = get_random_int32();
+ sconn->authenticated = 0; /* conn unauth. 'til we hear back */
/* initialize level from object's minimum acceptable level */
tsp = (struct rxkad_sprivate *)aobj->privateData;
sconn->level = tsp->level;
/* server: fill in a challenge in the packet */
-rxs_return_t rxkad_GetChallenge (aobj, aconn, apacket)
- IN struct rx_securityClass *aobj;
- IN struct rx_packet *apacket;
- IN struct rx_connection *aconn;
-{ struct rxkad_sconn *sconn;
+int
+rxkad_GetChallenge(struct rx_securityClass *aobj, struct rx_connection *aconn,
+ struct rx_packet *apacket)
+{
+ struct rxkad_sconn *sconn;
char *challenge;
int challengeSize;
- struct rxkad_v2Challenge c_v2; /* version 2 */
- struct rxkad_oldChallenge c_old; /* old style */
+ struct rxkad_v2Challenge c_v2; /* version 2 */
+ struct rxkad_oldChallenge c_old; /* old style */
- sconn = (struct rxkad_sconn *) aconn->securityData;
- if (rx_IsUsingPktCksum(aconn)) sconn->cksumSeen = 1;
+ sconn = (struct rxkad_sconn *)aconn->securityData;
+ if (rx_IsUsingPktCksum(aconn))
+ sconn->cksumSeen = 1;
if (sconn->cksumSeen) {
memset(&c_v2, 0, sizeof(c_v2));
c_v2.version = htonl(RXKAD_CHALLENGE_PROTOCOL_VERSION);
c_v2.challengeID = htonl(sconn->challengeID);
- c_v2.level = htonl((afs_int32)sconn->level);
+ c_v2.level = htonl((afs_int32) sconn->level);
c_v2.spare = 0;
challenge = (char *)&c_v2;
challengeSize = sizeof(c_v2);
} else {
memset(&c_old, 0, sizeof(c_old));
c_old.challengeID = htonl(sconn->challengeID);
- c_old.level = htonl((afs_int32)sconn->level);
+ c_old.level = htonl((afs_int32) sconn->level);
challenge = (char *)&c_old;
challengeSize = sizeof(c_old);
}
return RXKADPACKETSHORT; /* not enough space */
rx_packetwrite(apacket, 0, challengeSize, challenge);
- rx_SetDataSize (apacket, challengeSize);
+ rx_SetDataSize(apacket, challengeSize);
sconn->tried = 1;
- LOCK_RXKAD_STATS
- rxkad_stats.challengesSent++;
- UNLOCK_RXKAD_STATS
+ INC_RXKAD_STATS(challengesSent);
return 0;
}
/* XXX this does some copying of data in and out of the packet, but I'll bet it
* could just do it in place, especially if I used rx_Pullup...
*/
-rxs_return_t rxkad_CheckResponse (aobj, aconn, apacket)
- struct rx_securityClass *aobj;
- struct rx_packet *apacket;
- struct rx_connection *aconn;
-{ struct rxkad_sconn *sconn;
+int
+rxkad_CheckResponse(struct rx_securityClass *aobj,
+ struct rx_connection *aconn, struct rx_packet *apacket)
+{
+ struct rxkad_sconn *sconn;
struct rxkad_sprivate *tsp;
struct ktc_encryptionKey serverKey;
- struct rxkad_oldChallengeResponse oldr; /* response format */
+ struct rxkad_oldChallengeResponse oldr; /* response format */
struct rxkad_v2ChallengeResponse v2r;
- afs_int32 tlen; /* ticket len */
- afs_int32 kvno; /* key version of ticket */
- char tix[MAXKTCTICKETLEN];
- afs_int32 incChallengeID;
+ afs_int32 tlen; /* ticket len */
+ afs_int32 kvno; /* key version of ticket */
+ char tix[MAXKTCTICKETLEN];
+ afs_int32 incChallengeID;
rxkad_level level;
- int code;
+ int code;
/* ticket contents */
struct ktc_principal client;
struct ktc_encryptionKey sessionkey;
- afs_int32 host;
+ afs_int32 host;
afs_uint32 start;
afs_uint32 end;
unsigned int pos;
struct rxkad_serverinfo *rock;
- sconn = (struct rxkad_sconn *) aconn->securityData;
- tsp = (struct rxkad_sprivate *) aobj->privateData;
+ sconn = (struct rxkad_sconn *)aconn->securityData;
+ tsp = (struct rxkad_sprivate *)aobj->privateData;
if (sconn->cksumSeen) {
/* expect v2 response, leave fields in v2r in network order for cksum
- * computation which follows decryption. */
- if (rx_GetDataSize(apacket) < sizeof(v2r))
- return RXKADPACKETSHORT;
+ * computation which follows decryption. */
+ if (rx_GetDataSize(apacket) < sizeof(v2r))
+ return RXKADPACKETSHORT;
rx_packetread(apacket, 0, sizeof(v2r), &v2r);
pos = sizeof(v2r);
/* version == 2 */
/* ignore spare */
- kvno = ntohl (v2r.kvno);
+ kvno = ntohl(v2r.kvno);
tlen = ntohl(v2r.ticketLen);
if (rx_GetDataSize(apacket) < sizeof(v2r) + tlen)
return RXKADPACKETSHORT;
} else {
/* expect old format response */
- if (rx_GetDataSize(apacket) < sizeof(oldr)) return RXKADPACKETSHORT;
+ if (rx_GetDataSize(apacket) < sizeof(oldr))
+ return RXKADPACKETSHORT;
rx_packetread(apacket, 0, sizeof(oldr), &oldr);
pos = sizeof(oldr);
- kvno = ntohl (oldr.kvno);
+ kvno = ntohl(oldr.kvno);
tlen = ntohl(oldr.ticketLen);
if (rx_GetDataSize(apacket) != sizeof(oldr) + tlen)
return RXKADPACKETSHORT;
* the standard decoder.
*/
if (rxkad_AlternateTicketDecoder) {
- code = rxkad_AlternateTicketDecoder
- (kvno, tix, tlen, client.name, client.instance, client.cell,
- &sessionkey, &host, &start, &end);
+ code =
+ rxkad_AlternateTicketDecoder(kvno, tix, tlen, client.name,
+ client.instance, client.cell,
+ &sessionkey, &host, &start, &end);
if (code && code != -1) {
return code;
}
} else {
- code = -1; /* No alternate ticket decoder present */
+ code = -1; /* No alternate ticket decoder present */
}
/*
* If the alternate decoder is not present, or returns -1, then
* assume the ticket is of the default style.
*/
+ if (code == -1 && ((kvno == RXKAD_TKT_TYPE_KERBEROS_V5)
+ || (kvno == RXKAD_TKT_TYPE_KERBEROS_V5_ENCPART_ONLY))) {
+ code =
+ tkt_DecodeTicket5(tix, tlen, tsp->get_key, tsp->get_key_rock,
+ kvno, client.name, client.instance, client.cell,
+ &sessionkey, &host, &start, &end,
+ tsp->flags & RXS_CONFIG_FLAGS_DISABLE_DOTCHECK);
+ if (code)
+ return code;
+ }
+
+ /*
+ * If the alternate decoder/kerberos 5 decoder is not present, or
+ * returns -1, then assume the ticket is of the default style.
+ */
if (code == -1) {
/* get ticket's key */
- code = (*tsp->get_key)(tsp->get_key_rock, kvno, &serverKey);
- if (code) return RXKADUNKNOWNKEY; /* invalid kvno */
- code = tkt_DecodeTicket (tix, tlen, &serverKey,
- client.name, client.instance, client.cell,
- &sessionkey, &host, &start, &end);
- if (code) return RXKADBADTICKET;
+ code = (*tsp->get_key) (tsp->get_key_rock, kvno, &serverKey);
+ if (code)
+ return RXKADUNKNOWNKEY; /* invalid kvno */
+ code =
+ tkt_DecodeTicket(tix, tlen, &serverKey, client.name,
+ client.instance, client.cell, &sessionkey, &host,
+ &start, &end);
+ if (code)
+ return code;
}
- code = tkt_CheckTimes (start, end, time(0));
- if (code == -1) return RXKADEXPIRED;
- else if (code <= 0) return RXKADNOAUTH;
-
- code = fc_keysched (&sessionkey, sconn->keysched);
- if (code) return RXKADBADKEY;
+ code = tkt_CheckTimes(start, end, time(0));
+ if (code == 0)
+ return RXKADNOAUTH;
+ else if (code == -1)
+ return RXKADEXPIRED;
+ else if (code < -1)
+ return RXKADBADTICKET;
+
+ code = fc_keysched(&sessionkey, sconn->keysched);
+ if (code)
+ return RXKADBADKEY;
memcpy(sconn->ivec, &sessionkey, sizeof(sconn->ivec));
if (sconn->cksumSeen) {
/* using v2 response */
- afs_uint32 cksum; /* observed cksum */
+ afs_uint32 cksum; /* observed cksum */
struct rxkad_endpoint endpoint; /* connections endpoint */
int i;
afs_uint32 xor[2];
- memcpy(xor, sconn->ivec, 2*sizeof(afs_int32));
- fc_cbc_encrypt (&v2r.encrypted, &v2r.encrypted, sizeof(v2r.encrypted),
- sconn->keysched, xor, DECRYPT);
- cksum = rxkad_CksumChallengeResponse (&v2r);
+ memcpy(xor, sconn->ivec, 2 * sizeof(afs_int32));
+ fc_cbc_encrypt(&v2r.encrypted, &v2r.encrypted, sizeof(v2r.encrypted),
+ sconn->keysched, xor, DECRYPT);
+ cksum = rxkad_CksumChallengeResponse(&v2r);
if (cksum != v2r.encrypted.endpoint.cksum)
return RXKADSEALEDINCON;
- (void) rxkad_SetupEndpoint (aconn, &endpoint);
+ (void)rxkad_SetupEndpoint(aconn, &endpoint);
v2r.encrypted.endpoint.cksum = 0;
- if (memcmp (&endpoint, &v2r.encrypted.endpoint, sizeof(endpoint)) != 0)
+ if (memcmp(&endpoint, &v2r.encrypted.endpoint, sizeof(endpoint)) != 0)
return RXKADSEALEDINCON;
- for (i=0; i<RX_MAXCALLS; i++) {
- v2r.encrypted.callNumbers[i] = ntohl(v2r.encrypted.callNumbers[i]);
- if (v2r.encrypted.callNumbers[i] < 0) return RXKADSEALEDINCON;
+ for (i = 0; i < RX_MAXCALLS; i++) {
+ v2r.encrypted.callNumbers[i] =
+ ntohl(v2r.encrypted.callNumbers[i]);
+ if (v2r.encrypted.callNumbers[i] < 0)
+ return RXKADSEALEDINCON;
}
- (void) rxi_SetCallNumberVector (aconn, v2r.encrypted.callNumbers);
+ (void)rxi_SetCallNumberVector(aconn, v2r.encrypted.callNumbers);
incChallengeID = ntohl(v2r.encrypted.incChallengeID);
level = ntohl(v2r.encrypted.level);
} else {
/* expect old format response */
- fc_ecb_encrypt(&oldr.encrypted, &oldr.encrypted,
- sconn->keysched, DECRYPT);
+ fc_ecb_encrypt(&oldr.encrypted, &oldr.encrypted, sconn->keysched,
+ DECRYPT);
incChallengeID = ntohl(oldr.encrypted.incChallengeID);
level = ntohl(oldr.encrypted.level);
}
- if (incChallengeID != sconn->challengeID+1)
+ if (incChallengeID != sconn->challengeID + 1)
return RXKADOUTOFSEQUENCE; /* replay attempt */
- if ((level < sconn->level) || (level > rxkad_crypt)) return RXKADLEVELFAIL;
+ if ((level < sconn->level) || (level > rxkad_crypt))
+ return RXKADLEVELFAIL;
sconn->level = level;
- rxkad_SetLevel (aconn, sconn->level);
- LOCK_RXKAD_STATS
- rxkad_stats.responses[rxkad_LevelIndex(sconn->level)]++;
- UNLOCK_RXKAD_STATS
-
+ rxkad_SetLevel(aconn, sconn->level);
+ INC_RXKAD_STATS(responses[rxkad_LevelIndex(sconn->level)]);
/* now compute endpoint-specific info used for computing 16 bit checksum */
- rxkad_DeriveXORInfo(aconn, sconn->keysched, sconn->ivec, sconn->preSeq);
+ rxkad_DeriveXORInfo(aconn, &sconn->keysched, (char *)sconn->ivec, (char *)sconn->preSeq);
/* otherwise things are ok */
sconn->expirationTime = end;
sconn->authenticated = 1;
if (tsp->user_ok) {
- code = tsp->user_ok (client.name, client.instance, client.cell, kvno);
- if (code) return RXKADNOAUTH;
- }
- else { /* save the info for later retreival */
+ code = tsp->user_ok(client.name, client.instance, client.cell, kvno);
+ if (code)
+ return RXKADNOAUTH;
+ } else { /* save the info for later retreival */
int size = sizeof(struct rxkad_serverinfo);
- rock = (struct rxkad_serverinfo *) osi_Alloc (size);
+ rock = (struct rxkad_serverinfo *)osi_Alloc(size);
memset(rock, 0, size);
rock->kvno = kvno;
memcpy(&rock->client, &client, sizeof(rock->client));
/* return useful authentication info about a server-side connection */
-afs_int32 rxkad_GetServerInfo (aconn, level, expiration,
- name, instance, cell, kvno)
- struct rx_connection *aconn;
- rxkad_level *level;
- afs_uint32 *expiration;
- char *name;
- char *instance;
- char *cell;
- afs_int32 *kvno;
+afs_int32
+rxkad_GetServerInfo(struct rx_connection * aconn, rxkad_level * level,
+ afs_uint32 * expiration, char *name, char *instance,
+ char *cell, afs_int32 * kvno)
{
struct rxkad_sconn *sconn;
- sconn = (struct rxkad_sconn *) aconn->securityData;
- if (sconn && sconn->authenticated && sconn->rock &&
- (time(0) < sconn->expirationTime)) {
- if (level) *level = sconn->level;
- if (expiration) *expiration = sconn->expirationTime;
- if (name) strcpy (name, sconn->rock->client.name);
- if (instance) strcpy (instance, sconn->rock->client.instance);
- if (cell) strcpy (cell, sconn->rock->client.cell);
- if (kvno) *kvno = sconn->rock->kvno;
+ sconn = (struct rxkad_sconn *)aconn->securityData;
+ if (sconn && sconn->authenticated && sconn->rock
+ && (time(0) < sconn->expirationTime)) {
+ if (level)
+ *level = sconn->level;
+ if (expiration)
+ *expiration = sconn->expirationTime;
+ if (name)
+ strcpy(name, sconn->rock->client.name);
+ if (instance)
+ strcpy(instance, sconn->rock->client.instance);
+ if (cell)
+ strcpy(cell, sconn->rock->client.cell);
+ if (kvno)
+ *kvno = sconn->rock->kvno;
return 0;
+ } else
+ return RXKADNOAUTH;
+}
+
+/* Set security object configuration variables */
+afs_int32 rxkad_SetConfiguration(struct rx_securityClass *aobj,
+ struct rx_connection *aconn,
+ rx_securityConfigVariables atype,
+ void * avalue, void **currentValue)
+{
+ struct rxkad_sprivate *private =
+ (struct rxkad_sprivate *) aobj->privateData;
+
+ switch (atype) {
+ case RXS_CONFIG_FLAGS:
+ if (currentValue) {
+ *((afs_uint32 *)currentValue) = private->flags;
+ } else {
+ private->flags = (intptr_t)avalue;
+ }
+ break;
+ default:
+ break;
}
- else return RXKADNOAUTH;
+ return 0;
}