1 // SPDX-License-Identifier: GPL-2.0
3 * linux/fs/nfs/nfs4namespace.c
5 * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
6 * - Modified by David Howells <dhowells@redhat.com>
11 #include <linux/dcache.h>
12 #include <linux/mount.h>
13 #include <linux/namei.h>
14 #include <linux/nfs_fs.h>
15 #include <linux/nfs_mount.h>
16 #include <linux/slab.h>
17 #include <linux/string.h>
18 #include <linux/sunrpc/clnt.h>
19 #include <linux/sunrpc/addr.h>
20 #include <linux/vfs.h>
21 #include <linux/inet.h>
24 #include "dns_resolve.h"
26 #define NFSDBG_FACILITY NFSDBG_VFS
29 * Convert the NFSv4 pathname components into a standard posix path.
31 * Note that the resulting string will be placed at the end of the buffer
33 static inline char *nfs4_pathname_string(const struct nfs4_pathname
*pathname
,
34 char *buffer
, ssize_t buflen
)
36 char *end
= buffer
+ buflen
;
42 n
= pathname
->ncomponents
;
44 const struct nfs4_string
*component
= &pathname
->components
[n
];
45 buflen
-= component
->len
+ 1;
48 end
-= component
->len
;
49 memcpy(end
, component
->data
, component
->len
);
54 return ERR_PTR(-ENAMETOOLONG
);
58 * return the path component of "<server>:<path>"
59 * nfspath - the "<server>:<path>" string
60 * end - one past the last char that could contain "<server>:"
61 * returns NULL on failure
63 static char *nfs_path_component(const char *nfspath
, const char *end
)
67 if (*nfspath
== '[') {
68 /* parse [] escaped IPv6 addrs */
69 p
= strchr(nfspath
, ']');
70 if (p
!= NULL
&& ++p
< end
&& *p
== ':')
73 /* otherwise split on first colon */
74 p
= strchr(nfspath
, ':');
75 if (p
!= NULL
&& p
< end
)
82 * Determine the mount path as a string
84 static char *nfs4_path(struct dentry
*dentry
, char *buffer
, ssize_t buflen
)
87 char *path
= nfs_path(&limit
, dentry
, buffer
, buflen
,
90 char *path_component
= nfs_path_component(path
, limit
);
92 return path_component
;
98 * Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we
99 * believe to be the server path to this dentry
101 static int nfs4_validate_fspath(struct dentry
*dentry
,
102 const struct nfs4_fs_locations
*locations
,
103 char *page
, char *page2
)
105 const char *path
, *fs_path
;
107 path
= nfs4_path(dentry
, page
, PAGE_SIZE
);
109 return PTR_ERR(path
);
111 fs_path
= nfs4_pathname_string(&locations
->fs_path
, page2
, PAGE_SIZE
);
113 return PTR_ERR(fs_path
);
115 if (strncmp(path
, fs_path
, strlen(fs_path
)) != 0) {
116 dprintk("%s: path %s does not begin with fsroot %s\n",
117 __func__
, path
, fs_path
);
124 static size_t nfs_parse_server_name(char *string
, size_t len
,
125 struct sockaddr
*sa
, size_t salen
, struct net
*net
)
129 ret
= rpc_pton(net
, string
, len
, sa
, salen
);
131 ret
= nfs_dns_resolve_name(net
, string
, len
, sa
, salen
);
139 * nfs_find_best_sec - Find a security mechanism supported locally
140 * @clnt: pointer to rpc_clnt
141 * @server: NFS server struct
142 * @flavors: List of security tuples returned by SECINFO procedure
144 * Return an rpc client that uses the first security mechanism in
145 * "flavors" that is locally supported. The "flavors" array
146 * is searched in the order returned from the server, per RFC 3530
147 * recommendation and each flavor is checked for membership in the
148 * sec= mount option list if it exists.
150 * Return -EPERM if no matching flavor is found in the array.
152 * Please call rpc_shutdown_client() when you are done with this rpc client.
155 static struct rpc_clnt
*nfs_find_best_sec(struct rpc_clnt
*clnt
,
156 struct nfs_server
*server
,
157 struct nfs4_secinfo_flavors
*flavors
)
159 rpc_authflavor_t pflavor
;
160 struct nfs4_secinfo4
*secinfo
;
163 for (i
= 0; i
< flavors
->num_flavors
; i
++) {
164 secinfo
= &flavors
->flavors
[i
];
166 switch (secinfo
->flavor
) {
170 pflavor
= rpcauth_get_pseudoflavor(secinfo
->flavor
,
171 &secinfo
->flavor_info
);
172 /* does the pseudoflavor match a sec= mount opt? */
173 if (pflavor
!= RPC_AUTH_MAXFLAVOR
&&
174 nfs_auth_info_match(&server
->auth_info
, pflavor
)) {
175 struct rpc_clnt
*new;
176 struct rpc_cred
*cred
;
178 /* Cloning creates an rpc_auth for the flavor */
179 new = rpc_clone_client_set_auth(clnt
, pflavor
);
183 * Check that the user actually can use the
184 * flavor. This is mostly for RPC_AUTH_GSS
185 * where cr_init obtains a gss context
187 cred
= rpcauth_lookupcred(new->cl_auth
, 0);
189 rpc_shutdown_client(new);
197 return ERR_PTR(-EPERM
);
201 * nfs4_negotiate_security - in response to an NFS4ERR_WRONGSEC on lookup,
202 * return an rpc_clnt that uses the best available security flavor with
203 * respect to the secinfo flavor list and the sec= mount options.
205 * @clnt: RPC client to clone
206 * @inode: directory inode
209 * Please call rpc_shutdown_client() when you are done with this rpc client.
212 nfs4_negotiate_security(struct rpc_clnt
*clnt
, struct inode
*inode
,
213 const struct qstr
*name
)
216 struct nfs4_secinfo_flavors
*flavors
;
217 struct rpc_clnt
*new;
220 page
= alloc_page(GFP_KERNEL
);
222 return ERR_PTR(-ENOMEM
);
224 flavors
= page_address(page
);
226 err
= nfs4_proc_secinfo(inode
, name
, flavors
);
232 new = nfs_find_best_sec(clnt
, NFS_SERVER(inode
), flavors
);
239 static struct vfsmount
*try_location(struct nfs_clone_mount
*mountdata
,
240 char *page
, char *page2
,
241 const struct nfs4_fs_location
*location
)
243 const size_t addr_bufsize
= sizeof(struct sockaddr_storage
);
244 struct net
*net
= rpc_net_ns(NFS_SB(mountdata
->sb
)->client
);
245 struct vfsmount
*mnt
= ERR_PTR(-ENOENT
);
247 unsigned int maxbuflen
;
250 mnt_path
= nfs4_pathname_string(&location
->rootpath
, page2
, PAGE_SIZE
);
251 if (IS_ERR(mnt_path
))
252 return ERR_CAST(mnt_path
);
253 mountdata
->mnt_path
= mnt_path
;
254 maxbuflen
= mnt_path
- 1 - page2
;
256 mountdata
->addr
= kmalloc(addr_bufsize
, GFP_KERNEL
);
257 if (mountdata
->addr
== NULL
)
258 return ERR_PTR(-ENOMEM
);
260 for (s
= 0; s
< location
->nservers
; s
++) {
261 const struct nfs4_string
*buf
= &location
->servers
[s
];
263 if (buf
->len
<= 0 || buf
->len
>= maxbuflen
)
266 if (memchr(buf
->data
, IPV6_SCOPE_DELIMITER
, buf
->len
))
269 mountdata
->addrlen
= nfs_parse_server_name(buf
->data
, buf
->len
,
270 mountdata
->addr
, addr_bufsize
, net
);
271 if (mountdata
->addrlen
== 0)
274 memcpy(page2
, buf
->data
, buf
->len
);
275 page2
[buf
->len
] = '\0';
276 mountdata
->hostname
= page2
;
278 snprintf(page
, PAGE_SIZE
, "%s:%s",
280 mountdata
->mnt_path
);
282 mnt
= vfs_submount(mountdata
->dentry
, &nfs4_referral_fs_type
, page
, mountdata
);
286 kfree(mountdata
->addr
);
291 * nfs_follow_referral - set up mountpoint when hitting a referral on moved error
292 * @dentry: parent directory
293 * @locations: array of NFSv4 server location information
296 static struct vfsmount
*nfs_follow_referral(struct dentry
*dentry
,
297 const struct nfs4_fs_locations
*locations
)
299 struct vfsmount
*mnt
= ERR_PTR(-ENOENT
);
300 struct nfs_clone_mount mountdata
= {
303 .authflavor
= NFS_SB(dentry
->d_sb
)->client
->cl_auth
->au_flavor
,
305 char *page
= NULL
, *page2
= NULL
;
308 if (locations
== NULL
|| locations
->nlocations
<= 0)
311 dprintk("%s: referral at %pd2\n", __func__
, dentry
);
313 page
= (char *) __get_free_page(GFP_USER
);
317 page2
= (char *) __get_free_page(GFP_USER
);
321 /* Ensure fs path is a prefix of current dentry path */
322 error
= nfs4_validate_fspath(dentry
, locations
, page
, page2
);
324 mnt
= ERR_PTR(error
);
328 for (loc
= 0; loc
< locations
->nlocations
; loc
++) {
329 const struct nfs4_fs_location
*location
= &locations
->locations
[loc
];
331 if (location
== NULL
|| location
->nservers
<= 0 ||
332 location
->rootpath
.ncomponents
== 0)
335 mnt
= try_location(&mountdata
, page
, page2
, location
);
341 free_page((unsigned long) page
);
342 free_page((unsigned long) page2
);
347 * nfs_do_refmount - handle crossing a referral on server
348 * @dentry - dentry of referral
351 static struct vfsmount
*nfs_do_refmount(struct rpc_clnt
*client
, struct dentry
*dentry
)
353 struct vfsmount
*mnt
= ERR_PTR(-ENOMEM
);
354 struct dentry
*parent
;
355 struct nfs4_fs_locations
*fs_locations
= NULL
;
359 /* BUG_ON(IS_ROOT(dentry)); */
360 page
= alloc_page(GFP_KERNEL
);
364 fs_locations
= kmalloc(sizeof(struct nfs4_fs_locations
), GFP_KERNEL
);
365 if (fs_locations
== NULL
)
369 mnt
= ERR_PTR(-ENOENT
);
371 parent
= dget_parent(dentry
);
372 dprintk("%s: getting locations for %pd2\n",
375 err
= nfs4_proc_fs_locations(client
, d_inode(parent
), &dentry
->d_name
, fs_locations
, page
);
378 fs_locations
->nlocations
<= 0 ||
379 fs_locations
->fs_path
.ncomponents
<= 0)
382 mnt
= nfs_follow_referral(dentry
, fs_locations
);
389 struct vfsmount
*nfs4_submount(struct nfs_server
*server
, struct dentry
*dentry
,
390 struct nfs_fh
*fh
, struct nfs_fattr
*fattr
)
392 rpc_authflavor_t flavor
= server
->client
->cl_auth
->au_flavor
;
393 struct dentry
*parent
= dget_parent(dentry
);
394 struct inode
*dir
= d_inode(parent
);
395 const struct qstr
*name
= &dentry
->d_name
;
396 struct rpc_clnt
*client
;
397 struct vfsmount
*mnt
;
399 /* Look it up again to get its attributes and sec flavor */
400 client
= nfs4_proc_lookup_mountpoint(dir
, name
, fh
, fattr
);
403 return ERR_CAST(client
);
405 if (fattr
->valid
& NFS_ATTR_FATTR_V4_REFERRAL
) {
406 mnt
= nfs_do_refmount(client
, dentry
);
410 if (client
->cl_auth
->au_flavor
!= flavor
)
411 flavor
= client
->cl_auth
->au_flavor
;
412 mnt
= nfs_do_submount(dentry
, fh
, fattr
, flavor
);
414 rpc_shutdown_client(client
);
419 * Try one location from the fs_locations array.
421 * Returns zero on success, or a negative errno value.
423 static int nfs4_try_replacing_one_location(struct nfs_server
*server
,
424 char *page
, char *page2
,
425 const struct nfs4_fs_location
*location
)
427 const size_t addr_bufsize
= sizeof(struct sockaddr_storage
);
428 struct net
*net
= rpc_net_ns(server
->client
);
429 struct sockaddr
*sap
;
434 sap
= kmalloc(addr_bufsize
, GFP_KERNEL
);
439 for (s
= 0; s
< location
->nservers
; s
++) {
440 const struct nfs4_string
*buf
= &location
->servers
[s
];
443 if (buf
->len
<= 0 || buf
->len
> PAGE_SIZE
)
446 if (memchr(buf
->data
, IPV6_SCOPE_DELIMITER
, buf
->len
) != NULL
)
449 salen
= nfs_parse_server_name(buf
->data
, buf
->len
,
450 sap
, addr_bufsize
, net
);
453 rpc_set_port(sap
, NFS_PORT
);
456 hostname
= kstrndup(buf
->data
, buf
->len
, GFP_KERNEL
);
457 if (hostname
== NULL
)
460 error
= nfs4_update_server(server
, hostname
, sap
, salen
, net
);
471 * nfs4_replace_transport - set up transport to destination server
473 * @server: export being migrated
474 * @locations: fs_locations array
476 * Returns zero on success, or a negative errno value.
478 * The client tries all the entries in the "locations" array, in the
479 * order returned by the server, until one works or the end of the
482 int nfs4_replace_transport(struct nfs_server
*server
,
483 const struct nfs4_fs_locations
*locations
)
485 char *page
= NULL
, *page2
= NULL
;
489 if (locations
== NULL
|| locations
->nlocations
<= 0)
493 page
= (char *) __get_free_page(GFP_USER
);
496 page2
= (char *) __get_free_page(GFP_USER
);
500 for (loc
= 0; loc
< locations
->nlocations
; loc
++) {
501 const struct nfs4_fs_location
*location
=
502 &locations
->locations
[loc
];
504 if (location
== NULL
|| location
->nservers
<= 0 ||
505 location
->rootpath
.ncomponents
== 0)
508 error
= nfs4_try_replacing_one_location(server
, page
,
515 free_page((unsigned long)page
);
516 free_page((unsigned long)page2
);