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:
Linus Torvalds 2007-11-12 11:11:39 -08:00
commit 46015977e7
24 changed files with 726 additions and 170 deletions

View file

@ -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

View file

@ -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
------------

View file

@ -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

View file

@ -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;
}

128
fs/cifs/cifs_spnego.c Normal file
View file

@ -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;
}

46
fs/cifs/cifs_spnego.h Normal file
View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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];

View file

@ -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();

View file

@ -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 */

View file

@ -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;

View file

@ -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,

View file

@ -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 @@ CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
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 @@ CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
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 @@ CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
/* 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 @@ CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
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 @@ CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
} 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);

View file

@ -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));

View file

@ -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;

View file

@ -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;

View 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;

View file

@ -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);

View file

@ -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 */

View file

@ -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)));
}

View file

@ -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 @@ static int initiate_cifs_search(const int xid, struct file *file)
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)

View file

@ -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);

View file

@ -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);
}
}