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