2 Unix SMB/CIFS implementation.
4 dcerpc schannel operations
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "librpc/gen_ndr/ndr_schannel.h"
25 #include "auth/auth.h"
27 enum schannel_position
{
28 DCERPC_SCHANNEL_STATE_START
= 0,
29 DCERPC_SCHANNEL_STATE_UPDATE_1
32 struct dcerpc_schannel_state
{
33 enum schannel_position state
;
34 struct schannel_state
*schannel_state
;
35 struct creds_CredentialState
*creds
;
39 wrappers for the schannel_*() functions
41 These will become static again, when we get dynamic registration, and
42 decrpc_schannel_security_ops come back here.
44 static NTSTATUS
dcerpc_schannel_unseal_packet(struct gensec_security
*gensec_security
,
46 uint8_t *data
, size_t length
,
47 const uint8_t *whole_pdu
, size_t pdu_length
,
50 struct dcerpc_schannel_state
*dce_schan_state
= gensec_security
->private_data
;
52 return schannel_unseal_packet(dce_schan_state
->schannel_state
, mem_ctx
, data
, length
, sig
);
55 static NTSTATUS
dcerpc_schannel_check_packet(struct gensec_security
*gensec_security
,
57 const uint8_t *data
, size_t length
,
58 const uint8_t *whole_pdu
, size_t pdu_length
,
61 struct dcerpc_schannel_state
*dce_schan_state
= gensec_security
->private_data
;
63 return schannel_check_packet(dce_schan_state
->schannel_state
, data
, length
, sig
);
66 static NTSTATUS
dcerpc_schannel_seal_packet(struct gensec_security
*gensec_security
,
68 uint8_t *data
, size_t length
,
69 const uint8_t *whole_pdu
, size_t pdu_length
,
72 struct dcerpc_schannel_state
*dce_schan_state
= gensec_security
->private_data
;
74 return schannel_seal_packet(dce_schan_state
->schannel_state
, mem_ctx
, data
, length
, sig
);
77 static NTSTATUS
dcerpc_schannel_sign_packet(struct gensec_security
*gensec_security
,
79 const uint8_t *data
, size_t length
,
80 const uint8_t *whole_pdu
, size_t pdu_length
,
83 struct dcerpc_schannel_state
*dce_schan_state
= gensec_security
->private_data
;
85 return schannel_sign_packet(dce_schan_state
->schannel_state
, mem_ctx
, data
, length
, sig
);
88 static size_t dcerpc_schannel_sig_size(struct gensec_security
*gensec_security
)
93 static NTSTATUS
dcerpc_schannel_session_key(struct gensec_security
*gensec_security
,
94 DATA_BLOB
*session_key
)
96 return NT_STATUS_NOT_IMPLEMENTED
;
99 static NTSTATUS
dcerpc_schannel_update(struct gensec_security
*gensec_security
, TALLOC_CTX
*out_mem_ctx
,
100 const DATA_BLOB in
, DATA_BLOB
*out
)
102 struct dcerpc_schannel_state
*dce_schan_state
= gensec_security
->private_data
;
104 struct schannel_bind bind_schannel
;
105 struct schannel_bind_ack bind_schannel_ack
;
106 const char *workstation
;
108 *out
= data_blob(NULL
, 0);
110 switch (gensec_security
->gensec_role
) {
112 if (dce_schan_state
->state
!= DCERPC_SCHANNEL_STATE_START
) {
113 /* we could parse the bind ack, but we don't know what it is yet */
117 status
= schannel_start(dce_schan_state
,
118 &dce_schan_state
->schannel_state
,
119 dce_schan_state
->creds
->session_key
,
121 if (!NT_STATUS_IS_OK(status
)) {
122 DEBUG(1, ("Failed to start schannel client\n"));
125 talloc_steal(dce_schan_state
, dce_schan_state
->schannel_state
);
127 bind_schannel
.unknown1
= 0;
129 /* to support this we'd need to have access to the full domain name */
130 bind_schannel
.bind_type
= 23;
131 bind_schannel
.u
.info23
.domain
= gensec_security
->user
.domain
;
132 bind_schannel
.u
.info23
.account_name
= gensec_security
->user
.name
;
133 bind_schannel
.u
.info23
.dnsdomain
= str_format_nbt_domain(out_mem_ctx
, fulldomainname
);
134 bind_schannel
.u
.info23
.workstation
= str_format_nbt_domain(out_mem_ctx
, gensec_get_workstation(gensec_security
));
136 bind_schannel
.bind_type
= 3;
137 bind_schannel
.u
.info3
.domain
= gensec_security
->user
.domain
;
138 bind_schannel
.u
.info3
.workstation
= gensec_get_workstation(gensec_security
);
141 status
= ndr_push_struct_blob(out
, out_mem_ctx
, &bind_schannel
,
142 (ndr_push_flags_fn_t
)ndr_push_schannel_bind
);
143 if (!NT_STATUS_IS_OK(status
)) {
144 DEBUG(3, ("Could not create schannel bind: %s\n",
149 dce_schan_state
->state
= DCERPC_SCHANNEL_STATE_UPDATE_1
;
151 return NT_STATUS_MORE_PROCESSING_REQUIRED
;
154 if (dce_schan_state
->state
!= DCERPC_SCHANNEL_STATE_START
) {
155 /* no third leg on this protocol */
156 return NT_STATUS_INVALID_PARAMETER
;
159 /* parse the schannel startup blob */
160 status
= ndr_pull_struct_blob(&in
, out_mem_ctx
, &bind_schannel
,
161 (ndr_pull_flags_fn_t
)ndr_pull_schannel_bind
);
162 if (!NT_STATUS_IS_OK(status
)) {
166 if (bind_schannel
.bind_type
== 23) {
167 workstation
= bind_schannel
.u
.info23
.workstation
;
168 domain
= bind_schannel
.u
.info23
.domain
;
170 workstation
= bind_schannel
.u
.info3
.workstation
;
171 domain
= bind_schannel
.u
.info3
.domain
;
174 /* pull the session key for this client */
175 status
= schannel_fetch_session_key(out_mem_ctx
, workstation
,
176 domain
, &dce_schan_state
->creds
);
177 if (!NT_STATUS_IS_OK(status
)) {
178 DEBUG(3, ("Could not find session key for attempted schannel connection from %s: %s\n",
179 workstation
, nt_errstr(status
)));
183 /* start up the schannel server code */
184 status
= schannel_start(dce_schan_state
,
185 &dce_schan_state
->schannel_state
,
186 dce_schan_state
->creds
->session_key
, False
);
187 if (!NT_STATUS_IS_OK(status
)) {
188 DEBUG(3, ("Could not initialise schannel state from client %s: %s\n",
189 workstation
, nt_errstr(status
)));
192 talloc_steal(dce_schan_state
, dce_schan_state
->schannel_state
);
194 bind_schannel_ack
.unknown1
= 1;
195 bind_schannel_ack
.unknown2
= 0;
196 bind_schannel_ack
.unknown3
= 0x6c0000;
198 status
= ndr_push_struct_blob(out
, out_mem_ctx
, &bind_schannel_ack
,
199 (ndr_push_flags_fn_t
)ndr_push_schannel_bind_ack
);
200 if (!NT_STATUS_IS_OK(status
)) {
201 DEBUG(3, ("Could not return schannel bind ack for client %s: %s\n",
202 workstation
, nt_errstr(status
)));
206 dce_schan_state
->state
= DCERPC_SCHANNEL_STATE_UPDATE_1
;
210 return NT_STATUS_INVALID_PARAMETER
;
214 * Return the credentials of a logged on user, including session keys
217 * Only valid after a successful authentication
219 * May only be called once per authentication.
223 NTSTATUS
dcerpc_schannel_session_info(struct gensec_security
*gensec_security
,
224 struct auth_session_info
**session_info
)
226 (*session_info
) = talloc(gensec_security
, struct auth_session_info
);
227 NT_STATUS_HAVE_NO_MEMORY(*session_info
);
229 ZERO_STRUCTP(*session_info
);
235 * Return the struct creds_CredentialState.
237 * Make sure not to call this unless gensec is using schannel...
240 NTSTATUS
dcerpc_schannel_creds(struct gensec_security
*gensec_security
,
242 struct creds_CredentialState
**creds
)
244 struct dcerpc_schannel_state
*dce_schan_state
= gensec_security
->private_data
;
246 *creds
= talloc_reference(mem_ctx
, dce_schan_state
->creds
);
248 return NT_STATUS_NO_MEMORY
;
254 static NTSTATUS
dcerpc_schannel_start(struct gensec_security
*gensec_security
)
256 struct dcerpc_schannel_state
*dce_schan_state
;
258 dce_schan_state
= talloc(gensec_security
, struct dcerpc_schannel_state
);
259 if (!dce_schan_state
) {
260 return NT_STATUS_NO_MEMORY
;
263 dce_schan_state
->state
= DCERPC_SCHANNEL_STATE_START
;
264 gensec_security
->private_data
= dce_schan_state
;
269 static NTSTATUS
dcerpc_schannel_server_start(struct gensec_security
*gensec_security
)
273 status
= dcerpc_schannel_start(gensec_security
);
274 if (!NT_STATUS_IS_OK(status
)) {
281 static NTSTATUS
dcerpc_schannel_client_start(struct gensec_security
*gensec_security
)
285 status
= dcerpc_schannel_start(gensec_security
);
286 if (!NT_STATUS_IS_OK(status
)) {
295 get a schannel key using a netlogon challenge on a secondary pipe
297 static NTSTATUS
dcerpc_schannel_key(TALLOC_CTX
*tmp_ctx
,
298 struct dcerpc_pipe
*p
,
299 struct cli_credentials
*credentials
,
301 struct creds_CredentialState
*creds
)
304 struct dcerpc_binding
*b
;
305 struct dcerpc_pipe
*p2
;
306 struct netr_ServerReqChallenge r
;
307 struct netr_ServerAuthenticate2 a
;
308 struct netr_Credential credentials1
, credentials2
, credentials3
;
309 struct samr_Password mach_pwd
;
310 const char *workgroup
;
311 uint32_t negotiate_flags
;
313 if (p
->conn
->flags
& DCERPC_SCHANNEL_128
) {
314 negotiate_flags
= NETLOGON_NEG_AUTH2_ADS_FLAGS
;
316 negotiate_flags
= NETLOGON_NEG_AUTH2_FLAGS
;
319 workgroup
= cli_credentials_get_domain(credentials
);
322 step 1 - establish a netlogon connection, with no authentication
325 /* Find the original binding string */
326 status
= dcerpc_parse_binding(tmp_ctx
, p
->conn
->binding_string
, &b
);
327 if (!NT_STATUS_IS_OK(status
)) {
328 DEBUG(0,("Failed to parse dcerpc binding '%s'\n", p
->conn
->binding_string
));
332 /* Make binding string for netlogon, not the other pipe */
333 status
= dcerpc_epm_map_binding(tmp_ctx
, b
, DCERPC_NETLOGON_UUID
, DCERPC_NETLOGON_VERSION
);
334 if (!NT_STATUS_IS_OK(status
)) {
335 DEBUG(0,("Failed to map DCERPC/TCP NCACN_NP pipe for '%s' - %s\n",
336 DCERPC_NETLOGON_UUID
, nt_errstr(status
)));
340 status
= dcerpc_secondary_connection(p
, &p2
, b
);
341 if (!NT_STATUS_IS_OK(status
)) {
345 status
= dcerpc_bind_auth_none(p2
, DCERPC_NETLOGON_UUID
,
346 DCERPC_NETLOGON_VERSION
);
347 if (!NT_STATUS_IS_OK(status
)) {
353 step 2 - request a netlogon challenge
355 r
.in
.server_name
= talloc_asprintf(tmp_ctx
, "\\\\%s", dcerpc_server_name(p
));
356 r
.in
.computer_name
= cli_credentials_get_workstation(credentials
);
357 r
.in
.credentials
= &credentials1
;
358 r
.out
.credentials
= &credentials2
;
360 generate_random_buffer(credentials1
.data
, sizeof(credentials1
.data
));
362 status
= dcerpc_netr_ServerReqChallenge(p2
, tmp_ctx
, &r
);
363 if (!NT_STATUS_IS_OK(status
)) {
368 step 3 - authenticate on the netlogon pipe
370 E_md4hash(cli_credentials_get_password(credentials
), mach_pwd
.hash
);
371 creds_client_init(creds
, &credentials1
, &credentials2
,
372 cli_credentials_get_workstation(credentials
),
373 cli_credentials_get_domain(credentials
),
374 cli_credentials_get_username(credentials
),
375 &mach_pwd
, &credentials3
,
378 a
.in
.server_name
= r
.in
.server_name
;
379 a
.in
.account_name
= cli_credentials_get_username(credentials
);
380 a
.in
.secure_channel_type
= chan_type
;
381 a
.in
.computer_name
= cli_credentials_get_workstation(credentials
);
382 a
.in
.negotiate_flags
= &negotiate_flags
;
383 a
.out
.negotiate_flags
= &negotiate_flags
;
384 a
.in
.credentials
= &credentials3
;
385 a
.out
.credentials
= &credentials3
;
387 status
= dcerpc_netr_ServerAuthenticate2(p2
, tmp_ctx
, &a
);
388 if (!NT_STATUS_IS_OK(status
)) {
392 if (!creds_client_check(creds
, a
.out
.credentials
)) {
393 return NT_STATUS_UNSUCCESSFUL
;
397 the schannel session key is now in creds.session_key
399 we no longer need the netlogon pipe open
407 do a schannel style bind on a dcerpc pipe. The username is usually
408 of the form HOSTNAME$ and the password is the domain trust password
410 NTSTATUS
dcerpc_bind_auth_schannel_withkey(struct dcerpc_pipe
*p
,
411 const char *uuid
, uint_t version
,
412 struct creds_CredentialState
*creds
)
415 struct dcerpc_schannel_state
*dce_schan_state
;
417 status
= gensec_client_start(p
, &p
->conn
->security_state
.generic_state
);
418 if (!NT_STATUS_IS_OK(status
)) {
422 status
= gensec_set_workstation(p
->conn
->security_state
.generic_state
, creds
->computer_name
);
423 if (!NT_STATUS_IS_OK(status
)) {
424 DEBUG(1, ("Failed to set schannel workstation to %s: %s\n",
425 creds
->computer_name
, nt_errstr(status
)));
426 talloc_free(p
->conn
->security_state
.generic_state
);
427 p
->conn
->security_state
.generic_state
= NULL
;
431 status
= gensec_set_username(p
->conn
->security_state
.generic_state
, creds
->account_name
);
432 if (!NT_STATUS_IS_OK(status
)) {
433 DEBUG(1, ("Failed to set schannel username to %s: %s\n",
434 creds
->account_name
, nt_errstr(status
)));
435 talloc_free(p
->conn
->security_state
.generic_state
);
436 p
->conn
->security_state
.generic_state
= NULL
;
440 status
= gensec_set_domain(p
->conn
->security_state
.generic_state
, creds
->domain
);
441 if (!NT_STATUS_IS_OK(status
)) {
442 DEBUG(1, ("Failed to set schannel domain to %s: %s\n",
443 creds
->domain
, nt_errstr(status
)));
444 talloc_free(p
->conn
->security_state
.generic_state
);
445 p
->conn
->security_state
.generic_state
= NULL
;
449 status
= gensec_start_mech_by_authtype(p
->conn
->security_state
.generic_state
,
450 DCERPC_AUTH_TYPE_SCHANNEL
,
451 dcerpc_auth_level(p
->conn
));
453 if (!NT_STATUS_IS_OK(status
)) {
454 DEBUG(1, ("Failed to start SCHANNEL GENSEC backend: %s\n", nt_errstr(status
)));
455 talloc_free(p
->conn
->security_state
.generic_state
);
456 p
->conn
->security_state
.generic_state
= NULL
;
460 dce_schan_state
= p
->conn
->security_state
.generic_state
->private_data
;
461 dce_schan_state
->creds
= talloc_reference(dce_schan_state
, creds
);
463 status
= dcerpc_bind_auth(p
, DCERPC_AUTH_TYPE_SCHANNEL
, dcerpc_auth_level(p
->conn
),
466 if (!NT_STATUS_IS_OK(status
)) {
467 DEBUG(1, ("Failed to bind to pipe with SCHANNEL: %s\n", nt_errstr(status
)));
468 talloc_free(p
->conn
->security_state
.generic_state
);
469 p
->conn
->security_state
.generic_state
= NULL
;
476 NTSTATUS
dcerpc_bind_auth_schannel(TALLOC_CTX
*tmp_ctx
,
477 struct dcerpc_pipe
*p
,
478 const char *uuid
, uint_t version
,
479 struct cli_credentials
*credentials
)
483 struct creds_CredentialState
*creds
;
484 creds
= talloc(tmp_ctx
, struct creds_CredentialState
);
486 return NT_STATUS_NO_MEMORY
;
489 if (p
->conn
->flags
& DCERPC_SCHANNEL_BDC
) {
490 chan_type
= SEC_CHAN_BDC
;
491 } else if (p
->conn
->flags
& DCERPC_SCHANNEL_WORKSTATION
) {
492 chan_type
= SEC_CHAN_WKSTA
;
493 } else if (p
->conn
->flags
& DCERPC_SCHANNEL_DOMAIN
) {
494 chan_type
= SEC_CHAN_DOMAIN
;
497 status
= dcerpc_schannel_key(tmp_ctx
,
502 if (!NT_STATUS_IS_OK(status
)) {
503 DEBUG(1, ("Failed to fetch schannel session key: %s\n",
508 return dcerpc_bind_auth_schannel_withkey(p
, uuid
, version
, creds
);
511 static BOOL
dcerpc_schannel_have_feature(struct gensec_security
*gensec_security
,
514 if (feature
& (GENSEC_FEATURE_SESSION_KEY
|
515 GENSEC_FEATURE_SIGN
|
516 GENSEC_FEATURE_SEAL
)) {
523 static const struct gensec_security_ops gensec_dcerpc_schannel_security_ops
= {
524 .name
= "dcerpc_schannel",
525 .auth_type
= DCERPC_AUTH_TYPE_SCHANNEL
,
526 .client_start
= dcerpc_schannel_client_start
,
527 .server_start
= dcerpc_schannel_server_start
,
528 .update
= dcerpc_schannel_update
,
529 .seal_packet
= dcerpc_schannel_seal_packet
,
530 .sign_packet
= dcerpc_schannel_sign_packet
,
531 .check_packet
= dcerpc_schannel_check_packet
,
532 .unseal_packet
= dcerpc_schannel_unseal_packet
,
533 .session_key
= dcerpc_schannel_session_key
,
534 .session_info
= dcerpc_schannel_session_info
,
535 .sig_size
= dcerpc_schannel_sig_size
,
536 .have_feature
= dcerpc_schannel_have_feature
,
540 NTSTATUS
gensec_dcerpc_schannel_init(void)
543 ret
= gensec_register(&gensec_dcerpc_schannel_security_ops
);
544 if (!NT_STATUS_IS_OK(ret
)) {
545 DEBUG(0,("Failed to register '%s' gensec backend!\n",
546 gensec_dcerpc_schannel_security_ops
.name
));