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