diff options
author | Jeremy Allison <jra@samba.org> | 2005-12-12 18:21:59 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 11:05:48 -0500 |
commit | fa4df827d0b7e6e280a1736fb45772ed27131e64 (patch) | |
tree | 59f3f63ce8eedb97e1988afe7491ff5b47155b48 | |
parent | c9c8781ccf14271ac4baed838b59dcad50f8b742 (diff) | |
download | samba-fa4df827d0b7e6e280a1736fb45772ed27131e64.tar.gz samba-fa4df827d0b7e6e280a1736fb45772ed27131e64.tar.bz2 samba-fa4df827d0b7e6e280a1736fb45772ed27131e64.zip |
r12194: Ensure that when we set a connection path we've canonicalized
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)
-rw-r--r-- | source3/smbd/msdfs.c | 2 | ||||
-rw-r--r-- | source3/smbd/posix_acls.c | 6 | ||||
-rw-r--r-- | source3/smbd/reply.c | 2 | ||||
-rw-r--r-- | source3/smbd/service.c | 105 |
4 files changed, 107 insertions, 8 deletions
diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c index a4f371b18f..1279fe185d 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -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")); diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index 91a3f5ed48..1b8e1d6214 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -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")); diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 81240fcb92..d3739c8847 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -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) { diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 52f9229ee1..210edde5d8 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -24,6 +24,105 @@ 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 |