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