source4/torture: Fix prototypes for all functions.
[mdw/samba.git] / source4 / torture / winbind / struct_based.c
1 /*
2    Unix SMB/CIFS implementation.
3    SMB torture tester - winbind struct based protocol
4    Copyright (C) Stefan Metzmacher 2007
5    Copyright (C) Michael Adam 2007
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "torture/torture.h"
23 #include "nsswitch/winbind_client.h"
24 #include "libcli/security/security.h"
25 #include "librpc/gen_ndr/netlogon.h"
26 #include "param/param.h"
27 #include "../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(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 #define DO_STRUCT_REQ_REP(op,req,rep) do { \
56         bool __noop = false; \
57         DO_STRUCT_REQ_REP_EXT(op,req,rep,NSS_STATUS_SUCCESS,true,__noop=true,NULL); \
58 } while (0)
59
60 static bool torture_winbind_struct_interface_version(struct torture_context *torture)
61 {
62         struct winbindd_request req;
63         struct winbindd_response rep;
64
65         ZERO_STRUCT(req);
66         ZERO_STRUCT(rep);
67
68         torture_comment(torture, "Running WINBINDD_INTERFACE_VERSION (struct based)\n");
69
70         DO_STRUCT_REQ_REP(WINBINDD_INTERFACE_VERSION, &req, &rep);
71
72         torture_assert_int_equal(torture,
73                                  rep.data.interface_version,
74                                  WINBIND_INTERFACE_VERSION,
75                                  "winbind server and client doesn't match");
76
77         return true;
78 }
79
80 static bool torture_winbind_struct_ping(struct torture_context *torture)
81 {
82         struct timeval tv = timeval_current();
83         int timelimit = torture_setting_int(torture, "timelimit", 5);
84         uint32_t total = 0;
85
86         torture_comment(torture,
87                         "Running WINBINDD_PING (struct based) for %d seconds\n",
88                         timelimit);
89
90         while (timeval_elapsed(&tv) < timelimit) {
91                 DO_STRUCT_REQ_REP(WINBINDD_PING, NULL, NULL);
92                 total++;
93         }
94
95         torture_comment(torture,
96                         "%u (%.1f/s) WINBINDD_PING (struct based)\n",
97                         total, total / timeval_elapsed(&tv));
98
99         return true;
100 }
101
102
103 static char winbind_separator(struct torture_context *torture)
104 {
105         struct winbindd_response rep;
106
107         ZERO_STRUCT(rep);
108
109         DO_STRUCT_REQ_REP(WINBINDD_INFO, NULL, &rep);
110
111         return rep.data.info.winbind_separator;
112 }
113
114 static bool torture_winbind_struct_info(struct torture_context *torture)
115 {
116         struct winbindd_response rep;
117         const char *separator;
118
119         ZERO_STRUCT(rep);
120
121         torture_comment(torture, "Running WINBINDD_INFO (struct based)\n");
122
123         DO_STRUCT_REQ_REP(WINBINDD_INFO, NULL, &rep);
124
125         separator = torture_setting_string(torture,
126                                            "winbindd_separator",
127                                            lpcfg_winbind_separator(torture->lp_ctx));
128
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                                           lpcfg_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                                           lpcfg_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         char line[256];
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(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
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         const char *domain_name = torture_setting_string(torture,
479                                         "winbindd_netbios_domain",
480                                         lpcfg_workgroup(torture->lp_ctx));
481         struct torture_trust_domain *listd = NULL;
482         uint32_t i, count = 0;
483
484         torture_comment(torture, "Running WINBINDD_GETDCNAME (struct based)\n");
485
486         ok = get_trusted_domains(torture, &listd);
487         torture_assert(torture, ok, "failed to get trust list");
488
489         for (i=0; listd && listd[i].netbios_name; i++) {
490                 struct winbindd_request req;
491                 struct winbindd_response rep;
492
493                 /* getdcname is not expected to work on "BUILTIN" or our own
494                  * domain */
495                 if (strequal(listd[i].netbios_name, "BUILTIN") ||
496                     strequal(listd[i].netbios_name, domain_name)) {
497                         continue;
498                 }
499
500                 ZERO_STRUCT(req);
501                 ZERO_STRUCT(rep);
502
503                 fstrcpy(req.domain_name, listd[i].netbios_name);
504
505                 ok = true;
506                 DO_STRUCT_REQ_REP_EXT(WINBINDD_GETDCNAME, &req, &rep,
507                                       NSS_STATUS_SUCCESS,
508                                       (i <2 || strict), ok = false,
509                                       talloc_asprintf(torture, "DOMAIN '%s'",
510                                                       req.domain_name));
511                 if (!ok) continue;
512
513                 /* TODO: check rep.data.dc_name; */
514                 torture_comment(torture, "DOMAIN '%s' => DCNAME '%s'\n",
515                                 req.domain_name, rep.data.dc_name);
516                 count++;
517         }
518
519         if (strict) {
520                 torture_assert(torture, count > 0,
521                                "WiNBINDD_GETDCNAME was not tested");
522         }
523         return true;
524 }
525
526 static bool torture_winbind_struct_dsgetdcname(struct torture_context *torture)
527 {
528         bool ok;
529         bool strict = torture_setting_bool(torture, "strict mode", false);
530         struct torture_trust_domain *listd = NULL;
531         uint32_t i;
532         uint32_t count = 0;
533
534         torture_comment(torture, "Running WINBINDD_DSGETDCNAME (struct based)\n");
535
536         ok = get_trusted_domains(torture, &listd);
537         torture_assert(torture, ok, "failed to get trust list");
538
539         for (i=0; listd && listd[i].netbios_name; i++) {
540                 struct winbindd_request req;
541                 struct winbindd_response rep;
542
543                 ZERO_STRUCT(req);
544                 ZERO_STRUCT(rep);
545
546                 if (strlen(listd[i].dns_name) == 0) continue;
547
548                 /*
549                  * TODO: remove this and let winbindd give no dns name
550                  *       for NT4 domains
551                  */
552                 if (strcmp(listd[i].dns_name, listd[i].netbios_name) == 0) {
553                         continue;
554                 }
555
556                 fstrcpy(req.domain_name, listd[i].dns_name);
557
558                 /* TODO: test more flag combinations */
559                 req.flags = DS_DIRECTORY_SERVICE_REQUIRED;
560
561                 ok = true;
562                 DO_STRUCT_REQ_REP_EXT(WINBINDD_DSGETDCNAME, &req, &rep,
563                                       NSS_STATUS_SUCCESS,
564                                       strict, ok = false,
565                                       talloc_asprintf(torture, "DOMAIN '%s'",
566                                                       req.domain_name));
567                 if (!ok) continue;
568
569                 /* TODO: check rep.data.dc_name; */
570                 torture_comment(torture, "DOMAIN '%s' => DCNAME '%s'\n",
571                                 req.domain_name, rep.data.dc_name);
572
573                 count++;
574         }
575
576         if (count == 0) {
577                 torture_warning(torture, "WINBINDD_DSGETDCNAME"
578                                 " was not tested with %d non-AD domains",
579                                 i);
580         }
581
582         if (strict) {
583                 torture_assert(torture, count > 0,
584                                "WiNBINDD_DSGETDCNAME was not tested");
585         }
586
587         return true;
588 }
589
590 static bool get_user_list(struct torture_context *torture, char ***users)
591 {
592         struct winbindd_request req;
593         struct winbindd_response rep;
594         char **u = NULL;
595         uint32_t count;
596         char name[256];
597         const char *extra_data;
598
599         ZERO_STRUCT(req);
600         ZERO_STRUCT(rep);
601
602         DO_STRUCT_REQ_REP(WINBINDD_LIST_USERS, &req, &rep);
603
604         extra_data = (char *)rep.extra_data.data;
605         torture_assert(torture, extra_data, "NULL extra data");
606
607         for(count = 0;
608             next_token(&extra_data, name, ",", sizeof(name));
609             count++)
610         {
611                 u = talloc_realloc(torture, u, char *, count + 2);
612                 u[count+1] = NULL;
613                 u[count] = talloc_strdup(u, name);
614         }
615
616         SAFE_FREE(rep.extra_data.data);
617
618         *users = u;
619         return true;
620 }
621
622 static bool torture_winbind_struct_list_users(struct torture_context *torture)
623 {
624         char **users;
625         uint32_t count;
626         bool ok;
627
628         torture_comment(torture, "Running WINBINDD_LIST_USERS (struct based)\n");
629
630         ok = get_user_list(torture, &users);
631         torture_assert(torture, ok, "failed to get user list");
632
633         for (count = 0; users[count]; count++) { }
634
635         torture_comment(torture, "got %d users\n", count);
636
637         return true;
638 }
639
640 static bool get_group_list(struct torture_context *torture,
641                            unsigned int *num_entries,
642                            char ***groups)
643 {
644         struct winbindd_request req;
645         struct winbindd_response rep;
646         char **g = NULL;
647         uint32_t count;
648         char name[256];
649         const char *extra_data;
650
651         ZERO_STRUCT(req);
652         ZERO_STRUCT(rep);
653
654         DO_STRUCT_REQ_REP(WINBINDD_LIST_GROUPS, &req, &rep);
655         extra_data = (char *)rep.extra_data.data;
656
657         *num_entries = rep.data.num_entries;
658
659         if (*num_entries == 0) {
660                 torture_assert(torture, extra_data == NULL,
661                                "extra data is null for >0 reported entries\n");
662                 *groups = NULL;
663                 return true;
664         }
665
666         torture_assert(torture, extra_data, "NULL extra data");
667
668         for(count = 0;
669             next_token(&extra_data, name, ",", sizeof(name));
670             count++)
671         {
672                 g = talloc_realloc(torture, g, char *, count + 2);
673                 g[count+1] = NULL;
674                 g[count] = talloc_strdup(g, name);
675         }
676
677         SAFE_FREE(rep.extra_data.data);
678
679         torture_assert_int_equal(torture, *num_entries, count,
680                                  "Wrong number of group entries reported.");
681
682         *groups = g;
683         return true;
684 }
685
686 static bool torture_winbind_struct_list_groups(struct torture_context *torture)
687 {
688         char **groups;
689         uint32_t count;
690         bool ok;
691
692         torture_comment(torture, "Running WINBINDD_LIST_GROUPS (struct based)\n");
693
694         ok = get_group_list(torture, &count, &groups);
695         torture_assert(torture, ok, "failed to get group list");
696
697         torture_comment(torture, "got %d groups\n", count);
698
699         return true;
700 }
701
702 struct torture_domain_sequence {
703         const char *netbios_name;
704         uint32_t seq;
705 };
706
707 static bool get_sequence_numbers(struct torture_context *torture,
708                                  struct torture_domain_sequence **seqs)
709 {
710         struct winbindd_request req;
711         struct winbindd_response rep;
712         const char *extra_data;
713         char line[256];
714         uint32_t count = 0;
715         struct torture_domain_sequence *s = NULL;
716
717         ZERO_STRUCT(req);
718         ZERO_STRUCT(rep);
719
720         DO_STRUCT_REQ_REP(WINBINDD_SHOW_SEQUENCE, &req, &rep);
721
722         extra_data = (char *)rep.extra_data.data;
723         torture_assert(torture, extra_data, "NULL sequence list");
724
725         while (next_token(&extra_data, line, "\n", sizeof(line))) {
726                 char *p, *lp;
727                 uint32_t seq;
728
729                 s = talloc_realloc(torture, s, struct torture_domain_sequence,
730                                    count + 2);
731                 ZERO_STRUCT(s[count+1]);
732
733                 lp = line;
734                 p = strchr(lp, ' ');
735                 torture_assert(torture, p, "invalid line format");
736                 *p = 0;
737                 s[count].netbios_name = talloc_strdup(s, lp);
738
739                 lp = p+1;
740                 torture_assert(torture, strncmp(lp, ": ", 2) == 0,
741                                "invalid line format");
742                 lp += 2;
743                 if (strcmp(lp, "DISCONNECTED") == 0) {
744                         seq = (uint32_t)-1;
745                 } else {
746                         seq = (uint32_t)strtol(lp, &p, 10);
747                         torture_assert(torture, (*p == '\0'),
748                                        "invalid line format");
749                         torture_assert(torture, (seq != (uint32_t)-1),
750                                        "sequence number -1 encountered");
751                 }
752                 s[count].seq = seq;
753
754                 count++;
755         }
756         SAFE_FREE(rep.extra_data.data);
757
758         torture_assert(torture, count >= 2, "The list of domain sequence "
759                        "numbers should contain 2 entries");
760
761         *seqs = s;
762         return true;
763 }
764
765 static bool torture_winbind_struct_show_sequence(struct torture_context *torture)
766 {
767         bool ok;
768         uint32_t i;
769         struct torture_trust_domain *domlist = NULL;
770         struct torture_domain_sequence *s = NULL;
771
772         torture_comment(torture, "Running WINBINDD_SHOW_SEQUENCE (struct based)\n");
773
774         ok = get_sequence_numbers(torture, &s);
775         torture_assert(torture, ok, "failed to get list of sequence numbers");
776
777         ok = get_trusted_domains(torture, &domlist);
778         torture_assert(torture, ok, "failed to get trust list");
779
780         for (i=0; domlist[i].netbios_name; i++) {
781                 struct winbindd_request req;
782                 struct winbindd_response rep;
783                 uint32_t seq;
784
785                 torture_assert(torture, s[i].netbios_name,
786                                "more domains received in second run");
787                 torture_assert_str_equal(torture, domlist[i].netbios_name,
788                                          s[i].netbios_name,
789                                          "inconsistent order of domain lists");
790
791                 ZERO_STRUCT(req);
792                 ZERO_STRUCT(rep);
793                 fstrcpy(req.domain_name, domlist[i].netbios_name);
794
795                 DO_STRUCT_REQ_REP(WINBINDD_SHOW_SEQUENCE, &req, &rep);
796
797                 seq = rep.data.sequence_number;
798
799                 if (i == 0) {
800                         torture_assert(torture, (seq != (uint32_t)-1),
801                                        "BUILTIN domain disconnected");
802                 } else if (i == 1) {
803                         torture_assert(torture, (seq != (uint32_t)-1),
804                                        "local domain disconnected");
805                 }
806
807
808                 if (seq == (uint32_t)-1) {
809                         torture_comment(torture, " * %s : DISCONNECTED\n",
810                                         req.domain_name);
811                 } else {
812                         torture_comment(torture, " * %s : %d\n",
813                                         req.domain_name, seq);
814                 }
815                 torture_assert(torture, (seq >= s[i].seq),
816                                "illegal sequence number encountered");
817         }
818
819         return true;
820 }
821
822 static bool torture_winbind_struct_setpwent(struct torture_context *torture)
823 {
824         struct winbindd_request req;
825         struct winbindd_response rep;
826
827         torture_comment(torture, "Running WINBINDD_SETPWENT (struct based)\n");
828
829         ZERO_STRUCT(req);
830         ZERO_STRUCT(rep);
831
832         DO_STRUCT_REQ_REP(WINBINDD_SETPWENT, &req, &rep);
833
834         return true;
835 }
836
837 static bool torture_winbind_struct_getpwent(struct torture_context *torture)
838 {
839         struct winbindd_request req;
840         struct winbindd_response rep;
841         struct winbindd_pw *pwent;
842
843         torture_comment(torture, "Running WINBINDD_GETPWENT (struct based)\n");
844
845         torture_comment(torture, " - Running WINBINDD_SETPWENT first\n");
846         ZERO_STRUCT(req);
847         ZERO_STRUCT(rep);
848         DO_STRUCT_REQ_REP(WINBINDD_SETPWENT, &req, &rep);
849
850         torture_comment(torture, " - Running WINBINDD_GETPWENT now\n");
851         ZERO_STRUCT(req);
852         ZERO_STRUCT(rep);
853         req.data.num_entries = 1;
854         if (torture_setting_bool(torture, "samba3", false)) {
855                 bool __noop = false;
856                 DO_STRUCT_REQ_REP_EXT(WINBINDD_GETPWENT, &req, &rep,
857                                       NSS_STATUS_SUCCESS, false, __noop=true,
858                                       NULL);
859         } else {
860                 DO_STRUCT_REQ_REP(WINBINDD_GETPWENT, &req, &rep);
861         }
862         pwent = (struct winbindd_pw *)rep.extra_data.data;
863         if (!torture_setting_bool(torture, "samba3", false)) {
864                 torture_assert(torture, (pwent != NULL), "NULL pwent");
865         }
866         if (pwent) {
867                 torture_comment(torture, "name: %s, uid: %d, gid: %d, shell: %s\n",
868                                 pwent->pw_name, pwent->pw_uid, pwent->pw_gid,
869                                 pwent->pw_shell);
870         }
871
872         return true;
873 }
874
875 static bool torture_winbind_struct_endpwent(struct torture_context *torture)
876 {
877         struct winbindd_request req;
878         struct winbindd_response rep;
879
880         torture_comment(torture, "Running WINBINDD_ENDPWENT (struct based)\n");
881
882         ZERO_STRUCT(req);
883         ZERO_STRUCT(rep);
884
885         DO_STRUCT_REQ_REP(WINBINDD_ENDPWENT, &req, &rep);
886
887         return true;
888 }
889
890 /* Copy of parse_domain_user from winbindd_util.c.  Parse a string of the
891    form DOMAIN/user into a domain and a user */
892
893 static bool parse_domain_user(struct torture_context *torture,
894                               const char *domuser, fstring domain,
895                               fstring user)
896 {
897         char *p = strchr(domuser, winbind_separator(torture));
898         char *dom;
899
900         if (!p) {
901                 /* Maybe it was a UPN? */
902                 if ((p = strchr(domuser, '@')) != NULL) {
903                         fstrcpy(domain, "");
904                         fstrcpy(user, domuser);
905                         return true;
906                 }
907
908                 fstrcpy(user, domuser);
909                 get_winbind_domain(torture, &dom);
910                 fstrcpy(domain, dom);
911                 return true;
912         }
913
914         fstrcpy(user, p+1);
915         fstrcpy(domain, domuser);
916         domain[PTR_DIFF(p, domuser)] = 0;
917         strupper_m(domain);
918
919         return true;
920 }
921
922 static bool lookup_name_sid_list(struct torture_context *torture, char **list)
923 {
924         uint32_t count;
925
926         for (count = 0; list[count]; count++) {
927                 struct winbindd_request req;
928                 struct winbindd_response rep;
929                 char *sid;
930                 char *name;
931                 const char *domain_name = torture_setting_string(torture,
932                                                 "winbindd_netbios_domain",
933                                                 lpcfg_workgroup(torture->lp_ctx));
934
935                 ZERO_STRUCT(req);
936                 ZERO_STRUCT(rep);
937
938                 parse_domain_user(torture, list[count], req.data.name.dom_name,
939                                   req.data.name.name);
940
941                 DO_STRUCT_REQ_REP(WINBINDD_LOOKUPNAME, &req, &rep);
942
943                 sid = talloc_strdup(torture, rep.data.sid.sid);
944
945                 ZERO_STRUCT(req);
946                 ZERO_STRUCT(rep);
947
948                 fstrcpy(req.data.sid, sid);
949
950                 DO_STRUCT_REQ_REP(WINBINDD_LOOKUPSID, &req, &rep);
951
952                 if (strequal(rep.data.name.dom_name, domain_name)) {
953                         name = talloc_asprintf(torture, "%s",
954                                                rep.data.name.name);
955                 } else {
956                         name = talloc_asprintf(torture, "%s%c%s",
957                                                rep.data.name.dom_name,
958                                                winbind_separator(torture),
959                                                rep.data.name.name);
960                 }
961
962                 torture_assert_casestr_equal(torture, list[count], name,
963                                          "LOOKUP_SID after LOOKUP_NAME != id");
964
965 #if 0
966                 torture_comment(torture, " %s -> %s -> %s\n", list[count],
967                                 sid, name);
968 #endif
969
970                 talloc_free(sid);
971                 talloc_free(name);
972         }
973
974         return true;
975 }
976
977 static bool name_is_in_list(const char *name, const char **list)
978 {
979         uint32_t count;
980
981         for (count = 0; list && list[count]; count++) {
982                 if (strequal(name, list[count])) {
983                         return true;
984                 }
985         }
986         return false;
987 }
988
989 static bool torture_winbind_struct_lookup_name_sid(struct torture_context *torture)
990 {
991         struct winbindd_request req;
992         struct winbindd_response rep;
993         const char *invalid_sid = "S-0-0-7";
994         char *domain;
995         const char *invalid_user = "noone";
996         char *invalid_name;
997         bool strict = torture_setting_bool(torture, "strict mode", false);
998         char **users;
999         char **groups;
1000         uint32_t count, num_groups;
1001         bool ok;
1002
1003         torture_comment(torture, "Running WINBINDD_LOOKUP_NAME_SID (struct based)\n");
1004
1005         ok = get_user_list(torture, &users);
1006         torture_assert(torture, ok, "failed to retrieve list of users");
1007         lookup_name_sid_list(torture, users);
1008
1009         ok = get_group_list(torture, &num_groups, &groups);
1010         torture_assert(torture, ok, "failed to retrieve list of groups");
1011         if (num_groups > 0) {
1012                 lookup_name_sid_list(torture, groups);
1013         }
1014
1015         ZERO_STRUCT(req);
1016         ZERO_STRUCT(rep);
1017
1018         fstrcpy(req.data.sid, invalid_sid);
1019
1020         ok = true;
1021         DO_STRUCT_REQ_REP_EXT(WINBINDD_LOOKUPSID, &req, &rep,
1022                               NSS_STATUS_NOTFOUND,
1023                               strict,
1024                               ok=false,
1025                               talloc_asprintf(torture,
1026                                               "invalid sid %s was resolved",
1027                                               invalid_sid));
1028
1029         ZERO_STRUCT(req);
1030         ZERO_STRUCT(rep);
1031
1032         /* try to find an invalid name... */
1033
1034         count = 0;
1035         get_winbind_domain(torture, &domain);
1036         do {
1037                 count++;
1038                 invalid_name = talloc_asprintf(torture, "%s\\%s%u",
1039                                                domain,
1040                                                invalid_user, count);
1041         } while(name_is_in_list(invalid_name, (const char **)users) ||
1042                 name_is_in_list(invalid_name, (const char **)groups));
1043
1044         fstrcpy(req.data.name.dom_name, domain);
1045         fstrcpy(req.data.name.name,
1046                 talloc_asprintf(torture, "%s%u", invalid_user,
1047                                 count));
1048
1049         ok = true;
1050         DO_STRUCT_REQ_REP_EXT(WINBINDD_LOOKUPNAME, &req, &rep,
1051                               NSS_STATUS_NOTFOUND,
1052                               strict,
1053                               ok=false,
1054                               talloc_asprintf(torture,
1055                                               "invalid name %s was resolved",
1056                                               invalid_name));
1057
1058         talloc_free(users);
1059         talloc_free(groups);
1060
1061         return true;
1062 }
1063
1064 struct torture_suite *torture_winbind_struct_init(void)
1065 {
1066         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "struct");
1067
1068         torture_suite_add_simple_test(suite, "interface_version", torture_winbind_struct_interface_version);
1069         torture_suite_add_simple_test(suite, "ping", torture_winbind_struct_ping);
1070         torture_suite_add_simple_test(suite, "info", torture_winbind_struct_info);
1071         torture_suite_add_simple_test(suite, "priv_pipe_dir", torture_winbind_struct_priv_pipe_dir);
1072         torture_suite_add_simple_test(suite, "netbios_name", torture_winbind_struct_netbios_name);
1073         torture_suite_add_simple_test(suite, "domain_name", torture_winbind_struct_domain_name);
1074         torture_suite_add_simple_test(suite, "check_machacc", torture_winbind_struct_check_machacc);
1075         torture_suite_add_simple_test(suite, "list_trustdom", torture_winbind_struct_list_trustdom);
1076         torture_suite_add_simple_test(suite, "domain_info", torture_winbind_struct_domain_info);
1077         torture_suite_add_simple_test(suite, "getdcname", torture_winbind_struct_getdcname);
1078         torture_suite_add_simple_test(suite, "dsgetdcname", torture_winbind_struct_dsgetdcname);
1079         torture_suite_add_simple_test(suite, "list_users", torture_winbind_struct_list_users);
1080         torture_suite_add_simple_test(suite, "list_groups", torture_winbind_struct_list_groups);
1081         torture_suite_add_simple_test(suite, "show_sequence", torture_winbind_struct_show_sequence);
1082         torture_suite_add_simple_test(suite, "setpwent", torture_winbind_struct_setpwent);
1083         torture_suite_add_simple_test(suite, "getpwent", torture_winbind_struct_getpwent);
1084         torture_suite_add_simple_test(suite, "endpwent", torture_winbind_struct_endpwent);
1085         torture_suite_add_simple_test(suite, "lookup_name_sid", torture_winbind_struct_lookup_name_sid);
1086
1087         suite->description = talloc_strdup(suite, "WINBIND - struct based protocol tests");
1088
1089         return suite;
1090 }