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>
29 #if defined(AFS_AIX_ENV) || defined(AFS_AUX_ENV) || defined(AFS_SUN5_ENV)
32 #ifdef AFS_LINUX20_ENV
36 #include "netinet/in.h"
39 #include "afs/sysincludes.h"
41 #ifndef AFS_LINUX22_ENV
42 #include "rpc/types.h"
48 #include <sys/types.h>
60 #include <netinet/in.h>
64 #ifdef AFS_PTHREAD_ENV
66 #endif /* AFS_PTHREAD_ENV */
69 #include <des/stats.h>
70 #include "private_data.h"
71 #define XPRT_RXKAD_CLIENT
74 #define max(a,b) ((a) < (b)? (b) : (a))
77 static struct rx_securityOps rxkad_client_ops = {
79 rxkad_NewConnection, /* every new connection */
80 rxkad_PreparePacket, /* once per packet creation */
81 0, /* send packet (once per retrans.) */
85 rxkad_GetResponse, /* respond to challenge packet */
87 rxkad_CheckPacket, /* check data packet */
88 rxkad_DestroyConnection,
95 /* To minimize changes to epoch, we set this Cuid once, and everyone (including
96 * rxnull) uses it after that. This means that the Ksession of the first
97 * authencticated connection should be a good one. */
99 #ifdef AFS_PTHREAD_ENV
101 * This mutex protects the following global variables:
107 pthread_mutex_t rxkad_client_uid_mutex;
108 #define LOCK_CUID assert(pthread_mutex_lock(&rxkad_client_uid_mutex)==0)
109 #define UNLOCK_CUID assert(pthread_mutex_unlock(&rxkad_client_uid_mutex)==0)
113 #endif /* AFS_PTHREAD_ENV */
115 static afs_int32 Cuid[2]; /* set once and shared by all */
116 int rxkad_EpochWasSet = 0; /* TRUE => we called rx_SetEpoch */
118 /* allocate a new connetion ID in place */
120 rxkad_AllocCID(struct rx_securityClass *aobj, struct rx_connection *aconn)
122 struct rxkad_cprivate *tcp;
123 struct rxkad_cidgen tgen;
124 static afs_int32 counter = 0; /* not used anymore */
129 tgen.ipAddr = rxi_getaddr(); /* comes back in net order */
130 clock_GetTime(&tgen.time); /* changes time1 and time2 */
131 tgen.time.sec = htonl(tgen.time.sec);
132 tgen.time.usec = htonl(tgen.time.usec);
133 tgen.counter = htonl(counter);
136 tgen.random1 = afs_random() & 0x7fffffff; /* was "80000" */
137 tgen.random2 = afs_random() & 0x7fffffff; /* was "htonl(100)" */
139 tgen.random1 = htonl(getpid());
140 tgen.random2 = htonl(100);
143 /* block is ready for encryption with session key, let's go for it. */
144 tcp = (struct rxkad_cprivate *)aobj->privateData;
145 memcpy((void *)xor, (void *)tcp->ivec, 2 * sizeof(afs_int32));
146 fc_cbc_encrypt((char *)&tgen, (char *)&tgen, sizeof(tgen),
147 tcp->keysched, xor, ENCRYPT);
149 /* Create a session key so that we can encrypt it */
153 ((char *)&tgen) + sizeof(tgen) - ENCRYPTIONBLOCKSIZE,
154 ENCRYPTIONBLOCKSIZE);
155 Cuid[0] = (Cuid[0] & ~0x40000000) | 0x80000000;
156 Cuid[1] &= RX_CIDMASK;
157 rx_SetEpoch(Cuid[0]); /* for future rxnull connections */
165 aconn->epoch = Cuid[0];
166 aconn->cid = Cuid[1];
167 Cuid[1] += 1 << RX_CIDSHIFT;
172 /* Allocate a new client security object. Called with the encryption level,
173 * the session key and the ticket for the other side obtained from the
174 * AuthServer. Refers to export control to determine level. */
176 struct rx_securityClass *
177 rxkad_NewClientSecurityObject(rxkad_level level,
178 struct ktc_encryptionKey *sessionkey,
179 afs_int32 kvno, int ticketLen, char *ticket)
181 struct rx_securityClass *tsc;
182 struct rxkad_cprivate *tcp;
186 size = sizeof(struct rx_securityClass);
187 tsc = (struct rx_securityClass *)rxi_Alloc(size);
188 memset((void *)tsc, 0, size);
189 tsc->refCount = 1; /* caller gets one for free */
190 tsc->ops = &rxkad_client_ops;
192 psize = PDATA_SIZE(ticketLen);
193 tcp = (struct rxkad_cprivate *)rxi_Alloc(psize);
194 memset((void *)tcp, 0, psize);
195 tsc->privateData = (char *)tcp;
196 tcp->type |= rxkad_client;
198 code = fc_keysched(sessionkey, tcp->keysched);
200 rxi_Free(tcp, psize);
201 rxi_Free(tsc, sizeof(struct rx_securityClass));
202 return 0; /* bad key */
204 memcpy((void *)tcp->ivec, (void *)sessionkey, sizeof(tcp->ivec));
205 tcp->kvno = kvno; /* key version number */
206 tcp->ticketLen = ticketLen; /* length of ticket */
207 if (tcp->ticketLen > MAXKTCTICKETLEN) {
208 rxi_Free(tcp, psize);
209 rxi_Free(tsc, sizeof(struct rx_securityClass));
210 return 0; /* bad key */
212 memcpy(tcp->ticket, ticket, ticketLen);
214 INC_RXKAD_STATS(clientObjects);
218 /* client: respond to a challenge packet */
221 rxkad_GetResponse(struct rx_securityClass *aobj, struct rx_connection *aconn,
222 struct rx_packet *apacket)
224 struct rxkad_cprivate *tcp;
226 int v2; /* whether server is old style or v2 */
227 afs_int32 challengeID;
230 int responseSize, missing;
231 struct rxkad_v2ChallengeResponse r_v2;
232 struct rxkad_oldChallengeResponse r_old;
234 tcp = (struct rxkad_cprivate *)aobj->privateData;
236 if (!(tcp->type & rxkad_client))
237 return RXKADINCONSISTENCY;
239 v2 = (rx_Contiguous(apacket) > sizeof(struct rxkad_oldChallenge));
240 tp = rx_DataOf(apacket);
242 if (v2) { /* v2 challenge */
243 struct rxkad_v2Challenge *c_v2;
244 if (rx_GetDataSize(apacket) < sizeof(struct rxkad_v2Challenge))
245 return RXKADPACKETSHORT;
246 c_v2 = (struct rxkad_v2Challenge *)tp;
247 challengeID = ntohl(c_v2->challengeID);
248 level = ntohl(c_v2->level);
249 } else { /* old format challenge */
250 struct rxkad_oldChallenge *c_old;
251 if (rx_GetDataSize(apacket) < sizeof(struct rxkad_oldChallenge))
252 return RXKADPACKETSHORT;
253 c_old = (struct rxkad_oldChallenge *)tp;
254 challengeID = ntohl(c_old->challengeID);
255 level = ntohl(c_old->level);
258 if (level > tcp->level)
259 return RXKADLEVELFAIL;
260 INC_RXKAD_STATS(challenges[rxkad_LevelIndex(tcp->level)]);
264 memset((void *)&r_v2, 0, sizeof(r_v2));
265 r_v2.version = htonl(RXKAD_CHALLENGE_PROTOCOL_VERSION);
267 (void)rxkad_SetupEndpoint(aconn, &r_v2.encrypted.endpoint);
268 (void)rxi_GetCallNumberVector(aconn, r_v2.encrypted.callNumbers);
269 for (i = 0; i < RX_MAXCALLS; i++) {
270 if (r_v2.encrypted.callNumbers[i] < 0)
271 return RXKADINCONSISTENCY;
272 r_v2.encrypted.callNumbers[i] =
273 htonl(r_v2.encrypted.callNumbers[i]);
275 r_v2.encrypted.incChallengeID = htonl(challengeID + 1);
276 r_v2.encrypted.level = htonl((afs_int32) tcp->level);
277 r_v2.kvno = htonl(tcp->kvno);
278 r_v2.ticketLen = htonl(tcp->ticketLen);
279 r_v2.encrypted.endpoint.cksum = rxkad_CksumChallengeResponse(&r_v2);
280 memcpy((void *)xor, (void *)tcp->ivec, 2 * sizeof(afs_int32));
281 fc_cbc_encrypt(&r_v2.encrypted, &r_v2.encrypted,
282 sizeof(r_v2.encrypted), tcp->keysched, xor, ENCRYPT);
283 response = (char *)&r_v2;
284 responseSize = sizeof(r_v2);
286 memset((void *)&r_old, 0, sizeof(r_old));
287 r_old.encrypted.incChallengeID = htonl(challengeID + 1);
288 r_old.encrypted.level = htonl((afs_int32) tcp->level);
289 r_old.kvno = htonl(tcp->kvno);
290 r_old.ticketLen = htonl(tcp->ticketLen);
291 fc_ecb_encrypt(&r_old.encrypted, &r_old.encrypted, tcp->keysched,
293 response = (char *)&r_old;
294 responseSize = sizeof(r_old);
297 if (RX_MAX_PACKET_DATA_SIZE < responseSize + tcp->ticketLen)
298 return RXKADPACKETSHORT; /* not enough space */
300 rx_computelen(apacket, missing);
301 missing = responseSize + tcp->ticketLen - missing;
303 if (rxi_AllocDataBuf(apacket, missing, RX_PACKET_CLASS_SEND) > 0)
304 return RXKADPACKETSHORT; /* not enough space */
306 /* copy response and ticket into packet */
307 rx_packetwrite(apacket, 0, responseSize, response);
308 rx_packetwrite(apacket, responseSize, tcp->ticketLen, tcp->ticket);
310 rx_SetDataSize(apacket, responseSize + tcp->ticketLen);
315 rxkad_ResetState(void)
319 rxkad_EpochWasSet = 0;