1
2
3
4
5
6
7
8
9
10
11#include <linux/module.h>
12#include <linux/dcache.h>
13#include <linux/mount.h>
14#include <linux/namei.h>
15#include <linux/nfs_fs.h>
16#include <linux/nfs_mount.h>
17#include <linux/slab.h>
18#include <linux/string.h>
19#include <linux/sunrpc/clnt.h>
20#include <linux/sunrpc/addr.h>
21#include <linux/vfs.h>
22#include <linux/inet.h>
23#include "internal.h"
24#include "nfs4_fs.h"
25#include "nfs.h"
26#include "dns_resolve.h"
27
28#define NFSDBG_FACILITY NFSDBG_VFS
29
30
31
32
33
34static ssize_t nfs4_pathname_len(const struct nfs4_pathname *pathname)
35{
36 ssize_t len = 0;
37 int i;
38
39 for (i = 0; i < pathname->ncomponents; i++) {
40 const struct nfs4_string *component = &pathname->components[i];
41
42 if (component->len > NAME_MAX)
43 goto too_long;
44 len += 1 + component->len;
45 if (len > PATH_MAX)
46 goto too_long;
47 }
48 return len;
49
50too_long:
51 return -ENAMETOOLONG;
52}
53
54
55
56
57static char *nfs4_pathname_string(const struct nfs4_pathname *pathname,
58 unsigned short *_len)
59{
60 ssize_t len;
61 char *buf, *p;
62 int i;
63
64 len = nfs4_pathname_len(pathname);
65 if (len < 0)
66 return ERR_PTR(len);
67 *_len = len;
68
69 p = buf = kmalloc(len + 1, GFP_KERNEL);
70 if (!buf)
71 return ERR_PTR(-ENOMEM);
72
73 for (i = 0; i < pathname->ncomponents; i++) {
74 const struct nfs4_string *component = &pathname->components[i];
75
76 *p++ = '/';
77 memcpy(p, component->data, component->len);
78 p += component->len;
79 }
80
81 *p = 0;
82 return buf;
83}
84
85
86
87
88
89
90
91static char *nfs_path_component(const char *nfspath, const char *end)
92{
93 char *p;
94
95 if (*nfspath == '[') {
96
97 p = strchr(nfspath, ']');
98 if (p != NULL && ++p < end && *p == ':')
99 return p + 1;
100 } else {
101
102 p = strchr(nfspath, ':');
103 if (p != NULL && p < end)
104 return p + 1;
105 }
106 return NULL;
107}
108
109
110
111
112static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen)
113{
114 char *limit;
115 char *path = nfs_path(&limit, dentry, buffer, buflen,
116 NFS_PATH_CANONICAL);
117 if (!IS_ERR(path)) {
118 char *path_component = nfs_path_component(path, limit);
119 if (path_component)
120 return path_component;
121 }
122 return path;
123}
124
125
126
127
128
129static int nfs4_validate_fspath(struct dentry *dentry,
130 const struct nfs4_fs_locations *locations,
131 struct nfs_fs_context *ctx)
132{
133 const char *path;
134 char *fs_path;
135 unsigned short len;
136 char *buf;
137 int n;
138
139 buf = kmalloc(4096, GFP_KERNEL);
140 path = nfs4_path(dentry, buf, 4096);
141 if (IS_ERR(path)) {
142 kfree(buf);
143 return PTR_ERR(path);
144 }
145
146 fs_path = nfs4_pathname_string(&locations->fs_path, &len);
147 if (IS_ERR(fs_path)) {
148 kfree(buf);
149 return PTR_ERR(fs_path);
150 }
151
152 n = strncmp(path, fs_path, len);
153 kfree(buf);
154 kfree(fs_path);
155 if (n != 0) {
156 dprintk("%s: path %s does not begin with fsroot %s\n",
157 __func__, path, ctx->nfs_server.export_path);
158 return -ENOENT;
159 }
160
161 return 0;
162}
163
164static size_t nfs_parse_server_name(char *string, size_t len,
165 struct sockaddr *sa, size_t salen, struct net *net)
166{
167 ssize_t ret;
168
169 ret = rpc_pton(net, string, len, sa, salen);
170 if (ret == 0) {
171 ret = nfs_dns_resolve_name(net, string, len, sa, salen);
172 if (ret < 0)
173 ret = 0;
174 }
175 return ret;
176}
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195static struct rpc_clnt *nfs_find_best_sec(struct rpc_clnt *clnt,
196 struct nfs_server *server,
197 struct nfs4_secinfo_flavors *flavors)
198{
199 rpc_authflavor_t pflavor;
200 struct nfs4_secinfo4 *secinfo;
201 unsigned int i;
202
203 for (i = 0; i < flavors->num_flavors; i++) {
204 secinfo = &flavors->flavors[i];
205
206 switch (secinfo->flavor) {
207 case RPC_AUTH_NULL:
208 case RPC_AUTH_UNIX:
209 case RPC_AUTH_GSS:
210 pflavor = rpcauth_get_pseudoflavor(secinfo->flavor,
211 &secinfo->flavor_info);
212
213 if (pflavor != RPC_AUTH_MAXFLAVOR &&
214 nfs_auth_info_match(&server->auth_info, pflavor)) {
215 struct rpc_clnt *new;
216 struct rpc_cred *cred;
217
218
219 new = rpc_clone_client_set_auth(clnt, pflavor);
220 if (IS_ERR(new))
221 continue;
222
223
224
225
226
227 cred = rpcauth_lookupcred(new->cl_auth, 0);
228 if (IS_ERR(cred)) {
229 rpc_shutdown_client(new);
230 continue;
231 }
232 put_rpccred(cred);
233 return new;
234 }
235 }
236 }
237 return ERR_PTR(-EPERM);
238}
239
240
241
242
243
244
245
246
247
248
249
250
251struct rpc_clnt *
252nfs4_negotiate_security(struct rpc_clnt *clnt, struct inode *inode,
253 const struct qstr *name)
254{
255 struct page *page;
256 struct nfs4_secinfo_flavors *flavors;
257 struct rpc_clnt *new;
258 int err;
259
260 page = alloc_page(GFP_KERNEL);
261 if (!page)
262 return ERR_PTR(-ENOMEM);
263
264 flavors = page_address(page);
265
266 err = nfs4_proc_secinfo(inode, name, flavors);
267 if (err < 0) {
268 new = ERR_PTR(err);
269 goto out;
270 }
271
272 new = nfs_find_best_sec(clnt, NFS_SERVER(inode), flavors);
273
274out:
275 put_page(page);
276 return new;
277}
278
279static int try_location(struct fs_context *fc,
280 const struct nfs4_fs_location *location)
281{
282 struct nfs_fs_context *ctx = nfs_fc2context(fc);
283 unsigned int len, s;
284 char *export_path, *source, *p;
285 int ret = -ENOENT;
286
287
288
289
290
291 len = 0;
292 for (s = 0; s < location->nservers; s++) {
293 const struct nfs4_string *buf = &location->servers[s];
294 if (buf->len > len)
295 len = buf->len;
296 }
297
298 kfree(ctx->nfs_server.hostname);
299 ctx->nfs_server.hostname = kmalloc(len + 1, GFP_KERNEL);
300 if (!ctx->nfs_server.hostname)
301 return -ENOMEM;
302
303 export_path = nfs4_pathname_string(&location->rootpath,
304 &ctx->nfs_server.export_path_len);
305 if (IS_ERR(export_path))
306 return PTR_ERR(export_path);
307
308 kfree(ctx->nfs_server.export_path);
309 ctx->nfs_server.export_path = export_path;
310
311 source = kmalloc(len + 1 + ctx->nfs_server.export_path_len + 1,
312 GFP_KERNEL);
313 if (!source)
314 return -ENOMEM;
315
316 kfree(fc->source);
317 fc->source = source;
318 for (s = 0; s < location->nservers; s++) {
319 const struct nfs4_string *buf = &location->servers[s];
320
321 if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len))
322 continue;
323
324 ctx->nfs_server.addrlen =
325 nfs_parse_server_name(buf->data, buf->len,
326 &ctx->nfs_server.address,
327 sizeof(ctx->nfs_server._address),
328 fc->net_ns);
329 if (ctx->nfs_server.addrlen == 0)
330 continue;
331
332 rpc_set_port(&ctx->nfs_server.address, NFS_PORT);
333
334 memcpy(ctx->nfs_server.hostname, buf->data, buf->len);
335 ctx->nfs_server.hostname[buf->len] = '\0';
336
337 p = source;
338 memcpy(p, buf->data, buf->len);
339 p += buf->len;
340 *p++ = ':';
341 memcpy(p, ctx->nfs_server.export_path, ctx->nfs_server.export_path_len);
342 p += ctx->nfs_server.export_path_len;
343 *p = 0;
344
345 ret = nfs4_get_referral_tree(fc);
346 if (ret == 0)
347 return 0;
348 }
349
350 return ret;
351}
352
353
354
355
356
357
358
359static int nfs_follow_referral(struct fs_context *fc,
360 const struct nfs4_fs_locations *locations)
361{
362 struct nfs_fs_context *ctx = nfs_fc2context(fc);
363 int loc, error;
364
365 if (locations == NULL || locations->nlocations <= 0)
366 return -ENOENT;
367
368 dprintk("%s: referral at %pd2\n", __func__, ctx->clone_data.dentry);
369
370
371 error = nfs4_validate_fspath(ctx->clone_data.dentry, locations, ctx);
372 if (error < 0)
373 return error;
374
375 error = -ENOENT;
376 for (loc = 0; loc < locations->nlocations; loc++) {
377 const struct nfs4_fs_location *location = &locations->locations[loc];
378
379 if (location == NULL || location->nservers <= 0 ||
380 location->rootpath.ncomponents == 0)
381 continue;
382
383 error = try_location(fc, location);
384 if (error == 0)
385 return 0;
386 }
387
388 return error;
389}
390
391
392
393
394
395
396static int nfs_do_refmount(struct fs_context *fc, struct rpc_clnt *client)
397{
398 struct nfs_fs_context *ctx = nfs_fc2context(fc);
399 struct dentry *dentry, *parent;
400 struct nfs4_fs_locations *fs_locations = NULL;
401 struct page *page;
402 int err = -ENOMEM;
403
404
405 page = alloc_page(GFP_KERNEL);
406 if (!page)
407 return -ENOMEM;
408
409 fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
410 if (!fs_locations)
411 goto out_free;
412
413
414 dentry = ctx->clone_data.dentry;
415 parent = dget_parent(dentry);
416 dprintk("%s: getting locations for %pd2\n",
417 __func__, dentry);
418
419 err = nfs4_proc_fs_locations(client, d_inode(parent), &dentry->d_name, fs_locations, page);
420 dput(parent);
421 if (err != 0)
422 goto out_free_2;
423
424 err = -ENOENT;
425 if (fs_locations->nlocations <= 0 ||
426 fs_locations->fs_path.ncomponents <= 0)
427 goto out_free_2;
428
429 err = nfs_follow_referral(fc, fs_locations);
430out_free_2:
431 kfree(fs_locations);
432out_free:
433 __free_page(page);
434 return err;
435}
436
437int nfs4_submount(struct fs_context *fc, struct nfs_server *server)
438{
439 struct nfs_fs_context *ctx = nfs_fc2context(fc);
440 struct dentry *dentry = ctx->clone_data.dentry;
441 struct dentry *parent = dget_parent(dentry);
442 struct inode *dir = d_inode(parent);
443 struct rpc_clnt *client;
444 int ret;
445
446
447 client = nfs4_proc_lookup_mountpoint(dir, dentry, ctx->mntfh,
448 ctx->clone_data.fattr);
449 dput(parent);
450 if (IS_ERR(client))
451 return PTR_ERR(client);
452
453 ctx->selected_flavor = client->cl_auth->au_flavor;
454 if (ctx->clone_data.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
455 ret = nfs_do_refmount(fc, client);
456 } else {
457 ret = nfs_do_submount(fc);
458 }
459
460 rpc_shutdown_client(client);
461 return ret;
462}
463
464
465
466
467
468
469static int nfs4_try_replacing_one_location(struct nfs_server *server,
470 char *page, char *page2,
471 const struct nfs4_fs_location *location)
472{
473 const size_t addr_bufsize = sizeof(struct sockaddr_storage);
474 struct net *net = rpc_net_ns(server->client);
475 struct sockaddr *sap;
476 unsigned int s;
477 size_t salen;
478 int error;
479
480 sap = kmalloc(addr_bufsize, GFP_KERNEL);
481 if (sap == NULL)
482 return -ENOMEM;
483
484 error = -ENOENT;
485 for (s = 0; s < location->nservers; s++) {
486 const struct nfs4_string *buf = &location->servers[s];
487 char *hostname;
488
489 if (buf->len <= 0 || buf->len > PAGE_SIZE)
490 continue;
491
492 if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len) != NULL)
493 continue;
494
495 salen = nfs_parse_server_name(buf->data, buf->len,
496 sap, addr_bufsize, net);
497 if (salen == 0)
498 continue;
499 rpc_set_port(sap, NFS_PORT);
500
501 error = -ENOMEM;
502 hostname = kmemdup_nul(buf->data, buf->len, GFP_KERNEL);
503 if (hostname == NULL)
504 break;
505
506 error = nfs4_update_server(server, hostname, sap, salen, net);
507 kfree(hostname);
508 if (error == 0)
509 break;
510 }
511
512 kfree(sap);
513 return error;
514}
515
516
517
518
519
520
521
522
523
524
525
526
527
528int nfs4_replace_transport(struct nfs_server *server,
529 const struct nfs4_fs_locations *locations)
530{
531 char *page = NULL, *page2 = NULL;
532 int loc, error;
533
534 error = -ENOENT;
535 if (locations == NULL || locations->nlocations <= 0)
536 goto out;
537
538 error = -ENOMEM;
539 page = (char *) __get_free_page(GFP_USER);
540 if (!page)
541 goto out;
542 page2 = (char *) __get_free_page(GFP_USER);
543 if (!page2)
544 goto out;
545
546 for (loc = 0; loc < locations->nlocations; loc++) {
547 const struct nfs4_fs_location *location =
548 &locations->locations[loc];
549
550 if (location == NULL || location->nservers <= 0 ||
551 location->rootpath.ncomponents == 0)
552 continue;
553
554 error = nfs4_try_replacing_one_location(server, page,
555 page2, location);
556 if (error == 0)
557 break;
558 }
559
560out:
561 free_page((unsigned long)page);
562 free_page((unsigned long)page2);
563 return error;
564}
565