~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/libsmb/clispnego.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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