Coverage Report

Created: 2024-06-18 06:03

/src/gss-ntlmssp/src/ntlm.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright 2013 Simo Sorce <simo@samba.org>, see COPYING for license */
2
3
/* This File implements the NTLM protocol as specified by:
4
 *      [MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol
5
 *
6
 * Additional cross checking with:
7
 * http://davenport.sourceforge.net/ntlm.html
8
 */
9
10
#include <alloca.h>
11
#include <endian.h>
12
#include <errno.h>
13
#include <iconv.h>
14
#include <stddef.h>
15
#include <string.h>
16
#include <sys/time.h>
17
18
#include <unicase.h>
19
20
#include "ntlm.h"
21
22
#pragma pack(push, 1)
23
struct wire_av_pair {
24
    uint16_t av_id;
25
    uint16_t av_len;
26
    uint8_t value[]; /* variable */
27
};
28
#pragma pack(pop)
29
30
enum msv_av_ids {
31
    MSV_AV_EOL = 0,
32
    MSV_AV_NB_COMPUTER_NAME,
33
    MSV_AV_NB_DOMAIN_NAME,
34
    MSV_AV_DNS_COMPUTER_NAME,
35
    MSV_AV_DNS_DOMAIN_NAME,
36
    MSV_AV_DNS_TREE_NAME,
37
    MSV_AV_FLAGS,
38
    MSV_AV_TIMESTAMP,
39
    MSV_AV_SINGLE_HOST,
40
    MSV_AV_TARGET_NAME,
41
    MSV_AV_CHANNEL_BINDINGS
42
};
43
44
/* Used only on the same host */
45
#pragma pack(push, 1)
46
struct wire_single_host_data {
47
    uint32_t size;
48
    uint32_t Z4;
49
    uint32_t data_present;
50
    uint32_t custom_data;
51
    uint8_t machine_id[32];
52
};
53
#pragma pack(pop)
54
55
#pragma pack(push, 1)
56
struct wire_ntlm_cli_chal {
57
    uint8_t resp_type;
58
    uint8_t hi_resp_type;
59
    uint16_t reserved1;
60
    uint32_t reserved2;
61
    uint64_t timestamp;
62
    uint8_t cli_chal[8];
63
    uint32_t reserved3;
64
    uint8_t av_pairs[]; /* variable */
65
};
66
#pragma pack(pop)
67
68
struct ntlm_ctx {
69
    iconv_t from_oem;
70
    iconv_t to_oem;
71
};
72
73
int ntlm_init_ctx(struct ntlm_ctx **ctx)
74
1.14k
{
75
1.14k
    struct ntlm_ctx *_ctx;
76
1.14k
    int ret = 0;
77
78
1.14k
    _ctx = calloc(1, sizeof(struct ntlm_ctx));
79
1.14k
    if (!_ctx) return ENOMEM;
80
81
1.14k
    _ctx->from_oem = iconv_open("UTF-16LE", "UTF-8");
82
1.14k
    if (_ctx->from_oem == (iconv_t) -1) {
83
0
        ret = errno;
84
0
    }
85
86
1.14k
    _ctx->to_oem = iconv_open("UTF-8", "UTF-16LE");
87
1.14k
    if (_ctx->to_oem == (iconv_t) -1) {
88
0
        iconv_close(_ctx->from_oem);
89
0
        ret = errno;
90
0
    }
91
92
1.14k
    if (ret) {
93
0
        safefree(_ctx);
94
1.14k
    } else {
95
1.14k
        *ctx = _ctx;
96
1.14k
    }
97
1.14k
    return ret;
98
1.14k
}
99
100
int ntlm_free_ctx(struct ntlm_ctx **ctx)
101
1.14k
{
102
1.14k
    int ret;
103
104
1.14k
    if (!ctx || !*ctx) return 0;
105
106
1.14k
    if ((*ctx)->from_oem) {
107
1.14k
        ret = iconv_close((*ctx)->from_oem);
108
1.14k
        if (ret) goto done;
109
1.14k
    }
110
111
1.14k
    if ((*ctx)->to_oem) {
112
1.14k
        ret = iconv_close((*ctx)->to_oem);
113
1.14k
    }
114
115
1.14k
done:
116
1.14k
    if (ret) ret = errno;
117
1.14k
    safefree(*ctx);
118
1.14k
    return ret;
119
1.14k
}
120
121
void ntlm_free_buffer_data(struct ntlm_buffer *buf)
122
8.32k
{
123
8.32k
    if (!buf) return;
124
125
8.32k
    safefree(buf->data);
126
8.32k
    buf->length = 0;
127
8.32k
}
128
129
/* A FILETIME structure is effectively a little endian 64 bit integer
130
 * with the time from January 1, 1601 UTC with 10s of microsecond resolution.
131
 */
132
957
#define FILETIME_EPOCH_VALUE 116444736000000000LL
133
uint64_t ntlm_timestamp_now(void)
134
957
{
135
957
    struct timeval tv;
136
957
    uint64_t filetime;
137
138
957
    gettimeofday(&tv, NULL);
139
140
    /* set filetime to the time representing the eopch */
141
957
    filetime = FILETIME_EPOCH_VALUE;
142
    /* add the number of seconds since the epoch */
143
957
    filetime += (uint64_t)tv.tv_sec * 10000000;
144
    /* add the number of microseconds since the epoch */
145
957
    filetime += tv.tv_usec * 10;
146
147
957
    return filetime;
148
957
}
149
150
bool ntlm_casecmp(const char *s1, const char *s2)
151
0
{
152
0
    size_t s1_len, s2_len;
153
0
    int ret, res;
154
155
0
    if (s1 == s2) return true;
156
0
    if (!s1 || !s2) return false;
157
158
0
    s1_len = strlen(s1);
159
0
    s2_len = strlen(s2);
160
161
0
    ret = ulc_casecmp(s1, s1_len, s2, s2_len,
162
0
                      uc_locale_language(), NULL, &res);
163
0
    if (ret || res != 0) return false;
164
0
    return true;
165
0
}
166
167
168
/**
169
 * @brief  Converts a string using the provided iconv context.
170
 *         This function is ok only to convert utf8<->utf16le
171
 *
172
 * @param cd        The iconv context
173
 * @param in        Input buffer
174
 * @param out       Output buffer
175
 * @param baselen   Input length
176
 * @param outlen    Returned length of out buffer
177
 *
178
 * NOTE: out must be preallocated to a size of baselen * 2
179
 *
180
 * @return 0 on success or a standard error value on error.
181
 */
182
static int ntlm_str_convert(iconv_t cd,
183
                            const char *in, char *out,
184
                            size_t baselen, size_t *outlen)
