2 Unix SMB/CIFS implementation.
4 test suite for netlogon PAC operations
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
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 "torture/torture.h"
24 #include "lib/events/events.h"
25 #include "auth/auth.h"
26 #include "auth/gensec/gensec.h"
27 #include "lib/cmdline/popt_common.h"
28 #include "torture/rpc/rpc.h"
29 #include "torture/rpc/netlogon.h"
30 #include "libcli/auth/libcli_auth.h"
31 #include "librpc/gen_ndr/ndr_netlogon_c.h"
32 #include "librpc/gen_ndr/ndr_krb5pac.h"
33 #include "param/param.h"
34 #include "lib/messaging/irpc.h"
35 #include "cluster/cluster.h"
37 #define TEST_MACHINE_NAME "torturepactest"
39 /* Check to see if we can pass the PAC across to the NETLOGON server for validation */
41 /* Also happens to be a really good one-step verfication of our Kerberos stack */
43 static bool test_PACVerify(struct torture_context
*tctx
,
44 struct dcerpc_pipe
*p
,
45 struct cli_credentials
*credentials
)
49 struct netr_LogonSamLogon r
;
51 union netr_LogonLevel logon
;
52 union netr_Validation validation
;
53 uint8_t authoritative
;
54 struct netr_Authenticator return_authenticator
;
56 struct netr_GenericInfo generic
;
57 struct netr_Authenticator auth
, auth2
;
60 struct creds_CredentialState
*creds
;
61 struct gensec_security
*gensec_client_context
;
62 struct gensec_security
*gensec_server_context
;
64 struct messaging_context
*msg_server_ctx
;
65 DATA_BLOB client_to_server
, server_to_client
, pac_wrapped
, payload
;
66 struct PAC_Validate pac_wrapped_struct
;
68 enum ndr_err_code ndr_err
;
70 struct auth_session_info
*session_info
;
74 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
76 torture_assert(tctx
, tmp_ctx
!= NULL
, "talloc_new() failed");
78 if (!test_SetupCredentials2(p
, tctx
, NETLOGON_NEG_AUTH2_ADS_FLAGS
,
79 credentials
, SEC_CHAN_BDC
,
84 status
= torture_temp_dir(tctx
, "PACVerify", &tmp_dir
);
85 torture_assert_ntstatus_ok(tctx
, status
, "torture_temp_dir failed");
87 msg_server_ctx
= messaging_init(tctx
,
90 lp_iconv_convenience(tctx
->lp_ctx
),
93 torture_assert(tctx
, msg_server_ctx
!= NULL
, "Failed to init messaging context");
95 status
= gensec_client_start(tctx
, &gensec_client_context
, tctx
->ev
,
96 lp_gensec_settings(tctx
, tctx
->lp_ctx
));
97 torture_assert_ntstatus_ok(tctx
, status
, "gensec_client_start (client) failed");
99 status
= gensec_set_target_hostname(gensec_client_context
, TEST_MACHINE_NAME
);
101 status
= gensec_set_credentials(gensec_client_context
, cmdline_credentials
);
102 torture_assert_ntstatus_ok(tctx
, status
, "gensec_set_credentials (client) failed");
104 status
= gensec_start_mech_by_sasl_name(gensec_client_context
, "GSSAPI");
105 torture_assert_ntstatus_ok(tctx
, status
, "gensec_start_mech_by_sasl_name (client) failed");
107 status
= gensec_server_start(tctx
, tctx
->ev
,
108 lp_gensec_settings(tctx
, tctx
->lp_ctx
),
109 msg_server_ctx
, &gensec_server_context
);
110 torture_assert_ntstatus_ok(tctx
, status
, "gensec_server_start (server) failed");
112 status
= gensec_set_credentials(gensec_server_context
, credentials
);
113 torture_assert_ntstatus_ok(tctx
, status
, "gensec_set_credentials (server) failed");
115 status
= gensec_start_mech_by_sasl_name(gensec_server_context
, "GSSAPI");
116 torture_assert_ntstatus_ok(tctx
, status
, "gensec_start_mech_by_sasl_name (server) failed");
118 server_to_client
= data_blob(NULL
, 0);
121 /* Do a client-server update dance */
122 status
= gensec_update(gensec_client_context
, tmp_ctx
, server_to_client
, &client_to_server
);
123 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {;
124 torture_assert_ntstatus_ok(tctx
, status
, "gensec_update (client) failed");
127 status
= gensec_update(gensec_server_context
, tmp_ctx
, client_to_server
, &server_to_client
);
128 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {;
129 torture_assert_ntstatus_ok(tctx
, status
, "gensec_update (server) failed");
132 if (NT_STATUS_IS_OK(status
)) {
137 /* Extract the PAC using Samba's code */
139 status
= gensec_session_info(gensec_server_context
, &session_info
);
140 torture_assert_ntstatus_ok(tctx
, status
, "gensec_session_info failed");
142 pac_wrapped_struct
.ChecksumLength
= session_info
->server_info
->pac_srv_sig
.signature
.length
;
143 pac_wrapped_struct
.SignatureType
= session_info
->server_info
->pac_kdc_sig
.type
;
144 pac_wrapped_struct
.SignatureLength
= session_info
->server_info
->pac_kdc_sig
.signature
.length
;
145 pac_wrapped_struct
.ChecksumAndSignature
= payload
146 = data_blob_talloc(tmp_ctx
, NULL
,
147 pac_wrapped_struct
.ChecksumLength
148 + pac_wrapped_struct
.SignatureLength
);
149 memcpy(&payload
.data
[0],
150 session_info
->server_info
->pac_srv_sig
.signature
.data
,
151 pac_wrapped_struct
.ChecksumLength
);
152 memcpy(&payload
.data
[pac_wrapped_struct
.ChecksumLength
],
153 session_info
->server_info
->pac_kdc_sig
.signature
.data
,
154 pac_wrapped_struct
.SignatureLength
);
156 ndr_err
= ndr_push_struct_blob(&pac_wrapped
, tmp_ctx
, lp_iconv_convenience(tctx
->lp_ctx
), &pac_wrapped_struct
,
157 (ndr_push_flags_fn_t
)ndr_push_PAC_Validate
);
158 torture_assert(tctx
, NDR_ERR_CODE_IS_SUCCESS(ndr_err
), "ndr_push_struct_blob of PACValidate structure failed");
160 torture_assert(tctx
, (creds
->negotiate_flags
& NETLOGON_NEG_ARCFOUR
), "not willing to even try a PACValidate without RC4 encryption");
161 creds_arcfour_crypt(creds
, pac_wrapped
.data
, pac_wrapped
.length
);
163 generic
.length
= pac_wrapped
.length
;
164 generic
.data
= pac_wrapped
.data
;
166 /* Validate it over the netlogon pipe */
168 generic
.identity_info
.parameter_control
= 0;
169 generic
.identity_info
.logon_id_high
= 0;
170 generic
.identity_info
.logon_id_low
= 0;
171 generic
.identity_info
.domain_name
.string
= session_info
->server_info
->domain_name
;
172 generic
.identity_info
.account_name
.string
= session_info
->server_info
->account_name
;
173 generic
.identity_info
.workstation
.string
= TEST_MACHINE_NAME
;
175 generic
.package_name
.string
= "Kerberos";
177 logon
.generic
= &generic
;
180 creds_client_authenticator(creds
, &auth
);
181 r
.in
.credential
= &auth
;
182 r
.in
.return_authenticator
= &auth2
;
184 r
.in
.logon_level
= NetlogonGenericInformation
;
185 r
.in
.server_name
= talloc_asprintf(tctx
, "\\\\%s", dcerpc_server_name(p
));
186 r
.in
.computer_name
= cli_credentials_get_workstation(credentials
);
187 r
.in
.validation_level
= NetlogonValidationGenericInfo2
;
188 r
.out
.validation
= &validation
;
189 r
.out
.authoritative
= &authoritative
;
190 r
.out
.return_authenticator
= &return_authenticator
;
192 status
= dcerpc_netr_LogonSamLogon(p
, tctx
, &r
);
194 torture_assert_ntstatus_ok(tctx
, status
, "LogonSamLogon failed");
196 /* This will break the signature nicely (even in the crypto wrapping), check we get a logon failure */
197 generic
.data
[generic
.length
-1]++;
199 logon
.generic
= &generic
;
202 creds_client_authenticator(creds
, &auth
);
203 r
.in
.credential
= &auth
;
204 r
.in
.return_authenticator
= &auth2
;
205 r
.in
.logon_level
= NetlogonGenericInformation
;
207 r
.in
.server_name
= talloc_asprintf(tctx
, "\\\\%s", dcerpc_server_name(p
));
208 r
.in
.computer_name
= cli_credentials_get_workstation(credentials
);
209 r
.in
.validation_level
= NetlogonValidationGenericInfo2
;
211 status
= dcerpc_netr_LogonSamLogon(p
, tctx
, &r
);
213 torture_assert_ntstatus_equal(tctx
, status
, NT_STATUS_LOGON_FAILURE
, "LogonSamLogon failed");
215 torture_assert(tctx
, creds_client_check(creds
, &r
.out
.return_authenticator
->cred
),
216 "Credential chaining failed");
218 /* This will break the parsing nicely (even in the crypto wrapping), check we get INVALID_PARAMETER */
221 logon
.generic
= &generic
;
224 creds_client_authenticator(creds
, &auth
);
225 r
.in
.credential
= &auth
;
226 r
.in
.return_authenticator
= &auth2
;
227 r
.in
.logon_level
= NetlogonGenericInformation
;
229 r
.in
.server_name
= talloc_asprintf(tctx
, "\\\\%s", dcerpc_server_name(p
));
230 r
.in
.computer_name
= cli_credentials_get_workstation(credentials
);
231 r
.in
.validation_level
= NetlogonValidationGenericInfo2
;
233 status
= dcerpc_netr_LogonSamLogon(p
, tctx
, &r
);
235 torture_assert_ntstatus_equal(tctx
, status
, NT_STATUS_INVALID_PARAMETER
, "LogonSamLogon failed");
237 torture_assert(tctx
, creds_client_check(creds
, &r
.out
.return_authenticator
->cred
),
238 "Credential chaining failed");
240 pac_wrapped_struct
.ChecksumLength
= session_info
->server_info
->pac_srv_sig
.signature
.length
;
241 pac_wrapped_struct
.SignatureType
= session_info
->server_info
->pac_kdc_sig
.type
;
243 /* Break the SignatureType */
244 pac_wrapped_struct
.SignatureType
++;
246 pac_wrapped_struct
.SignatureLength
= session_info
->server_info
->pac_kdc_sig
.signature
.length
;
247 pac_wrapped_struct
.ChecksumAndSignature
= payload
248 = data_blob_talloc(tmp_ctx
, NULL
,
249 pac_wrapped_struct
.ChecksumLength
250 + pac_wrapped_struct
.SignatureLength
);
251 memcpy(&payload
.data
[0],
252 session_info
->server_info
->pac_srv_sig
.signature
.data
,
253 pac_wrapped_struct
.ChecksumLength
);
254 memcpy(&payload
.data
[pac_wrapped_struct
.ChecksumLength
],
255 session_info
->server_info
->pac_kdc_sig
.signature
.data
,
256 pac_wrapped_struct
.SignatureLength
);
258 ndr_err
= ndr_push_struct_blob(&pac_wrapped
, tmp_ctx
, lp_iconv_convenience(tctx
->lp_ctx
), &pac_wrapped_struct
,
259 (ndr_push_flags_fn_t
)ndr_push_PAC_Validate
);
260 torture_assert(tctx
, NDR_ERR_CODE_IS_SUCCESS(ndr_err
), "ndr_push_struct_blob of PACValidate structure failed");
262 torture_assert(tctx
, (creds
->negotiate_flags
& NETLOGON_NEG_ARCFOUR
), "not willing to even try a PACValidate without RC4 encryption");
263 creds_arcfour_crypt(creds
, pac_wrapped
.data
, pac_wrapped
.length
);
265 generic
.length
= pac_wrapped
.length
;
266 generic
.data
= pac_wrapped
.data
;
268 logon
.generic
= &generic
;
271 creds_client_authenticator(creds
, &auth
);
272 r
.in
.credential
= &auth
;
273 r
.in
.return_authenticator
= &auth2
;
274 r
.in
.logon_level
= NetlogonGenericInformation
;
276 r
.in
.server_name
= talloc_asprintf(tctx
, "\\\\%s", dcerpc_server_name(p
));
277 r
.in
.computer_name
= cli_credentials_get_workstation(credentials
);
278 r
.in
.validation_level
= NetlogonValidationGenericInfo2
;
280 status
= dcerpc_netr_LogonSamLogon(p
, tctx
, &r
);
282 torture_assert_ntstatus_equal(tctx
, status
, NT_STATUS_LOGON_FAILURE
, "LogonSamLogon failed");
284 torture_assert(tctx
, creds_client_check(creds
, &r
.out
.return_authenticator
->cred
),
285 "Credential chaining failed");
287 pac_wrapped_struct
.ChecksumLength
= session_info
->server_info
->pac_srv_sig
.signature
.length
;
288 pac_wrapped_struct
.SignatureType
= session_info
->server_info
->pac_kdc_sig
.type
;
289 pac_wrapped_struct
.SignatureLength
= session_info
->server_info
->pac_kdc_sig
.signature
.length
;
291 pac_wrapped_struct
.ChecksumAndSignature
= payload
292 = data_blob_talloc(tmp_ctx
, NULL
,
293 pac_wrapped_struct
.ChecksumLength
294 + pac_wrapped_struct
.SignatureLength
);
295 memcpy(&payload
.data
[0],
296 session_info
->server_info
->pac_srv_sig
.signature
.data
,
297 pac_wrapped_struct
.ChecksumLength
);
298 memcpy(&payload
.data
[pac_wrapped_struct
.ChecksumLength
],
299 session_info
->server_info
->pac_kdc_sig
.signature
.data
,
300 pac_wrapped_struct
.SignatureLength
);
302 /* Break the signature length */
303 pac_wrapped_struct
.SignatureLength
++;
305 ndr_err
= ndr_push_struct_blob(&pac_wrapped
, tmp_ctx
, lp_iconv_convenience(tctx
->lp_ctx
), &pac_wrapped_struct
,
306 (ndr_push_flags_fn_t
)ndr_push_PAC_Validate
);
307 torture_assert(tctx
, NDR_ERR_CODE_IS_SUCCESS(ndr_err
), "ndr_push_struct_blob of PACValidate structure failed");
309 torture_assert(tctx
, (creds
->negotiate_flags
& NETLOGON_NEG_ARCFOUR
), "not willing to even try a PACValidate without RC4 encryption");
310 creds_arcfour_crypt(creds
, pac_wrapped
.data
, pac_wrapped
.length
);
312 generic
.length
= pac_wrapped
.length
;
313 generic
.data
= pac_wrapped
.data
;
315 logon
.generic
= &generic
;
318 creds_client_authenticator(creds
, &auth
);
319 r
.in
.credential
= &auth
;
320 r
.in
.return_authenticator
= &auth2
;
321 r
.in
.logon_level
= NetlogonGenericInformation
;
323 r
.in
.server_name
= talloc_asprintf(tctx
, "\\\\%s", dcerpc_server_name(p
));
324 r
.in
.computer_name
= cli_credentials_get_workstation(credentials
);
325 r
.in
.validation_level
= NetlogonValidationGenericInfo2
;
327 status
= dcerpc_netr_LogonSamLogon(p
, tctx
, &r
);
329 torture_assert_ntstatus_equal(tctx
, status
, NT_STATUS_INVALID_PARAMETER
, "LogonSamLogon failed");
331 torture_assert(tctx
, creds_client_check(creds
, &r
.out
.return_authenticator
->cred
),
332 "Credential chaining failed");
336 struct torture_suite
*torture_rpc_remote_pac(TALLOC_CTX
*mem_ctx
)
338 struct torture_suite
*suite
= torture_suite_create(mem_ctx
, "PAC");
339 struct torture_rpc_tcase
*tcase
;
341 tcase
= torture_suite_add_machine_rpc_iface_tcase(suite
, "netlogon",
342 &ndr_table_netlogon
, TEST_MACHINE_NAME
);
343 torture_rpc_tcase_add_test_creds(tcase
, "verify", test_PACVerify
);