s4-torture: ran minimal_includes.pl over source4/torture
[samba.git] / source4 / torture / winbind / struct_based.c
1 /*
2    Unix SMB/CIFS implementation.
3    SMB torture tester - winbind struct based protocol
4    Copyright (C) Stefan Metzmacher 2007
5    Copyright (C) Michael Adam 2007
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "torture/torture.h"
23 #include "nsswitch/winbind_client.h"
24 #include "libcli/security/security.h"
25 #include "librpc/gen_ndr/netlogon.h"
26 #include "param/param.h"
27 #include "auth/ntlm/pam_errors.h"
28
29 #define DO_STRUCT_REQ_REP_EXT(op,req,rep,expected,strict,warnaction,cmt) do { \
30         NSS_STATUS __got, __expected = (expected); \
31         __got = winbindd_request_response(op, req, rep); \
32         if (__got != __expected) { \
33                 const char *__cmt = (cmt); \
34                 if (strict) { \
35                         torture_result(torture, TORTURE_FAIL, \
36                                 __location__ ": " __STRING(op) \
37                                 " returned %d, expected %d%s%s", \
38                                 __got, __expected, \
39                                 (__cmt) ? ": " : "", \
40                                 (__cmt) ? (__cmt) : ""); \
41                         return false; \
42                 } else { \
43                         torture_warning(torture, \
44                                 __location__ ": " __STRING(op) \
45                                 " returned %d, expected %d%s%s", \
46                                 __got, __expected, \
47                                 (__cmt) ? ": " : "", \
48                                 (__cmt) ? (__cmt) : ""); \
49                         warnaction; \
50                 } \
51         } \
52 } while(0)
53
54 #define DO_STRUCT_REQ_REP(op,req,rep) do { \
55         bool __noop = false; \
56         DO_STRUCT_REQ_REP_EXT(op,req,rep,NSS_STATUS_SUCCESS,true,__noop=true,NULL); \
57 } while (0)
58
59 static bool torture_winbind_struct_interface_version(struct torture_context *torture)
60 {
61         struct winbindd_request req;
62         struct winbindd_response rep;
63
64         ZERO_STRUCT(req);
65         ZERO_STRUCT(rep);
66
67         torture_comment(torture, "Running WINBINDD_INTERFACE_VERSION (struct based)\n");
68
69         DO_STRUCT_REQ_REP(WINBINDD_INTERFACE_VERSION, &req, &rep);
70
71         torture_assert_int_equal(torture,
72                                  rep.data.interface_version,
73                                  WINBIND_INTERFACE_VERSION,
74                                  "winbind server and client doesn't match");
75
76         return true;
77 }
78
79 static bool torture_winbind_struct_ping(struct torture_context *torture)
80 {
81         struct timeval tv = timeval_current();
82         int timelimit = torture_setting_int(torture, "timelimit", 5);
83         uint32_t total = 0;
84
85         torture_comment(torture,
86                         "Running WINBINDD_PING (struct based) for %d seconds\n",
87                         timelimit);
88
89         while (timeval_elapsed(&tv) < timelimit) {
90                 DO_STRUCT_REQ_REP(WINBINDD_PING, NULL, NULL);
91                 total++;
92         }
93
94         torture_comment(torture,
95                         "%u (%.1f/s) WINBINDD_PING (struct based)\n",
96                         total, total / timeval_elapsed(&tv));
97
98         return true;
99 }
100
101
102 static char winbind_separator(struct torture_context *torture)
103 {
104         struct winbindd_response rep;
105
106         ZERO_STRUCT(rep);
107
108         DO_STRUCT_REQ_REP(WINBINDD_INFO, NULL, &rep);
109
110         return rep.data.info.winbind_separator;
111 }
112
113 static bool torture_winbind_struct_info(struct torture_context *torture)
114 {
115         struct winbindd_response rep;
116         const char *separator;
117
118         ZERO_STRUCT(rep);
119
120         torture_comment(torture, "Running WINBINDD_INFO (struct based)\n");
121
122         DO_STRUCT_REQ_REP(WINBINDD_INFO, NULL, &rep);
123
124         separator = torture_setting_string(torture,
125                                            "winbindd separator",
126                                            lp_winbind_separator(torture->lp_ctx));
127         torture_assert_int_equal(torture,
128                                  rep.data.info.winbind_separator,
129                                  *separator,
130                                  "winbind separator doesn't match");
131
132         torture_comment(torture, "Samba Version '%s'\n",
133                         rep.data.info.samba_version);
134
135         return true;
136 }
137
138 static bool torture_winbind_struct_priv_pipe_dir(struct torture_context *torture)
139 {
140         struct winbindd_response rep;
141         const char *got_dir;
142
143         ZERO_STRUCT(rep);
144
145         torture_comment(torture, "Running WINBINDD_PRIV_PIPE_DIR (struct based)\n");
146
147         DO_STRUCT_REQ_REP(WINBINDD_PRIV_PIPE_DIR, NULL, &rep);
148
149         got_dir = (const char *)rep.extra_data.data;
150
151         torture_assert(torture, got_dir, "NULL WINBINDD_PRIV_PIPE_DIR\n");
152
153         SAFE_FREE(rep.extra_data.data);
154         return true;
155 }
156
157 static bool torture_winbind_struct_netbios_name(struct torture_context *torture)
158 {
159         struct winbindd_response rep;
160         const char *expected;
161
162         ZERO_STRUCT(rep);
163
164         torture_comment(torture, "Running WINBINDD_NETBIOS_NAME (struct based)\n");
165
166         DO_STRUCT_REQ_REP(WINBINDD_NETBIOS_NAME, NULL, &rep);
167
168         expected = torture_setting_string(torture,
169                                           "winbindd netbios name",
170                                           lp_netbios_name(torture->lp_ctx));
171         expected = strupper_talloc(torture, expected);
172         
173         torture_assert_str_equal(torture,
174                                  rep.data.netbios_name, expected,
175                                  "winbindd's netbios name doesn't match");
176
177         return true;
178 }
179
180 static bool get_winbind_domain(struct torture_context *torture, char **domain)
181 {
182         struct winbindd_response rep;
183
184         ZERO_STRUCT(rep);
185
186         DO_STRUCT_REQ_REP(WINBINDD_DOMAIN_NAME, NULL, &rep);
187
188         *domain = talloc_strdup(torture, rep.data.domain_name);
189         torture_assert(torture, domain, "talloc error");
190
191         return true;
192 }
193
194 static bool torture_winbind_struct_domain_name(struct torture_context *torture)
195 {
196         const char *expected;
197         char *domain;
198
199         torture_comment(torture, "Running WINBINDD_DOMAIN_NAME (struct based)\n");
200
201         expected = torture_setting_string(torture,
202                                           "winbindd netbios domain",
203                                           lp_workgroup(torture->lp_ctx));
204
205         get_winbind_domain(torture, &domain);
206
207         torture_assert_str_equal(torture, domain, expected,
208                                  "winbindd's netbios domain doesn't match");
209
210         return true;
211 }
212
213 static bool torture_winbind_struct_check_machacc(struct torture_context *torture)
214 {
215         bool ok;
216         bool strict = torture_setting_bool(torture, "strict mode", false);
217         struct winbindd_response rep;
218
219         ZERO_STRUCT(rep);
220
221         torture_comment(torture, "Running WINBINDD_CHECK_MACHACC (struct based)\n");
222
223         ok = true;
224         DO_STRUCT_REQ_REP_EXT(WINBINDD_CHECK_MACHACC, NULL, &rep,
225                               NSS_STATUS_SUCCESS, strict, ok = false,
226                               "WINBINDD_CHECK_MACHACC");
227
228         if (!ok) {
229                 torture_assert(torture,
230                                strlen(rep.data.auth.nt_status_string)>0,
231                                "Failed with empty nt_status_string");
232
233                 torture_warning(torture,"%s:%s:%s:%d\n",
234                                 nt_errstr(NT_STATUS(rep.data.auth.nt_status)),
235                                 rep.data.auth.nt_status_string,
236                                 rep.data.auth.error_string,
237                                 rep.data.auth.pam_error);
238                 return true;
239         }
240
241         torture_assert_ntstatus_ok(torture,
242                                    NT_STATUS(rep.data.auth.nt_status),
243                                    "WINBINDD_CHECK_MACHACC ok: nt_status");
244
245         torture_assert_str_equal(torture,
246                                  rep.data.auth.nt_status_string,
247                                  nt_errstr(NT_STATUS_OK),
248                                  "WINBINDD_CHECK_MACHACC ok:nt_status_string");
249
250         torture_assert_str_equal(torture,
251                                  rep.data.auth.error_string,
252                                  get_friendly_nt_error_msg(NT_STATUS_OK),
253                                  "WINBINDD_CHECK_MACHACC ok: error_string");
254
255         torture_assert_int_equal(torture,
256                                  rep.data.auth.pam_error,
257                                  nt_status_to_pam(NT_STATUS_OK),
258                                  "WINBINDD_CHECK_MACHACC ok: pam_error");
259
260         return true;
261 }
262
263 struct torture_trust_domain {
264         const char *netbios_name;
265         const char *dns_name;
266         struct dom_sid *sid;
267 };
268
269 static bool get_trusted_domains(struct torture_context *torture,
270                                 struct torture_trust_domain **_d)
271 {
272         struct winbindd_request req;
273         struct winbindd_response rep;
274         struct torture_trust_domain *d = NULL;
275         uint32_t dcount = 0;
276         char line[256];
277         const char *extra_data;
278
279         ZERO_STRUCT(req);
280         ZERO_STRUCT(rep);
281
282         DO_STRUCT_REQ_REP(WINBINDD_LIST_TRUSTDOM, &req, &rep);
283
284         extra_data = (char *)rep.extra_data.data;
285         if (!extra_data) {
286                 return true;
287         }
288
289         torture_assert(torture, extra_data, "NULL trust list");
290
291         while (next_token(&extra_data, line, "\n", sizeof(line))) {
292                 char *p, *lp;
293
294                 d = talloc_realloc(torture, d,
295                                    struct torture_trust_domain,
296                                    dcount + 2);
297                 ZERO_STRUCT(d[dcount+1]);
298
299                 lp = line;
300                 p = strchr(lp, '\\');
301                 torture_assert(torture, p, "missing 1st '\\' in line");
302                 *p = 0;
303                 d[dcount].netbios_name = talloc_strdup(d, lp);
304                 torture_assert(torture, strlen(d[dcount].netbios_name) > 0,
305                                "empty netbios_name");
306
307                 lp = p+1;
308                 p = strchr(lp, '\\');
309                 torture_assert(torture, p, "missing 2nd '\\' in line");
310                 *p = 0;
311                 d[dcount].dns_name = talloc_strdup(d, lp);
312                 /* it's ok to have an empty dns_name */
313
314                 lp = p+1;
315                 d[dcount].sid = dom_sid_parse_talloc(d, lp);
316                 torture_assert(torture, d[dcount].sid,
317                                "failed to parse sid");
318
319                 dcount++;
320         }
321         SAFE_FREE(rep.extra_data.data);
322
323         torture_assert(torture, dcount >= 2,
324                        "The list of trusted domain should contain 2 entries");
325
326         *_d = d;
327         return true;
328 }
329
330 static bool torture_winbind_struct_list_trustdom(struct torture_context *torture)
331 {
332         struct winbindd_request req;
333         struct winbindd_response rep;
334         char *list1;
335         char *list2;
336         bool ok;
337         struct torture_trust_domain *listd = NULL;
338         uint32_t i;
339
340         torture_comment(torture, "Running WINBINDD_LIST_TRUSTDOM (struct based)\n");
341
342         ZERO_STRUCT(req);
343         ZERO_STRUCT(rep);
344
345         req.data.list_all_domains = false;
346
347         DO_STRUCT_REQ_REP(WINBINDD_LIST_TRUSTDOM, &req, &rep);
348
349         list1 = (char *)rep.extra_data.data;
350
351         torture_comment(torture, "%s\n", list1);
352
353         ZERO_STRUCT(req);
354         ZERO_STRUCT(rep);
355
356         req.data.list_all_domains = true;
357
358         DO_STRUCT_REQ_REP(WINBINDD_LIST_TRUSTDOM, &req, &rep);
359
360         list2 = (char *)rep.extra_data.data;
361
362         /*
363          * The list_all_domains parameter should be ignored
364          */
365         torture_assert_str_equal(torture, list2, list1, "list_all_domains not ignored");
366
367         SAFE_FREE(list1);
368         SAFE_FREE(list2);
369
370         ok = get_trusted_domains(torture, &listd);
371         torture_assert(torture, ok, "failed to get trust list");
372
373         for (i=0; listd && listd[i].netbios_name; i++) {
374                 if (i == 0) {
375                         struct dom_sid *builtin_sid;
376
377                         builtin_sid = dom_sid_parse_talloc(torture, SID_BUILTIN);
378
379                         torture_assert_str_equal(torture,
380                                                  listd[i].netbios_name,
381                                                  NAME_BUILTIN,
382                                                  "first domain should be 'BUILTIN'");
383
384                         torture_assert_str_equal(torture,
385                                                  listd[i].dns_name,
386                                                  "",
387                                                  "BUILTIN domain should not have a dns name");
388
389                         ok = dom_sid_equal(builtin_sid,
390                                            listd[i].sid);
391                         torture_assert(torture, ok, "BUILTIN domain should have S-1-5-32");
392
393                         continue;
394                 }
395
396                 /*
397                  * TODO: verify the content of the 2nd and 3rd (in member server mode)
398                  *       domain entries
399                  */
400         }
401
402         return true;
403 }
404
405 static bool torture_winbind_struct_domain_info(struct torture_context *torture)
406 {
407         bool ok;
408         struct torture_trust_domain *listd = NULL;
409         uint32_t i;
410
411         torture_comment(torture, "Running WINBINDD_DOMAIN_INFO (struct based)\n");
412
413         ok = get_trusted_domains(torture, &listd);
414         torture_assert(torture, ok, "failed to get trust list");
415
416         for (i=0; listd && listd[i].netbios_name; i++) {
417                 struct winbindd_request req;
418                 struct winbindd_response rep;
419                 struct dom_sid *sid;
420                 char *flagstr = talloc_strdup(torture," ");
421
422                 ZERO_STRUCT(req);
423                 ZERO_STRUCT(rep);
424
425                 fstrcpy(req.domain_name, listd[i].netbios_name);
426
427                 DO_STRUCT_REQ_REP(WINBINDD_DOMAIN_INFO, &req, &rep);
428
429                 torture_assert_str_equal(torture,
430                                          rep.data.domain_info.name,
431                                          listd[i].netbios_name,
432                                          "Netbios domain name doesn't match");
433
434                 torture_assert_str_equal(torture,
435                                          rep.data.domain_info.alt_name,
436                                          listd[i].dns_name,
437                                          "DNS domain name doesn't match");
438
439                 sid = dom_sid_parse_talloc(torture, rep.data.domain_info.sid);
440                 torture_assert(torture, sid, "Failed to parse SID");
441
442                 ok = dom_sid_equal(listd[i].sid, sid);
443                 torture_assert(torture, ok, "SID's doesn't match");
444
445                 if (rep.data.domain_info.primary) {
446                         flagstr = talloc_strdup_append(flagstr, "PR ");
447                 }
448
449                 if (rep.data.domain_info.active_directory) {
450                         torture_assert(torture,
451                                        strlen(rep.data.domain_info.alt_name)>0,
452                                        "Active Directory without DNS name");
453                         flagstr = talloc_strdup_append(flagstr, "AD ");
454                 }
455
456                 if (rep.data.domain_info.native_mode) {
457                         torture_assert(torture,
458                                        rep.data.domain_info.active_directory,
459                                        "Native-Mode, but no Active Directory");
460                         flagstr = talloc_strdup_append(flagstr, "NA ");
461                 }
462
463                 torture_comment(torture, "DOMAIN '%s' => '%s' [%s]\n",
464                                 rep.data.domain_info.name,
465                                 rep.data.domain_info.alt_name,
466                                 flagstr);
467         }
468
469         return true;
470 }
471
472 static bool torture_winbind_struct_getdcname(struct torture_context *torture)
473 {
474         bool ok;
475         bool strict = torture_setting_bool(torture, "strict mode", false);
476         struct torture_trust_domain *listd = NULL;
477         uint32_t i, count = 0;
478
479         torture_comment(torture, "Running WINBINDD_GETDCNAME (struct based)\n");
480
481         ok = get_trusted_domains(torture, &listd);
482         torture_assert(torture, ok, "failed to get trust list");
483
484         for (i=0; listd && listd[i].netbios_name; i++) {
485                 struct winbindd_request req;
486                 struct winbindd_response rep;
487
488                 ZERO_STRUCT(req);
489                 ZERO_STRUCT(rep);
490
491                 fstrcpy(req.domain_name, listd[i].netbios_name);
492
493                 ok = true;
494                 DO_STRUCT_REQ_REP_EXT(WINBINDD_GETDCNAME, &req, &rep,
495                                       NSS_STATUS_SUCCESS,
496                                       (i <2 || strict), ok = false,
497                                       talloc_asprintf(torture, "DOMAIN '%s'",
498                                                       req.domain_name));
499                 if (!ok) continue;
500
501                 /* TODO: check rep.data.dc_name; */
502                 torture_comment(torture, "DOMAIN '%s' => DCNAME '%s'\n",
503                                 req.domain_name, rep.data.dc_name);
504                 count++;
505         }
506
507         if (strict) {
508                 torture_assert(torture, count > 0,
509                                "WiNBINDD_GETDCNAME was not tested");
510         }
511         return true;
512 }
513
514 static bool torture_winbind_struct_dsgetdcname(struct torture_context *torture)
515 {
516         bool ok;
517         bool strict = torture_setting_bool(torture, "strict mode", false);
518         struct torture_trust_domain *listd = NULL;
519         uint32_t i;
520         uint32_t count = 0;
521
522         torture_comment(torture, "Running WINBINDD_DSGETDCNAME (struct based)\n");
523
524         ok = get_trusted_domains(torture, &listd);
525         torture_assert(torture, ok, "failed to get trust list");
526
527         for (i=0; listd && listd[i].netbios_name; i++) {
528                 struct winbindd_request req;
529                 struct winbindd_response rep;
530
531                 ZERO_STRUCT(req);
532                 ZERO_STRUCT(rep);
533
534                 if (strlen(listd[i].dns_name) == 0) continue;
535
536                 /*
537                  * TODO: remove this and let winbindd give no dns name
538                  *       for NT4 domains
539                  */
540                 if (strcmp(listd[i].dns_name, listd[i].netbios_name) == 0) {
541                         continue;
542                 }
543
544                 fstrcpy(req.domain_name, listd[i].dns_name);
545
546                 /* TODO: test more flag combinations */
547                 req.flags = DS_DIRECTORY_SERVICE_REQUIRED;
548
549                 ok = true;
550                 DO_STRUCT_REQ_REP_EXT(WINBINDD_DSGETDCNAME, &req, &rep,
551                                       NSS_STATUS_SUCCESS,
552                                       strict, ok = false,
553                                       talloc_asprintf(torture, "DOMAIN '%s'",
554                                                       req.domain_name));
555                 if (!ok) continue;
556
557                 /* TODO: check rep.data.dc_name; */
558                 torture_comment(torture, "DOMAIN '%s' => DCNAME '%s'\n",
559                                 req.domain_name, rep.data.dc_name);
560
561                 count++;
562         }
563
564         if (count == 0) {
565                 torture_warning(torture, "WINBINDD_DSGETDCNAME"
566                                 " was not tested with %d non-AD domains",
567                                 i);
568         }
569
570         if (strict) {
571                 torture_assert(torture, count > 0,
572                                "WiNBINDD_DSGETDCNAME was not tested");
573         }
574
575         return true;
576 }
577
578 static bool get_user_list(struct torture_context *torture, char ***users)
579 {
580         struct winbindd_request req;
581         struct winbindd_response rep;
582         char **u = NULL;
583         uint32_t count;
584         char name[256];
585         const char *extra_data;
586
587         ZERO_STRUCT(req);
588         ZERO_STRUCT(rep);
589
590         DO_STRUCT_REQ_REP(WINBINDD_LIST_USERS, &req, &rep);
591
592         extra_data = (char *)rep.extra_data.data;
593         torture_assert(torture, extra_data, "NULL extra data");
594
595         for(count = 0;
596             next_token(&extra_data, name, ",", sizeof(name));
597             count++)
598         {
599                 u = talloc_realloc(torture, u, char *, count + 2);
600                 u[count+1] = NULL;
601                 u[count] = talloc_strdup(u, name);
602         }
603
604         SAFE_FREE(rep.extra_data.data);
605
606         *users = u;
607         return true;
608 }
609
610 static bool torture_winbind_struct_list_users(struct torture_context *torture)
611 {
612         char **users;
613         uint32_t count;
614         bool ok;
615
616         torture_comment(torture, "Running WINBINDD_LIST_USERS (struct based)\n");
617
618         ok = get_user_list(torture, &users);
619         torture_assert(torture, ok, "failed to get group list");
620
621         for (count = 0; users[count]; count++) { }
622
623         torture_comment(torture, "got %d users\n", count);
624
625         return true;
626 }
627
628 static bool get_group_list(struct torture_context *torture, char ***groups)
629 {
630         struct winbindd_request req;
631         struct winbindd_response rep;
632         char **g = NULL;
633         uint32_t count;
634         char name[256];
635         const char *extra_data;
636
637         ZERO_STRUCT(req);
638         ZERO_STRUCT(rep);
639
640         DO_STRUCT_REQ_REP(WINBINDD_LIST_GROUPS, &req, &rep);
641
642         extra_data = (char *)rep.extra_data.data;
643         torture_assert(torture, extra_data, "NULL extra data");
644
645         for(count = 0;
646             next_token(&extra_data, name, ",", sizeof(name));
647             count++)
648         {
649                 g = talloc_realloc(torture, g, char *, count + 2);
650                 g[count+1] = NULL;
651                 g[count] = talloc_strdup(g, name);
652         }
653
654         SAFE_FREE(rep.extra_data.data);
655
656         *groups = g;
657         return true;
658 }
659
660 static bool torture_winbind_struct_list_groups(struct torture_context *torture)
661 {
662         char **groups;
663         uint32_t count;
664         bool ok;
665
666         torture_comment(torture, "Running WINBINDD_LIST_GROUPS (struct based)\n");
667
668         ok = get_group_list(torture, &groups);
669         torture_assert(torture, ok, "failed to get group list");
670
671         for (count = 0; groups[count]; count++) { }
672
673         torture_comment(torture, "got %d groups\n", count);
674
675         return true;
676 }
677
678 struct torture_domain_sequence {
679         const char *netbios_name;
680         uint32_t seq;
681 };
682
683 static bool get_sequence_numbers(struct torture_context *torture,
684                                  struct torture_domain_sequence **seqs)
685 {
686         struct winbindd_request req;
687         struct winbindd_response rep;
688         const char *extra_data;
689         char line[256];
690         uint32_t count = 0;
691         struct torture_domain_sequence *s = NULL;
692
693         ZERO_STRUCT(req);
694         ZERO_STRUCT(rep);
695
696         DO_STRUCT_REQ_REP(WINBINDD_SHOW_SEQUENCE, &req, &rep);
697
698         extra_data = (char *)rep.extra_data.data;
699         torture_assert(torture, extra_data, "NULL sequence list");
700
701         while (next_token(&extra_data, line, "\n", sizeof(line))) {
702                 char *p, *lp;
703                 uint32_t seq;
704
705                 s = talloc_realloc(torture, s, struct torture_domain_sequence,
706                                    count + 2);
707                 ZERO_STRUCT(s[count+1]);
708
709                 lp = line;
710                 p = strchr(lp, ' ');
711                 torture_assert(torture, p, "invalid line format");
712                 *p = 0;
713                 s[count].netbios_name = talloc_strdup(s, lp);
714
715                 lp = p+1;
716                 torture_assert(torture, strncmp(lp, ": ", 2) == 0,
717                                "invalid line format");
718                 lp += 2;
719                 if (strcmp(lp, "DISCONNECTED") == 0) {
720                         seq = (uint32_t)-1;
721                 } else {
722                         seq = (uint32_t)strtol(lp, &p, 10);
723                         torture_assert(torture, (*p == '\0'),
724                                        "invalid line format");
725                         torture_assert(torture, (seq != (uint32_t)-1),
726                                        "sequence number -1 encountered");
727                 }
728                 s[count].seq = seq;
729
730                 count++;
731         }
732         SAFE_FREE(rep.extra_data.data);
733
734         torture_assert(torture, count >= 2, "The list of domain sequence "
735                        "numbers should contain 2 entries");
736
737         *seqs = s;
738         return true;
739 }
740
741 static bool torture_winbind_struct_show_sequence(struct torture_context *torture)
742 {
743         bool ok;
744         uint32_t i;
745         struct torture_trust_domain *domlist = NULL;
746         struct torture_domain_sequence *s = NULL;
747
748         torture_comment(torture, "Running WINBINDD_SHOW_SEQUENCE (struct based)\n");
749
750         ok = get_sequence_numbers(torture, &s);
751         torture_assert(torture, ok, "failed to get list of sequence numbers");
752
753         ok = get_trusted_domains(torture, &domlist);
754         torture_assert(torture, ok, "failed to get trust list");
755
756         for (i=0; domlist[i].netbios_name; i++) {
757                 struct winbindd_request req;
758                 struct winbindd_response rep;
759                 uint32_t seq;
760
761                 torture_assert(torture, s[i].netbios_name,
762                                "more domains recieved in second run");
763                 torture_assert_str_equal(torture, domlist[i].netbios_name,
764                                          s[i].netbios_name,
765                                          "inconsistent order of domain lists");
766
767                 ZERO_STRUCT(req);
768                 ZERO_STRUCT(rep);
769                 fstrcpy(req.domain_name, domlist[i].netbios_name);
770
771                 DO_STRUCT_REQ_REP(WINBINDD_SHOW_SEQUENCE, &req, &rep);
772
773                 seq = rep.data.sequence_number;
774
775                 if (i == 0) {
776                         torture_assert(torture, (seq != (uint32_t)-1),
777                                        "BUILTIN domain disconnected");
778                 } else if (i == 1) {
779                         torture_assert(torture, (seq != (uint32_t)-1),
780                                        "local domain disconnected");
781                 }
782
783
784                 if (seq == (uint32_t)-1) {
785                         torture_comment(torture, " * %s : DISCONNECTED\n",
786                                         req.domain_name);
787                 } else {
788                         torture_comment(torture, " * %s : %d\n",
789                                         req.domain_name, seq);
790                 }
791                 torture_assert(torture, (seq >= s[i].seq),
792                                "illegal sequence number encountered");
793         }
794
795         return true;
796 }
797
798 static bool torture_winbind_struct_setpwent(struct torture_context *torture)
799 {
800         struct winbindd_request req;
801         struct winbindd_response rep;
802
803         torture_comment(torture, "Running WINBINDD_SETPWENT (struct based)\n");
804
805         ZERO_STRUCT(req);
806         ZERO_STRUCT(rep);
807
808         DO_STRUCT_REQ_REP(WINBINDD_SETPWENT, &req, &rep);
809
810         return true;
811 }
812
813 static bool torture_winbind_struct_getpwent(struct torture_context *torture)
814 {
815         struct winbindd_request req;
816         struct winbindd_response rep;
817         struct winbindd_pw *pwent;
818
819         torture_comment(torture, "Running WINBINDD_GETPWENT (struct based)\n");
820
821         torture_comment(torture, " - Running WINBINDD_SETPWENT first\n");
822         ZERO_STRUCT(req);
823         ZERO_STRUCT(rep);
824         DO_STRUCT_REQ_REP(WINBINDD_SETPWENT, &req, &rep);
825
826         torture_comment(torture, " - Running WINBINDD_GETPWENT now\n");
827         ZERO_STRUCT(req);
828         ZERO_STRUCT(rep);
829         req.data.num_entries = 1;
830         DO_STRUCT_REQ_REP(WINBINDD_GETPWENT, &req, &rep);
831         pwent = (struct winbindd_pw *)rep.extra_data.data;
832         torture_assert(torture, (pwent != NULL), "NULL pwent");
833         torture_comment(torture, "name: %s, uid: %d, gid: %d, shell: %s\n",
834                         pwent->pw_name, pwent->pw_uid, pwent->pw_gid,
835                         pwent->pw_shell);
836
837         return true;
838 }
839
840 static bool torture_winbind_struct_endpwent(struct torture_context *torture)
841 {
842         struct winbindd_request req;
843         struct winbindd_response rep;
844
845         torture_comment(torture, "Running WINBINDD_ENDPWENT (struct based)\n");
846
847         ZERO_STRUCT(req);
848         ZERO_STRUCT(rep);
849
850         DO_STRUCT_REQ_REP(WINBINDD_ENDPWENT, &req, &rep);
851
852         return true;
853 }
854
855 /* Copy of parse_domain_user from winbindd_util.c.  Parse a string of the
856    form DOMAIN/user into a domain and a user */
857
858 static bool parse_domain_user(struct torture_context *torture,
859                               const char *domuser, fstring domain,
860                               fstring user)
861 {
862         char *p = strchr(domuser, winbind_separator(torture));
863         char *dom;
864
865         if (!p) {
866                 /* Maybe it was a UPN? */
867                 if ((p = strchr(domuser, '@')) != NULL) {
868                         fstrcpy(domain, "");
869                         fstrcpy(user, domuser);
870                         return true;
871                 }
872
873                 fstrcpy(user, domuser);
874                 get_winbind_domain(torture, &dom);
875                 fstrcpy(domain, dom);
876                 return true;
877         }
878
879         fstrcpy(user, p+1);
880         fstrcpy(domain, domuser);
881         domain[PTR_DIFF(p, domuser)] = 0;
882         strupper_m(domain);
883
884         return true;
885 }
886
887 static bool lookup_name_sid_list(struct torture_context *torture, char **list)
888 {
889         uint32_t count;
890
891         for (count = 0; list[count]; count++) {
892                 struct winbindd_request req;
893                 struct winbindd_response rep;
894                 char *sid;
895                 char *name;
896
897                 ZERO_STRUCT(req);
898                 ZERO_STRUCT(rep);
899
900                 parse_domain_user(torture, list[count], req.data.name.dom_name,
901                                   req.data.name.name);
902
903                 DO_STRUCT_REQ_REP(WINBINDD_LOOKUPNAME, &req, &rep);
904
905                 sid = talloc_strdup(torture, rep.data.sid.sid);
906
907                 ZERO_STRUCT(req);
908                 ZERO_STRUCT(rep);
909
910                 fstrcpy(req.data.sid, sid);
911
912                 DO_STRUCT_REQ_REP(WINBINDD_LOOKUPSID, &req, &rep);
913
914                 name = talloc_asprintf(torture, "%s%c%s",
915                                        rep.data.name.dom_name,
916                                        winbind_separator(torture),
917                                        rep.data.name.name);
918
919                 torture_assert_casestr_equal(torture, list[count], name,
920                                          "LOOKUP_SID after LOOKUP_NAME != id");
921
922 #if 0
923                 torture_comment(torture, " %s -> %s -> %s\n", list[count],
924                                 sid, name);
925 #endif
926
927                 talloc_free(sid);
928                 talloc_free(name);
929         }
930
931         return true;
932 }
933
934 static bool name_is_in_list(const char *name, const char **list)
935 {
936         uint32_t count;
937
938         for (count = 0; list[count]; count++) {
939                 if (strequal(name, list[count])) {
940                         return true;
941                 }
942         }
943         return false;
944 }
945
946 static bool torture_winbind_struct_lookup_name_sid(struct torture_context *torture)
947 {
948         struct winbindd_request req;
949         struct winbindd_response rep;
950         const char *invalid_sid = "S-0-0-7";
951         char *domain;
952         const char *invalid_user = "noone";
953         char *invalid_name;
954         bool strict = torture_setting_bool(torture, "strict mode", false);
955         char **users;
956         char **groups;
957         uint32_t count;
958         bool ok;
959
960         torture_comment(torture, "Running WINBINDD_LOOKUP_NAME_SID (struct based)\n");
961
962         ok = get_user_list(torture, &users);
963         torture_assert(torture, ok, "failed to retrieve list of users");
964         lookup_name_sid_list(torture, users);
965
966         ok = get_group_list(torture, &groups);
967         torture_assert(torture, ok, "failed to retrieve list of groups");
968         lookup_name_sid_list(torture, groups);
969
970         ZERO_STRUCT(req);
971         ZERO_STRUCT(rep);
972
973         fstrcpy(req.data.sid, invalid_sid);
974
975         ok = true;
976         DO_STRUCT_REQ_REP_EXT(WINBINDD_LOOKUPSID, &req, &rep,
977                               NSS_STATUS_NOTFOUND,
978                               strict,
979                               ok=false,
980                               talloc_asprintf(torture,
981                                               "invalid sid %s was resolved",
982                                               invalid_sid));
983
984         ZERO_STRUCT(req);
985         ZERO_STRUCT(rep);
986
987         /* try to find an invalid name... */
988
989         count = 0;
990         get_winbind_domain(torture, &domain);
991         do {
992                 count++;
993                 invalid_name = talloc_asprintf(torture, "%s\\%s%u",
994                                                domain,
995                                                invalid_user, count);
996         } while(name_is_in_list(invalid_name, (const char **)users) ||
997                 name_is_in_list(invalid_name, (const char **)groups));
998
999         fstrcpy(req.data.name.dom_name, domain);
1000         fstrcpy(req.data.name.name,
1001                 talloc_asprintf(torture, "%s%u", invalid_user,
1002                                 count));
1003
1004         ok = true;
1005         DO_STRUCT_REQ_REP_EXT(WINBINDD_LOOKUPNAME, &req, &rep,
1006                               NSS_STATUS_NOTFOUND,
1007                               strict,
1008                               ok=false,
1009                               talloc_asprintf(torture,
1010                                               "invalid name %s was resolved",
1011                                               invalid_name));
1012
1013         talloc_free(users);
1014         talloc_free(groups);
1015
1016         return true;
1017 }
1018
1019 struct torture_suite *torture_winbind_struct_init(void)
1020 {
1021         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "STRUCT");
1022
1023         torture_suite_add_simple_test(suite, "INTERFACE_VERSION", torture_winbind_struct_interface_version);
1024         torture_suite_add_simple_test(suite, "PING", torture_winbind_struct_ping);
1025         torture_suite_add_simple_test(suite, "INFO", torture_winbind_struct_info);
1026         torture_suite_add_simple_test(suite, "PRIV_PIPE_DIR", torture_winbind_struct_priv_pipe_dir);
1027         torture_suite_add_simple_test(suite, "NETBIOS_NAME", torture_winbind_struct_netbios_name);
1028         torture_suite_add_simple_test(suite, "DOMAIN_NAME", torture_winbind_struct_domain_name);
1029         torture_suite_add_simple_test(suite, "CHECK_MACHACC", torture_winbind_struct_check_machacc);
1030         torture_suite_add_simple_test(suite, "LIST_TRUSTDOM", torture_winbind_struct_list_trustdom);
1031         torture_suite_add_simple_test(suite, "DOMAIN_INFO", torture_winbind_struct_domain_info);
1032         torture_suite_add_simple_test(suite, "GETDCNAME", torture_winbind_struct_getdcname);
1033         torture_suite_add_simple_test(suite, "DSGETDCNAME", torture_winbind_struct_dsgetdcname);
1034         torture_suite_add_simple_test(suite, "LIST_USERS", torture_winbind_struct_list_users);
1035         torture_suite_add_simple_test(suite, "LIST_GROUPS", torture_winbind_struct_list_groups);
1036         torture_suite_add_simple_test(suite, "SHOW_SEQUENCE", torture_winbind_struct_show_sequence);
1037         torture_suite_add_simple_test(suite, "SETPWENT", torture_winbind_struct_setpwent);
1038         torture_suite_add_simple_test(suite, "GETPWENT", torture_winbind_struct_getpwent);
1039         torture_suite_add_simple_test(suite, "ENDPWENT", torture_winbind_struct_endpwent);
1040         torture_suite_add_simple_test(suite, "LOOKUP_NAME_SID", torture_winbind_struct_lookup_name_sid);
1041
1042         suite->description = talloc_strdup(suite, "WINBIND - struct based protocol tests");
1043
1044         return suite;
1045 }