1 /* 2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 3 * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. 4 * 5 * This copyrighted material is made available to anyone wishing to use, 6 * modify, copy, or redistribute it subject to the terms and conditions 7 * of the GNU General Public License version 2. 8 */ 9 10 #include <linux/sched.h> 11 #include <linux/slab.h> 12 #include <linux/spinlock.h> 13 #include <linux/completion.h> 14 #include <linux/buffer_head.h> 15 #include <linux/posix_acl.h> 16 #include <linux/posix_acl_xattr.h> 17 #include <linux/gfs2_ondisk.h> 18 19 #include "gfs2.h" 20 #include "incore.h" 21 #include "acl.h" 22 #include "eaops.h" 23 #include "eattr.h" 24 #include "glock.h" 25 #include "inode.h" 26 #include "meta_io.h" 27 #include "trans.h" 28 #include "util.h" 29 30 #define ACL_ACCESS 1 31 #define ACL_DEFAULT 0 32 33 int gfs2_acl_validate_set(struct gfs2_inode *ip, int access, 34 struct gfs2_ea_request *er, 35 int *remove, mode_t *mode) 36 { 37 struct posix_acl *acl; 38 int error; 39 40 error = gfs2_acl_validate_remove(ip, access); 41 if (error) 42 return error; 43 44 if (!er->er_data) 45 return -EINVAL; 46 47 acl = posix_acl_from_xattr(er->er_data, er->er_data_len); 48 if (IS_ERR(acl)) 49 return PTR_ERR(acl); 50 if (!acl) { 51 *remove = 1; 52 return 0; 53 } 54 55 error = posix_acl_valid(acl); 56 if (error) 57 goto out; 58 59 if (access) { 60 error = posix_acl_equiv_mode(acl, mode); 61 if (!error) 62 *remove = 1; 63 else if (error > 0) 64 error = 0; 65 } 66 67 out: 68 posix_acl_release(acl); 69 return error; 70 } 71 72 int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access) 73 { 74 if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl) 75 return -EOPNOTSUPP; 76 if (!is_owner_or_cap(&ip->i_inode)) 77 return -EPERM; 78 if (S_ISLNK(ip->i_inode.i_mode)) 79 return -EOPNOTSUPP; 80 if (!access && !S_ISDIR(ip->i_inode.i_mode)) 81 return -EACCES; 82 83 return 0; 84 } 85 86 static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl, 87 struct gfs2_ea_location *el, char **data, unsigned int *len) 88 { 89 struct gfs2_ea_request er; 90 struct gfs2_ea_location el_this; 91 int error; 92 93 if (!ip->i_eattr) 94 return 0; 95 96 memset(&er, 0, sizeof(struct gfs2_ea_request)); 97 if (access) { 98 er.er_name = GFS2_POSIX_ACL_ACCESS; 99 er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN; 100 } else { 101 er.er_name = GFS2_POSIX_ACL_DEFAULT; 102 er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN; 103 } 104 er.er_type = GFS2_EATYPE_SYS; 105 106 if (!el) 107 el = &el_this; 108 109 error = gfs2_ea_find(ip, &er, el); 110 if (error) 111 return error; 112 if (!el->el_ea) 113 return 0; 114 if (!GFS2_EA_DATA_LEN(el->el_ea)) 115 goto out; 116 117 er.er_data_len = GFS2_EA_DATA_LEN(el->el_ea); 118 er.er_data = kmalloc(er.er_data_len, GFP_NOFS); 119 error = -ENOMEM; 120 if (!er.er_data) 121 goto out; 122 123 error = gfs2_ea_get_copy(ip, el, er.er_data); 124 if (error) 125 goto out_kfree; 126 127 if (acl) { 128 *acl = posix_acl_from_xattr(er.er_data, er.er_data_len); 129 if (IS_ERR(*acl)) 130 error = PTR_ERR(*acl); 131 } 132 133 out_kfree: 134 if (error || !data) 135 kfree(er.er_data); 136 else { 137 *data = er.er_data; 138 *len = er.er_data_len; 139 } 140 out: 141 if (error || el == &el_this) 142 brelse(el->el_bh); 143 return error; 144 } 145 146 /** 147 * gfs2_check_acl - Check an ACL to see if we're allowed to do something 148 * @inode: the file we want to do something to 149 * @mask: what we want to do 150 * 151 * Returns: errno 152 */ 153 154 int gfs2_check_acl(struct inode *inode, int mask) 155 { 156 struct posix_acl *acl = NULL; 157 int error; 158 159 error = acl_get(GFS2_I(inode), ACL_ACCESS, &acl, NULL, NULL, NULL); 160 if (error) 161 return error; 162 163 if (acl) { 164 error = posix_acl_permission(inode, acl, mask); 165 posix_acl_release(acl); 166 return error; 167 } 168 169 return -EAGAIN; 170 } 171 172 static int munge_mode(struct gfs2_inode *ip, mode_t mode) 173 { 174 struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); 175 struct buffer_head *dibh; 176 int error; 177 178 error = gfs2_trans_begin(sdp, RES_DINODE, 0); 179 if (error) 180 return error; 181 182 error = gfs2_meta_inode_buffer(ip, &dibh); 183 if (!error) { 184 gfs2_assert_withdraw(sdp, 185 (ip->i_inode.i_mode & S_IFMT) == (mode & S_IFMT)); 186 ip->i_inode.i_mode = mode; 187 gfs2_trans_add_bh(ip->i_gl, dibh, 1); 188 gfs2_dinode_out(ip, dibh->b_data); 189 brelse(dibh); 190 } 191 192 gfs2_trans_end(sdp); 193 194 return 0; 195 } 196 197 int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) 198 { 199 struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); 200 struct posix_acl *acl = NULL, *clone; 201 struct gfs2_ea_request er; 202 mode_t mode = ip->i_inode.i_mode; 203 int error; 204 205 if (!sdp->sd_args.ar_posix_acl) 206 return 0; 207 if (S_ISLNK(ip->i_inode.i_mode)) 208 return 0; 209 210 memset(&er, 0, sizeof(struct gfs2_ea_request)); 211 er.er_type = GFS2_EATYPE_SYS; 212 213 error = acl_get(dip, ACL_DEFAULT, &acl, NULL, 214 &er.er_data, &er.er_data_len); 215 if (error) 216 return error; 217 if (!acl) { 218 mode &= ~current_umask(); 219 if (mode != ip->i_inode.i_mode) 220 error = munge_mode(ip, mode); 221 return error; 222 } 223 224 clone = posix_acl_clone(acl, GFP_NOFS); 225 error = -ENOMEM; 226 if (!clone) 227 goto out; 228 posix_acl_release(acl); 229 acl = clone; 230 231 if (S_ISDIR(ip->i_inode.i_mode)) { 232 er.er_name = GFS2_POSIX_ACL_DEFAULT; 233 er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN; 234 error = gfs2_system_eaops.eo_set(ip, &er); 235 if (error) 236 goto out; 237 } 238 239 error = posix_acl_create_masq(acl, &mode); 240 if (error < 0) 241 goto out; 242 if (error > 0) { 243 er.er_name = GFS2_POSIX_ACL_ACCESS; 244 er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN; 245 posix_acl_to_xattr(acl, er.er_data, er.er_data_len); 246 er.er_mode = mode; 247 er.er_flags = GFS2_ERF_MODE; 248 error = gfs2_system_eaops.eo_set(ip, &er); 249 if (error) 250 goto out; 251 } else 252 munge_mode(ip, mode); 253 254 out: 255 posix_acl_release(acl); 256 kfree(er.er_data); 257 return error; 258 } 259 260 int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) 261 { 262 struct posix_acl *acl = NULL, *clone; 263 struct gfs2_ea_location el; 264 char *data; 265 unsigned int len; 266 int error; 267 268 error = acl_get(ip, ACL_ACCESS, &acl, &el, &data, &len); 269 if (error) 270 return error; 271 if (!acl) 272 return gfs2_setattr_simple(ip, attr); 273 274 clone = posix_acl_clone(acl, GFP_NOFS); 275 error = -ENOMEM; 276 if (!clone) 277 goto out; 278 posix_acl_release(acl); 279 acl = clone; 280 281 error = posix_acl_chmod_masq(acl, attr->ia_mode); 282 if (!error) { 283 posix_acl_to_xattr(acl, data, len); 284 error = gfs2_ea_acl_chmod(ip, &el, attr, data); 285 } 286 287 out: 288 posix_acl_release(acl); 289 brelse(el.el_bh); 290 kfree(data); 291 return error; 292 } 293 294