diff options
Diffstat (limited to 'fs/nfs/nfs4namespace.c')
-rw-r--r-- | fs/nfs/nfs4namespace.c | 102 |
1 files changed, 57 insertions, 45 deletions
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 3d5dbf80d46a..3d83cb1fdc70 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -139,16 +139,22 @@ static size_t nfs_parse_server_name(char *string, size_t len, | |||
139 | * @server: NFS server struct | 139 | * @server: NFS server struct |
140 | * @flavors: List of security tuples returned by SECINFO procedure | 140 | * @flavors: List of security tuples returned by SECINFO procedure |
141 | * | 141 | * |
142 | * Return the pseudoflavor of the first security mechanism in | 142 | * Return an rpc client that uses the first security mechanism in |
143 | * "flavors" that is locally supported. Return RPC_AUTH_UNIX if | 143 | * "flavors" that is locally supported. The "flavors" array |
144 | * no matching flavor is found in the array. The "flavors" array | ||
145 | * is searched in the order returned from the server, per RFC 3530 | 144 | * is searched in the order returned from the server, per RFC 3530 |
146 | * recommendation. | 145 | * recommendation and each flavor is checked for membership in the |
146 | * sec= mount option list if it exists. | ||
147 | * | ||
148 | * Return -EPERM if no matching flavor is found in the array. | ||
149 | * | ||
150 | * Please call rpc_shutdown_client() when you are done with this rpc client. | ||
151 | * | ||
147 | */ | 152 | */ |
148 | static rpc_authflavor_t nfs_find_best_sec(struct nfs_server *server, | 153 | static struct rpc_clnt *nfs_find_best_sec(struct rpc_clnt *clnt, |
154 | struct nfs_server *server, | ||
149 | struct nfs4_secinfo_flavors *flavors) | 155 | struct nfs4_secinfo_flavors *flavors) |
150 | { | 156 | { |
151 | rpc_authflavor_t pseudoflavor; | 157 | rpc_authflavor_t pflavor; |
152 | struct nfs4_secinfo4 *secinfo; | 158 | struct nfs4_secinfo4 *secinfo; |
153 | unsigned int i; | 159 | unsigned int i; |
154 | 160 | ||
@@ -159,62 +165,73 @@ static rpc_authflavor_t nfs_find_best_sec(struct nfs_server *server, | |||
159 | case RPC_AUTH_NULL: | 165 | case RPC_AUTH_NULL: |
160 | case RPC_AUTH_UNIX: | 166 | case RPC_AUTH_UNIX: |
161 | case RPC_AUTH_GSS: | 167 | case RPC_AUTH_GSS: |
162 | pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor, | 168 | pflavor = rpcauth_get_pseudoflavor(secinfo->flavor, |
163 | &secinfo->flavor_info); | 169 | &secinfo->flavor_info); |
164 | /* make sure pseudoflavor matches sec= mount opt */ | 170 | /* does the pseudoflavor match a sec= mount opt? */ |
165 | if (pseudoflavor != RPC_AUTH_MAXFLAVOR && | 171 | if (pflavor != RPC_AUTH_MAXFLAVOR && |
166 | nfs_auth_info_match(&server->auth_info, | 172 | nfs_auth_info_match(&server->auth_info, pflavor)) { |
167 | pseudoflavor)) | 173 | struct rpc_clnt *new; |
168 | return pseudoflavor; | 174 | struct rpc_cred *cred; |
169 | break; | 175 | |
176 | /* Cloning creates an rpc_auth for the flavor */ | ||
177 | new = rpc_clone_client_set_auth(clnt, pflavor); | ||
178 | if (IS_ERR(new)) | ||
179 | continue; | ||
180 | /** | ||
181 | * Check that the user actually can use the | ||
182 | * flavor. This is mostly for RPC_AUTH_GSS | ||
183 | * where cr_init obtains a gss context | ||
184 | */ | ||
185 | cred = rpcauth_lookupcred(new->cl_auth, 0); | ||
186 | if (IS_ERR(cred)) { | ||
187 | rpc_shutdown_client(new); | ||
188 | continue; | ||
189 | } | ||
190 | put_rpccred(cred); | ||
191 | return new; | ||
192 | } | ||
170 | } | 193 | } |
171 | } | 194 | } |
172 | 195 | return ERR_PTR(-EPERM); | |
173 | /* if there were any sec= options then nothing matched */ | ||
174 | if (server->auth_info.flavor_len > 0) | ||
175 | return -EPERM; | ||
176 | |||
177 | return RPC_AUTH_UNIX; | ||
178 | } | 196 | } |
179 | 197 | ||
180 | static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name) | 198 | /** |
199 | * nfs4_negotiate_security - in response to an NFS4ERR_WRONGSEC on lookup, | ||
200 | * return an rpc_clnt that uses the best available security flavor with | ||
201 | * respect to the secinfo flavor list and the sec= mount options. | ||
202 | * | ||
203 | * @clnt: RPC client to clone | ||
204 | * @inode: directory inode | ||
205 | * @name: lookup name | ||
206 | * | ||
207 | * Please call rpc_shutdown_client() when you are done with this rpc client. | ||
208 | */ | ||
209 | struct rpc_clnt * | ||
210 | nfs4_negotiate_security(struct rpc_clnt *clnt, struct inode *inode, | ||
211 | struct qstr *name) | ||
181 | { | 212 | { |
182 | struct page *page; | 213 | struct page *page; |
183 | struct nfs4_secinfo_flavors *flavors; | 214 | struct nfs4_secinfo_flavors *flavors; |
184 | rpc_authflavor_t flavor; | 215 | struct rpc_clnt *new; |
185 | int err; | 216 | int err; |
186 | 217 | ||
187 | page = alloc_page(GFP_KERNEL); | 218 | page = alloc_page(GFP_KERNEL); |
188 | if (!page) | 219 | if (!page) |
189 | return -ENOMEM; | 220 | return ERR_PTR(-ENOMEM); |
221 | |||
190 | flavors = page_address(page); | 222 | flavors = page_address(page); |
191 | 223 | ||
192 | err = nfs4_proc_secinfo(inode, name, flavors); | 224 | err = nfs4_proc_secinfo(inode, name, flavors); |
193 | if (err < 0) { | 225 | if (err < 0) { |
194 | flavor = err; | 226 | new = ERR_PTR(err); |
195 | goto out; | 227 | goto out; |
196 | } | 228 | } |
197 | 229 | ||
198 | flavor = nfs_find_best_sec(NFS_SERVER(inode), flavors); | 230 | new = nfs_find_best_sec(clnt, NFS_SERVER(inode), flavors); |
199 | 231 | ||
200 | out: | 232 | out: |
201 | put_page(page); | 233 | put_page(page); |
202 | return flavor; | 234 | return new; |
203 | } | ||
204 | |||
205 | /* | ||
206 | * Please call rpc_shutdown_client() when you are done with this client. | ||
207 | */ | ||
208 | struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *clnt, struct inode *inode, | ||
209 | struct qstr *name) | ||
210 | { | ||
211 | rpc_authflavor_t flavor; | ||
212 | |||
213 | flavor = nfs4_negotiate_security(inode, name); | ||
214 | if ((int)flavor < 0) | ||
215 | return ERR_PTR((int)flavor); | ||
216 | |||
217 | return rpc_clone_client_set_auth(clnt, flavor); | ||
218 | } | 235 | } |
219 | 236 | ||
220 | static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | 237 | static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, |
@@ -397,11 +414,6 @@ struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry, | |||
397 | 414 | ||
398 | if (client->cl_auth->au_flavor != flavor) | 415 | if (client->cl_auth->au_flavor != flavor) |
399 | flavor = client->cl_auth->au_flavor; | 416 | flavor = client->cl_auth->au_flavor; |
400 | else { | ||
401 | rpc_authflavor_t new = nfs4_negotiate_security(dir, name); | ||
402 | if ((int)new >= 0) | ||
403 | flavor = new; | ||
404 | } | ||
405 | mnt = nfs_do_submount(dentry, fh, fattr, flavor); | 417 | mnt = nfs_do_submount(dentry, fh, fattr, flavor); |
406 | out: | 418 | out: |
407 | rpc_shutdown_client(client); | 419 | rpc_shutdown_client(client); |