Skip to content

Commit

Permalink
[CIFS] Support for setting up SMB sessions to legacy lanman servers p…
Browse files Browse the repository at this point in the history
…art 2
  • Loading branch information
Steve French committed Jun 1, 2006
1 parent 9c53588 commit 7c7b25b
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 75 deletions.
4 changes: 2 additions & 2 deletions fs/cifs/cifs_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ cifs_proc_init(void)
pde->write_proc = multiuser_mount_write;

pde =
create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs,
create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs,
extended_security_read, NULL);
if (pde)
pde->write_proc = extended_security_write;
Expand Down Expand Up @@ -547,7 +547,7 @@ cifs_proc_clean(void)
remove_proc_entry("MultiuserMount", proc_fs_cifs);
remove_proc_entry("OplockEnabled", proc_fs_cifs);
/* remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */
remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
remove_proc_entry("SecurityFlags",proc_fs_cifs);
/* remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); */
remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs);
remove_proc_entry("Experimental",proc_fs_cifs);
Expand Down
40 changes: 37 additions & 3 deletions fs/cifs/cifsencrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "md5.h"
#include "cifs_unicode.h"
#include "cifsproto.h"
#include <linux/ctype.h>

/* Calculate and return the CIFS signature based on the mac key and the smb pdu */
/* the 16 byte signature must be allocated by the caller */
Expand All @@ -35,6 +36,8 @@

extern void mdfour(unsigned char *out, unsigned char *in, int n);
extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24);

static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu,
const char * key, char * signature)
Expand All @@ -45,7 +48,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu,
return -EINVAL;

MD5Init(&context);
MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16);
MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length);
MD5Final(signature,&context);
return 0;
Expand Down Expand Up @@ -90,7 +93,7 @@ static int cifs_calc_signature2(const struct kvec * iov, int n_vec,
return -EINVAL;

MD5Init(&context);
MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16);
for(i=0;i<n_vec;i++) {
if(iov[i].iov_base == NULL) {
cERROR(1,("null iovec entry"));
Expand Down Expand Up @@ -204,7 +207,7 @@ int cifs_calculate_mac_key(char * key, const char * rn, const char * password)

E_md4hash(password, temp_key);
mdfour(key,temp_key,16);
memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE);
memcpy(key+16,rn, CIFS_SESS_KEY_SIZE);
return 0;
}

Expand Down Expand Up @@ -261,6 +264,37 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_
kfree(unicode_buf);
return 0;
}

#ifdef CONFIG_CIFS_WEAK_PW_HASH
void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
{
int i;
char password_with_pad[CIFS_ENCPWD_SIZE];

memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);

/* calculate old style session key */
/* calling toupper is less broken than repeatedly
calling nls_toupper would be since that will never
work for UTF8, but neither handles multibyte code pages
but the only alternative would be converting to UCS-16 (Unicode)
(using a routine something like UniStrupr) then
uppercasing and then converting back from Unicode - which
would only worth doing it if we knew it were utf8. Basically
utf8 and other multibyte codepages each need their own strupper
function since a byte at a time will ont work. */

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);
/* clear password before we return/free memory */
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
}
#endif /* CIFS_WEAK_PW_HASH */

void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response)
{
struct HMACMD5Context context;
Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ struct TCP_Server_Info {
/* 16th byte of RFC1001 workstation name is always null */
char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
__u32 sequence_number; /* needed for CIFS PDU signature */
char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16];
char mac_signing_key[CIFS_SESS_KEY_SIZE + 16];
};

/*
Expand Down
3 changes: 2 additions & 1 deletion fs/cifs/cifspdu.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@
/*
* Size of the session key (crypto key encrypted with the password
*/
#define CIFS_SESSION_KEY_SIZE (24)
#define CIFS_SESS_KEY_SIZE (24)
#define V2_SESS_KEY_SIZE (86)

/*
* Maximum user name length
Expand Down
3 changes: 3 additions & 0 deletions fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,9 @@ extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key,
extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass);
extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *);
extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * );
#ifdef CONFIG_CIFS_WEAK_PW_HASH
extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key);
#endif /* CIFS_WEAK_PW_HASH */
extern int CIFSSMBCopy(int xid,
struct cifsTconInfo *source_tcon,
const char *fromName,
Expand Down
27 changes: 22 additions & 5 deletions fs/cifs/cifssmb.c
Original file line number Diff line number Diff line change
Expand Up @@ -438,12 +438,19 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
goto neg_err_exit;
} else if((pSMBr->hdr.WordCount == 13) &&
(pSMBr->DialectIndex == LANMAN_PROT)) {
#ifdef CONFIG_CIFS_WEAK_PW_HASH
struct lanman_neg_rsp * rsp =
(struct lanman_neg_rsp *)pSMBr;


/* BB Mark ses struct as negotiated lanman level BB */
server->secType = LANMAN;
if((extended_security & CIFSSEC_MAY_LANMAN) ||
(extended_security & CIFSSEC_MAY_PLNTXT))
server->secType = LANMAN;
else {
cERROR(1, ("mount failed weak security disabled"
" in /proc/fs/cifs/SecurityFlags"));
rc = -EOPNOTSUPP;
goto neg_err_exit;
}
server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Expand All @@ -469,6 +476,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
}

