aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4namespace.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/nfs4namespace.c')
-rw-r--r--fs/nfs/nfs4namespace.c98
1 files changed, 55 insertions, 43 deletions
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index fd4dcb67cd15..3d83cb1fdc70 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -139,17 +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. The "flavors" array 143 * "flavors" that is locally supported. The "flavors" array
144 * 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
145 * recommendation. 145 * recommendation and each flavor is checked for membership in the
146 * sec= mount option list if it exists.
146 * 147 *
147 * Return -EPERM if no matching flavor is found in the array. 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 *
148 */ 152 */
149static rpc_authflavor_t nfs_find_best_sec(struct nfs_server *server, 153static struct rpc_clnt *nfs_find_best_sec(struct rpc_clnt *clnt,
154 struct nfs_server *server,
150 struct nfs4_secinfo_flavors *flavors) 155 struct nfs4_secinfo_flavors *flavors)
151{ 156{
152 rpc_authflavor_t pseudoflavor; 157 rpc_authflavor_t pflavor;
153 struct nfs4_secinfo4 *secinfo; 158 struct nfs4_secinfo4 *secinfo;
154 unsigned int i; 159 unsigned int i;
155 160
@@ -160,58 +165,73 @@ static rpc_authflavor_t nfs_find_best_sec(struct nfs_server *server,
160 case RPC_AUTH_NULL: 165 case RPC_AUTH_NULL:
161 case RPC_AUTH_UNIX: 166 case RPC_AUTH_UNIX:
162 case RPC_AUTH_GSS: 167 case RPC_AUTH_GSS:
163 pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor, 168 pflavor = rpcauth_get_pseudoflavor(secinfo->flavor,
164 &secinfo->flavor_info); 169 &secinfo->flavor_info);
165 /* make sure pseudoflavor matches sec= mount opt */ 170 /* does the pseudoflavor match a sec= mount opt? */
166 if (pseudoflavor != RPC_AUTH_MAXFLAVOR && 171 if (pflavor != RPC_AUTH_MAXFLAVOR &&
167 nfs_auth_info_match(&server->auth_info, 172 nfs_auth_info_match(&server->auth_info, pflavor)) {
168 pseudoflavor)) 173 struct rpc_clnt *new;
169 return pseudoflavor; 174 struct rpc_cred *cred;
170 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 }
171 } 193 }
172 } 194 }
173 195 return ERR_PTR(-EPERM);
174 return -EPERM;
175} 196}
176 197
177static 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 */
209struct rpc_clnt *
210nfs4_negotiate_security(struct rpc_clnt *clnt, struct inode *inode,
211 struct qstr *name)
178{ 212{
179 struct page *page; 213 struct page *page;
180 struct nfs4_secinfo_flavors *flavors; 214 struct nfs4_secinfo_flavors *flavors;
181 rpc_authflavor_t flavor; 215 struct rpc_clnt *new;
182 int err; 216 int err;
183 217
184 page = alloc_page(GFP_KERNEL); 218 page = alloc_page(GFP_KERNEL);
185 if (!page) 219 if (!page)
186 return -ENOMEM; 220 return ERR_PTR(-ENOMEM);
221
187 flavors = page_address(page); 222 flavors = page_address(page);
188 223
189 err = nfs4_proc_secinfo(inode, name, flavors); 224 err = nfs4_proc_secinfo(inode, name, flavors);
190 if (err < 0) { 225 if (err < 0) {
191 flavor = err; 226 new = ERR_PTR(err);
192 goto out; 227 goto out;
193 } 228 }
194 229
195 flavor = nfs_find_best_sec(NFS_SERVER(inode), flavors); 230 new = nfs_find_best_sec(clnt, NFS_SERVER(inode), flavors);
196 231
197out: 232out:
198 put_page(page); 233 put_page(page);
199 return flavor; 234 return new;
200}
201
202/*
203 * Please call rpc_shutdown_client() when you are done with this client.
204 */
205struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *clnt, struct inode *inode,
206 struct qstr *name)
207{
208 rpc_authflavor_t flavor;
209
210 flavor = nfs4_negotiate_security(inode, name);
211 if ((int)flavor < 0)
212 return ERR_PTR((int)flavor);
213
214 return rpc_clone_client_set_auth(clnt, flavor);
215} 235}
216 236
217static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, 237static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
@@ -394,14 +414,6 @@ struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry,
394 414
395 if (client->cl_auth->au_flavor != flavor) 415 if (client->cl_auth->au_flavor != flavor)
396 flavor = client->cl_auth->au_flavor; 416 flavor = client->cl_auth->au_flavor;
397 else {
398 rpc_authflavor_t new = nfs4_negotiate_security(dir, name);
399 if ((int)new < 0) {
400 mnt = ERR_PTR((int)new);
401 goto out;
402 }
403 flavor = new;
404 }
405 mnt = nfs_do_submount(dentry, fh, fattr, flavor); 417 mnt = nfs_do_submount(dentry, fh, fattr, flavor);
406out: 418out:
407 rpc_shutdown_client(client); 419 rpc_shutdown_client(client);