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