Coverage Report

Created: 2026-05-30 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gss-ntlmssp/src/ntlm.c
Line
Count
Source
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.17k
{
75
1.17k
    struct ntlm_ctx *_ctx;
76
1.17k
    int ret = 0;
77
78
1.17k
    _ctx = calloc(1, sizeof(struct ntlm_ctx));
79
1.17k
    if (!_ctx) return ENOMEM;
80
81
1.17k
    _ctx->from_oem = iconv_open("UTF-16LE", "UTF-8");
82
1.17k
    if (_ctx->from_oem == (iconv_t) -1) {
83
0
        ret = errno;
84
0
    }
85
86
1.17k
    _ctx->to_oem = iconv_open("UTF-8", "UTF-16LE");
87
1.17k
    if (_ctx->to_oem == (iconv_t) -1) {
88
0
        iconv_close(_ctx->from_oem);
89
0
        ret = errno;
90
0
    }
91
92
1.17k
    if (ret) {
93
0
        safefree(_ctx);
94
1.17k
    } else {
95
1.17k
        *ctx = _ctx;
96
1.17k
    }
97
1.17k
    return ret;
98
1.17k
}
99
100
int ntlm_free_ctx(struct ntlm_ctx **ctx)
101
1.17k
{
102
1.17k
    int ret;
103
104
1.17k
    if (!ctx || !*ctx) return 0;
105
106
1.17k
    if ((*ctx)->from_oem) {
107
1.17k
        ret = iconv_close((*ctx)->from_oem);
108
1.17k
        if (ret) goto done;
109
1.17k
    }
110
111
1.17k
    if ((*ctx)->to_oem) {
112
1.17k
        ret = iconv_close((*ctx)->to_oem);
113
1.17k
    }
114
115
1.17k
done:
116
1.17k
    if (ret) ret = errno;
117
1.17k
    safefree(*ctx);
118
1.17k
    return ret;
119
1.17k
}
120
121
void ntlm_free_buffer_data(struct ntlm_buffer *buf)
122
8.63k
{
123
8.63k
    if (!buf) return;
124
125
8.63k
    safefree(buf->data);
126
8.63k
    buf->length = 0;
127
8.63k
}
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
1.00k
#define FILETIME_EPOCH_VALUE 116444736000000000LL
133
uint64_t ntlm_timestamp_now(void)
134
1.00k
{
135
1.00k
    struct timeval tv;
136
1.00k
    uint64_t filetime;
137
138
1.00k
    gettimeofday(&tv, NULL);
139
140
    /* set filetime to the time representing the eopch */
141
1.00k
    filetime = FILETIME_EPOCH_VALUE;
142
    /* add the number of seconds since the epoch */
143
1.00k
    filetime += (uint64_t)tv.tv_sec * 10000000;
144
    /* add the number of microseconds since the epoch */
145
1.00k
    filetime += tv.tv_usec * 10;
146
147
1.00k
    return filetime;
148
1.00k
}
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.49k
{
186
3.49k
    char *_in;
187
3.49k
    size_t inleft, outleft;
188
3.49k
    size_t ret;
189
190
3.49k
    ret = iconv(cd, NULL, NULL, NULL, NULL);
191
3.49k
    if (ret == -1) return errno;
192
193
3.49k
    _in = discard_const(in);
194
3.49k
    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.49k
    outleft = baselen * 2;
198
199
3.49k
    ret = iconv(cd, &_in, &inleft, &out, &outleft);
200
3.49k
    if (ret == -1) return errno;
201
202
3.47k
    if (outlen) {
203
3.47k
        *outlen = baselen * 2 - outleft;
204
3.47k
    }
205
3.47k
    return 0;
206
3.49k
}
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
1.00k
{
212
1.00k
    memcpy(hdr->signature, ntlmssp_sig, 8);
213
1.00k
    hdr->msg_type = htole32(msg_type);
214
1.00k
}
215
216
static int ntlm_decode_header(struct wire_msg_hdr *hdr, uint32_t *msg_type)
217
2.13k
{
218
2.13k
    if (memcmp(hdr->signature, ntlmssp_sig, 8) != 0) {
219
99
        return ERR_DECODE;
220
99
    }
221
222
2.03k
    *msg_type = le32toh(hdr->msg_type);
223
2.03k
    return 0;
224
2.13k
}
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
727
{
231
727
    if (*data_offs + str_len > buffer->length) {
232
0
        return ERR_ENCODE;
233
0
    }
234
235
727
    memcpy(&buffer->data[*data_offs], str, str_len);
236
727
    hdr->len = htole16(str_len);
237
727
    hdr->max_len = htole16(str_len);
238
727
    hdr->offset = htole32(*data_offs);
239
240
727
    *data_offs += str_len;
241
727
    return 0;
242
727
}
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
785
{
248
785
    uint16_t str_len;
249
785
    uint32_t str_offs;
250
785
    char *str = NULL;
251
252
785
    str_len = le16toh(str_hdr->len);
253
785
    if (str_len == 0) goto done;
254
255
785
    str_offs = le32toh(str_hdr->offset);
256
785
    if ((str_offs < payload_offs) ||
257
762
        (str_offs > buffer->length) ||
258
631
        (UINT32_MAX - str_offs < str_len) ||
259
631
        (str_offs + str_len > buffer->length)) {
260
227
        return ERR_DECODE;
261
227
    }
262
263
558
    str = strndup((const char *)&buffer->data[str_offs], str_len);
264
558
    if (!str) return ENOMEM;
265
266
558
done:
267
558
    *_str = str;
268
558
    return 0;
269
558
}
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
274
{
277
274
    char *out;
278
274
    size_t outlen;
279
274
    int ret;
280
281
274
    out = (char *)&buffer->data[*data_offs];
282
283
274
    ret = ntlm_str_convert(ctx->from_oem, str, out, str_len, &outlen);
284
274
    if (ret) return ret;
285
286
274
    hdr->len = htole16(outlen);
287
274
    hdr->max_len = htole16(outlen);
288
274
    hdr->offset = htole32(*data_offs);
289
290
274
    *data_offs += outlen;
291
274
    return 0;
292
274
}
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
291
{
299
291
    char *in, *out = NULL;
300
291
    uint16_t str_len;
301
291
    uint32_t str_offs;
302
291
    size_t outlen = 0;
303
291
    int ret = 0;
304
305
291
    str_len = le16toh(str_hdr->len);
306
291
    if (str_len == 0) goto done;
307
308
291
    str_offs = le32toh(str_hdr->offset);
309
291
    if ((str_offs < payload_offs) ||
310
281
        (str_offs > buffer->length) ||
311
243
        (UINT32_MAX - str_offs < str_len) ||
312
243
        (str_offs + str_len > buffer->length)) {
313
71
        return ERR_DECODE;
314
71
    }
315
316
220
    in = (char *)&buffer->data[str_offs];
317
318
220
    out = malloc(str_len * 2 + 1);
319
220
    if (!out) return ENOMEM;
320
321
220
    ret = ntlm_str_convert(ctx->to_oem, in, out, str_len, &outlen);
322
323
220
done:
324
220
    if (ret) {
325
21
        safefree(out);
326
199
    } else {
327
        /* make sure to terminate output string */
328
199
        if (out) {
329
199
            out[outlen] = '\0';
330
199
        }
331
199
    }
332
333
220
    *str = out;
334
220
    return ret;
335
220
}
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
858
{
358
858
    if (data_offs + sizeof(struct wire_version) > buffer->length) {
359
0
        return ERR_ENCODE;
360
0
    }
361
362
858
    memcpy(&buffer->data[data_offs], &ntlmssp_version,
363
858
           sizeof(struct wire_version));
364
858
    return 0;
365
858
}
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
434
{
372
434
    if (*data_offs + field->length > buffer->length) {
373
0
        return ERR_ENCODE;
374
0
    }
375
376
434
    memcpy(&buffer->data[*data_offs], field->data, field->length);
377
434
    hdr->len = htole16(field->length);
378
434
    hdr->max_len = hdr->len;
379
434
    hdr->offset = htole32(*data_offs);
380
381
434
    *data_offs += field->length;
382
434
    return 0;
383
434
}
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
857
{
390
857
    struct ntlm_buffer b = { NULL, 0 };
391
857
    uint32_t offs;
392
857
    uint16_t len;
393
394
857
    len = le16toh(hdr->len);
395
857
    if (len == 0) goto done;
396
397
857
    offs = le32toh(hdr->offset);
398
857
    if ((offs < payload_offs) ||
399
841
        (offs > buffer->length) ||
400
719
        (UINT32_MAX - offs < len) ||
401
719
        (offs + len > buffer->length)) {
402
207
        return ERR_DECODE;
403
207
    }
404
405
650
    b.data = malloc(len);
406
650
    if (!b.data) return ENOMEM;
407
408
650
    b.length = len;
409
650
    memcpy(b.data, &buffer->data[offs], b.length);
410
411
650
done:
412
650
    *field = b;
413
650
    return 0;
414
650
}
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
3.00k
{
422
3.00k
    struct wire_av_pair *av_pair;
423
3.00k
    char *out;
424
3.00k
    size_t outlen;
425
3.00k
    int ret;
426
427
3.00k
    if (*data_offs + 4 + str_len > buffer->length) {
428
0
        return ERR_ENCODE;
429
0
    }
430
431
3.00k
    av_pair = (struct wire_av_pair *)&buffer->data[*data_offs];
432
3.00k
    out = (char *)av_pair->value;
433
434
3.00k
    ret = ntlm_str_convert(ctx->from_oem, str, out, str_len, &outlen);
435
3.00k
    if (ret) return ret;
436
437
3.00k
    av_pair->av_len = htole16(outlen);
438
3.00k
    av_pair->av_id = htole16(av_id);
439
440
3.00k
    *data_offs += av_pair->av_len + 4;
441
3.00k
    return 0;
442
3.00k
}
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
2.00k
{
473
2.00k
    struct wire_av_pair *av_pair;
474
475
2.00k
    if (*data_offs + 4 + value->length > buffer->length) {
476
0
        return ERR_ENCODE;
477
0
    }
478
479
2.00k
    av_pair = (struct wire_av_pair *)&buffer->data[*data_offs];
480
2.00k
    av_pair->av_id = htole16(av_id);
481
2.00k
    av_pair->av_len = htole16(value->length);
482
2.00k
    if (value->length) {
483
1.00k
        memcpy(av_pair->value, value->data, value->length);
484
1.00k
    }
485
486
2.00k
    *data_offs += value->length + 4;
487
2.00k
    return 0;
488
2.00k
}
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
1.00k
{
498
1.00k
    struct ntlm_buffer buffer;
499
1.00k
    size_t data_offs;
500
1.00k
    size_t max_size;
501
1.00k
    size_t nb_computer_name_len = 0;
502
1.00k
    size_t nb_domain_name_len = 0;
503
1.00k
    size_t dns_computer_name_len = 0;
504
1.00k
    size_t dns_domain_name_len = 0;
505
1.00k
    size_t dns_tree_name_len = 0;
506
1.00k
    size_t av_target_name_len = 0;
507
1.00k
    struct ntlm_buffer value;
508
1.00k
    int ret = 0;
509
510
1.00k
    max_size = 4; /* MSV_AV_EOL */
511
512
1.00k
    if (nb_computer_name) {
513
1.00k
        nb_computer_name_len = strlen(nb_computer_name);
514
1.00k
        max_size += 4 + nb_computer_name_len * 2;
515
1.00k
    }
516
1.00k
    if (nb_domain_name) {
517
1.00k
        nb_domain_name_len = strlen(nb_domain_name);
518
1.00k
        max_size += 4 + nb_domain_name_len * 2;
519
1.00k
    }
520
1.00k
    if (dns_computer_name) {
521
1.00k
        dns_computer_name_len = strlen(dns_computer_name);
522
1.00k
        max_size += 4 + dns_computer_name_len * 2;
523
1.00k
    }
524
1.00k
    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
1.00k
    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
1.00k
    if (av_flags) {
533
0
        max_size += 4 + 4;
534
0
    }
535
1.00k
    if (av_timestamp) {
536
1.00k
        max_size += 4 + 8;
537
1.00k
    }
538
1.00k
    if (av_single_host) {
539
0
        max_size += 4 + av_single_host->length;
540
0
    }
541
1.00k
    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
1.00k
    if (av_cb && av_cb->length > 0) {
546
0
        max_size += 4 + av_cb->length;
547
0
    }
548
549
1.00k
    data_offs = 0;
550
1.00k
    buffer.length = max_size;
551
1.00k
    buffer.data = calloc(1, buffer.length);
552
1.00k
    if (!buffer.data) return ENOMEM;
553
554
1.00k
    if (nb_computer_name) {
555
1.00k
        ret = ntlm_encode_av_pair_u16l_str(ctx, &buffer, &data_offs,
556
1.00k
                                           MSV_AV_NB_COMPUTER_NAME,
557
1.00k
                                           nb_computer_name,
558
1.00k
                                           nb_computer_name_len);
559
1.00k
        if (ret) goto done;
560
1.00k
    }
561
1.00k
    if (nb_domain_name) {
562
1.00k
        ret = ntlm_encode_av_pair_u16l_str(ctx, &buffer, &data_offs,
563
1.00k
                                           MSV_AV_NB_DOMAIN_NAME,
564
1.00k
                                           nb_domain_name,
565
1.00k
                                           nb_domain_name_len);
566
1.00k
        if (ret) goto done;
567
1.00k
    }
568
1.00k
    if (dns_computer_name) {
569
1.00k
        ret = ntlm_encode_av_pair_u16l_str(ctx, &buffer, &data_offs,
570
1.00k
                                           MSV_AV_DNS_COMPUTER_NAME,
571
1.00k
                                           dns_computer_name,
572
1.00k
                                           dns_computer_name_len);
573
1.00k
        if (ret) goto done;
574
1.00k
    }
575
1.00k
    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
1.00k
    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
1.00k
    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
1.00k
    if (av_timestamp) {
598
1.00k
        uint64_t timestamp = htole64(*av_timestamp);
599
1.00k
        value.data = (uint8_t *)&timestamp;
600
1.00k
        value.length = 8;
601
1.00k
        ret = ntlm_encode_av_pair_value(&buffer, &data_offs,
602
1.00k
                                        MSV_AV_TIMESTAMP, &value);
603
1.00k
        if (ret) goto done;
604
1.00k
    }
605
1.00k
    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
1.00k
    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
1.00k
    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
1.00k
    value.length = 0;
624
1.00k
    value.data = NULL;
625
1.00k
    ret = ntlm_encode_av_pair_value(&buffer, &data_offs, MSV_AV_EOL, &value);
626
1.00k
    buffer.length = data_offs;
627
628
1.00k
done:
629
1.00k
    if (ret) {
630
0
       safefree(buffer.data);
631
1.00k
    } else {
632
1.00k
        *target_info = buffer;
633
1.00k
    }
634
1.00k
    return ret;
635
1.00k
}
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
231
{
645
231
    struct wire_av_pair *av_pair;
646
231
    uint16_t av_id = (uint16_t)-1;
647
231
    uint16_t av_len = (uint16_t)-1;
648
231
    struct ntlm_buffer sh = { NULL, 0 };
649
231
    struct ntlm_buffer cb = { NULL, 0 };
650
231
    char *nb_computer = NULL;
651
231
    char *nb_domain = NULL;
652
231
    char *dns_computer = NULL;
653
231
    char *dns_domain = NULL;
654
231
    char *dns_tree = NULL;
655
231
    char *av_target = NULL;
656
231
    size_t data_offs = 0;
657
231
    uint64_t timestamp = 0;
658
231
    uint32_t flags = 0;
659
231
    int ret = 0;
660
661
5.95k
    while (data_offs + 4 <= buffer->length) {
662
5.83k
        av_pair = (struct wire_av_pair *)&buffer->data[data_offs];
663
5.83k
        data_offs += 4;
664
5.83k
        av_id = le16toh(av_pair->av_id);
665
5.83k
        av_len = le16toh(av_pair->av_len);
666
5.83k
        if (av_len > buffer->length - data_offs) {
667
59
            ret = ERR_DECODE;
668
59
            goto done;
669
59
        }
670
5.77k
        data_offs += av_len;
671
672
5.77k
        switch (av_id) {
673
286
        case MSV_AV_CHANNEL_BINDINGS:
674
286
            if (!av_cb) continue;
675
286
            cb.data = av_pair->value;
676
286
            cb.length = av_len;
677
286
            break;
678
484
        case MSV_AV_TARGET_NAME:
679
484
            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
537
        case MSV_AV_SINGLE_HOST:
684
537
            if (!av_single_host) continue;
685
0
            sh.data = av_pair->value;
686
0
            sh.length = av_len;
687
0
            break;
688
460
        case MSV_AV_TIMESTAMP:
689
460
            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
234
        case MSV_AV_FLAGS:
698
234
            if (!av_flags) continue;
699
234
            if (av_len < sizeof(flags)) {
700
3
                ret = ERR_DECODE;
701
3
                goto done;
702
3
            }
703
231
            memcpy(&flags, av_pair->value, sizeof(flags));
704
231
            flags = le32toh(flags);
705
231
            break;
706
246
        case MSV_AV_DNS_TREE_NAME:
707
246
            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
210
        case MSV_AV_DNS_DOMAIN_NAME:
712
210
            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
688
        case MSV_AV_DNS_COMPUTER_NAME:
717
688
            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
561
        case MSV_AV_NB_DOMAIN_NAME:
722
561
            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
236
        case MSV_AV_NB_COMPUTER_NAME:
727
236
            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
1.83k
        default:
732
            /* unknown av_pair, or EOL */
733
1.83k
            break;
734
5.77k
        }
735
2.35k
        if (av_id == MSV_AV_EOL) break;
736
2.35k
    }
737
738
169
    if (av_id != MSV_AV_EOL || av_len != 0) {
739
135
        ret = ERR_DECODE;
740
135
    }
741
742
231
done:
743
231
    if (ret) {
744
197
        safefree(nb_computer);
745
197
        safefree(nb_domain);
746
197
        safefree(dns_computer);
747
197
        safefree(dns_domain);
748
197
        safefree(dns_tree);
749
197
        safefree(av_target);
750
197
    } else {
751
34
        if (nb_computer_name) *nb_computer_name = nb_computer;
752
34
        if (nb_domain_name) *nb_domain_name = nb_domain;
753
34
        if (dns_computer_name) *dns_computer_name = dns_computer;
754
34
        if (dns_domain_name) *dns_domain_name = dns_domain;
755
34
        if (dns_tree_name) *dns_tree_name = dns_tree;
756
34
        if (av_target_name) *av_target_name = av_target;
757
34
        if (av_timestamp) *av_timestamp = timestamp;
758
34
        if (av_single_host) *av_single_host = sh;
759
34
        if (av_flags) *av_flags = flags;
760
34
        if (av_cb) *av_cb = cb;
761
34
    }
762
231
    return ret;
763
169
}
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.15k
{
851
2.15k
    struct wire_neg_msg *msg;
852
2.15k
    uint32_t msg_type;
853
2.15k
    int ret;
854
855
2.15k
    if (!ctx) return EINVAL;
856
857
2.15k
    if (buffer->length < sizeof(struct wire_msg_hdr)) {
858
26
        return ERR_DECODE;
859
26
    }
860
861
2.13k
    msg = (struct wire_neg_msg *)buffer->data;
862
863
2.13k
    ret = ntlm_decode_header(&msg->header, &msg_type);
864
2.13k
    if (ret) goto done;
865
866
2.03k
    switch (msg_type) {
867
1.01k
    case NEGOTIATE_MESSAGE:
868
1.01k
        if (buffer->length < sizeof(struct wire_neg_msg)) {
869
10
            return ERR_DECODE;
870
10
        }
871
1.00k
        break;
872
1.00k
    case CHALLENGE_MESSAGE:
873
32
        if (buffer->length < sizeof(struct wire_chal_msg) &&
874
19
            buffer->length != sizeof(struct wire_chal_msg_old)) {
875
17
            return ERR_DECODE;
876
17
        }
877
15
        break;
878
981
    case AUTHENTICATE_MESSAGE:
879
981
        if (buffer->length < sizeof(struct wire_auth_msg)) {
880
12
            return ERR_DECODE;
881
12
        }
882
969
        break;
883
969
    default:
884
3
        ret = ERR_DECODE;
885
3
        break;
886
2.03k
    }
887
888
2.09k
done:
889
2.09k
    if (ret == 0) {
890
1.99k
        *type = msg_type;
891
1.99k
    }
892
2.09k
    return ret;
893
2.03k
}
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
1.00k
{
963
1.00k
    struct wire_neg_msg *msg;
964
1.00k
    size_t payload_offs;
965
1.00k
    uint32_t neg_flags;
966
1.00k
    char *dom = NULL;
967
1.00k
    char *wks = NULL;
968
1.00k
    int ret = 0;
969
970
1.00k
    if (!ctx) return EINVAL;
971
972
1.00k
    msg = (struct wire_neg_msg *)buffer->data;
973
1.00k
    payload_offs = (char *)msg->payload - (char *)msg;
974
975
1.00k
    neg_flags = le32toh(msg->neg_flags);
976
977
1.00k
    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
563
        payload_offs -= sizeof(struct wire_version);
983
563
    }