185
3.40k
{
186
3.40k
    char *_in;
187
3.40k
    size_t inleft, outleft;
188
3.40k
    size_t ret;
189
190
3.40k
    ret = iconv(cd, NULL, NULL, NULL, NULL);
191
3.40k
    if (ret == -1) return errno;
192
193
3.40k
    _in = discard_const(in);
194
3.40k
    inleft = baselen;
195
    /* conservative max_size calculation in case lots of octects end up
196
     * being multiple bytes in length (in both directions) */
197
3.40k
    outleft = baselen * 2;
198
199
3.40k
    ret = iconv(cd, &_in, &inleft, &out, &outleft);
200
3.40k
    if (ret == -1) return errno;
201
202
3.38k
    if (outlen) {
203
3.38k
        *outlen = baselen * 2 - outleft;
204
3.38k
    }
205
3.38k
    return 0;
206
3.40k
}
207
208
uint8_t ntlmssp_sig[8] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0};
209
210
static void ntlm_encode_header(struct wire_msg_hdr *hdr, uint32_t msg_type)
211
957
{
212
957
    memcpy(hdr->signature, ntlmssp_sig, 8);
213
957
    hdr->msg_type = htole32(msg_type);
214
957
}
215
216
static int ntlm_decode_header(struct wire_msg_hdr *hdr, uint32_t *msg_type)
217
2.05k
{
218
2.05k
    if (memcmp(hdr->signature, ntlmssp_sig, 8) != 0) {
219
100
        return ERR_DECODE;
220
100
    }
221
222
1.95k
    *msg_type = le32toh(hdr->msg_type);
223
1.95k
    return 0;
224
2.05k
}
225
226
static int ntlm_encode_oem_str(struct wire_field_hdr *hdr,
227
                               struct ntlm_buffer *buffer,
228
                               size_t *data_offs,
229
                               const char *str, int str_len)
230
643
{
231
643
    if (*data_offs + str_len > buffer->length) {
232
0
        return ERR_ENCODE;
233
0
    }
234
235
643
    memcpy(&buffer->data[*data_offs], str, str_len);
236
643
    hdr->len = htole16(str_len);
237
643
    hdr->max_len = htole16(str_len);
238
643
    hdr->offset = htole32(*data_offs);
239
240
643
    *data_offs += str_len;
241
643
    return 0;
242
643
}
243
244
static int ntlm_decode_oem_str(struct wire_field_hdr *str_hdr,
245
                               struct ntlm_buffer *buffer,
246
                               size_t payload_offs, char **_str)
247
580
{
248
580
    uint16_t str_len;
249
580
    uint32_t str_offs;
250
580
    char *str = NULL;
251
252
580
    str_len = le16toh(str_hdr->len);
253
580
    if (str_len == 0) goto done;
254
255
580
    str_offs = le32toh(str_hdr->offset);
256
580
    if ((str_offs < payload_offs) ||
257
580
        (str_offs > buffer->length) ||
258
580
        (UINT32_MAX - str_offs < str_len) ||
259
580
        (str_offs + str_len > buffer->length)) {
260
211
        return ERR_DECODE;
261
211
    }
262
263
369
    str = strndup((const char *)&buffer->data[str_offs], str_len);
264
369
    if (!str) return ENOMEM;
265
266
369
done:
267
369
    *_str = str;
268
369
    return 0;
269
369
}
270
271
static int ntlm_encode_u16l_str_hdr(struct ntlm_ctx *ctx,
272
                                    struct wire_field_hdr *hdr,
273
                                    struct ntlm_buffer *buffer,
274
                                    size_t *data_offs,
275
                                    const char *str, int str_len)
276
314
{
277
314
    char *out;
278
314
    size_t outlen;
279
314
    int ret;
280
281
314
    out = (char *)&buffer->data[*data_offs];
282
283
314
    ret = ntlm_str_convert(ctx->from_oem, str, out, str_len, &outlen);
284
314
    if (ret) return ret;
285
286
314
    hdr->len = htole16(outlen);
287
314
    hdr->max_len = htole16(outlen);
288
314
    hdr->offset = htole32(*data_offs);
289
290
314
    *data_offs += outlen;
291
314
    return 0;
292
314
}
293
294
static int ntlm_decode_u16l_str_hdr(struct ntlm_ctx *ctx,
295
                                    struct wire_field_hdr *str_hdr,
296
                                    struct ntlm_buffer *buffer,
297
                                    size_t payload_offs, char **str)
298
305
{
299
305
    char *in, *out = NULL;
300
305
    uint16_t str_len;
301
305
    uint32_t str_offs;
302
305
    size_t outlen = 0;
303
305
    int ret = 0;
304
305
305
    str_len = le16toh(str_hdr->len);
306
305
    if (str_len == 0) goto done;
307
308
305
    str_offs = le32toh(str_hdr->offset);
309
305
    if ((str_offs < payload_offs) ||
310
305
        (str_offs > buffer->length) ||
311
305
        (UINT32_MAX - str_offs < str_len) ||
312
305
        (str_offs + str_len > buffer->length)) {
313
89
        return ERR_DECODE;
314
89
    }
315
316
216
    in = (char *)&buffer->data[str_offs];
317
318
216
    out = malloc(str_len * 2 + 1);
319
216
    if (!out) return ENOMEM;
320
321
216
    ret = ntlm_str_convert(ctx->to_oem, in, out, str_len, &outlen);
322
323
216
done:
324
216
    if (ret) {
325
20
        safefree(out);
326
196
    } else {
327
        /* make sure to terminate output string */
328
196
        if (out) {
329
196
            out[outlen] = '\0';
330
196
        }
331
196
    }
332
333
216
    *str = out;
334
216
    return ret;
335
216
}
336
337
struct wire_version ntlmssp_version = {
338
    NTLMSSP_VERSION_MAJOR,
339
    NTLMSSP_VERSION_MINOR,
340
    NTLMSSP_VERSION_BUILD, /* 0 is always 0 even in LE */
341
    { 0, 0, 0 },
342
    NTLMSSP_VERSION_REV
343
};
344
345
void ntlm_internal_set_version(uint8_t major, uint8_t minor,
346
                               uint16_t build, uint8_t revision)
347
0
{
348
0
    ntlmssp_version.major = major;
349
0
    ntlmssp_version.minor = minor;
350
0
    ntlmssp_version.build = htole16(build);
351
0
    ntlmssp_version.revision = revision;
352
0
}
353
354
static int ntlm_encode_version(struct ntlm_ctx *ctx,
355
                               struct ntlm_buffer *buffer,
356
                               size_t data_offs)
357
843
{
358
843
    if (data_offs + sizeof(struct wire_version) > buffer->length) {
359
0
        return ERR_ENCODE;
360
0
    }
361
362
843
    memcpy(&buffer->data[data_offs], &ntlmssp_version,
363
843
           sizeof(struct wire_version));
364
843
    return 0;
365
843
}
366
367
static int ntlm_encode_field(struct wire_field_hdr *hdr,
368
                             struct ntlm_buffer *buffer,
369
                             size_t *data_offs,
370
                             struct ntlm_buffer *field)
371
593
{
372
593
    if (*data_offs + field->length > buffer->length) {
373
0
        return ERR_ENCODE;
374
0
    }
375
376
593
    memcpy(&buffer->data[*data_offs], field->data, field->length);
377
593
    hdr->len = htole16(field->length);
378
593
    hdr->max_len = hdr->len;
379
593
    hdr->offset = htole32(*data_offs);
380
381
593
    *data_offs += field->length;
382
593
    return 0;
383
593
}
384
385
static int ntlm_decode_field(struct wire_field_hdr *hdr,
386
                             struct ntlm_buffer *buffer,
387
                             size_t payload_offs,
388
                             struct ntlm_buffer *field)
389
829
{
390
829
    struct ntlm_buffer b = { NULL, 0 };
391
829
    uint32_t offs;
392
829
    uint16_t len;
393
394
829
    len = le16toh(hdr->len);
395
829
    if (len == 0) goto done;
396
397
829
    offs = le32toh(hdr->offset);
398
829
    if ((offs < payload_offs) ||
399
829
        (offs > buffer->length) ||
400
829
        (UINT32_MAX - offs < len) ||
401
829
        (offs + len > buffer->length)) {
402
215
        return ERR_DECODE;
403
215
    }
404
405
614
    b.data = malloc(len);
406
614
    if (!b.data) return ENOMEM;
407
408
614
    b.length = len;
409
614
    memcpy(b.data, &buffer->data[offs], b.length);
410
411
614
done:
412
614
    *field = b;
413
614
    return 0;
414
614
}
415
416
static int ntlm_encode_av_pair_u16l_str(struct ntlm_ctx *ctx,
417
                                        struct ntlm_buffer *buffer,
418
                                        size_t *data_offs,
419
                                        enum msv_av_ids av_id,
420
                                        const char *str, size_t str_len)
