f48e4c2a08ab23be6872709832641261469835ed
[samba.git] / source4 / torture / rpc / schannel.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    test suite for schannel operations
5
6    Copyright (C) Andrew Tridgell 2004
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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "librpc/gen_ndr/ndr_netlogon.h"
25 #include "auth/credentials/credentials.h"
26 #include "torture/rpc/rpc.h"
27 #include "lib/cmdline/popt_common.h"
28 #include "auth/gensec/schannel_proto.h"
29 #include "libcli/auth/libcli_auth.h"
30 #include "libcli/security/proto.h"
31
32 #define TEST_MACHINE_NAME "schannel"
33
34 /*
35   try a netlogon SamLogon
36 */
37 BOOL test_netlogon_ex_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
38                           struct cli_credentials *credentials, 
39                           struct creds_CredentialState *creds)
40 {
41         NTSTATUS status;
42         struct netr_LogonSamLogonEx r;
43         struct netr_NetworkInfo ninfo;
44         DATA_BLOB names_blob, chal, lm_resp, nt_resp;
45         int i;
46         BOOL ret = True;
47         int flags = CLI_CRED_NTLM_AUTH;
48         if (lp_client_lanman_auth()) {
49                 flags |= CLI_CRED_LANMAN_AUTH;
50         }
51
52         if (lp_client_ntlmv2_auth()) {
53                 flags |= CLI_CRED_NTLMv2_AUTH;
54         }
55
56         cli_credentials_get_ntlm_username_domain(cmdline_credentials, mem_ctx, 
57                                                  &ninfo.identity_info.account_name.string,
58                                                  &ninfo.identity_info.domain_name.string);
59         
60         generate_random_buffer(ninfo.challenge, 
61                                sizeof(ninfo.challenge));
62         chal = data_blob_const(ninfo.challenge, 
63                                sizeof(ninfo.challenge));
64
65         names_blob = NTLMv2_generate_names_blob(mem_ctx, cli_credentials_get_workstation(credentials), 
66                                                 cli_credentials_get_domain(credentials));
67
68         status = cli_credentials_get_ntlm_response(cmdline_credentials, mem_ctx, 
69                                                    &flags, 
70                                                    chal,
71                                                    names_blob,
72                                                    &lm_resp, &nt_resp,
73                                                    NULL, NULL);
74         if (!NT_STATUS_IS_OK(status)) {
75                 printf("cli_credentials_get_ntlm_response failed: %s\n", 
76                        nt_errstr(status));
77                 return False;
78         }
79
80         ninfo.lm.data = lm_resp.data;
81         ninfo.lm.length = lm_resp.length;
82
83         ninfo.nt.data = nt_resp.data;
84         ninfo.nt.length = nt_resp.length;
85
86         ninfo.identity_info.parameter_control = 0;
87         ninfo.identity_info.logon_id_low = 0;
88         ninfo.identity_info.logon_id_high = 0;
89         ninfo.identity_info.workstation.string = cli_credentials_get_workstation(credentials);
90
91         r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
92         r.in.computer_name = cli_credentials_get_workstation(credentials);
93         r.in.logon_level = 2;
94         r.in.logon.network = &ninfo;
95         r.in.flags = 0;
96
97         printf("Testing LogonSamLogonEx with name %s\n", ninfo.identity_info.account_name.string);
98         
99         for (i=2;i<3;i++) {
100                 r.in.validation_level = i;
101                 
102                 status = dcerpc_netr_LogonSamLogonEx(p, mem_ctx, &r);
103                 if (!NT_STATUS_IS_OK(status)) {
104                         printf("LogonSamLogon failed: %s\n", 
105                                nt_errstr(status));
106                         return False;
107                 }
108         }
109
110         return ret;
111 }
112
113 /*
114   do some samr ops using the schannel connection
115  */
116 static BOOL test_samr_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
117 {
118         NTSTATUS status;
119         struct samr_GetDomPwInfo r;
120         struct samr_Connect connect;
121         struct samr_OpenDomain opendom;
122         int i;
123         struct lsa_String name;
124         struct policy_handle handle;
125         struct policy_handle domain_handle;
126
127         name.string = lp_workgroup();
128         r.in.domain_name = &name;
129
130         connect.in.system_name = 0;
131         connect.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
132         connect.out.connect_handle = &handle;
133         
134         printf("Testing Connect and OpenDomain on BUILTIN\n");
135
136         status = dcerpc_samr_Connect(p, mem_ctx, &connect);
137         if (!NT_STATUS_IS_OK(status)) {
138                 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
139                         printf("Connect failed (expected, schannel mapped to anonymous): %s\n",
140                                nt_errstr(status));
141                 } else {
142                         printf("Connect failed - %s\n", nt_errstr(status));
143                         return False;
144                 }
145         } else {
146                 opendom.in.connect_handle = &handle;
147                 opendom.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
148                 opendom.in.sid = dom_sid_parse_talloc(mem_ctx, "S-1-5-32");
149                 opendom.out.domain_handle = &domain_handle;
150                 
151                 status = dcerpc_samr_OpenDomain(p, mem_ctx, &opendom);
152                 if (!NT_STATUS_IS_OK(status)) {
153                         printf("OpenDomain failed - %s\n", nt_errstr(status));
154                         return False;
155                 }
156         }
157
158         printf("Testing GetDomPwInfo with name %s\n", r.in.domain_name->string);
159         
160         /* do several ops to test credential chaining */
161         for (i=0;i<5;i++) {
162                 status = dcerpc_samr_GetDomPwInfo(p, mem_ctx, &r);
163                 if (!NT_STATUS_IS_OK(status)) {
164                         if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
165                                 printf("GetDomPwInfo op %d failed - %s\n", i, nt_errstr(status));
166                                 return False;
167                         }
168                 }
169         }
170
171         return True;
172 }
173
174
175 /*
176   do some lsa ops using the schannel connection
177  */
178 static BOOL test_lsa_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
179 {
180         struct lsa_GetUserName r;
181         NTSTATUS status;
182         BOOL ret = True;
183         struct lsa_StringPointer authority_name_p;
184
185         printf("\nTesting GetUserName\n");
186
187         r.in.system_name = "\\";        
188         r.in.account_name = NULL;       
189         r.in.authority_name = &authority_name_p;
190         authority_name_p.string = NULL;
191
192         /* do several ops to test credential chaining and various operations */
193         status = dcerpc_lsa_GetUserName(p, mem_ctx, &r);
194         
195         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
196                 printf("not considering %s to be an error\n", nt_errstr(status));
197         } else if (!NT_STATUS_IS_OK(status)) {
198                 printf("GetUserName failed - %s\n", nt_errstr(status));
199                 return False;
200         } else {
201                 if (!r.out.account_name) {
202                         return False;
203                 }
204                 
205                 if (strcmp(r.out.account_name->string, "ANONYMOUS LOGON") != 0) {
206                         printf("GetUserName returned wrong user: %s, expected %s\n",
207                                r.out.account_name->string, "ANONYMOUS LOGON");
208                         return False;
209                 }
210                 if (!r.out.authority_name || !r.out.authority_name->string) {
211                         return False;
212                 }
213                 
214                 if (strcmp(r.out.authority_name->string->string, "NT AUTHORITY") != 0) {
215                         printf("GetUserName returned wrong user: %s, expected %s\n",
216                                r.out.authority_name->string->string, "NT AUTHORITY");
217                         return False;
218                 }
219         }
220         if (!test_many_LookupSids(p, mem_ctx, NULL)) {
221                 printf("LsaLookupSids3 failed!\n");
222                 return False;
223         }
224
225         return ret;
226 }
227
228
229 /*
230   test a schannel connection with the given flags
231  */
232 static BOOL test_schannel(TALLOC_CTX *mem_ctx, 
233                           uint16_t acct_flags, uint32_t dcerpc_flags,
234                           int i)
235 {
236         BOOL ret = True;
237
238         struct test_join *join_ctx;
239         NTSTATUS status;
240         const char *binding = lp_parm_string(-1, "torture", "binding");
241         struct dcerpc_binding *b;
242         struct dcerpc_pipe *p = NULL;
243         struct dcerpc_pipe *p_netlogon = NULL;
244         struct dcerpc_pipe *p_netlogon2 = NULL;
245         struct dcerpc_pipe *p_netlogon3 = NULL;
246         struct dcerpc_pipe *p_samr2 = NULL;
247         struct dcerpc_pipe *p_lsa = NULL;
248         struct creds_CredentialState *creds;
249         struct cli_credentials *credentials;
250
251         TALLOC_CTX *test_ctx = talloc_named(mem_ctx, 0, "test_schannel context");
252
253         join_ctx = torture_join_domain(talloc_asprintf(mem_ctx, "%s%d", TEST_MACHINE_NAME, i), 
254                                        acct_flags, &credentials);
255         if (!join_ctx) {
256                 printf("Failed to join domain with acct_flags=0x%x\n", acct_flags);
257                 talloc_free(test_ctx);
258                 return False;
259         }
260
261         status = dcerpc_parse_binding(test_ctx, binding, &b);
262         if (!NT_STATUS_IS_OK(status)) {
263                 printf("Bad binding string %s\n", binding);
264                 goto failed;
265         }
266
267         b->flags &= ~DCERPC_AUTH_OPTIONS;
268         b->flags |= dcerpc_flags;
269
270         status = dcerpc_pipe_connect_b(test_ctx, &p, b, &dcerpc_table_samr,
271                                        credentials, NULL);
272         if (!NT_STATUS_IS_OK(status)) {
273                 printf("Failed to connect with schannel: %s\n", nt_errstr(status));
274                 goto failed;
275         }
276
277         if (!test_samr_ops(p, test_ctx)) {
278                 printf("Failed to process schannel secured SAMR ops\n");
279                 ret = False;
280         }
281
282         /* Also test that when we connect to the netlogon pipe, that
283          * the credentials we setup on the first pipe are valid for
284          * the second */
285
286         /* Swap the binding details from SAMR to NETLOGON */
287         status = dcerpc_epm_map_binding(test_ctx, b, &dcerpc_table_netlogon, NULL);
288         if (!NT_STATUS_IS_OK(status)) {
289                 goto failed;
290         }
291
292         status = dcerpc_secondary_connection(p, &p_netlogon, 
293                                              b);
294
295         if (!NT_STATUS_IS_OK(status)) {
296                 goto failed;
297         }
298
299         status = dcerpc_bind_auth(p_netlogon, &dcerpc_table_netlogon,
300                                   credentials, DCERPC_AUTH_TYPE_SCHANNEL,
301                                   dcerpc_auth_level(p->conn),
302                                   NULL);
303
304         if (!NT_STATUS_IS_OK(status)) {
305                 goto failed;
306         }
307
308         status = dcerpc_schannel_creds(p_netlogon->conn->security_state.generic_state, test_ctx, &creds);
309         if (!NT_STATUS_IS_OK(status)) {
310                 goto failed;
311         }
312
313         /* do a couple of logins */
314         if (!test_netlogon_ops(p_netlogon, test_ctx, credentials, creds)) {
315                 printf("Failed to process schannel secured NETLOGON ops\n");
316                 ret = False;
317         }
318
319         if (!test_netlogon_ex_ops(p_netlogon, test_ctx, credentials, creds)) {
320                 printf("Failed to process schannel secured NETLOGON EX ops\n");
321                 ret = False;
322         }
323
324         /* Swap the binding details from SAMR to LSARPC */
325         status = dcerpc_epm_map_binding(test_ctx, b, &dcerpc_table_lsarpc, NULL);
326         if (!NT_STATUS_IS_OK(status)) {
327                 goto failed;
328         }
329
330         status = dcerpc_secondary_connection(p, &p_lsa, 
331                                              b);
332
333         if (!NT_STATUS_IS_OK(status)) {
334                 goto failed;
335         }
336
337         status = dcerpc_bind_auth(p_lsa, &dcerpc_table_lsarpc,
338                                   credentials, DCERPC_AUTH_TYPE_SCHANNEL,
339                                   dcerpc_auth_level(p->conn),
340                                   NULL);
341
342         if (!NT_STATUS_IS_OK(status)) {
343                 goto failed;
344         }
345
346         if (!test_lsa_ops(p_lsa, test_ctx)) {
347                 printf("Failed to process schannel secured LSA ops\n");
348                 ret = False;
349         }
350
351         /* Drop the socket, we want to start from scratch */
352         talloc_free(p);
353         p = NULL;
354
355         /* Now see what we are still allowed to do */
356         
357         status = dcerpc_parse_binding(test_ctx, binding, &b);
358         if (!NT_STATUS_IS_OK(status)) {
359                 printf("Bad binding string %s\n", binding);
360                 goto failed;
361         }
362
363         b->flags &= ~DCERPC_AUTH_OPTIONS;
364         b->flags |= dcerpc_flags;
365
366         status = dcerpc_pipe_connect_b(test_ctx, &p_samr2, b, &dcerpc_table_samr,
367                                        credentials, NULL);
368         if (!NT_STATUS_IS_OK(status)) {
369                 printf("Failed to connect with schannel: %s\n", nt_errstr(status));
370                 goto failed;
371         }
372
373         /* do a some SAMR operations.  We have *not* done a new serverauthenticate */
374         if (!test_samr_ops(p_samr2, test_ctx)) {
375                 printf("Failed to process schannel secured SAMR ops (on fresh connection)\n");
376                 goto failed;
377         }
378
379         /* Swap the binding details from SAMR to NETLOGON */
380         status = dcerpc_epm_map_binding(test_ctx, b, &dcerpc_table_netlogon, NULL);
381         if (!NT_STATUS_IS_OK(status)) {
382                 goto failed;
383         }
384
385         status = dcerpc_secondary_connection(p_samr2, &p_netlogon2, 
386                                              b);
387         if (!NT_STATUS_IS_OK(status)) {
388                 goto failed;
389         }
390
391         /* and now setup an SCHANNEL bind on netlogon */
392         status = dcerpc_bind_auth(p_netlogon2, &dcerpc_table_netlogon,
393                                   credentials, DCERPC_AUTH_TYPE_SCHANNEL,
394                                   dcerpc_auth_level(p_samr2->conn),
395                                   NULL);
396
397         if (!NT_STATUS_IS_OK(status)) {
398                 goto failed;
399         }
400         
401         /* Try the schannel-only SamLogonEx operation */
402         if (!test_netlogon_ex_ops(p_netlogon2, test_ctx, credentials, creds)) {
403                 printf("Failed to process schannel secured NETLOGON EX ops (on fresh connection)\n");
404                 ret = False;
405         }
406
407         /* And the more traditional style, proving that the
408          * credentials chaining state is fully present */
409         if (!test_netlogon_ops(p_netlogon2, test_ctx, credentials, creds)) {
410                 printf("Failed to process schannel secured NETLOGON ops (on fresh connection)\n");
411                 ret = False;
412         }
413
414         /* Drop the socket, we want to start from scratch (again) */
415         talloc_free(p_samr2);
416
417         /* We don't want schannel for this test */
418         b->flags &= ~DCERPC_AUTH_OPTIONS;
419
420         status = dcerpc_pipe_connect_b(test_ctx, &p_netlogon3, b, &dcerpc_table_netlogon,
421                                        credentials, NULL);
422         if (!NT_STATUS_IS_OK(status)) {
423                 printf("Failed to connect without schannel: %s\n", nt_errstr(status));
424                 goto failed;
425         }
426
427         if (test_netlogon_ex_ops(p_netlogon3, test_ctx, credentials, creds)) {
428                 printf("Processed NOT schannel secured NETLOGON EX ops without SCHANNEL (unsafe)\n");
429                 ret = False;
430         }
431
432         if (!test_netlogon_ops(p_netlogon3, test_ctx, credentials, creds)) {
433                 printf("Failed to processed NOT schannel secured NETLOGON ops without new ServerAuth\n");
434                 ret = False;
435         }
436
437         torture_leave_domain(join_ctx);
438         talloc_free(test_ctx);
439         return ret;
440
441 failed:
442         torture_leave_domain(join_ctx);
443         talloc_free(test_ctx);
444         return False;   
445 }
446
447 /*
448   a schannel test suite
449  */
450 BOOL torture_rpc_schannel(void)
451 {
452         TALLOC_CTX *mem_ctx;
453         BOOL ret = True;
454         struct {
455                 uint16_t acct_flags;
456                 uint32_t dcerpc_flags;
457         } tests[] = {
458                 { ACB_WSTRUST,   DCERPC_SCHANNEL | DCERPC_SIGN},
459                 { ACB_WSTRUST,   DCERPC_SCHANNEL | DCERPC_SEAL},
460                 { ACB_WSTRUST,   DCERPC_SCHANNEL | DCERPC_SIGN | DCERPC_SCHANNEL_128},
461                 { ACB_WSTRUST,   DCERPC_SCHANNEL | DCERPC_SEAL | DCERPC_SCHANNEL_128 },
462                 { ACB_SVRTRUST,  DCERPC_SCHANNEL | DCERPC_SIGN },
463                 { ACB_SVRTRUST,  DCERPC_SCHANNEL | DCERPC_SEAL },
464                 { ACB_SVRTRUST,  DCERPC_SCHANNEL | DCERPC_SIGN | DCERPC_SCHANNEL_128 },
465                 { ACB_SVRTRUST,  DCERPC_SCHANNEL | DCERPC_SEAL | DCERPC_SCHANNEL_128 }
466         };
467         int i;
468
469         mem_ctx = talloc_init("torture_rpc_schannel");
470
471         for (i=0;i<ARRAY_SIZE(tests);i++) {
472                 if (!test_schannel(mem_ctx, 
473                                    tests[i].acct_flags, tests[i].dcerpc_flags,
474                                    i)) {
475                         printf("Failed with acct_flags=0x%x dcerpc_flags=0x%x \n",
476                                tests[i].acct_flags, tests[i].dcerpc_flags);
477                         ret = False;
478                         break;
479                 }
480         }
481
482         talloc_free(mem_ctx);
483
484         return ret;
485 }