Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6ea75952 authored by Steve French's avatar Steve French
Browse files

Merge branch 'for-next'

parents 6b0cd00b d2445556
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -527,6 +527,11 @@ A partial list of the supported mount options follows:
		SFU does).  In the future the bottom 9 bits of the
		mode also will be emulated using queries of the security
		descriptor (ACL).
 mfsymlinks     Enable support for Minshall+French symlinks
		(see http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks)
		This option is ignored when specified together with the
		'sfu' option. Minshall+French symlinks are used even if
		the server supports the CIFS Unix Extensions.
 sign           Must use packet signing (helps avoid unwanted data modification
		by intermediate systems in the route).  Note that signing
		does not work with lanman or plaintext authentication.
+12 −9
Original line number Diff line number Diff line
@@ -306,6 +306,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
	int xid, i;
	int rc = 0;
	struct vfsmount *mnt = ERR_PTR(-ENOENT);
	struct tcon_link *tlink;

	cFYI(1, "in %s", __func__);
	BUG_ON(IS_ROOT(dentry));
@@ -315,14 +316,6 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
	dput(nd->path.dentry);
	nd->path.dentry = dget(dentry);

	cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
	ses = cifs_sb->tcon->ses;

	if (!ses) {
		rc = -EINVAL;
		goto out_err;
	}

	/*
	 * The MSDFS spec states that paths in DFS referral requests and
	 * responses must be prefixed by a single '\' character instead of
@@ -335,10 +328,20 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
		goto out_err;
	}

	cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink)) {
		rc = PTR_ERR(tlink);
		goto out_err;
	}
	ses = tlink_tcon(tlink)->ses;

	rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls,
		&num_referrals, &referrals,
		cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);

	cifs_put_tlink(tlink);

	for (i = 0; i < num_referrals; i++) {
		int len;
		dump_referral(referrals+i);
+9 −3
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
 *   the GNU Lesser General Public License for more details.
 *
 */
#include <linux/radix-tree.h>

#ifndef _CIFS_FS_SB_H
#define _CIFS_FS_SB_H

@@ -36,10 +38,13 @@
#define CIFS_MOUNT_NOPOSIXBRL   0x2000 /* mandatory not posix byte range lock */
#define CIFS_MOUNT_NOSSYNC      0x4000 /* don't do slow SMBflush on every sync*/
#define CIFS_MOUNT_FSCACHE	0x8000 /* local caching enabled */
#define CIFS_MOUNT_MF_SYMLINKS	0x10000 /* Minshall+French Symlinks enabled */
#define CIFS_MOUNT_MULTIUSER	0x20000 /* multiuser mount */

struct cifs_sb_info {
	struct cifsTconInfo *tcon;	/* primary mount */
	struct list_head nested_tcon_q;
	struct radix_tree_root tlink_tree;
#define CIFS_TLINK_MASTER_TAG		0	/* is "master" (mount) tcon */
	spinlock_t tlink_tree_lock;
	struct nls_table *local_nls;
	unsigned int rsize;
	unsigned int wsize;
@@ -47,12 +52,13 @@ struct cifs_sb_info {
	gid_t	mnt_gid;
	mode_t	mnt_file_mode;
	mode_t	mnt_dir_mode;
	int     mnt_cifs_flags;
	unsigned int mnt_cifs_flags;
	int	prepathlen;
	char   *prepath; /* relative path under the share to mount to */
#ifdef CONFIG_CIFS_DFS_UPCALL
	char   *mountdata; /* mount options received at mount time */
#endif
	struct backing_dev_info bdi;
	struct delayed_work prune_tlinks;
};
#endif				/* _CIFS_FS_SB_H */
+35 −11
Original line number Diff line number Diff line
@@ -557,11 +557,16 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
{
	struct cifs_ntsd *pntsd = NULL;
	int xid, rc;
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);

	if (IS_ERR(tlink))
		return NULL;

	xid = GetXid();
	rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
	rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
	FreeXid(xid);

	cifs_put_tlink(tlink);

	cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen);
	return pntsd;
@@ -574,10 +579,16 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
	int oplock = 0;
	int xid, rc;
	__u16 fid;
	struct cifsTconInfo *tcon;
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);

	if (IS_ERR(tlink))
		return NULL;

	tcon = tlink_tcon(tlink);
	xid = GetXid();

	rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, READ_CONTROL, 0,
	rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
			 &fid, &oplock, NULL, cifs_sb->local_nls,
			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
	if (rc) {
@@ -585,11 +596,12 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
		goto out;
	}

	rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
	rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
	cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen);

	CIFSSMBClose(xid, cifs_sb->tcon, fid);
	CIFSSMBClose(xid, tcon, fid);
 out:
	cifs_put_tlink(tlink);
	FreeXid(xid);
	return pntsd;
}
@@ -603,7 +615,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
	struct cifsFileInfo *open_file = NULL;

	if (inode)
		open_file = find_readable_file(CIFS_I(inode));
		open_file = find_readable_file(CIFS_I(inode), true);
	if (!open_file)
		return get_cifs_acl_by_path(cifs_sb, path, pacllen);