984
985
1.00k
    if (domain &&
986
0
        (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
1.00k
    if (workstation &&
992
0
        (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
1.00k
done:
999
1.00k
    if (ret) {
1000
0
        safefree(dom);
1001
0
        safefree(wks);
1002
1.00k
    } else {
1003
1.00k
        *flags = neg_flags;
1004
1.00k
        if (domain) *domain = dom;
1005
1.00k
        if (workstation) *workstation = wks;
1006
1.00k
    }
1007
1.00k
    return ret;
1008
1.00k
}
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
1.00k
{
1017
1.00k
    struct wire_chal_msg *msg;
1018
1.00k
    struct ntlm_buffer buffer;
1019
1.00k
    size_t data_offs;
1020
1.00k
    size_t target_len = 0;
1021
1.00k
    int ret = 0;
1022
1023
1.00k
    if (!ctx) return EINVAL;
1024
1025
1.00k
    if (!challenge || challenge->length != 8) return EINVAL;
1026
1027
1.00k
    buffer.length = sizeof(struct wire_chal_msg);
1028
1029
1.00k
    if ((flags & NTLMSSP_TARGET_TYPE_SERVER)
1030
1.00k
        || (flags & NTLMSSP_TARGET_TYPE_DOMAIN)) {
1031
1.00k
        if (!target_name) return EINVAL;
1032
1033
1.00k
        target_len = strlen(target_name);
1034
1.00k
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1035
274
            buffer.length += target_len * 2;
1036
727
        } else {
1037
727
            buffer.length += target_len;
1038
727
        }
1039
1.00k
    }
1040
1041
1.00k
    if (flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
1042
434
        if (!target_info) return EINVAL;
1043
1044
434
        buffer.length += target_info->length;
1045
434
    }
1046
1047
1.00k
    buffer.data = calloc(1, buffer.length);
1048
1.00k
    if (!buffer.data) return ENOMEM;
1049
1050
1.00k
    msg = (struct wire_chal_msg *)buffer.data;
1051
1.00k
    data_offs = (char *)msg->payload - (char *)msg;
1052
1053
1.00k
    ntlm_encode_header(&msg->header, CHALLENGE_MESSAGE);
1054
1055
    /* this must be first as it pushes the payload further down */
1056
1.00k
    if (flags & NTLMSSP_NEGOTIATE_VERSION) {
1057
858
        ret = ntlm_encode_version(ctx, &buffer,
1058
858
                                  (char *)&msg->version - (char *)msg);
1059
858
        if (ret) goto done;
1060
858
    }
1061
1062
1.00k
    if ((flags & NTLMSSP_TARGET_TYPE_SERVER)
1063
1.00k
        || (flags & NTLMSSP_TARGET_TYPE_DOMAIN)) {
1064
1.00k
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1065
274
            ret = ntlm_encode_u16l_str_hdr(ctx, &msg->target_name, &buffer,
1066
274
                                           &data_offs, target_name, target_len);
1067
727
        } else {
1068
727
            ret = ntlm_encode_oem_str(&msg->target_name, &buffer,
1069
727
                                      &data_offs, target_name, target_len);
1070
727
        }
1071
1.00k
        if (ret) goto done;
1072
1.00k
    }
1073
1074
1.00k
    msg->neg_flags = htole32(flags);
1075
1.00k
    memcpy(msg->server_challenge, challenge->data, 8);
1076
1077
1.00k
    if (flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
1078
434
        ret = ntlm_encode_field(&msg->target_info, &buffer,
1079
434
                                &data_offs, target_info);
1080
434
        if (ret) goto done;
1081
434
    }
1082
1083
1.00k
done:
1084
1.00k
    if (ret) {
1085
0
        safefree(buffer.data);
1086
1.00k
    } else {
1087
1.00k
        *message = buffer;
1088
1.00k
    }
1089
1.00k
    return ret;
1090
1.00k
}
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
961
{
1324
961
    struct wire_auth_msg *msg;
1325
961
    uint32_t neg_flags;
1326
961
    size_t payload_offs;
1327
961
    char *dom = NULL;
1328
961
    char *usr = NULL;
1329
961
    char *wks = NULL;
1330
961
    int ret = 0;
1331
1332
961
    if (!ctx) return EINVAL;
1333
1334
961
    if (lm_chalresp) lm_chalresp->data = NULL;
1335
961
    if (nt_chalresp) nt_chalresp->data = NULL;
1336
961
    if (enc_sess_key) enc_sess_key->data = NULL;
1337
1338
961
    msg = (struct wire_auth_msg *)buffer->data;
1339
961
    payload_offs = (char *)msg->payload - (char *)msg;
1340
1341
961
    neg_flags = le32toh(msg->neg_flags);
1342
961
    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
954
        payload_offs -= sizeof(struct wire_version);
1348
954
    }
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
961
    if (mic) {
1355
961
        size_t mic_offs = payload_offs;
1356
1357
961
        if (mic->length < 16) return ERR_DECODE;
1358
1359
961
        if ((neg_flags & NTLMSSP_NEGOTIATE_VERSION) == 0) {
1360
954
            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
954
            if (memcmp(&msg->version, &zver,
1366
954
                       sizeof(struct wire_version)) == 0) {
1367
42
                mic_offs += sizeof(struct wire_version);
1368
42
            }
1369
954
        }
1370
1371
961
        if (buffer->length - mic_offs < 16) return ERR_DECODE;
1372
947
        memcpy(mic->data, &buffer->data[mic_offs], 16);
1373
947
    }
1374
1375
947
    if (msg->lm_chalresp.len != 0 && lm_chalresp) {
1376
258
        ret = ntlm_decode_field(&msg->lm_chalresp, buffer,
1377
258
                                payload_offs, lm_chalresp);
1378
258
        if (ret) goto done;
1379
258
    }
1380
881
    if (msg->nt_chalresp.len != 0 && nt_chalresp) {
1381
363
        ret = ntlm_decode_field(&msg->nt_chalresp, buffer,
1382
363
                                payload_offs, nt_chalresp);
1383
363
        if (ret) goto done;
1384
1385
302
        if (target_info) {
1386
302
            union wire_ntlm_response *resp;
1387
302
            struct wire_ntlmv2_cli_chal *chal;
1388
302
            uint8_t *data;
1389
302
            int len;
1390
302
            resp = (union wire_ntlm_response *)nt_chalresp->data;
1391
302
            chal = (struct wire_ntlmv2_cli_chal *)resp->v2.cli_chal;
1392
302
            len = nt_chalresp->length - sizeof(resp->v2.resp)
1393
302
                    - offsetof(struct wire_ntlmv2_cli_chal, target_info);
1394
302
            if (len > 0) {
1395
249
                data = chal->target_info;
1396
249
                target_info->data = malloc(len);
1397
249
                if (!target_info->data) {
1398
0
                    ret = ENOMEM;
1399
0
                    goto done;
1400
0
                }
1401
249
                memcpy(target_info->data, data, len);
1402
249
                target_info->length = len;
1403
249
            }
1404
302
        }
1405
302
    }
1406
820
    if (msg->domain_name.len != 0 && domain_name) {
1407
406
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1408
118
            ret = ntlm_decode_u16l_str_hdr(ctx, &msg->domain_name, buffer,
1409
118
                                           payload_offs, &dom);
1410
288
        } else {
1411
288
            ret = ntlm_decode_oem_str(&msg->domain_name, buffer,
1412
288
                                      payload_offs, &dom);
1413
288
        }
1414
406
        if (ret) goto done;
1415
406
    }
