s4: torture: libsmbclient: Add a torture test to ensure smbc_stat() returns ENOENT...
[Samba.git] / source4 / torture / libsmbclient / libsmbclient.c
blobd335cad3a4e37dd6b5b14a5cd3466680241a8e11
1 /*
2 Unix SMB/CIFS implementation.
3 SMB torture tester
4 Copyright (C) Guenther Deschner 2010
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.
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.
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/>.
20 #include "includes.h"
21 #include "system/dir.h"
22 #include "torture/smbtorture.h"
23 #include "auth/credentials/credentials.h"
24 #include "lib/cmdline/cmdline.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 "libcli/smb/smb_constants.h"
30 #include "dynconfig.h"
31 #include "lib/util/time.h"
33 /* test string to compare with when debug_callback is called */
34 #define TEST_STRING "smbc_setLogCallback test"
36 /* Dummy log callback function */
37 static void debug_callback(void *private_ptr, int level, const char *msg)
39 bool *found = private_ptr;
40 if (strstr(msg, TEST_STRING) != NULL) {
41 *found = true;
43 return;
46 static void auth_callback(const char *srv,
47 const char *shr,
48 char *wg, int wglen,
49 char *un, int unlen,
50 char *pw, int pwlen)
52 const char *workgroup =
53 cli_credentials_get_domain(samba_cmdline_get_creds());
54 const char *username =
55 cli_credentials_get_username(samba_cmdline_get_creds());
56 const char *password =
57 cli_credentials_get_password(samba_cmdline_get_creds());
58 ssize_t ret;
60 if (workgroup != NULL) {
61 ret = strlcpy(wg, workgroup, wglen);
62 if (ret >= wglen) {
63 abort();
67 if (username != NULL) {
68 ret = strlcpy(un, username, unlen);
69 if (ret >= unlen) {
70 abort();
74 if (password != NULL) {
75 ret = strlcpy(pw, password, pwlen);
76 if (ret >= pwlen) {
77 abort();
82 bool torture_libsmbclient_init_context(struct torture_context *tctx,
83 SMBCCTX **ctx_p)
85 const char *workgroup =
86 cli_credentials_get_domain(samba_cmdline_get_creds());
87 const char *username =
88 cli_credentials_get_username(samba_cmdline_get_creds());
89 const char *client_proto =
90 torture_setting_string(tctx, "clientprotocol", NULL);
91 SMBCCTX *ctx = NULL;
92 SMBCCTX *p = NULL;
93 bool ok = true;
94 int dbglevel = DEBUGLEVEL;
96 ctx = smbc_new_context();
97 torture_assert_not_null_goto(tctx,
98 ctx,
99 ok,
100 out,
101 "Failed to create new context");
103 p = smbc_init_context(ctx);
104 torture_assert_not_null_goto(tctx,
107 out,
108 "Failed to initialize context");
110 smbc_setDebug(ctx, dbglevel);
111 smbc_setOptionDebugToStderr(ctx, 1);
113 if (workgroup != NULL) {
114 smbc_setWorkgroup(ctx, workgroup);
116 if (username != NULL) {
117 smbc_setUser(ctx, username);
120 smbc_setFunctionAuthData(ctx, auth_callback);
122 if (client_proto != NULL) {
123 smbc_setOptionProtocols(ctx, client_proto, client_proto);
126 *ctx_p = ctx;
128 out:
129 if (!ok) {
130 smbc_free_context(ctx, 1);
133 return ok;
136 static bool torture_libsmbclient_version(struct torture_context *tctx)
138 torture_comment(tctx, "Testing smbc_version\n");
140 torture_assert(tctx, smbc_version(), "failed to get version");
142 return true;
145 static bool torture_libsmbclient_initialize(struct torture_context *tctx)
147 SMBCCTX *ctx;
148 bool ret = false;
150 torture_comment(tctx, "Testing smbc_new_context\n");
152 ctx = smbc_new_context();
153 torture_assert(tctx, ctx, "failed to get new context");
155 torture_comment(tctx, "Testing smbc_init_context\n");
157 torture_assert(tctx, smbc_init_context(ctx), "failed to init context");
159 smbc_setLogCallback(ctx, &ret, debug_callback);
160 DEBUG(0, (TEST_STRING"\n"));
161 torture_assert(tctx, ret, "Failed debug_callback not called");
162 ret = false;
163 smbc_setLogCallback(ctx, NULL, NULL);
164 DEBUG(0, (TEST_STRING"\n"));
165 torture_assert(tctx, !ret, "Failed debug_callback called");
167 smbc_free_context(ctx, 1);
169 return true;
172 static bool torture_libsmbclient_setConfiguration(struct torture_context *tctx)
174 SMBCCTX *ctx;
175 struct loadparm_global *global_config = NULL;
176 const char *new_smb_conf = torture_setting_string(tctx,
177 "replace_smbconf",
178 "");
180 ctx = smbc_new_context();
181 torture_assert_not_null(tctx, ctx, "failed to get new context");
183 torture_assert_not_null(
184 tctx, smbc_init_context(ctx), "failed to init context");
186 torture_comment(tctx, "Testing smbc_setConfiguration - new file %s\n",
187 new_smb_conf);
189 global_config = get_globals();
190 torture_assert(tctx, global_config, "Global Config is NULL");
192 /* check configuration before smbc_setConfiguration call */
193 torture_comment(tctx, "'workgroup' before setConfiguration %s\n",
194 global_config->workgroup);
195 torture_comment(tctx, "'client min protocol' before "
196 "setConfiguration %d\n",
197 global_config->client_min_protocol);
198 torture_comment(tctx, "'client max protocol' before "
199 "setConfiguration %d\n",
200 global_config->_client_max_protocol);
201 torture_comment(tctx, "'client signing' before setConfiguration %d\n",
202 global_config->client_signing);
203 torture_comment(tctx, "'deadtime' before setConfiguration %d\n",
204 global_config->deadtime);
206 torture_assert_int_equal(tctx, smbc_setConfiguration(ctx, new_smb_conf),
207 0, "setConfiguration conf file not found");
209 /* verify configuration */
210 torture_assert_str_equal(tctx, global_config->workgroup,
211 "NEW_WORKGROUP",
212 "smbc_setConfiguration failed, "
213 "'workgroup' not updated");
214 torture_assert_int_equal(tctx, global_config->client_min_protocol, PROTOCOL_NT1,
215 "smbc_setConfiguration failed, 'client min protocol' "
216 "not updated");
217 torture_assert_int_equal(tctx, global_config->_client_max_protocol, PROTOCOL_SMB3_00,
218 "smbc_setConfiguration failed, 'client max protocol' "
219 "not updated");
220 torture_assert_int_equal(tctx, global_config->client_signing, 1,
221 "smbc_setConfiguration failed, 'client signing' "
222 "not updated");
223 torture_assert_int_equal(tctx, global_config->deadtime, 5,
224 "smbc_setConfiguration failed, 'deadtime' not updated");
226 /* Restore configuration to default */
227 smbc_setConfiguration(ctx, get_dyn_CONFIGFILE());
229 smbc_free_context(ctx, 1);
231 return true;
234 static bool test_opendir(struct torture_context *tctx,
235 SMBCCTX *ctx,
236 const char *fname,
237 bool expect_success)
239 int handle, ret;
241 torture_comment(tctx, "Testing smbc_opendir(%s)\n", fname);
243 handle = smbc_opendir(fname);
244 if (!expect_success) {
245 return true;
247 if (handle < 0) {
248 torture_fail(tctx, talloc_asprintf(tctx, "failed to obain file handle for '%s'", fname));
251 ret = smbc_closedir(handle);
252 torture_assert_int_equal(tctx, ret, 0,
253 talloc_asprintf(tctx, "failed to close file handle for '%s'", fname));
255 return true;
258 static bool torture_libsmbclient_opendir(struct torture_context *tctx)
260 size_t i;
261 SMBCCTX *ctx;
262 bool ret = true;
263 const char *bad_urls[] = {
265 NULL,
266 "smb",
267 "smb:",
268 "smb:/",
269 "smb:///",
270 "bms://",
271 ":",
272 ":/",
273 "://",
274 ":///",
275 "/",
276 "//",
277 "///"
279 const char *good_urls[] = {
280 "smb://",
281 "smb://WORKGROUP",
282 "smb://WORKGROUP/"
285 torture_assert(tctx, torture_libsmbclient_init_context(tctx, &ctx), "");
286 smbc_set_context(ctx);
288 for (i=0; i < ARRAY_SIZE(bad_urls); i++) {
289 ret &= test_opendir(tctx, ctx, bad_urls[i], false);
291 for (i=0; i < ARRAY_SIZE(good_urls); i++) {
292 ret &= test_opendir(tctx, ctx, good_urls[i], true);
295 smbc_free_context(ctx, 1);
297 return ret;
300 static bool torture_libsmbclient_readdirplus(struct torture_context *tctx)
302 SMBCCTX *ctx;
303 int ret = -1;
304 int dhandle = -1;
305 int fhandle = -1;
306 bool found = false;
307 const char *filename = NULL;
308 const char *smburl = torture_setting_string(tctx, "smburl", NULL);
310 if (smburl == NULL) {
311 torture_fail(tctx,
312 "option --option=torture:smburl="
313 "smb://user:password@server/share missing\n");
316 torture_assert(tctx, torture_libsmbclient_init_context(tctx, &ctx), "");
317 smbc_set_context(ctx);
319 filename = talloc_asprintf(tctx,
320 "%s/test_readdirplus.txt",
321 smburl);
322 if (filename == NULL) {
323 torture_fail(tctx,
324 "talloc fail\n");
326 /* Ensure the file doesn't exist. */
327 smbc_unlink(filename);
329 /* Create it. */
330 fhandle = smbc_creat(filename, 0666);
331 if (fhandle < 0) {
332 torture_fail(tctx,
333 talloc_asprintf(tctx,
334 "failed to create file '%s': %s",
335 filename,
336 strerror(errno)));
338 ret = smbc_close(fhandle);
339 torture_assert_int_equal(tctx,
340 ret,
342 talloc_asprintf(tctx,
343 "failed to close handle for '%s'",
344 filename));
346 dhandle = smbc_opendir(smburl);
347 if (dhandle < 0) {
348 int saved_errno = errno;
349 smbc_unlink(filename);
350 torture_fail(tctx,
351 talloc_asprintf(tctx,
352 "failed to obtain "
353 "directory handle for '%s' : %s",
354 smburl,
355 strerror(saved_errno)));
358 /* Readdirplus to ensure we see the new file. */
359 for (;;) {
360 const struct libsmb_file_info *exstat =
361 smbc_readdirplus(dhandle);
362 if (exstat == NULL) {
363 break;
365 if (strcmp(exstat->name, "test_readdirplus.txt") == 0) {
366 found = true;
367 break;
371 /* Remove it again. */
372 smbc_unlink(filename);
373 ret = smbc_closedir(dhandle);
374 torture_assert_int_equal(tctx,
375 ret,
377 talloc_asprintf(tctx,
378 "failed to close directory handle for '%s'",
379 smburl));
381 smbc_free_context(ctx, 1);
383 if (!found) {
384 torture_fail(tctx,
385 talloc_asprintf(tctx,
386 "failed to find file '%s'",
387 filename));
390 return true;
393 static bool torture_libsmbclient_readdirplus_seek(struct torture_context *tctx)
395 SMBCCTX *ctx;
396 int ret = -1;
397 int dhandle = -1;
398 int fhandle = -1;
399 const char *dname = NULL;
400 const char *full_filename[100] = {0};
401 const char *filename[100] = {0};
402 const struct libsmb_file_info *direntries[102] = {0};
403 unsigned int i = 0;
404 const char *smburl = torture_setting_string(tctx, "smburl", NULL);
405 bool success = false;
406 off_t telldir_50 = (off_t)-1;
407 off_t telldir_20 = (off_t)-1;
408 size_t getdentries_size = 0;
409 struct smbc_dirent *getdentries = NULL;
410 struct smbc_dirent *dirent_20 = NULL;
411 const struct libsmb_file_info *direntries_20 = NULL;
412 const struct libsmb_file_info *direntriesplus_20 = NULL;
413 const char *plus2_stat_path = NULL;
414 struct stat st = {0};
415 struct stat st2 = {0};
417 torture_assert_not_null(
418 tctx,
419 smburl,
420 "option --option=torture:smburl="
421 "smb://user:password@server/share missing\n");
423 DEBUG(0,("torture_libsmbclient_readdirplus_seek start\n"));
425 torture_assert(tctx, torture_libsmbclient_init_context(tctx, &ctx), "");
426 smbc_set_context(ctx);
428 dname = talloc_asprintf(tctx,
429 "%s/rd_seek",
430 smburl);
431 torture_assert_not_null_goto(
432 tctx, dname, success, done, "talloc fail\n");
434 /* Ensure the files don't exist. */
435 for (i = 0; i < 100; i++) {
436 filename[i] = talloc_asprintf(tctx,
437 "test_readdirplus_%u.txt",
439 torture_assert_not_null_goto(
440 tctx, filename[i], success, done, "talloc fail");
441 full_filename[i] = talloc_asprintf(tctx,
442 "%s/%s",
443 dname,
444 filename[i]);
445 torture_assert_not_null_goto(
446 tctx, full_filename[i], success, done, "talloc fail");
447 (void)smbc_unlink(full_filename[i]);
449 /* Ensure the directory doesn't exist. */
450 (void)smbc_rmdir(dname);
452 /* Create containing directory. */
453 ret = smbc_mkdir(dname, 0777);
454 torture_assert_goto(
455 tctx,
456 ret == 0,
457 success,
458 done,
459 talloc_asprintf(tctx,
460 "failed to create directory '%s': %s",
461 dname,
462 strerror(errno)));
464 DEBUG(0,("torture_libsmbclient_readdirplus_seek create\n"));
466 /* Create them. */
467 for (i = 0; i < 100; i++) {
468 fhandle = smbc_creat(full_filename[i], 0666);
469 if (fhandle < 0) {
470 torture_fail_goto(tctx,
471 done,
472 talloc_asprintf(tctx,
473 "failed to create file '%s': %s",
474 full_filename[i],
475 strerror(errno)));
477 ret = smbc_close(fhandle);
478 torture_assert_int_equal_goto(tctx,
479 ret,
481 success,
482 done,
483 talloc_asprintf(tctx,
484 "failed to close handle for '%s'",
485 full_filename[i]));
488 DEBUG(0,("torture_libsmbclient_readdirplus_seek enum\n"));
490 /* Now enumerate the directory. */
491 dhandle = smbc_opendir(dname);
492 torture_assert_goto(
493 tctx,
494 dhandle >= 0,
495 success,
496 done,
497 talloc_asprintf(tctx,
498 "failed to obtain "
499 "directory handle for '%s' : %s",
500 dname,
501 strerror(errno)));
503 /* Read all the files. 100 we created plus . and .. */
504 for (i = 0; i < 102; i++) {
505 bool found = false;
506 unsigned int j;
508 direntries[i] = smbc_readdirplus(dhandle);
509 if (direntries[i] == NULL) {
510 break;
513 /* Store at offset 50. */
514 if (i == 50) {
515 telldir_50 = smbc_telldir(dhandle);
516 torture_assert_goto(
517 tctx,
518 telldir_50 != (off_t)-1,
519 success,
520 done,
521 talloc_asprintf(tctx,
522 "telldir failed file %s\n",
523 direntries[i]->name));
526 if (ISDOT(direntries[i]->name)) {
527 continue;
529 if (ISDOTDOT(direntries[i]->name)) {
530 continue;
533 /* Ensure all our files exist. */
534 for (j = 0; j < 100; j++) {
535 if (strcmp(direntries[i]->name,
536 filename[j]) == 0) {
537 found = true;
540 torture_assert_goto(
541 tctx,
542 found,
543 success,
544 done,
545 talloc_asprintf(tctx,
546 "failed to find file %s\n",
547 direntries[i]->name));
551 * We're seeking on in-memory lists here, so
552 * whilst the handle is open we really should
553 * get the same files back in the same order.
556 ret = smbc_lseekdir(dhandle, telldir_50);
557 torture_assert_int_equal_goto(tctx,
558 ret,
560 success,
561 done,
562 talloc_asprintf(tctx,
563 "failed to seek (50) directory handle for '%s'",
564 dname));
566 DEBUG(0,("torture_libsmbclient_readdirplus_seek seek\n"));
568 for (i = 51; i < 102; i++) {
569 const struct libsmb_file_info *entry =
570 smbc_readdirplus(dhandle);
571 torture_assert_goto(
572 tctx,
573 entry == direntries[i],
574 success,
575 done,
576 talloc_asprintf(tctx,
577 "after seek - failed to find "
578 "file %s - got %s\n",
579 direntries[i]->name,
580 entry->name));
583 /* Seek back to the start. */
584 ret = smbc_lseekdir(dhandle, 0);
585 torture_assert_int_equal_goto(tctx,
586 ret,
588 success,
589 done,
590 talloc_asprintf(tctx,
591 "failed to seek directory handle to start for '%s'",
592 dname));
595 * Mix getdents/readdir/readdirplus with lseek to ensure
596 * we get the same result.
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.
603 getdentries_size = 20 * (sizeof(struct smbc_dirent) +
604 strlen("test_readdirplus_1000.txt") + 1);
606 getdentries = (struct smbc_dirent *)talloc_array_size(tctx,
607 getdentries_size,
609 torture_assert_not_null_goto(
610 tctx,
611 getdentries,
612 success,
613 done,
614 "talloc fail");
616 ret = smbc_getdents(dhandle, getdentries, getdentries_size);
617 torture_assert_goto(tctx,
618 (ret != -1),
619 success,
620 done,
621 talloc_asprintf(tctx,
622 "smbd_getdents(1) for '%s' failed\n",
623 dname));
625 telldir_20 = smbc_telldir(dhandle);
626 torture_assert_goto(
627 tctx,
628 telldir_20 != (off_t)-1,
629 success,
630 done,
631 "telldir (20) failed\n");
633 /* Read another 20. */
634 ret = smbc_getdents(dhandle, getdentries, getdentries_size);
635 torture_assert_goto(tctx,
636 (ret != -1),
637 success,
638 done,
639 talloc_asprintf(tctx,
640 "smbd_getdents(2) for '%s' failed\n",
641 dname));
643 /* Seek back to 20. */
644 ret = smbc_lseekdir(dhandle, telldir_20);
645 torture_assert_int_equal_goto(tctx,
646 ret,
648 success,
649 done,
650 talloc_asprintf(tctx,
651 "failed to seek (20) directory handle for '%s'",
652 dname));
654 /* Read with readdir. */
655 dirent_20 = smbc_readdir(dhandle);
656 torture_assert_not_null_goto(
657 tctx,
658 dirent_20,
659 success,
660 done,
661 "smbc_readdir (20) failed\n");
663 /* Ensure the getdents and readdir names are the same. */
664 ret = strcmp(dirent_20->name, getdentries[0].name);
665 torture_assert_goto(
666 tctx,
667 ret == 0,
668 success,
669 done,
670 talloc_asprintf(tctx,
671 "after seek (20) readdir name mismatch "
672 "file %s - got %s\n",
673 dirent_20->name,
674 getdentries[0].name));
676 /* Seek back to 20. */
677 ret = smbc_lseekdir(dhandle, telldir_20);
678 torture_assert_int_equal_goto(tctx,
679 ret,
681 success,
682 done,
683 talloc_asprintf(tctx,
684 "failed to seek (20) directory handle for '%s'",
685 dname));
686 /* Read with readdirplus. */
687 direntries_20 = smbc_readdirplus(dhandle);
688 torture_assert_not_null_goto(
689 tctx,
690 direntries_20,
691 success,
692 done,
693 "smbc_readdirplus (20) failed\n");
695 /* Ensure the readdirplus and readdir names are the same. */
696 ret = strcmp(dirent_20->name, direntries_20->name);
697 torture_assert_goto(
698 tctx,
699 ret == 0,
700 success,
701 done,
702 talloc_asprintf(tctx,
703 "after seek (20) readdirplus name mismatch "
704 "file %s - got %s\n",
705 dirent_20->name,
706 direntries_20->name));
708 /* Seek back to 20. */
709 ret = smbc_lseekdir(dhandle, telldir_20);
710 torture_assert_int_equal_goto(tctx,
711 ret,
713 success,
714 done,
715 talloc_asprintf(tctx,
716 "failed to seek (20) directory handle for '%s'",
717 dname));
719 /* Read with readdirplus2. */
720 direntriesplus_20 = smbc_readdirplus2(dhandle, &st2);
721 torture_assert_not_null_goto(
722 tctx,
723 direntriesplus_20,
724 success,
725 done,
726 "smbc_readdirplus2 (20) failed\n");
728 /* Ensure the readdirplus2 and readdirplus names are the same. */
729 ret = strcmp(direntries_20->name, direntriesplus_20->name);
730 torture_assert_goto(
731 tctx,
732 ret == 0,
733 success,
734 done,
735 talloc_asprintf(tctx,
736 "after seek (20) readdirplus2 name mismatch "
737 "file %s - got %s\n",
738 dirent_20->name,
739 direntries_20->name));
741 /* Ensure doing stat gets the same data. */
742 plus2_stat_path = talloc_asprintf(tctx,
743 "%s/%s",
744 dname,
745 direntriesplus_20->name);
746 torture_assert_not_null_goto(
747 tctx,
748 plus2_stat_path,
749 success,
750 done,
751 "talloc fail\n");
753 ret = smbc_stat(plus2_stat_path, &st);
754 torture_assert_int_equal_goto(tctx,
755 ret,
757 success,
758 done,
759 talloc_asprintf(tctx,
760 "failed to stat file '%s'",
761 plus2_stat_path));
763 torture_assert_int_equal(tctx,
764 st.st_ino,
765 st2.st_ino,
766 talloc_asprintf(tctx,
767 "file %s mismatched ino value "
768 "stat got %"PRIx64" readdirplus2 got %"PRIx64"" ,
769 plus2_stat_path,
770 (uint64_t)st.st_ino,
771 (uint64_t)st2.st_ino));
773 torture_assert_int_equal(tctx,
774 st.st_dev,
775 st2.st_dev,
776 talloc_asprintf(tctx,
777 "file %s mismatched dev value "
778 "stat got %"PRIx64" readdirplus2 got %"PRIx64"" ,
779 plus2_stat_path,
780 (uint64_t)st.st_dev,
781 (uint64_t)st2.st_dev));
783 ret = smbc_closedir(dhandle);
784 torture_assert_int_equal(tctx,
785 ret,
787 talloc_asprintf(tctx,
788 "failed to close directory handle for '%s'",
789 dname));
791 dhandle = -1;
792 success = true;
794 done:
796 /* Clean up. */
797 if (dhandle != -1) {
798 smbc_closedir(dhandle);
800 for (i = 0; i < 100; i++) {
801 if (full_filename[i] != NULL) {
802 smbc_unlink(full_filename[i]);
805 if (dname != NULL) {
806 smbc_rmdir(dname);
809 smbc_free_context(ctx, 1);
811 return success;
814 #ifndef SMBC_FILE_MODE
815 #define SMBC_FILE_MODE (S_IFREG | 0444)
816 #endif
818 static bool torture_libsmbclient_readdirplus2(struct torture_context *tctx)
820 SMBCCTX *ctx = NULL;
821 int dhandle = -1;
822 int fhandle = -1;
823 bool found = false;
824 bool success = false;
825 const char *filename = NULL;
826 struct stat st2 = {0};
827 struct stat st = {0};
828 int ret;
829 const char *smburl = torture_setting_string(tctx, "smburl", NULL);
831 if (smburl == NULL) {
832 torture_fail(tctx,
833 "option --option=torture:smburl="
834 "smb://user:password@server/share missing\n");
837 torture_assert_goto(tctx, torture_libsmbclient_init_context(tctx, &ctx), success, done, "");
838 smbc_set_context(ctx);
840 filename = talloc_asprintf(tctx,
841 "%s/test_readdirplus.txt",
842 smburl);
843 if (filename == NULL) {
844 torture_fail_goto(tctx, done, "talloc fail\n");
847 /* Ensure the file doesn't exist. */
848 smbc_unlink(filename);
850 /* Create it. */
851 fhandle = smbc_creat(filename, 0666);
852 if (fhandle < 0) {
853 torture_fail_goto(tctx,
854 done,
855 talloc_asprintf(tctx,
856 "failed to create file '%s': %s",
857 filename,
858 strerror(errno)));
860 ret = smbc_close(fhandle);
861 torture_assert_int_equal_goto(tctx,
862 ret,
864 success,
865 done,
866 talloc_asprintf(tctx,
867 "failed to close handle for '%s'",
868 filename));
870 dhandle = smbc_opendir(smburl);
871 if (dhandle < 0) {
872 int saved_errno = errno;
873 smbc_unlink(filename);
874 torture_fail_goto(tctx,
875 done,
876 talloc_asprintf(tctx,
877 "failed to obtain "
878 "directory handle for '%s' : %s",
879 smburl,
880 strerror(saved_errno)));
883 /* readdirplus2 to ensure we see the new file. */
884 for (;;) {
885 const struct libsmb_file_info *exstat =
886 smbc_readdirplus2(dhandle, &st2);
887 if (exstat == NULL) {
888 break;
891 if (strcmp(exstat->name, "test_readdirplus.txt") == 0) {
892 found = true;
893 break;
897 if (!found) {
898 smbc_unlink(filename);
899 torture_fail_goto(tctx,
900 done,
901 talloc_asprintf(tctx,
902 "failed to find file '%s'",
903 filename));
906 /* Ensure mode is as expected. */
908 * New file gets SMBC_FILE_MODE plus
909 * archive bit -> S_IXUSR
910 * !READONLY -> S_IWUSR.
912 torture_assert_int_equal_goto(tctx,
913 st2.st_mode,
914 SMBC_FILE_MODE|S_IXUSR|S_IWUSR,
915 success,
916 done,
917 talloc_asprintf(tctx,
918 "file %s st_mode should be 0%o, got 0%o'",
919 filename,
920 SMBC_FILE_MODE|S_IXUSR|S_IWUSR,
921 (unsigned int)st2.st_mode));
923 /* Ensure smbc_stat() gets the same data. */
924 ret = smbc_stat(filename, &st);
925 torture_assert_int_equal_goto(tctx,
926 ret,
928 success,
929 done,
930 talloc_asprintf(tctx,
931 "failed to stat file '%s'",
932 filename));
934 torture_assert_int_equal_goto(tctx,
935 st2.st_ino,
936 st.st_ino,
937 success,
938 done,
939 talloc_asprintf(tctx,
940 "filename '%s' ino mismatch. "
941 "From smbc_readdirplus2 = %"PRIx64" "
942 "From smbc_stat = %"PRIx64"",
943 filename,
944 (uint64_t)st2.st_ino,
945 (uint64_t)st.st_ino));
948 /* Remove it again. */
949 smbc_unlink(filename);
950 ret = smbc_closedir(dhandle);
951 torture_assert_int_equal_goto(tctx,
952 ret,
954 success,
955 done,
956 talloc_asprintf(tctx,
957 "failed to close directory handle for '%s'",
958 filename));
959 success = true;
961 done:
962 smbc_free_context(ctx, 1);
963 return success;
966 bool torture_libsmbclient_configuration(struct torture_context *tctx)
968 SMBCCTX *ctx;
969 bool ok = true;
971 ctx = smbc_new_context();
972 torture_assert(tctx, ctx, "failed to get new context");
973 torture_assert(tctx, smbc_init_context(ctx), "failed to init context");
975 torture_comment(tctx, "Testing smbc_(set|get)Debug\n");
976 smbc_setDebug(ctx, DEBUGLEVEL);
977 torture_assert_int_equal_goto(tctx,
978 smbc_getDebug(ctx),
979 DEBUGLEVEL,
981 done,
982 "failed to set DEBUGLEVEL");
984 torture_comment(tctx, "Testing smbc_(set|get)NetbiosName\n");
985 smbc_setNetbiosName(ctx, discard_const("torture_netbios"));
986 torture_assert_str_equal_goto(tctx,
987 smbc_getNetbiosName(ctx),
988 "torture_netbios",
990 done,
991 "failed to set NetbiosName");
993 torture_comment(tctx, "Testing smbc_(set|get)Workgroup\n");
994 smbc_setWorkgroup(ctx, discard_const("torture_workgroup"));
995 torture_assert_str_equal_goto(tctx,
996 smbc_getWorkgroup(ctx),
997 "torture_workgroup",
999 done,
1000 "failed to set Workgroup");
1002 torture_comment(tctx, "Testing smbc_(set|get)User\n");
1003 smbc_setUser(ctx, "torture_user");
1004 torture_assert_str_equal_goto(tctx,
1005 smbc_getUser(ctx),
1006 "torture_user",
1008 done,
1009 "failed to set User");
1011 torture_comment(tctx, "Testing smbc_(set|get)Timeout\n");
1012 smbc_setTimeout(ctx, 12345);
1013 torture_assert_int_equal_goto(tctx,
1014 smbc_getTimeout(ctx),
1015 12345,
1017 done,
1018 "failed to set Timeout");
1020 done:
1021 smbc_free_context(ctx, 1);
1023 return ok;
1026 bool torture_libsmbclient_options(struct torture_context *tctx)
1028 SMBCCTX *ctx;
1029 bool ok = true;
1031 ctx = smbc_new_context();
1032 torture_assert(tctx, ctx, "failed to get new context");
1033 torture_assert(tctx, smbc_init_context(ctx), "failed to init context");
1035 torture_comment(tctx, "Testing smbc_(set|get)OptionDebugToStderr\n");
1036 smbc_setOptionDebugToStderr(ctx, true);
1037 torture_assert_goto(tctx,
1038 smbc_getOptionDebugToStderr(ctx),
1040 done,
1041 "failed to set OptionDebugToStderr");
1043 torture_comment(tctx, "Testing smbc_(set|get)OptionFullTimeNames\n");
1044 smbc_setOptionFullTimeNames(ctx, true);
1045 torture_assert_goto(tctx,
1046 smbc_getOptionFullTimeNames(ctx),
1048 done,
1049 "failed to set OptionFullTimeNames");
1051 torture_comment(tctx, "Testing smbc_(set|get)OptionOpenShareMode\n");
1052 smbc_setOptionOpenShareMode(ctx, SMBC_SHAREMODE_DENY_ALL);
1053 torture_assert_int_equal_goto(tctx,
1054 smbc_getOptionOpenShareMode(ctx),
1055 SMBC_SHAREMODE_DENY_ALL,
1057 done,
1058 "failed to set OptionOpenShareMode");
1060 torture_comment(tctx, "Testing smbc_(set|get)OptionUserData\n");
1061 smbc_setOptionUserData(ctx, (void *)discard_const("torture_user_data"));
1062 torture_assert_str_equal_goto(tctx,
1063 (const char*)smbc_getOptionUserData(ctx),
1064 "torture_user_data",
1066 done,
1067 "failed to set OptionUserData");
1069 torture_comment(tctx,
1070 "Testing smbc_(set|get)OptionSmbEncryptionLevel\n");
1071 smbc_setOptionSmbEncryptionLevel(ctx, SMBC_ENCRYPTLEVEL_REQUEST);
1072 torture_assert_int_equal_goto(tctx,
1073 smbc_getOptionSmbEncryptionLevel(ctx),
1074 SMBC_ENCRYPTLEVEL_REQUEST,
1076 done,
1077 "failed to set OptionSmbEncryptionLevel");
1079 torture_comment(tctx, "Testing smbc_(set|get)OptionCaseSensitive\n");
1080 smbc_setOptionCaseSensitive(ctx, false);
1081 torture_assert_goto(tctx,
1082 !smbc_getOptionCaseSensitive(ctx),
1084 done,
1085 "failed to set OptionCaseSensitive");
1087 torture_comment(tctx,
1088 "Testing smbc_(set|get)OptionBrowseMaxLmbCount\n");
1089 smbc_setOptionBrowseMaxLmbCount(ctx, 2);
1090 torture_assert_int_equal_goto(tctx,
1091 smbc_getOptionBrowseMaxLmbCount(ctx),
1094 done,
1095 "failed to set OptionBrowseMaxLmbCount");
1097 torture_comment(tctx,
1098 "Testing smbc_(set|get)OptionUrlEncodeReaddirEntries\n");
1099 smbc_setOptionUrlEncodeReaddirEntries(ctx, true);
1100 torture_assert_goto(tctx,
1101 smbc_getOptionUrlEncodeReaddirEntries(ctx),
1103 done,
1104 "failed to set OptionUrlEncodeReaddirEntries");
1106 torture_comment(tctx,
1107 "Testing smbc_(set|get)OptionOneSharePerServer\n");
1108 smbc_setOptionOneSharePerServer(ctx, true);
1109 torture_assert_goto(tctx,
1110 smbc_getOptionOneSharePerServer(ctx),
1112 done,
1113 "failed to set OptionOneSharePerServer");
1115 torture_comment(tctx, "Testing smbc_(set|get)OptionUseKerberos\n");
1116 smbc_setOptionUseKerberos(ctx, false);
1117 torture_assert_goto(tctx,
1118 !smbc_getOptionUseKerberos(ctx),
1120 done,
1121 "failed to set OptionUseKerberos");
1123 torture_comment(tctx,
1124 "Testing smbc_(set|get)OptionFallbackAfterKerberos\n");
1125 smbc_setOptionFallbackAfterKerberos(ctx, false);
1126 torture_assert_goto(tctx,
1127 !smbc_getOptionFallbackAfterKerberos(ctx),
1129 done,
1130 "failed to set OptionFallbackAfterKerberos");
1132 torture_comment(tctx,
1133 "Testing smbc_(set|get)OptionNoAutoAnonymousLogin\n");
1134 smbc_setOptionNoAutoAnonymousLogin(ctx, true);
1135 torture_assert_goto(tctx,
1136 smbc_getOptionNoAutoAnonymousLogin(ctx),
1138 done,
1139 "failed to set OptionNoAutoAnonymousLogin");
1141 torture_comment(tctx, "Testing smbc_(set|get)OptionUseCCache\n");
1142 smbc_setOptionUseCCache(ctx, true);
1143 torture_assert_goto(tctx,
1144 smbc_getOptionUseCCache(ctx),
1146 done,
1147 "failed to set OptionUseCCache");
1149 done:
1150 smbc_free_context(ctx, 1);
1152 return ok;
1155 static bool torture_libsmbclient_list_shares(struct torture_context *tctx)
1157 const char *smburl = torture_setting_string(tctx, "smburl", NULL);
1158 struct smbc_dirent *dirent = NULL;
1159 SMBCCTX *ctx = NULL;
1160 int dhandle = -1;
1161 bool ipc_share_found = false;
1162 bool ok = true;
1164 if (smburl == NULL) {
1165 torture_fail(tctx,
1166 "option --option=torture:smburl="
1167 "smb://user:password@server missing\n");
1170 ok = torture_libsmbclient_init_context(tctx, &ctx);
1171 torture_assert_goto(tctx,
1174 out,
1175 "Failed to init context");
1176 smbc_set_context(ctx);
1178 torture_comment(tctx, "Listing: %s\n", smburl);
1179 dhandle = smbc_opendir(smburl);
1180 torture_assert_int_not_equal_goto(tctx,
1181 dhandle,
1184 out,
1185 "Failed to open smburl");
1187 while((dirent = smbc_readdir(dhandle)) != NULL) {
1188 torture_comment(tctx, "DIR: %s\n", dirent->name);
1189 torture_assert_not_null_goto(tctx,
1190 dirent->name,
1192 out,
1193 "Failed to read name");
1195 if (strequal(dirent->name, "IPC$")) {
1196 ipc_share_found = true;
1200 torture_assert_goto(tctx,
1201 ipc_share_found,
1203 out,
1204 "Failed to list IPC$ share");
1206 out:
1207 smbc_closedir(dhandle);
1208 return ok;
1211 static bool torture_libsmbclient_utimes(struct torture_context *tctx)
1213 const char *smburl = torture_setting_string(tctx, "smburl", NULL);
1214 SMBCCTX *ctx = NULL;
1215 struct stat st;
1216 int fhandle, ret;
1217 struct timeval tbuf[2];
1218 bool ok;
1220 if (smburl == NULL) {
1221 torture_fail(tctx,
1222 "option --option=torture:smburl="
1223 "smb://user:password@server missing\n");
1226 ok = torture_libsmbclient_init_context(tctx, &ctx);
1227 torture_assert(tctx, ok, "Failed to init context");
1228 smbc_set_context(ctx);
1230 fhandle = smbc_open(smburl, O_RDWR|O_CREAT, 0644);
1231 torture_assert_int_not_equal(tctx, fhandle, -1, "smbc_open failed");
1233 ret = smbc_fstat(fhandle, &st);
1234 torture_assert_int_not_equal(tctx, ret, -1, "smbc_fstat failed");
1236 tbuf[0] = convert_timespec_to_timeval(get_atimespec(&st));
1237 tbuf[1] = convert_timespec_to_timeval(get_mtimespec(&st));
1239 tbuf[1] = timeval_add(&tbuf[1], 0, 100000); /* 100 msec */
1241 ret = smbc_utimes(smburl, tbuf);
1242 torture_assert_int_not_equal(tctx, ret, -1, "smbc_utimes failed");
1244 ret = smbc_fstat(fhandle, &st);
1245 torture_assert_int_not_equal(tctx, ret, -1, "smbc_fstat failed");
1247 torture_assert_int_equal(
1248 tctx,
1249 get_mtimensec(&st) / 1000,
1250 tbuf[1].tv_usec,
1251 "smbc_utimes did not update msec");
1253 smbc_close(fhandle);
1254 smbc_unlink(smburl);
1255 return true;
1258 static bool torture_libsmbclient_noanon_list(struct torture_context *tctx)
1260 const char *smburl = torture_setting_string(tctx, "smburl", NULL);
1261 struct smbc_dirent *dirent = NULL;
1262 SMBCCTX *ctx = NULL;
1263 int dhandle = -1;
1264 bool ok = true;
1266 if (smburl == NULL) {
1267 torture_fail(tctx,
1268 "option --option=torture:smburl="
1269 "smb://user:password@server missing\n");
1272 ok = torture_libsmbclient_init_context(tctx, &ctx);
1273 torture_assert_goto(tctx,
1276 out,
1277 "Failed to init context");
1278 torture_comment(tctx,
1279 "Testing smbc_setOptionNoAutoAnonymousLogin\n");
1280 smbc_setOptionNoAutoAnonymousLogin(ctx, true);
1281 smbc_set_context(ctx);
1283 torture_comment(tctx, "Listing: %s\n", smburl);
1284 dhandle = smbc_opendir(smburl);
1285 torture_assert_int_not_equal_goto(tctx,
1286 dhandle,
1289 out,
1290 "Failed to open smburl");
1292 while((dirent = smbc_readdir(dhandle)) != NULL) {
1293 torture_comment(tctx, "DIR: %s\n", dirent->name);
1294 torture_assert_not_null_goto(tctx,
1295 dirent->name,
1297 out,
1298 "Failed to read name");
1301 out:
1302 smbc_closedir(dhandle);
1303 return ok;
1306 static bool torture_libsmbclient_rename(struct torture_context *tctx)
1308 SMBCCTX *ctx = NULL;
1309 int fhandle = -1;
1310 bool success = false;
1311 const char *filename_src = NULL;
1312 const char *filename_dst = NULL;
1313 int ret;
1314 const char *smburl = torture_setting_string(tctx, "smburl", NULL);
1316 if (smburl == NULL) {
1317 torture_fail(tctx,
1318 "option --option=torture:smburl="
1319 "smb://user:password@server/share missing\n");
1322 torture_assert_goto(tctx,
1323 torture_libsmbclient_init_context(tctx, &ctx),
1324 success,
1325 done,
1326 "");
1328 smbc_set_context(ctx);
1330 filename_src = talloc_asprintf(tctx,
1331 "%s/src",
1332 smburl);
1333 if (filename_src == NULL) {
1334 torture_fail_goto(tctx, done, "talloc fail\n");
1337 filename_dst = talloc_asprintf(tctx,
1338 "%s/dst",
1339 smburl);
1340 if (filename_dst == NULL) {
1341 torture_fail_goto(tctx, done, "talloc fail\n");
1344 /* Ensure the files don't exist. */
1345 smbc_unlink(filename_src);
1346 smbc_unlink(filename_dst);
1348 /* Create them. */
1349 fhandle = smbc_creat(filename_src, 0666);
1350 if (fhandle < 0) {
1351 torture_fail_goto(tctx,
1352 done,
1353 talloc_asprintf(tctx,
1354 "failed to create file '%s': %s",
1355 filename_src,
1356 strerror(errno)));
1358 ret = smbc_close(fhandle);
1359 torture_assert_int_equal_goto(tctx,
1360 ret,
1362 success,
1363 done,
1364 talloc_asprintf(tctx,
1365 "failed to close handle for '%s'",
1366 filename_src));
1368 fhandle = smbc_creat(filename_dst, 0666);
1369 if (fhandle < 0) {
1370 torture_fail_goto(tctx,
1371 done,
1372 talloc_asprintf(tctx,
1373 "failed to create file '%s': %s",
1374 filename_dst,
1375 strerror(errno)));
1377 ret = smbc_close(fhandle);
1378 torture_assert_int_equal_goto(tctx,
1379 ret,
1381 success,
1382 done,
1383 talloc_asprintf(tctx,
1384 "failed to close handle for '%s'",
1385 filename_dst));
1387 ret = smbc_rename(filename_src, filename_dst);
1390 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14938
1391 * gives ret == -1, but errno = 0 for overwrite renames
1392 * over SMB2.
1394 torture_assert_int_equal_goto(tctx,
1395 ret,
1397 success,
1398 done,
1399 talloc_asprintf(tctx,
1400 "smbc_rename '%s' -> '%s' failed with %s\n",
1401 filename_src,
1402 filename_dst,
1403 strerror(errno)));
1405 /* Remove them again. */
1406 smbc_unlink(filename_src);
1407 smbc_unlink(filename_dst);
1408 success = true;
1410 done:
1411 smbc_free_context(ctx, 1);
1412 return success;
1415 static bool torture_libsmbclient_getatr(struct torture_context *tctx)
1417 const char *smburl = torture_setting_string(tctx, "smburl", NULL);
1418 SMBCCTX *ctx = NULL;
1419 char *getatr_name = NULL;
1420 struct stat st = {0};
1421 bool ok;
1422 int ret = 0;
1423 int err = 0;
1425 if (smburl == NULL) {
1426 torture_fail(tctx,
1427 "option --option=torture:smburl="
1428 "smb://user:password@server missing\n");
1431 ok = torture_libsmbclient_init_context(tctx, &ctx);
1432 torture_assert(tctx, ok, "Failed to init context");
1433 smbc_set_context(ctx);
1435 getatr_name = talloc_asprintf(tctx,
1436 "%s/noexist",
1437 smburl);
1438 if (getatr_name == NULL) {
1439 torture_result(tctx,
1440 TORTURE_FAIL,
1441 __location__": %s",
1442 "talloc fail\n");
1443 return false;
1445 /* Ensure the file doesn't exist. */
1446 smbc_unlink(getatr_name);
1448 * smbc_stat() internally uses SMBC_getatr().
1449 * Make sure doing getatr on a non-existent file gives
1450 * an error of -1, errno = ENOENT.
1453 ret = smbc_stat(getatr_name, &st);
1454 if (ret == -1) {
1455 err = errno;
1457 torture_assert_int_equal(tctx,
1458 ret,
1460 talloc_asprintf(tctx,
1461 "smbc_stat on '%s' should "
1462 "get -1, got %d\n",
1463 getatr_name,
1464 ret));
1465 torture_assert_int_equal(tctx,
1466 err,
1467 ENOENT,
1468 talloc_asprintf(tctx,
1469 "smbc_stat on '%s' should "
1470 "get errno = ENOENT, got %s\n",
1471 getatr_name,
1472 strerror(err)));
1473 return true;
1476 NTSTATUS torture_libsmbclient_init(TALLOC_CTX *ctx)
1478 struct torture_suite *suite;
1480 suite = torture_suite_create(ctx, "libsmbclient");
1482 torture_suite_add_simple_test(suite, "version", torture_libsmbclient_version);
1483 torture_suite_add_simple_test(suite, "initialize", torture_libsmbclient_initialize);
1484 torture_suite_add_simple_test(suite, "configuration", torture_libsmbclient_configuration);
1485 torture_suite_add_simple_test(suite, "setConfiguration", torture_libsmbclient_setConfiguration);
1486 torture_suite_add_simple_test(suite, "options", torture_libsmbclient_options);
1487 torture_suite_add_simple_test(suite, "opendir", torture_libsmbclient_opendir);
1488 torture_suite_add_simple_test(suite, "list_shares", torture_libsmbclient_list_shares);
1489 torture_suite_add_simple_test(suite, "readdirplus",
1490 torture_libsmbclient_readdirplus);
1491 torture_suite_add_simple_test(suite, "readdirplus_seek",
1492 torture_libsmbclient_readdirplus_seek);
1493 torture_suite_add_simple_test(suite, "readdirplus2",
1494 torture_libsmbclient_readdirplus2);
1495 torture_suite_add_simple_test(
1496 suite, "utimes", torture_libsmbclient_utimes);
1497 torture_suite_add_simple_test(
1498 suite, "noanon_list", torture_libsmbclient_noanon_list);
1499 torture_suite_add_simple_test(suite,
1500 "rename",
1501 torture_libsmbclient_rename);
1502 torture_suite_add_simple_test(suite, "getatr",
1503 torture_libsmbclient_getatr);
1505 suite->description = talloc_strdup(suite, "libsmbclient interface tests");
1507 torture_register_suite(ctx, suite);
1509 return NT_STATUS_OK;