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