2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1998
6 Copyright (C) Derrell Lipman 2003-2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 int smbw_fd_map[__FD_SETSIZE];
31 int smbw_ref_count[__FD_SETSIZE];
32 char smbw_cwd[PATH_MAX];
33 char smbw_prefix[] = SMBW_PREFIX;
35 /* needs to be here because of dumb include files on some systems */
36 int creat_bits = O_WRONLY|O_CREAT|O_TRUNC;
38 int smbw_initialized = 0;
40 static int debug_level = 0;
42 static SMBCCTX *smbw_ctx;
44 extern int smbw_debug;
47 int smbw_ref(int client_fd, Ref_Count_Type type, ...)
51 /* client id values begin at SMBC_BASE_FC. */
52 client_fd -= SMBC_BASE_FD;
57 case SMBW_RCT_Increment:
58 return ++smbw_ref_count[client_fd];
60 case SMBW_RCT_Decrement:
61 return --smbw_ref_count[client_fd];
64 return smbw_ref_count[client_fd];
67 return (smbw_ref_count[client_fd] = va_arg(ap, int));
77 * Return a username and password given a server and share name
79 * Returns 0 upon success;
80 * non-zero otherwise, and errno is set to indicate the error.
82 static void get_envvar_auth_data(const char *srv,
92 /* Fall back to environment variables */
94 w = getenv("WORKGROUP");
95 if (w == NULL) w = "";
98 if (u == NULL) u = "";
100 p = getenv("PASSWORD");
101 if (p == NULL) p = "";
103 strncpy(wg, w, wglen);
104 strncpy(un, u, unlen);
105 strncpy(pw, p, pwlen);
108 static smbc_get_auth_data_fn get_auth_data_fn = get_envvar_auth_data;
110 /*****************************************************
111 set the get auth data function
112 ******************************************************/
113 void smbw_set_auth_data_fn(smbc_get_auth_data_fn fn)
115 get_auth_data_fn = fn;
119 /*****************************************************
120 ensure that all connections are terminated upon exit
121 ******************************************************/
122 static void do_shutdown(void)
124 if (smbw_ctx != NULL) {
125 smbc_free_context(smbw_ctx, 1);
130 /*****************************************************
131 initialise structures
132 *******************************************************/
133 static void do_init(int is_real_startup)
138 smbw_initialized = 1; /* this must be first to avoid recursion! */
140 smbw_ctx = NULL; /* don't free context until it's established */
142 /* initially, no file descriptors are mapped */
143 for (i = 0; i < __FD_SETSIZE; i++) {
145 smbw_ref_count[i] = 0;
148 /* See if we've been told to start in a particular directory */
149 if ((p=getenv("SMBW_DIR")) != NULL) {
150 strncpy(smbw_cwd, p, PATH_MAX);
152 /* we don't want the old directory to be busy */
153 (* smbw_libc.chdir)("/");
159 if ((p=getenv("DEBUG"))) {
160 debug_level = atoi(p);
163 if ((smbw_ctx = smbc_new_context()) == NULL) {
167 smbw_ctx->debug = debug_level;
168 smbw_ctx->callbacks.auth_fn = get_auth_data_fn;
169 smbw_ctx->options.browse_max_lmb_count = 0;
170 smbw_ctx->options.urlencode_readdir_entries = 1;
171 smbw_ctx->options.one_share_per_server = 1;
172 // smbw_cache_functions(smbw_ctx);
174 if (smbc_init_context(smbw_ctx) == NULL) {
178 smbc_set_context(smbw_ctx);
180 /* if not real startup, exit handler has already been established */
181 if (is_real_startup) {
186 /*****************************************************
187 initialise structures, real start up vs a fork()
188 *******************************************************/
195 /*****************************************************
196 determine if a file descriptor is a smb one
197 *******************************************************/
198 int smbw_fd(int smbw_fd)
202 return (smbw_fd >= 0 &&
203 smbw_fd < __FD_SETSIZE &&
204 smbw_fd_map[smbw_fd] >= SMBC_BASE_FD); /* minimum smbc_ fd */
208 /*****************************************************
209 determine if a path is a smb one
210 *******************************************************/
211 int smbw_path(const char *name)
221 len = strlen(smbw_prefix);
223 ret = ((strncmp(name, smbw_prefix, len) == 0 &&
224 (name[len] == '\0' || name[len] == '/')) ||
225 (*name != '/' && *smbw_cwd != '\0'));
232 /*****************************************************
233 remove redundent stuff from a filename
234 *******************************************************/
235 void smbw_clean_fname(char *name)
243 DEBUG(10, ("Clean [%s]...\n", name));
248 if ((p=strstr(name,"/./"))) {
254 DEBUG(10, ("\tclean 1 (/./) produced [%s]\n", name));
257 if ((p=strstr(name,"//"))) {
263 DEBUG(10, ("\tclean 2 (//) produced [%s]\n", name));
266 if (strcmp(name,"/../")==0) {
269 DEBUG(10,("\tclean 3 (^/../$) produced [%s]\n", name));
272 if ((p=strstr(name,"/../"))) {
274 for (p2 = (p > name ? p-1 : p); p2 > name; p2--) {
275 if (p2[0] == '/') break;
283 DEBUG(10, ("\tclean 4 (/../) produced [%s]\n", name));
286 if (strcmp(name,"/..")==0) {
289 DEBUG(10, ("\tclean 5 (^/..$) produced [%s]\n", name));
293 p = l>=3?(name+l-3):name;
294 if (strcmp(p,"/..")==0) {
296 for (p2=p-1;p2>name;p2--) {
297 if (p2[0] == '/') break;
305 DEBUG(10, ("\tclean 6 (/..) produced [%s]\n", name));
309 p = l>=2?(name+l-2):name;
310 if (strcmp(p,"/.")==0) {
317 DEBUG(10, ("\tclean 7 (/.) produced [%s]\n", name));
320 if (strncmp(p=name,"./",2) == 0) {
325 DEBUG(10, ("\tclean 8 (^./) produced [%s]\n", name));
329 if (l > 1 && p[l-1] == '/') {
332 DEBUG(10, ("\tclean 9 (/) produced [%s]\n", name));
337 void smbw_fix_path(const char *src, char *dest)
340 int len = strlen(smbw_prefix);
343 for (p = src + len; *p == '/'; p++)
345 snprintf(dest, PATH_MAX, "smb://%s", p);
347 snprintf(dest, PATH_MAX, "%s/%s", smbw_cwd, src);
350 smbw_clean_fname(dest + 5);
352 DEBUG(10, ("smbw_fix_path(%s) returning [%s]\n", src, dest));
357 /*****************************************************
359 *******************************************************/
360 int smbw_open(const char *fname, int flags, mode_t mode)
373 smbw_fd = (smbw_libc.open)(SMBW_DUMMY, O_WRONLY, 0200);
379 smbw_fix_path(fname, path);
380 if (flags == creat_bits) {
381 client_fd = smbc_creat(path, mode);
383 client_fd = smbc_open(path, flags, mode);
387 (* smbw_libc.close)(smbw_fd);
391 smbw_fd_map[smbw_fd] = client_fd;
392 smbw_ref(client_fd, SMBW_RCT_Increment);
397 /*****************************************************
398 a wrapper for pread()
400 there should really be an smbc_pread() to avoid the two
401 lseek()s required in this kludge.
402 *******************************************************/
403 ssize_t smbw_pread(int smbw_fd, void *buf, size_t count, SMBW_OFF_T ofs)
410 client_fd = smbw_fd_map[smbw_fd];
412 if ((old_ofs = smbc_lseek(client_fd, 0, SEEK_CUR)) < 0 ||
413 smbc_lseek(client_fd, ofs, SEEK_SET) < 0) {
417 if ((ret = smbc_read(client_fd, buf, count)) < 0) {
419 (void) smbc_lseek(client_fd, old_ofs, SEEK_SET);
427 /*****************************************************
429 *******************************************************/
430 ssize_t smbw_read(int smbw_fd, void *buf, size_t count)
434 client_fd = smbw_fd_map[smbw_fd];
436 return smbc_read(client_fd, buf, count);
441 /*****************************************************
442 a wrapper for write()
443 *******************************************************/
444 ssize_t smbw_write(int smbw_fd, void *buf, size_t count)
448 client_fd = smbw_fd_map[smbw_fd];
450 return smbc_write(client_fd, buf, count);
453 /*****************************************************
454 a wrapper for pwrite()
455 *******************************************************/
456 ssize_t smbw_pwrite(int smbw_fd, void *buf, size_t count, SMBW_OFF_T ofs)
463 client_fd = smbw_fd_map[smbw_fd];
465 if ((old_ofs = smbc_lseek(client_fd, 0, SEEK_CUR)) < 0 ||
466 smbc_lseek(client_fd, ofs, SEEK_SET) < 0) {
470 if ((ret = smbc_write(client_fd, buf, count)) < 0) {
472 (void) smbc_lseek(client_fd, old_ofs, SEEK_SET);
480 /*****************************************************
481 a wrapper for close()
482 *******************************************************/
483 int smbw_close(int smbw_fd)
487 client_fd = smbw_fd_map[smbw_fd];
489 if (smbw_ref(client_fd, SMBW_RCT_Decrement) > 0) {
493 (* smbw_libc.close)(smbw_fd);
494 smbw_fd_map[smbw_fd] = -1;
495 return smbc_close(client_fd);
499 /*****************************************************
500 a wrapper for fcntl()
501 *******************************************************/
502 int smbw_fcntl(int smbw_fd, int cmd, long arg)
508 /*****************************************************
509 a wrapper for access()
510 *******************************************************/
511 int smbw_access(const char *name, int mode)
517 if (smbw_stat(name, &st)) return -1;
519 if (((mode & R_OK) && !(st.s_mode & S_IRUSR)) ||
520 ((mode & W_OK) && !(st.s_mode & S_IWUSR)) ||
521 ((mode & X_OK) && !(st.s_mode & S_IXUSR))) {
529 /*****************************************************
530 a wrapper for readlink() - needed for correct errno setting
531 *******************************************************/
532 int smbw_readlink(const char *fname, char *buf, size_t bufsize)
539 ret = smbw_stat(fname, &st);
544 /* it exists - say it isn't a link */
550 /*****************************************************
551 a wrapper for unlink()
552 *******************************************************/
553 int smbw_unlink(const char *fname)
559 smbw_fix_path(fname, path);
560 return smbc_unlink(path);
564 /*****************************************************
565 a wrapper for rename()
566 *******************************************************/
567 int smbw_rename(const char *oldname, const char *newname)
569 char path_old[PATH_MAX];
570 char path_new[PATH_MAX];
574 smbw_fix_path(oldname, path_old);
575 smbw_fix_path(newname, path_new);
576 return smbc_rename(path_old, path_new);
580 /*****************************************************
582 *******************************************************/
583 int smbw_utimes(const char *fname, void *buf)
587 smbw_fix_path(fname, path);
588 return smbc_utimes(path, buf);
592 /*****************************************************
594 *******************************************************/
595 int smbw_utime(const char *fname, void *buf)
599 smbw_fix_path(fname, path);
600 return smbc_utime(path, buf);
603 /*****************************************************
604 a wrapper for chown()
605 *******************************************************/
606 int smbw_chown(const char *fname, uid_t owner, gid_t group)
608 /* always indiciate that this is not supported. */
613 /*****************************************************
614 a wrapper for chmod()
615 *******************************************************/
616 int smbw_chmod(const char *fname, mode_t newmode)
620 smbw_fix_path(fname, path);
621 return smbc_chmod(path, newmode);
625 /*****************************************************
626 a wrapper for lseek()
627 *******************************************************/
628 SMBW_OFF_T smbw_lseek(int smbw_fd,
635 client_fd = smbw_fd_map[smbw_fd];
637 ret = smbc_lseek(client_fd, offset, whence);
640 printf("smbw_lseek(%d/%d, 0x%llx) returned 0x%llx\n",
642 (unsigned long long) offset,
643 (unsigned long long) ret);
648 /*****************************************************
650 *******************************************************/
651 int smbw_dup(int smbw_fd)
655 fd2 = (smbw_libc.dup)(smbw_fd);
660 smbw_fd_map[fd2] = smbw_fd_map[smbw_fd];
661 smbw_ref(smbw_fd_map[smbw_fd], SMBW_RCT_Increment);
666 /*****************************************************
668 *******************************************************/
669 int smbw_dup2(int smbw_fd, int fd2)
671 if ((* smbw_libc.dup2)(smbw_fd, fd2) != fd2) {
675 smbw_fd_map[fd2] = smbw_fd_map[smbw_fd];
676 smbw_ref(smbw_fd_map[smbw_fd], SMBW_RCT_Increment);
681 /*****************************************************
682 when we fork we have to close all connections and files
684 *******************************************************/
694 if (pipe(p)) return (* smbw_libc.fork)();
696 child_pid = (* smbw_libc.fork)();
699 /* block the parent for a moment until the sockets are
701 (* smbw_libc.close)(p[1]);
702 (* smbw_libc.read)(p[0], &c, 1);
703 (* smbw_libc.close)(p[0]);
707 (* smbw_libc.close)(p[0]);
709 /* close all server connections and locally-opened files */
710 for (i = 0; i < __FD_SETSIZE; i++) {
711 if (smbw_fd_map[i] > 0 &&
712 smbw_ref(smbw_fd_map[i], SMBW_RCT_Get) > 0) {
714 smbc_close(smbw_fd_map[i]);
715 smbw_ref(smbw_fd_map[i], SMBW_RCT_Set, 0);
716 (* smbw_libc.close)(i);
722 /* unblock the parent */
724 (* smbw_libc.close)(p[1]);
726 /* specify directory to start in, if it's simulated smb */
727 if (*smbw_cwd != '\0') {
728 setenv("SMBW_DIR", smbw_cwd, 1);
730 unsetenv("SMBW_DIR");
733 /* Re-initialize this library for the child */
736 /* and continue in the child */
740 int smbw_setxattr(const char *fname,
748 if (strcmp(name, "system.posix_acl_access") == 0)
753 smbw_fix_path(fname, path);
754 return smbc_setxattr(path, name, value, size, flags);
757 int smbw_lsetxattr(const char *fname,
765 if (strcmp(name, "system.posix_acl_access") == 0)
770 smbw_fix_path(fname, path);
771 return smbc_lsetxattr(path, name, value, size, flags);
774 int smbw_fsetxattr(int smbw_fd,
782 if (strcmp(name, "system.posix_acl_access") == 0)
787 client_fd = smbw_fd_map[smbw_fd];
788 return smbc_fsetxattr(client_fd, name, value, size, flags);
791 int smbw_getxattr(const char *fname,
798 if (strcmp(name, "system.posix_acl_access") == 0)
803 smbw_fix_path(fname, path);
805 return smbc_getxattr(path, name, value, size);
808 int smbw_lgetxattr(const char *fname,
815 if (strcmp(name, "system.posix_acl_access") == 0)
820 smbw_fix_path(fname, path);
821 return smbc_lgetxattr(path, name, value, size);
824 int smbw_fgetxattr(int smbw_fd,
831 if (strcmp(name, "system.posix_acl_access") == 0)
836 client_fd = smbw_fd_map[smbw_fd];
837 return smbc_fgetxattr(client_fd, name, value, size);
840 int smbw_removexattr(const char *fname,
845 if (strcmp(name, "system.posix_acl_access") == 0)
850 smbw_fix_path(fname, path);
851 return smbc_removexattr(path, name);
854 int smbw_lremovexattr(const char *fname,
859 if (strcmp(name, "system.posix_acl_access") == 0)
864 smbw_fix_path(fname, path);
865 return smbc_lremovexattr(path, name);
868 int smbw_fremovexattr(int smbw_fd,
873 if (strcmp(name, "system.posix_acl_access") == 0)
878 client_fd = smbw_fd_map[smbw_fd];
879 return smbc_fremovexattr(client_fd, name);
882 int smbw_listxattr(const char *fname,
888 smbw_fix_path(fname, path);
889 return smbc_listxattr(path, list, size);
892 int smbw_llistxattr(const char *fname,
898 smbw_fix_path(fname, path);
899 return smbc_llistxattr(path, list, size);
902 int smbw_flistxattr(int smbw_fd,
908 client_fd = smbw_fd_map[smbw_fd];
909 return smbc_flistxattr(client_fd, list, size);