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