torture4: Use strlcpy() with size check instead of snprintf()
[gd/samba-autobuild/.git] / source4 / torture / libsmbclient / libsmbclient.c
1 /*
2    Unix SMB/CIFS implementation.
3    SMB torture tester
4    Copyright (C) Guenther Deschner 2010
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "system/dir.h"
22 #include "torture/smbtorture.h"
23 #include "auth/credentials/credentials.h"
24 #include "lib/cmdline/popt_common.h"
25 #include <libsmbclient.h>
26 #include "torture/libsmbclient/proto.h"
27 #include "lib/param/loadparm.h"
28 #include "lib/param/param_global.h"
29 #include "dynconfig.h"
30
31 /* test string to compare with when debug_callback is called */
32 #define TEST_STRING "smbc_setLogCallback test"
33
34 /* Dummy log callback function */
35 static void debug_callback(void *private_ptr, int level, const char *msg)
36 {
37         bool *found = private_ptr;
38         if (strstr(msg, TEST_STRING) != NULL) {
39                 *found = true;
40         }
41         return;
42 }
43
44 static void auth_callback(const char *srv,
45                           const char *shr,
46                           char *wg, int wglen,
47                           char *un, int unlen,
48                           char *pw, int pwlen)
49 {
50         const char *workgroup =
51                 cli_credentials_get_domain(popt_get_cmdline_credentials());
52         const char *username =
53                 cli_credentials_get_username(popt_get_cmdline_credentials());
54         const char *password =
55                 cli_credentials_get_password(popt_get_cmdline_credentials());
56         ssize_t ret;
57
58         if (workgroup != NULL) {
59                 ret = strlcpy(wg, workgroup, wglen);
60                 if (ret >= wglen) {
61                         abort();
62                 }
63         }
64
65         if (username != NULL) {
66                 ret = strlcpy(un, username, unlen);
67                 if (ret >= unlen) {
68                         abort();
69                 }
70         }
71
72         if (password != NULL) {
73                 ret = strlcpy(pw, password, pwlen);
74                 if (ret >= pwlen) {
75                         abort();
76                 }
77         }
78 };
79
80 bool torture_libsmbclient_init_context(struct torture_context *tctx,
81                                        SMBCCTX **ctx_p)
82 {
83         const char *workgroup =
84                 cli_credentials_get_domain(popt_get_cmdline_credentials());
85         const char *username =
86                 cli_credentials_get_username(popt_get_cmdline_credentials());
87         const char *client_proto =
88                 torture_setting_string(tctx, "clientprotocol", NULL);
89         SMBCCTX *ctx = NULL;
90         SMBCCTX *p = NULL;
91         bool ok = true;
92
93         ctx = smbc_new_context();
94         torture_assert_not_null_goto(tctx,
95                                      ctx,
96                                      ok,
97                                      out,
98                                      "Failed to create new context");
99
100         p = smbc_init_context(ctx);
101         torture_assert_not_null_goto(tctx,
102                                      p,
103                                      ok,
104                                      out,
105                                      "Failed to initialize context");
106
107         smbc_setDebug(ctx, DEBUGLEVEL);
108         smbc_setOptionDebugToStderr(ctx, 1);
109
110         if (workgroup != NULL) {
111                 smbc_setWorkgroup(ctx, workgroup);
112         }
113         if (username != NULL) {
114                 smbc_setUser(ctx, username);
115         }
116
117         smbc_setFunctionAuthData(ctx, auth_callback);
118
119         if (client_proto != NULL) {
120                 smbc_setOptionProtocols(ctx, client_proto, client_proto);
121         }
122
123         *ctx_p = ctx;
124
125 out:
126         if (!ok) {
127                 smbc_free_context(ctx, 1);
128         }
129
130         return ok;
131 }
132
133 static bool torture_libsmbclient_version(struct torture_context *tctx)
134 {
135         torture_comment(tctx, "Testing smbc_version\n");
136
137         torture_assert(tctx, smbc_version(), "failed to get version");
138
139         return true;
140 }
141
142 static bool torture_libsmbclient_initialize(struct torture_context *tctx)
143 {
144         SMBCCTX *ctx;
145         bool ret = false;
146
147         torture_comment(tctx, "Testing smbc_new_context\n");
148
149         ctx = smbc_new_context();
150         torture_assert(tctx, ctx, "failed to get new context");
151
152         torture_comment(tctx, "Testing smbc_init_context\n");
153
154         torture_assert(tctx, smbc_init_context(ctx), "failed to init context");
155
156         smbc_setLogCallback(ctx, &ret, debug_callback);
157         DEBUG(0, (TEST_STRING"\n"));
158         torture_assert(tctx, ret, "Failed debug_callback not called");
159         ret = false;
160         smbc_setLogCallback(ctx, NULL, NULL);
161         DEBUG(0, (TEST_STRING"\n"));
162         torture_assert(tctx, !ret, "Failed debug_callback called");
163
164         smbc_free_context(ctx, 1);
165
166         return true;
167 }
168
169 static bool torture_libsmbclient_setConfiguration(struct torture_context *tctx)
170 {
171         SMBCCTX *ctx;
172         struct loadparm_global *global_config = NULL;
173         const char *new_smb_conf = torture_setting_string(tctx,
174                                 "replace_smbconf",
175                                 "");
176
177         ctx = smbc_new_context();
178         torture_assert(tctx, ctx, "failed to get new context");
179
180         torture_assert(tctx, smbc_init_context(ctx), "failed to init context");
181
182         torture_comment(tctx, "Testing smbc_setConfiguration - new file %s\n",
183                 new_smb_conf);
184
185         global_config = get_globals();
186         torture_assert(tctx, global_config, "Global Config is NULL");
187
188         /* check configuration before smbc_setConfiguration call */
189         torture_comment(tctx, "'workgroup' before setConfiguration %s\n",
190                         global_config->workgroup);
191         torture_comment(tctx, "'client min protocol' before "
192                         "setConfiguration %d\n",
193                         global_config->client_min_protocol);
194         torture_comment(tctx, "'client max protocol' before "
195                         "setConfiguration %d\n",
196                         global_config->_client_max_protocol);
197         torture_comment(tctx, "'client signing' before setConfiguration %d\n",
198                         global_config->client_signing);
199         torture_comment(tctx, "'deadtime' before setConfiguration %d\n",
200                         global_config->deadtime);
201
202         torture_assert_int_equal(tctx, smbc_setConfiguration(ctx, new_smb_conf),
203                         0, "setConfiguration conf file not found");
204
205         /* verify configuration */
206         torture_assert_str_equal(tctx, global_config->workgroup,
207                         "NEW_WORKGROUP",
208                         "smbc_setConfiguration failed, "
209                         "'workgroup' not updated");
210         torture_assert_int_equal(tctx, global_config->client_min_protocol, 7,
211                         "smbc_setConfiguration failed, 'client min protocol' "
212                         "not updated");
213         torture_assert_int_equal(tctx, global_config->_client_max_protocol, 13,
214                         "smbc_setConfiguration failed, 'client max protocol' "
215                         "not updated");
216         torture_assert_int_equal(tctx, global_config->client_signing, 1,
217                         "smbc_setConfiguration failed, 'client signing' "
218                         "not updated");
219         torture_assert_int_equal(tctx, global_config->deadtime, 5,
220                         "smbc_setConfiguration failed, 'deadtime' not updated");
221
222         /* Restore configuration to default */
223         smbc_setConfiguration(ctx, get_dyn_CONFIGFILE());
224
225         smbc_free_context(ctx, 1);
226
227         return true;
228 }
229
230 static bool test_opendir(struct torture_context *tctx,
231                          SMBCCTX *ctx,
232                          const char *fname,
233                          bool expect_success)
234 {
235         int handle, ret;
236
237         torture_comment(tctx, "Testing smbc_opendir(%s)\n", fname);
238
239         handle = smbc_opendir(fname);
240         if (!expect_success) {
241                 return true;
242         }
243         if (handle < 0) {
244                 torture_fail(tctx, talloc_asprintf(tctx, "failed to obain file handle for '%s'", fname));
245         }
246
247         ret = smbc_closedir(handle);
248         torture_assert_int_equal(tctx, ret, 0,
249                 talloc_asprintf(tctx, "failed to close file handle for '%s'", fname));
250
251         return true;
252 }
253
254 static bool torture_libsmbclient_opendir(struct torture_context *tctx)
255 {
256         int i;
257         SMBCCTX *ctx;
258         bool ret = true;
259         const char *bad_urls[] = {
260                 "",
261                 NULL,
262                 "smb",
263                 "smb:",
264                 "smb:/",
265                 "smb:///",
266                 "bms://",
267                 ":",
268                 ":/",
269                 "://",
270                 ":///",
271                 "/",
272                 "//",
273                 "///"
274         };
275         const char *good_urls[] = {
276                 "smb://",
277                 "smb://WORKGROUP",
278                 "smb://WORKGROUP/"
279         };
280
281         torture_assert(tctx, torture_libsmbclient_init_context(tctx, &ctx), "");
282         smbc_set_context(ctx);
283
284         for (i=0; i < ARRAY_SIZE(bad_urls); i++) {
285                 ret &= test_opendir(tctx, ctx, bad_urls[i], false);
286         }
287         for (i=0; i < ARRAY_SIZE(good_urls); i++) {
288                 ret &= test_opendir(tctx, ctx, good_urls[i], true);
289         }
290
291         smbc_free_context(ctx, 1);
292
293         return ret;
294 }
295
296 static bool torture_libsmbclient_readdirplus(struct torture_context *tctx)
297 {
298         SMBCCTX *ctx;
299         int ret = -1;
300         int dhandle = -1;
301         int fhandle = -1;
302         bool found = false;
303         const char *filename = NULL;
304         const char *smburl = torture_setting_string(tctx, "smburl", NULL);
305
306         if (smburl == NULL) {
307                 torture_fail(tctx,
308                         "option --option=torture:smburl="
309                         "smb://user:password@server/share missing\n");
310         }
311
312         torture_assert(tctx, torture_libsmbclient_init_context(tctx, &ctx), "");
313         smbc_set_context(ctx);
314
315         filename = talloc_asprintf(tctx,
316                                 "%s/test_readdirplus.txt",
317                                 smburl);
318         if (filename == NULL) {
319                 torture_fail(tctx,
320                         "talloc fail\n");
321         }
322         /* Ensure the file doesn't exist. */
323         smbc_unlink(filename);
324
325         /* Create it. */
326         fhandle = smbc_creat(filename, 0666);
327         if (fhandle < 0) {
328                 torture_fail(tctx,
329                         talloc_asprintf(tctx,
330                                 "failed to create file '%s': %s",
331                                 filename,
332                                 strerror(errno)));
333         }
334         ret = smbc_close(fhandle);
335         torture_assert_int_equal(tctx,
336                 ret,
337                 0,
338                 talloc_asprintf(tctx,
339                         "failed to close handle for '%s'",
340                         filename));
341
342         dhandle = smbc_opendir(smburl);
343         if (dhandle < 0) {
344                 int saved_errno = errno;
345                 smbc_unlink(filename);
346                 torture_fail(tctx,
347                         talloc_asprintf(tctx,
348                                 "failed to obtain "
349                                 "directory handle for '%s' : %s",
350                                 smburl,
351                                 strerror(saved_errno)));
352         }
353
354         /* Readdirplus to ensure we see the new file. */
355         for (;;) {
356                 const struct libsmb_file_info *exstat =
357                         smbc_readdirplus(dhandle);
358                 if (exstat == NULL) {
359                         break;
360                 }
361                 if (strcmp(exstat->name, "test_readdirplus.txt") == 0) {
362                         found = true;
363                         break;
364                 }
365         }
366
367         /* Remove it again. */
368         smbc_unlink(filename);
369         ret = smbc_closedir(dhandle);
370         torture_assert_int_equal(tctx,
371                 ret,
372                 0,
373                 talloc_asprintf(tctx,
374                         "failed to close directory handle for '%s'",
375                         smburl));
376
377         smbc_free_context(ctx, 1);
378
379         if (!found) {
380                 torture_fail(tctx,
381                         talloc_asprintf(tctx,
382                                 "failed to find file '%s'",
383                                 filename));
384         }
385
386         return true;
387 }
388
389 static bool torture_libsmbclient_readdirplus_seek(struct torture_context *tctx)
390 {
391         SMBCCTX *ctx;
392         int ret = -1;
393         int dhandle = -1;
394         int fhandle = -1;
395         const char *dname = NULL;
396         const char *full_filename[100] = {0};
397         const char *filename[100] = {0};
398         const struct libsmb_file_info *direntries[102] = {0};
399         unsigned int i = 0;
400         const char *smburl = torture_setting_string(tctx, "smburl", NULL);
401         bool success = false;
402         off_t telldir_50 = (off_t)-1;
403         off_t telldir_20 = (off_t)-1;
404         size_t getdentries_size = 0;
405         struct smbc_dirent *getdentries = NULL;
406         struct smbc_dirent *dirent_20 = NULL;
407         const struct libsmb_file_info *direntries_20 = NULL;
408         const struct libsmb_file_info *direntriesplus_20 = NULL;
409         const char *plus2_stat_path = NULL;
410         struct stat st = {0};
411         struct stat st2 = {0};
412
413         if (smburl == NULL) {
414                 torture_fail(tctx,
415                         "option --option=torture:smburl="
416                         "smb://user:password@server/share missing\n");
417         }
418
419         DEBUG(0,("torture_libsmbclient_readdirplus_seek start\n"));
420
421         torture_assert(tctx, torture_libsmbclient_init_context(tctx, &ctx), "");
422         smbc_set_context(ctx);
423
424         dname = talloc_asprintf(tctx,
425                                 "%s/rd_seek",
426                                 smburl);
427         if (dname == NULL) {
428                 torture_fail_goto(tctx,
429                         done,
430                         "talloc fail\n");
431         }
432
433         /* Ensure the files don't exist. */
434         for (i = 0; i < 100; i++) {
435                 filename[i] = talloc_asprintf(tctx,
436                                 "test_readdirplus_%u.txt",
437                                 i);
438                 if (filename[i] == NULL) {
439                         torture_fail_goto(tctx,
440                                 done,
441                                 "talloc fail\n");
442                 }
443                 full_filename[i] = talloc_asprintf(tctx,
444                                 "%s/%s",
445                                 dname,
446                                 filename[i]);
447                 if (full_filename[i] == NULL) {
448                         torture_fail_goto(tctx,
449                                 done,
450                                 "talloc fail\n");
451                 }
452                 (void)smbc_unlink(full_filename[i]);
453         }
454         /* Ensure the directory doesn't exist. */
455         (void)smbc_rmdir(dname);
456
457         /* Create containing directory. */
458         ret = smbc_mkdir(dname, 0777);
459         if (ret != 0) {
460                 torture_fail_goto(tctx,
461                         done,
462                         talloc_asprintf(tctx,
463                                 "failed to create directory '%s': %s",
464                                 dname,
465                                 strerror(errno)));
466         }
467
468         DEBUG(0,("torture_libsmbclient_readdirplus_seek create\n"));
469
470         /* Create them. */
471         for (i = 0; i < 100; i++) {
472                 fhandle = smbc_creat(full_filename[i], 0666);
473                 if (fhandle < 0) {
474                         torture_fail_goto(tctx,
475                                 done,
476                                 talloc_asprintf(tctx,
477                                         "failed to create file '%s': %s",
478                                         full_filename[i],
479                                         strerror(errno)));
480                 }
481                 ret = smbc_close(fhandle);
482                 torture_assert_int_equal_goto(tctx,
483                         ret,
484                         0,
485                         success,
486                         done,
487                         talloc_asprintf(tctx,
488                                 "failed to close handle for '%s'",
489                                 full_filename[i]));
490         }
491
492         DEBUG(0,("torture_libsmbclient_readdirplus_seek enum\n"));
493
494         /* Now enumerate the directory. */
495         dhandle = smbc_opendir(dname);
496         if (dhandle < 0) {
497                 torture_fail_goto(tctx,
498                         done,
499                         talloc_asprintf(tctx,
500                                 "failed to obtain "
501                                 "directory handle for '%s' : %s",
502                                 dname,
503                                 strerror(errno)));
504         }
505
506         /* Read all the files. 100 we created plus . and .. */
507         for (i = 0; i < 102; i++) {
508                 bool found = false;
509                 unsigned int j;
510
511                 direntries[i] = smbc_readdirplus(dhandle);
512                 if (direntries[i] == NULL) {
513                         break;
514                 }
515
516                 /* Store at offset 50. */
517                 if (i == 50) {
518                         telldir_50 = smbc_telldir(dhandle);
519                         if (telldir_50 == (off_t)-1) {
520                                 torture_fail_goto(tctx,
521                                         done,
522                                         talloc_asprintf(tctx,
523                                                 "telldir failed file %s\n",
524                                                 direntries[i]->name));
525                         }
526                 }
527
528                 if (ISDOT(direntries[i]->name)) {
529                         continue;
530                 }
531                 if (ISDOTDOT(direntries[i]->name)) {
532                         continue;
533                 }
534
535                 /* Ensure all our files exist. */
536                 for (j = 0; j < 100; j++) {
537                         if (strcmp(direntries[i]->name,
538                                 filename[j]) == 0) {
539                                 found = true;
540                         }
541                 }
542                 if (!found) {
543                         torture_fail_goto(tctx,
544                                 done,
545                                 talloc_asprintf(tctx,
546                                         "failed to find file %s\n",
547                                         direntries[i]->name));
548                 }
549         }
550
551         /*
552          * We're seeking on in-memory lists here, so
553          * whilst the handle is open we really should
554          * get the same files back in the same order.
555          */
556
557         ret = smbc_lseekdir(dhandle, telldir_50);
558         torture_assert_int_equal_goto(tctx,
559                 ret,
560                 0,
561                 success,
562                 done,
563                 talloc_asprintf(tctx,
564                         "failed to seek (50) directory handle for '%s'",
565                         dname));
566
567         DEBUG(0,("torture_libsmbclient_readdirplus_seek seek\n"));
568
569         for (i = 51; i < 102; i++) {
570                 const struct libsmb_file_info *entry =
571                                 smbc_readdirplus(dhandle);
572                 if (entry != direntries[i]) {
573                         torture_fail_goto(tctx,
574                                 done,
575                                 talloc_asprintf(tctx,
576                                         "after seek - failed to find "
577                                         "file %s - got %s\n",
578                                         direntries[i]->name,
579                                         entry->name));
580                 }
581         }
582
583         /* Seek back to the start. */
584         ret = smbc_lseekdir(dhandle, 0);
585         torture_assert_int_equal_goto(tctx,
586                 ret,
587                 0,
588                 success,
589                 done,
590                 talloc_asprintf(tctx,
591                         "failed to seek directory handle to start for '%s'",
592                         dname));
593
594         /*
595          * Mix getdents/readdir/readdirplus with lseek to ensure
596          * we get the same result.
597          */
598
599         /* Allocate the space for 20 entries.
600          * Tricky as we need to allocate 20 struct smbc_dirent's + space
601          * for the name lengths.
602          */
603         getdentries_size = 20 * (sizeof(struct smbc_dirent) +
604                                 strlen("test_readdirplus_1000.txt") + 1);
605
606         getdentries = (struct smbc_dirent *)talloc_array_size(tctx,
607                                                 getdentries_size,
608                                                 1);
609
610         ret = smbc_getdents(dhandle, getdentries, getdentries_size);
611         torture_assert_goto(tctx,
612                 (ret != -1),
613                 success,
614                 done,
615                 talloc_asprintf(tctx,
616                         "smbd_getdents(1) for '%s' failed\n",
617                         dname));
618
619         telldir_20 = smbc_telldir(dhandle);
620         if (telldir_20 == (off_t)-1) {
621                 torture_fail_goto(tctx,
622                         done,
623                         talloc_asprintf(tctx,
624                                 "telldir (20) failed\n"));
625         }
626         /* Read another 20. */
627         ret = smbc_getdents(dhandle, getdentries, getdentries_size);
628         torture_assert_goto(tctx,
629                 (ret != -1),
630                 success,
631                 done,
632                 talloc_asprintf(tctx,
633                         "smbd_getdents(2) for '%s' failed\n",
634                         dname));
635
636         /* Seek back to 20. */
637         ret = smbc_lseekdir(dhandle, telldir_20);
638         torture_assert_int_equal_goto(tctx,
639                 ret,
640                 0,
641                 success,
642                 done,
643                 talloc_asprintf(tctx,
644                         "failed to seek (20) directory handle for '%s'",
645                         dname));
646
647         /* Read with readdir. */
648         dirent_20 = smbc_readdir(dhandle);
649         if (dirent_20 == NULL) {
650                 torture_fail_goto(tctx,
651                         done,
652                         talloc_asprintf(tctx,
653                                 "smbc_readdir (20) failed\n"));
654         }
655
656         /* Ensure the getdents and readdir names are the same. */
657         ret = strcmp(dirent_20->name, getdentries[0].name);
658         if (ret != 0) {
659                 torture_fail_goto(tctx,
660                         done,
661                         talloc_asprintf(tctx,
662                                 "after seek (20) readdir name missmatch "
663                                 "file %s - got %s\n",
664                                 dirent_20->name,
665                                 getdentries[0].name));
666         }
667
668         /* Seek back to 20. */
669         ret = smbc_lseekdir(dhandle, telldir_20);
670         torture_assert_int_equal_goto(tctx,
671                 ret,
672                 0,
673                 success,
674                 done,
675                 talloc_asprintf(tctx,
676                         "failed to seek (20) directory handle for '%s'",
677                         dname));
678         /* Read with readdirplus. */
679         direntries_20 = smbc_readdirplus(dhandle);
680         if (direntries_20 == NULL) {
681                 torture_fail_goto(tctx,
682                         done,
683                         talloc_asprintf(tctx,
684                                 "smbc_readdirplus (20) failed\n"));
685         }
686
687         /* Ensure the readdirplus and readdir names are the same. */
688         ret = strcmp(dirent_20->name, direntries_20->name);
689         if (ret != 0) {
690                 torture_fail_goto(tctx,
691                         done,
692                         talloc_asprintf(tctx,
693                                 "after seek (20) readdirplus name missmatch "
694                                 "file %s - got %s\n",
695                                 dirent_20->name,
696                                 direntries_20->name));
697         }
698
699         /* Seek back to 20. */
700         ret = smbc_lseekdir(dhandle, telldir_20);
701         torture_assert_int_equal_goto(tctx,
702                 ret,
703                 0,
704                 success,
705                 done,
706                 talloc_asprintf(tctx,
707                         "failed to seek (20) directory handle for '%s'",
708                         dname));
709
710         /* Read with readdirplus2. */
711         direntriesplus_20 = smbc_readdirplus2(dhandle, &st2);
712         if (direntriesplus_20 == NULL) {
713                 torture_fail_goto(tctx,
714                         done,
715                         talloc_asprintf(tctx,
716                                 "smbc_readdirplus2 (20) failed\n"));
717         }
718
719         /* Ensure the readdirplus2 and readdirplus names are the same. */
720         ret = strcmp(direntries_20->name, direntriesplus_20->name);
721         if (ret != 0) {
722                 torture_fail_goto(tctx,
723                         done,
724                         talloc_asprintf(tctx,
725                                 "after seek (20) readdirplus2 name missmatch "
726                                 "file %s - got %s\n",
727                                 dirent_20->name,
728                                 direntries_20->name));
729         }
730
731         /* Ensure doing stat gets the same data. */
732         plus2_stat_path = talloc_asprintf(tctx,
733                                 "%s/%s",
734                                 dname,
735                                 direntriesplus_20->name);
736         if (plus2_stat_path == NULL) {
737                 torture_fail_goto(tctx,
738                         done,
739                         "talloc fail\n");
740         }
741
742         ret = smbc_stat(plus2_stat_path, &st);
743         torture_assert_int_equal_goto(tctx,
744                 ret,
745                 0,
746                 success,
747                 done,
748                 talloc_asprintf(tctx,
749                         "failed to stat file '%s'",
750                         plus2_stat_path));
751
752         torture_assert_int_equal(tctx,
753                 st.st_ino,
754                 st2.st_ino,
755                 talloc_asprintf(tctx,
756                         "file %s mismatched ino value "
757                         "stat got %"PRIx64" readdirplus2 got %"PRIx64"" ,
758                         plus2_stat_path,
759                         (uint64_t)st.st_ino,
760                         (uint64_t)st2.st_ino));
761
762         torture_assert_int_equal(tctx,
763                 st.st_dev,
764                 st2.st_dev,
765                 talloc_asprintf(tctx,
766                         "file %s mismatched dev value "
767                         "stat got %"PRIx64" readdirplus2 got %"PRIx64"" ,
768                         plus2_stat_path,
769                         (uint64_t)st.st_dev,
770                         (uint64_t)st2.st_dev));
771
772         ret = smbc_closedir(dhandle);
773         torture_assert_int_equal(tctx,
774                 ret,
775                 0,
776                 talloc_asprintf(tctx,
777                         "failed to close directory handle for '%s'",
778                         dname));
779
780         dhandle = -1;
781         success = true;
782
783   done:
784
785         /* Clean up. */
786         if (dhandle != -1) {
787                 smbc_closedir(dhandle);
788         }
789         for (i = 0; i < 100; i++) {
790                 if (full_filename[i] != NULL) {
791                         smbc_unlink(full_filename[i]);
792                 }
793         }
794         if (dname != NULL) {
795                 smbc_rmdir(dname);
796         }
797
798         smbc_free_context(ctx, 1);
799
800         return success;
801 }
802
803 #ifndef SMBC_FILE_MODE
804 #define SMBC_FILE_MODE (S_IFREG | 0444)
805 #endif
806
807 static bool torture_libsmbclient_readdirplus2(struct torture_context *tctx)
808 {
809         SMBCCTX *ctx;
810         int dhandle = -1;
811         int fhandle = -1;
812         bool found = false;
813         bool success = false;
814         const char *filename = NULL;
815         struct stat st2 = {0};
816         struct stat st = {0};
817         int ret;
818         const char *smburl = torture_setting_string(tctx, "smburl", NULL);
819
820         if (smburl == NULL) {
821                 torture_fail(tctx,
822                         "option --option=torture:smburl="
823                         "smb://user:password@server/share missing\n");
824         }
825
826         torture_assert_goto(tctx, torture_libsmbclient_init_context(tctx, &ctx), success, done, "");
827         smbc_set_context(ctx);
828
829         filename = talloc_asprintf(tctx,
830                         "%s/test_readdirplus.txt",
831                         smburl);
832         if (filename == NULL) {
833                 torture_fail_goto(tctx, done, "talloc fail\n");
834         }
835
836         /* Ensure the file doesn't exist. */
837         smbc_unlink(filename);
838
839         /* Create it. */
840         fhandle = smbc_creat(filename, 0666);
841         if (fhandle < 0) {
842                 torture_fail_goto(tctx,
843                         done,
844                         talloc_asprintf(tctx,
845                                 "failed to create file '%s': %s",
846                                 filename,
847                                 strerror(errno)));
848         }
849         ret = smbc_close(fhandle);
850         torture_assert_int_equal_goto(tctx,
851                 ret,
852                 0,
853                 success,
854                 done,
855                 talloc_asprintf(tctx,
856                         "failed to close handle for '%s'",
857                         filename));
858
859         dhandle = smbc_opendir(smburl);
860         if (dhandle < 0) {
861                 int saved_errno = errno;
862                 smbc_unlink(filename);
863                 torture_fail_goto(tctx,
864                         done,
865                         talloc_asprintf(tctx,
866                                 "failed to obtain "
867                                 "directory handle for '%s' : %s",
868                                 smburl,
869                                 strerror(saved_errno)));
870         }
871
872         /* readdirplus2 to ensure we see the new file. */
873         for (;;) {
874                 const struct libsmb_file_info *exstat =
875                         smbc_readdirplus2(dhandle, &st2);
876                 if (exstat == NULL) {
877                         break;
878                 }
879
880                 if (strcmp(exstat->name, "test_readdirplus.txt") == 0) {
881                         found = true;
882                         break;
883                 }
884         }
885
886         if (!found) {
887                 smbc_unlink(filename);
888                 torture_fail_goto(tctx,
889                         done,
890                         talloc_asprintf(tctx,
891                                 "failed to find file '%s'",
892                                 filename));
893         }
894
895         /* Ensure mode is as expected. */
896         /*
897          * New file gets SMBC_FILE_MODE plus
898          * archive bit -> S_IXUSR
899          * !READONLY -> S_IWUSR.
900          */
901         torture_assert_int_equal_goto(tctx,
902                 st2.st_mode,
903                 SMBC_FILE_MODE|S_IXUSR|S_IWUSR,
904                 success,
905                 done,
906                 talloc_asprintf(tctx,
907                         "file %s st_mode should be 0%o, got 0%o'",
908                         filename,
909                         SMBC_FILE_MODE|S_IXUSR|S_IWUSR,
910                         (unsigned int)st2.st_mode));
911
912         /* Ensure smbc_stat() gets the same data. */
913         ret = smbc_stat(filename, &st);
914         torture_assert_int_equal_goto(tctx,
915                 ret,
916                 0,
917                 success,
918                 done,
919                 talloc_asprintf(tctx,
920                         "failed to stat file '%s'",
921                         filename));
922
923         torture_assert_int_equal_goto(tctx,
924                 st2.st_ino,
925                 st.st_ino,
926                 success,
927                 done,
928                 talloc_asprintf(tctx,
929                         "filename '%s' ino missmatch. "
930                         "From smbc_readdirplus2 = %"PRIx64" "
931                         "From smbc_stat = %"PRIx64"",
932                         filename,
933                         (uint64_t)st2.st_ino,
934                         (uint64_t)st.st_ino));
935
936
937         /* Remove it again. */
938         smbc_unlink(filename);
939         ret = smbc_closedir(dhandle);
940         torture_assert_int_equal_goto(tctx,
941                 ret,
942                 0,
943                 success,
944                 done,
945                 talloc_asprintf(tctx,
946                         "failed to close directory handle for '%s'",
947                         filename));
948         success = true;
949
950   done:
951         smbc_free_context(ctx, 1);
952         return success;
953 }
954
955 bool torture_libsmbclient_configuration(struct torture_context *tctx)
956 {
957         SMBCCTX *ctx;
958         bool ok = true;
959
960         ctx = smbc_new_context();
961         torture_assert(tctx, ctx, "failed to get new context");
962         torture_assert(tctx, smbc_init_context(ctx), "failed to init context");
963
964         torture_comment(tctx, "Testing smbc_(set|get)Debug\n");
965         smbc_setDebug(ctx, DEBUGLEVEL);
966         torture_assert_int_equal_goto(tctx,
967                                       smbc_getDebug(ctx),
968                                       DEBUGLEVEL,
969                                       ok,
970                                       done,
971                                       "failed to set DEBUGLEVEL");
972
973         torture_comment(tctx, "Testing smbc_(set|get)NetbiosName\n");
974         smbc_setNetbiosName(ctx, discard_const("torture_netbios"));
975         torture_assert_str_equal_goto(tctx,
976                                       smbc_getNetbiosName(ctx),
977                                       "torture_netbios",
978                                       ok,
979                                       done,
980                                       "failed to set NetbiosName");
981
982         torture_comment(tctx, "Testing smbc_(set|get)Workgroup\n");
983         smbc_setWorkgroup(ctx, discard_const("torture_workgroup"));
984         torture_assert_str_equal_goto(tctx,
985                                       smbc_getWorkgroup(ctx),
986                                       "torture_workgroup",
987                                       ok,
988                                       done,
989                                       "failed to set Workgroup");
990
991         torture_comment(tctx, "Testing smbc_(set|get)User\n");
992         smbc_setUser(ctx, "torture_user");
993         torture_assert_str_equal_goto(tctx,
994                                       smbc_getUser(ctx),
995                                       "torture_user",
996                                       ok,
997                                       done,
998                                       "failed to set User");
999
1000         torture_comment(tctx, "Testing smbc_(set|get)Timeout\n");
1001         smbc_setTimeout(ctx, 12345);
1002         torture_assert_int_equal_goto(tctx,
1003                                       smbc_getTimeout(ctx),
1004                                       12345,
1005                                       ok,
1006                                       done,
1007                                       "failed to set Timeout");
1008
1009 done:
1010         smbc_free_context(ctx, 1);
1011
1012         return ok;
1013 }
1014
1015 bool torture_libsmbclient_options(struct torture_context *tctx)
1016 {
1017         SMBCCTX *ctx;
1018         bool ok = true;
1019
1020         ctx = smbc_new_context();
1021         torture_assert(tctx, ctx, "failed to get new context");
1022         torture_assert(tctx, smbc_init_context(ctx), "failed to init context");
1023
1024         torture_comment(tctx, "Testing smbc_(set|get)OptionDebugToStderr\n");
1025         smbc_setOptionDebugToStderr(ctx, true);
1026         torture_assert_goto(tctx,
1027                             smbc_getOptionDebugToStderr(ctx),
1028                             ok,
1029                             done,
1030                             "failed to set OptionDebugToStderr");
1031
1032         torture_comment(tctx, "Testing smbc_(set|get)OptionFullTimeNames\n");
1033         smbc_setOptionFullTimeNames(ctx, true);
1034         torture_assert_goto(tctx,
1035                             smbc_getOptionFullTimeNames(ctx),
1036                             ok,
1037                             done,
1038                             "failed to set OptionFullTimeNames");
1039
1040         torture_comment(tctx, "Testing smbc_(set|get)OptionOpenShareMode\n");
1041         smbc_setOptionOpenShareMode(ctx, SMBC_SHAREMODE_DENY_ALL);
1042         torture_assert_int_equal_goto(tctx,
1043                                       smbc_getOptionOpenShareMode(ctx),
1044                                       SMBC_SHAREMODE_DENY_ALL,
1045                                       ok,
1046                                       done,
1047                                       "failed to set OptionOpenShareMode");
1048
1049         torture_comment(tctx, "Testing smbc_(set|get)OptionUserData\n");
1050         smbc_setOptionUserData(ctx, (void *)discard_const("torture_user_data"));
1051         torture_assert_str_equal_goto(tctx,
1052                                       (const char*)smbc_getOptionUserData(ctx),
1053                                       "torture_user_data",
1054                                       ok,
1055                                       done,
1056                                       "failed to set OptionUserData");
1057
1058         torture_comment(tctx,
1059                         "Testing smbc_(set|get)OptionSmbEncryptionLevel\n");
1060         smbc_setOptionSmbEncryptionLevel(ctx, SMBC_ENCRYPTLEVEL_REQUEST);
1061         torture_assert_int_equal_goto(tctx,
1062                                       smbc_getOptionSmbEncryptionLevel(ctx),
1063                                       SMBC_ENCRYPTLEVEL_REQUEST,
1064                                       ok,
1065                                       done,
1066                                       "failed to set OptionSmbEncryptionLevel");
1067
1068         torture_comment(tctx, "Testing smbc_(set|get)OptionCaseSensitive\n");
1069         smbc_setOptionCaseSensitive(ctx, false);
1070         torture_assert_goto(tctx,
1071                             !smbc_getOptionCaseSensitive(ctx),
1072                             ok,
1073                             done,
1074                             "failed to set OptionCaseSensitive");
1075
1076         torture_comment(tctx,
1077                         "Testing smbc_(set|get)OptionBrowseMaxLmbCount\n");
1078         smbc_setOptionBrowseMaxLmbCount(ctx, 2);
1079         torture_assert_int_equal_goto(tctx,
1080                                       smbc_getOptionBrowseMaxLmbCount(ctx),
1081                                       2,
1082                                       ok,
1083                                       done,
1084                                       "failed to set OptionBrowseMaxLmbCount");
1085
1086         torture_comment(tctx,
1087                        "Testing smbc_(set|get)OptionUrlEncodeReaddirEntries\n");
1088         smbc_setOptionUrlEncodeReaddirEntries(ctx, true);
1089         torture_assert_goto(tctx,
1090                             smbc_getOptionUrlEncodeReaddirEntries(ctx),
1091                             ok,
1092                             done,
1093                             "failed to set OptionUrlEncodeReaddirEntries");
1094
1095         torture_comment(tctx,
1096                         "Testing smbc_(set|get)OptionOneSharePerServer\n");
1097         smbc_setOptionOneSharePerServer(ctx, true);
1098         torture_assert_goto(tctx,
1099                             smbc_getOptionOneSharePerServer(ctx),
1100                             ok,
1101                             done,
1102                             "failed to set OptionOneSharePerServer");
1103
1104         torture_comment(tctx, "Testing smbc_(set|get)OptionUseKerberos\n");
1105         smbc_setOptionUseKerberos(ctx, false);
1106         torture_assert_goto(tctx,
1107                             !smbc_getOptionUseKerberos(ctx),
1108                             ok,
1109                             done,
1110                             "failed to set OptionUseKerberos");
1111
1112         torture_comment(tctx,
1113                         "Testing smbc_(set|get)OptionFallbackAfterKerberos\n");
1114         smbc_setOptionFallbackAfterKerberos(ctx, false);
1115         torture_assert_goto(tctx,
1116                             !smbc_getOptionFallbackAfterKerberos(ctx),
1117                             ok,
1118                             done,
1119                             "failed to set OptionFallbackAfterKerberos");
1120
1121         torture_comment(tctx,
1122                         "Testing smbc_(set|get)OptionNoAutoAnonymousLogin\n");
1123         smbc_setOptionNoAutoAnonymousLogin(ctx, true);
1124         torture_assert_goto(tctx,
1125                             smbc_getOptionNoAutoAnonymousLogin(ctx),
1126                             ok,
1127                             done,
1128                             "failed to set OptionNoAutoAnonymousLogin");
1129
1130         torture_comment(tctx, "Testing smbc_(set|get)OptionUseCCache\n");
1131         smbc_setOptionUseCCache(ctx, true);
1132         torture_assert_goto(tctx,
1133                             smbc_getOptionUseCCache(ctx),
1134                             ok,
1135                             done,
1136                             "failed to set OptionUseCCache");
1137
1138 done:
1139         smbc_free_context(ctx, 1);
1140
1141         return ok;
1142 }
1143
1144 static bool torture_libsmbclient_list_shares(struct torture_context *tctx)
1145 {
1146         const char *smburl = torture_setting_string(tctx, "smburl", NULL);
1147         struct smbc_dirent *dirent = NULL;
1148         SMBCCTX *ctx = NULL;
1149         int dhandle = -1;
1150         bool ipc_share_found = false;
1151         bool ok = true;
1152
1153         if (smburl == NULL) {
1154                 torture_fail(tctx,
1155                              "option --option=torture:smburl="
1156                              "smb://user:password@server missing\n");
1157         }
1158
1159         ok = torture_libsmbclient_init_context(tctx, &ctx);
1160         torture_assert_goto(tctx,
1161                             ok,
1162                             ok,
1163                             out,
1164                             "Failed to init context");
1165         smbc_set_context(ctx);
1166
1167         torture_comment(tctx, "Listing: %s\n", smburl);
1168         dhandle = smbc_opendir(smburl);
1169         torture_assert_int_not_equal_goto(tctx,
1170                                           dhandle,
1171                                           -1,
1172                                           ok,
1173                                           out,
1174                                           "Failed to open smburl");
1175
1176         while((dirent = smbc_readdir(dhandle)) != NULL) {
1177                 torture_comment(tctx, "DIR: %s\n", dirent->name);
1178                 torture_assert_not_null_goto(tctx,
1179                                              dirent->name,
1180                                              ok,
1181                                              out,
1182                                              "Failed to read name");
1183
1184                 if (strequal(dirent->name, "IPC$")) {
1185                         ipc_share_found = true;
1186                 }
1187         }
1188
1189         torture_assert_goto(tctx,
1190                             ipc_share_found,
1191                             ok,
1192                             out,
1193                             "Failed to list IPC$ share");
1194
1195 out:
1196         smbc_closedir(dhandle);
1197         return ok;
1198 }
1199
1200 NTSTATUS torture_libsmbclient_init(TALLOC_CTX *ctx)
1201 {
1202         struct torture_suite *suite;
1203
1204         suite = torture_suite_create(ctx, "libsmbclient");
1205
1206         torture_suite_add_simple_test(suite, "version", torture_libsmbclient_version);
1207         torture_suite_add_simple_test(suite, "initialize", torture_libsmbclient_initialize);
1208         torture_suite_add_simple_test(suite, "configuration", torture_libsmbclient_configuration);
1209         torture_suite_add_simple_test(suite, "setConfiguration", torture_libsmbclient_setConfiguration);
1210         torture_suite_add_simple_test(suite, "options", torture_libsmbclient_options);
1211         torture_suite_add_simple_test(suite, "opendir", torture_libsmbclient_opendir);
1212         torture_suite_add_simple_test(suite, "list_shares", torture_libsmbclient_list_shares);
1213         torture_suite_add_simple_test(suite, "readdirplus",
1214                 torture_libsmbclient_readdirplus);
1215         torture_suite_add_simple_test(suite, "readdirplus_seek",
1216                 torture_libsmbclient_readdirplus_seek);
1217         torture_suite_add_simple_test(suite, "readdirplus2",
1218                 torture_libsmbclient_readdirplus2);
1219
1220         suite->description = talloc_strdup(suite, "libsmbclient interface tests");
1221
1222         torture_register_suite(ctx, suite);
1223
1224         return NT_STATUS_OK;
1225 }