Merge branch 'master' of git+ssh://git.samba.org/data/git/sfrench/cifs-2.6
This commit is contained in:
commit
34f598ca08
|
@ -676,14 +676,23 @@ static ssize_t cifs_multiuser_mount_proc_write(struct file *file,
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
int rc;
|
int rc;
|
||||||
|
static bool warned;
|
||||||
|
|
||||||
rc = get_user(c, buffer);
|
rc = get_user(c, buffer);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
if (c == '0' || c == 'n' || c == 'N')
|
if (c == '0' || c == 'n' || c == 'N')
|
||||||
multiuser_mount = 0;
|
multiuser_mount = 0;
|
||||||
else if (c == '1' || c == 'y' || c == 'Y')
|
else if (c == '1' || c == 'y' || c == 'Y') {
|
||||||
multiuser_mount = 1;
|
multiuser_mount = 1;
|
||||||
|
if (!warned) {
|
||||||
|
warned = true;
|
||||||
|
printk(KERN_WARNING "CIFS VFS: The legacy multiuser "
|
||||||
|
"mount code is scheduled to be deprecated in "
|
||||||
|
"3.5. Please switch to using the multiuser "
|
||||||
|
"mount option.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,9 +113,11 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo)
|
||||||
MAX_MECH_STR_LEN +
|
MAX_MECH_STR_LEN +
|
||||||
UID_KEY_LEN + (sizeof(uid_t) * 2) +
|
UID_KEY_LEN + (sizeof(uid_t) * 2) +
|
||||||
CREDUID_KEY_LEN + (sizeof(uid_t) * 2) +
|
CREDUID_KEY_LEN + (sizeof(uid_t) * 2) +
|
||||||
USER_KEY_LEN + strlen(sesInfo->user_name) +
|
|
||||||
PID_KEY_LEN + (sizeof(pid_t) * 2) + 1;
|
PID_KEY_LEN + (sizeof(pid_t) * 2) + 1;
|
||||||
|
|
||||||
|
if (sesInfo->user_name)
|
||||||
|
desc_len += USER_KEY_LEN + strlen(sesInfo->user_name);
|
||||||
|
|
||||||
spnego_key = ERR_PTR(-ENOMEM);
|
spnego_key = ERR_PTR(-ENOMEM);
|
||||||
description = kzalloc(desc_len, GFP_KERNEL);
|
description = kzalloc(desc_len, GFP_KERNEL);
|
||||||
if (description == NULL)
|
if (description == NULL)
|
||||||
|
@ -152,8 +154,10 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo)
|
||||||
dp = description + strlen(description);
|
dp = description + strlen(description);
|
||||||
sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid);
|
sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid);
|
||||||
|
|
||||||
|
if (sesInfo->user_name) {
|
||||||
dp = description + strlen(description);
|
dp = description + strlen(description);
|
||||||
sprintf(dp, ";user=%s", sesInfo->user_name);
|
sprintf(dp, ";user=%s", sesInfo->user_name);
|
||||||
|
}
|
||||||
|
|
||||||
dp = description + strlen(description);
|
dp = description + strlen(description);
|
||||||
sprintf(dp, ";pid=0x%x", current->pid);
|
sprintf(dp, ";pid=0x%x", current->pid);
|
||||||
|
|
|
@ -420,15 +420,20 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert ses->user_name to unicode and uppercase */
|
/* convert ses->user_name to unicode and uppercase */
|
||||||
len = strlen(ses->user_name);
|
len = ses->user_name ? strlen(ses->user_name) : 0;
|
||||||
user = kmalloc(2 + (len * 2), GFP_KERNEL);
|
user = kmalloc(2 + (len * 2), GFP_KERNEL);
|
||||||
if (user == NULL) {
|
if (user == NULL) {
|
||||||
cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n");
|
cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n");
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (len) {
|
||||||
len = cifs_strtoUCS((__le16 *)user, ses->user_name, len, nls_cp);
|
len = cifs_strtoUCS((__le16 *)user, ses->user_name, len, nls_cp);
|
||||||
UniStrupr(user);
|
UniStrupr(user);
|
||||||
|
} else {
|
||||||
|
memset(user, '\0', 2);
|
||||||
|
}
|
||||||
|
|
||||||
rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
|
rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
|
||||||
(char *)user, 2 * len);
|
(char *)user, 2 * len);
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
#include <linux/inet.h>
|
#include <linux/inet.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <keys/user-type.h>
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
#include "cifspdu.h"
|
#include "cifspdu.h"
|
||||||
#include "cifsglob.h"
|
#include "cifsglob.h"
|
||||||
|
@ -225,76 +226,92 @@ static int check2ndT2(struct smb_hdr *pSMB)
|
||||||
|
|
||||||
static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
|
static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
|
||||||
{
|
{
|
||||||
struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
|
struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)psecond;
|
||||||
struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
|
struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
|
||||||
char *data_area_of_target;
|
char *data_area_of_tgt;
|
||||||
char *data_area_of_buf2;
|
char *data_area_of_src;
|
||||||
int remaining;
|
int remaining;
|
||||||
unsigned int byte_count, total_in_buf;
|
unsigned int byte_count, total_in_tgt;
|
||||||
__u16 total_data_size, total_in_buf2;
|
__u16 tgt_total_cnt, src_total_cnt, total_in_src;
|
||||||
|
|
||||||
total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
|
src_total_cnt = get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount);
|
||||||
|
tgt_total_cnt = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
|
||||||
|
|
||||||
if (total_data_size !=
|
if (tgt_total_cnt != src_total_cnt)
|
||||||
get_unaligned_le16(&pSMB2->t2_rsp.TotalDataCount))
|
cFYI(1, "total data count of primary and secondary t2 differ "
|
||||||
cFYI(1, "total data size of primary and secondary t2 differ");
|
"source=%hu target=%hu", src_total_cnt, tgt_total_cnt);
|
||||||
|
|
||||||
total_in_buf = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
|
total_in_tgt = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
|
||||||
|
|
||||||
remaining = total_data_size - total_in_buf;
|
remaining = tgt_total_cnt - total_in_tgt;
|
||||||
|
|
||||||
if (remaining < 0)
|
if (remaining < 0) {
|
||||||
|
cFYI(1, "Server sent too much data. tgt_total_cnt=%hu "
|
||||||
|
"total_in_tgt=%hu", tgt_total_cnt, total_in_tgt);
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
|
|
||||||
if (remaining == 0) /* nothing to do, ignore */
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
total_in_buf2 = get_unaligned_le16(&pSMB2->t2_rsp.DataCount);
|
|
||||||
if (remaining < total_in_buf2) {
|
|
||||||
cFYI(1, "transact2 2nd response contains too much data");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (remaining == 0) {
|
||||||
|
/* nothing to do, ignore */
|
||||||
|
cFYI(1, "no more data remains");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_in_src = get_unaligned_le16(&pSMBs->t2_rsp.DataCount);
|
||||||
|
if (remaining < total_in_src)
|
||||||
|
cFYI(1, "transact2 2nd response contains too much data");
|
||||||
|
|
||||||
/* find end of first SMB data area */
|
/* find end of first SMB data area */
|
||||||
data_area_of_target = (char *)&pSMBt->hdr.Protocol +
|
data_area_of_tgt = (char *)&pSMBt->hdr.Protocol +
|
||||||
get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
|
get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
|
||||||
|
|
||||||
/* validate target area */
|
/* validate target area */
|
||||||
|
data_area_of_src = (char *)&pSMBs->hdr.Protocol +
|
||||||
|
get_unaligned_le16(&pSMBs->t2_rsp.DataOffset);
|
||||||
|
|
||||||
data_area_of_buf2 = (char *)&pSMB2->hdr.Protocol +
|
data_area_of_tgt += total_in_tgt;
|
||||||
get_unaligned_le16(&pSMB2->t2_rsp.DataOffset);
|
|
||||||
|
|
||||||
data_area_of_target += total_in_buf;
|
total_in_tgt += total_in_src;
|
||||||
|
|
||||||
/* copy second buffer into end of first buffer */
|
|
||||||
total_in_buf += total_in_buf2;
|
|
||||||
/* is the result too big for the field? */
|
/* is the result too big for the field? */
|
||||||
if (total_in_buf > USHRT_MAX)
|
if (total_in_tgt > USHRT_MAX) {
|
||||||
|
cFYI(1, "coalesced DataCount too large (%u)", total_in_tgt);
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount);
|
}
|
||||||
|
put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount);
|
||||||
|
|
||||||
/* fix up the BCC */
|
/* fix up the BCC */
|
||||||
byte_count = get_bcc(pTargetSMB);
|
byte_count = get_bcc(pTargetSMB);
|
||||||
byte_count += total_in_buf2;
|
byte_count += total_in_src;
|
||||||
/* is the result too big for the field? */
|
/* is the result too big for the field? */
|
||||||
if (byte_count > USHRT_MAX)
|
if (byte_count > USHRT_MAX) {
|
||||||
|
cFYI(1, "coalesced BCC too large (%u)", byte_count);
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
|
}
|
||||||
put_bcc(byte_count, pTargetSMB);
|
put_bcc(byte_count, pTargetSMB);
|
||||||
|
|
||||||
byte_count = be32_to_cpu(pTargetSMB->smb_buf_length);
|
byte_count = be32_to_cpu(pTargetSMB->smb_buf_length);
|
||||||
byte_count += total_in_buf2;
|
byte_count += total_in_src;
|
||||||
/* don't allow buffer to overflow */
|
/* don't allow buffer to overflow */
|
||||||
if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)
|
if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||||
|
cFYI(1, "coalesced BCC exceeds buffer size (%u)", byte_count);
|
||||||
return -ENOBUFS;
|
return -ENOBUFS;
|
||||||
|
}
|
||||||
pTargetSMB->smb_buf_length = cpu_to_be32(byte_count);
|
pTargetSMB->smb_buf_length = cpu_to_be32(byte_count);
|
||||||
|
|
||||||
memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
|
/* copy second buffer into end of first buffer */
|
||||||
|
memcpy(data_area_of_tgt, data_area_of_src, total_in_src);
|
||||||
|
|
||||||
if (remaining == total_in_buf2) {
|
if (remaining != total_in_src) {
|
||||||
cFYI(1, "found the last secondary response");
|
/* more responses to go */
|
||||||
return 0; /* we are done */
|
cFYI(1, "waiting for more secondary responses");
|
||||||
} else /* more responses to go */
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* we are done */
|
||||||
|
cFYI(1, "found the last secondary response");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cifs_echo_request(struct work_struct *work)
|
cifs_echo_request(struct work_struct *work)
|
||||||
{
|
{
|
||||||
|
@ -1578,11 +1595,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vol->multiuser && !(vol->secFlg & CIFSSEC_MAY_KRB5)) {
|
#ifndef CONFIG_KEYS
|
||||||
cERROR(1, "Multiuser mounts currently require krb5 "
|
/* Muliuser mounts require CONFIG_KEYS support */
|
||||||
"authentication!");
|
if (vol->multiuser) {
|
||||||
|
cERROR(1, "Multiuser mounts require kernels with "
|
||||||
|
"CONFIG_KEYS enabled.");
|
||||||
goto cifs_parse_mount_err;
|
goto cifs_parse_mount_err;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (vol->UNCip == NULL)
|
if (vol->UNCip == NULL)
|
||||||
vol->UNCip = &vol->UNC[2];
|
vol->UNCip = &vol->UNC[2];
|
||||||
|
@ -1981,10 +2001,16 @@ static int match_session(struct cifs_ses *ses, struct smb_vol *vol)
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* anything else takes username/password */
|
/* NULL username means anonymous session */
|
||||||
if (ses->user_name == NULL)
|
if (ses->user_name == NULL) {
|
||||||
|
if (!vol->nullauth)
|
||||||
return 0;
|
return 0;
|
||||||
if (strncmp(ses->user_name, vol->username,
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* anything else takes username/password */
|
||||||
|
if (strncmp(ses->user_name,
|
||||||
|
vol->username ? vol->username : "",
|
||||||
MAX_USERNAME_SIZE))
|
MAX_USERNAME_SIZE))
|
||||||
return 0;
|
return 0;
|
||||||
if (strlen(vol->username) != 0 &&
|
if (strlen(vol->username) != 0 &&
|
||||||
|
@ -2039,6 +2065,132 @@ cifs_put_smb_ses(struct cifs_ses *ses)
|
||||||
cifs_put_tcp_session(server);
|
cifs_put_tcp_session(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_KEYS
|
||||||
|
|
||||||
|
/* strlen("cifs:a:") + INET6_ADDRSTRLEN + 1 */
|
||||||
|
#define CIFSCREDS_DESC_SIZE (7 + INET6_ADDRSTRLEN + 1)
|
||||||
|
|
||||||
|
/* Populate username and pw fields from keyring if possible */
|
||||||
|
static int
|
||||||
|
cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
char *desc, *delim, *payload;
|
||||||
|
ssize_t len;
|
||||||
|
struct key *key;
|
||||||
|
struct TCP_Server_Info *server = ses->server;
|
||||||
|
struct sockaddr_in *sa;
|
||||||
|
struct sockaddr_in6 *sa6;
|
||||||
|
struct user_key_payload *upayload;
|
||||||
|
|
||||||
|
desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL);
|
||||||
|
if (!desc)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* try to find an address key first */
|
||||||
|
switch (server->dstaddr.ss_family) {
|
||||||
|
case AF_INET:
|
||||||
|
sa = (struct sockaddr_in *)&server->dstaddr;
|
||||||
|
sprintf(desc, "cifs:a:%pI4", &sa->sin_addr.s_addr);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
sa6 = (struct sockaddr_in6 *)&server->dstaddr;
|
||||||
|
sprintf(desc, "cifs:a:%pI6c", &sa6->sin6_addr.s6_addr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cFYI(1, "Bad ss_family (%hu)", server->dstaddr.ss_family);
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
cFYI(1, "%s: desc=%s", __func__, desc);
|
||||||
|
key = request_key(&key_type_logon, desc, "");
|
||||||
|
if (IS_ERR(key)) {
|
||||||
|
if (!ses->domainName) {
|
||||||
|
cFYI(1, "domainName is NULL");
|
||||||
|
rc = PTR_ERR(key);
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* didn't work, try to find a domain key */
|
||||||
|
sprintf(desc, "cifs:d:%s", ses->domainName);
|
||||||
|
cFYI(1, "%s: desc=%s", __func__, desc);
|
||||||
|
key = request_key(&key_type_logon, desc, "");
|
||||||
|
if (IS_ERR(key)) {
|
||||||
|
rc = PTR_ERR(key);
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
down_read(&key->sem);
|
||||||
|
upayload = key->payload.data;
|
||||||
|
if (IS_ERR_OR_NULL(upayload)) {
|
||||||
|
rc = PTR_ERR(key);
|
||||||
|
goto out_key_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find first : in payload */
|
||||||
|
payload = (char *)upayload->data;
|
||||||
|
delim = strnchr(payload, upayload->datalen, ':');
|
||||||
|
cFYI(1, "payload=%s", payload);
|
||||||
|
if (!delim) {
|
||||||
|
cFYI(1, "Unable to find ':' in payload (datalen=%d)",
|
||||||
|
upayload->datalen);
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto out_key_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = delim - payload;
|
||||||
|
if (len > MAX_USERNAME_SIZE || len <= 0) {
|
||||||
|
cFYI(1, "Bad value from username search (len=%ld)", len);
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto out_key_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
vol->username = kstrndup(payload, len, GFP_KERNEL);
|
||||||
|
if (!vol->username) {
|
||||||
|
cFYI(1, "Unable to allocate %ld bytes for username", len);
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto out_key_put;
|
||||||
|
}
|
||||||
|
cFYI(1, "%s: username=%s", __func__, vol->username);
|
||||||
|
|
||||||
|
len = key->datalen - (len + 1);
|
||||||
|
if (len > MAX_PASSWORD_SIZE || len <= 0) {
|
||||||
|
cFYI(1, "Bad len for password search (len=%ld)", len);
|
||||||
|
rc = -EINVAL;
|
||||||
|
kfree(vol->username);
|
||||||
|
vol->username = NULL;
|
||||||
|
goto out_key_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
++delim;
|
||||||
|
vol->password = kstrndup(delim, len, GFP_KERNEL);
|
||||||
|
if (!vol->password) {
|
||||||
|
cFYI(1, "Unable to allocate %ld bytes for password", len);
|
||||||
|
rc = -ENOMEM;
|
||||||
|
kfree(vol->username);
|
||||||
|
vol->username = NULL;
|
||||||
|
goto out_key_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_key_put:
|
||||||
|
up_read(&key->sem);
|
||||||
|
key_put(key);
|
||||||
|
out_err:
|
||||||
|
kfree(desc);
|
||||||
|
cFYI(1, "%s: returning %d", __func__, rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#else /* ! CONFIG_KEYS */
|
||||||
|
static inline int
|
||||||
|
cifs_set_cifscreds(struct smb_vol *vol __attribute__((unused)),
|
||||||
|
struct cifs_ses *ses __attribute__((unused)))
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_KEYS */
|
||||||
|
|
||||||
static bool warned_on_ntlm; /* globals init to false automatically */
|
static bool warned_on_ntlm; /* globals init to false automatically */
|
||||||
|
|
||||||
static struct cifs_ses *
|
static struct cifs_ses *
|
||||||
|
@ -2914,18 +3066,33 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
|
||||||
#define CIFS_DEFAULT_IOSIZE (1024 * 1024)
|
#define CIFS_DEFAULT_IOSIZE (1024 * 1024)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Windows only supports a max of 60k reads. Default to that when posix
|
* Windows only supports a max of 60kb reads and 65535 byte writes. Default to
|
||||||
* extensions aren't in force.
|
* those values when posix extensions aren't in force. In actuality here, we
|
||||||
|
* use 65536 to allow for a write that is a multiple of 4k. Most servers seem
|
||||||
|
* to be ok with the extra byte even though Windows doesn't send writes that
|
||||||
|
* are that large.
|
||||||
|
*
|
||||||
|
* Citation:
|
||||||
|
*
|
||||||
|
* http://blogs.msdn.com/b/openspecification/archive/2009/04/10/smb-maximum-transmit-buffer-size-and-performance-tuning.aspx
|
||||||
*/
|
*/
|
||||||
#define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024)
|
#define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024)
|
||||||
|
#define CIFS_DEFAULT_NON_POSIX_WSIZE (65536)
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
|
cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
|
||||||
{
|
{
|
||||||
__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
|
__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
|
||||||
struct TCP_Server_Info *server = tcon->ses->server;
|
struct TCP_Server_Info *server = tcon->ses->server;
|
||||||
unsigned int wsize = pvolume_info->wsize ? pvolume_info->wsize :
|
unsigned int wsize;
|
||||||
CIFS_DEFAULT_IOSIZE;
|
|
||||||
|
/* start with specified wsize, or default */
|
||||||
|
if (pvolume_info->wsize)
|
||||||
|
wsize = pvolume_info->wsize;
|
||||||
|
else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
|
||||||
|
wsize = CIFS_DEFAULT_IOSIZE;
|
||||||
|
else
|
||||||
|
wsize = CIFS_DEFAULT_NON_POSIX_WSIZE;
|
||||||
|
|
||||||
/* can server support 24-bit write sizes? (via UNIX extensions) */
|
/* can server support 24-bit write sizes? (via UNIX extensions) */
|
||||||
if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
|
if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
|
||||||
|
@ -3136,10 +3303,9 @@ cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (volume_info->nullauth) {
|
if (volume_info->nullauth) {
|
||||||
cFYI(1, "null user");
|
cFYI(1, "Anonymous login");
|
||||||
volume_info->username = kzalloc(1, GFP_KERNEL);
|
kfree(volume_info->username);
|
||||||
if (volume_info->username == NULL)
|
volume_info->username = NULL;
|
||||||
return -ENOMEM;
|
|
||||||
} else if (volume_info->username) {
|
} else if (volume_info->username) {
|
||||||
/* BB fixme parse for domain name here */
|
/* BB fixme parse for domain name here */
|
||||||
cFYI(1, "Username: %s", volume_info->username);
|
cFYI(1, "Username: %s", volume_info->username);
|
||||||
|
@ -3657,16 +3823,38 @@ int cifs_setup_session(unsigned int xid, struct cifs_ses *ses,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cifs_set_vol_auth(struct smb_vol *vol, struct cifs_ses *ses)
|
||||||
|
{
|
||||||
|
switch (ses->server->secType) {
|
||||||
|
case Kerberos:
|
||||||
|
vol->secFlg = CIFSSEC_MUST_KRB5;
|
||||||
|
return 0;
|
||||||
|
case NTLMv2:
|
||||||
|
vol->secFlg = CIFSSEC_MUST_NTLMV2;
|
||||||
|
break;
|
||||||
|
case NTLM:
|
||||||
|
vol->secFlg = CIFSSEC_MUST_NTLM;
|
||||||
|
break;
|
||||||
|
case RawNTLMSSP:
|
||||||
|
vol->secFlg = CIFSSEC_MUST_NTLMSSP;
|
||||||
|
break;
|
||||||
|
case LANMAN:
|
||||||
|
vol->secFlg = CIFSSEC_MUST_LANMAN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cifs_set_cifscreds(vol, ses);
|
||||||
|
}
|
||||||
|
|
||||||
static struct cifs_tcon *
|
static struct cifs_tcon *
|
||||||
cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
|
cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
|
||||||
{
|
{
|
||||||
|
int rc;
|
||||||
struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb);
|
struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb);
|
||||||
struct cifs_ses *ses;
|
struct cifs_ses *ses;
|
||||||
struct cifs_tcon *tcon = NULL;
|
struct cifs_tcon *tcon = NULL;
|
||||||
struct smb_vol *vol_info;
|
struct smb_vol *vol_info;
|
||||||
char username[28]; /* big enough for "krb50x" + hex of ULONG_MAX 6+16 */
|
|
||||||
/* We used to have this as MAX_USERNAME which is */
|
|
||||||
/* way too big now (256 instead of 32) */
|
|
||||||
|
|
||||||
vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL);
|
vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL);
|
||||||
if (vol_info == NULL) {
|
if (vol_info == NULL) {
|
||||||
|
@ -3674,8 +3862,6 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(username, sizeof(username), "krb50x%x", fsuid);
|
|
||||||
vol_info->username = username;
|
|
||||||
vol_info->local_nls = cifs_sb->local_nls;
|
vol_info->local_nls = cifs_sb->local_nls;
|
||||||
vol_info->linux_uid = fsuid;
|
vol_info->linux_uid = fsuid;
|
||||||
vol_info->cred_uid = fsuid;
|
vol_info->cred_uid = fsuid;
|
||||||
|
@ -3685,8 +3871,11 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
|
||||||
vol_info->local_lease = master_tcon->local_lease;
|
vol_info->local_lease = master_tcon->local_lease;
|
||||||
vol_info->no_linux_ext = !master_tcon->unix_ext;
|
vol_info->no_linux_ext = !master_tcon->unix_ext;
|
||||||
|
|
||||||
/* FIXME: allow for other secFlg settings */
|
rc = cifs_set_vol_auth(vol_info, master_tcon->ses);
|
||||||
vol_info->secFlg = CIFSSEC_MUST_KRB5;
|
if (rc) {
|
||||||
|
tcon = ERR_PTR(rc);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* get a reference for the same TCP session */
|
/* get a reference for the same TCP session */
|
||||||
spin_lock(&cifs_tcp_ses_lock);
|
spin_lock(&cifs_tcp_ses_lock);
|
||||||
|
@ -3709,6 +3898,8 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
|
||||||
if (ses->capabilities & CAP_UNIX)
|
if (ses->capabilities & CAP_UNIX)
|
||||||
reset_cifs_unix_caps(0, tcon, NULL, vol_info);
|
reset_cifs_unix_caps(0, tcon, NULL, vol_info);
|
||||||
out:
|
out:
|
||||||
|
kfree(vol_info->username);
|
||||||
|
kfree(vol_info->password);
|
||||||
kfree(vol_info);
|
kfree(vol_info);
|
||||||
|
|
||||||
return tcon;
|
return tcon;
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/*
|
/*
|
||||||
* the payload for a key of type "user"
|
* the payload for a key of type "user" or "logon"
|
||||||
* - once filled in and attached to a key:
|
* - once filled in and attached to a key:
|
||||||
* - the payload struct is invariant may not be changed, only replaced
|
* - the payload struct is invariant may not be changed, only replaced
|
||||||
* - the payload must be read with RCU procedures or with the key semaphore
|
* - the payload must be read with RCU procedures or with the key semaphore
|
||||||
|
@ -33,6 +33,7 @@ struct user_key_payload {
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct key_type key_type_user;
|
extern struct key_type key_type_user;
|
||||||
|
extern struct key_type key_type_logon;
|
||||||
|
|
||||||
extern int user_instantiate(struct key *key, const void *data, size_t datalen);
|
extern int user_instantiate(struct key *key, const void *data, size_t datalen);
|
||||||
extern int user_update(struct key *key, const void *data, size_t datalen);
|
extern int user_update(struct key *key, const void *data, size_t datalen);
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
extern struct key_type key_type_dead;
|
extern struct key_type key_type_dead;
|
||||||
extern struct key_type key_type_user;
|
extern struct key_type key_type_user;
|
||||||
|
extern struct key_type key_type_logon;
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -999,6 +999,7 @@ void __init key_init(void)
|
||||||
list_add_tail(&key_type_keyring.link, &key_types_list);
|
list_add_tail(&key_type_keyring.link, &key_types_list);
|
||||||
list_add_tail(&key_type_dead.link, &key_types_list);
|
list_add_tail(&key_type_dead.link, &key_types_list);
|
||||||
list_add_tail(&key_type_user.link, &key_types_list);
|
list_add_tail(&key_type_user.link, &key_types_list);
|
||||||
|
list_add_tail(&key_type_logon.link, &key_types_list);
|
||||||
|
|
||||||
/* record the root user tracking */
|
/* record the root user tracking */
|
||||||
rb_link_node(&root_key_user.node,
|
rb_link_node(&root_key_user.node,
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
|
static int logon_vet_description(const char *desc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* user defined keys take an arbitrary string as the description and an
|
* user defined keys take an arbitrary string as the description and an
|
||||||
* arbitrary blob of data as the payload
|
* arbitrary blob of data as the payload
|
||||||
|
@ -35,6 +37,24 @@ struct key_type key_type_user = {
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(key_type_user);
|
EXPORT_SYMBOL_GPL(key_type_user);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This key type is essentially the same as key_type_user, but it does
|
||||||
|
* not define a .read op. This is suitable for storing username and
|
||||||
|
* password pairs in the keyring that you do not want to be readable
|
||||||
|
* from userspace.
|
||||||
|
*/
|
||||||
|
struct key_type key_type_logon = {
|
||||||
|
.name = "logon",
|
||||||
|
.instantiate = user_instantiate,
|
||||||
|
.update = user_update,
|
||||||
|
.match = user_match,
|
||||||
|
.revoke = user_revoke,
|
||||||
|
.destroy = user_destroy,
|
||||||
|
.describe = user_describe,
|
||||||
|
.vet_description = logon_vet_description,
|
||||||
|
};
|
||||||
|
EXPORT_SYMBOL_GPL(key_type_logon);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* instantiate a user defined key
|
* instantiate a user defined key
|
||||||
*/
|
*/
|
||||||
|
@ -189,3 +209,20 @@ long user_read(const struct key *key, char __user *buffer, size_t buflen)
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(user_read);
|
EXPORT_SYMBOL_GPL(user_read);
|
||||||
|
|
||||||
|
/* Vet the description for a "logon" key */
|
||||||
|
static int logon_vet_description(const char *desc)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
/* require a "qualified" description string */
|
||||||
|
p = strchr(desc, ':');
|
||||||
|
if (!p)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* also reject description with ':' as first char */
|
||||||
|
if (p == desc)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue