]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
windows-handle-invalid-utf16-names-20081019
authorAsanka Herath <asanka@secure-endpoints.com>
Mon, 20 Oct 2008 00:17:41 +0000 (00:17 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Mon, 20 Oct 2008 00:17:41 +0000 (00:17 +0000)
LICENSE MIT
FIXES 116641

Windows will deliver to OpenAFS UTF16 strings that are not valid Unicode
and cannot be converted to UTF8.  Return bad file name errors in those
cases.

Make sure all file server strings once converted to UTF16 can be converted
back.  If not, escape the invalid portions of the string so that the
file can be accessed.

src/WINNT/afsd/cm_btree.c
src/WINNT/afsd/cm_dir.c
src/WINNT/afsd/cm_ioctl.c
src/WINNT/afsd/cm_nls.c
src/WINNT/afsd/cm_nls.h
src/WINNT/afsd/cm_vnodeops.c
src/WINNT/afsd/cm_volstat.c
src/WINNT/afsd/smb.c
src/WINNT/afsd/smb3.c

index c7bc2b7e75e38859f05cfb43c5fb27c34dd4e261..ea0ec3abdaa236938989b852cd8f10b62559721c 100644 (file)
@@ -1588,6 +1588,10 @@ cm_BPlusDirLookupOriginalName(cm_dirOp_t * op, clientchar_t *centry,
     }
 
     entry = cm_ClientStringToNormStringAlloc(centry, -1, NULL);
+    if (!entry) {
+        rc = EINVAL;
+        goto done;
+    }
     key.name = entry;
 
     lock_AssertAny(&op->scp->dirlock);
@@ -1680,6 +1684,10 @@ cm_BPlusDirLookup(cm_dirOp_t * op, clientchar_t * centry, cm_fid_t * cfid)
     }
 
     entry = cm_ClientStringToNormStringAlloc(centry, -1, NULL);
+    if (!entry) {
+        rc = EINVAL;
+        goto done;
+    }
     key.name = entry;
 
     lock_AssertAny(&op->scp->dirlock);
@@ -1767,6 +1775,10 @@ long cm_BPlusDirCreateEntry(cm_dirOp_t * op, clientchar_t * entry, cm_fid_t * cf
     }
 
     normalizedName = cm_ClientStringToNormStringAlloc(entry, -1, NULL);
+    if (!normalizedName) {
+        rc = EINVAL;
+        goto done;
+    }
     key.name = normalizedName;
 
     lock_AssertWrite(&op->scp->dirlock);
@@ -1833,6 +1845,10 @@ int  cm_BPlusDirDeleteEntry(cm_dirOp_t * op, clientchar_t *centry)
     }
 
     normalizedEntry = cm_ClientStringToNormStringAlloc(centry, -1, NULL);
+    if (!normalizedEntry) {
+        rc = EINVAL;
+        goto done;
+    }
     key.name = normalizedEntry;
 
     lock_AssertWrite(&op->scp->dirlock);
@@ -2000,6 +2016,12 @@ int cm_BPlusDirFoo(struct cm_scache *scp, struct cm_dirEntry *dep,
     }
 
     data.cname = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
+    if (data.cname == NULL) {
+#ifdef DEBUG
+        DebugBreak();
+#endif
+        return 0;
+    }
     data.fsname = cm_FsStrDup(dep->name);
     data.shortform = FALSE;
 
@@ -2017,10 +2039,12 @@ int cm_BPlusDirFoo(struct cm_scache *scp, struct cm_dirEntry *dep,
 
         key.name = wshortName;
         data.cname = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
-        data.fsname = cm_FsStrDup(dep->name);
-        data.shortform = TRUE;
+        if (data.cname) {
+            data.fsname = cm_FsStrDup(dep->name);
+            data.shortform = TRUE;
 
-        insert(scp->dirBplus, key, data);
+            insert(scp->dirBplus, key, data);
+        }
     }
 
     if (normalized_name)
index edc4fc58f1b3aa99bce09d84db13c57b2f60a5a3..5f2439c1e3dabbe65c51e85516653a711ea5d7b9 100644 (file)
@@ -1293,7 +1293,6 @@ cm_DirOpAddBuffer(cm_dirOp_t * op, cm_buf_t * bufferp)
                               CM_SCACHESYNC_NEEDCALLBACK |
                               (op->lockType == CM_DIRLOCK_WRITE ? CM_SCACHESYNC_WRITE : CM_SCACHESYNC_READ) |
                               CM_SCACHESYNC_BUFLOCKED);
