diff options
Diffstat (limited to 'source4/smbwrapper')
-rw-r--r-- | source4/smbwrapper/.cvsignore | 8 | ||||
-rw-r--r-- | source4/smbwrapper/PORTING | 77 | ||||
-rw-r--r-- | source4/smbwrapper/README | 94 | ||||
-rw-r--r-- | source4/smbwrapper/realcalls.c | 48 | ||||
-rw-r--r-- | source4/smbwrapper/realcalls.h | 263 | ||||
-rw-r--r-- | source4/smbwrapper/shared.c | 203 | ||||
-rw-r--r-- | source4/smbwrapper/smbsh.c | 127 | ||||
-rw-r--r-- | source4/smbwrapper/smbsh.in | 54 | ||||
-rw-r--r-- | source4/smbwrapper/smbw.c | 1554 | ||||
-rw-r--r-- | source4/smbwrapper/smbw.h | 71 | ||||
-rw-r--r-- | source4/smbwrapper/smbw_cache.c | 207 | ||||
-rw-r--r-- | source4/smbwrapper/smbw_dir.c | 688 | ||||
-rw-r--r-- | source4/smbwrapper/smbw_stat.c | 250 | ||||
-rw-r--r-- | source4/smbwrapper/wrapped.c | 705 |
14 files changed, 4349 insertions, 0 deletions
diff --git a/source4/smbwrapper/.cvsignore b/source4/smbwrapper/.cvsignore new file mode 100644 index 0000000000..7835612d32 --- /dev/null +++ b/source4/smbwrapper/.cvsignore @@ -0,0 +1,8 @@ +*.po +*.po32 +kernel_stat.h +smbsh +tst +tst.c +wrapper.h +xstat.c diff --git a/source4/smbwrapper/PORTING b/source4/smbwrapper/PORTING new file mode 100644 index 0000000000..884246d078 --- /dev/null +++ b/source4/smbwrapper/PORTING @@ -0,0 +1,77 @@ +This describes how to port the smbwrapper portion of Samba to a new +unix-like platform. Note that porting smbwrapper is considerably +harder than porting Samba, for Samba you generally just need to run +configure and recompile whereas for smbwrapper some extra effort is +generally required. + + +STEP 1 +------ + +The first step is to work out how to create a shared library on your +OS and how to compile C code to produce position independent object +files (PIC files). You shoud be able to find this information in the +man pages for your compiler and loader (ld). Then modify configure.in +to give that information to Samba. + + +STEP 2 +------ + +The next step is to work out how to preload shared objects. On many +systems this is done using a LD_PRELOAD environment variable. On +others (shc as IRIX) it may use a _RTL_LIST variable. + +To make sure it works I suggest you create two C files like this: + +/* first C file */ +main() +{ + unlink("foo.txt"); +} + +/* second C file */ +#include <stdio.h> + +int unlink(char *fname) +{ + fprintf(stderr,"unlink(%s) called\n",fname); +} + + +then compile the first as an ordinary C program and the second as a +shared library. Then use LD_PRELOAD to preload the resulting shared +library. Then run the first program. It should print "unlink(foo.txt) +called". If it doesn't then consult your man pages till you get it +right. + +Once you work this out then edit smbwrapper/smbsh.in and add a section +if necessary to correctly set the necessary preload options for your +OS. + + +STEP 3 +------ + +The next step is to work out how to make direct system calls. On most +machines this will work without any source code changes to +smbwrapper. To test that it does work create the following C program: + +#include <sys/syscall.h> +main() +{ + syscall(SYS_write, 1, "hello world\n", 12); +} + +and try to compile/run it. If it produces "hello world" then syscall() +works as expected. If not then work out what needs to be changed and +then make that change in realcalls.h. For example, on IRIX 6.4 the +system call numbers are wrong and need to be fixed up by getting an +offset right. + + +STEP 4 +------ + +Try compiling smbwrapper! Then test it. Then debug it. Simple really :) + diff --git a/source4/smbwrapper/README b/source4/smbwrapper/README new file mode 100644 index 0000000000..8d5c376f82 --- /dev/null +++ b/source4/smbwrapper/README @@ -0,0 +1,94 @@ +This is a prelodable shared library that provides SMB client services +for existing executables. Using this you can simulate a smb +filesystem. + +*** This is code under development. Some things don't work yet *** + +Currently this code has been tested on: + +- Linux 2.0 with glibc2 (RH5.1) +- Linux 2.1 with glibc2 +- Solaris 2.5.1 with gcc +- Solaris 2.6 with gcc +- SunOS 4.1.3 with gcc +- IRIX 6.4 with cc +- OSF1 with gcc + + +It probably won't run on other systems without some porting. If you +have a different system then see the file PORTING. + +To use it you need to do this: + +1) build smbwrapper.so using the command "make smbwrapper" +3) run smbsh + +You will be asked for a username and password. After that you will be +returned to a shell prompt. It is actually a subshell running with +smbwrapper enabled. + +Now try to access /smb/SERVER for some SMB server name and see what +happens. If you use the -W option to set your workgroup or have +workgroup set in your smb.conf then listing /smb/ should list all SMB +servers in your workgroup. + + +OPTIONS +------- + +-U username + specify the username and optional password (as user%password) + +-d debug level + This is an integer that controls the internal debug level of smbw. It + defaults to 0, which means no debug info. + +-l logfile + The place where smbw debug logs are put. If this is not set then + stderr is used. + +-P prefix + The root of the SMB filesystem. This defaults to /smb/ but you can + set it to any name you like. + +-W workgroup + This is the workgroup used for browsing (ie. listing machines in the + /smb/ directory). It defaults to the one set in smb.conf. + +-R resolve order + This allows you to override the setting of the name resolve order + from smb.conf + + +ATTRIBUTE MAPPING +----------------- + +smbwrapper does an inverse attribute maping to what Samba does. This +means that the archive bit appears as the user execute bit, the system +bit appears as the group execute bit and the hidden bit appears as the +other execute bit. You can control these with chmod. The mapping can +be enabled an disabled using the normal smb.conf controls (ie. "map +archive", "map system" and "map hidden"). + +Read-only files appear as non-writeable by everyone. Writeable files +appear as writeable by the current user. + + +WHAT WORKS +---------- + +Things that I have tried and do seem to work include: + + emacs, tar, ls, cmp, cp, rsync, du, cat, rm, mv, less, more, wc, head, + tail, bash, tcsh, mkdir, rmdir, vim, xedit, diff + +things that I know don't work: + + anything executing from the share + anything that uses mmap + redirection within shells to smbsh files + +If you want to help with the development of this code then join the +samba-technical mailing list. + + diff --git a/source4/smbwrapper/realcalls.c b/source4/smbwrapper/realcalls.c new file mode 100644 index 0000000000..b64f4a43db --- /dev/null +++ b/source4/smbwrapper/realcalls.c @@ -0,0 +1,48 @@ +/* + Unix SMB/CIFS implementation. + SMB wrapper functions for calls that syscall() can't do + Copyright (C) Andrew Tridgell 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "realcalls.h" + +#ifdef REPLACE_UTIME +int real_utime(const char *name, struct utimbuf *buf) +{ + struct timeval tv[2]; + + tv[0].tv_sec = buf->actime; + tv[0].tv_usec = 0; + tv[1].tv_sec = buf->modtime; + tv[1].tv_usec = 0; + + return real_utimes(name, &tv[0]); +} +#endif + +#ifdef REPLACE_UTIMES +int real_utimes(const char *name, struct timeval tv[2]) +{ + struct utimbuf buf; + + buf.actime = tv[0].tv_sec; + buf.modtime = tv[1].tv_sec; + + return real_utime(name, &buf); +} +#endif diff --git a/source4/smbwrapper/realcalls.h b/source4/smbwrapper/realcalls.h new file mode 100644 index 0000000000..6c230dba05 --- /dev/null +++ b/source4/smbwrapper/realcalls.h @@ -0,0 +1,263 @@ +/* + Unix SMB/CIFS implementation. + defintions of syscall entries + Copyright (C) Andrew Tridgell 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#if HAVE_SYS_SYSCALL_H +#include <sys/syscall.h> +#elif HAVE_SYSCALL_H +#include <syscall.h> +#endif + +#ifdef IRIX +/* amazingly, IRIX gets its own syscall numbers wrong! */ +#ifdef SYSVoffset +#if (SYSVoffset == 1) +#undef SYSVoffset +#define SYSVoffset 1000 +#endif +#endif +#endif + +/* this file is partly derived from zlibc by Alain Knaff */ + +#define real_access(fn, mode) (syscall(SYS_access, (fn), (mode))) +#define real_chdir(fn) (syscall(SYS_chdir, (fn))) +#define real_chmod(fn, mode) (syscall(SYS_chmod,(fn), (mode))) +#define real_chown(fn, owner, group) (syscall(SYS_chown,(fn),(owner),(group))) + +#ifdef SYS_getdents +#define real_getdents(fd, dirp, count) (syscall(SYS_getdents, (fd), (dirp), (count))) +#endif + +#define real_link(fn1, fn2) (syscall(SYS_link, (fn1), (fn2))) + +#define real_open(fn,flags,mode) (syscall(SYS_open, (fn), (flags), (mode))) + +#ifdef SYS_open64 +#define real_open64(fn,flags,mode) (syscall(SYS_open64, (fn), (flags), (mode))) +#elif HAVE__OPEN64 +#define real_open64(fn,flags,mode) (_open64(fn,flags,mode)) +#define NO_OPEN64_ALIAS +#elif HAVE___OPEN64 +#define real_open64(fn,flags,mode) (__open64(fn,flags,mode)) +#define NO_OPEN64_ALIAS +#endif + +#ifdef HAVE__FORK +#define real_fork() (_fork()) +#elif HAVE___FORK +#define real_fork() (__fork()) +#elif SYS_fork +#define real_fork() (syscall(SYS_fork)) +#endif + +#ifdef HAVE__OPENDIR +#define real_opendir(fn) (_opendir(fn)) +#elif SYS_opendir +#define real_opendir(fn) (syscall(SYS_opendir,(fn))) +#elif HAVE___OPENDIR +#define real_opendir(fn) (__opendir(fn)) +#endif + +#ifdef HAVE__READDIR +#define real_readdir(d) (_readdir(d)) +#elif HAVE___READDIR +#define real_readdir(d) (__readdir(d)) +#elif SYS_readdir +#define real_readdir(d) (syscall(SYS_readdir,(d))) +#endif + +#ifdef HAVE__CLOSEDIR +#define real_closedir(d) (_closedir(d)) +#elif SYS_closedir +#define real_closedir(d) (syscall(SYS_closedir,(d))) +#elif HAVE___CLOSEDIR +#define real_closedir(d) (__closedir(d)) +#endif + +#ifdef HAVE__SEEKDIR +#define real_seekdir(d,l) (_seekdir(d,l)) +#elif SYS_seekdir +#define real_seekdir(d,l) (syscall(SYS_seekdir,(d),(l))) +#elif HAVE___SEEKDIR +#define real_seekdir(d,l) (__seekdir(d,l)) +#else +#define NO_SEEKDIR_WRAPPER +#endif + +#ifdef HAVE__TELLDIR +#define real_telldir(d) (_telldir(d)) +#elif SYS_telldir +#define real_telldir(d) (syscall(SYS_telldir,(d))) +#elif HAVE___TELLDIR +#define real_telldir(d) (__telldir(d)) +#endif + +#ifdef HAVE__DUP +#define real_dup(d) (_dup(d)) +#elif SYS_dup +#define real_dup(d) (syscall(SYS_dup,(d))) +#elif HAVE___DUP +#define real_dup(d) (__dup(d)) +#endif + +#ifdef HAVE__DUP2 +#define real_dup2(d1,d2) (_dup2(d1,d2)) +#elif SYS_dup2 +#define real_dup2(d1,d2) (syscall(SYS_dup2,(d1),(d2))) +#elif HAVE___DUP2 +#define real_dup2(d1,d2) (__dup2(d1,d2)) +#endif + +#ifdef HAVE__GETCWD +#define real_getcwd(b,s) ((char *)_getcwd(b,s)) +#elif SYS_getcwd +#define real_getcwd(b,s) ((char *)syscall(SYS_getcwd,(b),(s))) +#elif HAVE___GETCWD +#define real_getcwd(b,s) ((char *)__getcwd(b,s)) +#endif + +#ifdef HAVE__STAT +#define real_stat(fn,st) (_stat(fn,st)) +#elif SYS_stat +#define real_stat(fn,st) (syscall(SYS_stat,(fn),(st))) +#elif HAVE___STAT +#define real_stat(fn,st) (__stat(fn,st)) +#endif + +#ifdef HAVE__LSTAT +#define real_lstat(fn,st) (_lstat(fn,st)) +#elif SYS_lstat +#define real_lstat(fn,st) (syscall(SYS_lstat,(fn),(st))) +#elif HAVE___LSTAT +#define real_lstat(fn,st) (__lstat(fn,st)) +#endif + +#ifdef HAVE__FSTAT +#define real_fstat(fd,st) (_fstat(fd,st)) +#elif SYS_fstat +#define real_fstat(fd,st) (syscall(SYS_fstat,(fd),(st))) +#elif HAVE___FSTAT +#define real_fstat(fd,st) (__fstat(fd,st)) +#endif + +#if defined(HAVE_SYS_ACL_H) && defined(HAVE__ACL) +#define real_acl(fn,cmd,n,buf) (_acl(fn,cmd,n,buf)) +#elif SYS_acl +#define real_acl(fn,cmd,n,buf) (syscall(SYS_acl,(fn),(cmd),(n),(buf))) +#elif HAVE___ACL +#define real_acl(fn,cmd,n,buf) (__acl(fn,cmd,n,buf)) +#else +#define NO_ACL_WRAPPER +#endif + +#ifdef HAVE__FACL +#define real_facl(fd,cmd,n,buf) (_facl(fd,cmd,n,buf)) +#elif SYS_facl +#define real_facl(fd,cmd,n,buf) (syscall(SYS_facl,(fd),(cmd),(n),(buf))) +#elif HAVE___FACL +#define real_facl(fd,cmd,n,buf) (__facl(fd,cmd,n,buf)) +#else +#define NO_FACL_WRAPPER +#endif + + +#ifdef HAVE__STAT64 +#define real_stat64(fn,st) (_stat64(fn,st)) +#elif HAVE___STAT64 +#define real_stat64(fn,st) (__stat64(fn,st)) +#endif + +#ifdef HAVE__LSTAT64 +#define real_lstat64(fn,st) (_lstat64(fn,st)) +#elif HAVE___LSTAT64 +#define real_lstat64(fn,st) (__lstat64(fn,st)) +#endif + +#ifdef HAVE__FSTAT64 +#define real_fstat64(fd,st) (_fstat64(fd,st)) +#elif HAVE___FSTAT64 +#define real_fstat64(fd,st) (__fstat64(fd,st)) +#endif + +#ifdef HAVE__READDIR64 +#define real_readdir64(d) (_readdir64(d)) +#elif HAVE___READDIR64 +#define real_readdir64(d) (__readdir64(d)) +#endif + +#ifdef HAVE__LLSEEK +#define real_llseek(fd,ofs,whence) (_llseek(fd,ofs,whence)) +#elif HAVE___LLSEEK +#define real_llseek(fd,ofs,whence) (__llseek(fd,ofs,whence)) +#elif HAVE___SYS_LLSEEK +#define real_llseek(fd,ofs,whence) (__sys_llseek(fd,ofs,whence)) +#endif + + +#ifdef HAVE__PREAD +#define real_pread(fd,buf,size,ofs) (_pread(fd,buf,size,ofs)) +#elif HAVE___PREAD +#define real_pread(fd,buf,size,ofs) (__pread(fd,buf,size,ofs)) +#endif + +#ifdef HAVE__PREAD64 +#define real_pread64(fd,buf,size,ofs) (_pread64(fd,buf,size,ofs)) +#elif HAVE___PREAD64 +#define real_pread64(fd,buf,size,ofs) (__pread64(fd,buf,size,ofs)) +#endif + +#ifdef HAVE__PWRITE +#define real_pwrite(fd,buf,size,ofs) (_pwrite(fd,buf,size,ofs)) +#elif HAVE___PWRITE +#define real_pwrite(fd,buf,size,ofs) (__pwrite(fd,buf,size,ofs)) +#endif + +#ifdef HAVE__PWRITE64 +#define real_pwrite64(fd,buf,size,ofs) (_pwrite64(fd,buf,size,ofs)) +#elif HAVE___PWRITE64 +#define real_pwrite64(fd,buf,size,ofs) (__pwrite64(fd,buf,size,ofs)) +#endif + + +#define real_readlink(fn,buf,len) (syscall(SYS_readlink, (fn), (buf), (len))) +#define real_rename(fn1, fn2) (syscall(SYS_rename, (fn1), (fn2))) +#define real_symlink(fn1, fn2) (syscall(SYS_symlink, (fn1), (fn2))) +#define real_read(fd, buf, count ) (syscall(SYS_read, (fd), (buf), (count))) +#define real_lseek(fd, offset, whence) (syscall(SYS_lseek, (fd), (offset), (whence))) +#define real_write(fd, buf, count ) (syscall(SYS_write, (fd), (buf), (count))) +#define real_close(fd) (syscall(SYS_close, (fd))) +#define real_fchdir(fd) (syscall(SYS_fchdir, (fd))) +#define real_fcntl(fd,cmd,arg) (syscall(SYS_fcntl, (fd), (cmd), (arg))) +#define real_symlink(fn1, fn2) (syscall(SYS_symlink, (fn1), (fn2))) +#define real_unlink(fn) (syscall(SYS_unlink, (fn))) +#define real_rmdir(fn) (syscall(SYS_rmdir, (fn))) +#define real_mkdir(fn, mode) (syscall(SYS_mkdir, (fn), (mode))) + +#ifdef SYS_utime +#define real_utime(fn, buf) (syscall(SYS_utime, (fn), (buf))) +#else +#define REPLACE_UTIME 1 +#endif + +#ifdef SYS_utimes +#define real_utimes(fn, buf) (syscall(SYS_utimes, (fn), (buf))) +#else +#define REPLACE_UTIMES 1 +#endif diff --git a/source4/smbwrapper/shared.c b/source4/smbwrapper/shared.c new file mode 100644 index 0000000000..b4cfcf7148 --- /dev/null +++ b/source4/smbwrapper/shared.c @@ -0,0 +1,203 @@ +/* + Unix SMB/CIFS implementation. + SMB wrapper functions - shared variables + Copyright (C) Andrew Tridgell 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +static int shared_fd; +static char *variables; +static int shared_size; + +/***************************************************** +setup the shared area +*******************************************************/ +void smbw_setup_shared(void) +{ + int fd; + pstring name, s; + + slprintf(name,sizeof(name)-1, "%s/smbw.XXXXXX",tmpdir()); + + fd = smb_mkstemp(name); + + if (fd == -1) goto failed; + + unlink(name); + + shared_fd = set_maxfiles(SMBW_MAX_OPEN); + + while (shared_fd && dup2(fd, shared_fd) != shared_fd) shared_fd--; + + if (shared_fd == 0) goto failed; + + close(fd); + + DEBUG(4,("created shared_fd=%d\n", shared_fd)); + + slprintf(s,sizeof(s)-1,"%d", shared_fd); + + setenv("SMBW_HANDLE", s, 1); + + return; + + failed: + perror("Failed to setup shared variable area "); + exit(1); +} + +static int locked; + +/***************************************************** +lock the shared variable area +*******************************************************/ +static void lockit(void) +{ + if (shared_fd == 0) { + char *p = getenv("SMBW_HANDLE"); + if (!p) { + DEBUG(0,("ERROR: can't get smbw shared handle\n")); + exit(1); + } + shared_fd = atoi(p); + } + if (locked==0 && + fcntl_lock(shared_fd,SMB_F_SETLKW,0,1,F_WRLCK)==False) { + DEBUG(0,("ERROR: can't get smbw shared lock (%s)\n", strerror(errno))); + exit(1); + } + locked++; +} + +/***************************************************** +unlock the shared variable area +*******************************************************/ +static void unlockit(void) +{ + locked--; + if (locked == 0) { + fcntl_lock(shared_fd,SMB_F_SETLK,0,1,F_UNLCK); + } +} + + +/***************************************************** +get a variable from the shared area +*******************************************************/ +char *smbw_getshared(const char *name) +{ + int i; + struct stat st; + char *var; + + lockit(); + + /* maybe the area has changed */ + if (fstat(shared_fd, &st)) goto failed; + + if (st.st_size != shared_size) { + var = (char *)Realloc(variables, st.st_size); + if (!var) goto failed; + else variables = var; + shared_size = st.st_size; + lseek(shared_fd, 0, SEEK_SET); + if (read(shared_fd, variables, shared_size) != shared_size) { + goto failed; + } + } + + unlockit(); + + i=0; + while (i < shared_size) { + char *n, *v; + int l1, l2; + + l1 = SVAL(&variables[i], 0); + l2 = SVAL(&variables[i], 2); + + n = &variables[i+4]; + v = &variables[i+4+l1]; + i += 4+l1+l2; + + if (strcmp(name,n)) { + continue; + } + return v; + } + + return NULL; + + failed: + DEBUG(0,("smbw: shared variables corrupt (%s)\n", strerror(errno))); + exit(1); + return NULL; +} + + + +/***************************************************** +set a variable in the shared area +*******************************************************/ +void smbw_setshared(const char *name, const char *val) +{ + int l1, l2; + char *var; + + /* we don't allow variable overwrite */ + if (smbw_getshared(name)) return; + + lockit(); + + l1 = strlen(name)+1; + l2 = strlen(val)+1; + + var = (char *)Realloc(variables, shared_size + l1+l2+4); + + if (!var) { + DEBUG(0,("out of memory in smbw_setshared\n")); + exit(1); + } + + variables = var; + + SSVAL(&variables[shared_size], 0, l1); + SSVAL(&variables[shared_size], 2, l2); + + pstrcpy(&variables[shared_size] + 4, name); + pstrcpy(&variables[shared_size] + 4 + l1, val); + + shared_size += l1+l2+4; + + lseek(shared_fd, 0, SEEK_SET); + if (write(shared_fd, variables, shared_size) != shared_size) { + DEBUG(0,("smbw_setshared failed (%s)\n", strerror(errno))); + exit(1); + } + + unlockit(); +} + + +/***************************************************************** +return true if the passed fd is the SMBW_HANDLE +*****************************************************************/ +int smbw_shared_fd(int fd) +{ + return (shared_fd && shared_fd == fd); +} diff --git a/source4/smbwrapper/smbsh.c b/source4/smbwrapper/smbsh.c new file mode 100644 index 0000000000..221c6d87c2 --- /dev/null +++ b/source4/smbwrapper/smbsh.c @@ -0,0 +1,127 @@ +/* + Unix SMB/CIFS implementation. + SMB wrapper functions - frontend + Copyright (C) Andrew Tridgell 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +static void smbsh_usage(void) +{ + printf("smbsh [options]\n\n"); + printf(" -W workgroup\n"); + printf(" -U username\n"); + printf(" -P prefix\n"); + printf(" -R resolve order\n"); + printf(" -d debug level\n"); + printf(" -l logfile\n"); + printf(" -L libdir\n"); + exit(0); +} + +int main(int argc, char *argv[]) +{ + char *p, *u; + const char *libd = dyn_BINDIR; + pstring line, wd; + int opt; + extern char *optarg; + extern int optind; + + dbf = x_stdout; + smbw_setup_shared(); + + while ((opt = getopt(argc, argv, "W:U:R:d:P:l:hL:")) != EOF) { + switch (opt) { + case 'L': + libd = optarg; + break; + case 'W': + smbw_setshared("WORKGROUP", optarg); + break; + case 'l': + smbw_setshared("LOGFILE", optarg); + break; + case 'P': + smbw_setshared("PREFIX", optarg); + break; + case 'd': + smbw_setshared("DEBUG", optarg); + break; + case 'U': + p = strchr_m(optarg,'%'); + if (p) { + *p=0; + smbw_setshared("PASSWORD",p+1); + } + smbw_setshared("USER", optarg); + break; + case 'R': + smbw_setshared("RESOLVE_ORDER",optarg); + break; + + case 'h': + default: + smbsh_usage(); + } + } + + + if (!smbw_getshared("USER")) { + printf("Username: "); + u = fgets_slash(line, sizeof(line)-1, x_stdin); + smbw_setshared("USER", u); + } + + if (!smbw_getshared("PASSWORD")) { + p = getpass("Password: "); + smbw_setshared("PASSWORD", p); + } + + setenv("PS1", "smbsh$ ", 1); + + sys_getwd(wd); + + slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid()); + + smbw_setshared(line, wd); + + slprintf(line,sizeof(line)-1,"%s/smbwrapper.so", libd); + setenv("LD_PRELOAD", line, 1); + + slprintf(line,sizeof(line)-1,"%s/smbwrapper.32.so", libd); + + if (file_exist(line, NULL)) { + slprintf(line,sizeof(line)-1,"%s/smbwrapper.32.so:DEFAULT", libd); + setenv("_RLD_LIST", line, 1); + slprintf(line,sizeof(line)-1,"%s/smbwrapper.so:DEFAULT", libd); + setenv("_RLDN32_LIST", line, 1); + } else { + slprintf(line,sizeof(line)-1,"%s/smbwrapper.so:DEFAULT", libd); + setenv("_RLD_LIST", line, 1); + } + + { + char *shellpath = getenv("SHELL"); + if(shellpath) + execl(shellpath,"smbsh",NULL); + else + execl("/bin/sh","smbsh",NULL); + } + printf("launch failed!\n"); + return 1; +} diff --git a/source4/smbwrapper/smbsh.in b/source4/smbwrapper/smbsh.in new file mode 100644 index 0000000000..323f091699 --- /dev/null +++ b/source4/smbwrapper/smbsh.in @@ -0,0 +1,54 @@ +#! /bin/sh + +SMBW_LIBDIR=${SMBW_LIBDIR-@builddir@/smbwrapper} + +if [ ! -f ${SMBW_LIBDIR}/smbwrapper.so ]; then + echo You need to set LIBDIR in smbsh + exit +fi + +# a simple launcher for the smbwrapper.so preloadde library + +if [ x"${SMBW_USER+set}" != x"set" ]; then + echo username? + read user + SMBW_USER=$user + export SMBW_USER +fi + +# this doesn't hide the password - we need a proper launch app for that +if [ x"${SMBW_PASSWORD+set}" != x"set" ]; then + echo password? + read pass + SMBW_PASSWORD=$pass + export SMBW_PASSWORD +fi + +PWD=`pwd` +export PWD +PS1='smbsh$ ' +export PS1 + + +host_os=@HOST_OS@ + +case "$host_os" in + *irix*) + _RLDN32_LIST=$SMBW_LIBDIR/smbwrapper.so:DEFAULT + _RLD_LIST=$SMBW_LIBDIR/smbwrapper.32.so:DEFAULT + export _RLDN32_LIST + export _RLD_LIST + ;; + *osf*) + _RLD_LIST=$SMBW_LIBDIR/smbwrapper.so:DEFAULT + export _RLD_LIST + ;; + *) + LD_PRELOAD=$SMBW_LIBDIR/smbwrapper.so + export LD_PRELOAD + ;; +esac + +echo starting smbwrapper on $host_os + +exec ${SMBW_SHELL-${SHELL-/bin/sh}} ${1+"$@"} diff --git a/source4/smbwrapper/smbw.c b/source4/smbwrapper/smbw.c new file mode 100644 index 0000000000..fbc69b2371 --- /dev/null +++ b/source4/smbwrapper/smbw.c @@ -0,0 +1,1554 @@ +/* + Unix SMB/CIFS implementation. + SMB wrapper functions + Copyright (C) Andrew Tridgell 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "realcalls.h" + +pstring smbw_cwd; + +static struct smbw_file *smbw_files; +static struct smbw_server *smbw_srvs; + +struct bitmap *smbw_file_bmap; + +fstring smbw_prefix = SMBW_PREFIX; + +int smbw_busy=0; + +/* needs to be here because of dumb include files on some systems */ +int creat_bits = O_WRONLY|O_CREAT|O_TRUNC; + + +/***************************************************** +initialise structures +*******************************************************/ +void smbw_init(void) +{ + extern BOOL in_client; + static int initialised; + char *p; + int eno; + pstring line; + + if (initialised) return; + initialised = 1; + + eno = errno; + + smbw_busy++; + + DEBUGLEVEL = 0; + setup_logging("smbsh",True); + + dbf = x_stderr; + + if ((p=smbw_getshared("LOGFILE"))) { + dbf = sys_fopen(p, "a"); + } + + smbw_file_bmap = bitmap_allocate(SMBW_MAX_OPEN); + if (!smbw_file_bmap) { + exit(1); + } + + in_client = True; + + load_interfaces(); + + if ((p=smbw_getshared("SERVICESF"))) { + pstrcpy(dyn_CONFIGFILE, p); + } + + lp_load(dyn_CONFIGFILE,True,False,False); + + if (!init_names()) + exit(1); + + if ((p=smbw_getshared("DEBUG"))) { + DEBUGLEVEL = atoi(p); + } + + if ((p=smbw_getshared("RESOLVE_ORDER"))) { + lp_set_name_resolve_order(p); + } + + if ((p=smbw_getshared("PREFIX"))) { + slprintf(smbw_prefix,sizeof(fstring)-1, "/%s/", p); + all_string_sub(smbw_prefix,"//", "/", 0); + DEBUG(2,("SMBW_PREFIX is %s\n", smbw_prefix)); + } + + slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid()); + + p = smbw_getshared(line); + if (!p) { + sys_getwd(smbw_cwd); + } + pstrcpy(smbw_cwd, p); + DEBUG(4,("Initial cwd is %s\n", smbw_cwd)); + + smbw_busy--; + + set_maxfiles(SMBW_MAX_OPEN); + + BlockSignals(True,SIGPIPE); + + errno = eno; +} + +/***************************************************** +determine if a file descriptor is a smb one +*******************************************************/ +int smbw_fd(int fd) +{ + if (smbw_busy) return 0; + return smbw_file_bmap && bitmap_query(smbw_file_bmap, fd); +} + +/***************************************************** +determine if a file descriptor is an internal smbw fd +*******************************************************/ +int smbw_local_fd(int fd) +{ + struct smbw_server *srv; + + smbw_init(); + + if (smbw_busy) return 0; + if (smbw_shared_fd(fd)) return 1; + + for (srv=smbw_srvs;srv;srv=srv->next) { + if (srv->cli.fd == fd) return 1; + } + + return 0; +} + +/***************************************************** +a crude inode number generator +*******************************************************/ +ino_t smbw_inode(const char *name) +{ + if (!*name) return 2; + return (ino_t)str_checksum(name); +} + +/***************************************************** +remove redundent stuff from a filename +*******************************************************/ +void clean_fname(char *name) +{ + char *p, *p2; + int l; + int modified = 1; + + if (!name) return; + + while (modified) { + modified = 0; + + DEBUG(5,("cleaning %s\n", name)); + + if ((p=strstr(name,"/./"))) { + modified = 1; + while (*p) { + p[0] = p[2]; + p++; + } + } + + if ((p=strstr(name,"//"))) { + modified = 1; + while (*p) { + p[0] = p[1]; + p++; + } + } + + if (strcmp(name,"/../")==0) { + modified = 1; + name[1] = 0; + } + + if ((p=strstr(name,"/../"))) { + modified = 1; + for (p2=(p>name?p-1:p);p2>name;p2--) { + if (p2[0] == '/') break; + } + while (*p2) { + p2[0] = p2[3]; + p2++; + } + } + + if (strcmp(name,"/..")==0) { + modified = 1; + name[1] = 0; + } + + l = strlen(name); + p = l>=3?(name+l-3):name; + if (strcmp(p,"/..")==0) { + modified = 1; + for (p2=p-1;p2>name;p2--) { + if (p2[0] == '/') break; + } + if (p2==name) { + p[0] = '/'; + p[1] = 0; + } else { + p2[0] = 0; + } + } + + l = strlen(name); + p = l>=2?(name+l-2):name; + if (strcmp(p,"/.")==0) { + if (p == name) { + p[1] = 0; + } else { + p[0] = 0; + } + } + + if (strncmp(p=name,"./",2) == 0) { + modified = 1; + do { + p[0] = p[2]; + } while (*p++); + } + + l = strlen(p=name); + if (l > 1 && p[l-1] == '/') { + modified = 1; + p[l-1] = 0; + } + } +} + + + +/***************************************************** +find a workgroup (any workgroup!) that has a master +browser on the local network +*******************************************************/ +static char *smbw_find_workgroup(void) +{ + fstring server; + char *p; + struct in_addr *ip_list = NULL; + int count = 0; + int i; + + /* first off see if an existing workgroup name exists */ + p = smbw_getshared("WORKGROUP"); + if (!p) p = lp_workgroup(); + + slprintf(server, sizeof(server), "%s#1D", p); + if (smbw_server(server, "IPC$")) return p; + + /* go looking for workgroups */ + if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) { + DEBUG(1,("No workgroups found!")); + return p; + } + + for (i=0;i<count;i++) { + static fstring name; + if (name_status_find("*", 0, 0x1d, ip_list[i], name)) { + slprintf(server, sizeof(server), "%s#1D", name); + if (smbw_server(server, "IPC$")) { + smbw_setshared("WORKGROUP", name); + SAFE_FREE(ip_list); + return name; + } + } + } + + SAFE_FREE(ip_list); + + return p; +} + +/***************************************************** +parse a smb path into its components. +server is one of + 1) the name of the SMB server + 2) WORKGROUP#1D for share listing + 3) WORKGROUP#__ for workgroup listing +share is the share on the server to query +path is the SMB path on the server +return the full path (ie. add cwd if needed) +*******************************************************/ +char *smbw_parse_path(const char *fname, char *server, char *share, char *path) +{ + static pstring s; + char *p; + int len; + fstring workgroup; + + /* add cwd if necessary */ + if (fname[0] != '/') { + slprintf(s, sizeof(s), "%s/%s", smbw_cwd, fname); + } else { + pstrcpy(s, fname); + } + clean_fname(s); + + /* see if it has the right prefix */ + len = strlen(smbw_prefix)-1; + if (strncmp(s,smbw_prefix,len) || + (s[len] != '/' && s[len] != 0)) return s; + + /* ok, its for us. Now parse out the workgroup, share etc. */ + p = s+len; + if (*p == '/') p++; + if (!next_token(&p, workgroup, "/", sizeof(fstring))) { + /* we're in /smb - give a list of workgroups */ + slprintf(server,sizeof(fstring), "%s#01", smbw_find_workgroup()); + fstrcpy(share,"IPC$"); + pstrcpy(path,""); + return s; + } + + if (!next_token(&p, server, "/", sizeof(fstring))) { + /* we are in /smb/WORKGROUP */ + slprintf(server,sizeof(fstring), "%s#1D", workgroup); + fstrcpy(share,"IPC$"); + pstrcpy(path,""); + } + + if (!next_token(&p, share, "/", sizeof(fstring))) { + /* we are in /smb/WORKGROUP/SERVER */ + fstrcpy(share,"IPC$"); + pstrcpy(path,""); + } + + pstrcpy(path, p); + + all_string_sub(path, "/", "\\", 0); + + return s; +} + +/***************************************************** +determine if a path name (possibly relative) is in the +smb name space +*******************************************************/ +int smbw_path(const char *path) +{ + fstring server, share; + pstring s; + char *cwd; + int len; + + if(!path) + return 0; + + /* this is needed to prevent recursion with the BSD malloc which + opens /etc/malloc.conf on the first call */ + if (strncmp(path,"/etc/", 5) == 0) { + return 0; + } + + smbw_init(); + + len = strlen(smbw_prefix)-1; + + if (path[0] == '/' && strncmp(path,smbw_prefix,len)) { + return 0; + } + + if (smbw_busy) return 0; + + DEBUG(3,("smbw_path(%s)\n", path)); + + cwd = smbw_parse_path(path, server, share, s); + + if (strncmp(cwd,smbw_prefix,len) == 0 && + (cwd[len] == '/' || cwd[len] == 0)) { + return 1; + } + + return 0; +} + +/***************************************************** +return a unix errno from a SMB error pair +*******************************************************/ +int smbw_errno(struct cli_state *c) +{ + return cli_errno(c); +} + +/* Return a username and password given a server and share name */ + +void get_envvar_auth_data(char *server, char *share, char **workgroup, + char **username, char **password) +{ + /* Fall back to shared memory/environment variables */ + + *username = smbw_getshared("USER"); + if (!*username) *username = getenv("USER"); + if (!*username) *username = "guest"; + + *workgroup = smbw_getshared("WORKGROUP"); + if (!*workgroup) *workgroup = lp_workgroup(); + + *password = smbw_getshared("PASSWORD"); + if (!*password) *password = ""; +} + +static smbw_get_auth_data_fn get_auth_data_fn = get_envvar_auth_data; + +/***************************************************** +set the get auth data function +******************************************************/ +void smbw_set_auth_data_fn(smbw_get_auth_data_fn fn) +{ + get_auth_data_fn = fn; +} + +/***************************************************** +return a connection to a server (existing or new) +*******************************************************/ +struct smbw_server *smbw_server(char *server, char *share) +{ + struct smbw_server *srv=NULL; + struct cli_state c; + char *username; + char *password; + char *workgroup; + struct nmb_name called, calling; + char *p, *server_n = server; + fstring group; + pstring ipenv; + struct in_addr ip; + + zero_ip(&ip); + ZERO_STRUCT(c); + + get_auth_data_fn(server, share, &workgroup, &username, &password); + + /* try to use an existing connection */ + for (srv=smbw_srvs;srv;srv=srv->next) { + if (strcmp(server,srv->server_name)==0 && + strcmp(share,srv->share_name)==0 && + strcmp(workgroup,srv->workgroup)==0 && + strcmp(username, srv->username) == 0) + return srv; + } + + if (server[0] == 0) { + errno = EPERM; + return NULL; + } + + make_nmb_name(&calling, lp_netbios_name(), 0x0); + make_nmb_name(&called , server, 0x20); + + DEBUG(4,("server_n=[%s] server=[%s]\n", server_n, server)); + + if ((p=strchr_m(server_n,'#')) && + (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) { + struct in_addr sip; + pstring s; + + fstrcpy(group, server_n); + p = strchr_m(group,'#'); + *p = 0; + + /* cache the workgroup master lookup */ + slprintf(s,sizeof(s)-1,"MASTER_%s", group); + if (!(server_n = smbw_getshared(s))) { + if (!find_master_ip(group, &sip)) { + errno = ENOENT; + return NULL; + } + fstrcpy(group, inet_ntoa(sip)); + server_n = group; + smbw_setshared(s,server_n); + } + } + + DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); + + again: + slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n); + + zero_ip(&ip); + if ((p=smbw_getshared(ipenv))) { + ip = *(interpret_addr2(p)); + } + + /* have to open a new connection */ + if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) { + errno = ENOENT; + return NULL; + } + + if (!cli_session_request(&c, &calling, &called)) { + cli_shutdown(&c); + if (strcmp(called.name, "*SMBSERVER")) { + make_nmb_name(&called , "*SMBSERVER", 0x20); + goto again; + } + errno = ENOENT; + return NULL; + } + + DEBUG(4,(" session request ok\n")); + + if (!cli_negprot(&c)) { + cli_shutdown(&c); + errno = ENOENT; + return NULL; + } + + if (!cli_session_setup(&c, username, + password, strlen(password), + password, strlen(password), + workgroup) && + /* try an anonymous login if it failed */ + !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) { + cli_shutdown(&c); + errno = EPERM; + return NULL; + } + + DEBUG(4,(" session setup ok\n")); + + if (!cli_send_tconX(&c, share, "?????", + password, strlen(password)+1)) { + errno = smbw_errno(&c); + cli_shutdown(&c); + return NULL; + } + + smbw_setshared(ipenv,inet_ntoa(ip)); + + DEBUG(4,(" tconx ok\n")); + + srv = (struct smbw_server *)malloc(sizeof(*srv)); + if (!srv) { + errno = ENOMEM; + goto failed; + } + + ZERO_STRUCTP(srv); + + srv->cli = c; + + srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); + + srv->server_name = strdup(server); + if (!srv->server_name) { + errno = ENOMEM; + goto failed; + } + + srv->share_name = strdup(share); + if (!srv->share_name) { + errno = ENOMEM; + goto failed; + } + + srv->workgroup = strdup(workgroup); + if (!srv->workgroup) { + errno = ENOMEM; + goto failed; + } + + srv->username = strdup(username); + if (!srv->username) { + errno = ENOMEM; + goto failed; + } + + /* some programs play with file descriptors fairly intimately. We + try to get out of the way by duping to a high fd number */ + if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) { + if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) == + srv->cli.fd+SMBW_CLI_FD) { + close(srv->cli.fd); + srv->cli.fd += SMBW_CLI_FD; + } + } + + DLIST_ADD(smbw_srvs, srv); + + return srv; + + failed: + cli_shutdown(&c); + if (!srv) return NULL; + + SAFE_FREE(srv->server_name); + SAFE_FREE(srv->share_name); + SAFE_FREE(srv); + return NULL; +} + + +/***************************************************** +map a fd to a smbw_file structure +*******************************************************/ +struct smbw_file *smbw_file(int fd) +{ + struct smbw_file *file; + + for (file=smbw_files;file;file=file->next) { + if (file->fd == fd) return file; + } + return NULL; +} + +/***************************************************** +a wrapper for open() +*******************************************************/ +int smbw_open(const char *fname, int flags, mode_t mode) +{ + fstring server, share; + pstring path; + struct smbw_server *srv=NULL; + int eno=0, fd = -1; + struct smbw_file *file=NULL; + + smbw_init(); + + if (!fname) { + errno = EINVAL; + return -1; + } + + smbw_busy++; + + /* work out what server they are after */ + smbw_parse_path(fname, server, share, path); + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + if (path[strlen(path)-1] == '\\') { + fd = -1; + } else { + fd = cli_open(&srv->cli, path, flags, DENY_NONE); + } + if (fd == -1) { + /* it might be a directory. Maybe we should use chkpath? */ + eno = smbw_errno(&srv->cli); + fd = smbw_dir_open(fname); + if (fd == -1) errno = eno; + smbw_busy--; + return fd; + } + + file = (struct smbw_file *)malloc(sizeof(*file)); + if (!file) { + errno = ENOMEM; + goto failed; + } + + ZERO_STRUCTP(file); + + file->f = (struct smbw_filedes *)malloc(sizeof(*(file->f))); + if (!file->f) { + errno = ENOMEM; + goto failed; + } + + ZERO_STRUCTP(file->f); + + file->f->cli_fd = fd; + file->f->fname = strdup(path); + if (!file->f->fname) { + errno = ENOMEM; + goto failed; + } + file->srv = srv; + file->fd = open(SMBW_DUMMY, O_WRONLY); + if (file->fd == -1) { + errno = EMFILE; + goto failed; + } + + if (bitmap_query(smbw_file_bmap, file->fd)) { + DEBUG(0,("ERROR: fd used in smbw_open\n")); + errno = EIO; + goto failed; + } + + file->f->ref_count=1; + + bitmap_set(smbw_file_bmap, file->fd); + + DLIST_ADD(smbw_files, file); + + DEBUG(4,("opened %s\n", fname)); + + smbw_busy--; + return file->fd; + + failed: + if (fd != -1) { + cli_close(&srv->cli, fd); + } + if (file) { + if (file->f) { + SAFE_FREE(file->f->fname); + SAFE_FREE(file->f); + } + SAFE_FREE(file); + } + smbw_busy--; + return -1; +} + + +/***************************************************** +a wrapper for pread() +*******************************************************/ +ssize_t smbw_pread(int fd, void *buf, size_t count, off_t ofs) +{ + struct smbw_file *file; + int ret; + + smbw_busy++; + + file = smbw_file(fd); + if (!file) { + errno = EBADF; + smbw_busy--; + return -1; + } + + ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, ofs, count); + + if (ret == -1) { + errno = smbw_errno(&file->srv->cli); + smbw_busy--; + return -1; + } + + smbw_busy--; + return ret; +} + +/***************************************************** +a wrapper for read() +*******************************************************/ +ssize_t smbw_read(int fd, void *buf, size_t count) +{ + struct smbw_file *file; + int ret; + + DEBUG(4,("smbw_read(%d, %d)\n", fd, (int)count)); + + smbw_busy++; + + file = smbw_file(fd); + if (!file) { + errno = EBADF; + smbw_busy--; + return -1; + } + + ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, + file->f->offset, count); + + if (ret == -1) { + errno = smbw_errno(&file->srv->cli); + smbw_busy--; + return -1; + } + + file->f->offset += ret; + + DEBUG(4,(" -> %d\n", ret)); + + smbw_busy--; + return ret; +} + + + +/***************************************************** +a wrapper for write() +*******************************************************/ +ssize_t smbw_write(int fd, void *buf, size_t count) +{ + struct smbw_file *file; + int ret; + + smbw_busy++; + + file = smbw_file(fd); + if (!file) { + errno = EBADF; + smbw_busy--; + return -1; + } + + ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, file->f->offset, count); + + if (ret == -1) { + errno = smbw_errno(&file->srv->cli); + smbw_busy--; + return -1; + } + + file->f->offset += ret; + + smbw_busy--; + return ret; +} + +/***************************************************** +a wrapper for pwrite() +*******************************************************/ +ssize_t smbw_pwrite(int fd, void *buf, size_t count, off_t ofs) +{ + struct smbw_file *file; + int ret; + + smbw_busy++; + + file = smbw_file(fd); + if (!file) { + errno = EBADF; + smbw_busy--; + return -1; + } + + ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, ofs, count); + + if (ret == -1) { + errno = smbw_errno(&file->srv->cli); + smbw_busy--; + return -1; + } + + smbw_busy--; + return ret; +} + +/***************************************************** +a wrapper for close() +*******************************************************/ +int smbw_close(int fd) +{ + struct smbw_file *file; + + smbw_busy++; + + file = smbw_file(fd); + if (!file) { + int ret = smbw_dir_close(fd); + smbw_busy--; + return ret; + } + + if (file->f->ref_count == 1 && + !cli_close(&file->srv->cli, file->f->cli_fd)) { + errno = smbw_errno(&file->srv->cli); + smbw_busy--; + return -1; + } + + + bitmap_clear(smbw_file_bmap, file->fd); + close(file->fd); + + DLIST_REMOVE(smbw_files, file); + + file->f->ref_count--; + if (file->f->ref_count == 0) { + SAFE_FREE(file->f->fname); + SAFE_FREE(file->f); + } + ZERO_STRUCTP(file); + SAFE_FREE(file); + + smbw_busy--; + + return 0; +} + + +/***************************************************** +a wrapper for fcntl() +*******************************************************/ +int smbw_fcntl(int fd, int cmd, long arg) +{ + return 0; +} + + +/***************************************************** +a wrapper for access() +*******************************************************/ +int smbw_access(const char *name, int mode) +{ + struct stat st; + + DEBUG(4,("smbw_access(%s, 0x%x)\n", name, mode)); + + if (smbw_stat(name, &st)) return -1; + + if (((mode & R_OK) && !(st.st_mode & S_IRUSR)) || + ((mode & W_OK) && !(st.st_mode & S_IWUSR)) || + ((mode & X_OK) && !(st.st_mode & S_IXUSR))) { + errno = EACCES; + return -1; + } + + return 0; +} + +/***************************************************** +a wrapper for realink() - needed for correct errno setting +*******************************************************/ +int smbw_readlink(const char *path, char *buf, size_t bufsize) +{ + struct stat st; + int ret; + + ret = smbw_stat(path, &st); + if (ret != 0) { + DEBUG(4,("readlink(%s) failed\n", path)); + return -1; + } + + /* it exists - say it isn't a link */ + DEBUG(4,("readlink(%s) not a link\n", path)); + + errno = EINVAL; + return -1; +} + + +/***************************************************** +a wrapper for unlink() +*******************************************************/ +int smbw_unlink(const char *fname) +{ + struct smbw_server *srv; + fstring server, share; + pstring path; + + if (!fname) { + errno = EINVAL; + return -1; + } + + smbw_init(); + + smbw_busy++; + + /* work out what server they are after */ + smbw_parse_path(fname, server, share, path); + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + if (strncmp(srv->cli.dev, "LPT", 3) == 0) { + int job = smbw_stat_printjob(srv, path, NULL, NULL); + if (job == -1) { + goto failed; + } + if (cli_printjob_del(&srv->cli, job) != 0) { + goto failed; + } + } else if (!cli_unlink(&srv->cli, path)) { + errno = smbw_errno(&srv->cli); + goto failed; + } + + smbw_busy--; + return 0; + + failed: + smbw_busy--; + return -1; +} + + +/***************************************************** +a wrapper for rename() +*******************************************************/ +int smbw_rename(const char *oldname, const char *newname) +{ + struct smbw_server *srv; + fstring server1, share1; + pstring path1; + fstring server2, share2; + pstring path2; + + if (!oldname || !newname) { + errno = EINVAL; + return -1; + } + + smbw_init(); + + DEBUG(4,("smbw_rename(%s,%s)\n", oldname, newname)); + + smbw_busy++; + + /* work out what server they are after */ + smbw_parse_path(oldname, server1, share1, path1); + smbw_parse_path(newname, server2, share2, path2); + + if (strcmp(server1, server2) || strcmp(share1, share2)) { + /* can't cross filesystems */ + errno = EXDEV; + return -1; + } + + /* get a connection to the server */ + srv = smbw_server(server1, share1); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + if (!cli_rename(&srv->cli, path1, path2)) { + int eno = smbw_errno(&srv->cli); + if (eno != EEXIST || + !cli_unlink(&srv->cli, path2) || + !cli_rename(&srv->cli, path1, path2)) { + errno = eno; + goto failed; + } + } + + smbw_busy--; + return 0; + + failed: + smbw_busy--; + return -1; +} + + +/***************************************************** +a wrapper for utime and utimes +*******************************************************/ +static int smbw_settime(const char *fname, time_t t) +{ + struct smbw_server *srv; + fstring server, share; + pstring path; + uint16 mode; + + if (!fname) { + errno = EINVAL; + return -1; + } + + smbw_init(); + + smbw_busy++; + + /* work out what server they are after */ + smbw_parse_path(fname, server, share, path); + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) { + errno = smbw_errno(&srv->cli); + goto failed; + } + + if (!cli_setatr(&srv->cli, path, mode, t)) { + /* some servers always refuse directory changes */ + if (!(mode & aDIR)) { + errno = smbw_errno(&srv->cli); + goto failed; + } + } + + smbw_busy--; + return 0; + + failed: + smbw_busy--; + return -1; +} + +/***************************************************** +a wrapper for utime +*******************************************************/ +int smbw_utime(const char *fname, void *buf) +{ + struct utimbuf *tbuf = (struct utimbuf *)buf; + return smbw_settime(fname, tbuf?tbuf->modtime:time(NULL)); +} + +/***************************************************** +a wrapper for utime +*******************************************************/ +int smbw_utimes(const char *fname, void *buf) +{ + struct timeval *tbuf = (struct timeval *)buf; + return smbw_settime(fname, tbuf?tbuf->tv_sec:time(NULL)); +} + + +/***************************************************** +a wrapper for chown() +*******************************************************/ +int smbw_chown(const char *fname, uid_t owner, gid_t group) +{ + struct smbw_server *srv; + fstring server, share; + pstring path; + uint16 mode; + + if (!fname) { + errno = EINVAL; + return -1; + } + + smbw_init(); + + smbw_busy++; + + /* work out what server they are after */ + smbw_parse_path(fname, server, share, path); + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) { + errno = smbw_errno(&srv->cli); + goto failed; + } + + /* assume success */ + + smbw_busy--; + return 0; + + failed: + smbw_busy--; + return -1; +} + +/***************************************************** +a wrapper for chmod() +*******************************************************/ +int smbw_chmod(const char *fname, mode_t newmode) +{ + struct smbw_server *srv; + fstring server, share; + pstring path; + uint32 mode; + + if (!fname) { + errno = EINVAL; + return -1; + } + + smbw_init(); + + smbw_busy++; + + /* work out what server they are after */ + smbw_parse_path(fname, server, share, path); + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + mode = 0; + + if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY; + if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH; + if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM; + if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN; + + if (!cli_setatr(&srv->cli, path, mode, 0)) { + errno = smbw_errno(&srv->cli); + goto failed; + } + + smbw_busy--; + return 0; + + failed: + smbw_busy--; + return -1; +} + +/***************************************************** +a wrapper for lseek() +*******************************************************/ +off_t smbw_lseek(int fd, off_t offset, int whence) +{ + struct smbw_file *file; + size_t size; + + smbw_busy++; + + file = smbw_file(fd); + if (!file) { + off_t ret = smbw_dir_lseek(fd, offset, whence); + smbw_busy--; + return ret; + } + + switch (whence) { + case SEEK_SET: + file->f->offset = offset; + break; + case SEEK_CUR: + file->f->offset += offset; + break; + case SEEK_END: + if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd, + NULL, &size, NULL, NULL, NULL, + NULL, NULL) && + !cli_getattrE(&file->srv->cli, file->f->cli_fd, + NULL, &size, NULL, NULL, NULL)) { + errno = EINVAL; + smbw_busy--; + return -1; + } + file->f->offset = size + offset; + break; + } + + smbw_busy--; + return file->f->offset; +} + + +/***************************************************** +a wrapper for dup() +*******************************************************/ +int smbw_dup(int fd) +{ + int fd2; + struct smbw_file *file, *file2; + + smbw_busy++; + + file = smbw_file(fd); + if (!file) { + errno = EBADF; + goto failed; + } + + fd2 = dup(file->fd); + if (fd2 == -1) { + goto failed; + } + + if (bitmap_query(smbw_file_bmap, fd2)) { + DEBUG(0,("ERROR: fd already open in dup!\n")); + errno = EIO; + goto failed; + } + + file2 = (struct smbw_file *)malloc(sizeof(*file2)); + if (!file2) { + close(fd2); + errno = ENOMEM; + goto failed; + } + + ZERO_STRUCTP(file2); + + *file2 = *file; + file2->fd = fd2; + + file->f->ref_count++; + + bitmap_set(smbw_file_bmap, fd2); + + DLIST_ADD(smbw_files, file2); + + smbw_busy--; + return fd2; + + failed: + smbw_busy--; + return -1; +} + + +/***************************************************** +a wrapper for dup2() +*******************************************************/ +int smbw_dup2(int fd, int fd2) +{ + struct smbw_file *file, *file2; + + smbw_busy++; + + file = smbw_file(fd); + if (!file) { + errno = EBADF; + goto failed; + } + + if (bitmap_query(smbw_file_bmap, fd2)) { + DEBUG(0,("ERROR: fd already open in dup2!\n")); + errno = EIO; + goto failed; + } + + if (dup2(file->fd, fd2) != fd2) { + goto failed; + } + + file2 = (struct smbw_file *)malloc(sizeof(*file2)); + if (!file2) { + close(fd2); + errno = ENOMEM; + goto failed; + } + + ZERO_STRUCTP(file2); + + *file2 = *file; + file2->fd = fd2; + + file->f->ref_count++; + + bitmap_set(smbw_file_bmap, fd2); + + DLIST_ADD(smbw_files, file2); + + smbw_busy--; + return fd2; + + failed: + smbw_busy--; + return -1; +} + + +/***************************************************** +close a connection to a server +*******************************************************/ +static void smbw_srv_close(struct smbw_server *srv) +{ + smbw_busy++; + + cli_shutdown(&srv->cli); + + SAFE_FREE(srv->server_name); + SAFE_FREE(srv->share_name); + + DLIST_REMOVE(smbw_srvs, srv); + + ZERO_STRUCTP(srv); + + SAFE_FREE(srv); + + smbw_busy--; +} + +/***************************************************** +when we fork we have to close all connections and files +in the child +*******************************************************/ +int smbw_fork(void) +{ + pid_t child; + int p[2]; + char c=0; + pstring line; + + struct smbw_file *file, *next_file; + struct smbw_server *srv, *next_srv; + + if (pipe(p)) return real_fork(); + + child = real_fork(); + + if (child) { + /* block the parent for a moment until the sockets are + closed */ + close(p[1]); + read(p[0], &c, 1); + close(p[0]); + return child; + } + + close(p[0]); + + /* close all files */ + for (file=smbw_files;file;file=next_file) { + next_file = file->next; + close(file->fd); + } + + /* close all server connections */ + for (srv=smbw_srvs;srv;srv=next_srv) { + next_srv = srv->next; + smbw_srv_close(srv); + } + + slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid()); + smbw_setshared(line,smbw_cwd); + + /* unblock the parent */ + write(p[1], &c, 1); + close(p[1]); + + /* and continue in the child */ + return 0; +} + +#ifndef NO_ACL_WRAPPER +/***************************************************** +say no to acls +*******************************************************/ + int smbw_acl(const char *pathp, int cmd, int nentries, aclent_t *aclbufp) +{ + if (cmd == GETACL || cmd == GETACLCNT) return 0; + errno = ENOSYS; + return -1; +} +#endif + +#ifndef NO_FACL_WRAPPER +/***************************************************** +say no to acls +*******************************************************/ + int smbw_facl(int fd, int cmd, int nentries, aclent_t *aclbufp) +{ + if (cmd == GETACL || cmd == GETACLCNT) return 0; + errno = ENOSYS; + return -1; +} +#endif + +#ifdef HAVE_EXPLICIT_LARGEFILE_SUPPORT +#ifdef HAVE_STAT64 +/* this can't be in wrapped.c because of include conflicts */ + void stat64_convert(struct stat *st, struct stat64 *st64) +{ + st64->st_size = st->st_size; + st64->st_mode = st->st_mode; + st64->st_ino = st->st_ino; + st64->st_dev = st->st_dev; + st64->st_rdev = st->st_rdev; + st64->st_nlink = st->st_nlink; + st64->st_uid = st->st_uid; + st64->st_gid = st->st_gid; + st64->st_atime = st->st_atime; + st64->st_mtime = st->st_mtime; + st64->st_ctime = st->st_ctime; + st64->st_blksize = st->st_blksize; + st64->st_blocks = st->st_blocks; +} +#endif + +#ifdef HAVE_READDIR64 + void dirent64_convert(struct dirent *d, struct dirent64 *d64) +{ + d64->d_ino = d->d_ino; + d64->d_off = d->d_off; + d64->d_reclen = d->d_reclen; + pstrcpy(d64->d_name, d->d_name); +} +#endif +#endif + + +#ifdef HAVE___XSTAT +/* Definition of `struct stat' used in the linux kernel.. */ +struct kernel_stat { + unsigned short int st_dev; + unsigned short int __pad1; + unsigned long int st_ino; + unsigned short int st_mode; + unsigned short int st_nlink; + unsigned short int st_uid; + unsigned short int st_gid; + unsigned short int st_rdev; + unsigned short int __pad2; + unsigned long int st_size; + unsigned long int st_blksize; + unsigned long int st_blocks; + unsigned long int st_atime; + unsigned long int __unused1; + unsigned long int st_mtime; + unsigned long int __unused2; + unsigned long int st_ctime; + unsigned long int __unused3; + unsigned long int __unused4; + unsigned long int __unused5; +}; + +/* + * Prototype for gcc in 'fussy' mode. + */ + void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf); + void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf) +{ +#ifdef _STAT_VER_LINUX_OLD + if (vers == _STAT_VER_LINUX_OLD) { + memcpy(st, kbuf, sizeof(*st)); + return; + } +#endif + + ZERO_STRUCTP(st); + + st->st_dev = kbuf->st_dev; + st->st_ino = kbuf->st_ino; + st->st_mode = kbuf->st_mode; + st->st_nlink = kbuf->st_nlink; + st->st_uid = kbuf->st_uid; + st->st_gid = kbuf->st_gid; + st->st_rdev = kbuf->st_rdev; + st->st_size = kbuf->st_size; + st->st_blksize = kbuf->st_blksize; + st->st_blocks = kbuf->st_blocks; + st->st_atime = kbuf->st_atime; + st->st_mtime = kbuf->st_mtime; + st->st_ctime = kbuf->st_ctime; +} +#endif diff --git a/source4/smbwrapper/smbw.h b/source4/smbwrapper/smbw.h new file mode 100644 index 0000000000..3f0b1cbb44 --- /dev/null +++ b/source4/smbwrapper/smbw.h @@ -0,0 +1,71 @@ +/* + Unix SMB/CIFS implementation. + SMB wrapper functions - definitions + Copyright (C) Andrew Tridgell 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _SMBW_H +#define _SMBW_H + +#define SMBW_PREFIX "/smb/" +#define SMBW_DUMMY "/dev/null" + +#define SMBW_CLI_FD 512 +#define SMBW_MAX_OPEN 8192 + +#define SMBW_FILE_MODE (S_IFREG | 0444) +#define SMBW_DIR_MODE (S_IFDIR | 0555) + +struct smbw_server { + struct smbw_server *next, *prev; + struct cli_state cli; + char *server_name; + char *share_name; + char *workgroup; + char *username; + dev_t dev; + BOOL no_pathinfo2; +}; + +struct smbw_filedes { + int cli_fd; + int ref_count; + char *fname; + off_t offset; +}; + +struct smbw_file { + struct smbw_file *next, *prev; + struct smbw_filedes *f; + int fd; + struct smbw_server *srv; +}; + +struct smbw_dir { + struct smbw_dir *next, *prev; + int fd; + int offset, count, malloced; + struct smbw_server *srv; + struct file_info *list; + char *path; +}; + +typedef void (*smbw_get_auth_data_fn)(char *server, char *share, + char **workgroup, char **username, + char **password); + +#endif /* _SMBW_H */ diff --git a/source4/smbwrapper/smbw_cache.c b/source4/smbwrapper/smbw_cache.c new file mode 100644 index 0000000000..fcb0eda805 --- /dev/null +++ b/source4/smbwrapper/smbw_cache.c @@ -0,0 +1,207 @@ +/* + Unix SMB/CIFS implementation. + SMB wrapper directory functions + Copyright (C) Tim Potter 2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* We cache lists of workgroups, lists of servers in workgroups, and lists + of shares exported by servers. */ + +#define CACHE_TIMEOUT 30 + +struct name_list { + struct name_list *prev, *next; + char *name; + uint32 stype; + char *comment; +}; + +struct cached_names { + struct cached_names *prev, *next; + char *key; + struct name_list *name_list; + time_t cache_timeout; + int result; +}; + +static struct cached_names *cached_names = NULL; + +/* Find a list of cached name for a workgroup, server or share list */ + +static struct cached_names *find_cached_names(char *key) +{ + struct cached_names *tmp; + + for (tmp = cached_names; tmp; tmp = tmp->next) { + if (strequal(tmp->key, key)) { + return tmp; + } + } + + return NULL; +} + +/* Add a name to a list stored in the state variable */ + +static void add_cached_names(const char *name, uint32 stype, + const char *comment, void *state) +{ + struct name_list **name_list = (struct name_list **)state; + struct name_list *new_name; + + new_name = (struct name_list *)malloc(sizeof(struct name_list)); + if (!new_name) return; + + ZERO_STRUCTP(new_name); + + new_name->name = strdup(name); + new_name->stype = stype; + new_name->comment = strdup(comment); + + DLIST_ADD(*name_list, new_name); +} + +static void free_name_list(struct name_list *name_list) +{ + struct name_list *tmp = name_list; + + while(tmp) { + struct name_list *next; + + next = tmp->next; + + SAFE_FREE(tmp->name); + SAFE_FREE(tmp->comment); + SAFE_FREE(tmp); + + tmp = next; + } +} + +/* Wrapper for NetServerEnum function */ + +BOOL smbw_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype, + void (*fn)(const char *, uint32, const char *, void *), + void *state) +{ + struct cached_names *names; + struct name_list *tmp; + time_t now = time(NULL); + char key[PATH_MAX]; + BOOL result = True; + + slprintf(key, PATH_MAX - 1, "%s/%s#%s", cli->desthost, + workgroup, (stype == SV_TYPE_DOMAIN_ENUM ? "DOM" : "SRV")); + + names = find_cached_names(key); + + if (names == NULL || (now - names->cache_timeout) > CACHE_TIMEOUT) { + struct cached_names *new_names = NULL; + + /* No names cached for this workgroup */ + + if (names == NULL) { + new_names = (struct cached_names *) + malloc(sizeof(struct cached_names)); + + ZERO_STRUCTP(new_names); + DLIST_ADD(cached_names, new_names); + + } else { + + /* Dispose of out of date name list */ + + free_name_list(names->name_list); + names->name_list = NULL; + + new_names = names; + } + + result = cli_NetServerEnum(cli, workgroup, stype, + add_cached_names, + &new_names->name_list); + + new_names->cache_timeout = now; + new_names->result = result; + new_names->key = strdup(key); + + names = new_names; + } + + /* Return names by running callback function. */ + + for (tmp = names->name_list; tmp; tmp = tmp->next) + fn(tmp->name, stype, tmp->comment, state); + + return names->result; +} + +/* Wrapper for RNetShareEnum function */ + +int smbw_RNetShareEnum(struct cli_state *cli, + void (*fn)(const char *, uint32, const char *, void *), + void *state) +{ + struct cached_names *names; + struct name_list *tmp; + time_t now = time(NULL); + char key[PATH_MAX]; + + slprintf(key, PATH_MAX - 1, "SHARE/%s", cli->desthost); + + names = find_cached_names(key); + + if (names == NULL || (now - names->cache_timeout) > CACHE_TIMEOUT) { + struct cached_names *new_names = NULL; + + /* No names cached for this server */ + + if (names == NULL) { + new_names = (struct cached_names *) + malloc(sizeof(struct cached_names)); + + ZERO_STRUCTP(new_names); + DLIST_ADD(cached_names, new_names); + + } else { + + /* Dispose of out of date name list */ + + free_name_list(names->name_list); + names->name_list = NULL; + + new_names = names; + } + + new_names->result = cli_RNetShareEnum(cli, add_cached_names, + &new_names->name_list); + + new_names->cache_timeout = now; + new_names->key = strdup(key); + + names = new_names; + } + + /* Return names by running callback function. */ + + for (tmp = names->name_list; tmp; tmp = tmp->next) + fn(tmp->name, tmp->stype, tmp->comment, state); + + return names->result; +} diff --git a/source4/smbwrapper/smbw_dir.c b/source4/smbwrapper/smbw_dir.c new file mode 100644 index 0000000000..31d81a1e7e --- /dev/null +++ b/source4/smbwrapper/smbw_dir.c @@ -0,0 +1,688 @@ +/* + Unix SMB/CIFS implementation. + SMB wrapper directory functions + Copyright (C) Andrew Tridgell 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "realcalls.h" + +extern pstring smbw_cwd; +extern fstring smbw_prefix; + +static struct smbw_dir *smbw_dirs; + +extern struct bitmap *smbw_file_bmap; + +extern int smbw_busy; + +/***************************************************** +map a fd to a smbw_dir structure +*******************************************************/ +struct smbw_dir *smbw_dir(int fd) +{ + struct smbw_dir *dir; + + for (dir=smbw_dirs;dir;dir=dir->next) { + if (dir->fd == fd) return dir; + } + return NULL; +} + +/***************************************************** +check if a DIR* is one of ours +*******************************************************/ +int smbw_dirp(DIR *dirp) +{ + struct smbw_dir *d = (struct smbw_dir *)dirp; + struct smbw_dir *dir; + + for (dir=smbw_dirs;dir;dir=dir->next) { + if (dir == d) return 1; + } + return 0; +} + +/***************************************************** +free a smbw_dir structure and all entries +*******************************************************/ +static void free_dir(struct smbw_dir *dir) +{ + if(!dir) return; + + SAFE_FREE(dir->list); + SAFE_FREE(dir->path); + ZERO_STRUCTP(dir); + SAFE_FREE(dir); +} + +static struct smbw_dir *cur_dir; + +/***************************************************** +add a entry to a directory listing +*******************************************************/ +static void smbw_dir_add(struct file_info *finfo, const char *mask, + void *state) +{ + struct file_info *cdl; + + DEBUG(5,("%s\n", finfo->name)); + + if (cur_dir->malloced == cur_dir->count) { + cdl = (struct file_info *)Realloc(cur_dir->list, + sizeof(cur_dir->list[0])* + (cur_dir->count+100)); + if (!cdl) { + /* oops */ + return; + } + cur_dir->list = cdl; + cur_dir->malloced += 100; + } + + cur_dir->list[cur_dir->count] = *finfo; + cur_dir->count++; +} + +/***************************************************** +add a entry to a directory listing +*******************************************************/ +static void smbw_share_add(const char *share, uint32 type, + const char *comment, void *state) +{ + struct file_info finfo; + + if (strcmp(share,"IPC$") == 0) return; + + ZERO_STRUCT(finfo); + + pstrcpy(finfo.name, share); + finfo.mode = aRONLY | aDIR; + + smbw_dir_add(&finfo, NULL, NULL); +} + + +/***************************************************** +add a server to a directory listing +*******************************************************/ +static void smbw_server_add(const char *name, uint32 type, + const char *comment, void *state) +{ + struct file_info finfo; + + ZERO_STRUCT(finfo); + + pstrcpy(finfo.name, name); + finfo.mode = aRONLY | aDIR; + + smbw_dir_add(&finfo, NULL, NULL); +} + + +/***************************************************** +add a entry to a directory listing +*******************************************************/ +static void smbw_printjob_add(struct print_job_info *job) +{ + struct file_info finfo; + + ZERO_STRUCT(finfo); + + pstrcpy(finfo.name, job->name); + finfo.mode = aRONLY | aDIR; + finfo.mtime = job->t; + finfo.atime = job->t; + finfo.ctime = job->t; + finfo.uid = nametouid(job->user); + finfo.mode = aRONLY; + finfo.size = job->size; + + smbw_dir_add(&finfo, NULL, NULL); +} + + +/***************************************************** +open a directory on the server +*******************************************************/ +int smbw_dir_open(const char *fname) +{ + fstring server, share; + pstring path; + struct smbw_server *srv=NULL; + struct smbw_dir *dir=NULL; + pstring mask; + int fd; + char *s, *p; + + if (!fname) { + errno = EINVAL; + return -1; + } + + smbw_init(); + + /* work out what server they are after */ + s = smbw_parse_path(fname, server, share, path); + + DEBUG(4,("dir_open share=%s\n", share)); + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + dir = (struct smbw_dir *)malloc(sizeof(*dir)); + if (!dir) { + errno = ENOMEM; + goto failed; + } + + ZERO_STRUCTP(dir); + + cur_dir = dir; + + slprintf(mask, sizeof(mask)-1, "%s\\*", path); + all_string_sub(mask,"\\\\","\\",0); + + if ((p=strstr(srv->server_name,"#01"))) { + *p = 0; + smbw_server_add(".",0,"", NULL); + smbw_server_add("..",0,"", NULL); + smbw_NetServerEnum(&srv->cli, srv->server_name, + SV_TYPE_DOMAIN_ENUM, smbw_server_add, NULL); + *p = '#'; + } else if ((p=strstr(srv->server_name,"#1D"))) { + DEBUG(4,("doing NetServerEnum\n")); + *p = 0; + smbw_server_add(".",0,"", NULL); + smbw_server_add("..",0,"", NULL); + smbw_NetServerEnum(&srv->cli, srv->server_name, SV_TYPE_ALL, + smbw_server_add, NULL); + *p = '#'; + } else if (strcmp(srv->cli.dev,"IPC") == 0) { + DEBUG(4,("doing NetShareEnum\n")); + smbw_share_add(".",0,"", NULL); + smbw_share_add("..",0,"", NULL); + if (smbw_RNetShareEnum(&srv->cli, smbw_share_add, NULL) < 0) { + errno = smbw_errno(&srv->cli); + goto failed; + } + } else if (strncmp(srv->cli.dev,"LPT",3) == 0) { + smbw_share_add(".",0,"", NULL); + smbw_share_add("..",0,"", NULL); + if (cli_print_queue(&srv->cli, smbw_printjob_add) < 0) { + errno = smbw_errno(&srv->cli); + goto failed; + } + } else { +#if 0 + if (strcmp(path,"\\") == 0) { + smbw_share_add(".",0,""); + smbw_share_add("..",0,""); + } +#endif + if (cli_list(&srv->cli, mask, aHIDDEN|aSYSTEM|aDIR, + smbw_dir_add, NULL) < 0) { + errno = smbw_errno(&srv->cli); + goto failed; + } + } + + cur_dir = NULL; + + fd = open(SMBW_DUMMY, O_WRONLY); + if (fd == -1) { + errno = EMFILE; + goto failed; + } + + if (bitmap_query(smbw_file_bmap, fd)) { + DEBUG(0,("ERROR: fd used in smbw_dir_open\n")); + errno = EIO; + goto failed; + } + + DLIST_ADD(smbw_dirs, dir); + + bitmap_set(smbw_file_bmap, fd); + + dir->fd = fd; + dir->srv = srv; + dir->path = strdup(s); + + DEBUG(4,(" -> %d\n", dir->count)); + + return dir->fd; + + failed: + free_dir(dir); + + return -1; +} + +/***************************************************** +a wrapper for fstat() on a directory +*******************************************************/ +int smbw_dir_fstat(int fd, struct stat *st) +{ + struct smbw_dir *dir; + + dir = smbw_dir(fd); + if (!dir) { + errno = EBADF; + return -1; + } + + ZERO_STRUCTP(st); + + smbw_setup_stat(st, "", dir->count*DIRP_SIZE, aDIR); + + st->st_dev = dir->srv->dev; + + return 0; +} + +/***************************************************** +close a directory handle +*******************************************************/ +int smbw_dir_close(int fd) +{ + struct smbw_dir *dir; + + dir = smbw_dir(fd); + if (!dir) { + errno = EBADF; + return -1; + } + + bitmap_clear(smbw_file_bmap, dir->fd); + close(dir->fd); + + DLIST_REMOVE(smbw_dirs, dir); + + free_dir(dir); + + return 0; +} + +/***************************************************** +a wrapper for getdents() +*******************************************************/ +int smbw_getdents(unsigned int fd, struct dirent *dirp, int count) +{ + struct smbw_dir *dir; + int n=0; + + smbw_busy++; + + dir = smbw_dir(fd); + if (!dir) { + errno = EBADF; + smbw_busy--; + return -1; + } + + while (count>=DIRP_SIZE && (dir->offset < dir->count)) { +#if HAVE_DIRENT_D_OFF + dirp->d_off = (dir->offset+1)*DIRP_SIZE; +#endif + dirp->d_reclen = DIRP_SIZE; + fstrcpy(&dirp->d_name[0], dir->list[dir->offset].name); + dirp->d_ino = smbw_inode(dir->list[dir->offset].name); + dir->offset++; + count -= dirp->d_reclen; +#if HAVE_DIRENT_D_OFF + if (dir->offset == dir->count) { + dirp->d_off = -1; + } +#endif + dirp = (struct dirent *)(((char *)dirp) + DIRP_SIZE); + n++; + } + + smbw_busy--; + return n*DIRP_SIZE; +} + + +/***************************************************** +a wrapper for chdir() +*******************************************************/ +int smbw_chdir(const char *name) +{ + struct smbw_server *srv; + fstring server, share; + pstring path; + uint16 mode = aDIR; + char *cwd; + int len; + + smbw_init(); + + len = strlen(smbw_prefix); + + if (smbw_busy) return real_chdir(name); + + smbw_busy++; + + if (!name) { + errno = EINVAL; + goto failed; + } + + DEBUG(4,("smbw_chdir(%s)\n", name)); + + /* work out what server they are after */ + cwd = smbw_parse_path(name, server, share, path); + + /* a special case - accept cd to /smb */ + if (strncmp(cwd, smbw_prefix, len-1) == 0 && + cwd[len-1] == 0) { + goto success1; + } + + if (strncmp(cwd,smbw_prefix,strlen(smbw_prefix))) { + if (real_chdir(cwd) == 0) { + goto success2; + } + goto failed; + } + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + if (strncmp(srv->cli.dev,"IPC",3) && + strncmp(srv->cli.dev,"LPT",3) && + !smbw_getatr(srv, path, + &mode, NULL, NULL, NULL, NULL, NULL)) { + errno = smbw_errno(&srv->cli); + goto failed; + } + + if (!(mode & aDIR)) { + errno = ENOTDIR; + goto failed; + } + + success1: + /* we don't want the old directory to be busy */ + real_chdir("/"); + + success2: + + DEBUG(4,("set SMBW_CWD to %s\n", cwd)); + + pstrcpy(smbw_cwd, cwd); + + smbw_busy--; + return 0; + + failed: + smbw_busy--; + return -1; +} + + +/***************************************************** +a wrapper for lseek() on directories +*******************************************************/ +off_t smbw_dir_lseek(int fd, off_t offset, int whence) +{ + struct smbw_dir *dir; + off_t ret; + + dir = smbw_dir(fd); + if (!dir) { + errno = EBADF; + return -1; + } + + switch (whence) { + case SEEK_SET: + dir->offset = offset/DIRP_SIZE; + break; + case SEEK_CUR: + dir->offset += offset/DIRP_SIZE; + break; + case SEEK_END: + dir->offset = (dir->count * DIRP_SIZE) + offset; + dir->offset /= DIRP_SIZE; + break; + } + + ret = dir->offset * DIRP_SIZE; + + DEBUG(4,(" -> %d\n", (int)ret)); + + return ret; +} + + +/***************************************************** +a wrapper for mkdir() +*******************************************************/ +int smbw_mkdir(const char *fname, mode_t mode) +{ + struct smbw_server *srv; + fstring server, share; + pstring path; + + if (!fname) { + errno = EINVAL; + return -1; + } + + smbw_init(); + + smbw_busy++; + + /* work out what server they are after */ + smbw_parse_path(fname, server, share, path); + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + if (!cli_mkdir(&srv->cli, path)) { + errno = smbw_errno(&srv->cli); + goto failed; + } + + smbw_busy--; + return 0; + + failed: + smbw_busy--; + return -1; +} + +/***************************************************** +a wrapper for rmdir() +*******************************************************/ +int smbw_rmdir(const char *fname) +{ + struct smbw_server *srv; + fstring server, share; + pstring path; + + if (!fname) { + errno = EINVAL; + return -1; + } + + smbw_init(); + + smbw_busy++; + + /* work out what server they are after */ + smbw_parse_path(fname, server, share, path); + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + if (!cli_rmdir(&srv->cli, path)) { + errno = smbw_errno(&srv->cli); + goto failed; + } + + smbw_busy--; + return 0; + + failed: + smbw_busy--; + return -1; +} + + +/***************************************************** +a wrapper for getcwd() +*******************************************************/ +char *smbw_getcwd(char *buf, size_t size) +{ + smbw_init(); + + if (smbw_busy) { + return (char *)real_getcwd(buf, size); + } + + smbw_busy++; + + if (!buf) { + if (size <= 0) size = strlen(smbw_cwd)+1; + buf = (char *)malloc(size); + if (!buf) { + errno = ENOMEM; + smbw_busy--; + return NULL; + } + } + + if (strlen(smbw_cwd) > size-1) { + errno = ERANGE; + smbw_busy--; + return NULL; + } + + safe_strcpy(buf, smbw_cwd, size); + + smbw_busy--; + return buf; +} + +/***************************************************** +a wrapper for fchdir() +*******************************************************/ +int smbw_fchdir(unsigned int fd) +{ + struct smbw_dir *dir; + int ret; + + smbw_busy++; + + dir = smbw_dir(fd); + if (dir) { + smbw_busy--; + return chdir(dir->path); + } + + ret = real_fchdir(fd); + if (ret == 0) { + sys_getwd(smbw_cwd); + } + + smbw_busy--; + return ret; +} + +/***************************************************** +open a directory on the server +*******************************************************/ +DIR *smbw_opendir(const char *fname) +{ + int fd; + + smbw_busy++; + + fd = smbw_dir_open(fname); + + if (fd == -1) { + smbw_busy--; + return NULL; + } + + smbw_busy--; + + return (DIR *)smbw_dir(fd); +} + +/***************************************************** +read one entry from a directory +*******************************************************/ +struct dirent *smbw_readdir(DIR *dirp) +{ + struct smbw_dir *d = (struct smbw_dir *)dirp; + static union { + char buf[DIRP_SIZE]; + struct dirent de; + } dbuf; + + if (smbw_getdents(d->fd, &dbuf.de, DIRP_SIZE) > 0) + return &dbuf.de; + + return NULL; +} + +/***************************************************** +close a DIR* +*******************************************************/ +int smbw_closedir(DIR *dirp) +{ + struct smbw_dir *d = (struct smbw_dir *)dirp; + return smbw_close(d->fd); +} + +/***************************************************** +seek in a directory +*******************************************************/ +void smbw_seekdir(DIR *dirp, off_t offset) +{ + struct smbw_dir *d = (struct smbw_dir *)dirp; + smbw_dir_lseek(d->fd,offset, SEEK_SET); +} + +/***************************************************** +current loc in a directory +*******************************************************/ +off_t smbw_telldir(DIR *dirp) +{ + struct smbw_dir *d = (struct smbw_dir *)dirp; + return smbw_dir_lseek(d->fd,0,SEEK_CUR); +} diff --git a/source4/smbwrapper/smbw_stat.c b/source4/smbwrapper/smbw_stat.c new file mode 100644 index 0000000000..6c476a8a67 --- /dev/null +++ b/source4/smbwrapper/smbw_stat.c @@ -0,0 +1,250 @@ +/* + Unix SMB/CIFS implementation. + SMB wrapper stat functions + Copyright (C) Andrew Tridgell 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +extern int smbw_busy; + +/***************************************************** +setup basic info in a stat structure +*******************************************************/ +void smbw_setup_stat(struct stat *st, char *fname, size_t size, int mode) +{ + st->st_mode = 0; + + if (IS_DOS_DIR(mode)) { + st->st_mode = SMBW_DIR_MODE; + } else { + st->st_mode = SMBW_FILE_MODE; + } + + if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR; + if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP; + if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH; + if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR; + + st->st_size = size; + st->st_blksize = 512; + st->st_blocks = (size+511)/512; + st->st_uid = getuid(); + st->st_gid = getgid(); + if (IS_DOS_DIR(mode)) { + st->st_nlink = 2; + } else { + st->st_nlink = 1; + } + if (st->st_ino == 0) { + st->st_ino = smbw_inode(fname); + } +} + + +/***************************************************** +try to do a QPATHINFO and if that fails then do a getatr +this is needed because win95 sometimes refuses the qpathinfo +*******************************************************/ +BOOL smbw_getatr(struct smbw_server *srv, char *path, + uint16 *mode, size_t *size, + time_t *c_time, time_t *a_time, time_t *m_time, + SMB_INO_T *ino) +{ + DEBUG(4,("sending qpathinfo\n")); + + if (!srv->no_pathinfo2 && + cli_qpathinfo2(&srv->cli, path, c_time, a_time, m_time, NULL, + size, mode, ino)) return True; + + /* if this is NT then don't bother with the getatr */ + if (srv->cli.capabilities & CAP_NT_SMBS) return False; + + if (cli_getatr(&srv->cli, path, mode, size, m_time)) { + a_time = c_time = m_time; + srv->no_pathinfo2 = True; + return True; + } + return False; +} + + +static struct print_job_info printjob; + +/***************************************************** +gather info from a printjob listing +*******************************************************/ +static void smbw_printjob_stat(struct print_job_info *job) +{ + if (strcmp(job->name, printjob.name) == 0) { + printjob = *job; + } +} + +/***************************************************** +stat a printjob +*******************************************************/ +int smbw_stat_printjob(struct smbw_server *srv,char *path, + size_t *size, time_t *m_time) +{ + if (path[0] == '\\') path++; + + ZERO_STRUCT(printjob); + + fstrcpy(printjob.name, path); + cli_print_queue(&srv->cli, smbw_printjob_stat); + + if (size) { + *size = printjob.size; + } + if (m_time) { + *m_time = printjob.t; + } + return printjob.id; +} + + +/***************************************************** +a wrapper for fstat() +*******************************************************/ +int smbw_fstat(int fd, struct stat *st) +{ + struct smbw_file *file; + time_t c_time, a_time, m_time; + size_t size; + uint16 mode; + SMB_INO_T ino = 0; + + smbw_busy++; + + ZERO_STRUCTP(st); + + file = smbw_file(fd); + if (!file) { + int ret = smbw_dir_fstat(fd, st); + smbw_busy--; + return ret; + } + + if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd, + &mode, &size, &c_time, &a_time, &m_time, NULL, + &ino) && + !cli_getattrE(&file->srv->cli, file->f->cli_fd, + &mode, &size, &c_time, &a_time, &m_time)) { + errno = EINVAL; + smbw_busy--; + return -1; + } + + st->st_ino = ino; + + smbw_setup_stat(st, file->f->fname, size, mode); + + st->st_atime = a_time; + st->st_ctime = c_time; + st->st_mtime = m_time; + st->st_dev = file->srv->dev; + + smbw_busy--; + return 0; +} + + +/***************************************************** +a wrapper for stat() +*******************************************************/ +int smbw_stat(const char *fname, struct stat *st) +{ + struct smbw_server *srv; + fstring server, share; + pstring path; + time_t m_time=0, a_time=0, c_time=0; + size_t size=0; + uint16 mode=0; + SMB_INO_T ino = 0; + int result = 0; + + ZERO_STRUCTP(st); + + if (!fname) { + errno = EINVAL; + return -1; + } + + DEBUG(4,("stat(%s)\n", fname)); + + smbw_init(); + + smbw_busy++; + + /* work out what server they are after */ + smbw_parse_path(fname, server, share, path); + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + + /* For shares we aren't allowed to connect to, or no master + browser found, return an empty directory */ + + if ((server[0] && share[0] && !path[0] && errno == EACCES) || + (!path[0] && errno == ENOENT)) { + mode = aDIR | aRONLY; + smbw_setup_stat(st, path, size, mode); + goto done; + } + + /* smbw_server sets errno */ + result = -1; + goto done; + } + + DEBUG(4,("smbw_stat\n")); + + if (strncmp(srv->cli.dev,"IPC",3) == 0) { + mode = aDIR | aRONLY; + } else if (strncmp(srv->cli.dev,"LPT",3) == 0) { + if (strcmp(path,"\\") == 0) { + mode = aDIR | aRONLY; + } else { + mode = aRONLY; + smbw_stat_printjob(srv, path, &size, &m_time); + c_time = a_time = m_time; + } + } else { + if (!smbw_getatr(srv, path, + &mode, &size, &c_time, &a_time, &m_time, + &ino)) { + errno = smbw_errno(&srv->cli); + result = -1; + goto done; + } + } + + st->st_ino = ino; + + smbw_setup_stat(st, path, size, mode); + + st->st_atime = a_time; + st->st_ctime = c_time; + st->st_mtime = m_time; + st->st_dev = srv->dev; + + done: + smbw_busy--; + return result; +} diff --git a/source4/smbwrapper/wrapped.c b/source4/smbwrapper/wrapped.c new file mode 100644 index 0000000000..338ee0d5b1 --- /dev/null +++ b/source4/smbwrapper/wrapped.c @@ -0,0 +1,705 @@ +/* + Unix SMB/CIFS implementation. + SMB wrapper functions + Copyright (C) Andrew Tridgell 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* NOTE: This file WILL produce compiler warnings. They are unavoidable + + Do not try and get rid of them by including other include files or + by including includes.h or proto.h or you will break portability. + */ + +#include "config.h" +#include <sys/types.h> +#include <errno.h> +#include "realcalls.h" + +#ifndef NULL +# define NULL ((void *)0) +#endif + + int open(char *name, int flags, mode_t mode) +{ + if (smbw_path(name)) { + return smbw_open(name, flags, mode); + } + + return real_open(name, flags, mode); +} + +#ifdef HAVE__OPEN + int _open(char *name, int flags, mode_t mode) +{ + return open(name, flags, mode); +} +#elif HAVE___OPEN + int __open(char *name, int flags, mode_t mode) +{ + return open(name, flags, mode); +} +#endif + + +#ifdef HAVE_OPEN64 + int open64(char *name, int flags, mode_t mode) +{ + if (smbw_path(name)) { + return smbw_open(name, flags, mode); + } + + return real_open64(name, flags, mode); +} +#endif + +#ifndef NO_OPEN64_ALIAS +#ifdef HAVE__OPEN64 + int _open64(char *name, int flags, mode_t mode) +{ + return open64(name, flags, mode); +} +#elif HAVE___OPEN64 + int __open64(char *name, int flags, mode_t mode) +{ + return open64(name, flags, mode); +} +#endif +#endif + +#ifdef HAVE_PREAD + ssize_t pread(int fd, void *buf, size_t size, off_t ofs) +{ + if (smbw_fd(fd)) { + return smbw_pread(fd, buf, size, ofs); + } + + return real_pread(fd, buf, size, ofs); +} +#endif + +#if defined(HAVE_PREAD64) && defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) + ssize_t pread64(int fd, void *buf, size_t size, off64_t ofs) +{ + if (smbw_fd(fd)) { + return smbw_pread(fd, buf, size, ofs); + } + + return real_pread64(fd, buf, size, ofs); +} +#endif + +#ifdef HAVE_PWRITE + ssize_t pwrite(int fd, void *buf, size_t size, off_t ofs) +{ + if (smbw_fd(fd)) { + return smbw_pwrite(fd, buf, size, ofs); + } + + return real_pwrite(fd, buf, size, ofs); +} +#endif + +#if defined(HAVE_PWRITE64) && defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) + ssize_t pwrite64(int fd, void *buf, size_t size, off64_t ofs) +{ + if (smbw_fd(fd)) { + return smbw_pwrite(fd, buf, size, ofs); + } + + return real_pwrite64(fd, buf, size, ofs); +} +#endif + + + int chdir(char *name) +{ + return smbw_chdir(name); +} + +#ifdef HAVE___CHDIR + int __chdir(char *name) +{ + return chdir(name); +} +#elif HAVE__CHDIR + int _chdir(char *name) +{ + return chdir(name); +} +#endif + + + int close(int fd) +{ + if (smbw_fd(fd)) { + return smbw_close(fd); + } + if (smbw_local_fd(fd)) { + errno = EBADF; + return -1; + } + + return real_close(fd); +} + +#ifdef HAVE___CLOSE + int __close(int fd) +{ + return close(fd); +} +#elif HAVE__CLOSE + int _close(int fd) +{ + return close(fd); +} +#endif + + + int fchdir(int fd) +{ + return smbw_fchdir(fd); +} + +#ifdef HAVE___FCHDIR + int __fchdir(int fd) +{ + return fchdir(fd); +} +#elif HAVE__FCHDIR + int _fchdir(int fd) +{ + return fchdir(fd); +} +#endif + + + int fcntl(int fd, int cmd, long arg) +{ + if (smbw_fd(fd)) { + return smbw_fcntl(fd, cmd, arg); + } + + return real_fcntl(fd, cmd, arg); +} + + +#ifdef HAVE___FCNTL + int __fcntl(int fd, int cmd, long arg) +{ + return fcntl(fd, cmd, arg); +} +#elif HAVE__FCNTL + int _fcntl(int fd, int cmd, long arg) +{ + return fcntl(fd, cmd, arg); +} +#endif + + + +#ifdef real_getdents + int getdents(int fd, void *dirp, unsigned int count) +{ + if (smbw_fd(fd)) { + return smbw_getdents(fd, dirp, count); + } + + return real_getdents(fd, dirp, count); +} +#endif + +#ifdef HAVE___GETDENTS + int __getdents(int fd, void *dirp, unsigned int count) +{ + return getdents(fd, dirp, count); +} +#elif HAVE__GETDENTS + int _getdents(int fd, void *dirp, unsigned int count) +{ + return getdents(fd, dirp, count); +} +#endif + + + off_t lseek(int fd, off_t offset, int whence) +{ + if (smbw_fd(fd)) { + return smbw_lseek(fd, offset, whence); + } + + return real_lseek(fd, offset, whence); +} + +#ifdef HAVE___LSEEK + off_t __lseek(int fd, off_t offset, int whence) +{ + return lseek(fd, offset, whence); +} +#elif HAVE__LSEEK + off_t _lseek(int fd, off_t offset, int whence) +{ + return lseek(fd, offset, whence); +} +#endif + + + ssize_t read(int fd, void *buf, size_t count) +{ + if (smbw_fd(fd)) { + return smbw_read(fd, buf, count); + } + + return real_read(fd, buf, count); +} + +#ifdef HAVE___READ + ssize_t __read(int fd, void *buf, size_t count) +{ + return read(fd, buf, count); +} +#elif HAVE__READ + ssize_t _read(int fd, void *buf, size_t count) +{ + return read(fd, buf, count); +} +#endif + + + ssize_t write(int fd, void *buf, size_t count) +{ + if (smbw_fd(fd)) { + return smbw_write(fd, buf, count); + } + + return real_write(fd, buf, count); +} + +#ifdef HAVE___WRITE + ssize_t __write(int fd, void *buf, size_t count) +{ + return write(fd, buf, count); +} +#elif HAVE__WRITE + ssize_t _write(int fd, void *buf, size_t count) +{ + return write(fd, buf, count); +} +#endif + + + + int access(char *name, int mode) +{ + if (smbw_path(name)) { + return smbw_access(name, mode); + } + + return real_access(name, mode); +} + + + + int chmod(char *name,mode_t mode) +{ + if (smbw_path(name)) { + return smbw_chmod(name, mode); + } + + return real_chmod(name, mode); +} + + + + int chown(char *name,uid_t owner, gid_t group) +{ + if (smbw_path(name)) { + return smbw_chown(name, owner, group); + } + + return real_chown(name, owner, group); +} + + + char *getcwd(char *buf, size_t size) +{ + return (char *)smbw_getcwd(buf, size); +} + + + + + int mkdir(char *name, mode_t mode) +{ + if (smbw_path(name)) { + return smbw_mkdir(name, mode); + } + + return real_mkdir(name, mode); +} + + +#if HAVE___FXSTAT + int __fxstat(int vers, int fd, void *st) +{ + double xx[32]; + int ret; + + if (smbw_fd(fd)) { + return smbw_fstat(fd, st); + } + + ret = real_fstat(fd, xx); + xstat_convert(vers, st, xx); + return ret; +} +#endif + +#if HAVE___XSTAT + int __xstat(int vers, char *name, void *st) +{ + double xx[32]; + int ret; + + if (smbw_path(name)) { + return smbw_stat(name, st); + } + + ret = real_stat(name, xx); + xstat_convert(vers, st, xx); + return ret; +} +#endif + + +#if HAVE___LXSTAT + int __lxstat(int vers, char *name, void *st) +{ + double xx[32]; + int ret; + + if (smbw_path(name)) { + return smbw_stat(name, st); + } + + ret = real_lstat(name, xx); + xstat_convert(vers, st, xx); + return ret; +} +#endif + + + int stat(char *name, void *st) +{ +#if HAVE___XSTAT + return __xstat(0, name, st); +#else + if (smbw_path(name)) { + return smbw_stat(name, st); + } + return real_stat(name, st); +#endif +} + + int lstat(char *name, void *st) +{ +#if HAVE___LXSTAT + return __lxstat(0, name, st); +#else + if (smbw_path(name)) { + return smbw_stat(name, st); + } + return real_lstat(name, st); +#endif +} + + int fstat(int fd, void *st) +{ +#if HAVE___LXSTAT + return __fxstat(0, fd, st); +#else + if (smbw_fd(fd)) { + return smbw_fstat(fd, st); + } + return real_fstat(fd, st); +#endif +} + + + int unlink(char *name) +{ + if (smbw_path(name)) { + return smbw_unlink(name); + } + + return real_unlink(name); +} + + +#ifdef HAVE_UTIME + int utime(char *name,void *tvp) +{ + if (smbw_path(name)) { + return smbw_utime(name, tvp); + } + + return real_utime(name, tvp); +} +#endif + +#ifdef HAVE_UTIMES + int utimes(const char *name, const struct timeval *tvp) +{ + if (smbw_path(name)) { + return smbw_utimes(name, tvp); + } + + return real_utimes(name, tvp); +} +#endif + + int readlink(char *path, char *buf, size_t bufsize) +{ + if (smbw_path(path)) { + return smbw_readlink(path, buf, bufsize); + } + + return real_readlink(path, buf, bufsize); +} + + + int rename(char *oldname,char *newname) +{ + int p1, p2; + p1 = smbw_path(oldname); + p2 = smbw_path(newname); + if (p1 ^ p2) { + /* can't cross filesystem boundaries */ + errno = EXDEV; + return -1; + } + if (p1 && p2) { + return smbw_rename(oldname, newname); + } + + return real_rename(oldname, newname); +} + + int rmdir(char *name) +{ + if (smbw_path(name)) { + return smbw_rmdir(name); + } + + return real_rmdir(name); +} + + + int symlink(char *topath,char *frompath) +{ + int p1, p2; + p1 = smbw_path(topath); + p2 = smbw_path(frompath); + if (p1 || p2) { + /* can't handle symlinks */ + errno = EPERM; + return -1; + } + + return real_symlink(topath, frompath); +} + + int dup(int fd) +{ + if (smbw_fd(fd)) { + return smbw_dup(fd); + } + + return real_dup(fd); +} + + int dup2(int oldfd, int newfd) +{ + if (smbw_fd(newfd)) { + close(newfd); + } + + if (smbw_fd(oldfd)) { + return smbw_dup2(oldfd, newfd); + } + + return real_dup2(oldfd, newfd); +} + +#ifdef real_opendir + void *opendir(char *name) +{ + if (smbw_path(name)) { + return (void *)smbw_opendir(name); + } + + return (void *)real_opendir(name); +} +#endif + +#ifdef real_readdir + void *readdir(void *dir) +{ + if (smbw_dirp(dir)) { + return (void *)smbw_readdir(dir); + } + + return (void *)real_readdir(dir); +} +#endif + +#ifdef real_closedir + int closedir(void *dir) +{ + if (smbw_dirp(dir)) { + return smbw_closedir(dir); + } + + return real_closedir(dir); +} +#endif + +#ifdef real_telldir + off_t telldir(void *dir) +{ + if (smbw_dirp(dir)) { + return smbw_telldir(dir); + } + + return real_telldir(dir); +} +#endif + +#ifdef real_seekdir + int seekdir(void *dir, off_t offset) +{ + if (smbw_dirp(dir)) { + smbw_seekdir(dir, offset); + return 0; + } + + real_seekdir(dir, offset); + return 0; +} +#endif + + +#ifndef NO_ACL_WRAPPER + int acl(char *pathp, int cmd, int nentries, void *aclbufp) +{ + if (smbw_path(pathp)) { + return smbw_acl(pathp, cmd, nentries, aclbufp); + } + + return real_acl(pathp, cmd, nentries, aclbufp); +} +#endif + +#ifndef NO_FACL_WRAPPER + int facl(int fd, int cmd, int nentries, void *aclbufp) +{ + if (smbw_fd(fd)) { + return smbw_facl(fd, cmd, nentries, aclbufp); + } + + return real_facl(fd, cmd, nentries, aclbufp); +} +#endif + + int creat(char *path, mode_t mode) +{ + extern int creat_bits; + return open(path, creat_bits, mode); +} + +#ifdef HAVE_CREAT64 + int creat64(char *path, mode_t mode) +{ + extern int creat_bits; + return open64(path, creat_bits, mode); +} +#endif + +#ifdef HAVE_STAT64 + int stat64(char *name, void *st64) +{ + if (smbw_path(name)) { + double xx[32]; + int ret = stat(name, xx); + stat64_convert(xx, st64); + return ret; + } + return real_stat64(name, st64); +} + + int fstat64(int fd, void *st64) +{ + if (smbw_fd(fd)) { + double xx[32]; + int ret = fstat(fd, xx); + stat64_convert(xx, st64); + return ret; + } + return real_fstat64(fd, st64); +} + + int lstat64(char *name, void *st64) +{ + if (smbw_path(name)) { + double xx[32]; + int ret = lstat(name, xx); + stat64_convert(xx, st64); + return ret; + } + return real_lstat64(name, st64); +} +#endif + +#ifdef HAVE_LLSEEK + offset_t llseek(int fd, offset_t ofs, int whence) +{ + if (smbw_fd(fd)) { + return lseek(fd, ofs, whence); + } + return real_llseek(fd, ofs, whence); +} +#endif + +#ifdef HAVE_READDIR64 + void *readdir64(void *dir) +{ + if (smbw_dirp(dir)) { + static double xx[70]; + void *d; + d = (void *)readdir(dir); + if (!d) return NULL; + dirent64_convert(d, xx); + return xx; + } + return (void *)real_readdir64(dir); +} +#endif + + int fork(void) +{ + return smbw_fork(); +} + |