windows-handle-invalid-utf16-names-20081019

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.
This commit is contained in:
Asanka Herath 2008-10-20 00:17:41 +00:00 committed by Jeffrey Altman
parent 0c7d7ce3b8
commit 90e4242c2d
9 changed files with 499 additions and 55 deletions

View 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)

View 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;
}

View 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;

View 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

View 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,

View 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) {

View 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)

View 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);

View 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) {