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