1961c7fa22f09b9f5c199175ee0c851bf12dd07f
[amitay/samba.git] / source4 / heimdal / lib / ntlm / ntlm.c
1 /*
2  * Copyright (c) 2006 - 2007 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 #include <config.h>
35
36 RCSID("$Id: ntlm.c 21317 2007-06-25 19:22:02Z lha $");
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <assert.h>
41 #include <string.h>
42 #include <ctype.h>
43 #include <errno.h>
44 #include <limits.h>
45
46 #include <krb5.h>
47 #include <roken.h>
48
49 #include "krb5-types.h"
50 #include "crypto-headers.h"
51
52 #include <heimntlm.h>
53
54
55 /*
56  * Source of NTLM information:
57  * http://davenport.sourceforge.net/ntlm.html
58  */
59
60
61 struct sec_buffer {
62     uint16_t length;
63     uint16_t allocated;
64     uint32_t offset;
65 };
66
67 static const unsigned char ntlmsigature[8] = "NTLMSSP\x00";
68
69 /*
70  *
71  */
72
73 #define CHECK(f, e)                                                     \
74     do { ret = f ; if (ret != (e)) { ret = EINVAL; goto out; } } while(0)
75
76 static void
77 _ntlm_free_buf(struct ntlm_buf *p)
78 {
79     if (p->data)
80         free(p->data);
81     p->data = NULL;
82     p->length = 0;
83 }
84     
85
86 static int
87 ascii2ucs2le(const char *string, int up, struct ntlm_buf *buf)
88 {
89     unsigned char *p;
90     size_t len, i;
91
92     len = strlen(string);
93     if (len / 2 > UINT_MAX)
94         return ERANGE;
95
96     buf->length = len * 2;
97     buf->data = malloc(buf->length);
98     if (buf->data == NULL && len != 0) {
99         _ntlm_free_buf(buf);
100         return ENOMEM;
101     }
102
103     p = buf->data;
104     for (i = 0; i < len; i++) {
105         unsigned char t = (unsigned char)string[i];
106         if (t & 0x80) {
107             _ntlm_free_buf(buf);
108             return EINVAL;
109         }
110         if (up)
111             t = toupper(t);
112         p[(i * 2) + 0] = t;
113         p[(i * 2) + 1] = 0;
114     }
115     return 0;
116 }
117
118 /*
119  *
120  */
121
122 static krb5_error_code
123 ret_sec_buffer(krb5_storage *sp, struct sec_buffer *buf)
124 {
125     krb5_error_code ret;
126     CHECK(krb5_ret_uint16(sp, &buf->length), 0);
127     CHECK(krb5_ret_uint16(sp, &buf->allocated), 0);
128     CHECK(krb5_ret_uint32(sp, &buf->offset), 0);
129 out:
130     return ret;
131 }
132
133 static krb5_error_code
134 store_sec_buffer(krb5_storage *sp, const struct sec_buffer *buf)
135 {
136     krb5_error_code ret;
137     CHECK(krb5_store_uint16(sp, buf->length), 0);
138     CHECK(krb5_store_uint16(sp, buf->allocated), 0);
139     CHECK(krb5_store_uint32(sp, buf->offset), 0);
140 out:
141     return ret;
142 }
143
144 /*
145  * Strings are either OEM or UNICODE. The later is encoded as ucs2 on
146  * wire, but using utf8 in memory.
147  */
148
149 static krb5_error_code
150 len_string(int ucs2, const char *s)
151 {
152     size_t len = strlen(s);
153     if (ucs2)
154         len *= 2;
155     return len;
156 }
157
158 static krb5_error_code
159 ret_string(krb5_storage *sp, int ucs2, struct sec_buffer *desc, char **s)
160 {
161     krb5_error_code ret;
162
163     *s = malloc(desc->length + 1);
164     CHECK(krb5_storage_seek(sp, desc->offset, SEEK_SET), desc->offset);
165     CHECK(krb5_storage_read(sp, *s, desc->length), desc->length);
166     (*s)[desc->length] = '\0';
167
168     if (ucs2) {
169         size_t i;
170         for (i = 0; i < desc->length / 2; i++) {
171             (*s)[i] = (*s)[i * 2];
172             if ((*s)[i * 2 + 1]) {
173                 free(*s);
174                 *s = NULL;
175                 return EINVAL;
176             }
177         }
178         (*s)[i] = '\0';
179     }
180     ret = 0;
181 out:
182     return ret;
183
184     return 0;
185 }
186
187 static krb5_error_code
188 put_string(krb5_storage *sp, int ucs2, const char *s)
189 {
190     krb5_error_code ret;
191     struct ntlm_buf buf;
192
193     if (ucs2) {
194         ret = ascii2ucs2le(s, 0, &buf);
195         if (ret)
196             return ret;
197     } else {
198         buf.data = rk_UNCONST(s);
199         buf.length = strlen(s);
200     }
201
202     CHECK(krb5_storage_write(sp, buf.data, buf.length), buf.length);
203     if (ucs2)
204         _ntlm_free_buf(&buf);
205     ret = 0;
206 out:
207     return ret;
208 }
209
210 /*
211  *
212  */
213
214 static krb5_error_code
215 ret_buf(krb5_storage *sp, struct sec_buffer *desc, struct ntlm_buf *buf)
216 {
217     krb5_error_code ret;
218
219     buf->data = malloc(desc->length);
220     buf->length = desc->length;
221     CHECK(krb5_storage_seek(sp, desc->offset, SEEK_SET), desc->offset);
222     CHECK(krb5_storage_read(sp, buf->data, buf->length), buf->length);
223     ret = 0;
224 out:
225     return ret;
226 }
227
228 static krb5_error_code
229 put_buf(krb5_storage *sp, struct ntlm_buf *buf)
230 {
231     krb5_error_code ret;
232     CHECK(krb5_storage_write(sp, buf->data, buf->length), buf->length);
233     ret = 0;
234 out:
235     return ret;
236 }
237
238 /*
239  *
240  */
241
242 void
243 heim_ntlm_free_targetinfo(struct ntlm_targetinfo *ti)
244 {
245     free(ti->servername);
246     free(ti->domainname);
247     free(ti->dnsdomainname);
248     free(ti->dnsservername);
249     memset(ti, 0, sizeof(*ti));
250 }
251
252 static int
253 encode_ti_blob(krb5_storage *out, uint16_t type, int ucs2, char *s)
254 {
255     krb5_error_code ret;
256     CHECK(krb5_store_uint16(out, type), 0);
257     CHECK(krb5_store_uint16(out, len_string(ucs2, s)), 0);
258     CHECK(put_string(out, ucs2, s), 0);
259 out:
260     return ret;
261 }
262
263 int
264 heim_ntlm_encode_targetinfo(struct ntlm_targetinfo *ti,
265                             int ucs2, 
266                             struct ntlm_buf *data)
267 {
268     krb5_error_code ret;
269     krb5_storage *out;
270
271     data->data = NULL;
272     data->length = 0;
273
274     out = krb5_storage_emem();
275     if (out == NULL)
276         return ENOMEM;
277
278     if (ti->servername)
279         CHECK(encode_ti_blob(out, 1, ucs2, ti->servername), 0);
280     if (ti->domainname)
281         CHECK(encode_ti_blob(out, 2, ucs2, ti->domainname), 0);
282     if (ti->dnsservername)
283         CHECK(encode_ti_blob(out, 3, ucs2, ti->dnsservername), 0);
284     if (ti->dnsdomainname)
285         CHECK(encode_ti_blob(out, 4, ucs2, ti->dnsdomainname), 0);
286
287     /* end tag */
288     CHECK(krb5_store_int16(out, 0), 0);
289     CHECK(krb5_store_int16(out, 0), 0);
290
291     {
292         krb5_data d;
293         ret = krb5_storage_to_data(out, &d);
294         data->data = d.data;
295         data->length = d.length;
296     }
297 out:
298     krb5_storage_free(out);
299     return ret;
300 }
301
302 int
303 heim_ntlm_decode_targetinfo(struct ntlm_buf *data, int ucs2,
304                             struct ntlm_targetinfo *ti)
305 {
306     memset(ti, 0, sizeof(*ti));
307     return 0;
308 }
309
310 /*
311  * encoder/decoder type1 messages
312  */
313
314 void
315 heim_ntlm_free_type1(struct ntlm_type1 *data)
316 {
317     if (data->domain)
318         free(data->domain);
319     if (data->hostname)
320         free(data->hostname);
321     memset(data, 0, sizeof(*data));
322 }
323
324 int
325 heim_ntlm_decode_type1(const struct ntlm_buf *buf, struct ntlm_type1 *data)
326 {
327     krb5_error_code ret;
328     unsigned char sig[8];
329     uint32_t type;
330     struct sec_buffer domain, hostname;
331     krb5_storage *in;
332     
333     memset(data, 0, sizeof(*data));
334
335     in = krb5_storage_from_readonly_mem(buf->data, buf->length);
336     if (in == NULL) {
337         ret = EINVAL;
338         goto out;
339     }
340     krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
341
342     CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig));
343     CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0);
344     CHECK(krb5_ret_uint32(in, &type), 0);
345     CHECK(type, 1);
346     CHECK(krb5_ret_uint32(in, &data->flags), 0);
347     if (data->flags & NTLM_SUPPLIED_DOMAIN)
348         CHECK(ret_sec_buffer(in, &domain), 0);
349     if (data->flags & NTLM_SUPPLIED_WORKSTAION)
350         CHECK(ret_sec_buffer(in, &hostname), 0);
351 #if 0
352     if (domain.offset > 32) {
353         CHECK(krb5_ret_uint32(in, &data->os[0]), 0);
354         CHECK(krb5_ret_uint32(in, &data->os[1]), 0);
355     }
356 #endif
357     if (data->flags & NTLM_SUPPLIED_DOMAIN)
358         CHECK(ret_string(in, 0, &domain, &data->domain), 0);
359     if (data->flags & NTLM_SUPPLIED_WORKSTAION)
360         CHECK(ret_string(in, 0, &hostname, &data->hostname), 0);
361
362 out:
363     krb5_storage_free(in);
364     if (ret)
365         heim_ntlm_free_type1(data);
366
367     return ret;
368 }
369
370 int
371 heim_ntlm_encode_type1(const struct ntlm_type1 *type1, struct ntlm_buf *data)
372 {
373     krb5_error_code ret;
374     struct sec_buffer domain, hostname;
375     krb5_storage *out;
376     uint32_t base, flags;
377     
378     flags = type1->flags;
379     base = 16;
380
381     if (type1->domain) {
382         base += 8;
383         flags |= NTLM_SUPPLIED_DOMAIN;
384     }
385     if (type1->hostname) {
386         base += 8;
387         flags |= NTLM_SUPPLIED_WORKSTAION;
388     }
389     if (type1->os[0])
390         base += 8;
391
392     if (type1->domain) {
393         domain.offset = base;
394         domain.length = len_string(0, type1->domain);
395         domain.allocated = domain.length;
396     }
397     if (type1->hostname) {
398         hostname.offset = domain.allocated + domain.offset;
399         hostname.length = len_string(0, type1->hostname);
400         hostname.allocated = hostname.length;
401     }
402
403     out = krb5_storage_emem();
404     if (out == NULL)
405         return ENOMEM;
406
407     krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
408     CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)), 
409           sizeof(ntlmsigature));
410     CHECK(krb5_store_uint32(out, 1), 0);
411     CHECK(krb5_store_uint32(out, flags), 0);
412     
413     if (type1->domain)
414         CHECK(store_sec_buffer(out, &domain), 0);
415     if (type1->hostname)
416         CHECK(store_sec_buffer(out, &hostname), 0);
417     if (type1->os[0]) {
418         CHECK(krb5_store_uint32(out, type1->os[0]), 0);
419         CHECK(krb5_store_uint32(out, type1->os[1]), 0);
420     }
421     if (type1->domain)
422         CHECK(put_string(out, 0, type1->domain), 0);
423     if (type1->hostname)
424         CHECK(put_string(out, 0, type1->hostname), 0);
425
426     {
427         krb5_data d;
428         ret = krb5_storage_to_data(out, &d);
429         data->data = d.data;
430         data->length = d.length;
431     }
432 out:
433     krb5_storage_free(out);
434
435     return ret;
436 }
437
438 /*
439  * encoder/decoder type 2 messages
440  */
441
442 void
443 heim_ntlm_free_type2(struct ntlm_type2 *data)
444 {
445     if (data->targetname)
446         free(data->targetname);
447     _ntlm_free_buf(&data->targetinfo);
448     memset(data, 0, sizeof(*data));
449 }
450
451 int
452 heim_ntlm_decode_type2(const struct ntlm_buf *buf, struct ntlm_type2 *type2)
453 {
454     krb5_error_code ret;
455     unsigned char sig[8];
456     uint32_t type, ctx[2];
457     struct sec_buffer targetname, targetinfo;
458     krb5_storage *in;
459     int ucs2 = 0;
460     
461     memset(type2, 0, sizeof(*type2));
462
463     in = krb5_storage_from_readonly_mem(buf->data, buf->length);
464     if (in == NULL) {
465         ret = EINVAL;
466         goto out;
467     }
468     krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
469
470     CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig));
471     CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0);
472     CHECK(krb5_ret_uint32(in, &type), 0);
473     CHECK(type, 2);
474
475     CHECK(ret_sec_buffer(in, &targetname), 0);
476     CHECK(krb5_ret_uint32(in, &type2->flags), 0);
477     if (type2->flags & NTLM_NEG_UNICODE)
478         ucs2 = 1;
479     CHECK(krb5_storage_read(in, type2->challange, sizeof(type2->challange)),
480           sizeof(type2->challange));
481     CHECK(krb5_ret_uint32(in, &ctx[0]), 0); /* context */
482     CHECK(krb5_ret_uint32(in, &ctx[1]), 0);
483     CHECK(ret_sec_buffer(in, &targetinfo), 0);
484     /* os version */
485 #if 0
486     CHECK(krb5_ret_uint32(in, &type2->os[0]), 0);
487     CHECK(krb5_ret_uint32(in, &type2->os[1]), 0);
488 #endif
489
490     CHECK(ret_string(in, ucs2, &targetname, &type2->targetname), 0);
491     CHECK(ret_buf(in, &targetinfo, &type2->targetinfo), 0);
492     ret = 0;
493
494 out:
495     krb5_storage_free(in);
496     if (ret)
497         heim_ntlm_free_type2(type2);
498
499     return ret;
500 }
501
502 int
503 heim_ntlm_encode_type2(struct ntlm_type2 *type2, struct ntlm_buf *data)
504 {
505     struct sec_buffer targetname, targetinfo;
506     krb5_error_code ret;
507     krb5_storage *out = NULL;
508     uint32_t base;
509     int ucs2 = 0;
510
511     if (type2->os[0])
512         base = 56;
513     else
514         base = 48;
515
516     if (type2->flags & NTLM_NEG_UNICODE)
517         ucs2 = 1;
518
519     targetname.offset = base;
520     targetname.length = len_string(ucs2, type2->targetname);
521     targetname.allocated = targetname.length;
522
523     targetinfo.offset = targetname.allocated + targetname.offset;
524     targetinfo.length = type2->targetinfo.length;
525     targetinfo.allocated = type2->targetinfo.length;
526
527     out = krb5_storage_emem();
528     if (out == NULL)
529         return ENOMEM;
530
531     krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
532     CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)), 
533           sizeof(ntlmsigature));
534     CHECK(krb5_store_uint32(out, 2), 0);
535     CHECK(store_sec_buffer(out, &targetname), 0);
536     CHECK(krb5_store_uint32(out, type2->flags), 0);
537     CHECK(krb5_storage_write(out, type2->challange, sizeof(type2->challange)),
538           sizeof(type2->challange));
539     CHECK(krb5_store_uint32(out, 0), 0); /* context */
540     CHECK(krb5_store_uint32(out, 0), 0);
541     CHECK(store_sec_buffer(out, &targetinfo), 0);
542     /* os version */
543     if (type2->os[0]) {
544         CHECK(krb5_store_uint32(out, type2->os[0]), 0);
545         CHECK(krb5_store_uint32(out, type2->os[1]), 0);
546     }
547     CHECK(put_string(out, ucs2, type2->targetname), 0);
548     CHECK(krb5_storage_write(out, type2->targetinfo.data, 
549                              type2->targetinfo.length),
550           type2->targetinfo.length);
551     
552     {
553         krb5_data d;
554         ret = krb5_storage_to_data(out, &d);
555         data->data = d.data;
556         data->length = d.length;
557     }
558
559 out:
560     krb5_storage_free(out);
561
562     return ret;
563 }
564
565 /*
566  * encoder/decoder type 2 messages
567  */
568
569 void
570 heim_ntlm_free_type3(struct ntlm_type3 *data)
571 {
572     _ntlm_free_buf(&data->lm);
573     _ntlm_free_buf(&data->ntlm);
574     if (data->targetname)
575         free(data->targetname);
576     if (data->username)
577         free(data->username);
578     if (data->ws)
579         free(data->ws);
580     _ntlm_free_buf(&data->sessionkey);
581     memset(data, 0, sizeof(*data));
582 }
583
584 /*
585  *
586  */
587
588 int
589 heim_ntlm_decode_type3(const struct ntlm_buf *buf,
590                        int ucs2,
591                        struct ntlm_type3 *type3)
592 {
593     krb5_error_code ret;
594     unsigned char sig[8];
595     uint32_t type;
596     krb5_storage *in;
597     struct sec_buffer lm, ntlm, target, username, sessionkey, ws;
598
599     memset(type3, 0, sizeof(*type3));
600     memset(&sessionkey, 0, sizeof(sessionkey));
601
602     in = krb5_storage_from_readonly_mem(buf->data, buf->length);
603     if (in == NULL) {
604         ret = EINVAL;
605         goto out;
606     }
607     krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
608
609     CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig));
610     CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0);
611     CHECK(krb5_ret_uint32(in, &type), 0);
612     CHECK(type, 3);
613     CHECK(ret_sec_buffer(in, &lm), 0);
614     CHECK(ret_sec_buffer(in, &ntlm), 0);
615     CHECK(ret_sec_buffer(in, &target), 0);
616     CHECK(ret_sec_buffer(in, &username), 0);
617     CHECK(ret_sec_buffer(in, &ws), 0);
618     if (lm.offset >= 60) {
619         CHECK(ret_sec_buffer(in, &sessionkey), 0);
620     }
621     if (lm.offset >= 64) {
622         CHECK(krb5_ret_uint32(in, &type3->flags), 0);
623     }
624     if (lm.offset >= 72) {
625         CHECK(krb5_ret_uint32(in, &type3->os[0]), 0);
626         CHECK(krb5_ret_uint32(in, &type3->os[1]), 0);
627     }
628     CHECK(ret_buf(in, &lm, &type3->lm), 0);
629     CHECK(ret_buf(in, &ntlm, &type3->ntlm), 0);
630     CHECK(ret_string(in, ucs2, &target, &type3->targetname), 0);
631     CHECK(ret_string(in, ucs2, &username, &type3->username), 0);
632     CHECK(ret_string(in, ucs2, &username, &type3->ws), 0);
633     if (sessionkey.offset)
634         CHECK(ret_buf(in, &sessionkey, &type3->sessionkey), 0);
635
636 out:
637     krb5_storage_free(in);
638     if (ret)
639         heim_ntlm_free_type3(type3);
640
641     return ret;
642 }
643
644 int
645 heim_ntlm_encode_type3(struct ntlm_type3 *type3, struct ntlm_buf *data)
646 {
647     struct sec_buffer lm, ntlm, target, username, sessionkey, ws;
648     krb5_error_code ret;
649     krb5_storage *out = NULL;
650     uint32_t base;
651     int ucs2 = 0;
652
653     memset(&lm, 0, sizeof(lm));
654     memset(&ntlm, 0, sizeof(ntlm));
655     memset(&target, 0, sizeof(target));
656     memset(&username, 0, sizeof(username));
657     memset(&ws, 0, sizeof(ws));
658     memset(&sessionkey, 0, sizeof(sessionkey));
659
660     base = 52;
661     if (type3->sessionkey.length) {
662         base += 8; /* sessionkey sec buf */
663         base += 4; /* flags */
664     }
665     if (type3->os[0]) {
666         base += 8;
667     }
668
669     if (type3->flags & NTLM_NEG_UNICODE)
670         ucs2 = 1;
671
672     lm.offset = base;
673     lm.length = type3->lm.length;
674     lm.allocated = type3->lm.length;
675
676     ntlm.offset = lm.offset + lm.allocated;
677     ntlm.length = type3->ntlm.length;
678     ntlm.allocated = ntlm.length;
679
680     target.offset = ntlm.offset + ntlm.allocated;
681     target.length = len_string(ucs2, type3->targetname);
682     target.allocated = target.length;
683
684     username.offset = target.offset + target.allocated;
685     username.length = len_string(ucs2, type3->username);
686     username.allocated = username.length;
687
688     ws.offset = username.offset + username.allocated;
689     ws.length = len_string(ucs2, type3->ws);
690     ws.allocated = ws.length;
691
692     sessionkey.offset = ws.offset + ws.allocated;
693     sessionkey.length = type3->sessionkey.length;
694     sessionkey.allocated = type3->sessionkey.length;
695
696     out = krb5_storage_emem();
697     if (out == NULL)
698         return ENOMEM;
699
700     krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
701     CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)), 
702           sizeof(ntlmsigature));
703     CHECK(krb5_store_uint32(out, 3), 0);
704
705     CHECK(store_sec_buffer(out, &lm), 0);
706     CHECK(store_sec_buffer(out, &ntlm), 0);
707     CHECK(store_sec_buffer(out, &target), 0);
708     CHECK(store_sec_buffer(out, &username), 0);
709     CHECK(store_sec_buffer(out, &ws), 0);
710     /* optional */
711     if (type3->sessionkey.length) {
712         CHECK(store_sec_buffer(out, &sessionkey), 0);
713         CHECK(krb5_store_uint32(out, type3->flags), 0);
714     }
715 #if 0
716     CHECK(krb5_store_uint32(out, 0), 0); /* os0 */
717     CHECK(krb5_store_uint32(out, 0), 0); /* os1 */
718 #endif
719
720     CHECK(put_buf(out, &type3->lm), 0);
721     CHECK(put_buf(out, &type3->ntlm), 0);
722     CHECK(put_string(out, ucs2, type3->targetname), 0);
723     CHECK(put_string(out, ucs2, type3->username), 0);
724     CHECK(put_string(out, ucs2, type3->ws), 0);
725     CHECK(put_buf(out, &type3->sessionkey), 0);
726     
727     {
728         krb5_data d;
729         ret = krb5_storage_to_data(out, &d);
730         data->data = d.data;
731         data->length = d.length;
732     }
733
734 out:
735     krb5_storage_free(out);
736
737     return ret;
738 }
739
740
741 /*
742  *
743  */
744
745 static void
746 splitandenc(unsigned char *hash, 
747             unsigned char *challange,
748             unsigned char *answer)
749 {
750     DES_cblock key;
751     DES_key_schedule sched;
752
753     ((unsigned char*)key)[0] =  hash[0];
754     ((unsigned char*)key)[1] = (hash[0] << 7) | (hash[1] >> 1);
755     ((unsigned char*)key)[2] = (hash[1] << 6) | (hash[2] >> 2);
756     ((unsigned char*)key)[3] = (hash[2] << 5) | (hash[3] >> 3);
757     ((unsigned char*)key)[4] = (hash[3] << 4) | (hash[4] >> 4);
758     ((unsigned char*)key)[5] = (hash[4] << 3) | (hash[5] >> 5);
759     ((unsigned char*)key)[6] = (hash[5] << 2) | (hash[6] >> 6);
760     ((unsigned char*)key)[7] = (hash[6] << 1);
761
762     DES_set_odd_parity(&key);
763     DES_set_key(&key, &sched);
764     DES_ecb_encrypt((DES_cblock *)challange, (DES_cblock *)answer, &sched, 1);
765     memset(&sched, 0, sizeof(sched));
766     memset(key, 0, sizeof(key));
767 }
768
769 /*
770  * String-to-key function for NTLM
771  */
772
773 int
774 heim_ntlm_nt_key(const char *password, struct ntlm_buf *key)
775 {
776     struct ntlm_buf buf;
777     MD4_CTX ctx;
778     int ret;
779
780     key->data = malloc(MD5_DIGEST_LENGTH);
781     if (key->data == NULL)
782         return ENOMEM;
783     key->length = MD5_DIGEST_LENGTH;
784
785     ret = ascii2ucs2le(password, 0, &buf);
786     if (ret) {
787         _ntlm_free_buf(key);
788         return ret;
789     }
790     MD4_Init(&ctx);
791     MD4_Update(&ctx, buf.data, buf.length);
792     MD4_Final(key->data, &ctx);
793     _ntlm_free_buf(&buf);
794     return 0;
795 }
796
797 /*
798  * Calculate NTLMv1 response hash
799  */
800
801 int
802 heim_ntlm_calculate_ntlm1(void *key, size_t len,
803                           unsigned char challange[8],
804                           struct ntlm_buf *answer)
805 {
806     unsigned char res[21];
807
808     if (len != MD4_DIGEST_LENGTH)
809         return EINVAL;
810
811     memcpy(res, key, len);
812     memset(&res[MD4_DIGEST_LENGTH], 0, sizeof(res) - MD4_DIGEST_LENGTH);
813
814     answer->data = malloc(24);
815     if (answer->data == NULL)
816         return ENOMEM;
817     answer->length = 24;
818
819     splitandenc(&res[0],  challange, ((unsigned char *)answer->data) + 0);
820     splitandenc(&res[7],  challange, ((unsigned char *)answer->data) + 8);
821     splitandenc(&res[14], challange, ((unsigned char *)answer->data) + 16);
822
823     return 0;
824 }
825
826 /*
827  * Calculate NTLMv1 master key
828  */
829
830 int
831 heim_ntlm_build_ntlm1_master(void *key, size_t len,
832                              struct ntlm_buf *session,
833                              struct ntlm_buf *master)
834 {
835     RC4_KEY rc4;
836
837     memset(master, 0, sizeof(*master));
838     memset(session, 0, sizeof(*session));
839
840     if (len != MD4_DIGEST_LENGTH)
841         return EINVAL;
842     
843     session->length = MD4_DIGEST_LENGTH;
844     session->data = malloc(session->length);
845     if (session->data == NULL) {
846         session->length = 0;
847         return EINVAL;
848     }    
849     master->length = MD4_DIGEST_LENGTH;
850     master->data = malloc(master->length);
851     if (master->data == NULL) {
852         _ntlm_free_buf(master);
853         _ntlm_free_buf(session);
854         return EINVAL;
855     }
856     
857     {
858         unsigned char sessionkey[MD4_DIGEST_LENGTH];
859         MD4_CTX ctx;
860     
861         MD4_Init(&ctx);
862         MD4_Update(&ctx, key, len);
863         MD4_Final(sessionkey, &ctx);
864         
865         RC4_set_key(&rc4, sizeof(sessionkey), sessionkey);
866     }
867     
868     if (RAND_bytes(session->data, session->length) != 1) {
869         _ntlm_free_buf(master);
870         _ntlm_free_buf(session);
871         return EINVAL;
872     }
873     
874     RC4(&rc4, master->length, session->data, master->data);
875     memset(&rc4, 0, sizeof(rc4));
876     
877     return 0;
878 }
879
880 /*
881  *
882  */
883
884 void
885 heim_ntlm_ntlmv2_key(const void *key, size_t len,
886                      const char *username,
887                      const char *target,
888                      unsigned char ntlmv2[16])
889 {
890     unsigned int hmaclen;
891     HMAC_CTX c;
892
893     HMAC_CTX_init(&c);
894     HMAC_Init_ex(&c, key, len, EVP_md5(), NULL);
895     {
896         struct ntlm_buf buf;
897         /* uppercase username and turn it inte ucs2-le */
898         ascii2ucs2le(username, 1, &buf);
899         HMAC_Update(&c, buf.data, buf.length);
900         free(buf.data);
901         /* uppercase target and turn into ucs2-le */
902         ascii2ucs2le(target, 1, &buf);
903         HMAC_Update(&c, buf.data, buf.length);
904         free(buf.data);
905     }
906     HMAC_Final(&c, ntlmv2, &hmaclen);
907     HMAC_CTX_cleanup(&c);
908
909 }
910
911 /*
912  *
913  */
914
915 #define NTTIME_EPOCH 0x019DB1DED53E8000LL
916
917 static uint64_t
918 unix2nttime(time_t unix_time)
919 {
920     long long wt;
921     wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH;
922     return wt;
923 }
924
925 static time_t
926 nt2unixtime(uint64_t t)
927 {
928     t = ((t - (uint64_t)NTTIME_EPOCH) / (uint64_t)10000000);
929     if (t > (((time_t)(~(uint64_t)0)) >> 1))
930         return 0;
931     return (time_t)t;
932 }
933
934
935 /*
936  * Calculate NTLMv2 response
937  */
938
939 int
940 heim_ntlm_calculate_ntlm2(const void *key, size_t len,
941                           const char *username,
942                           const char *target,
943                           const unsigned char serverchallange[8],
944                           const struct ntlm_buf *infotarget,
945                           unsigned char ntlmv2[16],
946                           struct ntlm_buf *answer)
947 {
948     krb5_error_code ret;
949     krb5_data data;
950     unsigned int hmaclen;
951     unsigned char ntlmv2answer[16];
952     krb5_storage *sp;
953     unsigned char clientchallange[8];
954     HMAC_CTX c;
955     uint64_t t;
956     
957     t = unix2nttime(time(NULL));
958
959     if (RAND_bytes(clientchallange, sizeof(clientchallange)) != 1)
960         return EINVAL;
961     
962     /* calculate ntlmv2 key */
963
964     heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2);
965
966     /* calculate and build ntlmv2 answer */
967
968     sp = krb5_storage_emem();
969     if (sp == NULL)
970         return ENOMEM;
971     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
972
973     CHECK(krb5_store_uint32(sp, 0x00000101), 0);
974     CHECK(krb5_store_uint32(sp, 0), 0);
975     /* timestamp le 64 bit ts */
976     CHECK(krb5_store_uint32(sp, t & 0xffffffff), 0);
977     CHECK(krb5_store_uint32(sp, t >> 32), 0);
978
979     CHECK(krb5_storage_write(sp, clientchallange, 8), 8);
980
981     CHECK(krb5_store_uint32(sp, 0), 0);  /* unknown but zero will work */
982     CHECK(krb5_storage_write(sp, infotarget->data, infotarget->length), 
983           infotarget->length);
984     CHECK(krb5_store_uint32(sp, 0), 0); /* unknown but zero will work */
985     
986     CHECK(krb5_storage_to_data(sp, &data), 0);
987     krb5_storage_free(sp);
988     sp = NULL;
989
990     HMAC_CTX_init(&c);
991     HMAC_Init_ex(&c, ntlmv2, 16, EVP_md5(), NULL);
992     HMAC_Update(&c, serverchallange, 8);
993     HMAC_Update(&c, data.data, data.length);
994     HMAC_Final(&c, ntlmv2answer, &hmaclen);
995     HMAC_CTX_cleanup(&c);
996
997     sp = krb5_storage_emem();
998     if (sp == NULL) {
999         krb5_data_free(&data);
1000         return ENOMEM;
1001     }
1002
1003     CHECK(krb5_storage_write(sp, ntlmv2answer, 16), 16);
1004     CHECK(krb5_storage_write(sp, data.data, data.length), data.length);
1005     krb5_data_free(&data);
1006     
1007     CHECK(krb5_storage_to_data(sp, &data), 0);
1008     krb5_storage_free(sp);
1009     sp = NULL;
1010
1011     answer->data = data.data;
1012     answer->length = data.length;
1013
1014     return 0;
1015 out:
1016     if (sp)
1017         krb5_storage_free(sp);
1018     return ret;
1019 }
1020
1021 static const int authtimediff = 3600 * 2; /* 2 hours */
1022
1023 /*
1024  * Verify NTLMv2 response.
1025  */
1026
1027 int
1028 heim_ntlm_verify_ntlm2(const void *key, size_t len,
1029                        const char *username,
1030                        const char *target,
1031                        time_t now,
1032                        const unsigned char serverchallange[8],
1033                        const struct ntlm_buf *answer,
1034                        struct ntlm_buf *infotarget,
1035                        unsigned char ntlmv2[16])
1036 {
1037     krb5_error_code ret;
1038     unsigned int hmaclen;
1039     unsigned char clientanswer[16];
1040     unsigned char clientnonce[8];
1041     unsigned char serveranswer[16];
1042     krb5_storage *sp;
1043     HMAC_CTX c;
1044     uint64_t t;
1045     time_t authtime;
1046     uint32_t temp;
1047
1048     infotarget->length = 0;    
1049     infotarget->data = NULL;    
1050
1051     if (answer->length < 16)
1052         return EINVAL;
1053
1054     if (now == 0)
1055         now = time(NULL);
1056
1057     /* calculate ntlmv2 key */
1058
1059     heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2);
1060
1061     /* calculate and build ntlmv2 answer */
1062
1063     sp = krb5_storage_from_readonly_mem(answer->data, answer->length);
1064     if (sp == NULL)
1065         return ENOMEM;
1066     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
1067
1068     CHECK(krb5_storage_read(sp, clientanswer, 16), 16);
1069
1070     CHECK(krb5_ret_uint32(sp, &temp), 0);
1071     CHECK(temp, 0x00000101);
1072     CHECK(krb5_ret_uint32(sp, &temp), 0);
1073     CHECK(temp, 0);
1074     /* timestamp le 64 bit ts */
1075     CHECK(krb5_ret_uint32(sp, &temp), 0);
1076     t = temp;
1077     CHECK(krb5_ret_uint32(sp, &temp), 0);
1078     t |= ((uint64_t)temp)<< 32;
1079
1080     authtime = nt2unixtime(t);
1081
1082     if (abs((int)(authtime - now)) > authtimediff) {
1083         ret = EINVAL;
1084         goto out;
1085     }
1086
1087     /* client challange */
1088     CHECK(krb5_storage_read(sp, clientnonce, 8), 8);
1089
1090     CHECK(krb5_ret_uint32(sp, &temp), 0); /* unknown */
1091
1092     /* should really unparse the infotarget, but lets pick up everything */
1093     infotarget->length = answer->length - krb5_storage_seek(sp, 0, SEEK_CUR);
1094     infotarget->data = malloc(infotarget->length);
1095     if (infotarget->data == NULL) {
1096         ret = ENOMEM;
1097         goto out;
1098     }
1099     CHECK(krb5_storage_read(sp, infotarget->data, infotarget->length), 
1100           infotarget->length);
1101     /* XXX remove the unknown ?? */
1102     krb5_storage_free(sp);
1103     sp = NULL;
1104
1105     HMAC_CTX_init(&c);
1106     HMAC_Init_ex(&c, ntlmv2, 16, EVP_md5(), NULL);
1107     HMAC_Update(&c, serverchallange, 8);
1108     HMAC_Update(&c, ((char *)answer->data) + 16, answer->length - 16);
1109     HMAC_Final(&c, serveranswer, &hmaclen);
1110     HMAC_CTX_cleanup(&c);
1111
1112     if (memcmp(serveranswer, clientanswer, 16) != 0) {
1113         _ntlm_free_buf(infotarget);
1114         return EINVAL;
1115     }
1116
1117     return 0;
1118 out:
1119     _ntlm_free_buf(infotarget);
1120     if (sp)
1121         krb5_storage_free(sp);
1122     return ret;
1123 }
1124
1125
1126 /*
1127  * Calculate the NTLM2 Session Response
1128  */
1129
1130 int
1131 heim_ntlm_calculate_ntlm2_sess(const unsigned char clnt_nonce[8],
1132                                const unsigned char svr_chal[8],
1133                                const unsigned char ntlm_hash[16],
1134                                struct ntlm_buf *lm,
1135                                struct ntlm_buf *ntlm)
1136 {
1137     unsigned char ntlm2_sess_hash[MD5_DIGEST_LENGTH];
1138     unsigned char res[21], *resp;
1139     MD5_CTX md5;
1140
1141     lm->data = malloc(24);
1142     if (lm->data == NULL)
1143         return ENOMEM;
1144     lm->length = 24;
1145
1146     ntlm->data = malloc(24);
1147     if (ntlm->data == NULL) {
1148         free(lm->data);
1149         lm->data = NULL;
1150         return ENOMEM;
1151     }
1152     ntlm->length = 24;
1153
1154     /* first setup the lm resp */
1155     memset(lm->data, 0, 24);
1156     memcpy(lm->data, clnt_nonce, 8);
1157
1158     MD5_Init(&md5);
1159     MD5_Update(&md5, svr_chal, 8); /* session nonce part 1 */
1160     MD5_Update(&md5, clnt_nonce, 8); /* session nonce part 2 */
1161     MD5_Final(ntlm2_sess_hash, &md5); /* will only use first 8 bytes */
1162
1163     memset(res, 0, sizeof(res));
1164     memcpy(res, ntlm_hash, 16);
1165
1166     resp = ntlm->data;
1167     splitandenc(&res[0], ntlm2_sess_hash, resp + 0);
1168     splitandenc(&res[7], ntlm2_sess_hash, resp + 8);
1169     splitandenc(&res[14], ntlm2_sess_hash, resp + 16);
1170
1171     return 0;
1172 }