@@ -616,10 +628,15 @@ static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
		struct cifs_ntsd *pnntsd, u32 acllen)
{
	int xid, rc;
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);

	if (IS_ERR(tlink))
		return PTR_ERR(tlink);

	xid = GetXid();
	rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen);
	rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
	FreeXid(xid);
	cifs_put_tlink(tlink);

	cFYI(DBG2, "SetCIFSACL rc = %d", rc);
	return rc;
@@ -631,10 +648,16 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
	int oplock = 0;
	int xid, rc;
	__u16 fid;
	struct cifsTconInfo *tcon;
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);

	if (IS_ERR(tlink))
		return PTR_ERR(tlink);

	tcon = tlink_tcon(tlink);
	xid = GetXid();

	rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, WRITE_DAC, 0,
	rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0,
			 &fid, &oplock, NULL, cifs_sb->local_nls,
			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
	if (rc) {
@@ -642,12 +665,13 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
		goto out;
	}

	rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen);
	rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
	cFYI(DBG2, "SetCIFSACL rc = %d", rc);

	CIFSSMBClose(xid, cifs_sb->tcon, fid);
	CIFSSMBClose(xid, tcon, fid);
out:
	FreeXid(xid);
	cifs_put_tlink(tlink);
	return rc;
}

@@ -661,7 +685,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,

	cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);

	open_file = find_readable_file(CIFS_I(inode));
	open_file = find_readable_file(CIFS_I(inode), true);
	if (!open_file)
		return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);

+129 −17
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include "md5.h"
#include "cifs_unicode.h"
#include "cifsproto.h"
#include "ntlmssp.h"
#include <linux/ctype.h>
#include <linux/random.h>

@@ -42,7 +43,7 @@ extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
		       unsigned char *p24);