421
2.87k
{
422
2.87k
    struct wire_av_pair *av_pair;
423
2.87k
    char *out;
424
2.87k
    size_t outlen;
425
2.87k
    int ret;
426
427
2.87k
    if (*data_offs + 4 + str_len > buffer->length) {
428
0
        return ERR_ENCODE;
429
0
    }
430
431
2.87k
    av_pair = (struct wire_av_pair *)&buffer->data[*data_offs];
432
2.87k
    out = (char *)av_pair->value;
433
434
2.87k
    ret = ntlm_str_convert(ctx->from_oem, str, out, str_len, &outlen);
435
2.87k
    if (ret) return ret;
436
437
2.87k
    av_pair->av_len = htole16(outlen);
438
2.87k
    av_pair->av_id = htole16(av_id);
439
440
2.87k
    *data_offs += av_pair->av_len + 4;
441
2.87k
    return 0;
442
2.87k
}
443
444
static int ntlm_decode_av_pair_u16l_str(struct ntlm_ctx *ctx,
445
                                        struct wire_av_pair *av_pair,
446
                                        char **str)
447
0
{
448
0
    char *in, *out;
449
0
    size_t inlen, outlen;
450
0
    int ret;
451
452
0
    in = (char *)av_pair->value;
453
0
    inlen = le16toh(av_pair->av_len);
454
0
    out = malloc(inlen * 2 + 1);
455
456
0
    ret = ntlm_str_convert(ctx->to_oem, in, out, inlen, &outlen);
457
0
    if (ret) {
458
0
        safefree(out);
459
0
        return ret;
460
0
    }
461
    /* terminate out string for sure */
462
0
    out[outlen] = '\0';
463
464
0
    *str = out;
465
0
    return 0;
466
0
}
467
468
static int ntlm_encode_av_pair_value(struct ntlm_buffer *buffer,
469
                                     size_t *data_offs,
470
                                     enum msv_av_ids av_id,
471
                                     struct ntlm_buffer *value)
472
1.91k
{
473
1.91k
    struct wire_av_pair *av_pair;
474
475
1.91k
    if (*data_offs + 4 + value->length > buffer->length) {
476
0
        return ERR_ENCODE;
477
0
    }
478
479
1.91k
    av_pair = (struct wire_av_pair *)&buffer->data[*data_offs];
480
1.91k
    av_pair->av_id = htole16(av_id);
481
1.91k
    av_pair->av_len = htole16(value->length);
482
1.91k
    if (value->length) {
483
957
        memcpy(av_pair->value, value->data, value->length);
484
957
    }
485
486
1.91k
    *data_offs += value->length + 4;
487
1.91k
    return 0;
488
1.91k
}
489
490
int ntlm_encode_target_info(struct ntlm_ctx *ctx, char *nb_computer_name,
491
                            char *nb_domain_name, char *dns_computer_name,
492
                            char *dns_domain_name, char *dns_tree_name,
493
                            uint32_t *av_flags, uint64_t *av_timestamp,
494
                            struct ntlm_buffer *av_single_host,
495
                            char *av_target_name, struct ntlm_buffer *av_cb,
496
                            struct ntlm_buffer *target_info)
497
957
{
498
957
    struct ntlm_buffer buffer;
499
957
    size_t data_offs;
500
957
    size_t max_size;
501
957
    size_t nb_computer_name_len = 0;
502
957
    size_t nb_domain_name_len = 0;
503
957
    size_t dns_computer_name_len = 0;
504
957
    size_t dns_domain_name_len = 0;
505
957
    size_t dns_tree_name_len = 0;
506
957
    size_t av_target_name_len = 0;
507
957
    struct ntlm_buffer value;
508
957
    int ret = 0;
509
510
957
    max_size = 4; /* MSV_AV_EOL */
511
512
957
    if (nb_computer_name) {
513
957
        nb_computer_name_len = strlen(nb_computer_name);
514
957
        max_size += 4 + nb_computer_name_len * 2;
515
957
    }
516
957
    if (nb_domain_name) {
517
957
        nb_domain_name_len = strlen(nb_domain_name);
518
957
        max_size += 4 + nb_domain_name_len * 2;
519
957
    }
520
957
    if (dns_computer_name) {
521
957
        dns_computer_name_len = strlen(dns_computer_name);
522
957
        max_size += 4 + dns_computer_name_len * 2;
523
957
    }
524
957
    if (dns_domain_name) {
525
0
        dns_domain_name_len = strlen(dns_domain_name);
526
0
        max_size += 4 + dns_domain_name_len * 2;
527
0
    }
528
957
    if (dns_tree_name) {
529
0
        dns_tree_name_len = strlen(dns_tree_name);
530
0
        max_size += 4 + dns_tree_name_len * 2;
531
0
    }
532
957
    if (av_flags) {
533
0
        max_size += 4 + 4;
534
0
    }
535
957
    if (av_timestamp) {
536
957
        max_size += 4 + 8;
537
957
    }
538
957
    if (av_single_host) {
539
0
        max_size += 4 + av_single_host->length;
540
0
    }
541
957
    if (av_target_name) {
542
0
        av_target_name_len = strlen(av_target_name);
543
0
        max_size += 4 + av_target_name_len * 2;
544
0
    }
545
957
    if (av_cb && av_cb->length > 0) {
546
0
        max_size += 4 + av_cb->length;
547
0
    }
548
549
957
    data_offs = 0;
550
957
    buffer.length = max_size;
551
957
    buffer.data = calloc(1, buffer.length);
552
957
    if (!buffer.data) return ENOMEM;
553
554
957
    if (nb_computer_name) {
555
957
        ret = ntlm_encode_av_pair_u16l_str(ctx, &buffer, &data_offs,
556
957
                                           MSV_AV_NB_COMPUTER_NAME,
557
957
                                           nb_computer_name,
558
957
                                           nb_computer_name_len);
559
957
        if (ret) goto done;
560
957
    }
561
957
    if (nb_domain_name) {
562
957
        ret = ntlm_encode_av_pair_u16l_str(ctx, &buffer, &data_offs,
563
957
                                           MSV_AV_NB_DOMAIN_NAME,
564
957
                                           nb_domain_name,
565
957
                                           nb_domain_name_len);
566
957
        if (ret) goto done;
567
957
    }
568
957
    if (dns_computer_name) {
569
957
        ret = ntlm_encode_av_pair_u16l_str(ctx, &buffer, &data_offs,
570
957
                                           MSV_AV_DNS_COMPUTER_NAME,
571
957
                                           dns_computer_name,
572
957
                                           dns_computer_name_len);
573
957
        if (ret) goto done;
574
957
    }
575
957
    if (dns_domain_name) {
576
0
        ret = ntlm_encode_av_pair_u16l_str(ctx, &buffer, &data_offs,
577
0
                                           MSV_AV_DNS_DOMAIN_NAME,
578
0
                                           dns_domain_name,
579
0
                                           dns_domain_name_len);
580
0
        if (ret) goto done;
581
0
    }
582
957
    if (dns_tree_name) {
583
0
        ret = ntlm_encode_av_pair_u16l_str(ctx, &buffer, &data_offs,
584
0
                                           MSV_AV_DNS_TREE_NAME,
585
0
                                           dns_tree_name,
586
0
                                           dns_tree_name_len);
587
0
        if (ret) goto done;
588
0
    }
589
957
    if (av_flags) {
590
0
        uint32_t flags = htole32(*av_flags);
591
0
        value.data = (uint8_t *)&flags;
592
0
        value.length = 4;
593
0
        ret = ntlm_encode_av_pair_value(&buffer, &data_offs,
594
0
                                        MSV_AV_FLAGS, &value);
595
0
        if (ret) goto done;
596
0
    }
597
957
    if (av_timestamp) {
598
957
        uint64_t timestamp = htole64(*av_timestamp);
599
957
        value.data = (uint8_t *)&timestamp;
600
957
        value.length = 8;
601
957
        ret = ntlm_encode_av_pair_value(&buffer, &data_offs,
602
957
                                        MSV_AV_TIMESTAMP, &value);
603
957
        if (ret) goto done;
604
957
    }
605
957
    if (av_single_host) {
606
0
        ret = ntlm_encode_av_pair_value(&buffer, &data_offs,
607
0
                                        MSV_AV_SINGLE_HOST, av_single_host);
608
0
        if (ret) goto done;
609
0
    }
610
957
    if (av_target_name) {
611
0
        ret = ntlm_encode_av_pair_u16l_str(ctx, &buffer, &data_offs,
612
0
                                           MSV_AV_TARGET_NAME,
613
0
                                           av_target_name,
614
0
                                           av_target_name_len);
615
0
        if (ret) goto done;
616
0
    }
617
957
    if (av_cb && av_cb->length > 0) {
618
0
        ret = ntlm_encode_av_pair_value(&buffer, &data_offs,
619
0
                                        MSV_AV_CHANNEL_BINDINGS, av_cb);
620
0
        if (ret) goto done;
621
0
    }
622
623
957
    value.length = 0;
624
957
    value.data = NULL;
625
957
    ret = ntlm_encode_av_pair_value(&buffer, &data_offs, MSV_AV_EOL, &value);
626
957
    buffer.length = data_offs;
627
628
957
done:
629
957
    if (ret) {
630
0
       safefree(buffer.data);
631
957
    } else {
632
957
        *target_info = buffer;
633
957
    }
634
957
    return ret;
635
957
}
636
637
int ntlm_decode_target_info(struct ntlm_ctx *ctx, struct ntlm_buffer *buffer,
638
                            char **nb_computer_name, char **nb_domain_name,
639
                            char **dns_computer_name, char **dns_domain_name,
640
                            char **dns_tree_name, char **av_target_name,
641
                            uint32_t *av_flags, uint64_t *av_timestamp,
642
                            struct ntlm_buffer *av_single_host,
643
                            struct ntlm_buffer *av_cb)
