s3 selftest: Fix LOOKUP_SID test.
[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 user 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, int *num_entries,
639                            char ***groups)
640 {
641         struct winbindd_request req;
642         struct winbindd_response rep;
643         char **g = NULL;
644         uint32_t count;
645         char name[256];
646         const char *extra_data;
647
648         ZERO_STRUCT(req);
649         ZERO_STRUCT(rep);
650
651         DO_STRUCT_REQ_REP(WINBINDD_LIST_GROUPS, &req, &rep);
652         extra_data = (char *)rep.extra_data.data;
653
654         *num_entries = rep.data.num_entries;
655
656         if (*num_entries == 0) {
657                 torture_assert(torture, extra_data == NULL,
658                                "extra data is null for >0 reported entries\n");
659                 *groups = NULL;
660                 return true;
661         }
662
663         torture_assert(torture, extra_data, "NULL extra data");
664
665         for(count = 0;
666             next_token(&extra_data, name, ",", sizeof(name));
667             count++)
668         {
669                 g = talloc_realloc(torture, g, char *, count + 2);
670                 g[count+1] = NULL;
671                 g[count] = talloc_strdup(g, name);
672         }
673
674         SAFE_FREE(rep.extra_data.data);
675
676         torture_assert_int_equal(torture, *num_entries, count,
677                                  "Wrong number of group entries reported.");
678
679         *groups = g;
680         return true;
681 }
682
683 static bool torture_winbind_struct_list_groups(struct torture_context *torture)
684 {
685         char **groups;
686         uint32_t count;
687         bool ok;
688
689         torture_comment(torture, "Running WINBINDD_LIST_GROUPS (struct based)\n");
690
691         ok = get_group_list(torture, &count, &groups);
692         torture_assert(torture, ok, "failed to get group list");
693
694         torture_comment(torture, "got %d groups\n", count);
695
696         return true;
697 }
698
699 struct torture_domain_sequence {
700         const char *netbios_name;
701         uint32_t seq;
702 };
703
704 static bool get_sequence_numbers(struct torture_context *torture,
705                                  struct torture_domain_sequence **seqs)
706 {
707         struct winbindd_request req;
708         struct winbindd_response rep;
709         const char *extra_data;
710         char line[256];
711         uint32_t count = 0;
712         struct torture_domain_sequence *s = NULL;
713
714         ZERO_STRUCT(req);
715         ZERO_STRUCT(rep);
716
717         DO_STRUCT_REQ_REP(WINBINDD_SHOW_SEQUENCE, &req, &rep);
718
719         extra_data = (char *)rep.extra_data.data;
720         torture_assert(torture, extra_data, "NULL sequence list");
721
722         while (next_token(&extra_data, line, "\n", sizeof(line))) {
723                 char *p, *lp;
724                 uint32_t seq;
725
726                 s = talloc_realloc(torture, s, struct torture_domain_sequence,
727                                    count + 2);
728                 ZERO_STRUCT(s[count+1]);
729
730                 lp = line;
731                 p = strchr(lp, ' ');
732                 torture_assert(torture, p, "invalid line format");
733                 *p = 0;
734                 s[count].netbios_name = talloc_strdup(s, lp);
735
736                 lp = p+1;
737                 torture_assert(torture, strncmp(lp, ": ", 2) == 0,
738                                "invalid line format");
739                 lp += 2;
740                 if (strcmp(lp, "DISCONNECTED") == 0) {
741                         seq = (uint32_t)-1;
742                 } else {
743                         seq = (uint32_t)strtol(lp, &p, 10);
744                         torture_assert(torture, (*p == '\0'),
745                                        "invalid line format");
746                         torture_assert(torture, (seq != (uint32_t)-1),
747                                        "sequence number -1 encountered");
748                 }
749                 s[count].seq = seq;
750
751                 count++;
752         }
753         SAFE_FREE(rep.extra_data.data);
754
755         torture_assert(torture, count >= 2, "The list of domain sequence "
756                        "numbers should contain 2 entries");
757
758         *seqs = s;
759         return true;
760 }
761
762 static bool torture_winbind_struct_show_sequence(struct torture_context *torture)
763 {
764         bool ok;
765         uint32_t i;
766         struct torture_trust_domain *domlist = NULL;
767         struct torture_domain_sequence *s = NULL;
768
769         torture_comment(torture, "Running WINBINDD_SHOW_SEQUENCE (struct based)\n");
770
771         ok = get_sequence_numbers(torture, &s);
772         torture_assert(torture, ok, "failed to get list of sequence numbers");
773
774         ok = get_trusted_domains(torture, &domlist);
775         torture_assert(torture, ok, "failed to get trust list");
776
777         for (i=0; domlist[i].netbios_name; i++) {
778                 struct winbindd_request req;
779                 struct winbindd_response rep;
780                 uint32_t seq;
781
782                 torture_assert(torture, s[i].netbios_name,
783                                "more domains recieved in second run");
784                 torture_assert_str_equal(torture, domlist[i].netbios_name,
785                                          s[i].netbios_name,
786                                          "inconsistent order of domain lists");
787
788                 ZERO_STRUCT(req);
789                 ZERO_STRUCT(rep);
790                 fstrcpy(req.domain_name, domlist[i].netbios_name);
791
792                 DO_STRUCT_REQ_REP(WINBINDD_SHOW_SEQUENCE, &req, &rep);
793
794                 seq = rep.data.sequence_number;
795
796                 if (i == 0) {
797                         torture_assert(torture, (seq != (uint32_t)-1),
798                                        "BUILTIN domain disconnected");
799                 } else if (i == 1) {
800                         torture_assert(torture, (seq != (uint32_t)-1),
801                                        "local domain disconnected");
802                 }
803
804
805                 if (seq == (uint32_t)-1) {
806                         torture_comment(torture, " * %s : DISCONNECTED\n",
807                                         req.domain_name);
808                 } else {
809                         torture_comment(torture, " * %s : %d\n",
810                                         req.domain_name, seq);
811                 }
812                 torture_assert(torture, (seq >= s[i].seq),
813                                "illegal sequence number encountered");
814         }
815
816         return true;
817 }
818
819 static bool torture_winbind_struct_setpwent(struct torture_context *torture)
820 {
821         struct winbindd_request req;
822         struct winbindd_response rep;
823
824         torture_comment(torture, "Running WINBINDD_SETPWENT (struct based)\n");
825
826         ZERO_STRUCT(req);
827         ZERO_STRUCT(rep);
828
829         DO_STRUCT_REQ_REP(WINBINDD_SETPWENT, &req, &rep);
830
831         return true;
832 }
833
834 static bool torture_winbind_struct_getpwent(struct torture_context *torture)
835 {
836         struct winbindd_request req;
837         struct winbindd_response rep;
838         struct winbindd_pw *pwent;
839
840         torture_comment(torture, "Running WINBINDD_GETPWENT (struct based)\n");
841
842         torture_comment(torture, " - Running WINBINDD_SETPWENT first\n");
843         ZERO_STRUCT(req);
844         ZERO_STRUCT(rep);
845         DO_STRUCT_REQ_REP(WINBINDD_SETPWENT, &req, &rep);
846
847         torture_comment(torture, " - Running WINBINDD_GETPWENT now\n");
848         ZERO_STRUCT(req);
849         ZERO_STRUCT(rep);
850         req.data.num_entries = 1;
851         DO_STRUCT_REQ_REP(WINBINDD_GETPWENT, &req, &rep);
852         pwent = (struct winbindd_pw *)rep.extra_data.data;
853         torture_assert(torture, (pwent != NULL), "NULL pwent");
854         torture_comment(torture, "name: %s, uid: %d, gid: %d, shell: %s\n",
855                         pwent->pw_name, pwent->pw_uid, pwent->pw_gid,
856                         pwent->pw_shell);
857
858         return true;
859 }
860
861 static bool torture_winbind_struct_endpwent(struct torture_context *torture)
862 {
863         struct winbindd_request req;
864         struct winbindd_response rep;
865
866         torture_comment(torture, "Running WINBINDD_ENDPWENT (struct based)\n");
867
868         ZERO_STRUCT(req);
869         ZERO_STRUCT(rep);
870
871         DO_STRUCT_REQ_REP(WINBINDD_ENDPWENT, &req, &rep);
872
873         return true;
874 }
875
876 /* Copy of parse_domain_user from winbindd_util.c.  Parse a string of the
877    form DOMAIN/user into a domain and a user */
878
879 static bool parse_domain_user(struct torture_context *torture,
880                               const char *domuser, fstring domain,
881                               fstring user)
882 {
883         char *p = strchr(domuser, winbind_separator(torture));
884         char *dom;
885
886         if (!p) {
887                 /* Maybe it was a UPN? */
888                 if ((p = strchr(domuser, '@')) != NULL) {
889                         fstrcpy(domain, "");
890                         fstrcpy(user, domuser);
891                         return true;
892                 }
893
894                 fstrcpy(user, domuser);
895                 get_winbind_domain(torture, &dom);
896                 fstrcpy(domain, dom);
897                 return true;
898         }
899
900         fstrcpy(user, p+1);
901         fstrcpy(domain, domuser);
902         domain[PTR_DIFF(p, domuser)] = 0;
903         strupper_m(domain);
904
905         return true;
906 }
907
908 static bool lookup_name_sid_list(struct torture_context *torture, char **list)
909 {
910         uint32_t count;
911
912         for (count = 0; list[count]; count++) {
913                 struct winbindd_request req;
914                 struct winbindd_response rep;
915                 char *sid;
916                 char *name;
917                 const char *domain_name = torture_setting_string(torture,
918                                                 "winbindd netbios domain",
919                                                 lp_workgroup(torture->lp_ctx));
920
921                 ZERO_STRUCT(req);
922                 ZERO_STRUCT(rep);
923
924                 parse_domain_user(torture, list[count], req.data.name.dom_name,
925                                   req.data.name.name);
926
927                 DO_STRUCT_REQ_REP(WINBINDD_LOOKUPNAME, &req, &rep);
928
929                 sid = talloc_strdup(torture, rep.data.sid.sid);
930
931                 ZERO_STRUCT(req);
932                 ZERO_STRUCT(rep);
933
934                 fstrcpy(req.data.sid, sid);
935
936                 DO_STRUCT_REQ_REP(WINBINDD_LOOKUPSID, &req, &rep);
937
938                 if (strequal(rep.data.name.dom_name, domain_name)) {
939                         name = talloc_asprintf(torture, "%s",
940                                                rep.data.name.name);
941                 } else {
942                         name = talloc_asprintf(torture, "%s%c%s",
943                                                rep.data.name.dom_name,
944                                                winbind_separator(torture),
945                                                rep.data.name.name);
946                 }
947
948                 torture_assert_casestr_equal(torture, list[count], name,
949                                          "LOOKUP_SID after LOOKUP_NAME != id");
950
951 #if 0
952                 torture_comment(torture, " %s -> %s -> %s\n", list[count],
953                                 sid, name);
954 #endif
955
956                 talloc_free(sid);
957                 talloc_free(name);
958         }
959
960         return true;
961 }
962
963 static bool name_is_in_list(const char *name, const char **list)
964 {
965         uint32_t count;
966
967         for (count = 0; list && list[count]; count++) {
968                 if (strequal(name, list[count])) {
969                         return true;
970                 }
971         }
972         return false;
973 }
974
975 static bool torture_winbind_struct_lookup_name_sid(struct torture_context *torture)
976 {
977         struct winbindd_request req;
978         struct winbindd_response rep;
979         const char *invalid_sid = "S-0-0-7";
980         char *domain;
981         const char *invalid_user = "noone";
982         char *invalid_name;
983         bool strict = torture_setting_bool(torture, "strict mode", false);
984         char **users;
985         char **groups;
986         uint32_t count, num_groups;
987         bool ok;
988
989         torture_comment(torture, "Running WINBINDD_LOOKUP_NAME_SID (struct based)\n");
990
991         ok = get_user_list(torture, &users);
992         torture_assert(torture, ok, "failed to retrieve list of users");
993         lookup_name_sid_list(torture, users);
994
995         ok = get_group_list(torture, &num_groups, &groups);
996         torture_assert(torture, ok, "failed to retrieve list of groups");
997         if (num_groups > 0) {
998                 lookup_name_sid_list(torture, groups);
999         }
1000
1001         ZERO_STRUCT(req);
1002         ZERO_STRUCT(rep);
1003
1004         fstrcpy(req.data.sid, invalid_sid);
1005
1006         ok = true;
1007         DO_STRUCT_REQ_REP_EXT(WINBINDD_LOOKUPSID, &req, &rep,
1008                               NSS_STATUS_NOTFOUND,
1009                               strict,
1010                               ok=false,
1011                               talloc_asprintf(torture,
1012                                               "invalid sid %s was resolved",
1013                                               invalid_sid));
1014
1015         ZERO_STRUCT(req);
1016         ZERO_STRUCT(rep);
1017
1018         /* try to find an invalid name... */
1019
1020         count = 0;
1021         get_winbind_domain(torture, &domain);
1022         do {
1023                 count++;
1024                 invalid_name = talloc_asprintf(torture, "%s\\%s%u",
1025                                                domain,
1026                                                invalid_user, count);
1027         } while(name_is_in_list(invalid_name, (const char **)users) ||
1028                 name_is_in_list(invalid_name, (const char **)groups));
1029
1030         fstrcpy(req.data.name.dom_name, domain);
1031         fstrcpy(req.data.name.name,
1032                 talloc_asprintf(torture, "%s%u", invalid_user,
1033                                 count));
1034
1035         ok = true;
1036         DO_STRUCT_REQ_REP_EXT(WINBINDD_LOOKUPNAME, &req, &rep,
1037                               NSS_STATUS_NOTFOUND,
1038                               strict,
1039                               ok=false,
1040                               talloc_asprintf(torture,
1041                                               "invalid name %s was resolved",
1042                                               invalid_name));
1043
1044         talloc_free(users);
1045         talloc_free(groups);
1046
1047         return true;
1048 }
1049
1050 struct torture_suite *torture_winbind_struct_init(void)
1051 {
1052         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "STRUCT");
1053
1054         torture_suite_add_simple_test(suite, "INTERFACE_VERSION", torture_winbind_struct_interface_version);
1055         torture_suite_add_simple_test(suite, "PING", torture_winbind_struct_ping);
1056         torture_suite_add_simple_test(suite, "INFO", torture_winbind_struct_info);
1057         torture_suite_add_simple_test(suite, "PRIV_PIPE_DIR", torture_winbind_struct_priv_pipe_dir);
1058         torture_suite_add_simple_test(suite, "NETBIOS_NAME", torture_winbind_struct_netbios_name);
1059         torture_suite_add_simple_test(suite, "DOMAIN_NAME", torture_winbind_struct_domain_name);
1060         torture_suite_add_simple_test(suite, "CHECK_MACHACC", torture_winbind_struct_check_machacc);
1061         torture_suite_add_simple_test(suite, "LIST_TRUSTDOM", torture_winbind_struct_list_trustdom);
1062         torture_suite_add_simple_test(suite, "DOMAIN_INFO", torture_winbind_struct_domain_info);
1063         torture_suite_add_simple_test(suite, "GETDCNAME", torture_winbind_struct_getdcname);
1064         torture_suite_add_simple_test(suite, "DSGETDCNAME", torture_winbind_struct_dsgetdcname);
1065         torture_suite_add_simple_test(suite, "LIST_USERS", torture_winbind_struct_list_users);
1066         torture_suite_add_simple_test(suite, "LIST_GROUPS", torture_winbind_struct_list_groups);
1067         torture_suite_add_simple_test(suite, "SHOW_SEQUENCE", torture_winbind_struct_show_sequence);
1068         torture_suite_add_simple_test(suite, "SETPWENT", torture_winbind_struct_setpwent);
1069         torture_suite_add_simple_test(suite, "GETPWENT", torture_winbind_struct_getpwent);
1070         torture_suite_add_simple_test(suite, "ENDPWENT", torture_winbind_struct_endpwent);
1071         torture_suite_add_simple_test(suite, "LOOKUP_NAME_SID", torture_winbind_struct_lookup_name_sid);
1072
1073         suite->description = talloc_strdup(suite, "WINBIND - struct based protocol tests");
1074
1075         return suite;
1076 }