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: (21 commits) [CIFS] fix oops on second mount to same server when null auth is used [CIFS] Fix stale mode after readdir when cifsacl specified [CIFS] add mode to acl conversion helper function [CIFS] Fix incorrect mode when ACL had deny access control entries [CIFS] Add uid to key description so krb can handle user mounts [CIFS] Fix walking out end of cifs dacl [CIFS] Add upcall files for cifs to use spnego/kerberos [CIFS] add OIDs for KRB5 and MSKRB5 to ASN1 parsing routines [CIFS] Register and unregister cifs_spnego_key_type on module init/exit [CIFS] implement upcalls for SPNEGO blob via keyctl API [CIFS] allow cifs_calc_signature2 to deal with a zero length iovec [CIFS] If no Access Control Entries, set mode perm bits to zero [CIFS] when mount helper missing fix slash wrong direction in share [CIFS] Don't request too much permission when reading an ACL [CIFS] enable get mode from ACL when cifsacl mount option specified [CIFS] ACL support part 8 [CIFS] acl support part 7 [CIFS] acl support part 6 [CIFS] acl support part 6 [CIFS] remove unused funtion compile warning when experimental off ...
This commit is contained in:
Коммит
46015977e7
|
@ -2007,7 +2007,7 @@ config CIFS_EXPERIMENTAL
|
|||
config CIFS_UPCALL
|
||||
bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
|
||||
depends on CIFS_EXPERIMENTAL
|
||||
depends on CONNECTOR
|
||||
depends on KEYS
|
||||
help
|
||||
Enables an upcall mechanism for CIFS which will be used to contact
|
||||
userspace helper utilities to provide SPNEGO packaged Kerberos
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
Version 1.52
|
||||
------------
|
||||
Fix oops on second mount to server when null auth is used.
|
||||
|
||||
Version 1.51
|
||||
------------
|
||||
Fix memory leak in statfs when mounted to very old servers (e.g.
|
||||
|
@ -12,7 +16,12 @@ leak that causes cifsd not to stop and rmmod to fail to cleanup
|
|||
cifs_request_buffers pool. Fix problem with POSIX Open/Mkdir on
|
||||
bigendian architectures. Fix possible memory corruption when
|
||||
EAGAIN returned on kern_recvmsg. Return better error if server
|
||||
requires packet signing but client has disabled it.
|
||||
requires packet signing but client has disabled it. When mounted
|
||||
with cifsacl mount option - mode bits are approximated based
|
||||
on the contents of the ACL of the file or directory. When cifs
|
||||
mount helper is missing convert make sure that UNC name
|
||||
has backslash (not forward slash) between ip address of server
|
||||
and the share name.
|
||||
|
||||
Version 1.50
|
||||
------------
|
||||
|
|
|
@ -3,4 +3,9 @@
|
|||
#
|
||||
obj-$(CONFIG_CIFS) += cifs.o
|
||||
|
||||
cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o export.o cifsacl.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 \
|
||||
md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o \
|
||||
readdir.o ioctl.o sess.o export.o cifsacl.o
|
||||
|
||||
cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
|
||||
|
|
|
@ -77,8 +77,12 @@
|
|||
|
||||
#define SPNEGO_OID_LEN 7
|
||||
#define NTLMSSP_OID_LEN 10
|
||||
#define KRB5_OID_LEN 7
|
||||
#define MSKRB5_OID_LEN 7
|
||||
static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 };
|
||||
static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 };
|
||||
static unsigned long KRB5_OID[7] = { 1, 2, 840, 113554, 1, 2, 2 };
|
||||
static unsigned long MSKRB5_OID[7] = { 1, 2, 840, 48018, 1, 2, 2 };
|
||||
|
||||
/*
|
||||
* ASN.1 context.
|
||||
|
@ -457,6 +461,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
|
|||
unsigned long *oid = NULL;
|
||||
unsigned int cls, con, tag, oidlen, rc;
|
||||
int use_ntlmssp = FALSE;
|
||||
int use_kerberos = FALSE;
|
||||
|
||||
*secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default*/
|
||||
|
||||
|
@ -545,18 +550,28 @@ decode_negTokenInit(unsigned char *security_blob, int length,
|
|||
return 0;
|
||||
}
|
||||
if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
|
||||
rc = asn1_oid_decode(&ctx, end, &oid, &oidlen);
|
||||
if (rc) {
|
||||
if (asn1_oid_decode(&ctx, end, &oid, &oidlen)) {
|
||||
|
||||
cFYI(1,
|
||||
("OID len = %d oid = 0x%lx 0x%lx "
|
||||
"0x%lx 0x%lx",
|
||||
oidlen, *oid, *(oid + 1),
|
||||
*(oid + 2), *(oid + 3)));
|
||||
rc = compare_oid(oid, oidlen,
|
||||
NTLMSSP_OID, NTLMSSP_OID_LEN);
|
||||
kfree(oid);
|
||||
if (rc)
|
||||
|
||||
if (compare_oid(oid, oidlen,
|
||||
MSKRB5_OID,
|
||||
MSKRB5_OID_LEN))
|
||||
use_kerberos = TRUE;
|
||||
else if (compare_oid(oid, oidlen,
|
||||
KRB5_OID,
|
||||
KRB5_OID_LEN))
|
||||
use_kerberos = TRUE;
|
||||
else if (compare_oid(oid, oidlen,
|
||||
NTLMSSP_OID,
|
||||
NTLMSSP_OID_LEN))
|
||||
use_ntlmssp = TRUE;
|
||||
|
||||
kfree(oid);
|
||||
}
|
||||
} else {
|
||||
cFYI(1, ("Should be an oid what is going on?"));
|
||||
|
@ -609,12 +624,10 @@ decode_negTokenInit(unsigned char *security_blob, int length,
|
|||
ctx.pointer)); /* is this UTF-8 or ASCII? */
|
||||
}
|
||||
|
||||
/* if (use_kerberos)
|
||||
*secType = Kerberos
|
||||
else */
|
||||
if (use_ntlmssp) {
|
||||
if (use_kerberos)
|
||||
*secType = Kerberos;
|
||||
else if (use_ntlmssp)
|
||||
*secType = NTLMSSP;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* fs/cifs/cifs_spnego.c -- SPNEGO upcall management for CIFS
|
||||
*
|
||||
* Copyright (c) 2007 Red Hat, Inc.
|
||||
* Author(s): Jeff Layton (jlayton@redhat.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/string.h>
|
||||
#include <keys/user-type.h>
|
||||
#include <linux/key-type.h>
|
||||
#include "cifsglob.h"
|
||||
#include "cifs_spnego.h"
|
||||
#include "cifs_debug.h"
|
||||
|
||||
/* create a new cifs key */
|
||||
static int
|
||||
cifs_spnego_key_instantiate(struct key *key, const void *data, size_t datalen)
|
||||
{
|
||||
char *payload;
|
||||
int ret;
|
||||
|
||||
ret = -ENOMEM;
|
||||
payload = kmalloc(datalen, GFP_KERNEL);
|
||||
if (!payload)
|
||||
goto error;
|
||||
|
||||
/* attach the data */
|
||||
memcpy(payload, data, datalen);
|
||||
rcu_assign_pointer(key->payload.data, payload);
|
||||
ret = 0;
|
||||
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
cifs_spnego_key_destroy(struct key *key)
|
||||
{
|
||||
kfree(key->payload.data);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* keytype for CIFS spnego keys
|
||||
*/
|
||||
struct key_type cifs_spnego_key_type = {
|
||||
.name = "cifs.spnego",
|
||||
.instantiate = cifs_spnego_key_instantiate,
|
||||
.match = user_match,
|
||||
.destroy = cifs_spnego_key_destroy,
|
||||
.describe = user_describe,
|
||||
};
|
||||
|
||||
/* get a key struct with a SPNEGO security blob, suitable for session setup */
|
||||
struct key *
|
||||
cifs_get_spnego_key(struct cifsSesInfo *sesInfo, const char *hostname)
|
||||
{
|
||||
struct TCP_Server_Info *server = sesInfo->server;
|
||||
char *description, *dp;
|
||||
size_t desc_len;
|
||||
struct key *spnego_key;
|
||||
|
||||
|
||||
/* version + ;ip{4|6}= + address + ;host=hostname +
|
||||
;sec= + ;uid= + NULL */
|
||||
desc_len = 4 + 5 + 32 + 1 + 5 + strlen(hostname) +
|
||||
strlen(";sec=krb5") + 7 + sizeof(uid_t)*2 + 1;
|
||||
spnego_key = ERR_PTR(-ENOMEM);
|
||||
description = kzalloc(desc_len, GFP_KERNEL);
|
||||
if (description == NULL)
|
||||
goto out;
|
||||
|
||||
dp = description;
|
||||
/* start with version and hostname portion of UNC string */
|
||||
spnego_key = ERR_PTR(-EINVAL);
|
||||
sprintf(dp, "0x%2.2x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION,
|
||||
hostname);
|
||||
dp = description + strlen(description);
|
||||
|
||||
/* add the server address */
|
||||
if (server->addr.sockAddr.sin_family == AF_INET)
|
||||
sprintf(dp, "ip4=" NIPQUAD_FMT,
|
||||
NIPQUAD(server->addr.sockAddr.sin_addr));
|
||||
else if (server->addr.sockAddr.sin_family == AF_INET6)
|
||||
sprintf(dp, "ip6=" NIP6_SEQFMT,
|
||||
NIP6(server->addr.sockAddr6.sin6_addr));
|
||||
else
|
||||
goto out;
|
||||
|
||||
dp = description + strlen(description);
|
||||
|
||||
/* for now, only sec=krb5 is valid */
|
||||
if (server->secType == Kerberos)
|
||||
sprintf(dp, ";sec=krb5");
|
||||
else
|
||||
goto out;
|
||||
|
||||
dp = description + strlen(description);
|
||||
sprintf(dp, ";uid=0x%x", sesInfo->linux_uid);
|
||||
|
||||
cFYI(1, ("key description = %s", description));
|
||||
spnego_key = request_key(&cifs_spnego_key_type, description, "");
|
||||
|
||||
if (cifsFYI && !IS_ERR(spnego_key)) {
|
||||
struct cifs_spnego_msg *msg = spnego_key->payload.data;
|
||||
cifs_dump_mem("SPNEGO reply blob:", msg->data,
|
||||
msg->secblob_len + msg->sesskey_len);
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(description);
|
||||
return spnego_key;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* fs/cifs/cifs_spnego.h -- SPNEGO upcall management for CIFS
|
||||
*
|
||||
* Copyright (c) 2007 Red Hat, Inc.
|
||||
* Author(s): Jeff Layton (jlayton@redhat.com)
|
||||
* Steve French (sfrench@us.ibm.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _CIFS_SPNEGO_H
|
||||
#define _CIFS_SPNEGO_H
|
||||
|
||||
#define CIFS_SPNEGO_UPCALL_VERSION 1
|
||||
|
||||
/*
|
||||
* The version field should always be set to CIFS_SPNEGO_UPCALL_VERSION.
|
||||
* The flags field is for future use. The request-key callout should set
|
||||
* sesskey_len and secblob_len, and then concatenate the SessKey+SecBlob
|
||||
* and stuff it in the data field.
|
||||
*/
|
||||
struct cifs_spnego_msg {
|
||||
uint32_t version;
|
||||
uint32_t flags;
|
||||
uint32_t sesskey_len;
|
||||
uint32_t secblob_len;
|
||||
uint8_t data[1];
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
extern struct key_type cifs_spnego_key_type;
|
||||
#endif /* KERNEL */
|
||||
|
||||
#endif /* _CIFS_SPNEGO_H */
|
|
@ -38,13 +38,13 @@ static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
|
|||
{{1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(18), 0, 0, 0, 0} }, "sys"},
|
||||
{{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(544), 0, 0, 0} }, "root"},
|
||||
{{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(545), 0, 0, 0} }, "users"},
|
||||
{{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(546), 0, 0, 0} }, "guest"}
|
||||
};
|
||||
{{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(546), 0, 0, 0} }, "guest"} }
|
||||
;
|
||||
|
||||
|
||||
/* security id for everyone */
|
||||
static const struct cifs_sid sid_everyone =
|
||||
{1, 1, {0, 0, 0, 0, 0, 0}, {} };
|
||||
static const struct cifs_sid sid_everyone = {
|
||||
1, 1, {0, 0, 0, 0, 0, 1}, {0} };
|
||||
/* group users */
|
||||
static const struct cifs_sid sid_user =
|
||||
{1, 2 , {0, 0, 0, 0, 0, 5}, {} };
|
||||
|
@ -97,7 +97,7 @@ int match_sid(struct cifs_sid *ctsid)
|
|||
|
||||
/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
|
||||
the same returns 1, if they do not match returns 0 */
|
||||
int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid)
|
||||
int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
|
||||
{
|
||||
int i;
|
||||
int num_subauth, num_sat, num_saw;
|
||||
|
@ -129,66 +129,142 @@ int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid)
|
|||
return (1); /* sids compare/match */
|
||||
}
|
||||
|
||||
/*
|
||||
change posix mode to reflect permissions
|
||||
pmode is the existing mode (we only want to overwrite part of this
|
||||
bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
|
||||
*/
|
||||
static void access_flags_to_mode(__u32 ace_flags, int type, umode_t *pmode,
|
||||
umode_t *pbits_to_set)
|
||||
{
|
||||
/* the order of ACEs is important. The canonical order is to begin with
|
||||
DENY entries followed by ALLOW, otherwise an allow entry could be
|
||||
encountered first, making the subsequent deny entry like "dead code"
|
||||
which would be superflous since Windows stops when a match is made
|
||||
for the operation you are trying to perform for your user */
|
||||
|
||||
static void parse_ace(struct cifs_ace *pace, char *end_of_acl)
|
||||
/* For deny ACEs we change the mask so that subsequent allow access
|
||||
control entries do not turn on the bits we are denying */
|
||||
if (type == ACCESS_DENIED) {
|
||||
if (ace_flags & GENERIC_ALL) {
|
||||
*pbits_to_set &= ~S_IRWXUGO;
|
||||
}
|
||||
if ((ace_flags & GENERIC_WRITE) ||
|
||||
((ace_flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
|
||||
*pbits_to_set &= ~S_IWUGO;
|
||||
if ((ace_flags & GENERIC_READ) ||
|
||||
((ace_flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
|
||||
*pbits_to_set &= ~S_IRUGO;
|
||||
if ((ace_flags & GENERIC_EXECUTE) ||
|
||||
((ace_flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
|
||||
*pbits_to_set &= ~S_IXUGO;
|
||||
return;
|
||||
} else if (type != ACCESS_ALLOWED) {
|
||||
cERROR(1, ("unknown access control type %d", type));
|
||||
return;
|
||||
}
|
||||
/* else ACCESS_ALLOWED type */
|
||||
|
||||
if (ace_flags & GENERIC_ALL) {
|
||||
*pmode |= (S_IRWXUGO & (*pbits_to_set));
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
cFYI(1, ("all perms"));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if ((ace_flags & GENERIC_WRITE) ||
|
||||
((ace_flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
|
||||
*pmode |= (S_IWUGO & (*pbits_to_set));
|
||||
if ((ace_flags & GENERIC_READ) ||
|
||||
((ace_flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
|
||||
*pmode |= (S_IRUGO & (*pbits_to_set));
|
||||
if ((ace_flags & GENERIC_EXECUTE) ||
|
||||
((ace_flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
|
||||
*pmode |= (S_IXUGO & (*pbits_to_set));
|
||||
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
cFYI(1, ("access flags 0x%x mode now 0x%x", ace_flags, *pmode));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Generate access flags to reflect permissions mode is the existing mode.
|
||||
This function is called for every ACE in the DACL whose SID matches
|
||||
with either owner or group or everyone.
|
||||
*/
|
||||
|
||||
static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
|
||||
__u32 *pace_flags)
|
||||
{
|
||||
/* reset access mask */
|
||||
*pace_flags = 0x0;
|
||||
|
||||
/* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
|
||||
mode &= bits_to_use;
|
||||
|
||||
/* check for R/W/X UGO since we do not know whose flags
|
||||
is this but we have cleared all the bits sans RWX for
|
||||
either user or group or other as per bits_to_use */
|
||||
if (mode & S_IRUGO)
|
||||
*pace_flags |= SET_FILE_READ_RIGHTS;
|
||||
if (mode & S_IWUGO)
|
||||
*pace_flags |= SET_FILE_WRITE_RIGHTS;
|
||||
if (mode & S_IXUGO)
|
||||
*pace_flags |= SET_FILE_EXEC_RIGHTS;
|
||||
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
cFYI(1, ("mode: 0x%x, access flags now 0x%x", mode, *pace_flags));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
|
||||
{
|
||||
int num_subauth;
|
||||
|
||||
/* validate that we do not go past end of acl */
|
||||
|
||||
/* XXX this if statement can be removed
|
||||
if (end_of_acl < (char *)pace + sizeof(struct cifs_ace)) {
|
||||
if (le16_to_cpu(pace->size) < 16) {
|
||||
cERROR(1, ("ACE too small, %d", le16_to_cpu(pace->size)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
|
||||
cERROR(1, ("ACL too small to parse ACE"));
|
||||
return;
|
||||
} */
|
||||
}
|
||||
|
||||
num_subauth = pace->num_subauth;
|
||||
num_subauth = pace->sid.num_subauth;
|
||||
if (num_subauth) {
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
int i;
|
||||
cFYI(1, ("ACE revision %d num_subauth %d",
|
||||
pace->revision, pace->num_subauth));
|
||||
cFYI(1, ("ACE revision %d num_auth %d type %d flags %d size %d",
|
||||
pace->sid.revision, pace->sid.num_subauth, pace->type,
|
||||
pace->flags, pace->size));
|
||||
for (i = 0; i < num_subauth; ++i) {
|
||||
cFYI(1, ("ACE sub_auth[%d]: 0x%x", i,
|
||||
le32_to_cpu(pace->sub_auth[i])));
|
||||
le32_to_cpu(pace->sid.sub_auth[i])));
|
||||
}
|
||||
|
||||
/* BB add length check to make sure that we do not have huge
|
||||
num auths and therefore go off the end */
|
||||
|
||||
cFYI(1, ("RID %d", le32_to_cpu(pace->sub_auth[num_subauth-1])));
|
||||
#endif
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void parse_ntace(struct cifs_ntace *pntace, char *end_of_acl)
|
||||
{
|
||||
/* validate that we do not go past end of acl */
|
||||
if (end_of_acl < (char *)pntace + sizeof(struct cifs_ntace)) {
|
||||
cERROR(1, ("ACL too small to parse NT ACE"));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
cFYI(1, ("NTACE type %d flags 0x%x size %d, access Req 0x%x",
|
||||
pntace->type, pntace->flags, pntace->size,
|
||||
pntace->access_req));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
||||
struct cifs_sid *pownersid, struct cifs_sid *pgrpsid)
|
||||
struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
|
||||
struct inode *inode)
|
||||
{
|
||||
int i;
|
||||
int num_aces = 0;
|
||||
int acl_size;
|
||||
char *acl_base;
|
||||
struct cifs_ntace **ppntace;
|
||||
struct cifs_ace **ppace;
|
||||
|
||||
/* BB need to add parm so we can store the SID BB */
|
||||
|
@ -205,50 +281,63 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
|||
le32_to_cpu(pdacl->num_aces)));
|
||||
#endif
|
||||
|
||||
/* reset rwx permissions for user/group/other.
|
||||
Also, if num_aces is 0 i.e. DACL has no ACEs,
|
||||
user/group/other have no permissions */
|
||||
inode->i_mode &= ~(S_IRWXUGO);
|
||||
|
||||
if (!pdacl) {
|
||||
/* no DACL in the security descriptor, set
|
||||
all the permissions for user/group/other */
|
||||
inode->i_mode |= S_IRWXUGO;
|
||||
return;
|
||||
}
|
||||
acl_base = (char *)pdacl;
|
||||
acl_size = sizeof(struct cifs_acl);
|
||||
|
||||
num_aces = le32_to_cpu(pdacl->num_aces);
|
||||
if (num_aces > 0) {
|
||||
ppntace = kmalloc(num_aces * sizeof(struct cifs_ntace *),
|
||||
GFP_KERNEL);
|
||||
umode_t user_mask = S_IRWXU;
|
||||
umode_t group_mask = S_IRWXG;
|
||||
umode_t other_mask = S_IRWXO;
|
||||
|
||||
ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
|
||||
GFP_KERNEL);
|
||||
|
||||
/* cifscred->cecount = pdacl->num_aces;
|
||||
cifscred->ntaces = kmalloc(num_aces *
|
||||
sizeof(struct cifs_ntace *), GFP_KERNEL);
|
||||
cifscred->aces = kmalloc(num_aces *
|
||||
sizeof(struct cifs_ace *), GFP_KERNEL);*/
|
||||
|
||||
for (i = 0; i < num_aces; ++i) {
|
||||
ppntace[i] = (struct cifs_ntace *)
|
||||
(acl_base + acl_size);
|
||||
ppace[i] = (struct cifs_ace *) ((char *)ppntace[i] +
|
||||
sizeof(struct cifs_ntace));
|
||||
ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
dump_ace(ppace[i], end_of_acl);
|
||||
#endif
|
||||
if (compare_sids(&(ppace[i]->sid), pownersid))
|
||||
access_flags_to_mode(ppace[i]->access_req,
|
||||
ppace[i]->type,
|
||||
&(inode->i_mode),
|
||||
&user_mask);
|
||||
if (compare_sids(&(ppace[i]->sid), pgrpsid))
|
||||
access_flags_to_mode(ppace[i]->access_req,
|
||||
ppace[i]->type,
|
||||
&(inode->i_mode),
|
||||
&group_mask);
|
||||
if (compare_sids(&(ppace[i]->sid), &sid_everyone))
|
||||
access_flags_to_mode(ppace[i]->access_req,
|
||||
ppace[i]->type,
|
||||
&(inode->i_mode),
|
||||
&other_mask);
|
||||
|
||||
parse_ntace(ppntace[i], end_of_acl);
|
||||
if (end_of_acl < ((char *)ppace[i] +
|
||||
(le16_to_cpu(ppntace[i]->size) -
|
||||
sizeof(struct cifs_ntace)))) {
|
||||
cERROR(1, ("ACL too small to parse ACE"));
|
||||
break;
|
||||
} else
|
||||
parse_ace(ppace[i], end_of_acl);
|
||||
|
||||
/* memcpy((void *)(&(cifscred->ntaces[i])),
|
||||
(void *)ppntace[i],
|
||||
sizeof(struct cifs_ntace));
|
||||
memcpy((void *)(&(cifscred->aces[i])),
|
||||
/* memcpy((void *)(&(cifscred->aces[i])),
|
||||
(void *)ppace[i],
|
||||
sizeof(struct cifs_ace)); */
|
||||
|
||||
acl_base = (char *)ppntace[i];
|
||||
acl_size = le16_to_cpu(ppntace[i]->size);
|
||||
acl_base = (char *)ppace[i];
|
||||
acl_size = le16_to_cpu(ppace[i]->size);
|
||||
}
|
||||
|
||||
kfree(ppace);
|
||||
kfree(ppntace);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -257,20 +346,20 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
|||
|
||||
static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
|
||||
{
|
||||
|
||||
/* BB need to add parm so we can store the SID BB */
|
||||
|
||||
/* validate that we do not go past end of acl */
|
||||
if (end_of_acl < (char *)psid + sizeof(struct cifs_sid)) {
|
||||
cERROR(1, ("ACL too small to parse SID"));
|
||||
/* validate that we do not go past end of ACL - sid must be at least 8
|
||||
bytes long (assuming no sub-auths - e.g. the null SID */
|
||||
if (end_of_acl < (char *)psid + 8) {
|
||||
cERROR(1, ("ACL too small to parse SID %p", psid));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (psid->num_subauth) {
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
int i;
|
||||
cFYI(1, ("SID revision %d num_auth %d First subauth 0x%x",
|
||||
psid->revision, psid->num_subauth, psid->sub_auth[0]));
|
||||
cFYI(1, ("SID revision %d num_auth %d",
|
||||
psid->revision, psid->num_subauth));
|
||||
|
||||
for (i = 0; i < psid->num_subauth; i++) {
|
||||
cFYI(1, ("SID sub_auth[%d]: 0x%x ", i,
|
||||
|
@ -289,27 +378,32 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
|
|||
|
||||
|
||||
/* Convert CIFS ACL to POSIX form */
|
||||
int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len)
|
||||
static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
|
||||
struct inode *inode)
|
||||
{
|
||||
int rc;
|
||||
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;
|
||||
__u32 dacloffset;
|
||||
|
||||
if ((inode == NULL) || (pntsd == NULL))
|
||||
return -EIO;
|
||||
|
||||
owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
||||
le32_to_cpu(pntsd->osidoffset));
|
||||
group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
||||
le32_to_cpu(pntsd->gsidoffset));
|
||||
dacl_ptr = (struct cifs_acl *)((char *)pntsd +
|
||||
le32_to_cpu(pntsd->dacloffset));
|
||||
dacloffset = le32_to_cpu(pntsd->dacloffset);
|
||||
dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
cFYI(1, ("revision %d type 0x%x ooffset 0x%x goffset 0x%x "
|
||||
"sacloffset 0x%x dacloffset 0x%x",
|
||||
pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
|
||||
le32_to_cpu(pntsd->gsidoffset),
|
||||
le32_to_cpu(pntsd->sacloffset),
|
||||
le32_to_cpu(pntsd->dacloffset)));
|
||||
le32_to_cpu(pntsd->sacloffset), dacloffset));
|
||||
#endif
|
||||
/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
|
||||
rc = parse_sid(owner_sid_ptr, end_of_acl);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
@ -318,16 +412,120 @@ int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, group_sid_ptr);
|
||||
if (dacloffset)
|
||||
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
|
||||
group_sid_ptr, inode);
|
||||
else
|
||||
cFYI(1, ("no ACL")); /* BB grant all or default perms? */
|
||||
|
||||
/* cifscred->uid = owner_sid_ptr->rid;
|
||||
cifscred->gid = group_sid_ptr->rid;
|
||||
memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
|
||||
sizeof (struct cifs_sid));
|
||||
sizeof(struct cifs_sid));
|
||||
memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
|
||||
sizeof (struct cifs_sid)); */
|
||||
sizeof(struct cifs_sid)); */
|
||||
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* Retrieve an ACL from the server */
|
||||
static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
|
||||
const char *path)
|
||||
{
|
||||
struct cifsFileInfo *open_file;
|
||||
int unlock_file = FALSE;
|
||||
int xid;
|
||||
int rc = -EIO;
|
||||
__u16 fid;
|
||||
struct super_block *sb;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifs_ntsd *pntsd = NULL;
|
||||
|
||||
cFYI(1, ("get mode from ACL for %s", path));
|
||||
|
||||
if (inode == NULL)
|
||||
return NULL;
|
||||
|
||||
xid = GetXid();
|
||||
open_file = find_readable_file(CIFS_I(inode));
|
||||
sb = inode->i_sb;
|
||||
if (sb == NULL) {
|
||||
FreeXid(xid);
|
||||
return NULL;
|
||||
}
|
||||
cifs_sb = CIFS_SB(sb);
|
||||
|
||||
if (open_file) {
|
||||
unlock_file = TRUE;
|
||||
fid = open_file->netfid;
|
||||
} else {
|
||||
int oplock = FALSE;
|
||||
/* open file */
|
||||
rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN,
|
||||
READ_CONTROL, 0, &fid, &oplock, NULL,
|
||||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc != 0) {
|
||||
cERROR(1, ("Unable to open file to get ACL"));
|
||||
FreeXid(xid);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
|
||||
cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen));
|
||||
if (unlock_file == TRUE)
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
else
|
||||
CIFSSMBClose(xid, cifs_sb->tcon, fid);
|
||||
|
||||
FreeXid(xid);
|
||||
return pntsd;
|
||||
}
|
||||
|
||||
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
|
||||
void acl_to_uid_mode(struct inode *inode, const char *path)
|
||||
{
|
||||
struct cifs_ntsd *pntsd = NULL;
|
||||
u32 acllen = 0;
|
||||
int rc = 0;
|
||||
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
cFYI(1, ("converting ACL to mode for %s", path));
|
||||
#endif
|
||||
pntsd = get_cifs_acl(&acllen, inode, path);
|
||||
|
||||
/* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
|
||||
if (pntsd)
|
||||
rc = parse_sec_desc(pntsd, acllen, inode);
|
||||
if (rc)
|
||||
cFYI(1, ("parse sec desc failed rc = %d", rc));
|
||||
|
||||
kfree(pntsd);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert mode bits to an ACL so we can update the ACL on the server */
|
||||
int mode_to_acl(struct inode *inode, const char *path)
|
||||
{
|
||||
int rc = 0;
|
||||
__u32 acllen = 0;
|
||||
struct cifs_ntsd *pntsd = NULL;
|
||||
|
||||
cFYI(1, ("set ACL from mode for %s", path));
|
||||
|
||||
/* Get the security descriptor */
|
||||
pntsd = get_cifs_acl(&acllen, inode, path);
|
||||
|
||||
/* Add/Modify the three ACEs for owner, group, everyone
|
||||
while retaining the other ACEs */
|
||||
|
||||
/* Set the security descriptor */
|
||||
|
||||
|
||||
kfree(pntsd);
|
||||
return rc;
|
||||
}
|
||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
||||
|
|
|
@ -35,6 +35,9 @@
|
|||
#define UBITSHIFT 6
|
||||
#define GBITSHIFT 3
|
||||
|
||||
#define ACCESS_ALLOWED 0
|
||||
#define ACCESS_DENIED 1
|
||||
|
||||
struct cifs_ntsd {
|
||||
__le16 revision; /* revision level */
|
||||
__le16 type;
|
||||
|
@ -48,7 +51,7 @@ struct cifs_sid {
|
|||
__u8 revision; /* revision level */
|
||||
__u8 num_subauth;
|
||||
__u8 authority[6];
|
||||
__le32 sub_auth[5]; /* sub_auth[num_subauth] */ /* BB FIXME endianness BB */
|
||||
__le32 sub_auth[5]; /* sub_auth[num_subauth] */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct cifs_acl {
|
||||
|
@ -57,18 +60,12 @@ struct cifs_acl {
|
|||
__le32 num_aces;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct cifs_ntace { /* first part of ACE which contains perms */
|
||||
struct cifs_ace {
|
||||
__u8 type;
|
||||
__u8 flags;
|
||||
__le16 size;
|
||||
__le32 access_req;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct cifs_ace { /* last part of ACE which includes user info */
|
||||
__u8 revision; /* revision level */
|
||||
__u8 num_subauth;
|
||||
__u8 authority[6];
|
||||
__le32 sub_auth[5];
|
||||
struct cifs_sid sid; /* ie UUID of user or group who gets these perms */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct cifs_wksid {
|
||||
|
@ -79,7 +76,7 @@ struct cifs_wksid {
|
|||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
|
||||
extern int match_sid(struct cifs_sid *);
|
||||
extern int compare_sids(struct cifs_sid *, struct cifs_sid *);
|
||||
extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *);
|
||||
|
||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
||||
|
||||
|
|
|
@ -99,15 +99,16 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
|
|||
MD5Init(&context);
|
||||
MD5Update(&context, (char *)&key->data, key->len);
|
||||
for (i = 0; i < n_vec; i++) {
|
||||
if (iov[i].iov_len == 0)
|
||||
continue;
|
||||
if (iov[i].iov_base == NULL) {
|
||||
cERROR(1, ("null iovec entry"));
|
||||
return -EIO;
|
||||
} else if (iov[i].iov_len == 0)
|
||||
break; /* bail out if we are sent nothing to sign */
|
||||
}
|
||||
/* The first entry includes a length field (which does not get
|
||||
signed that occupies the first 4 bytes before the header */
|
||||
if (i == 0) {
|
||||
if (iov[0].iov_len <= 8 ) /* cmd field at offset 9 */
|
||||
if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
|
||||
break; /* nothing to sign or corrupt header */
|
||||
MD5Update(&context, iov[0].iov_base+4,
|
||||
iov[0].iov_len-4);
|
||||
|
@ -122,7 +123,7 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
|
|||
|
||||
|
||||
int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
|
||||
__u32 * pexpected_response_sequence_number)
|
||||
__u32 *pexpected_response_sequence_number)
|
||||
{
|
||||
int rc = 0;
|
||||
char smb_signature[20];
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
#include "cifs_debug.h"
|
||||
#include "cifs_fs_sb.h"
|
||||
#include <linux/mm.h>
|
||||
#include <linux/key-type.h>
|
||||
#include "cifs_spnego.h"
|
||||
#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
|
||||
|
||||
#ifdef CONFIG_CIFS_QUOTA
|
||||
|
@ -1005,12 +1007,16 @@ init_cifs(void)
|
|||
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
|
||||
oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd");
|
||||
if (IS_ERR(oplockThread)) {
|
||||
rc = PTR_ERR(oplockThread);
|
||||
cERROR(1, ("error %d create oplock thread", rc));
|
||||
goto out_unregister_filesystem;
|
||||
goto out_unregister_key_type;
|
||||
}
|
||||
|
||||
dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
|
||||
|
@ -1024,7 +1030,11 @@ init_cifs(void)
|
|||
|
||||
out_stop_oplock_thread:
|
||||
kthread_stop(oplockThread);
|
||||
out_unregister_key_type:
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
unregister_key_type(&cifs_spnego_key_type);
|
||||
out_unregister_filesystem:
|
||||
#endif
|
||||
unregister_filesystem(&cifs_fs_type);
|
||||
out_destroy_request_bufs:
|
||||
cifs_destroy_request_bufs();
|
||||
|
@ -1045,6 +1055,9 @@ exit_cifs(void)
|
|||
cFYI(0, ("exit_cifs"));
|
||||
#ifdef CONFIG_PROC_FS
|
||||
cifs_proc_clean();
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
unregister_key_type(&cifs_spnego_key_type);
|
||||
#endif
|
||||
unregister_filesystem(&cifs_fs_type);
|
||||
cifs_destroy_inodecache();
|
||||
|
|
|
@ -106,5 +106,5 @@ extern int cifs_ioctl(struct inode *inode, struct file *filep,
|
|||
extern const struct export_operations cifs_export_ops;
|
||||
#endif /* EXPERIMENTAL */
|
||||
|
||||
#define CIFS_VERSION "1.51"
|
||||
#define CIFS_VERSION "1.52"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
|
|
@ -220,6 +220,23 @@
|
|||
| FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES)
|
||||
#define FILE_EXEC_RIGHTS (FILE_EXECUTE)
|
||||
|
||||
#define SET_FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA | FILE_WRITE_EA \
|
||||
| FILE_READ_ATTRIBUTES \
|
||||
| FILE_WRITE_ATTRIBUTES \
|
||||
| DELETE | READ_CONTROL | WRITE_DAC \
|
||||
| WRITE_OWNER | SYNCHRONIZE)
|
||||
#define SET_FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \
|
||||
| FILE_READ_EA | FILE_WRITE_EA \
|
||||
| FILE_DELETE_CHILD | FILE_READ_ATTRIBUTES \
|
||||
| FILE_WRITE_ATTRIBUTES \
|
||||
| DELETE | READ_CONTROL | WRITE_DAC \
|
||||
| WRITE_OWNER | SYNCHRONIZE)
|
||||
#define SET_FILE_EXEC_RIGHTS (FILE_READ_EA | FILE_WRITE_EA | FILE_EXECUTE \
|
||||
| FILE_READ_ATTRIBUTES \
|
||||
| FILE_WRITE_ATTRIBUTES \
|
||||
| DELETE | READ_CONTROL | WRITE_DAC \
|
||||
| WRITE_OWNER | SYNCHRONIZE)
|
||||
|
||||
|
||||
/*
|
||||
* Invalid readdir handle
|
||||
|
@ -1211,6 +1228,29 @@ typedef struct smb_com_transaction_qsec_req {
|
|||
__le32 AclFlags;
|
||||
} __attribute__((packed)) QUERY_SEC_DESC_REQ;
|
||||
|
||||
|
||||
typedef struct smb_com_transaction_ssec_req {
|
||||
struct smb_hdr hdr; /* wct = 19 */
|
||||
__u8 MaxSetupCount;
|
||||
__u16 Reserved;
|
||||
__le32 TotalParameterCount;
|
||||
__le32 TotalDataCount;
|
||||
__le32 MaxParameterCount;
|
||||
__le32 MaxDataCount;
|
||||
__le32 ParameterCount;
|
||||
__le32 ParameterOffset;
|
||||
__le32 DataCount;
|
||||
__le32 DataOffset;
|
||||
__u8 SetupCount; /* no setup words follow subcommand */
|
||||
/* SNIA spec incorrectly included spurious pad here */
|
||||
__le16 SubCommand; /* 3 = SET_SECURITY_DESC */
|
||||
__le16 ByteCount; /* bcc = 3 + 8 */
|
||||
__u8 Pad[3];
|
||||
__u16 Fid;
|
||||
__u16 Reserved2;
|
||||
__le32 AclFlags;
|
||||
} __attribute__((packed)) SET_SEC_DESC_REQ;
|
||||
|
||||
typedef struct smb_com_transaction_change_notify_req {
|
||||
struct smb_hdr hdr; /* wct = 23 */
|
||||
__u8 MaxSetupCount;
|
||||
|
|
|
@ -61,6 +61,9 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
|
|||
extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
|
||||
extern int is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
|
||||
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *);
|
||||
#endif
|
||||
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,
|
||||
|
@ -73,6 +76,8 @@ extern void header_assemble(struct smb_hdr *, char /* command */ ,
|
|||
extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
|
||||
struct cifsSesInfo *ses,
|
||||
void **request_buf);
|
||||
extern struct key *cifs_get_spnego_key(struct cifsSesInfo *sesInfo,
|
||||
const char *hostname);
|
||||
extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
||||
const int stage,
|
||||
const struct nls_table *nls_cp);
|
||||
|
@ -92,6 +97,8 @@ extern int cifs_get_inode_info(struct inode **pinode,
|
|||
extern int cifs_get_inode_info_unix(struct inode **pinode,
|
||||
const unsigned char *search_path,
|
||||
struct super_block *sb, int xid);
|
||||
extern void acl_to_uid_mode(struct inode *inode, const char *search_path);
|
||||
extern int mode_to_acl(struct inode *inode, const char *path);
|
||||
|
||||
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
|
||||
const char *);
|
||||
|
@ -311,7 +318,6 @@ extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
|
|||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
extern void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key);
|
||||
#endif /* CIFS_WEAK_PW_HASH */
|
||||
extern int parse_sec_desc(struct cifs_ntsd *, int);
|
||||
extern int CIFSSMBCopy(int xid,
|
||||
struct cifsTconInfo *source_tcon,
|
||||
const char *fromName,
|
||||
|
@ -336,8 +342,7 @@ extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
|
|||
const void *ea_value, const __u16 ea_value_len,
|
||||
const struct nls_table *nls_codepage, int remap_special_chars);
|
||||
extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon,
|
||||
__u16 fid, char *acl_inf, const int buflen,
|
||||
const int acl_type /* ACCESS vs. DEFAULT */);
|
||||
__u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
|
||||
extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
|
||||
const unsigned char *searchName,
|
||||
char *acl_inf, const int buflen, const int acl_type,
|
||||
|
|
|
@ -647,8 +647,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||
count - 16,
|
||||
&server->secType);
|
||||
if (rc == 1) {
|
||||
/* BB Need to fill struct for sessetup here */
|
||||
rc = -EOPNOTSUPP;
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
@ -2486,6 +2485,7 @@ querySymLinkRetry:
|
|||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
/* Initialize NT TRANSACT SMB into small smb request buffer.
|
||||
This assumes that all NT TRANSACTS that we init here have
|
||||
total parm and data under about 400 bytes (to fit in small cifs
|
||||
|
@ -2494,7 +2494,7 @@ querySymLinkRetry:
|
|||
MaxSetupCount (size of returned setup area) and
|
||||
MaxParameterCount (returned parms size) must be set by caller */
|
||||
static int
|
||||
smb_init_ntransact(const __u16 sub_command, const int setup_count,
|
||||
smb_init_nttransact(const __u16 sub_command, const int setup_count,
|
||||
const int parm_len, struct cifsTconInfo *tcon,
|
||||
void **ret_buf)
|
||||
{
|
||||
|
@ -2525,12 +2525,15 @@ smb_init_ntransact(const __u16 sub_command, const int setup_count,
|
|||
|
||||
static int
|
||||
validate_ntransact(char *buf, char **ppparm, char **ppdata,
|
||||
int *pdatalen, int *pparmlen)
|
||||
__u32 *pparmlen, __u32 *pdatalen)
|
||||
{
|
||||
char *end_of_smb;
|
||||
__u32 data_count, data_offset, parm_count, parm_offset;
|
||||
struct smb_com_ntransact_rsp *pSMBr;
|
||||
|
||||
*pdatalen = 0;
|
||||
*pparmlen = 0;
|
||||
|
||||
if (buf == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -2567,8 +2570,11 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata,
|
|||
cFYI(1, ("parm count and data count larger than SMB"));
|
||||
return -EINVAL;
|
||||
}
|
||||
*pdatalen = data_count;
|
||||
*pparmlen = parm_count;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CIFS_EXPERIMENTAL */
|
||||
|
||||
int
|
||||
CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
|
||||
|
@ -3067,8 +3073,7 @@ GetExtAttrOut:
|
|||
/* Get Security Descriptor (by handle) from remote server for a file or dir */
|
||||
int
|
||||
CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
|
||||
/* BB fix up return info */ char *acl_inf, const int buflen,
|
||||
const int acl_type)
|
||||
struct cifs_ntsd **acl_inf, __u32 *pbuflen)
|
||||
{
|
||||
int rc = 0;
|
||||
int buf_type = 0;
|
||||
|
@ -3077,7 +3082,10 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
|
|||
|
||||
cFYI(1, ("GetCifsACL"));
|
||||
|
||||
rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
|
||||
*pbuflen = 0;
|
||||
*acl_inf = NULL;
|
||||
|
||||
rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
|
||||
8 /* parm len */, tcon, (void **) &pSMB);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
@ -3099,34 +3107,52 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
|
|||
if (rc) {
|
||||
cFYI(1, ("Send error in QuerySecDesc = %d", rc));
|
||||
} else { /* decode response */
|
||||
struct cifs_ntsd *psec_desc;
|
||||
__le32 * parm;
|
||||
int parm_len;
|
||||
int data_len;
|
||||
int acl_len;
|
||||
__u32 parm_len;
|
||||
__u32 acl_len;
|
||||
struct smb_com_ntransact_rsp *pSMBr;
|
||||
char *pdata;
|
||||
|
||||
/* validate_nttransact */
|
||||
rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
|
||||
(char **)&psec_desc,
|
||||
&parm_len, &data_len);
|
||||
&pdata, &parm_len, pbuflen);
|
||||
if (rc)
|
||||
goto qsec_out;
|
||||
pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
|
||||
|
||||
cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, psec_desc));
|
||||
cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
|
||||
|
||||
if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
|
||||
rc = -EIO; /* bad smb */
|
||||
*pbuflen = 0;
|
||||
goto qsec_out;
|
||||
}
|
||||
|
||||
/* BB check that data area is minimum length and as big as acl_len */
|
||||
|
||||
acl_len = le32_to_cpu(*parm);
|
||||
/* BB check if (acl_len > bufsize) */
|
||||
if (acl_len != *pbuflen) {
|
||||
cERROR(1, ("acl length %d does not match %d",
|
||||
acl_len, *pbuflen));
|
||||
if (*pbuflen > acl_len)
|
||||
*pbuflen = acl_len;
|
||||
}
|
||||
|
||||
parse_sec_desc(psec_desc, acl_len);
|
||||
/* check if buffer is big enough for the acl
|
||||
header followed by the smallest SID */
|
||||
if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
|
||||
(*pbuflen >= 64 * 1024)) {
|
||||
cERROR(1, ("bad acl length %d", *pbuflen));
|
||||
rc = -EINVAL;
|
||||
*pbuflen = 0;
|
||||
} else {
|
||||
*acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
|
||||
if (*acl_inf == NULL) {
|
||||
*pbuflen = 0;
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
memcpy(*acl_inf, pdata, *pbuflen);
|
||||
}
|
||||
}
|
||||
qsec_out:
|
||||
if (buf_type == CIFS_SMALL_BUFFER)
|
||||
|
@ -3381,7 +3407,7 @@ UnixQPathInfoRetry:
|
|||
memcpy((char *) pFindData,
|
||||
(char *) &pSMBr->hdr.Protocol +
|
||||
data_offset,
|
||||
sizeof (FILE_UNIX_BASIC_INFO));
|
||||
sizeof(FILE_UNIX_BASIC_INFO));
|
||||
}
|
||||
}
|
||||
cifs_buf_release(pSMB);
|
||||
|
@ -3649,7 +3675,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
|
|||
pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
|
||||
pSMB->SearchHandle = searchHandle; /* always kept as le */
|
||||
pSMB->SearchCount =
|
||||
cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
|
||||
cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
|
||||
pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
|
||||
pSMB->ResumeKey = psrch_inf->resume_key;
|
||||
pSMB->SearchFlags =
|
||||
|
@ -4331,7 +4357,7 @@ QFSDeviceRetry:
|
|||
} else { /* decode response */
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
|
||||
if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
|
||||
if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
|
||||
rc = -EIO; /* bad smb */
|
||||
else {
|
||||
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
||||
|
|
|
@ -793,7 +793,7 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
vol->linux_gid = current->gid;
|
||||
vol->dir_mode = S_IRWXUGO;
|
||||
/* 2767 perms indicate mandatory locking support */
|
||||
vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
|
||||
vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
|
||||
|
||||
/* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
|
||||
vol->rw = TRUE;
|
||||
|
@ -1790,7 +1790,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
|
||||
if (volume_info.nullauth) {
|
||||
cFYI(1, ("null user"));
|
||||
volume_info.username = NULL;
|
||||
volume_info.username = "";
|
||||
} else if (volume_info.username) {
|
||||
/* BB fixme parse for domain name here */
|
||||
cFYI(1, ("Username: %s", volume_info.username));
|
||||
|
|
|
@ -593,7 +593,7 @@ static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
|
|||
* case take precedence. If a is not a negative dentry, this
|
||||
* should have no side effects
|
||||
*/
|
||||
memcpy((unsigned char *)a->name, b->name, a->len);
|
||||
memcpy(a->name, b->name, a->len);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
|
|
@ -1026,6 +1026,37 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
|
|||
return total_written;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
|
||||
{
|
||||
struct cifsFileInfo *open_file = NULL;
|
||||
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
/* we could simply get the first_list_entry since write-only entries
|
||||
are always at the end of the list but since the first entry might
|
||||
have a close pending, we go through the whole list */
|
||||
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
|
||||
if (open_file->closePend)
|
||||
continue;
|
||||
if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
|
||||
(open_file->pfile->f_flags & O_RDONLY))) {
|
||||
if (!open_file->invalidHandle) {
|
||||
/* found a good file */
|
||||
/* lock it so it will not be closed on us */
|
||||
atomic_inc(&open_file->wrtPending);
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
return open_file;
|
||||
} /* else might as well continue, and look for
|
||||
another, or simply have the caller reopen it
|
||||
again rather than trying to fix this handle */
|
||||
} else /* write only file */
|
||||
break; /* write only files are last so must be done */
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
|
||||
{
|
||||
struct cifsFileInfo *open_file;
|
||||
|
|
|
@ -289,7 +289,7 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
|
|||
|
||||
#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
|
||||
|
||||
static int get_sfu_uid_mode(struct inode *inode,
|
||||
static int get_sfu_mode(struct inode *inode,
|
||||
const unsigned char *path,
|
||||
struct cifs_sb_info *cifs_sb, int xid)
|
||||
{
|
||||
|
@ -527,11 +527,16 @@ int cifs_get_inode_info(struct inode **pinode,
|
|||
|
||||
/* BB fill in uid and gid here? with help from winbind?
|
||||
or retrieve from NTFS stream extended attribute */
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
/* fill in 0777 bits from ACL */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
|
||||
cFYI(1, ("Getting mode bits from ACL"));
|
||||
acl_to_uid_mode(inode, search_path);
|
||||
}
|
||||
#endif
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
|
||||
/* fill in uid, gid, mode from server ACL */
|
||||
/* BB FIXME this should also take into account the
|
||||
* default uid specified on mount if present */
|
||||
get_sfu_uid_mode(inode, search_path, cifs_sb, xid);
|
||||
/* fill in remaining high mode bits e.g. SUID, VTX */
|
||||
get_sfu_mode(inode, search_path, cifs_sb, xid);
|
||||
} else if (atomic_read(&cifsInfo->inUse) == 0) {
|
||||
inode->i_uid = cifs_sb->mnt_uid;
|
||||
inode->i_gid = cifs_sb->mnt_gid;
|
||||
|
|
|
@ -276,8 +276,8 @@ hmac_md5_init_rfc2104(unsigned char *key, int key_len,
|
|||
}
|
||||
|
||||
/* start out by storing key in pads */
|
||||
memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad));
|
||||
memset(ctx->k_opad, 0, sizeof (ctx->k_opad));
|
||||
memset(ctx->k_ipad, 0, sizeof(ctx->k_ipad));
|
||||
memset(ctx->k_opad, 0, sizeof(ctx->k_opad));
|
||||
memcpy(ctx->k_ipad, key, key_len);
|
||||
memcpy(ctx->k_opad, key, key_len);
|
||||
|
||||
|
@ -307,8 +307,8 @@ hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
|
|||
}
|
||||
|
||||
/* start out by storing key in pads */
|
||||
memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad));
|
||||
memset(ctx->k_opad, 0, sizeof (ctx->k_opad));
|
||||
memset(ctx->k_ipad, 0, sizeof(ctx->k_ipad));
|
||||
memset(ctx->k_opad, 0, sizeof(ctx->k_opad));
|
||||
memcpy(ctx->k_ipad, key, key_len);
|
||||
memcpy(ctx->k_opad, key, key_len);
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ sesInfoAlloc(void)
|
|||
{
|
||||
struct cifsSesInfo *ret_buf;
|
||||
|
||||
ret_buf = kzalloc(sizeof (struct cifsSesInfo), GFP_KERNEL);
|
||||
ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL);
|
||||
if (ret_buf) {
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
atomic_inc(&sesInfoAllocCount);
|
||||
|
@ -109,7 +109,7 @@ struct cifsTconInfo *
|
|||
tconInfoAlloc(void)
|
||||
{
|
||||
struct cifsTconInfo *ret_buf;
|
||||
ret_buf = kzalloc(sizeof (struct cifsTconInfo), GFP_KERNEL);
|
||||
ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL);
|
||||
if (ret_buf) {
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
atomic_inc(&tconInfoAllocCount);
|
||||
|
@ -298,7 +298,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
|
|||
memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */
|
||||
|
||||
buffer->smb_buf_length =
|
||||
(2 * word_count) + sizeof (struct smb_hdr) -
|
||||
(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
|
||||
|
@ -422,8 +422,8 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
|
|||
__u32 clc_len; /* calculated length */
|
||||
cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len));
|
||||
|
||||
if (length < 2 + sizeof (struct smb_hdr)) {
|
||||
if ((length >= sizeof (struct smb_hdr) - 1)
|
||||
if (length < 2 + sizeof(struct smb_hdr)) {
|
||||
if ((length >= sizeof(struct smb_hdr) - 1)
|
||||
&& (smb->Status.CifsError != 0)) {
|
||||
smb->WordCount = 0;
|
||||
/* some error cases do not return wct and bcc */
|
||||
|
|
|
@ -132,6 +132,34 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
|
|||
{0, 0}
|
||||
};
|
||||
|
||||
|
||||
/* if the mount helper is missing we need to reverse the 1st slash
|
||||
from '/' to backslash in order to format the UNC properly for
|
||||
ip address parsing and for tree connect (unless the user
|
||||
remembered to put the UNC name in properly). Fortunately we do
|
||||
not have to call this twice (we check for IPv4 addresses
|
||||
first, so it is already converted by the time we
|
||||
try IPv6 addresses */
|
||||
static int canonicalize_unc(char *cp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= 46 /* INET6_ADDRSTRLEN */ ; i++) {
|
||||
if (cp[i] == 0)
|
||||
break;
|
||||
if (cp[i] == '\\')
|
||||
break;
|
||||
if (cp[i] == '/') {
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
cFYI(1, ("change slash to backslash in malformed UNC"));
|
||||
#endif
|
||||
cp[i] = '\\';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert string containing dotted ip address to binary form */
|
||||
/* returns 0 if invalid address */
|
||||
|
||||
|
@ -141,11 +169,13 @@ cifs_inet_pton(int address_family, char *cp, void *dst)
|
|||
int ret = 0;
|
||||
|
||||
/* calculate length by finding first slash or NULL */
|
||||
/* BB Should we convert '/' slash to '\' here since it seems already
|
||||
* done before this */
|
||||
if ( address_family == AF_INET ) {
|
||||
ret = in4_pton(cp, -1 /* len */, dst , '\\', NULL);
|
||||
} else if ( address_family == AF_INET6 ) {
|
||||
if (address_family == AF_INET) {
|
||||
ret = in4_pton(cp, -1 /* len */, dst, '\\', NULL);
|
||||
if (ret == 0) {
|
||||
if (canonicalize_unc(cp))
|
||||
ret = in4_pton(cp, -1, dst, '\\', NULL);
|
||||
}
|
||||
} else if (address_family == AF_INET6) {
|
||||
ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL);
|
||||
}
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
|
@ -740,7 +770,7 @@ cifs_print_status(__u32 status_code)
|
|||
|
||||
|
||||
static void
|
||||
ntstatus_to_dos(__u32 ntstatus, __u8 * eclass, __u16 * ecode)
|
||||
ntstatus_to_dos(__u32 ntstatus, __u8 *eclass, __u16 *ecode)
|
||||
{
|
||||
int i;
|
||||
if (ntstatus == 0) {
|
||||
|
@ -793,8 +823,8 @@ map_smb_to_linux_error(struct smb_hdr *smb, int logErr)
|
|||
if (smberrclass == ERRDOS) { /* 1 byte field no need to byte reverse */
|
||||
for (i = 0;
|
||||
i <
|
||||
sizeof (mapping_table_ERRDOS) /
|
||||
sizeof (struct smb_to_posix_error); i++) {
|
||||
sizeof(mapping_table_ERRDOS) /
|
||||
sizeof(struct smb_to_posix_error); i++) {
|
||||
if (mapping_table_ERRDOS[i].smb_err == 0)
|
||||
break;
|
||||
else if (mapping_table_ERRDOS[i].smb_err ==
|
||||
|
@ -807,8 +837,8 @@ map_smb_to_linux_error(struct smb_hdr *smb, int logErr)
|
|||
} else if (smberrclass == ERRSRV) { /* server class of error codes */
|
||||
for (i = 0;
|
||||
i <
|
||||
sizeof (mapping_table_ERRSRV) /
|
||||
sizeof (struct smb_to_posix_error); i++) {
|
||||
sizeof(mapping_table_ERRSRV) /
|
||||
sizeof(struct smb_to_posix_error); i++) {
|
||||
if (mapping_table_ERRSRV[i].smb_err == 0)
|
||||
break;
|
||||
else if (mapping_table_ERRSRV[i].smb_err ==
|
||||
|
@ -837,14 +867,14 @@ map_smb_to_linux_error(struct smb_hdr *smb, int logErr)
|
|||
unsigned int
|
||||
smbCalcSize(struct smb_hdr *ptr)
|
||||
{
|
||||
return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
|
||||
return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
|
||||
2 /* size of the bcc field */ + BCC(ptr));
|
||||
}
|
||||
|
||||
unsigned int
|
||||
smbCalcSize_LE(struct smb_hdr *ptr)
|
||||
{
|
||||
return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
|
||||
return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
|
||||
2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr)));
|
||||
}
|
||||
|
||||
|
|
|
@ -171,6 +171,12 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
|
|||
/* Linux can not store file creation time unfortunately so ignore it */
|
||||
|
||||
cifsInfo->cifsAttrs = attr;
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
|
||||
/* get more accurate mode via ACL - so force inode refresh */
|
||||
cifsInfo->time = 0;
|
||||
} else
|
||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
||||
cifsInfo->time = jiffies;
|
||||
|
||||
/* treat dos attribute of read-only as read-only mode bit e.g. 555? */
|
||||
|
@ -495,7 +501,7 @@ ffirst_retry:
|
|||
static int cifs_unicode_bytelen(char *str)
|
||||
{
|
||||
int len;
|
||||
__le16 * ustr = (__le16 *)str;
|
||||
__le16 *ustr = (__le16 *)str;
|
||||
|
||||
for (len = 0; len <= PATH_MAX; len++) {
|
||||
if (ustr[len] == 0)
|
||||
|
|
|
@ -80,7 +80,7 @@ SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
|
|||
|
||||
/* Routines for Windows NT MD4 Hash functions. */
|
||||
static int
|
||||
_my_wcslen(__u16 * str)
|
||||
_my_wcslen(__u16 *str)
|
||||
{
|
||||
int len = 0;
|
||||
while (*str++ != 0)
|
||||
|
@ -96,7 +96,7 @@ _my_wcslen(__u16 * str)
|
|||
*/
|
||||
|
||||
static int
|
||||
_my_mbstowcs(__u16 * dst, const unsigned char *src, int len)
|
||||
_my_mbstowcs(__u16 *dst, const unsigned char *src, int len)
|
||||
{ /* BB not a very good conversion routine - change/fix */
|
||||
int i;
|
||||
__u16 val;
|
||||
|
@ -125,9 +125,9 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
|
|||
/* Password cannot be longer than 128 characters */
|
||||
if (passwd) {
|
||||
len = strlen((char *) passwd);
|
||||
if (len > 128) {
|
||||
if (len > 128)
|
||||
len = 128;
|
||||
}
|
||||
|
||||
/* Password must be converted to NT unicode */
|
||||
_my_mbstowcs(wpwd, passwd, len);
|
||||
} else
|
||||
|
@ -135,7 +135,7 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
|
|||
|
||||
wpwd[len] = 0; /* Ensure string is null terminated */
|
||||
/* Calculate length in bytes */
|
||||
len = _my_wcslen(wpwd) * sizeof (__u16);
|
||||
len = _my_wcslen(wpwd) * sizeof(__u16);
|
||||
|
||||
mdfour(p16, (unsigned char *) wpwd, len);
|
||||
memset(wpwd, 0, 129 * 2);
|
||||
|
@ -167,7 +167,7 @@ nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
|
|||
E_P16((unsigned char *) passwd, (unsigned char *) p16);
|
||||
|
||||
/* clear out local copy of user's password (just being paranoid). */
|
||||
memset(passwd, '\0', sizeof (passwd));
|
||||
memset(passwd, '\0', sizeof(passwd));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -189,8 +189,10 @@ ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
|
|||
return;
|
||||
dom_u = user_u + 1024;
|
||||
|
||||
/* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER);
|
||||
push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */
|
||||
/* push_ucs2(NULL, user_u, user_n, (user_l+1)*2,
|
||||
STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER);
|
||||
push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2,
|
||||
STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */
|
||||
|
||||
/* BB user and domain may need to be uppercased */
|
||||
user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage);
|
||||
|
|
|
@ -265,6 +265,8 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
|
|||
else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
|
||||
__u16 fid;
|
||||
int oplock = FALSE;
|
||||
struct cifs_ntsd *pacl = NULL;
|
||||
__u32 buflen = 0;
|
||||
if (experimEnabled)
|
||||
rc = CIFSSMBOpen(xid, pTcon, full_path,
|
||||
FILE_OPEN, GENERIC_READ, 0, &fid,
|
||||
|
@ -273,10 +275,9 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
|
|||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
/* else rc is EOPNOTSUPP from above */
|
||||
|
||||
if(rc == 0) {
|
||||
rc = CIFSSMBGetCIFSACL(xid, pTcon, fid,
|
||||
ea_value, buf_size,
|
||||
ACL_TYPE_ACCESS);
|
||||
if (rc == 0) {
|
||||
rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, &pacl,
|
||||
&buflen);
|
||||
CIFSSMBClose(xid, pTcon, fid);
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче