Blame view

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