-
             code = CM_ERROR_NOTINCACHE;
         }
 
index 1d78f0c67db560899c1da1756e1cfaa2451bac87..c24ce06b2312d17b19af4ce1db0c87428a915db7 100644 (file)
@@ -457,9 +457,13 @@ cm_IoctlGetFileCellName(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scach
             clientchar_t * cellname;
 
             cellname = cm_FsStringToClientStringAlloc(cellp->name, -1, NULL); 
+            if (cellname == NULL) {
+                code = CM_ERROR_NOSUCHCELL;
+            } else {
             cm_UnparseIoctlString(ioctlp, NULL, cellname, -1);
             free(cellname);
             code = 0;
+            }
         } else
             code = CM_ERROR_NOSUCHCELL;
     }
@@ -1354,8 +1358,12 @@ cm_IoctlGetCell(struct cm_ioctl *ioctlp, struct cm_user *userp)
         ioctlp->outDatap = basep + max * sizeof(afs_int32);
 
         cellnamep = cm_FsStringToClientStringAlloc(tcellp->name, -1, NULL);
+        if (cellnamep) {
         cm_UnparseIoctlString(ioctlp, NULL, cellnamep, -1);
         free(cellnamep);
+        } else {
+            tcellp = NULL;
+        }
     }
 
     if (tcellp) 