static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
				    const struct mac_key *key, char *signature)
				const struct session_key *key, char *signature)
{
	struct	MD5Context context;

@@ -78,7 +79,7 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
	server->sequence_number++;
	spin_unlock(&GlobalMid_Lock);

	rc = cifs_calculate_signature(cifs_pdu, &server->mac_signing_key,
	rc = cifs_calculate_signature(cifs_pdu, &server->session_key,
				      smb_signature);
	if (rc)
		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
@@ -89,7 +90,7 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
}

static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
				const struct mac_key *key, char *signature)
				const struct session_key *key, char *signature)
{
	struct  MD5Context context;
	int i;
@@ -145,7 +146,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
	server->sequence_number++;
	spin_unlock(&GlobalMid_Lock);

	rc = cifs_calc_signature2(iov, n_vec, &server->mac_signing_key,
	rc = cifs_calc_signature2(iov, n_vec, &server->session_key,
				      smb_signature);
	if (rc)
		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
@@ -156,14 +157,14 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
}

int cifs_verify_signature(struct smb_hdr *cifs_pdu,
			  const struct mac_key *mac_key,
			  const struct session_key *session_key,
			  __u32 expected_sequence_number)
{
	unsigned int rc;
	char server_response_sig[8];
	char what_we_think_sig_should_be[20];

	if ((cifs_pdu == NULL) || (mac_key == NULL))
	if (cifs_pdu == NULL || session_key == NULL)
		return -EINVAL;

	if (cifs_pdu->Command == SMB_COM_NEGOTIATE)
@@ -192,7 +193,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
					cpu_to_le32(expected_sequence_number);
	cifs_pdu->Signature.Sequence.Reserved = 0;

	rc = cifs_calculate_signature(cifs_pdu, mac_key,
	rc = cifs_calculate_signature(cifs_pdu, session_key,
		what_we_think_sig_should_be);

	if (rc)
@@ -209,7 +210,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
}

/* We fill in key by putting in 40 byte array which was allocated by caller */
int cifs_calculate_mac_key(struct mac_key *key, const char *rn,
int cifs_calculate_session_key(struct session_key *key, const char *rn,
			   const char *password)
{
	char temp_key[16];
@@ -262,6 +263,90 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
}
#endif /* CIFS_WEAK_PW_HASH */

/* This is just a filler for ntlmv2 type of security mechanisms.
 * Older servers are not very particular about the contents of av pairs
 * in the blob and for sec mechs like ntlmv2, there is no negotiation
 * as in ntlmssp, so unless domain and server  netbios and dns names
 * are specified, there is no way to obtain name.  In case of ntlmssp,
 * server provides that info in type 2 challenge packet
 */
static int
build_avpair_blob(struct cifsSesInfo *ses)
{
	struct ntlmssp2_name *attrptr;

	ses->tilen = 2 * sizeof(struct ntlmssp2_name);
	ses->tiblob = kzalloc(ses->tilen, GFP_KERNEL);
	if (!ses->tiblob) {
		ses->tilen = 0;
		cERROR(1, "Challenge target info allocation failure");
		return -ENOMEM;
	}
	attrptr = (struct ntlmssp2_name *) ses->tiblob;
	attrptr->type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE);

	return 0;
}

/* Server has provided av pairs/target info in the type 2 challenge
 * packet and we have plucked it and stored within smb session.
 * We parse that blob here to find netbios domain name to be used
 * as part of ntlmv2 authentication (in Target String), if not already
 * specified on the command line.
 * If this function returns without any error but without fetching
 * domain name, authentication may fail against some server but
 * may not fail against other (those who are not very particular
 * about target string i.e. for some, just user name might suffice.
 */
static int
find_domain_name(struct cifsSesInfo *ses)
{
	unsigned int attrsize;
	unsigned int type;
	unsigned int onesize = sizeof(struct ntlmssp2_name);
	unsigned char *blobptr;
	unsigned char *blobend;
	struct ntlmssp2_name *attrptr;

	if (!ses->tilen || !ses->tiblob)
		return 0;

	blobptr = ses->tiblob;
	blobend = ses->tiblob + ses->tilen;

	while (blobptr + onesize < blobend) {
		attrptr = (struct ntlmssp2_name *) blobptr;
		type = le16_to_cpu(attrptr->type);
		if (type == NTLMSSP_AV_EOL)
			break;
		blobptr += 2; /* advance attr type */
		attrsize = le16_to_cpu(attrptr->length);
		blobptr += 2; /* advance attr size */
		if (blobptr + attrsize > blobend)
			break;
		if (type == NTLMSSP_AV_NB_DOMAIN_NAME) {
			if (!attrsize)
				break;
			if (!ses->domainName) {
				struct nls_table *default_nls;
				ses->domainName =
					kmalloc(attrsize + 1, GFP_KERNEL);
				if (!ses->domainName)
						return -ENOMEM;
				default_nls = load_nls_default();
				cifs_from_ucs2(ses->domainName,
					(__le16 *)blobptr, attrsize, attrsize,
					default_nls, false);
				unload_nls(default_nls);
				break;
			}
		}
		blobptr += attrsize; /* advance attr  value */
	}

	return 0;
}

static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
			    const struct nls_table *nls_cp)
{
@@ -321,7 +406,8 @@ calc_exit_2:
	return rc;
}

void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
int
setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
		      const struct nls_table *nls_cp)
{
	int rc;
@@ -333,25 +419,48 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
	buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
	get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
	buf->reserved2 = 0;
	buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE);
	buf->names[0].length = 0;
	buf->names[1].type = 0;
	buf->names[1].length = 0;

	if (ses->server->secType == RawNTLMSSP) {
		if (!ses->domainName) {
			rc = find_domain_name(ses);
			if (rc) {
				cERROR(1, "error %d finding domain name", rc);
				goto setup_ntlmv2_rsp_ret;
			}
		}
	} else {
		rc = build_avpair_blob(ses);
		if (rc) {
			cERROR(1, "error %d building av pair blob", rc);
			return rc;
		}
	}

	/* calculate buf->ntlmv2_hash */
	rc = calc_ntlmv2_hash(ses, nls_cp);
	if (rc)
	if (rc) {
		cERROR(1, "could not get v2 hash rc %d", rc);
		goto setup_ntlmv2_rsp_ret;
	}
	CalcNTLMv2_response(ses, resp_buf);

	/* now calculate the MAC key for NTLMv2 */
	hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context);
	hmac_md5_update(resp_buf, 16, &context);
	hmac_md5_final(ses->server->mac_signing_key.data.ntlmv2.key, &context);
	hmac_md5_final(ses->server->session_key.data.ntlmv2.key, &context);

	memcpy(&ses->server->mac_signing_key.data.ntlmv2.resp, resp_buf,
	memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf,
	       sizeof(struct ntlmv2_resp));
	ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp);
	ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp);

	return 0;

setup_ntlmv2_rsp_ret:
	kfree(ses->tiblob);
	ses->tiblob = NULL;
	ses->tilen = 0;

	return rc;
}

void CalcNTLMv2_response(const struct cifsSesInfo *ses,
@@ -365,6 +474,9 @@ void CalcNTLMv2_response(const struct cifsSesInfo *ses,
	hmac_md5_update(v2_session_response+8,
			sizeof(struct ntlmv2_resp) - 8, &context);

	if (ses->tilen)
		hmac_md5_update(ses->tiblob, ses->tilen, &context);

	hmac_md5_final(v2_session_response, &context);
/*	cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
}
Loading