644
209
{
645
209
    struct wire_av_pair *av_pair;
646
209
    uint16_t av_id = (uint16_t)-1;
647
209
    uint16_t av_len = (uint16_t)-1;
648
209
    struct ntlm_buffer sh = { NULL, 0 };
649
209
    struct ntlm_buffer cb = { NULL, 0 };
650
209
    char *nb_computer = NULL;
651
209
    char *nb_domain = NULL;
652
209
    char *dns_computer = NULL;
653
209
    char *dns_domain = NULL;
654
209
    char *dns_tree = NULL;
655
209
    char *av_target = NULL;
656
209
    size_t data_offs = 0;
657
209
    uint64_t timestamp = 0;
658
209
    uint32_t flags = 0;
659
209
    int ret = 0;
660
661
3.35k
    while (data_offs + 4 <= buffer->length) {
662
3.23k
        av_pair = (struct wire_av_pair *)&buffer->data[data_offs];
663
3.23k
        data_offs += 4;
664
3.23k
        av_id = le16toh(av_pair->av_id);
665
3.23k
        av_len = le16toh(av_pair->av_len);
666
3.23k
        if (av_len > buffer->length - data_offs) {
667
46
            ret = ERR_DECODE;
668
46
            goto done;
669
46
        }
670
3.18k
        data_offs += av_len;
671
672
3.18k
        switch (av_id) {
673
298
        case MSV_AV_CHANNEL_BINDINGS:
674
298
            if (!av_cb) continue;
675
298
            cb.data = av_pair->value;
676
298
            cb.length = av_len;
677
298
            break;
678
238
        case MSV_AV_TARGET_NAME:
679
238
            if (!av_target_name) continue;
680
0
            ret = ntlm_decode_av_pair_u16l_str(ctx, av_pair, &av_target);
681
0
            if (ret) goto done;
682
0
            break;
683
242
        case MSV_AV_SINGLE_HOST:
684
242
            if (!av_single_host) continue;
685
0
            sh.data = av_pair->value;
686
0
            sh.length = av_len;
687
0
            break;
688
237
        case MSV_AV_TIMESTAMP:
689
237
            if (!av_timestamp) continue;
690
0
            if (av_len < sizeof(timestamp)) {
691
0
                ret = ERR_DECODE;
692
0
                goto done;
693
0
            }
694
0
            memcpy(&timestamp, av_pair->value, sizeof(timestamp));
695
0
            timestamp = le64toh(timestamp);
696
0
            break;
697
417
        case MSV_AV_FLAGS:
698
417
            if (!av_flags) continue;
699
417
            if (av_len < sizeof(flags)) {
700
4
                ret = ERR_DECODE;
701
4
                goto done;
702
4
            }
703
413
            memcpy(&flags, av_pair->value, sizeof(flags));
704
413
            flags = le32toh(flags);
705
413
            break;
706
200
        case MSV_AV_DNS_TREE_NAME:
707
200
            if (!dns_tree_name) continue;
708
0
            ret = ntlm_decode_av_pair_u16l_str(ctx, av_pair, &dns_tree);
709
0
            if (ret) goto done;
710
0
            break;
711
243
        case MSV_AV_DNS_DOMAIN_NAME:
712
243
            if (!dns_domain_name) continue;
713
0
            ret = ntlm_decode_av_pair_u16l_str(ctx, av_pair, &dns_domain);
714
0
            if (ret) goto done;
715
0
            break;
716
222
        case MSV_AV_DNS_COMPUTER_NAME:
717
222
            if (!dns_computer_name) continue;
718
0
            ret = ntlm_decode_av_pair_u16l_str(ctx, av_pair, &dns_computer);
719
0
            if (ret) goto done;
720
0
            break;
721
220
        case MSV_AV_NB_DOMAIN_NAME:
722
220
            if (!nb_domain_name) continue;
723
0
            ret = ntlm_decode_av_pair_u16l_str(ctx, av_pair, &nb_domain);
724
0
            if (ret) goto done;
725
0
            break;
726
381
        case MSV_AV_NB_COMPUTER_NAME:
727
381
            if (!nb_computer_name) continue;
728
0
            ret = ntlm_decode_av_pair_u16l_str(ctx, av_pair, &nb_computer);
729
0
            if (ret) goto done;
730
0
            break;
731
491
        default:
732
            /* unknown av_pair, or EOL */
733
491
            break;
734
3.18k
        }
735
1.20k
        if (av_id == MSV_AV_EOL) break;
736
1.20k
    }
737
738
159
    if (av_id != MSV_AV_EOL || av_len != 0) {
739
144
        ret = ERR_DECODE;
740
144
    }
741
742
209
done:
743
209
    if (ret) {
744
194
        safefree(nb_computer);
745
194
        safefree(nb_domain);
746
194
        safefree(dns_computer);
747
194
        safefree(dns_domain);
748
194
        safefree(dns_tree);
749
194
        safefree(av_target);
750
194
    } else {
751
15
        if (nb_computer_name) *nb_computer_name = nb_computer;
752
15
        if (nb_domain_name) *nb_domain_name = nb_domain;
753
15
        if (dns_computer_name) *dns_computer_name = dns_computer;
754
15
        if (dns_domain_name) *dns_domain_name = dns_domain;
755
15
        if (dns_tree_name) *dns_tree_name = dns_tree;
756
15
        if (av_target_name) *av_target_name = av_target;
757
15
        if (av_timestamp) *av_timestamp = timestamp;
758
15
        if (av_single_host) *av_single_host = sh;
759
15
        if (av_flags) *av_flags = flags;
760
15
        if (av_cb) *av_cb = cb;
761
15
    }
762
209
    return ret;
763
159
}
764
765
int ntlm_process_target_info(struct ntlm_ctx *ctx, bool protect,
766
                             struct ntlm_buffer *in,
767
                             const char *spn,
768
                             struct ntlm_buffer *unhashed_cb,
769
                             struct ntlm_buffer *out,
770
                             uint64_t *out_srv_time,
771
                             bool *add_mic)
