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