Skip to content

Commit

Permalink
CIFS: Retrieve uid and gid from special sid if enabled
Browse files Browse the repository at this point in the history
New mount option "idsfromsid" indicates to cifs.ko that
it should try to retrieve the uid and gid owner fields
from special sids.  This patch adds the code to parse the owner
sids in the ACL to see if they match, and if so populate the
uid and/or gid from them.  This is faster than upcalling for
them and asking winbind, and is a fairly common case, and is
also helpful when cifs.upcall and idmapping is not configured.

Signed-off-by: Steve French <steve.french@primarydata.com>
Reviewed-by:  Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
  • Loading branch information
Steve French committed Oct 14, 2016
1 parent 9593265 commit 3514de3
Showing 1 changed file with 123 additions and 0 deletions.
123 changes: 123 additions & 0 deletions fs/cifs/cifsacl.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,35 @@ static const struct cifs_sid sid_authusers = {
/* group users */
static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };

/* 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} };

static const struct cred *root_cred;

static int
Expand Down Expand Up @@ -183,6 +212,62 @@ compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
return 0; /* sids compare/match */
}

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

static void
cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
{
Expand Down Expand Up @@ -276,6 +361,43 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
return -EIO;
}

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:
sidstr = sid_to_key_str(psid, sidtype);
if (!sidstr)
return -ENOMEM;
Expand Down Expand Up @@ -329,6 +451,7 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
* Note that we return 0 here unconditionally. If the mapping
* fails then we just fall back to using the mnt_uid/mnt_gid.
*/
got_valid_id:
if (sidtype == SIDOWNER)
fattr->cf_uid = fuid;
else
Expand Down

0 comments on commit 3514de3

Please sign in to comment.