diff --git a/src/WINNT/afsd/cm_btree.c b/src/WINNT/afsd/cm_btree.c index c7bc2b7e75..ea0ec3abda 100644 --- a/src/WINNT/afsd/cm_btree.c +++ b/src/WINNT/afsd/cm_btree.c @@ -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) diff --git a/src/WINNT/afsd/cm_dir.c b/src/WINNT/afsd/cm_dir.c index edc4fc58f1..5f2439c1e3 100644 --- a/src/WINNT/afsd/cm_dir.c +++ b/src/WINNT/afsd/cm_dir.c @@ -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; } diff --git a/src/WINNT/afsd/cm_ioctl.c b/src/WINNT/afsd/cm_ioctl.c index 1d78f0c67d..c24ce06b23 100644 --- a/src/WINNT/afsd/cm_ioctl.c +++ b/src/WINNT/afsd/cm_ioctl.c @@ -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; diff --git a/src/WINNT/afsd/cm_nls.c b/src/WINNT/afsd/cm_nls.c index 8d3eb215ae..63e56e40d3 100644 --- a/src/WINNT/afsd/cm_nls.c +++ b/src/WINNT/afsd/cm_nls.c @@ -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, ¤t, &cb, 0, + L"%04x", (int) *c); + if (len > 1) + StringCbCatExW(current, cb, L",", ¤t, &cb, 0); + } + + return ret; +} +#endif diff --git a/src/WINNT/afsd/cm_nls.h b/src/WINNT/afsd/cm_nls.h index 017d2718ae..3d7517ea5d 100644 --- a/src/WINNT/afsd/cm_nls.h +++ b/src/WINNT/afsd/cm_nls.h @@ -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, diff --git a/src/WINNT/afsd/cm_vnodeops.c b/src/WINNT/afsd/cm_vnodeops.c index 82b57a8ced..e9d8d54d01 100644 --- a/src/WINNT/afsd/cm_vnodeops.c +++ b/src/WINNT/afsd/cm_vnodeops.c @@ -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) { diff --git a/src/WINNT/afsd/cm_volstat.c b/src/WINNT/afsd/cm_volstat.c index 3f1a2f6196..3336aae43b 100644 --- a/src/WINNT/afsd/cm_volstat.c +++ b/src/WINNT/afsd/cm_volstat.c @@ -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) diff --git a/src/WINNT/afsd/smb.c b/src/WINNT/afsd/smb.c index f66cc05c5f..d1d4ac980d 100644 --- a/src/WINNT/afsd/smb.c +++ b/src/WINNT/afsd/smb.c @@ -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); diff --git a/src/WINNT/afsd/smb3.c b/src/WINNT/afsd/smb3.c index 2ec4362b67..68d398d786 100644 --- a/src/WINNT/afsd/smb3.c +++ b/src/WINNT/afsd/smb3.c @@ -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) {