Coverage Report

Created: 2024-06-18 06:03

/src/gss-ntlmssp/src/gss_sec_ctx.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright 2013 Simo Sorce <simo@samba.org>, see COPYING for license */
2
3
#include <endian.h>
4
#include <errno.h>
5
#include <stdlib.h>
6
#include <string.h>
7
#include <time.h>
8
9
#include "gssapi_ntlmssp.h"
10
#include "gss_ntlmssp.h"
11
12
uint32_t gssntlm_init_sec_context(uint32_t *minor_status,
13
                                  gss_cred_id_t claimant_cred_handle,
14
                                  gss_ctx_id_t *context_handle,
15
                                  gss_name_t target_name,
16
                                  gss_OID mech_type,
17
                                  uint32_t req_flags,
18
                                  uint32_t time_req,
19
                                  gss_channel_bindings_t input_chan_bindings,
20
                                  gss_buffer_t input_token,
21
                                  gss_OID *actual_mech_type,
22
                                  gss_buffer_t output_token,
23
                                  uint32_t *ret_flags,
24
                                  uint32_t *time_rec)
25
0
{
26
0
    struct gssntlm_ctx *ctx;
27
0
    struct gssntlm_name *server = NULL;
28
0
    struct gssntlm_cred *cred = NULL;
29
0
    char *nb_computer_name = NULL;
30
0
    char *nb_domain_name = NULL;
31
0
    struct gssntlm_name *client_name = NULL;
32
0
    uint32_t in_flags;
33
0
    uint32_t msg_type;
34
0
    char *trgt_name = NULL;
35
0
    struct ntlm_buffer challenge = { 0 };
36
0
    struct ntlm_buffer target_info = { 0 };
37
0
    int lm_compat_lvl;
38
0
    uint32_t tmpmin;
39
0
    uint32_t retmin = 0;
40
0
    uint32_t retmaj = 0;
41
42
0
    ctx = (struct gssntlm_ctx *)(*context_handle);
43
44
    /* reset return values */
45
0
    if (actual_mech_type) *actual_mech_type = NULL;
46
0
    if (ret_flags) *ret_flags = 0;
47
0
    if (time_rec) *time_rec = 0;
48
49
0
    if (output_token == GSS_C_NO_BUFFER) {
50
0
        return GSSERRS(0, GSS_S_CALL_INACCESSIBLE_WRITE);
51
0
    }
52
53
0
    if (target_name) {
54
0
        server = (struct gssntlm_name *)target_name;
55
0
        if (server->type != GSSNTLM_NAME_SERVER) {
56
0
            return GSSERRS(ERR_NOSRVNAME, GSS_S_BAD_NAMETYPE);
57
0
        }
58
0
        if (!server->data.server.name ||
59
0
            !server->data.server.name[0]) {
60
0
            return GSSERRS(ERR_NONAME, GSS_S_BAD_NAME);
61
0
        }
62
0
    }
63
64
0
    if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
65
0
        if (req_flags & GSS_C_ANON_FLAG) {
66
0
            set_GSSERRS(ERR_NOARG, GSS_S_UNAVAILABLE);
67
0
            goto done;
68
0
        } else {
69
0
            retmaj = gssntlm_acquire_cred(&retmin,
70
0
                                           NULL, time_req,
71
0
                                           NULL, GSS_C_INITIATE,
72
0
                                           (gss_cred_id_t *)&cred,
73
0
                                           NULL, time_rec);
74
0
            if (retmaj) goto done;
75
0
        }
76
0
    } else {
77
0
        cred = (struct gssntlm_cred *)claimant_cred_handle;
78
0
        if (cred->type != GSSNTLM_CRED_USER &&
79
0
            cred->type != GSSNTLM_CRED_EXTERNAL) {
80
0
            set_GSSERRS(ERR_NOARG, GSS_S_CRED_UNAVAIL);
81
0
            goto done;
82
0
        }
83
0
        if (cred->type == GSSNTLM_CRED_EXTERNAL &&
84
0
            cred->cred.external.creds_in_cache == 0) {
85
0
            set_GSSERRS(ERR_NOARG, GSS_S_CRED_UNAVAIL);
86
0
            goto done;
87
0
        }
88
0
    }
89
90
0
    if (ctx == NULL) {
91
92
        /* first call */
93
0
        ctx = calloc(1, sizeof(struct gssntlm_ctx));
94
0
        if (!ctx) {
95
0
            set_GSSERR(ENOMEM);
96
0
            goto done;
97
0
        }
98
99
0
        ctx->external_context = external_get_context();
100
101
0
        retmin = gssntlm_copy_name(&cred->cred.user.user,
102
0
                                   &ctx->source_name);
103
0
        if (retmin) {
104
0
            set_GSSERR(retmin);
105
0
            goto done;
106
0
        }
107
108
0
        if (server) {
109
0
            retmin = gssntlm_copy_name(server, &ctx->target_name);
110
0
            if (retmin) {
111
0
                set_GSSERR(retmin);
112
0
                goto done;
113
0
            }
114
0
        }
115
116
0
        ctx->gss_flags = req_flags;
117
118
0
        ctx->neg_flags = NTLMSSP_DEFAULT_CLIENT_FLAGS;
119
        /* override neg_flags default if requested */
120
0
        if (cred->neg_flags) {
121
0
            ctx->neg_flags = cred->neg_flags;
122
0
        }
123
124
        /*
125
         * we ignore unsupported flags for now
126
         *
127
         * GSS_C_DELEG_FLAG
128
         * GSS_C_MUTUAL_FLAG
129
         * GSS_C_PROT_READY_FLAG
130
         * GSS_C_TRANS_FLAG
131
         * GSS_C_DELEG_POLICY_FLAG
132
         * GSS_C_DCE_STYLE
133
         * GSS_C_EXTENDED_ERROR_FLAG
134
         */
135
0
        if ((req_flags & GSS_C_INTEG_FLAG) ||
136
0
            (req_flags & GSS_C_REPLAY_FLAG) ||
137
0
            (req_flags & GSS_C_SEQUENCE_FLAG)) {
138
0
            ctx->neg_flags |= NTLMSSP_NEGOTIATE_SIGN |
139
0
                              NTLMSSP_NEGOTIATE_KEY_EXCH;
140
0
        }
141
0
        if (req_flags & GSS_C_CONF_FLAG) {
142
0
            ctx->neg_flags |= NTLMSSP_NEGOTIATE_SEAL |
143
0
                              NTLMSSP_NEGOTIATE_KEY_EXCH |
144
0
                              NTLMSSP_NEGOTIATE_LM_KEY |
145
0
                              NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY;
146
0
        }
147
0
        if (req_flags & GSS_C_ANON_FLAG) {
148
0
            ctx->neg_flags |= NTLMSSP_ANONYMOUS;
149
0
        }
150
0
        if (req_flags & GSS_C_IDENTIFY_FLAG) {
151
0
            ctx->neg_flags |= NTLMSSP_NEGOTIATE_IDENTIFY;
152
0
        }
153
0
        if (req_flags & GSS_C_DATAGRAM_FLAG) {
154
0
            ctx->neg_flags |= NTLMSSP_NEGOTIATE_DATAGRAM |
155
0
                              NTLMSSP_NEGOTIATE_KEY_EXCH;
156
0
        }
157
158
        /* acquire our own name */
159
0
        if (!client_name) {
160
0
            gss_buffer_desc tmpbuf;
161
0
            tmpbuf.value = discard_const("");
162
0
            tmpbuf.length = 0;
163
0
            retmaj = gssntlm_import_name_by_mech(&retmin,
164
0
                                                 &gssntlm_oid,
165
0
                                                 &tmpbuf,
166
0
                                                 GSS_C_NT_HOSTBASED_SERVICE,
167
0
                                                 (gss_name_t *)&client_name);
168
0
            if (retmaj) goto done;
169
0
        }
170
171
0
        retmin = netbios_get_names(ctx->external_context,
172
0
                                   client_name->data.server.name,
173
0
                                   &nb_computer_name, &nb_domain_name);
174
0
        if (retmin) {
175
0
            set_GSSERR(retmin);
176
0
            goto done;
177
0
        }
178
179
0
        ctx->workstation = strdup(nb_computer_name);
180
0
        if (!ctx->workstation) {
181
0
            set_GSSERR(ENOMEM);
182
0
            goto done;
183
0
        }
184
185
0
        gssntlm_set_role(ctx, GSSNTLM_CLIENT, nb_domain_name);
186
187
0
        lm_compat_lvl = gssntlm_get_lm_compatibility_level();
188
0
        if (!gssntlm_required_security(lm_compat_lvl, ctx)) {
189
0
            set_GSSERR(ERR_BADLMLVL);
190
0
            goto done;
191
0
        }
192
0
        if (!gssntlm_sec_lm_ok(ctx)) {
193
0
            ctx->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
194
0
            ctx->neg_flags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY;
195
0
        }
196
0
        if (!gssntlm_ext_sec_ok(ctx)) {
197
0
            ctx->neg_flags &= ~NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY;
198
0
        }
199
200
0
        retmin = ntlm_init_ctx(&ctx->ntlm);
201
0
        if (retmin) {
202
0
            set_GSSERR(retmin);
203
0
            goto done;
204
0
        }
205
206
        /* only in connectionless mode we may receive an input buffer
207
         * on the the first call, if DATAGRAM is not selected and
208
         * we have a buffer here, somethings wrong */
209
0
        if (ctx->neg_flags & NTLMSSP_NEGOTIATE_DATAGRAM) {
210
211
0
            if ((input_token == GSS_C_NO_BUFFER) ||
212
0
                (input_token->length == 0)) {
213
                /* in connectionless mode we return an empty buffer here:
214
                 * see MS-NLMP 1.3.1.3 and 1.7 */
215
0
                output_token->value = NULL;
216
0
                output_token->length = 0;
217
218
                /* and return the ball */
219
0
                ctx->stage = NTLMSSP_STAGE_NEGOTIATE;
220
0
                set_GSSERRS(0, GSS_S_CONTINUE_NEEDED);
221
0
                goto done;
222
0
            }
223
0
        } else {
224
225
0
            if (input_token && input_token->length != 0) {
226
0
                set_GSSERRS(ERR_BADARG, GSS_S_DEFECTIVE_TOKEN);
227
0
                goto done;
228
0
            }
229
230
0
            retmin = ntlm_encode_neg_msg(ctx->ntlm, ctx->neg_flags,
231
0
                                         NULL, NULL, &ctx->nego_msg);
232
0
            if (retmin) {
233
0
                set_GSSERR(retmin);
234
0
                goto done;
235
0
            }
236
237
0
            output_token->value = malloc(ctx->nego_msg.length);
238
0
            if (!output_token->value) {
239
0
                set_GSSERR(ENOMEM);
240
0
                goto done;
241
0
            }
242
0
            memcpy(output_token->value, ctx->nego_msg.data, ctx->nego_msg.length);
243
0
            output_token->length = ctx->nego_msg.length;
244
245
0
            ctx->stage = NTLMSSP_STAGE_NEGOTIATE;
246
0
            set_GSSERRS(0, GSS_S_CONTINUE_NEEDED);
247
0
            goto done;
248
0
        }
249
250
        /* If we get here we are in connectionless mode and where called
251
         * with a chalenge message in the input buffer */
252
0
        ctx->stage = NTLMSSP_STAGE_NEGOTIATE;
253
0
    }
