summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2005-12-12 18:21:59 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:05:48 -0500
commitfa4df827d0b7e6e280a1736fb45772ed27131e64 (patch)
tree59f3f63ce8eedb97e1988afe7491ff5b47155b48
parentc9c8781ccf14271ac4baed838b59dcad50f8b742 (diff)
downloadsamba-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.c2
-rw-r--r--source3/smbd/posix_acls.c6
-rw-r--r--source3/smbd/reply.c2
-rw-r--r--source3/smbd/service.c105
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