1 /* The rxkad security object. Authentication using a DES-encrypted
2 * Kerberos-style ticket. These are the client-only routines. They do not
3 * make any use of DES. */
5 /* Copyright (C) 1991, 1989 Transarc Corporation - All rights reserved */
7 ****************************************************************************
8 * Copyright IBM Corporation 1988, 1989 - All Rights Reserved *
10 * Permission to use, copy, modify, and distribute this software and its *
11 * documentation for any purpose and without fee is hereby granted, *
12 * provided that the above copyright notice appear in all copies and *
13 * that both that copyright notice and this permission notice appear in *
14 * supporting documentation, and that the name of IBM not be used in *
15 * advertising or publicity pertaining to distribution of the software *
16 * without specific, written prior permission. *
18 * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL *
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM *
20 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY *
21 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER *
22 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING *
23 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
24 ****************************************************************************
30 #include "../afs/param.h"
31 #include "../afs/stds.h"
33 #include "../h/types.h"
34 #include "../h/time.h"
35 #ifdef AFS_LINUX20_ENV
36 #include "../h/socket.h"
38 #include "../netinet/in.h"
40 #include "../afs/sysincludes.h"
42 #ifndef AFS_LINUX22_ENV
43 #include "../rpc/types.h"
44 #include "../rpc/xdr.h"
49 #include <afs/param.h>
51 #include <sys/types.h>
56 #include <netinet/in.h>
60 #ifdef AFS_PTHREAD_ENV
61 #include "../rxkad/rxkad.h"
62 #endif /* AFS_PTHREAD_ENV */
66 #include "private_data.h"
67 #define XPRT_RXKAD_CLIENT
69 #include "../afs/permit_xprt.h"
71 #include "../permit_xprt.h"
78 #define max(a,b) ((a) < (b)? (b) : (a))
81 static struct rx_securityOps rxkad_client_ops = {
83 rxkad_NewConnection, /* every new connection */
84 rxkad_PreparePacket, /* once per packet creation */
85 0, /* send packet (once per retrans.) */
89 rxkad_GetResponse, /* respond to challenge packet */
91 rxkad_CheckPacket, /* check data packet */
92 rxkad_DestroyConnection,
99 /* To minimize changes to epoch, we set this Cuid once, and everyone (including
100 * rxnull) uses it after that. This means that the Ksession of the first
101 * authencticated connection should be a good one. */
103 #ifdef AFS_PTHREAD_ENV
105 * This mutex protects the following global variables:
111 pthread_mutex_t rxkad_client_uid_mutex;
112 #define LOCK_CUID assert(pthread_mutex_lock(&rxkad_client_uid_mutex)==0);
113 #define UNLOCK_CUID assert(pthread_mutex_unlock(&rxkad_client_uid_mutex)==0);
117 #endif /* AFS_PTHREAD_ENV */
119 static afs_int32 Cuid[2]; /* set once and shared by all */
120 int rxkad_EpochWasSet = 0; /* TRUE => we called rx_SetEpoch */
122 /* allocate a new connetion ID in place */
123 rxkad_AllocCID(aobj, aconn)
124 struct rx_securityClass *aobj;
125 struct rx_connection *aconn;
127 struct rxkad_cprivate *tcp;
128 struct rxkad_cidgen tgen;
129 static afs_int32 counter = 0; /* not used anymore */
134 tgen.ipAddr = rxi_getaddr(); /* comes back in net order */
135 clock_GetTime(&tgen.time); /* changes time1 and time2 */
136 tgen.time.sec = htonl(tgen.time.sec);
137 tgen.time.usec = htonl(tgen.time.usec);
138 tgen.counter = htonl(counter++);
140 tgen.random1 = afs_random() & 0x7fffffff; /* was "80000" */
141 tgen.random2 = afs_random() & 0x7fffffff; /* was "htonl(100)" */
143 tgen.random1 = htonl(getpid());
144 tgen.random2 = htonl(100);
147 /* block is ready for encryption with session key, let's go for it. */
148 tcp = (struct rxkad_cprivate *) aobj->privateData;
149 bcopy((void *)tcp->ivec, (void *)xor, 2*sizeof(afs_int32));
150 fc_cbc_encrypt((char *) &tgen, (char *) &tgen, sizeof(tgen),
151 tcp->keysched, xor, ENCRYPT);
153 /* Create a session key so that we can encrypt it */
156 bcopy(((char *)&tgen) + sizeof(tgen) - ENCRYPTIONBLOCKSIZE,
157 (void *)Cuid, ENCRYPTIONBLOCKSIZE);
158 Cuid[0] = (Cuid[0] & ~0x40000000) | 0x80000000;
159 Cuid[1] &= RX_CIDMASK;
160 rx_SetEpoch (Cuid[0]); /* for future rxnull connections */
168 aconn->epoch = Cuid[0];
169 aconn->cid = Cuid[1];
170 Cuid[1] += 1<<RX_CIDSHIFT;
175 /* Allocate a new client security object. Called with the encryption level,
176 * the session key and the ticket for the other side obtained from the
177 * AuthServer. Refers to export control to determine level. */
179 struct rx_securityClass *
180 rxkad_NewClientSecurityObject(level, sessionkey, kvno, ticketLen, ticket)
182 struct ktc_encryptionKey *sessionkey;
186 { struct rx_securityClass *tsc;
187 struct rxkad_cprivate *tcp;
191 size = sizeof(struct rx_securityClass);
192 tsc = (struct rx_securityClass *) rxi_Alloc (size);
193 bzero ((void *)tsc, size);
194 tsc->refCount = 1; /* caller gets one for free */
195 tsc->ops = &rxkad_client_ops;
197 size = sizeof(struct rxkad_cprivate);
198 tcp = (struct rxkad_cprivate *) rxi_Alloc (size);
199 bzero ((void *)tcp, size);
200 tsc->privateData = (char *) tcp;
201 tcp->type |= rxkad_client;
202 tcp->level = xprt_CoerceLevel(level);
203 code = fc_keysched (sessionkey, tcp->keysched);
204 if (code) return 0; /* bad key */
205 bcopy ((void *)sessionkey, (void *)tcp->ivec, sizeof(tcp->ivec));
206 tcp->kvno = kvno; /* key version number */
207 tcp->ticketLen = ticketLen; /* length of ticket */
208 bcopy(ticket, tcp->ticket, ticketLen);
211 rxkad_stats_clientObjects++;
216 /* client: respond to a challenge packet */
218 rxs_return_t rxkad_GetResponse (aobj, aconn, apacket)
219 IN struct rx_securityClass *aobj;
220 IN struct rx_packet *apacket;
221 IN struct rx_connection *aconn;
222 { struct rxkad_cprivate *tcp;
224 int v2; /* whether server is old style or v2 */
225 afs_int32 challengeID;
228 int responseSize, missing;
229 struct rxkad_v2ChallengeResponse r_v2;
230 struct rxkad_oldChallengeResponse r_old;
232 tcp = (struct rxkad_cprivate *) aobj->privateData;
234 if (!(tcp->type & rxkad_client)) return RXKADINCONSISTENCY;
236 v2 = (rx_Contiguous(apacket) > sizeof(struct rxkad_oldChallenge));
237 tp = rx_DataOf(apacket);
239 if (v2) { /* v2 challenge */
240 struct rxkad_v2Challenge *c_v2;
241 if (rx_GetDataSize(apacket) < sizeof(struct rxkad_v2Challenge))
242 return RXKADPACKETSHORT;
243 c_v2 = (struct rxkad_v2Challenge *)tp;
244 challengeID = ntohl(c_v2->challengeID);
245 level = ntohl(c_v2->level);
246 } else { /* old format challenge */
247 struct rxkad_oldChallenge *c_old;
248 if (rx_GetDataSize(apacket) < sizeof(struct rxkad_oldChallenge))
249 return RXKADPACKETSHORT;
250 c_old = (struct rxkad_oldChallenge *)tp;
251 challengeID = ntohl(c_old->challengeID);
252 level = ntohl(c_old->level);
255 if (level > tcp->level) return RXKADLEVELFAIL;
257 rxkad_stats.challenges[rxkad_LevelIndex(tcp->level)]++;
263 bzero ((void *)&r_v2, sizeof(r_v2));
264 r_v2.version = htonl(RXKAD_CHALLENGE_PROTOCOL_VERSION);
266 (void) rxkad_SetupEndpoint (aconn, &r_v2.encrypted.endpoint);
267 (void) rxi_GetCallNumberVector (aconn, r_v2.encrypted.callNumbers);
268 for (i=0; i<RX_MAXCALLS; i++) {
269 if (r_v2.encrypted.callNumbers[i] < 0) return RXKADINCONSISTENCY;
270 r_v2.encrypted.callNumbers[i] = htonl(r_v2.encrypted.callNumbers[i]);
272 r_v2.encrypted.incChallengeID = htonl(challengeID + 1);
273 r_v2.encrypted.level = htonl((afs_int32)tcp->level);
274 r_v2.kvno = htonl(tcp->kvno);
275 r_v2.ticketLen = htonl(tcp->ticketLen);
276 r_v2.encrypted.endpoint.cksum = rxkad_CksumChallengeResponse (&r_v2);
277 bcopy((void *)tcp->ivec, (void *)xor, 2*sizeof(afs_int32));
278 fc_cbc_encrypt (&r_v2.encrypted, &r_v2.encrypted,
279 sizeof(r_v2.encrypted), tcp->keysched, xor, ENCRYPT);
280 response = (char *)&r_v2;
281 responseSize = sizeof(r_v2);
283 bzero ((void *)&r_old, sizeof(r_old));
284 r_old.encrypted.incChallengeID = htonl(challengeID + 1);
285 r_old.encrypted.level = htonl((afs_int32)tcp->level);
286 r_old.kvno = htonl(tcp->kvno);
287 r_old.ticketLen = htonl(tcp->ticketLen);
288 fc_ecb_encrypt (&r_old.encrypted, &r_old.encrypted, tcp->keysched, ENCRYPT);
289 response = (char *)&r_old;
290 responseSize = sizeof(r_old);
293 if (RX_MAX_PACKET_DATA_SIZE < responseSize + tcp->ticketLen)
294 return RXKADPACKETSHORT; /* not enough space */
296 rx_computelen(apacket, missing);
297 missing = responseSize + tcp->ticketLen - missing;
299 if (rxi_AllocDataBuf(apacket, missing) > 0)
300 return RXKADPACKETSHORT; /* not enough space */
302 /* copy response and ticket into packet */
303 rx_packetwrite(apacket, 0, responseSize, response);
304 rx_packetwrite(apacket, responseSize, tcp->ticketLen, tcp->ticket);
306 rx_SetDataSize (apacket, responseSize + tcp->ticketLen);