254
255
0
    if (ctx == NULL) {
256
        /* this should not happen */
257
0
        set_GSSERR(ERR_IMPOSSIBLE);
258
0
        goto done;
259
260
0
    } else {
261
262
0
        if (!gssntlm_role_is_client(ctx)) {
263
0
            set_GSSERRS(ERR_WRONGCTX, GSS_S_NO_CONTEXT);
264
0
            goto done;
265
0
        }
266
267
0
        ctx->chal_msg.data = malloc(input_token->length);
268
0
        if (!ctx->chal_msg.data) {
269
0
            set_GSSERR(ENOMEM);
270
0
            goto done;
271
0
        }
272
0
        memcpy(ctx->chal_msg.data, input_token->value, input_token->length);
273
0
        ctx->chal_msg.length = input_token->length;
274
275
0
        retmin = ntlm_decode_msg_type(ctx->ntlm, &ctx->chal_msg, &msg_type);
276
0
        if (retmin) {
277
0
            set_GSSERRS(retmin, GSS_S_DEFECTIVE_TOKEN);
278
0
            goto done;
279
0
        }
280
281
0
        if (msg_type != CHALLENGE_MESSAGE ||
282
0
                ctx->stage != NTLMSSP_STAGE_NEGOTIATE) {
283
0
            set_GSSERRS(ERR_WRONGMSG, GSS_S_NO_CONTEXT);
284
0
            goto done;
285
0
        }
286
287
        /* store challenge in ctx */
288
0
        challenge.data = ctx->server_chal;
289
0
        challenge.length = 8;
290
0
        retmin = ntlm_decode_chal_msg(ctx->ntlm, &ctx->chal_msg, &in_flags,
291
0
                                      &trgt_name, &challenge, &target_info);
292
0
        if (retmin) {
293
0
            set_GSSERRS(retmin, GSS_S_DEFECTIVE_TOKEN);
294
0
            goto done;
295
0
        }
296
297
        /* mask unacceptable flags */
298
0
        if (!gssntlm_sec_lm_ok(ctx)) {
299
0
            in_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
300
0
        }
301
0
        if (!(ctx->neg_flags & NTLMSSP_NEGOTIATE_56)) {
302
0
            in_flags &= ~NTLMSSP_NEGOTIATE_56;
303
0
        }
304
0
        if (!(ctx->neg_flags & NTLMSSP_NEGOTIATE_128)) {
305
0
            in_flags &= ~NTLMSSP_NEGOTIATE_128;
306
0
        }
307
0
        if (!(ctx->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
308
0
            in_flags &= ~NTLMSSP_NEGOTIATE_KEY_EXCH;
309
0
        }
310
0
        if (!(ctx->neg_flags & NTLMSSP_NEGOTIATE_OEM)) {
311
0
            in_flags &= ~NTLMSSP_NEGOTIATE_OEM;
312
0
        }
313
0
        if (!(ctx->neg_flags & NTLMSSP_NEGOTIATE_UNICODE)) {
314
0
            in_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
315
0
        }
316
317
        /* check required flags */
318
0
        if ((ctx->neg_flags & NTLMSSP_NEGOTIATE_128) &&
319
0
            (!(ctx->neg_flags & NTLMSSP_NEGOTIATE_56)) &&
320
0
            (!(in_flags & NTLMSSP_NEGOTIATE_128))) {
321
0
            set_GSSERR(ERR_REQNEGFLAG);
322
0
            goto done;
323
0
        }
324
0
        if ((ctx->neg_flags & NTLMSSP_NEGOTIATE_SEAL) &&
325
0
            (!(in_flags & NTLMSSP_NEGOTIATE_SEAL))) {
326
0
            set_GSSERR(ERR_REQNEGFLAG);
327
0
            goto done;
328
0
        }
329
0
        if ((ctx->neg_flags & NTLMSSP_NEGOTIATE_SIGN) &&
330
0
            (!(in_flags & NTLMSSP_NEGOTIATE_SIGN))) {
331
0
            set_GSSERR(ERR_REQNEGFLAG);
332
0
            goto done;
333
0
        }
334
335
0
        if (!(in_flags & (NTLMSSP_NEGOTIATE_OEM |
336
0
                          NTLMSSP_NEGOTIATE_UNICODE))) {
337
            /* no common understanding */
338
0
            set_GSSERR(ERR_FAILNEGFLAGS);
339
0
            goto done;
340
0
        }
341
342
0
        if (ctx->gss_flags & GSS_C_DATAGRAM_FLAG) {
343
0
            if (!(in_flags & NTLMSSP_NEGOTIATE_DATAGRAM)) {
344
                /* no common understanding */
345
0
                set_GSSERR(ERR_FAILNEGFLAGS);
346
0
                goto done;
347
0
            }
348
0
            if (!(in_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
349
                /* no common understanding */
350
0
                set_GSSERR(ERR_FAILNEGFLAGS);
351
0
                goto done;
352
0
            }
353
0
            if ((in_flags & NTLMSSP_NEGOTIATE_OEM) &&
354
0
                (in_flags & NTLMSSP_NEGOTIATE_UNICODE)) {
355
                /* prefer Unicode */
356
0
                in_flags &= ~NTLMSSP_NEGOTIATE_OEM;
357
0
            }
358
0
        } else {
359
0
            in_flags &= ~NTLMSSP_NEGOTIATE_DATAGRAM;
360
361
0
            if ((in_flags & NTLMSSP_NEGOTIATE_OEM) &&
362
0
                (in_flags & NTLMSSP_NEGOTIATE_UNICODE)) {
363
                /* server sent both?? This is broken, proceed only if there
364
                 * are no strings set in the challenge packet and downgrade
365
                 * to OEM charset hoping the server will cope */
366
0
                if (in_flags & (NTLMSSP_NEGOTIATE_TARGET_INFO |
367
0
                                NTLMSSP_TARGET_TYPE_SERVER |
368
0
                                NTLMSSP_TARGET_TYPE_DOMAIN)) {
369
0
                    set_GSSERR(ERR_BADNEGFLAGS);
370
0
                    goto done;
371
0
                } else {
372
0
                    in_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
373
0
                }
374
0
            }
375
0
        }
376
377
        /* Now that everything has been checked clear non
378
         * negotiated flags */
379
0
        ctx->neg_flags &= in_flags;
380
381
0
       retmaj = gssntlm_cli_auth(&retmin, ctx, cred, &target_info,
382
0
                                  in_flags, input_chan_bindings);
383
0
        if (retmaj) goto done;
384
385
0
        if (in_flags & (NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL)) {
386
0
            retmin = ntlm_signseal_keys(in_flags, true,
387
0
                                        &ctx->exported_session_key,
388
0
                                        &ctx->crypto_state);
389
0
            if (retmin) {
390
0
                set_GSSERR(retmin);
391
0
                goto done;
392
0
            }
393
0
        }
394
395
0
        if (ctx->neg_flags & NTLMSSP_NEGOTIATE_SIGN) {
396
0
            ctx->gss_flags |= GSS_C_INTEG_FLAG;
397
0
        }
398
0
        if (ctx->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
399
0
            ctx->gss_flags |= GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG;
400
0
        }
401
402
0
        ctx->stage = NTLMSSP_STAGE_DONE;
403
404
0
        output_token->value = malloc(ctx->auth_msg.length);
405
0
        if (!output_token->value) {
406
0
            set_GSSERR(ENOMEM);
407
0
            goto done;
408
0
        }
409
0
        memcpy(output_token->value, ctx->auth_msg.data, ctx->auth_msg.length);
410
0
        output_token->length = ctx->auth_msg.length;
411
412
        /* For now use the same as the challenge/response lifetime (36h) */
413
0
        ctx->expiration_time = time(NULL) + MAX_CHALRESP_LIFETIME;
414
0
        ctx->int_flags |= NTLMSSP_CTX_FLAG_ESTABLISHED;
415
416
0
        set_GSSERRS(0, GSS_S_COMPLETE);
417
0
    }
418
419
0
done:
420
0
    if ((retmaj != GSS_S_COMPLETE) &&
421
0
        (retmaj != GSS_S_CONTINUE_NEEDED)) {
422
0
        gssntlm_delete_sec_context(&tmpmin, (gss_ctx_id_t *)&ctx, NULL);
423
0
    } else {
424
0
        if (actual_mech_type) *actual_mech_type = discard_const(&gssntlm_oid);
425
0
        if (ret_flags) *ret_flags = ctx->gss_flags;
426
0
        if (time_rec) *time_rec = GSS_C_INDEFINITE;
427
0
    }
428
0
    *context_handle = (gss_ctx_id_t)ctx;
429
0
    if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
430
        /* do not leak it, if not passed in */
431
0
        gssntlm_release_cred(&tmpmin, (gss_cred_id_t *)&cred);
432
0
    }
433
0
    gssntlm_release_name(&tmpmin, (gss_name_t *)&client_name);
434
0
    safefree(nb_computer_name);
435
0
    safefree(nb_domain_name);
436
0
    safefree(trgt_name);
437
0
    ntlm_free_buffer_data(&target_info);
438
439
0
    return GSSERR();
440
0
}
441
442
uint32_t gssntlm_delete_sec_context(uint32_t *minor_status,
443
                                    gss_ctx_id_t *context_handle,
444
                                    gss_buffer_t output_token)
