Coverage Report

Created: 2026-04-01 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source4/librpc/rpc/dcerpc_schannel.c
Line
Count
Source
1
/* 
2
   Unix SMB/CIFS implementation.
3
4
   dcerpc schannel operations
5
6
   Copyright (C) Andrew Tridgell 2004
7
   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
8
   Copyright (C) Rafal Szczesniak 2006
9
10
   This program is free software; you can redistribute it and/or modify
11
   it under the terms of the GNU General Public License as published by
12
   the Free Software Foundation; either version 3 of the License, or
13
   (at your option) any later version.
14
   
15
   This program is distributed in the hope that it will be useful,
16
   but WITHOUT ANY WARRANTY; without even the implied warranty of
17
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
   GNU General Public License for more details.
19
   
20
   You should have received a copy of the GNU General Public License
21
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
*/
23
24
#define SOURCE4_LIBRPC_INTERNALS 1
25
26
#include "includes.h"
27
#include <tevent.h>
28
#include "auth/auth.h"
29
#include "libcli/composite/composite.h"
30
#include "libcli/auth/libcli_auth.h"
31
#include "librpc/gen_ndr/ndr_netlogon.h"
32
#include "librpc/gen_ndr/ndr_netlogon_c.h"
33
#include "auth/credentials/credentials.h"
34
#include "librpc/rpc/dcerpc_proto.h"
35
#include "param/param.h"
36
#include "lib/param/loadparm.h"
37
38
struct schannel_key_state {
39
  struct loadparm_context *lp_ctx;
40
  struct dcerpc_pipe *pipe;
41
  struct dcerpc_pipe *pipe2;
42
  struct dcerpc_binding *binding;
43
  bool dcerpc_schannel_auto;
44
  struct cli_credentials *credentials;
45
  struct netlogon_creds_CredentialState *creds;
46
  uint32_t requested_negotiate_flags;
47
  uint32_t required_negotiate_flags;
48
  uint32_t local_negotiate_flags;
49
  uint32_t remote_negotiate_flags;
50
  struct netr_Credential credentials1;
51
  struct netr_Credential credentials2;
52
  struct netr_Credential credentials3;
53
  struct netr_ServerReqChallenge r;
54
  struct netr_ServerAuthenticate2 a;
55
  uint32_t rid;
56
  struct netr_ServerAuthenticateKerberos k;
57
  const struct samr_Password *mach_pwd;
58
};
59
60
61
static void continue_secondary_connection(struct composite_context *ctx);
62
static void continue_bind_auth_krb5(struct composite_context *ctx);
63
static void continue_srv_auth_krb5(struct tevent_req *subreq);
64
static void continue_bind_auth_none(struct composite_context *ctx);
65
static void start_srv_challenge(struct composite_context *c);
66
static void continue_srv_challenge(struct tevent_req *subreq);
67
static void continue_srv_auth2(struct tevent_req *subreq);
68
static void continue_get_negotiated_capabilities(struct tevent_req *subreq);
69
static void continue_get_client_capabilities(struct tevent_req *subreq);
70
71
72
/*
73
  Stage 2 of schannel_key: Receive endpoint mapping and request secondary
74
  rpc connection
75
*/
76
static void continue_epm_map_binding(struct composite_context *ctx)
77
0
{
78
0
  struct composite_context *c;
79
0
  struct schannel_key_state *s;
80
0
  struct composite_context *sec_conn_req;
81
82
0
  c = talloc_get_type(ctx->async.private_data, struct composite_context);
83
0
  s = talloc_get_type(c->private_data, struct schannel_key_state);
84
85
  /* receive endpoint mapping */
86
0
  c->status = dcerpc_epm_map_binding_recv(ctx);
87
0
  if (!NT_STATUS_IS_OK(c->status)) {
88
0
    DEBUG(0,("Failed to map DCERPC/TCP NCACN_NP pipe for '%s' - %s\n",
89
0
       NDR_NETLOGON_UUID, nt_errstr(c->status)));
90
0
    composite_error(c, c->status);
91
0
    return;
92
0
  }
93
94
  /* send a request for secondary rpc connection */
95
0
  sec_conn_req = dcerpc_secondary_connection_send(s->pipe,
96
0
              s->binding);
97
0
  if (composite_nomem(sec_conn_req, c)) return;
98
99
0
  composite_continue(c, sec_conn_req, continue_secondary_connection, c);
100
0
}
101
102
103
/*
104
  Stage 3 of schannel_key: Receive secondary rpc connection and perform
105
  non-authenticated bind request
106
*/
107
static void continue_secondary_connection(struct composite_context *ctx)
108
0
{
109
0
  struct composite_context *c;
110
0
  struct schannel_key_state *s;
111
0
  struct composite_context *auth_none_req;
112
113
0
  c = talloc_get_type(ctx->async.private_data, struct composite_context);
114
0
  s = talloc_get_type(c->private_data, struct schannel_key_state);
115
116
  /* receive secondary rpc connection */
117
0
  c->status = dcerpc_secondary_connection_recv(ctx, &s->pipe2);
118
0
  if (!composite_is_ok(c)) return;
119
120
0
  talloc_steal(s, s->pipe2);
121
122
0
  s->r.in.server_name   = talloc_asprintf(c, "\\\\%s", dcerpc_server_name(s->pipe));
123
0
  if (composite_nomem(s->r.in.server_name, c)) return;
124
0
  s->r.in.computer_name = cli_credentials_get_workstation(s->credentials);
125
126
0
  if (s->requested_negotiate_flags & NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH) {
127
0
    struct composite_context *auth_krb5_req = NULL;
128
0
    const char *target_service =
129
0
      ndr_table_netlogon.authservices->names[0];
130
131
0
    auth_krb5_req = dcerpc_bind_auth_send(c,
132
0
                  s->pipe2,
133
0
                  &ndr_table_netlogon,
134
0
                  s->credentials,
135
0
                  lpcfg_gensec_settings(c, s->lp_ctx),
136
0
                  DCERPC_AUTH_TYPE_KRB5,
137
0
                  DCERPC_AUTH_LEVEL_PRIVACY,
138
0
                  target_service);
139
0
    composite_continue(c, auth_krb5_req, continue_bind_auth_krb5, c);
140
0
    return;
141
0
  }
142
143
  /* initiate a non-authenticated bind */
144
0
  auth_none_req = dcerpc_bind_auth_none_send(c, s->pipe2, &ndr_table_netlogon);
145
0
  if (composite_nomem(auth_none_req, c)) return;
146
147
0
  composite_continue(c, auth_none_req, continue_bind_auth_none, c);
148
0
}
149
150
static void continue_bind_auth_krb5(struct composite_context *ctx)
151
0
{
152
0
  struct composite_context *c;
153
0
  struct schannel_key_state *s;
154
0
  struct tevent_req *subreq;
155
0
  NTSTATUS status;
156
157
0
  c = talloc_get_type(ctx->async.private_data, struct composite_context);
158
0
  s = talloc_get_type(c->private_data, struct schannel_key_state);
159
160
  /* receive result of krb5 bind request */
161
0
  status = dcerpc_bind_auth_recv(ctx);
162
0
  if (!NT_STATUS_IS_OK(status)) {
163
0
    struct composite_context *auth_none_req = NULL;
164
165
0
    if (s->required_negotiate_flags & NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH) {
166
0
      composite_error(c, status);
167
0
      return;
168
0
    }
169
170
    /* initiate a non-authenticated bind */
171
0
    auth_none_req = dcerpc_bind_auth_none_send(c, s->pipe2, &ndr_table_netlogon);
172
0
    if (composite_nomem(auth_none_req, c)) return;
173
174
0
    composite_continue(c, auth_none_req, continue_bind_auth_none, c);
175
0
    return;
176
0
  }
177
178
  /* AuthenticateKerberos request arguments */
179
0
  s->k.in.server_name      = talloc_asprintf(c, "\\\\%s", dcerpc_server_name(s->pipe2));
180
0
  if (composite_nomem(s->k.in.server_name, c)) return;
181
0
  s->k.in.account_name     = cli_credentials_get_username(s->credentials);
182
0
  s->k.in.account_type     =
183
0
    cli_credentials_get_secure_channel_type(s->credentials);
184
0
  s->k.in.computer_name    = cli_credentials_get_workstation(s->credentials);
185
0
  s->k.in.negotiate_flags  = &s->requested_negotiate_flags;
186
0
  s->k.out.rid             = &s->rid;
187
0
  s->k.out.negotiate_flags = &s->remote_negotiate_flags;
188
189
0
  s->creds = netlogon_creds_kerberos_init(s,
190
0
                  s->k.in.account_name,
191
0
                  s->k.in.computer_name,
192
0
                  s->k.in.account_type,
193
0
                  s->requested_negotiate_flags,
194
0
            NULL, /* client_sid */
195
0
                  s->local_negotiate_flags);
196
0
  if (composite_nomem(s->creds, c)) {
197
0
    return;
198
0
  }
199
200
  /*
201
    authenticate on the netlogon pipe - a rpc request over secondary pipe
202
  */
203
0
  subreq = dcerpc_netr_ServerAuthenticateKerberos_r_send(s, c->event_ctx,
204
0
                     s->pipe2->binding_handle,
205
0
                     &s->k);
206
0
  if (composite_nomem(subreq, c)) return;
207
208
0
  tevent_req_set_callback(subreq, continue_srv_auth_krb5, c);
209
0
}
210
211
static void continue_srv_auth_krb5(struct tevent_req *subreq)
212
0
{
213
0
  struct composite_context *c;
214
0
  struct schannel_key_state *s;
215
216
0
  c = tevent_req_callback_data(subreq, struct composite_context);
217
0
  s = talloc_get_type(c->private_data, struct schannel_key_state);
218
219
0
  c->status = dcerpc_netr_ServerAuthenticateKerberos_r_recv(subreq, s);
220
0
  TALLOC_FREE(subreq);
221
0
  if (NT_STATUS_EQUAL(c->status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
222
0
    if (s->required_negotiate_flags & NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH) {
223
0
      DBG_ERR("%s: NT_STATUS_DOWNGRADE_DETECTED\n", __location__);
224
0
      composite_error(c, NT_STATUS_DOWNGRADE_DETECTED);
225
0
      return;
226
0
    }
227
228
0
    if (!s->dcerpc_schannel_auto) {
229
0
      composite_error(c, c->status);
230
0
      return;
231
0
    }
232
233
    /*
234
     * Fallback to ServerReqChallenge
235
     * and ServerAuthenticate2
236
     */
237
0
    start_srv_challenge(c);
238
0
    return;
239
0
  }
240
241
0
  if (!composite_is_ok(c)) return;
242
243
0
  if (!NT_STATUS_IS_OK(s->k.out.result)) {
244
0
    composite_error(c, s->k.out.result);
245
0
    return;
246
0
  }
247
248
0
  SMB_ASSERT(s->requested_negotiate_flags == s->local_negotiate_flags);
249
250
0
  {
251
0
    uint32_t rqf = s->required_negotiate_flags;
252
0
    uint32_t rf = s->remote_negotiate_flags;
253
0
    uint32_t lf = s->local_negotiate_flags;
254
255
0
    rqf |= NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH;
256
257
0
    if (rf & NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH) {
258
0
      rqf &= ~NETLOGON_NEG_ARCFOUR;
259
0
      rqf &= ~NETLOGON_NEG_STRONG_KEYS;
260
0
      rqf &= ~NETLOGON_NEG_SUPPORTS_AES;
261
0
    }
262
263
0
    if ((rqf & rf) != rqf) {
264
0
      rqf = s->required_negotiate_flags;
265
0
      DBG_ERR("The client capabilities don't match "
266
0
        "the server capabilities: local[0x%08X] "
267
0
        "required[0x%08X] remote[0x%08X]\n",
268
0
        lf, rqf, rf);
269
0
      composite_error(c, NT_STATUS_DOWNGRADE_DETECTED);
270
0
      return;
271
0
    }
272
0
  }
273
274
  /*
275
   * Without a downgrade in the crypto we proposed
276
   * we can adjust the otherwise downgraded flags
277
   * before storing.
278
   */
279
0
  s->creds->negotiate_flags &= s->remote_negotiate_flags;
280
281
0
  composite_done(c);
282
0
}
283
284
/*
285
  Stage 4 of schannel_key: Receive non-authenticated bind and get
286
  a netlogon challenge
287
*/
288
static void continue_bind_auth_none(struct composite_context *ctx)
289
0
{
290
0
  struct composite_context *c;
291
292
0
  c = talloc_get_type(ctx->async.private_data, struct composite_context);
293
294
  /* receive result of non-authenticated bind request */
295
0
  c->status = dcerpc_bind_auth_none_recv(ctx);
296
0
  if (!composite_is_ok(c)) return;
297
298
0
  start_srv_challenge(c);
299
0
}
300
301
static void start_srv_challenge(struct composite_context *c)
302
0
{
303
0
  struct schannel_key_state *s = NULL;
304
0
  struct tevent_req *subreq = NULL;
305
306
0
  s = talloc_get_type(c->private_data, struct schannel_key_state);
307
308
  /* prepare a challenge request */
309
0
  s->r.in.server_name   = talloc_asprintf(c, "\\\\%s", dcerpc_server_name(s->pipe));
310
0
  if (composite_nomem(s->r.in.server_name, c)) return;
311
0
  s->r.in.computer_name = cli_credentials_get_workstation(s->credentials);
312
0
  s->r.in.credentials   = &s->credentials1;
313
0
  s->r.out.return_credentials  = &s->credentials2;
314
  
315
0
  generate_random_buffer(s->credentials1.data, sizeof(s->credentials1.data));
316
317
  /*
318
    request a netlogon challenge - a rpc request over opened secondary pipe
319
  */
320
0
  subreq = dcerpc_netr_ServerReqChallenge_r_send(s, c->event_ctx,
321
0
                   s->pipe2->binding_handle,
322
0
                   &s->r);
323
0
  if (composite_nomem(subreq, c)) return;
324
325
0
  tevent_req_set_callback(subreq, continue_srv_challenge, c);
326
0
}
327
328
329
/*
330
  Stage 5 of schannel_key: Receive a challenge and perform authentication
331
  on the netlogon pipe
332
*/
333
static void continue_srv_challenge(struct tevent_req *subreq)
334
0
{
335
0
  struct composite_context *c;
336
0
  struct schannel_key_state *s;
337
338
0
  c = tevent_req_callback_data(subreq, struct composite_context);
339
0
  s = talloc_get_type(c->private_data, struct schannel_key_state);
340
341
  /* receive rpc request result - netlogon challenge */
342
0
  c->status = dcerpc_netr_ServerReqChallenge_r_recv(subreq, s);
343
0
  TALLOC_FREE(subreq);
344
0
  if (!composite_is_ok(c)) return;
345
346
  /* prepare credentials for auth2 request */
347
0
  s->mach_pwd = cli_credentials_get_nt_hash(s->credentials, c);
348
0
  if (s->mach_pwd == NULL) {
349
0
    return composite_error(c, NT_STATUS_INTERNAL_ERROR);
350
0
  }
351
352
  /* auth2 request arguments */
353
0
  s->a.in.server_name      = s->r.in.server_name;
354
0
  s->a.in.account_name     = cli_credentials_get_username(s->credentials);
355
0
  s->a.in.secure_channel_type =
356
0
    cli_credentials_get_secure_channel_type(s->credentials);
357
0
  s->a.in.computer_name    = cli_credentials_get_workstation(s->credentials);
358
0
  s->a.in.negotiate_flags  = &s->requested_negotiate_flags;
359
0
  s->a.in.credentials      = &s->credentials3;
360
0
  s->a.out.negotiate_flags = &s->remote_negotiate_flags;
361
0
  s->a.out.return_credentials     = &s->credentials3;
362
363
0
  s->creds = netlogon_creds_client_init(s, 
364
0
                s->a.in.account_name, 
365
0
                s->a.in.computer_name,
366
0
                s->a.in.secure_channel_type,
367
0
                &s->credentials1, &s->credentials2,
368
0
                s->mach_pwd, &s->credentials3,
369
0
                s->requested_negotiate_flags,
370
0
                s->local_negotiate_flags);
371
0
  if (composite_nomem(s->creds, c)) {
372
0
    return;
373
0
  }
374
  /*
375
    authenticate on the netlogon pipe - a rpc request over secondary pipe
376
  */
377
0
  subreq = dcerpc_netr_ServerAuthenticate2_r_send(s, c->event_ctx,
378
0
              s->pipe2->binding_handle,
379
0
              &s->a);
380
0
  if (composite_nomem(subreq, c)) return;
381
382
0
  tevent_req_set_callback(subreq, continue_srv_auth2, c);
383
0
}
384
385
386
/*
387
  Stage 6 of schannel_key: Receive authentication request result and verify
388
  received credentials
389
*/
390
static void continue_srv_auth2(struct tevent_req *subreq)
391
0
{
392
0
  struct composite_context *c;
393
0
  struct schannel_key_state *s;
394
0
  enum dcerpc_AuthType auth_type;
395
0
  enum dcerpc_AuthLevel auth_level;
396
0
  NTSTATUS status;
397
398
0
  c = tevent_req_callback_data(subreq, struct composite_context);
399
0
  s = talloc_get_type(c->private_data, struct schannel_key_state);
400
401
0
  dcerpc_binding_handle_auth_info(s->pipe2->binding_handle,
402
0
          &auth_type,
403
0
          &auth_level);
404
405
  /* receive rpc request result - auth2 credentials */ 
406
0
  c->status = dcerpc_netr_ServerAuthenticate2_r_recv(subreq, s);
407
0
  TALLOC_FREE(subreq);
408
0
  if (!composite_is_ok(c)) return;
409
410
0
  if (!NT_STATUS_EQUAL(s->a.out.result, NT_STATUS_ACCESS_DENIED) &&
411
0
      !NT_STATUS_IS_OK(s->a.out.result)) {
412
0
    composite_error(c, s->a.out.result);
413
0
    return;
414
0
  }
415
416
0
  {
417
0
    uint32_t rqf = s->required_negotiate_flags;
418
0
    uint32_t rf = s->remote_negotiate_flags;
419
0
    uint32_t lf = s->local_negotiate_flags;
420
421
0
    if ((rf & NETLOGON_NEG_SUPPORTS_AES) &&
422
0
        (lf & NETLOGON_NEG_SUPPORTS_AES))
423
0
    {
424
0
      rqf &= ~NETLOGON_NEG_ARCFOUR;
425
0
      rqf &= ~NETLOGON_NEG_STRONG_KEYS;
426
0
    }
427
428
0
    if ((rqf & rf) != rqf) {
429
0
      rqf = s->required_negotiate_flags;
430
0
      DBG_ERR("The client capabilities don't match "
431
0
        "the server capabilities: local[0x%08X] "
432
0
        "required[0x%08X] remote[0x%08X]\n",
433
0
        lf, rqf, rf);
434
0
      composite_error(c, NT_STATUS_DOWNGRADE_DETECTED);
435
0
      return;
436
0
    }
437
0
  }
438
439
  /*
440
   * Strong keys could be unsupported (NT4) or disabled. So retry with the
441
   * flags returned by the server. - asn
442
   */
443
0
  if (NT_STATUS_EQUAL(s->a.out.result, NT_STATUS_ACCESS_DENIED)) {
444
0
    uint32_t lf = s->local_negotiate_flags;
445
0
    const char *ln = NULL;
446
0
    uint32_t rf = s->remote_negotiate_flags;
447
0
    const char *rn = NULL;
448
449
0
    if ((lf & rf) == lf) {
450
      /*
451
       * without a change in flags
452
       * there's no need to retry...
453
       */
454
0
      s->dcerpc_schannel_auto = false;
455
0
    }
456
457
0
    if (!s->dcerpc_schannel_auto) {
458
0
      composite_error(c, s->a.out.result);
459
0
      return;
460
0
    }
461
0
    s->dcerpc_schannel_auto = false;
462
463
0
    if (lf & NETLOGON_NEG_SUPPORTS_AES)  {
464
0
      ln = "aes";
465
0
      if (rf & NETLOGON_NEG_SUPPORTS_AES) {
466
0
        composite_error(c, s->a.out.result);
467
0
        return;
468
0
      }
469
0
    } else if (lf & NETLOGON_NEG_STRONG_KEYS) {
470
0
      ln = "strong";
471
0
      if (rf & NETLOGON_NEG_STRONG_KEYS) {
472
0
        composite_error(c, s->a.out.result);
473
0
        return;
474
0
      }
475
0
    } else {
476
0
      ln = "des";
477
0
    }
478
479
0
    if (rf & NETLOGON_NEG_SUPPORTS_AES)  {
480
0
      rn = "aes";
481
0
    } else if (rf & NETLOGON_NEG_STRONG_KEYS) {
482
0
      rn = "strong";
483
0
    } else {
484
0
      rn = "des";
485
0
    }
486
487
0
    DEBUG(3, ("Server doesn't support %s keys, downgrade to %s"
488
0
        "and retry! local[0x%08X] remote[0x%08X]\n",
489
0
        ln, rn, lf, rf));
490
491
0
    s->local_negotiate_flags &= s->remote_negotiate_flags;
492
493
0
    generate_random_buffer(s->credentials1.data,
494
0
               sizeof(s->credentials1.data));
495
496
0
    subreq = dcerpc_netr_ServerReqChallenge_r_send(s,
497
0
                     c->event_ctx,
498
0
                     s->pipe2->binding_handle,
499
0
                     &s->r);
500
0
    if (composite_nomem(subreq, c)) return;
501
502
0
    tevent_req_set_callback(subreq, continue_srv_challenge, c);
503
0
    return;
504
0
  }
505
506
  /* verify credentials */
507
0
  status = netlogon_creds_client_verify(s->creds,
508
0
                s->a.out.return_credentials,
509
0
                auth_type,
510
0
                auth_level);
511
0
  if (!NT_STATUS_IS_OK(status)) {
512
0
    composite_error(c, status);
513
0
    return;
514
0
  }
515
516
0
  if (s->requested_negotiate_flags == s->local_negotiate_flags) {
517
    /*
518
     * Without a downgrade in the crypto we proposed
519
     * we can adjust the otherwise downgraded flags
520
     * before storing.
521
     */
522
0
    s->creds->negotiate_flags &= s->remote_negotiate_flags;
523
0
  } else if (s->local_negotiate_flags != s->remote_negotiate_flags) {
524
    /*
525
     * We downgraded our crypto once, we should not
526
     * allow any additional downgrade!
527
     */
528
0
    DBG_ERR("%s: NT_STATUS_DOWNGRADE_DETECTED\n", __location__);
529
0
    composite_error(c, NT_STATUS_DOWNGRADE_DETECTED);
530
0
    return;
531
0
  }
532
533
0
  composite_done(c);
534
0
}
535
536
/*
537
  Initiate establishing a schannel key using netlogon challenge
538
  on a secondary pipe
539
*/
540
static struct composite_context *dcerpc_schannel_key_send(TALLOC_CTX *mem_ctx,
541
               struct dcerpc_pipe *p,
542
               struct cli_credentials *credentials,
543
               struct loadparm_context *lp_ctx)
544
0
{
545
0
  struct composite_context *c;
546
0
  struct schannel_key_state *s;
547
0
  struct composite_context *epm_map_req;
548
0
  enum netr_SchannelType schannel_type = cli_credentials_get_secure_channel_type(credentials);
549
0
  enum credentials_use_kerberos krb5_state =
550
0
    cli_credentials_get_kerberos_state(credentials);
551
0
  struct cli_credentials *epm_creds = NULL;
552
0
  bool reject_aes_servers = false;
553
0
  bool reject_md5_servers = false;
554
0
  bool require_strong_key = false;
555
0
#if defined(HAVE_ADS) && defined(HAVE_KRB5_INIT_CREDS_STEP)
556
0
  const bool support_krb5_netlogon = true;
557
#else
558
  const bool support_krb5_netlogon = false;
559
#endif
560
561
  /* composite context allocation and setup */
562
0
  c = composite_create(mem_ctx, p->conn->event_ctx);
563
0
  if (c == NULL) return NULL;
564
565
0
  s = talloc_zero(c, struct schannel_key_state);
566
0
  if (composite_nomem(s, c)) return c;
567
0
  c->private_data = s;
568
569
  /* store parameters in the state structure */
570
0
  s->lp_ctx      = lp_ctx;
571
0
  s->pipe        = p;
572
0
  s->credentials = credentials;
573
0
  s->local_negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
574
0
  s->required_negotiate_flags = NETLOGON_NEG_AUTHENTICATED_RPC;
575
576
  /* allocate credentials */
577
0
  if (s->pipe->conn->flags & DCERPC_SCHANNEL_128) {
578
0
    s->local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
579
0
    require_strong_key = true;
580
0
  }
581
0
  if (s->pipe->conn->flags & DCERPC_SCHANNEL_AES) {
582
0
    s->local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
583
0
    reject_md5_servers = true;
584
0
  }
585
0
  if (s->pipe->conn->flags & DCERPC_SCHANNEL_KRB5) {
586
0
    s->local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
587
0
    reject_aes_servers = true;
588
0
  }
589
0
  if (s->pipe->conn->flags & DCERPC_SCHANNEL_AUTO) {
590
0
    bool trust_support_kerberos = false;
591
0
    int use_krb5_netlogon = true;
592
0
    enum dcerpc_transport_t transport =
593
0
      dcerpc_binding_get_transport(s->pipe->binding);
594
595
0
    if (schannel_type != SEC_CHAN_DOMAIN) {
596
0
      if (krb5_state != CRED_USE_KERBEROS_DISABLED) {
597
0
        trust_support_kerberos = true;
598
0
      }
599
0
    }
600
601
0
    switch (transport) {
602
0
    case NCACN_NP:
603
0
    case NCACN_IP_TCP:
604
0
      break;
605
0
    default:
606
      /*
607
       * Things like NCALRPC don't support
608
       * kerberos.
609
       */
610
0
      trust_support_kerberos = false;
611
0
      break;
612
0
    }
613
614
0
    s->local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
615
0
    s->local_negotiate_flags |= NETLOGON_NEG_SUPPORTS_AES;
616
0
    s->dcerpc_schannel_auto = true;
617
618
0
    use_krb5_netlogon = lpcfg_client_use_krb5_netlogon(lp_ctx);
619
0
    if (use_krb5_netlogon == Auto) {
620
0
      if (support_krb5_netlogon) {
621
0
        use_krb5_netlogon = trust_support_kerberos;
622
0
      } else {
623
0
        use_krb5_netlogon = false;
624
0
      }
625
0
    }
626
627
0
    if (use_krb5_netlogon) {
628
0
      s->local_negotiate_flags |=
629
0
        NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH;
630
0
    }
631
632
0
    reject_aes_servers = lpcfg_reject_aes_netlogon_servers(lp_ctx);
633
0
    reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
634
0
    require_strong_key = lpcfg_require_strong_key(lp_ctx);
635
0
  }
636
637
0
  if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED) {
638
0
    reject_md5_servers = true;
639
0
  }
640
641
0
  if (reject_aes_servers) {
642
0
    reject_md5_servers = true;
643
0
  }
644
645
0
  if (reject_md5_servers) {
646
0
    require_strong_key = true;
647
0
  }
648
649
0
  if (require_strong_key) {
650
0
    s->required_negotiate_flags |= NETLOGON_NEG_ARCFOUR;
651
0
    s->required_negotiate_flags |= NETLOGON_NEG_STRONG_KEYS;
652
0
  }
653
654
0
  if (reject_md5_servers) {
655
0
    s->required_negotiate_flags |= NETLOGON_NEG_PASSWORD_SET2;
656
0
    s->required_negotiate_flags |= NETLOGON_NEG_SUPPORTS_AES;
657
0
  }
658
659
0
  if (reject_aes_servers) {
660
0
    s->required_negotiate_flags |= NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH;
661
0
  }
662
663
0
  s->local_negotiate_flags |= s->required_negotiate_flags;
664
665
0
  if (s->local_negotiate_flags & NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH) {
666
0
    if (!support_krb5_netlogon) {
667
0
      DBG_ERR("No support for ServerAuthenticateKerberos!\n");
668
0
      composite_error(c, NT_STATUS_DEVICE_FEATURE_NOT_SUPPORTED);
669
0
      return c;
670
0
    }
671
0
    s->pipe->conn->flags |= DCERPC_SEAL;
672
0
  }
673
674
0
  if (s->required_negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
675
0
    s->required_negotiate_flags &= ~NETLOGON_NEG_ARCFOUR;
676
0
    s->required_negotiate_flags &= ~NETLOGON_NEG_STRONG_KEYS;
677
0
  }
678
679
0
  if (s->required_negotiate_flags & NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH) {
680
0
    s->required_negotiate_flags &= ~NETLOGON_NEG_SUPPORTS_AES;
681
0
  }
682
683
  /* type of authentication depends on schannel type */
684
0
  if (schannel_type == SEC_CHAN_RODC) {
685
0
    s->local_negotiate_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
686
0
  }
687
688
0
  s->requested_negotiate_flags = s->local_negotiate_flags;
689
690
0
  epm_creds = cli_credentials_init_anon(s);
691
0
  if (composite_nomem(epm_creds, c)) return c;
692
693
  /* allocate binding structure */
694
0
  s->binding = dcerpc_binding_dup(s, s->pipe->binding);
695
0
  if (composite_nomem(s->binding, c)) return c;
696
697
  /* request the netlogon endpoint mapping */
698
0
  epm_map_req = dcerpc_epm_map_binding_send(c, s->binding,
699
0
              &ndr_table_netlogon,
700
0
              epm_creds,
701
0
              s->pipe->conn->event_ctx,
702
0
              lp_ctx);
703
0
  if (composite_nomem(epm_map_req, c)) return c;
704
705
0
  composite_continue(c, epm_map_req, continue_epm_map_binding, c);
706
0
  return c;
707
0
}
708
709
710
/*
711
  Receive result of schannel key request
712
 */
