Skip to content

Commit 3514de3

Browse files
committed
CIFS: Retrieve uid and gid from special sid if enabled
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>
1 parent 9593265 commit 3514de3

1 file changed

Lines changed: 123 additions & 0 deletions

File tree

fs/cifs/cifsacl.c

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,35 @@ static const struct cifs_sid sid_authusers = {
4242
/* group users */
4343
static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
4444

45+
/* S-1-22-1 Unmapped Unix users */
46+
static const struct cifs_sid sid_unix_users = {1, 1, {0, 0, 0, 0, 0, 22},
47+
{cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
48+
49+
/* S-1-22-2 Unmapped Unix groups */
50+
static const struct cifs_sid sid_unix_groups = { 1, 1, {0, 0, 0, 0, 0, 22},
51+
{cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
52+
53+
/*
54+
* See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
55+
*/
56+
57+
/* S-1-5-88 MS NFS and Apple style UID/GID/mode */
58+
59+
/* S-1-5-88-1 Unix uid */
60+
static const struct cifs_sid sid_unix_NFS_users = { 1, 2, {0, 0, 0, 0, 0, 5},
61+
{cpu_to_le32(88),
62+
cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
63+
64+
/* S-1-5-88-2 Unix gid */
65+
static const struct cifs_sid sid_unix_NFS_groups = { 1, 2, {0, 0, 0, 0, 0, 5},
66+
{cpu_to_le32(88),
67+
cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
68+
69+
/* S-1-5-88-3 Unix mode */
70+
static const struct cifs_sid sid_unix_NFS_mode = { 1, 2, {0, 0, 0, 0, 0, 5},
71+
{cpu_to_le32(88),
72+
cpu_to_le32(3), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
73+
4574
static const struct cred *root_cred;
4675

4776
static int
@@ -183,6 +212,62 @@ compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
183212
return 0; /* sids compare/match */
184213
}
185214

215+
static bool
216+
is_well_known_sid(const struct cifs_sid *psid, uint32_t *puid, bool is_group)
217+
{
218+
int i;
219+
int num_subauth;
220+
const struct cifs_sid *pwell_known_sid;
221+
222+
if (!psid || (puid == NULL))
223+
return false;
224+
225+
num_subauth = psid->num_subauth;
226+
227+
/* check if Mac (or Windows NFS) vs. Samba format for Unix owner SID */
228+
if (num_subauth == 2) {
229+
if (is_group)
230+
pwell_known_sid = &sid_unix_groups;
231+
else
232+
pwell_known_sid = &sid_unix_users;
233+
} else if (num_subauth == 3) {
234+
if (is_group)
235+
pwell_known_sid = &sid_unix_NFS_groups;
236+
else
237+
pwell_known_sid = &sid_unix_NFS_users;
238+
} else
239+
return false;
240+
241+
/* compare the revision */
242+
if (psid->revision != pwell_known_sid->revision)
243+
return false;
244+
245+
/* compare all of the six auth values */
246+
for (i = 0; i < NUM_AUTHS; ++i) {
247+
if (psid->authority[i] != pwell_known_sid->authority[i]) {
248+
cifs_dbg(FYI, "auth %d did not match\n", i);
249+
return false;
250+
}
251+
}
252+
253+
if (num_subauth == 2) {
254+
if (psid->sub_auth[0] != pwell_known_sid->sub_auth[0])
255+
return false;
256+
257+
*puid = le32_to_cpu(psid->sub_auth[1]);
258+
} else /* 3 subauths, ie Windows/Mac style */ {
259+
*puid = le32_to_cpu(psid->sub_auth[0]);
260+
if ((psid->sub_auth[0] != pwell_known_sid->sub_auth[0]) ||
261+
(psid->sub_auth[1] != pwell_known_sid->sub_auth[1]))
262+
return false;
263+
264+
*puid = le32_to_cpu(psid->sub_auth[2]);
265+
}
266+
267+
cifs_dbg(FYI, "Unix UID %d returned from SID\n", *puid);
268+
return true; /* well known sid found, uid returned */
269+
}
270+
186271
static void
187272
cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
188273
{
@@ -276,6 +361,43 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
276361
return -EIO;
277362
}
278363

364+
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) {
365+
uint32_t unix_id;
366+
bool is_group;
367+
368+
if (sidtype != SIDOWNER)
369+
is_group = true;
370+
else
371+
is_group = false;
372+
373+
if (is_well_known_sid(psid, &unix_id, is_group) == false)
374+
goto try_upcall_to_get_id;
375+
376+
if (is_group) {
377+
kgid_t gid;
378+
gid_t id;
379+
380+
id = (gid_t)unix_id;
381+
gid = make_kgid(&init_user_ns, id);
382+
if (gid_valid(gid)) {
383+
fgid = gid;
384+
goto got_valid_id;
385+
}
386+
} else {
387+
kuid_t uid;
388+
uid_t id;
389+
390+
id = (uid_t)unix_id;
391+
uid = make_kuid(&init_user_ns, id);
392+
if (uid_valid(uid)) {
393+
fuid = uid;
394+
goto got_valid_id;
395+
}
396+
}
397+
/* If unable to find uid/gid easily from SID try via upcall */
398+
}
399+
400+
try_upcall_to_get_id:
279401
sidstr = sid_to_key_str(psid, sidtype);
280402
if (!sidstr)
281403
return -ENOMEM;
@@ -329,6 +451,7 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
329451
* Note that we return 0 here unconditionally. If the mapping
330452
* fails then we just fall back to using the mnt_uid/mnt_gid.
331453
*/
454+
got_valid_id:
332455
if (sidtype == SIDOWNER)
333456
fattr->cf_uid = fuid;
334457
else

0 commit comments

Comments
 (0)