772
0
{
773
0
    char *nb_computer_name = NULL;
774
0
    char *nb_domain_name = NULL;
775
0
    char *dns_computer_name = NULL;
776
0
    char *dns_domain_name = NULL;
777
0
    char *dns_tree_name = NULL;
778
0
    char *av_target_name = NULL;
779
0
    uint32_t av_flags = 0;
780
0
    uint64_t srv_time = 0;
781
0
    uint8_t cb[16] = { 0 };
782
0
    struct ntlm_buffer av_cb = { NULL, 0 };
783
0
    int ret = 0;
784
785
    /* TODO: check that returned netbios/dns names match ? */
786
    /* TODO: support SingleHost buffers */
787
0
    ret = ntlm_decode_target_info(ctx, in,
788
0
                                  &nb_computer_name, &nb_domain_name,
789
0
                                  &dns_computer_name, &dns_domain_name,
790
0
                                  &dns_tree_name, &av_target_name,
791
0
                                  &av_flags, &srv_time, NULL, NULL);
792
0
    if (ret) goto done;
793
794
0
    if (protect && (!nb_computer_name || nb_computer_name[0] == '\0')) {
795
0
        ret = EINVAL;
796
0
        goto done;
797
0
    }
798
799
0
    if (spn && av_target_name &&
800
0
        ((av_flags & MSVAVFLAGS_UNVERIFIED_SPN) == 0)) {
801
0
        if (strcasecmp(spn, av_target_name) != 0) {
802
0
            ret = EINVAL;
803
0
            goto done;
804
0
        }
805
0
    }
806
807
    /* the server did not send the timestamp, use current time */
808
0
    if (srv_time == 0) {
809
0
        srv_time = ntlm_timestamp_now();
810
0
    } else if (add_mic) {
811
0
        av_flags |= MSVAVFLAGS_MIC_PRESENT;
812
0
        *add_mic = true;
813
0
    }
814
815
0
    if (unhashed_cb->length > 0) {
816
0
        av_cb.data = cb;
817
0
        av_cb.length = 16;
818
0
        ret = ntlm_hash_channel_bindings(unhashed_cb, &av_cb);
819
0
        if (ret) goto done;
820
0
    }
821
822
0
    if (!av_target_name && spn) {
823
0
        av_target_name = strdup(spn);
824
0
        if (!av_target_name) {
825
0
            ret = ENOMEM;
826
0
            goto done;
827
0
        }
828
0
    }
829
830
0
    ret = ntlm_encode_target_info(ctx,
831
0
                                  nb_computer_name, nb_domain_name,
832
0
                                  dns_computer_name, dns_domain_name,
833
0
                                  dns_tree_name, &av_flags, &srv_time,
834
0
                                  NULL, av_target_name, &av_cb, out);
835
836
0
done:
837
0
    safefree(nb_computer_name);
838
0
    safefree(nb_domain_name);
839
0
    safefree(dns_computer_name);
840
0
    safefree(dns_domain_name);
841
0
    safefree(dns_tree_name);
842
0
    safefree(av_target_name);
843
0
    *out_srv_time = srv_time;
844
0
    return ret;
845
0
}
846
847
int ntlm_decode_msg_type(struct ntlm_ctx *ctx,
848
                         struct ntlm_buffer *buffer,
849
                         uint32_t *type)
850
2.08k
{
851
2.08k
    struct wire_neg_msg *msg;
852
2.08k
    uint32_t msg_type;
853
2.08k
    int ret;
854
855
2.08k
    if (!ctx) return EINVAL;
856
857
2.08k
    if (buffer->length < sizeof(struct wire_msg_hdr)) {
858
30
        return ERR_DECODE;
859
30
    }
860
861
2.05k
    msg = (struct wire_neg_msg *)buffer->data;
862
863
2.05k
    ret = ntlm_decode_header(&msg->header, &msg_type);
864
2.05k
    if (ret) goto done;
865
866
1.95k
    switch (msg_type) {
867
975
    case NEGOTIATE_MESSAGE:
868
975
        if (buffer->length < sizeof(struct wire_neg_msg)) {
869
10
            return ERR_DECODE;
870
10
        }
871
965
        break;
872
965
    case CHALLENGE_MESSAGE:
873
29
        if (buffer->length < sizeof(struct wire_chal_msg) &&
874
29
            buffer->length != sizeof(struct wire_chal_msg_old)) {
875
14
            return ERR_DECODE;
876
14
        }
877
15
        break;
878
944
    case AUTHENTICATE_MESSAGE:
879
944
        if (buffer->length < sizeof(struct wire_auth_msg)) {
880
12
            return ERR_DECODE;
881
12
        }
882
932
        break;
883
932
    default:
884
3
        ret = ERR_DECODE;
885
3
        break;
886
1.95k
    }
887
888
2.01k
done:
889
2.01k
    if (ret == 0) {
890
1.91k
        *type = msg_type;
891
1.91k
    }
892
2.01k
    return ret;
893
1.95k
}
894
895
int ntlm_encode_neg_msg(struct ntlm_ctx *ctx, uint32_t flags,
896
                        const char *domain, const char *workstation,
897
                        struct ntlm_buffer *message)
