summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/smbd/reply.c154
-rw-r--r--source3/smbd/trans2.c5
2 files changed, 87 insertions, 72 deletions
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 30616a66fb..b20b0fe922 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -48,6 +48,7 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname, BOOL allow_w
char *d = destname;
const char *s = srcname;
NTSTATUS ret = NT_STATUS_OK;
+ BOOL start_of_name_component = True;
while (*s) {
if (IS_DIRECTORY_SEP(*s)) {
@@ -58,100 +59,109 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname, BOOL allow_w
while (IS_DIRECTORY_SEP(*s)) {
s++;
}
- if ((s[0] == '.') && (s[1] == '\0')) {
- ret = NT_STATUS_OBJECT_NAME_INVALID;
- break;
- }
if ((d != destname) && (*s != '\0')) {
/* We only care about non-leading or trailing '/' or '\\' */
*d++ = '/';
}
- } else if ((s[0] == '.') && (s[1] == '.') && (IS_DIRECTORY_SEP(s[2]) || s[2] == '\0')) {
- /* Uh oh - "../" or "..\\" or "..\0" ! */
- /*
- * No mb char starts with '.' so we're safe checking the directory separator here.
- */
+ start_of_name_component = True;
+ continue;
+ }
- /* If we just added a '/', delete it. */
+ if (start_of_name_component) {
+ if ((s[0] == '.') && (s[1] == '.') && (IS_DIRECTORY_SEP(s[2]) || s[2] == '\0')) {
+ /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
- if ((d > destname) && (*(d-1) == '/')) {
- *(d-1) = '\0';
- if (d == (destname + 1)) {
+ /*
+ * No mb char starts with '.' so we're safe checking the directory separator here.
+ */
+
+ /* If we just added a '/' - delete it */
+ if ((d > destname) && (*(d-1) == '/')) {
+ *(d-1) = '\0';
d--;
- } else {
- d -= 2;
}
- }
- /* Are we at the start ? Can't go back further if so. */
- if (d == destname) {
- ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
- break;
- }
- /* Go back one level... */
- /* We know this is safe as '/' cannot be part of a mb sequence. */
- /* NOTE - if this assumption is invalid we are not in good shape... */
- while (d > destname) {
- if (*d == '/')
+
+ /* Are we at the start ? Can't go back further if so. */
+ if (d <= destname) {
+ ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
break;
- d--;
- }
- s += 3;
- } else if ((s[0] == '.') && (s[1] == '\0')) {
- if (s == srcname) {
- ret = NT_STATUS_OBJECT_NAME_INVALID;
+ }
+ /* Go back one level... */
+ /* We know this is safe as '/' cannot be part of a mb sequence. */
+ /* NOTE - if this assumption is invalid we are not in good shape... */
+ /* Decrement d first as d points to the *next* char to write into. */
+ for (d--; d > destname; d--) {
+ if (*d == '/')
+ break;
+ }
+ s += 2; /* Else go past the .. */
+ /* We're still at the start of a name component, just the previous one. */
+ continue;
+
+ } else if ((s[0] == '.') && (s[1] == '\0')) {
+ /* Component of pathname can't be "." only. */
+ ret = NT_STATUS_OBJECT_NAME_INVALID;
break;
- }
- *d++ = *s++;
- } else if ((s[0] == '.') && IS_DIRECTORY_SEP(s[1])) {
- /*
- * No mb char starts with '.' so we're safe checking the directory separator here.
- */
+ } else if ((s[0] == '.') && IS_DIRECTORY_SEP(s[1])) {
+ /*
+ * No mb char starts with '.' so we're safe checking the directory separator here.
+ */
- /* "./" or ".\\" fails with a different error depending on what is after it... */
+ /* Component of pathname can't be ".\\ANYTHING". */
- if (s[2] == '\0') {
- ret = NT_STATUS_OBJECT_NAME_INVALID;
- } else {
- ret = NT_STATUS_OBJECT_PATH_NOT_FOUND;
- }
- break;
- } else {
- if (!(*s & 0x80)) {
- if (allow_wcard_names) {
- *d++ = *s++;
+ /* "/./" or "\\.\\" fails with a different error depending on what is after it... */
+
+ /* Eat multiple '/' or '\\' */
+ for (s++; IS_DIRECTORY_SEP(*s); s++) {
+ ;
+ }
+
+ if (*s == '\0') {
+ ret = NT_STATUS_OBJECT_NAME_INVALID;
} else {
- switch (*s) {
- case '*':
- case '?':
- case '<':
- case '>':
- case '"':
- return NT_STATUS_OBJECT_NAME_INVALID;
- default:
- *d++ = *s++;
- break;
- }
+ ret = NT_STATUS_OBJECT_PATH_NOT_FOUND;
}
+ break;
+ }
+ }
+
+ if (!(*s & 0x80)) {
+ if (allow_wcard_names) {
+ *d++ = *s++;
} else {
- switch(next_mb_char_size(s)) {
- case 4:
- *d++ = *s++;
- case 3:
- *d++ = *s++;
- case 2:
- *d++ = *s++;
- case 1:
+ switch (*s) {
+ case '*':
+ case '?':
+ case '<':
+ case '>':
+ case '"':
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ default:
*d++ = *s++;
break;
- default:
- DEBUG(0,("check_path_syntax: character length assumptions invalid !\n"));
- *d = '\0';
- return NT_STATUS_INVALID_PARAMETER;
}
}
+ } 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:
+ DEBUG(0,("check_path_syntax: character length assumptions invalid !\n"));
+ *d = '\0';
+ return NT_STATUS_INVALID_PARAMETER;
+ }
}
+ start_of_name_component = False;
}
+
*d = '\0';
return ret;
}
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index f3176940c2..0a6ff04ad2 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -1381,6 +1381,11 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
srvstr_get_path(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus, True);
if (!NT_STATUS_IS_OK(ntstatus)) {
+ /* W2k3 never seems to return OBJECT_PATH_NOT_FOUND on a
+ bad pathname parse in a findfirst, but always OBJECT_NAME_INVALID. JRA */
+ /* It remains to be seen what it does on CreateFile(). JRA. (ie. I need to check) */
+ if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND,ntstatus))
+ return ERROR_NT(NT_STATUS_OBJECT_NAME_INVALID);
return ERROR_NT(ntstatus);
}