cFYI(1,("LANMAN negotiated")); /* BB removeme BB */
#else /* weak security disabled */
cERROR(1,("mount failed, cifs module not built with "
"CIFS_WEAK_PW_HASH support"));
rc = -EOPNOTSUPP;
#endif /* WEAK_PW_HASH */
goto neg_err_exit;
} else if(pSMBr->hdr.WordCount != 17) {
/* unknown wct */
Expand All @@ -479,8 +491,13 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
server->secMode = pSMBr->SecurityMode;
if((server->secMode & SECMODE_USER) == 0)
cFYI(1,("share mode security"));
server->secType = NTLM; /* BB override default for
NTLMv2 or kerberos v5 */

if(extended_security & CIFSSEC_MUST_NTLMV2)
server->secType = NTLMv2;
else
server->secType = NTLM;
/* else krb5 ... */

/* one byte - no need to convert this or EncryptionKeyLen
from little endian */
server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
Expand Down
47 changes: 29 additions & 18 deletions fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -1990,7 +1990,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,

static int
CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
char session_key[CIFS_SESSION_KEY_SIZE],
char session_key[CIFS_SESS_KEY_SIZE],
const struct nls_table *nls_codepage)
{
struct smb_hdr *smb_buffer;
Expand Down Expand Up @@ -2048,15 +2048,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);

pSMB->req_no_secext.CaseInsensitivePasswordLength =
cpu_to_le16(CIFS_SESSION_KEY_SIZE);
cpu_to_le16(CIFS_SESS_KEY_SIZE);

pSMB->req_no_secext.CaseSensitivePasswordLength =
cpu_to_le16(CIFS_SESSION_KEY_SIZE);
cpu_to_le16(CIFS_SESS_KEY_SIZE);
bcc_ptr = pByteArea(smb_buffer);
memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
bcc_ptr += CIFS_SESSION_KEY_SIZE;
memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
bcc_ptr += CIFS_SESSION_KEY_SIZE;
memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
bcc_ptr += CIFS_SESS_KEY_SIZE;
memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
bcc_ptr += CIFS_SESS_KEY_SIZE;

if (ses->capabilities & CAP_UNICODE) {
if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
Expand Down Expand Up @@ -3004,14 +3004,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
SecurityBlob->LmChallengeResponse.Buffer = 0;

SecurityBlob->NtChallengeResponse.Length =
cpu_to_le16(CIFS_SESSION_KEY_SIZE);
cpu_to_le16(CIFS_SESS_KEY_SIZE);
SecurityBlob->NtChallengeResponse.MaximumLength =
cpu_to_le16(CIFS_SESSION_KEY_SIZE);
memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
cpu_to_le16(CIFS_SESS_KEY_SIZE);
memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
SecurityBlob->NtChallengeResponse.Buffer =
cpu_to_le32(SecurityBlobLength);
SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
bcc_ptr += CIFS_SESSION_KEY_SIZE;
SecurityBlobLength += CIFS_SESS_KEY_SIZE;
bcc_ptr += CIFS_SESS_KEY_SIZE;

if (ses->capabilities & CAP_UNICODE) {
if (domain == NULL) {
Expand Down Expand Up @@ -3350,22 +3350,33 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr = &pSMB->Password[0];
if((ses->server->secMode) & SECMODE_USER) {
pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
*bcc_ptr = 0; /* password is null byte */
bcc_ptr++; /* skip password */
/* already aligned so no need to do it below */
} else {
pSMB->PasswordLength = cpu_to_le16(CIFS_SESSION_KEY_SIZE);
pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
/* BB FIXME add code to fail this if NTLMv2 or Kerberos
specified as required (when that support is added to
the vfs in the future) as only NTLM or the much
weaker LANMAN (which we do not send) is accepted
weaker LANMAN (which we do not send by default) is accepted
by Samba (not sure whether other servers allow
NTLMv2 password here) */
#ifdef CONFIG_CIFS_WEAK_PW_HASH
if((extended_security & CIFSSEC_MAY_LANMAN) &&
(ses->server->secType == LANMAN))
calc_lanman_hash(ses, bcc_ptr);
else
#endif /* CIFS_WEAK_PW_HASH */
SMBNTencrypt(ses->password,
ses->server->cryptKey,
bcc_ptr);

bcc_ptr += CIFS_SESSION_KEY_SIZE;
*bcc_ptr = 0;
bcc_ptr++; /* align */
bcc_ptr += CIFS_SESS_KEY_SIZE;
if(ses->capabilities & CAP_UNICODE) {
/* must align unicode strings */
*bcc_ptr = 0; /* null byte password */
bcc_ptr++;
}
}

if(ses->server->secMode &
Expand Down Expand Up @@ -3507,7 +3518,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
struct nls_table * nls_info)
{
int rc = 0;
char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
char ntlm_session_key[CIFS_SESS_KEY_SIZE];
int ntlmv2_flag = FALSE;
int first_time = 0;

Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/netmisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {

static const struct smb_to_posix_error mapping_table_ERRSRV[] = {
{ERRerror, -EIO},
{ERRbadpw, -EPERM},
{ERRbadpw, -EACCES}, /* was EPERM */
{ERRbadtype, -EREMOTE},
{ERRaccess, -EACCES},
{ERRinvtid, -ENXIO},
Expand Down
Loading

0 comments on commit 7c7b25b

Please sign in to comment.