1416
712
    if (msg->user_name.len != 0 && user_name) {
1417
387
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1418
105
            ret = ntlm_decode_u16l_str_hdr(ctx, &msg->user_name, buffer,
1419
105
                                           payload_offs, &usr);
1420
282
        } else {
1421
282
            ret = ntlm_decode_oem_str(&msg->user_name, buffer,
1422
282
                                      payload_offs, &usr);
1423
282
        }
1424
387
        if (ret) goto done;
1425
387
    }
1426
607
    if (msg->workstation.len != 0 && workstation) {
1427
283
        if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
1428
68
            ret = ntlm_decode_u16l_str_hdr(ctx, &msg->workstation, buffer,
1429
68
                                           payload_offs, &wks);
1430
215
        } else {
1431
215
            ret = ntlm_decode_oem_str(&msg->workstation, buffer,
1432
215
                                      payload_offs, &wks);
1433
215
        }
1434
283
        if (ret) goto done;
1435
283
    }
1436
501
    if (msg->enc_sess_key.len != 0 && enc_sess_key) {
1437
236
        ret = ntlm_decode_field(&msg->enc_sess_key, buffer,
1438
236
                                payload_offs, enc_sess_key);
1439
236
    }
1440
1441
    /* ignore returned flags, our flags are authoritative
1442
    flags = le32toh(msg->neg_flags);
1443
    */
1444
1445
947
done:
1446
947
    if (ret) {
1447
526
        if (lm_chalresp) safefree(lm_chalresp->data);
1448
526
        if (nt_chalresp) safefree(nt_chalresp->data);
1449
526
        if (enc_sess_key) safefree(enc_sess_key->data);
1450
526
        safefree(dom);
1451
526
        safefree(usr);
1452
526
        safefree(wks);
1453
526
    } else {
1454
421
        if (domain_name) *domain_name = dom;
1455
421
        if (user_name) *user_name = usr;
1456
421
        if (workstation) *workstation = wks;
1457
421
    }
1458
947
    return ret;
1459
501
}