diff options
Diffstat (limited to 'net/sunrpc/rpcb_clnt.c')
-rw-r--r-- | net/sunrpc/rpcb_clnt.c | 151 |
1 files changed, 98 insertions, 53 deletions
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index d1740dbab991..a05493aedb68 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
@@ -16,11 +16,14 @@ | |||
16 | 16 | ||
17 | #include <linux/types.h> | 17 | #include <linux/types.h> |
18 | #include <linux/socket.h> | 18 | #include <linux/socket.h> |
19 | #include <linux/in.h> | ||
20 | #include <linux/in6.h> | ||
19 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
20 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
21 | 23 | ||
22 | #include <linux/sunrpc/clnt.h> | 24 | #include <linux/sunrpc/clnt.h> |
23 | #include <linux/sunrpc/sched.h> | 25 | #include <linux/sunrpc/sched.h> |
26 | #include <linux/sunrpc/xprtsock.h> | ||
24 | 27 | ||
25 | #ifdef RPC_DEBUG | 28 | #ifdef RPC_DEBUG |
26 | # define RPCDBG_FACILITY RPCDBG_BIND | 29 | # define RPCDBG_FACILITY RPCDBG_BIND |
@@ -91,26 +94,6 @@ enum { | |||
91 | #define RPCB_MAXADDRLEN (128u) | 94 | #define RPCB_MAXADDRLEN (128u) |
92 | 95 | ||
93 | /* | 96 | /* |
94 | * r_netid | ||
95 | * | ||
96 | * Quoting RFC 3530, section 2.2: | ||
97 | * | ||
98 | * For TCP over IPv4 the value of r_netid is the string "tcp". For UDP | ||
99 | * over IPv4 the value of r_netid is the string "udp". | ||
100 | * | ||
101 | * ... | ||
102 | * | ||
103 | * For TCP over IPv6 the value of r_netid is the string "tcp6". For UDP | ||
104 | * over IPv6 the value of r_netid is the string "udp6". | ||
105 | */ | ||
106 | #define RPCB_NETID_UDP "\165\144\160" /* "udp" */ | ||
107 | #define RPCB_NETID_TCP "\164\143\160" /* "tcp" */ | ||
108 | #define RPCB_NETID_UDP6 "\165\144\160\066" /* "udp6" */ | ||
109 | #define RPCB_NETID_TCP6 "\164\143\160\066" /* "tcp6" */ | ||
110 | |||
111 | #define RPCB_MAXNETIDLEN (4u) | ||
112 | |||
113 | /* | ||
114 | * r_owner | 97 | * r_owner |
115 | * | 98 | * |
116 | * The "owner" is allowed to unset a service in the rpcbind database. | 99 | * The "owner" is allowed to unset a service in the rpcbind database. |
@@ -120,7 +103,7 @@ enum { | |||
120 | #define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING) | 103 | #define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING) |
121 | 104 | ||
122 | static void rpcb_getport_done(struct rpc_task *, void *); | 105 | static void rpcb_getport_done(struct rpc_task *, void *); |
123 | extern struct rpc_program rpcb_program; | 106 | static struct rpc_program rpcb_program; |
124 | 107 | ||
125 | struct rpcbind_args { | 108 | struct rpcbind_args { |
126 | struct rpc_xprt * r_xprt; | 109 | struct rpc_xprt * r_xprt; |
@@ -137,10 +120,13 @@ struct rpcbind_args { | |||
137 | static struct rpc_procinfo rpcb_procedures2[]; | 120 | static struct rpc_procinfo rpcb_procedures2[]; |
138 | static struct rpc_procinfo rpcb_procedures3[]; | 121 | static struct rpc_procinfo rpcb_procedures3[]; |
139 | 122 | ||
140 | static struct rpcb_info { | 123 | struct rpcb_info { |
141 | int rpc_vers; | 124 | int rpc_vers; |
142 | struct rpc_procinfo * rpc_proc; | 125 | struct rpc_procinfo * rpc_proc; |
143 | } rpcb_next_version[]; | 126 | }; |
127 | |||
128 | static struct rpcb_info rpcb_next_version[]; | ||
129 | static struct rpcb_info rpcb_next_version6[]; | ||
144 | 130 | ||
145 | static void rpcb_getport_prepare(struct rpc_task *task, void *calldata) | 131 | static void rpcb_getport_prepare(struct rpc_task *task, void *calldata) |
146 | { | 132 | { |
@@ -190,7 +176,17 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, | |||
190 | RPC_CLNT_CREATE_INTR), | 176 | RPC_CLNT_CREATE_INTR), |
191 | }; | 177 | }; |
192 | 178 | ||
193 | ((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT); | 179 | switch (srvaddr->sa_family) { |
180 | case AF_INET: | ||
181 | ((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT); | ||
182 | break; | ||
183 | case AF_INET6: | ||
184 | ((struct sockaddr_in6 *)srvaddr)->sin6_port = htons(RPCBIND_PORT); | ||
185 | break; | ||
186 | default: | ||
187 | return NULL; | ||
188 | } | ||
189 | |||
194 | if (!privileged) | 190 | if (!privileged) |
195 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; | 191 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; |
196 | return rpc_create(&args); | 192 | return rpc_create(&args); |
@@ -234,7 +230,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | |||
234 | prog, vers, prot, port); | 230 | prog, vers, prot, port); |
235 | 231 | ||
236 | rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin, | 232 | rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin, |
237 | IPPROTO_UDP, 2, 1); | 233 | XPRT_TRANSPORT_UDP, 2, 1); |
238 | if (IS_ERR(rpcb_clnt)) | 234 | if (IS_ERR(rpcb_clnt)) |
239 | return PTR_ERR(rpcb_clnt); | 235 | return PTR_ERR(rpcb_clnt); |
240 | 236 | ||
@@ -316,6 +312,7 @@ void rpcb_getport_async(struct rpc_task *task) | |||
316 | struct rpc_task *child; | 312 | struct rpc_task *child; |
317 | struct sockaddr addr; | 313 | struct sockaddr addr; |
318 | int status; | 314 | int status; |
315 | struct rpcb_info *info; | ||
319 | 316 | ||
320 | dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", | 317 | dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", |
321 | task->tk_pid, __FUNCTION__, | 318 | task->tk_pid, __FUNCTION__, |
@@ -325,7 +322,7 @@ void rpcb_getport_async(struct rpc_task *task) | |||
325 | BUG_ON(clnt->cl_parent != clnt); | 322 | BUG_ON(clnt->cl_parent != clnt); |
326 | 323 | ||
327 | if (xprt_test_and_set_binding(xprt)) { | 324 | if (xprt_test_and_set_binding(xprt)) { |
328 | status = -EACCES; /* tell caller to check again */ | 325 | status = -EAGAIN; /* tell caller to check again */ |
329 | dprintk("RPC: %5u %s: waiting for another binder\n", | 326 | dprintk("RPC: %5u %s: waiting for another binder\n", |
330 | task->tk_pid, __FUNCTION__); | 327 | task->tk_pid, __FUNCTION__); |
331 | goto bailout_nowake; | 328 | goto bailout_nowake; |
@@ -343,18 +340,43 @@ void rpcb_getport_async(struct rpc_task *task) | |||
343 | goto bailout_nofree; | 340 | goto bailout_nofree; |
344 | } | 341 | } |
345 | 342 | ||
346 | if (rpcb_next_version[xprt->bind_index].rpc_proc == NULL) { | 343 | rpc_peeraddr(clnt, (void *)&addr, sizeof(addr)); |
344 | |||
345 | /* Don't ever use rpcbind v2 for AF_INET6 requests */ | ||
346 | switch (addr.sa_family) { | ||
347 | case AF_INET: | ||
348 | info = rpcb_next_version; | ||
349 | break; | ||
350 | case AF_INET6: | ||
351 | info = rpcb_next_version6; | ||
352 | break; | ||
353 | default: | ||
354 | status = -EAFNOSUPPORT; | ||
355 | dprintk("RPC: %5u %s: bad address family\n", | ||
356 | task->tk_pid, __FUNCTION__); | ||
357 | goto bailout_nofree; | ||
358 | } | ||
359 | if (info[xprt->bind_index].rpc_proc == NULL) { | ||
347 | xprt->bind_index = 0; | 360 | xprt->bind_index = 0; |
348 | status = -EACCES; /* tell caller to try again later */ | 361 | status = -EPFNOSUPPORT; |
349 | dprintk("RPC: %5u %s: no more getport versions available\n", | 362 | dprintk("RPC: %5u %s: no more getport versions available\n", |
350 | task->tk_pid, __FUNCTION__); | 363 | task->tk_pid, __FUNCTION__); |
351 | goto bailout_nofree; | 364 | goto bailout_nofree; |
352 | } | 365 | } |
353 | bind_version = rpcb_next_version[xprt->bind_index].rpc_vers; | 366 | bind_version = info[xprt->bind_index].rpc_vers; |
354 | 367 | ||
355 | dprintk("RPC: %5u %s: trying rpcbind version %u\n", | 368 | dprintk("RPC: %5u %s: trying rpcbind version %u\n", |
356 | task->tk_pid, __FUNCTION__, bind_version); | 369 | task->tk_pid, __FUNCTION__, bind_version); |
357 | 370 | ||
371 | rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot, | ||
372 | bind_version, 0); | ||
373 | if (IS_ERR(rpcb_clnt)) { | ||
374 | status = PTR_ERR(rpcb_clnt); | ||
375 | dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n", | ||
376 | task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt)); | ||
377 | goto bailout_nofree; | ||
378 | } | ||
379 | |||
358 | map = kzalloc(sizeof(struct rpcbind_args), GFP_ATOMIC); | 380 | map = kzalloc(sizeof(struct rpcbind_args), GFP_ATOMIC); |
359 | if (!map) { | 381 | if (!map) { |
360 | status = -ENOMEM; | 382 | status = -ENOMEM; |
@@ -367,28 +389,19 @@ void rpcb_getport_async(struct rpc_task *task) | |||
367 | map->r_prot = xprt->prot; | 389 | map->r_prot = xprt->prot; |
368 | map->r_port = 0; | 390 | map->r_port = 0; |
369 | map->r_xprt = xprt_get(xprt); | 391 | map->r_xprt = xprt_get(xprt); |
370 | map->r_netid = (xprt->prot == IPPROTO_TCP) ? RPCB_NETID_TCP : | 392 | map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); |
371 | RPCB_NETID_UDP; | 393 | memcpy(map->r_addr, |
372 | memcpy(&map->r_addr, rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR), | 394 | rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR), |
373 | sizeof(map->r_addr)); | 395 | sizeof(map->r_addr)); |
374 | map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */ | 396 | map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */ |
375 | 397 | ||
376 | rpc_peeraddr(clnt, (void *)&addr, sizeof(addr)); | ||
377 | rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot, bind_version, 0); | ||
378 | if (IS_ERR(rpcb_clnt)) { | ||
379 | status = PTR_ERR(rpcb_clnt); | ||
380 | dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n", | ||
381 | task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt)); | ||
382 | goto bailout; | ||
383 | } | ||
384 | |||
385 | child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map); | 398 | child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map); |
386 | rpc_release_client(rpcb_clnt); | 399 | rpc_release_client(rpcb_clnt); |
387 | if (IS_ERR(child)) { | 400 | if (IS_ERR(child)) { |
388 | status = -EIO; | 401 | status = -EIO; |
389 | dprintk("RPC: %5u %s: rpc_run_task failed\n", | 402 | dprintk("RPC: %5u %s: rpc_run_task failed\n", |
390 | task->tk_pid, __FUNCTION__); | 403 | task->tk_pid, __FUNCTION__); |
391 | goto bailout_nofree; | 404 | goto bailout; |
392 | } | 405 | } |
393 | rpc_put_task(child); | 406 | rpc_put_task(child); |
394 | 407 | ||
@@ -403,6 +416,7 @@ bailout_nofree: | |||
403 | bailout_nowake: | 416 | bailout_nowake: |
404 | task->tk_status = status; | 417 | task->tk_status = status; |
405 | } | 418 | } |
419 | EXPORT_SYMBOL_GPL(rpcb_getport_async); | ||
406 | 420 | ||
407 | /* | 421 | /* |
408 | * Rpcbind child task calls this callback via tk_exit. | 422 | * Rpcbind child task calls this callback via tk_exit. |
@@ -413,6 +427,10 @@ static void rpcb_getport_done(struct rpc_task *child, void *data) | |||
413 | struct rpc_xprt *xprt = map->r_xprt; | 427 | struct rpc_xprt *xprt = map->r_xprt; |
414 | int status = child->tk_status; | 428 | int status = child->tk_status; |
415 | 429 | ||
430 | /* Garbage reply: retry with a lesser rpcbind version */ | ||
431 | if (status == -EIO) | ||
432 | status = -EPROTONOSUPPORT; | ||
433 | |||
416 | /* rpcbind server doesn't support this rpcbind protocol version */ | 434 | /* rpcbind server doesn't support this rpcbind protocol version */ |
417 | if (status == -EPROTONOSUPPORT) | 435 | if (status == -EPROTONOSUPPORT) |
418 | xprt->bind_index++; | 436 | xprt->bind_index++; |
@@ -490,16 +508,24 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p, | |||
490 | unsigned short *portp) | 508 | unsigned short *portp) |
491 | { | 509 | { |
492 | char *addr; | 510 | char *addr; |
493 | int addr_len, c, i, f, first, val; | 511 | u32 addr_len; |
512 | int c, i, f, first, val; | ||
494 | 513 | ||
495 | *portp = 0; | 514 | *portp = 0; |
496 | addr_len = (unsigned int) ntohl(*p++); | 515 | addr_len = ntohl(*p++); |
497 | if (addr_len > RPCB_MAXADDRLEN) /* sanity */ | 516 | |
498 | return -EINVAL; | 517 | /* |
499 | 518 | * Simple sanity check. The smallest possible universal | |
500 | dprintk("RPC: rpcb_decode_getaddr returned string: '%s'\n", | 519 | * address is an IPv4 address string containing 11 bytes. |
501 | (char *) p); | 520 | */ |
502 | 521 | if (addr_len < 11 || addr_len > RPCB_MAXADDRLEN) | |
522 | goto out_err; | ||
523 | |||
524 | /* | ||
525 | * Start at the end and walk backwards until the first dot | ||
526 | * is encountered. When the second dot is found, we have | ||
527 | * both parts of the port number. | ||
528 | */ | ||
503 | addr = (char *)p; | 529 | addr = (char *)p; |
504 | val = 0; | 530 | val = 0; |
505 | first = 1; | 531 | first = 1; |
@@ -521,8 +547,19 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p, | |||
521 | } | 547 | } |
522 | } | 548 | } |
523 | 549 | ||
550 | /* | ||
551 | * Simple sanity check. If we never saw a dot in the reply, | ||
552 | * then this was probably just garbage. | ||
553 | */ | ||
554 | if (first) | ||
555 | goto out_err; | ||
556 | |||
524 | dprintk("RPC: rpcb_decode_getaddr port=%u\n", *portp); | 557 | dprintk("RPC: rpcb_decode_getaddr port=%u\n", *portp); |
525 | return 0; | 558 | return 0; |
559 | |||
560 | out_err: | ||
561 | dprintk("RPC: rpcbind server returned malformed reply\n"); | ||
562 | return -EIO; | ||
526 | } | 563 | } |
527 | 564 | ||
528 | #define RPCB_program_sz (1u) | 565 | #define RPCB_program_sz (1u) |
@@ -531,7 +568,7 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p, | |||
531 | #define RPCB_port_sz (1u) | 568 | #define RPCB_port_sz (1u) |
532 | #define RPCB_boolean_sz (1u) | 569 | #define RPCB_boolean_sz (1u) |
533 | 570 | ||
534 | #define RPCB_netid_sz (1+XDR_QUADLEN(RPCB_MAXNETIDLEN)) | 571 | #define RPCB_netid_sz (1+XDR_QUADLEN(RPCBIND_MAXNETIDLEN)) |
535 | #define RPCB_addr_sz (1+XDR_QUADLEN(RPCB_MAXADDRLEN)) | 572 | #define RPCB_addr_sz (1+XDR_QUADLEN(RPCB_MAXADDRLEN)) |
536 | #define RPCB_ownerstring_sz (1+XDR_QUADLEN(RPCB_MAXOWNERLEN)) | 573 | #define RPCB_ownerstring_sz (1+XDR_QUADLEN(RPCB_MAXOWNERLEN)) |
537 | 574 | ||
@@ -593,6 +630,14 @@ static struct rpcb_info rpcb_next_version[] = { | |||
593 | { 0, NULL }, | 630 | { 0, NULL }, |
594 | }; | 631 | }; |
595 | 632 | ||
633 | static struct rpcb_info rpcb_next_version6[] = { | ||
634 | #ifdef CONFIG_SUNRPC_BIND34 | ||
635 | { 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] }, | ||
636 | { 3, &rpcb_procedures3[RPCBPROC_GETADDR] }, | ||
637 | #endif | ||
638 | { 0, NULL }, | ||
639 | }; | ||
640 | |||
596 | static struct rpc_version rpcb_version2 = { | 641 | static struct rpc_version rpcb_version2 = { |
597 | .number = 2, | 642 | .number = 2, |
598 | .nrprocs = RPCB_HIGHPROC_2, | 643 | .nrprocs = RPCB_HIGHPROC_2, |
@@ -621,7 +666,7 @@ static struct rpc_version *rpcb_version[] = { | |||
621 | 666 | ||
622 | static struct rpc_stat rpcb_stats; | 667 | static struct rpc_stat rpcb_stats; |
623 | 668 | ||
624 | struct rpc_program rpcb_program = { | 669 | static struct rpc_program rpcb_program = { |
625 | .name = "rpcbind", | 670 | .name = "rpcbind", |
626 | .number = RPCBIND_PROGRAM, | 671 | .number = RPCBIND_PROGRAM, |
627 | .nrvers = ARRAY_SIZE(rpcb_version), | 672 | .nrvers = ARRAY_SIZE(rpcb_version), |