diff options
author | David Howells <dhowells@redhat.com> | 2007-04-26 18:57:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-04-26 18:57:07 -0400 |
commit | 00d3b7a4533e367b0dc2812a706db8f9f071c27f (patch) | |
tree | f0b1ae0266267cb2c54cb11aa61ad0758ce9c0f5 /fs/afs/dir.c | |
parent | 436058a49e0fb91c74454dbee9cfee6fb53b4336 (diff) |
[AFS]: Add security support.
Add security support to the AFS filesystem. Kerberos IV tickets are added as
RxRPC keys are added to the session keyring with the klog program. open() and
other VFS operations then find this ticket with request_key() and either use
it immediately (eg: mkdir, unlink) or attach it to a file descriptor (open).
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'fs/afs/dir.c')
-rw-r--r-- | fs/afs/dir.c | 51 |
1 files changed, 38 insertions, 13 deletions
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index d7697f6f3b7..87368417e4d 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
17 | #include <linux/pagemap.h> | 17 | #include <linux/pagemap.h> |
18 | #include <linux/ctype.h> | ||
18 | #include "internal.h" | 19 | #include "internal.h" |
19 | 20 | ||
20 | static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, | 21 | static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, |
@@ -28,11 +29,13 @@ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, | |||
28 | 29 | ||
29 | const struct file_operations afs_dir_file_operations = { | 30 | const struct file_operations afs_dir_file_operations = { |
30 | .open = afs_dir_open, | 31 | .open = afs_dir_open, |
32 | .release = afs_release, | ||
31 | .readdir = afs_dir_readdir, | 33 | .readdir = afs_dir_readdir, |
32 | }; | 34 | }; |
33 | 35 | ||
34 | const struct inode_operations afs_dir_inode_operations = { | 36 | const struct inode_operations afs_dir_inode_operations = { |
35 | .lookup = afs_dir_lookup, | 37 | .lookup = afs_dir_lookup, |
38 | .permission = afs_permission, | ||
36 | .getattr = afs_inode_getattr, | 39 | .getattr = afs_inode_getattr, |
37 | #if 0 /* TODO */ | 40 | #if 0 /* TODO */ |
38 | .create = afs_dir_create, | 41 | .create = afs_dir_create, |
@@ -169,13 +172,17 @@ static inline void afs_dir_put_page(struct page *page) | |||
169 | /* | 172 | /* |
170 | * get a page into the pagecache | 173 | * get a page into the pagecache |
171 | */ | 174 | */ |
172 | static struct page *afs_dir_get_page(struct inode *dir, unsigned long index) | 175 | static struct page *afs_dir_get_page(struct inode *dir, unsigned long index, |
176 | struct key *key) | ||
173 | { | 177 | { |
174 | struct page *page; | 178 | struct page *page; |
179 | struct file file = { | ||
180 | .private_data = key, | ||
181 | }; | ||
175 | 182 | ||
176 | _enter("{%lu},%lu", dir->i_ino, index); | 183 | _enter("{%lu},%lu", dir->i_ino, index); |
177 | 184 | ||
178 | page = read_mapping_page(dir->i_mapping, index, NULL); | 185 | page = read_mapping_page(dir->i_mapping, index, &file); |
179 | if (!IS_ERR(page)) { | 186 | if (!IS_ERR(page)) { |
180 | wait_on_page_locked(page); | 187 | wait_on_page_locked(page); |
181 | kmap(page); | 188 | kmap(page); |
@@ -207,8 +214,7 @@ static int afs_dir_open(struct inode *inode, struct file *file) | |||
207 | if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags)) | 214 | if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags)) |
208 | return -ENOENT; | 215 | return -ENOENT; |
209 | 216 | ||
210 | _leave(" = 0"); | 217 | return afs_open(inode, file); |
211 | return 0; | ||
212 | } | 218 | } |
213 | 219 | ||
214 | /* | 220 | /* |
@@ -311,7 +317,7 @@ static int afs_dir_iterate_block(unsigned *fpos, | |||
311 | * iterate through the data blob that lists the contents of an AFS directory | 317 | * iterate through the data blob that lists the contents of an AFS directory |
312 | */ | 318 | */ |
313 | static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, | 319 | static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, |
314 | filldir_t filldir) | 320 | filldir_t filldir, struct key *key) |
315 | { | 321 | { |
316 | union afs_dir_block *dblock; | 322 | union afs_dir_block *dblock; |
317 | struct afs_dir_page *dbuf; | 323 | struct afs_dir_page *dbuf; |
@@ -336,7 +342,7 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, | |||
336 | blkoff = *fpos & ~(sizeof(union afs_dir_block) - 1); | 342 | blkoff = *fpos & ~(sizeof(union afs_dir_block) - 1); |
337 | 343 | ||
338 | /* fetch the appropriate page from the directory */ | 344 | /* fetch the appropriate page from the directory */ |
339 | page = afs_dir_get_page(dir, blkoff / PAGE_SIZE); | 345 | page = afs_dir_get_page(dir, blkoff / PAGE_SIZE, key); |
340 | if (IS_ERR(page)) { | 346 | if (IS_ERR(page)) { |
341 | ret = PTR_ERR(page); | 347 | ret = PTR_ERR(page); |
342 | break; | 348 | break; |
@@ -381,9 +387,11 @@ static int afs_dir_readdir(struct file *file, void *cookie, filldir_t filldir) | |||
381 | _enter("{%Ld,{%lu}}", | 387 | _enter("{%Ld,{%lu}}", |
382 | file->f_pos, file->f_path.dentry->d_inode->i_ino); | 388 | file->f_pos, file->f_path.dentry->d_inode->i_ino); |
383 | 389 | ||
390 | ASSERT(file->private_data != NULL); | ||
391 | |||
384 | fpos = file->f_pos; | 392 | fpos = file->f_pos; |
385 | ret = afs_dir_iterate(file->f_path.dentry->d_inode, &fpos, | 393 | ret = afs_dir_iterate(file->f_path.dentry->d_inode, &fpos, |
386 | cookie, filldir); | 394 | cookie, filldir, file->private_data); |
387 | file->f_pos = fpos; | 395 | file->f_pos = fpos; |
388 | 396 | ||
389 | _leave(" = %d", ret); | 397 | _leave(" = %d", ret); |
@@ -424,7 +432,7 @@ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, | |||
424 | * do a lookup in a directory | 432 | * do a lookup in a directory |
425 | */ | 433 | */ |
426 | static int afs_do_lookup(struct inode *dir, struct dentry *dentry, | 434 | static int afs_do_lookup(struct inode *dir, struct dentry *dentry, |
427 | struct afs_fid *fid) | 435 | struct afs_fid *fid, struct key *key) |
428 | { | 436 | { |
429 | struct afs_dir_lookup_cookie cookie; | 437 | struct afs_dir_lookup_cookie cookie; |
430 | struct afs_super_info *as; | 438 | struct afs_super_info *as; |
@@ -442,7 +450,8 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry, | |||
442 | cookie.found = 0; | 450 | cookie.found = 0; |
443 | 451 | ||
444 | fpos = 0; | 452 | fpos = 0; |
445 | ret = afs_dir_iterate(dir, &fpos, &cookie, afs_dir_lookup_filldir); | 453 | ret = afs_dir_iterate(dir, &fpos, &cookie, afs_dir_lookup_filldir, |
454 | key); | ||
446 | if (ret < 0) { | 455 | if (ret < 0) { |
447 | _leave(" = %d [iter]", ret); | 456 | _leave(" = %d [iter]", ret); |
448 | return ret; | 457 | return ret; |
@@ -468,6 +477,7 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, | |||
468 | struct afs_vnode *vnode; | 477 | struct afs_vnode *vnode; |
469 | struct afs_fid fid; | 478 | struct afs_fid fid; |
470 | struct inode *inode; | 479 | struct inode *inode; |
480 | struct key *key; | ||
471 | int ret; | 481 | int ret; |
472 | 482 | ||
473 | _enter("{%lu},%p{%s}", dir->i_ino, dentry, dentry->d_name.name); | 483 | _enter("{%lu},%p{%s}", dir->i_ino, dentry, dentry->d_name.name); |
@@ -483,14 +493,22 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, | |||
483 | return ERR_PTR(-ESTALE); | 493 | return ERR_PTR(-ESTALE); |
484 | } | 494 | } |
485 | 495 | ||
486 | ret = afs_do_lookup(dir, dentry, &fid); | 496 | key = afs_request_key(vnode->volume->cell); |
497 | if (IS_ERR(key)) { | ||
498 | _leave(" = %ld [key]", PTR_ERR(key)); | ||
499 | return ERR_PTR(PTR_ERR(key)); | ||
500 | } | ||
501 | |||
502 | ret = afs_do_lookup(dir, dentry, &fid, key); | ||
487 | if (ret < 0) { | 503 | if (ret < 0) { |
504 | key_put(key); | ||
488 | _leave(" = %d [do]", ret); | 505 | _leave(" = %d [do]", ret); |
489 | return ERR_PTR(ret); | 506 | return ERR_PTR(ret); |
490 | } | 507 | } |
491 | 508 | ||
492 | /* instantiate the dentry */ | 509 | /* instantiate the dentry */ |
493 | inode = afs_iget(dir->i_sb, &fid); | 510 | inode = afs_iget(dir->i_sb, key, &fid); |
511 | key_put(key); | ||
494 | if (IS_ERR(inode)) { | 512 | if (IS_ERR(inode)) { |
495 | _leave(" = %ld", PTR_ERR(inode)); | 513 | _leave(" = %ld", PTR_ERR(inode)); |
496 | return ERR_PTR(PTR_ERR(inode)); | 514 | return ERR_PTR(PTR_ERR(inode)); |
@@ -559,6 +577,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
559 | struct afs_fid fid; | 577 | struct afs_fid fid; |
560 | struct dentry *parent; | 578 | struct dentry *parent; |
561 | struct inode *inode, *dir; | 579 | struct inode *inode, *dir; |
580 | struct key *key; | ||
562 | int ret; | 581 | int ret; |
563 | 582 | ||
564 | vnode = AFS_FS_I(dentry->d_inode); | 583 | vnode = AFS_FS_I(dentry->d_inode); |
@@ -566,6 +585,10 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
566 | _enter("{sb=%p n=%s fl=%lx},", | 585 | _enter("{sb=%p n=%s fl=%lx},", |
567 | dentry->d_sb, dentry->d_name.name, vnode->flags); | 586 | dentry->d_sb, dentry->d_name.name, vnode->flags); |
568 | 587 | ||
588 | key = afs_request_key(vnode->volume->cell); | ||
589 | if (IS_ERR(key)) | ||
590 | key = NULL; | ||
591 | |||
569 | /* lock down the parent dentry so we can peer at it */ | 592 | /* lock down the parent dentry so we can peer at it */ |
570 | parent = dget_parent(dentry); | 593 | parent = dget_parent(dentry); |
571 | 594 | ||
@@ -595,7 +618,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
595 | _debug("dir modified"); | 618 | _debug("dir modified"); |
596 | 619 | ||
597 | /* search the directory for this vnode */ | 620 | /* search the directory for this vnode */ |
598 | ret = afs_do_lookup(dir, dentry, &fid); | 621 | ret = afs_do_lookup(dir, dentry, &fid, key); |
599 | if (ret == -ENOENT) { | 622 | if (ret == -ENOENT) { |
600 | _debug("%s: dirent not found", dentry->d_name.name); | 623 | _debug("%s: dirent not found", dentry->d_name.name); |
601 | goto not_found; | 624 | goto not_found; |
@@ -637,7 +660,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
637 | test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { | 660 | test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { |
638 | _debug("%s: changed", dentry->d_name.name); | 661 | _debug("%s: changed", dentry->d_name.name); |
639 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); | 662 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); |
640 | if (afs_vnode_fetch_status(vnode) < 0) { | 663 | if (afs_vnode_fetch_status(vnode, NULL, key) < 0) { |
641 | mutex_unlock(&vnode->cb_broken_lock); | 664 | mutex_unlock(&vnode->cb_broken_lock); |
642 | goto out_bad; | 665 | goto out_bad; |
643 | } | 666 | } |
@@ -667,6 +690,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
667 | 690 | ||
668 | out_valid: | 691 | out_valid: |
669 | dput(parent); | 692 | dput(parent); |
693 | key_put(key); | ||
670 | _leave(" = 1 [valid]"); | 694 | _leave(" = 1 [valid]"); |
671 | return 1; | 695 | return 1; |
672 | 696 | ||
@@ -688,6 +712,7 @@ out_bad: | |||
688 | shrink_dcache_parent(dentry); | 712 | shrink_dcache_parent(dentry); |
689 | d_drop(dentry); | 713 | d_drop(dentry); |
690 | dput(parent); | 714 | dput(parent); |
715 | key_put(key); | ||
691 | 716 | ||
692 | _leave(" = 0 [bad]"); | 717 | _leave(" = 0 [bad]"); |
693 | return 0; | 718 | return 0; |