713
static NTSTATUS dcerpc_schannel_key_recv(struct composite_context *c,
714
        TALLOC_CTX *mem_ctx,
715
        struct netlogon_creds_CredentialState **creds)
716
0
{
717
0
  NTSTATUS status = composite_wait(c);
718
719
0
  if (NT_STATUS_IS_OK(status)) {
720
0
    struct schannel_key_state *s =
721
0
      talloc_get_type_abort(c->private_data,
722
0
      struct schannel_key_state);
723
0
    *creds = talloc_move(mem_ctx, &s->creds);
724
0
  }
725
726
0
  talloc_free(c);
727
0
  return status;
728
0
}
729
730
731
struct auth_schannel_state {
732
  struct dcerpc_pipe *pipe;
733
  struct cli_credentials *credentials;
734
  uint32_t requested_negotiate_flags;
735
  const struct ndr_interface_table *table;
736
  struct loadparm_context *lp_ctx;
737
  uint8_t auth_level;
738
  struct netlogon_creds_CredentialState *creds_state;
739
  struct netlogon_creds_CredentialState save_creds_state;
740
  struct netr_Authenticator auth;
741
  struct netr_Authenticator return_auth;
742
  union netr_Capabilities capabilities;
743
  union netr_Capabilities client_caps;
744
  struct netr_LogonGetCapabilities c;
745
  union netr_CONTROL_QUERY_INFORMATION ctrl_info;
746
};
747
748
749
static void continue_bind_auth(struct composite_context *ctx);
750
751
752
/*
753
  Stage 2 of auth_schannel: Receive schannel key and initiate an
754
  authenticated bind using received credentials
755
 */