@@ -1452,8 +1460,12 @@ cm_IoctlGetWsCell(cm_ioctl_t *ioctlp, cm_user_t *userp)
     } else if (cm_data.rootCellp) {
         clientchar_t * cellnamep = cm_FsStringToClientStringAlloc(cm_data.rootCellp->name, -1, NULL);
         /* return the default cellname to the caller */
+        if (cellnamep) {
         cm_UnparseIoctlString(ioctlp, NULL, cellnamep, -1);
         free(cellnamep);
+    } else {
+            code = CM_ERROR_NOSUCHCELL;
+        }
     } else {
         /* if we don't know our default cell, return failure */
         code = CM_ERROR_NOSUCHCELL;
index 8d3eb215ae914a4394f377bb6bada689b8b86011..63e56e40d317495cb3a47f7f1cb687602acf98af 100644 (file)
@@ -550,6 +550,76 @@ static int sanitize_bytestring(const char * src, int cch_src,
     return (int)(dest - odest);
 }
 
+static int sanitize_utf16char(wchar_t c, wchar_t ** pdest, size_t * pcch)
+{
+    if (*pcch >= 6) {
+        StringCchPrintfExW(*pdest, *pcch, pdest, pcch, 0, L"%%%04x", (int) c);
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+static int sanitize_utf16string(const wchar_t * src, size_t cch_src,
+                                wchar_t * dest, size_t cch_dest)
+{
+    int cch_dest_o = cch_dest;
+
+    if (dest == NULL) {
+        /* only estimating */
+        for (cch_dest = 0; cch_src > 0;) {
+            if (*src >= 0xd800 && *src < 0xdc00) {
+                if (cch_src <= 1 || src[1] < 0xdc00 || src[1] > 0xdfff) {
+                    /* dangling surrogate */
+                    src++;
+                    cch_src --;
+                    cch_dest += 5;
+                } else {
+                    /* surrogate pair */
+                    src += 2;
+                    cch_src -= 2;
+                    cch_dest += 2;
+                }
+            } else if (*src >= 0xdc00 && *src <= 0xdfff) {
+                /* dangling surrogate */
+                src++;
+                cch_src --;
+                cch_dest += 5;
+            } else {
+                /* normal char */
+                src++; cch_src --;
+                cch_dest++;
+            }
+        }
+
+        return cch_dest;
+    }
+
+    while (cch_src > 0 && cch_dest > 0) {
+        if (*src >= 0xd800 && *src < 0xdc00) {
+            if (cch_src <= 1 || src[1] < 0xdc00 || src[1] > 0xdfff) {
+                if (!sanitize_utf16char(*src++, &dest, &cch_dest))
+                    return 0;
+                cch_src--;
+            } else {
+                /* found a surrogate pair */
+                *dest++ = *src++;
+                *dest++ = *src++;
+                cch_dest -= 2; cch_src -= 2;
+            }
+        } else if (*src >= 0xdc00 && *src <= 0xdfff) {
+            if (!sanitize_utf16char(*src++, &dest, &cch_dest))
+                return 0;
+            cch_src--;
+        } else {
+            *dest++ = *src++;
+            cch_dest--; cch_src--;
+        }
+    }
+
+    return (cch_src == 0) ? cch_dest_o - cch_dest : 0;
+}
+
 #undef Esc
 #undef IS_ESCAPED
 #undef ESCVAL
@@ -575,6 +645,10 @@ long cm_NormalizeUtf8StringToUtf16(const char * src, int cch_src,
         return 1;
     }
 
+    if (dest && cch_dest > 0) {
+        dest[0] = L'\0';
+    }
+
     if (cch_src == -1) {
         cch_src = strlen(src) + 1;
     }
@@ -582,6 +656,18 @@ long cm_NormalizeUtf8StringToUtf16(const char * src, int cch_src,
     cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
                               cch_src * sizeof(char), wsrcbuf, NLSMAXCCH);
 
+    if (cch != 0 && !cm_is_valid_utf16(wsrcbuf, cch)) {
+        wchar_t wsanitized[NLSMAXCCH];
+
+        /* We successfully converted, but the resulting UTF-16 string
+           has dangling surrogates.  We should try and escape those
+           next.  */
+        cch = sanitize_utf16string(wsrcbuf, cch, wsanitized, NLSMAXCCH);
+        if (cch != 0) {
+            memcpy(wsrcbuf, wsanitized, cch * sizeof(wchar_t));
+        }
+    }
+
     if (cch == 0) {
         if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
             char sanitized[NLSMAXCCH];
@@ -665,6 +751,18 @@ cm_normchar_t *cm_NormalizeUtf8StringToUtf16Alloc(const cm_utf8char_t * src, int
     cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
                               cch_src * sizeof(char), wsrcbuf, NLSMAXCCH);
 
+    if (cch != 0 && !cm_is_valid_utf16(wsrcbuf, cch)) {
+        wchar_t wsanitized[NLSMAXCCH];
+
+        /* We successfully converted, but the resulting UTF-16 string
+           has dangling surrogates.  We should try and escape those
+           next.  */
+        cch = sanitize_utf16string(wsrcbuf, cch, wsanitized, NLSMAXCCH);
+        if (cch != 0) {
+            memcpy(wsrcbuf, wsanitized, cch * sizeof(wchar_t));
+        }
+    }
+
     if (cch == 0) {
         if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
             char sanitized[NLSMAXCCH];
@@ -720,6 +818,10 @@ int cm_Utf8ToUtf16(const cm_utf8char_t * src, int cch_src,
 {
     int cch;
 
+    if (cch_dest >= 1 && dest != NULL) {
+        dest[0] = L'\0';
+    }
+
     if (!nls_init)
         cm_InitNormalization();
 
@@ -730,6 +832,15 @@ int cm_Utf8ToUtf16(const cm_utf8char_t * src, int cch_src,
     cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
                               cch_src * sizeof(char), dest, cch_dest);
 
+    if (cch != 0 && !cm_is_valid_utf16(dest, cch)) {
+        wchar_t wsanitized[NLSMAXCCH];
+
+        cch = sanitize_utf16string(dest, cch, wsanitized, NLSMAXCCH);
+        if (cch != 0) {
+            memcpy(dest, wsanitized, cch * sizeof(wchar_t));
+        }
+    }
+
     if (cch == 0) {
         if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
             char sanitized[NLSMAXCCH];
@@ -838,6 +949,28 @@ cm_unichar_t  * cm_Utf8ToUtf16Alloc(const cm_utf8char_t * src, int cch_src, int
         cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
                                   cch_src * sizeof(char), ustr, cch);
         ustr[cch] = 0;
+
+        if (!cm_is_valid_utf16(ustr, cch)) {
+            cm_unichar_t * us = NULL;
+            int cch_s;
+
+            cch_s = sanitize_utf16string(ustr, cch, NULL, 0);
+            if (cch_s != 0) {
+                us = malloc(cch_s * sizeof(wchar_t));
+                cch_s = sanitize_utf16string(ustr, cch, us, cch_s);
+            }
+
+            if (cch_s != 0) {
+                free(ustr);
+                ustr = us;
+                us = NULL;
+            } else {
+                if (us)
+                    free(us);
+                free(ustr);
+                ustr = NULL;
+            }
+        }
     }
 
     if (pcch_dest)
@@ -897,6 +1030,15 @@ long cm_NormalizeUtf8String(const char * src, int cch_src,
     cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
                               cch_src * sizeof(char), wsrcbuf, NLSMAXCCH);
 
+    if (cch != 0 && !cm_is_valid_utf16(wsrcbuf, cch)) {
+        wchar_t wsanitized[NLSMAXCCH];
+
+        cch = sanitize_utf16string(wsrcbuf, cch, wsanitized, NLSMAXCCH);
+        if (cch != 0) {
+            memcpy(wsrcbuf, wsanitized, cch * sizeof(wchar_t));
+        }
+    }
+
     if (cch == 0) {
         if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
             char sanitized[NLSMAXCCH];
@@ -1265,3 +1407,49 @@ wchar_t * char_this_utf16(const wchar_t * c)
     return (wchar_t *) c;
 }
 
+int cm_is_valid_utf16(const wchar_t * c, int cch)
+{
+    if (cch < 0)
+        cch = wcslen(c) + 1;
+
+    for (; cch > 0; c++, cch--) {
+        if (*c >= 0xd800 && *c < 0xdc00) {
+            c++; cch--;
+            if (cch == 0 || *c < 0xdc00 || *c > 0xdfff)
+                return 0;
+        } else if (*c >= 0xdc00 && *c <= 0xdfff) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+#ifdef DEBUG
+wchar_t * cm_GetRawCharsAlloc(const wchar_t * c, int len)
+{
+    wchar_t * ret;
+    wchar_t * current;
+    size_t cb;
+
+    if (len == -1)
+        len = wcslen(c);
+
+    if (len == 0)
+        return wcsdup(L"(empty)");
+
+    cb = len * 5 * sizeof(wchar_t);
+    current = ret = malloc(cb);
+    if (ret == NULL)
+        return NULL;
+
+    for (; len > 0; ++c, --len) {
+        StringCbPrintfExW(current, cb, &current, &cb, 0,
+                         L"%04x", (int) *c);
+        if (len > 1)
+            StringCbCatExW(current, cb, L",", &current, &cb, 0);
+    }
+
+    return ret;
+}
+#endif
index 017d2718aec91e404fa448a227fb2751a4669008..3d7517ea5d875f1b204d4ad5395932b452cb4818 100644 (file)
@@ -132,12 +132,25 @@ typedef cm_normchar_t normchar_t;
 #define cm_NormStrCmp wcscmp
 #define cm_NormCharUpr towupper
 
+#define cm_IsValidClientString(s) cm_is_valid_utf16((s), -1)
+#define cm_IsValidNormString(s) cm_is_valid_utf16((s), -1)
+
 #define cm_Utf16ToClientString cm_Utf16ToUtf16
 
 extern long cm_InitNormalization(void);
 
 /* Functions annotated in accordance with sal.h */
 
+#ifndef __in_z
+
+#define __out_ecount_full_z(x)
+#define __out_ecount_full_z_opt(x)
+#define __in_z
+#define __out_z
+#define __inout_z
+
+#endif
+
 extern __out_ecount_full_z(*pcch_dest) __checkReturn __success(return != NULL) cm_normchar_t *
     cm_NormalizeStringAlloc
     (__in_ecount(cch_src) const cm_unichar_t * s,
@@ -254,6 +267,13 @@ cm_strlwr_utf16(__inout_z cm_unichar_t * str);
 extern __out_z cm_unichar_t *
 cm_strupr_utf16(__inout_z cm_unichar_t * str);
 
+extern int
+cm_is_valid_utf16(__in_z const wchar_t * c, int cch);
+
+#ifdef DEBUG
+wchar_t * cm_GetRawCharsAlloc(const wchar_t * c, int len);
+#endif
+
 #if 0
 
 extern long cm_NormalizeUtf16StringToUtf8(const wchar_t * src, int cch_src,
index 82b57a8ceddd6c95a024fd269b19b9be131722d7..e9d8d54d010920fbf2327511058522dcf65d34d0 100644 (file)
@@ -727,7 +727,11 @@ long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
 
     sp = (cm_lookupSearch_t *) rockp;
 
-    cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
+    if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
+        /* Can't normalize FS string. */
+        return 0;
+    }
+
     if (sp->caseFold)
         match = cm_NormStrCmpI(matchName, sp->nsearchNamep);
     else
@@ -1040,7 +1044,15 @@ long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_u
     }
 
     nnamep = cm_ClientStringToNormStringAlloc(cnamep, -1, NULL);
+    if (!nnamep) {
+        code = CM_ERROR_NOSUCHFILE;
+        goto done;
+    }
     fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
+    if (!fnamep) {
+        code = CM_ERROR_NOSUCHFILE;
+        goto done;
+    }
 
     if (flags & CM_FLAG_NOMOUNTCHASE) {
         /* In this case, we should go and call cm_Dir* functions
@@ -1235,6 +1247,7 @@ long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_u
             if (nnamep) 
                 free(nnamep);
             nnamep = cm_ClientStringToNormStringAlloc(cnamep, -1, NULL);
+            if (nnamep)
             cm_dnlcEnter(dscp, nnamep, tscp);
         }
         lock_ReleaseRead(&dscp->rw);
@@ -1755,12 +1768,19 @@ long cm_AssembleLink(cm_scache_t *linkScp, fschar_t *pathSuffixp,
         StringCchCatA(tsp->data,lengthof(tsp->data), "\\");
         StringCchCatA(tsp->data,lengthof(tsp->data), pathSuffixp);
     }
+
     if (code == 0) {
         clientchar_t * cpath = cm_FsStringToClientStringAlloc(tsp->data, -1, NULL);
+        if (cpath != NULL) {
         cm_ClientStrCpy(tsp->wdata, lengthof(tsp->wdata), cpath);
         free(cpath);
         *newSpaceBufferp = tsp;
     } else {
+            code = CM_ERROR_NOSUCHPATH;
+        }
+    } 
+
+    if (code != 0) {
         cm_FreeSpace(tsp);
 
         if (code == CM_ERROR_PATH_NOT_COVERED && reqp->tidPathp && reqp->relPathp) {
index 3f1a2f61961b993470e69b9198b3c7dee82af88c..3336aae43b4f073aa9ddd9b576fcf6991cc813f0 100644 (file)
@@ -325,6 +325,13 @@ cm_VolStatus_Path_To_ID(const char * share, const char * path, afs_uint32 * cell
     cpath = cm_FsStringToClientStringAlloc(path, -1, NULL);
     cshare = cm_FsStringToClientStringAlloc(share, -1, NULL);
 
+    if (cpath == NULL || cshare == NULL) {
+        osi_Log1(afsd_logp, "Can't convert %s string. Aborting",
+                 (cpath == NULL)? "path" : "share");
+        code = CM_ERROR_NOSUCHPATH;
+        goto done;
+    }
+
     code = cm_NameI(cm_data.rootSCachep, cpath,
                     CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                     cm_rootUserp, cshare, &req, &scp);
@@ -385,6 +392,13 @@ cm_VolStatus_Path_To_DFSlink(const char * share, const char * path, afs_uint32 *
     cpath = cm_FsStringToClientStringAlloc(path, -1, NULL);
     cshare = cm_FsStringToClientStringAlloc(share, -1, NULL);
 
+    if (cpath == NULL || cshare == NULL) {
+        osi_Log1(afsd_logp, "Can't convert %s string. Aborting",
+                 (cpath == NULL)? "path" : "share");
+        code = CM_ERROR_NOSUCHPATH;
+        goto done;
+    }
+
     code = cm_NameI(cm_data.rootSCachep, cpath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, 
                     cm_rootUserp, cshare, &req, &scp);
     if (code)
index f66cc05c5fe067e57a48fa2d3a684d1ee74a6dbe..d1d4ac980dee47ba9eec50d3b78f5f49607c3ad6 100644 (file)
@@ -1763,7 +1763,11 @@ long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
     normchar_t normName[MAX_PATH];
 
-    cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0]));
+    if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
+        osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
+                 osi_LogSaveString(smb_logp, dep->name));
+        return 0;
+    }
 
     if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
         if(!cm_ClientStrCmpI(normName, vrock->shareName))
@@ -1956,6 +1960,8 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
         thyper.LowPart = 0;
 
         vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
+        if (vrock.shareName == NULL) 
+            return 0;
         vrock.match = NULL;
         vrock.matchType = 0;
 
@@ -1996,13 +2002,14 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
         if (code == 0) {
             clientchar_t temp[1024];
 
-            cm_FsStringToClientString(ftemp, -1, temp, 1024);
+            if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
             cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
                                 rw ? _C("/.%S/") : _C("/%S/"), temp);
             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
             return 1;
         }
     }
+    }
     /* failure */
     *pathNamep = NULL;
     return 0;
@@ -4686,7 +4693,8 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     code = 0;
     returnedNames = 0;
     while (1) {
-        clientchar_t *actualName;
+        clientchar_t *actualName = NULL;
+        int           free_actualName = 0;
         clientchar_t shortName[13];
         clientchar_t *shortNameEnd;
 
@@ -4834,6 +4842,16 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
             free(actualName);
             cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
             actualName = shortName;
+            free_actualName = 0;
+        } else {
+            free_actualName = 1;
+        }
+
+        if (actualName == NULL) {
+            /* Couldn't convert the name for some reason */
+            osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
+                     osi_LogSaveString(smb_logp, dep->name));
+            goto nextEntry;
         }
 
         osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
@@ -4934,6 +4952,11 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         }      /* if we're including this name */
 
       nextEntry:
+        if (free_actualName && actualName) {
+            free(actualName);
+            actualName = NULL;
+        }
+
         /* and adjust curOffset to be where the new cookie is */
         thyper.HighPart = 0;
         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
@@ -5397,6 +5420,21 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     }
 #endif
 
+    if (!cm_IsValidClientString(pathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(pathp, -1);
+        osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
+            free(hexp);
+#else
+        osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
+#endif
+        return CM_ERROR_BADNTFILENAME;
+    }
+
     share = smb_GetSMBParm(inp, 0);
     attribute = smb_GetSMBParm(inp, 1);
 
@@ -5538,7 +5576,13 @@ int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
         caseFold |= CM_FLAG_8DOT3;
 
-    cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
+    if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
+        /* Can't convert name */
+        osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
+                 osi_LogSaveString(smb_logp, dep->name));
+        return 0;
+    }
+
     match = cm_MatchMask(matchName, rockp->maskp, caseFold);
     if (!match &&
         (rockp->flags & SMB_MASKFLAG_TILDE) &&
@@ -5584,6 +5628,7 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_req_t req;
 
     smb_InitReq(&req);
+    memset(&rock, 0, sizeof(rock));
 
     attribute = smb_GetSMBParm(inp, 0);
         
@@ -5632,6 +5677,10 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     rock.any = 0;
     rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
+    if (!rock.maskp) {
+        code = CM_ERROR_NOSUCHFILE;
+        goto done;
+    }
     rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
 
     thyper.LowPart = 0;
@@ -5672,6 +5721,8 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             osi_Log1(smb_logp, "Unlinking %s",
                      osi_LogSaveString(smb_logp, entry->name));
 
+            /* We assume this works because entry->name was
+               successfully converted in smb_UnlinkProc() once. */
             cm_FsStringToNormString(entry->name, -1,
                                     normalizedName, lengthof(normalizedName));
 
@@ -5686,10 +5737,14 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     cm_DirEntryListFree(&rock.matches);
 
+  done:
+    if (userp)
     cm_ReleaseUser(userp);
         
+    if (dscp)
     cm_ReleaseSCache(dscp);
 
+    if (rock.maskp)
     free(rock.maskp);
 
     if (code == 0 && !rock.any)
@@ -5721,7 +5776,13 @@ int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
 
     rockp = (smb_renameRock_t *) vrockp;
 
-    cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
+    if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
+        /* Can't convert string */
+        osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
+                 osi_LogSaveString(smb_logp, dep->name));
+        return 0;
+    }
+
     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
         caseFold |= CM_FLAG_8DOT3;
@@ -5775,6 +5836,8 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar
     }
 
     smb_InitReq(&req);
+    memset(&rock, 0, sizeof(rock));
+
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
 
@@ -5840,19 +5903,6 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar
 
     /* TODO: The old name could be a wildcard.  The new name must not be */
 
-    /* do the vnode call */
-    rock.odscp = oldDscp;
-    rock.ndscp = newDscp;
-    rock.userp = userp;
-    rock.reqp = &req;
-    rock.vcp = vcp;
-    rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
-    rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
-    rock.newNamep = newLastNamep;
-    rock.fsOldName[0] = '\0';
-    rock.clOldName[0] = '\0';
-    rock.any = 0;
-
     /* Check if the file already exists; if so return error */
     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
@@ -5886,15 +5936,27 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar
 
         if (tmpscp != NULL)
             cm_ReleaseSCache(tmpscp);
-        cm_ReleaseSCache(newDscp);
-        cm_ReleaseSCache(oldDscp);
-        cm_ReleaseUser(userp);
 
-        free(rock.maskp);
-        rock.maskp = NULL;
-        return code; 
+        goto done;
     }
 
+    /* do the vnode call */
+    rock.odscp = oldDscp;
+    rock.ndscp = newDscp;
+    rock.userp = userp;
+    rock.reqp = &req;
+    rock.vcp = vcp;
+    rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
+    if (!rock.maskp) {
+        code = CM_ERROR_NOSUCHFILE;
+        goto done;
+    }
+    rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
+    rock.newNamep = newLastNamep;
+    rock.fsOldName[0] = '\0';
+    rock.clOldName[0] = '\0';
+    rock.any = 0;
+
     /* Now search the directory for the pattern, and do the appropriate rename when found */
     thyper.LowPart = 0;                /* search dir from here */
     thyper.HighPart = 0;
@@ -5946,14 +6008,17 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar
         }
     }
 
+  done:
     if (tmpscp != NULL) 
         cm_ReleaseSCache(tmpscp);
-    cm_ReleaseUser(userp);
-    cm_ReleaseSCache(oldDscp);
-    cm_ReleaseSCache(newDscp);
-
-    free(rock.maskp);
-    rock.maskp = NULL;
+    if (userp)
+        cm_ReleaseUser(userp);
+    if (oldDscp)
+        cm_ReleaseSCache(oldDscp);
+    if (newDscp)
+        cm_ReleaseSCache(newDscp);
+    if (rock.maskp)
+        free(rock.maskp);
 
     return code;
 }       
