steps to support modern FreeBSD. After Robert Watson <rwatson@FreeBSD.org> and Alec...
[arla.git] / rxkad / rxk_clnt.c
blob358c82e20e1eb0f50d0e55cd7b130f1581bb7713
1 /*
2 * Copyright (c) 1995 - 2000, 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "rxkad_locl.h"
36 RCSID("$Id$");
38 /* This code also links into the kernel so we need to use osi_Alloc()
39 * to avoid calling malloc(). Similar trick with memcpy() */
41 #undef osi_Alloc
42 #undef osi_Free
43 char *osi_Alloc(int32_t size);
44 void osi_Free(void *p, int32_t size);
46 #undef memcpy
47 #define memcpy(to, from, len) bcopy1((from), (to), (len))
49 static
50 void
51 bcopy1(const void *from_, void *to_, size_t n)
53 char *to = to_;
54 const char *from = from_;
55 for (; n > 0; n--)
57 *to = *from;
58 to++;
59 from++;
63 /* Security object specific client data */
64 typedef struct rxkad_clnt_class {
65 struct rx_securityClass klass;
66 rxkad_level level;
67 key_stuff k;
68 int32_t kvno;
69 int32_t ticket_len;
70 char *ticket;
71 } rxkad_clnt_class;
73 /* Per connection specific client data */
74 typedef struct clnt_con_data {
75 end_stuff e;
76 } clnt_con_data;
78 static
79 int
80 client_NewConnection(struct rx_securityClass *obj_, struct rx_connection *con)
82 rxkad_clnt_class *obj = (rxkad_clnt_class *) obj_;
83 clnt_con_data *cdat;
85 assert(con->securityData == 0);
86 obj->klass.refCount++;
87 cdat = (clnt_con_data *) osi_Alloc(sizeof(clnt_con_data));
88 cdat->e.bytesReceived = cdat->e.packetsReceived = 0;
89 cdat->e.bytesSent = cdat->e.packetsSent = 0;
91 con->securityData = (char *) cdat;
92 rx_nextCid += RX_MAXCALLS;
93 con->epoch = rx_epoch;
94 con->cid = rx_nextCid;
95 /* We don't use trailers but the transarc implementation breaks when
96 * we don't set the trailer size, packets get to large */
97 switch (obj->level) {
98 case rxkad_clear:
99 /* nichts */
100 break;
101 case rxkad_auth:
102 rx_SetSecurityHeaderSize(con, 4);
103 rx_SetSecurityMaxTrailerSize(con, 4);
104 break;
105 case rxkad_crypt:
106 rx_SetSecurityHeaderSize(con, 8);
107 rx_SetSecurityMaxTrailerSize(con, 8);
108 break;
109 default:
110 assert(0);
112 rxkad_calc_header_iv(con, obj->k.keysched,
113 obj->k.key.data, cdat->e.header_iv);
114 return 0;
117 static
119 client_Close(struct rx_securityClass *obj_)
121 rxkad_clnt_class *obj = (rxkad_clnt_class *) obj_;
122 obj->klass.refCount--;
123 if (obj->klass.refCount <= 0)
125 osi_Free(obj->ticket, obj->ticket_len);
126 osi_Free(obj, sizeof(rxkad_clnt_class));
128 return 0;
131 static
133 client_DestroyConnection(struct rx_securityClass *obj,
134 struct rx_connection *con)
136 clnt_con_data *cdat = (clnt_con_data *)con->securityData;
138 if (cdat)
139 osi_Free(cdat, sizeof(clnt_con_data));
140 return client_Close(obj);
144 * Receive a challange and respond.
146 static
148 client_GetResponse(const struct rx_securityClass *obj_,
149 const struct rx_connection *con,
150 struct rx_packet *pkt)
152 rxkad_clnt_class *obj = (rxkad_clnt_class *) obj_;
153 rxkad_challenge c;
154 rxkad_response r;
156 /* Get challenge */
157 if (rx_SlowReadPacket(pkt, 0, sizeof(c), &c) != sizeof(c))
158 return RXKADPACKETSHORT;
160 if (ntohl(c.version) < RXKAD_VERSION)
161 return RXKADINCONSISTENCY; /* Don't know how to make vers 1 response. */
162 /* Always make a vers 2 response. */
164 if (ntohl(c.min_level) > obj->level)
165 return RXKADLEVELFAIL;
167 /* Make response */
168 r.version = htonl(RXKAD_VERSION);
169 r.unused = 0;
170 r.encrypted.epoch = htonl(con->epoch);
171 r.encrypted.cid = htonl(con->cid & RX_CIDMASK);
172 r.encrypted.cksum = 0;
173 r.encrypted.security_index = htonl(con->securityIndex);
175 int i;
176 /* Get and fixup call number vector */
177 rxi_GetCallNumberVector(con, r.encrypted.call_numbers);
178 for (i = 0; i < RX_MAXCALLS; i++)
180 if (r.encrypted.call_numbers[i] < 0)
181 return RXKADINCONSISTENCY;
182 r.encrypted.call_numbers[i] = htonl(r.encrypted.call_numbers[i]);
185 r.encrypted.inc_nonce = htonl(ntohl(c.nonce) + 1);
186 r.encrypted.level = htonl((int32_t)obj->level);
187 r.kvno = htonl(obj->kvno);
188 r.ticket_len = htonl(obj->ticket_len);
189 /* Make checksum before we seal r.encrypted */
190 r.encrypted.cksum = rxkad_cksum_response(&r);
191 /* Seal r.encrypted */
192 fc_cbc_enc2(&r.encrypted, &r.encrypted, sizeof(r.encrypted),
193 obj->k.keysched, (uint32_t*)obj->k.key.data, FC_ENCRYPT);
195 /* Stuff response and kerberos ticket into packet */
196 if (rx_SlowWritePacket(pkt, 0, sizeof(r), &r) != sizeof(r))
197 return RXKADPACKETSHORT;
198 if (rx_SlowWritePacket(pkt, sizeof(r), obj->ticket_len, obj->ticket) != obj->ticket_len)
199 return RXKADPACKETSHORT;
200 rx_SetDataSize(pkt, sizeof(r) + obj->ticket_len);
201 return 0;
205 * Checksum and/or encrypt packet.
207 static
209 client_PreparePacket(struct rx_securityClass *obj_,
210 struct rx_call *call,
211 struct rx_packet *pkt)
213 rxkad_clnt_class *obj = (rxkad_clnt_class *) obj_;
214 key_stuff *k = &obj->k;
215 struct rx_connection *con = rx_ConnectionOf(call);
216 end_stuff *e = &((clnt_con_data *) con->securityData)->e;
218 return rxkad_prepare_packet(pkt, con, obj->level, k, e);
222 * Verify checksums and/or decrypt packet.
224 static
226 client_CheckPacket(struct rx_securityClass *obj_,
227 struct rx_call *call,
228 struct rx_packet *pkt)
230 rxkad_clnt_class *obj = (rxkad_clnt_class *) obj_;
231 key_stuff *k = &obj->k;
232 struct rx_connection *con = rx_ConnectionOf(call);
233 end_stuff *e = &((clnt_con_data *) con->securityData)->e;
235 return rxkad_check_packet(pkt, con, obj->level, k, e);
238 static
240 client_GetStats(const struct rx_securityClass *obj,
241 const struct rx_connection *con,
242 struct rx_securityObjectStats *st)
244 clnt_con_data *cdat = (clnt_con_data *) con->securityData;
246 st->type = rxkad_disipline;
247 st->level = ((rxkad_clnt_class *)obj)->level;
248 st->flags = rxkad_checksummed;
249 if (cdat == 0)
250 st->flags |= rxkad_unallocated;
252 st->bytesReceived = cdat->e.bytesReceived;
253 st->packetsReceived = cdat->e.packetsReceived;
254 st->bytesSent = cdat->e.bytesSent;
255 st->packetsSent = cdat->e.packetsSent;
257 return 0;
260 static
261 struct rx_securityOps client_ops = {
262 client_Close,
263 client_NewConnection,
264 client_PreparePacket,
269 client_GetResponse,
271 client_CheckPacket,
272 client_DestroyConnection,
273 client_GetStats,
279 int rxkad_EpochWasSet = 0;
281 int rxkad_min_level = rxkad_clear; /* rxkad_{clear, auth, crypt} */
283 struct rx_securityClass *
284 rxkad_NewClientSecurityObject(/*rxkad_level*/ int level,
285 void *sessionkey, /* should be ktc_encryptionKey */
286 int32_t kvno,
287 int ticket_len,
288 char *ticket)
290 rxkad_clnt_class *obj;
291 static int inited = 0;
293 if (level < rxkad_min_level)
294 level = rxkad_min_level; /* Boost security level */
296 if (!inited)
298 /* Any good random numbers will do, no real need to use
299 * cryptographic techniques here */
300 union {
301 uint32_t rnd[2];
302 struct ktc_encryptionKey k;
303 } u;
304 int32_t sched[ROUNDS];
305 u_long next_epoch;
307 u.rnd[0] = rx_nextCid;
308 u.rnd[1] = rx_epoch;
309 fc_keysched(sessionkey, sched);
310 fc_ecb_encrypt(&u.k, &u.k, sched, FC_ENCRYPT);
312 /* Some paranoia so we won't reveal the key */
313 /*des_set_odd_parity(&u.k);*/
314 fc_keysched(&u.k, sched);
315 fc_ecb_encrypt(&u.k, &u.k, sched, FC_ENCRYPT);
317 /* Some paranoia so we won't reveal the key */
318 /*des_set_odd_parity(&u.k);*/
319 fc_keysched(&u.k, sched);
320 fc_ecb_encrypt(&u.k, &u.k, sched, FC_ENCRYPT);
322 /* Set new cid and epoch generator */
323 rx_nextCid = u.rnd[0] << RX_CIDSHIFT;
324 next_epoch = u.rnd[0] ^ u.rnd[1];
325 next_epoch &= 0x7FFFFFFF;
326 rx_SetEpoch(next_epoch);
327 rxkad_EpochWasSet = 1;
328 inited = 1;
331 #if 0
332 /* If we are passed a to large kerberos 5 ticket hope for the best */
333 if (ticket_len > MAXKRB5TICKETLEN)
334 ticket_len = MAXKRB5TICKETLEN;
335 #endif
337 obj = (rxkad_clnt_class *) osi_Alloc(sizeof(rxkad_clnt_class));
338 obj->klass.refCount = 1;
339 obj->klass.ops = &client_ops;
341 obj->klass.privateData = (char *) obj;
343 obj->level = level;
344 fc_keysched(sessionkey, obj->k.keysched);
345 memcpy(obj->k.key.data, sessionkey, 8);
346 obj->kvno = kvno;
348 obj->ticket_len = ticket_len;
349 obj->ticket = osi_Alloc(ticket_len);
350 memcpy(obj->ticket, ticket, ticket_len);
352 return &obj->klass;