756
static void continue_schannel_key(struct composite_context *ctx)
757
0
{
758
0
  struct composite_context *auth_req;
759
0
  struct composite_context *c = talloc_get_type(ctx->async.private_data,
760
0
                  struct composite_context);
761
0
  struct auth_schannel_state *s = talloc_get_type(c->private_data,
762
0
              struct auth_schannel_state);
763
0
  enum dcerpc_AuthType auth_type;
764
0
  NTSTATUS status;
765
766
  /* receive schannel key */
767
0
  c->status = dcerpc_schannel_key_recv(ctx,
768
0
               s,
769
0
               &s->creds_state);
770
0
  status = c->status;
771
0
  if (!composite_is_ok(c)) {
772
0
    DEBUG(1, ("Failed to setup credentials: %s\n", nt_errstr(status)));
773
0
    return;
774
0
  }
775
776
0
  s->requested_negotiate_flags =
777
0
    s->creds_state->client_requested_flags;
778
779
0
  if (s->creds_state->authenticate_kerberos) {
780
0
    auth_type = DCERPC_AUTH_TYPE_KRB5;
781
0
    s->auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
782
0
  } else {
783
0
    auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
784
0
  }
785
786
  /* send bind auth request with received creds */
787
0
  cli_credentials_set_netlogon_creds(s->credentials, s->creds_state);
788
789
0
  auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, s->credentials, 
790
0
           lpcfg_gensec_settings(c, s->lp_ctx),
791
0
           auth_type, s->auth_level,
792
0
           NULL);