898
0
{
899
0
    struct wire_neg_msg *msg;
900
0
    struct ntlm_buffer buffer;
901
0
    size_t data_offs;
902
0
    size_t dom_len = 0;
903
0
    size_t wks_len = 0;
904
0
    int ret = 0;
905
906
0
    if (!ctx) return EINVAL;
907
908
0
    buffer.length = sizeof(struct wire_neg_msg);
909
910
    /* Strings MUST use OEM charset in negotiate message */
911
0
    if (flags & NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED) {
912
0
        if (!domain) return EINVAL;
913
0
        dom_len = strlen(domain);
914
0
        buffer.length += dom_len;
915
0
    }
916
0
    if (flags & NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED) {
917
0
        if (!workstation) return EINVAL;
918
0
        wks_len = strlen(workstation);
919
0
        buffer.length += wks_len;
920
0
    }
921
922
0
    buffer.data = calloc(1, buffer.length);
923
0
    if (!buffer.data) return ENOMEM;
924
925
0
    msg = (struct wire_neg_msg *)buffer.data;
926
0
    data_offs = (char *)msg->payload - (char *)msg;
927
928
0
    ntlm_encode_header(&msg->header, NEGOTIATE_MESSAGE);
929
930
0
    msg->neg_flags = htole32(flags);
931
932
0
    if (dom_len) {
933
0
        ret = ntlm_encode_oem_str(&msg->domain_name, &buffer,
934
0
                                  &data_offs, domain, dom_len);
935
0
        if (ret) goto done;
936
0
    }
937
938
0
    if (wks_len) {
939
0
        ret = ntlm_encode_oem_str(&msg->workstation_name, &buffer,
940
0
                                  &data_offs, workstation, wks_len);
941
0
        if (ret) goto done;
942
0
    }
943
944
0
    if (flags & NTLMSSP_NEGOTIATE_VERSION) {
945
0
        ret = ntlm_encode_version(ctx, &buffer,
946
0
                                  (char *)&msg->version - (char *)msg);
947
0
        if (ret) goto done;
948
0
    }
949
950
0
done:
951
0
    if (ret) {
952
0
        safefree(buffer.data);
953
0
    } else {
954
0
        *message = buffer;
955
0
    }
956
0
    return ret;
957
0
}
958
959
int ntlm_decode_neg_msg(struct ntlm_ctx *ctx,
960
                        struct ntlm_buffer *buffer, uint32_t *flags,
961
                        char **domain, char **workstation)
962
961
{
963
961
    struct wire_neg_msg *msg;
964
961
    size_t payload_offs;
965
961
    uint32_t neg_flags;
966
961
    char *dom = NULL;
967
961
    char *wks = NULL;
968
961
    int ret = 0;
969
970
961
    if (!ctx) return EINVAL;
971
972
961
    msg = (struct wire_neg_msg *)buffer->data;
973
961
    payload_offs = (char *)msg->payload - (char *)msg;
974
975
961
    neg_flags = le32toh(msg->neg_flags);
976
977
961
    if ((neg_flags & NTLMSSP_NEGOTIATE_VERSION) == 0) {
978
        /* adjust the payload offset to point to the
979
         * version field, for compatibility with older
980
         * clients that completely omitted the structure
981
         * on the wire */
982
659
        payload_offs -= sizeof(struct wire_version);
983
659
    }
984
985
961
    if (domain &&
986
961
        (neg_flags & NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED)) {
987
0
        ret = ntlm_decode_oem_str(&msg->domain_name, buffer,
988
0
                                  payload_offs, &dom);
989
0
        if (ret) goto done;
990
0
    }
991
961
    if (workstation &&
992
961
        (neg_flags & NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED)) {
993
0
        ret = ntlm_decode_oem_str(&msg->workstation_name, buffer,
994
0
                                  payload_offs, &wks);
995
0
        if (ret) goto done;
996
0
    }
997
998
961
done:
999
961
    if (ret) {
1000
0
        safefree(dom);
1001
0
        safefree(wks);
1002
961
    } else {
1003
961
        *flags = neg_flags;
1004
961
        if (domain) *domain = dom;
1005
961
        if (workstation) *workstation = wks;
1006
961
    }
1007
961
    return ret;
1008
961
}
1009
1010
int ntlm_encode_chal_msg(struct ntlm_ctx *ctx,
1011
                         uint32_t flags,
1012
                         const char *target_name,
1013
                         struct ntlm_buffer *challenge,
1014
                         struct ntlm_buffer *target_info,
1015
                         struct ntlm_buffer *message)
1016
957
{
1017
957
    struct wire_chal_msg *msg;
1018
957
    struct ntlm_buffer buffer;
1019
957
    size_t data_offs;
1020
957
    size_t target_len = 0;
1021
957
    int ret = 0;
1022
1023
957
    if (!ctx) return EINVAL;
1024
1025
957
    if (!challenge || challenge->length != 8) return EINVAL;
1026
1027
957
    buffer.length = sizeof(struct wire_chal_msg);
1028
1029
957
    if ((flags & NTLMSSP_TARGET_TYPE_SERVER)
1030
957
        || (flags & NTLMSSP_TARGET_TYPE_DOMAIN)) {
1031
957
        if (!target_name) return EINVAL;
1032
1033
957
        target_len = strlen(target_name);
1034
957
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1035
314
            buffer.length += target_len * 2;
1036
643
        } else {
1037
643
            buffer.length += target_len;
1038
643
        }
1039
957
    }
1040
1041
957
    if (flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
1042
593
        if (!target_info) return EINVAL;
1043
1044
593
        buffer.length += target_info->length;
1045
593
    }
1046
1047
957
    buffer.data = calloc(1, buffer.length);
1048
957
    if (!buffer.data) return ENOMEM;
1049
1050
957
    msg = (struct wire_chal_msg *)buffer.data;
1051
957
    data_offs = (char *)msg->payload - (char *)msg;
1052
1053
957
    ntlm_encode_header(&msg->header, CHALLENGE_MESSAGE);
1054
1055
    /* this must be first as it pushes the payload further down */
1056
957
    if (flags & NTLMSSP_NEGOTIATE_VERSION) {
1057
843
        ret = ntlm_encode_version(ctx, &buffer,
1058
843
                                  (char *)&msg->version - (char *)msg);
1059
843
        if (ret) goto done;
1060
843
    }
1061
1062
957
    if ((flags & NTLMSSP_TARGET_TYPE_SERVER)
1063
957
        || (flags & NTLMSSP_TARGET_TYPE_DOMAIN)) {
1064
957
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1065
314
            ret = ntlm_encode_u16l_str_hdr(ctx, &msg->target_name, &buffer,
1066
314
                                           &data_offs, target_name, target_len);
1067
643
        } else {
1068
643
            ret = ntlm_encode_oem_str(&msg->target_name, &buffer,
1069
643
                                      &data_offs, target_name, target_len);
1070
643
        }
1071
957
        if (ret) goto done;
1072
957
    }
1073
1074
957
    msg->neg_flags = htole32(flags);
1075
957
    memcpy(msg->server_challenge, challenge->data, 8);
1076
1077
957
    if (flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
1078
593
        ret = ntlm_encode_field(&msg->target_info, &buffer,
1079
593
                                &data_offs, target_info);
1080
593
        if (ret) goto done;
1081
593
    }
1082
1083
957
done:
1084
957
    if (ret) {
1085
0
        safefree(buffer.data);
1086
957
    } else {
1087
957
        *message = buffer;
1088
957
    }
1089
957
    return ret;
1090
957
}
1091
1092
int ntlm_decode_chal_msg(struct ntlm_ctx *ctx,
1093
                         struct ntlm_buffer *buffer,
1094
                         uint32_t *_flags, char **target_name,
1095
                         struct ntlm_buffer *challenge,
1096
                         struct ntlm_buffer *target_info)
