selftest: add a test for PAC delegation-info blob in S4U2Proxy
[bbaumbach/samba-autobuild/.git] / source4 / torture / rpc / remote_pac.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    test suite for netlogon PAC operations
5
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2012
7
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.
12
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.
17
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/>.
20 */
21
22 #include "includes.h"
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"
38 #include <ldb.h>
39 #include "ldb_wrap.h"
40 #include "dsdb/samdb/samdb.h"
41
42 #define TEST_MACHINE_NAME_BDC "torturepacbdc"
43 #define TEST_MACHINE_NAME_WKSTA "torturepacwksta"
44 #define TEST_MACHINE_NAME_WKSTA_DES "torturepacwkdes"
45 #define TEST_MACHINE_NAME_S4U2SELF_BDC "tests4u2selfbdc"
46 #define TEST_MACHINE_NAME_S4U2SELF_WKSTA "tests4u2selfwk"
47 #define TEST_MACHINE_NAME_S4U2PROXY_WKSTA "tests4u2proxywk"
48
49 struct pac_data {
50         DATA_BLOB pac_blob;
51         struct PAC_SIGNATURE_DATA *pac_srv_sig;
52         struct PAC_SIGNATURE_DATA *pac_kdc_sig;
53 };
54
55 /* A helper function which avoids touching the local databases to
56  * generate the session info, as we just want to verify the PAC
57  * details, not the full local token */
58 static NTSTATUS test_generate_session_info_pac(struct auth4_context *auth_ctx,
59                                                TALLOC_CTX *mem_ctx,
60                                                struct smb_krb5_context *smb_krb5_context,
61                                                DATA_BLOB *pac_blob,
62                                                const char *principal_name,
63                                                const struct tsocket_address *remote_address,
64                                                uint32_t session_info_flags,
65                                                struct auth_session_info **session_info)
66 {
67         NTSTATUS nt_status;
68         struct auth_user_info_dc *user_info_dc;
69         TALLOC_CTX *tmp_ctx;
70         struct pac_data *pac_data;
71
72         tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
73         NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
74
75         auth_ctx->private_data = pac_data = talloc_zero(auth_ctx, struct pac_data);
76
77         pac_data->pac_blob = data_blob_dup_talloc(pac_data, *pac_blob);
78         if (pac_data->pac_blob.length != pac_blob->length) {
79                 talloc_free(tmp_ctx);
80                 return NT_STATUS_NO_MEMORY;
81         }
82
83         pac_data->pac_srv_sig = talloc(tmp_ctx, struct PAC_SIGNATURE_DATA);
84         if (!pac_data->pac_srv_sig) {
85                 talloc_free(tmp_ctx);
86                 return NT_STATUS_NO_MEMORY;
87         }
88         pac_data->pac_kdc_sig = talloc(tmp_ctx, struct PAC_SIGNATURE_DATA);
89         if (!pac_data->pac_kdc_sig) {
90                 talloc_free(tmp_ctx);
91                 return NT_STATUS_NO_MEMORY;
92         }
93
94         nt_status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
95                                                       *pac_blob,
96                                                       smb_krb5_context->krb5_context,
97                                                       &user_info_dc,
98                                                       pac_data->pac_srv_sig,
99                                                       pac_data->pac_kdc_sig);
100         if (!NT_STATUS_IS_OK(nt_status)) {
101                 talloc_free(tmp_ctx);
102                 return nt_status;
103         }
104
105         talloc_steal(pac_data, pac_data->pac_srv_sig);
106         talloc_steal(pac_data, pac_data->pac_kdc_sig);
107
108         if (user_info_dc->info->authenticated) {
109                 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
110         }
111
112         session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
113         nt_status = auth_generate_session_info(mem_ctx,
114                                                NULL,
115                                                NULL,
116                                                user_info_dc, session_info_flags,
117                                                session_info);
118         if (!NT_STATUS_IS_OK(nt_status)) {
119                 talloc_free(tmp_ctx);
120                 return nt_status;
121         }
122
123         talloc_free(tmp_ctx);
124         return nt_status;
125 }
126
127 /* Check to see if we can pass the PAC across to the NETLOGON server for validation */
128
129 static const struct PAC_BUFFER *get_pac_buffer(const struct PAC_DATA *pac_data,
130                                                enum PAC_TYPE type)
131 {
132         const struct PAC_BUFFER *pac_buf = NULL;
133         uint32_t i;
134
135         for (i = 0; i < pac_data->num_buffers; ++i) {
136                 pac_buf = &pac_data->buffers[i];
137
138                 if (pac_buf->type == type) {
139                         break;
140                 }
141         }
142
143         return pac_buf;
144 }
145
146 /* Also happens to be a really good one-step verfication of our Kerberos stack */
147
148 static bool netlogon_validate_pac(struct torture_context *tctx,
149                                   struct dcerpc_pipe *p1,
150                                   struct cli_credentials *server_creds,
151                                   enum netr_SchannelType secure_channel_type,
152                                   const char *test_machine_name,
153                                   uint32_t negotiate_flags,
154                                   struct pac_data *pac_data,
155                                   struct auth_session_info *session_info);
156
157 static bool test_PACVerify(struct torture_context *tctx,
158                            struct dcerpc_pipe *p,
159                            struct cli_credentials *credentials,
160                            enum netr_SchannelType secure_channel_type,
161                            const char *test_machine_name,
162                            uint32_t negotiate_flags)
163 {
164         NTSTATUS status;
165         bool ok;
166         bool pkinit_in_use = torture_setting_bool(tctx, "pkinit_in_use", false);
167         bool expect_pac_upn_dns_info = torture_setting_bool(tctx, "expect_pac_upn_dns_info", true);
168         size_t num_pac_buffers;
169         struct gensec_security *gensec_client_context;
170         struct gensec_security *gensec_server_context;
171         struct cli_credentials *client_creds;
172         struct cli_credentials *server_creds;
173
174         DATA_BLOB client_to_server, server_to_client;
175         struct PAC_DATA pac_data_struct;
176         enum ndr_err_code ndr_err;
177
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;
182
183         TALLOC_CTX *tmp_ctx = talloc_new(tctx);
184         torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed");
185
186         torture_comment(tctx,
187                 "Testing PAC Verify (secure_channel_type: %d, machine: %s, negotiate_flags: 0x%08x\n",
188                 secure_channel_type, test_machine_name, negotiate_flags);
189
190         /*
191          * Copy the credentials in order to use a different MEMORY krb5 ccache
192          * for each client/server setup. The MEMORY cache identifier is a
193          * pointer to the creds container. If we copy it the pointer changes and
194          * we will get a new clean memory cache.
195          */
196         client_creds = cli_credentials_shallow_copy(tmp_ctx,
197                                             popt_get_cmdline_credentials());
198         torture_assert(tctx, client_creds, "Failed to copy of credentials");
199         if (!pkinit_in_use) {
200                 /* Invalidate the gss creds container to allocate a new MEMORY ccache */
201                 cli_credentials_invalidate_ccache(client_creds, CRED_SPECIFIED);
202         }
203
204         server_creds = cli_credentials_shallow_copy(tmp_ctx,
205                                                     credentials);
206         torture_assert(tctx, server_creds, "Failed to copy of credentials");
207
208         auth_context = talloc_zero(tmp_ctx, struct auth4_context);
209         torture_assert(tctx, auth_context != NULL, "talloc_new() failed");
210
211         auth_context->generate_session_info_pac = test_generate_session_info_pac;
212
213         status = gensec_client_start(tctx, &gensec_client_context,
214                                      lpcfg_gensec_settings(tctx, tctx->lp_ctx));
215         torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");
216
217         status = gensec_set_target_hostname(gensec_client_context, test_machine_name);
218
219         status = gensec_set_credentials(gensec_client_context, client_creds);
220         torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
221
222         status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI");
223         torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");
224
225         status = gensec_server_start(tctx,
226                                      lpcfg_gensec_settings(tctx, tctx->lp_ctx),
227                                      auth_context, &gensec_server_context);
228         torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
229
230         status = gensec_set_credentials(gensec_server_context, server_creds);
231         torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
232
233         status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI");
234         torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (server) failed");
235
236         server_to_client = data_blob(NULL, 0);
237
238         do {
239                 /* Do a client-server update dance */
240                 status = gensec_update(gensec_client_context, tmp_ctx, server_to_client, &client_to_server);
241                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
242                         torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
243                 }
244
245                 status = gensec_update(gensec_server_context, tmp_ctx, client_to_server, &server_to_client);
246                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
247                         torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed");
248                 }
249
250                 if (NT_STATUS_IS_OK(status)) {
251                         break;
252                 }
253         } while (1);
254
255         /* Extract the PAC using Samba's code */
256
257         status = gensec_session_info(gensec_server_context, gensec_server_context, &session_info);
258         torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");
259
260         pac_data = talloc_get_type(auth_context->private_data, struct pac_data);
261
262         torture_assert(tctx, pac_data != NULL, "gensec_update failed to fill in pac_data in auth_context");
263         torture_assert(tctx, pac_data->pac_srv_sig != NULL, "pac_srv_sig not present");
264         torture_assert(tctx, pac_data->pac_kdc_sig != NULL, "pac_kdc_sig not present");
265
266         ndr_err = ndr_pull_struct_blob(&pac_data->pac_blob, tmp_ctx, &pac_data_struct,
267                                        (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
268         torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_pull_struct_blob of PAC_DATA structure failed");
269
270         num_pac_buffers = 4;
271         if (expect_pac_upn_dns_info) {
272                 num_pac_buffers += 1;
273         }
274         if (pkinit_in_use) {
275                 num_pac_buffers += 1;
276         }
277
278         torture_assert_int_equal(tctx, pac_data_struct.version, 0, "version");
279         torture_assert_int_equal(tctx, pac_data_struct.num_buffers, num_pac_buffers, "num_buffers");
280
281         pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_LOGON_INFO);
282         torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_LOGON_INFO");
283         torture_assert(tctx,
284                        pac_buf->info != NULL,
285                        "PAC_TYPE_LOGON_INFO info");
286
287         if (pkinit_in_use) {
288                 pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_CREDENTIAL_INFO);
289                 torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_CREDENTIAL_INFO");
290                 torture_assert(tctx,
291                                pac_buf->info != NULL,
292                                "PAC_TYPE_CREDENTIAL_INFO info");
293         }
294
295         pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_LOGON_NAME);
296         torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_LOGON_NAME");
297         torture_assert(tctx,
298                        pac_buf->info != NULL,
299                        "PAC_TYPE_LOGON_NAME info");
300
301         if (expect_pac_upn_dns_info) {
302                 pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_UPN_DNS_INFO);
303                 torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_UPN_DNS_INFO");
304                 torture_assert(tctx,
305                                pac_buf->info != NULL,
306                                "PAC_TYPE_UPN_DNS_INFO info");
307         }
308
309         pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_SRV_CHECKSUM);
310         torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_SRV_CHECKSUM");
311         torture_assert(tctx,
312                        pac_buf->info != NULL,
313                        "PAC_TYPE_SRV_CHECKSUM info");
314
315         pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_KDC_CHECKSUM);
316         torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_KDC_CHECKSUM");
317         torture_assert(tctx,
318                        pac_buf->info != NULL,
319                        "PAC_TYPE_KDC_CHECKSUM info");
320
321         ok = netlogon_validate_pac(tctx, p, server_creds, secure_channel_type, test_machine_name,
322                                    negotiate_flags, pac_data, session_info);
323
324         talloc_free(tmp_ctx);
325
326         return ok;
327 }
328
329 static bool netlogon_validate_pac(struct torture_context *tctx,
330                                   struct dcerpc_pipe *p1,
331                                   struct cli_credentials *server_creds,
332                                   enum netr_SchannelType secure_channel_type,
333                                   const char *test_machine_name,
334                                   uint32_t negotiate_flags,
335                                   struct pac_data *pac_data,
336                                   struct auth_session_info *session_info)
337 {
338         struct PAC_Validate pac_wrapped_struct;
339         struct netlogon_creds_CredentialState *creds = NULL;
340         struct netr_Authenticator return_authenticator;
341         struct netr_Authenticator auth, auth2;
342         struct netr_GenericInfo generic;
343         struct netr_LogonSamLogon r;
344         union netr_Validation validation;
345         union netr_LogonLevel logon;
346         uint8_t authoritative;
347         struct dcerpc_pipe *p = NULL;
348         struct dcerpc_binding_handle *b = NULL;
349         enum ndr_err_code ndr_err;
350         DATA_BLOB payload, pac_wrapped;
351
352         if (!test_SetupCredentials2(p1, tctx, negotiate_flags,
353                                     server_creds, secure_channel_type,
354                                     &creds)) {
355                 return false;
356         }
357         if (!test_SetupCredentialsPipe(p1, tctx, server_creds, creds,
358                                        DCERPC_SIGN | DCERPC_SEAL, &p)) {
359                 return false;
360         }
361         b = p->binding_handle;
362
363         pac_wrapped_struct.ChecksumLength = pac_data->pac_srv_sig->signature.length;
364         pac_wrapped_struct.SignatureType = pac_data->pac_kdc_sig->type;
365         pac_wrapped_struct.SignatureLength = pac_data->pac_kdc_sig->signature.length;
366         pac_wrapped_struct.ChecksumAndSignature = payload
367                 = data_blob_talloc(tctx, NULL,
368                                    pac_wrapped_struct.ChecksumLength
369                                    + pac_wrapped_struct.SignatureLength);
370         memcpy(&payload.data[0],
371                pac_data->pac_srv_sig->signature.data,
372                pac_wrapped_struct.ChecksumLength);
373         memcpy(&payload.data[pac_wrapped_struct.ChecksumLength],
374                pac_data->pac_kdc_sig->signature.data,
375                pac_wrapped_struct.SignatureLength);
376
377         ndr_err = ndr_push_struct_blob(&pac_wrapped, tctx, &pac_wrapped_struct,
378                                        (ndr_push_flags_fn_t)ndr_push_PAC_Validate);
379         torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed");
380
381         torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption");
382         if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
383                 netlogon_creds_aes_encrypt(creds, pac_wrapped.data, pac_wrapped.length);
384         } else {
385                 netlogon_creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length);
386         }
387
388         generic.length = pac_wrapped.length;
389         generic.data = pac_wrapped.data;
390
391         /* Validate it over the netlogon pipe */
392
393         generic.identity_info.parameter_control = 0;
394         generic.identity_info.logon_id = 0;
395         generic.identity_info.domain_name.string = session_info->info->domain_name;
396         generic.identity_info.account_name.string = session_info->info->account_name;
397         generic.identity_info.workstation.string = test_machine_name;
398
399         generic.package_name.string = "Kerberos";
400
401         logon.generic = &generic;
402
403         ZERO_STRUCT(auth2);
404         netlogon_creds_client_authenticator(creds, &auth);
405         r.in.credential = &auth;
406         r.in.return_authenticator = &auth2;
407         r.in.logon = &logon;
408         r.in.logon_level = NetlogonGenericInformation;
409         r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
410         r.in.computer_name = cli_credentials_get_workstation(server_creds);
411         r.in.validation_level = NetlogonValidationGenericInfo2;
412         r.out.validation = &validation;
413         r.out.authoritative = &authoritative;
414         r.out.return_authenticator = &return_authenticator;
415
416         torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
417                 "LogonSamLogon failed");
418
419         torture_assert_ntstatus_ok(tctx, r.out.result, "LogonSamLogon failed");
420
421         /* This will break the signature nicely (even in the crypto wrapping), check we get a logon failure */
422         generic.data[generic.length-1]++;
423
424         logon.generic = &generic;
425
426         ZERO_STRUCT(auth2);
427         netlogon_creds_client_authenticator(creds, &auth);
428         r.in.credential = &auth;
429         r.in.return_authenticator = &auth2;
430         r.in.logon_level = NetlogonGenericInformation;
431         r.in.logon = &logon;
432         r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
433         r.in.computer_name = cli_credentials_get_workstation(server_creds);
434         r.in.validation_level = NetlogonValidationGenericInfo2;
435
436         torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
437                 "LogonSamLogon failed");
438
439         torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_LOGON_FAILURE, "LogonSamLogon failed");
440
441         torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred),
442                        "Credential chaining failed");
443
444         /* This will break the parsing nicely (even in the crypto wrapping), check we get INVALID_PARAMETER */
445         generic.length--;
446
447         logon.generic = &generic;
448
449         ZERO_STRUCT(auth2);
450         netlogon_creds_client_authenticator(creds, &auth);
451         r.in.credential = &auth;
452         r.in.return_authenticator = &auth2;
453         r.in.logon_level = NetlogonGenericInformation;
454         r.in.logon = &logon;
455         r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
456         r.in.computer_name = cli_credentials_get_workstation(server_creds);
457         r.in.validation_level = NetlogonValidationGenericInfo2;
458
459         torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
460                 "LogonSamLogon failed");
461
462         torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_INVALID_PARAMETER, "LogonSamLogon failed");
463
464         torture_assert(tctx, netlogon_creds_client_check(creds,
465                                                          &r.out.return_authenticator->cred),
466                        "Credential chaining failed");
467
468         pac_wrapped_struct.ChecksumLength = pac_data->pac_srv_sig->signature.length;
469         pac_wrapped_struct.SignatureType = pac_data->pac_kdc_sig->type;
470
471         /* Break the SignatureType */
472         pac_wrapped_struct.SignatureType++;
473
474         pac_wrapped_struct.SignatureLength = pac_data->pac_kdc_sig->signature.length;
475         pac_wrapped_struct.ChecksumAndSignature = payload
476                 = data_blob_talloc(tctx, NULL,
477                                    pac_wrapped_struct.ChecksumLength
478                                    + pac_wrapped_struct.SignatureLength);
479         memcpy(&payload.data[0],
480                pac_data->pac_srv_sig->signature.data,
481                pac_wrapped_struct.ChecksumLength);
482         memcpy(&payload.data[pac_wrapped_struct.ChecksumLength],
483                pac_data->pac_kdc_sig->signature.data,
484                pac_wrapped_struct.SignatureLength);
485
486         ndr_err = ndr_push_struct_blob(&pac_wrapped, tctx, &pac_wrapped_struct,
487                                        (ndr_push_flags_fn_t)ndr_push_PAC_Validate);
488         torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed");
489
490         torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption");
491         if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
492                 netlogon_creds_aes_encrypt(creds, pac_wrapped.data, pac_wrapped.length);
493         } else {
494                 netlogon_creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length);
495         }
496
497         generic.length = pac_wrapped.length;
498         generic.data = pac_wrapped.data;
499
500         logon.generic = &generic;
501
502         ZERO_STRUCT(auth2);
503         netlogon_creds_client_authenticator(creds, &auth);
504         r.in.credential = &auth;
505         r.in.return_authenticator = &auth2;
506         r.in.logon_level = NetlogonGenericInformation;
507         r.in.logon = &logon;
508         r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
509         r.in.computer_name = cli_credentials_get_workstation(server_creds);
510         r.in.validation_level = NetlogonValidationGenericInfo2;
511
512         torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
513                 "LogonSamLogon failed");
514
515         torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_LOGON_FAILURE, "LogonSamLogon failed");
516
517         torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred),
518                        "Credential chaining failed");
519
520         pac_wrapped_struct.ChecksumLength = pac_data->pac_srv_sig->signature.length;
521         pac_wrapped_struct.SignatureType = pac_data->pac_kdc_sig->type;
522         pac_wrapped_struct.SignatureLength = pac_data->pac_kdc_sig->signature.length;
523
524         pac_wrapped_struct.ChecksumAndSignature = payload
525                 = data_blob_talloc(tctx, NULL,
526                                    pac_wrapped_struct.ChecksumLength
527                                    + pac_wrapped_struct.SignatureLength);
528         memcpy(&payload.data[0],
529                pac_data->pac_srv_sig->signature.data,
530                pac_wrapped_struct.ChecksumLength);
531         memcpy(&payload.data[pac_wrapped_struct.ChecksumLength],
532                pac_data->pac_kdc_sig->signature.data,
533                pac_wrapped_struct.SignatureLength);
534
535         /* Break the signature length */
536         pac_wrapped_struct.SignatureLength++;
537
538         ndr_err = ndr_push_struct_blob(&pac_wrapped, tctx, &pac_wrapped_struct,
539                                        (ndr_push_flags_fn_t)ndr_push_PAC_Validate);
540         torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed");
541
542         torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption");
543         if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
544                 netlogon_creds_aes_encrypt(creds, pac_wrapped.data, pac_wrapped.length);
545         } else {
546                 netlogon_creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length);
547         }
548
549         generic.length = pac_wrapped.length;
550         generic.data = pac_wrapped.data;
551
552         logon.generic = &generic;
553
554         ZERO_STRUCT(auth2);
555         netlogon_creds_client_authenticator(creds, &auth);
556         r.in.credential = &auth;
557         r.in.return_authenticator = &auth2;
558         r.in.logon_level = NetlogonGenericInformation;
559         r.in.logon = &logon;
560         r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
561         r.in.computer_name = cli_credentials_get_workstation(server_creds);
562         r.in.validation_level = NetlogonValidationGenericInfo2;
563
564         torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
565                 "LogonSamLogon failed");
566
567         torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_INVALID_PARAMETER, "LogonSamLogon failed");
568
569         torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred),
570                        "Credential chaining failed");
571
572         return true;
573 }
574
575 static bool test_PACVerify_bdc_arcfour(struct torture_context *tctx,
576                                        struct dcerpc_pipe *p,
577                                        struct cli_credentials *credentials)
578 {
579         return test_PACVerify(tctx, p, credentials, SEC_CHAN_BDC,
580                               TEST_MACHINE_NAME_BDC,
581                               NETLOGON_NEG_AUTH2_ADS_FLAGS);
582 }
583
584 static bool test_PACVerify_bdc_aes(struct torture_context *tctx,
585                                    struct dcerpc_pipe *p,
586                                    struct cli_credentials *credentials)
587 {
588         return test_PACVerify(tctx, p, credentials, SEC_CHAN_BDC,
589                               TEST_MACHINE_NAME_BDC,
590                               NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES);
591 }
592
593 static bool test_PACVerify_workstation_arcfour(struct torture_context *tctx,
594                                                struct dcerpc_pipe *p,
595                                                struct cli_credentials *credentials)
596 {
597         return test_PACVerify(tctx, p, credentials, SEC_CHAN_WKSTA,
598                               TEST_MACHINE_NAME_WKSTA,
599                               NETLOGON_NEG_AUTH2_ADS_FLAGS);
600 }
601
602 static bool test_PACVerify_workstation_aes(struct torture_context *tctx,
603                                            struct dcerpc_pipe *p,
604                                            struct cli_credentials *credentials)
605 {
606         return test_PACVerify(tctx, p, credentials, SEC_CHAN_WKSTA,
607                               TEST_MACHINE_NAME_WKSTA,
608                               NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES);
609 }
610
611 static bool test_PACVerify_workstation_des(struct torture_context *tctx,
612                                            struct dcerpc_pipe *p, struct cli_credentials *credentials, struct test_join *join_ctx)
613 {
614         struct samr_SetUserInfo r;
615         union samr_UserInfo user_info;
616         struct dcerpc_pipe *samr_pipe = torture_join_samr_pipe(join_ctx);
617         struct smb_krb5_context *smb_krb5_context;
618         krb5_error_code ret;
619
620         ret = cli_credentials_get_krb5_context(popt_get_cmdline_credentials(),
621                         tctx->lp_ctx, &smb_krb5_context);
622         torture_assert_int_equal(tctx, ret, 0, "cli_credentials_get_krb5_context() failed");
623
624         if (smb_krb5_get_allowed_weak_crypto(smb_krb5_context->krb5_context) == FALSE) {
625                 torture_skip(tctx, "Cannot test DES without [libdefaults] allow_weak_crypto = yes");
626         }
627
628         /* Mark this workstation with DES-only */
629         user_info.info16.acct_flags = ACB_USE_DES_KEY_ONLY | ACB_WSTRUST;
630         r.in.user_handle = torture_join_samr_user_policy(join_ctx);
631         r.in.level = 16;
632         r.in.info = &user_info;
633
634         torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(samr_pipe->binding_handle, tctx, &r),
635                 "failed to set DES info account flags");
636         torture_assert_ntstatus_ok(tctx, r.out.result,
637                 "failed to set DES into account flags");
638
639         return test_PACVerify(tctx, p, credentials, SEC_CHAN_WKSTA,
640                               TEST_MACHINE_NAME_WKSTA_DES,
641                               NETLOGON_NEG_AUTH2_ADS_FLAGS);
642 }
643
644 #ifdef SAMBA4_USES_HEIMDAL
645 static NTSTATUS check_primary_group_in_validation(TALLOC_CTX *mem_ctx,
646                                                   uint16_t validation_level,
647                                                   const union netr_Validation *validation)
648 {
649         const struct netr_SamBaseInfo *base = NULL;
650         int i;
651         switch (validation_level) {
652         case 2:
653                 if (!validation || !validation->sam2) {
654                         return NT_STATUS_INVALID_PARAMETER;
655                 }
656                 base = &validation->sam2->base;
657                 break;
658         case 3:
659                 if (!validation || !validation->sam3) {
660                         return NT_STATUS_INVALID_PARAMETER;
661                 }
662                 base = &validation->sam3->base;
663                 break;
664         case 6:
665                 if (!validation || !validation->sam6) {
666                         return NT_STATUS_INVALID_PARAMETER;
667                 }
668                 base = &validation->sam6->base;
669                 break;
670         default:
671                 return NT_STATUS_INVALID_LEVEL;
672         }
673
674         for (i = 0; i < base->groups.count; i++) {
675                 if (base->groups.rids[i].rid == base->primary_gid) {
676                         return NT_STATUS_OK;
677                 }
678         }
679         return NT_STATUS_INVALID_PARAMETER;
680 }
681
682 /* Check various ways to get the PAC, in particular check the group membership and
683  * other details between the PAC from a normal kinit, S4U2Self and a SamLogon */
684 static bool test_S4U2Self(struct torture_context *tctx,
685                           struct dcerpc_pipe *p1,
686                           struct cli_credentials *credentials,
687                           enum netr_SchannelType secure_channel_type,
688                           const char *test_machine_name,
689                           uint32_t negotiate_flags)
690 {
691         NTSTATUS status;
692         struct dcerpc_pipe *p = NULL;
693         struct dcerpc_binding_handle *b = NULL;
694
695         struct netr_LogonSamLogon r;
696
697         union netr_LogonLevel logon;
698         union netr_Validation validation;
699         uint8_t authoritative;
700
701         struct netr_Authenticator auth, auth2;
702
703         DATA_BLOB client_to_server, server_to_client;
704
705         struct netlogon_creds_CredentialState *creds;
706         struct gensec_security *gensec_client_context;
707         struct gensec_security *gensec_server_context;
708         struct cli_credentials *client_creds;
709         struct cli_credentials *server_creds;
710
711         struct auth4_context *auth_context;
712         struct auth_session_info *kinit_session_info;
713         struct auth_session_info *s4u2self_session_info;
714         struct auth_user_info_dc *netlogon_user_info_dc;
715
716         struct netr_NetworkInfo ninfo;
717         DATA_BLOB names_blob, chal, lm_resp, nt_resp;
718         size_t i;
719         int flags = CLI_CRED_NTLMv2_AUTH;
720
721         struct dom_sid *builtin_domain;
722
723         TALLOC_CTX *tmp_ctx = talloc_new(tctx);
724
725         torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed");
726
727         torture_comment(tctx,
728                 "Testing S4U2SELF (secure_channel_type: %d, machine: %s, negotiate_flags: 0x%08x\n",
729                 secure_channel_type, test_machine_name, negotiate_flags);
730
731         /*
732          * Copy the credentials in order to use a different MEMORY krb5 ccache
733          * for each client/server setup. The MEMORY cache identifier is a
734          * pointer to the creds container. If we copy it the pointer changes and
735          * we will get a new clean memory cache.
736          */
737         client_creds = cli_credentials_shallow_copy(tmp_ctx,
738                                             popt_get_cmdline_credentials());
739         torture_assert(tctx, client_creds, "Failed to copy of credentials");
740
741         server_creds = cli_credentials_shallow_copy(tmp_ctx,
742                                                     credentials);
743         torture_assert(tctx, server_creds, "Failed to copy of credentials");
744
745         if (!test_SetupCredentials2(p1, tctx, negotiate_flags,
746                                     server_creds, secure_channel_type,
747                                     &creds)) {
748                 return false;
749         }
750         if (!test_SetupCredentialsPipe(p1, tctx, server_creds, creds,
751                                        DCERPC_SIGN | DCERPC_SEAL, &p)) {
752                 return false;
753         }
754         b = p->binding_handle;
755
756         auth_context = talloc_zero(tmp_ctx, struct auth4_context);
757         torture_assert(tctx, auth_context != NULL, "talloc_new() failed");
758
759         auth_context->generate_session_info_pac = test_generate_session_info_pac;
760
761         /* First, do a normal Kerberos connection */
762
763         status = gensec_client_start(tctx, &gensec_client_context,
764                                      lpcfg_gensec_settings(tctx, tctx->lp_ctx));
765         torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");
766
767         status = gensec_set_target_hostname(gensec_client_context, test_machine_name);
768
769         status = gensec_set_credentials(gensec_client_context, client_creds);
770         torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
771
772         status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI");
773         torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");
774
775         status = gensec_server_start(tctx,
776                                      lpcfg_gensec_settings(tctx, tctx->lp_ctx),
777                                      auth_context, &gensec_server_context);
778         torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
779
780         status = gensec_set_credentials(gensec_server_context, server_creds);
781         torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
782
783         status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI");
784         torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (server) failed");
785
786         server_to_client = data_blob(NULL, 0);
787
788         do {
789                 /* Do a client-server update dance */
790                 status = gensec_update(gensec_client_context, tmp_ctx, server_to_client, &client_to_server);
791                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
792                         torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
793                 }
794
795                 status = gensec_update(gensec_server_context, tmp_ctx, client_to_server, &server_to_client);
796                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
797                         torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed");
798                 }
799
800                 if (NT_STATUS_IS_OK(status)) {
801                         break;
802                 }
803         } while (1);
804
805         /* Extract the PAC using Samba's code */
806
807         status = gensec_session_info(gensec_server_context, gensec_server_context, &kinit_session_info);
808         torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");
809
810
811         /* Now do the dance with S4U2Self */
812
813         /* Wipe out any existing ccache */
814         cli_credentials_invalidate_ccache(client_creds, CRED_SPECIFIED);
815         cli_credentials_invalidate_ccache(server_creds, CRED_SPECIFIED);
816         cli_credentials_set_impersonate_principal(server_creds,
817                         cli_credentials_get_principal(client_creds, tmp_ctx),
818                         talloc_asprintf(tmp_ctx, "host/%s", test_machine_name));
819
820         status = gensec_client_start(tctx, &gensec_client_context,
821                                      lpcfg_gensec_settings(tctx, tctx->lp_ctx));
822         torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");
823
824         status = gensec_set_target_hostname(gensec_client_context, test_machine_name);
825
826         /* We now set the same credentials on both client and server contexts */
827         status = gensec_set_credentials(gensec_client_context, server_creds);
828         torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
829
830         status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI");
831         torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");
832
833         status = gensec_server_start(tctx,
834                                      lpcfg_gensec_settings(tctx, tctx->lp_ctx),
835                                      auth_context, &gensec_server_context);
836         torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
837
838         status = gensec_set_credentials(gensec_server_context, server_creds);
839         torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
840
841         status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI");
842         torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (server) failed");
843
844         server_to_client = data_blob(NULL, 0);
845
846         do {
847                 /* Do a client-server update dance */
848                 status = gensec_update(gensec_client_context, tmp_ctx, server_to_client, &client_to_server);
849                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
850                         torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
851                 }
852
853                 status = gensec_update(gensec_server_context, tmp_ctx, client_to_server, &server_to_client);
854                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
855                         torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed");
856                 }
857
858                 if (NT_STATUS_IS_OK(status)) {
859                         break;
860                 }
861         } while (1);
862
863         /* Don't pollute the remaining tests with the changed credentials */
864         cli_credentials_invalidate_ccache(server_creds, CRED_SPECIFIED);
865         cli_credentials_set_target_service(server_creds, NULL);
866         cli_credentials_set_impersonate_principal(server_creds, NULL, NULL);
867
868         /* Extract the PAC using Samba's code */
869
870         status = gensec_session_info(gensec_server_context, gensec_server_context, &s4u2self_session_info);
871         torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");
872
873         cli_credentials_get_ntlm_username_domain(client_creds, tctx,
874                                                  &ninfo.identity_info.account_name.string,
875                                                  &ninfo.identity_info.domain_name.string);
876
877         /* Now try with SamLogon */
878         generate_random_buffer(ninfo.challenge,
879                                sizeof(ninfo.challenge));
880         chal = data_blob_const(ninfo.challenge,
881                                sizeof(ninfo.challenge));
882
883         names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(server_creds),
884                                                 cli_credentials_get_domain(server_creds));
885
886         status = cli_credentials_get_ntlm_response(client_creds, tctx,
887                                                    &flags,
888                                                    chal,
889                                                    NULL, /* server_timestamp */
890                                                    names_blob,
891                                                    &lm_resp, &nt_resp,
892                                                    NULL, NULL);
893         torture_assert_ntstatus_ok(tctx, status, "cli_credentials_get_ntlm_response failed");
894
895         ninfo.lm.data = lm_resp.data;
896         ninfo.lm.length = lm_resp.length;
897
898         ninfo.nt.data = nt_resp.data;
899         ninfo.nt.length = nt_resp.length;
900
901         ninfo.identity_info.parameter_control = 0;
902         ninfo.identity_info.logon_id = 0;
903         ninfo.identity_info.workstation.string = cli_credentials_get_workstation(server_creds);
904
905         logon.network = &ninfo;
906
907         r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
908         r.in.computer_name = cli_credentials_get_workstation(server_creds);
909         r.in.credential = &auth;
910         r.in.return_authenticator = &auth2;
911         r.in.logon_level = NetlogonNetworkInformation;
912         r.in.logon = &logon;
913         r.out.validation = &validation;
914         r.out.authoritative = &authoritative;
915
916         ZERO_STRUCT(auth2);
917         netlogon_creds_client_authenticator(creds, &auth);
918
919         r.in.validation_level = 3;
920
921         status = dcerpc_netr_LogonSamLogon_r(b, tctx, &r);
922         torture_assert_ntstatus_ok(tctx, status, "LogonSamLogon failed");
923
924         torture_assert(tctx, netlogon_creds_client_check(creds,
925                                                          &r.out.return_authenticator->cred),
926                        "Credential chaining failed");
927
928         torture_assert_ntstatus_ok(tctx, r.out.result, "LogonSamLogon failed");
929
930         status = make_user_info_dc_netlogon_validation(tmp_ctx,
931                                                       ninfo.identity_info.account_name.string,
932                                                       r.in.validation_level,
933                                                       r.out.validation,
934                                                           true, /* This user was authenticated */
935                                                       &netlogon_user_info_dc);
936
937         torture_assert_ntstatus_ok(tctx, status, "make_user_info_dc_netlogon_validation failed");
938
939         /* Check that the primary group is present in validation's RID array */
940         status = check_primary_group_in_validation(tmp_ctx, r.in.validation_level, r.out.validation);
941         torture_assert_ntstatus_ok(tctx, status, "check_primary_group_in_validation failed");
942
943         /* Check that the primary group is not duplicated in user_info_dc SID array */
944         for (i = 2; i < netlogon_user_info_dc->num_sids; i++) {
945                 torture_assert(tctx, !dom_sid_equal(&netlogon_user_info_dc->sids[1],
946                                                     &netlogon_user_info_dc->sids[i]),
947                                "Duplicate PrimaryGroupId in return SID array");
948         }
949
950         torture_assert_str_equal(tctx, netlogon_user_info_dc->info->account_name == NULL ? "" : netlogon_user_info_dc->info->account_name,
951                                  kinit_session_info->info->account_name, "Account name differs for kinit-based PAC");
952         torture_assert_str_equal(tctx,netlogon_user_info_dc->info->account_name == NULL ? "" : netlogon_user_info_dc->info->account_name,
953                                  s4u2self_session_info->info->account_name, "Account name differs for S4U2Self");
954         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");
955         torture_assert_str_equal(tctx, netlogon_user_info_dc->info->full_name == NULL ? "" : netlogon_user_info_dc->info->full_name, s4u2self_session_info->info->full_name, "Full name differs for S4U2Self");
956         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");
957         torture_assert_int_equal(tctx, netlogon_user_info_dc->num_sids, s4u2self_session_info->torture->num_dc_sids, "Different numbers of domain groups for S4U2Self");
958
959         builtin_domain = dom_sid_parse_talloc(tmp_ctx, SID_BUILTIN);
960
961         for (i = 0; i < kinit_session_info->torture->num_dc_sids; i++) {
962                 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");
963                 torture_assert(tctx, dom_sid_equal(&netlogon_user_info_dc->sids[i], &s4u2self_session_info->torture->dc_sids[i]), "Different domain groups for S4U2Self");
964                 torture_assert(tctx, !dom_sid_in_domain(builtin_domain, &s4u2self_session_info->torture->dc_sids[i]), "Returned BUILTIN domain in groups for S4U2Self");
965                 torture_assert(tctx, !dom_sid_in_domain(builtin_domain, &kinit_session_info->torture->dc_sids[i]), "Returned BUILTIN domain in groups kinit-based PAC");
966                 torture_assert(tctx, !dom_sid_in_domain(builtin_domain, &netlogon_user_info_dc->sids[i]), "Returned BUILTIN domian in groups from NETLOGON SamLogon reply");
967         }
968
969         return true;
970 }
971
972 static bool test_S4U2Self_bdc_arcfour(struct torture_context *tctx,
973                                       struct dcerpc_pipe *p,
974                                       struct cli_credentials *credentials)
975 {
976         return test_S4U2Self(tctx, p, credentials, SEC_CHAN_BDC,
977                              TEST_MACHINE_NAME_S4U2SELF_BDC,
978                              NETLOGON_NEG_AUTH2_ADS_FLAGS);
979 }
980
981 static bool test_S4U2Self_bdc_aes(struct torture_context *tctx,
982                                   struct dcerpc_pipe *p,
983                                   struct cli_credentials *credentials)
984 {
985         return test_S4U2Self(tctx, p, credentials, SEC_CHAN_BDC,
986                              TEST_MACHINE_NAME_S4U2SELF_BDC,
987                              NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES);
988 }
989
990 static bool test_S4U2Self_workstation_arcfour(struct torture_context *tctx,
991                                               struct dcerpc_pipe *p,
992                                               struct cli_credentials *credentials)
993 {
994         return test_S4U2Self(tctx, p, credentials, SEC_CHAN_WKSTA,
995                              TEST_MACHINE_NAME_S4U2SELF_WKSTA,
996                              NETLOGON_NEG_AUTH2_ADS_FLAGS);
997 }
998
999 static bool test_S4U2Self_workstation_aes(struct torture_context *tctx,
1000                                           struct dcerpc_pipe *p,
1001                                           struct cli_credentials *credentials)
1002 {
1003         return test_S4U2Self(tctx, p, credentials, SEC_CHAN_WKSTA,
1004                              TEST_MACHINE_NAME_S4U2SELF_WKSTA,
1005                              NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES);
1006 }
1007
1008 static bool test_S4U2Proxy(struct torture_context *tctx,
1009                            struct dcerpc_pipe *p,
1010                            struct cli_credentials *credentials,
1011                            enum netr_SchannelType secure_channel_type,
1012                            const char *test_machine_name,
1013                            uint32_t negotiate_flags)
1014 {
1015         NTSTATUS status;
1016         struct gensec_security *gensec_client_context = NULL;
1017         struct gensec_security *gensec_server_context = NULL;
1018         struct cli_credentials *server_creds = NULL;
1019         size_t num_pac_buffers;
1020         struct auth4_context *auth_context = NULL;
1021         struct auth_session_info *session_info = NULL;
1022         struct pac_data *pac_data = NULL;
1023         const struct PAC_BUFFER *pac_buf = NULL;
1024         char *impersonate_princ = NULL, *self_princ = NULL, *target_princ = NULL;
1025         enum ndr_err_code ndr_err;
1026         struct PAC_DATA pac_data_struct;
1027         struct PAC_CONSTRAINED_DELEGATION *deleg = NULL;
1028
1029         DATA_BLOB client_to_server, server_to_client;
1030
1031         auth_context = talloc_zero(tctx, struct auth4_context);
1032         torture_assert_not_null(tctx, auth_context, "talloc_new() failed");
1033
1034         auth_context->generate_session_info_pac = test_generate_session_info_pac;
1035
1036         torture_comment(tctx,
1037                 "Testing S4U2Proxy (secure_channel_type: %d, machine: %s, negotiate_flags: 0x%08x\n",
1038                 secure_channel_type, test_machine_name, negotiate_flags);
1039
1040         impersonate_princ = cli_credentials_get_principal(popt_get_cmdline_credentials(), tctx);
1041         torture_assert_not_null(tctx, impersonate_princ, "Failed to get impersonate client name");
1042
1043         server_creds = cli_credentials_shallow_copy(tctx, credentials);
1044         torture_assert_not_null(tctx, server_creds, "Failed to copy of credentials");
1045
1046         self_princ = talloc_asprintf(tctx, "host/%s", test_machine_name);
1047         cli_credentials_invalidate_ccache(server_creds, CRED_SPECIFIED);
1048         cli_credentials_set_impersonate_principal(server_creds, impersonate_princ, self_princ);
1049
1050         /* Trigger S4U2Proxy by setting a target_service different than self_principal */
1051         target_princ = talloc_asprintf(tctx, "%s$", test_machine_name);
1052         cli_credentials_set_target_service(server_creds, target_princ);
1053
1054         status = gensec_client_start(tctx, &gensec_client_context,
1055                                      lpcfg_gensec_settings(tctx, tctx->lp_ctx));
1056         torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");
1057
1058         status = gensec_set_target_principal(gensec_client_context, target_princ);
1059         torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_hostname (client) failed");
1060
1061         /* We now set the same credentials on both client and server contexts */
1062         status = gensec_set_credentials(gensec_client_context, server_creds);
1063         torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
1064
1065         status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI");
1066         torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");
1067
1068         status = gensec_server_start(tctx,
1069                                      lpcfg_gensec_settings(tctx, tctx->lp_ctx),
1070                                      auth_context, &gensec_server_context);
1071         torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
1072
1073         status = gensec_set_credentials(gensec_server_context, server_creds);
1074         torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
1075
1076         status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI");
1077         torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (server) failed");
1078
1079         server_to_client = data_blob(NULL, 0);
1080
1081         do {
1082                 /* Do a client-server update dance */
1083                 status = gensec_update(gensec_client_context, tctx, server_to_client, &client_to_server);
1084                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
1085                         torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
1086                 }
1087
1088                 status = gensec_update(gensec_server_context, tctx, client_to_server, &server_to_client);
1089                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
1090                         torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed");
1091                 }
1092
1093                 if (NT_STATUS_IS_OK(status)) {
1094                         break;
1095                 }
1096         } while (1);
1097
1098         /* Extract the PAC using Samba's code */
1099
1100         status = gensec_session_info(gensec_server_context, gensec_server_context, &session_info);
1101         torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");
1102
1103         pac_data = talloc_get_type(auth_context->private_data, struct pac_data);
1104
1105         torture_assert_not_null(tctx, pac_data, "gensec_update failed to fill in pac_data in auth_context");
1106         torture_assert_not_null(tctx, pac_data->pac_srv_sig, "pac_srv_sig not present");
1107         torture_assert_not_null(tctx, pac_data->pac_kdc_sig, "pac_kdc_sig not present");
1108
1109         ndr_err = ndr_pull_struct_blob(&pac_data->pac_blob, tctx, &pac_data_struct,
1110                                        (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
1111         torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_pull_struct_blob of PAC_DATA structure failed");
1112
1113         num_pac_buffers = 6;
1114
1115         torture_assert_int_equal(tctx, pac_data_struct.version, 0, "version");
1116         torture_assert_int_equal(tctx, pac_data_struct.num_buffers, num_pac_buffers, "num_buffers");
1117
1118         pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_LOGON_INFO);
1119         torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_LOGON_INFO");
1120         torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_LOGON_INFO info");
1121
1122         pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_LOGON_NAME);
1123         torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_LOGON_NAME");
1124         torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_LOGON_NAME info");
1125
1126         pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_UPN_DNS_INFO);
1127         torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_UPN_DNS_INFO");
1128         torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_UPN_DNS_INFO info");
1129
1130         pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_SRV_CHECKSUM);
1131         torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_SRV_CHECKSUM");
1132         torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_SRV_CHECKSUM info");
1133
1134         pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_KDC_CHECKSUM);
1135         torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_KDC_CHECKSUM");
1136         torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_KDC_CHECKSUM info");
1137
1138         pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_CONSTRAINED_DELEGATION);
1139         torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_CONSTRAINED_DELEGATION");
1140         torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_CONSTRAINED_DELEGATION info");
1141
1142         deleg = pac_buf->info->constrained_delegation.info;
1143         torture_assert_str_equal(tctx, deleg->proxy_target.string, target_princ, "wrong proxy_target");
1144         torture_assert_int_equal(tctx, deleg->num_transited_services, 1, "wrong transited_services number");
1145         torture_assert_str_equal(tctx, deleg->transited_services[0].string,
1146                                  talloc_asprintf(tctx, "%s@%s", self_princ, cli_credentials_get_realm(credentials)),
1147                                  "wrong transited_services[0]");
1148
1149         return netlogon_validate_pac(tctx, p, server_creds, secure_channel_type, test_machine_name,
1150                                      negotiate_flags, pac_data, session_info);
1151 }
1152
1153 static bool setup_constrained_delegation(struct torture_context *tctx,
1154                                          struct dcerpc_pipe *p,
1155                                          struct test_join *join_ctx,
1156                                          const char *machine_name)
1157 {
1158         struct samr_SetUserInfo r;
1159         union samr_UserInfo user_info;
1160         struct dcerpc_pipe *samr_pipe = torture_join_samr_pipe(join_ctx);
1161         const char *server_dn_str = NULL;
1162         struct ldb_context *sam_ctx = NULL;
1163         struct ldb_dn *server_dn = NULL;
1164         struct ldb_message *msg = NULL;
1165         char *url = NULL;
1166         int ret;
1167
1168         url = talloc_asprintf(tctx, "ldap://%s", dcerpc_server_name(p));
1169         sam_ctx = ldb_wrap_connect(tctx, tctx->ev, tctx->lp_ctx, url, NULL, popt_get_cmdline_credentials(), 0);
1170         torture_assert_not_null(tctx, sam_ctx, "Connection to the SAMDB on DC failed!");
1171
1172         server_dn_str = samdb_search_string(sam_ctx, tctx, ldb_get_default_basedn(sam_ctx), "distinguishedName",
1173                                             "samaccountname=%s$", machine_name);
1174         torture_assert_not_null(tctx, server_dn_str, "samdb_search_string()");
1175
1176         server_dn = ldb_dn_new(tctx, sam_ctx, server_dn_str);
1177         torture_assert_not_null(tctx, server_dn, "ldb_dn_new()");
1178
1179         msg = ldb_msg_new(tctx);
1180         torture_assert_not_null(tctx, msg, "ldb_msg_new()");
1181
1182         msg->dn = server_dn;
1183         ret = ldb_msg_add_string(msg, "msDS-AllowedToDelegateTo", talloc_asprintf(tctx, "%s$", machine_name));
1184         torture_assert_int_equal(tctx, ret, 0, "ldb_msg_add_string())");
1185
1186         ret = ldb_modify(sam_ctx, msg);
1187         torture_assert_int_equal(tctx, ret, 0, "ldb_modify()");
1188
1189         /* Allow forwardable flag in S4U2Self */
1190         user_info.info16.acct_flags = ACB_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION | ACB_WSTRUST;
1191         r.in.user_handle = torture_join_samr_user_policy(join_ctx);
1192         r.in.level = 16;
1193         r.in.info = &user_info;
1194
1195         torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(samr_pipe->binding_handle, tctx, &r),
1196                 "failed to set ACB_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION info account flags");
1197         torture_assert_ntstatus_ok(tctx, r.out.result,
1198                 "failed to set ACB_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION into account flags");
1199
1200         return true;
1201 }
1202
1203 static bool test_S4U2Proxy_workstation_arcfour(struct torture_context *tctx,
1204                                                struct dcerpc_pipe *p,
1205                                                struct cli_credentials *credentials,
1206                                                struct test_join *join_ctx)
1207 {
1208         torture_assert(tctx, setup_constrained_delegation(tctx, p, join_ctx,
1209                                                           TEST_MACHINE_NAME_S4U2PROXY_WKSTA),
1210                                                           "setup_constrained_delegation() failed");
1211         return test_S4U2Proxy(tctx, p, credentials, SEC_CHAN_WKSTA,
1212                               TEST_MACHINE_NAME_S4U2PROXY_WKSTA,
1213                               NETLOGON_NEG_AUTH2_ADS_FLAGS);
1214 }
1215
1216 static bool test_S4U2Proxy_workstation_aes(struct torture_context *tctx,
1217                                            struct dcerpc_pipe *p,
1218                                            struct cli_credentials *credentials,
1219                                            struct test_join *join_ctx)
1220 {
1221         torture_assert(tctx, setup_constrained_delegation(tctx, p, join_ctx,
1222                                                           TEST_MACHINE_NAME_S4U2PROXY_WKSTA),
1223                                                           "setup_constrained_delegation() failed");
1224         return test_S4U2Proxy(tctx, p, credentials, SEC_CHAN_WKSTA,
1225                               TEST_MACHINE_NAME_S4U2PROXY_WKSTA,
1226                               NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES);
1227 }
1228 #endif
1229
1230 struct torture_suite *torture_rpc_remote_pac(TALLOC_CTX *mem_ctx)
1231 {
1232         struct torture_suite *suite = torture_suite_create(mem_ctx, "pac");
1233         struct torture_rpc_tcase *tcase;
1234
1235         tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "netr-bdc-arcfour",
1236                                                               &ndr_table_netlogon, TEST_MACHINE_NAME_BDC);
1237         torture_rpc_tcase_add_test_creds(tcase, "verify-sig-arcfour", test_PACVerify_bdc_arcfour);
1238
1239         tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "netr-bdc-aes",
1240                                                               &ndr_table_netlogon, TEST_MACHINE_NAME_BDC);
1241         torture_rpc_tcase_add_test_creds(tcase, "verify-sig-aes", test_PACVerify_bdc_aes);
1242
1243         tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netr-mem-arcfour",
1244                                                                       &ndr_table_netlogon, TEST_MACHINE_NAME_WKSTA);
1245         torture_rpc_tcase_add_test_creds(tcase, "verify-sig-arcfour", test_PACVerify_workstation_arcfour);
1246
1247         tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netr-mem-aes",
1248                                                                       &ndr_table_netlogon, TEST_MACHINE_NAME_WKSTA);
1249         torture_rpc_tcase_add_test_creds(tcase, "verify-sig-aes", test_PACVerify_workstation_aes);
1250
1251         tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netlogon-member-des",
1252                                                                       &ndr_table_netlogon, TEST_MACHINE_NAME_WKSTA_DES);
1253         torture_rpc_tcase_add_test_join(tcase, "verify-sig", test_PACVerify_workstation_des);
1254 #ifdef SAMBA4_USES_HEIMDAL
1255         tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "netr-bdc-arcfour",
1256                                                               &ndr_table_netlogon, TEST_MACHINE_NAME_S4U2SELF_BDC);
1257         torture_rpc_tcase_add_test_creds(tcase, "s4u2self-arcfour", test_S4U2Self_bdc_arcfour);
1258
1259         tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "netr-bcd-aes",
1260                                                               &ndr_table_netlogon, TEST_MACHINE_NAME_S4U2SELF_BDC);
1261         torture_rpc_tcase_add_test_creds(tcase, "s4u2self-aes", test_S4U2Self_bdc_aes);
1262
1263         tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netr-mem-arcfour",
1264                                                                       &ndr_table_netlogon, TEST_MACHINE_NAME_S4U2SELF_WKSTA);
1265         torture_rpc_tcase_add_test_creds(tcase, "s4u2self-arcfour", test_S4U2Self_workstation_arcfour);
1266
1267         tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netr-mem-aes",
1268                                                                       &ndr_table_netlogon, TEST_MACHINE_NAME_S4U2SELF_WKSTA);
1269         torture_rpc_tcase_add_test_creds(tcase, "s4u2self-aes", test_S4U2Self_workstation_aes);
1270
1271         tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netr-mem-arcfour",
1272                                                                       &ndr_table_netlogon, TEST_MACHINE_NAME_S4U2PROXY_WKSTA);
1273         torture_rpc_tcase_add_test_join(tcase, "s4u2proxy-arcfour", test_S4U2Proxy_workstation_arcfour);
1274
1275         tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netr-mem-aes",
1276                                                                       &ndr_table_netlogon, TEST_MACHINE_NAME_S4U2PROXY_WKSTA);
1277         torture_rpc_tcase_add_test_join(tcase, "s4u2proxy-aes", test_S4U2Proxy_workstation_aes);
1278 #endif
1279         return suite;
1280 }