Use rfc3961 library to decrypt kerberos 5 tickets
[openafs.git] / src / rxkad / rxkad_server.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 server-only routines. */
12
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16 #include <afs/stds.h>
17
18 #include <roken.h>
19
20 #if (defined(AFS_AIX_ENV) && defined(KERNEL) && !defined(UKERNEL)) || defined(AFS_AUX_ENV) || defined(AFS_SUN5_ENV)
21 #include <sys/systm.h>
22 #endif
23
24 #include <afs/opr.h>
25 #include <rx/rx.h>
26 #include <rx/xdr.h>
27 #include <rx/rx_packet.h>
28 #include <afs/afsutil.h>
29
30 #include "stats.h"
31 #include "private_data.h"
32 #define XPRT_RXKAD_SERVER
33
34 /*
35  * This can be set to allow alternate ticket decoding.
36  * Currently only used by the AFS/DFS protocol translator to recognize
37  * Kerberos V5 tickets. The actual code to do that is provided externally.
38  */
39 afs_int32(*rxkad_AlternateTicketDecoder) (afs_int32, char *, afs_int32,
40                                           char *, char *, char *,
41                                           struct ktc_encryptionKey *,
42                                           afs_int32 *, afs_uint32 *,
43                                           afs_uint32 *);
44
45 static struct rx_securityOps rxkad_server_ops = {
46     rxkad_Close,
47     rxkad_NewConnection,
48     rxkad_PreparePacket,        /* once per packet creation */
49     0,                          /* send packet (once per retrans) */
50     rxkad_CheckAuthentication,
51     rxkad_CreateChallenge,
52     rxkad_GetChallenge,
53     0,
54     rxkad_CheckResponse,
55     rxkad_CheckPacket,          /* check data packet */
56     rxkad_DestroyConnection,
57     rxkad_GetStats,
58     rxkad_SetConfiguration,
59     0,                          /* spare 2 */
60     0,                          /* spare 3 */
61 };
62 extern afs_uint32 rx_MyMaxSendSize;
63
64 /* Miscellaneous random number routines that use the fcrypt module and the
65  * timeofday. */
66
67 static fc_KeySchedule random_int32_schedule;
68
69 #ifdef AFS_PTHREAD_ENV
70 /*
71  * This mutex protects the following global variables:
72  * random_int32_schedule
73  * seed
74  */
75
76 pthread_mutex_t rxkad_random_mutex
77 #ifdef PTHREAD_MUTEX_INITIALIZER
78 = PTHREAD_MUTEX_INITIALIZER
79 #endif
80 ;
81 #define LOCK_RM opr_Verify(pthread_mutex_lock(&rxkad_random_mutex)==0)
82 #define UNLOCK_RM opr_Verify(pthread_mutex_unlock(&rxkad_random_mutex)==0)
83 #else
84 #define LOCK_RM
85 #define UNLOCK_RM
86 #endif /* AFS_PTHREAD_ENV */
87
88 static void
89 init_random_int32(void)
90 {
91     struct timeval key;
92
93     gettimeofday(&key, NULL);
94     LOCK_RM;
95     fc_keysched((struct ktc_encryptionKey*)&key, random_int32_schedule);
96     UNLOCK_RM;
97 }
98
99 static afs_int32
100 get_random_int32(void)
101 {
102     static struct timeval seed;
103     afs_int32 rc;
104
105     LOCK_RM;
106     fc_ecb_encrypt(&seed, &seed, random_int32_schedule, ENCRYPT);
107     rc = seed.tv_sec;
108     UNLOCK_RM;
109     return rc;
110 }
111
112 /* Called with four parameters.  The first is the level of encryption, as
113    defined in the rxkad.h file.  The second and third are a rock and a
114    procedure that is called with the key version number that accompanies the
115    ticket and returns a pointer to the server's decryption key.  The fourth
116    argument, if not NULL, is a pointer to a function that will be called for
117    every new connection with the name, instance and cell of the client.  The
118    routine should return zero if the user is NOT acceptible to the server.  If
119    this routine is not supplied, the server can call rxkad_GetServerInfo with
120    the rx connection pointer passed to the RPC routine to obtain information
121    about the client. */
122
123 /*
124   rxkad_level      level;               * minimum level *
125   char            *get_key_rock;        * rock for get_key implementor *
126   int            (*get_key)();          * passed kvno & addr(key) to fill *
127   int            (*user_ok)();          * passed name, inst, cell => bool *
128 */
129
130 struct rx_securityClass *
131 rxkad_NewServerSecurityObject(rxkad_level level, void *get_key_rock,
132                               int (*get_key) (void *get_key_rock, int kvno,
133                                               struct ktc_encryptionKey *
134                                               serverKey),
135                               int (*user_ok) (char *name, char *instance,
136                                               char *cell, afs_int32 kvno))
137 {
138     struct rx_securityClass *tsc;
139     struct rxkad_sprivate *tsp;
140     int size;
141
142     rxkad_Init();
143
144     if (!get_key)
145         return 0;
146
147     size = sizeof(struct rx_securityClass);
148     tsc = rxi_Alloc(size);
149     memset(tsc, 0, size);
150     tsc->refCount = 1;          /* caller has one reference */
151     tsc->ops = &rxkad_server_ops;
152     size = sizeof(struct rxkad_sprivate);
153     tsp = rxi_Alloc(size);
154     memset(tsp, 0, size);
155     tsc->privateData = (char *)tsp;
156
157     tsp->type |= rxkad_server;  /* so can identify later */
158     tsp->level = level;         /* level of encryption */
159     tsp->get_key_rock = get_key_rock;
160     tsp->get_key = get_key;     /* to get server ticket */
161     tsp->user_ok = user_ok;     /* to inform server of client id. */
162     init_random_int32();
163
164     INC_RXKAD_STATS(serverObjects);
165     return tsc;
166 }
167
168 struct rx_securityClass *
169 rxkad_NewKrb5ServerSecurityObject(rxkad_level level, void *get_key_rock,
170                                   int (*get_key) (void *get_key_rock, int kvno,
171                                                   struct ktc_encryptionKey *
172                                                   serverKey),
173                                   rxkad_get_key_enctype_func get_key_enctype,
174                                   int (*user_ok) (char *name, char *instance,
175                                                   char *cell, afs_int32 kvno)
176 ) {
177     struct rx_securityClass *tsc;
178     struct rxkad_sprivate *tsp;
179     tsc = rxkad_NewServerSecurityObject(level, get_key_rock, get_key, user_ok);
180     tsp = (struct rxkad_sprivate *)tsc->privateData;
181     tsp->get_key_enctype = get_key_enctype;
182     return tsc;
183 }
184
185 /* server: called to tell if a connection authenticated properly */
186
187 int
188 rxkad_CheckAuthentication(struct rx_securityClass *aobj,
189                           struct rx_connection *aconn)
190 {
191     struct rxkad_sconn *sconn = rx_GetSecurityData(aconn);
192
193     /* first make sure the object exists */
194     if (!sconn)
195         return RXKADINCONSISTENCY;
196
197     return !sconn->authenticated;
198 }
199
200 /* server: put the current challenge in the connection structure for later use
201    by packet sender */
202
203 int
204 rxkad_CreateChallenge(struct rx_securityClass *aobj,
205                       struct rx_connection *aconn)
206 {
207     struct rxkad_sconn *sconn = rx_GetSecurityData(aconn);
208     struct rxkad_sprivate *tsp;
209
210     sconn->challengeID = get_random_int32();
211     sconn->authenticated = 0;   /* conn unauth. 'til we hear back */
212     /* initialize level from object's minimum acceptable level */
213     tsp = (struct rxkad_sprivate *)aobj->privateData;
214     sconn->level = tsp->level;
215     return 0;
216 }
217
218 /* server: fill in a challenge in the packet */
219
220 int
221 rxkad_GetChallenge(struct rx_securityClass *aobj, struct rx_connection *aconn,
222                    struct rx_packet *apacket)
223 {
224     struct rxkad_sconn *sconn = rx_GetSecurityData(aconn);
225     char *challenge;
226     int challengeSize;
227     struct rxkad_v2Challenge c_v2;      /* version 2 */
228     struct rxkad_oldChallenge c_old;    /* old style */
229
230     if (rx_IsUsingPktCksum(aconn))
231         sconn->cksumSeen = 1;
232
233     if (sconn->cksumSeen) {
234         memset(&c_v2, 0, sizeof(c_v2));
235         c_v2.version = htonl(RXKAD_CHALLENGE_PROTOCOL_VERSION);
236         c_v2.challengeID = htonl(sconn->challengeID);
237         c_v2.level = htonl((afs_int32) sconn->level);
238         c_v2.spare = 0;
239         challenge = (char *)&c_v2;
240         challengeSize = sizeof(c_v2);
241     } else {
242         memset(&c_old, 0, sizeof(c_old));
243         c_old.challengeID = htonl(sconn->challengeID);
244         c_old.level = htonl((afs_int32) sconn->level);
245         challenge = (char *)&c_old;
246         challengeSize = sizeof(c_old);
247     }
248     if (rx_MyMaxSendSize < challengeSize)
249         return RXKADPACKETSHORT;        /* not enough space */
250
251     rx_packetwrite(apacket, 0, challengeSize, challenge);
252     rx_SetDataSize(apacket, challengeSize);
253     sconn->tried = 1;
254     INC_RXKAD_STATS(challengesSent);
255     return 0;
256 }
257
258 /* server: process a response to a challenge packet */
259 /* XXX this does some copying of data in and out of the packet, but I'll bet it
260  * could just do it in place, especially if I used rx_Pullup...
261  */
262 int
263 rxkad_CheckResponse(struct rx_securityClass *aobj,
264                     struct rx_connection *aconn, struct rx_packet *apacket)
265 {
266     struct rxkad_sconn *sconn;
267     struct rxkad_sprivate *tsp;
268     struct ktc_encryptionKey serverKey;
269     struct rxkad_oldChallengeResponse oldr;     /* response format */
270     struct rxkad_v2ChallengeResponse v2r;
271     afs_int32 tlen;             /* ticket len */
272     afs_int32 kvno;             /* key version of ticket */
273     char tix[MAXKTCTICKETLEN];
274     afs_int32 incChallengeID;
275     rxkad_level level;
276     int code;
277     /* ticket contents */
278     struct ktc_principal client;
279     struct ktc_encryptionKey sessionkey;
280     afs_int32 host;
281     afs_uint32 start;
282     afs_uint32 end;
283     unsigned int pos;
284     struct rxkad_serverinfo *rock;
285
286     sconn = rx_GetSecurityData(aconn);
287     tsp = (struct rxkad_sprivate *)aobj->privateData;
288
289     if (sconn->cksumSeen) {
290         /* expect v2 response, leave fields in v2r in network order for cksum
291          * computation which follows decryption. */
292         if (rx_GetDataSize(apacket) < sizeof(v2r))
293             return RXKADPACKETSHORT;
294         rx_packetread(apacket, 0, sizeof(v2r), &v2r);
295         pos = sizeof(v2r);
296         /* version == 2 */
297         /* ignore spare */
298         kvno = ntohl(v2r.kvno);
299         tlen = ntohl(v2r.ticketLen);
300         if (rx_GetDataSize(apacket) < sizeof(v2r) + tlen)
301             return RXKADPACKETSHORT;
302     } else {
303         /* expect old format response */
304         if (rx_GetDataSize(apacket) < sizeof(oldr))
305             return RXKADPACKETSHORT;
306         rx_packetread(apacket, 0, sizeof(oldr), &oldr);
307         pos = sizeof(oldr);
308
309         kvno = ntohl(oldr.kvno);
310         tlen = ntohl(oldr.ticketLen);
311         if (rx_GetDataSize(apacket) != sizeof(oldr) + tlen)
312             return RXKADPACKETSHORT;
313     }
314     if ((tlen < MINKTCTICKETLEN) || (tlen > MAXKTCTICKETLEN))
315         return RXKADTICKETLEN;
316
317     rx_packetread(apacket, pos, tlen, tix);     /* get ticket */
318
319     /*
320      * We allow the ticket to be optionally decoded by an alternate
321      * ticket decoder, if the function variable
322      * rxkad_AlternateTicketDecoder is set. That function should
323      * return a code of -1 if it wants the ticket to be decoded by
324      * the standard decoder.
325      */
326     if (rxkad_AlternateTicketDecoder) {
327         code =
328             rxkad_AlternateTicketDecoder(kvno, tix, tlen, client.name,
329                                          client.instance, client.cell,
330                                          &sessionkey, &host, &start, &end);
331         if (code && code != -1) {
332             return code;
333         }
334     } else {
335         code = -1;              /* No alternate ticket decoder present */
336     }
337
338     /*
339      * If the alternate decoder is not present, or returns -1, then
340      * assume the ticket is of the default style.
341      */
342     if (code == -1 && ((kvno == RXKAD_TKT_TYPE_KERBEROS_V5)
343         || (kvno == RXKAD_TKT_TYPE_KERBEROS_V5_ENCPART_ONLY))) {
344         code =
345             tkt_DecodeTicket5(tix, tlen, tsp->get_key, tsp->get_key_enctype,
346                               tsp->get_key_rock, kvno, client.name,
347                               client.instance, client.cell,
348                               &sessionkey, &host, &start, &end,
349                               tsp->flags & RXS_CONFIG_FLAGS_DISABLE_DOTCHECK);
350         if (code)
351             return code;
352     }
353
354     /*
355      * If the alternate decoder/kerberos 5 decoder is not present, or
356      * returns -1, then assume the ticket is of the default style.
357      */
358     if (code == -1) {
359         /* get ticket's key */
360         code = (*tsp->get_key) (tsp->get_key_rock, kvno, &serverKey);
361         if (code)
362             return RXKADUNKNOWNKEY;     /* invalid kvno */
363         code =
364             tkt_DecodeTicket(tix, tlen, &serverKey, client.name,
365                              client.instance, client.cell, &sessionkey, &host,
366                              &start, &end);
367         if (code)
368             return code;
369     }
370     code = tkt_CheckTimes(start, end, time(0));
371     if (code == 0)
372         return RXKADNOAUTH;
373     else if (code == -1)
374         return RXKADEXPIRED;
375     else if (code < -1)
376         return RXKADBADTICKET;
377
378     code = fc_keysched(&sessionkey, sconn->keysched);
379     if (code)
380         return RXKADBADKEY;
381     memcpy(sconn->ivec, &sessionkey, sizeof(sconn->ivec));
382
383     if (sconn->cksumSeen) {
384         /* using v2 response */
385         afs_uint32 cksum;       /* observed cksum */
386         struct rxkad_endpoint endpoint; /* connections endpoint */
387         int i;
388         afs_uint32 xor[2];
389
390         memcpy(xor, sconn->ivec, 2 * sizeof(afs_int32));
391         fc_cbc_encrypt(&v2r.encrypted, &v2r.encrypted, sizeof(v2r.encrypted),
392                        sconn->keysched, xor, DECRYPT);
393         cksum = rxkad_CksumChallengeResponse(&v2r);
394         if (cksum != v2r.encrypted.endpoint.cksum)
395             return RXKADSEALEDINCON;
396         (void)rxkad_SetupEndpoint(aconn, &endpoint);
397         v2r.encrypted.endpoint.cksum = 0;
398         if (memcmp(&endpoint, &v2r.encrypted.endpoint, sizeof(endpoint)) != 0)
399             return RXKADSEALEDINCON;
400         for (i = 0; i < RX_MAXCALLS; i++) {
401             v2r.encrypted.callNumbers[i] =
402                 ntohl(v2r.encrypted.callNumbers[i]);
403             if (v2r.encrypted.callNumbers[i] < 0)
404                 return RXKADSEALEDINCON;
405         }
406
407         (void)rxi_SetCallNumberVector(aconn, v2r.encrypted.callNumbers);
408         incChallengeID = ntohl(v2r.encrypted.incChallengeID);
409         level = ntohl(v2r.encrypted.level);
410     } else {
411         /* expect old format response */
412         fc_ecb_encrypt(&oldr.encrypted, &oldr.encrypted, sconn->keysched,
413                        DECRYPT);
414         incChallengeID = ntohl(oldr.encrypted.incChallengeID);
415         level = ntohl(oldr.encrypted.level);
416     }
417     if (incChallengeID != sconn->challengeID + 1)
418         return RXKADOUTOFSEQUENCE;      /* replay attempt */
419     if ((level < sconn->level) || (level > rxkad_crypt))
420         return RXKADLEVELFAIL;
421     sconn->level = level;
422     rxkad_SetLevel(aconn, sconn->level);
423     INC_RXKAD_STATS(responses[rxkad_LevelIndex(sconn->level)]);
424     /* now compute endpoint-specific info used for computing 16 bit checksum */
425     rxkad_DeriveXORInfo(aconn, &sconn->keysched, (char *)sconn->ivec, (char *)sconn->preSeq);
426
427     /* otherwise things are ok */
428     sconn->expirationTime = end;
429     sconn->authenticated = 1;
430
431     if (tsp->user_ok) {
432         code = tsp->user_ok(client.name, client.instance, client.cell, kvno);
433         if (code)
434             return RXKADNOAUTH;
435     } else {                    /* save the info for later retreival */
436         int size = sizeof(struct rxkad_serverinfo);
437         rock = rxi_Alloc(size);
438         memset(rock, 0, size);
439         rock->kvno = kvno;
440         memcpy(&rock->client, &client, sizeof(rock->client));
441         sconn->rock = rock;
442     }
443     return 0;
444 }
445
446 /* return useful authentication info about a server-side connection */
447
448 afs_int32
449 rxkad_GetServerInfo(struct rx_connection * aconn, rxkad_level * level,
450                     afs_uint32 * expiration, char *name, char *instance,
451                     char *cell, afs_int32 * kvno)
452 {
453     struct rxkad_sconn *sconn;
454
455     sconn = rx_GetSecurityData(aconn);
456     if (sconn && sconn->authenticated && sconn->rock
457         && (time(0) < sconn->expirationTime)) {
458         if (level)
459             *level = sconn->level;
460         if (expiration)
461             *expiration = sconn->expirationTime;
462         if (name)
463             strcpy(name, sconn->rock->client.name);
464         if (instance)
465             strcpy(instance, sconn->rock->client.instance);
466         if (cell)
467             strcpy(cell, sconn->rock->client.cell);
468         if (kvno)
469             *kvno = sconn->rock->kvno;
470         return 0;
471     } else
472         return RXKADNOAUTH;
473 }
474
475 /* Set security object configuration variables */
476 afs_int32 rxkad_SetConfiguration(struct rx_securityClass *aobj,
477                                  struct rx_connection *aconn,
478                                  rx_securityConfigVariables atype,
479                                          void * avalue, void **currentValue)
480 {
481     struct rxkad_sprivate *private =
482     (struct rxkad_sprivate *) aobj->privateData;
483
484     switch (atype) {
485     case RXS_CONFIG_FLAGS:
486         if (currentValue) {
487             *((afs_uint32 *)currentValue) = private->flags;
488         } else {
489             private->flags = (intptr_t)avalue;
490         }
491         break;
492     default:
493         break;
494     }
495     return 0;
496 }