1 /* 2 * linux/fs/nfsd/nfs3acl.c 3 * 4 * Process version 3 NFSACL requests. 5 * 6 * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de> 7 */ 8 9 #include <linux/sunrpc/svc.h> 10 #include <linux/nfs3.h> 11 #include <linux/nfsd/nfsd.h> 12 #include <linux/nfsd/cache.h> 13 #include <linux/nfsd/xdr3.h> 14 #include <linux/posix_acl.h> 15 #include <linux/nfsacl.h> 16 17 #define RETURN_STATUS(st) { resp->status = (st); return (st); } 18 19 /* 20 * NULL call. 21 */ 22 static __be32 23 nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) 24 { 25 return nfs_ok; 26 } 27 28 /* 29 * Get the Access and/or Default ACL of a file. 30 */ 31 static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, 32 struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) 33 { 34 svc_fh *fh; 35 struct posix_acl *acl; 36 __be32 nfserr = 0; 37 38 fh = fh_copy(&resp->fh, &argp->fh); 39 if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP))) 40 RETURN_STATUS(nfserr_inval); 41 42 if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) 43 RETURN_STATUS(nfserr_inval); 44 resp->mask = argp->mask; 45 46 if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { 47 acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); 48 if (IS_ERR(acl)) { 49 int err = PTR_ERR(acl); 50 51 if (err == -ENODATA || err == -EOPNOTSUPP) 52 acl = NULL; 53 else { 54 nfserr = nfserrno(err); 55 goto fail; 56 } 57 } 58 if (acl == NULL) { 59 /* Solaris returns the inode's minimum ACL. */ 60 61 struct inode *inode = fh->fh_dentry->d_inode; 62 acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); 63 } 64 resp->acl_access = acl; 65 } 66 if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { 67 /* Check how Solaris handles requests for the Default ACL 68 of a non-directory! */ 69 70 acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); 71 if (IS_ERR(acl)) { 72 int err = PTR_ERR(acl); 73 74 if (err == -ENODATA || err == -EOPNOTSUPP) 75 acl = NULL; 76 else { 77 nfserr = nfserrno(err); 78 goto fail; 79 } 80 } 81 resp->acl_default = acl; 82 } 83 84 /* resp->acl_{access,default} are released in nfs3svc_release_getacl. */ 85 RETURN_STATUS(0); 86 87 fail: 88 posix_acl_release(resp->acl_access); 89 posix_acl_release(resp->acl_default); 90 RETURN_STATUS(nfserr); 91 } 92 93 /* 94 * Set the Access and/or Default ACL of a file. 95 */ 96 static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp, 97 struct nfsd3_setaclargs *argp, 98 struct nfsd3_attrstat *resp) 99 { 100 svc_fh *fh; 101 __be32 nfserr = 0; 102 103 fh = fh_copy(&resp->fh, &argp->fh); 104 nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_SATTR); 105 106 if (!nfserr) { 107 nfserr = nfserrno( nfsd_set_posix_acl( 108 fh, ACL_TYPE_ACCESS, argp->acl_access) ); 109 } 110 if (!nfserr) { 111 nfserr = nfserrno( nfsd_set_posix_acl( 112 fh, ACL_TYPE_DEFAULT, argp->acl_default) ); 113 } 114 115 /* argp->acl_{access,default} may have been allocated in 116 nfs3svc_decode_setaclargs. */ 117 posix_acl_release(argp->acl_access); 118 posix_acl_release(argp->acl_default); 119 RETURN_STATUS(nfserr); 120 } 121 122 /* 123 * XDR decode functions 124 */ 125 static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p, 126 struct nfsd3_getaclargs *args) 127 { 128 if (!(p = nfs3svc_decode_fh(p, &args->fh))) 129 return 0; 130 args->mask = ntohl(*p); p++; 131 132 return xdr_argsize_check(rqstp, p); 133 } 134 135 136 static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p, 137 struct nfsd3_setaclargs *args) 138 { 139 struct kvec *head = rqstp->rq_arg.head; 140 unsigned int base; 141 int n; 142 143 if (!(p = nfs3svc_decode_fh(p, &args->fh))) 144 return 0; 145 args->mask = ntohl(*p++); 146 if (args->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) || 147 !xdr_argsize_check(rqstp, p)) 148 return 0; 149 150 base = (char *)p - (char *)head->iov_base; 151 n = nfsacl_decode(&rqstp->rq_arg, base, NULL, 152 (args->mask & NFS_ACL) ? 153 &args->acl_access : NULL); 154 if (n > 0) 155 n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL, 156 (args->mask & NFS_DFACL) ? 157 &args->acl_default : NULL); 158 return (n > 0); 159 } 160 161 /* 162 * XDR encode functions 163 */ 164 165 /* GETACL */ 166 static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, 167 struct nfsd3_getaclres *resp) 168 { 169 struct dentry *dentry = resp->fh.fh_dentry; 170 171 p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); 172 if (resp->status == 0 && dentry && dentry->d_inode) { 173 struct inode *inode = dentry->d_inode; 174 struct kvec *head = rqstp->rq_res.head; 175 unsigned int base; 176 int n; 177 int w; 178 179 *p++ = htonl(resp->mask); 180 if (!xdr_ressize_check(rqstp, p)) 181 return 0; 182 base = (char *)p - (char *)head->iov_base; 183 184 rqstp->rq_res.page_len = w = nfsacl_size( 185 (resp->mask & NFS_ACL) ? resp->acl_access : NULL, 186 (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); 187 while (w > 0) { 188 if (!rqstp->rq_respages[rqstp->rq_resused++]) 189 return 0; 190 w -= PAGE_SIZE; 191 } 192 193 n = nfsacl_encode(&rqstp->rq_res, base, inode, 194 resp->acl_access, 195 resp->mask & NFS_ACL, 0); 196 if (n > 0) 197 n = nfsacl_encode(&rqstp->rq_res, base + n, inode, 198 resp->acl_default, 199 resp->mask & NFS_DFACL, 200 NFS_ACL_DEFAULT); 201 if (n <= 0) 202 return 0; 203 } else 204 if (!xdr_ressize_check(rqstp, p)) 205 return 0; 206 207 return 1; 208 } 209 210 /* SETACL */ 211 static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p, 212 struct nfsd3_attrstat *resp) 213 { 214 p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); 215 216 return xdr_ressize_check(rqstp, p); 217 } 218 219 /* 220 * XDR release functions 221 */ 222 static int nfs3svc_release_getacl(struct svc_rqst *rqstp, __be32 *p, 223 struct nfsd3_getaclres *resp) 224 { 225 fh_put(&resp->fh); 226 posix_acl_release(resp->acl_access); 227 posix_acl_release(resp->acl_default); 228 return 1; 229 } 230 231 #define nfs3svc_decode_voidargs NULL 232 #define nfs3svc_release_void NULL 233 #define nfsd3_setaclres nfsd3_attrstat 234 #define nfsd3_voidres nfsd3_voidargs 235 struct nfsd3_voidargs { int dummy; }; 236 237 #define PROC(name, argt, rest, relt, cache, respsize) \ 238 { (svc_procfunc) nfsd3_proc_##name, \ 239 (kxdrproc_t) nfs3svc_decode_##argt##args, \ 240 (kxdrproc_t) nfs3svc_encode_##rest##res, \ 241 (kxdrproc_t) nfs3svc_release_##relt, \ 242 sizeof(struct nfsd3_##argt##args), \ 243 sizeof(struct nfsd3_##rest##res), \ 244 0, \ 245 cache, \ 246 respsize, \ 247 } 248 249 #define ST 1 /* status*/ 250 #define AT 21 /* attributes */ 251 #define pAT (1+AT) /* post attributes - conditional */ 252 #define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */ 253 254 static struct svc_procedure nfsd_acl_procedures3[] = { 255 PROC(null, void, void, void, RC_NOCACHE, ST), 256 PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)), 257 PROC(setacl, setacl, setacl, fhandle, RC_NOCACHE, ST+pAT), 258 }; 259 260 struct svc_version nfsd_acl_version3 = { 261 .vs_vers = 3, 262 .vs_nproc = 3, 263 .vs_proc = nfsd_acl_procedures3, 264 .vs_dispatch = nfsd_dispatch, 265 .vs_xdrsize = NFS3_SVC_XDRSIZE, 266 .vs_hidden = 1, 267 }; 268 269