@@ -6131,6 +6196,21 @@ smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
              osi_LogSaveClientString(smb_logp, oldPathp),
              osi_LogSaveClientString(smb_logp, newPathp));
 
+    if (!cm_IsValidClientString(newPathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(newPathp, -1);
+        osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
+            free(hexp);
+#else
+        osi_Log0(smb_logp, "CoreRename rejecting invalid name");
+#endif
+        return CM_ERROR_BADNTFILENAME;
+    }
+
     code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
 
     osi_Log1(smb_logp, "smb rename returns 0x%x", code);
@@ -6158,7 +6238,12 @@ int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper
         
     rockp = (smb_rmdirRock_t *) vrockp;
 
-    cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
+    if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
+        osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
+                 osi_LogSaveString(smb_logp, dep->name));
+        return 0;
+    }
+
     if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
         match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
     else
@@ -6195,6 +6280,7 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     cm_req_t req;
 
     smb_InitReq(&req);
+    memset(&rock, 0, sizeof(rock));
 
     tp = smb_GetSMBData(inp, NULL);
     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
@@ -6239,6 +6325,10 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
        
     rock.any = 0;
     rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
+    if (!rock.maskp) {
+        code = CM_ERROR_NOSUCHFILE;
+        goto done;
+    }
     rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
 
     thyper.LowPart = 0;
@@ -6263,6 +6353,8 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
             clientchar_t clientName[MAX_PATH];
 
+            /* We assume this will succeed because smb_RmdirProc()
+               successfully converted entry->name once above. */
             cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
 
             osi_Log1(smb_logp, "Removing directory %s",
@@ -6277,17 +6369,21 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         }
     }
 
+  done:
+    if (rock.matches)
     cm_DirEntryListFree(&rock.matches);
 
+    if (userp)
     cm_ReleaseUser(userp);
         
+    if (dscp)
     cm_ReleaseSCache(dscp);
 
     if (code == 0 && !rock.any)
         code = CM_ERROR_NOSUCHFILE;        
 
+    if (rock.maskp)
     free(rock.maskp);
-    rock.maskp = NULL;
 
     return code;
 }
@@ -6362,7 +6458,11 @@ int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
 
     vrockp = (struct smb_FullNameRock *)rockp;
 
-    cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
+    if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
+        osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
+                 osi_LogSaveString(smb_logp, dep->name));
+        return 0;
+    }
 
     if (!cm_Is8Dot3(matchName)) {
         clientchar_t shortName[13];
@@ -7704,6 +7804,21 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     tp = smb_GetSMBData(inp, NULL);
     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
 
+    if (!cm_IsValidClientString(pathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(pathp, -1);
+        osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
+            free(hexp);
+#else
+        osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
+#endif
+        return CM_ERROR_BADNTFILENAME;
+    }
+
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
 
index 2ec4362b67052826b6684b7bc1c45e3c2591bd77..68d398d7860b3940e9fe2dacecee0df7dca65cd5 100644 (file)
@@ -2361,6 +2361,22 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         return 0;
     }
 
+    if (!cm_IsValidClientString(pathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(pathp, -1);
+        osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
+            free(hexp);
+#else
+        osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
+#endif
+        smb_FreeTran2Packet(outp);
+        return CM_ERROR_BADNTFILENAME;
+    }
+
 #ifdef DEBUG_VERBOSE
     {
         char *hexp, *asciip;
@@ -2800,7 +2816,11 @@ int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
 
     rockp = vrockp;
 
-    cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t));
+    if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
+        osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
+                 osi_LogSaveString(smb_logp, dep->name));
+        return 0;
+    }
 
     /* compare both names and vnodes, though probably just comparing vnodes
      * would be safe enough.
@@ -5287,8 +5307,13 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         if (dep->fid.vnode == 0) 
             goto nextEntry;             /* This entry is not in use */
 
