r656: Make widelinks use realpath(). Tidy up cases where we need to become a service.
authorJeremy Allison <jra@samba.org>
Thu, 13 May 2004 00:20:50 +0000 (00:20 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:51:33 +0000 (10:51 -0500)
Jeremy.

source/configure.in
source/smbd/conn.c
source/smbd/filename.c
source/smbd/process.c
source/smbd/service.c
source/smbd/vfs.c

index f4383ea337bdd946628fdeae4c6e8c876eddce47..7d6cfee111538ffc085de5ee24f28d22f62c0853 100644 (file)
@@ -2277,7 +2277,21 @@ if test x"$samba_cv_BROKEN_NISPLUS_INCLUDE_FILES" = x"yes"; then
        AC_DEFINE(BROKEN_NISPLUS_INCLUDE_FILES,1,[Whether the nisplus include files are broken])
 fi
 
+AC_CACHE_CHECK([if the realpath function allows a NULL argument],samba_cv_REALPATH_TAKES_NULL,[
+AC_TRY_RUN([
+#include <stdio.h>
+#include <limits.h>
+main() {
+       char *newpath = realpath("/tmp", NULL);
+       exit ((newpath != NULL) ? 0 : 1);
+}
+],
+samba_cv_REALPATH_TAKES_NULL=yes,samba_cv_REALPATH_TAKES_NULL=no,samba_cv_REALPATH_TAKES_NULL=cross)])
+if test x"$samba_cv_REALPATH_TAKES_NULL" = x"yes"; then
+    AC_DEFINE(REALPATH_TAKES_NULL,1,[Whether the realpath function allows NULL])
+fi
 
+A
 #################################################
 # check for smbwrapper support
 AC_MSG_CHECKING(whether to use smbwrapper)
index 9bac0acdb9fd3b6e622e26a6f2211bffade5e896..e083e144263a27b0c26ea90aa49494236e2f7682 100644 (file)
@@ -161,6 +161,7 @@ void conn_close_all(void)
        connection_struct *conn, *next;
        for (conn=Connections;conn;conn=next) {
                next=conn->next;
+               set_current_service(conn, True);
                close_cnum(conn, conn->vuid);
        }
 }
index 692c7f7610aa60aea92e42e05bbd974d478be82d..a7223e7527e8a1a30597b1cb700352908b3045cd 100644 (file)
@@ -399,7 +399,7 @@ BOOL check_name(pstring name,connection_struct *conn)
        }
 
        if (!lp_widelinks(SNUM(conn))) {
-               ret = reduce_name(conn,name,conn->connectpath);
+               ret = reduce_name(conn,name);
        }
 
        /* Check if we are allowing users to follow symlinks */
index 966bb63c1eac5bb07f22bb6092f935330ff5eeae..d0dfc6dd7dbb01c2c9d5783f45b7898c2411959f 100644 (file)
@@ -344,6 +344,7 @@ force write permissions on print services.
 #define CAN_IPC (1<<3)
 #define AS_GUEST (1<<5)
 #define QUEUE_IN_OPLOCK (1<<6)
+#define DO_CHDIR (1<<7)
 
 /* 
    define a list of possible SMB messages and their corresponding
@@ -373,7 +374,7 @@ static const struct smb_message_struct {
 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER | QUEUE_IN_OPLOCK },
 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER}, 
 /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
-/* 0x11 */ { "SMBexit",reply_exit,0},
+/* 0x11 */ { "SMBexit",reply_exit,DO_CHDIR},
 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
@@ -469,7 +470,7 @@ static const struct smb_message_struct {
 /* 0x6e */ { NULL, NULL, 0 },
 /* 0x6f */ { NULL, NULL, 0 },
 /* 0x70 */ { "SMBtcon",reply_tcon,0},
-/* 0x71 */ { "SMBtdis",reply_tdis,0},
+/* 0x71 */ { "SMBtdis",reply_tdis,DO_CHDIR},
 /* 0x72 */ { "SMBnegprot",reply_negprot,0},
 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup_and_X,0},
 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
@@ -754,7 +755,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
                        return(ERROR_DOS(ERRSRV,ERRaccess));        
 
                /* load service specific parameters */
-               if (conn && !set_current_service(conn,(flags & AS_USER)?True:False))
+               if (conn && !set_current_service(conn,(flags & (AS_USER|DO_CHDIR)?True:False)))
                        return(ERROR_DOS(ERRSRV,ERRaccess));
 
                /* does this protocol need to be run as guest? */
