static int decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses, const struct nls_table *nls_cp) { int rc = 0; int words_left, len; char *data = *pbcc_area; cFYI(1, ("bleft %d", bleft)); /* SMB header is unaligned, so cifs servers word align start of Unicode strings */ data++; bleft--; /* Windows servers do not always double null terminate their final Unicode string - in which case we now will not attempt to decode the byte of junk which follows it */ words_left = bleft / 2; /* save off server operating system */ len = UniStrnlen((wchar_t *) data, words_left); /* We look for obvious messed up bcc or strings in response so we do not go off the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ if (len >= words_left) return rc; kfree(ses->serverOS); /* UTF-8 string will not grow more than four times as big as UCS-16 */ ses->serverOS = kzalloc(4 * len, GFP_KERNEL); if (ses->serverOS != NULL) cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp); data += 2 * (len + 1); words_left -= len + 1; /* save off server network operating system */ len = UniStrnlen((wchar_t *) data, words_left); if (len >= words_left) return rc; kfree(ses->serverNOS); ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */ if (ses->serverNOS != NULL) { cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len, nls_cp); if (strncmp(ses->serverNOS, "NT LAN Manager 4", 16) == 0) { cFYI(1, ("NT4 server")); ses->flags |= CIFS_SES_NT4; } } data += 2 * (len + 1); words_left -= len + 1; /* save off server domain */ len = UniStrnlen((wchar_t *) data, words_left); if (len > words_left) return rc; kfree(ses->serverDomain); ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */ if (ses->serverDomain != NULL) { cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, nls_cp); ses->serverDomain[2*len] = 0; ses->serverDomain[(2*len) + 1] = 0; } data += 2 * (len + 1); words_left -= len + 1; cFYI(1, ("words left: %d", words_left)); return rc; }
/* inode num, inode type and filename returned */ static int cifs_get_name_from_search_buf(struct qstr *pqst, char *current_entry, __u16 level, unsigned int unicode, struct cifs_sb_info *cifs_sb, int max_len, __u64 *pinum) { int rc = 0; unsigned int len = 0; char *filename; struct nls_table *nlt = cifs_sb->local_nls; *pinum = 0; if (level == SMB_FIND_FILE_UNIX) { FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry; filename = &pFindData->FileName[0]; if (unicode) { len = cifs_unicode_bytelen(filename); } else { /* BB should we make this strnlen of PATH_MAX? */ len = strnlen(filename, PATH_MAX); } *pinum = pFindData->UniqueId; } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) { FILE_DIRECTORY_INFO *pFindData = (FILE_DIRECTORY_INFO *)current_entry; filename = &pFindData->FileName[0]; len = le32_to_cpu(pFindData->FileNameLength); } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) { FILE_FULL_DIRECTORY_INFO *pFindData = (FILE_FULL_DIRECTORY_INFO *)current_entry; filename = &pFindData->FileName[0]; len = le32_to_cpu(pFindData->FileNameLength); } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) { SEARCH_ID_FULL_DIR_INFO *pFindData = (SEARCH_ID_FULL_DIR_INFO *)current_entry; filename = &pFindData->FileName[0]; len = le32_to_cpu(pFindData->FileNameLength); *pinum = pFindData->UniqueId; } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { FILE_BOTH_DIRECTORY_INFO *pFindData = (FILE_BOTH_DIRECTORY_INFO *)current_entry; filename = &pFindData->FileName[0]; len = le32_to_cpu(pFindData->FileNameLength); } else if (level == SMB_FIND_FILE_INFO_STANDARD) { FIND_FILE_STANDARD_INFO *pFindData = (FIND_FILE_STANDARD_INFO *)current_entry; filename = &pFindData->FileName[0]; /* one byte length, no name conversion */ len = (unsigned int)pFindData->FileNameLength; } else { cFYI(1, ("Unknown findfirst level %d", level)); return -EINVAL; } if (len > max_len) { cERROR(1, ("bad search response length %d past smb end", len)); return -EINVAL; } if (unicode) { /* BB fixme - test with long names */ /* Note converted filename can be longer than in unicode */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) pqst->len = cifs_convertUCSpath((char *)pqst->name, (__le16 *)filename, len/2, nlt); else pqst->len = cifs_strfromUCS_le((char *)pqst->name, (__le16 *)filename, len/2, nlt); } else { pqst->name = filename; pqst->len = len; } pqst->hash = full_name_hash(pqst->name, pqst->len); /* cFYI(1, ("filldir on %s",pqst->name)); */ return rc; }
static int decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses, const struct nls_table *nls_cp) { int rc = 0; int words_left, len; char *data = *pbcc_area; cFYI(1, ("bleft %d", bleft)); /* * Windows servers do not always double null terminate their final * Unicode string. Check to see if there are an uneven number of bytes * left. If so, then add an extra NULL pad byte to the end of the * response. * * See section 2.7.2 in "Implementing CIFS" for details */ if (bleft % 2) { data[bleft] = 0; ++bleft; } words_left = bleft / 2; /* save off server operating system */ len = UniStrnlen((wchar_t *) data, words_left); if (len >= words_left) return rc; kfree(ses->serverOS); /* UTF-8 string will not grow more than four times as big as UCS-16 */ ses->serverOS = kzalloc(4 * len, GFP_KERNEL); if (ses->serverOS != NULL) cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp); data += 2 * (len + 1); words_left -= len + 1; /* save off server network operating system */ len = UniStrnlen((wchar_t *) data, words_left); if (len >= words_left) return rc; kfree(ses->serverNOS); ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */ if (ses->serverNOS != NULL) { cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len, nls_cp); if (strncmp(ses->serverNOS, "NT LAN Manager 4", 16) == 0) { cFYI(1, ("NT4 server")); ses->flags |= CIFS_SES_NT4; } } data += 2 * (len + 1); words_left -= len + 1; /* save off server domain */ len = UniStrnlen((wchar_t *) data, words_left); if (len > words_left) return rc; kfree(ses->serverDomain); ses->serverDomain = kzalloc((4 * len) + 2, GFP_KERNEL); if (ses->serverDomain != NULL) cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, nls_cp); data += 2 * (len + 1); words_left -= len + 1; cFYI(1, ("words left: %d", words_left)); return rc; }