summaryrefslogtreecommitdiff
path: root/source4/ntvfs/posix/pvfs_resolve.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-10-26 05:39:54 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:04:45 -0500
commite9820e1b6e62240c5a18fa85e38a99685beed2df (patch)
tree888af697a28788ad89a2c43be1bf0d13799c3785 /source4/ntvfs/posix/pvfs_resolve.c
parent84bbf02e95639536c34140906aa4652ad61ea2c3 (diff)
downloadsamba-e9820e1b6e62240c5a18fa85e38a99685beed2df.tar.gz
samba-e9820e1b6e62240c5a18fa85e38a99685beed2df.tar.bz2
samba-e9820e1b6e62240c5a18fa85e38a99685beed2df.zip
r3240: - update the rules for what error codes should be given on the
different type of unlink an seach mismatches - wildcard directory listings that have attribute FILE_ATTRIBUTE_DIRECTORY and match "." or ".." should be failed. - don't set the write_time on SMBclose unless it is non-zero - added much better support for setfileinfo and setpathinfo in pvfs - better (and more efficient) handling of .. and . components in filenames (This used to be commit 9305b07af395a158cb9f0c1c9486f7122c79d357)
Diffstat (limited to 'source4/ntvfs/posix/pvfs_resolve.c')
-rw-r--r--source4/ntvfs/posix/pvfs_resolve.c116
1 files changed, 107 insertions, 9 deletions
diff --git a/source4/ntvfs/posix/pvfs_resolve.c b/source4/ntvfs/posix/pvfs_resolve.c
index 271dbc2b9a..a7a693b217 100644
--- a/source4/ntvfs/posix/pvfs_resolve.c
+++ b/source4/ntvfs/posix/pvfs_resolve.c
@@ -194,7 +194,6 @@ static NTSTATUS pvfs_unix_path(struct pvfs_state *pvfs, const char *cifs_name,
{
char *ret, *p, *p_start;
size_t len;
- int num_components=0;
name->original_name = talloc_strdup(name, cifs_name);
name->stream_name = NULL;
@@ -242,7 +241,6 @@ static NTSTATUS pvfs_unix_path(struct pvfs_state *pvfs, const char *cifs_name,
return NT_STATUS_ILLEGAL_CHARACTER;
}
*p = '/';
- num_components++;
break;
case ':':
if (!(flags & PVFS_RESOLVE_STREAMS)) {
@@ -268,14 +266,19 @@ static NTSTATUS pvfs_unix_path(struct pvfs_state *pvfs, const char *cifs_name,
case '|':
return NT_STATUS_ILLEGAL_CHARACTER;
case '.':
- if (p[1] != '.' ||
- (p[2] != '\\' && p[2] != 0) ||
- (p != p_start && p[-1] != '/')) {
- break;
+ /* see if it is definately a .. or
+ . component. If it is then fail here, and
+ let the next layer up try again after
+ pvfs_reduce_name() if it wants to. This is
+ much more efficient on average than always
+ scanning for these separately */
+ if (p[1] == '.' &&
+ (p[2] == 0 || p[2] == '\\') &&
+ (p == p_start || p[-1] == '/')) {
+ return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
}
- /* its definately a .. component */
- num_components--;
- if (num_components <= 0) {
+ if ((p[1] == 0 || p[1] == '\\') &&
+ (p == p_start || p[-1] == '/')) {
return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
}
break;
@@ -291,6 +294,92 @@ static NTSTATUS pvfs_unix_path(struct pvfs_state *pvfs, const char *cifs_name,
/*
+ reduce a name that contains .. components or repeated \ separators
+ return NULL if it can't be reduced
+*/
+const char *pvfs_reduce_name(TALLOC_CTX *mem_ctx, const char *fname)
+{
+ codepoint_t c;
+ size_t c_size, len;
+ int i, num_components;
+ char **components;
+ char *p, *s, *ret;
+
+ s = talloc_strdup(mem_ctx, fname);
+ if (s == NULL) return NULL;
+
+ for (num_components=1, p=s; *p; p += c_size) {
+ c = next_codepoint(p, &c_size);
+ if (c == '\\') num_components++;
+ }
+ if (num_components < 2) {
+ talloc_free(s);
+ return NULL;
+ }
+
+ components = talloc_array_p(s, char *, num_components+1);
+ if (components == NULL) {
+ talloc_free(s);
+ return NULL;
+ }
+
+ components[0] = s;
+ for (i=0, p=s; *p; p += c_size) {
+ c = next_codepoint(p, &c_size);
+ if (c == '\\') {
+ *p = 0;
+ components[++i] = p+1;
+ }
+ }
+ components[i+1] = NULL;
+
+ /* remove any null components */
+ for (i=0;components[i];i++) {
+ if (strcmp(components[i], "") == 0 ||
+ strcmp(components[i], ".") == 0) {
+ memmove(&components[i], &components[i+1],
+ sizeof(char *)*(num_components-i));
+ i--;
+ }
+ if (strcmp(components[i], "..") == 0) {
+ if (i < 1) return NULL;
+ memmove(&components[i-1], &components[i+1],
+ sizeof(char *)*(num_components-(i+1)));
+ i -= 2;
+ }
+ }
+
+ if (components[0] == NULL) {
+ talloc_free(s);
+ return talloc_strdup(mem_ctx, "\\");
+ }
+
+ for (len=i=0;components[i];i++) {
+ len += strlen(components[i]) + 1;
+ }
+
+ /* rebuild the name */
+ ret = talloc(mem_ctx, len+1);
+ if (ret == NULL) {
+ talloc_free(s);
+ return NULL;
+ }
+
+ for (len=0,i=0;components[i];i++) {
+ size_t len1 = strlen(components[i]);
+ ret[len] = '\\';
+ memcpy(ret+len+1, components[i], len1);
+ len += len1 + 1;
+ }
+ ret[len] = 0;
+
+ talloc_free(s);
+
+ return ret;
+}
+
+
+/*
resolve a name from relative client format to a struct pvfs_filename
the memory for the filename is made as a talloc child of 'name'
@@ -316,6 +405,15 @@ NTSTATUS pvfs_resolve_name(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
/* do the basic conversion to a unix formatted path,
also checking for allowable characters */
status = pvfs_unix_path(pvfs, cifs_name, flags, *name);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD)) {
+ /* it might contain .. components which need to be reduced */
+ cifs_name = pvfs_reduce_name(*name, cifs_name);
+ if (cifs_name) {
+ status = pvfs_unix_path(pvfs, cifs_name, flags, *name);
+ }
+ }
+
if (!NT_STATUS_IS_OK(status)) {
return status;
}