Skip to content

Commit 66b0686

Browse files
androsadamsontrondmypd
authored andcommitted
NFSv4: test SECINFO RPC_AUTH_GSS pseudoflavors for support
Fix nfs4_negotiate_security to create an rpc_clnt used to test each SECINFO returned pseudoflavor. Check credential creation (and gss_context creation) which is important for RPC_AUTH_GSS pseudoflavors which can fail for multiple reasons including mis-configuration. Don't call nfs4_negotiate in nfs4_submount as it was just called by nfs4_proc_lookup_mountpoint (nfs4_proc_lookup_common) Signed-off-by: Andy Adamson <[email protected]> [Trond: fix corrupt return value from nfs_find_best_sec()] Signed-off-by: Trond Myklebust <[email protected]>
1 parent 8445cd3 commit 66b0686

File tree

4 files changed

+58
-45
lines changed

4 files changed

+58
-45
lines changed

fs/nfs/nfs4_fs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ int nfs_atomic_open(struct inode *, struct dentry *, struct file *,
230230
extern struct file_system_type nfs4_fs_type;
231231

232232
/* nfs4namespace.c */
233-
struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *);
233+
struct rpc_clnt *nfs4_negotiate_security(struct rpc_clnt *, struct inode *, struct qstr *);
234234
struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *,
235235
struct nfs_fh *, struct nfs_fattr *);
236236
int nfs4_replace_transport(struct nfs_server *server,

fs/nfs/nfs4namespace.c

Lines changed: 55 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -139,17 +139,22 @@ static size_t nfs_parse_server_name(char *string, size_t len,
139139
* @server: NFS server struct
140140
* @flavors: List of security tuples returned by SECINFO procedure
141141
*
142-
* Return the pseudoflavor of the first security mechanism in
143-
* "flavors" that is locally supported. The "flavors" array
142+
* Return an rpc client that uses the first security mechanism in
143+
* "flavors" that is locally supported. The "flavors" array
144144
* 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.
146147
*
147148
* 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+
*
148152
*/
149-
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,
150155
struct nfs4_secinfo_flavors *flavors)
151156
{
152-
rpc_authflavor_t pseudoflavor;
157+
rpc_authflavor_t pflavor;
153158
struct nfs4_secinfo4 *secinfo;
154159
unsigned int i;
155160

@@ -160,58 +165,73 @@ static rpc_authflavor_t nfs_find_best_sec(struct nfs_server *server,
160165
case RPC_AUTH_NULL:
161166
case RPC_AUTH_UNIX:
162167
case RPC_AUTH_GSS:
163-
pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor,
168+
pflavor = rpcauth_get_pseudoflavor(secinfo->flavor,
164169
&secinfo->flavor_info);
165-
/* make sure pseudoflavor matches sec= mount opt */
166-
if (pseudoflavor != RPC_AUTH_MAXFLAVOR &&
167-
nfs_auth_info_match(&server->auth_info,
168-
pseudoflavor))
169-
return pseudoflavor;
170-
break;
170+
/* does the pseudoflavor match a sec= mount opt? */
171+
if (pflavor != RPC_AUTH_MAXFLAVOR &&
172+
nfs_auth_info_match(&server->auth_info, pflavor)) {
173+
struct rpc_clnt *new;
174+
struct rpc_cred *cred;
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+
}
171193
}
172194
}
173-
174-
return -EPERM;
195+
return ERR_PTR(-EPERM);
175196
}
176197

177-
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)
178212
{
179213
struct page *page;
180214
struct nfs4_secinfo_flavors *flavors;
181-
rpc_authflavor_t flavor;
215+
struct rpc_clnt *new;
182216
int err;
183217

184218
page = alloc_page(GFP_KERNEL);
185219
if (!page)
186-
return -ENOMEM;
220+
return ERR_PTR(-ENOMEM);
221+
187222
flavors = page_address(page);
188223

189224
err = nfs4_proc_secinfo(inode, name, flavors);
190225
if (err < 0) {
191-
flavor = err;
226+
new = ERR_PTR(err);
192227
goto out;
193228
}
194229

195-
flavor = nfs_find_best_sec(NFS_SERVER(inode), flavors);
230+
new = nfs_find_best_sec(clnt, NFS_SERVER(inode), flavors);
196231

197232
out:
198233
put_page(page);
199-
return flavor;
200-
}
201-
202-
/*
203-
* Please call rpc_shutdown_client() when you are done with this client.
204-
*/
205-
struct 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);
234+
return new;
215235
}
216236

217237
static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
@@ -394,14 +414,6 @@ struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry,
394414

395415
if (client->cl_auth->au_flavor != flavor)
396416
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-
}
405417
mnt = nfs_do_submount(dentry, fh, fattr, flavor);
406418
out:
407419
rpc_shutdown_client(client);

fs/nfs/nfs4proc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3247,7 +3247,7 @@ static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
32473247
err = -EPERM;
32483248
if (client != *clnt)
32493249
goto out;
3250-
client = nfs4_create_sec_client(client, dir, name);
3250+
client = nfs4_negotiate_security(client, dir, name);
32513251
if (IS_ERR(client))
32523252
return PTR_ERR(client);
32533253

net/sunrpc/auth.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,7 @@ rpcauth_lookupcred(struct rpc_auth *auth, int flags)
592592
put_group_info(acred.group_info);
593593
return ret;
594594
}
595+
EXPORT_SYMBOL_GPL(rpcauth_lookupcred);
595596

596597
void
597598
rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred,

0 commit comments

Comments
 (0)