r12194: Ensure that when we set a connection path we've canonicalized
authorJeremy Allison <jra@samba.org>
Mon, 12 Dec 2005 18:21:59 +0000 (18:21 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 16:05:48 +0000 (11:05 -0500)
the name (must be abolute - start with /, must not end in /,
must have ./ and ../ removed). Of course for realpath resolved
paths this won't be the case but for others we need this name
to be canonicalized. This name is going into the sharemode db
for #3303 so needs to be in a normalized format.
Jeremy.
(This used to be commit 22e3300911809692b595f49e87d91e3111923e6a)

source3/smbd/msdfs.c
source3/smbd/posix_acls.c
source3/smbd/reply.c
source3/smbd/service.c

index a4f371b18ffa0a418ff88ccff1a694fe806d1929..1279fe185d20f60c0e0d22e3a41c0467bbb0915e 100644 (file)
@@ -146,7 +146,7 @@ static BOOL create_conn_struct(connection_struct *conn, int snum, char *path)
                 return False;
         }
        
-       string_set(&conn->connectpath, connpath);
+       set_conn_connectpath(conn, connpath);
 
        if (!smbd_vfs_init(conn)) {
                DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
index 91a3f5ed481de25eba150d06fd51a4376ab014c6..1b8e1d62143094766a8ef2d23cffdab0a1d67865 100644 (file)
@@ -4220,7 +4220,7 @@ SEC_DESC* get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
        connection_struct conn;
        files_struct finfo;
        struct fd_handle fh;
-       fstring path;
+       pstring path;
        pstring filename;
        
        ZERO_STRUCT( conn );
@@ -4231,8 +4231,8 @@ SEC_DESC* get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
                return NULL;
        }
        
-       fstrcpy( path, "/" );
-       string_set(&conn.connectpath, path);
+       pstrcpy( path, "/" );
+       set_conn_connectpath(&conn, path);
        
        if (!smbd_vfs_init(&conn)) {
                DEBUG(0,("novfs_get_nt_acl: Unable to create a fake connection struct!\n"));
index 81240fcb92de7475ed3876cb15fdb3aec9c9849f..d3739c8847f585badc985d0204cbdc3f2bcf91fc 100644 (file)
@@ -4954,7 +4954,7 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        } else {
                ok = vfs_directory_exist(conn,newdir,NULL);
                if (ok)
-                       string_set(&conn->connectpath,newdir);
+                       set_conn_connectpath(conn,newdir);
        }
   
        if (!ok) {
index 52f9229ee1c7f59c877cc8a4e77c3de61d0581ab..210edde5d8fd20367625b335244e5e4e30e1a17e 100644 (file)
 extern struct timeval smb_last_time;
 extern userdom_struct current_user_info;
 
+/****************************************************************************
+ Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
+ absolute path stating in / and not ending in /.
+ Observent people will notice a similarity between this and check_path_syntax :-).
+****************************************************************************/
+
+void set_conn_connectpath(connection_struct *conn, const pstring connectpath)
+{
+       pstring destname;
+       char *d = destname;
+       const char *s = connectpath;
+        BOOL start_of_name_component = True;
+
+       *d++ = '/'; /* Always start with root. */
+
+       while (*s) {
+               if (*s == '/') {
+                       /* Eat multiple '/' */
+                       while (*s == '/') {
+                                s++;
+                        }
+                       if ((d != destname) && (*s != '\0')) {
+                               *d++ = '/';
+                       }
+                       start_of_name_component = True;
+                       continue;
+               }
+
+               if (start_of_name_component) {
+                       if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) {
+                               /* Uh oh - "/../" or "/..\0" ! */
+
+                               /* Go past the ../ or .. */
+                               if (s[2] == '/') {
+                                       s += 3;
+                               } else {
+                                       s += 2; /* Go past the .. */
+                               }
+
+                               /* If  we just added a '/' - delete it */
+                               if ((d > destname) && (*(d-1) == '/')) {
+                                       *(d-1) = '\0';
+                                       d--;
+                               }
+
+                               /* Are we at the start ? Can't go back further if so. */
+                               if (d <= destname) {
+                                       *d++ = '/'; /* Can't delete root */
+                                       continue;
+                               }
+                               /* Go back one level... */
+                               /* Decrement d first as d points to the *next* char to write into. */
+                               for (d--; d > destname; d--) {
+                                       if (*d == '/') {
+                                               break;
+                                       }
+                               }
+                               /* We're still at the start of a name component, just the previous one. */
+                               continue;
+                       } else if ((s[0] == '.') && ((s[1] == '\0') || s[1] == '/')) {
+                               /* Component of pathname can't be "." only - skip the '.' . */
+                               if (s[1] == '/') {
+                                       s += 2;
+                               } else {
+                                       s++;
+                               }
+                               continue;
+                       }
+               }
+
+               if (!(*s & 0x80)) {
+                       *d++ = *s++;
+               } else {
+                       switch(next_mb_char_size(s)) {
+                               case 4:
+                                       *d++ = *s++;
+                               case 3:
+                                       *d++ = *s++;
+                               case 2:
+                                       *d++ = *s++;
+                               case 1:
+                                       *d++ = *s++;
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               start_of_name_component = False;
+       }
+       *d = '\0';
+
+       /* And must not end in '/' */
+       if (d > destname + 1 && (*(d-1) == '/')) {
+               *(d-1) = '\0';
+       }
+
+       string_set(&conn->connectpath, destname);
+}
+
 /****************************************************************************
  Load parameters specific to a connection/service.
 ****************************************************************************/
@@ -474,7 +573,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
                pstring s;
                pstrcpy(s,lp_pathname(snum));
                standard_sub_conn(conn,s,sizeof(s));
-               string_set(&conn->connectpath,s);
+               set_conn_connectpath(conn,s);
                DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
        }
 
@@ -537,7 +636,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
                pstring s;
                pstrcpy(s,conn->connectpath);
                canonicalize_path(conn, s);
-               string_set(&conn->connectpath,s);
+               set_conn_connectpath(conn,s);
        }
 
 /* ROOT Activities: */ 
@@ -652,7 +751,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
                pstring s;
                pstrcpy(s,conn->connectpath);
                vfs_GetWd(conn,s);
-               string_set(&conn->connectpath,s);
+               set_conn_connectpath(conn,s);
                vfs_ChDir(conn,conn->connectpath);
        }
 #endif