1097
0
{
1098
0
    struct wire_chal_msg *msg;
1099
0
    size_t payload_offs;
1100
0
    size_t base_chal_size;
1101
0
    uint32_t flags;
1102
0
    char *trg = NULL;
1103
0
    int ret = 0;
1104
1105
0
    if (!ctx) return EINVAL;
1106
1107
0
    if (challenge->length < 8) return EINVAL;
1108
1109
0
    msg = (struct wire_chal_msg *)buffer->data;
1110
0
    payload_offs = (char *)msg->payload - (char *)msg;
1111
1112
0
    flags = le32toh(msg->neg_flags);
1113
0
    base_chal_size = sizeof(struct wire_chal_msg);
1114
1115
0
    if ((flags & NTLMSSP_NEGOTIATE_VERSION) == 0) {
1116
        /* adjust the payload offset to point to the
1117
         * version field, for compatibility with older
1118
         * clients that completely omitted the structure
1119
         * on the wire */
1120
0
        payload_offs -= sizeof(struct wire_version);
1121
0
        base_chal_size -= sizeof(struct wire_version);
1122
0
    }
1123
1124
0
    if ((flags & NTLMSSP_TARGET_TYPE_SERVER)
1125
0
        || (flags & NTLMSSP_TARGET_TYPE_DOMAIN)) {
1126
0
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1127
0
            ret = ntlm_decode_u16l_str_hdr(ctx, &msg->target_name, buffer,
1128
0
                                           payload_offs, &trg);
1129
0
        } else {
1130
0
            ret = ntlm_decode_oem_str(&msg->target_name, buffer,
1131
0
                                      payload_offs, &trg);
1132
0
        }
1133
0
        if (ret) goto done;
1134
0
    }
1135
1136
0
    memcpy(challenge->data, msg->server_challenge, 8);
1137
0
    challenge->length = 8;
1138
1139
    /* if we allowed a broken short challenge message from an old
1140
     * server we must stop here */
1141
0
    if (buffer->length < base_chal_size) {
1142
0
        if (flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
1143
0
            ret = ERR_DECODE;
1144
0
        }
1145
0
        goto done;
1146
0
    }
1147
1148
0
    if (flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
1149
0
        ret = ntlm_decode_field(&msg->target_info, buffer,
1150
0
                                payload_offs, target_info);
1151
0
        if (ret) goto done;
1152
0
    }
1153
1154
0
done:
1155
0
    if (ret) {
1156
0
        safefree(trg);
1157
0
    } else {
1158
0
        *_flags = flags;
1159
0
        *target_name = trg;
1160
0
    }
1161
0
    return ret;
1162
0
}
1163
1164
int ntlm_encode_auth_msg(struct ntlm_ctx *ctx,
1165
                         uint32_t flags,
1166
                         struct ntlm_buffer *lm_chalresp,
1167
                         struct ntlm_buffer *nt_chalresp,
1168
                         char *domain_name, char *user_name,
1169
                         char *workstation,
1170
                         struct ntlm_buffer *enc_sess_key,
1171
                         struct ntlm_buffer *mic,
1172
                         struct ntlm_buffer *message)
1173
0
{
1174
0
    struct wire_auth_msg *msg;
1175
0
    struct ntlm_buffer buffer;
1176
0
    struct ntlm_buffer empty_chalresp = { 0 };
1177
0
    size_t data_offs;
1178
0
    size_t domain_name_len = 0;
1179
0
    size_t user_name_len = 0;
1180
0
    size_t workstation_len = 0;
1181
0
    int ret = 0;
1182
1183
0
    if (!ctx) return EINVAL;
1184
1185
0
    buffer.length = sizeof(struct wire_auth_msg);
1186
1187
0
    if (lm_chalresp) {
1188
0
        buffer.length += lm_chalresp->length;
1189
0
    } else {
1190
0
        lm_chalresp = &empty_chalresp;
1191
0
    }
1192
0
    if (nt_chalresp) {
1193
0
        buffer.length += nt_chalresp->length;
1194
0
    } else {
1195
0
        nt_chalresp = &empty_chalresp;
1196
0
    }
1197
0
    if (domain_name) {
1198
0
        domain_name_len = strlen(domain_name);
1199
0
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1200
0
            buffer.length += domain_name_len * 2;
1201
0
        } else {
1202
0
            buffer.length += domain_name_len;
1203
0
        }
1204
0
    }
1205
0
    if (user_name) {
1206
0
        user_name_len = strlen(user_name);
1207
0
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1208
0
            buffer.length += user_name_len * 2;
1209
0
        } else {
1210
0
            buffer.length += user_name_len;
1211
0
        }
1212
0
    }
1213
0
    if (workstation) {
1214
0
        workstation_len = strlen(workstation);
1215
0
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1216
0
            buffer.length += workstation_len * 2;
1217
0
        } else {
1218
0
            buffer.length += workstation_len;
1219
0
        }
1220
0
    }
1221
0
    if (enc_sess_key) {
1222
0
        buffer.length += enc_sess_key->length;
1223
0
    }
1224
0
    if (mic) {
1225
0
        buffer.length += 16;
1226
0
    }
1227
1228
0
    buffer.data = calloc(1, buffer.length);
1229
0
    if (!buffer.data) return ENOMEM;
1230
1231
0
    msg = (struct wire_auth_msg *)buffer.data;
1232
0
    data_offs = (char *)msg->payload - (char *)msg;
1233
1234
0
    ntlm_encode_header(&msg->header, AUTHENTICATE_MESSAGE);
1235
1236
    /* this must be first as it pushes the payload further down */
1237
0
    if (flags & NTLMSSP_NEGOTIATE_VERSION) {
1238
0
        ret = ntlm_encode_version(ctx, &buffer,
1239
0
                                  (char *)&msg->version - (char *)msg);
1240
0
        if (ret) goto done;
1241
0
    }
1242
1243
    /* this pushes the payload further down */
1244
0
    if (mic) {
1245
0
        memset(&buffer.data[data_offs], 0, mic->length);
1246
        /* return the actual pointer back in the mic, as it will
1247
         * be backfilled later by the caller */
1248
0
        mic->data = &buffer.data[data_offs];
1249
0
        data_offs += mic->length;
1250
0
    }
1251
1252
0
    ret = ntlm_encode_field(&msg->lm_chalresp, &buffer,
1253
0
                            &data_offs, lm_chalresp);
1254
0
    if (ret) goto done;
1255
1256
0
    ret = ntlm_encode_field(&msg->nt_chalresp, &buffer,
1257
0
                            &data_offs, nt_chalresp);
1258
0
    if (ret) goto done;
1259
1260
0
    if (domain_name_len) {
1261
0
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1262
0
            ret = ntlm_encode_u16l_str_hdr(ctx, &msg->domain_name,
1263
0
                                           &buffer, &data_offs,
1264
0
                                           domain_name, domain_name_len);
1265
0
        } else {
1266
0
            ret = ntlm_encode_oem_str(&msg->domain_name,
1267
0
                                      &buffer, &data_offs,
1268
0
                                      domain_name, domain_name_len);
1269
0
        }
1270
0
        if (ret) goto done;
1271
0
    }
1272
0
    if (user_name_len) {
1273
0
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1274
0
            ret = ntlm_encode_u16l_str_hdr(ctx, &msg->user_name,
1275
0
                                           &buffer, &data_offs,
1276
0
                                           user_name, user_name_len);
1277
0
        } else {
1278
0
            ret = ntlm_encode_oem_str(&msg->user_name,
1279
0
                                      &buffer, &data_offs,
1280
0
                                      user_name, user_name_len);
1281
0
        }
1282
0
        if (ret) goto done;
1283
0
    }
1284
0
    if (workstation_len) {
1285
0
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1286
0
            ret = ntlm_encode_u16l_str_hdr(ctx, &msg->workstation,
1287
0
                                           &buffer, &data_offs,
1288
0
                                           workstation, workstation_len);
1289
0
        } else {
1290
0
            ret = ntlm_encode_oem_str(&msg->workstation,
1291
0
                                      &buffer, &data_offs,
1292
0
                                      workstation, workstation_len);
1293
0
        }
1294
0
        if (ret) goto done;
1295
0
    }
