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