mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: (32 commits) [CIFS] Fix double list addition in cifs posix open code [CIFS] Allow raw ntlmssp code to be enabled with sec=ntlmssp [CIFS] Fix SMB uid in NTLMSSP authenticate request [CIFS] NTLMSSP reenabled after move from connect.c to sess.c [CIFS] Remove sparse warning [CIFS] remove checkpatch warning [CIFS] Fix final user of old string conversion code [CIFS] remove cifs_strfromUCS_le [CIFS] NTLMSSP support moving into new file, old dead code removed [CIFS] Fix endian conversion of vcnum field [CIFS] Remove trailing whitespace [CIFS] Remove sparse endian warnings [CIFS] Add remaining ntlmssp flags and standardize field names [CIFS] Fix build warning cifs: fix length handling in cifs_get_name_from_search_buf [CIFS] Remove unneeded QuerySymlink call and fix mapping for unmapped status [CIFS] rename cifs_strndup to cifs_strndup_from_ucs Added loop check when mounting DFS tree. Enable dfs submounts to handle remote referrals. [CIFS] Remove older session setup implementation ...
This commit is contained in:
commit
d7a5926978
@ -1,3 +1,16 @@
|
||||
Version 1.58
|
||||
------------
|
||||
Guard against buffer overruns in various UCS-2 to UTF-8 string conversions
|
||||
when the UTF-8 string is composed of unusually long (more than 4 byte) converted
|
||||
characters. Add support for mounting root of a share which redirects immediately
|
||||
to DFS target. Convert string conversion functions from Unicode to more
|
||||
accurately mark string length before allocating memory (which may help the
|
||||
rare cases where a UTF-8 string is much larger than the UCS2 string that
|
||||
we converted from). Fix endianness of the vcnum field used during
|
||||
session setup to distinguish multiple mounts to same server from different
|
||||
userids. Raw NTLMSSP fixed (it requires /proc/fs/cifs/experimental
|
||||
flag to be set to 2, and mount must enable krb5 to turn on extended security).
|
||||
|
||||
Version 1.57
|
||||
------------
|
||||
Improve support for multiple security contexts to the same server. We
|
||||
|
@ -651,7 +651,15 @@ Experimental When set to 1 used to enable certain experimental
|
||||
signing turned on in case buffer was modified
|
||||
just before it was sent, also this flag will
|
||||
be used to use the new experimental directory change
|
||||
notification code).
|
||||
notification code). When set to 2 enables
|
||||
an additional experimental feature, "raw ntlmssp"
|
||||
session establishment support (which allows
|
||||
specifying "sec=ntlmssp" on mount). The Linux cifs
|
||||
module will use ntlmv2 authentication encapsulated
|
||||
in "raw ntlmssp" (not using SPNEGO) when
|
||||
"sec=ntlmssp" is specified on mount.
|
||||
This support also requires building cifs with
|
||||
the CONFIG_CIFS_EXPERIMENTAL configuration flag.
|
||||
|
||||
These experimental features and tracing can be enabled by changing flags in
|
||||
/proc/fs/cifs (after the cifs module has been installed or built into the
|
||||
|
@ -340,28 +340,24 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
|
||||
for (i = 0; i < num_referrals; i++) {
|
||||
int len;
|
||||
dump_referral(referrals+i);
|
||||
/* connect to a storage node */
|
||||
if (referrals[i].flags & DFSREF_STORAGE_SERVER) {
|
||||
int len;
|
||||
len = strlen(referrals[i].node_name);
|
||||
if (len < 2) {
|
||||
cERROR(1, ("%s: Net Address path too short: %s",
|
||||
/* connect to a node */
|
||||
len = strlen(referrals[i].node_name);
|
||||
if (len < 2) {
|
||||
cERROR(1, ("%s: Net Address path too short: %s",
|
||||
__func__, referrals[i].node_name));
|
||||
rc = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
mnt = cifs_dfs_do_refmount(nd->path.mnt,
|
||||
nd->path.dentry,
|
||||
referrals + i);
|
||||
cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p",
|
||||
__func__,
|
||||
rc = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
mnt = cifs_dfs_do_refmount(nd->path.mnt,
|
||||
nd->path.dentry, referrals + i);
|
||||
cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__,
|
||||
referrals[i].node_name, mnt));
|
||||
|
||||
/* complete mount procedure if we accured submount */
|
||||
if (!IS_ERR(mnt))
|
||||
break;
|
||||
}
|
||||
/* complete mount procedure if we accured submount */
|
||||
if (!IS_ERR(mnt))
|
||||
break;
|
||||
}
|
||||
|
||||
/* we need it cause for() above could exit without valid submount */
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* fs/cifs/cifs_unicode.c
|
||||
*
|
||||
* Copyright (c) International Business Machines Corp., 2000,2005
|
||||
* Copyright (c) International Business Machines Corp., 2000,2009
|
||||
* Modified by Steve French (sfrench@us.ibm.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -26,31 +26,157 @@
|
||||
#include "cifs_debug.h"
|
||||
|
||||
/*
|
||||
* NAME: cifs_strfromUCS()
|
||||
*
|
||||
* FUNCTION: Convert little-endian unicode string to character string
|
||||
* cifs_ucs2_bytes - how long will a string be after conversion?
|
||||
* @ucs - pointer to input string
|
||||
* @maxbytes - don't go past this many bytes of input string
|
||||
* @codepage - destination codepage
|
||||
*
|
||||
* Walk a ucs2le string and return the number of bytes that the string will
|
||||
* be after being converted to the given charset, not including any null
|
||||
* termination required. Don't walk past maxbytes in the source buffer.
|
||||
*/
|
||||
int
|
||||
cifs_strfromUCS_le(char *to, const __le16 *from,
|
||||
int len, const struct nls_table *codepage)
|
||||
cifs_ucs2_bytes(const __le16 *from, int maxbytes,
|
||||
const struct nls_table *codepage)
|
||||
{
|
||||
int i;
|
||||
int outlen = 0;
|
||||
int charlen, outlen = 0;
|
||||
int maxwords = maxbytes / 2;
|
||||
char tmp[NLS_MAX_CHARSET_SIZE];
|
||||
|
||||
for (i = 0; (i < len) && from[i]; i++) {
|
||||
int charlen;
|
||||
/* 2.4.0 kernel or greater */
|
||||
charlen =
|
||||
codepage->uni2char(le16_to_cpu(from[i]), &to[outlen],
|
||||
NLS_MAX_CHARSET_SIZE);
|
||||
if (charlen > 0) {
|
||||
for (i = 0; from[i] && i < maxwords; i++) {
|
||||
charlen = codepage->uni2char(le16_to_cpu(from[i]), tmp,
|
||||
NLS_MAX_CHARSET_SIZE);
|
||||
if (charlen > 0)
|
||||
outlen += charlen;
|
||||
} else {
|
||||
to[outlen++] = '?';
|
||||
}
|
||||
else
|
||||
outlen++;
|
||||
}
|
||||
to[outlen] = 0;
|
||||
|
||||
return outlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* cifs_mapchar - convert a little-endian char to proper char in codepage
|
||||
* @target - where converted character should be copied
|
||||
* @src_char - 2 byte little-endian source character
|
||||
* @cp - codepage to which character should be converted
|
||||
* @mapchar - should character be mapped according to mapchars mount option?
|
||||
*
|
||||
* This function handles the conversion of a single character. It is the
|
||||
* responsibility of the caller to ensure that the target buffer is large
|
||||
* enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE).
|
||||
*/
|
||||
static int
|
||||
cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp,
|
||||
bool mapchar)
|
||||
{
|
||||
int len = 1;
|
||||
|
||||
if (!mapchar)
|
||||
goto cp_convert;
|
||||
|
||||
/*
|
||||
* BB: Cannot handle remapping UNI_SLASH until all the calls to
|
||||
* build_path_from_dentry are modified, as they use slash as
|
||||
* separator.
|
||||
*/
|
||||
switch (le16_to_cpu(src_char)) {
|
||||
case UNI_COLON:
|
||||
*target = ':';
|
||||
break;
|
||||
case UNI_ASTERIK:
|
||||
*target = '*';
|
||||
break;
|
||||
case UNI_QUESTION:
|
||||
*target = '?';
|
||||
break;
|
||||
case UNI_PIPE:
|
||||
*target = '|';
|
||||
break;
|
||||
case UNI_GRTRTHAN:
|
||||
*target = '>';
|
||||
break;
|
||||
case UNI_LESSTHAN:
|
||||
*target = '<';
|
||||
break;
|
||||
default:
|
||||
goto cp_convert;
|
||||
}
|
||||
|
||||
out:
|
||||
return len;
|
||||
|
||||
cp_convert:
|
||||
len = cp->uni2char(le16_to_cpu(src_char), target,
|
||||
NLS_MAX_CHARSET_SIZE);
|
||||
if (len <= 0) {
|
||||
*target = '?';
|
||||
len = 1;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* cifs_from_ucs2 - convert utf16le string to local charset
|
||||
* @to - destination buffer
|
||||
* @from - source buffer
|
||||
* @tolen - destination buffer size (in bytes)
|
||||
* @fromlen - source buffer size (in bytes)
|
||||
* @codepage - codepage to which characters should be converted
|
||||
* @mapchar - should characters be remapped according to the mapchars option?
|
||||
*
|
||||
* Convert a little-endian ucs2le string (as sent by the server) to a string
|
||||
* in the provided codepage. The tolen and fromlen parameters are to ensure
|
||||
* that the code doesn't walk off of the end of the buffer (which is always
|
||||
* a danger if the alignment of the source buffer is off). The destination
|
||||
* string is always properly null terminated and fits in the destination
|
||||
* buffer. Returns the length of the destination string in bytes (including
|
||||
* null terminator).
|
||||
*
|
||||
* Note that some windows versions actually send multiword UTF-16 characters
|
||||
* instead of straight UCS-2. The linux nls routines however aren't able to
|
||||
* deal with those characters properly. In the event that we get some of
|
||||
* those characters, they won't be translated properly.
|
||||
*/
|
||||
int
|
||||
cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen,
|
||||
const struct nls_table *codepage, bool mapchar)
|
||||
{
|
||||
int i, charlen, safelen;
|
||||
int outlen = 0;
|
||||
int nullsize = nls_nullsize(codepage);
|
||||
int fromwords = fromlen / 2;
|
||||
char tmp[NLS_MAX_CHARSET_SIZE];
|
||||
|
||||
/*
|
||||
* because the chars can be of varying widths, we need to take care
|
||||
* not to overflow the destination buffer when we get close to the
|
||||
* end of it. Until we get to this offset, we don't need to check
|
||||
* for overflow however.
|
||||
*/
|
||||
safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize);
|
||||
|
||||
for (i = 0; i < fromwords && from[i]; i++) {
|
||||
/*
|
||||
* check to see if converting this character might make the
|
||||
* conversion bleed into the null terminator
|
||||
*/
|
||||
if (outlen >= safelen) {
|
||||
charlen = cifs_mapchar(tmp, from[i], codepage, mapchar);
|
||||
if ((outlen + charlen) > (tolen - nullsize))
|
||||
break;
|
||||
}
|
||||
|
||||
/* put converted char into 'to' buffer */
|
||||
charlen = cifs_mapchar(&to[outlen], from[i], codepage, mapchar);
|
||||
outlen += charlen;
|
||||
}
|
||||
|
||||
/* properly null-terminate string */
|
||||
for (i = 0; i < nullsize; i++)
|
||||
to[outlen++] = 0;
|
||||
|
||||
return outlen;
|
||||
}
|
||||
|
||||
@ -88,3 +214,41 @@ cifs_strtoUCS(__le16 *to, const char *from, int len,
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* cifs_strndup_from_ucs - copy a string from wire format to the local codepage
|
||||
* @src - source string
|
||||
* @maxlen - don't walk past this many bytes in the source string
|
||||
* @is_unicode - is this a unicode string?
|
||||
* @codepage - destination codepage
|
||||
*
|
||||
* Take a string given by the server, convert it to the local codepage and
|
||||
* put it in a new buffer. Returns a pointer to the new string or NULL on
|
||||
* error.
|
||||
*/
|
||||
char *
|
||||
cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode,
|
||||
const struct nls_table *codepage)
|
||||
{
|
||||
int len;
|
||||
char *dst;
|
||||
|
||||
if (is_unicode) {
|
||||
len = cifs_ucs2_bytes((__le16 *) src, maxlen, codepage);
|
||||
len += nls_nullsize(codepage);
|
||||
dst = kmalloc(len, GFP_KERNEL);
|
||||
if (!dst)
|
||||
return NULL;
|
||||
cifs_from_ucs2(dst, (__le16 *) src, len, maxlen, codepage,
|
||||
false);
|
||||
} else {
|
||||
len = strnlen(src, maxlen);
|
||||
len++;
|
||||
dst = kmalloc(len, GFP_KERNEL);
|
||||
if (!dst)
|
||||
return NULL;
|
||||
strlcpy(dst, src, len);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Convert a unicode character to upper or lower case using
|
||||
* compressed tables.
|
||||
*
|
||||
* Copyright (c) International Business Machines Corp., 2000,2007
|
||||
* Copyright (c) International Business Machines Corp., 2000,2009
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -37,6 +37,19 @@
|
||||
|
||||
#define UNIUPR_NOLOWER /* Example to not expand lower case tables */
|
||||
|
||||
/*
|
||||
* Windows maps these to the user defined 16 bit Unicode range since they are
|
||||
* reserved symbols (along with \ and /), otherwise illegal to store
|
||||
* in filenames in NTFS
|
||||
*/
|
||||
#define UNI_ASTERIK (__u16) ('*' + 0xF000)
|
||||
#define UNI_QUESTION (__u16) ('?' + 0xF000)
|
||||
#define UNI_COLON (__u16) (':' + 0xF000)
|
||||
#define UNI_GRTRTHAN (__u16) ('>' + 0xF000)
|
||||
#define UNI_LESSTHAN (__u16) ('<' + 0xF000)
|
||||
#define UNI_PIPE (__u16) ('|' + 0xF000)
|
||||
#define UNI_SLASH (__u16) ('\\' + 0xF000)
|
||||
|
||||
/* Just define what we want from uniupr.h. We don't want to define the tables
|
||||
* in each source file.
|
||||
*/
|
||||
@ -59,8 +72,14 @@ extern struct UniCaseRange UniLowerRange[];
|
||||
#endif /* UNIUPR_NOLOWER */
|
||||
|
||||
#ifdef __KERNEL__
|
||||
int cifs_strfromUCS_le(char *, const __le16 *, int, const struct nls_table *);
|
||||
int cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen,
|
||||
const struct nls_table *codepage, bool mapchar);
|
||||
int cifs_ucs2_bytes(const __le16 *from, int maxbytes,
|
||||
const struct nls_table *codepage);
|
||||
int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *);
|
||||
char *cifs_strndup_from_ucs(const char *src, const int maxlen,
|
||||
const bool is_unicode,
|
||||
const struct nls_table *codepage);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -100,5 +100,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
||||
extern const struct export_operations cifs_export_ops;
|
||||
#endif /* EXPERIMENTAL */
|
||||
|
||||
#define CIFS_VERSION "1.57"
|
||||
#define CIFS_VERSION "1.58"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
@ -82,8 +82,8 @@ enum securityEnum {
|
||||
LANMAN, /* Legacy LANMAN auth */
|
||||
NTLM, /* Legacy NTLM012 auth with NTLM hash */
|
||||
NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */
|
||||
RawNTLMSSP, /* NTLMSSP without SPNEGO */
|
||||
NTLMSSP, /* NTLMSSP via SPNEGO */
|
||||
RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */
|
||||
NTLMSSP, /* NTLMSSP via SPNEGO, NTLMv2 hash */
|
||||
Kerberos, /* Kerberos via SPNEGO */
|
||||
MSKerberos, /* MS Kerberos via SPNEGO */
|
||||
};
|
||||
@ -531,6 +531,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
|
||||
#define CIFSSEC_MAY_PLNTXT 0
|
||||
#endif /* weak passwords */
|
||||
#define CIFSSEC_MAY_SEAL 0x00040 /* not supported yet */
|
||||
#define CIFSSEC_MAY_NTLMSSP 0x00080 /* raw ntlmssp with ntlmv2 */
|
||||
|
||||
#define CIFSSEC_MUST_SIGN 0x01001
|
||||
/* note that only one of the following can be set so the
|
||||
@ -543,22 +544,23 @@ require use of the stronger protocol */
|
||||
#define CIFSSEC_MUST_LANMAN 0x10010
|
||||
#define CIFSSEC_MUST_PLNTXT 0x20020
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
#define CIFSSEC_MASK 0x3F03F /* allows weak security but also krb5 */
|
||||
#define CIFSSEC_MASK 0xAF0AF /* allows weak security but also krb5 */
|
||||
#else
|
||||
#define CIFSSEC_MASK 0x37037 /* current flags supported if weak */
|
||||
#define CIFSSEC_MASK 0xA70A7 /* current flags supported if weak */
|
||||
#endif /* UPCALL */
|
||||
#else /* do not allow weak pw hash */
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
#define CIFSSEC_MASK 0x0F00F /* flags supported if no weak allowed */
|
||||
#define CIFSSEC_MASK 0x8F08F /* flags supported if no weak allowed */
|
||||
#else
|
||||
#define CIFSSEC_MASK 0x07007 /* flags supported if no weak allowed */
|
||||
#define CIFSSEC_MASK 0x87087 /* flags supported if no weak allowed */
|
||||
#endif /* UPCALL */
|
||||
#endif /* WEAK_PW_HASH */
|
||||
#define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */
|
||||
#define CIFSSEC_MUST_NTLMSSP 0x80080 /* raw ntlmssp with ntlmv2 */
|
||||
|
||||
#define CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2)
|
||||
#define CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2)
|
||||
#define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5)
|
||||
#define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP)
|
||||
/*
|
||||
*****************************************************************
|
||||
* All constants go here
|
||||
|
@ -260,8 +260,7 @@ extern int CIFSUnixCreateSymLink(const int xid,
|
||||
const struct nls_table *nls_codepage);
|
||||
extern int CIFSSMBUnixQuerySymLink(const int xid,
|
||||
struct cifsTconInfo *tcon,
|
||||
const unsigned char *searchName,
|
||||
char *syminfo, const int buflen,
|
||||
const unsigned char *searchName, char **syminfo,
|
||||
const struct nls_table *nls_codepage);
|
||||
extern int CIFSSMBQueryReparseLinkInfo(const int xid,
|
||||
struct cifsTconInfo *tcon,
|
||||
@ -307,8 +306,6 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
|
||||
const unsigned char *searchName, __u64 *inode_number,
|
||||
const struct nls_table *nls_codepage,
|
||||
int remap_special_chars);
|
||||
extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen,
|
||||
const struct nls_table *codepage);
|
||||
extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
|
||||
const struct nls_table *cp, int mapChars);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* fs/cifs/cifssmb.c
|
||||
*
|
||||
* Copyright (C) International Business Machines Corp., 2002,2008
|
||||
* Copyright (C) International Business Machines Corp., 2002,2009
|
||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||
*
|
||||
* Contains the routines for constructing the SMB PDUs themselves
|
||||
@ -81,41 +81,6 @@ static struct {
|
||||
#endif /* CONFIG_CIFS_WEAK_PW_HASH */
|
||||
#endif /* CIFS_POSIX */
|
||||
|
||||
/* Allocates buffer into dst and copies smb string from src to it.
|
||||
* caller is responsible for freeing dst if function returned 0.
|
||||
* returns:
|
||||
* on success - 0
|
||||
* on failure - errno
|
||||
*/
|
||||
static int
|
||||
cifs_strncpy_to_host(char **dst, const char *src, const int maxlen,
|
||||
const bool is_unicode, const struct nls_table *nls_codepage)
|
||||
{
|
||||
int plen;
|
||||
|
||||
if (is_unicode) {
|
||||
plen = UniStrnlen((wchar_t *)src, maxlen);
|
||||
*dst = kmalloc(plen + 2, GFP_KERNEL);
|
||||
if (!*dst)
|
||||
goto cifs_strncpy_to_host_ErrExit;
|
||||
cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage);
|
||||
} else {
|
||||
plen = strnlen(src, maxlen);
|
||||
*dst = kmalloc(plen + 2, GFP_KERNEL);
|
||||
if (!*dst)
|
||||
goto cifs_strncpy_to_host_ErrExit;
|
||||
strncpy(*dst, src, plen);
|
||||
}
|
||||
(*dst)[plen] = 0;
|
||||
(*dst)[plen+1] = 0; /* harmless for ASCII case, needed for Unicode */
|
||||
return 0;
|
||||
|
||||
cifs_strncpy_to_host_ErrExit:
|
||||
cERROR(1, ("Failed to allocate buffer for string\n"));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
/* Mark as invalid, all open files on tree connections since they
|
||||
were closed when session to server was lost */
|
||||
static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
|
||||
@ -484,6 +449,14 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
||||
cFYI(1, ("Kerberos only mechanism, enable extended security"));
|
||||
pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
}
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
|
||||
pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
|
||||
cFYI(1, ("NTLMSSP only mechanism, enable extended security"));
|
||||
pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
}
|
||||
#endif
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < CIFS_NUM_PROT; i++) {
|
||||
@ -620,6 +593,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
||||
server->secType = NTLMv2;
|
||||
else if (secFlags & CIFSSEC_MAY_KRB5)
|
||||
server->secType = Kerberos;
|
||||
else if (secFlags & CIFSSEC_MAY_NTLMSSP)
|
||||
server->secType = NTLMSSP;
|
||||
else if (secFlags & CIFSSEC_MAY_LANMAN)
|
||||
server->secType = LANMAN;
|
||||
/* #ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
@ -2417,8 +2392,7 @@ winCreateHardLinkRetry:
|
||||
|
||||
int
|
||||
CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
|
||||
const unsigned char *searchName,
|
||||
char *symlinkinfo, const int buflen,
|
||||
const unsigned char *searchName, char **symlinkinfo,
|
||||
const struct nls_table *nls_codepage)
|
||||
{
|
||||
/* SMB_QUERY_FILE_UNIX_LINK */
|
||||
@ -2428,6 +2402,7 @@ CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
|
||||
int bytes_returned;
|
||||
int name_len;
|
||||
__u16 params, byte_count;
|
||||
char *data_start;
|
||||
|
||||
cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
|
||||
|
||||
@ -2482,30 +2457,26 @@ querySymLinkRetry:
|
||||
/* decode response */
|
||||
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
if (rc || (pSMBr->ByteCount < 2))
|
||||
/* BB also check enough total bytes returned */
|
||||
rc = -EIO; /* bad smb */
|
||||
if (rc || (pSMBr->ByteCount < 2))
|
||||
rc = -EIO;
|
||||
else {
|
||||
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
||||
__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
|
||||
bool is_unicode;
|
||||
u16 count = le16_to_cpu(pSMBr->t2.DataCount);
|
||||
|
||||
data_start = ((char *) &pSMBr->hdr.Protocol) +
|
||||
le16_to_cpu(pSMBr->t2.DataOffset);
|
||||
|
||||
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
|
||||
is_unicode = true;
|
||||
else
|
||||
is_unicode = false;
|
||||
|
||||
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
|
||||
name_len = UniStrnlen((wchar_t *) ((char *)
|
||||
&pSMBr->hdr.Protocol + data_offset),
|
||||
min_t(const int, buflen, count) / 2);
|
||||
/* BB FIXME investigate remapping reserved chars here */
|
||||
cifs_strfromUCS_le(symlinkinfo,
|
||||
(__le16 *) ((char *)&pSMBr->hdr.Protocol
|
||||
+ data_offset),
|
||||
name_len, nls_codepage);
|
||||
} else {
|
||||
strncpy(symlinkinfo,
|
||||
(char *) &pSMBr->hdr.Protocol +
|
||||
data_offset,
|
||||
min_t(const int, buflen, count));
|
||||
}
|
||||
symlinkinfo[buflen] = 0;
|
||||
/* just in case so calling code does not go off the end of buffer */
|
||||
*symlinkinfo = cifs_strndup_from_ucs(data_start, count,
|
||||
is_unicode, nls_codepage);
|
||||
if (!symlinkinfo)
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
}
|
||||
cifs_buf_release(pSMB);
|
||||
@ -2603,7 +2574,6 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata,
|
||||
*pparmlen = parm_count;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CIFS_EXPERIMENTAL */
|
||||
|
||||
int
|
||||
CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
|
||||
@ -2613,7 +2583,6 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
|
||||
{
|
||||
int rc = 0;
|
||||
int bytes_returned;
|
||||
int name_len;
|
||||
struct smb_com_transaction_ioctl_req *pSMB;
|
||||
struct smb_com_transaction_ioctl_rsp *pSMBr;
|
||||
|
||||
@ -2650,59 +2619,55 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
|
||||
} else { /* decode response */
|
||||
__u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
|
||||
__u32 data_count = le32_to_cpu(pSMBr->DataCount);
|
||||
if ((pSMBr->ByteCount < 2) || (data_offset > 512))
|
||||
if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
|
||||
/* BB also check enough total bytes returned */
|
||||
rc = -EIO; /* bad smb */
|
||||
else {
|
||||
if (data_count && (data_count < 2048)) {
|
||||
char *end_of_smb = 2 /* sizeof byte count */ +
|
||||
pSMBr->ByteCount +
|
||||
(char *)&pSMBr->ByteCount;
|
||||
goto qreparse_out;
|
||||
}
|
||||
if (data_count && (data_count < 2048)) {
|
||||
char *end_of_smb = 2 /* sizeof byte count */ +
|
||||
pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
|
||||
|
||||
struct reparse_data *reparse_buf =
|
||||
struct reparse_data *reparse_buf =
|
||||
(struct reparse_data *)
|
||||
((char *)&pSMBr->hdr.Protocol
|
||||
+ data_offset);
|
||||
if ((char *)reparse_buf >= end_of_smb) {
|
||||
rc = -EIO;
|
||||
goto qreparse_out;
|
||||
}
|
||||
if ((reparse_buf->LinkNamesBuf +
|
||||
reparse_buf->TargetNameOffset +
|
||||
reparse_buf->TargetNameLen) >
|
||||
end_of_smb) {
|
||||
cFYI(1, ("reparse buf beyond SMB"));
|
||||
rc = -EIO;
|
||||
goto qreparse_out;
|
||||
}
|
||||
if ((char *)reparse_buf >= end_of_smb) {
|
||||
rc = -EIO;
|
||||
goto qreparse_out;
|
||||
}
|
||||
if ((reparse_buf->LinkNamesBuf +
|
||||
reparse_buf->TargetNameOffset +
|
||||
reparse_buf->TargetNameLen) > end_of_smb) {
|
||||
cFYI(1, ("reparse buf beyond SMB"));
|
||||
rc = -EIO;
|
||||
goto qreparse_out;
|
||||
}
|
||||
|
||||
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
|
||||
name_len = UniStrnlen((wchar_t *)
|
||||
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
|
||||
cifs_from_ucs2(symlinkinfo, (__le16 *)
|
||||
(reparse_buf->LinkNamesBuf +
|
||||
reparse_buf->TargetNameOffset),
|
||||
min(buflen/2,
|
||||
reparse_buf->TargetNameLen / 2));
|
||||
cifs_strfromUCS_le(symlinkinfo,
|
||||
(__le16 *) (reparse_buf->LinkNamesBuf +
|
||||
reparse_buf->TargetNameOffset),
|
||||
name_len, nls_codepage);
|
||||
} else { /* ASCII names */
|
||||
strncpy(symlinkinfo,
|
||||
reparse_buf->LinkNamesBuf +
|
||||
reparse_buf->TargetNameOffset,
|
||||
min_t(const int, buflen,
|
||||
reparse_buf->TargetNameLen));
|
||||
}
|
||||
} else {
|
||||
rc = -EIO;
|
||||
cFYI(1, ("Invalid return data count on "
|
||||
"get reparse info ioctl"));
|
||||
buflen,
|
||||
reparse_buf->TargetNameLen,
|
||||
nls_codepage, 0);
|
||||
} else { /* ASCII names */
|
||||
strncpy(symlinkinfo,
|
||||
reparse_buf->LinkNamesBuf +
|
||||
reparse_buf->TargetNameOffset,
|
||||
min_t(const int, buflen,
|
||||
reparse_buf->TargetNameLen));
|
||||
}
|
||||
symlinkinfo[buflen] = 0; /* just in case so the caller
|
||||
does not go off the end of the buffer */
|
||||
cFYI(1, ("readlink result - %s", symlinkinfo));
|
||||
} else {
|
||||
rc = -EIO;
|
||||
cFYI(1, ("Invalid return data count on "
|
||||
"get reparse info ioctl"));
|
||||
}
|
||||
symlinkinfo[buflen] = 0; /* just in case so the caller
|
||||
does not go off the end of the buffer */
|
||||
cFYI(1, ("readlink result - %s", symlinkinfo));
|
||||
}
|
||||
|
||||
qreparse_out:
|
||||
cifs_buf_release(pSMB);
|
||||
|
||||
@ -2711,6 +2676,7 @@ qreparse_out:
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* CIFS_EXPERIMENTAL */
|
||||
|
||||
#ifdef CONFIG_CIFS_POSIX
|
||||
|
||||
@ -3928,27 +3894,6 @@ GetInodeNumOut:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* computes length of UCS string converted to host codepage
|
||||
* @src: UCS string
|
||||
* @maxlen: length of the input string in UCS characters
|
||||
* (not in bytes)
|
||||
*
|
||||
* return: size of input string in host codepage
|
||||
*/
|
||||
static int hostlen_fromUCS(const __le16 *src, const int maxlen,
|
||||
const struct nls_table *nls_codepage) {
|
||||
int i;
|
||||
int hostlen = 0;
|
||||
char to[4];
|
||||
int charlen;
|
||||
for (i = 0; (i < maxlen) && src[i]; ++i) {
|
||||
charlen = nls_codepage->uni2char(le16_to_cpu(src[i]),
|
||||
to, NLS_MAX_CHARSET_SIZE);
|
||||
hostlen += charlen > 0 ? charlen : 1;
|
||||
}
|
||||
return hostlen;
|
||||
}
|
||||
|
||||
/* parses DFS refferal V3 structure
|
||||
* caller is responsible for freeing target_nodes
|
||||
* returns:
|
||||
@ -3994,7 +3939,7 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
|
||||
|
||||
cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
|
||||
*num_of_nodes,
|
||||
le16_to_cpu(pSMBr->DFSFlags)));
|
||||
le32_to_cpu(pSMBr->DFSFlags)));
|
||||
|
||||
*target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
|
||||
*num_of_nodes, GFP_KERNEL);
|
||||
@ -4010,14 +3955,14 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
|
||||
int max_len;
|
||||
struct dfs_info3_param *node = (*target_nodes)+i;
|
||||
|
||||
node->flags = le16_to_cpu(pSMBr->DFSFlags);
|
||||
node->flags = le32_to_cpu(pSMBr->DFSFlags);
|
||||
if (is_unicode) {
|
||||
__le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
|
||||
GFP_KERNEL);
|
||||
cifsConvertToUCS((__le16 *) tmp, searchName,
|
||||
PATH_MAX, nls_codepage, remap);
|
||||
node->path_consumed = hostlen_fromUCS(tmp,
|
||||
le16_to_cpu(pSMBr->PathConsumed)/2,
|
||||
node->path_consumed = cifs_ucs2_bytes(tmp,
|
||||
le16_to_cpu(pSMBr->PathConsumed),
|
||||
nls_codepage);
|
||||
kfree(tmp);
|
||||
} else
|
||||
@ -4029,20 +3974,24 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
|
||||
/* copy DfsPath */
|
||||
temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
|
||||
max_len = data_end - temp;
|
||||
rc = cifs_strncpy_to_host(&(node->path_name), temp,
|
||||
max_len, is_unicode, nls_codepage);
|
||||
if (rc)
|
||||
node->path_name = cifs_strndup_from_ucs(temp, max_len,
|
||||
is_unicode, nls_codepage);
|
||||
if (IS_ERR(node->path_name)) {
|
||||
rc = PTR_ERR(node->path_name);
|
||||
node->path_name = NULL;
|
||||
goto parse_DFS_referrals_exit;
|
||||
}
|
||||
|
||||
/* copy link target UNC */
|
||||
temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
|
||||
max_len = data_end - temp;
|
||||
rc = cifs_strncpy_to_host(&(node->node_name), temp,
|
||||
max_len, is_unicode, nls_codepage);
|
||||
if (rc)
|
||||
node->node_name = cifs_strndup_from_ucs(temp, max_len,
|
||||
is_unicode, nls_codepage);
|
||||
if (IS_ERR(node->node_name)) {
|
||||
rc = PTR_ERR(node->node_name);
|
||||
node->node_name = NULL;
|
||||
goto parse_DFS_referrals_exit;
|
||||
|
||||
ref += le16_to_cpu(ref->Size);
|
||||
}
|
||||
}
|
||||
|
||||
parse_DFS_referrals_exit:
|
||||
|
1190
fs/cifs/connect.c
1190
fs/cifs/connect.c
File diff suppressed because it is too large
Load Diff
@ -281,6 +281,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
||||
int create_options = CREATE_NOT_DIR;
|
||||
int oplock = 0;
|
||||
int oflags;
|
||||
bool posix_create = false;
|
||||
/*
|
||||
* BB below access is probably too much for mknod to request
|
||||
* but we have to do query and setpathinfo so requesting
|
||||
@ -328,11 +329,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
||||
negotation. EREMOTE indicates DFS junction, which is not
|
||||
handled in posix open */
|
||||
|
||||
if ((rc == 0) && (newinode == NULL))
|
||||
goto cifs_create_get_file_info; /* query inode info */
|
||||
else if (rc == 0) /* success, no need to query */
|
||||
goto cifs_create_set_dentry;
|
||||
else if ((rc != -EIO) && (rc != -EREMOTE) &&
|
||||
if (rc == 0) {
|
||||
posix_create = true;
|
||||
if (newinode == NULL) /* query inode info */
|
||||
goto cifs_create_get_file_info;
|
||||
else /* success, no need to query */
|
||||
goto cifs_create_set_dentry;
|
||||
} else if ((rc != -EIO) && (rc != -EREMOTE) &&
|
||||
(rc != -EOPNOTSUPP)) /* path not found or net err */
|
||||
goto cifs_create_out;
|
||||
/* else fallthrough to retry, using older open call, this is
|
||||
@ -464,7 +467,7 @@ cifs_create_set_dentry:
|
||||
if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) {
|
||||
/* mknod case - do not leave file open */
|
||||
CIFSSMBClose(xid, tcon, fileHandle);
|
||||
} else if (newinode) {
|
||||
} else if (!(posix_create) && (newinode)) {
|
||||
cifs_fill_fileinfo(newinode, fileHandle,
|
||||
cifs_sb->tcon, write_only);
|
||||
}
|
||||
|
@ -129,15 +129,12 @@ static inline int cifs_posix_open_inode_helper(struct inode *inode,
|
||||
struct file *file, struct cifsInodeInfo *pCifsInode,
|
||||
struct cifsFileInfo *pCifsFile, int oplock, u16 netfid)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
/* struct timespec temp; */ /* BB REMOVEME BB */
|
||||
|
||||
file->private_data = kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
|
||||
if (file->private_data == NULL)
|
||||
return -ENOMEM;
|
||||
pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList);
|
||||
|
||||
pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
|
||||
if (pCifsInode == NULL) {
|
||||
@ -145,17 +142,6 @@ static inline int cifs_posix_open_inode_helper(struct inode *inode,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* want handles we can use to read with first
|
||||
in the list so we do not have to walk the
|
||||
list to search for one in write_begin */
|
||||
if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
|
||||
list_add_tail(&pCifsFile->flist,
|
||||
&pCifsInode->openFileList);
|
||||
} else {
|
||||
list_add(&pCifsFile->flist,
|
||||
&pCifsInode->openFileList);
|
||||
}
|
||||
|
||||
if (pCifsInode->clientCanCacheRead) {
|
||||
/* we have the inode open somewhere else
|
||||
no need to discard cache data */
|
||||
|
@ -962,13 +962,21 @@ undo_setattr:
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If dentry->d_inode is null (usually meaning the cached dentry
|
||||
* is a negative dentry) then we would attempt a standard SMB delete, but
|
||||
* if that fails we can not attempt the fall back mechanisms on EACESS
|
||||
* but will return the EACESS to the caller. Note that the VFS does not call
|
||||
* unlink on negative dentries currently.
|
||||
*/
|
||||
int cifs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
int rc = 0;
|
||||
int xid;
|
||||
char *full_path = NULL;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
|
||||
struct cifsInodeInfo *cifs_inode;
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
struct cifsTconInfo *tcon = cifs_sb->tcon;
|
||||
@ -1012,7 +1020,7 @@ psx_del_no_retry:
|
||||
rc = cifs_rename_pending_delete(full_path, dentry, xid);
|
||||
if (rc == 0)
|
||||
drop_nlink(inode);
|
||||
} else if (rc == -EACCES && dosattr == 0) {
|
||||
} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
|
||||
attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
|
||||
if (attrs == NULL) {
|
||||
rc = -ENOMEM;
|
||||
@ -1020,7 +1028,8 @@ psx_del_no_retry:
|
||||
}
|
||||
|
||||
/* try to reset dos attributes */
|
||||
origattr = cifsInode->cifsAttrs;
|
||||
cifs_inode = CIFS_I(inode);
|
||||
origattr = cifs_inode->cifsAttrs;
|
||||
if (origattr == 0)
|
||||
origattr |= ATTR_NORMAL;
|
||||
dosattr = origattr & ~ATTR_READONLY;
|
||||
@ -1041,13 +1050,13 @@ psx_del_no_retry:
|
||||
|
||||
out_reval:
|
||||
if (inode) {
|
||||
cifsInode = CIFS_I(inode);
|
||||
cifsInode->time = 0; /* will force revalidate to get info
|
||||
cifs_inode = CIFS_I(inode);
|
||||
cifs_inode->time = 0; /* will force revalidate to get info
|
||||
when needed */
|
||||
inode->i_ctime = current_fs_time(sb);
|
||||
}
|
||||
dir->i_ctime = dir->i_mtime = current_fs_time(sb);
|
||||
cifsInode = CIFS_I(dir);
|
||||
cifs_inode = CIFS_I(dir);
|
||||
CIFS_I(dir)->time = 0; /* force revalidate of dir as well */
|
||||
|
||||
kfree(full_path);
|
||||
|
114
fs/cifs/link.c
114
fs/cifs/link.c
@ -119,16 +119,11 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
|
||||
full_path = build_path_from_dentry(direntry);
|
||||
|
||||
if (!full_path)
|
||||
goto out_no_free;
|
||||
goto out;
|
||||
|
||||
cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode));
|
||||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
pTcon = cifs_sb->tcon;
|
||||
target_path = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
if (!target_path) {
|
||||
target_path = ERR_PTR(-ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* We could change this to:
|
||||
if (pTcon->unix_ext)
|
||||
@ -138,8 +133,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
|
||||
|
||||
if (pTcon->ses->capabilities & CAP_UNIX)
|
||||
rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
|
||||
target_path,
|
||||
PATH_MAX-1,
|
||||
&target_path,
|
||||
cifs_sb->local_nls);
|
||||
else {
|
||||
/* BB add read reparse point symlink code here */
|
||||
@ -148,22 +142,16 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
|
||||
/* BB Add MAC style xsymlink check here if enabled */
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
|
||||
/* BB Add special case check for Samba DFS symlinks */
|
||||
|
||||
target_path[PATH_MAX-1] = 0;
|
||||
} else {
|
||||
if (rc != 0) {
|
||||
kfree(target_path);
|
||||
target_path = ERR_PTR(rc);
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(full_path);
|
||||
out_no_free:
|
||||
out:
|
||||
FreeXid(xid);
|
||||
nd_set_link(nd, target_path);
|
||||
return NULL; /* No cookie */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
@ -224,98 +212,6 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
|
||||
{
|
||||
struct inode *inode = direntry->d_inode;
|
||||
int rc = -EACCES;
|
||||
int xid;
|
||||
int oplock = 0;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo *pTcon;
|
||||
char *full_path = NULL;
|
||||
char *tmpbuffer;
|
||||
int len;
|
||||
__u16 fid;
|
||||
|
||||
xid = GetXid();
|
||||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
pTcon = cifs_sb->tcon;
|
||||
|
||||
/* BB would it be safe against deadlock to grab this sem
|
||||
even though rename itself grabs the sem and calls lookup? */
|
||||
/* mutex_lock(&inode->i_sb->s_vfs_rename_mutex);*/
|
||||
full_path = build_path_from_dentry(direntry);
|
||||
/* mutex_unlock(&inode->i_sb->s_vfs_rename_mutex);*/
|
||||
|
||||
if (full_path == NULL) {
|
||||
FreeXid(xid);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cFYI(1,
|
||||
("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d",
|
||||
full_path, inode, pBuffer, buflen));
|
||||
if (buflen > PATH_MAX)
|
||||
len = PATH_MAX;
|
||||
else
|
||||
len = buflen;
|
||||
tmpbuffer = kmalloc(len, GFP_KERNEL);
|
||||
if (tmpbuffer == NULL) {
|
||||
kfree(full_path);
|
||||
FreeXid(xid);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* BB add read reparse point symlink code and
|
||||
Unix extensions symlink code here BB */
|
||||
/* We could disable this based on pTcon->unix_ext flag instead ... but why? */
|
||||
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
|
||||
rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
|
||||
tmpbuffer,
|
||||
len - 1,
|
||||
cifs_sb->local_nls);
|
||||
else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
|
||||
cERROR(1, ("SFU style symlinks not implemented yet"));
|
||||
/* add open and read as in fs/cifs/inode.c */
|
||||
} else {
|
||||
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
|
||||
OPEN_REPARSE_POINT, &fid, &oplock, NULL,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (!rc) {
|
||||
rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
|
||||
tmpbuffer,
|
||||
len - 1,
|
||||
fid,
|
||||
cifs_sb->local_nls);
|
||||
if (CIFSSMBClose(xid, pTcon, fid)) {
|
||||
cFYI(1, ("Error closing junction point "
|
||||
"(open for ioctl)"));
|
||||
}
|
||||
/* If it is a DFS junction earlier we would have gotten
|
||||
PATH_NOT_COVERED returned from server so we do
|
||||
not need to request the DFS info here */
|
||||
}
|
||||
}
|
||||
/* BB Anything else to do to handle recursive links? */
|
||||
/* BB Should we be using page ops here? */
|
||||
|
||||
/* BB null terminate returned string in pBuffer? BB */
|
||||
if (rc == 0) {
|
||||
rc = vfs_readlink(direntry, pBuffer, len, tmpbuffer);
|
||||
cFYI(1,
|
||||
("vfs_readlink called from cifs_readlink returned %d",
|
||||
rc));
|
||||
}
|
||||
|
||||
kfree(tmpbuffer);
|
||||
kfree(full_path);
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie)
|
||||
{
|
||||
char *p = nd_get_link(nd);
|
||||
|
@ -635,77 +635,6 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Windows maps these to the user defined 16 bit Unicode range since they are
|
||||
reserved symbols (along with \ and /), otherwise illegal to store
|
||||
in filenames in NTFS */
|
||||
#define UNI_ASTERIK (__u16) ('*' + 0xF000)
|
||||
#define UNI_QUESTION (__u16) ('?' + 0xF000)
|
||||
#define UNI_COLON (__u16) (':' + 0xF000)
|
||||
#define UNI_GRTRTHAN (__u16) ('>' + 0xF000)
|
||||
#define UNI_LESSTHAN (__u16) ('<' + 0xF000)
|
||||
#define UNI_PIPE (__u16) ('|' + 0xF000)
|
||||
#define UNI_SLASH (__u16) ('\\' + 0xF000)
|
||||
|
||||
/* Convert 16 bit Unicode pathname from wire format to string in current code
|
||||
page. Conversion may involve remapping up the seven characters that are
|
||||
only legal in POSIX-like OS (if they are present in the string). Path
|
||||
names are little endian 16 bit Unicode on the wire */
|
||||
int
|
||||
cifs_convertUCSpath(char *target, const __le16 *source, int maxlen,
|
||||
const struct nls_table *cp)
|
||||
{
|
||||
int i, j, len;
|
||||
__u16 src_char;
|
||||
|
||||
for (i = 0, j = 0; i < maxlen; i++) {
|
||||
src_char = le16_to_cpu(source[i]);
|
||||
switch (src_char) {
|
||||
case 0:
|
||||
goto cUCS_out; /* BB check this BB */
|
||||
case UNI_COLON:
|
||||
target[j] = ':';
|
||||
break;
|
||||
case UNI_ASTERIK:
|
||||
target[j] = '*';
|
||||
break;
|
||||
case UNI_QUESTION:
|
||||
target[j] = '?';
|
||||
break;
|
||||
/* BB We can not handle remapping slash until
|
||||
all the calls to build_path_from_dentry
|
||||
are modified, as they use slash as separator BB */
|
||||
/* case UNI_SLASH:
|
||||
target[j] = '\\';
|
||||
break;*/
|
||||
case UNI_PIPE:
|
||||
target[j] = '|';
|
||||
break;
|
||||
case UNI_GRTRTHAN:
|
||||
target[j] = '>';
|
||||
break;
|
||||
case UNI_LESSTHAN:
|
||||
target[j] = '<';
|
||||
break;
|
||||
default:
|
||||
len = cp->uni2char(src_char, &target[j],
|
||||
NLS_MAX_CHARSET_SIZE);
|
||||
if (len > 0) {
|
||||
j += len;
|
||||
continue;
|
||||
} else {
|
||||
target[j] = '?';
|
||||
}
|
||||
}
|
||||
j++;
|
||||
/* make sure we do not overrun callers allocated temp buffer */
|
||||
if (j >= (2 * NAME_MAX))
|
||||
break;
|
||||
}
|
||||
cUCS_out:
|
||||
target[j] = 0;
|
||||
return j;
|
||||
}
|
||||
|
||||
/* Convert 16 bit Unicode pathname to wire format from string in current code
|
||||
page. Conversion may involve remapping up the seven characters that are
|
||||
only legal in POSIX-like OS (if they are present in the string). Path
|
||||
|
@ -79,6 +79,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
|
||||
{ErrQuota, -EDQUOT},
|
||||
{ErrNotALink, -ENOLINK},
|
||||
{ERRnetlogonNotStarted, -ENOPROTOOPT},
|
||||
{ERRsymlink, -EOPNOTSUPP},
|
||||
{ErrTooManyLinks, -EMLINK},
|
||||
{0, 0}
|
||||
};
|
||||
@ -714,6 +715,7 @@ static const struct {
|
||||
ERRDOS, ERRnoaccess, 0xc000028f}, {
|
||||
ERRDOS, ERRnoaccess, 0xc0000290}, {
|
||||
ERRDOS, ERRbadfunc, 0xc000029c}, {
|
||||
ERRDOS, ERRsymlink, NT_STATUS_STOPPED_ON_SYMLINK}, {
|
||||
ERRDOS, ERRinvlevel, 0x007c0001}, };
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -35,8 +35,6 @@ struct nt_err_code_struct {
|
||||
extern const struct nt_err_code_struct nt_errs[];
|
||||
|
||||
/* Win32 Status codes. */
|
||||
|
||||
#define STATUS_BUFFER_OVERFLOW 0x80000005
|
||||
#define STATUS_MORE_ENTRIES 0x0105
|
||||
#define ERROR_INVALID_PARAMETER 0x0057
|
||||
#define ERROR_INSUFFICIENT_BUFFER 0x007a
|
||||
@ -50,6 +48,13 @@ extern const struct nt_err_code_struct nt_errs[];
|
||||
#define STATUS_SOME_UNMAPPED 0x0107
|
||||
#define STATUS_BUFFER_OVERFLOW 0x80000005
|
||||
#define NT_STATUS_NO_MORE_ENTRIES 0x8000001a
|
||||
#define NT_STATUS_MEDIA_CHANGED 0x8000001c
|
||||
#define NT_STATUS_END_OF_MEDIA 0x8000001e
|
||||
#define NT_STATUS_MEDIA_CHECK 0x80000020
|
||||
#define NT_STATUS_NO_DATA_DETECTED 0x8000001c
|
||||
#define NT_STATUS_STOPPED_ON_SYMLINK 0x8000002d
|
||||
#define NT_STATUS_DEVICE_REQUIRES_CLEANING 0x80000288
|
||||
#define NT_STATUS_DEVICE_DOOR_OPEN 0x80000288
|
||||
#define NT_STATUS_UNSUCCESSFUL 0xC0000000 | 0x0001
|
||||
#define NT_STATUS_NOT_IMPLEMENTED 0xC0000000 | 0x0002
|
||||
#define NT_STATUS_INVALID_INFO_CLASS 0xC0000000 | 0x0003
|
||||
|
@ -27,29 +27,39 @@
|
||||
#define UnknownMessage cpu_to_le32(8)
|
||||
|
||||
/* Negotiate Flags */
|
||||
#define NTLMSSP_NEGOTIATE_UNICODE 0x01 /* Text strings are in unicode */
|
||||
#define NTLMSSP_NEGOTIATE_OEM 0x02 /* Text strings are in OEM */
|
||||
#define NTLMSSP_REQUEST_TARGET 0x04 /* Server return its auth realm */
|
||||
#define NTLMSSP_NEGOTIATE_SIGN 0x0010 /* Request signature capability */
|
||||
#define NTLMSSP_NEGOTIATE_SEAL 0x0020 /* Request confidentiality */
|
||||
#define NTLMSSP_NEGOTIATE_DGRAM 0x0040
|
||||
#define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 /* Sign/seal use LM session key */
|
||||
#define NTLMSSP_NEGOTIATE_NTLM 0x0200 /* NTLM authentication */
|
||||
#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000
|
||||
#define NTLMSSP_NEGOTIATE_UNICODE 0x01 /* Text strings are unicode */
|
||||
#define NTLMSSP_NEGOTIATE_OEM 0x02 /* Text strings are in OEM */
|
||||
#define NTLMSSP_REQUEST_TARGET 0x04 /* Srv returns its auth realm */
|
||||
/* define reserved9 0x08 */
|
||||
#define NTLMSSP_NEGOTIATE_SIGN 0x0010 /* Request signing capability */
|
||||
#define NTLMSSP_NEGOTIATE_SEAL 0x0020 /* Request confidentiality */
|
||||
#define NTLMSSP_NEGOTIATE_DGRAM 0x0040
|
||||
#define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 /* Use LM session key */
|
||||
/* defined reserved 8 0x0100 */
|
||||
#define NTLMSSP_NEGOTIATE_NTLM 0x0200 /* NTLM authentication */
|
||||
#define NTLMSSP_NEGOTIATE_NT_ONLY 0x0400 /* Lanman not allowed */
|
||||
#define NTLMSSP_ANONYMOUS 0x0800
|
||||
#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000 /* reserved6 */
|
||||
#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000
|
||||
#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 /* client/server on same machine */
|
||||
#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 /* Sign for all security levels */
|
||||
#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000
|
||||
#define NTLMSSP_TARGET_TYPE_SERVER 0x20000
|
||||
#define NTLMSSP_TARGET_TYPE_SHARE 0x40000
|
||||
#define NTLMSSP_NEGOTIATE_NTLMV2 0x80000
|
||||
#define NTLMSSP_REQUEST_INIT_RESP 0x100000
|
||||
#define NTLMSSP_REQUEST_ACCEPT_RESP 0x200000
|
||||
#define NTLMSSP_REQUEST_NOT_NT_KEY 0x400000
|
||||
#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 /* client/server same machine */
|
||||
#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 /* Sign. All security levels */
|
||||
#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000
|
||||
#define NTLMSSP_TARGET_TYPE_SERVER 0x20000
|
||||
#define NTLMSSP_TARGET_TYPE_SHARE 0x40000
|
||||
#define NTLMSSP_NEGOTIATE_EXTENDED_SEC 0x80000 /* NB:not related to NTLMv2 pwd*/
|
||||
/* #define NTLMSSP_REQUEST_INIT_RESP 0x100000 */
|
||||
#define NTLMSSP_NEGOTIATE_IDENTIFY 0x100000
|
||||
#define NTLMSSP_REQUEST_ACCEPT_RESP 0x200000 /* reserved5 */
|
||||
#define NTLMSSP_REQUEST_NON_NT_KEY 0x400000
|
||||
#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000
|
||||
#define NTLMSSP_NEGOTIATE_128 0x20000000
|
||||
#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000
|
||||
#define NTLMSSP_NEGOTIATE_56 0x80000000
|
||||
/* #define reserved4 0x1000000 */
|
||||
#define NTLMSSP_NEGOTIATE_VERSION 0x2000000 /* we do not set */
|
||||
/* #define reserved3 0x4000000 */
|
||||
/* #define reserved2 0x8000000 */
|
||||
/* #define reserved1 0x10000000 */
|
||||
#define NTLMSSP_NEGOTIATE_128 0x20000000
|
||||
#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000
|
||||
#define NTLMSSP_NEGOTIATE_56 0x80000000
|
||||
|
||||
/* Although typedefs are not commonly used for structure definitions */
|
||||
/* in the Linux kernel, in this particular case they are useful */
|
||||
@ -60,32 +70,36 @@
|
||||
typedef struct _SECURITY_BUFFER {
|
||||
__le16 Length;
|
||||
__le16 MaximumLength;
|
||||
__le32 Buffer; /* offset to buffer */
|
||||
__le32 BufferOffset; /* offset to buffer */
|
||||
} __attribute__((packed)) SECURITY_BUFFER;
|
||||
|
||||
typedef struct _NEGOTIATE_MESSAGE {
|
||||
__u8 Signature[sizeof(NTLMSSP_SIGNATURE)];
|
||||
__le32 MessageType; /* 1 */
|
||||
__le32 MessageType; /* NtLmNegotiate = 1 */
|
||||
__le32 NegotiateFlags;
|
||||
SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */
|
||||
SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */
|
||||
/* SECURITY_BUFFER for version info not present since we
|
||||
do not set the version is present flag */
|
||||
char DomainString[0];
|
||||
/* followed by WorkstationString */
|
||||
} __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
|
||||
|
||||
typedef struct _CHALLENGE_MESSAGE {
|
||||
__u8 Signature[sizeof(NTLMSSP_SIGNATURE)];
|
||||
__le32 MessageType; /* 2 */
|
||||
__le32 MessageType; /* NtLmChallenge = 2 */
|
||||
SECURITY_BUFFER TargetName;
|
||||
__le32 NegotiateFlags;
|
||||
__u8 Challenge[CIFS_CRYPTO_KEY_SIZE];
|
||||
__u8 Reserved[8];
|
||||
SECURITY_BUFFER TargetInfoArray;
|
||||
/* SECURITY_BUFFER for version info not present since we
|
||||
do not set the version is present flag */
|
||||
} __attribute__((packed)) CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE;
|
||||
|
||||
typedef struct _AUTHENTICATE_MESSAGE {
|
||||
__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
|
||||
__le32 MessageType; /* 3 */
|
||||
__u8 Signature[sizeof(NTLMSSP_SIGNATURE)];
|
||||
__le32 MessageType; /* NtLmsAuthenticate = 3 */
|
||||
SECURITY_BUFFER LmChallengeResponse;
|
||||
SECURITY_BUFFER NtChallengeResponse;
|
||||
SECURITY_BUFFER DomainName;
|
||||
@ -93,5 +107,7 @@ typedef struct _AUTHENTICATE_MESSAGE {
|
||||
SECURITY_BUFFER WorkstationName;
|
||||
SECURITY_BUFFER SessionKey;
|
||||
__le32 NegotiateFlags;
|
||||
/* SECURITY_BUFFER for version info not present since we
|
||||
do not set the version is present flag */
|
||||
char UserString[0];
|
||||
} __attribute__((packed)) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
|
||||
|
@ -31,6 +31,13 @@
|
||||
#include "cifs_fs_sb.h"
|
||||
#include "cifsfs.h"
|
||||
|
||||
/*
|
||||
* To be safe - for UCS to UTF-8 with strings loaded with the rare long
|
||||
* characters alloc more to account for such multibyte target UTF-8
|
||||
* characters.
|
||||
*/
|
||||
#define UNICODE_NAME_MAX ((4 * NAME_MAX) + 2)
|
||||
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
static void dump_cifs_file_struct(struct file *file, char *label)
|
||||
{
|
||||
@ -438,6 +445,38 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
|
||||
}
|
||||
}
|
||||
|
||||
/* BB eventually need to add the following helper function to
|
||||
resolve NT_STATUS_STOPPED_ON_SYMLINK return code when
|
||||
we try to do FindFirst on (NTFS) directory symlinks */
|
||||
/*
|
||||
int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
|
||||
int xid)
|
||||
{
|
||||
__u16 fid;
|
||||
int len;
|
||||
int oplock = 0;
|
||||
int rc;
|
||||
struct cifsTconInfo *ptcon = cifs_sb->tcon;
|
||||
char *tmpbuffer;
|
||||
|
||||
rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ,
|
||||
OPEN_REPARSE_POINT, &fid, &oplock, NULL,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (!rc) {
|
||||
tmpbuffer = kmalloc(maxpath);
|
||||
rc = CIFSSMBQueryReparseLinkInfo(xid, ptcon, full_path,
|
||||
tmpbuffer,
|
||||
maxpath -1,
|
||||
fid,
|
||||
cifs_sb->local_nls);
|
||||
if (CIFSSMBClose(xid, ptcon, fid)) {
|
||||
cFYI(1, ("Error closing temporary reparsepoint open)"));
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static int initiate_cifs_search(const int xid, struct file *file)
|
||||
{
|
||||
int rc = 0;
|
||||
@ -493,7 +532,10 @@ ffirst_retry:
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
|
||||
if (rc == 0)
|
||||
cifsFile->invalidHandle = false;
|
||||
if ((rc == -EOPNOTSUPP) &&
|
||||
/* BB add following call to handle readdir on new NTFS symlink errors
|
||||
else if STATUS_STOPPED_ON_SYMLINK
|
||||
call get_symlink_reparse_path and retry with new path */
|
||||
else if ((rc == -EOPNOTSUPP) &&
|
||||
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
|
||||
cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
|
||||
goto ffirst_retry;
|
||||
@ -822,7 +864,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
|
||||
/* 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)
|
||||
struct cifs_sb_info *cifs_sb, unsigned int max_len, __u64 *pinum)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned int len = 0;
|
||||
@ -881,14 +923,12 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
|
||||
}
|
||||
|
||||
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);
|
||||
pqst->len = cifs_from_ucs2((char *) pqst->name,
|
||||
(__le16 *) filename,
|
||||
UNICODE_NAME_MAX,
|
||||
min(len, max_len), nlt,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
} else {
|
||||
pqst->name = filename;
|
||||
pqst->len = len;
|
||||
@ -898,8 +938,8 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cifs_filldir(char *pfindEntry, struct file *file,
|
||||
filldir_t filldir, void *direntry, char *scratch_buf, int max_len)
|
||||
static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
|
||||
void *direntry, char *scratch_buf, unsigned int max_len)
|
||||
{
|
||||
int rc = 0;
|
||||
struct qstr qstring;
|
||||
@ -996,7 +1036,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
|
||||
int num_to_fill = 0;
|
||||
char *tmp_buf = NULL;
|
||||
char *end_of_smb;
|
||||
int max_len;
|
||||
unsigned int max_len;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
@ -1070,11 +1110,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
|
||||
cifsFile->srch_inf.ntwrk_buf_start);
|
||||
end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
|
||||
|
||||
/* To be safe - for UCS to UTF-8 with strings loaded
|
||||
with the rare long characters alloc more to account for
|
||||
such multibyte target UTF-8 characters. cifs_unicode.c,
|
||||
which actually does the conversion, has the same limit */
|
||||
tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL);
|
||||
tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
|
||||
for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
|
||||
if (current_entry == NULL) {
|
||||
/* evaluate whether this case is an error */
|
||||
|
340
fs/cifs/sess.c
340
fs/cifs/sess.c
@ -3,7 +3,7 @@
|
||||
*
|
||||
* SMB/CIFS session setup handling routines
|
||||
*
|
||||
* Copyright (c) International Business Machines Corp., 2006, 2007
|
||||
* Copyright (c) International Business Machines Corp., 2006, 2009
|
||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
@ -111,7 +111,7 @@ static __le16 get_next_vcnum(struct cifsSesInfo *ses)
|
||||
get_vc_num_exit:
|
||||
write_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
return le16_to_cpu(vcnum);
|
||||
return cpu_to_le16(vcnum);
|
||||
}
|
||||
|
||||
static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
|
||||
@ -277,12 +277,11 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
|
||||
*pbcc_area = bcc_ptr;
|
||||
}
|
||||
|
||||
static int decode_unicode_ssetup(char **pbcc_area, int bleft,
|
||||
struct cifsSesInfo *ses,
|
||||
const struct nls_table *nls_cp)
|
||||
static void
|
||||
decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses,
|
||||
const struct nls_table *nls_cp)
|
||||
{
|
||||
int rc = 0;
|
||||
int words_left, len;
|
||||
int len;
|
||||
char *data = *pbcc_area;
|
||||
|
||||
cFYI(1, ("bleft %d", bleft));
|
||||
@ -300,63 +299,29 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft,
|
||||
++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) + 2 /* trailing null */, GFP_KERNEL);
|
||||
if (ses->serverOS != NULL) {
|
||||
cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp);
|
||||
cFYI(1, ("serverOS=%s", ses->serverOS));
|
||||
}
|
||||
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;
|
||||
ses->serverOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp);
|
||||
cFYI(1, ("serverOS=%s", ses->serverOS));
|
||||
len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2;
|
||||
data += len;
|
||||
bleft -= len;
|
||||
if (bleft <= 0)
|
||||
return;
|
||||
|
||||
kfree(ses->serverNOS);
|
||||
ses->serverNOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL);
|
||||
if (ses->serverNOS != NULL) {
|
||||
cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len,
|
||||
nls_cp);
|
||||
cFYI(1, ("serverNOS=%s", ses->serverNOS));
|
||||
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;
|
||||
ses->serverNOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp);
|
||||
cFYI(1, ("serverNOS=%s", ses->serverNOS));
|
||||
len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2;
|
||||
data += len;
|
||||
bleft -= len;
|
||||
if (bleft <= 0)
|
||||
return;
|
||||
|
||||
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);
|
||||
cFYI(1, ("serverDomain=%s", ses->serverDomain));
|
||||
}
|
||||
data += 2 * (len + 1);
|
||||
words_left -= len + 1;
|
||||
ses->serverDomain = cifs_strndup_from_ucs(data, bleft, true, nls_cp);
|
||||
cFYI(1, ("serverDomain=%s", ses->serverDomain));
|
||||
|
||||
cFYI(1, ("words left: %d", words_left));
|
||||
|
||||
return rc;
|
||||
return;
|
||||
}
|
||||
|
||||
static int decode_ascii_ssetup(char **pbcc_area, int bleft,
|
||||
@ -413,6 +378,186 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
|
||||
struct cifsSesInfo *ses)
|
||||
{
|
||||
CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr;
|
||||
|
||||
if (blob_len < sizeof(CHALLENGE_MESSAGE)) {
|
||||
cERROR(1, ("challenge blob len %d too small", blob_len));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (memcmp(pblob->Signature, "NTLMSSP", 8)) {
|
||||
cERROR(1, ("blob signature incorrect %s", pblob->Signature));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (pblob->MessageType != NtLmChallenge) {
|
||||
cERROR(1, ("Incorrect message type %d", pblob->MessageType));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(ses->server->cryptKey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE);
|
||||
/* BB we could decode pblob->NegotiateFlags; some may be useful */
|
||||
/* In particular we can examine sign flags */
|
||||
/* BB spec says that if AvId field of MsvAvTimestamp is populated then
|
||||
we must set the MIC field of the AUTHENTICATE_MESSAGE */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
/* BB Move to ntlmssp.c eventually */
|
||||
|
||||
/* We do not malloc the blob, it is passed in pbuffer, because
|
||||
it is fixed size, and small, making this approach cleaner */
|
||||
static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
|
||||
struct cifsSesInfo *ses)
|
||||
{
|
||||
NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer;
|
||||
__u32 flags;
|
||||
|
||||
memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
|
||||
sec_blob->MessageType = NtLmNegotiate;
|
||||
|
||||
/* BB is NTLMV2 session security format easier to use here? */
|
||||
flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET |
|
||||
NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
|
||||
NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM;
|
||||
if (ses->server->secMode &
|
||||
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
|
||||
flags |= NTLMSSP_NEGOTIATE_SIGN;
|
||||
if (ses->server->secMode & SECMODE_SIGN_REQUIRED)
|
||||
flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
|
||||
|
||||
sec_blob->NegotiateFlags |= cpu_to_le32(flags);
|
||||
|
||||
sec_blob->WorkstationName.BufferOffset = 0;
|
||||
sec_blob->WorkstationName.Length = 0;
|
||||
sec_blob->WorkstationName.MaximumLength = 0;
|
||||
|
||||
/* Domain name is sent on the Challenge not Negotiate NTLMSSP request */
|
||||
sec_blob->DomainName.BufferOffset = 0;
|
||||
sec_blob->DomainName.Length = 0;
|
||||
sec_blob->DomainName.MaximumLength = 0;
|
||||
}
|
||||
|
||||
/* We do not malloc the blob, it is passed in pbuffer, because its
|
||||
maximum possible size is fixed and small, making this approach cleaner.
|
||||
This function returns the length of the data in the blob */
|
||||
static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
|
||||
struct cifsSesInfo *ses,
|
||||
const struct nls_table *nls_cp, int first)
|
||||
{
|
||||
AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer;
|
||||
__u32 flags;
|
||||
unsigned char *tmp;
|
||||
char ntlm_session_key[CIFS_SESS_KEY_SIZE];
|
||||
|
||||
memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
|
||||
sec_blob->MessageType = NtLmAuthenticate;
|
||||
|
||||
flags = NTLMSSP_NEGOTIATE_56 |
|
||||
NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
|
||||
NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
|
||||
NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM;
|
||||
if (ses->server->secMode &
|
||||
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
|
||||
flags |= NTLMSSP_NEGOTIATE_SIGN;
|
||||
if (ses->server->secMode & SECMODE_SIGN_REQUIRED)
|
||||
flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
|
||||
|
||||
tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE);
|
||||
sec_blob->NegotiateFlags |= cpu_to_le32(flags);
|
||||
|
||||
sec_blob->LmChallengeResponse.BufferOffset =
|
||||
cpu_to_le32(sizeof(AUTHENTICATE_MESSAGE));
|
||||
sec_blob->LmChallengeResponse.Length = 0;
|
||||
sec_blob->LmChallengeResponse.MaximumLength = 0;
|
||||
|
||||
/* calculate session key, BB what about adding similar ntlmv2 path? */
|
||||
SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key);
|
||||
if (first)
|
||||
cifs_calculate_mac_key(&ses->server->mac_signing_key,
|
||||
ntlm_session_key, ses->password);
|
||||
|
||||
memcpy(tmp, ntlm_session_key, CIFS_SESS_KEY_SIZE);
|
||||
sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer);
|
||||
sec_blob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE);
|
||||
sec_blob->NtChallengeResponse.MaximumLength =
|
||||
cpu_to_le16(CIFS_SESS_KEY_SIZE);
|
||||
|
||||
tmp += CIFS_SESS_KEY_SIZE;
|
||||
|
||||
if (ses->domainName == NULL) {
|
||||
sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
|
||||
sec_blob->DomainName.Length = 0;
|
||||
sec_blob->DomainName.MaximumLength = 0;
|
||||
tmp += 2;
|
||||
} else {
|
||||
int len;
|
||||
len = cifs_strtoUCS((__le16 *)tmp, ses->domainName,
|
||||
MAX_USERNAME_SIZE, nls_cp);
|
||||
len *= 2; /* unicode is 2 bytes each */
|
||||
len += 2; /* trailing null */
|
||||
sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
|
||||
sec_blob->DomainName.Length = cpu_to_le16(len);
|
||||
sec_blob->DomainName.MaximumLength = cpu_to_le16(len);
|
||||
tmp += len;
|
||||
}
|
||||
|
||||
if (ses->userName == NULL) {
|
||||
sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer);
|
||||
sec_blob->UserName.Length = 0;
|
||||
sec_blob->UserName.MaximumLength = 0;
|
||||
tmp += 2;
|
||||
} else {
|
||||
int len;
|
||||
len = cifs_strtoUCS((__le16 *)tmp, ses->userName,
|
||||
MAX_USERNAME_SIZE, nls_cp);
|
||||
len *= 2; /* unicode is 2 bytes each */
|
||||
len += 2; /* trailing null */
|
||||
sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer);
|
||||
sec_blob->UserName.Length = cpu_to_le16(len);
|
||||
sec_blob->UserName.MaximumLength = cpu_to_le16(len);
|
||||
tmp += len;
|
||||
}
|
||||
|
||||
sec_blob->WorkstationName.BufferOffset = cpu_to_le32(tmp - pbuffer);
|
||||
sec_blob->WorkstationName.Length = 0;
|
||||
sec_blob->WorkstationName.MaximumLength = 0;
|
||||
tmp += 2;
|
||||
|
||||
sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
|
||||
sec_blob->SessionKey.Length = 0;
|
||||
sec_blob->SessionKey.MaximumLength = 0;
|
||||
return tmp - pbuffer;
|
||||
}
|
||||
|
||||
|
||||
static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB,
|
||||
struct cifsSesInfo *ses)
|
||||
{
|
||||
build_ntlmssp_negotiate_blob(&pSMB->req.SecurityBlob[0], ses);
|
||||
pSMB->req.SecurityBlobLength = cpu_to_le16(sizeof(NEGOTIATE_MESSAGE));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int setup_ntlmssp_auth_req(SESSION_SETUP_ANDX *pSMB,
|
||||
struct cifsSesInfo *ses,
|
||||
const struct nls_table *nls, int first_time)
|
||||
{
|
||||
int bloblen;
|
||||
|
||||
bloblen = build_ntlmssp_auth_blob(&pSMB->req.SecurityBlob[0], ses, nls,
|
||||
first_time);
|
||||
pSMB->req.SecurityBlobLength = cpu_to_le16(bloblen);
|
||||
|
||||
return bloblen;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
||||
const struct nls_table *nls_cp)
|
||||
@ -431,6 +576,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
||||
__u16 action;
|
||||
int bytes_remaining;
|
||||
struct key *spnego_key = NULL;
|
||||
__le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
|
||||
|
||||
if (ses == NULL)
|
||||
return -EINVAL;
|
||||
@ -438,6 +584,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
||||
type = ses->server->secType;
|
||||
|
||||
cFYI(1, ("sess setup type %d", type));
|
||||
ssetup_ntlmssp_authenticate:
|
||||
if (phase == NtLmChallenge)
|
||||
phase = NtLmAuthenticate; /* if ntlmssp, now final phase */
|
||||
|
||||
if (type == LANMAN) {
|
||||
#ifndef CONFIG_CIFS_WEAK_PW_HASH
|
||||
/* LANMAN and plaintext are less secure and off by default.
|
||||
@ -651,9 +801,53 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
||||
goto ssetup_exit;
|
||||
#endif /* CONFIG_CIFS_UPCALL */
|
||||
} else {
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
if ((experimEnabled > 1) && (type == RawNTLMSSP)) {
|
||||
if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
|
||||
cERROR(1, ("NTLMSSP requires Unicode support"));
|
||||
rc = -ENOSYS;
|
||||
goto ssetup_exit;
|
||||
}
|
||||
|
||||
cFYI(1, ("ntlmssp session setup phase %d", phase));
|
||||
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
capabilities |= CAP_EXTENDED_SECURITY;
|
||||
pSMB->req.Capabilities |= cpu_to_le32(capabilities);
|
||||
if (phase == NtLmNegotiate) {
|
||||
setup_ntlmssp_neg_req(pSMB, ses);
|
||||
iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE);
|
||||
} else if (phase == NtLmAuthenticate) {
|
||||
int blob_len;
|
||||
blob_len = setup_ntlmssp_auth_req(pSMB, ses,
|
||||
nls_cp,
|
||||
first_time);
|
||||
iov[1].iov_len = blob_len;
|
||||
/* Make sure that we tell the server that we
|
||||
are using the uid that it just gave us back
|
||||
on the response (challenge) */
|
||||
smb_buf->Uid = ses->Suid;
|
||||
} else {
|
||||
cERROR(1, ("invalid phase %d", phase));
|
||||
rc = -ENOSYS;
|
||||
goto ssetup_exit;
|
||||
}
|
||||
iov[1].iov_base = &pSMB->req.SecurityBlob[0];
|
||||
/* unicode strings must be word aligned */
|
||||
if ((iov[0].iov_len + iov[1].iov_len) % 2) {
|
||||
*bcc_ptr = 0;
|
||||
bcc_ptr++;
|
||||
}
|
||||
unicode_oslm_strings(&bcc_ptr, nls_cp);
|
||||
} else {
|
||||
cERROR(1, ("secType %d not supported!", type));
|
||||
rc = -ENOSYS;
|
||||
goto ssetup_exit;
|
||||
}
|
||||
#else
|
||||
cERROR(1, ("secType %d not supported!", type));
|
||||
rc = -ENOSYS;
|
||||
goto ssetup_exit;
|
||||
#endif
|
||||
}
|
||||
|
||||
iov[2].iov_base = str_area;
|
||||
@ -669,12 +863,23 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
||||
/* SMB request buf freed in SendReceive2 */
|
||||
|
||||
cFYI(1, ("ssetup rc from sendrecv2 is %d", rc));
|
||||
if (rc)
|
||||
goto ssetup_exit;
|
||||
|
||||
pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
|
||||
smb_buf = (struct smb_hdr *)iov[0].iov_base;
|
||||
|
||||
if ((type == RawNTLMSSP) && (smb_buf->Status.CifsError ==
|
||||
cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))) {
|
||||
if (phase != NtLmNegotiate) {
|
||||
cERROR(1, ("Unexpected more processing error"));
|
||||
goto ssetup_exit;
|
||||
}
|
||||
/* NTLMSSP Negotiate sent now processing challenge (response) */
|
||||
phase = NtLmChallenge; /* process ntlmssp challenge */
|
||||
rc = 0; /* MORE_PROC rc is not an error here, but expected */
|
||||
}
|
||||
if (rc)
|
||||
goto ssetup_exit;
|
||||
|
||||
if ((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) {
|
||||
rc = -EIO;
|
||||
cERROR(1, ("bad word count %d", smb_buf->WordCount));
|
||||
@ -693,12 +898,18 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
||||
if (smb_buf->WordCount == 4) {
|
||||
__u16 blob_len;
|
||||
blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
|
||||
bcc_ptr += blob_len;
|
||||
if (blob_len > bytes_remaining) {
|
||||
cERROR(1, ("bad security blob length %d", blob_len));
|
||||
rc = -EINVAL;
|
||||
goto ssetup_exit;
|
||||
}
|
||||
if (phase == NtLmChallenge) {
|
||||
rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses);
|
||||
/* now goto beginning for ntlmssp authenticate phase */
|
||||
if (rc)
|
||||
goto ssetup_exit;
|
||||
}
|
||||
bcc_ptr += blob_len;
|
||||
bytes_remaining -= blob_len;
|
||||
}
|
||||
|
||||
@ -709,8 +920,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
||||
++bcc_ptr;
|
||||
--bytes_remaining;
|
||||
}
|
||||
rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining,
|
||||
ses, nls_cp);
|
||||
decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp);
|
||||
} else {
|
||||
rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining,
|
||||
ses, nls_cp);
|
||||
@ -728,5 +938,9 @@ ssetup_exit:
|
||||
} else if (resp_buf_type == CIFS_LARGE_BUFFER)
|
||||
cifs_buf_release(iov[0].iov_base);
|
||||
|
||||
/* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */
|
||||
if ((phase == NtLmChallenge) && (rc == 0))
|
||||
goto ssetup_ntlmssp_authenticate;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -110,6 +110,7 @@
|
||||
|
||||
/* Below errors are used internally (do not come over the wire) for passthrough
|
||||
from STATUS codes to POSIX only */
|
||||
#define ERRsymlink 0xFFFD
|
||||
#define ErrTooManyLinks 0xFFFE
|
||||
|
||||
/* Following error codes may be generated with the ERRSRV error class.*/
|
||||
|
@ -58,6 +58,25 @@ static inline int nls_strnicmp(struct nls_table *t, const unsigned char *s1,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* nls_nullsize - return length of null character for codepage
|
||||
* @codepage - codepage for which to return length of NULL terminator
|
||||
*
|
||||
* Since we can't guarantee that the null terminator will be a particular
|
||||
* length, we have to check against the codepage. If there's a problem
|
||||
* determining it, assume a single-byte NULL terminator.
|
||||
*/
|
||||
static inline int
|
||||
nls_nullsize(const struct nls_table *codepage)
|
||||
{
|
||||
int charlen;
|
||||
char tmp[NLS_MAX_CHARSET_SIZE];
|
||||
|
||||
charlen = codepage->uni2char(0, tmp, NLS_MAX_CHARSET_SIZE);
|
||||
|
||||
return charlen > 0 ? charlen : 1;
|
||||
}
|
||||
|
||||
#define MODULE_ALIAS_NLS(name) MODULE_ALIAS("nls_" __stringify(name))
|
||||
|
||||
#endif /* _LINUX_NLS_H */
|
||||
|
Loading…
Reference in New Issue
Block a user