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