445
2.29k
{
446
2.29k
    struct gssntlm_ctx *ctx;
447
2.29k
    uint32_t retmin;
448
2.29k
    uint32_t retmaj;
449
2.29k
    int ret;
450
451
2.29k
    if (!context_handle) {
452
0
        set_GSSERRS(ERR_NOARG, GSS_S_CALL_INACCESSIBLE_READ);
453
0
        goto done;
454
0
    }
455
2.29k
    if (*context_handle == NULL) {
456
1.14k
        set_GSSERRS(ERR_NOARG, GSS_S_NO_CONTEXT);
457
1.14k
        goto done;
458
1.14k
    }
459
460
1.14k
    ctx = (struct gssntlm_ctx *)*context_handle;
461
462
1.14k
    safefree(ctx->workstation);
463
464
1.14k
    ret = ntlm_free_ctx(&ctx->ntlm);
465
466
1.14k
    safefree(ctx->nego_msg.data);
467
1.14k
    safefree(ctx->chal_msg.data);
468
1.14k
    safefree(ctx->auth_msg.data);
469
1.14k
    ctx->nego_msg.length = 0;
470
1.14k
    ctx->chal_msg.length = 0;
471
1.14k
    ctx->auth_msg.length = 0;
472
473
1.14k
    gssntlm_int_release_name(&ctx->source_name);
474
1.14k
    gssntlm_int_release_name(&ctx->target_name);
475
476
1.14k
    ntlm_release_rc4_state(&ctx->crypto_state);
477
478
1.14k
    external_free_context(ctx->external_context);
479
480
1.14k
    safezero((uint8_t *)ctx, sizeof(struct gssntlm_ctx));
481
1.14k
    safefree(*context_handle);
482
483
1.14k
    set_GSSERRS(ret, ret ? GSS_S_FAILURE : GSS_S_COMPLETE);
484
2.29k
done:
485
2.29k
    return GSSERR();
486
1.14k
}
487
488
uint32_t gssntlm_context_time(uint32_t *minor_status,
489
                              gss_ctx_id_t context_handle,
490
                              uint32_t *time_rec)
491
0
{
492
0
    struct gssntlm_ctx *ctx;
493
0
    time_t now;
494
0
    uint32_t retmin;
495
0
    uint32_t retmaj;
496
497
0
    if (context_handle == GSS_C_NO_CONTEXT) {
498
0
        set_GSSERRS(ERR_NOARG, GSS_S_CALL_INACCESSIBLE_READ);
499
0
        goto done;
500
0
    }
501
502
0
    ctx = (struct gssntlm_ctx *)context_handle;
503
0
    retmaj = gssntlm_context_is_valid(ctx, &now);
504
0
    if (retmaj) {
505
0
        set_GSSERRS(ERR_BADCTX, retmaj);
506
0
        goto done;
507
0
    }
508
509
0
    *time_rec = ctx->expiration_time - now;
510
0
    set_GSSERRS(0, GSS_S_COMPLETE);
511
0
done:
512
0
    return GSSERR();
513
0
}
514
515
uint32_t gssntlm_accept_sec_context(uint32_t *minor_status,
516
                                    gss_ctx_id_t *context_handle,
517
                                    gss_cred_id_t acceptor_cred_handle,
518
                                    gss_buffer_t input_token,
519
                                    gss_channel_bindings_t input_chan_bindings,
520
                                    gss_name_t *src_name,
521
                                    gss_OID *mech_type,
522
                                    gss_buffer_t output_token,
523
                                    uint32_t *ret_flags,
524
                                    uint32_t *time_rec,
525
                                    gss_cred_id_t *delegated_cred_handle)
