Tidy up UKERNEL includes
[openafs.git] / src / rxkad / ticket5.c
1 /*
2  * Copyright (c) 1995, 1996, 1997, 2002 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.
12  * 
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.
16  * 
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.
20  * 
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.
32  */
33 /*
34  * Copyright 1992, 2002 by the Massachusetts Institute of Technology.
35  * All Rights Reserved.
36  *
37  * Export of this software from the United States of America may
38  *   require a specific license from the United States Government.
39  *   It is the responsibility of any person or organization contemplating
40  *   export to obtain such a license before exporting.
41  * 
42  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
43  * distribute this software and its documentation for any purpose and
44  * without fee is hereby granted, provided that the above copyright
45  * notice appear in all copies and that both that copyright notice and
46  * this permission notice appear in supporting documentation, and that
47  * the name of M.I.T. not be used in advertising or publicity pertaining
48  * to distribution of the software without specific, written prior
49  * permission.  Furthermore if you modify this software you must label
50  * your software as modified software and not distribute it in such a
51  * fashion that it might be confused with the original M.I.T. software.
52  * M.I.T. makes no representations about the suitability of
53  * this software for any purpose.  It is provided "as is" without express
54  * or implied warranty.
55  */
56
57 #include <afsconfig.h>
58 #include <afs/param.h>
59
60 #ifdef IGNORE_SOME_GCC_WARNINGS
61 # pragma GCC diagnostic warning "-Wimplicit-function-declaration"
62 #endif
63
64 #include <afs/stds.h>
65 #include <sys/types.h>
66 #ifdef AFS_NT40_ENV
67 #include <winsock2.h>
68 #else
69 #include <netinet/in.h>
70 #endif
71 #include <string.h>
72 #include <rx/xdr.h>
73 #include <rx/rx.h>
74 #include "lifetimes.h"
75 #include "rxkad.h"
76
77 #include "v5gen-rewrite.h"
78 #include "asn1-common.h"
79 #include "der.h"
80 #include "v5gen.h"
81 #include "v5der.c"
82 #include "v5gen.c"
83 #include "md4.h"
84 #include "md5.h"
85
86 /*
87  * Principal conversion Taken from src/lib/krb5/krb/conv_princ from MIT Kerberos.  If you
88  * find a need to change the services here, please consider opening a
89  * bug with MIT by sending mail to krb5-bugs@mit.edu.
90  */
91
92 extern afs_int32 des_cbc_encrypt(void * in, void * out,
93                                  register afs_int32 length,
94                                  des_key_schedule key, des_cblock *iv,
95                                  int encrypt);
96 extern int des_key_sched(register des_cblock k, des_key_schedule schedule);
97
98 struct krb_convert {
99     char *v4_str;
100     char *v5_str;
101     unsigned int flags;
102     unsigned int len;
103 };
104
105 #define DO_REALM_CONVERSION 0x00000001
106
107 /*
108  * Kadmin doesn't do realm conversion because it's currently
109  * kadmin/REALM.NAME.  Zephyr doesn't because it's just zephyr/zephyr.
110  *
111  * "Realm conversion" is a bit of a misnomer; really, the v5 name is
112  * using a FQDN or something that looks like it, where the v4 name is
113  * just using the first label.  Sometimes that second principal name
114  * component is a hostname, sometimes the realm name, sometimes it's
115  * neither.
116  *
117  * This list should probably be more configurable, and more than
118  * likely on a per-realm basis, so locally-defined services can be
119  * added, or not.
120  */
121 static const struct krb_convert sconv_list[] = {
122     /* Realm conversion, Change service name */
123 #define RC(V5NAME,V4NAME) { V5NAME, V4NAME, DO_REALM_CONVERSION, sizeof(V5NAME)-1 }
124     /* Realm conversion */
125 #define R(NAME)         { NAME, NAME, DO_REALM_CONVERSION, sizeof(NAME)-1 }
126     /* No Realm conversion */
127 #define NR(NAME)        { NAME, NAME, 0, sizeof(NAME)-1 }
128
129     NR("kadmin"),
130     RC("rcmd", "host"),
131     R("discuss"),
132     R("rvdsrv"),
133     R("sample"),
134     R("olc"),
135     R("pop"),
136     R("sis"),
137     R("rfs"),
138     R("imap"),
139     R("ftp"),
140     R("ecat"),
141     R("daemon"),
142     R("gnats"),
143     R("moira"),
144     R("prms"),
145     R("mandarin"),
146     R("register"),
147     R("changepw"),
148     R("sms"),
149     R("afpserver"),
150     R("gdss"),
151     R("news"),
152     R("abs"),
153     R("nfs"),
154     R("tftp"),
155     NR("zephyr"),
156     R("http"),
157     R("khttp"),
158     R("pgpsigner"),
159     R("irc"),
160     R("mandarin-agent"),
161     R("write"),
162     R("palladium"),
163     R("imap"),
164     R("smtp"),
165     R("lmtp"),
166     R("ldap"),
167     R("acap"),
168     R("argus"),
169     R("mupdate"),
170     R("argus"),
171     {0, 0, 0, 0},
172 #undef R
173 #undef RC
174 #undef NR
175 };
176
177 static int
178   krb5_des_decrypt(struct ktc_encryptionKey *, int, void *, size_t, void *,
179                    size_t *);
180
181
182
183
184 int
185 tkt_DecodeTicket5(char *ticket, afs_int32 ticket_len,
186                   int (*get_key) (void *, int, struct ktc_encryptionKey *),
187                   char *get_key_rock, int serv_kvno, char *name, char *inst,
188                   char *cell, struct ktc_encryptionKey *session_key, afs_int32 * host,
189                   afs_uint32 * start, afs_uint32 * end, afs_int32 disableCheckdot)
190 {
191     char plain[MAXKRB5TICKETLEN];
192     struct ktc_encryptionKey serv_key;
193     Ticket t5;                  /* Must free */
194     EncTicketPart decr_part;    /* Must free */
195     int code;
196     size_t siz, plainsiz;
197     int v5_serv_kvno;
198     char *v5_comp0, *v5_comp1, *c;
199     const struct krb_convert *p;
200
201     memset(&t5, 0, sizeof(t5));
202     memset(&decr_part, 0, sizeof(decr_part));
203
204     *host = 0;
205
206     if (ticket_len == 0)
207         return RXKADBADTICKET;  /* no ticket */
208
209     if (serv_kvno == RXKAD_TKT_TYPE_KERBEROS_V5) {
210         code = decode_Ticket((unsigned char *)ticket, ticket_len, &t5, &siz);
211         if (code != 0)
212             goto cleanup;
213
214         if (t5.tkt_vno != 5)
215             goto bad_ticket;
216     } else {
217         code = decode_EncryptedData((unsigned char *)ticket, ticket_len, &t5.enc_part, &siz);
218         if (code != 0)
219             goto cleanup;
220     }
221
222     /* If kvno is null, it's probably not included because it was kvno==0 
223      * in the ticket */
224     if (t5.enc_part.kvno == NULL) {
225         v5_serv_kvno = 0;
226     } else {
227         v5_serv_kvno = *t5.enc_part.kvno;
228     }
229
230     /* Check that the key type really fit into 8 bytes */
231     switch (t5.enc_part.etype) {
232     case ETYPE_DES_CBC_CRC:
233     case ETYPE_DES_CBC_MD4:
234     case ETYPE_DES_CBC_MD5:
235         break;
236     default:
237         goto unknown_key;
238     }
239
240     /* check ticket */
241     if (t5.enc_part.cipher.length > sizeof(plain)
242         || t5.enc_part.cipher.length % 8 != 0)
243         goto bad_ticket;
244
245     code = (*get_key) (get_key_rock, v5_serv_kvno, &serv_key);
246     if (code)
247         goto unknown_key;
248
249     /* Decrypt data here, save in plain, assume it will shrink */
250     code =
251         krb5_des_decrypt(&serv_key, t5.enc_part.etype,
252                          t5.enc_part.cipher.data, t5.enc_part.cipher.length,
253                          plain, &plainsiz);
254     if (code != 0)
255         goto bad_ticket;
256
257     /* Decode ticket */
258     code = decode_EncTicketPart((unsigned char *)plain, plainsiz, &decr_part, &siz);
259     if (code != 0)
260         goto bad_ticket;
261
262     /* Extract realm and principal */
263     strncpy(cell, decr_part.crealm, MAXKTCNAMELEN);
264     cell[MAXKTCNAMELEN - 1] = '\0';
265     inst[0] = '\0';
266     switch (decr_part.cname.name_string.len) {
267     case 2:
268         v5_comp0 = decr_part.cname.name_string.val[0];
269         v5_comp1 = decr_part.cname.name_string.val[1];
270         p = sconv_list;
271         while (p->v4_str) {
272             if (strcmp(p->v5_str, v5_comp0) == 0) {
273                 /*
274                  * It is, so set the new name now, and chop off
275                  * instance's domain name if requested.
276                  */
277                 strncpy(name, p->v4_str, MAXKTCNAMELEN);
278                 name[MAXKTCNAMELEN - 1] = '\0';
279                 if (p->flags & DO_REALM_CONVERSION) {
280                     c = strchr(v5_comp1, '.');
281                     if (!c || (c - v5_comp1) >= MAXKTCNAMELEN - 1)
282                         goto bad_ticket;
283                     strncpy(inst, v5_comp1, c - v5_comp1);
284                     inst[c - v5_comp1] = '\0';
285                 }
286                 break;
287             }
288             p++;
289         }
290
291         if (!p->v4_str) {
292             strncpy(inst, decr_part.cname.name_string.val[1], MAXKTCNAMELEN);
293             inst[MAXKTCNAMELEN - 1] = '\0';
294             strncpy(name, decr_part.cname.name_string.val[0], MAXKTCNAMELEN);
295             name[MAXKTCNAMELEN - 1] = '\0';
296         }
297         break;
298     case 1:
299         strncpy(name, decr_part.cname.name_string.val[0], MAXKTCNAMELEN);
300         name[MAXKTCNAMELEN - 1] = '\0';
301         break;
302     default:
303         goto bad_ticket;
304     }
305
306     if (!disableCheckdot) {
307         /* 
308          * If the first part of the name_string contains a dot, punt since
309          * then we can't see the diffrence between the kerberos 5
310          * principals foo.root and foo/root later in the fileserver.
311          */
312         if (strchr(decr_part.cname.name_string.val[0], '.') != NULL)
313             goto bad_ticket;
314     }
315
316     /* Verify that decr_part.key is of right type */
317     switch (decr_part.key.keytype) {
318     case ETYPE_DES_CBC_CRC:
319     case ETYPE_DES_CBC_MD4:
320     case ETYPE_DES_CBC_MD5:
321         break;
322     default:
323         goto bad_ticket;
324     }
325
326     if (decr_part.key.keyvalue.length != 8)
327         goto bad_ticket;
328
329     /* Extract session key */
330     memcpy(session_key, decr_part.key.keyvalue.data, 8);
331
332     /* Check lifetimes and host addresses, flags etc */
333     {
334         time_t now = time(0);   /* Use fast time package instead??? */
335         *start = decr_part.authtime;
336         if (decr_part.starttime)
337             *start = *decr_part.starttime;
338 #if 0
339         if (*start - now > CLOCK_SKEW || decr_part.flags.invalid)
340             goto no_auth;
341 #else
342         if (decr_part.flags.invalid)
343             goto no_auth;
344 #endif
345         if (now > decr_part.endtime)
346             goto tkt_expired;
347         *end = decr_part.endtime;
348     }
349
350   cleanup:
351     if (serv_kvno == RXKAD_TKT_TYPE_KERBEROS_V5)
352         free_Ticket(&t5);
353     else
354         free_EncryptedData(&t5.enc_part);
355     free_EncTicketPart(&decr_part);
356     memset(&serv_key, 0, sizeof(serv_key));
357     return code;
358
359   unknown_key:
360     code = RXKADUNKNOWNKEY;
361     goto cleanup;
362   no_auth:
363     code = RXKADNOAUTH;
364     goto cleanup;
365   tkt_expired:
366     code = RXKADEXPIRED;
367     goto cleanup;
368   bad_ticket:
369     code = RXKADBADTICKET;
370     goto cleanup;
371
372 }
373
374 static int
375 verify_checksum_md4(void *data, size_t len,
376                     void *cksum, size_t cksumsz,
377                     struct ktc_encryptionKey *key)
378 {
379     MD4_CTX md4;
380     unsigned char tmp[16];
381
382     MD4_Init(&md4);
383     MD4_Update(&md4, data, len);
384     MD4_Final(tmp, &md4);
385
386     if (memcmp(tmp, cksum, cksumsz) != 0)
387         return 1;
388     return 0;
389 }
390
391 static int
392 verify_checksum_md5(void *data, size_t len,
393                     void *cksum, size_t cksumsz,
394                     struct ktc_encryptionKey *key)
395 {
396     MD5_CTX md5;
397     unsigned char tmp[16];
398
399     MD5_Init(&md5);
400     MD5_Update(&md5, data, len);
401     MD5_Final(tmp, &md5);
402
403     if (memcmp(tmp, cksum, cksumsz) != 0)
404         return 1;
405     return 0;
406 }
407
408 static int
409 verify_checksum_crc(void *data, size_t len, void *cksum, size_t cksumsz,
410                     struct ktc_encryptionKey *key)
411 {
412     afs_uint32 crc;
413     char r[4];
414
415     _rxkad_crc_init_table();
416     crc = _rxkad_crc_update(data, len, 0);
417     r[0] = crc & 0xff;
418     r[1] = (crc >> 8) & 0xff;
419     r[2] = (crc >> 16) & 0xff;
420     r[3] = (crc >> 24) & 0xff;
421
422     if (memcmp(cksum, r, 4) != 0)
423         return 1;
424     return 0;
425 }
426
427
428 static int
429 krb5_des_decrypt(struct ktc_encryptionKey *key, int etype, void *in,
430                  size_t insz, void *out, size_t * outsz)
431 {
432     int (*cksum_func) (void *, size_t, void *, size_t,
433                        struct ktc_encryptionKey *);
434     des_cblock ivec;
435     des_key_schedule s;
436     char cksum[24];
437     size_t cksumsz;
438     int ret = 1;                /* failure */
439
440     cksum_func = NULL;
441
442     des_key_sched(ktc_to_cblock(key), (struct des_ks_struct *)&s);
443
444 #define CONFOUNDERSZ 8
445
446     switch (etype) {
447     case ETYPE_DES_CBC_CRC:
448         memcpy(&ivec, key, sizeof(ivec));
449         cksumsz = 4;
450         cksum_func = verify_checksum_crc;
451         break;
452     case ETYPE_DES_CBC_MD4:
453         memset(&ivec, 0, sizeof(ivec));
454         cksumsz = 16;
455         cksum_func = verify_checksum_md4;
456         break;
457     case ETYPE_DES_CBC_MD5:
458         memset(&ivec, 0, sizeof(ivec));
459         cksumsz = 16;
460         cksum_func = verify_checksum_md5;
461         break;
462     default:
463         abort();
464     }
465
466     des_cbc_encrypt(in, out, insz, s, &ivec, 0);
467
468     memcpy(cksum, (char *)out + CONFOUNDERSZ, cksumsz);
469     memset((char *)out + CONFOUNDERSZ, 0, cksumsz);
470
471     if (cksum_func)
472         ret = (*cksum_func) (out, insz, cksum, cksumsz, key);
473
474     *outsz = insz - CONFOUNDERSZ - cksumsz;
475     memmove(out, (char *)out + CONFOUNDERSZ + cksumsz, *outsz);
476
477     return ret;
478 }