s3: Fix uninitialized memory read in talloc_free()
[samba.git] / source3 / libsmb / clispnego.c
1 /* 
2    Unix SMB/CIFS implementation.
3    simple kerberos5/SPNEGO routines
4    Copyright (C) Andrew Tridgell 2001
5    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
6    Copyright (C) Luke Howard     2003
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "../libcli/auth/spnego.h"
24 #include "smb_krb5.h"
25
26 /*
27   generate a negTokenInit packet given a GUID, a list of supported
28   OIDs (the mechanisms) and a principal name string 
29 */
30 DATA_BLOB spnego_gen_negTokenInit(char guid[16], 
31                                   const char *OIDs[], 
32                                   const char *principal)
33 {
34         int i;
35         ASN1_DATA *data;
36         DATA_BLOB ret;
37
38         data = asn1_init(talloc_tos());
39         if (data == NULL) {
40                 return data_blob_null;
41         }
42
43         asn1_write(data, guid, 16);
44         asn1_push_tag(data,ASN1_APPLICATION(0));
45         asn1_write_OID(data,OID_SPNEGO);
46         asn1_push_tag(data,ASN1_CONTEXT(0));
47         asn1_push_tag(data,ASN1_SEQUENCE(0));
48
49         asn1_push_tag(data,ASN1_CONTEXT(0));
50         asn1_push_tag(data,ASN1_SEQUENCE(0));
51         for (i=0; OIDs[i]; i++) {
52                 asn1_write_OID(data,OIDs[i]);
53         }
54         asn1_pop_tag(data);
55         asn1_pop_tag(data);
56
57         asn1_push_tag(data, ASN1_CONTEXT(3));
58         asn1_push_tag(data, ASN1_SEQUENCE(0));
59         asn1_push_tag(data, ASN1_CONTEXT(0));
60         asn1_write_GeneralString(data,principal);
61         asn1_pop_tag(data);
62         asn1_pop_tag(data);
63         asn1_pop_tag(data);
64
65         asn1_pop_tag(data);
66         asn1_pop_tag(data);
67
68         asn1_pop_tag(data);
69
70         if (data->has_error) {
71                 DEBUG(1,("Failed to build negTokenInit at offset %d\n", (int)data->ofs));
72         }
73
74         ret = data_blob(data->data, data->length);
75         asn1_free(data);
76
77         return ret;
78 }
79
80 /*
81   Generate a negTokenInit as used by the client side ... It has a mechType
82   (OID), and a mechToken (a security blob) ... 
83
84   Really, we need to break out the NTLMSSP stuff as well, because it could be
85   raw in the packets!
86 */
87 DATA_BLOB gen_negTokenInit(const char *OID, DATA_BLOB blob)
88 {
89         ASN1_DATA *data;
90         DATA_BLOB ret;
91
92         data = asn1_init(talloc_tos());
93         if (data == NULL) {
94                 return data_blob_null;
95         }
96
97         asn1_push_tag(data, ASN1_APPLICATION(0));
98         asn1_write_OID(data,OID_SPNEGO);
99         asn1_push_tag(data, ASN1_CONTEXT(0));
100         asn1_push_tag(data, ASN1_SEQUENCE(0));
101
102         asn1_push_tag(data, ASN1_CONTEXT(0));
103         asn1_push_tag(data, ASN1_SEQUENCE(0));
104         asn1_write_OID(data, OID);
105         asn1_pop_tag(data);
106         asn1_pop_tag(data);
107
108         asn1_push_tag(data, ASN1_CONTEXT(2));
109         asn1_write_OctetString(data,blob.data,blob.length);
110         asn1_pop_tag(data);
111
112         asn1_pop_tag(data);
113         asn1_pop_tag(data);
114
115         asn1_pop_tag(data);
116
117         if (data->has_error) {
118                 DEBUG(1,("Failed to build negTokenInit at offset %d\n", (int)data->ofs));
119         }
120
121         ret = data_blob(data->data, data->length);
122         asn1_free(data);
123
124         return ret;
125 }
126
127 /*
128   parse a negTokenInit packet giving a GUID, a list of supported
129   OIDs (the mechanisms) and a principal name string 
130 */
131 bool spnego_parse_negTokenInit(DATA_BLOB blob,
132                                char *OIDs[ASN1_MAX_OIDS],
133                                char **principal)
134 {
135         int i;
136         bool ret;
137         ASN1_DATA *data;
138
139         data = asn1_init(talloc_tos());
140         if (data == NULL) {
141                 return false;
142         }
143
144         asn1_load(data, blob);
145
146         asn1_start_tag(data,ASN1_APPLICATION(0));
147
148         asn1_check_OID(data,OID_SPNEGO);
149
150         /* negTokenInit  [0]  NegTokenInit */
151         asn1_start_tag(data,ASN1_CONTEXT(0));
152         asn1_start_tag(data,ASN1_SEQUENCE(0));
153
154         /* mechTypes [0] MechTypeList  OPTIONAL */
155
156         /* Not really optional, we depend on this to decide
157          * what mechanisms we have to work with. */
158
159         asn1_start_tag(data,ASN1_CONTEXT(0));
160         asn1_start_tag(data,ASN1_SEQUENCE(0));
161         for (i=0; asn1_tag_remaining(data) > 0 && i < ASN1_MAX_OIDS-1; i++) {
162                 const char *oid_str = NULL;
163                 asn1_read_OID(data,talloc_autofree_context(),&oid_str);
164                 if (data->has_error) {
165                         break;
166                 }
167                 OIDs[i] = CONST_DISCARD(char *, oid_str);
168         }
169         OIDs[i] = NULL;
170         asn1_end_tag(data);
171         asn1_end_tag(data);
172
173         *principal = NULL;
174
175         /*
176           Win7 + Live Sign-in Assistant attaches a mechToken
177           ASN1_CONTEXT(2) to the negTokenInit packet
178           which breaks our negotiation if we just assume
179           the next tag is ASN1_CONTEXT(3).
180         */
181
182         if (asn1_peek_tag(data, ASN1_CONTEXT(1))) {
183                 uint8 flags;
184
185                 /* reqFlags [1] ContextFlags  OPTIONAL */
186                 asn1_start_tag(data, ASN1_CONTEXT(1));
187                 asn1_start_tag(data, ASN1_BIT_STRING);
188                 while (asn1_tag_remaining(data) > 0) {
189                         asn1_read_uint8(data, &flags);
190                 }
191                 asn1_end_tag(data);
192                 asn1_end_tag(data);
193         }
194
195         if (asn1_peek_tag(data, ASN1_CONTEXT(2))) {
196                 /* mechToken [2] OCTET STRING  OPTIONAL */
197                 DATA_BLOB token;
198                 asn1_start_tag(data, ASN1_CONTEXT(2));
199                 asn1_read_OctetString(data, talloc_autofree_context(),
200                         &token);
201                 asn1_end_tag(data);
202                 /* Throw away the token - not used. */
203                 data_blob_free(&token);
204         }
205
206         if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
207                 /* mechListMIC [3] OCTET STRING  OPTIONAL */
208                 asn1_start_tag(data, ASN1_CONTEXT(3));
209                 asn1_start_tag(data, ASN1_SEQUENCE(0));
210                 asn1_start_tag(data, ASN1_CONTEXT(0));
211                 asn1_read_GeneralString(data,talloc_autofree_context(),
212                         principal);
213                 asn1_end_tag(data);
214                 asn1_end_tag(data);
215                 asn1_end_tag(data);
216         }
217
218         asn1_end_tag(data);
219         asn1_end_tag(data);
220
221         asn1_end_tag(data);
222
223         ret = !data->has_error;
224         if (data->has_error) {
225                 int j;
226                 TALLOC_FREE(*principal);
227                 for(j = 0; j < i && j < ASN1_MAX_OIDS-1; j++) {
228                         TALLOC_FREE(OIDs[j]);
229                 }
230         }
231
232         asn1_free(data);
233         return ret;
234 }
235
236 /*
237   generate a negTokenTarg packet given a list of OIDs and a security blob
238 */
239 DATA_BLOB gen_negTokenTarg(const char *OIDs[], DATA_BLOB blob)
240 {
241         int i;
242         ASN1_DATA *data;
243         DATA_BLOB ret;
244
245         data = asn1_init(talloc_tos());
246         if (data == NULL) {
247                 return data_blob_null;
248         }
249
250         asn1_push_tag(data, ASN1_APPLICATION(0));
251         asn1_write_OID(data,OID_SPNEGO);
252         asn1_push_tag(data, ASN1_CONTEXT(0));
253         asn1_push_tag(data, ASN1_SEQUENCE(0));
254
255         asn1_push_tag(data, ASN1_CONTEXT(0));
256         asn1_push_tag(data, ASN1_SEQUENCE(0));
257         for (i=0; OIDs[i]; i++) {
258                 asn1_write_OID(data,OIDs[i]);
259         }
260         asn1_pop_tag(data);
261         asn1_pop_tag(data);
262
263         asn1_push_tag(data, ASN1_CONTEXT(2));
264         asn1_write_OctetString(data,blob.data,blob.length);
265         asn1_pop_tag(data);
266
267         asn1_pop_tag(data);
268         asn1_pop_tag(data);
269
270         asn1_pop_tag(data);
271
272         if (data->has_error) {
273                 DEBUG(1,("Failed to build negTokenTarg at offset %d\n", (int)data->ofs));
274         }
275
276         ret = data_blob(data->data, data->length);
277         asn1_free(data);
278
279         return ret;
280 }
281
282 /*
283   parse a negTokenTarg packet giving a list of OIDs and a security blob
284 */
285 bool parse_negTokenTarg(DATA_BLOB blob, char *OIDs[ASN1_MAX_OIDS], DATA_BLOB *secblob)
286 {
287         int i;
288         ASN1_DATA *data;
289
290         data = asn1_init(talloc_tos());
291         if (data == NULL) {
292                 return false;
293         }
294
295         asn1_load(data, blob);
296         asn1_start_tag(data, ASN1_APPLICATION(0));
297         asn1_check_OID(data,OID_SPNEGO);
298         asn1_start_tag(data, ASN1_CONTEXT(0));
299         asn1_start_tag(data, ASN1_SEQUENCE(0));
300
301         asn1_start_tag(data, ASN1_CONTEXT(0));
302         asn1_start_tag(data, ASN1_SEQUENCE(0));
303         for (i=0; asn1_tag_remaining(data) > 0 && i < ASN1_MAX_OIDS-1; i++) {
304                 const char *oid_str = NULL;
305                 asn1_read_OID(data,talloc_autofree_context(),&oid_str);
306                 OIDs[i] = CONST_DISCARD(char *, oid_str);
307         }
308         OIDs[i] = NULL;
309         asn1_end_tag(data);
310         asn1_end_tag(data);
311
312         /* Skip any optional req_flags that are sent per RFC 4178 */
313         if (asn1_peek_tag(data, ASN1_CONTEXT(1))) {
314                 uint8 flags;
315
316                 asn1_start_tag(data, ASN1_CONTEXT(1));
317                 asn1_start_tag(data, ASN1_BIT_STRING);
318                 while (asn1_tag_remaining(data) > 0)
319                         asn1_read_uint8(data, &flags);
320                 asn1_end_tag(data);
321                 asn1_end_tag(data);
322         }
323
324         asn1_start_tag(data, ASN1_CONTEXT(2));
325         asn1_read_OctetString(data,talloc_autofree_context(),secblob);
326         asn1_end_tag(data);
327
328         asn1_end_tag(data);
329         asn1_end_tag(data);
330
331         asn1_end_tag(data);
332
333         if (data->has_error) {
334                 int j;
335                 data_blob_free(secblob);
336                 for(j = 0; j < i && j < ASN1_MAX_OIDS-1; j++) {
337                         TALLOC_FREE(OIDs[j]);
338                 }
339                 DEBUG(1,("Failed to parse negTokenTarg at offset %d\n", (int)data->ofs));
340                 asn1_free(data);
341                 return False;
342         }
343
344         asn1_free(data);
345         return True;
346 }
347
348 /*
349   generate a krb5 GSS-API wrapper packet given a ticket
350 */
351 DATA_BLOB spnego_gen_krb5_wrap(const DATA_BLOB ticket, const uint8 tok_id[2])
352 {
353         ASN1_DATA *data;
354         DATA_BLOB ret;
355
356         data = asn1_init(talloc_tos());
357         if (data == NULL) {
358                 return data_blob_null;
359         }
360
361         asn1_push_tag(data, ASN1_APPLICATION(0));
362         asn1_write_OID(data, OID_KERBEROS5);
363
364         asn1_write(data, tok_id, 2);
365         asn1_write(data, ticket.data, ticket.length);
366         asn1_pop_tag(data);
367
368         if (data->has_error) {
369                 DEBUG(1,("Failed to build krb5 wrapper at offset %d\n", (int)data->ofs));
370         }
371
372         ret = data_blob(data->data, data->length);
373         asn1_free(data);
374
375         return ret;
376 }
377
378 /*
379   parse a krb5 GSS-API wrapper packet giving a ticket
380 */
381 bool spnego_parse_krb5_wrap(DATA_BLOB blob, DATA_BLOB *ticket, uint8 tok_id[2])
382 {
383         bool ret;
384         ASN1_DATA *data;
385         int data_remaining;
386
387         data = asn1_init(talloc_tos());
388         if (data == NULL) {
389                 return false;
390         }
391
392         asn1_load(data, blob);
393         asn1_start_tag(data, ASN1_APPLICATION(0));
394         asn1_check_OID(data, OID_KERBEROS5);
395
396         data_remaining = asn1_tag_remaining(data);
397
398         if (data_remaining < 3) {
399                 data->has_error = True;
400         } else {
401                 asn1_read(data, tok_id, 2);
402                 data_remaining -= 2;
403                 *ticket = data_blob(NULL, data_remaining);
404                 asn1_read(data, ticket->data, ticket->length);
405         }
406
407         asn1_end_tag(data);
408
409         ret = !data->has_error;
410
411         if (data->has_error) {
412                 data_blob_free(ticket);
413         }
414
415         asn1_free(data);
416
417         return ret;
418 }
419
420
421 /* 
422    generate a SPNEGO negTokenTarg packet, ready for a EXTENDED_SECURITY
423    kerberos session setup 
424 */
425 int spnego_gen_negTokenTarg(const char *principal, int time_offset, 
426                             DATA_BLOB *targ, 
427                             DATA_BLOB *session_key_krb5, uint32 extra_ap_opts,
428                             time_t *expire_time)
429 {
430         int retval;
431         DATA_BLOB tkt, tkt_wrapped;
432         const char *krb_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
433
434         /* get a kerberos ticket for the service and extract the session key */
435         retval = cli_krb5_get_ticket(principal, time_offset,
436                                         &tkt, session_key_krb5, extra_ap_opts, NULL, 
437                                         expire_time, NULL);
438
439         if (retval)
440                 return retval;
441
442         /* wrap that up in a nice GSS-API wrapping */
443         tkt_wrapped = spnego_gen_krb5_wrap(tkt, TOK_ID_KRB_AP_REQ);
444
445         /* and wrap that in a shiny SPNEGO wrapper */
446         *targ = gen_negTokenTarg(krb_mechs, tkt_wrapped);
447
448         data_blob_free(&tkt_wrapped);
449         data_blob_free(&tkt);
450
451         return retval;
452 }
453
454
455 /*
456   parse a spnego NTLMSSP challenge packet giving two security blobs
457 */
458 bool spnego_parse_challenge(const DATA_BLOB blob,
459                             DATA_BLOB *chal1, DATA_BLOB *chal2)
460 {
461         bool ret;
462         ASN1_DATA *data;
463
464         ZERO_STRUCTP(chal1);
465         ZERO_STRUCTP(chal2);
466
467         data = asn1_init(talloc_tos());
468         if (data == NULL) {
469                 return false;
470         }
471
472         asn1_load(data, blob);
473         asn1_start_tag(data,ASN1_CONTEXT(1));
474         asn1_start_tag(data,ASN1_SEQUENCE(0));
475
476         asn1_start_tag(data,ASN1_CONTEXT(0));
477         asn1_check_enumerated(data,1);
478         asn1_end_tag(data);
479
480         asn1_start_tag(data,ASN1_CONTEXT(1));
481         asn1_check_OID(data, OID_NTLMSSP);
482         asn1_end_tag(data);
483
484         asn1_start_tag(data,ASN1_CONTEXT(2));
485         asn1_read_OctetString(data, talloc_autofree_context(), chal1);
486         asn1_end_tag(data);
487
488         /* the second challenge is optional (XP doesn't send it) */
489         if (asn1_tag_remaining(data)) {
490                 asn1_start_tag(data,ASN1_CONTEXT(3));
491                 asn1_read_OctetString(data, talloc_autofree_context(), chal2);
492                 asn1_end_tag(data);
493         }
494
495         asn1_end_tag(data);
496         asn1_end_tag(data);
497
498         ret = !data->has_error;
499
500         if (data->has_error) {
501                 data_blob_free(chal1);
502                 data_blob_free(chal2);
503         }
504
505         asn1_free(data);
506         return ret;
507 }
508
509
510 /*
511  generate a SPNEGO auth packet. This will contain the encrypted passwords
512 */
513 DATA_BLOB spnego_gen_auth(DATA_BLOB blob)
514 {
515         ASN1_DATA *data;
516         DATA_BLOB ret;
517
518         data = asn1_init(talloc_tos());
519         if (data == NULL) {
520                 return data_blob_null;
521         }
522
523         asn1_push_tag(data, ASN1_CONTEXT(1));
524         asn1_push_tag(data, ASN1_SEQUENCE(0));
525         asn1_push_tag(data, ASN1_CONTEXT(2));
526         asn1_write_OctetString(data,blob.data,blob.length);
527         asn1_pop_tag(data);
528         asn1_pop_tag(data);
529         asn1_pop_tag(data);
530
531         ret = data_blob(data->data, data->length);
532
533         asn1_free(data);
534
535         return ret;
536 }
537
538 /*
539  parse a SPNEGO auth packet. This contains the encrypted passwords
540 */
541 bool spnego_parse_auth(DATA_BLOB blob, DATA_BLOB *auth)
542 {
543         ssize_t len;
544         struct spnego_data token;
545
546         len = spnego_read_data(talloc_tos(), blob, &token);
547         if (len == -1) {
548                 DEBUG(3,("spnego_parse_auth: spnego_read_data failed\n"));
549                 return false;
550         }
551
552         if (token.type != SPNEGO_NEG_TOKEN_TARG) {
553                 DEBUG(3,("spnego_parse_auth: wrong token type: %d\n",
554                         token.type));
555                 spnego_free_data(&token);
556                 return false;
557         }
558
559         *auth = data_blob_talloc(talloc_tos(),
560                                  token.negTokenTarg.responseToken.data,
561                                  token.negTokenTarg.responseToken.length);
562         spnego_free_data(&token);
563
564         return true;
565 }
566
567 /*
568   generate a minimal SPNEGO response packet.  Doesn't contain much.
569 */
570 DATA_BLOB spnego_gen_auth_response(DATA_BLOB *reply, NTSTATUS nt_status,
571                                    const char *mechOID)
572 {
573         ASN1_DATA *data;
574         DATA_BLOB ret;
575         uint8 negResult;
576
577         if (NT_STATUS_IS_OK(nt_status)) {
578                 negResult = SPNEGO_ACCEPT_COMPLETED;
579         } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
580                 negResult = SPNEGO_ACCEPT_INCOMPLETE;
581         } else {
582                 negResult = SPNEGO_REJECT;
583         }
584
585         data = asn1_init(talloc_tos());
586         if (data == NULL) {
587                 return data_blob_null;
588         }
589
590         asn1_push_tag(data, ASN1_CONTEXT(1));
591         asn1_push_tag(data, ASN1_SEQUENCE(0));
592         asn1_push_tag(data, ASN1_CONTEXT(0));
593         asn1_write_enumerated(data, negResult);
594         asn1_pop_tag(data);
595
596         if (mechOID) {
597                 asn1_push_tag(data,ASN1_CONTEXT(1));
598                 asn1_write_OID(data, mechOID);
599                 asn1_pop_tag(data);
600         }
601
602         if (reply && reply->data != NULL) {
603                 asn1_push_tag(data,ASN1_CONTEXT(2));
604                 asn1_write_OctetString(data, reply->data, reply->length);
605                 asn1_pop_tag(data);
606         }
607
608         asn1_pop_tag(data);
609         asn1_pop_tag(data);
610
611         ret = data_blob(data->data, data->length);
612         asn1_free(data);
613         return ret;
614 }
615
616 /*
617  parse a SPNEGO auth packet. This contains the encrypted passwords
618 */
619 bool spnego_parse_auth_response(DATA_BLOB blob, NTSTATUS nt_status,
620                                 const char *mechOID,
621                                 DATA_BLOB *auth)
622 {
623         ASN1_DATA *data;
624         uint8 negResult;
625
626         if (NT_STATUS_IS_OK(nt_status)) {
627                 negResult = SPNEGO_ACCEPT_COMPLETED;
628         } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
629                 negResult = SPNEGO_ACCEPT_INCOMPLETE;
630         } else {
631                 negResult = SPNEGO_REJECT;
632         }
633
634         data = asn1_init(talloc_tos());
635         if (data == NULL) {
636                 return false;
637         }
638
639         asn1_load(data, blob);
640         asn1_start_tag(data, ASN1_CONTEXT(1));
641         asn1_start_tag(data, ASN1_SEQUENCE(0));
642         asn1_start_tag(data, ASN1_CONTEXT(0));
643         asn1_check_enumerated(data, negResult);
644         asn1_end_tag(data);
645
646         *auth = data_blob_null;
647
648         if (asn1_tag_remaining(data)) {
649                 asn1_start_tag(data,ASN1_CONTEXT(1));
650                 asn1_check_OID(data, mechOID);
651                 asn1_end_tag(data);
652
653                 if (asn1_tag_remaining(data)) {
654                         asn1_start_tag(data,ASN1_CONTEXT(2));
655                         asn1_read_OctetString(data, talloc_autofree_context(), auth);
656                         asn1_end_tag(data);
657                 }
658         } else if (negResult == SPNEGO_ACCEPT_INCOMPLETE) {
659                 data->has_error = 1;
660         }
661
662         /* Binding against Win2K DC returns a duplicate of the responseToken in
663          * the optional mechListMIC field. This is a bug in Win2K. We ignore
664          * this field if it exists. Win2K8 may return a proper mechListMIC at
665          * which point we need to implement the integrity checking. */
666         if (asn1_tag_remaining(data)) {
667                 DATA_BLOB mechList = data_blob_null;
668                 asn1_start_tag(data, ASN1_CONTEXT(3));
669                 asn1_read_OctetString(data, talloc_autofree_context(), &mechList);
670                 asn1_end_tag(data);
671                 data_blob_free(&mechList);
672                 DEBUG(5,("spnego_parse_auth_response received mechListMIC, "
673                     "ignoring.\n"));
674         }
675
676         asn1_end_tag(data);
677         asn1_end_tag(data);
678
679         if (data->has_error) {
680                 DEBUG(3,("spnego_parse_auth_response failed at %d\n", (int)data->ofs));
681                 asn1_free(data);
682                 data_blob_free(auth);
683                 return False;
684         }
685
686         asn1_free(data);
687         return True;
688 }