Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / rxkad / rxkad_client.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. Authentication using a DES-encrypted
11 * Kerberos-style ticket. These are the client-only routines. They do not
12 * make any use of DES. */
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16 #include <afs/stds.h>
17
18 #ifdef KERNEL
19 #ifndef UKERNEL
20 #include "h/types.h"
21 #include "h/time.h"
22 #if defined(AFS_AIX_ENV) || defined(AFS_AUX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_XBSD_ENV)
23 #include "h/systm.h"
24 #endif
25 #ifdef AFS_LINUX20_ENV
26 #include "h/socket.h"
27 #endif
28 #ifndef AFS_OBSD_ENV
29 #include "netinet/in.h"
30 #endif
31 #else /* !UKERNEL */
32 #include "afs/sysincludes.h"
33 #endif /* !UKERNEL */
34 #else /* ! KERNEL */
35 #include <roken.h>
36 #include <afs/opr.h>
37 #endif /* KERNEL */
38
39
40 #include <rx/rx.h>
41 #include <rx/xdr.h>
42 #include <rx/rx_packet.h>
43
44 #include "rxkad.h"
45 #include "stats.h"
46 #include "private_data.h"
47 #define XPRT_RXKAD_CLIENT
48
49 #ifndef max
50 #define max(a,b) ((a) < (b)? (b) : (a))
51 #endif /* max */
52
53 static struct rx_securityOps rxkad_client_ops = {
54 rxkad_Close,
55 rxkad_NewConnection, /* every new connection */
56 rxkad_PreparePacket, /* once per packet creation */
57 0, /* send packet (once per retrans.) */
58 0,
59 0,
60 0,
61 rxkad_GetResponse, /* respond to challenge packet */
62 0,
63 rxkad_CheckPacket, /* check data packet */
64 rxkad_DestroyConnection,
65 rxkad_GetStats,
66 0,
67 0,
68 0,
69 };
70
71 /* Allocate a new client security object. Called with the encryption level,
72 * the session key and the ticket for the other side obtained from the
73 * AuthServer. Refers to export control to determine level. */
74
75 struct rx_securityClass *
76 rxkad_NewClientSecurityObject(rxkad_level level,
77 struct ktc_encryptionKey *sessionkey,
78 afs_int32 kvno, int ticketLen, char *ticket)
79 {
80 struct rx_securityClass *tsc;
81 struct rxkad_cprivate *tcp;
82 int code;
83 int size, psize;
84
85 rxkad_Init();
86
87 size = sizeof(struct rx_securityClass);
88 tsc = rxi_Alloc(size);
89 memset((void *)tsc, 0, size);
90 tsc->refCount = 1; /* caller gets one for free */
91 tsc->ops = &rxkad_client_ops;
92
93 psize = PDATA_SIZE(ticketLen);
94 tcp = rxi_Alloc(psize);
95 memset((void *)tcp, 0, psize);
96 tsc->privateData = (char *)tcp;
97 tcp->type |= rxkad_client;
98 tcp->level = level;
99 code = fc_keysched(sessionkey, tcp->keysched);
100 if (code) {
101 rxi_Free(tcp, psize);
102 rxi_Free(tsc, sizeof(struct rx_securityClass));
103 return 0; /* bad key */
104 }
105 memcpy((void *)tcp->ivec, (void *)sessionkey, sizeof(tcp->ivec));
106 tcp->kvno = kvno; /* key version number */
107 tcp->ticketLen = ticketLen; /* length of ticket */
108 if (tcp->ticketLen > MAXKTCTICKETLEN) {
109 rxi_Free(tcp, psize);
110 rxi_Free(tsc, sizeof(struct rx_securityClass));
111 return 0; /* bad key */
112 }
113 memcpy(tcp->ticket, ticket, ticketLen);
114
115 INC_RXKAD_STATS(clientObjects);
116 return tsc;
117 }
118
119 /* client: respond to a challenge packet */
120
121 int
122 rxkad_GetResponse(struct rx_securityClass *aobj, struct rx_connection *aconn,
123 struct rx_packet *apacket)
124 {
125 struct rxkad_cprivate *tcp;
126 char *tp;
127 int v2; /* whether server is old style or v2 */
128 afs_int32 challengeID;
129 rxkad_level level;
130 char *response;
131 int responseSize, missing;
132 struct rxkad_v2ChallengeResponse r_v2;
133 struct rxkad_oldChallengeResponse r_old;
134
135 tcp = (struct rxkad_cprivate *)aobj->privateData;
136
137 if (!(tcp->type & rxkad_client))
138 return RXKADINCONSISTENCY;
139
140 v2 = (rx_Contiguous(apacket) > sizeof(struct rxkad_oldChallenge));
141 tp = rx_DataOf(apacket);
142
143 if (v2) { /* v2 challenge */
144 struct rxkad_v2Challenge *c_v2;
145 if (rx_GetDataSize(apacket) < sizeof(struct rxkad_v2Challenge))
146 return RXKADPACKETSHORT;
147 c_v2 = (struct rxkad_v2Challenge *)tp;
148 challengeID = ntohl(c_v2->challengeID);
149 level = ntohl(c_v2->level);
150 } else { /* old format challenge */
151 struct rxkad_oldChallenge *c_old;
152 if (rx_GetDataSize(apacket) < sizeof(struct rxkad_oldChallenge))
153 return RXKADPACKETSHORT;
154 c_old = (struct rxkad_oldChallenge *)tp;
155 challengeID = ntohl(c_old->challengeID);
156 level = ntohl(c_old->level);
157 }
158
159 if (level > tcp->level)
160 return RXKADLEVELFAIL;
161 INC_RXKAD_STATS(challenges[rxkad_LevelIndex(tcp->level)]);
162 if (v2) {
163 int i;
164 afs_uint32 xor[2];
165 memset((void *)&r_v2, 0, sizeof(r_v2));
166 r_v2.version = htonl(RXKAD_CHALLENGE_PROTOCOL_VERSION);
167 r_v2.spare = 0;
168 (void)rxkad_SetupEndpoint(aconn, &r_v2.encrypted.endpoint);
169 (void)rxi_GetCallNumberVector(aconn, r_v2.encrypted.callNumbers);
170 for (i = 0; i < RX_MAXCALLS; i++) {
171 if (r_v2.encrypted.callNumbers[i] < 0)
172 return RXKADINCONSISTENCY;
173 r_v2.encrypted.callNumbers[i] =
174 htonl(r_v2.encrypted.callNumbers[i]);
175 }
176 r_v2.encrypted.incChallengeID = htonl(challengeID + 1);
177 r_v2.encrypted.level = htonl((afs_int32) tcp->level);
178 r_v2.kvno = htonl(tcp->kvno);
179 r_v2.ticketLen = htonl(tcp->ticketLen);
180 r_v2.encrypted.endpoint.cksum = rxkad_CksumChallengeResponse(&r_v2);
181 memcpy((void *)xor, (void *)tcp->ivec, 2 * sizeof(afs_int32));
182 fc_cbc_encrypt(&r_v2.encrypted, &r_v2.encrypted,
183 sizeof(r_v2.encrypted), tcp->keysched, xor, ENCRYPT);
184 response = (char *)&r_v2;
185 responseSize = sizeof(r_v2);
186 } else {
187 memset((void *)&r_old, 0, sizeof(r_old));
188 r_old.encrypted.incChallengeID = htonl(challengeID + 1);
189 r_old.encrypted.level = htonl((afs_int32) tcp->level);
190 r_old.kvno = htonl(tcp->kvno);
191 r_old.ticketLen = htonl(tcp->ticketLen);
192 fc_ecb_encrypt(&r_old.encrypted, &r_old.encrypted, tcp->keysched,
193 ENCRYPT);
194 response = (char *)&r_old;
195 responseSize = sizeof(r_old);
196 }
197
198 if (RX_MAX_PACKET_DATA_SIZE < responseSize + tcp->ticketLen)
199 return RXKADPACKETSHORT; /* not enough space */
200
201 rx_computelen(apacket, missing);
202 missing = responseSize + tcp->ticketLen - missing;
203 if (missing > 0)
204 if (rxi_AllocDataBuf(apacket, missing, RX_PACKET_CLASS_SEND) > 0)
205 return RXKADPACKETSHORT; /* not enough space */
206
207 /* copy response and ticket into packet */
208 rx_packetwrite(apacket, 0, responseSize, response);
209 rx_packetwrite(apacket, responseSize, tcp->ticketLen, tcp->ticket);
210
211 rx_SetDataSize(apacket, responseSize + tcp->ticketLen);
212 return 0;
213 }