r2194: Here is the efforts of much pain reproducing W2K3 pathname
authorJeremy Allison <jra@samba.org>
Thu, 2 Sep 2004 22:35:36 +0000 (22:35 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:52:35 +0000 (10:52 -0500)
parsing. :-(. One more check for CreateFile() needed.
Jeremy.

source/smbd/reply.c
source/smbd/trans2.c

index 30616a66fbfc98bda835e7a3c071a416929d9002..b20b0fe922abc5f3c0e1d92df126f4c1d8deacac 100644 (file)
@@ -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;
 }
index f3176940c2fc109b6d83e4044bffce32a8b589b6..0a6ff04ad251df873243abdee6d3108dab63c5ed 100644 (file)
@@ -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);
        }