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 /* The rxkad security object. Authentication using a DES-encrypted
11 * Kerberos-style ticket. These are the client-only routines. They do not
12 * make any use of DES. */
14 #include <afsconfig.h>
16 #include "../afs/param.h"
18 #include <afs/param.h>
24 #include "../afs/stds.h"
26 #include "../h/types.h"
27 #include "../h/time.h"
28 #ifdef AFS_LINUX20_ENV
29 #include "../h/socket.h"
31 #include "../netinet/in.h"
33 #include "../afs/sysincludes.h"
35 #ifndef AFS_LINUX22_ENV
36 #include "../rpc/types.h"
37 #include "../rx/xdr.h"
42 #include <sys/types.h>
54 #include <netinet/in.h>
58 #ifdef AFS_PTHREAD_ENV
59 #include "../rxkad/rxkad.h"
60 #endif /* AFS_PTHREAD_ENV */
63 #include "private_data.h"
64 #define XPRT_RXKAD_CLIENT
69 #define max(a,b) ((a) < (b)? (b) : (a))
72 static struct rx_securityOps rxkad_client_ops = {
74 rxkad_NewConnection, /* every new connection */
75 rxkad_PreparePacket, /* once per packet creation */
76 0, /* send packet (once per retrans.) */
80 rxkad_GetResponse, /* respond to challenge packet */
82 rxkad_CheckPacket, /* check data packet */
83 rxkad_DestroyConnection,
90 /* To minimize changes to epoch, we set this Cuid once, and everyone (including
91 * rxnull) uses it after that. This means that the Ksession of the first
92 * authencticated connection should be a good one. */
94 #ifdef AFS_PTHREAD_ENV
96 * This mutex protects the following global variables:
102 pthread_mutex_t rxkad_client_uid_mutex;
103 #define LOCK_CUID assert(pthread_mutex_lock(&rxkad_client_uid_mutex)==0);
104 #define UNLOCK_CUID assert(pthread_mutex_unlock(&rxkad_client_uid_mutex)==0);
108 #endif /* AFS_PTHREAD_ENV */
110 static afs_int32 Cuid[2]; /* set once and shared by all */
111 int rxkad_EpochWasSet = 0; /* TRUE => we called rx_SetEpoch */
113 /* allocate a new connetion ID in place */
114 rxkad_AllocCID(aobj, aconn)
115 struct rx_securityClass *aobj;
116 struct rx_connection *aconn;
118 struct rxkad_cprivate *tcp;
119 struct rxkad_cidgen tgen;
120 static afs_int32 counter = 0; /* not used anymore */
125 tgen.ipAddr = rxi_getaddr(); /* comes back in net order */
126 clock_GetTime(&tgen.time); /* changes time1 and time2 */
127 tgen.time.sec = htonl(tgen.time.sec);
128 tgen.time.usec = htonl(tgen.time.usec);
129 tgen.counter = htonl(counter);
132 tgen.random1 = afs_random() & 0x7fffffff; /* was "80000" */
133 tgen.random2 = afs_random() & 0x7fffffff; /* was "htonl(100)" */
135 tgen.random1 = htonl(getpid());
136 tgen.random2 = htonl(100);
139 /* block is ready for encryption with session key, let's go for it. */
140 tcp = (struct rxkad_cprivate *) aobj->privateData;
141 memcpy((void *)xor, (void *)tcp->ivec, 2*sizeof(afs_int32));
142 fc_cbc_encrypt((char *) &tgen, (char *) &tgen, sizeof(tgen),
143 tcp->keysched, xor, ENCRYPT);
145 /* Create a session key so that we can encrypt it */
148 memcpy((void *)Cuid, ((char *)&tgen) + sizeof(tgen) - ENCRYPTIONBLOCKSIZE, ENCRYPTIONBLOCKSIZE);
149 Cuid[0] = (Cuid[0] & ~0x40000000) | 0x80000000;
150 Cuid[1] &= RX_CIDMASK;
151 rx_SetEpoch (Cuid[0]); /* for future rxnull connections */
159 aconn->epoch = Cuid[0];
160 aconn->cid = Cuid[1];
161 Cuid[1] += 1<<RX_CIDSHIFT;
166 /* Allocate a new client security object. Called with the encryption level,
167 * the session key and the ticket for the other side obtained from the
168 * AuthServer. Refers to export control to determine level. */
170 struct rx_securityClass *
171 rxkad_NewClientSecurityObject(level, sessionkey, kvno, ticketLen, ticket)
173 struct ktc_encryptionKey *sessionkey;
177 { struct rx_securityClass *tsc;
178 struct rxkad_cprivate *tcp;
182 size = sizeof(struct rx_securityClass);
183 tsc = (struct rx_securityClass *) rxi_Alloc (size);
184 memset((void *)tsc, 0, size);
185 tsc->refCount = 1; /* caller gets one for free */
186 tsc->ops = &rxkad_client_ops;
188 size = sizeof(struct rxkad_cprivate);
189 tcp = (struct rxkad_cprivate *) rxi_Alloc (size);
190 memset((void *)tcp, 0, size);
191 tsc->privateData = (char *) tcp;
192 tcp->type |= rxkad_client;
194 code = fc_keysched (sessionkey, tcp->keysched);
195 if (code) return 0; /* bad key */
196 memcpy((void *)tcp->ivec, (void *)sessionkey, sizeof(tcp->ivec));
197 tcp->kvno = kvno; /* key version number */
198 tcp->ticketLen = ticketLen; /* length of ticket */
199 memcpy(tcp->ticket, ticket, ticketLen);
202 rxkad_stats_clientObjects++;
207 /* client: respond to a challenge packet */
209 rxs_return_t rxkad_GetResponse (aobj, aconn, apacket)
210 IN struct rx_securityClass *aobj;
211 IN struct rx_packet *apacket;
212 IN struct rx_connection *aconn;
213 { struct rxkad_cprivate *tcp;
215 int v2; /* whether server is old style or v2 */
216 afs_int32 challengeID;
219 int responseSize, missing;
220 struct rxkad_v2ChallengeResponse r_v2;
221 struct rxkad_oldChallengeResponse r_old;
223 tcp = (struct rxkad_cprivate *) aobj->privateData;
225 if (!(tcp->type & rxkad_client)) return RXKADINCONSISTENCY;
227 v2 = (rx_Contiguous(apacket) > sizeof(struct rxkad_oldChallenge));
228 tp = rx_DataOf(apacket);
230 if (v2) { /* v2 challenge */
231 struct rxkad_v2Challenge *c_v2;
232 if (rx_GetDataSize(apacket) < sizeof(struct rxkad_v2Challenge))
233 return RXKADPACKETSHORT;
234 c_v2 = (struct rxkad_v2Challenge *)tp;
235 challengeID = ntohl(c_v2->challengeID);
236 level = ntohl(c_v2->level);
237 } else { /* old format challenge */
238 struct rxkad_oldChallenge *c_old;
239 if (rx_GetDataSize(apacket) < sizeof(struct rxkad_oldChallenge))
240 return RXKADPACKETSHORT;
241 c_old = (struct rxkad_oldChallenge *)tp;
242 challengeID = ntohl(c_old->challengeID);
243 level = ntohl(c_old->level);
246 if (level > tcp->level) return RXKADLEVELFAIL;
248 rxkad_stats.challenges[rxkad_LevelIndex(tcp->level)]++;
254 memset((void *)&r_v2, 0, sizeof(r_v2));
255 r_v2.version = htonl(RXKAD_CHALLENGE_PROTOCOL_VERSION);
257 (void) rxkad_SetupEndpoint (aconn, &r_v2.encrypted.endpoint);
258 (void) rxi_GetCallNumberVector (aconn, r_v2.encrypted.callNumbers);
259 for (i=0; i<RX_MAXCALLS; i++) {
260 if (r_v2.encrypted.callNumbers[i] < 0) return RXKADINCONSISTENCY;
261 r_v2.encrypted.callNumbers[i] = htonl(r_v2.encrypted.callNumbers[i]);
263 r_v2.encrypted.incChallengeID = htonl(challengeID + 1);
264 r_v2.encrypted.level = htonl((afs_int32)tcp->level);
265 r_v2.kvno = htonl(tcp->kvno);
266 r_v2.ticketLen = htonl(tcp->ticketLen);
267 r_v2.encrypted.endpoint.cksum = rxkad_CksumChallengeResponse (&r_v2);
268 memcpy((void *)xor, (void *)tcp->ivec, 2*sizeof(afs_int32));
269 fc_cbc_encrypt (&r_v2.encrypted, &r_v2.encrypted,
270 sizeof(r_v2.encrypted), tcp->keysched, xor, ENCRYPT);
271 response = (char *)&r_v2;
272 responseSize = sizeof(r_v2);
274 memset((void *)&r_old, 0, sizeof(r_old));
275 r_old.encrypted.incChallengeID = htonl(challengeID + 1);
276 r_old.encrypted.level = htonl((afs_int32)tcp->level);
277 r_old.kvno = htonl(tcp->kvno);
278 r_old.ticketLen = htonl(tcp->ticketLen);
279 fc_ecb_encrypt (&r_old.encrypted, &r_old.encrypted, tcp->keysched, ENCRYPT);
280 response = (char *)&r_old;
281 responseSize = sizeof(r_old);
284 if (RX_MAX_PACKET_DATA_SIZE < responseSize + tcp->ticketLen)
285 return RXKADPACKETSHORT; /* not enough space */
287 rx_computelen(apacket, missing);
288 missing = responseSize + tcp->ticketLen - missing;
290 if (rxi_AllocDataBuf(apacket, missing) > 0)
291 return RXKADPACKETSHORT; /* not enough space */
293 /* copy response and ticket into packet */
294 rx_packetwrite(apacket, 0, responseSize, response);
295 rx_packetwrite(apacket, responseSize, tcp->ticketLen, tcp->ticket);
297 rx_SetDataSize (apacket, responseSize + tcp->ticketLen);