526
2.08k
{
527
2.08k
    struct gssntlm_ctx *ctx;
528
2.08k
    struct gssntlm_cred *cred = NULL;
529
2.08k
    int lm_compat_lvl = -1;
530
2.08k
    struct ntlm_buffer challenge = { 0 };
531
2.08k
    struct gssntlm_name *server_name = NULL;
532
2.08k
    char *nb_computer_name = NULL;
533
2.08k
    char *nb_domain_name = NULL;
534
2.08k
    char *chal_target_name;
535
2.08k
    uint64_t timestamp;
536
2.08k
    struct ntlm_buffer target_info = { 0 };
537
2.08k
    struct ntlm_buffer nt_chal_resp = { 0 };
538
2.08k
    struct ntlm_buffer lm_chal_resp = { 0 };
539
2.08k
    struct ntlm_buffer enc_sess_key = { 0 };
540
2.08k
    struct ntlm_key encrypted_random_session_key = { .length = 16 };
541
2.08k
    struct ntlm_key key_exchange_key = { .length = 16 };
542
2.08k
    uint8_t micbuf[16];
543
2.08k
    struct ntlm_buffer mic = { micbuf, 16 };
544
2.08k
    char *dom_name = NULL;
545
2.08k
    char *usr_name = NULL;
546
2.08k
    char *wks_name = NULL;
547
2.08k
    struct gssntlm_name *gss_usrname = NULL;
548
2.08k
    struct gssntlm_cred *usr_cred = NULL;
549
2.08k
    uint32_t retmin;
550
2.08k
    uint32_t retmaj;
551
2.08k
    uint32_t tmpmin;
552
2.08k
    uint32_t in_flags;
553
2.08k
    uint32_t msg_type;
554
2.08k
    uint32_t av_flags = 0;
555
2.08k
    struct ntlm_buffer unhashed_cb = { 0 };
556
2.08k
    struct ntlm_buffer av_cb = { 0 };
557
558
2.08k
    if (context_handle == NULL) {
559
0
        return GSSERRS(ERR_NOARG, GSS_S_CALL_INACCESSIBLE_READ);
560
0
    }
561
2.08k
    if (output_token == GSS_C_NO_BUFFER) {
562
0
        return GSSERRS(ERR_NOARG, GSS_S_CALL_INACCESSIBLE_WRITE);
563
0
    }
564
565
2.08k
    if (src_name) *src_name = GSS_C_NO_NAME;
566
2.08k
    if (mech_type) *mech_type = GSS_C_NO_OID;
567
2.08k
    if (ret_flags) *ret_flags = 0;
568
2.08k
    if (time_rec) *time_rec = 0;
569
2.08k
    if (delegated_cred_handle) *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
570
571
2.08k
    if (acceptor_cred_handle) {
572
0
        cred = (struct gssntlm_cred *)acceptor_cred_handle;
573
0
        if (cred->type != GSSNTLM_CRED_SERVER) {
574
0
            set_GSSERRS(ERR_NOSRVCRED, GSS_S_DEFECTIVE_CREDENTIAL);
575
0
            goto done;
576
0
        }
577
0
        if (cred->cred.server.name.type != GSSNTLM_NAME_SERVER) {
578
0
            set_GSSERRS(ERR_NOSRVNAME, GSS_S_DEFECTIVE_CREDENTIAL);
579
0
            goto done;
580
0
        }
581
0
        retmaj = gssntlm_duplicate_name(&retmin,
582
0
                                (const gss_name_t)&cred->cred.server.name,
583
0
                                (gss_name_t *)&server_name);
584
0
        if (retmaj) goto done;
585
0
    }
586
587
2.08k
    if (*context_handle == GSS_C_NO_CONTEXT) {
588
589
        /* first call */
590
1.14k
        ctx = calloc(1, sizeof(struct gssntlm_ctx));
591
1.14k
        if (!ctx) {
592
0
            set_GSSERR(ENOMEM);
593
0
            goto done;
594
0
        }
595
596
1.14k
        ctx->external_context = external_get_context();
597
598
        /* acquire our own name */
599
1.14k
        if (!server_name) {
600
1.14k
            gss_buffer_desc tmpbuf;
601
1.14k
            tmpbuf.value = discard_const("");
602
1.14k
            tmpbuf.length = 0;
603
1.14k
            retmaj = gssntlm_import_name_by_mech(&retmin,
604
1.14k
                                                 &gssntlm_oid,
605
1.14k
                                                 &tmpbuf,
606
1.14k
                                                 GSS_C_NT_HOSTBASED_SERVICE,
607
1.14k
                                                 (gss_name_t *)&server_name);
608
1.14k
            if (retmaj) goto done;
609
1.14k
        }
610
611
1.14k
        retmin = gssntlm_copy_name(server_name, &ctx->target_name);
612
1.14k
        if (retmin) {
613
0
            set_GSSERR(retmin);
614
0
            goto done;
615
0
        }
616
617
1.14k
        retmin = netbios_get_names(ctx->external_context,
618
1.14k
                                   server_name->data.server.name,
619
1.14k
                                   &nb_computer_name, &nb_domain_name);
620
1.14k
        if (retmin) {
621
0
            set_GSSERR(retmin);
622
0
            goto done;
623
0
        }
624
625
1.14k
        ctx->workstation = strdup(nb_computer_name);
626
1.14k
        if (!ctx->workstation) {
627
0
            set_GSSERR(ENOMEM);
628
0
            goto done;
629
0
        }
630
631
1.14k
        gssntlm_set_role(ctx, GSSNTLM_SERVER, nb_domain_name);
632
633
1.14k
        lm_compat_lvl = gssntlm_get_lm_compatibility_level();
634
1.14k
        if (!gssntlm_required_security(lm_compat_lvl, ctx)) {
635
0
            set_GSSERR(ERR_BADLMLVL);
636
0
            goto done;
637
0
        }
638
639
1.14k
        ctx->neg_flags = NTLMSSP_DEFAULT_SERVER_FLAGS;
640
        /* Fixme: How do we allow anonymous negotition ? */
641
642
        /* override neg_flags default if requested */
643
1.14k
        if (cred && cred->neg_flags) {
644
0
            ctx->neg_flags = cred->neg_flags;
645
0
        }
646
647
1.14k
        if (gssntlm_sec_lm_ok(ctx)) {
648
0
            ctx->neg_flags |= NTLMSSP_REQUEST_NON_NT_SESSION_KEY;
649
0
            ctx->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
650
0
        }
651
1.14k
        if (gssntlm_ext_sec_ok(ctx)) {
652
1.14k
            ctx->neg_flags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY;
653
1.14k
        }
654
655
1.14k
        retmin = ntlm_init_ctx(&ctx->ntlm);
656
1.14k
        if (retmin) {
657
0
            set_GSSERR(retmin);
658
0
            goto done;
659
0
        }
660
661
1.14k
        if (input_token && input_token->length != 0) {
662
1.14k
            ctx->nego_msg.data = malloc(input_token->length);
663
1.14k
            if (!ctx->nego_msg.data) {
664
0
                set_GSSERR(ENOMEM);
665
0
                goto done;
666
0
            }
667
1.14k
            memcpy(ctx->nego_msg.data, input_token->value, input_token->length);
668
1.14k
            ctx->nego_msg.length = input_token->length;
669
670
1.14k
            retmin = ntlm_decode_msg_type(ctx->ntlm, &ctx->nego_msg, &msg_type);
671
1.14k
            if (retmin || (msg_type != NEGOTIATE_MESSAGE)) {
672
185
                set_GSSERRS(retmin, GSS_S_DEFECTIVE_TOKEN);
673
185
                goto done;
674
185
            }
675
676
961
            retmin = ntlm_decode_neg_msg(ctx->ntlm, &ctx->nego_msg, &in_flags,
677
961
                                         NULL, NULL);
678
961
            if (retmin) {
679
0
                set_GSSERRS(retmin, GSS_S_DEFECTIVE_TOKEN);
680
0
                goto done;
681
0
            }
682
683
            /* leave only the crossing between requested and allowed flags */
684
961
            ctx->neg_flags &= in_flags;
685
686
            /* Try to force the use of NTLMSSP_NEGOTIATE_VERSION even if the
687
             * client did not advertize it in their negotiate message, but
688
             * should be capable of providing it.
689
             * This is what Windows Server 2022 also does, and addresses
690
             * issues with older clients that incorrectly deal with MIC
691
             * calculations in absence of this flag. */
692
961
            if ((ctx->neg_flags & (NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
693
961
                                    NTLMSSP_NEGOTIATE_SEAL |
694
961
                                    NTLMSSP_NEGOTIATE_SIGN))) {
695
798
                ctx->neg_flags |= NTLMSSP_NEGOTIATE_VERSION;
696
798
            }
697
961
        } else {
698
            /* If there is no negotiate message set datagram mode */
699
0
            ctx->neg_flags |= NTLMSSP_NEGOTIATE_DATAGRAM | \
700
0
                              NTLMSSP_NEGOTIATE_KEY_EXCH;
701
0
        }
702
703
        /* TODO: Check some minimum required flags ? */
704
        /* TODO: Check MS-NLMP ServerRequire128bitEncryption */
705
706
961
        if (ctx->neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
707
            /* Choose unicode in preferemce if both are set */
708
314
            ctx->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM;
709
647
        } else if (!(ctx->neg_flags & NTLMSSP_NEGOTIATE_OEM)) {
710
            /* no agreement */
711
4
            set_GSSERR(ERR_FAILNEGFLAGS);
712
4
            goto done;
713
4
        }
714
715
957
        if (ctx->neg_flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY) {
716
362
            ctx->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
717
362
        }
718
719
957
        if (ctx->neg_flags & NTLMSSP_REQUEST_TARGET) {
720
593
            ctx->neg_flags |= NTLMSSP_NEGOTIATE_TARGET_INFO;
721
593
        }
722
723
957
        if (ctx->neg_flags & NTLMSSP_NEGOTIATE_SIGN) {
724
401
            ctx->gss_flags |= GSS_C_INTEG_FLAG;
725
401
        }
726
957
        if (ctx->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
727
515
            ctx->gss_flags |= GSS_C_CONF_FLAG;
728
515
        }
729
957
        if (ctx->neg_flags & NTLMSSP_NEGOTIATE_DATAGRAM) {
730
0
            ctx->gss_flags |= GSS_C_DATAGRAM_FLAG;
731
0
        }
732
733
        /* Random server challenge */
734
957
        challenge.data = ctx->server_chal;
735
957
        challenge.length = 8;
736
957
        retmin = RAND_BUFFER(&challenge);
737
957
        if (retmin) {
738
0
            set_GSSERR(retmin);
739
0
            goto done;
740
0
        }
741
742
        /* TODO: allow client applications to set a context option to
743
         * provide an av_flags default value so that flags like
744
         * MSVAVFLAGS_UNVERIFIED_SPN can be set. By default SSPI does
745
         * not set this flag, and setting it causes servers with restrictive
746
         * policy to fail authentication. Given no MS client set this flag
747
         * by default, neither should we until there is a clear need. We
748
         * trust our calling applications to do the right thing here.
749
         * av_flags = MSVAVFLAGS_UNVERIFIED_SPN;
750
         */
751
752
957
        timestamp = ntlm_timestamp_now();
753
754
957
        retmin = ntlm_encode_target_info(ctx->ntlm,
755
957
                                         nb_computer_name,
756
957
                                         nb_domain_name,
757
957
                                         server_name->data.server.name,
758
957
                                         NULL, NULL,
759
957
                                         av_flags ? &av_flags : NULL, /* don't include empty MsvAvFlags */
760
957
                                         &timestamp,
761
957
                                         NULL,
762
957
                                         server_name->data.server.spn,
763
957
                                         NULL,
764
957
                                         &target_info);
765
957
        if (retmin) {
766
0
            set_GSSERR(retmin);
767
0
            goto done;
768
0
        }
769
770
957
        if (gssntlm_role_is_domain_member(ctx)) {
771
0
            chal_target_name = nb_domain_name;
772
0
            ctx->neg_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;
773
957
        } else {
774
957
            chal_target_name = nb_computer_name;
775
957
            ctx->neg_flags |= NTLMSSP_TARGET_TYPE_SERVER;
776
957
        }
777
778
957
        retmin = ntlm_encode_chal_msg(ctx->ntlm, ctx->neg_flags,
779
957
                                      chal_target_name, &challenge,
780
957
                                      &target_info, &ctx->chal_msg);
781
957
        if (retmin) {
782
0
            set_GSSERR(retmin);
783
0
            goto done;
784
0
        }
785
786
957
        ctx->stage = NTLMSSP_STAGE_CHALLENGE;
787
788
957
        output_token->value = malloc(ctx->chal_msg.length);
789
957
        if (!output_token->value) {
790
0
            set_GSSERR(ENOMEM);
791
0
            goto done;
792
0
        }
793
957
        memcpy(output_token->value, ctx->chal_msg.data, ctx->chal_msg.length);
794
957
        output_token->length = ctx->chal_msg.length;
795
796
957
        retmaj = GSS_S_CONTINUE_NEEDED;
797
798
957
    } else {
799
935
        ctx = (struct gssntlm_ctx *)(*context_handle);
800
801
935
        if (!gssntlm_role_is_server(ctx)) {
802
0
            set_GSSERRS(ERR_WRONGCTX, GSS_S_NO_CONTEXT);
803
0
            goto done;
804
0
        }
805
806
935
        if ((input_token == GSS_C_NO_BUFFER) ||
807
935
            (input_token->length == 0)) {
808
0
            set_GSSERRS(ERR_NOTOKEN, GSS_S_DEFECTIVE_TOKEN);
809
0
            goto done;
810
0
        }
811
812
935
        ctx->auth_msg.data = malloc(input_token->length);
813
935
        if (!ctx->auth_msg.data) {
814
0
            set_GSSERR(ENOMEM);
815
0
            goto done;
816
0
        }
817
935
        memcpy(ctx->auth_msg.data, input_token->value, input_token->length);
818
935
        ctx->auth_msg.length = input_token->length;
819
820
935
        retmin = ntlm_decode_msg_type(ctx->ntlm, &ctx->auth_msg, &msg_type);
821
935
        if (retmin) {
822
9
            set_GSSERRS(retmin, GSS_S_DEFECTIVE_TOKEN);
823
9
            goto done;
824
9
        }
825
826
926
        if (msg_type != AUTHENTICATE_MESSAGE ||
827
926
                ctx->stage != NTLMSSP_STAGE_CHALLENGE) {
828
5
            set_GSSERRS(ERR_WRONGMSG, GSS_S_NO_CONTEXT);
829
5
            goto done;
830
5
        }
831
832
921
        retmin = ntlm_decode_auth_msg(ctx->ntlm, &ctx->auth_msg,
833
921
                                      ctx->neg_flags,
834
921
                                      &lm_chal_resp, &nt_chal_resp,
835
921
                                      &dom_name, &usr_name, &wks_name,
836
921
                                      &enc_sess_key, &target_info, &mic);
837
921
        if (retmin) {
838
548
            set_GSSERRS(retmin, GSS_S_DEFECTIVE_TOKEN);
839
548
            goto done;
840
548
        }
841
842
373
        if (target_info.length > 0) {
843
209
            retmin = ntlm_decode_target_info(ctx->ntlm, &target_info,
844
209
                                             NULL, NULL, NULL, NULL,
845
209
                                             NULL, NULL, &av_flags,
846
209
                                             NULL, NULL, &av_cb);
847
209
            if (retmin) {
848
194
                set_GSSERR(retmin);
849
194
                goto done;
850
194
            }
851
209
        }
852
853
179
        if ((ctx->neg_flags & NTLMSSP_NEGOTIATE_DATAGRAM) &&
854
179
            !(ctx->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
855
0
            set_GSSERRS(ERR_BADNEGFLAGS, GSS_S_DEFECTIVE_TOKEN);
856
0
            goto done;
857
0
        }
858
859
179
        if ((usr_name == NULL) || (usr_name[0] == '\0')) {
860
74
            if ((nt_chal_resp.length == 0) &&
861
74
                (((lm_chal_resp.length == 1) &&
862
60
                  (lm_chal_resp.data[0] == '\0')) ||
863
60
                 (lm_chal_resp.length == 0))) {
864
                /* Anonymous auth */
865
                /* FIXME: not supported for now */
866
14
                set_GSSERR(ERR_NOTSUPPORTED);
867
14
                goto done;
868
60
            } else {
869
60
                set_GSSERR(ERR_NOUSRFOUND);
870
60
                goto done;
871
60
            }
872
105
        } else {
873
874
105
            char useratdom[1024];
875
105
            size_t ulen, dlen, uadlen;
876
105
            gss_buffer_desc usrname;
877
105
            gss_const_key_value_set_t cred_store = GSS_C_NO_CRED_STORE;
878
105
            gss_key_value_set_desc cs;
879
105
            gss_key_value_element_desc cs_el;
880
881
105
            if (!dom_name) {
882
12
                dom_name = strdup("");
883
12
                if (!dom_name) {
884
0
                    set_GSSERR(ENOMEM);
885
0
                    goto done;
886
0
                }
887
12
            }
888
889
            /* Use domain\username format as that allows to pass in
890
             * enterprise names without the need to escape them */
891
105
            ulen = strlen(usr_name);
892
105
            dlen = strlen(dom_name);
893
105
            if (ulen + dlen + 2 > 1024) {
894
17
                set_GSSERR(ERR_NAMETOOLONG);
895
17
                goto done;
896
17
            }
897
88
            uadlen = dlen;
898
88
            if (dlen) {
899
74
                memcpy(useratdom, dom_name, dlen);
900
74
            }
901
902
            /* always add the domain separator, this way if the username
903
             * is an enteprise name (user@email.domain form) it will be
904
             * correctly recognized by gssntlm_import_name() as such */
905
88
            useratdom[uadlen] = '\\';
906
88
            uadlen++;
907
908
            /* finally add usernmae part */
909
88
            memcpy(&useratdom[uadlen], usr_name, ulen);
910
88
            uadlen += ulen;
911
88
            useratdom[uadlen] = '\0';
912
913
88
            usrname.value = useratdom;
914
88
            usrname.length = uadlen;
915
88
            retmaj = gssntlm_import_name(&retmin, &usrname,
916
88
                                         GSS_C_NT_USER_NAME,
917
88
                                         (gss_name_t *)&gss_usrname);
918
88
            if (retmaj) goto done;
919
920
80
            if (cred && cred->cred.server.keyfile) {
921
0
                cs_el.key = GSS_NTLMSSP_CS_KEYFILE;
922
0
                cs_el.value = cred->cred.server.keyfile;
923
0
                cs.count = 1;
924
0
                cs.elements = &cs_el;
925
0
                cred_store = &cs;
926
0
            }
927
928
80
            retmaj = gssntlm_acquire_cred_from(&retmin, ctx->external_context,
929
80
                                               (gss_name_t)gss_usrname,
930
80
                                                GSS_C_INDEFINITE,
931
80
                                                GSS_C_NO_OID_SET,
932
80
                                                GSS_C_INITIATE,
933
80
                                                cred_store,
934
80
                                                (gss_cred_id_t *)&usr_cred,
935
80
                                                NULL, NULL);
936
80
            if (retmaj) goto done;
937
            /* We can't handle winbind credentials yet */
938
0
            if (usr_cred->type != GSSNTLM_CRED_USER &&
939
0
                usr_cred->type != GSSNTLM_CRED_EXTERNAL) {
940
0
                set_GSSERRS(ERR_NOUSRCRED, GSS_S_DEFECTIVE_CREDENTIAL);
941
0
                goto done;
942
0
            }
943
944
0
            retmin = gssntlm_copy_name(gss_usrname, &ctx->source_name);
945
0
            if (retmin) {
946
0
                set_GSSERR(retmin);
947
0
                goto done;
948
0
            }
949
950
0
            retmaj = gssntlm_srv_auth(&retmin, ctx, usr_cred,
951
0
                                      &nt_chal_resp, &lm_chal_resp,
952
0
                                      &key_exchange_key);
953
0
            if (retmaj) goto done;
954
0
        }
955
956
0
        if (ctx->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
957
0
            memcpy(encrypted_random_session_key.data, enc_sess_key.data, 16);
958
0
            ctx->exported_session_key.length = 16;
959
960
0
            retmin = ntlm_encrypted_session_key(&key_exchange_key,
961
0
                                                &encrypted_random_session_key,
962
0
                                                &ctx->exported_session_key);
963
0
            if (retmin) {
964
0
                set_GSSERR(retmin);
965
0
                goto done;
966
0
            }
967
0
        } else {
968
0
            ctx->exported_session_key = key_exchange_key;
969
0
        }
970
971
        /* check if MIC was sent */
972
0
        if (av_flags & MSVAVFLAGS_MIC_PRESENT) {
973
0
            retmin = ntlm_verify_mic(&ctx->exported_session_key,
974
0
                                     &ctx->nego_msg, &ctx->chal_msg,
975
0
                                     &ctx->auth_msg, &mic);
976
0
            if (retmin) {
977
0
                set_GSSERRS(retmin, GSS_S_DEFECTIVE_TOKEN);
978
0
                goto done;
979
0
            }
980
0
        }
981
982
0
        if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) {
983
0
            uint8_t zero_cb[16] = { 0 };
984
0
            if (input_chan_bindings->initiator_addrtype != 0 ||
985
0
                input_chan_bindings->initiator_address.length != 0 ||
986
0
                input_chan_bindings->acceptor_addrtype != 0 ||
987
0
                input_chan_bindings->acceptor_address.length != 0 ||
988
0
                input_chan_bindings->application_data.length == 0) {
989
0
                set_GSSERRS(ERR_BADARG, GSS_S_BAD_BINDINGS);
990
0
                goto done;
991
0
            }
992
0
            unhashed_cb.length = input_chan_bindings->application_data.length;
993
0
            unhashed_cb.data = input_chan_bindings->application_data.value;
994
995
0
            if (av_cb.length && (av_cb.length != 16)) {
996
0
                set_GSSERRS(retmin, GSS_S_DEFECTIVE_TOKEN);
997
0
                goto done;
998
0
            }
999
0
            if (av_cb.length &&
1000
0
                (memcmp(av_cb.data, zero_cb, 16) != 0)) {
1001
0
                retmin = ntlm_verify_channel_bindings(&unhashed_cb, &av_cb);
1002
0
                if (retmin) {
1003
0
                    set_GSSERRS(retmin, GSS_S_DEFECTIVE_TOKEN);
1004
0
                    goto done;
1005
/* This flag has been introduced only recently in MIT krb5 */
1006
#ifdef GSS_C_CHANNEL_BOUND_FLAG
1007
                } else {
1008
                    ctx->gss_flags |= GSS_C_CHANNEL_BOUND_FLAG;
1009
#endif /* GSS_C_CHANNEL_BOUND_FLAG */
1010
0
                }
1011
0
            }
1012
0
        }
1013
1014
0
        if (ctx->neg_flags & (NTLMSSP_NEGOTIATE_SIGN |
1015
0
                                NTLMSSP_NEGOTIATE_SEAL)) {
1016
0
            retmin = ntlm_signseal_keys(ctx->neg_flags, false,
1017
0
                                        &ctx->exported_session_key,
1018
0
                                        &ctx->crypto_state);
1019
0
            if (retmin) {
1020
0
                set_GSSERR(retmin);
1021
0
                goto done;
1022
0
            }
1023
0
        }
1024
1025
0
        if (src_name) {
1026
0
            retmaj = gssntlm_duplicate_name(&retmin,
1027
0
                                            (gss_name_t)&ctx->source_name,
1028
0
                                            src_name);
1029
0
            if (retmaj) goto done;
1030
0
        }
1031
1032
0
        ctx->stage = NTLMSSP_STAGE_DONE;
1033
0
        ctx->expiration_time = time(NULL) + MAX_CHALRESP_LIFETIME;
1034
0
        ctx->int_flags |= NTLMSSP_CTX_FLAG_ESTABLISHED;
1035
0
        set_GSSERRS(0, GSS_S_COMPLETE);
1036
0
    }
1037
1038
2.08k
done:
1039
1040
2.08k
    if ((retmaj != GSS_S_COMPLETE) &&
1041
2.08k
        (retmaj != GSS_S_CONTINUE_NEEDED)) {
1042
1.12k
        gssntlm_delete_sec_context(&tmpmin, (gss_ctx_id_t *)&ctx, NULL);
1043
1.12k
    } else {
1044
957
        if (mech_type) *mech_type = discard_const(&gssntlm_oid);
1045
957
        if (ret_flags) *ret_flags = ctx->gss_flags;
1046
957
        if (time_rec) *time_rec = GSS_C_INDEFINITE;
1047
957
    }
1048
2.08k
    *context_handle = (gss_ctx_id_t)ctx;
1049
2.08k
    gssntlm_release_name(&tmpmin, (gss_name_t *)&server_name);
1050
2.08k
    gssntlm_release_name(&tmpmin, (gss_name_t *)&gss_usrname);
1051
2.08k
    gssntlm_release_cred(&tmpmin, (gss_cred_id_t *)&usr_cred);
1052
2.08k
    safefree(nb_computer_name);
1053
2.08k
    safefree(nb_domain_name);
1054
2.08k
    safefree(usr_name);
1055
2.08k
    safefree(dom_name);
1056
2.08k
    safefree(wks_name);
1057
2.08k
    ntlm_free_buffer_data(&nt_chal_resp);
1058
2.08k
    ntlm_free_buffer_data(&lm_chal_resp);
1059
2.08k
    ntlm_free_buffer_data(&enc_sess_key);
1060
2.08k
    ntlm_free_buffer_data(&target_info);
1061
1062
2.08k
    return GSSERR();
1063
2.08k
}
1064
1065
uint32_t gssntlm_inquire_context(uint32_t *minor_status,
1066
                                 gss_ctx_id_t context_handle,
1067
                                 gss_name_t *src_name,
1068
                                 gss_name_t *targ_name,
1069
                                 uint32_t *lifetime_rec,
1070
                                 gss_OID *mech_type,
1071
                                 uint32_t *ctx_flags,
1072
                                 int *locally_initiated,
1073
                                 int *open)
