mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
[CIFS] Support for setting up SMB sessions to legacy lanman servers
This commit is contained in:
parent
26a21b980b
commit
3979877e56
20 changed files with 836 additions and 75 deletions
40
fs/Kconfig
40
fs/Kconfig
|
@ -1663,7 +1663,7 @@ config CIFS_STATS
|
|||
mounted by the cifs client to be displayed in /proc/fs/cifs/Stats
|
||||
|
||||
config CIFS_STATS2
|
||||
bool "CIFS extended statistics"
|
||||
bool "Extended statistics"
|
||||
depends on CIFS_STATS
|
||||
help
|
||||
Enabling this option will allow more detailed statistics on SMB
|
||||
|
@ -1676,6 +1676,32 @@ config CIFS_STATS2
|
|||
Unless you are a developer or are doing network performance analysis
|
||||
or tuning, say N.
|
||||
|
||||
config CIFS_WEAK_PW_HASH
|
||||
bool "Support legacy servers which use weaker LANMAN security"
|
||||
depends on CIFS
|
||||
help
|
||||
Modern CIFS servers including Samba and most Windows versions
|
||||
(since 1997) support stronger NTLM (and even NTLMv2 and Kerberos)
|
||||
security mechanisms. These hash the password more securely
|
||||
than the mechanisms used in the older LANMAN version of the
|
||||
SMB protocol needed to establish sessions with old SMB servers.
|
||||
|
||||
Enabling this option allows the cifs module to mount to older
|
||||
LANMAN based servers such as OS/2 and Windows 95, but such
|
||||
mounts may be less secure than mounts using NTLM or more recent
|
||||
security mechanisms if you are on a public network. Unless you
|
||||
have a need to access old SMB servers (and are on a private
|
||||
network) you probably want to say N. Even if this support
|
||||
is enabled in the kernel build, they will not be used
|
||||
automatically. At runtime LANMAN mounts are disabled but
|
||||
can be set to required (or optional) either in
|
||||
/proc/fs/cifs (see fs/cifs/README for more detail) or via an
|
||||
option on the mount command. This support is disabled by
|
||||
default in order to reduce the possibility of a downgrade
|
||||
attack.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config CIFS_XATTR
|
||||
bool "CIFS extended attributes"
|
||||
depends on CIFS
|
||||
|
@ -1704,6 +1730,16 @@ config CIFS_POSIX
|
|||
(such as Samba 3.10 and later) which can negotiate
|
||||
CIFS POSIX ACL support. If unsure, say N.
|
||||
|
||||
config CIFS_DEBUG2
|
||||
bool "Enable additional CIFS debugging routines
|
||||
help
|
||||
Enabling this option adds a few more debugging routines
|
||||
to the cifs code which slightly increases the size of
|
||||
the cifs module and can cause additional logging of debug
|
||||
messages in some error paths, slowing performance. This
|
||||
option can be turned off unless you are debugging
|
||||
cifs problems. If unsure, say N.
|
||||
|
||||
config CIFS_EXPERIMENTAL
|
||||
bool "CIFS Experimental Features (EXPERIMENTAL)"
|
||||
depends on CIFS && EXPERIMENTAL
|
||||
|
@ -1719,7 +1755,7 @@ config CIFS_EXPERIMENTAL
|
|||
If unsure, say N.
|
||||
|
||||
config CIFS_UPCALL
|
||||
bool "CIFS Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
|
||||
bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
|
||||
depends on CIFS_EXPERIMENTAL
|
||||
select CONNECTOR
|
||||
help
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
Version 1.44
|
||||
------------
|
||||
Rewritten sessionsetup support, including support for legacy SMB
|
||||
session setup needed for OS/2 and older servers such as Windows 95 and 98.
|
||||
|
||||
Version 1.43
|
||||
------------
|
||||
POSIX locking to servers which support CIFS POSIX Extensions
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
#
|
||||
obj-$(CONFIG_CIFS) += cifs.o
|
||||
|
||||
cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o ntlmssp.o
|
||||
cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o
|
||||
|
|
|
@ -39,7 +39,7 @@ cifs_dump_mem(char *label, void *data, int length)
|
|||
char *charptr = data;
|
||||
char buf[10], line[80];
|
||||
|
||||
printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n\n",
|
||||
printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n",
|
||||
label, length, data);
|
||||
for (i = 0; i < length; i += 16) {
|
||||
line[0] = 0;
|
||||
|
@ -57,6 +57,57 @@ cifs_dump_mem(char *label, void *data, int length)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
void cifs_dump_detail(struct smb_hdr * smb)
|
||||
{
|
||||
cERROR(1,("Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d",
|
||||
smb->Command, smb->Status.CifsError,
|
||||
smb->Flags, smb->Flags2, smb->Mid, smb->Pid));
|
||||
cERROR(1,("smb buf %p len %d", smb, smbCalcSize_LE(smb)));
|
||||
}
|
||||
|
||||
|
||||
void cifs_dump_mids(struct TCP_Server_Info * server)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct mid_q_entry * mid_entry;
|
||||
|
||||
if(server == NULL)
|
||||
return;
|
||||
|
||||
cERROR(1,("Dump pending requests:"));
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
list_for_each(tmp, &server->pending_mid_q) {
|
||||
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
|
||||
if(mid_entry) {
|
||||
cERROR(1,("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d",
|
||||
mid_entry->midState,
|
||||
(int)mid_entry->command,
|
||||
mid_entry->pid,
|
||||
mid_entry->tsk,
|
||||
mid_entry->mid));
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
cERROR(1,("IsLarge: %d buf: %p time rcv: %ld now: %ld",
|
||||
mid_entry->largeBuf,
|
||||
mid_entry->resp_buf,
|
||||
mid_entry->when_received,
|
||||
jiffies));
|
||||
#endif /* STATS2 */
|
||||
cERROR(1,("IsMult: %d IsEnd: %d", mid_entry->multiRsp,
|
||||
mid_entry->multiEnd));
|
||||
if(mid_entry->resp_buf) {
|
||||
cifs_dump_detail(mid_entry->resp_buf);
|
||||
cifs_dump_mem("existing buf: ",
|
||||
mid_entry->resp_buf,
|
||||
62 /* fixme */);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
}
|
||||
#endif /* CONFIG_CIFS_DEBUG2 */
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static int
|
||||
cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
|
||||
|
@ -73,7 +124,6 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
|
|||
|
||||
*beginBuffer = buf + offset;
|
||||
|
||||
|
||||
length =
|
||||
sprintf(buf,
|
||||
"Display Internal CIFS Data Structures for Debugging\n"
|
||||
|
@ -397,10 +447,10 @@ static read_proc_t multiuser_mount_read;
|
|||
static write_proc_t multiuser_mount_write;
|
||||
static read_proc_t extended_security_read;
|
||||
static write_proc_t extended_security_write;
|
||||
static read_proc_t ntlmv2_enabled_read;
|
||||
/* static read_proc_t ntlmv2_enabled_read;
|
||||
static write_proc_t ntlmv2_enabled_write;
|
||||
static read_proc_t packet_signing_enabled_read;
|
||||
static write_proc_t packet_signing_enabled_write;
|
||||
static write_proc_t packet_signing_enabled_write;*/
|
||||
static read_proc_t experimEnabled_read;
|
||||
static write_proc_t experimEnabled_write;
|
||||
static read_proc_t linuxExtensionsEnabled_read;
|
||||
|
@ -469,7 +519,7 @@ cifs_proc_init(void)
|
|||
if (pde)
|
||||
pde->write_proc = lookupFlag_write;
|
||||
|
||||
pde =
|
||||
/* pde =
|
||||
create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
|
||||
ntlmv2_enabled_read, NULL);
|
||||
if (pde)
|
||||
|
@ -479,7 +529,7 @@ cifs_proc_init(void)
|
|||
create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs,
|
||||
packet_signing_enabled_read, NULL);
|
||||
if (pde)
|
||||
pde->write_proc = packet_signing_enabled_write;
|
||||
pde->write_proc = packet_signing_enabled_write;*/
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -496,9 +546,9 @@ cifs_proc_clean(void)
|
|||
#endif
|
||||
remove_proc_entry("MultiuserMount", proc_fs_cifs);
|
||||
remove_proc_entry("OplockEnabled", proc_fs_cifs);
|
||||
remove_proc_entry("NTLMV2Enabled",proc_fs_cifs);
|
||||
/* remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */
|
||||
remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
|
||||
remove_proc_entry("PacketSigningEnabled",proc_fs_cifs);
|
||||
/* remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); */
|
||||
remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs);
|
||||
remove_proc_entry("Experimental",proc_fs_cifs);
|
||||
remove_proc_entry("LookupCacheEnabled",proc_fs_cifs);
|
||||
|
@ -787,7 +837,7 @@ extended_security_read(char *page, char **start, off_t off,
|
|||
{
|
||||
int len;
|
||||
|
||||
len = sprintf(page, "%d\n", extended_security);
|
||||
len = sprintf(page, "0x%x\n", extended_security);
|
||||
|
||||
len -= off;
|
||||
*start = page + off;
|
||||
|
@ -808,19 +858,25 @@ extended_security_write(struct file *file, const char __user *buffer,
|
|||
{
|
||||
char c;
|
||||
int rc;
|
||||
cERROR(1,("size %ld",count)); /* BB removeme BB */
|
||||
if((count < 2) || (count > 8))
|
||||
return -EINVAL;
|
||||
|
||||
rc = get_user(c, buffer);
|
||||
|
||||
/* BB fixme need to parse more characters in order to handle CIFSSEC flags */
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
if (c == '0' || c == 'n' || c == 'N')
|
||||
extended_security = 0;
|
||||
extended_security = CIFSSEC_DEF; /* default */
|
||||
else if (c == '1' || c == 'y' || c == 'Y')
|
||||
extended_security = 1;
|
||||
extended_security = CIFSSEC_MAX;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int
|
||||
/* static int
|
||||
ntlmv2_enabled_read(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
|
@ -855,6 +911,8 @@ ntlmv2_enabled_write(struct file *file, const char __user *buffer,
|
|||
ntlmv2_support = 0;
|
||||
else if (c == '1' || c == 'y' || c == 'Y')
|
||||
ntlmv2_support = 1;
|
||||
else if (c == '2')
|
||||
ntlmv2_support = 2;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -898,7 +956,7 @@ packet_signing_enabled_write(struct file *file, const char __user *buffer,
|
|||
sign_CIFS_PDUs = 2;
|
||||
|
||||
return count;
|
||||
}
|
||||
} */
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
#define _H_CIFS_DEBUG
|
||||
|
||||
void cifs_dump_mem(char *label, void *data, int length);
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
void cifs_dump_detail(struct smb_hdr *);
|
||||
void cifs_dump_mids(struct TCP_Server_Info *);
|
||||
#endif
|
||||
extern int traceSMB; /* flag which enables the function below */
|
||||
void dump_smb(struct smb_hdr *, int);
|
||||
#define CIFS_INFO 0x01
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "cifs_unicode.h"
|
||||
#include "cifs_uniupr.h"
|
||||
#include "cifspdu.h"
|
||||
#include "cifsglob.h"
|
||||
#include "cifs_debug.h"
|
||||
|
||||
/*
|
||||
|
|
|
@ -225,6 +225,8 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_
|
|||
user_name_len = strlen(ses->userName);
|
||||
if(user_name_len > MAX_USERNAME_SIZE)
|
||||
return -EINVAL;
|
||||
if(ses->domainName == NULL)
|
||||
return -EINVAL; /* BB should we use CIFS_LINUX_DOM */
|
||||
dom_name_len = strlen(ses->domainName);
|
||||
if(dom_name_len > MAX_USERNAME_SIZE)
|
||||
return -EINVAL;
|
||||
|
|
|
@ -56,8 +56,8 @@ unsigned int experimEnabled = 0;
|
|||
unsigned int linuxExtEnabled = 1;
|
||||
unsigned int lookupCacheEnabled = 1;
|
||||
unsigned int multiuser_mount = 0;
|
||||
unsigned int extended_security = 0;
|
||||
unsigned int ntlmv2_support = 0;
|
||||
unsigned int extended_security = CIFSSEC_DEF;
|
||||
/* unsigned int ntlmv2_support = 0; */
|
||||
unsigned int sign_CIFS_PDUs = 1;
|
||||
extern struct task_struct * oplockThread; /* remove sparse warning */
|
||||
struct task_struct * oplockThread = NULL;
|
||||
|
|
|
@ -88,7 +88,8 @@ enum statusEnum {
|
|||
};
|
||||
|
||||
enum securityEnum {
|
||||
NTLM = 0, /* Legacy NTLM012 auth with NTLM hash */
|
||||
LANMAN = 0, /* 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 */
|
||||
|
@ -179,7 +180,9 @@ struct cifsUidInfo {
|
|||
struct cifsSesInfo {
|
||||
struct list_head cifsSessionList;
|
||||
struct semaphore sesSem;
|
||||
#if 0
|
||||
struct cifsUidInfo *uidInfo; /* pointer to user info */
|
||||
#endif
|
||||
struct TCP_Server_Info *server; /* pointer to server info */
|
||||
atomic_t inUse; /* # of mounts (tree connections) on this ses */
|
||||
enum statusEnum status;
|
||||
|
@ -194,7 +197,7 @@ struct cifsSesInfo {
|
|||
char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for
|
||||
TCP names - will ipv6 and sctp addresses fit? */
|
||||
char userName[MAX_USERNAME_SIZE + 1];
|
||||
char domainName[MAX_USERNAME_SIZE + 1];
|
||||
char * domainName;
|
||||
char * password;
|
||||
};
|
||||
/* session flags */
|
||||
|
@ -391,9 +394,9 @@ struct mid_q_entry {
|
|||
struct smb_hdr *resp_buf; /* response buffer */
|
||||
int midState; /* wish this were enum but can not pass to wait_event */
|
||||
__u8 command; /* smb command code */
|
||||
unsigned multiPart:1; /* multiple responses to one SMB request */
|
||||
unsigned largeBuf:1; /* if valid response, is pointer to large buf */
|
||||
unsigned multiResp:1; /* multiple trans2 responses for one request */
|
||||
unsigned multiRsp:1; /* multiple trans2 responses for one request */
|
||||
unsigned multiEnd:1; /* both received */
|
||||
};
|
||||
|
||||
struct oplock_q_entry {
|
||||
|
@ -430,15 +433,35 @@ struct dir_notify_req {
|
|||
#define CIFS_LARGE_BUFFER 2
|
||||
#define CIFS_IOVEC 4 /* array of response buffers */
|
||||
|
||||
/* Type of session setup needed */
|
||||
#define CIFS_PLAINTEXT 0
|
||||
#define CIFS_LANMAN 1
|
||||
#define CIFS_NTLM 2
|
||||
#define CIFS_NTLMSSP_NEG 3
|
||||
#define CIFS_NTLMSSP_AUTH 4
|
||||
#define CIFS_SPNEGO_INIT 5
|
||||
#define CIFS_SPNEGO_TARG 6
|
||||
/* Security Flags: indicate type of session setup needed */
|
||||
#define CIFSSEC_MAY_SIGN 0x00001
|
||||
#define CIFSSEC_MAY_NTLM 0x00002
|
||||
#define CIFSSEC_MAY_NTLMV2 0x00004
|
||||
#define CIFSSEC_MAY_KRB5 0x00008
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
#define CIFSSEC_MAY_LANMAN 0x00010
|
||||
#define CIFSSEC_MAY_PLNTXT 0x00020
|
||||
#endif /* weak passwords */
|
||||
#define CIFSSEC_MAY_SEAL 0x00040 /* not supported yet */
|
||||
|
||||
#define CIFSSEC_MUST_SIGN 0x01001
|
||||
/* note that only one of the following can be set so the
|
||||
result of setting MUST flags more than once will be to
|
||||
require use of the stronger protocol */
|
||||
#define CIFSSEC_MUST_NTLM 0x02002
|
||||
#define CIFSSEC_MUST_NTLMV2 0x04004
|
||||
#define CIFSSEC_MUST_KRB5 0x08008
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
#define CIFSSEC_MUST_LANMAN 0x10010
|
||||
#define CIFSSEC_MUST_PLNTXT 0x20020
|
||||
#define CIFSSEC_MASK 0x37037 /* current flags supported if weak */
|
||||
#else
|
||||
#define CIFSSEC_MASK 0x07007 /* flags supported if no weak config */
|
||||
#endif /* WEAK_PW_HASH */
|
||||
#define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */
|
||||
|
||||
#define CIFSSEC_DEF CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2
|
||||
#define CIFSSEC_MAX CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2
|
||||
/*
|
||||
*****************************************************************
|
||||
* All constants go here
|
||||
|
@ -540,8 +563,8 @@ GLOBAL_EXTERN unsigned int experimEnabled;
|
|||
GLOBAL_EXTERN unsigned int lookupCacheEnabled;
|
||||
GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
|
||||
with more secure ntlmssp2 challenge/resp */
|
||||
GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */
|
||||
GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */
|
||||
GLOBAL_EXTERN unsigned int secFlags;
|
||||
GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
|
||||
GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */
|
||||
GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _CIFSPDU_H
|
||||
|
@ -24,8 +24,14 @@
|
|||
|
||||
#include <net/sock.h>
|
||||
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
#define LANMAN_PROT 0
|
||||
#define CIFS_PROT 1
|
||||
#else
|
||||
#define CIFS_PROT 0
|
||||
#define BAD_PROT CIFS_PROT+1
|
||||
#endif
|
||||
#define POSIX_PROT CIFS_PROT+1
|
||||
#define BAD_PROT 0xFFFF
|
||||
|
||||
/* SMB command codes */
|
||||
/* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses
|
||||
|
@ -400,6 +406,25 @@ typedef struct negotiate_req {
|
|||
unsigned char DialectsArray[1];
|
||||
} __attribute__((packed)) NEGOTIATE_REQ;
|
||||
|
||||
/* Dialect index is 13 for LANMAN */
|
||||
|
||||
typedef struct lanman_neg_rsp {
|
||||
struct smb_hdr hdr; /* wct = 13 */
|
||||
__le16 DialectIndex;
|
||||
__le16 SecurityMode;
|
||||
__le16 MaxBufSize;
|
||||
__le16 MaxMpxCount;
|
||||
__le16 MaxNumberVcs;
|
||||
__le16 RawMode;
|
||||
__le32 SessionKey;
|
||||
__le32 ServerTime;
|
||||
__le16 ServerTimeZone;
|
||||
__le16 EncryptionKeyLength;
|
||||
__le16 Reserved;
|
||||
__u16 ByteCount;
|
||||
unsigned char EncryptionKey[1];
|
||||
} __attribute__((packed)) LANMAN_NEG_RSP;
|
||||
|
||||
typedef struct negotiate_rsp {
|
||||
struct smb_hdr hdr; /* wct = 17 */
|
||||
__le16 DialectIndex;
|
||||
|
@ -520,8 +545,8 @@ typedef union smb_com_session_setup_andx {
|
|||
__le16 MaxMpxCount;
|
||||
__le16 VcNumber;
|
||||
__u32 SessionKey;
|
||||
__le16 PassswordLength;
|
||||
__u32 Reserved;
|
||||
__le16 PasswordLength;
|
||||
__u32 Reserved; /* encrypt key len and offset */
|
||||
__le16 ByteCount;
|
||||
unsigned char AccountPassword[1]; /* followed by */
|
||||
/* STRING AccountName */
|
||||
|
@ -1844,13 +1869,13 @@ typedef struct {
|
|||
typedef struct {
|
||||
__le32 DeviceType;
|
||||
__le32 DeviceCharacteristics;
|
||||
} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */
|
||||
} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */
|
||||
|
||||
typedef struct {
|
||||
__le32 Attributes;
|
||||
__le32 MaxPathNameComponentLength;
|
||||
__le32 FileSystemNameLen;
|
||||
char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */
|
||||
char FileSystemName[52]; /* do not have to save this - get subset? */
|
||||
} __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO;
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -69,7 +69,7 @@ extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
|
|||
struct cifsSesInfo *ses,
|
||||
void ** request_buf);
|
||||
extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
||||
const int stage, int * pNTLMv2_flg,
|
||||
const int stage,
|
||||
const struct nls_table *nls_cp);
|
||||
#endif
|
||||
extern __u16 GetNextMid(struct TCP_Server_Info *server);
|
||||
|
|
|
@ -44,8 +44,11 @@ static struct {
|
|||
int index;
|
||||
char *name;
|
||||
} protocols[] = {
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
{LANMAN_PROT, "\2LM1.2X002"},
|
||||
#endif /* weak password hashing for legacy clients */
|
||||
{CIFS_PROT, "\2NT LM 0.12"},
|
||||
{CIFS_PROT, "\2POSIX 2"},
|
||||
{POSIX_PROT, "\2POSIX 2"},
|
||||
{BAD_PROT, "\2"}
|
||||
};
|
||||
#else
|
||||
|
@ -53,11 +56,29 @@ static struct {
|
|||
int index;
|
||||
char *name;
|
||||
} protocols[] = {
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
{LANMAN_PROT, "\2LM1.2X002"},
|
||||
#endif /* weak password hashing for legacy clients */
|
||||
{CIFS_PROT, "\2NT LM 0.12"},
|
||||
{BAD_PROT, "\2"}
|
||||
};
|
||||
#endif
|
||||
|
||||
/* define the number of elements in the cifs dialect array */
|
||||
#ifdef CONFIG_CIFS_POSIX
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
#define CIFS_NUM_PROT 3
|
||||
#else
|
||||
#define CIFS_NUM_PROT 2
|
||||
#endif /* CIFS_WEAK_PW_HASH */
|
||||
#else /* not posix */
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
#define CIFS_NUM_PROT 2
|
||||
#else
|
||||
#define CIFS_NUM_PROT 1
|
||||
#endif /* CONFIG_CIFS_WEAK_PW_HASH */
|
||||
#endif /* CIFS_POSIX */
|
||||
|
||||
|
||||
/* Mark as invalid, all open files on tree connections since they
|
||||
were closed when session to server was lost */
|
||||
|
@ -322,7 +343,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
|
|||
/* potential retries of smb operations it turns out we can determine */
|
||||
/* from the mid flags when the request buffer can be resent without */
|
||||
/* having to use a second distinct buffer for the response */
|
||||
*response_buf = *request_buf;
|
||||
if(response_buf)
|
||||
*response_buf = *request_buf;
|
||||
|
||||
header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
|
||||
wct /*wct */ );
|
||||
|
@ -373,6 +395,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||
NEGOTIATE_RSP *pSMBr;
|
||||
int rc = 0;
|
||||
int bytes_returned;
|
||||
int i;
|
||||
struct TCP_Server_Info * server;
|
||||
u16 count;
|
||||
|
||||
|
@ -388,19 +411,71 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||
return rc;
|
||||
pSMB->hdr.Mid = GetNextMid(server);
|
||||
pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
|
||||
if (extended_security)
|
||||
pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
|
||||
count = strlen(protocols[0].name) + 1;
|
||||
strncpy(pSMB->DialectsArray, protocols[0].name, 30);
|
||||
/* null guaranteed to be at end of source and target buffers anyway */
|
||||
|
||||
/* if (extended_security)
|
||||
pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;*/
|
||||
|
||||
count = 0;
|
||||
for(i=0;i<CIFS_NUM_PROT;i++) {
|
||||
strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
|
||||
count += strlen(protocols[i].name) + 1;
|
||||
/* null at end of source and target buffers anyway */
|
||||
}
|
||||
pSMB->hdr.smb_buf_length += count;
|
||||
pSMB->ByteCount = cpu_to_le16(count);
|
||||
|
||||
rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
if (rc == 0) {
|
||||
cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
|
||||
/* Check wct = 1 error case */
|
||||
if((pSMBr->hdr.WordCount < 13)
|
||||
|| (pSMBr->DialectIndex == BAD_PROT)) {
|
||||
/* core returns wct = 1, but we do not ask for
|
||||
core - otherwise it just comes when dialect
|
||||
index is -1 indicating we could not negotiate
|
||||
a common dialect */
|
||||
rc = -EOPNOTSUPP;
|
||||
goto neg_err_exit;
|
||||
} else if((pSMBr->hdr.WordCount == 13) &&
|
||||
(pSMBr->DialectIndex == LANMAN_PROT)) {
|
||||
struct lanman_neg_rsp * rsp =
|
||||
(struct lanman_neg_rsp *)pSMBr;
|
||||
|
||||
|
||||
/* BB Mark ses struct as negotiated lanman level BB */
|
||||
server->secType = LANMAN;
|
||||
server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
|
||||
server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
|
||||
server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
|
||||
(__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
|
||||
|
||||
/* BB what do we do with raw mode? BB */
|
||||
server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
|
||||
/* Do we have to set signing flags? no signing
|
||||
was available LANMAN - default should be ok */
|
||||
|
||||
/* BB FIXME set default dummy capabilities since
|
||||
they are not returned by the server in this dialect */
|
||||
|
||||
/* get server time for time conversions and add
|
||||
code to use it and timezone since this is not UTC */
|
||||
|
||||
if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
|
||||
memcpy(server->cryptKey, rsp->EncryptionKey,
|
||||
CIFS_CRYPTO_KEY_SIZE);
|
||||
} else {
|
||||
rc = -EIO;
|
||||
goto neg_err_exit;
|
||||
}
|
||||
|
||||
cFYI(1,("LANMAN negotiated")); /* BB removeme BB */
|
||||
goto neg_err_exit;
|
||||
} else if(pSMBr->hdr.WordCount != 17) {
|
||||
/* unknown wct */
|
||||
rc = -EOPNOTSUPP;
|
||||
goto neg_err_exit;
|
||||
}
|
||||
|
||||
server->secMode = pSMBr->SecurityMode;
|
||||
if((server->secMode & SECMODE_USER) == 0)
|
||||
cFYI(1,("share mode security"));
|
||||
|
@ -479,7 +554,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
neg_err_exit:
|
||||
cifs_buf_release(pSMB);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -49,8 +49,6 @@
|
|||
|
||||
static DECLARE_COMPLETION(cifsd_complete);
|
||||
|
||||
extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
|
||||
|
@ -585,9 +583,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
|||
/* merge response - fix up 1st*/
|
||||
if(coalesce_t2(smb_buffer,
|
||||
mid_entry->resp_buf)) {
|
||||
mid_entry->multiRsp = 1;
|
||||
break;
|
||||
} else {
|
||||
/* all parts received */
|
||||
mid_entry->multiEnd = 1;
|
||||
goto multi_t2_fnd;
|
||||
}
|
||||
} else {
|
||||
|
@ -632,9 +632,14 @@ multi_t2_fnd:
|
|||
wake_up_process(task_to_wake);
|
||||
} else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
|
||||
&& (isMultiRsp == FALSE)) {
|
||||
cERROR(1, ("No task to wake, unknown frame rcvd!"));
|
||||
cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter));
|
||||
cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
|
||||
sizeof(struct smb_hdr));
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
cifs_dump_detail(smb_buffer);
|
||||
cifs_dump_mids(server);
|
||||
#endif /* CIFS_DEBUG2 */
|
||||
|
||||
}
|
||||
} /* end while !EXITING */
|
||||
|
||||
|
@ -976,7 +981,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
|
|||
}
|
||||
/* BB are there cases in which a comma can be valid in
|
||||
a domain name and need special handling? */
|
||||
if (strnlen(value, 65) < 65) {
|
||||
if (strnlen(value, 256) < 256) {
|
||||
vol->domainname = value;
|
||||
cFYI(1, ("Domain name set"));
|
||||
} else {
|
||||
|
@ -1762,9 +1767,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
if (volume_info.username)
|
||||
strncpy(pSesInfo->userName,
|
||||
volume_info.username,MAX_USERNAME_SIZE);
|
||||
if (volume_info.domainname)
|
||||
strncpy(pSesInfo->domainName,
|
||||
volume_info.domainname,MAX_USERNAME_SIZE);
|
||||
if (volume_info.domainname) {
|
||||
int len = strlen(volume_info.domainname);
|
||||
pSesInfo->domainName =
|
||||
kmalloc(len + 1, GFP_KERNEL);
|
||||
if(pSesInfo->domainName)
|
||||
strcpy(pSesInfo->domainName,
|
||||
volume_info.domainname);
|
||||
}
|
||||
pSesInfo->linux_uid = volume_info.linux_uid;
|
||||
down(&pSesInfo->sesSem);
|
||||
rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
|
||||
|
@ -2054,7 +2064,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
bcc_ptr++;
|
||||
}
|
||||
if(user == NULL)
|
||||
bytes_returned = 0; /* skill null user */
|
||||
bytes_returned = 0; /* skip null user */
|
||||
else
|
||||
bytes_returned =
|
||||
cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
|
||||
|
@ -2635,8 +2645,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
|
|||
/* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
|
||||
if(sign_CIFS_PDUs)
|
||||
negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
|
||||
if(ntlmv2_support)
|
||||
negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
|
||||
/* if(ntlmv2_support)
|
||||
negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
|
||||
/* setup pointers to domain name and workstation name */
|
||||
bcc_ptr += SecurityBlobLength;
|
||||
|
||||
|
@ -3429,7 +3439,10 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
|
|||
}
|
||||
/* else do not bother copying these informational fields */
|
||||
}
|
||||
tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
|
||||
if(smb_buffer_response->WordCount == 3)
|
||||
tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
|
||||
else
|
||||
tcon->Flags = 0;
|
||||
cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
|
||||
} else if ((rc == 0) && tcon == NULL) {
|
||||
/* all we need to save for IPC$ connection */
|
||||
|
@ -3528,8 +3541,8 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
|
|||
pSesInfo->server->timeZone));
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
if(experimEnabled > 1)
|
||||
rc = CIFS_SessSetup(xid, pSesInfo, CIFS_NTLM /* type */,
|
||||
&ntlmv2_flag, nls_info);
|
||||
rc = CIFS_SessSetup(xid, pSesInfo,
|
||||
first_time, nls_info);
|
||||
else
|
||||
#endif
|
||||
if (extended_security
|
||||
|
|
|
@ -113,7 +113,7 @@ cifs_bp_rename_retry:
|
|||
full_path[namelen+2] = 0;
|
||||
BB remove above eight lines BB */
|
||||
|
||||
/* Inode operations in similar order to how they appear in the Linux file fs.h */
|
||||
/* Inode operations in similar order to how they appear in Linux file fs.h */
|
||||
|
||||
int
|
||||
cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
||||
|
|
|
@ -91,14 +91,14 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
|
|||
if(full_path == NULL) {
|
||||
rc = -ENOMEM;
|
||||
} else {
|
||||
cERROR(1,("cifs dir notify on file %s with arg 0x%lx",full_path,arg)); /* BB removeme BB */
|
||||
cFYI(1,("dir notify on file %s Arg 0x%lx",full_path,arg));
|
||||
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
|
||||
GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
|
||||
&netfid, &oplock,NULL, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
/* BB fixme - add this handle to a notify handle list */
|
||||
if(rc) {
|
||||
cERROR(1,("Could not open directory for notify")); /* BB remove BB */
|
||||
cFYI(1,("Could not open directory for notify"));
|
||||
} else {
|
||||
filter = convert_to_cifs_notify_flags(arg);
|
||||
if(filter != 0) {
|
||||
|
|
|
@ -1121,7 +1121,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
|||
|
||||
xid = GetXid();
|
||||
|
||||
cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x",
|
||||
cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
|
||||
direntry->d_name.name, attrs->ia_valid));
|
||||
|
||||
cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
|
||||
|
@ -1157,6 +1157,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
|||
when the local oplock break takes longer to flush
|
||||
writebehind data than the SMB timeout for the SetPathInfo
|
||||
request would allow */
|
||||
|
||||
open_file = find_writable_file(cifsInode);
|
||||
if (open_file) {
|
||||
__u16 nfid = open_file->netfid;
|
||||
|
|
|
@ -101,6 +101,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
|
|||
kfree(buf_to_free->serverDomain);
|
||||
kfree(buf_to_free->serverNOS);
|
||||
kfree(buf_to_free->password);
|
||||
kfree(buf_to_free->domainName);
|
||||
kfree(buf_to_free);
|
||||
}
|
||||
|
||||
|
@ -499,11 +500,12 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
|
|||
if(pSMBr->ByteCount > sizeof(struct file_notify_information)) {
|
||||
data_offset = le32_to_cpu(pSMBr->DataOffset);
|
||||
|
||||
pnotify = (struct file_notify_information *)((char *)&pSMBr->hdr.Protocol
|
||||
+ data_offset);
|
||||
cFYI(1,("dnotify on %s with action: 0x%x",pnotify->FileName,
|
||||
pnotify = (struct file_notify_information *)
|
||||
((char *)&pSMBr->hdr.Protocol + data_offset);
|
||||
cFYI(1,("dnotify on %s Action: 0x%x",pnotify->FileName,
|
||||
pnotify->Action)); /* BB removeme BB */
|
||||
/* cifs_dump_mem("Received notify Data is: ",buf,sizeof(struct smb_hdr)+60); */
|
||||
/* cifs_dump_mem("Rcvd notify Data: ",buf,
|
||||
sizeof(struct smb_hdr)+60); */
|
||||
return TRUE;
|
||||
}
|
||||
if(pSMBr->hdr.Status.CifsError) {
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
#include "cifs_fs_sb.h"
|
||||
#include "cifsfs.h"
|
||||
|
||||
/* BB fixme - add debug wrappers around this function to disable it fixme BB */
|
||||
/* static void dump_cifs_file_struct(struct file *file, char *label)
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
static void dump_cifs_file_struct(struct file *file, char *label)
|
||||
{
|
||||
struct cifsFileInfo * cf;
|
||||
|
||||
|
@ -53,7 +53,8 @@
|
|||
}
|
||||
|
||||
}
|
||||
} */
|
||||
}
|
||||
#endif /* DEBUG2 */
|
||||
|
||||
/* Returns one if new inode created (which therefore needs to be hashed) */
|
||||
/* Might check in the future if inode number changed so we can rehash inode */
|
||||
|
@ -597,7 +598,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
|
|||
. and .. for the root of a drive and for those we need
|
||||
to start two entries earlier */
|
||||
|
||||
/* dump_cifs_file_struct(file, "In fce ");*/
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
dump_cifs_file_struct(file, "In fce ");
|
||||
#endif
|
||||
if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
|
||||
is_dir_changed(file)) ||
|
||||
(index_to_find < first_entry_in_buffer)) {
|
||||
|
@ -980,9 +983,10 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
|
|||
rc = cifs_filldir(current_entry, file,
|
||||
filldir, direntry,tmp_buf);
|
||||
file->f_pos++;
|
||||
if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) {
|
||||
if(file->f_pos ==
|
||||
cifsFile->srch_inf.index_of_last_entry) {
|
||||
cFYI(1,("last entry in buf at pos %lld %s",
|
||||
file->f_pos,tmp_buf)); /* BB removeme BB */
|
||||
file->f_pos,tmp_buf));
|
||||
cifs_save_resume_key(current_entry,cifsFile);
|
||||
break;
|
||||
} else
|
||||
|
|
511
fs/cifs/sess.c
Normal file
511
fs/cifs/sess.c
Normal file
|
@ -0,0 +1,511 @@
|
|||
/*
|
||||
* fs/cifs/sess.c
|
||||
*
|
||||
* SMB/CIFS session setup handling routines
|
||||
*
|
||||
* Copyright (c) International Business Machines Corp., 2006
|
||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "cifspdu.h"
|
||||
#include "cifsglob.h"
|
||||
#include "cifsproto.h"
|
||||
#include "cifs_unicode.h"
|
||||
#include "cifs_debug.h"
|
||||
#include "ntlmssp.h"
|
||||
#include "nterr.h"
|
||||
#include <linux/ctype.h>
|
||||
|
||||
extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
|
||||
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
|
||||
static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
|
||||
{
|
||||
__u32 capabilities = 0;
|
||||
|
||||
/* init fields common to all four types of SessSetup */
|
||||
/* note that header is initialized to zero in header_assemble */
|
||||
pSMB->req.AndXCommand = 0xFF;
|
||||
pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
|
||||
pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
|
||||
|
||||
/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
|
||||
|
||||
/* BB verify whether signing required on neg or just on auth frame
|
||||
(and NTLM case) */
|
||||
|
||||
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
|
||||
CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
|
||||
|
||||
if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
|
||||
pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
|
||||
|
||||
if (ses->capabilities & CAP_UNICODE) {
|
||||
pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE;
|
||||
capabilities |= CAP_UNICODE;
|
||||
}
|
||||
if (ses->capabilities & CAP_STATUS32) {
|
||||
pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS;
|
||||
capabilities |= CAP_STATUS32;
|
||||
}
|
||||
if (ses->capabilities & CAP_DFS) {
|
||||
pSMB->req.hdr.Flags2 |= SMBFLG2_DFS;
|
||||
capabilities |= CAP_DFS;
|
||||
}
|
||||
if (ses->capabilities & CAP_UNIX) {
|
||||
capabilities |= CAP_UNIX;
|
||||
}
|
||||
|
||||
/* BB check whether to init vcnum BB */
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
|
||||
const struct nls_table * nls_cp)
|
||||
{
|
||||
char * bcc_ptr = *pbcc_area;
|
||||
int bytes_ret = 0;
|
||||
|
||||
/* BB FIXME add check that strings total less
|
||||
than 335 or will need to send them as arrays */
|
||||
|
||||
/* align unicode strings, must be word aligned */
|
||||
if ((long) bcc_ptr % 2) {
|
||||
*bcc_ptr = 0;
|
||||
bcc_ptr++;
|
||||
}
|
||||
/* copy user */
|
||||
if(ses->userName == NULL) {
|
||||
/* BB what about null user mounts - check that we do this BB */
|
||||
} else { /* 300 should be long enough for any conceivable user name */
|
||||
bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName,
|
||||
300, nls_cp);
|
||||
}
|
||||
bcc_ptr += 2 * bytes_ret;
|
||||
bcc_ptr += 2; /* account for null termination */
|
||||
/* copy domain */
|
||||
if(ses->domainName == NULL)
|
||||
bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr,
|
||||
"CIFS_LINUX_DOM", 32, nls_cp);
|
||||
else
|
||||
bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName,
|
||||
256, nls_cp);
|
||||
bcc_ptr += 2 * bytes_ret;
|
||||
bcc_ptr += 2; /* account for null terminator */
|
||||
|
||||
/* Copy OS version */
|
||||
bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32,
|
||||
nls_cp);
|
||||
bcc_ptr += 2 * bytes_ret;
|
||||
bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
|
||||
32, nls_cp);
|
||||
bcc_ptr += 2 * bytes_ret;
|
||||
bcc_ptr += 2; /* trailing null */
|
||||
|
||||
bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
|
||||
32, nls_cp);
|
||||
bcc_ptr += 2 * bytes_ret;
|
||||
bcc_ptr += 2; /* trailing null */
|
||||
|
||||
*pbcc_area = bcc_ptr;
|
||||
}
|
||||
|
||||
void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
|
||||
const struct nls_table * nls_cp)
|
||||
{
|
||||
char * bcc_ptr = *pbcc_area;
|
||||
|
||||
/* copy user */
|
||||
/* BB what about null user mounts - check that we do this BB */
|
||||
/* copy user */
|
||||
if(ses->userName == NULL) {
|
||||
/* BB what about null user mounts - check that we do this BB */
|
||||
} else { /* 300 should be long enough for any conceivable user name */
|
||||
strncpy(bcc_ptr, ses->userName, 300);
|
||||
}
|
||||
/* BB improve check for overflow */
|
||||
bcc_ptr += strnlen(ses->userName, 200);
|
||||
*bcc_ptr = 0;
|
||||
bcc_ptr++; /* account for null termination */
|
||||
|
||||
/* copy domain */
|
||||
|
||||
if(ses->domainName == NULL) {
|
||||
strcpy(bcc_ptr, "CIFS_LINUX_DOM");
|
||||
bcc_ptr += 14; /* strlen(CIFS_LINUX_DOM) */
|
||||
} else {
|
||||
strncpy(bcc_ptr, ses->domainName, 256);
|
||||
bcc_ptr += strnlen(ses->domainName, 256);
|
||||
}
|
||||
*bcc_ptr = 0;
|
||||
bcc_ptr++;
|
||||
|
||||
/* BB check for overflow here */
|
||||
|
||||
strcpy(bcc_ptr, "Linux version ");
|
||||
bcc_ptr += strlen("Linux version ");
|
||||
strcpy(bcc_ptr, system_utsname.release);
|
||||
bcc_ptr += strlen(system_utsname.release) + 1;
|
||||
|
||||
strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
|
||||
bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
|
||||
|
||||
*pbcc_area = bcc_ptr;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
|
||||
/* word align, if bytes remaining is not even */
|
||||
if(bleft % 2) {
|
||||
bleft--;
|
||||
data++;
|
||||
}
|
||||
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;
|
||||
|
||||
if(ses->serverOS)
|
||||
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;
|
||||
|
||||
if(ses->serverNOS)
|
||||
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;
|
||||
|
||||
if(ses->serverDomain)
|
||||
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;
|
||||
}
|
||||
|
||||
int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
|
||||
const struct nls_table * nls_cp)
|
||||
{
|
||||
int rc = 0;
|
||||
int len;
|
||||
char * bcc_ptr = *pbcc_area;
|
||||
|
||||
cFYI(1,("decode sessetup ascii. bleft %d", bleft));
|
||||
|
||||
len = strnlen(bcc_ptr, bleft);
|
||||
if(len >= bleft)
|
||||
return rc;
|
||||
|
||||
if(ses->serverOS)
|
||||
kfree(ses->serverOS);
|
||||
|
||||
ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
|
||||
if(ses->serverOS)
|
||||
strncpy(ses->serverOS, bcc_ptr, len);
|
||||
|
||||
bcc_ptr += len + 1;
|
||||
bleft -= len + 1;
|
||||
|
||||
len = strnlen(bcc_ptr, bleft);
|
||||
if(len >= bleft)
|
||||
return rc;
|
||||
|
||||
if(ses->serverNOS)
|
||||
kfree(ses->serverNOS);
|
||||
|
||||
ses->serverNOS = kzalloc(len + 1, GFP_KERNEL);
|
||||
if(ses->serverNOS)
|
||||
strncpy(ses->serverNOS, bcc_ptr, len);
|
||||
|
||||
bcc_ptr += len + 1;
|
||||
bleft -= len + 1;
|
||||
|
||||
len = strnlen(bcc_ptr, bleft);
|
||||
if(len > bleft)
|
||||
return rc;
|
||||
|
||||
if(ses->serverDomain)
|
||||
kfree(ses->serverDomain);
|
||||
|
||||
ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
|
||||
if(ses->serverOS)
|
||||
strncpy(ses->serverOS, bcc_ptr, len);
|
||||
|
||||
bcc_ptr += len + 1;
|
||||
bleft -= len + 1;
|
||||
|
||||
cFYI(1,("ascii: bytes left %d",bleft));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
||||
const struct nls_table *nls_cp)
|
||||
{
|
||||
int rc = 0;
|
||||
int wct;
|
||||
int i;
|
||||
struct smb_hdr *smb_buf;
|
||||
char *bcc_ptr;
|
||||
SESSION_SETUP_ANDX *pSMB;
|
||||
__u32 capabilities;
|
||||
int count;
|
||||
int resp_buf_type = 0;
|
||||
struct kvec iov[1];
|
||||
enum securityEnum type;
|
||||
__u16 action;
|
||||
int bytes_remaining;
|
||||
|
||||
if(ses == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
type = ses->server->secType;
|
||||
if(type == LANMAN) {
|
||||
#ifndef CONFIG_CIFS_WEAK_PW_HASH
|
||||
/* LANMAN and plaintext are less secure and off by default.
|
||||
So we make this explicitly be turned on in kconfig (in the
|
||||
build) and turned on at runtime (changed from the default)
|
||||
in proc/fs/cifs or via mount parm. Unfortunately this is
|
||||
needed for old Win (e.g. Win95), some obscure NAS and OS/2 */
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
wct = 10; /* lanman 2 style sessionsetup */
|
||||
} else if(type == NTLM) /* NTLMv2 may retry NTLM */
|
||||
wct = 13; /* old style NTLM sessionsetup */
|
||||
else /* same size for negotiate or auth, NTLMSSP or extended security */
|
||||
wct = 12;
|
||||
|
||||
rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
|
||||
(void **)&smb_buf);
|
||||
if(rc)
|
||||
return rc;
|
||||
|
||||
pSMB = (SESSION_SETUP_ANDX *)smb_buf;
|
||||
|
||||
capabilities = cifs_ssetup_hdr(ses, pSMB);
|
||||
bcc_ptr = pByteArea(smb_buf);
|
||||
|
||||
if(type == LANMAN) {
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
char lnm_session_key[CIFS_SESSION_KEY_SIZE];
|
||||
char password_with_pad[CIFS_ENCPWD_SIZE];
|
||||
|
||||
/* no capabilities flags in old lanman negotiation */
|
||||
|
||||
pSMB->old_req.PasswordLength = CIFS_SESSION_KEY_SIZE;
|
||||
/* BB calculate hash with password */
|
||||
/* and copy into bcc */
|
||||
|
||||
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
|
||||
strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
|
||||
|
||||
/* calculate old style session key */
|
||||
/* toupper may be less broken then repeatedly calling
|
||||
nls_toupper would be, but neither handles multibyte code pages
|
||||
but the only alternative would be converting to UCS-16 (Unicode)
|
||||
uppercasing and converting back which is only worth doing if
|
||||
we knew it were utf8. utf8 code page needs its own
|
||||
toupper and tolower and strnicmp functions */
|
||||
|
||||
for(i = 0; i< CIFS_ENCPWD_SIZE; i++) {
|
||||
password_with_pad[i] = toupper(password_with_pad[i]);
|
||||
}
|
||||
|
||||
SMBencrypt(password_with_pad, ses->server->cryptKey,
|
||||
lnm_session_key);
|
||||
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
|
||||
CIFS_SESSION_KEY_SIZE);
|
||||
#endif
|
||||
/* clear password before we return/free memory */
|
||||
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
|
||||
memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESSION_KEY_SIZE);
|
||||
bcc_ptr += CIFS_SESSION_KEY_SIZE;
|
||||
|
||||
/* can not sign if LANMAN negotiated so no need
|
||||
to calculate signing key? but what if server
|
||||
changed to do higher than lanman dialect and
|
||||
we reconnected would we ever calc signing_key? */
|
||||
|
||||
cERROR(1,("Negotiating LANMAN setting up strings"));
|
||||
/* Unicode not allowed for LANMAN dialects */
|
||||
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
|
||||
#endif
|
||||
} else if (type == NTLM) {
|
||||
char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
|
||||
|
||||
pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
|
||||
pSMB->req_no_secext.CaseInsensitivePasswordLength =
|
||||
cpu_to_le16(CIFS_SESSION_KEY_SIZE);
|
||||
pSMB->req_no_secext.CaseSensitivePasswordLength =
|
||||
cpu_to_le16(CIFS_SESSION_KEY_SIZE);
|
||||
|
||||
/* calculate session key */
|
||||
SMBNTencrypt(ses->password, ses->server->cryptKey,
|
||||
ntlm_session_key);
|
||||
|
||||
if(first_time) /* should this be moved into common code
|
||||
with similar ntlmv2 path? */
|
||||
cifs_calculate_mac_key(
|
||||
ses->server->mac_signing_key,
|
||||
ntlm_session_key, ses->password);
|
||||
/* copy session key */
|
||||
|
||||
memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE);
|
||||
bcc_ptr += CIFS_SESSION_KEY_SIZE;
|
||||
memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE);
|
||||
bcc_ptr += CIFS_SESSION_KEY_SIZE;
|
||||
if(ses->capabilities & CAP_UNICODE)
|
||||
unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
|
||||
else
|
||||
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
|
||||
} else /* NTLMSSP or SPNEGO */ {
|
||||
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
capabilities |= CAP_EXTENDED_SECURITY;
|
||||
pSMB->req.Capabilities = cpu_to_le32(capabilities);
|
||||
/* BB set password lengths */
|
||||
}
|
||||
|
||||
count = (long) bcc_ptr - (long) pByteArea(smb_buf);
|
||||
smb_buf->smb_buf_length += count;
|
||||
|
||||
/* if we switch to small buffers, count will need to be fewer
|
||||
than 383 (strings less than 335 bytes) */
|
||||
|
||||
BCC_LE(smb_buf) = cpu_to_le16(count);
|
||||
|
||||
|
||||
/* BB FIXME check for other non ntlm code paths */
|
||||
|
||||
/* BB check is this too big for a small smb? */
|
||||
|
||||
iov[0].iov_base = (char *)pSMB;
|
||||
iov[0].iov_len = smb_buf->smb_buf_length + 4;
|
||||
|
||||
rc = SendReceive2(xid, ses, iov, 1 /* num_iovecs */, &resp_buf_type, 0);
|
||||
/* 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((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) {
|
||||
rc = -EIO;
|
||||
cERROR(1,("bad word count %d", smb_buf->WordCount));
|
||||
goto ssetup_exit;
|
||||
}
|
||||
action = le16_to_cpu(pSMB->resp.Action);
|
||||
if (action & GUEST_LOGIN)
|
||||
cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
|
||||
ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */
|
||||
cFYI(1, ("UID = %d ", ses->Suid));
|
||||
/* response can have either 3 or 4 word count - Samba sends 3 */
|
||||
/* and lanman response is 3 */
|
||||
bytes_remaining = BCC(smb_buf);
|
||||
bcc_ptr = pByteArea(smb_buf);
|
||||
|
||||
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;
|
||||
}
|
||||
bytes_remaining -= blob_len;
|
||||
}
|
||||
|
||||
/* BB check if Unicode and decode strings */
|
||||
if(smb_buf->Flags2 & SMBFLG2_UNICODE)
|
||||
rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining,
|
||||
ses, nls_cp);
|
||||
else
|
||||
rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp);
|
||||
|
||||
ssetup_exit:
|
||||
if(resp_buf_type == CIFS_SMALL_BUFFER) {
|
||||
cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base));
|
||||
cifs_small_buf_release(iov[0].iov_base);
|
||||
} else if(resp_buf_type == CIFS_LARGE_BUFFER)
|
||||
cifs_buf_release(iov[0].iov_base);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/random.h>
|
||||
#include "cifs_unicode.h"
|
||||
#include "cifspdu.h"
|
||||
#include "cifsglob.h"
|
||||
#include "md5.h"
|
||||
#include "cifs_debug.h"
|
||||
#include "cifsencrypt.h"
|
||||
|
|
Loading…
Reference in a new issue