index 93b017e94c729989407e39db35d8b4a58762d004..04cade9577965fdc43d2ebc4f184fa3c76044145 100644 (file)
@@ -788,6 +788,9 @@ void close_cnum(connection_struct *conn, uint16 vuid)
 {
        DirCacheFlush(SNUM(conn));
 
+       file_close_conn(conn);
+       dptr_closecnum(conn);
+
        change_to_root_user();
 
        DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
@@ -799,9 +802,6 @@ void close_cnum(connection_struct *conn, uint16 vuid)
 
        yield_connection(conn, lp_servicename(SNUM(conn)));
 
-       file_close_conn(conn);
-       dptr_closecnum(conn);
-
        /* make sure we leave the directory available for unmount */
        vfs_ChDir(conn, "/");
 
index 533220e7dfba0b82123995036e62fffd52d49972..0f3d591ebb7184694d12cfb0b4b3857f94ff19c3 100644 (file)
@@ -784,168 +784,123 @@ char *vfs_GetWd(connection_struct *conn, char *path)
        return (path);
 }
 
-
-/* check if the file 'nmae' is a symlink, in that case check that it point to
-   a file that reside under the 'dir' tree */
-
-static BOOL readlink_check(connection_struct *conn, const char *dir, char *name)
-{
-       BOOL ret = True;
-       pstring flink;
-       pstring cleanlink;
-       pstring savedir;
-       pstring realdir;
-       size_t reallen;
-
-       if (!vfs_GetWd(conn, savedir)) {
-               DEBUG(0,("couldn't vfs_GetWd for %s %s\n", name, dir));
-               return False;
-       }
-
-       if (vfs_ChDir(conn, dir) != 0) {
-               DEBUG(0,("couldn't vfs_ChDir to %s\n", dir));
-               return False;
-       }
-
-       if (!vfs_GetWd(conn, realdir)) {
-               DEBUG(0,("couldn't vfs_GetWd for %s\n", dir));
-               vfs_ChDir(conn, savedir);
-               return(False);
-       }
-       
-       reallen = strlen(realdir);
-       if (realdir[reallen -1] == '/') {
-               reallen--;
-               realdir[reallen] = 0;
-       }
-
-       if (SMB_VFS_READLINK(conn, name, flink, sizeof(pstring) -1) != -1) {
-               DEBUG(3,("readlink_check: file path name %s is a symlink\nChecking it's path\n", name));
-               if (*flink == '/') {
-                       pstrcpy(cleanlink, flink);
-               } else {
-                       pstrcpy(cleanlink, realdir);
-                       pstrcat(cleanlink, "/");
-                       pstrcat(cleanlink, flink);
-               }
-               unix_clean_name(cleanlink);
-
-               if (strncmp(cleanlink, realdir, reallen) != 0) {
-                       DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n", name, realdir, cleanlink, (int)reallen));
-                       ret = False;
-               }
-       }
-
-       vfs_ChDir(conn, savedir);
-       
-       return ret;
-}
-
 /*******************************************************************
  Reduce a file name, removing .. elements and checking that
- it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
- on the system that has the referenced file system.
+ it is below dir in the heirachy. This uses realpath.
 ********************************************************************/
 
-BOOL reduce_name(connection_struct *conn, pstring s, const char *dir)
+BOOL reduce_name(connection_struct *conn, pstring fname)
 {
-#ifndef REDUCE_PATHS
-       return True;
+#ifdef REALPATH_TAKES_NULL
+       BOOL free_resolved_name = True;
 #else
-       pstring dir2;
-       pstring wd;
-       pstring base_name;
-       pstring newname;
-       char *p=NULL;
-       BOOL relative = (*s != '/');
-
-       *dir2 = *wd = *base_name = *newname = 0;
-
-       DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
-
-       /* We know there are no double slashes as this comes from srvstr_get_path().
-          and has gone through check_path_syntax(). JRA */
-
-       pstrcpy(base_name,s);
-       p = strrchr_m(base_name,'/');
+#ifdef PATH_MAX
+        char resolved_name_buf[PATH_MAX+1];
+#else
+        pstring resolved_name_buf;
+#endif
+       BOOL free_resolved_name = False;
+#endif
+       char *resolved_name = NULL;
+       size_t con_path_len = strlen(conn->connectpath);
+       char *p = NULL;
 
-       if (!p)
-               return readlink_check(conn, dir, s);
+       DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
 
-       if (!vfs_GetWd(conn,wd)) {
-               DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir));
-               return(False);
-       }
+#ifdef REALPATH_TAKES_NULL
+       resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
+#else
+       resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
+#endif
 
