2007-09-26 00:17:24 +08:00
|
|
|
/*
|
|
|
|
* fs/cifs/cifsacl.c
|
|
|
|
*
|
2008-03-15 06:37:16 +08:00
|
|
|
* Copyright (C) International Business Machines Corp., 2007,2008
|
2007-09-26 00:17:24 +08:00
|
|
|
* Author(s): Steve French (sfrench@us.ibm.com)
|
|
|
|
*
|
|
|
|
* Contains the routines for mapping CIFS/NTFS ACLs
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2007-09-26 03:53:44 +08:00
|
|
|
#include <linux/fs.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
|
|
|
#include <linux/slab.h>
|
2011-04-28 12:34:35 +08:00
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/keyctl.h>
|
|
|
|
#include <linux/key-type.h>
|
|
|
|
#include <keys/user-type.h>
|
2007-09-26 03:53:44 +08:00
|
|
|
#include "cifspdu.h"
|
|
|
|
#include "cifsglob.h"
|
2007-10-04 02:22:19 +08:00
|
|
|
#include "cifsacl.h"
|
2007-09-26 03:53:44 +08:00
|
|
|
#include "cifsproto.h"
|
|
|
|
#include "cifs_debug.h"
|
|
|
|
|
keys: Replace uid/gid/perm permissions checking with an ACL
Replace the uid/gid/perm permissions checking on a key with an ACL to allow
the SETATTR and SEARCH permissions to be split. This will also allow a
greater range of subjects to represented.
============
WHY DO THIS?
============
The problem is that SETATTR and SEARCH cover a slew of actions, not all of
which should be grouped together.
For SETATTR, this includes actions that are about controlling access to a
key:
(1) Changing a key's ownership.
(2) Changing a key's security information.
(3) Setting a keyring's restriction.
And actions that are about managing a key's lifetime:
(4) Setting an expiry time.
(5) Revoking a key.
and (proposed) managing a key as part of a cache:
(6) Invalidating a key.
Managing a key's lifetime doesn't really have anything to do with
controlling access to that key.
Expiry time is awkward since it's more about the lifetime of the content
and so, in some ways goes better with WRITE permission. It can, however,
be set unconditionally by a process with an appropriate authorisation token
for instantiating a key, and can also be set by the key type driver when a
key is instantiated, so lumping it with the access-controlling actions is
probably okay.
As for SEARCH permission, that currently covers:
(1) Finding keys in a keyring tree during a search.
(2) Permitting keyrings to be joined.
(3) Invalidation.
But these don't really belong together either, since these actions really
need to be controlled separately.
Finally, there are number of special cases to do with granting the
administrator special rights to invalidate or clear keys that I would like
to handle with the ACL rather than key flags and special checks.
===============
WHAT IS CHANGED
===============
The SETATTR permission is split to create two new permissions:
(1) SET_SECURITY - which allows the key's owner, group and ACL to be
changed and a restriction to be placed on a keyring.
(2) REVOKE - which allows a key to be revoked.
The SEARCH permission is split to create:
(1) SEARCH - which allows a keyring to be search and a key to be found.
(2) JOIN - which allows a keyring to be joined as a session keyring.
(3) INVAL - which allows a key to be invalidated.
The WRITE permission is also split to create:
(1) WRITE - which allows a key's content to be altered and links to be
added, removed and replaced in a keyring.
(2) CLEAR - which allows a keyring to be cleared completely. This is
split out to make it possible to give just this to an administrator.
(3) REVOKE - see above.
Keys acquire ACLs which consist of a series of ACEs, and all that apply are
unioned together. An ACE specifies a subject, such as:
(*) Possessor - permitted to anyone who 'possesses' a key
(*) Owner - permitted to the key owner
(*) Group - permitted to the key group
(*) Everyone - permitted to everyone
Note that 'Other' has been replaced with 'Everyone' on the assumption that
you wouldn't grant a permit to 'Other' that you wouldn't also grant to
everyone else.
Further subjects may be made available by later patches.
The ACE also specifies a permissions mask. The set of permissions is now:
VIEW Can view the key metadata
READ Can read the key content
WRITE Can update/modify the key content
SEARCH Can find the key by searching/requesting
LINK Can make a link to the key
SET_SECURITY Can change owner, ACL, expiry
INVAL Can invalidate
REVOKE Can revoke
JOIN Can join this keyring
CLEAR Can clear this keyring
The KEYCTL_SETPERM function is then deprecated.
The KEYCTL_SET_TIMEOUT function then is permitted if SET_SECURITY is set,
or if the caller has a valid instantiation auth token.
The KEYCTL_INVALIDATE function then requires INVAL.
The KEYCTL_REVOKE function then requires REVOKE.
The KEYCTL_JOIN_SESSION_KEYRING function then requires JOIN to join an
existing keyring.
The JOIN permission is enabled by default for session keyrings and manually
created keyrings only.
======================
BACKWARD COMPATIBILITY
======================
To maintain backward compatibility, KEYCTL_SETPERM will translate the
permissions mask it is given into a new ACL for a key - unless
KEYCTL_SET_ACL has been called on that key, in which case an error will be
returned.
It will convert possessor, owner, group and other permissions into separate
ACEs, if each portion of the mask is non-zero.
SETATTR permission turns on all of INVAL, REVOKE and SET_SECURITY. WRITE
permission turns on WRITE, REVOKE and, if a keyring, CLEAR. JOIN is turned
on if a keyring is being altered.
The KEYCTL_DESCRIBE function translates the ACL back into a permissions
mask to return depending on possessor, owner, group and everyone ACEs.
It will make the following mappings:
(1) INVAL, JOIN -> SEARCH
(2) SET_SECURITY -> SETATTR
(3) REVOKE -> WRITE if SETATTR isn't already set
(4) CLEAR -> WRITE
Note that the value subsequently returned by KEYCTL_DESCRIBE may not match
the value set with KEYCTL_SETATTR.
=======
TESTING
=======
This passes the keyutils testsuite for all but a couple of tests:
(1) tests/keyctl/dh_compute/badargs: The first wrong-key-type test now
returns EOPNOTSUPP rather than ENOKEY as READ permission isn't removed
if the type doesn't have ->read(). You still can't actually read the
key.
(2) tests/keyctl/permitting/valid: The view-other-permissions test doesn't
work as Other has been replaced with Everyone in the ACL.
Signed-off-by: David Howells <dhowells@redhat.com>
2019-06-28 06:03:07 +08:00
|
|
|
static struct key_acl cifs_idmap_key_acl = {
|
|
|
|
.usage = REFCOUNT_INIT(1),
|
|
|
|
.nr_ace = 2,
|
|
|
|
.possessor_viewable = true,
|
|
|
|
.aces = {
|
|
|
|
KEY_POSSESSOR_ACE(KEY_ACE_VIEW | KEY_ACE_SEARCH | KEY_ACE_READ),
|
|
|
|
KEY_OWNER_ACE(KEY_ACE_VIEW),
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct key_acl cifs_idmap_keyring_acl = {
|
|
|
|
.usage = REFCOUNT_INIT(1),
|
|
|
|
.nr_ace = 2,
|
|
|
|
.aces = {
|
|
|
|
KEY_POSSESSOR_ACE(KEY_ACE_SEARCH | KEY_ACE_WRITE),
|
|
|
|
KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ),
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-12-07 04:56:46 +08:00
|
|
|
/* security id for everyone/world system group */
|
2007-10-30 12:45:14 +08:00
|
|
|
static const struct cifs_sid sid_everyone = {
|
|
|
|
1, 1, {0, 0, 0, 0, 0, 1}, {0} };
|
2010-12-07 04:56:46 +08:00
|
|
|
/* security id for Authenticated Users system group */
|
|
|
|
static const struct cifs_sid sid_authusers = {
|
2014-12-11 07:41:15 +08:00
|
|
|
1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(11)} };
|
2007-09-26 00:17:24 +08:00
|
|
|
/* group users */
|
2008-02-08 07:25:02 +08:00
|
|
|
static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
|
2007-10-04 02:22:19 +08:00
|
|
|
|
2016-10-14 08:06:23 +08:00
|
|
|
/* S-1-22-1 Unmapped Unix users */
|
|
|
|
static const struct cifs_sid sid_unix_users = {1, 1, {0, 0, 0, 0, 0, 22},
|
|
|
|
{cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
|
|
|
|
|
|
|
|
/* S-1-22-2 Unmapped Unix groups */
|
|
|
|
static const struct cifs_sid sid_unix_groups = { 1, 1, {0, 0, 0, 0, 0, 22},
|
|
|
|
{cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* S-1-5-88 MS NFS and Apple style UID/GID/mode */
|
|
|
|
|
|
|
|
/* S-1-5-88-1 Unix uid */
|
|
|
|
static const struct cifs_sid sid_unix_NFS_users = { 1, 2, {0, 0, 0, 0, 0, 5},
|
|
|
|
{cpu_to_le32(88),
|
|
|
|
cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
|
|
|
|
|
|
|
|
/* S-1-5-88-2 Unix gid */
|
|
|
|
static const struct cifs_sid sid_unix_NFS_groups = { 1, 2, {0, 0, 0, 0, 0, 5},
|
|
|
|
{cpu_to_le32(88),
|
|
|
|
cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
|
|
|
|
|
|
|
|
/* S-1-5-88-3 Unix mode */
|
|
|
|
static const struct cifs_sid sid_unix_NFS_mode = { 1, 2, {0, 0, 0, 0, 0, 5},
|
|
|
|
{cpu_to_le32(88),
|
|
|
|
cpu_to_le32(3), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
|
|
|
|
|
2012-11-25 21:00:38 +08:00
|
|
|
static const struct cred *root_cred;
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
|
2011-04-28 12:34:35 +08:00
|
|
|
static int
|
2012-09-13 20:06:29 +08:00
|
|
|
cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
2011-04-28 12:34:35 +08:00
|
|
|
{
|
|
|
|
char *payload;
|
|
|
|
|
2012-12-03 19:05:29 +08:00
|
|
|
/*
|
|
|
|
* If the payload is less than or equal to the size of a pointer, then
|
|
|
|
* an allocation here is wasteful. Just copy the data directly to the
|
|
|
|
* payload.value union member instead.
|
|
|
|
*
|
|
|
|
* With this however, you must check the datalen before trying to
|
|
|
|
* dereference payload.data!
|
|
|
|
*/
|
2012-12-03 19:05:31 +08:00
|
|
|
if (prep->datalen <= sizeof(key->payload)) {
|
2015-10-21 21:04:48 +08:00
|
|
|
key->payload.data[0] = NULL;
|
|
|
|
memcpy(&key->payload, prep->data, prep->datalen);
|
|
|
|
} else {
|
|
|
|
payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
|
|
|
|
if (!payload)
|
|
|
|
return -ENOMEM;
|
|
|
|
key->payload.data[0] = payload;
|
2012-12-03 19:05:29 +08:00
|
|
|
}
|
2011-04-28 12:34:35 +08:00
|
|
|
|
2012-09-13 20:06:29 +08:00
|
|
|
key->datalen = prep->datalen;
|
2011-04-28 12:34:35 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
cifs_idmap_key_destroy(struct key *key)
|
|
|
|
{
|
2012-12-03 19:05:31 +08:00
|
|
|
if (key->datalen > sizeof(key->payload))
|
2015-10-21 21:04:48 +08:00
|
|
|
kfree(key->payload.data[0]);
|
2011-04-28 12:34:35 +08:00
|
|
|
}
|
|
|
|
|
2012-11-25 21:00:38 +08:00
|
|
|
static struct key_type cifs_idmap_key_type = {
|
2011-05-06 15:35:00 +08:00
|
|
|
.name = "cifs.idmap",
|
2011-04-28 12:34:35 +08:00
|
|
|
.instantiate = cifs_idmap_key_instantiate,
|
|
|
|
.destroy = cifs_idmap_key_destroy,
|
|
|
|
.describe = user_describe,
|
|
|
|
};
|
|
|
|
|
2012-12-03 19:05:29 +08:00
|
|
|
static char *
|
|
|
|
sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
{
|
2012-12-03 19:05:29 +08:00
|
|
|
int i, len;
|
2012-11-25 21:00:38 +08:00
|
|
|
unsigned int saval;
|
2012-12-03 19:05:29 +08:00
|
|
|
char *sidstr, *strptr;
|
2012-12-10 19:10:44 +08:00
|
|
|
unsigned long long id_auth_val;
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
|
2012-12-03 19:05:29 +08:00
|
|
|
/* 3 bytes for prefix */
|
|
|
|
sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
|
|
|
|
(SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!sidstr)
|
|
|
|
return sidstr;
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
|
2012-12-03 19:05:29 +08:00
|
|
|
strptr = sidstr;
|
|
|
|
len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
|
|
|
|
sidptr->revision);
|
|
|
|
strptr += len;
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
|
2012-12-10 19:10:44 +08:00
|
|
|
/* The authority field is a single 48-bit number */
|
|
|
|
id_auth_val = (unsigned long long)sidptr->authority[5];
|
|
|
|
id_auth_val |= (unsigned long long)sidptr->authority[4] << 8;
|
|
|
|
id_auth_val |= (unsigned long long)sidptr->authority[3] << 16;
|
|
|
|
id_auth_val |= (unsigned long long)sidptr->authority[2] << 24;
|
|
|
|
id_auth_val |= (unsigned long long)sidptr->authority[1] << 32;
|
|
|
|
id_auth_val |= (unsigned long long)sidptr->authority[0] << 48;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* MS-DTYP states that if the authority is >= 2^32, then it should be
|
|
|
|
* expressed as a hex value.
|
|
|
|
*/
|
|
|
|
if (id_auth_val <= UINT_MAX)
|
|
|
|
len = sprintf(strptr, "-%llu", id_auth_val);
|
|
|
|
else
|
|
|
|
len = sprintf(strptr, "-0x%llx", id_auth_val);
|
|
|
|
|
|
|
|
strptr += len;
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
|
|
|
|
for (i = 0; i < sidptr->num_subauth; ++i) {
|
|
|
|
saval = le32_to_cpu(sidptr->sub_auth[i]);
|
2012-12-03 19:05:29 +08:00
|
|
|
len = sprintf(strptr, "-%u", saval);
|
|
|
|
strptr += len;
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
}
|
2012-12-03 19:05:29 +08:00
|
|
|
|
|
|
|
return sidstr;
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
}
|
|
|
|
|
2012-11-25 21:00:36 +08:00
|
|
|
/*
|
|
|
|
* if the two SIDs (roughly equivalent to a UUID for a user or group) are
|
|
|
|
* the same returns zero, if they do not match returns non-zero.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int num_subauth, num_sat, num_saw;
|
|
|
|
|
|
|
|
if ((!ctsid) || (!cwsid))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* compare the revision */
|
|
|
|
if (ctsid->revision != cwsid->revision) {
|
|
|
|
if (ctsid->revision > cwsid->revision)
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* compare all of the six auth values */
|
|
|
|
for (i = 0; i < NUM_AUTHS; ++i) {
|
|
|
|
if (ctsid->authority[i] != cwsid->authority[i]) {
|
|
|
|
if (ctsid->authority[i] > cwsid->authority[i])
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* compare all of the subauth values if any */
|
|
|
|
num_sat = ctsid->num_subauth;
|
|
|
|
num_saw = cwsid->num_subauth;
|
|
|
|
num_subauth = num_sat < num_saw ? num_sat : num_saw;
|
|
|
|
if (num_subauth) {
|
|
|
|
for (i = 0; i < num_subauth; ++i) {
|
|
|
|
if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
|
|
|
|
if (le32_to_cpu(ctsid->sub_auth[i]) >
|
|
|
|
le32_to_cpu(cwsid->sub_auth[i]))
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0; /* sids compare/match */
|
|
|
|
}
|
|
|
|
|
2016-10-14 08:06:23 +08:00
|
|
|
static bool
|
|
|
|
is_well_known_sid(const struct cifs_sid *psid, uint32_t *puid, bool is_group)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int num_subauth;
|
|
|
|
const struct cifs_sid *pwell_known_sid;
|
|
|
|
|
|
|
|
if (!psid || (puid == NULL))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
num_subauth = psid->num_subauth;
|
|
|
|
|
|
|
|
/* check if Mac (or Windows NFS) vs. Samba format for Unix owner SID */
|
|
|
|
if (num_subauth == 2) {
|
|
|
|
if (is_group)
|
|
|
|
pwell_known_sid = &sid_unix_groups;
|
|
|
|
else
|
|
|
|
pwell_known_sid = &sid_unix_users;
|
|
|
|
} else if (num_subauth == 3) {
|
|
|
|
if (is_group)
|
|
|
|
pwell_known_sid = &sid_unix_NFS_groups;
|
|
|
|
else
|
|
|
|
pwell_known_sid = &sid_unix_NFS_users;
|
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* compare the revision */
|
|
|
|
if (psid->revision != pwell_known_sid->revision)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* compare all of the six auth values */
|
|
|
|
for (i = 0; i < NUM_AUTHS; ++i) {
|
|
|
|
if (psid->authority[i] != pwell_known_sid->authority[i]) {
|
|
|
|
cifs_dbg(FYI, "auth %d did not match\n", i);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num_subauth == 2) {
|
|
|
|
if (psid->sub_auth[0] != pwell_known_sid->sub_auth[0])
|
|
|
|
return false;
|
|
|
|
|
|
|
|
*puid = le32_to_cpu(psid->sub_auth[1]);
|
|
|
|
} else /* 3 subauths, ie Windows/Mac style */ {
|
|
|
|
*puid = le32_to_cpu(psid->sub_auth[0]);
|
|
|
|
if ((psid->sub_auth[0] != pwell_known_sid->sub_auth[0]) ||
|
|
|
|
(psid->sub_auth[1] != pwell_known_sid->sub_auth[1]))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
*puid = le32_to_cpu(psid->sub_auth[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
cifs_dbg(FYI, "Unix UID %d returned from SID\n", *puid);
|
|
|
|
return true; /* well known sid found, uid returned */
|
|
|
|
}
|
|
|
|
|
cifs: fix potential buffer overrun in cifs.idmap handling code
The userspace cifs.idmap program generally works with the wbclient libs
to generate binary SIDs in userspace. That program defines the struct
that holds these values as having a max of 15 subauthorities. The kernel
idmapping code however limits that value to 5.
When the kernel copies those values around though, it doesn't sanity
check the num_subauths value handed back from userspace or from the
server. It's possible therefore for userspace to hand us back a bogus
num_subauths value (or one that's valid, but greater than 5) that could
cause the kernel to walk off the end of the cifs_sid->sub_auths array.
Fix this by defining a new routine for copying sids and using that in
all of the places that copy it. If we end up with a sid that's longer
than expected then this approach will just lop off the "extra" subauths,
but that's basically what the code does today already. Better approaches
might be to fix this code to reject SIDs with >5 subauths, or fix it
to handle the subauths array dynamically.
At the same time, change the kernel to check the length of the data
returned by userspace. If it's shorter than struct cifs_sid, reject it
and return -EIO. If that happens we'll end up with fields that are
basically uninitialized.
Long term, it might make sense to redefine cifs_sid using a flexarray at
the end, to allow for variable-length subauth lists, and teach the code
to handle the case where the subauths array being passed in from
userspace is shorter than 5 elements.
Note too, that I don't consider this a security issue since you'd need
a compromised cifs.idmap program. If you have that, you can do all sorts
of nefarious stuff. Still, this is probably reasonable for stable.
Cc: stable@kernel.org
Reviewed-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
2012-11-03 21:37:28 +08:00
|
|
|
static void
|
|
|
|
cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
|
|
|
|
{
|
2012-11-25 21:00:37 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
dst->revision = src->revision;
|
2012-11-25 21:00:37 +08:00
|
|
|
dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
|
2012-11-25 21:00:37 +08:00
|
|
|
for (i = 0; i < NUM_AUTHS; ++i)
|
|
|
|
dst->authority[i] = src->authority[i];
|
|
|
|
for (i = 0; i < dst->num_subauth; ++i)
|
|
|
|
dst->sub_auth[i] = src->sub_auth[i];
|
cifs: fix potential buffer overrun in cifs.idmap handling code
The userspace cifs.idmap program generally works with the wbclient libs
to generate binary SIDs in userspace. That program defines the struct
that holds these values as having a max of 15 subauthorities. The kernel
idmapping code however limits that value to 5.
When the kernel copies those values around though, it doesn't sanity
check the num_subauths value handed back from userspace or from the
server. It's possible therefore for userspace to hand us back a bogus
num_subauths value (or one that's valid, but greater than 5) that could
cause the kernel to walk off the end of the cifs_sid->sub_auths array.
Fix this by defining a new routine for copying sids and using that in
all of the places that copy it. If we end up with a sid that's longer
than expected then this approach will just lop off the "extra" subauths,
but that's basically what the code does today already. Better approaches
might be to fix this code to reject SIDs with >5 subauths, or fix it
to handle the subauths array dynamically.
At the same time, change the kernel to check the length of the data
returned by userspace. If it's shorter than struct cifs_sid, reject it
and return -EIO. If that happens we'll end up with fields that are
basically uninitialized.
Long term, it might make sense to redefine cifs_sid using a flexarray at
the end, to allow for variable-length subauth lists, and teach the code
to handle the case where the subauths array being passed in from
userspace is shorter than 5 elements.
Note too, that I don't consider this a security issue since you'd need
a compromised cifs.idmap program. If you have that, you can do all sorts
of nefarious stuff. Still, this is probably reasonable for stable.
Cc: stable@kernel.org
Reviewed-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
2012-11-03 21:37:28 +08:00
|
|
|
}
|
|
|
|
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
static int
|
2012-12-03 19:05:29 +08:00
|
|
|
id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
{
|
2012-12-03 19:05:29 +08:00
|
|
|
int rc;
|
cifs: Add data structures and functions for uid/gid to SID mapping (try #4)
Add data structures and functions necessary to map a uid and gid to SID.
These functions are very similar to the ones used to map a SID to uid and gid.
This time, instead of storing sid to id mapping sorted on a sid value,
id to sid is stored, sorted on an id.
A cifs upcall sends an id (uid or gid) and expects a SID structure
in return, if mapping was done successfully.
A failed id to sid mapping to EINVAL.
This patchset aims to enable chown and chgrp commands when
cifsacl mount option is specified, especially to Windows SMB servers.
Currently we can't do that. So now along with chmod command,
chown and chgrp work.
Winbind is used to map id to a SID. chown and chgrp use an upcall
to provide an id to winbind and upcall returns with corrosponding
SID if any exists. That SID is used to build security descriptor.
The DACL part of a security descriptor is not changed by either
chown or chgrp functionality.
cifs client maintains a separate caches for uid to SID and
gid to SID mapping. This is similar to the one used earlier
to map SID to id (as part of ID mapping code).
I tested it by mounting shares from a Windows (2003) server by
authenticating as two users, one at a time, as Administrator and
as a ordinary user.
And then attempting to change owner of a file on the share.
Depending on the permissions/privileges at the server for that file,
chown request fails to either open a file (to change the ownership)
or to set security descriptor.
So it all depends on privileges on the file at the server and what
user you are authenticated as at the server, cifs client is just a
conduit.
I compared the security descriptor during chown command to that
what smbcacls sends when it is used with -M OWNNER: option
and they are similar.
This patchset aim to enable chown and chgrp commands when
cifsacl mount option is specified, especially to Windows SMB servers.
Currently we can't do that. So now along with chmod command,
chown and chgrp work.
I tested it by mounting shares from a Windows (2003) server by
authenticating as two users, one at a time, as Administrator and
as a ordinary user.
And then attempting to change owner of a file on the share.
Depending on the permissions/privileges at the server for that file,
chown request fails to either open a file (to change the ownership)
or to set security descriptor.
So it all depends on privileges on the file at the server and what
user you are authenticated as at the server, cifs client is just a
conduit.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Steve French <smfrench@gmail.com>
2011-08-10 03:30:48 +08:00
|
|
|
struct key *sidkey;
|
2012-12-03 19:05:30 +08:00
|
|
|
struct cifs_sid *ksid;
|
|
|
|
unsigned int ksid_size;
|
2012-12-03 19:05:29 +08:00
|
|
|
char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
|
cifs: Add data structures and functions for uid/gid to SID mapping (try #4)
Add data structures and functions necessary to map a uid and gid to SID.
These functions are very similar to the ones used to map a SID to uid and gid.
This time, instead of storing sid to id mapping sorted on a sid value,
id to sid is stored, sorted on an id.
A cifs upcall sends an id (uid or gid) and expects a SID structure
in return, if mapping was done successfully.
A failed id to sid mapping to EINVAL.
This patchset aims to enable chown and chgrp commands when
cifsacl mount option is specified, especially to Windows SMB servers.
Currently we can't do that. So now along with chmod command,
chown and chgrp work.
Winbind is used to map id to a SID. chown and chgrp use an upcall
to provide an id to winbind and upcall returns with corrosponding
SID if any exists. That SID is used to build security descriptor.
The DACL part of a security descriptor is not changed by either
chown or chgrp functionality.
cifs client maintains a separate caches for uid to SID and
gid to SID mapping. This is similar to the one used earlier
to map SID to id (as part of ID mapping code).
I tested it by mounting shares from a Windows (2003) server by
authenticating as two users, one at a time, as Administrator and
as a ordinary user.
And then attempting to change owner of a file on the share.
Depending on the permissions/privileges at the server for that file,
chown request fails to either open a file (to change the ownership)
or to set security descriptor.
So it all depends on privileges on the file at the server and what
user you are authenticated as at the server, cifs client is just a
conduit.
I compared the security descriptor during chown command to that
what smbcacls sends when it is used with -M OWNNER: option
and they are similar.
This patchset aim to enable chown and chgrp commands when
cifsacl mount option is specified, especially to Windows SMB servers.
Currently we can't do that. So now along with chmod command,
chown and chgrp work.
I tested it by mounting shares from a Windows (2003) server by
authenticating as two users, one at a time, as Administrator and
as a ordinary user.
And then attempting to change owner of a file on the share.
Depending on the permissions/privileges at the server for that file,
chown request fails to either open a file (to change the ownership)
or to set security descriptor.
So it all depends on privileges on the file at the server and what
user you are authenticated as at the server, cifs client is just a
conduit.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Steve French <smfrench@gmail.com>
2011-08-10 03:30:48 +08:00
|
|
|
const struct cred *saved_cred;
|
|
|
|
|
2012-12-03 19:05:29 +08:00
|
|
|
rc = snprintf(desc, sizeof(desc), "%ci:%u",
|
|
|
|
sidtype == SIDOWNER ? 'o' : 'g', cid);
|
|
|
|
if (rc >= sizeof(desc))
|
|
|
|
return -EINVAL;
|
cifs: Add data structures and functions for uid/gid to SID mapping (try #4)
Add data structures and functions necessary to map a uid and gid to SID.
These functions are very similar to the ones used to map a SID to uid and gid.
This time, instead of storing sid to id mapping sorted on a sid value,
id to sid is stored, sorted on an id.
A cifs upcall sends an id (uid or gid) and expects a SID structure
in return, if mapping was done successfully.
A failed id to sid mapping to EINVAL.
This patchset aims to enable chown and chgrp commands when
cifsacl mount option is specified, especially to Windows SMB servers.
Currently we can't do that. So now along with chmod command,
chown and chgrp work.
Winbind is used to map id to a SID. chown and chgrp use an upcall
to provide an id to winbind and upcall returns with corrosponding
SID if any exists. That SID is used to build security descriptor.
The DACL part of a security descriptor is not changed by either
chown or chgrp functionality.
cifs client maintains a separate caches for uid to SID and
gid to SID mapping. This is similar to the one used earlier
to map SID to id (as part of ID mapping code).
I tested it by mounting shares from a Windows (2003) server by
authenticating as two users, one at a time, as Administrator and
as a ordinary user.
And then attempting to change owner of a file on the share.
Depending on the permissions/privileges at the server for that file,
chown request fails to either open a file (to change the ownership)
or to set security descriptor.
So it all depends on privileges on the file at the server and what
user you are authenticated as at the server, cifs client is just a
conduit.
I compared the security descriptor during chown command to that
what smbcacls sends when it is used with -M OWNNER: option
and they are similar.
This patchset aim to enable chown and chgrp commands when
cifsacl mount option is specified, especially to Windows SMB servers.
Currently we can't do that. So now along with chmod command,
chown and chgrp work.
I tested it by mounting shares from a Windows (2003) server by
authenticating as two users, one at a time, as Administrator and
as a ordinary user.
And then attempting to change owner of a file on the share.
Depending on the permissions/privileges at the server for that file,
chown request fails to either open a file (to change the ownership)
or to set security descriptor.
So it all depends on privileges on the file at the server and what
user you are authenticated as at the server, cifs client is just a
conduit.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Steve French <smfrench@gmail.com>
2011-08-10 03:30:48 +08:00
|
|
|
|
2012-12-03 19:05:29 +08:00
|
|
|
rc = 0;
|
|
|
|
saved_cred = override_creds(root_cred);
|
keys: Replace uid/gid/perm permissions checking with an ACL
Replace the uid/gid/perm permissions checking on a key with an ACL to allow
the SETATTR and SEARCH permissions to be split. This will also allow a
greater range of subjects to represented.
============
WHY DO THIS?
============
The problem is that SETATTR and SEARCH cover a slew of actions, not all of
which should be grouped together.
For SETATTR, this includes actions that are about controlling access to a
key:
(1) Changing a key's ownership.
(2) Changing a key's security information.
(3) Setting a keyring's restriction.
And actions that are about managing a key's lifetime:
(4) Setting an expiry time.
(5) Revoking a key.
and (proposed) managing a key as part of a cache:
(6) Invalidating a key.
Managing a key's lifetime doesn't really have anything to do with
controlling access to that key.
Expiry time is awkward since it's more about the lifetime of the content
and so, in some ways goes better with WRITE permission. It can, however,
be set unconditionally by a process with an appropriate authorisation token
for instantiating a key, and can also be set by the key type driver when a
key is instantiated, so lumping it with the access-controlling actions is
probably okay.
As for SEARCH permission, that currently covers:
(1) Finding keys in a keyring tree during a search.
(2) Permitting keyrings to be joined.
(3) Invalidation.
But these don't really belong together either, since these actions really
need to be controlled separately.
Finally, there are number of special cases to do with granting the
administrator special rights to invalidate or clear keys that I would like
to handle with the ACL rather than key flags and special checks.
===============
WHAT IS CHANGED
===============
The SETATTR permission is split to create two new permissions:
(1) SET_SECURITY - which allows the key's owner, group and ACL to be
changed and a restriction to be placed on a keyring.
(2) REVOKE - which allows a key to be revoked.
The SEARCH permission is split to create:
(1) SEARCH - which allows a keyring to be search and a key to be found.
(2) JOIN - which allows a keyring to be joined as a session keyring.
(3) INVAL - which allows a key to be invalidated.
The WRITE permission is also split to create:
(1) WRITE - which allows a key's content to be altered and links to be
added, removed and replaced in a keyring.
(2) CLEAR - which allows a keyring to be cleared completely. This is
split out to make it possible to give just this to an administrator.
(3) REVOKE - see above.
Keys acquire ACLs which consist of a series of ACEs, and all that apply are
unioned together. An ACE specifies a subject, such as:
(*) Possessor - permitted to anyone who 'possesses' a key
(*) Owner - permitted to the key owner
(*) Group - permitted to the key group
(*) Everyone - permitted to everyone
Note that 'Other' has been replaced with 'Everyone' on the assumption that
you wouldn't grant a permit to 'Other' that you wouldn't also grant to
everyone else.
Further subjects may be made available by later patches.
The ACE also specifies a permissions mask. The set of permissions is now:
VIEW Can view the key metadata
READ Can read the key content
WRITE Can update/modify the key content
SEARCH Can find the key by searching/requesting
LINK Can make a link to the key
SET_SECURITY Can change owner, ACL, expiry
INVAL Can invalidate
REVOKE Can revoke
JOIN Can join this keyring
CLEAR Can clear this keyring
The KEYCTL_SETPERM function is then deprecated.
The KEYCTL_SET_TIMEOUT function then is permitted if SET_SECURITY is set,
or if the caller has a valid instantiation auth token.
The KEYCTL_INVALIDATE function then requires INVAL.
The KEYCTL_REVOKE function then requires REVOKE.
The KEYCTL_JOIN_SESSION_KEYRING function then requires JOIN to join an
existing keyring.
The JOIN permission is enabled by default for session keyrings and manually
created keyrings only.
======================
BACKWARD COMPATIBILITY
======================
To maintain backward compatibility, KEYCTL_SETPERM will translate the
permissions mask it is given into a new ACL for a key - unless
KEYCTL_SET_ACL has been called on that key, in which case an error will be
returned.
It will convert possessor, owner, group and other permissions into separate
ACEs, if each portion of the mask is non-zero.
SETATTR permission turns on all of INVAL, REVOKE and SET_SECURITY. WRITE
permission turns on WRITE, REVOKE and, if a keyring, CLEAR. JOIN is turned
on if a keyring is being altered.
The KEYCTL_DESCRIBE function translates the ACL back into a permissions
mask to return depending on possessor, owner, group and everyone ACEs.
It will make the following mappings:
(1) INVAL, JOIN -> SEARCH
(2) SET_SECURITY -> SETATTR
(3) REVOKE -> WRITE if SETATTR isn't already set
(4) CLEAR -> WRITE
Note that the value subsequently returned by KEYCTL_DESCRIBE may not match
the value set with KEYCTL_SETATTR.
=======
TESTING
=======
This passes the keyutils testsuite for all but a couple of tests:
(1) tests/keyctl/dh_compute/badargs: The first wrong-key-type test now
returns EOPNOTSUPP rather than ENOKEY as READ permission isn't removed
if the type doesn't have ->read(). You still can't actually read the
key.
(2) tests/keyctl/permitting/valid: The view-other-permissions test doesn't
work as Other has been replaced with Everyone in the ACL.
Signed-off-by: David Howells <dhowells@redhat.com>
2019-06-28 06:03:07 +08:00
|
|
|
sidkey = request_key(&cifs_idmap_key_type, desc, "",
|
|
|
|
&cifs_idmap_key_acl);
|
2012-12-03 19:05:29 +08:00
|
|
|
if (IS_ERR(sidkey)) {
|
cifs: Add data structures and functions for uid/gid to SID mapping (try #4)
Add data structures and functions necessary to map a uid and gid to SID.
These functions are very similar to the ones used to map a SID to uid and gid.
This time, instead of storing sid to id mapping sorted on a sid value,
id to sid is stored, sorted on an id.
A cifs upcall sends an id (uid or gid) and expects a SID structure
in return, if mapping was done successfully.
A failed id to sid mapping to EINVAL.
This patchset aims to enable chown and chgrp commands when
cifsacl mount option is specified, especially to Windows SMB servers.
Currently we can't do that. So now along with chmod command,
chown and chgrp work.
Winbind is used to map id to a SID. chown and chgrp use an upcall
to provide an id to winbind and upcall returns with corrosponding
SID if any exists. That SID is used to build security descriptor.
The DACL part of a security descriptor is not changed by either
chown or chgrp functionality.
cifs client maintains a separate caches for uid to SID and
gid to SID mapping. This is similar to the one used earlier
to map SID to id (as part of ID mapping code).
I tested it by mounting shares from a Windows (2003) server by
authenticating as two users, one at a time, as Administrator and
as a ordinary user.
And then attempting to change owner of a file on the share.
Depending on the permissions/privileges at the server for that file,
chown request fails to either open a file (to change the ownership)
or to set security descriptor.
So it all depends on privileges on the file at the server and what
user you are authenticated as at the server, cifs client is just a
conduit.
I compared the security descriptor during chown command to that
what smbcacls sends when it is used with -M OWNNER: option
and they are similar.
This patchset aim to enable chown and chgrp commands when
cifsacl mount option is specified, especially to Windows SMB servers.
Currently we can't do that. So now along with chmod command,
chown and chgrp work.
I tested it by mounting shares from a Windows (2003) server by
authenticating as two users, one at a time, as Administrator and
as a ordinary user.
And then attempting to change owner of a file on the share.
Depending on the permissions/privileges at the server for that file,
chown request fails to either open a file (to change the ownership)
or to set security descriptor.
So it all depends on privileges on the file at the server and what
user you are authenticated as at the server, cifs client is just a
conduit.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Steve French <smfrench@gmail.com>
2011-08-10 03:30:48 +08:00
|
|
|
rc = -EINVAL;
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "%s: Can't map %cid %u to a SID\n",
|
|
|
|
__func__, sidtype == SIDOWNER ? 'u' : 'g', cid);
|
2012-12-03 19:05:29 +08:00
|
|
|
goto out_revert_creds;
|
|
|
|
} else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
|
|
|
|
rc = -EIO;
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
|
|
|
|
__func__, sidkey->datalen);
|
2012-12-03 19:05:30 +08:00
|
|
|
goto invalidate_key;
|
cifs: Add data structures and functions for uid/gid to SID mapping (try #4)
Add data structures and functions necessary to map a uid and gid to SID.
These functions are very similar to the ones used to map a SID to uid and gid.
This time, instead of storing sid to id mapping sorted on a sid value,
id to sid is stored, sorted on an id.
A cifs upcall sends an id (uid or gid) and expects a SID structure
in return, if mapping was done successfully.
A failed id to sid mapping to EINVAL.
This patchset aims to enable chown and chgrp commands when
cifsacl mount option is specified, especially to Windows SMB servers.
Currently we can't do that. So now along with chmod command,
chown and chgrp work.
Winbind is used to map id to a SID. chown and chgrp use an upcall
to provide an id to winbind and upcall returns with corrosponding
SID if any exists. That SID is used to build security descriptor.
The DACL part of a security descriptor is not changed by either
chown or chgrp functionality.
cifs client maintains a separate caches for uid to SID and
gid to SID mapping. This is similar to the one used earlier
to map SID to id (as part of ID mapping code).
I tested it by mounting shares from a Windows (2003) server by
authenticating as two users, one at a time, as Administrator and
as a ordinary user.
And then attempting to change owner of a file on the share.
Depending on the permissions/privileges at the server for that file,
chown request fails to either open a file (to change the ownership)
or to set security descriptor.
So it all depends on privileges on the file at the server and what
user you are authenticated as at the server, cifs client is just a
conduit.
I compared the security descriptor during chown command to that
what smbcacls sends when it is used with -M OWNNER: option
and they are similar.
This patchset aim to enable chown and chgrp commands when
cifsacl mount option is specified, especially to Windows SMB servers.
Currently we can't do that. So now along with chmod command,
chown and chgrp work.
I tested it by mounting shares from a Windows (2003) server by
authenticating as two users, one at a time, as Administrator and
as a ordinary user.
And then attempting to change owner of a file on the share.
Depending on the permissions/privileges at the server for that file,
chown request fails to either open a file (to change the ownership)
or to set security descriptor.
So it all depends on privileges on the file at the server and what
user you are authenticated as at the server, cifs client is just a
conduit.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Steve French <smfrench@gmail.com>
2011-08-10 03:30:48 +08:00
|
|
|
}
|
2012-12-03 19:05:30 +08:00
|
|
|
|
2012-12-03 19:05:31 +08:00
|
|
|
/*
|
|
|
|
* A sid is usually too large to be embedded in payload.value, but if
|
|
|
|
* there are no subauthorities and the host has 8-byte pointers, then
|
|
|
|
* it could be.
|
|
|
|
*/
|
|
|
|
ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
|
2015-10-21 21:04:48 +08:00
|
|
|
(struct cifs_sid *)&sidkey->payload :
|
|
|
|
(struct cifs_sid *)sidkey->payload.data[0];
|
2012-12-03 19:05:31 +08:00
|
|
|
|
2012-12-03 19:05:30 +08:00
|
|
|
ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
|
|
|
|
if (ksid_size > sidkey->datalen) {
|
|
|
|
rc = -EIO;
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n",
|
|
|
|
__func__, sidkey->datalen, ksid_size);
|
2012-12-03 19:05:30 +08:00
|
|
|
goto invalidate_key;
|
|
|
|
}
|
2012-12-03 19:05:31 +08:00
|
|
|
|
2012-12-03 19:05:30 +08:00
|
|
|
cifs_copy_sid(ssid, ksid);
|
2012-12-03 19:05:29 +08:00
|
|
|
out_key_put:
|
|
|
|
key_put(sidkey);
|
|
|
|
out_revert_creds:
|
|
|
|
revert_creds(saved_cred);
|
cifs: Add data structures and functions for uid/gid to SID mapping (try #4)
Add data structures and functions necessary to map a uid and gid to SID.
These functions are very similar to the ones used to map a SID to uid and gid.
This time, instead of storing sid to id mapping sorted on a sid value,
id to sid is stored, sorted on an id.
A cifs upcall sends an id (uid or gid) and expects a SID structure
in return, if mapping was done successfully.
A failed id to sid mapping to EINVAL.
This patchset aims to enable chown and chgrp commands when
cifsacl mount option is specified, especially to Windows SMB servers.
Currently we can't do that. So now along with chmod command,
chown and chgrp work.
Winbind is used to map id to a SID. chown and chgrp use an upcall
to provide an id to winbind and upcall returns with corrosponding
SID if any exists. That SID is used to build security descriptor.
The DACL part of a security descriptor is not changed by either
chown or chgrp functionality.
cifs client maintains a separate caches for uid to SID and
gid to SID mapping. This is similar to the one used earlier
to map SID to id (as part of ID mapping code).
I tested it by mounting shares from a Windows (2003) server by
authenticating as two users, one at a time, as Administrator and
as a ordinary user.
And then attempting to change owner of a file on the share.
Depending on the permissions/privileges at the server for that file,
chown request fails to either open a file (to change the ownership)
or to set security descriptor.
So it all depends on privileges on the file at the server and what
user you are authenticated as at the server, cifs client is just a
conduit.
I compared the security descriptor during chown command to that
what smbcacls sends when it is used with -M OWNNER: option
and they are similar.
This patchset aim to enable chown and chgrp commands when
cifsacl mount option is specified, especially to Windows SMB servers.
Currently we can't do that. So now along with chmod command,
chown and chgrp work.
I tested it by mounting shares from a Windows (2003) server by
authenticating as two users, one at a time, as Administrator and
as a ordinary user.
And then attempting to change owner of a file on the share.
Depending on the permissions/privileges at the server for that file,
chown request fails to either open a file (to change the ownership)
or to set security descriptor.
So it all depends on privileges on the file at the server and what
user you are authenticated as at the server, cifs client is just a
conduit.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Steve French <smfrench@gmail.com>
2011-08-10 03:30:48 +08:00
|
|
|
return rc;
|
2012-12-03 19:05:30 +08:00
|
|
|
|
|
|
|
invalidate_key:
|
|
|
|
key_invalidate(sidkey);
|
|
|
|
goto out_key_put;
|
cifs: Add data structures and functions for uid/gid to SID mapping (try #4)
Add data structures and functions necessary to map a uid and gid to SID.
These functions are very similar to the ones used to map a SID to uid and gid.
This time, instead of storing sid to id mapping sorted on a sid value,
id to sid is stored, sorted on an id.
A cifs upcall sends an id (uid or gid) and expects a SID structure
in return, if mapping was done successfully.
A failed id to sid mapping to EINVAL.
This patchset aims to enable chown and chgrp commands when
cifsacl mount option is specified, especially to Windows SMB servers.
Currently we can't do that. So now along with chmod command,
chown and chgrp work.
Winbind is used to map id to a SID. chown and chgrp use an upcall
to provide an id to winbind and upcall returns with corrosponding
SID if any exists. That SID is used to build security descriptor.
The DACL part of a security descriptor is not changed by either
chown or chgrp functionality.
cifs client maintains a separate caches for uid to SID and
gid to SID mapping. This is similar to the one used earlier
to map SID to id (as part of ID mapping code).
I tested it by mounting shares from a Windows (2003) server by
authenticating as two users, one at a time, as Administrator and
as a ordinary user.
And then attempting to change owner of a file on the share.
Depending on the permissions/privileges at the server for that file,
chown request fails to either open a file (to change the ownership)
or to set security descriptor.
So it all depends on privileges on the file at the server and what
user you are authenticated as at the server, cifs client is just a
conduit.
I compared the security descriptor during chown command to that
what smbcacls sends when it is used with -M OWNNER: option
and they are similar.
This patchset aim to enable chown and chgrp commands when
cifsacl mount option is specified, especially to Windows SMB servers.
Currently we can't do that. So now along with chmod command,
chown and chgrp work.
I tested it by mounting shares from a Windows (2003) server by
authenticating as two users, one at a time, as Administrator and
as a ordinary user.
And then attempting to change owner of a file on the share.
Depending on the permissions/privileges at the server for that file,
chown request fails to either open a file (to change the ownership)
or to set security descriptor.
So it all depends on privileges on the file at the server and what
user you are authenticated as at the server, cifs client is just a
conduit.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Steve French <smfrench@gmail.com>
2011-08-10 03:30:48 +08:00
|
|
|
}
|
|
|
|
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
static int
|
|
|
|
sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
|
|
|
|
struct cifs_fattr *fattr, uint sidtype)
|
|
|
|
{
|
|
|
|
int rc;
|
2012-12-03 19:05:29 +08:00
|
|
|
struct key *sidkey;
|
|
|
|
char *sidstr;
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
const struct cred *saved_cred;
|
2013-02-06 16:33:17 +08:00
|
|
|
kuid_t fuid = cifs_sb->mnt_uid;
|
|
|
|
kgid_t fgid = cifs_sb->mnt_gid;
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
|
|
|
|
/*
|
2012-12-03 19:05:29 +08:00
|
|
|
* If we have too many subauthorities, then something is really wrong.
|
|
|
|
* Just return an error.
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
*/
|
2012-12-03 19:05:29 +08:00
|
|
|
if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "%s: %u subauthorities is too many!\n",
|
|
|
|
__func__, psid->num_subauth);
|
2012-12-03 19:05:29 +08:00
|
|
|
return -EIO;
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
}
|
|
|
|
|
2016-10-14 08:06:23 +08:00
|
|
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) {
|
|
|
|
uint32_t unix_id;
|
|
|
|
bool is_group;
|
|
|
|
|
|
|
|
if (sidtype != SIDOWNER)
|
|
|
|
is_group = true;
|
|
|
|
else
|
|
|
|
is_group = false;
|
|
|
|
|
|
|
|
if (is_well_known_sid(psid, &unix_id, is_group) == false)
|
|
|
|
goto try_upcall_to_get_id;
|
|
|
|
|
|
|
|
if (is_group) {
|
|
|
|
kgid_t gid;
|
|
|
|
gid_t id;
|
|
|
|
|
|
|
|
id = (gid_t)unix_id;
|
|
|
|
gid = make_kgid(&init_user_ns, id);
|
|
|
|
if (gid_valid(gid)) {
|
|
|
|
fgid = gid;
|
|
|
|
goto got_valid_id;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
kuid_t uid;
|
|
|
|
uid_t id;
|
|
|
|
|
|
|
|
id = (uid_t)unix_id;
|
|
|
|
uid = make_kuid(&init_user_ns, id);
|
|
|
|
if (uid_valid(uid)) {
|
|
|
|
fuid = uid;
|
|
|
|
goto got_valid_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* If unable to find uid/gid easily from SID try via upcall */
|
|
|
|
}
|
|
|
|
|
|
|
|
try_upcall_to_get_id:
|
2012-12-03 19:05:29 +08:00
|
|
|
sidstr = sid_to_key_str(psid, sidtype);
|
|
|
|
if (!sidstr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
saved_cred = override_creds(root_cred);
|
keys: Replace uid/gid/perm permissions checking with an ACL
Replace the uid/gid/perm permissions checking on a key with an ACL to allow
the SETATTR and SEARCH permissions to be split. This will also allow a
greater range of subjects to represented.
============
WHY DO THIS?
============
The problem is that SETATTR and SEARCH cover a slew of actions, not all of
which should be grouped together.
For SETATTR, this includes actions that are about controlling access to a
key:
(1) Changing a key's ownership.
(2) Changing a key's security information.
(3) Setting a keyring's restriction.
And actions that are about managing a key's lifetime:
(4) Setting an expiry time.
(5) Revoking a key.
and (proposed) managing a key as part of a cache:
(6) Invalidating a key.
Managing a key's lifetime doesn't really have anything to do with
controlling access to that key.
Expiry time is awkward since it's more about the lifetime of the content
and so, in some ways goes better with WRITE permission. It can, however,
be set unconditionally by a process with an appropriate authorisation token
for instantiating a key, and can also be set by the key type driver when a
key is instantiated, so lumping it with the access-controlling actions is
probably okay.
As for SEARCH permission, that currently covers:
(1) Finding keys in a keyring tree during a search.
(2) Permitting keyrings to be joined.
(3) Invalidation.
But these don't really belong together either, since these actions really
need to be controlled separately.
Finally, there are number of special cases to do with granting the
administrator special rights to invalidate or clear keys that I would like
to handle with the ACL rather than key flags and special checks.
===============
WHAT IS CHANGED
===============
The SETATTR permission is split to create two new permissions:
(1) SET_SECURITY - which allows the key's owner, group and ACL to be
changed and a restriction to be placed on a keyring.
(2) REVOKE - which allows a key to be revoked.
The SEARCH permission is split to create:
(1) SEARCH - which allows a keyring to be search and a key to be found.
(2) JOIN - which allows a keyring to be joined as a session keyring.
(3) INVAL - which allows a key to be invalidated.
The WRITE permission is also split to create:
(1) WRITE - which allows a key's content to be altered and links to be
added, removed and replaced in a keyring.
(2) CLEAR - which allows a keyring to be cleared completely. This is
split out to make it possible to give just this to an administrator.
(3) REVOKE - see above.
Keys acquire ACLs which consist of a series of ACEs, and all that apply are
unioned together. An ACE specifies a subject, such as:
(*) Possessor - permitted to anyone who 'possesses' a key
(*) Owner - permitted to the key owner
(*) Group - permitted to the key group
(*) Everyone - permitted to everyone
Note that 'Other' has been replaced with 'Everyone' on the assumption that
you wouldn't grant a permit to 'Other' that you wouldn't also grant to
everyone else.
Further subjects may be made available by later patches.
The ACE also specifies a permissions mask. The set of permissions is now:
VIEW Can view the key metadata
READ Can read the key content
WRITE Can update/modify the key content
SEARCH Can find the key by searching/requesting
LINK Can make a link to the key
SET_SECURITY Can change owner, ACL, expiry
INVAL Can invalidate
REVOKE Can revoke
JOIN Can join this keyring
CLEAR Can clear this keyring
The KEYCTL_SETPERM function is then deprecated.
The KEYCTL_SET_TIMEOUT function then is permitted if SET_SECURITY is set,
or if the caller has a valid instantiation auth token.
The KEYCTL_INVALIDATE function then requires INVAL.
The KEYCTL_REVOKE function then requires REVOKE.
The KEYCTL_JOIN_SESSION_KEYRING function then requires JOIN to join an
existing keyring.
The JOIN permission is enabled by default for session keyrings and manually
created keyrings only.
======================
BACKWARD COMPATIBILITY
======================
To maintain backward compatibility, KEYCTL_SETPERM will translate the
permissions mask it is given into a new ACL for a key - unless
KEYCTL_SET_ACL has been called on that key, in which case an error will be
returned.
It will convert possessor, owner, group and other permissions into separate
ACEs, if each portion of the mask is non-zero.
SETATTR permission turns on all of INVAL, REVOKE and SET_SECURITY. WRITE
permission turns on WRITE, REVOKE and, if a keyring, CLEAR. JOIN is turned
on if a keyring is being altered.
The KEYCTL_DESCRIBE function translates the ACL back into a permissions
mask to return depending on possessor, owner, group and everyone ACEs.
It will make the following mappings:
(1) INVAL, JOIN -> SEARCH
(2) SET_SECURITY -> SETATTR
(3) REVOKE -> WRITE if SETATTR isn't already set
(4) CLEAR -> WRITE
Note that the value subsequently returned by KEYCTL_DESCRIBE may not match
the value set with KEYCTL_SETATTR.
=======
TESTING
=======
This passes the keyutils testsuite for all but a couple of tests:
(1) tests/keyctl/dh_compute/badargs: The first wrong-key-type test now
returns EOPNOTSUPP rather than ENOKEY as READ permission isn't removed
if the type doesn't have ->read(). You still can't actually read the
key.
(2) tests/keyctl/permitting/valid: The view-other-permissions test doesn't
work as Other has been replaced with Everyone in the ACL.
Signed-off-by: David Howells <dhowells@redhat.com>
2019-06-28 06:03:07 +08:00
|
|
|
sidkey = request_key(&cifs_idmap_key_type, sidstr, "",
|
|
|
|
&cifs_idmap_key_acl);
|
2012-12-03 19:05:29 +08:00
|
|
|
if (IS_ERR(sidkey)) {
|
|
|
|
rc = -EINVAL;
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "%s: Can't map SID %s to a %cid\n",
|
|
|
|
__func__, sidstr, sidtype == SIDOWNER ? 'u' : 'g');
|
2012-12-03 19:05:29 +08:00
|
|
|
goto out_revert_creds;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME: Here we assume that uid_t and gid_t are same size. It's
|
|
|
|
* probably a safe assumption but might be better to check based on
|
|
|
|
* sidtype.
|
|
|
|
*/
|
2013-02-06 16:10:23 +08:00
|
|
|
BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
|
2012-12-03 19:05:29 +08:00
|
|
|
if (sidkey->datalen != sizeof(uid_t)) {
|
2012-12-03 19:05:29 +08:00
|
|
|
rc = -EIO;
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
|
|
|
|
__func__, sidkey->datalen);
|
2012-12-03 19:05:30 +08:00
|
|
|
key_invalidate(sidkey);
|
2012-12-03 19:05:29 +08:00
|
|
|
goto out_key_put;
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
}
|
|
|
|
|
2013-02-06 16:33:17 +08:00
|
|
|
if (sidtype == SIDOWNER) {
|
|
|
|
kuid_t uid;
|
|
|
|
uid_t id;
|
2015-10-21 21:04:48 +08:00
|
|
|
memcpy(&id, &sidkey->payload.data[0], sizeof(uid_t));
|
2013-02-06 16:33:17 +08:00
|
|
|
uid = make_kuid(&init_user_ns, id);
|
|
|
|
if (uid_valid(uid))
|
|
|
|
fuid = uid;
|
|
|
|
} else {
|
|
|
|
kgid_t gid;
|
|
|
|
gid_t id;
|
2015-10-21 21:04:48 +08:00
|
|
|
memcpy(&id, &sidkey->payload.data[0], sizeof(gid_t));
|
2013-02-06 16:33:17 +08:00
|
|
|
gid = make_kgid(&init_user_ns, id);
|
|
|
|
if (gid_valid(gid))
|
|
|
|
fgid = gid;
|
|
|
|
}
|
2012-12-03 19:05:29 +08:00
|
|
|
|
|
|
|
out_key_put:
|
|
|
|
key_put(sidkey);
|
|
|
|
out_revert_creds:
|
|
|
|
revert_creds(saved_cred);
|
|
|
|
kfree(sidstr);
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
|
2012-12-03 19:05:29 +08:00
|
|
|
/*
|
|
|
|
* Note that we return 0 here unconditionally. If the mapping
|
|
|
|
* fails then we just fall back to using the mnt_uid/mnt_gid.
|
|
|
|
*/
|
2016-10-14 08:06:23 +08:00
|
|
|
got_valid_id:
|
2012-12-03 19:05:29 +08:00
|
|
|
if (sidtype == SIDOWNER)
|
|
|
|
fattr->cf_uid = fuid;
|
|
|
|
else
|
|
|
|
fattr->cf_gid = fgid;
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-04-28 12:34:35 +08:00
|
|
|
int
|
|
|
|
init_cifs_idmap(void)
|
|
|
|
{
|
|
|
|
struct cred *cred;
|
|
|
|
struct key *keyring;
|
|
|
|
int ret;
|
|
|
|
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "Registering the %s key type\n",
|
|
|
|
cifs_idmap_key_type.name);
|
2011-04-28 12:34:35 +08:00
|
|
|
|
|
|
|
/* create an override credential set with a special thread keyring in
|
|
|
|
* which requests are cached
|
|
|
|
*
|
|
|
|
* this is used to prevent malicious redirections from being installed
|
|
|
|
* with add_key().
|
|
|
|
*/
|
|
|
|
cred = prepare_kernel_cred(NULL);
|
|
|
|
if (!cred)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2013-02-06 16:21:22 +08:00
|
|
|
keyring = keyring_alloc(".cifs_idmap",
|
|
|
|
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
|
keys: Replace uid/gid/perm permissions checking with an ACL
Replace the uid/gid/perm permissions checking on a key with an ACL to allow
the SETATTR and SEARCH permissions to be split. This will also allow a
greater range of subjects to represented.
============
WHY DO THIS?
============
The problem is that SETATTR and SEARCH cover a slew of actions, not all of
which should be grouped together.
For SETATTR, this includes actions that are about controlling access to a
key:
(1) Changing a key's ownership.
(2) Changing a key's security information.
(3) Setting a keyring's restriction.
And actions that are about managing a key's lifetime:
(4) Setting an expiry time.
(5) Revoking a key.
and (proposed) managing a key as part of a cache:
(6) Invalidating a key.
Managing a key's lifetime doesn't really have anything to do with
controlling access to that key.
Expiry time is awkward since it's more about the lifetime of the content
and so, in some ways goes better with WRITE permission. It can, however,
be set unconditionally by a process with an appropriate authorisation token
for instantiating a key, and can also be set by the key type driver when a
key is instantiated, so lumping it with the access-controlling actions is
probably okay.
As for SEARCH permission, that currently covers:
(1) Finding keys in a keyring tree during a search.
(2) Permitting keyrings to be joined.
(3) Invalidation.
But these don't really belong together either, since these actions really
need to be controlled separately.
Finally, there are number of special cases to do with granting the
administrator special rights to invalidate or clear keys that I would like
to handle with the ACL rather than key flags and special checks.
===============
WHAT IS CHANGED
===============
The SETATTR permission is split to create two new permissions:
(1) SET_SECURITY - which allows the key's owner, group and ACL to be
changed and a restriction to be placed on a keyring.
(2) REVOKE - which allows a key to be revoked.
The SEARCH permission is split to create:
(1) SEARCH - which allows a keyring to be search and a key to be found.
(2) JOIN - which allows a keyring to be joined as a session keyring.
(3) INVAL - which allows a key to be invalidated.
The WRITE permission is also split to create:
(1) WRITE - which allows a key's content to be altered and links to be
added, removed and replaced in a keyring.
(2) CLEAR - which allows a keyring to be cleared completely. This is
split out to make it possible to give just this to an administrator.
(3) REVOKE - see above.
Keys acquire ACLs which consist of a series of ACEs, and all that apply are
unioned together. An ACE specifies a subject, such as:
(*) Possessor - permitted to anyone who 'possesses' a key
(*) Owner - permitted to the key owner
(*) Group - permitted to the key group
(*) Everyone - permitted to everyone
Note that 'Other' has been replaced with 'Everyone' on the assumption that
you wouldn't grant a permit to 'Other' that you wouldn't also grant to
everyone else.
Further subjects may be made available by later patches.
The ACE also specifies a permissions mask. The set of permissions is now:
VIEW Can view the key metadata
READ Can read the key content
WRITE Can update/modify the key content
SEARCH Can find the key by searching/requesting
LINK Can make a link to the key
SET_SECURITY Can change owner, ACL, expiry
INVAL Can invalidate
REVOKE Can revoke
JOIN Can join this keyring
CLEAR Can clear this keyring
The KEYCTL_SETPERM function is then deprecated.
The KEYCTL_SET_TIMEOUT function then is permitted if SET_SECURITY is set,
or if the caller has a valid instantiation auth token.
The KEYCTL_INVALIDATE function then requires INVAL.
The KEYCTL_REVOKE function then requires REVOKE.
The KEYCTL_JOIN_SESSION_KEYRING function then requires JOIN to join an
existing keyring.
The JOIN permission is enabled by default for session keyrings and manually
created keyrings only.
======================
BACKWARD COMPATIBILITY
======================
To maintain backward compatibility, KEYCTL_SETPERM will translate the
permissions mask it is given into a new ACL for a key - unless
KEYCTL_SET_ACL has been called on that key, in which case an error will be
returned.
It will convert possessor, owner, group and other permissions into separate
ACEs, if each portion of the mask is non-zero.
SETATTR permission turns on all of INVAL, REVOKE and SET_SECURITY. WRITE
permission turns on WRITE, REVOKE and, if a keyring, CLEAR. JOIN is turned
on if a keyring is being altered.
The KEYCTL_DESCRIBE function translates the ACL back into a permissions
mask to return depending on possessor, owner, group and everyone ACEs.
It will make the following mappings:
(1) INVAL, JOIN -> SEARCH
(2) SET_SECURITY -> SETATTR
(3) REVOKE -> WRITE if SETATTR isn't already set
(4) CLEAR -> WRITE
Note that the value subsequently returned by KEYCTL_DESCRIBE may not match
the value set with KEYCTL_SETATTR.
=======
TESTING
=======
This passes the keyutils testsuite for all but a couple of tests:
(1) tests/keyctl/dh_compute/badargs: The first wrong-key-type test now
returns EOPNOTSUPP rather than ENOKEY as READ permission isn't removed
if the type doesn't have ->read(). You still can't actually read the
key.
(2) tests/keyctl/permitting/valid: The view-other-permissions test doesn't
work as Other has been replaced with Everyone in the ACL.
Signed-off-by: David Howells <dhowells@redhat.com>
2019-06-28 06:03:07 +08:00
|
|
|
&cifs_idmap_keyring_acl,
|
KEYS: Add a facility to restrict new links into a keyring
Add a facility whereby proposed new links to be added to a keyring can be
vetted, permitting them to be rejected if necessary. This can be used to
block public keys from which the signature cannot be verified or for which
the signature verification fails. It could also be used to provide
blacklisting.
This affects operations like add_key(), KEYCTL_LINK and KEYCTL_INSTANTIATE.
To this end:
(1) A function pointer is added to the key struct that, if set, points to
the vetting function. This is called as:
int (*restrict_link)(struct key *keyring,
const struct key_type *key_type,
unsigned long key_flags,
const union key_payload *key_payload),
where 'keyring' will be the keyring being added to, key_type and
key_payload will describe the key being added and key_flags[*] can be
AND'ed with KEY_FLAG_TRUSTED.
[*] This parameter will be removed in a later patch when
KEY_FLAG_TRUSTED is removed.
The function should return 0 to allow the link to take place or an
error (typically -ENOKEY, -ENOPKG or -EKEYREJECTED) to reject the
link.
The pointer should not be set directly, but rather should be set
through keyring_alloc().
Note that if called during add_key(), preparse is called before this
method, but a key isn't actually allocated until after this function
is called.
(2) KEY_ALLOC_BYPASS_RESTRICTION is added. This can be passed to
key_create_or_update() or key_instantiate_and_link() to bypass the
restriction check.
(3) KEY_FLAG_TRUSTED_ONLY is removed. The entire contents of a keyring
with this restriction emplaced can be considered 'trustworthy' by
virtue of being in the keyring when that keyring is consulted.
(4) key_alloc() and keyring_alloc() take an extra argument that will be
used to set restrict_link in the new key. This ensures that the
pointer is set before the key is published, thus preventing a window
of unrestrictedness. Normally this argument will be NULL.
(5) As a temporary affair, keyring_restrict_trusted_only() is added. It
should be passed to keyring_alloc() as the extra argument instead of
setting KEY_FLAG_TRUSTED_ONLY on a keyring. This will be replaced in
a later patch with functions that look in the appropriate places for
authoritative keys.
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
2016-04-06 23:14:24 +08:00
|
|
|
KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
|
2011-04-28 12:34:35 +08:00
|
|
|
if (IS_ERR(keyring)) {
|
|
|
|
ret = PTR_ERR(keyring);
|
|
|
|
goto failed_put_cred;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = register_key_type(&cifs_idmap_key_type);
|
|
|
|
if (ret < 0)
|
|
|
|
goto failed_put_key;
|
|
|
|
|
|
|
|
/* instruct request_key() to use this special keyring as a cache for
|
|
|
|
* the results it looks up */
|
2012-01-18 23:31:45 +08:00
|
|
|
set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
|
2011-04-28 12:34:35 +08:00
|
|
|
cred->thread_keyring = keyring;
|
|
|
|
cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
|
|
|
|
root_cred = cred;
|
|
|
|
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "cifs idmap keyring: %d\n", key_serial(keyring));
|
2011-04-28 12:34:35 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
failed_put_key:
|
|
|
|
key_put(keyring);
|
|
|
|
failed_put_cred:
|
|
|
|
put_cred(cred);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
exit_cifs_idmap(void)
|
|
|
|
{
|
|
|
|
key_revoke(root_cred->thread_keyring);
|
|
|
|
unregister_key_type(&cifs_idmap_key_type);
|
|
|
|
put_cred(root_cred);
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "Unregistered %s key type\n", cifs_idmap_key_type.name);
|
2011-04-28 12:34:35 +08:00
|
|
|
}
|
|
|
|
|
2007-12-31 15:47:21 +08:00
|
|
|
/* copy ntsd, owner sid, and group sid from a security descriptor to another */
|
|
|
|
static void copy_sec_desc(const struct cifs_ntsd *pntsd,
|
|
|
|
struct cifs_ntsd *pnntsd, __u32 sidsoffset)
|
|
|
|
{
|
|
|
|
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
|
|
|
|
struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
|
|
|
|
|
|
|
|
/* copy security descriptor control portion */
|
|
|
|
pnntsd->revision = pntsd->revision;
|
|
|
|
pnntsd->type = pntsd->type;
|
|
|
|
pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
|
|
|
|
pnntsd->sacloffset = 0;
|
|
|
|
pnntsd->osidoffset = cpu_to_le32(sidsoffset);
|
|
|
|
pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
|
|
|
|
|
|
|
|
/* copy owner sid */
|
|
|
|
owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
|
|
|
le32_to_cpu(pntsd->osidoffset));
|
|
|
|
nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
|
cifs: fix potential buffer overrun in cifs.idmap handling code
The userspace cifs.idmap program generally works with the wbclient libs
to generate binary SIDs in userspace. That program defines the struct
that holds these values as having a max of 15 subauthorities. The kernel
idmapping code however limits that value to 5.
When the kernel copies those values around though, it doesn't sanity
check the num_subauths value handed back from userspace or from the
server. It's possible therefore for userspace to hand us back a bogus
num_subauths value (or one that's valid, but greater than 5) that could
cause the kernel to walk off the end of the cifs_sid->sub_auths array.
Fix this by defining a new routine for copying sids and using that in
all of the places that copy it. If we end up with a sid that's longer
than expected then this approach will just lop off the "extra" subauths,
but that's basically what the code does today already. Better approaches
might be to fix this code to reject SIDs with >5 subauths, or fix it
to handle the subauths array dynamically.
At the same time, change the kernel to check the length of the data
returned by userspace. If it's shorter than struct cifs_sid, reject it
and return -EIO. If that happens we'll end up with fields that are
basically uninitialized.
Long term, it might make sense to redefine cifs_sid using a flexarray at
the end, to allow for variable-length subauth lists, and teach the code
to handle the case where the subauths array being passed in from
userspace is shorter than 5 elements.
Note too, that I don't consider this a security issue since you'd need
a compromised cifs.idmap program. If you have that, you can do all sorts
of nefarious stuff. Still, this is probably reasonable for stable.
Cc: stable@kernel.org
Reviewed-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
2012-11-03 21:37:28 +08:00
|
|
|
cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
|
2007-12-31 15:47:21 +08:00
|
|
|
|
|
|
|
/* copy group sid */
|
|
|
|
group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
|
|
|
le32_to_cpu(pntsd->gsidoffset));
|
|
|
|
ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
|
|
|
|
sizeof(struct cifs_sid));
|
cifs: fix potential buffer overrun in cifs.idmap handling code
The userspace cifs.idmap program generally works with the wbclient libs
to generate binary SIDs in userspace. That program defines the struct
that holds these values as having a max of 15 subauthorities. The kernel
idmapping code however limits that value to 5.
When the kernel copies those values around though, it doesn't sanity
check the num_subauths value handed back from userspace or from the
server. It's possible therefore for userspace to hand us back a bogus
num_subauths value (or one that's valid, but greater than 5) that could
cause the kernel to walk off the end of the cifs_sid->sub_auths array.
Fix this by defining a new routine for copying sids and using that in
all of the places that copy it. If we end up with a sid that's longer
than expected then this approach will just lop off the "extra" subauths,
but that's basically what the code does today already. Better approaches
might be to fix this code to reject SIDs with >5 subauths, or fix it
to handle the subauths array dynamically.
At the same time, change the kernel to check the length of the data
returned by userspace. If it's shorter than struct cifs_sid, reject it
and return -EIO. If that happens we'll end up with fields that are
basically uninitialized.
Long term, it might make sense to redefine cifs_sid using a flexarray at
the end, to allow for variable-length subauth lists, and teach the code
to handle the case where the subauths array being passed in from
userspace is shorter than 5 elements.
Note too, that I don't consider this a security issue since you'd need
a compromised cifs.idmap program. If you have that, you can do all sorts
of nefarious stuff. Still, this is probably reasonable for stable.
Cc: stable@kernel.org
Reviewed-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
2012-11-03 21:37:28 +08:00
|
|
|
cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
|
2007-12-31 15:47:21 +08:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-26 05:17:17 +08:00
|
|
|
/*
|
|
|
|
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
|
|
|
|
*/
|
2007-12-05 16:24:38 +08:00
|
|
|
static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
|
2007-11-09 01:57:40 +08:00
|
|
|
umode_t *pbits_to_set)
|
2007-10-26 05:17:17 +08:00
|
|
|
{
|
2007-12-05 16:24:38 +08:00
|
|
|
__u32 flags = le32_to_cpu(ace_flags);
|
2007-11-09 01:57:40 +08:00
|
|
|
/* the order of ACEs is important. The canonical order is to begin with
|
2007-11-09 05:12:01 +08:00
|
|
|
DENY entries followed by ALLOW, otherwise an allow entry could be
|
2007-11-09 01:57:40 +08:00
|
|
|
encountered first, making the subsequent deny entry like "dead code"
|
2007-11-09 05:12:01 +08:00
|
|
|
which would be superflous since Windows stops when a match is made
|
2007-11-09 01:57:40 +08:00
|
|
|
for the operation you are trying to perform for your user */
|
|
|
|
|
|
|
|
/* 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) {
|
2008-02-08 07:25:02 +08:00
|
|
|
if (flags & GENERIC_ALL)
|
2007-11-09 01:57:40 +08:00
|
|
|
*pbits_to_set &= ~S_IRWXUGO;
|
2008-02-08 07:25:02 +08:00
|
|
|
|
2007-12-05 16:24:38 +08:00
|
|
|
if ((flags & GENERIC_WRITE) ||
|
|
|
|
((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
|
2007-11-09 01:57:40 +08:00
|
|
|
*pbits_to_set &= ~S_IWUGO;
|
2007-12-05 16:24:38 +08:00
|
|
|
if ((flags & GENERIC_READ) ||
|
|
|
|
((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
|
2007-11-09 01:57:40 +08:00
|
|
|
*pbits_to_set &= ~S_IRUGO;
|
2007-12-05 16:24:38 +08:00
|
|
|
if ((flags & GENERIC_EXECUTE) ||
|
|
|
|
((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
|
2007-11-09 01:57:40 +08:00
|
|
|
*pbits_to_set &= ~S_IXUGO;
|
|
|
|
return;
|
|
|
|
} else if (type != ACCESS_ALLOWED) {
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(VFS, "unknown access control type %d\n", type);
|
2007-11-09 01:57:40 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* else ACCESS_ALLOWED type */
|
2007-10-26 05:17:17 +08:00
|
|
|
|
2007-12-05 16:24:38 +08:00
|
|
|
if (flags & GENERIC_ALL) {
|
2007-11-09 01:57:40 +08:00
|
|
|
*pmode |= (S_IRWXUGO & (*pbits_to_set));
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(NOISY, "all perms\n");
|
2007-10-26 12:32:43 +08:00
|
|
|
return;
|
|
|
|
}
|
2007-12-05 16:24:38 +08:00
|
|
|
if ((flags & GENERIC_WRITE) ||
|
|
|
|
((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
|
2007-11-09 01:57:40 +08:00
|
|
|
*pmode |= (S_IWUGO & (*pbits_to_set));
|
2007-12-05 16:24:38 +08:00
|
|
|
if ((flags & GENERIC_READ) ||
|
|
|
|
((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
|
2007-11-09 01:57:40 +08:00
|
|
|
*pmode |= (S_IRUGO & (*pbits_to_set));
|
2007-12-05 16:24:38 +08:00
|
|
|
if ((flags & GENERIC_EXECUTE) ||
|
|
|
|
((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
|
2007-11-09 01:57:40 +08:00
|
|
|
*pmode |= (S_IXUGO & (*pbits_to_set));
|
2007-10-26 05:17:17 +08:00
|
|
|
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(NOISY, "access flags 0x%x mode now 0x%x\n", flags, *pmode);
|
2007-10-26 05:17:17 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-11-09 05:12:01 +08:00
|
|
|
/*
|
|
|
|
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;
|
|
|
|
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(NOISY, "mode: 0x%x, access flags now 0x%x\n",
|
|
|
|
mode, *pace_flags);
|
2007-11-09 05:12:01 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-03-29 11:09:18 +08:00
|
|
|
static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
|
2007-12-31 15:47:21 +08:00
|
|
|
const struct cifs_sid *psid, __u64 nmode, umode_t bits)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
__u16 size = 0;
|
|
|
|
__u32 access_req = 0;
|
|
|
|
|
|
|
|
pntace->type = ACCESS_ALLOWED;
|
|
|
|
pntace->flags = 0x0;
|
|
|
|
mode_to_access_flags(nmode, bits, &access_req);
|
|
|
|
if (!access_req)
|
|
|
|
access_req = SET_MINIMUM_RIGHTS;
|
|
|
|
pntace->access_req = cpu_to_le32(access_req);
|
|
|
|
|
|
|
|
pntace->sid.revision = psid->revision;
|
|
|
|
pntace->sid.num_subauth = psid->num_subauth;
|
2012-11-25 21:00:36 +08:00
|
|
|
for (i = 0; i < NUM_AUTHS; i++)
|
2007-12-31 15:47:21 +08:00
|
|
|
pntace->sid.authority[i] = psid->authority[i];
|
|
|
|
for (i = 0; i < psid->num_subauth; i++)
|
|
|
|
pntace->sid.sub_auth[i] = psid->sub_auth[i];
|
|
|
|
|
|
|
|
size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
|
|
|
|
pntace->size = cpu_to_le16(size);
|
|
|
|
|
2008-07-24 23:56:05 +08:00
|
|
|
return size;
|
2007-12-31 15:47:21 +08:00
|
|
|
}
|
|
|
|
|
2007-10-12 12:11:59 +08:00
|
|
|
|
2007-10-31 12:54:42 +08:00
|
|
|
#ifdef CONFIG_CIFS_DEBUG2
|
|
|
|
static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
|
2007-10-04 02:22:19 +08:00
|
|
|
{
|
|
|
|
int num_subauth;
|
|
|
|
|
|
|
|
/* validate that we do not go past end of acl */
|
2007-10-12 12:11:59 +08:00
|
|
|
|
2007-10-24 05:22:55 +08:00
|
|
|
if (le16_to_cpu(pace->size) < 16) {
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(VFS, "ACE too small %d\n", le16_to_cpu(pace->size));
|
2007-10-24 05:22:55 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(VFS, "ACL too small to parse ACE\n");
|
2007-10-04 02:22:19 +08:00
|
|
|
return;
|
2007-10-24 05:22:55 +08:00
|
|
|
}
|
2007-10-04 02:22:19 +08:00
|
|
|
|
2007-10-24 05:22:55 +08:00
|
|
|
num_subauth = pace->sid.num_subauth;
|
2007-10-04 02:22:19 +08:00
|
|
|
if (num_subauth) {
|
2007-10-13 02:54:12 +08:00
|
|
|
int i;
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "ACE revision %d num_auth %d type %d flags %d size %d\n",
|
|
|
|
pace->sid.revision, pace->sid.num_subauth, pace->type,
|
|
|
|
pace->flags, le16_to_cpu(pace->size));
|
2007-10-04 03:43:19 +08:00
|
|
|
for (i = 0; i < num_subauth; ++i) {
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "ACE sub_auth[%d]: 0x%x\n",
|
|
|
|
i, le32_to_cpu(pace->sid.sub_auth[i]));
|
2007-10-04 03:43:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* BB add length check to make sure that we do not have huge
|
|
|
|
num auths and therefore go off the end */
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2007-10-31 12:54:42 +08:00
|
|
|
#endif
|
2007-10-04 03:43:19 +08:00
|
|
|
|
2007-10-04 02:22:19 +08:00
|
|
|
|
2007-10-18 06:50:39 +08:00
|
|
|
static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
2007-10-26 12:32:43 +08:00
|
|
|
struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
|
2009-07-09 13:46:37 +08:00
|
|
|
struct cifs_fattr *fattr)
|
2007-10-04 02:22:19 +08:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int num_aces = 0;
|
|
|
|
int acl_size;
|
|
|
|
char *acl_base;
|
|
|
|
struct cifs_ace **ppace;
|
|
|
|
|
|
|
|
/* BB need to add parm so we can store the SID BB */
|
|
|
|
|
2007-11-25 18:01:00 +08:00
|
|
|
if (!pdacl) {
|
|
|
|
/* no DACL in the security descriptor, set
|
|
|
|
all the permissions for user/group/other */
|
2009-07-09 13:46:37 +08:00
|
|
|
fattr->cf_mode |= S_IRWXUGO;
|
2007-11-25 18:01:00 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-10-04 02:22:19 +08:00
|
|
|
/* validate that we do not go past end of acl */
|
2007-10-17 02:40:37 +08:00
|
|
|
if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(VFS, "ACL too small to parse DACL\n");
|
2007-10-04 02:22:19 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
|
|
|
|
le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
|
|
|
|
le32_to_cpu(pdacl->num_aces));
|
2007-10-04 02:22:19 +08:00
|
|
|
|
2007-11-02 02:03:01 +08:00
|
|
|
/* 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 */
|
2009-07-09 13:46:37 +08:00
|
|
|
fattr->cf_mode &= ~(S_IRWXUGO);
|
2007-11-02 02:03:01 +08:00
|
|
|
|
2007-10-04 02:22:19 +08:00
|
|
|
acl_base = (char *)pdacl;
|
|
|
|
acl_size = sizeof(struct cifs_acl);
|
|
|
|
|
2007-10-17 10:12:46 +08:00
|
|
|
num_aces = le32_to_cpu(pdacl->num_aces);
|
2011-10-13 23:26:03 +08:00
|
|
|
if (num_aces > 0) {
|
2007-11-09 01:57:40 +08:00
|
|
|
umode_t user_mask = S_IRWXU;
|
|
|
|
umode_t group_mask = S_IRWXG;
|
2010-12-07 04:56:46 +08:00
|
|
|
umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
|
2007-11-09 01:57:40 +08:00
|
|
|
|
2012-01-11 15:46:27 +08:00
|
|
|
if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
|
|
|
|
return;
|
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 04:55:00 +08:00
|
|
|
ppace = kmalloc_array(num_aces, sizeof(struct cifs_ace *),
|
|
|
|
GFP_KERNEL);
|
2013-05-05 11:12:25 +08:00
|
|
|
if (!ppace)
|
2011-02-06 07:05:28 +08:00
|
|
|
return;
|
2007-10-04 02:22:19 +08:00
|
|
|
|
|
|
|
for (i = 0; i < num_aces; ++i) {
|
2007-10-24 05:22:55 +08:00
|
|
|
ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
|
2007-10-31 12:54:42 +08:00
|
|
|
#ifdef CONFIG_CIFS_DEBUG2
|
|
|
|
dump_ace(ppace[i], end_of_acl);
|
|
|
|
#endif
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
|
2007-10-30 12:45:14 +08:00
|
|
|
access_flags_to_mode(ppace[i]->access_req,
|
2007-11-09 01:57:40 +08:00
|
|
|
ppace[i]->type,
|
2009-07-09 13:46:37 +08:00
|
|
|
&fattr->cf_mode,
|
2007-11-09 01:57:40 +08:00
|
|
|
&user_mask);
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
|
2007-10-30 12:45:14 +08:00
|
|
|
access_flags_to_mode(ppace[i]->access_req,
|
2007-11-09 01:57:40 +08:00
|
|
|
ppace[i]->type,
|
2009-07-09 13:46:37 +08:00
|
|
|
&fattr->cf_mode,
|
2007-11-09 01:57:40 +08:00
|
|
|
&group_mask);
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
|
2007-10-30 12:45:14 +08:00
|
|
|
access_flags_to_mode(ppace[i]->access_req,
|
2007-11-09 01:57:40 +08:00
|
|
|
ppace[i]->type,
|
2009-07-09 13:46:37 +08:00
|
|
|
&fattr->cf_mode,
|
2007-11-09 01:57:40 +08:00
|
|
|
&other_mask);
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
|
2010-12-07 04:56:46 +08:00
|
|
|
access_flags_to_mode(ppace[i]->access_req,
|
|
|
|
ppace[i]->type,
|
|
|
|
&fattr->cf_mode,
|
|
|
|
&other_mask);
|
|
|
|
|
2007-10-30 12:45:14 +08:00
|
|
|
|
2007-10-24 05:22:55 +08:00
|
|
|
/* memcpy((void *)(&(cifscred->aces[i])),
|
2007-10-04 03:43:19 +08:00
|
|
|
(void *)ppace[i],
|
|
|
|
sizeof(struct cifs_ace)); */
|
2007-10-04 02:22:19 +08:00
|
|
|
|
2007-10-24 05:22:55 +08:00
|
|
|
acl_base = (char *)ppace[i];
|
|
|
|
acl_size = le16_to_cpu(ppace[i]->size);
|
2007-10-04 02:22:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
kfree(ppace);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-09-26 00:17:24 +08:00
|
|
|
|
2007-12-31 15:47:21 +08:00
|
|
|
static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
|
|
|
|
struct cifs_sid *pgrpsid, __u64 nmode)
|
|
|
|
{
|
2008-03-29 11:09:18 +08:00
|
|
|
u16 size = 0;
|
2007-12-31 15:47:21 +08:00
|
|
|
struct cifs_acl *pnndacl;
|
|
|
|
|
|
|
|
pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
|
|
|
|
|
|
|
|
size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
|
|
|
|
pownersid, nmode, S_IRWXU);
|
|
|
|
size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
|
|
|
|
pgrpsid, nmode, S_IRWXG);
|
|
|
|
size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
|
|
|
|
&sid_everyone, nmode, S_IRWXO);
|
|
|
|
|
|
|
|
pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
|
2008-02-13 04:46:26 +08:00
|
|
|
pndacl->num_aces = cpu_to_le32(3);
|
2007-12-31 15:47:21 +08:00
|
|
|
|
2008-07-24 23:56:05 +08:00
|
|
|
return 0;
|
2007-12-31 15:47:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-26 00:17:24 +08:00
|
|
|
static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
|
|
|
|
{
|
|
|
|
/* BB need to add parm so we can store the SID BB */
|
|
|
|
|
2007-10-27 07:40:20 +08:00
|
|
|
/* 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) {
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(VFS, "ACL too small to parse SID %p\n", psid);
|
2007-09-26 00:17:24 +08:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
2007-10-04 02:22:19 +08:00
|
|
|
|
2007-09-26 00:17:24 +08:00
|
|
|
#ifdef CONFIG_CIFS_DEBUG2
|
2012-11-25 21:00:35 +08:00
|
|
|
if (psid->num_subauth) {
|
2007-10-13 02:54:12 +08:00
|
|
|
int i;
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "SID revision %d num_auth %d\n",
|
|
|
|
psid->revision, psid->num_subauth);
|
2007-09-26 00:17:24 +08:00
|
|
|
|
2007-10-17 02:40:37 +08:00
|
|
|
for (i = 0; i < psid->num_subauth; i++) {
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "SID sub_auth[%d]: 0x%x\n",
|
|
|
|
i, le32_to_cpu(psid->sub_auth[i]));
|
2007-10-04 02:22:19 +08:00
|
|
|
}
|
|
|
|
|
2007-10-04 03:43:19 +08:00
|
|
|
/* BB add length check to make sure that we do not have huge
|
2007-10-04 02:22:19 +08:00
|
|
|
num auths and therefore go off the end */
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "RID 0x%x\n",
|
|
|
|
le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
|
2007-10-04 02:22:19 +08:00
|
|
|
}
|
2012-11-25 21:00:35 +08:00
|
|
|
#endif
|
2007-10-04 02:22:19 +08:00
|
|
|
|
2007-09-26 00:17:24 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-10-04 02:22:19 +08:00
|
|
|
|
2007-09-26 00:17:24 +08:00
|
|
|
/* Convert CIFS ACL to POSIX form */
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
|
|
|
|
struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
|
2007-09-26 00:17:24 +08:00
|
|
|
{
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
int rc = 0;
|
2007-09-26 00:17:24 +08:00
|
|
|
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;
|
2007-11-02 02:03:01 +08:00
|
|
|
__u32 dacloffset;
|
2007-09-26 00:17:24 +08:00
|
|
|
|
2009-07-09 13:46:37 +08:00
|
|
|
if (pntsd == NULL)
|
2007-10-27 07:40:20 +08:00
|
|
|
return -EIO;
|
|
|
|
|
2007-09-26 00:17:24 +08:00
|
|
|
owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
2007-10-17 02:40:37 +08:00
|
|
|
le32_to_cpu(pntsd->osidoffset));
|
2007-09-26 00:17:24 +08:00
|
|
|
group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
2007-10-17 02:40:37 +08:00
|
|
|
le32_to_cpu(pntsd->gsidoffset));
|
2007-11-02 02:03:01 +08:00
|
|
|
dacloffset = le32_to_cpu(pntsd->dacloffset);
|
2007-11-06 05:46:10 +08:00
|
|
|
dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n",
|
2007-10-17 02:40:37 +08:00
|
|
|
pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
|
|
|
|
le32_to_cpu(pntsd->gsidoffset),
|
2010-04-21 11:50:45 +08:00
|
|
|
le32_to_cpu(pntsd->sacloffset), dacloffset);
|
2007-10-27 07:40:20 +08:00
|
|
|
/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
|
2007-09-26 00:17:24 +08:00
|
|
|
rc = parse_sid(owner_sid_ptr, end_of_acl);
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
if (rc) {
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc);
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
|
|
|
|
if (rc) {
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
|
|
|
|
__func__, rc);
|
2007-09-26 00:17:24 +08:00
|
|
|
return rc;
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
}
|
2007-09-26 00:17:24 +08:00
|
|
|
|
|
|
|
rc = parse_sid(group_sid_ptr, end_of_acl);
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
if (rc) {
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "%s: Error %d mapping Owner SID to gid\n",
|
|
|
|
__func__, rc);
|
2007-09-26 00:17:24 +08:00
|
|
|
return rc;
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
}
|
|
|
|
rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
|
|
|
|
if (rc) {
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
|
|
|
|
__func__, rc);
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
return rc;
|
|
|
|
}
|
2007-09-26 00:17:24 +08:00
|
|
|
|
2007-11-02 02:03:01 +08:00
|
|
|
if (dacloffset)
|
|
|
|
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
|
2009-07-09 13:46:37 +08:00
|
|
|
group_sid_ptr, fattr);
|
2007-11-02 02:03:01 +08:00
|
|
|
else
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
|
2007-10-04 02:22:19 +08:00
|
|
|
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
return rc;
|
2007-09-26 00:17:24 +08:00
|
|
|
}
|
2007-10-27 07:40:20 +08:00
|
|
|
|
2007-12-31 15:47:21 +08:00
|
|
|
/* Convert permission bits from mode to equivalent CIFS ACL */
|
|
|
|
static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
|
2013-02-06 16:33:17 +08:00
|
|
|
__u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, int *aclflag)
|
2007-12-31 15:47:21 +08:00
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
__u32 dacloffset;
|
|
|
|
__u32 ndacloffset;
|
|
|
|
__u32 sidsoffset;
|
|
|
|
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
|
2011-10-13 23:26:03 +08:00
|
|
|
struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
|
2007-12-31 15:47:21 +08:00
|
|
|
struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
|
|
|
|
struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
|
|
|
|
|
2011-10-13 23:26:03 +08:00
|
|
|
if (nmode != NO_CHANGE_64) { /* chmod */
|
|
|
|
owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
2007-12-31 15:47:21 +08:00
|
|
|
le32_to_cpu(pntsd->osidoffset));
|
2011-10-13 23:26:03 +08:00
|
|
|
group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
2007-12-31 15:47:21 +08:00
|
|
|
le32_to_cpu(pntsd->gsidoffset));
|
2011-10-13 23:26:03 +08:00
|
|
|
dacloffset = le32_to_cpu(pntsd->dacloffset);
|
|
|
|
dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
|
|
|
|
ndacloffset = sizeof(struct cifs_ntsd);
|
|
|
|
ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
|
|
|
|
ndacl_ptr->revision = dacl_ptr->revision;
|
|
|
|
ndacl_ptr->size = 0;
|
|
|
|
ndacl_ptr->num_aces = 0;
|
|
|
|
|
|
|
|
rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
|
|
|
|
nmode);
|
|
|
|
sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
|
|
|
|
/* copy sec desc control portion & owner and group sids */
|
|
|
|
copy_sec_desc(pntsd, pnntsd, sidsoffset);
|
|
|
|
*aclflag = CIFS_ACL_DACL;
|
|
|
|
} else {
|
|
|
|
memcpy(pnntsd, pntsd, secdesclen);
|
2013-02-06 16:33:17 +08:00
|
|
|
if (uid_valid(uid)) { /* chown */
|
|
|
|
uid_t id;
|
2011-10-13 23:26:03 +08:00
|
|
|
owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
|
|
|
|
le32_to_cpu(pnntsd->osidoffset));
|
|
|
|
nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!nowner_sid_ptr)
|
|
|
|
return -ENOMEM;
|
2013-02-06 16:33:17 +08:00
|
|
|
id = from_kuid(&init_user_ns, uid);
|
|
|
|
rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
|
2011-10-13 23:26:03 +08:00
|
|
|
if (rc) {
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
|
|
|
|
__func__, rc, id);
|
2011-10-13 23:26:03 +08:00
|
|
|
kfree(nowner_sid_ptr);
|
|
|
|
return rc;
|
|
|
|
}
|
cifs: fix potential buffer overrun in cifs.idmap handling code
The userspace cifs.idmap program generally works with the wbclient libs
to generate binary SIDs in userspace. That program defines the struct
that holds these values as having a max of 15 subauthorities. The kernel
idmapping code however limits that value to 5.
When the kernel copies those values around though, it doesn't sanity
check the num_subauths value handed back from userspace or from the
server. It's possible therefore for userspace to hand us back a bogus
num_subauths value (or one that's valid, but greater than 5) that could
cause the kernel to walk off the end of the cifs_sid->sub_auths array.
Fix this by defining a new routine for copying sids and using that in
all of the places that copy it. If we end up with a sid that's longer
than expected then this approach will just lop off the "extra" subauths,
but that's basically what the code does today already. Better approaches
might be to fix this code to reject SIDs with >5 subauths, or fix it
to handle the subauths array dynamically.
At the same time, change the kernel to check the length of the data
returned by userspace. If it's shorter than struct cifs_sid, reject it
and return -EIO. If that happens we'll end up with fields that are
basically uninitialized.
Long term, it might make sense to redefine cifs_sid using a flexarray at
the end, to allow for variable-length subauth lists, and teach the code
to handle the case where the subauths array being passed in from
userspace is shorter than 5 elements.
Note too, that I don't consider this a security issue since you'd need
a compromised cifs.idmap program. If you have that, you can do all sorts
of nefarious stuff. Still, this is probably reasonable for stable.
Cc: stable@kernel.org
Reviewed-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
2012-11-03 21:37:28 +08:00
|
|
|
cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
|
2011-10-13 23:26:03 +08:00
|
|
|
kfree(nowner_sid_ptr);
|
|
|
|
*aclflag = CIFS_ACL_OWNER;
|
|
|
|
}
|
2013-02-06 16:33:17 +08:00
|
|
|
if (gid_valid(gid)) { /* chgrp */
|
|
|
|
gid_t id;
|
2011-10-13 23:26:03 +08:00
|
|
|
group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
|
|
|
|
le32_to_cpu(pnntsd->gsidoffset));
|
|
|
|
ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!ngroup_sid_ptr)
|
|
|
|
return -ENOMEM;
|
2013-02-06 16:33:17 +08:00
|
|
|
id = from_kgid(&init_user_ns, gid);
|
|
|
|
rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
|
2011-10-13 23:26:03 +08:00
|
|
|
if (rc) {
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
|
|
|
|
__func__, rc, id);
|
2011-10-13 23:26:03 +08:00
|
|
|
kfree(ngroup_sid_ptr);
|
|
|
|
return rc;
|
|
|
|
}
|
cifs: fix potential buffer overrun in cifs.idmap handling code
The userspace cifs.idmap program generally works with the wbclient libs
to generate binary SIDs in userspace. That program defines the struct
that holds these values as having a max of 15 subauthorities. The kernel
idmapping code however limits that value to 5.
When the kernel copies those values around though, it doesn't sanity
check the num_subauths value handed back from userspace or from the
server. It's possible therefore for userspace to hand us back a bogus
num_subauths value (or one that's valid, but greater than 5) that could
cause the kernel to walk off the end of the cifs_sid->sub_auths array.
Fix this by defining a new routine for copying sids and using that in
all of the places that copy it. If we end up with a sid that's longer
than expected then this approach will just lop off the "extra" subauths,
but that's basically what the code does today already. Better approaches
might be to fix this code to reject SIDs with >5 subauths, or fix it
to handle the subauths array dynamically.
At the same time, change the kernel to check the length of the data
returned by userspace. If it's shorter than struct cifs_sid, reject it
and return -EIO. If that happens we'll end up with fields that are
basically uninitialized.
Long term, it might make sense to redefine cifs_sid using a flexarray at
the end, to allow for variable-length subauth lists, and teach the code
to handle the case where the subauths array being passed in from
userspace is shorter than 5 elements.
Note too, that I don't consider this a security issue since you'd need
a compromised cifs.idmap program. If you have that, you can do all sorts
of nefarious stuff. Still, this is probably reasonable for stable.
Cc: stable@kernel.org
Reviewed-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
2012-11-03 21:37:28 +08:00
|
|
|
cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
|
2011-10-13 23:26:03 +08:00
|
|
|
kfree(ngroup_sid_ptr);
|
|
|
|
*aclflag = CIFS_ACL_GROUP;
|
|
|
|
}
|
|
|
|
}
|
2007-12-31 15:47:21 +08:00
|
|
|
|
2008-07-24 23:56:05 +08:00
|
|
|
return rc;
|
2007-12-31 15:47:21 +08:00
|
|
|
}
|
|
|
|
|
2014-02-11 04:08:16 +08:00
|
|
|
struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
|
|
|
|
const struct cifs_fid *cifsfid, u32 *pacllen)
|
2007-10-27 07:40:20 +08:00
|
|
|
{
|
|
|
|
struct cifs_ntsd *pntsd = NULL;
|
2012-06-20 15:21:16 +08:00
|
|
|
unsigned int xid;
|
|
|
|
int rc;
|
2010-09-30 07:51:11 +08:00
|
|
|
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
|
|
|
|
|
|
|
if (IS_ERR(tlink))
|
2010-11-10 21:50:35 +08:00
|
|
|
return ERR_CAST(tlink);
|
2007-10-27 07:40:20 +08:00
|
|
|
|
2012-06-20 15:21:16 +08:00
|
|
|
xid = get_xid();
|
2014-02-11 04:08:16 +08:00
|
|
|
rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
|
|
|
|
pacllen);
|
2012-06-20 15:21:16 +08:00
|
|
|
free_xid(xid);
|
2007-10-27 07:40:20 +08:00
|
|
|
|
2010-09-30 07:51:11 +08:00
|
|
|
cifs_put_tlink(tlink);
|
2007-10-27 07:40:20 +08:00
|
|
|
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
|
2010-11-10 21:50:35 +08:00
|
|
|
if (rc)
|
|
|
|
return ERR_PTR(rc);
|
2009-05-27 21:37:33 +08:00
|
|
|
return pntsd;
|
|
|
|
}
|
2008-03-15 06:37:16 +08:00
|
|
|
|
2009-05-27 21:37:33 +08:00
|
|
|
static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
|
|
|
|
const char *path, u32 *pacllen)
|
|
|
|
{
|
|
|
|
struct cifs_ntsd *pntsd = NULL;
|
|
|
|
int oplock = 0;
|
2012-06-20 15:21:16 +08:00
|
|
|
unsigned int xid;
|
|
|
|
int rc, create_options = 0;
|
2011-05-27 12:34:02 +08:00
|
|
|
struct cifs_tcon *tcon;
|
2010-09-30 07:51:11 +08:00
|
|
|
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
2014-01-16 19:53:36 +08:00
|
|
|
struct cifs_fid fid;
|
|
|
|
struct cifs_open_parms oparms;
|
2010-09-30 07:51:11 +08:00
|
|
|
|
|
|
|
if (IS_ERR(tlink))
|
2010-11-10 21:50:35 +08:00
|
|
|
return ERR_CAST(tlink);
|
2007-10-27 07:40:20 +08:00
|
|
|
|
2010-09-30 07:51:11 +08:00
|
|
|
tcon = tlink_tcon(tlink);
|
2012-06-20 15:21:16 +08:00
|
|
|
xid = get_xid();
|
2009-05-27 21:37:33 +08:00
|
|
|
|
2011-09-26 22:56:44 +08:00
|
|
|
if (backup_cred(cifs_sb))
|
|
|
|
create_options |= CREATE_OPEN_BACKUP_INTENT;
|
|
|
|
|
2014-01-16 19:53:36 +08:00
|
|
|
oparms.tcon = tcon;
|
|
|
|
oparms.cifs_sb = cifs_sb;
|
|
|
|
oparms.desired_access = READ_CONTROL;
|
|
|
|
oparms.create_options = create_options;
|
|
|
|
oparms.disposition = FILE_OPEN;
|
|
|
|
oparms.path = path;
|
|
|
|
oparms.fid = &fid;
|
|
|
|
oparms.reconnect = false;
|
|
|
|
|
|
|
|
rc = CIFS_open(xid, &oparms, &oplock, NULL);
|
2010-11-10 21:50:35 +08:00
|
|
|
if (!rc) {
|
2014-01-16 19:53:36 +08:00
|
|
|
rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
|
|
|
|
CIFSSMBClose(xid, tcon, fid.netfid);
|
2007-10-27 07:40:20 +08:00
|
|
|
}
|
|
|
|
|
2010-09-30 07:51:11 +08:00
|
|
|
cifs_put_tlink(tlink);
|
2012-06-20 15:21:16 +08:00
|
|
|
free_xid(xid);
|
2010-11-10 21:50:35 +08:00
|
|
|
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
|
2010-11-10 21:50:35 +08:00
|
|
|
if (rc)
|
|
|
|
return ERR_PTR(rc);
|
2007-11-02 02:03:01 +08:00
|
|
|
return pntsd;
|
|
|
|
}
|
|
|
|
|
2009-05-27 21:37:33 +08:00
|
|
|
/* Retrieve an ACL from the server */
|
2010-11-28 01:37:54 +08:00
|
|
|
struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
|
2009-05-27 21:37:33 +08:00
|
|
|
struct inode *inode, const char *path,
|
|
|
|
u32 *pacllen)
|
|
|
|
{
|
|
|
|
struct cifs_ntsd *pntsd = NULL;
|
|
|
|
struct cifsFileInfo *open_file = NULL;
|
|
|
|
|
|
|
|
if (inode)
|
2010-09-30 07:51:11 +08:00
|
|
|
open_file = find_readable_file(CIFS_I(inode), true);
|
2009-05-27 21:37:33 +08:00
|
|
|
if (!open_file)
|
|
|
|
return get_cifs_acl_by_path(cifs_sb, path, pacllen);
|
|
|
|
|
2014-02-11 04:08:16 +08:00
|
|
|
pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
|
2009-08-31 23:07:12 +08:00
|
|
|
cifsFileInfo_put(open_file);
|
2009-05-27 21:37:33 +08:00
|
|
|
return pntsd;
|
|
|
|
}
|
|
|
|
|
2011-10-13 23:26:03 +08:00
|
|
|
/* Set an ACL on the server */
|
|
|
|
int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
|
|
|
struct inode *inode, const char *path, int aclflag)
|
2009-05-27 21:37:33 +08:00
|
|
|
{
|
|
|
|
int oplock = 0;
|
2012-06-20 15:21:16 +08:00
|
|
|
unsigned int xid;
|
|
|
|
int rc, access_flags, create_options = 0;
|
2011-05-27 12:34:02 +08:00
|
|
|
struct cifs_tcon *tcon;
|
2011-10-13 23:26:03 +08:00
|
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
2010-09-30 07:51:11 +08:00
|
|
|
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
2014-01-16 19:53:36 +08:00
|
|
|
struct cifs_fid fid;
|
|
|
|
struct cifs_open_parms oparms;
|
2007-12-31 15:47:21 +08:00
|
|
|
|
2010-09-30 07:51:11 +08:00
|
|
|
if (IS_ERR(tlink))
|
|
|
|
return PTR_ERR(tlink);
|
|
|
|
|
|
|
|
tcon = tlink_tcon(tlink);
|
2012-06-20 15:21:16 +08:00
|
|
|
xid = get_xid();
|
2007-12-31 15:47:21 +08:00
|
|
|
|
2011-09-26 22:56:44 +08:00
|
|
|
if (backup_cred(cifs_sb))
|
|
|
|
create_options |= CREATE_OPEN_BACKUP_INTENT;
|
|
|
|
|
2011-10-13 23:26:03 +08:00
|
|
|
if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
|
|
|
|
access_flags = WRITE_OWNER;
|
|
|
|
else
|
|
|
|
access_flags = WRITE_DAC;
|
|
|
|
|
2014-01-16 19:53:36 +08:00
|
|
|
oparms.tcon = tcon;
|
|
|
|
oparms.cifs_sb = cifs_sb;
|
|
|
|
oparms.desired_access = access_flags;
|
|
|
|
oparms.create_options = create_options;
|
|
|
|
oparms.disposition = FILE_OPEN;
|
|
|
|
oparms.path = path;
|
|
|
|
oparms.fid = &fid;
|
|
|
|
oparms.reconnect = false;
|
|
|
|
|
|
|
|
rc = CIFS_open(xid, &oparms, &oplock, NULL);
|
2009-05-27 21:37:33 +08:00
|
|
|
if (rc) {
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(VFS, "Unable to open file to set ACL\n");
|
2009-05-27 21:37:33 +08:00
|
|
|
goto out;
|
2007-12-31 15:47:21 +08:00
|
|
|
}
|
|
|
|
|
2014-01-16 19:53:36 +08:00
|
|
|
rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag);
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);
|
2007-12-31 15:47:21 +08:00
|
|
|
|
2014-01-16 19:53:36 +08:00
|
|
|
CIFSSMBClose(xid, tcon, fid.netfid);
|
2010-09-30 07:51:11 +08:00
|
|
|
out:
|
2012-06-20 15:21:16 +08:00
|
|
|
free_xid(xid);
|
2010-09-30 07:51:11 +08:00
|
|
|
cifs_put_tlink(tlink);
|
2009-05-27 21:37:33 +08:00
|
|
|
return rc;
|
|
|
|
}
|
2007-12-31 15:47:21 +08:00
|
|
|
|
2018-01-28 16:09:48 +08:00
|
|
|
/* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */
|
2010-11-10 21:50:35 +08:00
|
|
|
int
|
2009-07-09 13:46:37 +08:00
|
|
|
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
2014-02-11 04:08:16 +08:00
|
|
|
struct inode *inode, const char *path,
|
|
|
|
const struct cifs_fid *pfid)
|
2007-11-02 02:03:01 +08:00
|
|
|
{
|
|
|
|
struct cifs_ntsd *pntsd = NULL;
|
|
|
|
u32 acllen = 0;
|
|
|
|
int rc = 0;
|
2014-02-11 04:08:16 +08:00
|
|
|
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
2017-05-07 16:31:47 +08:00
|
|
|
struct smb_version_operations *ops;
|
2007-11-02 02:03:01 +08:00
|
|
|
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
|
2009-05-27 21:37:33 +08:00
|
|
|
|
2014-02-11 04:08:16 +08:00
|
|
|
if (IS_ERR(tlink))
|
|
|
|
return PTR_ERR(tlink);
|
2007-11-02 02:03:01 +08:00
|
|
|
|
2017-05-07 16:31:47 +08:00
|
|
|
ops = tlink_tcon(tlink)->ses->server->ops;
|
|
|
|
|
|
|
|
if (pfid && (ops->get_acl_by_fid))
|
|
|
|
pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen);
|
|
|
|
else if (ops->get_acl)
|
|
|
|
pntsd = ops->get_acl(cifs_sb, inode, path, &acllen);
|
2014-02-11 04:08:16 +08:00
|
|
|
else {
|
|
|
|
cifs_put_tlink(tlink);
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
2007-11-02 02:03:01 +08:00
|
|
|
/* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
|
2010-11-10 21:50:35 +08:00
|
|
|
if (IS_ERR(pntsd)) {
|
|
|
|
rc = PTR_ERR(pntsd);
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
|
2010-11-10 21:50:35 +08:00
|
|
|
} else {
|
cifs: Invoke id mapping functions (try #17 repost)
rb tree search and insertion routines.
A SID which needs to be mapped, is looked up in one of the rb trees
depending on whether SID is either owner or group SID.
If found in the tree, a (mapped) id from that node is assigned to
uid or gid as appropriate. If unmapped, an upcall is attempted to
map the SID to an id. If upcall is successful, node is marked as
mapped. If upcall fails, node stays marked as unmapped and a mapping
is attempted again only after an arbitrary time period has passed.
To map a SID, which can be either a Owner SID or a Group SID, key
description starts with the string "os" or "gs" followed by SID converted
to a string. Without "os" or "gs", cifs.upcall does not know whether
SID needs to be mapped to either an uid or a gid.
Nodes in rb tree have fields to prevent multiple upcalls for
a SID. Searching, adding, and removing nodes is done within global locks.
Whenever a node is either found or inserted in a tree, a reference
is taken on that node.
Shrinker routine prunes a node if it has expired but does not prune
an expired node if its refcount is not zero (i.e. sid/id of that node
is_being/will_be accessed).
Thus a node, if its SID needs to be mapped by making an upcall,
can safely stay and its fields accessed without shrinker pruning it.
A reference (refcount) is put on the node without holding the spinlock
but a reference is get on the node by holding the spinlock.
Every time an existing mapped node is accessed or mapping is attempted,
its timestamp is updated to prevent it from getting erased or a
to prevent multiple unnecessary repeat mapping retries respectively.
For now, cifs.upcall is only used to map a SID to an id (uid or gid) but
it would be used to obtain an SID for an id.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
2011-04-23 01:09:36 +08:00
|
|
|
rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
|
2010-11-10 21:50:35 +08:00
|
|
|
kfree(pntsd);
|
|
|
|
if (rc)
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
|
2010-11-10 21:50:35 +08:00
|
|
|
}
|
2007-11-02 02:03:01 +08:00
|
|
|
|
2014-02-11 04:08:16 +08:00
|
|
|
cifs_put_tlink(tlink);
|
|
|
|
|
2010-11-10 21:50:35 +08:00
|
|
|
return rc;
|
2007-10-27 07:40:20 +08:00
|
|
|
}
|
2007-10-31 12:54:42 +08:00
|
|
|
|
2007-11-02 02:03:01 +08:00
|
|
|
/* Convert mode bits to an ACL so we can update the ACL on the server */
|
2011-10-13 23:26:03 +08:00
|
|
|
int
|
|
|
|
id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
|
2013-02-06 16:33:17 +08:00
|
|
|
kuid_t uid, kgid_t gid)
|
2007-10-31 12:54:42 +08:00
|
|
|
{
|
|
|
|
int rc = 0;
|
2011-10-13 23:26:03 +08:00
|
|
|
int aclflag = CIFS_ACL_DACL; /* default flag to set */
|
2008-04-10 04:55:31 +08:00
|
|
|
__u32 secdesclen = 0;
|
2007-12-31 15:47:21 +08:00
|
|
|
struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
|
|
|
|
struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
|
2014-02-03 13:31:47 +08:00
|
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
|
|
|
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
2017-05-07 16:31:47 +08:00
|
|
|
struct smb_version_operations *ops;
|
2014-02-03 13:31:47 +08:00
|
|
|
|
|
|
|
if (IS_ERR(tlink))
|
|
|
|
return PTR_ERR(tlink);
|
2017-05-07 16:31:47 +08:00
|
|
|
|
|
|
|
ops = tlink_tcon(tlink)->ses->server->ops;
|
2007-10-31 12:54:42 +08:00
|
|
|
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
|
2007-10-31 12:54:42 +08:00
|
|
|
|
|
|
|
/* Get the security descriptor */
|
2014-02-03 13:31:47 +08:00
|
|
|
|
2017-05-07 16:31:47 +08:00
|
|
|
if (ops->get_acl == NULL) {
|
2014-02-03 13:31:47 +08:00
|
|
|
cifs_put_tlink(tlink);
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
2017-05-07 16:31:47 +08:00
|
|
|
pntsd = ops->get_acl(cifs_sb, inode, path, &secdesclen);
|
2010-11-10 21:50:35 +08:00
|
|
|
if (IS_ERR(pntsd)) {
|
|
|
|
rc = PTR_ERR(pntsd);
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
|
2014-02-03 13:31:47 +08:00
|
|
|
cifs_put_tlink(tlink);
|
|
|
|
return rc;
|
2012-11-25 21:00:35 +08:00
|
|
|
}
|
2007-11-02 02:03:01 +08:00
|
|
|
|
2012-11-25 21:00:35 +08:00
|
|
|
/*
|
|
|
|
* Add three ACEs for owner, group, everyone getting rid of other ACEs
|
|
|
|
* as chmod disables ACEs and set the security descriptor. Allocate
|
|
|
|
* memory for the smb header, set security descriptor request security
|
|
|
|
* descriptor parameters, and secuirty descriptor itself
|
|
|
|
*/
|
2012-12-03 19:05:31 +08:00
|
|
|
secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
|
2012-11-25 21:00:35 +08:00
|
|
|
pnntsd = kmalloc(secdesclen, GFP_KERNEL);
|
|
|
|
if (!pnntsd) {
|
|
|
|
kfree(pntsd);
|
2014-02-03 13:31:47 +08:00
|
|
|
cifs_put_tlink(tlink);
|
2012-11-25 21:00:35 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2007-12-31 15:47:21 +08:00
|
|
|
|
2012-11-25 21:00:35 +08:00
|
|
|
rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
|
|
|
|
&aclflag);
|
2007-12-31 15:47:21 +08:00
|
|
|
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
|
2007-12-31 15:47:21 +08:00
|
|
|
|
2017-05-07 16:31:47 +08:00
|
|
|
if (ops->set_acl == NULL)
|
2014-02-03 13:31:47 +08:00
|
|
|
rc = -EOPNOTSUPP;
|
|
|
|
|
2012-11-25 21:00:35 +08:00
|
|
|
if (!rc) {
|
|
|
|
/* Set the security descriptor */
|
2017-05-07 16:31:47 +08:00
|
|
|
rc = ops->set_acl(pnntsd, secdesclen, inode, path, aclflag);
|
2013-05-05 11:12:25 +08:00
|
|
|
cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
|
2007-12-31 15:47:21 +08:00
|
|
|
}
|
2014-02-03 13:31:47 +08:00
|
|
|
cifs_put_tlink(tlink);
|
2007-12-31 15:47:21 +08:00
|
|
|
|
2012-11-25 21:00:35 +08:00
|
|
|
kfree(pnntsd);
|
|
|
|
kfree(pntsd);
|
2008-07-24 23:56:05 +08:00
|
|
|
return rc;
|
2007-10-31 12:54:42 +08:00
|
|
|
}
|