793
0
  if (composite_nomem(auth_req, c)) return;
794
  
795
0
  composite_continue(c, auth_req, continue_bind_auth, c);
796
0
}
797
798
799
/*
800
  Stage 3 of auth_schannel: Receive result of authenticated bind
801
  and say if we're done ok.
802
*/
803
static void continue_bind_auth(struct composite_context *ctx)
804
0
{
805
0
  struct composite_context *c = talloc_get_type(ctx->async.private_data,
806
0
                  struct composite_context);
807
0
  struct auth_schannel_state *s = talloc_get_type(c->private_data,
808
0
              struct auth_schannel_state);
809
0
  struct tevent_req *subreq;
810
811
0
  c->status = dcerpc_bind_auth_recv(ctx);
812
0
  if (!composite_is_ok(c)) return;
813
814
  /* if we have a AES encrypted connection, verify the capabilities */
815
0
  if (ndr_syntax_id_equal(&s->table->syntax_id,
816
0
        &ndr_table_netlogon.syntax_id)) {
817
0
    NTSTATUS status;
818
0
    ZERO_STRUCT(s->return_auth);
819
820
0
    s->save_creds_state = *s->creds_state;
821
0
    status = netlogon_creds_client_authenticator(&s->save_creds_state,
822
0
                   &s->auth);
823
0
    if (!NT_STATUS_IS_OK(status)) {
824
0
      composite_error(c, status);
825
0
      return;
826
0
    }
827
828
0
    s->c.in.server_name = talloc_asprintf(c,
829
0
                  "\\\\%s",
830
0
                  dcerpc_server_name(s->pipe));
831
0
    if (composite_nomem(s->c.in.server_name, c)) return;
832
0
    s->c.in.computer_name         = cli_credentials_get_workstation(s->credentials);
833
0
    s->c.in.credential            = &s->auth;
834
0
    s->c.in.return_authenticator  = &s->return_auth;
835
0
    s->c.in.query_level           = 1;
836
837
0
    s->c.out.capabilities         = &s->capabilities;
838
0
    s->c.out.return_authenticator = &s->return_auth;
839
840
0
    DEBUG(5, ("We established a AES connection, verifying logon "
841
0
        "capabilities\n"));
842
843
0
    subreq = dcerpc_netr_LogonGetCapabilities_r_send(s,
844
0
                 c->event_ctx,
845
0
                 s->pipe->binding_handle,
846
0
                 &s->c);
847
0
    if (composite_nomem(subreq, c)) return;
848
849
0
    tevent_req_set_callback(subreq,
850
0
          continue_get_negotiated_capabilities,
851
0
          c);
852
0
    return;
853
0
  }
854
855
0
  composite_done(c);
856
0
}
857
858
static void continue_logon_control_do(struct composite_context *c);
859
860
/*
861
  Stage 4 of auth_schannel: Get the Logon Capabilities and verify them.
862
*/
863
static void continue_get_negotiated_capabilities(struct tevent_req *subreq)
864
0
{
865
0
  struct composite_context *c;
866
0
  struct auth_schannel_state *s;
867
0
  enum dcerpc_AuthType auth_type;
868
0
  enum dcerpc_AuthLevel auth_level;
869
0
  NTSTATUS status;
870
871
0
  c = tevent_req_callback_data(subreq, struct composite_context);
872
0
  s = talloc_get_type(c->private_data, struct auth_schannel_state);
873
874
0
  dcerpc_binding_handle_auth_info(s->pipe->binding_handle,
875
0
          &auth_type,
876
0
          &auth_level);
877
878
  /* receive rpc request result */
879
0
  c->status = dcerpc_netr_LogonGetCapabilities_r_recv(subreq, s);
880
0
  TALLOC_FREE(subreq);
881
0
  if (NT_STATUS_EQUAL(c->status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
882
0
    if (s->creds_state->authenticate_kerberos) {
883
0
      DBG_ERR("%s: NT_STATUS_DOWNGRADE_DETECTED\n", __location__);
884
0
      composite_error(c, NT_STATUS_DOWNGRADE_DETECTED);
885
0
      return;
886
0
    }
887
888
0
    if (s->creds_state->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
889
0
      DBG_ERR("%s: NT_STATUS_DOWNGRADE_DETECTED\n", __location__);
890
0
      composite_error(c, NT_STATUS_DOWNGRADE_DETECTED);
891
0
      return;
892
0
    } else if (s->creds_state->negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
893
0
      DBG_ERR("%s: NT_STATUS_DOWNGRADE_DETECTED\n", __location__);
894
0
      composite_error(c, NT_STATUS_DOWNGRADE_DETECTED);
895
0
      return;
896
0
    }
897
898
    /* This is probably NT */
899
0
    continue_logon_control_do(c);
900
0
    return;
901
0
  } else if (!composite_is_ok(c)) {
902
0
    return;
903
0
  }
904
905
0
  if (NT_STATUS_EQUAL(s->c.out.result, NT_STATUS_NOT_IMPLEMENTED)) {
906
0
    if (s->creds_state->authenticate_kerberos) {
907
0
      DBG_ERR("%s: NT_STATUS_DOWNGRADE_DETECTED\n", __location__);
908
0
      composite_error(c, NT_STATUS_DOWNGRADE_DETECTED);
909
0
      return;
910
0
    }
911
912
0
    if (s->creds_state->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
913
      /* This means AES isn't supported. */
914
0
      DBG_ERR("%s: NT_STATUS_DOWNGRADE_DETECTED\n", __location__);
915
0
      composite_error(c, NT_STATUS_DOWNGRADE_DETECTED);
916
0
      return;
917
0
    }
918
919
    /* This is probably an old Samba version */
920
0
    composite_done(c);
921
0
    return;
922
0
  }
923
924
  /* verify credentials */
925
0
  status = netlogon_creds_client_verify(&s->save_creds_state,
926
0
                &s->c.out.return_authenticator->cred,
927
0
                auth_type,
928
0
                auth_level);
929
0
  if (!NT_STATUS_IS_OK(status)) {
930
0
    composite_error(c, status);
931
0
    return;
932
0
  }
933
934
0
  *s->creds_state = s->save_creds_state;
935
0
  cli_credentials_set_netlogon_creds(s->credentials, s->creds_state);
936
937
0
  if (!NT_STATUS_IS_OK(s->c.out.result)) {
938
0
    composite_error(c, s->c.out.result);
939
0
    return;
940
0
  }
941
942
  /* compare capabilities */
943
0
  if (s->creds_state->negotiate_flags != s->capabilities.server_capabilities) {
944
0
    DBG_ERR("The client capabilities don't match the server "
945
0
      "capabilities: local[0x%08X] remote[0x%08X]\n",
946
0
      s->creds_state->negotiate_flags,
947
0
      s->capabilities.server_capabilities);
948
0
    composite_error(c, NT_STATUS_DOWNGRADE_DETECTED);
949
0
    return;
950
0
  }
951
952
0
  if (!s->creds_state->authenticate_kerberos &&
953
0
      (s->requested_negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) &&
954
0
      (!(s->creds_state->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES)))
955
0
  {
956
0
    DBG_ERR("%s: NT_STATUS_DOWNGRADE_DETECTED\n", __location__);
957
0
    composite_error(c, NT_STATUS_DOWNGRADE_DETECTED);
958
0
    return;
959
0
  }
960
961
0
  ZERO_STRUCT(s->return_auth);
962
963
0
  s->save_creds_state = *s->creds_state;
964
0
  status = netlogon_creds_client_authenticator(&s->save_creds_state,
965
0
                 &s->auth);
966
0
  if (!NT_STATUS_IS_OK(status)) {
967
0
    composite_error(c, status);
968
0
    return;
969
0
  }
970
971
0
  s->c.in.credential            = &s->auth;
972
0
  s->c.in.return_authenticator  = &s->return_auth;
973
0
  s->c.in.query_level           = 2;
974
975
0
  s->c.out.capabilities         = &s->client_caps;
976
0
  s->c.out.return_authenticator = &s->return_auth;
977
978
0
  subreq = dcerpc_netr_LogonGetCapabilities_r_send(s,
979
0
               c->event_ctx,
980
0
               s->pipe->binding_handle,
981
0
               &s->c);
982
0
  if (composite_nomem(subreq, c)) return;
983
984
0
  tevent_req_set_callback(subreq, continue_get_client_capabilities, c);
985
0
  return;
986
0
}
987
988
static void continue_get_client_capabilities(struct tevent_req *subreq)
989
0
{
990
0
  struct composite_context *c;
991
0
  struct auth_schannel_state *s;
992
0
  enum dcerpc_AuthType auth_type;
993
0
  enum dcerpc_AuthLevel auth_level;
994
0
  NTSTATUS status;
995
996
0
  c = tevent_req_callback_data(subreq, struct composite_context);
997
0
  s = talloc_get_type(c->private_data, struct auth_schannel_state);
998
999
0
  dcerpc_binding_handle_auth_info(s->pipe->binding_handle,
1000
0
          &auth_type,
1001
0
          &auth_level);
1002
1003
  /* receive rpc request result */
1004
0
  c->status = dcerpc_netr_LogonGetCapabilities_r_recv(subreq, s);
1005
0
  TALLOC_FREE(subreq);
1006
0
  if (NT_STATUS_EQUAL(c->status, NT_STATUS_RPC_BAD_STUB_DATA)) {
1007
    /*
1008
     * unpatched Samba server, see
1009
     * https://bugzilla.samba.org/show_bug.cgi?id=15418
1010
     */
1011
0
    c->status = NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE;
1012
0
  }
1013
0
  if (NT_STATUS_EQUAL(c->status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
1014
0
    if (s->creds_state->authenticate_kerberos) {
1015
0
      DBG_ERR("%s: NT_STATUS_DOWNGRADE_DETECTED\n", __location__);
1016
0
      composite_error(c, NT_STATUS_DOWNGRADE_DETECTED);
1017
0
      return;
1018
0
    }
1019
1020
    /*
1021
     * Here we know the negotiated flags were already
1022
     * verified with query_level=1, which means
1023
     * the server supported NETLOGON_NEG_SUPPORTS_AES
1024
     * and also NETLOGON_NEG_AUTHENTICATED_RPC
1025
     *
1026
     * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1027
     * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1028
     * we should detect a faked
1029
     * NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE
1030
     * with the next request as the sequence number processing
1031
     * gets out of sync.
1032
     *
1033
     * So we'll do a LogonControl message to check that...
1034
     */
1035
0
    continue_logon_control_do(c);
1036
0
    return;
1037
0
  }
1038
0
  if (!composite_is_ok(c)) {
1039
0
    return;
1040
0
  }
1041
1042
  /* verify credentials */
1043
0
  status = netlogon_creds_client_verify(&s->save_creds_state,
1044
0
                &s->c.out.return_authenticator->cred,
1045
0
                auth_type,
1046
0
                auth_level);
1047
0
  if (!NT_STATUS_IS_OK(status)) {
1048
0
    composite_error(c, status);
1049
0
    return;
1050
0
  }
1051
1052
0
  if (!NT_STATUS_IS_OK(s->c.out.result)) {
1053
0
    composite_error(c, s->c.out.result);
1054
0
    return;
1055
0
  }
1056
1057
  /* compare capabilities */
1058
0
  if (s->requested_negotiate_flags != s->client_caps.requested_flags) {
1059
0
    DBG_ERR("The client requested capabilities did not reach"
1060
0
      "the server! local[0x%08X] remote[0x%08X]\n",
1061
0
      s->requested_negotiate_flags,
1062
0
      s->client_caps.requested_flags);
1063
0
    composite_error(c, NT_STATUS_DOWNGRADE_DETECTED);
1064
0
    return;
1065
0
  }
1066
1067
0
  *s->creds_state = s->save_creds_state;
1068
0
  cli_credentials_set_netlogon_creds(s->credentials, s->creds_state);
1069
1070
0
  composite_done(c);
1071
0
}
1072
1073
static void continue_logon_control_done(struct tevent_req *subreq);
1074
1075
static void continue_logon_control_do(struct composite_context *c)
1076
0
{
1077
0
  struct auth_schannel_state *s = NULL;
1078
0
  struct tevent_req *subreq = NULL;
1079
1080
0
  s = talloc_get_type(c->private_data, struct auth_schannel_state);
1081
1082
0
  subreq = dcerpc_netr_LogonControl_send(s,
1083
0
                 c->event_ctx,
1084
0
                 s->pipe->binding_handle,
1085
0
                 s->c.in.server_name,
1086
0
                 NETLOGON_CONTROL_QUERY,
1087
0
                 2,
1088
0
                 &s->ctrl_info);
1089
0
  if (composite_nomem(subreq, c)) return;
1090
1091
0
  tevent_req_set_callback(subreq, continue_logon_control_done, c);
1092
0
}
1093
1094
static void continue_logon_control_done(struct tevent_req *subreq)
1095
0
{
1096
0
  struct composite_context *c = NULL;
1097
0
  struct auth_schannel_state *s = NULL;
1098
0
  WERROR werr;
1099
1100
0
  c = tevent_req_callback_data(subreq, struct composite_context);
1101
0
  s = talloc_get_type(c->private_data, struct auth_schannel_state);
1102
1103
  /* receive rpc request result */
1104
0
  c->status = dcerpc_netr_LogonControl_recv(subreq, s, &werr);
1105
0
  TALLOC_FREE(subreq);
1106
0
  if (!NT_STATUS_IS_OK(c->status)) {
1107
0
    DBG_ERR("%s: NT_STATUS_DOWNGRADE_DETECTED\n", __location__);
1108
0
    composite_error(c, NT_STATUS_DOWNGRADE_DETECTED);
1109
0
    return;
1110
0
  }
1111
1112
0
  if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
1113
0
    DBG_ERR("%s: NT_STATUS_DOWNGRADE_DETECTED\n", __location__);
1114
0
    composite_error(c, NT_STATUS_DOWNGRADE_DETECTED);
1115
0
    return;
1116
0
  }
1117
1118
0
  composite_done(c);
1119
0
}
1120
1121
/*
1122
  Initiate schannel authentication request
1123
*/
1124
struct composite_context *dcerpc_bind_auth_schannel_send(TALLOC_CTX *tmp_ctx, 
1125
               struct dcerpc_pipe *p,
1126
               const struct ndr_interface_table *table,
1127
               struct cli_credentials *credentials,
1128
               struct loadparm_context *lp_ctx,
1129
               uint8_t auth_level)
1130
0
{
1131
0
  struct composite_context *c;
1132
0
  struct auth_schannel_state *s;
1133
0
  struct composite_context *schan_key_req;
1134
1135
  /* composite context allocation and setup */
1136
0
  c = composite_create(tmp_ctx, p->conn->event_ctx);
1137
0
  if (c == NULL) return NULL;
1138
  
1139
0
  s = talloc_zero(c, struct auth_schannel_state);
1140
0
  if (composite_nomem(s, c)) return c;
1141
0
  c->private_data = s;
1142
1143
  /* store parameters in the state structure */
1144
0
  s->pipe        = p;
1145
0
  s->credentials = credentials;
1146
0
  s->table       = table;
1147
0
  s->auth_level  = auth_level;
1148
0
  s->lp_ctx      = lp_ctx;
1149
1150
  /* start getting schannel key first */
1151
0
  schan_key_req = dcerpc_schannel_key_send(c, p, credentials, lp_ctx);
1152
0
  if (composite_nomem(schan_key_req, c)) return c;
1153
1154
0
  composite_continue(c, schan_key_req, continue_schannel_key, c);
1155
0
  return c;
1156
0
}
1157
1158
1159
/*
1160
  Receive result of schannel authentication request
1161
*/
1162
NTSTATUS dcerpc_bind_auth_schannel_recv(struct composite_context *c)
1163
0
{
1164
0
  NTSTATUS status = composite_wait(c);
1165
  
1166
  talloc_free(c);
1167
0
  return status;
1168
0
}