-        cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName));
-        cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName));
+        if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
+            cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
+
+            osi_Log1(smb_logp, "Skipping entry [%s].  Can't convert or normalize FS String",
+                     osi_LogSaveString(smb_logp, dep->name));
+            goto nextEntry;
+        }
 
         /* Need 8.3 name? */
         NeedShortName = 0;
@@ -5700,6 +5725,21 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return 0;
     }
 
+    if (!cm_IsValidClientString(pathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(pathp, -1);
+        osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
+            free(hexp);
+#else
+        osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
+#endif
+        return CM_ERROR_BADNTFILENAME;
+    }
+
 #ifdef DEBUG_VERBOSE
     {
        char *hexp, *asciip;
@@ -6858,15 +6898,21 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return 0;
     }
 
-#ifdef DEBUG_VERBOSE
-    {
-       char *hexp, *asciip;
-       asciip = (lastNamep? lastNamep : realPathp);
-       hexp = osi_HexifyString( asciip );
-       DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
+    if (!cm_IsValidClientString(realPathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(realPathp, -1);
+        osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
        free(hexp);
-    }
+#else
+        osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
 #endif
+        free(realPathp);
+        return CM_ERROR_BADNTFILENAME;
+    }
 
     userp = smb_GetUserFromVCP(vcp, inp);
     if (!userp) {
@@ -7679,15 +7725,21 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
      * Will add it if necessary.
      */
 
-#ifdef DEBUG_VERBOSE
-    {
-        char *hexp, *asciip;
-        asciip = (lastNamep? lastNamep : realPathp);
-        hexp = osi_HexifyString( asciip );
-        DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
+    if (!cm_IsValidClientString(realPathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(realPathp, -1);
+        osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
         free(hexp);
-    }
+#else
+        osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
 #endif
+        free(realPathp);
+        return CM_ERROR_BADNTFILENAME;
+    }
 
     userp = smb_GetUserFromVCP(vcp, inp);
     if (!userp) {