*** empty log message ***
[arla.git] / rxgk / rxgk_clnt.c
blobe41429cea6300483dc5728bfa49d55982e2664c8
1 /*
2 * Copyright (c) 1995 - 2004, 2007 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 "rxgk_locl.h"
36 RCSID("$Id$");
38 /* Security object specific client data */
39 typedef struct rxgk_clnt_class {
40 struct rx_securityClass klass;
41 rxgk_level level;
42 struct rxgk_keyblock k0;
43 int32_t kvno;
44 RXGK_Token ticket;
45 uint32_t serviceId;
46 } rxgk_clnt_class;
48 /* Per connection specific client data */
49 typedef struct clnt_con_data {
50 RXGK_Token auth_token;
51 int32_t auth_token_kvno;
52 int64_t start_time;
53 struct rxgk_keyblock tk;
54 key_stuff k;
55 end_stuff e;
56 } clnt_con_data;
58 static
59 int
60 client_NewConnection(struct rx_securityClass *obj_, struct rx_connection *con)
62 rxgk_clnt_class *obj = (rxgk_clnt_class *) obj_;
63 clnt_con_data *cdat;
64 int ret;
66 assert(con->securityData == 0);
67 obj->klass.refCount++;
68 cdat = (clnt_con_data *) osi_Alloc(sizeof(clnt_con_data));
69 cdat->e.bytesReceived = cdat->e.packetsReceived = 0;
70 cdat->e.bytesSent = cdat->e.packetsSent = 0;
72 con->securityData = (char *) cdat;
73 rx_nextCid += RX_MAXCALLS;
74 con->epoch = rx_epoch;
75 con->cid = rx_nextCid;
76 cdat->auth_token.len = obj->ticket.len;
77 cdat->auth_token.val = obj->ticket.val;
78 cdat->start_time = time(NULL);
80 ret = rxgk_derive_transport_key(&obj->k0, &cdat->tk,
81 con->epoch, con->cid, cdat->start_time);
82 if (ret) {
83 return ret;
86 ret = rxgk_crypto_init(&cdat->tk, &cdat->k);
88 if (ret) {
89 return ret;
92 return 0;
95 static
96 int
97 client_Close(struct rx_securityClass *obj_)
99 rxgk_clnt_class *obj = (rxgk_clnt_class *) obj_;
100 obj->klass.refCount--;
101 if (obj->klass.refCount <= 0)
103 osi_Free(obj->ticket.val, obj->ticket.len);
104 osi_Free(obj, sizeof(rxgk_clnt_class));
106 return 0;
109 static
111 client_DestroyConnection(struct rx_securityClass *obj,
112 struct rx_connection *con)
114 clnt_con_data *cdat = (clnt_con_data *)con->securityData;
116 if (cdat)
117 osi_Free(cdat, sizeof(clnt_con_data));
118 return client_Close(obj);
122 * Receive a challange and respond.
124 static
126 client_GetResponse(const struct rx_securityClass *obj_,
127 const struct rx_connection *con,
128 struct rx_packet *pkt)
130 struct RXGK_Challenge c;
131 struct RXGK_Response r;
132 clnt_con_data *cdat = (clnt_con_data *)con->securityData;
133 size_t len;
134 char bufr[RXGK_RESPONSE_MAX_SIZE];
135 char *p;
136 struct RXGK_Response_Crypt rc;
137 RXGK_Token rc_clear, rc_crypt;
138 int ret;
139 int i;
141 memset(&r, 0, sizeof(r));
143 /* Get challenge */
144 if (rx_SlowReadPacket(pkt, 0, sizeof(c), &c) != sizeof(c))
145 return RXGKPACKETSHORT;
147 if (ntohl(c.rc_version) != RXGK_VERSION)
148 return RXGKINCONSISTENCY;
150 memset(&rc, 0, sizeof(rc));
151 memcpy(rc.nonce, c.rc_nonce, sizeof(rc.nonce));
152 rc.epoch = con->epoch;
153 rc.cid = con->cid & RX_CIDMASK;
155 rxi_GetCallNumberVector(con, rc.call_numbers);
157 for (i = 0; i < RX_MAXCALLS; i++) {
158 if (rc.call_numbers[i] < 0)
159 return RXGKINCONSISTENCY;
162 len = RXGK_RESPONSE_CRYPT_SIZE;
163 rc_clear.val = malloc(len);
164 p = ydr_encode_RXGK_Response_Crypt(&rc, rc_clear.val, &len);
165 if (p == NULL)
166 return RXGKINCONSISTENCY;
167 rc_clear.len = RXGK_RESPONSE_CRYPT_SIZE - len;
169 ret = rxgk_encrypt_buffer(&rc_clear, &rc_crypt,
170 &cdat->tk, RXGK_CLIENT_ENC_RESPONSE);
171 if (ret) {
172 free(rc_clear.val);
173 return RXGKINCONSISTENCY;
176 r.rr_version = RXGK_VERSION;
177 r.rr_authenticator.val = cdat->auth_token.val;
178 r.rr_authenticator.len = cdat->auth_token.len;
179 r.rr_ctext.val = rc_crypt.val;
180 r.rr_ctext.len = rc_crypt.len;
181 r.start_time = cdat->start_time;
183 len = sizeof(bufr);
184 p = ydr_encode_RXGK_Response(&r, bufr, &len);
185 len = sizeof(bufr) - len;
187 if (p == NULL)
188 return RXGKINCONSISTENCY;
190 if (rx_SlowWritePacket(pkt, 0, len, bufr) != len)
191 return RXGKPACKETSHORT;
192 rx_SetDataSize(pkt, len);
194 free(rc_crypt.val);
195 free(rc_clear.val);
197 #if 0
198 rxgk_clnt_class *obj = (rxgk_clnt_class *) obj_;
199 key_stuff *k = &obj->k;
200 krb5_data data;
201 int ret;
204 memcpy(rc.nonce, c.rc_nonce, sizeof(rc.nonce));
207 ret = krb5_encrypt(rxgk_krb5_context, k->ks_crypto,
208 RXGK_CLIENT_ENC_CHALLENGE, bufrc, len, &data);
209 if (ret)
210 return ret;
212 krb5_data_free(&data);
214 #endif
215 return 0;
219 * Checksum and/or encrypt packet.
221 static int
222 client_PreparePacket(struct rx_securityClass *obj_,
223 struct rx_call *call,
224 struct rx_packet *pkt)
226 rxgk_clnt_class *obj = (rxgk_clnt_class *) obj_;
227 struct rx_connection *con = rx_ConnectionOf(call);
228 clnt_con_data *cdat = (clnt_con_data *) con->securityData;
230 return rxgk_prepare_packet(pkt, con, obj->level, &cdat->k, &cdat->e,
231 RXGK_CLIENT_ENC_PACKET,
232 RXGK_CLIENT_MIC_PACKET);
236 * Verify checksums and/or decrypt packet.
238 static int
239 client_CheckPacket(struct rx_securityClass *obj_,
240 struct rx_call *call,
241 struct rx_packet *pkt)
243 rxgk_clnt_class *obj = (rxgk_clnt_class *) obj_;
244 struct rx_connection *con = rx_ConnectionOf(call);
245 clnt_con_data *cdat = (clnt_con_data *) con->securityData;
247 return rxgk_check_packet(pkt, con, obj->level, &cdat->k, &cdat->e,
248 RXGK_SERVER_ENC_PACKET,
249 RXGK_SERVER_MIC_PACKET);
252 static int
253 client_GetStats(const struct rx_securityClass *obj,
254 const struct rx_connection *con,
255 struct rx_securityObjectStats *st)
257 clnt_con_data *cdat = (clnt_con_data *) con->securityData;
259 st->type = rxgk_disipline;
260 st->level = ((rxgk_clnt_class *)obj)->level;
261 st->flags = rxgk_checksummed;
262 if (cdat == 0)
263 st->flags |= rxgk_unallocated;
265 st->bytesReceived = cdat->e.bytesReceived;
266 st->packetsReceived = cdat->e.packetsReceived;
267 st->bytesSent = cdat->e.bytesSent;
268 st->packetsSent = cdat->e.packetsSent;
270 return 0;
273 static struct rx_securityOps client_ops = {
274 client_Close,
275 client_NewConnection,
276 client_PreparePacket,
277 NULL,
278 NULL,
279 NULL,
280 NULL,
281 client_GetResponse,
282 NULL,
283 client_CheckPacket,
284 client_DestroyConnection,
285 client_GetStats,
286 NULL,
287 NULL,
288 NULL,
291 int rxgk_EpochWasSet = 0;
293 struct rx_securityClass *
294 rxgk_NewClientSecurityObject (rxgk_level level,
295 RXGK_Ticket_Crypt *token,
296 struct rxgk_keyblock *key)
298 rxgk_clnt_class *obj;
299 static int inited = 0;
301 if (rxgk_krb5_context == NULL) {
302 krb5_init_context(&rxgk_krb5_context);
305 if (!inited) {
306 rx_SetEpoch(17);
307 inited = 1;
310 obj = (rxgk_clnt_class *) osi_Alloc(sizeof(rxgk_clnt_class));
311 obj->klass.refCount = 1;
312 obj->klass.ops = &client_ops;
314 obj->klass.privateData = (char *)obj;
316 obj->level = level;
318 obj->k0.enctype = key->enctype;
319 obj->k0.length = key->length;
320 obj->k0.data = malloc(key->length);
321 if (obj->k0.data == NULL) {
322 osi_Free(obj, sizeof(rxgk_clnt_class));
323 return NULL;
325 memcpy(obj->k0.data, key->data, key->length);
327 obj->ticket.len = token->len;
328 obj->ticket.val = osi_Alloc(token->len);
329 memcpy(obj->ticket.val, token->val, obj->ticket.len);
331 return &obj->klass;