Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / rxkad / rxkad_common.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
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
8 */
9
10 /* The rxkad security object. Routines used by both client and servers. */
11
12 #include <afsconfig.h>
13 #include <afs/param.h>
14 #include <afs/stds.h>
15
16 #ifdef AFS_SUN59_ENV
17 #include <sys/time_impl.h>
18 #endif
19
20 #define INCLUDE_RXKAD_PRIVATE_DECLS
21
22 #ifdef KERNEL
23 #ifndef UKERNEL
24 #include "afs/afs_osi.h"
25 #if defined(AFS_AIX_ENV) || defined(AFS_AUX_ENV) || defined(AFS_SUN5_ENV)
26 #include "h/systm.h"
27 #endif
28 #if defined(AFS_DARWIN_ENV) || defined(AFS_OBSD_ENV)
29 #include "h/kernel.h"
30 #endif
31 #include "h/types.h"
32 #include "h/time.h"
33 #else /* !UKERNEL */
34 #include "afs/sysincludes.h"
35 #include "afsincludes.h"
36 #endif /* !UKERNEL */
37 #else /* KERNEL */
38 #include <roken.h>
39 #include <afs/opr.h>
40 #if defined(AFS_NT40_ENV) && defined(AFS_PTHREAD_ENV)
41 #define RXKAD_STATS_DECLSPEC __declspec(dllexport)
42 #endif
43 #endif /* KERNEL */
44
45 #include <rx/rx.h>
46 #include <rx/rx_packet.h>
47 #include <rx/xdr.h>
48
49 #include "stats.h"
50 #include "private_data.h"
51 #define XPRT_RXKAD_COMMON
52
53 #ifndef afs_max
54 #define afs_max(a,b) ((a) < (b)? (b) : (a))
55 #endif /* afs_max */
56
57 #ifndef KERNEL
58 #define osi_Time() time(0)
59 #endif
60 /* variable initialization for the benefit of darwin compiler; if it causes
61 problems elsewhere, conditionalize for darwin or fc_test compile breaks */
62 #if defined(AFS_PTHREAD_ENV) && !defined(KERNEL)
63 struct rxkad_global_stats rxkad_global_stats;
64 pthread_mutex_t rxkad_global_stats_lock;
65 pthread_key_t rxkad_stats_key;
66 #else /* AFS_PTHREAD_ENV && !KERNEL */
67 struct rxkad_stats rxkad_stats;
68 #endif /* AFS_PTHREAD_ENV && !KERNEL */
69
70 #if defined(AFS_PTHREAD_ENV) && !defined(KERNEL)
71 /* Pthread initialisation */
72 static pthread_once_t rxkad_once_init = PTHREAD_ONCE_INIT;
73 extern pthread_mutex_t rxkad_random_mutex;
74
75 static void
76 rxkad_global_stats_init(void)
77 {
78 osi_Assert(pthread_mutex_init(&rxkad_global_stats_lock, (const pthread_mutexattr_t *)0) == 0);
79 osi_Assert(pthread_key_create(&rxkad_stats_key, NULL) == 0);
80 memset(&rxkad_global_stats, 0, sizeof(rxkad_global_stats));
81 }
82
83 static void
84 rxkad_InitPthread(void) {
85 MUTEX_INIT(&rxkad_random_mutex, "rxkad random", MUTEX_DEFAULT, 0);
86
87 rxkad_global_stats_init();
88 }
89
90 void
91 rxkad_Init(void) {
92 osi_Assert(pthread_once(&rxkad_once_init, rxkad_InitPthread) == 0);
93 }
94
95 /* rxkad_stats related stuff */
96
97 /*
98 * Macro to insert an element at the tail of a doubly linked list
99 */
100 #define DLL_INSERT_TAIL(ptr,head,tail,next,prev) \
101 do { \
102 (ptr)->next = NULL; \
103 (ptr)->prev = (tail); \
104 (tail) = (ptr); \
105 if ((ptr)->prev) \
106 (ptr)->prev->next = (ptr); \
107 else \
108 (head) = (ptr); \
109 osi_Assert((head) && ((head)->prev == NULL)); \
110 } while(0)
111
112 rxkad_stats_t *
113 rxkad_thr_stats_init(void) {
114 rxkad_stats_t * rxkad_stats;
115 rxkad_stats = calloc(1, sizeof(rxkad_stats_t));
116 osi_Assert(rxkad_stats != NULL && pthread_setspecific(rxkad_stats_key,rxkad_stats) == 0);
117 RXKAD_GLOBAL_STATS_LOCK;
118 DLL_INSERT_TAIL(rxkad_stats, rxkad_global_stats.first, rxkad_global_stats.last, next, prev);
119 RXKAD_GLOBAL_STATS_UNLOCK;
120 return rxkad_stats;
121 }
122
123 int rxkad_stats_agg(rxkad_stats_t * rxkad_stats) {
124 rxkad_stats_t * thr_stats;
125 osi_Assert(rxkad_stats != NULL);
126 memset(rxkad_stats, 0, sizeof(rxkad_stats_t));
127 RXKAD_GLOBAL_STATS_LOCK;
128 for (thr_stats = rxkad_global_stats.first; thr_stats != NULL; thr_stats = thr_stats->next) {
129 rxkad_stats->connections[0] += thr_stats->connections[0];
130 rxkad_stats->connections[1] += thr_stats->connections[1];
131 rxkad_stats->connections[2] += thr_stats->connections[2];
132 rxkad_stats->destroyObject += thr_stats->destroyObject;
133 rxkad_stats->destroyClient += thr_stats->destroyClient;
134 rxkad_stats->destroyUnused += thr_stats->destroyUnused;
135 rxkad_stats->destroyUnauth += thr_stats->destroyUnauth;
136 rxkad_stats->destroyConn[0] += thr_stats->destroyConn[0];
137 rxkad_stats->destroyConn[1] += thr_stats->destroyConn[1];
138 rxkad_stats->destroyConn[2] += thr_stats->destroyConn[2];
139 rxkad_stats->expired += thr_stats->expired;
140 rxkad_stats->challengesSent += thr_stats->challengesSent;
141 rxkad_stats->challenges[0] += thr_stats->challenges[0];
142 rxkad_stats->challenges[1] += thr_stats->challenges[1];
143 rxkad_stats->challenges[2] += thr_stats->challenges[2];
144 rxkad_stats->responses[0] += thr_stats->responses[0];
145 rxkad_stats->responses[1] += thr_stats->responses[1];
146 rxkad_stats->responses[2] += thr_stats->responses[2];
147 rxkad_stats->preparePackets[0] += thr_stats->preparePackets[0];
148 rxkad_stats->preparePackets[1] += thr_stats->preparePackets[1];
149 rxkad_stats->preparePackets[2] += thr_stats->preparePackets[2];
150 rxkad_stats->preparePackets[3] += thr_stats->preparePackets[3];
151 rxkad_stats->preparePackets[4] += thr_stats->preparePackets[4];
152 rxkad_stats->preparePackets[5] += thr_stats->preparePackets[5];
153 rxkad_stats->checkPackets[0] += thr_stats->checkPackets[0];
154 rxkad_stats->checkPackets[1] += thr_stats->checkPackets[1];
155 rxkad_stats->checkPackets[2] += thr_stats->checkPackets[2];
156 rxkad_stats->checkPackets[3] += thr_stats->checkPackets[3];
157 rxkad_stats->checkPackets[4] += thr_stats->checkPackets[4];
158 rxkad_stats->checkPackets[5] += thr_stats->checkPackets[5];
159 rxkad_stats->bytesEncrypted[0] += thr_stats->bytesEncrypted[0];
160 rxkad_stats->bytesEncrypted[1] += thr_stats->bytesEncrypted[1];
161 rxkad_stats->bytesDecrypted[0] += thr_stats->bytesDecrypted[0];
162 rxkad_stats->bytesDecrypted[1] += thr_stats->bytesDecrypted[1];
163 rxkad_stats->fc_encrypts[0] += thr_stats->fc_encrypts[0];
164 rxkad_stats->fc_encrypts[1] += thr_stats->fc_encrypts[1];
165 rxkad_stats->fc_key_scheds += thr_stats->fc_key_scheds;
166 rxkad_stats->des_encrypts[0] += thr_stats->des_encrypts[0];
167 rxkad_stats->des_encrypts[1] += thr_stats->des_encrypts[1];
168 rxkad_stats->des_key_scheds += thr_stats->des_key_scheds;
169 rxkad_stats->des_randoms += thr_stats->des_randoms;
170 rxkad_stats->clientObjects += thr_stats->clientObjects;
171 rxkad_stats->serverObjects += thr_stats->serverObjects;
172 rxkad_stats->spares[0] += thr_stats->spares[0];
173 rxkad_stats->spares[1] += thr_stats->spares[1];
174 rxkad_stats->spares[2] += thr_stats->spares[2];
175 rxkad_stats->spares[3] += thr_stats->spares[3];
176 rxkad_stats->spares[4] += thr_stats->spares[4];
177 rxkad_stats->spares[5] += thr_stats->spares[5];
178 rxkad_stats->spares[6] += thr_stats->spares[6];
179 rxkad_stats->spares[7] += thr_stats->spares[7];
180 }
181 RXKAD_GLOBAL_STATS_UNLOCK;
182 return 0;
183 }
184 #else /* AFS_PTHREAD_ENV && !KERNEL */
185 void
186 rxkad_Init(void)
187 {
188 return;
189 }
190 #endif /* AFS_PTHREAD_ENV && !KERNEL */
191
192 /* static prototypes */
193 static afs_int32 ComputeSum(struct rx_packet *apacket,
194 fc_KeySchedule * aschedule, afs_int32 * aivec);
195 static afs_int32 FreeObject(struct rx_securityClass *aobj);
196
197 /* this call sets up an endpoint structure, leaving it in *network* byte
198 * order so that it can be used quickly for encryption.
199 */
200 int
201 rxkad_SetupEndpoint(struct rx_connection *aconnp,
202 struct rxkad_endpoint *aendpointp)
203 {
204 afs_int32 i;
205
206 aendpointp->cuid[0] = htonl(rx_GetConnectionEpoch(aconnp));
207 i = rx_GetConnectionId(aconnp) & RX_CIDMASK;
208 aendpointp->cuid[1] = htonl(i);
209 aendpointp->cksum = 0; /* used as cksum only in chal resp. */
210 aendpointp->securityIndex = htonl(rx_SecurityClassOf(aconnp));
211 return 0;
212 }
213
214 /* setup xor information based on session key */
215 int
216 rxkad_DeriveXORInfo(struct rx_connection *aconnp, fc_KeySchedule * aschedule,
217 char *aivec, char *aresult)
218 {
219 struct rxkad_endpoint tendpoint;
220 afs_uint32 xor[2];
221
222 rxkad_SetupEndpoint(aconnp, &tendpoint);
223 memcpy((void *)xor, aivec, 2 * sizeof(afs_int32));
224 fc_cbc_encrypt(&tendpoint, &tendpoint, sizeof(tendpoint), *aschedule, xor,
225 ENCRYPT);
226 memcpy(aresult,
227 ((char *)&tendpoint) + sizeof(tendpoint) - ENCRYPTIONBLOCKSIZE,
228 ENCRYPTIONBLOCKSIZE);
229 return 0;
230 }
231
232 /* rxkad_CksumChallengeResponse - computes a checksum of the components of a
233 * challenge response packet (which must be unencrypted and in network order).
234 * The endpoint.cksum field is omitted and treated as zero. The cksum is
235 * returned in network order. */
236
237 afs_uint32
238 rxkad_CksumChallengeResponse(struct rxkad_v2ChallengeResponse * v2r)
239 {
240 int i;
241 afs_uint32 cksum;
242 u_char *cp = (u_char *) v2r;
243 afs_uint32 savedCksum = v2r->encrypted.endpoint.cksum;
244
245 v2r->encrypted.endpoint.cksum = 0;
246
247 /* this function captured from budb/db_hash.c */
248 cksum = 1000003;
249 for (i = 0; i < sizeof(*v2r); i++)
250 cksum = (*cp++) + cksum * 0x10204081;
251
252 v2r->encrypted.endpoint.cksum = savedCksum;
253 return htonl(cksum);
254 }
255
256 void
257 rxkad_SetLevel(struct rx_connection *conn, rxkad_level level)
258 {
259 if (level == rxkad_auth) {
260 rx_SetSecurityHeaderSize(conn, 4);
261 rx_SetSecurityMaxTrailerSize(conn, 4);
262 } else if (level == rxkad_crypt) {
263 rx_SetSecurityHeaderSize(conn, 8);
264 rx_SetSecurityMaxTrailerSize(conn, 8); /* XXX was 7, but why screw with
265 * unaligned accesses? */
266 }
267 }
268
269 /* returns a short integer in host byte order representing a good checksum of
270 * the packet header.
271 */
272 static afs_int32
273 ComputeSum(struct rx_packet *apacket, fc_KeySchedule * aschedule,
274 afs_int32 * aivec)
275 {
276 afs_uint32 word[2];
277 afs_uint32 t;
278
279 t = apacket->header.callNumber;
280 word[0] = htonl(t);
281 /* note that word [1] includes the channel # */
282 t = ((apacket->header.cid & 0x3) << 30)
283 | ((apacket->header.seq & 0x3fffffff));
284 word[1] = htonl(t);
285 /* XOR in the ivec from the per-endpoint encryption */
286 word[0] ^= aivec[0];
287 word[1] ^= aivec[1];
288 /* encrypts word as if it were a character string */
289 fc_ecb_encrypt(word, word, *aschedule, ENCRYPT);
290 t = ntohl(word[1]);
291 t = (t >> 16) & 0xffff;
292 if (t == 0)
293 t = 1; /* so that 0 means don't care */
294 return t;
295 }
296
297
298 static afs_int32
299 FreeObject(struct rx_securityClass *aobj)
300 {
301 struct rxkad_cprivate *tcp; /* both structs start w/ type field */
302
303 if (aobj->refCount > 0)
304 return 0; /* still in use */
305 tcp = (struct rxkad_cprivate *)aobj->privateData;
306 rxi_Free(aobj, sizeof(struct rx_securityClass));
307 if (tcp->type & rxkad_client) {
308 afs_int32 psize = PDATA_SIZE(tcp->ticketLen);
309 rxi_Free(tcp, psize);
310 } else if (tcp->type & rxkad_server) {
311 rxi_Free(tcp, sizeof(struct rxkad_sprivate));
312 } else {
313 return RXKADINCONSISTENCY;
314 } /* unknown type */
315 INC_RXKAD_STATS(destroyObject);
316 return 0;
317 }
318
319 /* rxkad_Close - called by rx with the security class object as a parameter
320 * when a security object is to be discarded */
321
322 int
323 rxkad_Close(struct rx_securityClass *aobj)
324 {
325 afs_int32 code;
326 aobj->refCount--;
327 code = FreeObject(aobj);
328 return code;
329 }
330
331 /* either: called to (re)create a new connection. */
332
333 int
334 rxkad_NewConnection(struct rx_securityClass *aobj,
335 struct rx_connection *aconn)
336 {
337 if (rx_GetSecurityData(aconn) != NULL)
338 return RXKADINCONSISTENCY; /* already allocated??? */
339
340 if (rx_IsServerConn(aconn)) {
341 struct rxkad_sconn *data;
342 data = rxi_Alloc(sizeof(struct rxkad_sconn));
343 memset(data, 0, sizeof(struct rxkad_sconn));
344 rx_SetSecurityData(aconn, data);
345 } else { /* client */
346 struct rxkad_cprivate *tcp;
347 struct rxkad_cconn *data;
348
349 data = rxi_Alloc(sizeof(struct rxkad_cconn));
350 memset(data, 0, sizeof(struct rxkad_cconn));
351 rx_SetSecurityData(aconn, data);
352
353 tcp = (struct rxkad_cprivate *)aobj->privateData;
354 if (!(tcp->type & rxkad_client))
355 return RXKADINCONSISTENCY;
356 rxkad_SetLevel(aconn, tcp->level); /* set header and trailer sizes */
357 rxkad_DeriveXORInfo(aconn, (fc_KeySchedule *)tcp->keysched, (char *)tcp->ivec, (char *)data->preSeq);
358 INC_RXKAD_STATS(connections[rxkad_LevelIndex(tcp->level)]);
359 }
360
361 aobj->refCount++; /* attached connection */
362 return 0;
363 }
364
365 /* either: called to destroy a connection. */
366
367 int
368 rxkad_DestroyConnection(struct rx_securityClass *aobj,
369 struct rx_connection *aconn)
370 {
371 if (rx_IsServerConn(aconn)) {
372 struct rxkad_sconn *sconn;
373 struct rxkad_serverinfo *rock;
374 sconn = rx_GetSecurityData(aconn);
375 if (sconn) {
376 rx_SetSecurityData(aconn, NULL);
377 if (sconn->authenticated)
378 INC_RXKAD_STATS(destroyConn[rxkad_LevelIndex(sconn->level)]);
379 else
380 INC_RXKAD_STATS(destroyUnauth);
381 rock = sconn->rock;
382 if (rock)
383 rxi_Free(rock, sizeof(struct rxkad_serverinfo));
384 rxi_Free(sconn, sizeof(struct rxkad_sconn));
385 } else {
386 INC_RXKAD_STATS(destroyUnused);
387 }
388 } else { /* client */
389 struct rxkad_cconn *cconn;
390 struct rxkad_cprivate *tcp;
391 cconn = rx_GetSecurityData(aconn);
392 tcp = (struct rxkad_cprivate *)aobj->privateData;
393 if (!(tcp->type & rxkad_client))
394 return RXKADINCONSISTENCY;
395 if (cconn) {
396 rx_SetSecurityData(aconn, NULL);
397 rxi_Free(cconn, sizeof(struct rxkad_cconn));
398 }
399 INC_RXKAD_STATS(destroyClient);
400 }
401 aobj->refCount--; /* decrement connection counter */
402 if (aobj->refCount <= 0) {
403 afs_int32 code;
404 code = FreeObject(aobj);
405 if (code)
406 return code;
407 }
408 return 0;
409 }
410
411 /* either: decode packet */
412
413 int
414 rxkad_CheckPacket(struct rx_securityClass *aobj, struct rx_call *acall,
415 struct rx_packet *apacket)
416 {
417 struct rx_connection *tconn;
418 rxkad_level level;
419 const fc_KeySchedule *schedule;
420 fc_InitializationVector *ivec;
421 int len;
422 int nlen = 0;
423 u_int word; /* so we get unsigned right-shift */
424 int checkCksum;
425 afs_int32 *preSeq;
426 afs_int32 code;
427
428 tconn = rx_ConnectionOf(acall);
429 len = rx_GetDataSize(apacket);
430 if (rx_IsServerConn(tconn)) {
431 struct rxkad_sconn *sconn;
432 sconn = rx_GetSecurityData(tconn);
433 if (rx_GetPacketCksum(apacket) != 0)
434 sconn->cksumSeen = 1;
435 checkCksum = sconn->cksumSeen;
436 if (sconn && sconn->authenticated
437 && (osi_Time() < sconn->expirationTime)) {
438 level = sconn->level;
439 INC_RXKAD_STATS(checkPackets[rxkad_StatIndex(rxkad_server, level)]);
440 sconn->stats.packetsReceived++;
441 sconn->stats.bytesReceived += len;
442 schedule = (const fc_KeySchedule *) sconn->keysched;
443 ivec = (fc_InitializationVector *) sconn->ivec;
444 } else {
445 INC_RXKAD_STATS(expired);
446 return RXKADEXPIRED;
447 }
448 preSeq = sconn->preSeq;
449 } else { /* client connection */
450 struct rxkad_cconn *cconn;
451 struct rxkad_cprivate *tcp;
452 cconn = rx_GetSecurityData(tconn);
453 if (rx_GetPacketCksum(apacket) != 0)
454 cconn->cksumSeen = 1;
455 checkCksum = cconn->cksumSeen;
456 tcp = (struct rxkad_cprivate *)aobj->privateData;
457 if (!(tcp->type & rxkad_client))
458 return RXKADINCONSISTENCY;
459 level = tcp->level;
460 INC_RXKAD_STATS(checkPackets[rxkad_StatIndex(rxkad_client, level)]);
461 cconn->stats.packetsReceived++;
462 cconn->stats.bytesReceived += len;
463 preSeq = cconn->preSeq;
464 schedule = (const fc_KeySchedule *) tcp->keysched;
465 ivec = (fc_InitializationVector *) tcp->ivec;
466 }
467
468 if (checkCksum) {
469 code = ComputeSum(apacket, (fc_KeySchedule *)schedule, preSeq);
470 if (code != rx_GetPacketCksum(apacket))
471 return RXKADSEALEDINCON;
472 }
473
474 switch (level) {
475 case rxkad_clear:
476 return 0; /* shouldn't happen */
477 case rxkad_auth:
478 rx_Pullup(apacket, 8); /* the following encrypts 8 bytes only */
479 fc_ecb_encrypt(rx_DataOf(apacket), rx_DataOf(apacket), *schedule,
480 DECRYPT);
481 break;
482 case rxkad_crypt:
483 code = rxkad_DecryptPacket(tconn, schedule, (const fc_InitializationVector *)ivec, len, apacket);
484 if (code)
485 return code;
486 break;
487 }
488 word = ntohl(rx_GetInt32(apacket, 0)); /* get first sealed word */
489 if ((word >> 16) !=
490 ((apacket->header.seq ^ apacket->header.callNumber) & 0xffff))
491 return RXKADSEALEDINCON;
492 nlen = word & 0xffff; /* get real user data length */
493
494 /* The sealed length should be no larger than the initial length, since the
495 * reverse (round-up) occurs in ...PreparePacket */
496 if (nlen > len)
497 return RXKADDATALEN;
498 rx_SetDataSize(apacket, nlen);
499 return 0;
500 }
501
502 /* either: encode packet */
503
504 int
505 rxkad_PreparePacket(struct rx_securityClass *aobj, struct rx_call *acall,
506 struct rx_packet *apacket)
507 {
508 struct rx_connection *tconn;
509 rxkad_level level;
510 fc_KeySchedule *schedule;
511 fc_InitializationVector *ivec;
512 int len;
513 int nlen = 0;
514 int word;
515 afs_int32 code;
516 afs_int32 *preSeq;
517
518 tconn = rx_ConnectionOf(acall);
519 len = rx_GetDataSize(apacket);
520 if (rx_IsServerConn(tconn)) {
521 struct rxkad_sconn *sconn;
522 sconn = rx_GetSecurityData(tconn);
523 if (sconn && sconn->authenticated
524 && (osi_Time() < sconn->expirationTime)) {
525 level = sconn->level;
526 INC_RXKAD_STATS(preparePackets[rxkad_StatIndex(rxkad_server, level)]);
527 sconn->stats.packetsSent++;
528 sconn->stats.bytesSent += len;
529 schedule = (fc_KeySchedule *) sconn->keysched;
530 ivec = (fc_InitializationVector *) sconn->ivec;
531 } else {
532 INC_RXKAD_STATS(expired); /* this is a pretty unlikely path... */
533 return RXKADEXPIRED;
534 }
535 preSeq = sconn->preSeq;
536 } else { /* client connection */
537 struct rxkad_cconn *cconn;
538 struct rxkad_cprivate *tcp;
539 cconn = rx_GetSecurityData(tconn);
540 tcp = (struct rxkad_cprivate *)aobj->privateData;
541 if (!(tcp->type & rxkad_client))
542 return RXKADINCONSISTENCY;
543 level = tcp->level;
544 INC_RXKAD_STATS(preparePackets[rxkad_StatIndex(rxkad_client, level)]);
545 cconn->stats.packetsSent++;
546 cconn->stats.bytesSent += len;
547 preSeq = cconn->preSeq;
548 schedule = (fc_KeySchedule *) tcp->keysched;
549 ivec = (fc_InitializationVector *) tcp->ivec;
550 }
551
552 /* compute upward compatible checksum */
553 rx_SetPacketCksum(apacket, ComputeSum(apacket, schedule, preSeq));
554 if (level == rxkad_clear)
555 return 0;
556
557 len = rx_GetDataSize(apacket);
558 word = (((apacket->header.seq ^ apacket->header.callNumber)
559 & 0xffff) << 16) | (len & 0xffff);
560 rx_PutInt32(apacket, 0, htonl(word));
561
562 switch (level) {
563 case rxkad_clear:
564 return 0; /* shouldn't happen */
565 case rxkad_auth:
566 nlen =
567 afs_max(ENCRYPTIONBLOCKSIZE,
568 len + rx_GetSecurityHeaderSize(tconn));
569 if (nlen > (len + rx_GetSecurityHeaderSize(tconn))) {
570 rxi_RoundUpPacket(apacket,
571 nlen - (len + rx_GetSecurityHeaderSize(tconn)));
572 }
573 rx_Pullup(apacket, 8); /* the following encrypts 8 bytes only */
574 fc_ecb_encrypt(rx_DataOf(apacket), rx_DataOf(apacket), *schedule,
575 ENCRYPT);
576 break;
577 case rxkad_crypt:
578 nlen = round_up_to_ebs(len + rx_GetSecurityHeaderSize(tconn));
579 if (nlen > (len + rx_GetSecurityHeaderSize(tconn))) {
580 rxi_RoundUpPacket(apacket,
581 nlen - (len + rx_GetSecurityHeaderSize(tconn)));
582 }
583 code = rxkad_EncryptPacket(tconn, (const fc_KeySchedule *)schedule, (const fc_InitializationVector *)ivec, nlen, apacket);
584 if (code)
585 return code;
586 break;
587 }
588 rx_SetDataSize(apacket, nlen);
589 return 0;
590 }
591
592 /* either: return connection stats */
593
594 int
595 rxkad_GetStats(struct rx_securityClass *aobj, struct rx_connection *aconn,
596 struct rx_securityObjectStats *astats)
597 {
598 void *securityData;
599
600 astats->type = RX_SECTYPE_KAD;
601 astats->level = ((struct rxkad_cprivate *)aobj->privateData)->level;
602
603 securityData = rx_GetSecurityData(aconn);
604
605 if (!securityData) {
606 astats->flags |= 1;
607 return 0;
608 }
609 if (rx_IsServerConn(aconn)) {
610 struct rxkad_sconn *sconn = securityData;
611
612 astats->level = sconn->level;
613 if (sconn->authenticated)
614 astats->flags |= 2;
615 if (sconn->cksumSeen)
616 astats->flags |= 8;
617 astats->expires = sconn->expirationTime;
618 astats->bytesReceived = sconn->stats.bytesReceived;
619 astats->packetsReceived = sconn->stats.packetsReceived;
620 astats->bytesSent = sconn->stats.bytesSent;
621 astats->packetsSent = sconn->stats.packetsSent;
622 } else { /* client connection */
623 struct rxkad_cconn *cconn = securityData;
624
625 if (cconn->cksumSeen)
626 astats->flags |= 8;
627 astats->bytesReceived = cconn->stats.bytesReceived;
628 astats->packetsReceived = cconn->stats.packetsReceived;
629 astats->bytesSent = cconn->stats.bytesSent;
630 astats->packetsSent = cconn->stats.packetsSent;
631 }
632 return 0;
633 }
634
635 rxkad_level
636 rxkad_StringToLevel(char *name)
637 {
638 if (strcmp(name, "clear") == 0)
639 return rxkad_clear;
640 if (strcmp(name, "auth") == 0)
641 return rxkad_auth;
642 if (strcmp(name, "crypt") == 0)
643 return rxkad_crypt;
644 return -1;
645 }
646
647 char *
648 rxkad_LevelToString(rxkad_level level)
649 {
650 if (level == rxkad_clear)
651 return "clear";
652 if (level == rxkad_auth)
653 return "auth";
654 if (level == rxkad_crypt)
655 return "crypt";
656 return "unknown";
657 }