Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | /* * linux/fs/attr.c * * Copyright (C) 1991, 1992 Linus Torvalds * changes by Thomas Schoebel-Theuer */ #include <linux/sched.h> #include <linux/mm.h> #include <linux/string.h> /* Taken over from the old code... */ /* POSIX UID/GID verification for setting inode attributes. */ int inode_change_ok(struct inode *inode, struct iattr *attr) { int retval = -EPERM; unsigned int ia_valid = attr->ia_valid; /* If force is set do it anyway. */ if (ia_valid & ATTR_FORCE) goto fine; /* Make sure a caller can chown. */ if ((ia_valid & ATTR_UID) && (current->fsuid != inode->i_uid || attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN)) goto error; /* Make sure caller can chgrp. */ if ((ia_valid & ATTR_GID) && (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid) && !capable(CAP_CHOWN)) goto error; /* Make sure a caller can chmod. */ if (ia_valid & ATTR_MODE) { if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) goto error; /* Also check the setgid bit! */ if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : inode->i_gid) && !capable(CAP_FSETID)) attr->ia_mode &= ~S_ISGID; } /* Check for setting the inode time. */ if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) { if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER)) goto error; } fine: retval = 0; error: return retval; } void inode_setattr(struct inode * inode, struct iattr * attr) { unsigned int ia_valid = attr->ia_valid; if (ia_valid & ATTR_UID) inode->i_uid = attr->ia_uid; if (ia_valid & ATTR_GID) inode->i_gid = attr->ia_gid; if (ia_valid & ATTR_SIZE) inode->i_size = attr->ia_size; if (ia_valid & ATTR_ATIME) inode->i_atime = attr->ia_atime; if (ia_valid & ATTR_MTIME) inode->i_mtime = attr->ia_mtime; if (ia_valid & ATTR_CTIME) inode->i_ctime = attr->ia_ctime; if (ia_valid & ATTR_MODE) { inode->i_mode = attr->ia_mode; if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) inode->i_mode &= ~S_ISGID; } mark_inode_dirty(inode); } int notify_change(struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; int error; time_t now = CURRENT_TIME; unsigned int ia_valid = attr->ia_valid; attr->ia_ctime = now; if (!(ia_valid & ATTR_ATIME_SET)) attr->ia_atime = now; if (!(ia_valid & ATTR_MTIME_SET)) attr->ia_mtime = now; if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->notify_change) error = inode->i_sb->s_op->notify_change(dentry, attr); else { error = inode_change_ok(inode, attr); if (!error) inode_setattr(inode, attr); } return error; } |