1074
0
{
1075
0
    struct gssntlm_ctx *ctx;
1076
0
    uint32_t retmaj;
1077
0
    uint32_t retmin;
1078
0
    time_t now;
1079
1080
0
    ctx = (struct gssntlm_ctx *)context_handle;
1081
0
    if (!ctx) {
1082
0
        return GSSERRS(ERR_NOARG, GSS_S_NO_CONTEXT);
1083
0
    }
1084
1085
0
    if (src_name) {
1086
0
        retmaj = gssntlm_duplicate_name(&retmin,
1087
0
                                        (gss_name_t)&ctx->source_name,
1088
0
                                        src_name);
1089
0
        if (retmaj) goto done;
1090
0
    }
1091
1092
0
    if (targ_name) {
1093
0
        retmaj = gssntlm_duplicate_name(&retmin,
1094
0
                                        (gss_name_t)&ctx->target_name,
1095
0
                                        targ_name);
1096
0
        if (retmaj) goto done;
1097
0
    }
1098
1099
0
    if (mech_type) {
1100
0
        *mech_type = discard_const(&gssntlm_oid);
1101
0
    }
1102
1103
0
    if (ctx_flags) {
1104
0
        *ctx_flags = ctx->gss_flags;
1105
0
    }
1106
1107
0
    if (locally_initiated) {
1108
0
        if (gssntlm_role_is_client(ctx)) {
1109
0
            *locally_initiated = 1;
1110
0
        } else {
1111
0
            *locally_initiated = 0;
1112
0
        }
1113
0
    }
1114
1115
0
    if (ctx->int_flags & NTLMSSP_CTX_FLAG_ESTABLISHED) {
1116
0
        if (lifetime_rec) {
1117
0
            now = time(NULL);
1118
0
            if (ctx->expiration_time > now) {
1119
0
                *lifetime_rec = 0;
1120
0
            } else {
1121
0
                *lifetime_rec = ctx->expiration_time - now;
1122
0
            }
1123
0
        }
1124
0
        if (open) {
1125
0
            *open = 1;
1126
0
        }
1127
0
    } else {
1128
0
        if (lifetime_rec) {
1129
0
            *lifetime_rec = 0;
1130
0
        }
1131
0
        if (open) {
1132
0
            *open = 0;
1133
0
        }
1134
0
    }
1135
1136
0
    set_GSSERRS(0, GSS_S_COMPLETE);
1137
1138
0
done:
1139
0
    return GSSERR();
1140
0
}
1141
1142
gss_OID_desc set_seq_num_oid = {
1143
    GSS_NTLMSSP_SET_SEQ_NUM_OID_LENGTH,
1144
    discard_const(GSS_NTLMSSP_SET_SEQ_NUM_OID_STRING)
1145
};
1146
1147
uint32_t gssntlm_set_seq_num(uint32_t *minor_status,
1148
                             struct gssntlm_ctx *ctx,
1149
                             const gss_buffer_t value)
1150
0
{
1151
0
    uint32_t retmin;
1152
0
    uint32_t retmaj;
1153
1154
0
    if (ctx->gss_flags & GSS_C_DATAGRAM_FLAG) {
1155
0
        if (value->length != 4) {
1156
0
            return GSSERRS(ERR_BADARG, GSS_S_FAILURE);
1157
0
        }
1158
0
        memcpy(&ctx->crypto_state.recv.seq_num,
1159
0
               value->value, value->length);
1160
0
        ctx->crypto_state.send.seq_num = ctx->crypto_state.recv.seq_num;
1161
0
    } else {
1162
0
        return GSSERRS(ERR_WRONGCTX, GSS_S_FAILURE);
1163
0
    }
1164
1165
0
    return GSSERRS(0, GSS_S_COMPLETE);
1166
0
}
1167
1168
gss_OID_desc reset_crypto_oid = {
1169
    GSS_NTLMSSP_RESET_CRYPTO_OID_LENGTH,
1170
    discard_const(GSS_NTLMSSP_RESET_CRYPTO_OID_STRING)
1171
};
1172
1173
uint32_t gssntlm_reset_crypto(uint32_t *minor_status,
1174
                              struct gssntlm_ctx *ctx,
1175
                              const gss_buffer_t value)
1176
0
{
1177
0
    uint32_t retmin;
1178
0
    uint32_t retmaj;
1179
1180
0
    if (value->length != 4) {
1181
0
        return GSSERRS(ERR_BADARG, GSS_S_FAILURE);
1182
0
    }
1183
1184
    /* reset crypto state */
1185
0
    if (ctx->neg_flags & (NTLMSSP_NEGOTIATE_SIGN |
1186
0
                            NTLMSSP_NEGOTIATE_SEAL)) {
1187
0
        uint32_t val;
1188
1189
0
        memcpy(&val, value->value, value->length);
1190
1191
        /* A val of 1 means we want to reset the verifier handle,
1192
         * which is the receive handle for NTLM, otherwise we reset
1193
         * the send handle. */
1194
0
        retmin = ntlm_reset_rc4_state(ctx->neg_flags, (val == 1),
1195
0
                                      &ctx->exported_session_key,
1196
0
                                      &ctx->crypto_state);
1197
0
        if (retmin) {
1198
0
            return GSSERRS(retmin, GSS_S_FAILURE);
1199
0
        }
1200
0
    }
1201
1202
0
    return GSSERRS(0, GSS_S_COMPLETE);
1203
0
}
1204
1205
uint32_t gssntlm_set_sec_context_option(uint32_t *minor_status,
1206
                                        gss_ctx_id_t *context_handle,
1207
                                        const gss_OID desired_object,
1208
                                        const gss_buffer_t value)