-       if (vfs_ChDir(conn,dir) != 0) {
-               DEBUG(0,("couldn't vfs_ChDir to %s\n",dir));
-               return(False);
+       if (!resolved_name) {
+               switch (errno) {
+                       case ENOTDIR:
+                               DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
+                               return False;
+                       case ENOENT:
+                       {
+                               pstring tmp_fname;
+                               fstring last_component;
+                               /* Last component didn't exist. Remove it and try and canonicalise the directory. */
+
+                               pstrcpy(tmp_fname, fname);
+                               p = strrchr_m(tmp_fname, '/');
+                               if (p) {
+                                       *p++ = '\0';
+                                       fstrcpy(last_component, p);
+                               }
+#ifdef REALPATH_TAKES_NULL
+                               resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
+#else
+                               resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
+#endif
+                               if (!resolved_name) {
+                                       DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
+                                       return False;
+                               }
+                               pstrcpy(tmp_fname, resolved_name);
+                               pstrcat(tmp_fname, "/");
+                               pstrcat(tmp_fname, last_component);
+#ifdef REALPATH_TAKES_NULL
+                               SAFE_FREE(resolved_name);
+                               resolved_name = strdup(tmp_fname);
+                               if (!resolved_name) {
+                                       DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
+                                       return False;
+                               }
+#else
+#ifdef PATH_MAX
+                               safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
+#else
+                               pstrcpy(pstring resolved_name_buf, tmp_fname);
+#endif
+                               resolved_name = resolved_name_buf;
+#endif
+                               break;
+                       }
+                       default:
+                               DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
+                               return False;
+               }
        }
 
-       if (!vfs_GetWd(conn,dir2)) {
-               DEBUG(0,("couldn't vfs_GetWd for %s\n",dir));
-               vfs_ChDir(conn,wd);
-               return(False);
-       }
+       DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
 
-       if (p && (p != base_name)) {
-               *p = 0;
-               if (strcmp(p+1,".")==0)
-                       p[1]=0;
-               if (strcmp(p+1,"..")==0)
-                       *p = '/';
+       if (*resolved_name != '/') {
+               DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
+               if (free_resolved_name)
+                       SAFE_FREE(resolved_name);
+               return False;
        }
 
-       if (vfs_ChDir(conn,base_name) != 0) {
-               vfs_ChDir(conn,wd);
-               DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name));
-               return(False);
+       if (strncmp(conn->connectpath, resolved_name, con_path_len) != 0) {
+               DEBUG(2, ("reduce_name: Bad access attemt: %s is a symlink outside the share path", fname));
+               if (free_resolved_name)
+                       SAFE_FREE(resolved_name);
+               return False;
        }
 
-       if (!vfs_GetWd(conn,newname)) {
-               vfs_ChDir(conn,wd);
-               DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,base_name));
-               return(False);
+       /* Move path the connect path to the last part of the filename. */
+       p = resolved_name + con_path_len;
+       if (*p == '/') {
+               p++;
        }
 
-       if (p && (p != base_name)) {
-               pstrcat(newname,"/");
-               pstrcat(newname,p+1);
+       if (!*p) {
+               pstrcpy(resolved_name, ".");
+               p = resolved_name;
        }
 
-       {
-               size_t l = strlen(dir2);
-               char *last_slash = strrchr_m(dir2, '/');
-
-               if (last_slash && (last_slash[1] == '\0'))
-                       l--;
-
-               if (strncmp(newname,dir2,l) != 0) {
-                       vfs_ChDir(conn,wd);
-                       DEBUG(2,("Bad access attempt: s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
-                       return(False);
-               }
-
-               if (!readlink_check(conn, dir, newname)) {
-                       DEBUG(2, ("Bad access attemt: %s is a symlink outside the share path", s));
-                       return(False);
-               }
-
-               if (relative) {
-                       if (newname[l] == '/')
-                               pstrcpy(s,newname + l + 1);
-                       else
-                               pstrcpy(s,newname+l);
-               } else
-                       pstrcpy(s,newname);
+       if (!lp_symlinks(SNUM(conn)) && (strcmp(fname, p)!=0)) {
+               DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",fname));
+               if (free_resolved_name)
+                       SAFE_FREE(resolved_name);
+               return False;
        }
 
-       vfs_ChDir(conn,wd);
-
-       if (strlen(s) == 0)
-               pstrcpy(s,"./");
-
-       DEBUG(3,("reduced to %s\n",s));
+       DEBUG(3,("reduce_name: %s reduced to %s\n", fname, p));
+       if (free_resolved_name)
+               SAFE_FREE(resolved_name);
        return(True);
-#endif
 }