From 649e1274c7e5992b34125c5df507d5f50903729d Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 2 Sep 2004 22:35:36 +0000 Subject: r2194: Here is the efforts of much pain reproducing W2K3 pathname parsing. :-(. One more check for CreateFile() needed. Jeremy. (This used to be commit 294e2021b34c806900ec65ecbf17d9038ac6229a) --- source3/smbd/reply.c | 154 +++++++++++++++++++++++++++----------------------- source3/smbd/trans2.c | 5 ++ 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); } -- cgit