1296
0
    if (enc_sess_key) {
1297
0
        ret = ntlm_encode_field(&msg->enc_sess_key, &buffer,
1298
0
                                &data_offs, enc_sess_key);
1299
0
        if (ret) goto done;
1300
0
    }
1301
1302
0
    msg->neg_flags = htole32(flags);
1303
1304
0
done:
1305
0
    if (ret) {
1306
0
        safefree(buffer.data);
1307
0
    } else {
1308
0
        *message = buffer;
1309
0
    }
1310
0
    return ret;
1311
0
}
1312
1313
int ntlm_decode_auth_msg(struct ntlm_ctx *ctx,
1314
                         struct ntlm_buffer *buffer,
1315
                         uint32_t flags,
1316
                         struct ntlm_buffer *lm_chalresp,
1317
                         struct ntlm_buffer *nt_chalresp,
1318
                         char **domain_name, char **user_name,
1319
                         char **workstation,
1320
                         struct ntlm_buffer *enc_sess_key,
1321
                         struct ntlm_buffer *target_info,
1322
                         struct ntlm_buffer *mic)
1323
921
{
1324
921
    struct wire_auth_msg *msg;
1325
921
    uint32_t neg_flags;
1326
921
    size_t payload_offs;
1327
921
    char *dom = NULL;
1328
921
    char *usr = NULL;
1329
921
    char *wks = NULL;
1330
921
    int ret = 0;
1331
1332
921
    if (!ctx) return EINVAL;
1333
1334
921
    if (lm_chalresp) lm_chalresp->data = NULL;
1335
921
    if (nt_chalresp) nt_chalresp->data = NULL;
1336
921
    if (enc_sess_key) enc_sess_key->data = NULL;
1337
1338
921
    msg = (struct wire_auth_msg *)buffer->data;
1339
921
    payload_offs = (char *)msg->payload - (char *)msg;
1340
1341
921
    neg_flags = le32toh(msg->neg_flags);
1342
921
    if ((neg_flags & NTLMSSP_NEGOTIATE_VERSION) == 0) {
1343
        /* adjust the payload offset to point to the
1344
         * version field, for compatibility with older
1345
         * clients that completely omitted the structure
1346
         * on the wire */
1347
916
        payload_offs -= sizeof(struct wire_version);
1348
916
    }
1349
1350
    /* Unconditionally copy 16 bytes for the MIC, if it was really
1351
     * added by the client it will be flagged in the AV_PAIR contained
1352
     * in the NT Response, that will be fully decoded later by the caller
1353
     * and the MIC checked otherwise these 16 bytes will just be ignored */
1354
921
    if (mic) {
1355
921
        size_t mic_offs = payload_offs;
1356
1357
921
        if (mic->length < 16) return ERR_DECODE;
1358
1359
921
        if ((neg_flags & NTLMSSP_NEGOTIATE_VERSION) == 0) {
1360
916
            struct wire_version zver = {0};
1361
            /* mic is at payload_offs right now, but this offset may be
1362
             * wrongly reduced for compatibility with older clients,
1363
             * if all bytes are zeroed, then it means there was an actual
1364
             * empty version struct */
1365
916
            if (memcmp(&msg->version, &zver,
1366
916
                       sizeof(struct wire_version)) == 0) {
1367
29
                mic_offs += sizeof(struct wire_version);
1368
29
            }
1369
916
        }
1370
1371
921
        if (buffer->length - mic_offs < 16) return ERR_DECODE;
1372
908
        memcpy(mic->data, &buffer->data[mic_offs], 16);
1373
908
    }
1374
1375
908
    if (msg->lm_chalresp.len != 0 && lm_chalresp) {
1376
271
        ret = ntlm_decode_field(&msg->lm_chalresp, buffer,
1377
271
                                payload_offs, lm_chalresp);
1378
271
        if (ret) goto done;
1379
271
    }
1380
847
    if (msg->nt_chalresp.len != 0 && nt_chalresp) {
1381
344
        ret = ntlm_decode_field(&msg->nt_chalresp, buffer,
1382
344
                                payload_offs, nt_chalresp);
1383
344
        if (ret) goto done;
1384
1385
276
        if (target_info) {
1386
276
            union wire_ntlm_response *resp;
1387
276
            struct wire_ntlmv2_cli_chal *chal;
1388
276
            uint8_t *data;
1389
276
            int len;
1390
276
            resp = (union wire_ntlm_response *)nt_chalresp->data;
1391
276
            chal = (struct wire_ntlmv2_cli_chal *)resp->v2.cli_chal;
1392
276
            len = nt_chalresp->length - sizeof(resp->v2.resp)
1393
276
                    - offsetof(struct wire_ntlmv2_cli_chal, target_info);
1394
276
            if (len > 0) {
1395
228
                data = chal->target_info;
1396
228
                target_info->data = malloc(len);
1397
228
                if (!target_info->data) {
1398
0
                    ret = ENOMEM;
1399
0
                    goto done;
1400
0
                }
1401
228
                memcpy(target_info->data, data, len);
1402
228
                target_info->length = len;
1403
228
            }
1404
276
        }
1405
276
    }
1406
779
    if (msg->domain_name.len != 0 && domain_name) {
1407
355
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1408
128
            ret = ntlm_decode_u16l_str_hdr(ctx, &msg->domain_name, buffer,
1409
128
                                           payload_offs, &dom);
1410
227
        } else {
1411
227
            ret = ntlm_decode_oem_str(&msg->domain_name, buffer,
1412
227
                                      payload_offs, &dom);
1413
227
        }
1414
355
        if (ret) goto done;
1415
355
    }
1416
661
    if (msg->user_name.len != 0 && user_name) {
1417
330
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1418
111
            ret = ntlm_decode_u16l_str_hdr(ctx, &msg->user_name, buffer,
1419
111
                                           payload_offs, &usr);
1420
219
        } else {
1421
219
            ret = ntlm_decode_oem_str(&msg->user_name, buffer,
1422
219
                                      payload_offs, &usr);
1423
219
        }
1424
330
        if (ret) goto done;
1425
330
    }
1426
556
    if (msg->workstation.len != 0 && workstation) {
1427
200
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1428
66
            ret = ntlm_decode_u16l_str_hdr(ctx, &msg->workstation, buffer,
1429
66
                                           payload_offs, &wks);
1430
134
        } else {
1431
134
            ret = ntlm_decode_oem_str(&msg->workstation, buffer,
1432
134
                                      payload_offs, &wks);
1433
134
        }
1434
200
        if (ret) goto done;
1435
200
    }
1436
459
    if (msg->enc_sess_key.len != 0 && enc_sess_key) {
1437
214
        ret = ntlm_decode_field(&msg->enc_sess_key, buffer,
1438
214
                                payload_offs, enc_sess_key);
1439
214
    }
1440
1441
    /* ignore returned flags, our flags are authoritative
1442
    flags = le32toh(msg->neg_flags);
1443
    */
1444
1445
908
done:
1446
908
    if (ret) {
1447
535
        if (lm_chalresp) safefree(lm_chalresp->data);
1448
535
        if (nt_chalresp) safefree(nt_chalresp->data);
1449
535
        if (enc_sess_key) safefree(enc_sess_key->data);
1450
535
        safefree(dom);
1451
535
        safefree(usr);
1452
535
        safefree(wks);
1453
535
    } else {
1454
373
        if (domain_name) *domain_name = dom;
1455
373
        if (user_name) *user_name = usr;
1456
373
        if (workstation) *workstation = wks;
1457
373
    }
1458
908
    return ret;
1459
459
}