Initial IBM OpenAFS 1.0 tree
[openafs.git] / src / rxkad / rxkad_client.c
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. */
4
5 /* Copyright (C) 1991, 1989 Transarc Corporation - All rights reserved */
6 /*
7 ****************************************************************************
8 *        Copyright IBM Corporation 1988, 1989 - All Rights Reserved        *
9 *                                                                          *
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.                              *
17 *                                                                          *
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 ****************************************************************************
25 */
26
27
28 #ifdef KERNEL
29
30 #include "../afs/param.h"
31 #include "../afs/stds.h"
32 #ifndef UKERNEL
33 #include "../h/types.h"
34 #include "../h/time.h"
35 #ifdef AFS_LINUX20_ENV
36 #include "../h/socket.h"
37 #endif
38 #include "../netinet/in.h"
39 #else /* !UKERNEL */
40 #include "../afs/sysincludes.h"
41 #endif /* !UKERNEL */
42 #ifndef AFS_LINUX22_ENV
43 #include "../rpc/types.h"
44 #include "../rpc/xdr.h"
45 #endif
46 #include "../rx/rx.h"
47 #else /* KERNEL */
48
49 #include <afs/param.h>
50 #include <afs/stds.h>
51 #include <sys/types.h>
52 #include <time.h>
53 #ifdef AFS_NT40_ENV
54 #include <winsock2.h>
55 #else
56 #include <netinet/in.h>
57 #endif
58 #include <rx/rx.h>
59 #include <rx/xdr.h>
60 #ifdef AFS_PTHREAD_ENV
61 #include "../rxkad/rxkad.h"
62 #endif /* AFS_PTHREAD_ENV */
63
64 #endif /* KERNEL */
65
66 #include "private_data.h"
67 #define XPRT_RXKAD_CLIENT
68 #ifdef KERNEL
69 #include "../afs/permit_xprt.h"
70 #else
71 #include "../permit_xprt.h"
72 #endif
73
74
75 char *rxi_Alloc();
76
77 #ifndef max
78 #define max(a,b)    ((a) < (b)? (b) : (a))
79 #endif /* max */
80
81 static struct rx_securityOps rxkad_client_ops = {
82     rxkad_Close,
83     rxkad_NewConnection,                /* every new connection */
84     rxkad_PreparePacket,                /* once per packet creation */
85     0,                                  /* send packet (once per retrans.) */
86     0,
87     0,
88     0,
89     rxkad_GetResponse,                  /* respond to challenge packet */
90     0,
91     rxkad_CheckPacket,                  /* check data packet */
92     rxkad_DestroyConnection,
93     rxkad_GetStats,
94     0,
95     0,
96     0,
97 };
98
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. */
102
103 #ifdef AFS_PTHREAD_ENV
104 /*
105  * This mutex protects the following global variables:
106  * Cuid
107  * counter
108  * rxkad_EpochWasSet
109  */
110 #include <assert.h>
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);
114 #else
115 #define LOCK_CUID
116 #define UNLOCK_CUID
117 #endif /* AFS_PTHREAD_ENV */
118
119 static afs_int32 Cuid[2];                       /* set once and shared by all */
120 int rxkad_EpochWasSet = 0;              /* TRUE => we called rx_SetEpoch */
121
122 /* allocate a new connetion ID in place */
123 rxkad_AllocCID(aobj, aconn)
124   struct rx_securityClass *aobj;
125   struct rx_connection *aconn;
126 {
127     struct rxkad_cprivate *tcp;
128     struct rxkad_cidgen tgen;
129     static afs_int32 counter = 0;               /* not used anymore */
130
131     LOCK_CUID
132     if (Cuid[0] == 0) {
133         afs_uint32 xor[2];
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++);
139 #ifdef KERNEL
140         tgen.random1 = afs_random() & 0x7fffffff;       /* was "80000" */
141         tgen.random2 = afs_random() & 0x7fffffff;       /* was "htonl(100)" */
142 #else
143         tgen.random1 = htonl(getpid());
144         tgen.random2 = htonl(100);
145 #endif
146         if (aobj) {
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);
152         } else {
153             /* Create a session key so that we can encrypt it */
154
155         }
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 */
161         rxkad_EpochWasSet++;
162     }
163
164     if (!aconn) {
165         UNLOCK_CUID
166         return 0;
167     }
168     aconn->epoch = Cuid[0];
169     aconn->cid = Cuid[1];
170     Cuid[1] += 1<<RX_CIDSHIFT;
171     UNLOCK_CUID
172     return 0;
173 }
174
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. */
178
179 struct rx_securityClass *
180 rxkad_NewClientSecurityObject(level, sessionkey, kvno, ticketLen, ticket)
181   rxkad_level      level;
182   struct ktc_encryptionKey *sessionkey;
183   afs_int32                kvno;
184   int              ticketLen;
185   char            *ticket;
186 {   struct rx_securityClass *tsc;
187     struct rxkad_cprivate   *tcp;
188     int                      code;
189     int                      size;
190
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;
196
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);
209
210     LOCK_RXKAD_STATS
211     rxkad_stats_clientObjects++;
212     UNLOCK_RXKAD_STATS
213     return tsc;
214 }
215
216 /* client: respond to a challenge packet */
217
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;
223     char *tp;
224     int   v2;                           /* whether server is old style or v2 */
225     afs_int32  challengeID;
226     rxkad_level level;
227     char *response;
228     int   responseSize, missing;
229     struct rxkad_v2ChallengeResponse  r_v2;
230     struct rxkad_oldChallengeResponse r_old;
231
232     tcp = (struct rxkad_cprivate *) aobj->privateData;
233
234     if (!(tcp->type & rxkad_client)) return RXKADINCONSISTENCY;
235
236     v2 = (rx_Contiguous(apacket) > sizeof(struct rxkad_oldChallenge));
237     tp = rx_DataOf(apacket);
238
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);
253     }
254
255     if (level > tcp->level) return RXKADLEVELFAIL;
256     LOCK_RXKAD_STATS
257     rxkad_stats.challenges[rxkad_LevelIndex(tcp->level)]++;
258     UNLOCK_RXKAD_STATS
259
260     if (v2) {
261         int i;
262         afs_uint32 xor[2];
263         bzero ((void *)&r_v2, sizeof(r_v2));
264         r_v2.version = htonl(RXKAD_CHALLENGE_PROTOCOL_VERSION);
265         r_v2.spare   = 0;
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]);
271         }
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);
282     } else {
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);
291     }
292
293     if (RX_MAX_PACKET_DATA_SIZE < responseSize + tcp->ticketLen)
294         return RXKADPACKETSHORT;        /* not enough space */
295
296     rx_computelen(apacket, missing);
297     missing = responseSize + tcp->ticketLen - missing;
298     if (missing > 0) 
299        if (rxi_AllocDataBuf(apacket, missing) > 0)
300           return RXKADPACKETSHORT;      /* not enough space */
301
302     /* copy response and ticket into packet */
303     rx_packetwrite(apacket, 0, responseSize, response);
304     rx_packetwrite(apacket, responseSize, tcp->ticketLen, tcp->ticket);
305
306     rx_SetDataSize (apacket, responseSize + tcp->ticketLen);
307     return 0;
308 }
309
310
311 rxkad_ResetState()
312 {
313     LOCK_CUID
314     Cuid[0] = 0;
315     rxkad_EpochWasSet=0;
316     UNLOCK_CUID
317 }