Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: (32 commits) [CIFS] Fix to problem with getattr caused by invalidate simplification patch [CIFS] Remove sparse warning [CIFS] Update cifs to version 1.72 cifs: Change key name to cifs.idmap, misc. clean-up cifs: Unconditionally copy mount options to superblock info cifs: Use kstrndup for cifs_sb->mountdata cifs: Simplify handling of submount options in cifs_mount. cifs: cifs_parse_mount_options: do not tokenize mount options in-place cifs: Add support for mounting Windows 2008 DFS shares cifs: Extract DFS referral expansion logic to separate function cifs: turn BCC into a static inlined function cifs: keep BCC in little-endian format cifs: fix some unused variable warnings in id_rb_search CIFS: Simplify invalidate part (try #5) CIFS: directio read/write cleanups consistently use smb_buf_length as be32 for cifs (try 3) cifs: Invoke id mapping functions (try #17 repost) cifs: Add idmap key and related data structures and functions (try #17 repost) CIFS: Add launder_page operation (try #3) Introduce smb2 mounts as vers=2 ...
This commit is contained in:
commit
91444f47b2
|
@ -7,6 +7,7 @@ config CIFS
|
|||
select CRYPTO_MD5
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_ARC4
|
||||
select CRYPTO_DES
|
||||
help
|
||||
This is the client VFS module for the Common Internet File System
|
||||
(CIFS) protocol which is the successor to the Server Message Block
|
||||
|
@ -152,16 +153,28 @@ config CIFS_ACL
|
|||
Allows to fetch CIFS/NTFS ACL from the server. The DACL blob
|
||||
is handed over to the application/caller.
|
||||
|
||||
config CIFS_EXPERIMENTAL
|
||||
bool "CIFS Experimental Features (EXPERIMENTAL)"
|
||||
config CIFS_SMB2
|
||||
bool "SMB2 network file system support (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && INET && BROKEN
|
||||
select NLS
|
||||
select KEYS
|
||||
select FSCACHE
|
||||
select DNS_RESOLVER
|
||||
|
||||
help
|
||||
This enables experimental support for the SMB2 (Server Message Block
|
||||
version 2) protocol. The SMB2 protocol is the successor to the
|
||||
popular CIFS and SMB network file sharing protocols. SMB2 is the
|
||||
native file sharing mechanism for recent versions of Windows
|
||||
operating systems (since Vista). SMB2 enablement will eventually
|
||||
allow users better performance, security and features, than would be
|
||||
possible with cifs. Note that smb2 mount options also are simpler
|
||||
(compared to cifs) due to protocol improvements.
|
||||
|
||||
Unless you are a developer or tester, say N.
|
||||
|
||||
config CIFS_NFSD_EXPORT
|
||||
bool "Allow nfsd to export CIFS file system (EXPERIMENTAL)"
|
||||
depends on CIFS && EXPERIMENTAL
|
||||
help
|
||||
Enables cifs features under testing. These features are
|
||||
experimental and currently include DFS support and directory
|
||||
change notification ie fcntl(F_DNOTIFY), as well as the upcall
|
||||
mechanism which will be used for Kerberos session negotiation
|
||||
and uid remapping. Some of these features also may depend on
|
||||
setting a value of 1 to the pseudo-file /proc/fs/cifs/Experimental
|
||||
(which is disabled by default). See the file fs/cifs/README
|
||||
for more details. If unsure, say N.
|
||||
|
||||
Allows NFS server to export a CIFS mounted share (nfsd over cifs)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
obj-$(CONFIG_CIFS) += cifs.o
|
||||
|
||||
cifs-y := 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 \
|
||||
link.o misc.o netmisc.o smbencrypt.o transport.o asn1.o \
|
||||
cifs_unicode.o nterr.o xattr.o cifsencrypt.o \
|
||||
readdir.o ioctl.o sess.o export.o
|
||||
|
||||
|
|
|
@ -704,18 +704,6 @@ the start of smb requests and responses can be enabled via:
|
|||
|
||||
echo 1 > /proc/fs/cifs/traceSMB
|
||||
|
||||
Two other experimental features are under development. To test these
|
||||
requires enabling CONFIG_CIFS_EXPERIMENTAL
|
||||
|
||||
cifsacl support needed to retrieve approximated mode bits based on
|
||||
the contents on the CIFS ACL.
|
||||
|
||||
lease support: cifs will check the oplock state before calling into
|
||||
the vfs to see if we can grant a lease on a file.
|
||||
|
||||
DNOTIFY fcntl: needed for support of directory change
|
||||
notification and perhaps later for file leases)
|
||||
|
||||
Per share (per client mount) statistics are available in /proc/fs/cifs/Stats
|
||||
if the kernel was configured with cifs statistics enabled. The statistics
|
||||
represent the number of successful (ie non-zero return code from the server)
|
||||
|
|
|
@ -63,7 +63,7 @@ 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));
|
||||
cERROR(1, "smb buf %p len %d", smb, smbCalcSize(smb));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -58,9 +58,7 @@ struct cifs_sb_info {
|
|||
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
|
||||
char *mountdata; /* options received at mount time or via DFS refs */
|
||||
struct backing_dev_info bdi;
|
||||
struct delayed_work prune_tlinks;
|
||||
};
|
||||
|
|
|
@ -82,6 +82,9 @@ int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *);
|
|||
char *cifs_strndup_from_ucs(const char *src, const int maxlen,
|
||||
const bool is_unicode,
|
||||
const struct nls_table *codepage);
|
||||
extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
|
||||
const struct nls_table *cp, int mapChars);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
@ -23,24 +23,16 @@
|
|||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/keyctl.h>
|
||||
#include <linux/key-type.h>
|
||||
#include <keys/user-type.h>
|
||||
#include "cifspdu.h"
|
||||
#include "cifsglob.h"
|
||||
#include "cifsacl.h"
|
||||
#include "cifsproto.h"
|
||||
#include "cifs_debug.h"
|
||||
|
||||
|
||||
static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
|
||||
{{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"},
|
||||
{{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"},
|
||||
{{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"},
|
||||
{{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(18), 0, 0, 0, 0} }, "sys"},
|
||||
{{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(544), 0, 0, 0} }, "root"},
|
||||
{{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(545), 0, 0, 0} }, "users"},
|
||||
{{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(546), 0, 0, 0} }, "guest"} }
|
||||
;
|
||||
|
||||
|
||||
/* security id for everyone/world system group */
|
||||
static const struct cifs_sid sid_everyone = {
|
||||
1, 1, {0, 0, 0, 0, 0, 1}, {0} };
|
||||
|
@ -50,50 +42,385 @@ static const struct cifs_sid sid_authusers = {
|
|||
/* group users */
|
||||
static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
|
||||
|
||||
const struct cred *root_cred;
|
||||
|
||||
int match_sid(struct cifs_sid *ctsid)
|
||||
static void
|
||||
shrink_idmap_tree(struct rb_root *root, int nr_to_scan, int *nr_rem,
|
||||
int *nr_del)
|
||||
{
|
||||
int i, j;
|
||||
int num_subauth, num_sat, num_saw;
|
||||
struct cifs_sid *cwsid;
|
||||
struct rb_node *node;
|
||||
struct rb_node *tmp;
|
||||
struct cifs_sid_id *psidid;
|
||||
|
||||
if (!ctsid)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < NUM_WK_SIDS; ++i) {
|
||||
cwsid = &(wksidarr[i].cifssid);
|
||||
|
||||
/* compare the revision */
|
||||
if (ctsid->revision != cwsid->revision)
|
||||
continue;
|
||||
|
||||
/* compare all of the six auth values */
|
||||
for (j = 0; j < 6; ++j) {
|
||||
if (ctsid->authority[j] != cwsid->authority[j])
|
||||
break;
|
||||
node = rb_first(root);
|
||||
while (node) {
|
||||
tmp = node;
|
||||
node = rb_next(tmp);
|
||||
psidid = rb_entry(tmp, struct cifs_sid_id, rbnode);
|
||||
if (nr_to_scan == 0 || *nr_del == nr_to_scan)
|
||||
++(*nr_rem);
|
||||
else {
|
||||
if (time_after(jiffies, psidid->time + SID_MAP_EXPIRE)
|
||||
&& psidid->refcount == 0) {
|
||||
rb_erase(tmp, root);
|
||||
++(*nr_del);
|
||||
} else
|
||||
++(*nr_rem);
|
||||
}
|
||||
if (j < 6)
|
||||
continue; /* all of the auth values did not match */
|
||||
}
|
||||
}
|
||||
|
||||
/* compare all of the subauth values if any */
|
||||
num_sat = ctsid->num_subauth;
|
||||
num_saw = cwsid->num_subauth;
|
||||
num_subauth = num_sat < num_saw ? num_sat : num_saw;
|
||||
if (num_subauth) {
|
||||
for (j = 0; j < num_subauth; ++j) {
|
||||
if (ctsid->sub_auth[j] != cwsid->sub_auth[j])
|
||||
break;
|
||||
}
|
||||
if (j < num_subauth)
|
||||
continue; /* all sub_auth values do not match */
|
||||
/*
|
||||
* Run idmap cache shrinker.
|
||||
*/
|
||||
static int
|
||||
cifs_idmap_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
|
||||
{
|
||||
int nr_del = 0;
|
||||
int nr_rem = 0;
|
||||
struct rb_root *root;
|
||||
|
||||
root = &uidtree;
|
||||
spin_lock(&siduidlock);
|
||||
shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
|
||||
spin_unlock(&siduidlock);
|
||||
|
||||
root = &gidtree;
|
||||
spin_lock(&sidgidlock);
|
||||
shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
|
||||
spin_unlock(&sidgidlock);
|
||||
|
||||
return nr_rem;
|
||||
}
|
||||
|
||||
static struct shrinker cifs_shrinker = {
|
||||
.shrink = cifs_idmap_shrinker,
|
||||
.seeks = DEFAULT_SEEKS,
|
||||
};
|
||||
|
||||
static int
|
||||
cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen)
|
||||
{
|
||||
char *payload;
|
||||
|
||||
payload = kmalloc(datalen, GFP_KERNEL);
|
||||
if (!payload)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(payload, data, datalen);
|
||||
key->payload.data = payload;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
cifs_idmap_key_destroy(struct key *key)
|
||||
{
|
||||
kfree(key->payload.data);
|
||||
}
|
||||
|
||||
struct key_type cifs_idmap_key_type = {
|
||||
.name = "cifs.idmap",
|
||||
.instantiate = cifs_idmap_key_instantiate,
|
||||
.destroy = cifs_idmap_key_destroy,
|
||||
.describe = user_describe,
|
||||
.match = user_match,
|
||||
};
|
||||
|
||||
static void
|
||||
sid_to_str(struct cifs_sid *sidptr, char *sidstr)
|
||||
{
|
||||
int i;
|
||||
unsigned long saval;
|
||||
char *strptr;
|
||||
|
||||
strptr = sidstr;
|
||||
|
||||
sprintf(strptr, "%s", "S");
|
||||
strptr = sidstr + strlen(sidstr);
|
||||
|
||||
sprintf(strptr, "-%d", sidptr->revision);
|
||||
strptr = sidstr + strlen(sidstr);
|
||||
|
||||
for (i = 0; i < 6; ++i) {
|
||||
if (sidptr->authority[i]) {
|
||||
sprintf(strptr, "-%d", sidptr->authority[i]);
|
||||
strptr = sidstr + strlen(sidstr);
|
||||
}
|
||||
|
||||
cFYI(1, "matching sid: %s\n", wksidarr[i].sidname);
|
||||
return 0; /* sids compare/match */
|
||||
}
|
||||
|
||||
cFYI(1, "No matching sid");
|
||||
return -1;
|
||||
for (i = 0; i < sidptr->num_subauth; ++i) {
|
||||
saval = le32_to_cpu(sidptr->sub_auth[i]);
|
||||
sprintf(strptr, "-%ld", saval);
|
||||
strptr = sidstr + strlen(sidstr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr,
|
||||
struct cifs_sid_id **psidid, char *typestr)
|
||||
{
|
||||
int rc;
|
||||
char *strptr;
|
||||
struct rb_node *node = root->rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
struct rb_node **linkto = &(root->rb_node);
|
||||
struct cifs_sid_id *lsidid;
|
||||
|
||||
while (node) {
|
||||
lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
|
||||
parent = node;
|
||||
rc = compare_sids(sidptr, &((lsidid)->sid));
|
||||
if (rc > 0) {
|
||||
linkto = &(node->rb_left);
|
||||
node = node->rb_left;
|
||||
} else if (rc < 0) {
|
||||
linkto = &(node->rb_right);
|
||||
node = node->rb_right;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&(*psidid)->sid, sidptr, sizeof(struct cifs_sid));
|
||||
(*psidid)->time = jiffies - (SID_MAP_RETRY + 1);
|
||||
(*psidid)->refcount = 0;
|
||||
|
||||
sprintf((*psidid)->sidstr, "%s", typestr);
|
||||
strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr);
|
||||
sid_to_str(&(*psidid)->sid, strptr);
|
||||
|
||||
clear_bit(SID_ID_PENDING, &(*psidid)->state);
|
||||
clear_bit(SID_ID_MAPPED, &(*psidid)->state);
|
||||
|
||||
rb_link_node(&(*psidid)->rbnode, parent, linkto);
|
||||
rb_insert_color(&(*psidid)->rbnode, root);
|
||||
}
|
||||
|
||||
static struct cifs_sid_id *
|
||||
id_rb_search(struct rb_root *root, struct cifs_sid *sidptr)
|
||||
{
|
||||
int rc;
|
||||
struct rb_node *node = root->rb_node;
|
||||
struct cifs_sid_id *lsidid;
|
||||
|
||||
while (node) {
|
||||
lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
|
||||
rc = compare_sids(sidptr, &((lsidid)->sid));
|
||||
if (rc > 0) {
|
||||
node = node->rb_left;
|
||||
} else if (rc < 0) {
|
||||
node = node->rb_right;
|
||||
} else /* node found */
|
||||
return lsidid;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
sidid_pending_wait(void *unused)
|
||||
{
|
||||
schedule();
|
||||
return signal_pending(current) ? -ERESTARTSYS : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
|
||||
struct cifs_fattr *fattr, uint sidtype)
|
||||
{
|
||||
int rc;
|
||||
unsigned long cid;
|
||||
struct key *idkey;
|
||||
const struct cred *saved_cred;
|
||||
struct cifs_sid_id *psidid, *npsidid;
|
||||
struct rb_root *cidtree;
|
||||
spinlock_t *cidlock;
|
||||
|
||||
if (sidtype == SIDOWNER) {
|
||||
cid = cifs_sb->mnt_uid; /* default uid, in case upcall fails */
|
||||
cidlock = &siduidlock;
|
||||
cidtree = &uidtree;
|
||||
} else if (sidtype == SIDGROUP) {
|
||||
cid = cifs_sb->mnt_gid; /* default gid, in case upcall fails */
|
||||
cidlock = &sidgidlock;
|
||||
cidtree = &gidtree;
|
||||
} else
|
||||
return -ENOENT;
|
||||
|
||||
spin_lock(cidlock);
|
||||
psidid = id_rb_search(cidtree, psid);
|
||||
|
||||
if (!psidid) { /* node does not exist, allocate one & attempt adding */
|
||||
spin_unlock(cidlock);
|
||||
npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
|
||||
if (!npsidid)
|
||||
return -ENOMEM;
|
||||
|
||||
npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL);
|
||||
if (!npsidid->sidstr) {
|
||||
kfree(npsidid);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spin_lock(cidlock);
|
||||
psidid = id_rb_search(cidtree, psid);
|
||||
if (psidid) { /* node happened to get inserted meanwhile */
|
||||
++psidid->refcount;
|
||||
spin_unlock(cidlock);
|
||||
kfree(npsidid->sidstr);
|
||||
kfree(npsidid);
|
||||
} else {
|
||||
psidid = npsidid;
|
||||
id_rb_insert(cidtree, psid, &psidid,
|
||||
sidtype == SIDOWNER ? "os:" : "gs:");
|
||||
++psidid->refcount;
|
||||
spin_unlock(cidlock);
|
||||
}
|
||||
} else {
|
||||
++psidid->refcount;
|
||||
spin_unlock(cidlock);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are here, it is safe to access psidid and its fields
|
||||
* since a reference was taken earlier while holding the spinlock.
|
||||
* A reference on the node is put without holding the spinlock
|
||||
* and it is OK to do so in this case, shrinker will not erase
|
||||
* this node until all references are put and we do not access
|
||||
* any fields of the node after a reference is put .
|
||||
*/
|
||||
if (test_bit(SID_ID_MAPPED, &psidid->state)) {
|
||||
cid = psidid->id;
|
||||
psidid->time = jiffies; /* update ts for accessing */
|
||||
goto sid_to_id_out;
|
||||
}
|
||||
|
||||
if (time_after(psidid->time + SID_MAP_RETRY, jiffies))
|
||||
goto sid_to_id_out;
|
||||
|
||||
if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
|
||||
saved_cred = override_creds(root_cred);
|
||||
idkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
|
||||
if (IS_ERR(idkey))
|
||||
cFYI(1, "%s: Can't map SID to an id", __func__);
|
||||
else {
|
||||
cid = *(unsigned long *)idkey->payload.value;
|
||||
psidid->id = cid;
|
||||
set_bit(SID_ID_MAPPED, &psidid->state);
|
||||
key_put(idkey);
|
||||
kfree(psidid->sidstr);
|
||||
}
|
||||
revert_creds(saved_cred);
|
||||
psidid->time = jiffies; /* update ts for accessing */
|
||||
clear_bit(SID_ID_PENDING, &psidid->state);
|
||||
wake_up_bit(&psidid->state, SID_ID_PENDING);
|
||||
} else {
|
||||
rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
|
||||
sidid_pending_wait, TASK_INTERRUPTIBLE);
|
||||
if (rc) {
|
||||
cFYI(1, "%s: sidid_pending_wait interrupted %d",
|
||||
__func__, rc);
|
||||
--psidid->refcount; /* decremented without spinlock */
|
||||
return rc;
|
||||
}
|
||||
if (test_bit(SID_ID_MAPPED, &psidid->state))
|
||||
cid = psidid->id;
|
||||
}
|
||||
|
||||
sid_to_id_out:
|
||||
--psidid->refcount; /* decremented without spinlock */
|
||||
if (sidtype == SIDOWNER)
|
||||
fattr->cf_uid = cid;
|
||||
else
|
||||
fattr->cf_gid = cid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
init_cifs_idmap(void)
|
||||
{
|
||||
struct cred *cred;
|
||||
struct key *keyring;
|
||||
int ret;
|
||||
|
||||
cFYI(1, "Registering the %s key type\n", cifs_idmap_key_type.name);
|
||||
|
||||
/* create an override credential set with a special thread keyring in
|
||||
* which requests are cached
|
||||
*
|
||||
* this is used to prevent malicious redirections from being installed
|
||||
* with add_key().
|
||||
*/
|
||||
cred = prepare_kernel_cred(NULL);
|
||||
if (!cred)
|
||||
return -ENOMEM;
|
||||
|
||||
keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
|
||||
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
||||
KEY_USR_VIEW | KEY_USR_READ,
|
||||
KEY_ALLOC_NOT_IN_QUOTA);
|
||||
if (IS_ERR(keyring)) {
|
||||
ret = PTR_ERR(keyring);
|
||||
goto failed_put_cred;
|
||||
}
|
||||
|
||||
ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
|
||||
if (ret < 0)
|
||||
goto failed_put_key;
|
||||
|
||||
ret = register_key_type(&cifs_idmap_key_type);
|
||||
if (ret < 0)
|
||||
goto failed_put_key;
|
||||
|
||||
/* instruct request_key() to use this special keyring as a cache for
|
||||
* the results it looks up */
|
||||
cred->thread_keyring = keyring;
|
||||
cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
|
||||
root_cred = cred;
|
||||
|
||||
spin_lock_init(&siduidlock);
|
||||
uidtree = RB_ROOT;
|
||||
spin_lock_init(&sidgidlock);
|
||||
gidtree = RB_ROOT;
|
||||
|
||||
register_shrinker(&cifs_shrinker);
|
||||
|
||||
cFYI(1, "cifs idmap keyring: %d\n", key_serial(keyring));
|
||||
return 0;
|
||||
|
||||
failed_put_key:
|
||||
key_put(keyring);
|
||||
failed_put_cred:
|
||||
put_cred(cred);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
exit_cifs_idmap(void)
|
||||
{
|
||||
key_revoke(root_cred->thread_keyring);
|
||||
unregister_key_type(&cifs_idmap_key_type);
|
||||
put_cred(root_cred);
|
||||
unregister_shrinker(&cifs_shrinker);
|
||||
cFYI(1, "Unregistered %s key type\n", cifs_idmap_key_type.name);
|
||||
}
|
||||
|
||||
void
|
||||
cifs_destroy_idmaptrees(void)
|
||||
{
|
||||
struct rb_root *root;
|
||||
struct rb_node *node;
|
||||
|
||||
root = &uidtree;
|
||||
spin_lock(&siduidlock);
|
||||
while ((node = rb_first(root)))
|
||||
rb_erase(node, root);
|
||||
spin_unlock(&siduidlock);
|
||||
|
||||
root = &gidtree;
|
||||
spin_lock(&sidgidlock);
|
||||
while ((node = rb_first(root)))
|
||||
rb_erase(node, root);
|
||||
spin_unlock(&sidgidlock);
|
||||
}
|
||||
|
||||
/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
|
||||
|
@ -104,16 +431,24 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
|
|||
int num_subauth, num_sat, num_saw;
|
||||
|
||||
if ((!ctsid) || (!cwsid))
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
/* compare the revision */
|
||||
if (ctsid->revision != cwsid->revision)
|
||||
return 0;
|
||||
if (ctsid->revision != cwsid->revision) {
|
||||
if (ctsid->revision > cwsid->revision)
|
||||
return 1;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* compare all of the six auth values */
|
||||
for (i = 0; i < 6; ++i) {
|
||||
if (ctsid->authority[i] != cwsid->authority[i])
|
||||
return 0;
|
||||
if (ctsid->authority[i] != cwsid->authority[i]) {
|
||||
if (ctsid->authority[i] > cwsid->authority[i])
|
||||
return 1;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* compare all of the subauth values if any */
|
||||
|
@ -122,12 +457,16 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
|
|||
num_subauth = num_sat < num_saw ? num_sat : num_saw;
|
||||
if (num_subauth) {
|
||||
for (i = 0; i < num_subauth; ++i) {
|
||||
if (ctsid->sub_auth[i] != cwsid->sub_auth[i])
|
||||
return 0;
|
||||
if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
|
||||
if (ctsid->sub_auth[i] > cwsid->sub_auth[i])
|
||||
return 1;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1; /* sids compare/match */
|
||||
return 0; /* sids compare/match */
|
||||
}
|
||||
|
||||
|
||||
|
@ -382,22 +721,22 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
|||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
dump_ace(ppace[i], end_of_acl);
|
||||
#endif
|
||||
if (compare_sids(&(ppace[i]->sid), pownersid))
|
||||
if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
|
||||
access_flags_to_mode(ppace[i]->access_req,
|
||||
ppace[i]->type,
|
||||
&fattr->cf_mode,
|
||||
&user_mask);
|
||||
if (compare_sids(&(ppace[i]->sid), pgrpsid))
|
||||
if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
|
||||
access_flags_to_mode(ppace[i]->access_req,
|
||||
ppace[i]->type,
|
||||
&fattr->cf_mode,
|
||||
&group_mask);
|
||||
if (compare_sids(&(ppace[i]->sid), &sid_everyone))
|
||||
if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
|
||||
access_flags_to_mode(ppace[i]->access_req,
|
||||
ppace[i]->type,
|
||||
&fattr->cf_mode,
|
||||
&other_mask);
|
||||
if (compare_sids(&(ppace[i]->sid), &sid_authusers))
|
||||
if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
|
||||
access_flags_to_mode(ppace[i]->access_req,
|
||||
ppace[i]->type,
|
||||
&fattr->cf_mode,
|
||||
|
@ -475,10 +814,10 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
|
|||
|
||||
|
||||
/* Convert CIFS ACL to POSIX form */
|
||||
static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
|
||||
struct cifs_fattr *fattr)
|
||||
static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
|
||||
struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
|
||||
{
|
||||
int rc;
|
||||
int rc = 0;
|
||||
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
|
||||
struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
|
||||
char *end_of_acl = ((char *)pntsd) + acl_len;
|
||||
|
@ -500,12 +839,26 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
|
|||
le32_to_cpu(pntsd->sacloffset), dacloffset);
|
||||
/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
|
||||
rc = parse_sid(owner_sid_ptr, end_of_acl);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
|
||||
if (rc) {
|
||||
cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = parse_sid(group_sid_ptr, end_of_acl);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
|
||||
if (rc) {
|
||||
cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (dacloffset)
|
||||
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
|
||||
|
@ -520,7 +873,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
|
|||
memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
|
||||
sizeof(struct cifs_sid)); */
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
@ -688,7 +1041,7 @@ out:
|
|||
}
|
||||
|
||||
/* Set an ACL on the server */
|
||||
static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
||||
int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
||||
struct inode *inode, const char *path)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
|
@ -727,7 +1080,7 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
|||
rc = PTR_ERR(pntsd);
|
||||
cERROR(1, "%s: error %d getting sec desc", __func__, rc);
|
||||
} else {
|
||||
rc = parse_sec_desc(pntsd, acllen, fattr);
|
||||
rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
|
||||
kfree(pntsd);
|
||||
if (rc)
|
||||
cERROR(1, "parse sec desc failed rc = %d", rc);
|
||||
|
|
|
@ -39,6 +39,15 @@
|
|||
#define ACCESS_ALLOWED 0
|
||||
#define ACCESS_DENIED 1
|
||||
|
||||
#define SIDOWNER 1
|
||||
#define SIDGROUP 2
|
||||
#define SIDLEN 150 /* S- 1 revision- 6 authorities- max 5 sub authorities */
|
||||
|
||||
#define SID_ID_MAPPED 0
|
||||
#define SID_ID_PENDING 1
|
||||
#define SID_MAP_EXPIRE (3600 * HZ) /* map entry expires after one hour */
|
||||
#define SID_MAP_RETRY (300 * HZ) /* wait 5 minutes for next attempt to map */
|
||||
|
||||
struct cifs_ntsd {
|
||||
__le16 revision; /* revision level */
|
||||
__le16 type;
|
||||
|
@ -74,7 +83,21 @@ struct cifs_wksid {
|
|||
char sidname[SIDNAMELENGTH];
|
||||
} __attribute__((packed));
|
||||
|
||||
extern int match_sid(struct cifs_sid *);
|
||||
struct cifs_sid_id {
|
||||
unsigned int refcount; /* increment with spinlock, decrement without */
|
||||
unsigned long id;
|
||||
unsigned long time;
|
||||
unsigned long state;
|
||||
char *sidstr;
|
||||
struct rb_node rbnode;
|
||||
struct cifs_sid sid;
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
extern struct key_type cifs_idmap_key_type;
|
||||
extern const struct cred *root_cred;
|
||||
#endif /* KERNEL */
|
||||
|
||||
extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *);
|
||||
|
||||
#endif /* _CIFSACL_H */
|
||||
|
|
|
@ -60,7 +60,7 @@ static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
|
|||
server->session_key.response, server->session_key.len);
|
||||
|
||||
crypto_shash_update(&server->secmech.sdescmd5->shash,
|
||||
cifs_pdu->Protocol, cifs_pdu->smb_buf_length);
|
||||
cifs_pdu->Protocol, be32_to_cpu(cifs_pdu->smb_buf_length));
|
||||
|
||||
rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature);
|
||||
|
||||
|
@ -268,10 +268,11 @@ int setup_ntlm_response(struct cifsSesInfo *ses)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
|
||||
int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
|
||||
char *lnm_session_key)
|
||||
{
|
||||
int i;
|
||||
int rc;
|
||||
char password_with_pad[CIFS_ENCPWD_SIZE];
|
||||
|
||||
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
|
||||
|
@ -282,7 +283,7 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
|
|||
memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE);
|
||||
memcpy(lnm_session_key, password_with_pad,
|
||||
CIFS_ENCPWD_SIZE);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* calculate old style session key */
|
||||
|
@ -299,10 +300,9 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
|
|||
for (i = 0; i < CIFS_ENCPWD_SIZE; i++)
|
||||
password_with_pad[i] = toupper(password_with_pad[i]);
|
||||
|
||||
SMBencrypt(password_with_pad, cryptkey, lnm_session_key);
|
||||
rc = SMBencrypt(password_with_pad, cryptkey, lnm_session_key);
|
||||
|
||||
/* clear password before we return/free memory */
|
||||
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
|
||||
return rc;
|
||||
}
|
||||
#endif /* CIFS_WEAK_PW_HASH */
|
||||
|
||||
|
|
115
fs/cifs/cifsfs.c
115
fs/cifs/cifsfs.c
|
@ -128,29 +128,22 @@ cifs_read_super(struct super_block *sb, void *data,
|
|||
}
|
||||
cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages;
|
||||
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
/* copy mount params to sb for use in submounts */
|
||||
/* BB: should we move this after the mount so we
|
||||
* do not have to do the copy on failed mounts?
|
||||
* BB: May be it is better to do simple copy before
|
||||
* complex operation (mount), and in case of fail
|
||||
* just exit instead of doing mount and attempting
|
||||
* undo it if this copy fails?*/
|
||||
/*
|
||||
* Copy mount params to sb for use in submounts. Better to do
|
||||
* the copy here and deal with the error before cleanup gets
|
||||
* complicated post-mount.
|
||||
*/
|
||||
if (data) {
|
||||
int len = strlen(data);
|
||||
cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL);
|
||||
cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL);
|
||||
if (cifs_sb->mountdata == NULL) {
|
||||
bdi_destroy(&cifs_sb->bdi);
|
||||
kfree(sb->s_fs_info);
|
||||
sb->s_fs_info = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
strncpy(cifs_sb->mountdata, data, len + 1);
|
||||
cifs_sb->mountdata[len] = '\0';
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = cifs_mount(sb, cifs_sb, data, devname);
|
||||
rc = cifs_mount(sb, cifs_sb, devname);
|
||||
|
||||
if (rc) {
|
||||
if (!silent)
|
||||
|
@ -163,7 +156,7 @@ cifs_read_super(struct super_block *sb, void *data,
|
|||
sb->s_bdi = &cifs_sb->bdi;
|
||||
sb->s_blocksize = CIFS_MAX_MSGSIZE;
|
||||
sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */
|
||||
inode = cifs_root_iget(sb, ROOT_I);
|
||||
inode = cifs_root_iget(sb);
|
||||
|
||||
if (IS_ERR(inode)) {
|
||||
rc = PTR_ERR(inode);
|
||||
|
@ -184,12 +177,12 @@ cifs_read_super(struct super_block *sb, void *data,
|
|||
else
|
||||
sb->s_d_op = &cifs_dentry_ops;
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
#ifdef CIFS_NFSD_EXPORT
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
|
||||
cFYI(1, "export ops supported");
|
||||
sb->s_export_op = &cifs_export_ops;
|
||||
}
|
||||
#endif /* EXPERIMENTAL */
|
||||
#endif /* CIFS_NFSD_EXPORT */
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -202,12 +195,10 @@ out_no_root:
|
|||
|
||||
out_mount_failed:
|
||||
if (cifs_sb) {
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
if (cifs_sb->mountdata) {
|
||||
kfree(cifs_sb->mountdata);
|
||||
cifs_sb->mountdata = NULL;
|
||||
}
|
||||
#endif
|
||||
unload_nls(cifs_sb->local_nls);
|
||||
bdi_destroy(&cifs_sb->bdi);
|
||||
kfree(cifs_sb);
|
||||
|
@ -231,12 +222,10 @@ cifs_put_super(struct super_block *sb)
|
|||
rc = cifs_umount(sb, cifs_sb);
|
||||
if (rc)
|
||||
cERROR(1, "cifs_umount failed with return code %d", rc);
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
if (cifs_sb->mountdata) {
|
||||
kfree(cifs_sb->mountdata);
|
||||
cifs_sb->mountdata = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
unload_nls(cifs_sb->local_nls);
|
||||
bdi_destroy(&cifs_sb->bdi);
|
||||
|
@ -618,16 +607,31 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
|
|||
{
|
||||
/* origin == SEEK_END => we must revalidate the cached file length */
|
||||
if (origin == SEEK_END) {
|
||||
int retval;
|
||||
int rc;
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
|
||||
/* some applications poll for the file length in this strange
|
||||
way so we must seek to end on non-oplocked files by
|
||||
setting the revalidate time to zero */
|
||||
CIFS_I(file->f_path.dentry->d_inode)->time = 0;
|
||||
/*
|
||||
* We need to be sure that all dirty pages are written and the
|
||||
* server has the newest file length.
|
||||
*/
|
||||
if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping &&
|
||||
inode->i_mapping->nrpages != 0) {
|
||||
rc = filemap_fdatawait(inode->i_mapping);
|
||||
if (rc) {
|
||||
mapping_set_error(inode->i_mapping, rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Some applications poll for the file length in this strange
|
||||
* way so we must seek to end on non-oplocked files by
|
||||
* setting the revalidate time to zero.
|
||||
*/
|
||||
CIFS_I(inode)->time = 0;
|
||||
|
||||
retval = cifs_revalidate_file(file);
|
||||
if (retval < 0)
|
||||
return (loff_t)retval;
|
||||
rc = cifs_revalidate_file_attr(file);
|
||||
if (rc < 0)
|
||||
return (loff_t)rc;
|
||||
}
|
||||
return generic_file_llseek_unlocked(file, offset, origin);
|
||||
}
|
||||
|
@ -760,10 +764,11 @@ const struct file_operations cifs_file_strict_ops = {
|
|||
};
|
||||
|
||||
const struct file_operations cifs_file_direct_ops = {
|
||||
/* no aio, no readv -
|
||||
BB reevaluate whether they can be done with directio, no cache */
|
||||
.read = cifs_user_read,
|
||||
.write = cifs_user_write,
|
||||
/* BB reevaluate whether they can be done with directio, no cache */
|
||||
.read = do_sync_read,
|
||||
.write = do_sync_write,
|
||||
.aio_read = cifs_user_readv,
|
||||
.aio_write = cifs_user_writev,
|
||||
.open = cifs_open,
|
||||
.release = cifs_close,
|
||||
.lock = cifs_lock,
|
||||
|
@ -815,10 +820,11 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
|
|||
};
|
||||
|
||||
const struct file_operations cifs_file_direct_nobrl_ops = {
|
||||
/* no mmap, no aio, no readv -
|
||||
BB reevaluate whether they can be done with directio, no cache */
|
||||
.read = cifs_user_read,
|
||||
.write = cifs_user_write,
|
||||
/* BB reevaluate whether they can be done with directio, no cache */
|
||||
.read = do_sync_read,
|
||||
.write = do_sync_write,
|
||||
.aio_read = cifs_user_readv,
|
||||
.aio_write = cifs_user_writev,
|
||||
.open = cifs_open,
|
||||
.release = cifs_close,
|
||||
.fsync = cifs_fsync,
|
||||
|
@ -981,10 +987,10 @@ init_cifs(void)
|
|||
int rc = 0;
|
||||
cifs_proc_init();
|
||||
INIT_LIST_HEAD(&cifs_tcp_ses_list);
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */
|
||||
INIT_LIST_HEAD(&GlobalDnotifyReqList);
|
||||
INIT_LIST_HEAD(&GlobalDnotifyRsp_Q);
|
||||
#endif
|
||||
#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */
|
||||
/*
|
||||
* Initialize Global counters
|
||||
*/
|
||||
|
@ -1033,22 +1039,33 @@ init_cifs(void)
|
|||
if (rc)
|
||||
goto out_destroy_mids;
|
||||
|
||||
rc = register_filesystem(&cifs_fs_type);
|
||||
if (rc)
|
||||
goto out_destroy_request_bufs;
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
rc = register_key_type(&cifs_spnego_key_type);
|
||||
if (rc)
|
||||
goto out_unregister_filesystem;
|
||||
#endif
|
||||
goto out_destroy_request_bufs;
|
||||
#endif /* CONFIG_CIFS_UPCALL */
|
||||
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
rc = init_cifs_idmap();
|
||||
if (rc)
|
||||
goto out_register_key_type;
|
||||
#endif /* CONFIG_CIFS_ACL */
|
||||
|
||||
rc = register_filesystem(&cifs_fs_type);
|
||||
if (rc)
|
||||
goto out_init_cifs_idmap;
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
out_unregister_filesystem:
|
||||
unregister_filesystem(&cifs_fs_type);
|
||||
out_init_cifs_idmap:
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
exit_cifs_idmap();
|
||||
out_register_key_type:
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
unregister_key_type(&cifs_spnego_key_type);
|
||||
out_destroy_request_bufs:
|
||||
#endif
|
||||
cifs_destroy_request_bufs();
|
||||
out_destroy_mids:
|
||||
cifs_destroy_mids();
|
||||
|
@ -1070,6 +1087,10 @@ exit_cifs(void)
|
|||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
cifs_dfs_release_automount_timer();
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
cifs_destroy_idmaptrees();
|
||||
exit_cifs_idmap();
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
unregister_key_type(&cifs_spnego_key_type);
|
||||
#endif
|
||||
|
|
|
@ -47,7 +47,7 @@ extern void cifs_sb_deactive(struct super_block *sb);
|
|||
|
||||
/* Functions related to inodes */
|
||||
extern const struct inode_operations cifs_dir_inode_ops;
|
||||
extern struct inode *cifs_root_iget(struct super_block *, unsigned long);
|
||||
extern struct inode *cifs_root_iget(struct super_block *);
|
||||
extern int cifs_create(struct inode *, struct dentry *, int,
|
||||
struct nameidata *);
|
||||
extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
|
||||
|
@ -59,9 +59,11 @@ extern int cifs_mkdir(struct inode *, struct dentry *, int);
|
|||
extern int cifs_rmdir(struct inode *, struct dentry *);
|
||||
extern int cifs_rename(struct inode *, struct dentry *, struct inode *,
|
||||
struct dentry *);
|
||||
extern int cifs_revalidate_file_attr(struct file *filp);
|
||||
extern int cifs_revalidate_dentry_attr(struct dentry *);
|
||||
extern int cifs_revalidate_file(struct file *filp);
|
||||
extern int cifs_revalidate_dentry(struct dentry *);
|
||||
extern void cifs_invalidate_mapping(struct inode *inode);
|
||||
extern int cifs_invalidate_mapping(struct inode *inode);
|
||||
extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
|
||||
extern int cifs_setattr(struct dentry *, struct iattr *);
|
||||
|
||||
|
@ -80,12 +82,12 @@ extern const struct file_operations cifs_file_strict_nobrl_ops;
|
|||
extern int cifs_open(struct inode *inode, struct file *file);
|
||||
extern int cifs_close(struct inode *inode, struct file *file);
|
||||
extern int cifs_closedir(struct inode *inode, struct file *file);
|
||||
extern ssize_t cifs_user_read(struct file *file, char __user *read_data,
|
||||
size_t read_size, loff_t *poffset);
|
||||
extern ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t pos);
|
||||
extern ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t pos);
|
||||
extern ssize_t cifs_user_write(struct file *file, const char __user *write_data,
|
||||
size_t write_size, loff_t *poffset);
|
||||
extern ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t pos);
|
||||
extern ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t pos);
|
||||
extern int cifs_lock(struct file *, int, struct file_lock *);
|
||||
|
@ -123,9 +125,9 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
|
|||
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
|
||||
extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
#ifdef CIFS_NFSD_EXPORT
|
||||
extern const struct export_operations cifs_export_ops;
|
||||
#endif /* EXPERIMENTAL */
|
||||
#endif /* CIFS_NFSD_EXPORT */
|
||||
|
||||
#define CIFS_VERSION "1.71"
|
||||
#define CIFS_VERSION "1.72"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
|
|
@ -274,7 +274,8 @@ struct cifsSesInfo {
|
|||
int capabilities;
|
||||
char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for
|
||||
TCP names - will ipv6 and sctp addresses fit? */
|
||||
char *user_name;
|
||||
char *user_name; /* must not be null except during init of sess
|
||||
and after mount option parsing we fill it */
|
||||
char *domainName;
|
||||
char *password;
|
||||
struct session_key auth_key;
|
||||
|
@ -780,10 +781,12 @@ GLOBAL_EXTERN spinlock_t cifs_tcp_ses_lock;
|
|||
*/
|
||||
GLOBAL_EXTERN spinlock_t cifs_file_list_lock;
|
||||
|
||||
#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */
|
||||
/* Outstanding dir notify requests */
|
||||
GLOBAL_EXTERN struct list_head GlobalDnotifyReqList;
|
||||
/* DirNotify response queue */
|
||||
GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q;
|
||||
#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */
|
||||
|
||||
/*
|
||||
* Global transaction id (XID) information
|
||||
|
@ -830,6 +833,11 @@ GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
|
|||
/* reconnect after this many failed echo attempts */
|
||||
GLOBAL_EXTERN unsigned short echo_retries;
|
||||
|
||||
GLOBAL_EXTERN struct rb_root uidtree;
|
||||
GLOBAL_EXTERN struct rb_root gidtree;
|
||||
GLOBAL_EXTERN spinlock_t siduidlock;
|
||||
GLOBAL_EXTERN spinlock_t sidgidlock;
|
||||
|
||||
void cifs_oplock_break(struct work_struct *work);
|
||||
void cifs_oplock_break_get(struct cifsFileInfo *cfile);
|
||||
void cifs_oplock_break_put(struct cifsFileInfo *cfile);
|
||||
|
|
|
@ -397,9 +397,9 @@
|
|||
#define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */
|
||||
|
||||
struct smb_hdr {
|
||||
__u32 smb_buf_length; /* big endian on wire *//* BB length is only two
|
||||
or three bytes - with one or two byte type preceding it that are
|
||||
zero - we could mask the type byte off just in case BB */
|
||||
__be32 smb_buf_length; /* BB length is only two (rarely three) bytes,
|
||||
with one or two byte "type" preceding it that will be
|
||||
zero - we could mask the type byte off */
|
||||
__u8 Protocol[4];
|
||||
__u8 Command;
|
||||
union {
|
||||
|
@ -428,43 +428,28 @@ struct smb_hdr {
|
|||
__u8 WordCount;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* given a pointer to an smb_hdr retrieve a char pointer to the byte count */
|
||||
#define BCC(smb_var) ((unsigned char *)(smb_var) + sizeof(struct smb_hdr) + \
|
||||
(2 * (smb_var)->WordCount))
|
||||
/* given a pointer to an smb_hdr, retrieve a void pointer to the ByteCount */
|
||||
static inline void *
|
||||
BCC(struct smb_hdr *smb)
|
||||
{
|
||||
return (void *)smb + sizeof(*smb) + 2 * smb->WordCount;
|
||||
}
|
||||
|
||||
/* given a pointer to an smb_hdr retrieve the pointer to the byte area */
|
||||
#define pByteArea(smb_var) (BCC(smb_var) + 2)
|
||||
|
||||
/* get the converted ByteCount for a SMB packet and return it */
|
||||
static inline __u16
|
||||
get_bcc(struct smb_hdr *hdr)
|
||||
{
|
||||
__u16 *bc_ptr = (__u16 *)BCC(hdr);
|
||||
|
||||
return get_unaligned(bc_ptr);
|
||||
}
|
||||
|
||||
/* get the unconverted ByteCount for a SMB packet and return it */
|
||||
static inline __u16
|
||||
get_bcc_le(struct smb_hdr *hdr)
|
||||
get_bcc(struct smb_hdr *hdr)
|
||||
{
|
||||
__le16 *bc_ptr = (__le16 *)BCC(hdr);
|
||||
|
||||
return get_unaligned_le16(bc_ptr);
|
||||
}
|
||||
|
||||
/* set the ByteCount for a SMB packet in host-byte order */
|
||||
static inline void
|
||||
put_bcc(__u16 count, struct smb_hdr *hdr)
|
||||
{
|
||||
__u16 *bc_ptr = (__u16 *)BCC(hdr);
|
||||
|
||||
put_unaligned(count, bc_ptr);
|
||||
}
|
||||
|
||||
/* set the ByteCount for a SMB packet in little-endian */
|
||||
static inline void
|
||||
put_bcc_le(__u16 count, struct smb_hdr *hdr)
|
||||
put_bcc(__u16 count, struct smb_hdr *hdr)
|
||||
{
|
||||
__le16 *bc_ptr = (__le16 *)BCC(hdr);
|
||||
|
||||
|
|
|
@ -53,6 +53,9 @@ do { \
|
|||
cFYI(1, "CIFS VFS: leaving %s (xid = %d) rc = %d", \
|
||||
__func__, curr_xid, (int)rc); \
|
||||
} while (0)
|
||||
extern int init_cifs_idmap(void);
|
||||
extern void exit_cifs_idmap(void);
|
||||
extern void cifs_destroy_idmaptrees(void);
|
||||
extern char *build_path_from_dentry(struct dentry *);
|
||||
extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
|
||||
struct cifsTconInfo *tcon);
|
||||
|
@ -90,7 +93,6 @@ extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
|
|||
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
|
||||
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
|
||||
extern unsigned int smbCalcSize(struct smb_hdr *ptr);
|
||||
extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
|
||||
extern int decode_negTokenInit(unsigned char *security_blob, int length,
|
||||
struct TCP_Server_Info *server);
|
||||
extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
|
||||
|
@ -143,8 +145,10 @@ extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
|
|||
extern int mode_to_cifs_acl(struct inode *inode, const char *path, __u64);
|
||||
extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
|
||||
const char *, u32 *);
|
||||
extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
|
||||
const char *);
|
||||
|
||||
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
|
||||
extern int cifs_mount(struct super_block *, struct cifs_sb_info *,
|
||||
const char *);
|
||||
extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
|
||||
extern void cifs_dfs_release_automount_timer(void);
|
||||
|
@ -304,12 +308,13 @@ extern int CIFSSMBUnixQuerySymLink(const int xid,
|
|||
struct cifsTconInfo *tcon,
|
||||
const unsigned char *searchName, char **syminfo,
|
||||
const struct nls_table *nls_codepage);
|
||||
#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
|
||||
extern int CIFSSMBQueryReparseLinkInfo(const int xid,
|
||||
struct cifsTconInfo *tcon,
|
||||
const unsigned char *searchName,
|
||||
char *symlinkinfo, const int buflen, __u16 fid,
|
||||
const struct nls_table *nls_codepage);
|
||||
|
||||
#endif /* temporarily unused until cifs_symlink fixed */
|
||||
extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
|
||||
const char *fileName, const int disposition,
|
||||
const int access_flags, const int omode,
|
||||
|
@ -348,8 +353,6 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
|
|||
const unsigned char *searchName, __u64 *inode_number,
|
||||
const struct nls_table *nls_codepage,
|
||||
int remap_special_chars);
|
||||
extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
|
||||
const struct nls_table *cp, int mapChars);
|
||||
|
||||
extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
|
||||
const __u16 netfid, const __u64 len,
|
||||
|
@ -383,9 +386,15 @@ extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
|
|||
extern int calc_seckey(struct cifsSesInfo *);
|
||||
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
extern void calc_lanman_hash(const char *password, const char *cryptkey,
|
||||
extern int calc_lanman_hash(const char *password, const char *cryptkey,
|
||||
bool encrypt, char *lnm_session_key);
|
||||
#endif /* CIFS_WEAK_PW_HASH */
|
||||
#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */
|
||||
extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
|
||||
const int notify_subdirs, const __u16 netfid,
|
||||
__u32 filter, struct file *file, int multishot,
|
||||
const struct nls_table *nls_codepage);
|
||||
#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */
|
||||
extern int CIFSSMBCopy(int xid,
|
||||
struct cifsTconInfo *source_tcon,
|
||||
const char *fromName,
|
||||
|
@ -393,10 +402,6 @@ extern int CIFSSMBCopy(int xid,
|
|||
const char *toName, const int flags,
|
||||
const struct nls_table *nls_codepage,
|
||||
int remap_special_chars);
|
||||
extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
|
||||
const int notify_subdirs, const __u16 netfid,
|
||||
__u32 filter, struct file *file, int multishot,
|
||||
const struct nls_table *nls_codepage);
|
||||
extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
|
||||
const unsigned char *searchName,
|
||||
const unsigned char *ea_name, char *EAData,
|
||||
|
@ -427,9 +432,6 @@ extern int CIFSCheckMFSymlink(struct cifs_fattr *fattr,
|
|||
struct cifs_sb_info *cifs_sb, int xid);
|
||||
extern int mdfour(unsigned char *, unsigned char *, int);
|
||||
extern int E_md4hash(const unsigned char *passwd, unsigned char *p16);
|
||||
extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
extern void E_P16(unsigned char *p14, unsigned char *p16);
|
||||
extern void E_P24(unsigned char *p21, const unsigned char *c8,
|
||||
extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
#endif /* _CIFSPROTO_H */
|
||||
|
|
|
@ -339,12 +339,13 @@ static int validate_t2(struct smb_t2_rsp *pSMB)
|
|||
get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
|
||||
goto vt2_err;
|
||||
|
||||
/* check that bcc is at least as big as parms + data */
|
||||
/* check that bcc is less than negotiated smb buffer */
|
||||
total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
|
||||
if (total_size >= 512)
|
||||
goto vt2_err;
|
||||
|
||||
/* check that bcc is at least as big as parms + data, and that it is
|
||||
* less than negotiated smb buffer
|
||||
*/
|
||||
total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
|
||||
if (total_size > get_bcc(&pSMB->hdr) ||
|
||||
total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
|
||||
|
@ -357,6 +358,13 @@ vt2_err:
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void inc_rfc1001_len(void *pSMB, int count)
|
||||
{
|
||||
struct smb_hdr *hdr = (struct smb_hdr *)pSMB;
|
||||
|
||||
be32_add_cpu(&hdr->smb_buf_length, count);
|
||||
}
|
||||
|
||||
int
|
||||
CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
||||
{
|
||||
|
@ -409,7 +417,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||
count += strlen(protocols[i].name) + 1;
|
||||
/* null at end of source and target buffers anyway */
|
||||
}
|
||||
pSMB->hdr.smb_buf_length += count;
|
||||
inc_rfc1001_len(pSMB, count);
|
||||
pSMB->ByteCount = cpu_to_le16(count);
|
||||
|
||||
rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -541,10 +549,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||
server->secType = RawNTLMSSP;
|
||||
else if (secFlags & CIFSSEC_MAY_LANMAN)
|
||||
server->secType = LANMAN;
|
||||
/* #ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
else if (secFlags & CIFSSEC_MAY_PLNTXT)
|
||||
server->secType = ??
|
||||
#endif */
|
||||
else {
|
||||
rc = -EOPNOTSUPP;
|
||||
cERROR(1, "Invalid security type");
|
||||
|
@ -578,7 +582,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||
|
||||
if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
|
||||
(server->capabilities & CAP_EXTENDED_SECURITY)) {
|
||||
count = pSMBr->ByteCount;
|
||||
count = get_bcc(&pSMBr->hdr);
|
||||
if (count < 16) {
|
||||
rc = -EIO;
|
||||
goto neg_err_exit;
|
||||
|
@ -732,9 +736,9 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
|
|||
smb->hdr.Tid = 0xffff;
|
||||
smb->hdr.WordCount = 1;
|
||||
put_unaligned_le16(1, &smb->EchoCount);
|
||||
put_bcc_le(1, &smb->hdr);
|
||||
put_bcc(1, &smb->hdr);
|
||||
smb->Data[0] = 'a';
|
||||
smb->hdr.smb_buf_length += 3;
|
||||
inc_rfc1001_len(smb, 3);
|
||||
|
||||
rc = cifs_call_async(server, (struct smb_hdr *)smb,
|
||||
cifs_echo_callback, server);
|
||||
|
@ -852,7 +856,7 @@ PsxDelete:
|
|||
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
|
@ -898,7 +902,7 @@ DelFileRetry:
|
|||
pSMB->SearchAttributes =
|
||||
cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
|
||||
pSMB->BufferFormat = 0x04;
|
||||
pSMB->hdr.smb_buf_length += name_len + 1;
|
||||
inc_rfc1001_len(pSMB, name_len + 1);
|
||||
pSMB->ByteCount = cpu_to_le16(name_len + 1);
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
|
@ -942,7 +946,7 @@ RmDirRetry:
|
|||
}
|
||||
|
||||
pSMB->BufferFormat = 0x04;
|
||||
pSMB->hdr.smb_buf_length += name_len + 1;
|
||||
inc_rfc1001_len(pSMB, name_len + 1);
|
||||
pSMB->ByteCount = cpu_to_le16(name_len + 1);
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
|
@ -985,7 +989,7 @@ MkDirRetry:
|
|||
}
|
||||
|
||||
pSMB->BufferFormat = 0x04;
|
||||
pSMB->hdr.smb_buf_length += name_len + 1;
|
||||
inc_rfc1001_len(pSMB, name_len + 1);
|
||||
pSMB->ByteCount = cpu_to_le16(name_len + 1);
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
|
@ -1063,7 +1067,7 @@ PsxCreat:
|
|||
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
|
@ -1075,7 +1079,7 @@ PsxCreat:
|
|||
cFYI(1, "copying inode info");
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
|
||||
if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
|
||||
if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
|
||||
rc = -EIO; /* bad smb */
|
||||
goto psx_create_err;
|
||||
}
|
||||
|
@ -1096,7 +1100,7 @@ PsxCreat:
|
|||
pRetData->Type = cpu_to_le32(-1); /* unknown */
|
||||
cFYI(DBG2, "unknown type");
|
||||
} else {
|
||||
if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
|
||||
if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
|
||||
+ sizeof(FILE_UNIX_BASIC_INFO)) {
|
||||
cERROR(1, "Open response data too small");
|
||||
pRetData->Type = cpu_to_le32(-1);
|
||||
|
@ -1228,7 +1232,7 @@ OldOpenRetry:
|
|||
pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
|
||||
pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
|
||||
count += name_len;
|
||||
pSMB->hdr.smb_buf_length += count;
|
||||
inc_rfc1001_len(pSMB, count);
|
||||
|
||||
pSMB->ByteCount = cpu_to_le16(count);
|
||||
/* long_op set to 1 to allow for oplock break timeouts */
|
||||
|
@ -1341,7 +1345,7 @@ openRetry:
|
|||
SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
|
||||
|
||||
count += name_len;
|
||||
pSMB->hdr.smb_buf_length += count;
|
||||
inc_rfc1001_len(pSMB, count);
|
||||
|
||||
pSMB->ByteCount = cpu_to_le16(count);
|
||||
/* long_op set to 1 to allow for oplock break timeouts */
|
||||
|
@ -1426,7 +1430,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
|
|||
}
|
||||
|
||||
iov[0].iov_base = (char *)pSMB;
|
||||
iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
|
||||
iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
|
||||
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
|
||||
&resp_buf_type, CIFS_LOG_ERROR);
|
||||
cifs_stats_inc(&tcon->num_reads);
|
||||
|
@ -1560,7 +1564,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
|
|||
|
||||
pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
|
||||
pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
|
||||
if (wct == 14)
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
@ -1644,11 +1648,12 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
|
|||
|
||||
pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
|
||||
pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
|
||||
smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
|
||||
/* header + 1 byte pad */
|
||||
smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
|
||||
if (wct == 14)
|
||||
pSMB->hdr.smb_buf_length += count+1;
|
||||
inc_rfc1001_len(pSMB, count + 1);
|
||||
else /* wct == 12 */
|
||||
pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
|
||||
inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
|
||||
if (wct == 14)
|
||||
pSMB->ByteCount = cpu_to_le16(count + 1);
|
||||
else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
|
||||
|
@ -1748,7 +1753,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
|
|||
/* oplock break */
|
||||
count = 0;
|
||||
}
|
||||
pSMB->hdr.smb_buf_length += count;
|
||||
inc_rfc1001_len(pSMB, count);
|
||||
pSMB->ByteCount = cpu_to_le16(count);
|
||||
|
||||
if (waitFlag) {
|
||||
|
@ -1839,14 +1844,14 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
|||
pSMB->Fid = smb_file_id;
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
if (waitFlag) {
|
||||
rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned);
|
||||
} else {
|
||||
iov[0].iov_base = (char *)pSMB;
|
||||
iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
|
||||
iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
|
||||
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
|
||||
&resp_buf_type, timeout);
|
||||
pSMB = NULL; /* request buf already freed by SendReceive2. Do
|
||||
|
@ -1862,7 +1867,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
|||
__u16 data_count;
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
|
||||
if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
|
||||
if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
|
||||
rc = -EIO; /* bad smb */
|
||||
goto plk_err_exit;
|
||||
}
|
||||
|
@ -2012,7 +2017,7 @@ renameRetry:
|
|||
}
|
||||
|
||||
count = 1 /* 1st signature byte */ + name_len + name_len2;
|
||||
pSMB->hdr.smb_buf_length += count;
|
||||
inc_rfc1001_len(pSMB, count);
|
||||
pSMB->ByteCount = cpu_to_le16(count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -2092,7 +2097,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
|
|||
pSMB->InformationLevel =
|
||||
cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
|
@ -2159,7 +2164,7 @@ copyRetry:
|
|||
}
|
||||
|
||||
count = 1 /* 1st signature byte */ + name_len + name_len2;
|
||||
pSMB->hdr.smb_buf_length += count;
|
||||
inc_rfc1001_len(pSMB, count);
|
||||
pSMB->ByteCount = cpu_to_le16(count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -2249,7 +2254,7 @@ createSymLinkRetry:
|
|||
pSMB->DataOffset = cpu_to_le16(offset);
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
|
@ -2335,7 +2340,7 @@ createHardLinkRetry:
|
|||
pSMB->DataOffset = cpu_to_le16(offset);
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
|
@ -2406,7 +2411,7 @@ winCreateHardLinkRetry:
|
|||
}
|
||||
|
||||
count = 1 /* string type byte */ + name_len + name_len2;
|
||||
pSMB->hdr.smb_buf_length += count;
|
||||
inc_rfc1001_len(pSMB, count);
|
||||
pSMB->ByteCount = cpu_to_le16(count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -2477,7 +2482,7 @@ querySymLinkRetry:
|
|||
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -2489,7 +2494,7 @@ querySymLinkRetry:
|
|||
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
/* BB also check enough total bytes returned */
|
||||
if (rc || (pSMBr->ByteCount < 2))
|
||||
if (rc || get_bcc(&pSMBr->hdr) < 2)
|
||||
rc = -EIO;
|
||||
else {
|
||||
bool is_unicode;
|
||||
|
@ -2516,7 +2521,17 @@ querySymLinkRetry:
|
|||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
|
||||
/*
|
||||
* Recent Windows versions now create symlinks more frequently
|
||||
* and they use the "reparse point" mechanism below. We can of course
|
||||
* do symlinks nicely to Samba and other servers which support the
|
||||
* CIFS Unix Extensions and we can also do SFU symlinks and "client only"
|
||||
* "MF" symlinks optionally, but for recent Windows we really need to
|
||||
* reenable the code below and fix the cifs_symlink callers to handle this.
|
||||
* In the interim this code has been moved to its own config option so
|
||||
* it is not compiled in by default until callers fixed up and more tested.
|
||||
*/
|
||||
int
|
||||
CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
|
||||
const unsigned char *searchName,
|
||||
|
@ -2561,14 +2576,14 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
|
|||
} else { /* decode response */
|
||||
__u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
|
||||
__u32 data_count = le32_to_cpu(pSMBr->DataCount);
|
||||
if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
|
||||
/* BB also check enough total bytes returned */
|
||||
if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
|
||||
/* BB also check enough total bytes returned */
|
||||
rc = -EIO; /* bad smb */
|
||||
goto qreparse_out;
|
||||
}
|
||||
if (data_count && (data_count < 2048)) {
|
||||
char *end_of_smb = 2 /* sizeof byte count */ +
|
||||
pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
|
||||
get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
|
||||
|
||||
struct reparse_data *reparse_buf =
|
||||
(struct reparse_data *)
|
||||
|
@ -2618,7 +2633,7 @@ qreparse_out:
|
|||
|
||||
return rc;
|
||||
}
|
||||
#endif /* CIFS_EXPERIMENTAL */
|
||||
#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
|
||||
|
||||
#ifdef CONFIG_CIFS_POSIX
|
||||
|
||||
|
@ -2814,7 +2829,7 @@ queryAclRetry:
|
|||
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -2826,8 +2841,8 @@ queryAclRetry:
|
|||
/* decode response */
|
||||
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
if (rc || (pSMBr->ByteCount < 2))
|
||||
/* BB also check enough total bytes returned */
|
||||
if (rc || get_bcc(&pSMBr->hdr) < 2)
|
||||
rc = -EIO; /* bad smb */
|
||||
else {
|
||||
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
||||
|
@ -2908,7 +2923,7 @@ setAclRetry:
|
|||
pSMB->ParameterCount = cpu_to_le16(params);
|
||||
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
|
@ -2966,7 +2981,7 @@ GetExtAttrRetry:
|
|||
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
|
||||
pSMB->Pad = 0;
|
||||
pSMB->Fid = netfid;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->t2.ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -2976,8 +2991,8 @@ GetExtAttrRetry:
|
|||
} else {
|
||||
/* decode response */
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
if (rc || (pSMBr->ByteCount < 2))
|
||||
/* BB also check enough total bytes returned */
|
||||
if (rc || get_bcc(&pSMBr->hdr) < 2)
|
||||
/* If rc should we check for EOPNOSUPP and
|
||||
disable the srvino flag? or in caller? */
|
||||
rc = -EIO; /* bad smb */
|
||||
|
@ -3052,6 +3067,7 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata,
|
|||
char *end_of_smb;
|
||||
__u32 data_count, data_offset, parm_count, parm_offset;
|
||||
struct smb_com_ntransact_rsp *pSMBr;
|
||||
u16 bcc;
|
||||
|
||||
*pdatalen = 0;
|
||||
*pparmlen = 0;
|
||||
|
@ -3061,8 +3077,8 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata,
|
|||
|
||||
pSMBr = (struct smb_com_ntransact_rsp *)buf;
|
||||
|
||||
/* ByteCount was converted from little endian in SendReceive */
|
||||
end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
|
||||
bcc = get_bcc(&pSMBr->hdr);
|
||||
end_of_smb = 2 /* sizeof byte count */ + bcc +
|
||||
(char *)&pSMBr->ByteCount;
|
||||
|
||||
data_offset = le32_to_cpu(pSMBr->DataOffset);
|
||||
|
@ -3088,7 +3104,7 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata,
|
|||
*ppdata, data_count, (data_count + *ppdata),
|
||||
end_of_smb, pSMBr);
|
||||
return -EINVAL;
|
||||
} else if (parm_count + data_count > pSMBr->ByteCount) {
|
||||
} else if (parm_count + data_count > bcc) {
|
||||
cFYI(1, "parm count and data count larger than SMB");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -3124,9 +3140,9 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
|
|||
pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
|
||||
CIFS_ACL_DACL);
|
||||
pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
|
||||
pSMB->hdr.smb_buf_length += 11;
|
||||
inc_rfc1001_len(pSMB, 11);
|
||||
iov[0].iov_base = (char *)pSMB;
|
||||
iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
|
||||
iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
|
||||
|
||||
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
|
||||
0);
|
||||
|
@ -3235,10 +3251,9 @@ setCifsAclRetry:
|
|||
memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
|
||||
(char *) pntsd,
|
||||
acllen);
|
||||
pSMB->hdr.smb_buf_length += (byte_count + data_count);
|
||||
|
||||
inc_rfc1001_len(pSMB, byte_count + data_count);
|
||||
} else
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
|
@ -3289,7 +3304,7 @@ QInfRetry:
|
|||
}
|
||||
pSMB->BufferFormat = 0x04;
|
||||
name_len++; /* account for buffer type byte */
|
||||
pSMB->hdr.smb_buf_length += (__u16) name_len;
|
||||
inc_rfc1001_len(pSMB, (__u16)name_len);
|
||||
pSMB->ByteCount = cpu_to_le16(name_len);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -3364,7 +3379,7 @@ QFileInfoRetry:
|
|||
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
|
||||
pSMB->Pad = 0;
|
||||
pSMB->Fid = netfid;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
|
@ -3375,7 +3390,7 @@ QFileInfoRetry:
|
|||
|
||||
if (rc) /* BB add auto retry on EOPNOTSUPP? */
|
||||
rc = -EIO;
|
||||
else if (pSMBr->ByteCount < 40)
|
||||
else if (get_bcc(&pSMBr->hdr) < 40)
|
||||
rc = -EIO; /* bad smb */
|
||||
else if (pFindData) {
|
||||
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
||||
|
@ -3451,7 +3466,7 @@ QPathInfoRetry:
|
|||
else
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -3463,9 +3478,9 @@ QPathInfoRetry:
|
|||
|
||||
if (rc) /* BB add auto retry on EOPNOTSUPP? */
|
||||
rc = -EIO;
|
||||
else if (!legacy && (pSMBr->ByteCount < 40))
|
||||
else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
|
||||
rc = -EIO; /* bad smb */
|
||||
else if (legacy && (pSMBr->ByteCount < 24))
|
||||
else if (legacy && get_bcc(&pSMBr->hdr) < 24)
|
||||
rc = -EIO; /* 24 or 26 expected but we do not read
|
||||
last field */
|
||||
else if (pFindData) {
|
||||
|
@ -3532,7 +3547,7 @@ UnixQFileInfoRetry:
|
|||
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
|
||||
pSMB->Pad = 0;
|
||||
pSMB->Fid = netfid;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
|
@ -3541,7 +3556,7 @@ UnixQFileInfoRetry:
|
|||
} else { /* decode response */
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
|
||||
if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
|
||||
if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
|
||||
cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
|
||||
"Unix Extensions can be disabled on mount "
|
||||
"by specifying the nosfu mount option.");
|
||||
|
@ -3617,7 +3632,7 @@ UnixQPathInfoRetry:
|
|||
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -3627,7 +3642,7 @@ UnixQPathInfoRetry:
|
|||
} else { /* decode response */
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
|
||||
if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
|
||||
if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
|
||||
cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
|
||||
"Unix Extensions can be disabled on mount "
|
||||
"by specifying the nosfu mount option.");
|
||||
|
@ -3731,7 +3746,7 @@ findFirstRetry:
|
|||
|
||||
/* BB what should we set StorageType to? Does it matter? BB */
|
||||
pSMB->SearchStorageType = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -3860,7 +3875,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
|
|||
byte_count = params + 1 /* pad */ ;
|
||||
pSMB->TotalParameterCount = cpu_to_le16(params);
|
||||
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -4022,7 +4037,7 @@ GetInodeNumberRetry:
|
|||
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -4032,8 +4047,8 @@ GetInodeNumberRetry:
|
|||
} else {
|
||||
/* decode response */
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
if (rc || (pSMBr->ByteCount < 2))
|
||||
/* BB also check enough total bytes returned */
|
||||
if (rc || get_bcc(&pSMBr->hdr) < 2)
|
||||
/* If rc should we check for EOPNOSUPP and
|
||||
disable the srvino flag? or in caller? */
|
||||
rc = -EIO; /* bad smb */
|
||||
|
@ -4246,7 +4261,7 @@ getDFSRetry:
|
|||
pSMB->ParameterCount = cpu_to_le16(params);
|
||||
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
||||
pSMB->MaxReferralLevel = cpu_to_le16(3);
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -4258,13 +4273,13 @@ getDFSRetry:
|
|||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
|
||||
/* BB Also check if enough total bytes returned? */
|
||||
if (rc || (pSMBr->ByteCount < 17)) {
|
||||
if (rc || get_bcc(&pSMBr->hdr) < 17) {
|
||||
rc = -EIO; /* bad smb */
|
||||
goto GetDFSRefExit;
|
||||
}
|
||||
|
||||
cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
|
||||
pSMBr->ByteCount,
|
||||
get_bcc(&pSMBr->hdr),
|
||||
le16_to_cpu(pSMBr->t2.DataOffset));
|
||||
|
||||
/* parse returned result into more usable form */
|
||||
|
@ -4320,7 +4335,7 @@ oldQFSInfoRetry:
|
|||
pSMB->Reserved3 = 0;
|
||||
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -4330,12 +4345,12 @@ oldQFSInfoRetry:
|
|||
} else { /* decode response */
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
|
||||
if (rc || (pSMBr->ByteCount < 18))
|
||||
if (rc || get_bcc(&pSMBr->hdr) < 18)
|
||||
rc = -EIO; /* bad smb */
|
||||
else {
|
||||
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
||||
cFYI(1, "qfsinf resp BCC: %d Offset %d",
|
||||
pSMBr->ByteCount, data_offset);
|
||||
get_bcc(&pSMBr->hdr), data_offset);
|
||||
|
||||
response_data = (FILE_SYSTEM_ALLOC_INFO *)
|
||||
(((char *) &pSMBr->hdr.Protocol) + data_offset);
|
||||
|
@ -4399,7 +4414,7 @@ QFSInfoRetry:
|
|||
pSMB->Reserved3 = 0;
|
||||
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -4409,7 +4424,7 @@ QFSInfoRetry:
|
|||
} else { /* decode response */
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
|
||||
if (rc || (pSMBr->ByteCount < 24))
|
||||
if (rc || get_bcc(&pSMBr->hdr) < 24)
|
||||
rc = -EIO; /* bad smb */
|
||||
else {
|
||||
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
||||
|
@ -4479,7 +4494,7 @@ QFSAttributeRetry:
|
|||
pSMB->Reserved3 = 0;
|
||||
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -4489,7 +4504,7 @@ QFSAttributeRetry:
|
|||
} else { /* decode response */
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
|
||||
if (rc || (pSMBr->ByteCount < 13)) {
|
||||
if (rc || get_bcc(&pSMBr->hdr) < 13) {
|
||||
/* BB also check if enough bytes returned */
|
||||
rc = -EIO; /* bad smb */
|
||||
} else {
|
||||
|
@ -4550,7 +4565,7 @@ QFSDeviceRetry:
|
|||
pSMB->Reserved3 = 0;
|
||||
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -4560,7 +4575,8 @@ QFSDeviceRetry:
|
|||
} else { /* decode response */
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
|
||||
if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
|
||||
if (rc || get_bcc(&pSMBr->hdr) <
|
||||
sizeof(FILE_SYSTEM_DEVICE_INFO))
|
||||
rc = -EIO; /* bad smb */
|
||||
else {
|
||||
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
||||
|
@ -4619,7 +4635,7 @@ QFSUnixRetry:
|
|||
pSMB->Reserved3 = 0;
|
||||
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -4629,7 +4645,7 @@ QFSUnixRetry:
|
|||
} else { /* decode response */
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
|
||||
if (rc || (pSMBr->ByteCount < 13)) {
|
||||
if (rc || get_bcc(&pSMBr->hdr) < 13) {
|
||||
rc = -EIO; /* bad smb */
|
||||
} else {
|
||||
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
||||
|
@ -4702,7 +4718,7 @@ SETFSUnixRetry:
|
|||
pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
|
||||
pSMB->ClientUnixCap = cpu_to_le64(cap);
|
||||
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -4764,7 +4780,7 @@ QFSPosixRetry:
|
|||
pSMB->Reserved3 = 0;
|
||||
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -4774,7 +4790,7 @@ QFSPosixRetry:
|
|||
} else { /* decode response */
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
|
||||
if (rc || (pSMBr->ByteCount < 13)) {
|
||||
if (rc || get_bcc(&pSMBr->hdr) < 13) {
|
||||
rc = -EIO; /* bad smb */
|
||||
} else {
|
||||
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
||||
|
@ -4890,7 +4906,7 @@ SetEOFRetry:
|
|||
pSMB->ParameterCount = cpu_to_le16(params);
|
||||
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
parm_data->FileSize = cpu_to_le64(size);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -4969,7 +4985,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
|
|||
cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
|
||||
}
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
|
||||
if (rc) {
|
||||
|
@ -5037,7 +5053,7 @@ CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
|
|||
else
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
|
||||
rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
|
||||
|
@ -5096,7 +5112,7 @@ CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
|
|||
pSMB->Fid = fid;
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
*data_offset = delete_file ? 1 : 0;
|
||||
rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
|
||||
|
@ -5169,7 +5185,7 @@ SetTimesRetry:
|
|||
else
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -5221,7 +5237,7 @@ SetAttrLgcyRetry:
|
|||
}
|
||||
pSMB->attr = cpu_to_le16(dos_attrs);
|
||||
pSMB->BufferFormat = 0x04;
|
||||
pSMB->hdr.smb_buf_length += name_len + 1;
|
||||
inc_rfc1001_len(pSMB, name_len + 1);
|
||||
pSMB->ByteCount = cpu_to_le16(name_len + 1);
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
|
@ -5326,7 +5342,7 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
|
|||
pSMB->Fid = fid;
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
cifs_fill_unix_set_info(data_offset, args);
|
||||
|
@ -5402,7 +5418,7 @@ setPermsRetry:
|
|||
pSMB->TotalDataCount = pSMB->DataCount;
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
|
||||
cifs_fill_unix_set_info(data_offset, args);
|
||||
|
||||
|
@ -5418,79 +5434,6 @@ setPermsRetry:
|
|||
return rc;
|
||||
}
|
||||
|
||||
int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
|
||||
const int notify_subdirs, const __u16 netfid,
|
||||
__u32 filter, struct file *pfile, int multishot,
|
||||
const struct nls_table *nls_codepage)
|
||||
{
|
||||
int rc = 0;
|
||||
struct smb_com_transaction_change_notify_req *pSMB = NULL;
|
||||
struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
|
||||
struct dir_notify_req *dnotify_req;
|
||||
int bytes_returned;
|
||||
|
||||
cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
|
||||
rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
|
||||
(void **) &pSMBr);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pSMB->TotalParameterCount = 0 ;
|
||||
pSMB->TotalDataCount = 0;
|
||||
pSMB->MaxParameterCount = cpu_to_le32(2);
|
||||
/* BB find exact data count max from sess structure BB */
|
||||
pSMB->MaxDataCount = 0; /* same in little endian or be */
|
||||
/* BB VERIFY verify which is correct for above BB */
|
||||
pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
|
||||
MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
|
||||
|
||||
pSMB->MaxSetupCount = 4;
|
||||
pSMB->Reserved = 0;
|
||||
pSMB->ParameterOffset = 0;
|
||||
pSMB->DataCount = 0;
|
||||
pSMB->DataOffset = 0;
|
||||
pSMB->SetupCount = 4; /* single byte does not need le conversion */
|
||||
pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
|
||||
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
||||
if (notify_subdirs)
|
||||
pSMB->WatchTree = 1; /* one byte - no le conversion needed */
|
||||
pSMB->Reserved2 = 0;
|
||||
pSMB->CompletionFilter = cpu_to_le32(filter);
|
||||
pSMB->Fid = netfid; /* file handle always le */
|
||||
pSMB->ByteCount = 0;
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *)pSMBr, &bytes_returned,
|
||||
CIFS_ASYNC_OP);
|
||||
if (rc) {
|
||||
cFYI(1, "Error in Notify = %d", rc);
|
||||
} else {
|
||||
/* Add file to outstanding requests */
|
||||
/* BB change to kmem cache alloc */
|
||||
dnotify_req = kmalloc(
|
||||
sizeof(struct dir_notify_req),
|
||||
GFP_KERNEL);
|
||||
if (dnotify_req) {
|
||||
dnotify_req->Pid = pSMB->hdr.Pid;
|
||||
dnotify_req->PidHigh = pSMB->hdr.PidHigh;
|
||||
dnotify_req->Mid = pSMB->hdr.Mid;
|
||||
dnotify_req->Tid = pSMB->hdr.Tid;
|
||||
dnotify_req->Uid = pSMB->hdr.Uid;
|
||||
dnotify_req->netfid = netfid;
|
||||
dnotify_req->pfile = pfile;
|
||||
dnotify_req->filter = filter;
|
||||
dnotify_req->multishot = multishot;
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
list_add_tail(&dnotify_req->lhead,
|
||||
&GlobalDnotifyReqList);
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
} else
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
cifs_buf_release(pSMB);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_XATTR
|
||||
/*
|
||||
* Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
|
||||
|
@ -5560,7 +5503,7 @@ QAllEAsRetry:
|
|||
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -5576,7 +5519,7 @@ QAllEAsRetry:
|
|||
of these trans2 responses */
|
||||
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
if (rc || (pSMBr->ByteCount < 4)) {
|
||||
if (rc || get_bcc(&pSMBr->hdr) < 4) {
|
||||
rc = -EIO; /* bad smb */
|
||||
goto QAllEAsOut;
|
||||
}
|
||||
|
@ -5773,7 +5716,7 @@ SetEARetry:
|
|||
pSMB->ParameterCount = cpu_to_le16(params);
|
||||
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
inc_rfc1001_len(pSMB, byte_count);
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
|
@ -5787,5 +5730,99 @@ SetEARetry:
|
|||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
|
||||
/*
|
||||
* Years ago the kernel added a "dnotify" function for Samba server,
|
||||
* to allow network clients (such as Windows) to display updated
|
||||
* lists of files in directory listings automatically when
|
||||
* files are added by one user when another user has the
|
||||
* same directory open on their desktop. The Linux cifs kernel
|
||||
* client hooked into the kernel side of this interface for
|
||||
* the same reason, but ironically when the VFS moved from
|
||||
* "dnotify" to "inotify" it became harder to plug in Linux
|
||||
* network file system clients (the most obvious use case
|
||||
* for notify interfaces is when multiple users can update
|
||||
* the contents of the same directory - exactly what network
|
||||
* file systems can do) although the server (Samba) could
|
||||
* still use it. For the short term we leave the worker
|
||||
* function ifdeffed out (below) until inotify is fixed
|
||||
* in the VFS to make it easier to plug in network file
|
||||
* system clients. If inotify turns out to be permanently
|
||||
* incompatible for network fs clients, we could instead simply
|
||||
* expose this config flag by adding a future cifs (and smb2) notify ioctl.
|
||||
*/
|
||||
int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
|
||||
const int notify_subdirs, const __u16 netfid,
|
||||
__u32 filter, struct file *pfile, int multishot,
|
||||
const struct nls_table *nls_codepage)
|
||||
{
|
||||
int rc = 0;
|
||||
struct smb_com_transaction_change_notify_req *pSMB = NULL;
|
||||
struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
|
||||
struct dir_notify_req *dnotify_req;
|
||||
int bytes_returned;
|
||||
|
||||
cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
|
||||
rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
|
||||
(void **) &pSMBr);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pSMB->TotalParameterCount = 0 ;
|
||||
pSMB->TotalDataCount = 0;
|
||||
pSMB->MaxParameterCount = cpu_to_le32(2);
|
||||
/* BB find exact data count max from sess structure BB */
|
||||
pSMB->MaxDataCount = 0; /* same in little endian or be */
|
||||
/* BB VERIFY verify which is correct for above BB */
|
||||
pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
|
||||
MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
|
||||
|
||||
pSMB->MaxSetupCount = 4;
|
||||
pSMB->Reserved = 0;
|
||||
pSMB->ParameterOffset = 0;
|
||||
pSMB->DataCount = 0;
|
||||
pSMB->DataOffset = 0;
|
||||
pSMB->SetupCount = 4; /* single byte does not need le conversion */
|
||||
pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
|
||||
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
||||
if (notify_subdirs)
|
||||
pSMB->WatchTree = 1; /* one byte - no le conversion needed */
|
||||
pSMB->Reserved2 = 0;
|
||||
pSMB->CompletionFilter = cpu_to_le32(filter);
|
||||
pSMB->Fid = netfid; /* file handle always le */
|
||||
pSMB->ByteCount = 0;
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *)pSMBr, &bytes_returned,
|
||||
CIFS_ASYNC_OP);
|
||||
if (rc) {
|
||||
cFYI(1, "Error in Notify = %d", rc);
|
||||
} else {
|
||||
/* Add file to outstanding requests */
|
||||
/* BB change to kmem cache alloc */
|
||||
dnotify_req = kmalloc(
|
||||
sizeof(struct dir_notify_req),
|
||||
GFP_KERNEL);
|
||||
if (dnotify_req) {
|
||||
dnotify_req->Pid = pSMB->hdr.Pid;
|
||||
dnotify_req->PidHigh = pSMB->hdr.PidHigh;
|
||||
dnotify_req->Mid = pSMB->hdr.Mid;
|
||||
dnotify_req->Tid = pSMB->hdr.Tid;
|
||||
dnotify_req->Uid = pSMB->hdr.Uid;
|
||||
dnotify_req->netfid = netfid;
|
||||
dnotify_req->pfile = pfile;
|
||||
dnotify_req->filter = filter;
|
||||
dnotify_req->multishot = multishot;
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
list_add_tail(&dnotify_req->lhead,
|
||||
&GlobalDnotifyReqList);
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
} else
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
cifs_buf_release(pSMB);
|
||||
return rc;
|
||||
}
|
||||
#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */
|
||||
|
|
|
@ -102,6 +102,7 @@ struct smb_vol {
|
|||
bool fsc:1; /* enable fscache */
|
||||
bool mfsymlinks:1; /* use Minshall+French Symlinks */
|
||||
bool multiuser:1;
|
||||
bool use_smb2:1; /* force smb2 use on mount instead of cifs */
|
||||
unsigned int rsize;
|
||||
unsigned int wsize;
|
||||
bool sockopt_tcp_nodelay:1;
|
||||
|
@ -316,19 +317,19 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
|
|||
put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount);
|
||||
|
||||
/* fix up the BCC */
|
||||
byte_count = get_bcc_le(pTargetSMB);
|
||||
byte_count = get_bcc(pTargetSMB);
|
||||
byte_count += total_in_buf2;
|
||||
/* is the result too big for the field? */
|
||||
if (byte_count > USHRT_MAX)
|
||||
return -EPROTO;
|
||||
put_bcc_le(byte_count, pTargetSMB);
|
||||
put_bcc(byte_count, pTargetSMB);
|
||||
|
||||
byte_count = pTargetSMB->smb_buf_length;
|
||||
byte_count = be32_to_cpu(pTargetSMB->smb_buf_length);
|
||||
byte_count += total_in_buf2;
|
||||
/* don't allow buffer to overflow */
|
||||
if (byte_count > CIFSMaxBufSize)
|
||||
return -ENOBUFS;
|
||||
pTargetSMB->smb_buf_length = byte_count;
|
||||
pTargetSMB->smb_buf_length = cpu_to_be32(byte_count);
|
||||
|
||||
memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
|
||||
|
||||
|
@ -495,8 +496,7 @@ incomplete_rcv:
|
|||
/* Note that FC 1001 length is big endian on the wire,
|
||||
but we convert it here so it is always manipulated
|
||||
as host byte order */
|
||||
pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length);
|
||||
smb_buffer->smb_buf_length = pdu_length;
|
||||
pdu_length = be32_to_cpu(smb_buffer->smb_buf_length);
|
||||
|
||||
cFYI(1, "rfc1002 length 0x%x", pdu_length+4);
|
||||
|
||||
|
@ -735,7 +735,7 @@ multi_t2_fnd:
|
|||
sock_release(csocket);
|
||||
server->ssocket = NULL;
|
||||
}
|
||||
/* buffer usuallly freed in free_mid - need to free it here on exit */
|
||||
/* buffer usually freed in free_mid - need to free it here on exit */
|
||||
cifs_buf_release(bigbuf);
|
||||
if (smallbuf) /* no sense logging a debug message if NULL */
|
||||
cifs_small_buf_release(smallbuf);
|
||||
|
@ -818,10 +818,11 @@ extract_hostname(const char *unc)
|
|||
}
|
||||
|
||||
static int
|
||||
cifs_parse_mount_options(char *options, const char *devname,
|
||||
cifs_parse_mount_options(const char *mountdata, const char *devname,
|
||||
struct smb_vol *vol)
|
||||
{
|
||||
char *value, *data, *end;
|
||||
char *mountdata_copy, *options;
|
||||
unsigned int temp_len, i, j;
|
||||
char separator[2];
|
||||
short int override_uid = -1;
|
||||
|
@ -861,9 +862,14 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
|
||||
vol->actimeo = CIFS_DEF_ACTIMEO;
|
||||
|
||||
if (!options)
|
||||
return 1;
|
||||
if (!mountdata)
|
||||
goto cifs_parse_mount_err;
|
||||
|
||||
mountdata_copy = kstrndup(mountdata, PAGE_SIZE, GFP_KERNEL);
|
||||
if (!mountdata_copy)
|
||||
goto cifs_parse_mount_err;
|
||||
|
||||
options = mountdata_copy;
|
||||
end = options + strlen(options);
|
||||
if (strncmp(options, "sep=", 4) == 0) {
|
||||
if (options[4] != 0) {
|
||||
|
@ -889,17 +895,22 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
if (!value) {
|
||||
printk(KERN_WARNING
|
||||
"CIFS: invalid or missing username\n");
|
||||
return 1; /* needs_arg; */
|
||||
goto cifs_parse_mount_err;
|
||||
} else if (!*value) {
|
||||
/* null user, ie anonymous, authentication */
|
||||
vol->nullauth = 1;
|
||||
}
|
||||
if (strnlen(value, MAX_USERNAME_SIZE) <
|
||||
MAX_USERNAME_SIZE) {
|
||||
vol->username = value;
|
||||
vol->username = kstrdup(value, GFP_KERNEL);
|
||||
if (!vol->username) {
|
||||
printk(KERN_WARNING "CIFS: no memory "
|
||||
"for username\n");
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
} else {
|
||||
printk(KERN_WARNING "CIFS: username too long\n");
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
} else if (strnicmp(data, "pass", 4) == 0) {
|
||||
if (!value) {
|
||||
|
@ -963,7 +974,7 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
if (vol->password == NULL) {
|
||||
printk(KERN_WARNING "CIFS: no memory "
|
||||
"for password\n");
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
for (i = 0, j = 0; i < temp_len; i++, j++) {
|
||||
vol->password[j] = value[i];
|
||||
|
@ -979,7 +990,7 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
if (vol->password == NULL) {
|
||||
printk(KERN_WARNING "CIFS: no memory "
|
||||
"for password\n");
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
strcpy(vol->password, value);
|
||||
}
|
||||
|
@ -989,11 +1000,16 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
vol->UNCip = NULL;
|
||||
} else if (strnlen(value, INET6_ADDRSTRLEN) <
|
||||
INET6_ADDRSTRLEN) {
|
||||
vol->UNCip = value;
|
||||
vol->UNCip = kstrdup(value, GFP_KERNEL);
|
||||
if (!vol->UNCip) {
|
||||
printk(KERN_WARNING "CIFS: no memory "
|
||||
"for UNC IP\n");
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
} else {
|
||||
printk(KERN_WARNING "CIFS: ip address "
|
||||
"too long\n");
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
} else if (strnicmp(data, "sec", 3) == 0) {
|
||||
if (!value || !*value) {
|
||||
|
@ -1006,7 +1022,7 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
/* vol->secFlg |= CIFSSEC_MUST_SEAL |
|
||||
CIFSSEC_MAY_KRB5; */
|
||||
cERROR(1, "Krb5 cifs privacy not supported");
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
} else if (strnicmp(value, "krb5", 4) == 0) {
|
||||
vol->secFlg |= CIFSSEC_MAY_KRB5;
|
||||
} else if (strnicmp(value, "ntlmsspi", 8) == 0) {
|
||||
|
@ -1036,7 +1052,23 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
vol->nullauth = 1;
|
||||
} else {
|
||||
cERROR(1, "bad security option: %s", value);
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
} else if (strnicmp(data, "vers", 3) == 0) {
|
||||
if (!value || !*value) {
|
||||
cERROR(1, "no protocol version specified"
|
||||
" after vers= mount option");
|
||||
} else if ((strnicmp(value, "cifs", 4) == 0) ||
|
||||
(strnicmp(value, "1", 1) == 0)) {
|
||||
/* this is the default */
|
||||
continue;
|
||||
} else if ((strnicmp(value, "smb2", 4) == 0) ||
|
||||
(strnicmp(value, "2", 1) == 0)) {
|
||||
#ifdef CONFIG_CIFS_SMB2
|
||||
vol->use_smb2 = true;
|
||||
#else
|
||||
cERROR(1, "smb2 support not enabled");
|
||||
#endif /* CONFIG_CIFS_SMB2 */
|
||||
}
|
||||
} else if ((strnicmp(data, "unc", 3) == 0)
|
||||
|| (strnicmp(data, "target", 6) == 0)
|
||||
|
@ -1044,12 +1076,12 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
if (!value || !*value) {
|
||||
printk(KERN_WARNING "CIFS: invalid path to "
|
||||
"network resource\n");
|
||||
return 1; /* needs_arg; */
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
if ((temp_len = strnlen(value, 300)) < 300) {
|
||||
vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
|
||||
if (vol->UNC == NULL)
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
strcpy(vol->UNC, value);
|
||||
if (strncmp(vol->UNC, "//", 2) == 0) {
|
||||
vol->UNC[0] = '\\';
|
||||
|
@ -1058,27 +1090,32 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
printk(KERN_WARNING
|
||||
"CIFS: UNC Path does not begin "
|
||||
"with // or \\\\ \n");
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
} else {
|
||||
printk(KERN_WARNING "CIFS: UNC name too long\n");
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
} else if ((strnicmp(data, "domain", 3) == 0)
|
||||
|| (strnicmp(data, "workgroup", 5) == 0)) {
|
||||
if (!value || !*value) {
|
||||
printk(KERN_WARNING "CIFS: invalid domain name\n");
|
||||
return 1; /* needs_arg; */
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
/* BB are there cases in which a comma can be valid in
|
||||
a domain name and need special handling? */
|
||||
if (strnlen(value, 256) < 256) {
|
||||
vol->domainname = value;
|
||||
vol->domainname = kstrdup(value, GFP_KERNEL);
|
||||
if (!vol->domainname) {
|
||||
printk(KERN_WARNING "CIFS: no memory "
|
||||
"for domainname\n");
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
cFYI(1, "Domain name set");
|
||||
} else {
|
||||
printk(KERN_WARNING "CIFS: domain name too "
|
||||
"long\n");
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
} else if (strnicmp(data, "srcaddr", 7) == 0) {
|
||||
vol->srcaddr.ss_family = AF_UNSPEC;
|
||||
|
@ -1086,7 +1123,7 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
if (!value || !*value) {
|
||||
printk(KERN_WARNING "CIFS: srcaddr value"
|
||||
" not specified.\n");
|
||||
return 1; /* needs_arg; */
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
i = cifs_convert_address((struct sockaddr *)&vol->srcaddr,
|
||||
value, strlen(value));
|
||||
|
@ -1094,20 +1131,20 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
printk(KERN_WARNING "CIFS: Could not parse"
|
||||
" srcaddr: %s\n",
|
||||
value);
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
} else if (strnicmp(data, "prefixpath", 10) == 0) {
|
||||
if (!value || !*value) {
|
||||
printk(KERN_WARNING
|
||||
"CIFS: invalid path prefix\n");
|
||||
return 1; /* needs_argument */
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
if ((temp_len = strnlen(value, 1024)) < 1024) {
|
||||
if (value[0] != '/')
|
||||
temp_len++; /* missing leading slash */
|
||||
vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
|
||||
if (vol->prepath == NULL)
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
if (value[0] != '/') {
|
||||
vol->prepath[0] = '/';
|
||||
strcpy(vol->prepath+1, value);
|
||||
|
@ -1116,24 +1153,33 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
cFYI(1, "prefix path %s", vol->prepath);
|
||||
} else {
|
||||
printk(KERN_WARNING "CIFS: prefix too long\n");
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
} else if (strnicmp(data, "iocharset", 9) == 0) {
|
||||
if (!value || !*value) {
|
||||
printk(KERN_WARNING "CIFS: invalid iocharset "
|
||||
"specified\n");
|
||||
return 1; /* needs_arg; */
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
if (strnlen(value, 65) < 65) {
|
||||
if (strnicmp(value, "default", 7))
|
||||
vol->iocharset = value;
|
||||
if (strnicmp(value, "default", 7)) {
|
||||
vol->iocharset = kstrdup(value,
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!vol->iocharset) {
|
||||
printk(KERN_WARNING "CIFS: no "
|
||||
"memory for"
|
||||
"charset\n");
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
}
|
||||
/* if iocharset not set then load_nls_default
|
||||
is used by caller */
|
||||
cFYI(1, "iocharset set to %s", value);
|
||||
} else {
|
||||
printk(KERN_WARNING "CIFS: iocharset name "
|
||||
"too long.\n");
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
} else if (!strnicmp(data, "uid", 3) && value && *value) {
|
||||
vol->linux_uid = simple_strtoul(value, &value, 0);
|
||||
|
@ -1246,7 +1292,7 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
if (vol->actimeo > CIFS_MAX_ACTIMEO) {
|
||||
cERROR(1, "CIFS: attribute cache"
|
||||
"timeout too large");
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
}
|
||||
} else if (strnicmp(data, "credentials", 4) == 0) {
|
||||
|
@ -1390,7 +1436,7 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
#ifndef CONFIG_CIFS_FSCACHE
|
||||
cERROR(1, "FS-Cache support needs CONFIG_CIFS_FSCACHE"
|
||||
"kernel config option set");
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
#endif
|
||||
vol->fsc = true;
|
||||
} else if (strnicmp(data, "mfsymlinks", 10) == 0) {
|
||||
|
@ -1405,12 +1451,12 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
if (devname == NULL) {
|
||||
printk(KERN_WARNING "CIFS: Missing UNC name for mount "
|
||||
"target\n");
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
if ((temp_len = strnlen(devname, 300)) < 300) {
|
||||
vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
|
||||
if (vol->UNC == NULL)
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
strcpy(vol->UNC, devname);
|
||||
if (strncmp(vol->UNC, "//", 2) == 0) {
|
||||
vol->UNC[0] = '\\';
|
||||
|
@ -1418,21 +1464,21 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
} else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
|
||||
printk(KERN_WARNING "CIFS: UNC Path does not "
|
||||
"begin with // or \\\\ \n");
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
value = strpbrk(vol->UNC+2, "/\\");
|
||||
if (value)
|
||||
*value = '\\';
|
||||
} else {
|
||||
printk(KERN_WARNING "CIFS: UNC name too long\n");
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
}
|
||||
|
||||
if (vol->multiuser && !(vol->secFlg & CIFSSEC_MAY_KRB5)) {
|
||||
cERROR(1, "Multiuser mounts currently require krb5 "
|
||||
"authentication!");
|
||||
return 1;
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
|
||||
if (vol->UNCip == NULL)
|
||||
|
@ -1450,7 +1496,12 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
printk(KERN_NOTICE "CIFS: ignoring forcegid mount option "
|
||||
"specified with no gid= option.\n");
|
||||
|
||||
kfree(mountdata_copy);
|
||||
return 0;
|
||||
|
||||
cifs_parse_mount_err:
|
||||
kfree(mountdata_copy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Returns true if srcaddr isn't specified and rhs isn't
|
||||
|
@ -2280,7 +2331,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
|
|||
smb_buf = (struct smb_hdr *)ses_init_buf;
|
||||
|
||||
/* sizeof RFC1002_SESSION_REQUEST with no scope */
|
||||
smb_buf->smb_buf_length = 0x81000044;
|
||||
smb_buf->smb_buf_length = cpu_to_be32(0x81000044);
|
||||
rc = smb_send(server, smb_buf, 0x44);
|
||||
kfree(ses_init_buf);
|
||||
/*
|
||||
|
@ -2691,8 +2742,12 @@ cleanup_volume_info(struct smb_vol **pvolume_info)
|
|||
return;
|
||||
|
||||
volume_info = *pvolume_info;
|
||||
kfree(volume_info->username);
|
||||
kzfree(volume_info->password);
|
||||
kfree(volume_info->UNC);
|
||||
kfree(volume_info->UNCip);
|
||||
kfree(volume_info->domainname);
|
||||
kfree(volume_info->iocharset);
|
||||
kfree(volume_info->prepath);
|
||||
kfree(volume_info);
|
||||
*pvolume_info = NULL;
|
||||
|
@ -2729,11 +2784,65 @@ build_unc_path_to_root(const struct smb_vol *volume_info,
|
|||
full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */
|
||||
return full_path;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a dfs referral query for a share and (optionally) prefix
|
||||
*
|
||||
* If a referral is found, cifs_sb->mountdata will be (re-)allocated
|
||||
* to a string containing updated options for the submount. Otherwise it
|
||||
* will be left untouched.
|
||||
*
|
||||
* Returns the rc from get_dfs_path to the caller, which can be used to
|
||||
* determine whether there were referrals.
|
||||
*/
|
||||
static int
|
||||
expand_dfs_referral(int xid, struct cifsSesInfo *pSesInfo,
|
||||
struct smb_vol *volume_info, struct cifs_sb_info *cifs_sb,
|
||||
int check_prefix)
|
||||
{
|
||||
int rc;
|
||||
unsigned int num_referrals = 0;
|
||||
struct dfs_info3_param *referrals = NULL;
|
||||
char *full_path = NULL, *ref_path = NULL, *mdata = NULL;
|
||||
|
||||
full_path = build_unc_path_to_root(volume_info, cifs_sb);
|
||||
if (IS_ERR(full_path))
|
||||
return PTR_ERR(full_path);
|
||||
|
||||
/* For DFS paths, skip the first '\' of the UNC */
|
||||
ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1;
|
||||
|
||||
rc = get_dfs_path(xid, pSesInfo , ref_path, cifs_sb->local_nls,
|
||||
&num_referrals, &referrals,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
|
||||
if (!rc && num_referrals > 0) {
|
||||
char *fake_devname = NULL;
|
||||
|
||||
mdata = cifs_compose_mount_options(cifs_sb->mountdata,
|
||||
full_path + 1, referrals,
|
||||
&fake_devname);
|
||||
|
||||
free_dfs_info_array(referrals, num_referrals);
|
||||
kfree(fake_devname);
|
||||
|
||||
if (cifs_sb->mountdata != NULL)
|
||||
kfree(cifs_sb->mountdata);
|
||||
|
||||
if (IS_ERR(mdata)) {
|
||||
rc = PTR_ERR(mdata);
|
||||
mdata = NULL;
|
||||
}
|
||||
cifs_sb->mountdata = mdata;
|
||||
}
|
||||
kfree(full_path);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||
char *mount_data_global, const char *devname)
|
||||
const char *devname)
|
||||
{
|
||||
int rc;
|
||||
int xid;
|
||||
|
@ -2742,13 +2851,20 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
struct cifsTconInfo *tcon;
|
||||
struct TCP_Server_Info *srvTcp;
|
||||
char *full_path;
|
||||
char *mount_data = mount_data_global;
|
||||
struct tcon_link *tlink;
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
struct dfs_info3_param *referrals = NULL;
|
||||
unsigned int num_referrals = 0;
|
||||
int referral_walks_count = 0;
|
||||
try_mount_again:
|
||||
/* cleanup activities if we're chasing a referral */
|
||||
if (referral_walks_count) {
|
||||
if (tcon)
|
||||
cifs_put_tcon(tcon);
|
||||
else if (pSesInfo)
|
||||
cifs_put_smb_ses(pSesInfo);
|
||||
|
||||
cleanup_volume_info(&volume_info);
|
||||
FreeXid(xid);
|
||||
}
|
||||
#endif
|
||||
rc = 0;
|
||||
tcon = NULL;
|
||||
|
@ -2765,7 +2881,8 @@ try_mount_again:
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (cifs_parse_mount_options(mount_data, devname, volume_info)) {
|
||||
if (cifs_parse_mount_options(cifs_sb->mountdata, devname,
|
||||
volume_info)) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
@ -2861,6 +2978,24 @@ try_mount_again:
|
|||
(tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
|
||||
|
||||
remote_path_check:
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
/*
|
||||
* Perform an unconditional check for whether there are DFS
|
||||
* referrals for this path without prefix, to provide support
|
||||
* for DFS referrals from w2k8 servers which don't seem to respond
|
||||
* with PATH_NOT_COVERED to requests that include the prefix.
|
||||
* Chase the referral if found, otherwise continue normally.
|
||||
*/
|
||||
if (referral_walks_count == 0) {
|
||||
int refrc = expand_dfs_referral(xid, pSesInfo, volume_info,
|
||||
cifs_sb, false);
|
||||
if (!refrc) {
|
||||
referral_walks_count++;
|
||||
goto try_mount_again;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check if a whole path (including prepath) is not remote */
|
||||
if (!rc && tcon) {
|
||||
/* build_path_to_root works only when we have a valid tcon */
|
||||
|
@ -2894,46 +3029,15 @@ remote_path_check:
|
|||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
|
||||
convert_delimiter(cifs_sb->prepath,
|
||||
CIFS_DIR_SEP(cifs_sb));
|
||||
full_path = build_unc_path_to_root(volume_info, cifs_sb);
|
||||
if (IS_ERR(full_path)) {
|
||||
rc = PTR_ERR(full_path);
|
||||
goto mount_fail_check;
|
||||
}
|
||||
|
||||
cFYI(1, "Getting referral for: %s", full_path);
|
||||
rc = get_dfs_path(xid, pSesInfo , full_path + 1,
|
||||
cifs_sb->local_nls, &num_referrals, &referrals,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (!rc && num_referrals > 0) {
|
||||
char *fake_devname = NULL;
|
||||
rc = expand_dfs_referral(xid, pSesInfo, volume_info, cifs_sb,
|
||||
true);
|
||||
|
||||
if (mount_data != mount_data_global)
|
||||
kfree(mount_data);
|
||||
|
||||
mount_data = cifs_compose_mount_options(
|
||||
cifs_sb->mountdata, full_path + 1,
|
||||
referrals, &fake_devname);
|
||||
|
||||
free_dfs_info_array(referrals, num_referrals);
|
||||
kfree(fake_devname);
|
||||
kfree(full_path);
|
||||
|
||||
if (IS_ERR(mount_data)) {
|
||||
rc = PTR_ERR(mount_data);
|
||||
mount_data = NULL;
|
||||
goto mount_fail_check;
|
||||
}
|
||||
|
||||
if (tcon)
|
||||
cifs_put_tcon(tcon);
|
||||
else if (pSesInfo)
|
||||
cifs_put_smb_ses(pSesInfo);
|
||||
|
||||
cleanup_volume_info(&volume_info);
|
||||
if (!rc) {
|
||||
referral_walks_count++;
|
||||
FreeXid(xid);
|
||||
goto try_mount_again;
|
||||
}
|
||||
goto mount_fail_check;
|
||||
#else /* No DFS support, return error on mount */
|
||||
rc = -EOPNOTSUPP;
|
||||
#endif
|
||||
|
@ -2966,8 +3070,6 @@ remote_path_check:
|
|||
mount_fail_check:
|
||||
/* on error free sesinfo and tcon struct if needed */
|
||||
if (rc) {
|
||||
if (mount_data != mount_data_global)
|
||||
kfree(mount_data);
|
||||
/* If find_unc succeeded then rc == 0 so we can not end */
|
||||
/* up accidentally freeing someone elses tcon struct */
|
||||
if (tcon)
|
||||
|
@ -3083,7 +3185,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
|
|||
bcc_ptr += strlen("?????");
|
||||
bcc_ptr += 1;
|
||||
count = bcc_ptr - &pSMB->Password[0];
|
||||
pSMB->hdr.smb_buf_length += count;
|
||||
pSMB->hdr.smb_buf_length = cpu_to_be32(be32_to_cpu(
|
||||
pSMB->hdr.smb_buf_length) + count);
|
||||
pSMB->ByteCount = cpu_to_le16(count);
|
||||
|
||||
rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
|
||||
|
@ -3258,7 +3361,9 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
|
|||
struct cifsSesInfo *ses;
|
||||
struct cifsTconInfo *tcon = NULL;
|
||||
struct smb_vol *vol_info;
|
||||
char username[MAX_USERNAME_SIZE + 1];
|
||||
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);
|
||||
if (vol_info == NULL) {
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
#include "cifs_debug.h"
|
||||
#include "cifsfs.h"
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
#ifdef CIFS_NFSD_EXPORT
|
||||
static struct dentry *cifs_get_parent(struct dentry *dentry)
|
||||
{
|
||||
/* BB need to add code here eventually to enable export via NFSD */
|
||||
|
@ -63,5 +63,5 @@ const struct export_operations cifs_export_ops = {
|
|||
.encode_fs = */
|
||||
};
|
||||
|
||||
#endif /* EXPERIMENTAL */
|
||||
#endif /* CIFS_NFSD_EXPORT */
|
||||
|
||||
|
|
167
fs/cifs/file.c
167
fs/cifs/file.c
|
@ -857,95 +857,6 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
|
|||
cifsi->server_eof = end_of_write;
|
||||
}
|
||||
|
||||
ssize_t cifs_user_write(struct file *file, const char __user *write_data,
|
||||
size_t write_size, loff_t *poffset)
|
||||
{
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
int rc = 0;
|
||||
unsigned int bytes_written = 0;
|
||||
unsigned int total_written;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo *pTcon;
|
||||
int xid;
|
||||
struct cifsFileInfo *open_file;
|
||||
struct cifsInodeInfo *cifsi = CIFS_I(inode);
|
||||
|
||||
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
||||
|
||||
/* cFYI(1, " write %d bytes to offset %lld of %s", write_size,
|
||||
*poffset, file->f_path.dentry->d_name.name); */
|
||||
|
||||
if (file->private_data == NULL)
|
||||
return -EBADF;
|
||||
|
||||
open_file = file->private_data;
|
||||
pTcon = tlink_tcon(open_file->tlink);
|
||||
|
||||
rc = generic_write_checks(file, poffset, &write_size, 0);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
for (total_written = 0; write_size > total_written;
|
||||
total_written += bytes_written) {
|
||||
rc = -EAGAIN;
|
||||
while (rc == -EAGAIN) {
|
||||
if (file->private_data == NULL) {
|
||||
/* file has been closed on us */
|
||||
FreeXid(xid);
|
||||
/* if we have gotten here we have written some data
|
||||
and blocked, and the file has been freed on us while
|
||||
we blocked so return what we managed to write */
|
||||
return total_written;
|
||||
}
|
||||
if (open_file->invalidHandle) {
|
||||
/* we could deadlock if we called
|
||||
filemap_fdatawait from here so tell
|
||||
reopen_file not to flush data to server
|
||||
now */
|
||||
rc = cifs_reopen_file(open_file, false);
|
||||
if (rc != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
rc = CIFSSMBWrite(xid, pTcon,
|
||||
open_file->netfid,
|
||||
min_t(const int, cifs_sb->wsize,
|
||||
write_size - total_written),
|
||||
*poffset, &bytes_written,
|
||||
NULL, write_data + total_written, 0);
|
||||
}
|
||||
if (rc || (bytes_written == 0)) {
|
||||
if (total_written)
|
||||
break;
|
||||
else {
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
cifs_update_eof(cifsi, *poffset, bytes_written);
|
||||
*poffset += bytes_written;
|
||||
}
|
||||
}
|
||||
|
||||
cifs_stats_bytes_written(pTcon, total_written);
|
||||
|
||||
/* Do not update local mtime - server will set its actual value on write
|
||||
* inode->i_ctime = inode->i_mtime =
|
||||
* current_fs_time(inode->i_sb);*/
|
||||
if (total_written > 0) {
|
||||
spin_lock(&inode->i_lock);
|
||||
if (*poffset > inode->i_size)
|
||||
i_size_write(inode, *poffset);
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
mark_inode_dirty_sync(inode);
|
||||
|
||||
FreeXid(xid);
|
||||
return total_written;
|
||||
}
|
||||
|
||||
static ssize_t cifs_write(struct cifsFileInfo *open_file,
|
||||
const char *write_data, size_t write_size,
|
||||
loff_t *poffset)
|
||||
|
@ -1420,9 +1331,10 @@ retry_write:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int cifs_writepage(struct page *page, struct writeback_control *wbc)
|
||||
static int
|
||||
cifs_writepage_locked(struct page *page, struct writeback_control *wbc)
|
||||
{
|
||||
int rc = -EFAULT;
|
||||
int rc;
|
||||
int xid;
|
||||
|
||||
xid = GetXid();
|
||||
|
@ -1442,15 +1354,29 @@ static int cifs_writepage(struct page *page, struct writeback_control *wbc)
|
|||
* to fail to update with the state of the page correctly.
|
||||
*/
|
||||
set_page_writeback(page);
|
||||
retry_write:
|
||||
rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
|
||||
SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
|
||||
unlock_page(page);
|
||||
if (rc == -EAGAIN && wbc->sync_mode == WB_SYNC_ALL)
|
||||
goto retry_write;
|
||||
else if (rc == -EAGAIN)
|
||||
redirty_page_for_writepage(wbc, page);
|
||||
else if (rc != 0)
|
||||
SetPageError(page);
|
||||
else
|
||||
SetPageUptodate(page);
|
||||
end_page_writeback(page);
|
||||
page_cache_release(page);
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cifs_writepage(struct page *page, struct writeback_control *wbc)
|
||||
{
|
||||
int rc = cifs_writepage_locked(page, wbc);
|
||||
unlock_page(page);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cifs_write_end(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned copied,
|
||||
struct page *page, void *fsdata)
|
||||
|
@ -1519,8 +1445,13 @@ int cifs_strict_fsync(struct file *file, int datasync)
|
|||
cFYI(1, "Sync file - name: %s datasync: 0x%x",
|
||||
file->f_path.dentry->d_name.name, datasync);
|
||||
|
||||
if (!CIFS_I(inode)->clientCanCacheRead)
|
||||
cifs_invalidate_mapping(inode);
|
||||
if (!CIFS_I(inode)->clientCanCacheRead) {
|
||||
rc = cifs_invalidate_mapping(inode);
|
||||
if (rc) {
|
||||
cFYI(1, "rc: %d during invalidate phase", rc);
|
||||
rc = 0; /* don't care about it in fsync */
|
||||
}
|
||||
}
|
||||
|
||||
tcon = tlink_tcon(smbfile->tlink);
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
|
||||
|
@ -1726,7 +1657,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
|
|||
return total_written;
|
||||
}
|
||||
|
||||
static ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
|
||||
ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t pos)
|
||||
{
|
||||
ssize_t written;
|
||||
|
@ -1849,17 +1780,7 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
|
|||
return total_read;
|
||||
}
|
||||
|
||||
ssize_t cifs_user_read(struct file *file, char __user *read_data,
|
||||
size_t read_size, loff_t *poffset)
|
||||
{
|
||||
struct iovec iov;
|
||||
iov.iov_base = read_data;
|
||||
iov.iov_len = read_size;
|
||||
|
||||
return cifs_iovec_read(file, &iov, 1, poffset);
|
||||
}
|
||||
|
||||
static ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov,
|
||||
ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t pos)
|
||||
{
|
||||
ssize_t read;
|
||||
|
@ -1987,8 +1908,11 @@ int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
|
|||
|
||||
xid = GetXid();
|
||||
|
||||
if (!CIFS_I(inode)->clientCanCacheRead)
|
||||
cifs_invalidate_mapping(inode);
|
||||
if (!CIFS_I(inode)->clientCanCacheRead) {
|
||||
rc = cifs_invalidate_mapping(inode);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = generic_file_mmap(file, vma);
|
||||
if (rc == 0)
|
||||
|
@ -2415,6 +2339,27 @@ static void cifs_invalidate_page(struct page *page, unsigned long offset)
|
|||
cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
|
||||
}
|
||||
|
||||
static int cifs_launder_page(struct page *page)
|
||||
{
|
||||
int rc = 0;
|
||||
loff_t range_start = page_offset(page);
|
||||
loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1);
|
||||
struct writeback_control wbc = {
|
||||
.sync_mode = WB_SYNC_ALL,
|
||||
.nr_to_write = 0,
|
||||
.range_start = range_start,
|
||||
.range_end = range_end,
|
||||
};
|
||||
|
||||
cFYI(1, "Launder page: %p", page);
|
||||
|
||||
if (clear_page_dirty_for_io(page))
|
||||
rc = cifs_writepage_locked(page, &wbc);
|
||||
|
||||
cifs_fscache_invalidate_page(page, page->mapping->host);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void cifs_oplock_break(struct work_struct *work)
|
||||
{
|
||||
struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
|
||||
|
@ -2486,7 +2431,7 @@ const struct address_space_operations cifs_addr_ops = {
|
|||
.set_page_dirty = __set_page_dirty_nobuffers,
|
||||
.releasepage = cifs_release_page,
|
||||
.invalidatepage = cifs_invalidate_page,
|
||||
/* .direct_IO = */
|
||||
.launder_page = cifs_launder_page,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -2503,5 +2448,5 @@ const struct address_space_operations cifs_addr_ops_smallbuf = {
|
|||
.set_page_dirty = __set_page_dirty_nobuffers,
|
||||
.releasepage = cifs_release_page,
|
||||
.invalidatepage = cifs_invalidate_page,
|
||||
/* .direct_IO = */
|
||||
.launder_page = cifs_launder_page,
|
||||
};
|
||||
|
|
129
fs/cifs/inode.c
129
fs/cifs/inode.c
|
@ -878,7 +878,7 @@ retry_iget5_locked:
|
|||
}
|
||||
|
||||
/* gets root inode */
|
||||
struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
|
||||
struct inode *cifs_root_iget(struct super_block *sb)
|
||||
{
|
||||
int xid;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
|
@ -1683,71 +1683,70 @@ cifs_inode_needs_reval(struct inode *inode)
|
|||
/*
|
||||
* Zap the cache. Called when invalid_mapping flag is set.
|
||||
*/
|
||||
void
|
||||
int
|
||||
cifs_invalidate_mapping(struct inode *inode)
|
||||
{
|
||||
int rc;
|
||||
int rc = 0;
|
||||
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
|
||||
|
||||
cifs_i->invalid_mapping = false;
|
||||
|
||||
/* write back any cached data */
|
||||
if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
|
||||
rc = filemap_write_and_wait(inode->i_mapping);
|
||||
mapping_set_error(inode->i_mapping, rc);
|
||||
rc = invalidate_inode_pages2(inode->i_mapping);
|
||||
if (rc) {
|
||||
cERROR(1, "%s: could not invalidate inode %p", __func__,
|
||||
inode);
|
||||
cifs_i->invalid_mapping = true;
|
||||
}
|
||||
}
|
||||
invalidate_remote_inode(inode);
|
||||
|
||||
cifs_fscache_reset_inode_cookie(inode);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cifs_revalidate_file(struct file *filp)
|
||||
int cifs_revalidate_file_attr(struct file *filp)
|
||||
{
|
||||
int rc = 0;
|
||||
struct inode *inode = filp->f_path.dentry->d_inode;
|
||||
struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
|
||||
|
||||
if (!cifs_inode_needs_reval(inode))
|
||||
goto check_inval;
|
||||
return rc;
|
||||
|
||||
if (tlink_tcon(cfile->tlink)->unix_ext)
|
||||
rc = cifs_get_file_info_unix(filp);
|
||||
else
|
||||
rc = cifs_get_file_info(filp);
|
||||
|
||||
check_inval:
|
||||
if (CIFS_I(inode)->invalid_mapping)
|
||||
cifs_invalidate_mapping(inode);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* revalidate a dentry's inode attributes */
|
||||
int cifs_revalidate_dentry(struct dentry *dentry)
|
||||
int cifs_revalidate_dentry_attr(struct dentry *dentry)
|
||||
{
|
||||
int xid;
|
||||
int rc = 0;
|
||||
char *full_path = NULL;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct super_block *sb = dentry->d_sb;
|
||||
char *full_path = NULL;
|
||||
|
||||
if (inode == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
if (!cifs_inode_needs_reval(inode))
|
||||
goto check_inval;
|
||||
return rc;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
/* can not safely grab the rename sem here if rename calls revalidate
|
||||
since that would deadlock */
|
||||
full_path = build_path_from_dentry(dentry);
|
||||
if (full_path == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto check_inval;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cFYI(1, "Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
|
||||
"jiffies %ld", full_path, inode, inode->i_count.counter,
|
||||
cFYI(1, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time "
|
||||
"%ld jiffies %ld", full_path, inode, inode->i_count.counter,
|
||||
dentry, dentry->d_time, jiffies);
|
||||
|
||||
if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
|
||||
|
@ -1756,41 +1755,83 @@ int cifs_revalidate_dentry(struct dentry *dentry)
|
|||
rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
|
||||
xid, NULL);
|
||||
|
||||
check_inval:
|
||||
if (CIFS_I(inode)->invalid_mapping)
|
||||
cifs_invalidate_mapping(inode);
|
||||
|
||||
out:
|
||||
kfree(full_path);
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cifs_revalidate_file(struct file *filp)
|
||||
{
|
||||
int rc;
|
||||
struct inode *inode = filp->f_path.dentry->d_inode;
|
||||
|
||||
rc = cifs_revalidate_file_attr(filp);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (CIFS_I(inode)->invalid_mapping)
|
||||
rc = cifs_invalidate_mapping(inode);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* revalidate a dentry's inode attributes */
|
||||
int cifs_revalidate_dentry(struct dentry *dentry)
|
||||
{
|
||||
int rc;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
|
||||
rc = cifs_revalidate_dentry_attr(dentry);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (CIFS_I(inode)->invalid_mapping)
|
||||
rc = cifs_invalidate_mapping(inode);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
||||
struct kstat *stat)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
|
||||
struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
|
||||
int err = cifs_revalidate_dentry(dentry);
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int rc;
|
||||
|
||||
if (!err) {
|
||||
generic_fillattr(dentry->d_inode, stat);
|
||||
stat->blksize = CIFS_MAX_MSGSIZE;
|
||||
stat->ino = CIFS_I(dentry->d_inode)->uniqueid;
|
||||
|
||||
/*
|
||||
* If on a multiuser mount without unix extensions, and the
|
||||
* admin hasn't overridden them, set the ownership to the
|
||||
* fsuid/fsgid of the current process.
|
||||
*/
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) &&
|
||||
!tcon->unix_ext) {
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID))
|
||||
stat->uid = current_fsuid();
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID))
|
||||
stat->gid = current_fsgid();
|
||||
/*
|
||||
* We need to be sure that all dirty pages are written and the server
|
||||
* has actual ctime, mtime and file length.
|
||||
*/
|
||||
if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping &&
|
||||
inode->i_mapping->nrpages != 0) {
|
||||
rc = filemap_fdatawait(inode->i_mapping);
|
||||
if (rc) {
|
||||
mapping_set_error(inode->i_mapping, rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
|
||||
rc = cifs_revalidate_dentry_attr(dentry);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
generic_fillattr(inode, stat);
|
||||
stat->blksize = CIFS_MAX_MSGSIZE;
|
||||
stat->ino = CIFS_I(inode)->uniqueid;
|
||||
|
||||
/*
|
||||
* If on a multiuser mount without unix extensions, and the admin hasn't
|
||||
* overridden them, set the ownership to the fsuid/fsgid of the current
|
||||
* process.
|
||||
*/
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) &&
|
||||
!tcon->unix_ext) {
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID))
|
||||
stat->uid = current_fsuid();
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID))
|
||||
stat->gid = current_fsgid();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cifs_truncate_page(struct address_space *mapping, loff_t from)
|
||||
|
|
|
@ -304,12 +304,10 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
|
|||
|
||||
memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */
|
||||
|
||||
buffer->smb_buf_length =
|
||||
buffer->smb_buf_length = cpu_to_be32(
|
||||
(2 * word_count) + sizeof(struct smb_hdr) -
|
||||
4 /* RFC 1001 length field does not count */ +
|
||||
2 /* for bcc field itself */ ;
|
||||
/* Note that this is the only network field that has to be converted
|
||||
to big endian and it is done just before we send it */
|
||||
2 /* for bcc field itself */) ;
|
||||
|
||||
buffer->Protocol[0] = 0xFF;
|
||||
buffer->Protocol[1] = 'S';
|
||||
|
@ -424,7 +422,7 @@ check_smb_hdr(struct smb_hdr *smb, __u16 mid)
|
|||
int
|
||||
checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
|
||||
{
|
||||
__u32 len = smb->smb_buf_length;
|
||||
__u32 len = be32_to_cpu(smb->smb_buf_length);
|
||||
__u32 clc_len; /* calculated length */
|
||||
cFYI(0, "checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len);
|
||||
|
||||
|
@ -464,7 +462,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
|
|||
|
||||
if (check_smb_hdr(smb, mid))
|
||||
return 1;
|
||||
clc_len = smbCalcSize_LE(smb);
|
||||
clc_len = smbCalcSize(smb);
|
||||
|
||||
if (4 + len != length) {
|
||||
cERROR(1, "Length read does not match RFC1001 length %d",
|
||||
|
@ -521,7 +519,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
|
|||
(struct smb_com_transaction_change_notify_rsp *)buf;
|
||||
struct file_notify_information *pnotify;
|
||||
__u32 data_offset = 0;
|
||||
if (get_bcc_le(buf) > sizeof(struct file_notify_information)) {
|
||||
if (get_bcc(buf) > sizeof(struct file_notify_information)) {
|
||||
data_offset = le32_to_cpu(pSMBr->DataOffset);
|
||||
|
||||
pnotify = (struct file_notify_information *)
|
||||
|
|
|
@ -919,13 +919,6 @@ smbCalcSize(struct smb_hdr *ptr)
|
|||
2 /* size of the bcc field */ + get_bcc(ptr));
|
||||
}
|
||||
|
||||
unsigned int
|
||||
smbCalcSize_LE(struct smb_hdr *ptr)
|
||||
{
|
||||
return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
|
||||
2 /* size of the bcc field */ + get_bcc_le(ptr));
|
||||
}
|
||||
|
||||
/* The following are taken from fs/ntfs/util.c */
|
||||
|
||||
#define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000)
|
||||
|
|
|
@ -621,7 +621,7 @@ ssetup_ntlmssp_authenticate:
|
|||
and rest of bcc area. This allows us to avoid
|
||||
a large buffer 17K allocation */
|
||||
iov[0].iov_base = (char *)pSMB;
|
||||
iov[0].iov_len = smb_buf->smb_buf_length + 4;
|
||||
iov[0].iov_len = be32_to_cpu(smb_buf->smb_buf_length) + 4;
|
||||
|
||||
/* setting this here allows the code at the end of the function
|
||||
to free the request buffer if there's an error */
|
||||
|
@ -656,7 +656,7 @@ ssetup_ntlmssp_authenticate:
|
|||
* to use challenge/response method (i.e. Password bit is 1).
|
||||
*/
|
||||
|
||||
calc_lanman_hash(ses->password, ses->server->cryptkey,
|
||||
rc = calc_lanman_hash(ses->password, ses->server->cryptkey,
|
||||
ses->server->secMode & SECMODE_PW_ENCRYPT ?
|
||||
true : false, lnm_session_key);
|
||||
|
||||
|
@ -859,9 +859,10 @@ ssetup_ntlmssp_authenticate:
|
|||
iov[2].iov_len = (long) bcc_ptr - (long) str_area;
|
||||
|
||||
count = iov[1].iov_len + iov[2].iov_len;
|
||||
smb_buf->smb_buf_length += count;
|
||||
smb_buf->smb_buf_length =
|
||||
cpu_to_be32(be32_to_cpu(smb_buf->smb_buf_length) + count);
|
||||
|
||||
put_bcc_le(count, smb_buf);
|
||||
put_bcc(count, smb_buf);
|
||||
|
||||
rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type,
|
||||
CIFS_LOG_ERROR);
|
||||
|
|
418
fs/cifs/smbdes.c
418
fs/cifs/smbdes.c
|
@ -1,418 +0,0 @@
|
|||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 1.9.
|
||||
|
||||
a partial implementation of DES designed for use in the
|
||||
SMB authentication protocol
|
||||
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
Modified by Steve French (sfrench@us.ibm.com) 2002,2004
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* NOTES:
|
||||
|
||||
This code makes no attempt to be fast! In fact, it is a very
|
||||
slow implementation
|
||||
|
||||
This code is NOT a complete DES implementation. It implements only
|
||||
the minimum necessary for SMB authentication, as used by all SMB
|
||||
products (including every copy of Microsoft Windows95 ever sold)
|
||||
|
||||
In particular, it can only do a unchained forward DES pass. This
|
||||
means it is not possible to use this code for encryption/decryption
|
||||
of data, instead it is only useful as a "hash" algorithm.
|
||||
|
||||
There is no entry point into this code that allows normal DES operation.
|
||||
|
||||
I believe this means that this code does not come under ITAR
|
||||
regulations but this is NOT a legal opinion. If you are concerned
|
||||
about the applicability of ITAR regulations to this code then you
|
||||
should confirm it for yourself (and maybe let me know if you come
|
||||
up with a different answer to the one above)
|
||||
*/
|
||||
#include <linux/slab.h>
|
||||
#define uchar unsigned char
|
||||
|
||||
static uchar perm1[56] = { 57, 49, 41, 33, 25, 17, 9,
|
||||
1, 58, 50, 42, 34, 26, 18,
|
||||
10, 2, 59, 51, 43, 35, 27,
|
||||
19, 11, 3, 60, 52, 44, 36,
|
||||
63, 55, 47, 39, 31, 23, 15,
|
||||
7, 62, 54, 46, 38, 30, 22,
|
||||
14, 6, 61, 53, 45, 37, 29,
|
||||
21, 13, 5, 28, 20, 12, 4
|
||||
};
|
||||
|
||||
static uchar perm2[48] = { 14, 17, 11, 24, 1, 5,
|
||||
3, 28, 15, 6, 21, 10,
|
||||
23, 19, 12, 4, 26, 8,
|
||||
16, 7, 27, 20, 13, 2,
|
||||
41, 52, 31, 37, 47, 55,
|
||||
30, 40, 51, 45, 33, 48,
|
||||
44, 49, 39, 56, 34, 53,
|
||||
46, 42, 50, 36, 29, 32
|
||||
};
|
||||
|
||||
static uchar perm3[64] = { 58, 50, 42, 34, 26, 18, 10, 2,
|
||||
60, 52, 44, 36, 28, 20, 12, 4,
|
||||
62, 54, 46, 38, 30, 22, 14, 6,
|
||||
64, 56, 48, 40, 32, 24, 16, 8,
|
||||
57, 49, 41, 33, 25, 17, 9, 1,
|
||||
59, 51, 43, 35, 27, 19, 11, 3,
|
||||
61, 53, 45, 37, 29, 21, 13, 5,
|
||||
63, 55, 47, 39, 31, 23, 15, 7
|
||||
};
|
||||
|
||||
static uchar perm4[48] = { 32, 1, 2, 3, 4, 5,
|
||||
4, 5, 6, 7, 8, 9,
|
||||
8, 9, 10, 11, 12, 13,
|
||||
12, 13, 14, 15, 16, 17,
|
||||
16, 17, 18, 19, 20, 21,
|
||||
20, 21, 22, 23, 24, 25,
|
||||
24, 25, 26, 27, 28, 29,
|
||||
28, 29, 30, 31, 32, 1
|
||||
};
|
||||
|
||||
static uchar perm5[32] = { 16, 7, 20, 21,
|
||||
29, 12, 28, 17,
|
||||
1, 15, 23, 26,
|
||||
5, 18, 31, 10,
|
||||
2, 8, 24, 14,
|
||||
32, 27, 3, 9,
|
||||
19, 13, 30, 6,
|
||||
22, 11, 4, 25
|
||||
};
|
||||
|
||||
static uchar perm6[64] = { 40, 8, 48, 16, 56, 24, 64, 32,
|
||||
39, 7, 47, 15, 55, 23, 63, 31,
|
||||
38, 6, 46, 14, 54, 22, 62, 30,
|
||||
37, 5, 45, 13, 53, 21, 61, 29,
|
||||
36, 4, 44, 12, 52, 20, 60, 28,
|
||||
35, 3, 43, 11, 51, 19, 59, 27,
|
||||
34, 2, 42, 10, 50, 18, 58, 26,
|
||||
33, 1, 41, 9, 49, 17, 57, 25
|
||||
};
|
||||
|
||||
static uchar sc[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
|
||||
|
||||
static uchar sbox[8][4][16] = {
|
||||
{{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
|
||||
{0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
|
||||
{4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
|
||||
{15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13} },
|
||||
|
||||
{{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
|
||||
{3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
|
||||
{0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
|
||||
{13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9} },
|
||||
|
||||
{{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
|
||||
{13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
|
||||
{13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
|
||||
{1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12} },
|
||||
|
||||
{{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
|
||||
{13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
|
||||
{10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
|
||||
{3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14} },
|
||||
|
||||
{{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
|
||||
{14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
|
||||
{4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
|
||||
{11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3} },
|
||||
|
||||
{{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
|
||||
{10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
|
||||
{9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
|
||||
{4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13} },
|
||||
|
||||
{{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
|
||||
{13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
|
||||
{1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
|
||||
{6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12} },
|
||||
|
||||
{{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
|
||||
{1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
|
||||
{7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
|
||||
{2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11} }
|
||||
};
|
||||
|
||||
static void
|
||||
permute(char *out, char *in, uchar *p, int n)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n; i++)
|
||||
out[i] = in[p[i] - 1];
|
||||
}
|
||||
|
||||
static void
|
||||
lshift(char *d, int count, int n)
|
||||
{
|
||||
char out[64];
|
||||
int i;
|
||||
for (i = 0; i < n; i++)
|
||||
out[i] = d[(i + count) % n];
|
||||
for (i = 0; i < n; i++)
|
||||
d[i] = out[i];
|
||||
}
|
||||
|
||||
static void
|
||||
concat(char *out, char *in1, char *in2, int l1, int l2)
|
||||
{
|
||||
while (l1--)
|
||||
*out++ = *in1++;
|
||||
while (l2--)
|
||||
*out++ = *in2++;
|
||||
}
|
||||
|
||||
static void
|
||||
xor(char *out, char *in1, char *in2, int n)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n; i++)
|
||||
out[i] = in1[i] ^ in2[i];
|
||||
}
|
||||
|
||||
static void
|
||||
dohash(char *out, char *in, char *key, int forw)
|
||||
{
|
||||
int i, j, k;
|
||||
char *pk1;
|
||||
char c[28];
|
||||
char d[28];
|
||||
char *cd;
|
||||
char (*ki)[48];
|
||||
char *pd1;
|
||||
char l[32], r[32];
|
||||
char *rl;
|
||||
|
||||
/* Have to reduce stack usage */
|
||||
pk1 = kmalloc(56+56+64+64, GFP_KERNEL);
|
||||
if (pk1 == NULL)
|
||||
return;
|
||||
|
||||
ki = kmalloc(16*48, GFP_KERNEL);
|
||||
if (ki == NULL) {
|
||||
kfree(pk1);
|
||||
return;
|
||||
}
|
||||
|
||||
cd = pk1 + 56;
|
||||
pd1 = cd + 56;
|
||||
rl = pd1 + 64;
|
||||
|
||||
permute(pk1, key, perm1, 56);
|
||||
|
||||
for (i = 0; i < 28; i++)
|
||||
c[i] = pk1[i];
|
||||
for (i = 0; i < 28; i++)
|
||||
d[i] = pk1[i + 28];
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
lshift(c, sc[i], 28);
|
||||
lshift(d, sc[i], 28);
|
||||
|
||||
concat(cd, c, d, 28, 28);
|
||||
permute(ki[i], cd, perm2, 48);
|
||||
}
|
||||
|
||||
permute(pd1, in, perm3, 64);
|
||||
|
||||
for (j = 0; j < 32; j++) {
|
||||
l[j] = pd1[j];
|
||||
r[j] = pd1[j + 32];
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
char *er; /* er[48] */
|
||||
char *erk; /* erk[48] */
|
||||
char b[8][6];
|
||||
char *cb; /* cb[32] */
|
||||
char *pcb; /* pcb[32] */
|
||||
char *r2; /* r2[32] */
|
||||
|
||||
er = kmalloc(48+48+32+32+32, GFP_KERNEL);
|
||||
if (er == NULL) {
|
||||
kfree(pk1);
|
||||
kfree(ki);
|
||||
return;
|
||||
}
|
||||
erk = er+48;
|
||||
cb = erk+48;
|
||||
pcb = cb+32;
|
||||
r2 = pcb+32;
|
||||
|
||||
permute(er, r, perm4, 48);
|
||||
|
||||
xor(erk, er, ki[forw ? i : 15 - i], 48);
|
||||
|
||||
for (j = 0; j < 8; j++)
|
||||
for (k = 0; k < 6; k++)
|
||||
b[j][k] = erk[j * 6 + k];
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
int m, n;
|
||||
m = (b[j][0] << 1) | b[j][5];
|
||||
|
||||
n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] <<
|
||||
1) | b[j][4];
|
||||
|
||||
for (k = 0; k < 4; k++)
|
||||
b[j][k] =
|
||||
(sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0;
|
||||
}
|
||||
|
||||
for (j = 0; j < 8; j++)
|
||||
for (k = 0; k < 4; k++)
|
||||
cb[j * 4 + k] = b[j][k];
|
||||
permute(pcb, cb, perm5, 32);
|
||||
|
||||
xor(r2, l, pcb, 32);
|
||||
|
||||
for (j = 0; j < 32; j++)
|
||||
l[j] = r[j];
|
||||
|
||||
for (j = 0; j < 32; j++)
|
||||
r[j] = r2[j];
|
||||
|
||||
kfree(er);
|
||||
}
|
||||
|
||||
concat(rl, r, l, 32, 32);
|
||||
|
||||
permute(out, rl, perm6, 64);
|
||||
kfree(pk1);
|
||||
kfree(ki);
|
||||
}
|
||||
|
||||
static void
|
||||
str_to_key(unsigned char *str, unsigned char *key)
|
||||
{
|
||||
int i;
|
||||
|
||||
key[0] = str[0] >> 1;
|
||||
key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2);
|
||||
key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3);
|
||||
key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4);
|
||||
key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5);
|
||||
key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6);
|
||||
key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7);
|
||||
key[7] = str[6] & 0x7F;
|
||||
for (i = 0; i < 8; i++)
|
||||
key[i] = (key[i] << 1);
|
||||
}
|
||||
|
||||
static void
|
||||
smbhash(unsigned char *out, const unsigned char *in, unsigned char *key,
|
||||
int forw)
|
||||
{
|
||||
int i;
|
||||
char *outb; /* outb[64] */
|
||||
char *inb; /* inb[64] */
|
||||
char *keyb; /* keyb[64] */
|
||||
unsigned char key2[8];
|
||||
|
||||
outb = kmalloc(64 * 3, GFP_KERNEL);
|
||||
if (outb == NULL)
|
||||
return;
|
||||
|
||||
inb = outb + 64;
|
||||
keyb = inb + 64;
|
||||
|
||||
str_to_key(key, key2);
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
|
||||
keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
|
||||
outb[i] = 0;
|
||||
}
|
||||
|
||||
dohash(outb, inb, keyb, forw);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
out[i] = 0;
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
if (outb[i])
|
||||
out[i / 8] |= (1 << (7 - (i % 8)));
|
||||
}
|
||||
kfree(outb);
|
||||
}
|
||||
|
||||
void
|
||||
E_P16(unsigned char *p14, unsigned char *p16)
|
||||
{
|
||||
unsigned char sp8[8] =
|
||||
{ 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
|
||||
smbhash(p16, sp8, p14, 1);
|
||||
smbhash(p16 + 8, sp8, p14 + 7, 1);
|
||||
}
|
||||
|
||||
void
|
||||
E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24)
|
||||
{
|
||||
smbhash(p24, c8, p21, 1);
|
||||
smbhash(p24 + 8, c8, p21 + 7, 1);
|
||||
smbhash(p24 + 16, c8, p21 + 14, 1);
|
||||
}
|
||||
|
||||
#if 0 /* currently unused */
|
||||
static void
|
||||
D_P16(unsigned char *p14, unsigned char *in, unsigned char *out)
|
||||
{
|
||||
smbhash(out, in, p14, 0);
|
||||
smbhash(out + 8, in + 8, p14 + 7, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out)
|
||||
{
|
||||
smbhash(out, in, p14, 1);
|
||||
smbhash(out + 8, in + 8, p14 + 7, 1);
|
||||
}
|
||||
/* these routines are currently unneeded, but may be
|
||||
needed later */
|
||||
void
|
||||
cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key)
|
||||
{
|
||||
unsigned char buf[8];
|
||||
|
||||
smbhash(buf, in, key, 1);
|
||||
smbhash(out, buf, key + 9, 1);
|
||||
}
|
||||
|
||||
void
|
||||
cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key)
|
||||
{
|
||||
unsigned char buf[8];
|
||||
static unsigned char key2[8];
|
||||
|
||||
smbhash(buf, in, key, 1);
|
||||
key2[0] = key[7];
|
||||
smbhash(out, buf, key2, 1);
|
||||
}
|
||||
|
||||
void
|
||||
cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
|
||||
{
|
||||
static unsigned char key2[8];
|
||||
|
||||
smbhash(out, in, key, forw);
|
||||
key2[0] = key[7];
|
||||
smbhash(out + 8, in + 8, key2, forw);
|
||||
}
|
||||
#endif /* unneeded routines */
|
|
@ -47,6 +47,88 @@
|
|||
#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
|
||||
#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val)))
|
||||
|
||||
static void
|
||||
str_to_key(unsigned char *str, unsigned char *key)
|
||||
{
|
||||
int i;
|
||||
|
||||
key[0] = str[0] >> 1;
|
||||
key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2);
|
||||
key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3);
|
||||
key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4);
|
||||
key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5);
|
||||
key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6);
|
||||
key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7);
|
||||
key[7] = str[6] & 0x7F;
|
||||
for (i = 0; i < 8; i++)
|
||||
key[i] = (key[i] << 1);
|
||||
}
|
||||
|
||||
static int
|
||||
smbhash(unsigned char *out, const unsigned char *in, unsigned char *key)
|
||||
{
|
||||
int rc;
|
||||
unsigned char key2[8];
|
||||
struct crypto_blkcipher *tfm_des;
|
||||
struct scatterlist sgin, sgout;
|
||||
struct blkcipher_desc desc;
|
||||
|
||||
str_to_key(key, key2);
|
||||
|
||||
tfm_des = crypto_alloc_blkcipher("ecb(des)", 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(tfm_des)) {
|
||||
rc = PTR_ERR(tfm_des);
|
||||
cERROR(1, "could not allocate des crypto API\n");
|
||||
goto smbhash_err;
|
||||
}
|
||||
|
||||
desc.tfm = tfm_des;
|
||||
|
||||
crypto_blkcipher_setkey(tfm_des, key2, 8);
|
||||
|
||||
sg_init_one(&sgin, in, 8);
|
||||
sg_init_one(&sgout, out, 8);
|
||||
|
||||
rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, 8);
|
||||
if (rc) {
|
||||
cERROR(1, "could not encrypt crypt key rc: %d\n", rc);
|
||||
crypto_free_blkcipher(tfm_des);
|
||||
goto smbhash_err;
|
||||
}
|
||||
|
||||
smbhash_err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
E_P16(unsigned char *p14, unsigned char *p16)
|
||||
{
|
||||
int rc;
|
||||
unsigned char sp8[8] =
|
||||
{ 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
|
||||
|
||||
rc = smbhash(p16, sp8, p14);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = smbhash(p16 + 8, sp8, p14 + 7);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = smbhash(p24, c8, p21);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = smbhash(p24 + 8, c8, p21 + 7);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = smbhash(p24 + 16, c8, p21 + 14);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* produce a md4 message digest from data of length n bytes */
|
||||
int
|
||||
mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len)
|
||||
|
@ -87,40 +169,30 @@ mdfour_err:
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* Does the des encryption from the NT or LM MD4 hash. */
|
||||
static void
|
||||
SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8,
|
||||
unsigned char p24[24])
|
||||
{
|
||||
unsigned char p21[21];
|
||||
|
||||
memset(p21, '\0', 21);
|
||||
|
||||
memcpy(p21, passwd, 16);
|
||||
E_P24(p21, c8, p24);
|
||||
}
|
||||
|
||||
/*
|
||||
This implements the X/Open SMB password encryption
|
||||
It takes a password, a 8 byte "crypt key" and puts 24 bytes of
|
||||
encrypted password into p24 */
|
||||
/* Note that password must be uppercased and null terminated */
|
||||
void
|
||||
int
|
||||
SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24)
|
||||
{
|
||||
unsigned char p14[15], p21[21];
|
||||
int rc;
|
||||
unsigned char p14[14], p16[16], p21[21];
|
||||
|
||||
memset(p21, '\0', 21);
|
||||
memset(p14, '\0', 14);
|
||||
strncpy((char *) p14, (char *) passwd, 14);
|
||||
memset(p16, '\0', 16);
|
||||
memset(p21, '\0', 21);
|
||||
|
||||
/* strupper((char *)p14); *//* BB at least uppercase the easy range */
|
||||
E_P16(p14, p21);
|
||||
memcpy(p14, passwd, 14);
|
||||
rc = E_P16(p14, p16);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
SMBOWFencrypt(p21, c8, p24);
|
||||
memcpy(p21, p16, 16);
|
||||
rc = E_P24(p21, c8, p24);
|
||||
|
||||
memset(p14, 0, 15);
|
||||
memset(p21, 0, 21);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Routines for Windows NT MD4 Hash functions. */
|
||||
|
@ -279,16 +351,18 @@ int
|
|||
SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
|
||||
{
|
||||
int rc;
|
||||
unsigned char p21[21];
|
||||
unsigned char p16[16], p21[21];
|
||||
|
||||
memset(p16, '\0', 16);
|
||||
memset(p21, '\0', 21);
|
||||
|
||||
rc = E_md4hash(passwd, p21);
|
||||
rc = E_md4hash(passwd, p16);
|
||||
if (rc) {
|
||||
cFYI(1, "%s Can't generate NT hash, error: %d", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
SMBOWFencrypt(p21, c8, p24);
|
||||
memcpy(p21, p16, 16);
|
||||
rc = E_P24(p21, c8, p24);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
|
|||
unsigned int len = iov[0].iov_len;
|
||||
unsigned int total_len;
|
||||
int first_vec = 0;
|
||||
unsigned int smb_buf_length = smb_buffer->smb_buf_length;
|
||||
unsigned int smb_buf_length = be32_to_cpu(smb_buffer->smb_buf_length);
|
||||
struct socket *ssocket = server->ssocket;
|
||||
|
||||
if (ssocket == NULL)
|
||||
|
@ -144,17 +144,10 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
|
|||
else
|
||||
smb_msg.msg_flags = MSG_NOSIGNAL;
|
||||
|
||||
/* smb header is converted in header_assemble. bcc and rest of SMB word
|
||||
area, and byte area if necessary, is converted to littleendian in
|
||||
cifssmb.c and RFC1001 len is converted to bigendian in smb_send
|
||||
Flags2 is converted in SendReceive */
|
||||
|
||||
|
||||
total_len = 0;
|
||||
for (i = 0; i < n_vec; i++)
|
||||
total_len += iov[i].iov_len;
|
||||
|
||||
smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
|
||||
cFYI(1, "Sending smb: total_len %d", total_len);
|
||||
dump_smb(smb_buffer, len);
|
||||
|
||||
|
@ -243,7 +236,7 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
|
|||
|
||||
/* Don't want to modify the buffer as a
|
||||
side effect of this call. */
|
||||
smb_buffer->smb_buf_length = smb_buf_length;
|
||||
smb_buffer->smb_buf_length = cpu_to_be32(smb_buf_length);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -387,7 +380,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
|
|||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_inc(&server->inSend);
|
||||
#endif
|
||||
rc = smb_send(server, in_buf, in_buf->smb_buf_length);
|
||||
rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_dec(&server->inSend);
|
||||
mid->when_sent = jiffies;
|
||||
|
@ -422,7 +415,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
int resp_buf_type;
|
||||
|
||||
iov[0].iov_base = (char *)in_buf;
|
||||
iov[0].iov_len = in_buf->smb_buf_length + 4;
|
||||
iov[0].iov_len = be32_to_cpu(in_buf->smb_buf_length) + 4;
|
||||
flags |= CIFS_NO_RESP;
|
||||
rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
|
||||
cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc);
|
||||
|
@ -488,10 +481,10 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
|
|||
int rc = 0;
|
||||
|
||||
/* -4 for RFC1001 length and +2 for BCC field */
|
||||
in_buf->smb_buf_length = sizeof(struct smb_hdr) - 4 + 2;
|
||||
in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2);
|
||||
in_buf->Command = SMB_COM_NT_CANCEL;
|
||||
in_buf->WordCount = 0;
|
||||
put_bcc_le(0, in_buf);
|
||||
put_bcc(0, in_buf);
|
||||
|
||||
mutex_lock(&server->srv_mutex);
|
||||
rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
|
||||
|
@ -499,7 +492,7 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
|
|||
mutex_unlock(&server->srv_mutex);
|
||||
return rc;
|
||||
}
|
||||
rc = smb_send(server, in_buf, in_buf->smb_buf_length);
|
||||
rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
|
||||
mutex_unlock(&server->srv_mutex);
|
||||
|
||||
cFYI(1, "issued NT_CANCEL for mid %u, rc = %d",
|
||||
|
@ -612,7 +605,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
return rc;
|
||||
}
|
||||
|
||||
receive_len = midQ->resp_buf->smb_buf_length;
|
||||
receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length);
|
||||
|
||||
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
|
||||
cERROR(1, "Frame too large received. Length: %d Xid: %d",
|
||||
|
@ -651,11 +644,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
rc = map_smb_to_linux_error(midQ->resp_buf,
|
||||
flags & CIFS_LOG_ERROR);
|
||||
|
||||
/* convert ByteCount if necessary */
|
||||
if (receive_len >= sizeof(struct smb_hdr) - 4
|
||||
/* do not count RFC1001 header */ +
|
||||
(2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
|
||||
put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf);
|
||||
if ((flags & CIFS_NO_RESP) == 0)
|
||||
midQ->resp_buf = NULL; /* mark it so buf will
|
||||
not be freed by
|
||||
|
@ -698,9 +686,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
to the same server. We may make this configurable later or
|
||||
use ses->maxReq */
|
||||
|
||||
if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||
if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize +
|
||||
MAX_CIFS_HDR_SIZE - 4) {
|
||||
cERROR(1, "Illegal length, greater than maximum frame, %d",
|
||||
in_buf->smb_buf_length);
|
||||
be32_to_cpu(in_buf->smb_buf_length));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -733,7 +722,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_inc(&ses->server->inSend);
|
||||
#endif
|
||||
rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
|
||||
rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_dec(&ses->server->inSend);
|
||||
midQ->when_sent = jiffies;
|
||||
|
@ -768,7 +757,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
return rc;
|
||||
}
|
||||
|
||||
receive_len = midQ->resp_buf->smb_buf_length;
|
||||
receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length);
|
||||
|
||||
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
|
||||
cERROR(1, "Frame too large received. Length: %d Xid: %d",
|
||||
|
@ -781,7 +770,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
|
||||
if (midQ->resp_buf && out_buf
|
||||
&& (midQ->midState == MID_RESPONSE_RECEIVED)) {
|
||||
out_buf->smb_buf_length = receive_len;
|
||||
out_buf->smb_buf_length = cpu_to_be32(receive_len);
|
||||
memcpy((char *)out_buf + 4,
|
||||
(char *)midQ->resp_buf + 4,
|
||||
receive_len);
|
||||
|
@ -800,16 +789,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
}
|
||||
}
|
||||
|
||||
*pbytes_returned = out_buf->smb_buf_length;
|
||||
*pbytes_returned = be32_to_cpu(out_buf->smb_buf_length);
|
||||
|
||||
/* BB special case reconnect tid and uid here? */
|
||||
rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
|
||||
|
||||
/* convert ByteCount if necessary */
|
||||
if (receive_len >= sizeof(struct smb_hdr) - 4
|
||||
/* do not count RFC1001 header */ +
|
||||
(2 * out_buf->WordCount) + 2 /* bcc */ )
|
||||
put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf);
|
||||
} else {
|
||||
rc = -EIO;
|
||||
cERROR(1, "Bad MID state?");
|
||||
|
@ -877,9 +860,10 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
|||
to the same server. We may make this configurable later or
|
||||
use ses->maxReq */
|
||||
|
||||
if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||
if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize +
|
||||
MAX_CIFS_HDR_SIZE - 4) {
|
||||
cERROR(1, "Illegal length, greater than maximum frame, %d",
|
||||
in_buf->smb_buf_length);
|
||||
be32_to_cpu(in_buf->smb_buf_length));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -910,7 +894,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
|||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_inc(&ses->server->inSend);
|
||||
#endif
|
||||
rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
|
||||
rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_dec(&ses->server->inSend);
|
||||
midQ->when_sent = jiffies;
|
||||
|
@ -977,7 +961,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
|||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
receive_len = midQ->resp_buf->smb_buf_length;
|
||||
receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length);
|
||||
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
|
||||
cERROR(1, "Frame too large received. Length: %d Xid: %d",
|
||||
receive_len, xid);
|
||||
|
@ -993,7 +977,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
|||
goto out;
|
||||
}
|
||||
|
||||
out_buf->smb_buf_length = receive_len;
|
||||
out_buf->smb_buf_length = cpu_to_be32(receive_len);
|
||||
memcpy((char *)out_buf + 4,
|
||||
(char *)midQ->resp_buf + 4,
|
||||
receive_len);
|
||||
|
@ -1012,17 +996,11 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
|||
}
|
||||
}
|
||||
|
||||
*pbytes_returned = out_buf->smb_buf_length;
|
||||
*pbytes_returned = be32_to_cpu(out_buf->smb_buf_length);
|
||||
|
||||
/* BB special case reconnect tid and uid here? */
|
||||
rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
|
||||
|
||||
/* convert ByteCount if necessary */
|
||||
if (receive_len >= sizeof(struct smb_hdr) - 4
|
||||
/* do not count RFC1001 header */ +
|
||||
(2 * out_buf->WordCount) + 2 /* bcc */ )
|
||||
put_bcc(get_bcc_le(out_buf), out_buf);
|
||||
|
||||
out:
|
||||
delete_mid(midQ);
|
||||
if (rstart && rc == -EACCES)
|
||||
|
|
|
@ -112,6 +112,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
|
|||
struct cifsTconInfo *pTcon;
|
||||
struct super_block *sb;
|
||||
char *full_path;
|
||||
struct cifs_ntsd *pacl;
|
||||
|
||||
if (direntry == NULL)
|
||||
return -EIO;
|
||||
|
@ -166,6 +167,25 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
|
|||
rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
|
||||
(__u16)value_size, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
} else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
|
||||
strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
|
||||
pacl = kmalloc(value_size, GFP_KERNEL);
|
||||
if (!pacl) {
|
||||
cFYI(1, "%s: Can't allocate memory for ACL",
|
||||
__func__);
|
||||
rc = -ENOMEM;
|
||||
} else {
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
memcpy(pacl, ea_value, value_size);
|
||||
rc = set_cifs_acl(pacl, value_size,
|
||||
direntry->d_inode, full_path);
|
||||
if (rc == 0) /* force revalidate of the inode */
|
||||
CIFS_I(direntry->d_inode)->time = 0;
|
||||
kfree(pacl);
|
||||
#else
|
||||
cFYI(1, "Set CIFS ACL not supported yet");
|
||||
#endif /* CONFIG_CIFS_ACL */
|
||||
}
|
||||
} else {
|
||||
int temp;
|
||||
temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
|
||||
|
|
|
@ -948,8 +948,7 @@ mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
|
|||
* filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE
|
||||
* but s_maxbytes was an unsigned long long for many releases. Throw
|
||||
* this warning for a little while to try and catch filesystems that
|
||||
* violate this rule. This warning should be either removed or
|
||||
* converted to a BUG() in 2.6.34.
|
||||
* violate this rule.
|
||||
*/
|
||||
WARN((sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "
|
||||
"negative value (%lld)\n", type->name, sb->s_maxbytes);
|
||||
|
|
Loading…
Reference in New Issue