1209
0
{
1210
0
    struct gssntlm_ctx *ctx;
1211
0
    uint32_t retmin;
1212
0
    uint32_t retmaj;
1213
1214
0
    if (context_handle == NULL || *context_handle == NULL) {
1215
0
        return GSSERRS(ERR_NOARG, GSS_S_CALL_INACCESSIBLE_READ);
1216
0
    }
1217
0
    if (desired_object == GSS_C_NO_OID) {
1218
0
        return GSSERRS(ERR_NOARG, GSS_S_CALL_INACCESSIBLE_READ);
1219
0
    }
1220
1221
0
    ctx = (struct gssntlm_ctx *)*context_handle;
1222
1223
    /* set seq num */
1224
0
    if (gss_oid_equal(desired_object, &set_seq_num_oid)) {
1225
0
        return gssntlm_set_seq_num(minor_status, ctx, value);
1226
0
    } else if (gss_oid_equal(desired_object, &reset_crypto_oid)) {
1227
0
        return gssntlm_reset_crypto(minor_status, ctx, value);
1228
0
    }
1229
1230
0
    return GSSERRS(ERR_BADARG, GSS_S_UNAVAILABLE);
1231
0
}
1232
1233
gss_OID_desc spnego_req_mic_oid = {
1234
    GSS_SPNEGO_REQUIRE_MIC_OID_LENGTH,
1235
    discard_const(GSS_SPNEGO_REQUIRE_MIC_OID_STRING)
1236
};
1237
1238
uint32_t gssntlm_spnego_req_mic(uint32_t *minor_status,
1239
                                struct gssntlm_ctx *ctx,
1240
                                gss_buffer_set_t *data_set)
1241
0
{
1242
0
    gss_buffer_desc mic_buf;
1243
0
    uint32_t retmin;
1244
0
    uint32_t retmaj;
1245
0
    uint32_t tmpmin;
1246
0
    uint8_t mic_set;
1247
1248
    /* the simple fact the spnego layer is asking means it can handle
1249
     * forcing mechlistMIC if we add a MIC to the Authenticate packet.
1250
     * We expect this to be called before the authenticate token is
1251
     * generated to set this flag ... */
1252
0
    ctx->int_flags |= NTLMSSP_CTX_FLAG_SPNEGO_CAN_MIC;
1253
1254
    /* ... and then again after, in which case if we actually did add
1255
     * a MIC we can tell spnego to add a mechlistMIC */
1256
0
    if (ctx->int_flags & NTLMSSP_CTX_FLAG_AUTH_WITH_MIC) {
1257
0
        mic_set = 1;
1258
0
    } else {
1259
0
        mic_set = 0;
1260
0
    }
1261
1262
0
    mic_buf.value = &mic_set;
1263
0
    mic_buf.length = sizeof(mic_set);
1264
1265
0
    retmaj = gss_add_buffer_set_member(&retmin, &mic_buf, data_set);
1266
0
    if (retmaj != GSS_S_COMPLETE) {
1267
0
        (void)gss_release_buffer_set(&tmpmin, data_set);
1268
0
    }
1269
1270
0
    return GSSERRS(retmin, retmaj);
1271
0
}
1272
1273
static const gss_OID_desc sasl_ssf_oid = {
1274
    11, discard_const("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0f")
1275
};
1276
1277
static uint32_t gssntlm_sasl_ssf(uint32_t *minor_status,
1278
                                 struct gssntlm_ctx *ctx,
1279
                                 gss_buffer_set_t *data_set)
1280
0
{
1281
0
    uint32_t retmin;
1282
0
    uint32_t retmaj;
1283
0
    uint32_t tmpmin;
1284
0
    gss_buffer_desc ssf_buf;
1285
0
    uint32_t ssf = 0;
1286
1287
    /* Handwaving a bit here but this is what SSF is all about */
1288
0
    if (ctx->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
1289
0
        if (ctx->neg_flags & NTLMSSP_NEGOTIATE_128) {
1290
            /* Technically we use RC4 with a 128 bit key, but we
1291
             * consider the RC4 strenght degraded so we assign
1292
             * it a value of 64, this is consistent with what
1293
             * the krb5 mechanism does for the Rc4-HMAC enctype */
1294
0
            ssf = 64;
1295
0
        } else if (ctx->neg_flags & NTLMSSP_NEGOTIATE_56) {
1296
0
            ssf = 56;
1297
0
        } else {
1298
0
            ssf = 40;
1299
0
        }
1300
0
    } else if (ctx->neg_flags & NTLMSSP_NEGOTIATE_SIGN) {
1301
0
        ssf = 1;
1302
0
    }
1303
1304
0
    ssf = htobe32(ssf);
1305
0
    ssf_buf.value = &ssf;
1306
0
    ssf_buf.length = 4;
1307
1308
0
    retmaj = gss_add_buffer_set_member(&retmin, &ssf_buf, data_set);
1309
0
    if (retmaj != GSS_S_COMPLETE) {
1310
0
        (void)gss_release_buffer_set(&tmpmin, data_set);
1311
0
    }
1312
1313
0
    return GSSERRS(retmin, retmaj);
1314
0
}
1315
1316
static uint32_t gssntlm_sspi_session_key(uint32_t *minor_status,
1317
                                         struct gssntlm_ctx *ctx,
1318
                                         gss_buffer_set_t *data_set)
1319
0
{
1320
0
    uint32_t retmin;
1321
0
    uint32_t retmaj;
1322
0
    uint32_t tmpmin;
1323
0
    gss_buffer_desc session_key_buf;
1324
1325
0
    if (ctx->exported_session_key.length == 0) {
1326
0
      return GSSERRS(ERR_NOTAVAIL, GSS_S_UNAVAILABLE);
1327
0
    }
1328
1329
0
    session_key_buf.length = ctx->exported_session_key.length;
1330
0
    session_key_buf.value = ctx->exported_session_key.data;
1331
1332
0
    retmaj = gss_add_buffer_set_member(&retmin, &session_key_buf,  data_set);
1333
0
    if (retmaj != GSS_S_COMPLETE) {
1334
0
        (void)gss_release_buffer_set(&tmpmin, data_set);
1335
0
    }
1336
0
    return GSSERRS(retmin, retmaj);
1337
0
}
1338
1339
uint32_t gssntlm_inquire_sec_context_by_oid(uint32_t *minor_status,
1340
                                      const gss_ctx_id_t context_handle,
1341
                                      const gss_OID desired_object,
1342
                                      gss_buffer_set_t *data_set)
1343
0
{
1344
0
    struct gssntlm_ctx *ctx;
1345
0
    uint32_t retmin;
1346
0
    uint32_t retmaj;
1347
1348
0
    if (context_handle == NULL) {
1349
0
        return GSSERRS(ERR_NOARG, GSS_S_CALL_INACCESSIBLE_READ);
1350
0
    }
1351
0
    if (desired_object == GSS_C_NO_OID) {
1352
0
        return GSSERRS(ERR_NOARG, GSS_S_CALL_INACCESSIBLE_READ);
1353
0
    }
1354
0
    if (!data_set) {
1355
0
        return GSSERRS(ERR_NOARG, GSS_S_CALL_INACCESSIBLE_WRITE);
1356
0
    }
1357
1358
0
    ctx = (struct gssntlm_ctx *)context_handle;
1359
0
    *data_set = GSS_C_NO_BUFFER_SET;
1360
1361
0
    if (gss_oid_equal(desired_object, &spnego_req_mic_oid)) {
1362
0
        return gssntlm_spnego_req_mic(minor_status, ctx, data_set);
1363
0
    } else if (gss_oid_equal(desired_object, &sasl_ssf_oid)){
1364
0
        return gssntlm_sasl_ssf(minor_status, ctx, data_set);
1365
0
    } else if (gss_oid_equal(desired_object, GSS_C_INQ_SSPI_SESSION_KEY)) {
1366
0
      return gssntlm_sspi_session_key(minor_status, ctx, data_set);
1367
0
    }
1368
1369
0
    return GSSERRS(ERR_NOTSUPPORTED, GSS_S_UNAVAILABLE);
1370
0
}