2 Unix SMB/CIFS implementation.
4 test suite for netlogon PAC operations
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2012
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 3 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, see <http://www.gnu.org/licenses/>.
23 #include "auth/auth.h"
24 #include "auth/auth_sam_reply.h"
25 #include "auth/gensec/gensec.h"
26 #include "system/kerberos.h"
27 #include "auth/kerberos/kerberos.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/credentials/credentials_krb5.h"
30 #include "lib/cmdline/popt_common.h"
31 #include "torture/rpc/torture_rpc.h"
32 #include "libcli/auth/libcli_auth.h"
33 #include "libcli/security/security.h"
34 #include "librpc/gen_ndr/ndr_netlogon_c.h"
35 #include "librpc/gen_ndr/ndr_krb5pac.h"
36 #include "librpc/gen_ndr/ndr_samr_c.h"
37 #include "param/param.h"
39 #define TEST_MACHINE_NAME_BDC "torturepacbdc"
40 #define TEST_MACHINE_NAME_WKSTA "torturepacwksta"
41 #define TEST_MACHINE_NAME_WKSTA_DES "torturepacwkdes"
42 #define TEST_MACHINE_NAME_S2U4SELF_BDC "tests2u4selfbdc"
43 #define TEST_MACHINE_NAME_S2U4SELF_WKSTA "tests2u4selfwk"
47 struct PAC_SIGNATURE_DATA
*pac_srv_sig
;
48 struct PAC_SIGNATURE_DATA
*pac_kdc_sig
;
51 /* A helper function which avoids touching the local databases to
52 * generate the session info, as we just want to verify the PAC
53 * details, not the full local token */
54 static NTSTATUS
test_generate_session_info_pac(struct auth4_context
*auth_ctx
,
56 struct smb_krb5_context
*smb_krb5_context
,
58 const char *principal_name
,
59 const struct tsocket_address
*remote_address
,
60 uint32_t session_info_flags
,
61 struct auth_session_info
**session_info
)
64 struct auth_user_info_dc
*user_info_dc
;
66 struct pac_data
*pac_data
;
68 tmp_ctx
= talloc_named(mem_ctx
, 0, "gensec_gssapi_session_info context");
69 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
71 auth_ctx
->private_data
= pac_data
= talloc_zero(auth_ctx
, struct pac_data
);
73 pac_data
->pac_blob
= data_blob_dup_talloc(pac_data
, *pac_blob
);
74 if (pac_data
->pac_blob
.length
!= pac_blob
->length
) {
76 return NT_STATUS_NO_MEMORY
;
79 pac_data
->pac_srv_sig
= talloc(tmp_ctx
, struct PAC_SIGNATURE_DATA
);
80 if (!pac_data
->pac_srv_sig
) {
82 return NT_STATUS_NO_MEMORY
;
84 pac_data
->pac_kdc_sig
= talloc(tmp_ctx
, struct PAC_SIGNATURE_DATA
);
85 if (!pac_data
->pac_kdc_sig
) {
87 return NT_STATUS_NO_MEMORY
;
90 nt_status
= kerberos_pac_blob_to_user_info_dc(tmp_ctx
,
92 smb_krb5_context
->krb5_context
,
94 pac_data
->pac_srv_sig
,
95 pac_data
->pac_kdc_sig
);
96 if (!NT_STATUS_IS_OK(nt_status
)) {
101 talloc_steal(pac_data
, pac_data
->pac_srv_sig
);
102 talloc_steal(pac_data
, pac_data
->pac_kdc_sig
);
104 if (user_info_dc
->info
->authenticated
) {
105 session_info_flags
|= AUTH_SESSION_INFO_AUTHENTICATED
;
108 session_info_flags
|= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES
;
109 nt_status
= auth_generate_session_info(mem_ctx
,
112 user_info_dc
, session_info_flags
,
114 if (!NT_STATUS_IS_OK(nt_status
)) {
115 talloc_free(tmp_ctx
);
119 talloc_free(tmp_ctx
);
123 /* Check to see if we can pass the PAC across to the NETLOGON server for validation */
125 static const struct PAC_BUFFER
*get_pac_buffer(const struct PAC_DATA
*pac_data
,
128 const struct PAC_BUFFER
*pac_buf
= NULL
;
131 for (i
= 0; i
< pac_data
->num_buffers
; ++i
) {
132 pac_buf
= &pac_data
->buffers
[i
];
134 if (pac_buf
->type
== type
) {
142 /* Also happens to be a really good one-step verfication of our Kerberos stack */
144 static bool test_PACVerify(struct torture_context
*tctx
,
145 struct dcerpc_pipe
*p1
,
146 struct cli_credentials
*credentials
,
147 enum netr_SchannelType secure_channel_type
,
148 const char *test_machine_name
,
149 uint32_t negotiate_flags
)
152 bool pkinit_in_use
= torture_setting_bool(tctx
, "pkinit_in_use", false);
153 bool expect_pac_upn_dns_info
= torture_setting_bool(tctx
, "expect_pac_upn_dns_info", true);
154 size_t num_pac_buffers
;
156 struct netr_LogonSamLogon r
;
158 union netr_LogonLevel logon
;
159 union netr_Validation validation
;
160 uint8_t authoritative
;
161 struct netr_Authenticator return_authenticator
;
163 struct netr_GenericInfo generic
;
164 struct netr_Authenticator auth
, auth2
;
166 struct netlogon_creds_CredentialState
*creds
;
167 struct gensec_security
*gensec_client_context
;
168 struct gensec_security
*gensec_server_context
;
169 struct cli_credentials
*client_creds
;
170 struct cli_credentials
*server_creds
;
172 DATA_BLOB client_to_server
, server_to_client
, pac_wrapped
, payload
;
173 struct PAC_Validate pac_wrapped_struct
;
174 struct PAC_DATA pac_data_struct
;
176 enum ndr_err_code ndr_err
;
178 struct auth4_context
*auth_context
;
179 struct auth_session_info
*session_info
;
180 struct pac_data
*pac_data
;
181 const struct PAC_BUFFER
*pac_buf
= NULL
;
183 struct dcerpc_pipe
*p
= NULL
;
184 struct dcerpc_binding_handle
*b
= NULL
;
185 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
186 torture_assert(tctx
, tmp_ctx
!= NULL
, "talloc_new() failed");
188 torture_comment(tctx
,
189 "Testing PAC Verify (secure_channel_type: %d, machine: %s, negotiate_flags: 0x%08x\n",
190 secure_channel_type
, test_machine_name
, negotiate_flags
);
193 * Copy the credentials in order to use a different MEMORY krb5 ccache
194 * for each client/server setup. The MEMORY cache identifier is a
195 * pointer to the creds container. If we copy it the pointer changes and
196 * we will get a new clean memory cache.
198 client_creds
= cli_credentials_shallow_copy(tmp_ctx
,
199 popt_get_cmdline_credentials());
200 torture_assert(tctx
, client_creds
, "Failed to copy of credentials");
201 if (!pkinit_in_use
) {
202 /* Invalidate the gss creds container to allocate a new MEMORY ccache */
203 cli_credentials_invalidate_ccache(client_creds
, CRED_SPECIFIED
);
206 server_creds
= cli_credentials_shallow_copy(tmp_ctx
,
208 torture_assert(tctx
, server_creds
, "Failed to copy of credentials");
210 if (!test_SetupCredentials2(p1
, tctx
, negotiate_flags
,
211 server_creds
, secure_channel_type
,
215 if (!test_SetupCredentialsPipe(p1
, tctx
, server_creds
, creds
,
216 DCERPC_SIGN
| DCERPC_SEAL
, &p
)) {
219 b
= p
->binding_handle
;
221 auth_context
= talloc_zero(tmp_ctx
, struct auth4_context
);
222 torture_assert(tctx
, auth_context
!= NULL
, "talloc_new() failed");
224 auth_context
->generate_session_info_pac
= test_generate_session_info_pac
;
226 status
= gensec_client_start(tctx
, &gensec_client_context
,
227 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
));
228 torture_assert_ntstatus_ok(tctx
, status
, "gensec_client_start (client) failed");
230 status
= gensec_set_target_hostname(gensec_client_context
, test_machine_name
);
232 status
= gensec_set_credentials(gensec_client_context
, client_creds
);
233 torture_assert_ntstatus_ok(tctx
, status
, "gensec_set_credentials (client) failed");
235 status
= gensec_start_mech_by_sasl_name(gensec_client_context
, "GSSAPI");
236 torture_assert_ntstatus_ok(tctx
, status
, "gensec_start_mech_by_sasl_name (client) failed");
238 status
= gensec_server_start(tctx
,
239 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
),
240 auth_context
, &gensec_server_context
);
241 torture_assert_ntstatus_ok(tctx
, status
, "gensec_server_start (server) failed");
243 status
= gensec_set_credentials(gensec_server_context
, server_creds
);
244 torture_assert_ntstatus_ok(tctx
, status
, "gensec_set_credentials (server) failed");
246 status
= gensec_start_mech_by_sasl_name(gensec_server_context
, "GSSAPI");
247 torture_assert_ntstatus_ok(tctx
, status
, "gensec_start_mech_by_sasl_name (server) failed");
249 server_to_client
= data_blob(NULL
, 0);
252 /* Do a client-server update dance */
253 status
= gensec_update(gensec_client_context
, tmp_ctx
, server_to_client
, &client_to_server
);
254 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {;
255 torture_assert_ntstatus_ok(tctx
, status
, "gensec_update (client) failed");
258 status
= gensec_update(gensec_server_context
, tmp_ctx
, client_to_server
, &server_to_client
);
259 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {;
260 torture_assert_ntstatus_ok(tctx
, status
, "gensec_update (server) failed");
263 if (NT_STATUS_IS_OK(status
)) {
268 /* Extract the PAC using Samba's code */
270 status
= gensec_session_info(gensec_server_context
, gensec_server_context
, &session_info
);
271 torture_assert_ntstatus_ok(tctx
, status
, "gensec_session_info failed");
273 pac_data
= talloc_get_type(auth_context
->private_data
, struct pac_data
);
275 torture_assert(tctx
, pac_data
!= NULL
, "gensec_update failed to fill in pac_data in auth_context");
276 torture_assert(tctx
, pac_data
->pac_srv_sig
!= NULL
, "pac_srv_sig not present");
277 torture_assert(tctx
, pac_data
->pac_kdc_sig
!= NULL
, "pac_kdc_sig not present");
279 ndr_err
= ndr_pull_struct_blob(&pac_data
->pac_blob
, tmp_ctx
, &pac_data_struct
,
280 (ndr_pull_flags_fn_t
)ndr_pull_PAC_DATA
);
281 torture_assert(tctx
, NDR_ERR_CODE_IS_SUCCESS(ndr_err
), "ndr_pull_struct_blob of PAC_DATA structure failed");
284 if (expect_pac_upn_dns_info
) {
285 num_pac_buffers
+= 1;
288 num_pac_buffers
+= 1;
291 torture_assert_int_equal(tctx
, pac_data_struct
.version
, 0, "version");
292 torture_assert_int_equal(tctx
, pac_data_struct
.num_buffers
, num_pac_buffers
, "num_buffers");
294 pac_buf
= get_pac_buffer(&pac_data_struct
, PAC_TYPE_LOGON_INFO
);
295 torture_assert_not_null(tctx
, pac_buf
, "PAC_TYPE_LOGON_INFO");
297 pac_buf
->info
!= NULL
,
298 "PAC_TYPE_LOGON_INFO info");
301 pac_buf
= get_pac_buffer(&pac_data_struct
, PAC_TYPE_CREDENTIAL_INFO
);
302 torture_assert_not_null(tctx
, pac_buf
, "PAC_TYPE_CREDENTIAL_INFO");
304 pac_buf
->info
!= NULL
,
305 "PAC_TYPE_CREDENTIAL_INFO info");
308 pac_buf
= get_pac_buffer(&pac_data_struct
, PAC_TYPE_LOGON_NAME
);
309 torture_assert_not_null(tctx
, pac_buf
, "PAC_TYPE_LOGON_NAME");
311 pac_buf
->info
!= NULL
,
312 "PAC_TYPE_LOGON_NAME info");
314 if (expect_pac_upn_dns_info
) {
315 pac_buf
= get_pac_buffer(&pac_data_struct
, PAC_TYPE_UPN_DNS_INFO
);
316 torture_assert_not_null(tctx
, pac_buf
, "PAC_TYPE_UPN_DNS_INFO");
318 pac_buf
->info
!= NULL
,
319 "PAC_TYPE_UPN_DNS_INFO info");
322 pac_buf
= get_pac_buffer(&pac_data_struct
, PAC_TYPE_SRV_CHECKSUM
);
323 torture_assert_not_null(tctx
, pac_buf
, "PAC_TYPE_SRV_CHECKSUM");
325 pac_buf
->info
!= NULL
,
326 "PAC_TYPE_SRV_CHECKSUM info");
328 pac_buf
= get_pac_buffer(&pac_data_struct
, PAC_TYPE_KDC_CHECKSUM
);
329 torture_assert_not_null(tctx
, pac_buf
, "PAC_TYPE_KDC_CHECKSUM");
331 pac_buf
->info
!= NULL
,
332 "PAC_TYPE_KDC_CHECKSUM info");
334 pac_wrapped_struct
.ChecksumLength
= pac_data
->pac_srv_sig
->signature
.length
;
335 pac_wrapped_struct
.SignatureType
= pac_data
->pac_kdc_sig
->type
;
336 pac_wrapped_struct
.SignatureLength
= pac_data
->pac_kdc_sig
->signature
.length
;
337 pac_wrapped_struct
.ChecksumAndSignature
= payload
338 = data_blob_talloc(tmp_ctx
, NULL
,
339 pac_wrapped_struct
.ChecksumLength
340 + pac_wrapped_struct
.SignatureLength
);
341 memcpy(&payload
.data
[0],
342 pac_data
->pac_srv_sig
->signature
.data
,
343 pac_wrapped_struct
.ChecksumLength
);
344 memcpy(&payload
.data
[pac_wrapped_struct
.ChecksumLength
],
345 pac_data
->pac_kdc_sig
->signature
.data
,
346 pac_wrapped_struct
.SignatureLength
);
348 ndr_err
= ndr_push_struct_blob(&pac_wrapped
, tmp_ctx
, &pac_wrapped_struct
,
349 (ndr_push_flags_fn_t
)ndr_push_PAC_Validate
);
350 torture_assert(tctx
, NDR_ERR_CODE_IS_SUCCESS(ndr_err
), "ndr_push_struct_blob of PACValidate structure failed");
352 torture_assert(tctx
, (creds
->negotiate_flags
& NETLOGON_NEG_ARCFOUR
), "not willing to even try a PACValidate without RC4 encryption");
353 if (creds
->negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
354 netlogon_creds_aes_encrypt(creds
, pac_wrapped
.data
, pac_wrapped
.length
);
356 netlogon_creds_arcfour_crypt(creds
, pac_wrapped
.data
, pac_wrapped
.length
);
359 generic
.length
= pac_wrapped
.length
;
360 generic
.data
= pac_wrapped
.data
;
362 /* Validate it over the netlogon pipe */
364 generic
.identity_info
.parameter_control
= 0;
365 generic
.identity_info
.logon_id_high
= 0;
366 generic
.identity_info
.logon_id_low
= 0;
367 generic
.identity_info
.domain_name
.string
= session_info
->info
->domain_name
;
368 generic
.identity_info
.account_name
.string
= session_info
->info
->account_name
;
369 generic
.identity_info
.workstation
.string
= test_machine_name
;
371 generic
.package_name
.string
= "Kerberos";
373 logon
.generic
= &generic
;
376 netlogon_creds_client_authenticator(creds
, &auth
);
377 r
.in
.credential
= &auth
;
378 r
.in
.return_authenticator
= &auth2
;
380 r
.in
.logon_level
= NetlogonGenericInformation
;
381 r
.in
.server_name
= talloc_asprintf(tctx
, "\\\\%s", dcerpc_server_name(p
));
382 r
.in
.computer_name
= cli_credentials_get_workstation(server_creds
);
383 r
.in
.validation_level
= NetlogonValidationGenericInfo2
;
384 r
.out
.validation
= &validation
;
385 r
.out
.authoritative
= &authoritative
;
386 r
.out
.return_authenticator
= &return_authenticator
;
388 torture_assert_ntstatus_ok(tctx
, dcerpc_netr_LogonSamLogon_r(b
, tctx
, &r
),
389 "LogonSamLogon failed");
391 torture_assert_ntstatus_ok(tctx
, r
.out
.result
, "LogonSamLogon failed");
393 /* This will break the signature nicely (even in the crypto wrapping), check we get a logon failure */
394 generic
.data
[generic
.length
-1]++;
396 logon
.generic
= &generic
;
399 netlogon_creds_client_authenticator(creds
, &auth
);
400 r
.in
.credential
= &auth
;
401 r
.in
.return_authenticator
= &auth2
;
402 r
.in
.logon_level
= NetlogonGenericInformation
;
404 r
.in
.server_name
= talloc_asprintf(tctx
, "\\\\%s", dcerpc_server_name(p
));
405 r
.in
.computer_name
= cli_credentials_get_workstation(server_creds
);
406 r
.in
.validation_level
= NetlogonValidationGenericInfo2
;
408 torture_assert_ntstatus_ok(tctx
, dcerpc_netr_LogonSamLogon_r(b
, tctx
, &r
),
409 "LogonSamLogon failed");
411 torture_assert_ntstatus_equal(tctx
, r
.out
.result
, NT_STATUS_LOGON_FAILURE
, "LogonSamLogon failed");
413 torture_assert(tctx
, netlogon_creds_client_check(creds
, &r
.out
.return_authenticator
->cred
),
414 "Credential chaining failed");
416 /* This will break the parsing nicely (even in the crypto wrapping), check we get INVALID_PARAMETER */
419 logon
.generic
= &generic
;
422 netlogon_creds_client_authenticator(creds
, &auth
);
423 r
.in
.credential
= &auth
;
424 r
.in
.return_authenticator
= &auth2
;
425 r
.in
.logon_level
= NetlogonGenericInformation
;
427 r
.in
.server_name
= talloc_asprintf(tctx
, "\\\\%s", dcerpc_server_name(p
));
428 r
.in
.computer_name
= cli_credentials_get_workstation(server_creds
);
429 r
.in
.validation_level
= NetlogonValidationGenericInfo2
;
431 torture_assert_ntstatus_ok(tctx
, dcerpc_netr_LogonSamLogon_r(b
, tctx
, &r
),
432 "LogonSamLogon failed");
434 torture_assert_ntstatus_equal(tctx
, r
.out
.result
, NT_STATUS_INVALID_PARAMETER
, "LogonSamLogon failed");
436 torture_assert(tctx
, netlogon_creds_client_check(creds
,
437 &r
.out
.return_authenticator
->cred
),
438 "Credential chaining failed");
440 pac_wrapped_struct
.ChecksumLength
= pac_data
->pac_srv_sig
->signature
.length
;
441 pac_wrapped_struct
.SignatureType
= pac_data
->pac_kdc_sig
->type
;
443 /* Break the SignatureType */
444 pac_wrapped_struct
.SignatureType
++;
446 pac_wrapped_struct
.SignatureLength
= pac_data
->pac_kdc_sig
->signature
.length
;
447 pac_wrapped_struct
.ChecksumAndSignature
= payload
448 = data_blob_talloc(tmp_ctx
, NULL
,
449 pac_wrapped_struct
.ChecksumLength
450 + pac_wrapped_struct
.SignatureLength
);
451 memcpy(&payload
.data
[0],
452 pac_data
->pac_srv_sig
->signature
.data
,
453 pac_wrapped_struct
.ChecksumLength
);
454 memcpy(&payload
.data
[pac_wrapped_struct
.ChecksumLength
],
455 pac_data
->pac_kdc_sig
->signature
.data
,
456 pac_wrapped_struct
.SignatureLength
);
458 ndr_err
= ndr_push_struct_blob(&pac_wrapped
, tmp_ctx
, &pac_wrapped_struct
,
459 (ndr_push_flags_fn_t
)ndr_push_PAC_Validate
);
460 torture_assert(tctx
, NDR_ERR_CODE_IS_SUCCESS(ndr_err
), "ndr_push_struct_blob of PACValidate structure failed");
462 torture_assert(tctx
, (creds
->negotiate_flags
& NETLOGON_NEG_ARCFOUR
), "not willing to even try a PACValidate without RC4 encryption");
463 if (creds
->negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
464 netlogon_creds_aes_encrypt(creds
, pac_wrapped
.data
, pac_wrapped
.length
);
466 netlogon_creds_arcfour_crypt(creds
, pac_wrapped
.data
, pac_wrapped
.length
);
469 generic
.length
= pac_wrapped
.length
;
470 generic
.data
= pac_wrapped
.data
;
472 logon
.generic
= &generic
;
475 netlogon_creds_client_authenticator(creds
, &auth
);
476 r
.in
.credential
= &auth
;
477 r
.in
.return_authenticator
= &auth2
;
478 r
.in
.logon_level
= NetlogonGenericInformation
;
480 r
.in
.server_name
= talloc_asprintf(tctx
, "\\\\%s", dcerpc_server_name(p
));
481 r
.in
.computer_name
= cli_credentials_get_workstation(server_creds
);
482 r
.in
.validation_level
= NetlogonValidationGenericInfo2
;
484 torture_assert_ntstatus_ok(tctx
, dcerpc_netr_LogonSamLogon_r(b
, tctx
, &r
),
485 "LogonSamLogon failed");
487 torture_assert_ntstatus_equal(tctx
, r
.out
.result
, NT_STATUS_LOGON_FAILURE
, "LogonSamLogon failed");
489 torture_assert(tctx
, netlogon_creds_client_check(creds
, &r
.out
.return_authenticator
->cred
),
490 "Credential chaining failed");
492 pac_wrapped_struct
.ChecksumLength
= pac_data
->pac_srv_sig
->signature
.length
;
493 pac_wrapped_struct
.SignatureType
= pac_data
->pac_kdc_sig
->type
;
494 pac_wrapped_struct
.SignatureLength
= pac_data
->pac_kdc_sig
->signature
.length
;
496 pac_wrapped_struct
.ChecksumAndSignature
= payload
497 = data_blob_talloc(tmp_ctx
, NULL
,
498 pac_wrapped_struct
.ChecksumLength
499 + pac_wrapped_struct
.SignatureLength
);
500 memcpy(&payload
.data
[0],
501 pac_data
->pac_srv_sig
->signature
.data
,
502 pac_wrapped_struct
.ChecksumLength
);
503 memcpy(&payload
.data
[pac_wrapped_struct
.ChecksumLength
],
504 pac_data
->pac_kdc_sig
->signature
.data
,
505 pac_wrapped_struct
.SignatureLength
);
507 /* Break the signature length */
508 pac_wrapped_struct
.SignatureLength
++;
510 ndr_err
= ndr_push_struct_blob(&pac_wrapped
, tmp_ctx
, &pac_wrapped_struct
,
511 (ndr_push_flags_fn_t
)ndr_push_PAC_Validate
);
512 torture_assert(tctx
, NDR_ERR_CODE_IS_SUCCESS(ndr_err
), "ndr_push_struct_blob of PACValidate structure failed");
514 torture_assert(tctx
, (creds
->negotiate_flags
& NETLOGON_NEG_ARCFOUR
), "not willing to even try a PACValidate without RC4 encryption");
515 if (creds
->negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
516 netlogon_creds_aes_encrypt(creds
, pac_wrapped
.data
, pac_wrapped
.length
);
518 netlogon_creds_arcfour_crypt(creds
, pac_wrapped
.data
, pac_wrapped
.length
);
521 generic
.length
= pac_wrapped
.length
;
522 generic
.data
= pac_wrapped
.data
;
524 logon
.generic
= &generic
;
527 netlogon_creds_client_authenticator(creds
, &auth
);
528 r
.in
.credential
= &auth
;
529 r
.in
.return_authenticator
= &auth2
;
530 r
.in
.logon_level
= NetlogonGenericInformation
;
532 r
.in
.server_name
= talloc_asprintf(tctx
, "\\\\%s", dcerpc_server_name(p
));
533 r
.in
.computer_name
= cli_credentials_get_workstation(server_creds
);
534 r
.in
.validation_level
= NetlogonValidationGenericInfo2
;
536 torture_assert_ntstatus_ok(tctx
, dcerpc_netr_LogonSamLogon_r(b
, tctx
, &r
),
537 "LogonSamLogon failed");
539 torture_assert_ntstatus_equal(tctx
, r
.out
.result
, NT_STATUS_INVALID_PARAMETER
, "LogonSamLogon failed");
541 torture_assert(tctx
, netlogon_creds_client_check(creds
, &r
.out
.return_authenticator
->cred
),
542 "Credential chaining failed");
544 talloc_free(tmp_ctx
);
549 static bool test_PACVerify_bdc_arcfour(struct torture_context
*tctx
,
550 struct dcerpc_pipe
*p
,
551 struct cli_credentials
*credentials
)
553 return test_PACVerify(tctx
, p
, credentials
, SEC_CHAN_BDC
,
554 TEST_MACHINE_NAME_BDC
,
555 NETLOGON_NEG_AUTH2_ADS_FLAGS
);
558 static bool test_PACVerify_bdc_aes(struct torture_context
*tctx
,
559 struct dcerpc_pipe
*p
,
560 struct cli_credentials
*credentials
)
562 return test_PACVerify(tctx
, p
, credentials
, SEC_CHAN_BDC
,
563 TEST_MACHINE_NAME_BDC
,
564 NETLOGON_NEG_AUTH2_ADS_FLAGS
| NETLOGON_NEG_SUPPORTS_AES
);
567 static bool test_PACVerify_workstation_arcfour(struct torture_context
*tctx
,
568 struct dcerpc_pipe
*p
,
569 struct cli_credentials
*credentials
)
571 return test_PACVerify(tctx
, p
, credentials
, SEC_CHAN_WKSTA
,
572 TEST_MACHINE_NAME_WKSTA
,
573 NETLOGON_NEG_AUTH2_ADS_FLAGS
);
576 static bool test_PACVerify_workstation_aes(struct torture_context
*tctx
,
577 struct dcerpc_pipe
*p
,
578 struct cli_credentials
*credentials
)
580 return test_PACVerify(tctx
, p
, credentials
, SEC_CHAN_WKSTA
,
581 TEST_MACHINE_NAME_WKSTA
,
582 NETLOGON_NEG_AUTH2_ADS_FLAGS
| NETLOGON_NEG_SUPPORTS_AES
);
585 static bool test_PACVerify_workstation_des(struct torture_context
*tctx
,
586 struct dcerpc_pipe
*p
, struct cli_credentials
*credentials
, struct test_join
*join_ctx
)
588 struct samr_SetUserInfo r
;
589 union samr_UserInfo user_info
;
590 struct dcerpc_pipe
*samr_pipe
= torture_join_samr_pipe(join_ctx
);
591 struct smb_krb5_context
*smb_krb5_context
;
594 ret
= cli_credentials_get_krb5_context(popt_get_cmdline_credentials(),
595 tctx
->lp_ctx
, &smb_krb5_context
);
596 torture_assert_int_equal(tctx
, ret
, 0, "cli_credentials_get_krb5_context() failed");
598 if (smb_krb5_get_allowed_weak_crypto(smb_krb5_context
->krb5_context
) == FALSE
) {
599 torture_skip(tctx
, "Cannot test DES without [libdefaults] allow_weak_crypto = yes");
602 /* Mark this workstation with DES-only */
603 user_info
.info16
.acct_flags
= ACB_USE_DES_KEY_ONLY
| ACB_WSTRUST
;
604 r
.in
.user_handle
= torture_join_samr_user_policy(join_ctx
);
606 r
.in
.info
= &user_info
;
608 torture_assert_ntstatus_ok(tctx
, dcerpc_samr_SetUserInfo_r(samr_pipe
->binding_handle
, tctx
, &r
),
609 "failed to set DES info account flags");
610 torture_assert_ntstatus_ok(tctx
, r
.out
.result
,
611 "failed to set DES into account flags");
613 return test_PACVerify(tctx
, p
, credentials
, SEC_CHAN_WKSTA
,
614 TEST_MACHINE_NAME_WKSTA_DES
,
615 NETLOGON_NEG_AUTH2_ADS_FLAGS
);
619 /* Check various ways to get the PAC, in particular check the group membership and other details between the PAC from a normal kinit, S2U4Self and a SamLogon */
620 #ifdef SAMBA4_USES_HEIMDAL
621 static bool test_S2U4Self(struct torture_context
*tctx
,
622 struct dcerpc_pipe
*p1
,
623 struct cli_credentials
*credentials
,
624 enum netr_SchannelType secure_channel_type
,
625 const char *test_machine_name
,
626 uint32_t negotiate_flags
)
629 struct dcerpc_pipe
*p
= NULL
;
630 struct dcerpc_binding_handle
*b
= NULL
;
632 struct netr_LogonSamLogon r
;
634 union netr_LogonLevel logon
;
635 union netr_Validation validation
;
636 uint8_t authoritative
;
638 struct netr_Authenticator auth
, auth2
;
640 DATA_BLOB client_to_server
, server_to_client
;
642 struct netlogon_creds_CredentialState
*creds
;
643 struct gensec_security
*gensec_client_context
;
644 struct gensec_security
*gensec_server_context
;
645 struct cli_credentials
*client_creds
;
646 struct cli_credentials
*server_creds
;
648 struct auth4_context
*auth_context
;
649 struct auth_session_info
*kinit_session_info
;
650 struct auth_session_info
*s2u4self_session_info
;
651 struct auth_user_info_dc
*netlogon_user_info_dc
;
653 struct netr_NetworkInfo ninfo
;
654 DATA_BLOB names_blob
, chal
, lm_resp
, nt_resp
;
656 int flags
= CLI_CRED_NTLMv2_AUTH
;
658 struct dom_sid
*builtin_domain
;
660 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
662 torture_assert(tctx
, tmp_ctx
!= NULL
, "talloc_new() failed");
664 torture_comment(tctx
,
665 "Testing S4U2SELF (secure_channel_type: %d, machine: %s, negotiate_flags: 0x%08x\n",
666 secure_channel_type
, test_machine_name
, negotiate_flags
);
669 * Copy the credentials in order to use a different MEMORY krb5 ccache
670 * for each client/server setup. The MEMORY cache identifier is a
671 * pointer to the creds container. If we copy it the pointer changes and
672 * we will get a new clean memory cache.
674 client_creds
= cli_credentials_shallow_copy(tmp_ctx
,
675 popt_get_cmdline_credentials());
676 torture_assert(tctx
, client_creds
, "Failed to copy of credentials");
678 server_creds
= cli_credentials_shallow_copy(tmp_ctx
,
680 torture_assert(tctx
, server_creds
, "Failed to copy of credentials");
682 if (!test_SetupCredentials2(p1
, tctx
, negotiate_flags
,
683 server_creds
, secure_channel_type
,
687 if (!test_SetupCredentialsPipe(p1
, tctx
, server_creds
, creds
,
688 DCERPC_SIGN
| DCERPC_SEAL
, &p
)) {
691 b
= p
->binding_handle
;
693 auth_context
= talloc_zero(tmp_ctx
, struct auth4_context
);
694 torture_assert(tctx
, auth_context
!= NULL
, "talloc_new() failed");
696 auth_context
->generate_session_info_pac
= test_generate_session_info_pac
;
698 /* First, do a normal Kerberos connection */
700 status
= gensec_client_start(tctx
, &gensec_client_context
,
701 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
));
702 torture_assert_ntstatus_ok(tctx
, status
, "gensec_client_start (client) failed");
704 status
= gensec_set_target_hostname(gensec_client_context
, test_machine_name
);
706 status
= gensec_set_credentials(gensec_client_context
, client_creds
);
707 torture_assert_ntstatus_ok(tctx
, status
, "gensec_set_credentials (client) failed");
709 status
= gensec_start_mech_by_sasl_name(gensec_client_context
, "GSSAPI");
710 torture_assert_ntstatus_ok(tctx
, status
, "gensec_start_mech_by_sasl_name (client) failed");
712 status
= gensec_server_start(tctx
,
713 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
),
714 auth_context
, &gensec_server_context
);
715 torture_assert_ntstatus_ok(tctx
, status
, "gensec_server_start (server) failed");
717 status
= gensec_set_credentials(gensec_server_context
, server_creds
);
718 torture_assert_ntstatus_ok(tctx
, status
, "gensec_set_credentials (server) failed");
720 status
= gensec_start_mech_by_sasl_name(gensec_server_context
, "GSSAPI");
721 torture_assert_ntstatus_ok(tctx
, status
, "gensec_start_mech_by_sasl_name (server) failed");
723 server_to_client
= data_blob(NULL
, 0);
726 /* Do a client-server update dance */
727 status
= gensec_update(gensec_client_context
, tmp_ctx
, server_to_client
, &client_to_server
);
728 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {;
729 torture_assert_ntstatus_ok(tctx
, status
, "gensec_update (client) failed");
732 status
= gensec_update(gensec_server_context
, tmp_ctx
, client_to_server
, &server_to_client
);
733 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {;
734 torture_assert_ntstatus_ok(tctx
, status
, "gensec_update (server) failed");
737 if (NT_STATUS_IS_OK(status
)) {
742 /* Extract the PAC using Samba's code */
744 status
= gensec_session_info(gensec_server_context
, gensec_server_context
, &kinit_session_info
);
745 torture_assert_ntstatus_ok(tctx
, status
, "gensec_session_info failed");
748 /* Now do the dance with S2U4Self */
750 /* Wipe out any existing ccache */
751 cli_credentials_invalidate_ccache(client_creds
, CRED_SPECIFIED
);
752 cli_credentials_invalidate_ccache(server_creds
, CRED_SPECIFIED
);
753 cli_credentials_set_impersonate_principal(server_creds
,
754 cli_credentials_get_principal(client_creds
, tmp_ctx
),
755 talloc_asprintf(tmp_ctx
, "host/%s", test_machine_name
));
757 status
= gensec_client_start(tctx
, &gensec_client_context
,
758 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
));
759 torture_assert_ntstatus_ok(tctx
, status
, "gensec_client_start (client) failed");
761 status
= gensec_set_target_hostname(gensec_client_context
, test_machine_name
);
763 /* We now set the same credentials on both client and server contexts */
764 status
= gensec_set_credentials(gensec_client_context
, server_creds
);
765 torture_assert_ntstatus_ok(tctx
, status
, "gensec_set_credentials (client) failed");
767 status
= gensec_start_mech_by_sasl_name(gensec_client_context
, "GSSAPI");
768 torture_assert_ntstatus_ok(tctx
, status
, "gensec_start_mech_by_sasl_name (client) failed");
770 status
= gensec_server_start(tctx
,
771 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
),
772 auth_context
, &gensec_server_context
);
773 torture_assert_ntstatus_ok(tctx
, status
, "gensec_server_start (server) failed");
775 status
= gensec_set_credentials(gensec_server_context
, server_creds
);
776 torture_assert_ntstatus_ok(tctx
, status
, "gensec_set_credentials (server) failed");
778 status
= gensec_start_mech_by_sasl_name(gensec_server_context
, "GSSAPI");
779 torture_assert_ntstatus_ok(tctx
, status
, "gensec_start_mech_by_sasl_name (server) failed");
781 server_to_client
= data_blob(NULL
, 0);
784 /* Do a client-server update dance */
785 status
= gensec_update(gensec_client_context
, tmp_ctx
, server_to_client
, &client_to_server
);
786 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {;
787 torture_assert_ntstatus_ok(tctx
, status
, "gensec_update (client) failed");
790 status
= gensec_update(gensec_server_context
, tmp_ctx
, client_to_server
, &server_to_client
);
791 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {;
792 torture_assert_ntstatus_ok(tctx
, status
, "gensec_update (server) failed");
795 if (NT_STATUS_IS_OK(status
)) {
800 /* Don't pollute the remaining tests with the changed credentials */
801 cli_credentials_invalidate_ccache(server_creds
, CRED_SPECIFIED
);
802 cli_credentials_set_target_service(server_creds
, NULL
);
803 cli_credentials_set_impersonate_principal(server_creds
, NULL
, NULL
);
805 /* Extract the PAC using Samba's code */
807 status
= gensec_session_info(gensec_server_context
, gensec_server_context
, &s2u4self_session_info
);
808 torture_assert_ntstatus_ok(tctx
, status
, "gensec_session_info failed");
810 cli_credentials_get_ntlm_username_domain(client_creds
, tctx
,
811 &ninfo
.identity_info
.account_name
.string
,
812 &ninfo
.identity_info
.domain_name
.string
);
814 /* Now try with SamLogon */
815 generate_random_buffer(ninfo
.challenge
,
816 sizeof(ninfo
.challenge
));
817 chal
= data_blob_const(ninfo
.challenge
,
818 sizeof(ninfo
.challenge
));
820 names_blob
= NTLMv2_generate_names_blob(tctx
, cli_credentials_get_workstation(server_creds
),
821 cli_credentials_get_domain(server_creds
));
823 status
= cli_credentials_get_ntlm_response(client_creds
, tctx
,
826 NULL
, /* server_timestamp */
830 torture_assert_ntstatus_ok(tctx
, status
, "cli_credentials_get_ntlm_response failed");
832 ninfo
.lm
.data
= lm_resp
.data
;
833 ninfo
.lm
.length
= lm_resp
.length
;
835 ninfo
.nt
.data
= nt_resp
.data
;
836 ninfo
.nt
.length
= nt_resp
.length
;
838 ninfo
.identity_info
.parameter_control
= 0;
839 ninfo
.identity_info
.logon_id_low
= 0;
840 ninfo
.identity_info
.logon_id_high
= 0;
841 ninfo
.identity_info
.workstation
.string
= cli_credentials_get_workstation(server_creds
);
843 logon
.network
= &ninfo
;
845 r
.in
.server_name
= talloc_asprintf(tctx
, "\\\\%s", dcerpc_server_name(p
));
846 r
.in
.computer_name
= cli_credentials_get_workstation(server_creds
);
847 r
.in
.credential
= &auth
;
848 r
.in
.return_authenticator
= &auth2
;
849 r
.in
.logon_level
= NetlogonNetworkInformation
;
851 r
.out
.validation
= &validation
;
852 r
.out
.authoritative
= &authoritative
;
855 netlogon_creds_client_authenticator(creds
, &auth
);
857 r
.in
.validation_level
= 3;
859 status
= dcerpc_netr_LogonSamLogon_r(b
, tctx
, &r
);
860 torture_assert_ntstatus_ok(tctx
, status
, "LogonSamLogon failed");
862 torture_assert(tctx
, netlogon_creds_client_check(creds
,
863 &r
.out
.return_authenticator
->cred
),
864 "Credential chaining failed");
866 torture_assert_ntstatus_ok(tctx
, r
.out
.result
, "LogonSamLogon failed");
868 status
= make_user_info_dc_netlogon_validation(tmp_ctx
,
869 ninfo
.identity_info
.account_name
.string
,
870 r
.in
.validation_level
,
872 true, /* This user was authenticated */
873 &netlogon_user_info_dc
);
875 torture_assert_ntstatus_ok(tctx
, status
, "make_user_info_dc_netlogon_validation failed");
877 torture_assert_str_equal(tctx
, netlogon_user_info_dc
->info
->account_name
== NULL
? "" : netlogon_user_info_dc
->info
->account_name
,
878 kinit_session_info
->info
->account_name
, "Account name differs for kinit-based PAC");
879 torture_assert_str_equal(tctx
,netlogon_user_info_dc
->info
->account_name
== NULL
? "" : netlogon_user_info_dc
->info
->account_name
,
880 s2u4self_session_info
->info
->account_name
, "Account name differs for S2U4Self");
881 torture_assert_str_equal(tctx
, netlogon_user_info_dc
->info
->full_name
== NULL
? "" : netlogon_user_info_dc
->info
->full_name
, kinit_session_info
->info
->full_name
, "Full name differs for kinit-based PAC");
882 torture_assert_str_equal(tctx
, netlogon_user_info_dc
->info
->full_name
== NULL
? "" : netlogon_user_info_dc
->info
->full_name
, s2u4self_session_info
->info
->full_name
, "Full name differs for S2U4Self");
883 torture_assert_int_equal(tctx
, netlogon_user_info_dc
->num_sids
, kinit_session_info
->torture
->num_dc_sids
, "Different numbers of domain groups for kinit-based PAC");
884 torture_assert_int_equal(tctx
, netlogon_user_info_dc
->num_sids
, s2u4self_session_info
->torture
->num_dc_sids
, "Different numbers of domain groups for S2U4Self");
886 builtin_domain
= dom_sid_parse_talloc(tmp_ctx
, SID_BUILTIN
);
888 for (i
= 0; i
< kinit_session_info
->torture
->num_dc_sids
; i
++) {
889 torture_assert(tctx
, dom_sid_equal(&netlogon_user_info_dc
->sids
[i
], &kinit_session_info
->torture
->dc_sids
[i
]), "Different domain groups for kinit-based PAC");
890 torture_assert(tctx
, dom_sid_equal(&netlogon_user_info_dc
->sids
[i
], &s2u4self_session_info
->torture
->dc_sids
[i
]), "Different domain groups for S2U4Self");
891 torture_assert(tctx
, !dom_sid_in_domain(builtin_domain
, &s2u4self_session_info
->torture
->dc_sids
[i
]), "Returned BUILTIN domain in groups for S2U4Self");
892 torture_assert(tctx
, !dom_sid_in_domain(builtin_domain
, &kinit_session_info
->torture
->dc_sids
[i
]), "Returned BUILTIN domain in groups kinit-based PAC");
893 torture_assert(tctx
, !dom_sid_in_domain(builtin_domain
, &netlogon_user_info_dc
->sids
[i
]), "Returned BUILTIN domian in groups from NETLOGON SamLogon reply");
899 static bool test_S2U4Self_bdc_arcfour(struct torture_context
*tctx
,
900 struct dcerpc_pipe
*p
,
901 struct cli_credentials
*credentials
)
903 return test_S2U4Self(tctx
, p
, credentials
, SEC_CHAN_BDC
,
904 TEST_MACHINE_NAME_S2U4SELF_BDC
,
905 NETLOGON_NEG_AUTH2_ADS_FLAGS
);
908 static bool test_S2U4Self_bdc_aes(struct torture_context
*tctx
,
909 struct dcerpc_pipe
*p
,
910 struct cli_credentials
*credentials
)
912 return test_S2U4Self(tctx
, p
, credentials
, SEC_CHAN_BDC
,
913 TEST_MACHINE_NAME_S2U4SELF_BDC
,
914 NETLOGON_NEG_AUTH2_ADS_FLAGS
| NETLOGON_NEG_SUPPORTS_AES
);
917 static bool test_S2U4Self_workstation_arcfour(struct torture_context
*tctx
,
918 struct dcerpc_pipe
*p
,
919 struct cli_credentials
*credentials
)
921 return test_S2U4Self(tctx
, p
, credentials
, SEC_CHAN_WKSTA
,
922 TEST_MACHINE_NAME_S2U4SELF_WKSTA
,
923 NETLOGON_NEG_AUTH2_ADS_FLAGS
);
926 static bool test_S2U4Self_workstation_aes(struct torture_context
*tctx
,
927 struct dcerpc_pipe
*p
,
928 struct cli_credentials
*credentials
)
930 return test_S2U4Self(tctx
, p
, credentials
, SEC_CHAN_WKSTA
,
931 TEST_MACHINE_NAME_S2U4SELF_WKSTA
,
932 NETLOGON_NEG_AUTH2_ADS_FLAGS
| NETLOGON_NEG_SUPPORTS_AES
);
936 struct torture_suite
*torture_rpc_remote_pac(TALLOC_CTX
*mem_ctx
)
938 struct torture_suite
*suite
= torture_suite_create(mem_ctx
, "pac");
939 struct torture_rpc_tcase
*tcase
;
941 tcase
= torture_suite_add_machine_bdc_rpc_iface_tcase(suite
, "netr-bdc-arcfour",
942 &ndr_table_netlogon
, TEST_MACHINE_NAME_BDC
);
943 torture_rpc_tcase_add_test_creds(tcase
, "verify-sig-arcfour", test_PACVerify_bdc_arcfour
);
945 tcase
= torture_suite_add_machine_bdc_rpc_iface_tcase(suite
, "netr-bdc-aes",
946 &ndr_table_netlogon
, TEST_MACHINE_NAME_BDC
);
947 torture_rpc_tcase_add_test_creds(tcase
, "verify-sig-aes", test_PACVerify_bdc_aes
);
949 tcase
= torture_suite_add_machine_workstation_rpc_iface_tcase(suite
, "netr-mem-arcfour",
950 &ndr_table_netlogon
, TEST_MACHINE_NAME_WKSTA
);
951 torture_rpc_tcase_add_test_creds(tcase
, "verify-sig-arcfour", test_PACVerify_workstation_arcfour
);
953 tcase
= torture_suite_add_machine_workstation_rpc_iface_tcase(suite
, "netr-mem-aes",
954 &ndr_table_netlogon
, TEST_MACHINE_NAME_WKSTA
);
955 torture_rpc_tcase_add_test_creds(tcase
, "verify-sig-aes", test_PACVerify_workstation_aes
);
957 tcase
= torture_suite_add_machine_workstation_rpc_iface_tcase(suite
, "netlogon-member-des",
958 &ndr_table_netlogon
, TEST_MACHINE_NAME_WKSTA_DES
);
959 torture_rpc_tcase_add_test_join(tcase
, "verify-sig", test_PACVerify_workstation_des
);
960 #ifdef SAMBA4_USES_HEIMDAL
961 tcase
= torture_suite_add_machine_bdc_rpc_iface_tcase(suite
, "netr-bdc-arcfour",
962 &ndr_table_netlogon
, TEST_MACHINE_NAME_S2U4SELF_BDC
);
963 torture_rpc_tcase_add_test_creds(tcase
, "s2u4self-arcfour", test_S2U4Self_bdc_arcfour
);
965 tcase
= torture_suite_add_machine_bdc_rpc_iface_tcase(suite
, "netr-bcd-aes",
966 &ndr_table_netlogon
, TEST_MACHINE_NAME_S2U4SELF_BDC
);
967 torture_rpc_tcase_add_test_creds(tcase
, "s2u4self-aes", test_S2U4Self_bdc_aes
);
969 tcase
= torture_suite_add_machine_workstation_rpc_iface_tcase(suite
, "netr-mem-arcfour",
970 &ndr_table_netlogon
, TEST_MACHINE_NAME_S2U4SELF_WKSTA
);
971 torture_rpc_tcase_add_test_creds(tcase
, "s2u4self-arcfour", test_S2U4Self_workstation_arcfour
);
973 tcase
= torture_suite_add_machine_workstation_rpc_iface_tcase(suite
, "netr-mem-aes",
974 &ndr_table_netlogon
, TEST_MACHINE_NAME_S2U4SELF_WKSTA
);
975 torture_rpc_tcase_add_test_creds(tcase
, "s2u4self-aes", test_S2U4Self_workstation_aes
);