aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsacl.c325
-rw-r--r--fs/cifs/cifsacl.h24
2 files changed, 325 insertions, 24 deletions
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index 061fc3afd841..a4aa0f0af5c3 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -54,7 +54,33 @@ static const struct cifs_sid sid_authusers = {
54/* group users */ 54/* group users */
55static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; 55static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
56 56
57static const struct cred *root_cred; 57const struct cred *root_cred;
58
59static void
60shrink_idmap_tree(struct rb_root *root, int nr_to_scan, int *nr_rem,
61 int *nr_del)
62{
63 struct rb_node *node;
64 struct rb_node *tmp;
65 struct cifs_sid_id *psidid;
66
67 node = rb_first(root);
68 while (node) {
69 tmp = node;
70 node = rb_next(tmp);
71 psidid = rb_entry(tmp, struct cifs_sid_id, rbnode);
72 if (nr_to_scan == 0 || *nr_del == nr_to_scan)
73 ++(*nr_rem);
74 else {
75 if (time_after(jiffies, psidid->time + SID_MAP_EXPIRE)
76 && psidid->refcount == 0) {
77 rb_erase(tmp, root);
78 ++(*nr_del);
79 } else
80 ++(*nr_rem);
81 }
82 }
83}
58 84
59/* 85/*
60 * Run idmap cache shrinker. 86 * Run idmap cache shrinker.
@@ -62,9 +88,21 @@ static const struct cred *root_cred;
62static int 88static int
63cifs_idmap_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) 89cifs_idmap_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
64{ 90{
65 /* Use a pruning scheme in a subsequent patch instead */ 91 int nr_del = 0;
66 cifs_destroy_idmaptrees(); 92 int nr_rem = 0;
67 return 0; 93 struct rb_root *root;
94
95 root = &uidtree;
96 spin_lock(&siduidlock);
97 shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
98 spin_unlock(&siduidlock);
99
100 root = &gidtree;
101 spin_lock(&sidgidlock);
102 shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
103 spin_unlock(&sidgidlock);
104
105 return nr_rem;
68} 106}
69 107
70static struct shrinker cifs_shrinker = { 108static struct shrinker cifs_shrinker = {
@@ -92,7 +130,6 @@ cifs_idmap_key_destroy(struct key *key)
92 kfree(key->payload.data); 130 kfree(key->payload.data);
93} 131}
94 132
95static
96struct key_type cifs_idmap_key_type = { 133struct key_type cifs_idmap_key_type = {
97 .name = "cifs.cifs_idmap", 134 .name = "cifs.cifs_idmap",
98 .instantiate = cifs_idmap_key_instantiate, 135 .instantiate = cifs_idmap_key_instantiate,
@@ -101,6 +138,220 @@ struct key_type cifs_idmap_key_type = {
101 .match = user_match, 138 .match = user_match,
102}; 139};
103 140
141static void
142sid_to_str(struct cifs_sid *sidptr, char *sidstr)
143{
144 int i;
145 unsigned long saval;
146 char *strptr;
147
148 strptr = sidstr;
149
150 sprintf(strptr, "%s", "S");
151 strptr = sidstr + strlen(sidstr);
152
153 sprintf(strptr, "-%d", sidptr->revision);
154 strptr = sidstr + strlen(sidstr);
155
156 for (i = 0; i < 6; ++i) {
157 if (sidptr->authority[i]) {
158 sprintf(strptr, "-%d", sidptr->authority[i]);
159 strptr = sidstr + strlen(sidstr);
160 }
161 }
162
163 for (i = 0; i < sidptr->num_subauth; ++i) {
164 saval = le32_to_cpu(sidptr->sub_auth[i]);
165 sprintf(strptr, "-%ld", saval);
166 strptr = sidstr + strlen(sidstr);
167 }
168}
169
170static void
171id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr,
172 struct cifs_sid_id **psidid, char *typestr)
173{
174 int rc;
175 char *strptr;
176 struct rb_node *node = root->rb_node;
177 struct rb_node *parent = NULL;
178 struct rb_node **linkto = &(root->rb_node);
179 struct cifs_sid_id *lsidid;
180
181 while (node) {
182 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
183 parent = node;
184 rc = compare_sids(sidptr, &((lsidid)->sid));
185 if (rc > 0) {
186 linkto = &(node->rb_left);
187 node = node->rb_left;
188 } else if (rc < 0) {
189 linkto = &(node->rb_right);
190 node = node->rb_right;
191 }
192 }
193
194 memcpy(&(*psidid)->sid, sidptr, sizeof(struct cifs_sid));
195 (*psidid)->time = jiffies - (SID_MAP_RETRY + 1);
196 (*psidid)->refcount = 0;
197
198 sprintf((*psidid)->sidstr, "%s", typestr);
199 strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr);
200 sid_to_str(&(*psidid)->sid, strptr);
201
202 clear_bit(SID_ID_PENDING, &(*psidid)->state);
203 clear_bit(SID_ID_MAPPED, &(*psidid)->state);
204
205 rb_link_node(&(*psidid)->rbnode, parent, linkto);
206 rb_insert_color(&(*psidid)->rbnode, root);
207}
208
209static struct cifs_sid_id *
210id_rb_search(struct rb_root *root, struct cifs_sid *sidptr)
211{
212 int rc;
213 struct rb_node *node = root->rb_node;
214 struct rb_node *parent = NULL;
215 struct rb_node **linkto = &(root->rb_node);
216 struct cifs_sid_id *lsidid;
217
218 while (node) {
219 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
220 parent = node;
221 rc = compare_sids(sidptr, &((lsidid)->sid));
222 if (rc > 0) {
223 linkto = &(node->rb_left);
224 node = node->rb_left;
225 } else if (rc < 0) {
226 linkto = &(node->rb_right);
227 node = node->rb_right;
228 } else /* node found */
229 return lsidid;
230 }
231
232 return NULL;
233}
234
235static int
236sidid_pending_wait(void *unused)
237{
238 schedule();
239 return signal_pending(current) ? -ERESTARTSYS : 0;
240}
241
242static int
243sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
244 struct cifs_fattr *fattr, uint sidtype)
245{
246 int rc;
247 unsigned long cid;
248 struct key *idkey;
249 const struct cred *saved_cred;
250 struct cifs_sid_id *psidid, *npsidid;
251 struct rb_root *cidtree;
252 spinlock_t *cidlock;
253
254 if (sidtype == SIDOWNER) {
255 cid = cifs_sb->mnt_uid; /* default uid, in case upcall fails */
256 cidlock = &siduidlock;
257 cidtree = &uidtree;
258 } else if (sidtype == SIDGROUP) {
259 cid = cifs_sb->mnt_gid; /* default gid, in case upcall fails */
260 cidlock = &sidgidlock;
261 cidtree = &gidtree;
262 } else
263 return -ENOENT;
264
265 spin_lock(cidlock);
266 psidid = id_rb_search(cidtree, psid);
267
268 if (!psidid) { /* node does not exist, allocate one & attempt adding */
269 spin_unlock(cidlock);
270 npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
271 if (!npsidid)
272 return -ENOMEM;
273
274 npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL);
275 if (!npsidid->sidstr) {
276 kfree(npsidid);
277 return -ENOMEM;
278 }
279
280 spin_lock(cidlock);
281 psidid = id_rb_search(cidtree, psid);
282 if (psidid) { /* node happened to get inserted meanwhile */
283 ++psidid->refcount;
284 spin_unlock(cidlock);
285 kfree(npsidid->sidstr);
286 kfree(npsidid);
287 } else {
288 psidid = npsidid;
289 id_rb_insert(cidtree, psid, &psidid,
290 sidtype == SIDOWNER ? "os:" : "gs:");
291 ++psidid->refcount;
292 spin_unlock(cidlock);
293 }
294 } else {
295 ++psidid->refcount;
296 spin_unlock(cidlock);
297 }
298
299 /*
300 * If we are here, it is safe to access psidid and its fields
301 * since a reference was taken earlier while holding the spinlock.
302 * A reference on the node is put without holding the spinlock
303 * and it is OK to do so in this case, shrinker will not erase
304 * this node until all references are put and we do not access
305 * any fields of the node after a reference is put .
306 */
307 if (test_bit(SID_ID_MAPPED, &psidid->state)) {
308 cid = psidid->id;
309 psidid->time = jiffies; /* update ts for accessing */
310 goto sid_to_id_out;
311 }
312
313 if (time_after(psidid->time + SID_MAP_RETRY, jiffies))
314 goto sid_to_id_out;
315
316 if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
317 saved_cred = override_creds(root_cred);
318 idkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
319 if (IS_ERR(idkey))
320 cFYI(1, "%s: Can't map SID to an id", __func__);
321 else {
322 cid = *(unsigned long *)idkey->payload.value;
323 psidid->id = cid;
324 set_bit(SID_ID_MAPPED, &psidid->state);
325 key_put(idkey);
326 kfree(psidid->sidstr);
327 }
328 revert_creds(saved_cred);
329 psidid->time = jiffies; /* update ts for accessing */
330 clear_bit(SID_ID_PENDING, &psidid->state);
331 wake_up_bit(&psidid->state, SID_ID_PENDING);
332 } else {
333 rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
334 sidid_pending_wait, TASK_INTERRUPTIBLE);
335 if (rc) {
336 cFYI(1, "%s: sidid_pending_wait interrupted %d",
337 __func__, rc);
338 --psidid->refcount; /* decremented without spinlock */
339 return rc;
340 }
341 if (test_bit(SID_ID_MAPPED, &psidid->state))
342 cid = psidid->id;
343 }
344
345sid_to_id_out:
346 --psidid->refcount; /* decremented without spinlock */
347 if (sidtype == SIDOWNER)
348 fattr->cf_uid = cid;
349 else
350 fattr->cf_gid = cid;
351
352 return 0;
353}
354
104int 355int
105init_cifs_idmap(void) 356init_cifs_idmap(void)
106{ 357{
@@ -242,16 +493,24 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
242 int num_subauth, num_sat, num_saw; 493 int num_subauth, num_sat, num_saw;
243 494
244 if ((!ctsid) || (!cwsid)) 495 if ((!ctsid) || (!cwsid))
245 return 0; 496 return 1;
246 497
247 /* compare the revision */ 498 /* compare the revision */
248 if (ctsid->revision != cwsid->revision) 499 if (ctsid->revision != cwsid->revision) {
249 return 0; 500 if (ctsid->revision > cwsid->revision)
501 return 1;
502 else
503 return -1;
504 }
250 505
251 /* compare all of the six auth values */ 506 /* compare all of the six auth values */
252 for (i = 0; i < 6; ++i) { 507 for (i = 0; i < 6; ++i) {
253 if (ctsid->authority[i] != cwsid->authority[i]) 508 if (ctsid->authority[i] != cwsid->authority[i]) {
254 return 0; 509 if (ctsid->authority[i] > cwsid->authority[i])
510 return 1;
511 else
512 return -1;
513 }
255 } 514 }
256 515
257 /* compare all of the subauth values if any */ 516 /* compare all of the subauth values if any */
@@ -260,12 +519,16 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
260 num_subauth = num_sat < num_saw ? num_sat : num_saw; 519 num_subauth = num_sat < num_saw ? num_sat : num_saw;
261 if (num_subauth) { 520 if (num_subauth) {
262 for (i = 0; i < num_subauth; ++i) { 521 for (i = 0; i < num_subauth; ++i) {
263 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) 522 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
264 return 0; 523 if (ctsid->sub_auth[i] > cwsid->sub_auth[i])
524 return 1;
525 else
526 return -1;
527 }
265 } 528 }
266 } 529 }
267 530
268 return 1; /* sids compare/match */ 531 return 0; /* sids compare/match */
269} 532}
270 533
271 534
@@ -520,22 +783,22 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
520#ifdef CONFIG_CIFS_DEBUG2 783#ifdef CONFIG_CIFS_DEBUG2
521 dump_ace(ppace[i], end_of_acl); 784 dump_ace(ppace[i], end_of_acl);
522#endif 785#endif
523 if (compare_sids(&(ppace[i]->sid), pownersid)) 786 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
524 access_flags_to_mode(ppace[i]->access_req, 787 access_flags_to_mode(ppace[i]->access_req,
525 ppace[i]->type, 788 ppace[i]->type,
526 &fattr->cf_mode, 789 &fattr->cf_mode,
527 &user_mask); 790 &user_mask);
528 if (compare_sids(&(ppace[i]->sid), pgrpsid)) 791 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
529 access_flags_to_mode(ppace[i]->access_req, 792 access_flags_to_mode(ppace[i]->access_req,
530 ppace[i]->type, 793 ppace[i]->type,
531 &fattr->cf_mode, 794 &fattr->cf_mode,
532 &group_mask); 795 &group_mask);
533 if (compare_sids(&(ppace[i]->sid), &sid_everyone)) 796 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
534 access_flags_to_mode(ppace[i]->access_req, 797 access_flags_to_mode(ppace[i]->access_req,
535 ppace[i]->type, 798 ppace[i]->type,
536 &fattr->cf_mode, 799 &fattr->cf_mode,
537 &other_mask); 800 &other_mask);
538 if (compare_sids(&(ppace[i]->sid), &sid_authusers)) 801 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
539 access_flags_to_mode(ppace[i]->access_req, 802 access_flags_to_mode(ppace[i]->access_req,
540 ppace[i]->type, 803 ppace[i]->type,
541 &fattr->cf_mode, 804 &fattr->cf_mode,
@@ -613,10 +876,10 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
613 876
614 877
615/* Convert CIFS ACL to POSIX form */ 878/* Convert CIFS ACL to POSIX form */
616static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, 879static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
617 struct cifs_fattr *fattr) 880 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
618{ 881{
619 int rc; 882 int rc = 0;
620 struct cifs_sid *owner_sid_ptr, *group_sid_ptr; 883 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
621 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ 884 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
622 char *end_of_acl = ((char *)pntsd) + acl_len; 885 char *end_of_acl = ((char *)pntsd) + acl_len;
@@ -638,12 +901,26 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
638 le32_to_cpu(pntsd->sacloffset), dacloffset); 901 le32_to_cpu(pntsd->sacloffset), dacloffset);
639/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */ 902/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
640 rc = parse_sid(owner_sid_ptr, end_of_acl); 903 rc = parse_sid(owner_sid_ptr, end_of_acl);
641 if (rc) 904 if (rc) {
905 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
642 return rc; 906 return rc;
907 }
908 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
909 if (rc) {
910 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
911 return rc;
912 }
643 913
644 rc = parse_sid(group_sid_ptr, end_of_acl); 914 rc = parse_sid(group_sid_ptr, end_of_acl);
645 if (rc) 915 if (rc) {
916 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
646 return rc; 917 return rc;
918 }
919 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
920 if (rc) {
921 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
922 return rc;
923 }
647 924
648 if (dacloffset) 925 if (dacloffset)
649 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, 926 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
@@ -658,7 +935,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
658 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, 935 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
659 sizeof(struct cifs_sid)); */ 936 sizeof(struct cifs_sid)); */
660 937
661 return 0; 938 return rc;
662} 939}
663 940
664 941
@@ -865,7 +1142,7 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
865 rc = PTR_ERR(pntsd); 1142 rc = PTR_ERR(pntsd);
866 cERROR(1, "%s: error %d getting sec desc", __func__, rc); 1143 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
867 } else { 1144 } else {
868 rc = parse_sec_desc(pntsd, acllen, fattr); 1145 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
869 kfree(pntsd); 1146 kfree(pntsd);
870 if (rc) 1147 if (rc)
871 cERROR(1, "parse sec desc failed rc = %d", rc); 1148 cERROR(1, "parse sec desc failed rc = %d", rc);
diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h
index c4ae7d036563..757cf5aec3ee 100644
--- a/fs/cifs/cifsacl.h
+++ b/fs/cifs/cifsacl.h
@@ -39,6 +39,15 @@
39#define ACCESS_ALLOWED 0 39#define ACCESS_ALLOWED 0
40#define ACCESS_DENIED 1 40#define ACCESS_DENIED 1
41 41
42#define SIDOWNER 1
43#define SIDGROUP 2
44#define SIDLEN 150 /* S- 1 revision- 6 authorities- max 5 sub authorities */
45
46#define SID_ID_MAPPED 0
47#define SID_ID_PENDING 1
48#define SID_MAP_EXPIRE (3600 * HZ) /* map entry expires after one hour */
49#define SID_MAP_RETRY (300 * HZ) /* wait 5 minutes for next attempt to map */
50
42struct cifs_ntsd { 51struct cifs_ntsd {
43 __le16 revision; /* revision level */ 52 __le16 revision; /* revision level */
44 __le16 type; 53 __le16 type;
@@ -74,6 +83,21 @@ struct cifs_wksid {
74 char sidname[SIDNAMELENGTH]; 83 char sidname[SIDNAMELENGTH];
75} __attribute__((packed)); 84} __attribute__((packed));
76 85
86struct cifs_sid_id {
87 unsigned int refcount; /* increment with spinlock, decrement without */
88 unsigned long id;
89 unsigned long time;
90 unsigned long state;
91 char *sidstr;
92 struct rb_node rbnode;
93 struct cifs_sid sid;
94};
95
96#ifdef __KERNEL__
97extern struct key_type cifs_idmap_key_type;
98extern const struct cred *root_cred;
99#endif /* KERNEL */
100
77extern int match_sid(struct cifs_sid *); 101extern int match_sid(struct cifs_sid *);
78extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *); 102extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *);
79 103