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