VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / fs / attr.c
1 /*
2  *  linux/fs/attr.c
3  *
4  *  Copyright (C) 1991, 1992  Linus Torvalds
5  *  changes by Thomas Schoebel-Theuer
6  */
7
8 #include <linux/module.h>
9 #include <linux/time.h>
10 #include <linux/mm.h>
11 #include <linux/string.h>
12 #include <linux/smp_lock.h>
13 #include <linux/dnotify.h>
14 #include <linux/fcntl.h>
15 #include <linux/quotaops.h>
16 #include <linux/security.h>
17 #include <linux/vs_base.h>
18 #include <linux/proc_fs.h>
19 #include <linux/devpts_fs.h>
20
21 /* Taken over from the old code... */
22
23 /* POSIX UID/GID verification for setting inode attributes. */
24 int inode_change_ok(struct inode *inode, struct iattr *attr)
25 {
26         int retval = -EPERM;
27         unsigned int ia_valid = attr->ia_valid;
28
29         /* If force is set do it anyway. */
30         if (ia_valid & ATTR_FORCE)
31                 goto fine;
32
33         /* Make sure a caller can chown. */
34         if ((ia_valid & ATTR_UID) &&
35             (current->fsuid != inode->i_uid ||
36              attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
37                 goto error;
38
39         /* Make sure caller can chgrp. */
40         if ((ia_valid & ATTR_GID) &&
41             (current->fsuid != inode->i_uid ||
42             (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) &&
43             !capable(CAP_CHOWN))
44                 goto error;
45
46         /* Make sure a caller can chmod. */
47         if (ia_valid & ATTR_MODE) {
48                 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
49                         goto error;
50                 /* Also check the setgid bit! */
51                 if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
52                                 inode->i_gid) && !capable(CAP_FSETID))
53                         attr->ia_mode &= ~S_ISGID;
54         }
55
56         /* Check for setting the inode time. */
57         if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
58                 if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
59                         goto error;
60         }
61
62         /* Check for evil vserver activity */
63         if (vx_check(0, VX_ADMIN))
64                 goto fine;
65
66         if (IS_BARRIER(inode)) {
67                 printk(KERN_WARNING
68                         "VSW: xid=%d messing with the barrier.\n",
69                         vx_current_xid());
70                 goto error;
71         }
72         switch (inode->i_sb->s_magic) {
73                 case PROC_SUPER_MAGIC:
74                         printk(KERN_WARNING
75                                 "VSW: xid=%d messing with the procfs.\n",
76                                 vx_current_xid());
77                         goto error;
78                 case DEVPTS_SUPER_MAGIC:
79                         if (vx_check(inode->i_xid, VX_IDENT))
80                                 goto fine;
81                         printk(KERN_WARNING
82                                 "VSW: xid=%d messing with the devpts.\n",
83                                 vx_current_xid());
84                         goto error;     
85         }
86 fine:
87         retval = 0;
88 error:
89         return retval;
90 }
91
92 EXPORT_SYMBOL(inode_change_ok);
93
94 int inode_setattr_flags(struct inode *inode, unsigned int flags)
95 {
96         unsigned int oldflags, newflags;
97
98         oldflags = inode->i_flags;
99         newflags = oldflags & ~(S_IMMUTABLE | S_IUNLINK | S_BARRIER);
100         if (flags & ATTR_FLAG_IMMUTABLE)
101                 newflags |= S_IMMUTABLE;
102         if (flags & ATTR_FLAG_IUNLINK)
103                 newflags |= S_IUNLINK;
104         if (flags & ATTR_FLAG_BARRIER)
105                 newflags |= S_BARRIER;
106
107         if (oldflags ^ newflags)
108                 inode->i_flags = newflags;
109         return 0;
110 }
111
112 int inode_setattr(struct inode * inode, struct iattr * attr)
113 {
114         unsigned int ia_valid = attr->ia_valid;
115         int error = 0;
116
117         if (ia_valid & ATTR_SIZE) {
118                 if (attr->ia_size != i_size_read(inode)) {
119                         error = vmtruncate(inode, attr->ia_size);
120                         if (error || (ia_valid == ATTR_SIZE))
121                                 goto out;
122                 } else {
123                         /*
124                          * We skipped the truncate but must still update
125                          * timestamps
126                          */
127                         ia_valid |= ATTR_MTIME|ATTR_CTIME;
128                 }
129         }
130
131         if (ia_valid & ATTR_UID)
132                 inode->i_uid = attr->ia_uid;
133         if (ia_valid & ATTR_GID)
134                 inode->i_gid = attr->ia_gid;
135         if (ia_valid & ATTR_XID)
136                 inode->i_xid = attr->ia_xid;
137         if (ia_valid & ATTR_ATIME)
138                 inode->i_atime = attr->ia_atime;
139         if (ia_valid & ATTR_MTIME)
140                 inode->i_mtime = attr->ia_mtime;
141         if (ia_valid & ATTR_CTIME)
142                 inode->i_ctime = attr->ia_ctime;
143         if (ia_valid & ATTR_MODE) {
144                 umode_t mode = attr->ia_mode;
145
146                 if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
147                         mode &= ~S_ISGID;
148                 inode->i_mode = mode;
149         }
150         if (ia_valid & ATTR_ATTR_FLAG)
151                 inode_setattr_flags(inode, attr->ia_attr_flags);
152         mark_inode_dirty(inode);
153 out:
154         return error;
155 }
156
157 EXPORT_SYMBOL(inode_setattr);
158
159 int setattr_mask(unsigned int ia_valid)
160 {
161         unsigned long dn_mask = 0;
162
163         if (ia_valid & ATTR_UID)
164                 dn_mask |= DN_ATTRIB;
165         if (ia_valid & ATTR_GID)
166                 dn_mask |= DN_ATTRIB;
167         if (ia_valid & ATTR_XID)
168                 dn_mask |= DN_ATTRIB;
169         if (ia_valid & ATTR_SIZE)
170                 dn_mask |= DN_MODIFY;
171         /* both times implies a utime(s) call */
172         if ((ia_valid & (ATTR_ATIME|ATTR_MTIME)) == (ATTR_ATIME|ATTR_MTIME))
173                 dn_mask |= DN_ATTRIB;
174         else if (ia_valid & ATTR_ATIME)
175                 dn_mask |= DN_ACCESS;
176         else if (ia_valid & ATTR_MTIME)
177                 dn_mask |= DN_MODIFY;
178         if (ia_valid & ATTR_MODE)
179                 dn_mask |= DN_ATTRIB;
180         return dn_mask;
181 }
182
183 int notify_change(struct dentry * dentry, struct iattr * attr)
184 {
185         struct inode *inode = dentry->d_inode;
186         mode_t mode = inode->i_mode;
187         int error;
188         struct timespec now = CURRENT_TIME;
189         unsigned int ia_valid = attr->ia_valid;
190
191         if (!inode)
192                 BUG();
193
194         attr->ia_ctime = now;
195         if (!(ia_valid & ATTR_ATIME_SET))
196                 attr->ia_atime = now;
197         if (!(ia_valid & ATTR_MTIME_SET))
198                 attr->ia_mtime = now;
199         if (ia_valid & ATTR_KILL_SUID) {
200                 attr->ia_valid &= ~ATTR_KILL_SUID;
201                 if (mode & S_ISUID) {
202                         if (!(ia_valid & ATTR_MODE)) {
203                                 ia_valid = attr->ia_valid |= ATTR_MODE;
204                                 attr->ia_mode = inode->i_mode;
205                         }
206                         attr->ia_mode &= ~S_ISUID;
207                 }
208         }
209         if (ia_valid & ATTR_KILL_SGID) {
210                 attr->ia_valid &= ~ ATTR_KILL_SGID;
211                 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
212                         if (!(ia_valid & ATTR_MODE)) {
213                                 ia_valid = attr->ia_valid |= ATTR_MODE;
214                                 attr->ia_mode = inode->i_mode;
215                         }
216                         attr->ia_mode &= ~S_ISGID;
217                 }
218         }
219         if (!attr->ia_valid)
220                 return 0;
221
222         if (inode->i_op && inode->i_op->setattr) {
223                 error = security_inode_setattr(dentry, attr);
224                 if (!error)
225                         error = inode->i_op->setattr(dentry, attr);
226         } else {
227                 error = inode_change_ok(inode, attr);
228                 if (!error)
229                         error = security_inode_setattr(dentry, attr);
230                 if (!error) {
231                         if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
232                             (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid) ||
233                             (ia_valid & ATTR_XID && attr->ia_xid != inode->i_xid))
234                                 error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
235                         if (!error)
236                                 error = inode_setattr(inode, attr);
237                 }
238         }
239         if (!error) {
240                 unsigned long dn_mask = setattr_mask(ia_valid);
241                 if (dn_mask)
242                         dnotify_parent(dentry, dn_mask);
243         }
244         return error;
245 }
246
247 EXPORT_SYMBOL(notify_change);