1 | #include <machine/rtems-bsd-user-space.h> |
---|
2 | |
---|
3 | /* $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $ */ |
---|
4 | |
---|
5 | /*- |
---|
6 | * Copyright (c) 2009, Sun Microsystems, Inc. |
---|
7 | * All rights reserved. |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions are met: |
---|
11 | * - Redistributions of source code must retain the above copyright notice, |
---|
12 | * this list of conditions and the following disclaimer. |
---|
13 | * - Redistributions in binary form must reproduce the above copyright notice, |
---|
14 | * this list of conditions and the following disclaimer in the documentation |
---|
15 | * and/or other materials provided with the distribution. |
---|
16 | * - Neither the name of Sun Microsystems, Inc. nor the names of its |
---|
17 | * contributors may be used to endorse or promote products derived |
---|
18 | * from this software without specific prior written permission. |
---|
19 | * |
---|
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
---|
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
---|
24 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
---|
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
---|
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
---|
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
---|
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
---|
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
---|
30 | * POSSIBILITY OF SUCH DAMAGE. |
---|
31 | */ |
---|
32 | /* |
---|
33 | * Copyright (c) 1986-1991 by Sun Microsystems Inc. |
---|
34 | */ |
---|
35 | |
---|
36 | /* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */ |
---|
37 | #include <sys/cdefs.h> |
---|
38 | __FBSDID("$FreeBSD$"); |
---|
39 | |
---|
40 | /* |
---|
41 | * rpc_generic.c, Miscl routines for RPC. |
---|
42 | * |
---|
43 | */ |
---|
44 | |
---|
45 | #include "namespace.h" |
---|
46 | #include "reentrant.h" |
---|
47 | #include <sys/types.h> |
---|
48 | #include <rtems/bsd/sys/param.h> |
---|
49 | #include <sys/socket.h> |
---|
50 | #include <sys/time.h> |
---|
51 | #include <sys/un.h> |
---|
52 | #include <rtems/bsd/sys/resource.h> |
---|
53 | #include <netinet/in.h> |
---|
54 | #include <arpa/inet.h> |
---|
55 | #include <rpc/rpc.h> |
---|
56 | #include <ctype.h> |
---|
57 | #include <stddef.h> |
---|
58 | #include <stdio.h> |
---|
59 | #include <netdb.h> |
---|
60 | #include <netconfig.h> |
---|
61 | #include <stdlib.h> |
---|
62 | #include <string.h> |
---|
63 | #include <syslog.h> |
---|
64 | #include <rpc/nettype.h> |
---|
65 | #include "un-namespace.h" |
---|
66 | #include "rpc_com.h" |
---|
67 | #include "mt_misc.h" |
---|
68 | |
---|
69 | struct handle { |
---|
70 | NCONF_HANDLE *nhandle; |
---|
71 | int nflag; /* Whether NETPATH or NETCONFIG */ |
---|
72 | int nettype; |
---|
73 | }; |
---|
74 | |
---|
75 | static const struct _rpcnettype { |
---|
76 | const char *name; |
---|
77 | const int type; |
---|
78 | } _rpctypelist[] = { |
---|
79 | { "netpath", _RPC_NETPATH }, |
---|
80 | { "visible", _RPC_VISIBLE }, |
---|
81 | { "circuit_v", _RPC_CIRCUIT_V }, |
---|
82 | { "datagram_v", _RPC_DATAGRAM_V }, |
---|
83 | { "circuit_n", _RPC_CIRCUIT_N }, |
---|
84 | { "datagram_n", _RPC_DATAGRAM_N }, |
---|
85 | { "tcp", _RPC_TCP }, |
---|
86 | { "udp", _RPC_UDP }, |
---|
87 | { 0, _RPC_NONE } |
---|
88 | }; |
---|
89 | |
---|
90 | struct netid_af { |
---|
91 | const char *netid; |
---|
92 | int af; |
---|
93 | int protocol; |
---|
94 | }; |
---|
95 | |
---|
96 | static const struct netid_af na_cvt[] = { |
---|
97 | { "udp", AF_INET, IPPROTO_UDP }, |
---|
98 | { "tcp", AF_INET, IPPROTO_TCP }, |
---|
99 | #ifdef INET6 |
---|
100 | { "udp6", AF_INET6, IPPROTO_UDP }, |
---|
101 | { "tcp6", AF_INET6, IPPROTO_TCP }, |
---|
102 | #endif |
---|
103 | { "local", AF_LOCAL, 0 } |
---|
104 | }; |
---|
105 | |
---|
106 | #if 0 |
---|
107 | static char *strlocase(char *); |
---|
108 | #endif |
---|
109 | static int getnettype(const char *); |
---|
110 | |
---|
111 | /* |
---|
112 | * Cache the result of getrlimit(), so we don't have to do an |
---|
113 | * expensive call every time. |
---|
114 | */ |
---|
115 | int |
---|
116 | __rpc_dtbsize() |
---|
117 | { |
---|
118 | static int tbsize; |
---|
119 | struct rlimit rl; |
---|
120 | |
---|
121 | if (tbsize) { |
---|
122 | return (tbsize); |
---|
123 | } |
---|
124 | if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { |
---|
125 | return (tbsize = (int)rl.rlim_max); |
---|
126 | } |
---|
127 | /* |
---|
128 | * Something wrong. I'll try to save face by returning a |
---|
129 | * pessimistic number. |
---|
130 | */ |
---|
131 | return (32); |
---|
132 | } |
---|
133 | |
---|
134 | |
---|
135 | /* |
---|
136 | * Find the appropriate buffer size |
---|
137 | */ |
---|
138 | u_int |
---|
139 | /*ARGSUSED*/ |
---|
140 | __rpc_get_t_size(af, proto, size) |
---|
141 | int af, proto; |
---|
142 | int size; /* Size requested */ |
---|
143 | { |
---|
144 | int maxsize, defsize; |
---|
145 | |
---|
146 | maxsize = 256 * 1024; /* XXX */ |
---|
147 | switch (proto) { |
---|
148 | case IPPROTO_TCP: |
---|
149 | defsize = 64 * 1024; /* XXX */ |
---|
150 | break; |
---|
151 | case IPPROTO_UDP: |
---|
152 | defsize = UDPMSGSIZE; |
---|
153 | break; |
---|
154 | default: |
---|
155 | defsize = RPC_MAXDATASIZE; |
---|
156 | break; |
---|
157 | } |
---|
158 | if (size == 0) |
---|
159 | return defsize; |
---|
160 | |
---|
161 | /* Check whether the value is within the upper max limit */ |
---|
162 | return (size > maxsize ? (u_int)maxsize : (u_int)size); |
---|
163 | } |
---|
164 | |
---|
165 | /* |
---|
166 | * Find the appropriate address buffer size |
---|
167 | */ |
---|
168 | u_int |
---|
169 | __rpc_get_a_size(af) |
---|
170 | int af; |
---|
171 | { |
---|
172 | switch (af) { |
---|
173 | case AF_INET: |
---|
174 | return sizeof (struct sockaddr_in); |
---|
175 | #ifdef INET6 |
---|
176 | case AF_INET6: |
---|
177 | return sizeof (struct sockaddr_in6); |
---|
178 | #endif |
---|
179 | case AF_LOCAL: |
---|
180 | return sizeof (struct sockaddr_un); |
---|
181 | default: |
---|
182 | break; |
---|
183 | } |
---|
184 | return ((u_int)RPC_MAXADDRSIZE); |
---|
185 | } |
---|
186 | |
---|
187 | #if 0 |
---|
188 | static char * |
---|
189 | strlocase(p) |
---|
190 | char *p; |
---|
191 | { |
---|
192 | char *t = p; |
---|
193 | |
---|
194 | for (; *p; p++) |
---|
195 | if (isupper(*p)) |
---|
196 | *p = tolower(*p); |
---|
197 | return (t); |
---|
198 | } |
---|
199 | #endif |
---|
200 | |
---|
201 | /* |
---|
202 | * Returns the type of the network as defined in <rpc/nettype.h> |
---|
203 | * If nettype is NULL, it defaults to NETPATH. |
---|
204 | */ |
---|
205 | static int |
---|
206 | getnettype(nettype) |
---|
207 | const char *nettype; |
---|
208 | { |
---|
209 | int i; |
---|
210 | |
---|
211 | if ((nettype == NULL) || (nettype[0] == 0)) { |
---|
212 | return (_RPC_NETPATH); /* Default */ |
---|
213 | } |
---|
214 | |
---|
215 | #if 0 |
---|
216 | nettype = strlocase(nettype); |
---|
217 | #endif |
---|
218 | for (i = 0; _rpctypelist[i].name; i++) |
---|
219 | if (strcasecmp(nettype, _rpctypelist[i].name) == 0) { |
---|
220 | return (_rpctypelist[i].type); |
---|
221 | } |
---|
222 | return (_rpctypelist[i].type); |
---|
223 | } |
---|
224 | |
---|
225 | static thread_key_t tcp_key, udp_key; |
---|
226 | static once_t keys_once = ONCE_INITIALIZER; |
---|
227 | static int tcp_key_error, udp_key_error; |
---|
228 | |
---|
229 | static void |
---|
230 | keys_init(void) |
---|
231 | { |
---|
232 | |
---|
233 | tcp_key_error = thr_keycreate(&tcp_key, free); |
---|
234 | udp_key_error = thr_keycreate(&udp_key, free); |
---|
235 | } |
---|
236 | |
---|
237 | /* |
---|
238 | * For the given nettype (tcp or udp only), return the first structure found. |
---|
239 | * This should be freed by calling freenetconfigent() |
---|
240 | */ |
---|
241 | struct netconfig * |
---|
242 | __rpc_getconfip(nettype) |
---|
243 | const char *nettype; |
---|
244 | { |
---|
245 | char *netid; |
---|
246 | char *netid_tcp = (char *) NULL; |
---|
247 | char *netid_udp = (char *) NULL; |
---|
248 | static char *netid_tcp_main; |
---|
249 | static char *netid_udp_main; |
---|
250 | struct netconfig *dummy; |
---|
251 | int main_thread; |
---|
252 | |
---|
253 | if ((main_thread = thr_main())) { |
---|
254 | netid_udp = netid_udp_main; |
---|
255 | netid_tcp = netid_tcp_main; |
---|
256 | } else { |
---|
257 | if (thr_once(&keys_once, keys_init) != 0 || |
---|
258 | tcp_key_error != 0 || udp_key_error != 0) |
---|
259 | return (NULL); |
---|
260 | netid_tcp = (char *)thr_getspecific(tcp_key); |
---|
261 | netid_udp = (char *)thr_getspecific(udp_key); |
---|
262 | } |
---|
263 | if (!netid_udp && !netid_tcp) { |
---|
264 | struct netconfig *nconf; |
---|
265 | void *confighandle; |
---|
266 | |
---|
267 | if (!(confighandle = setnetconfig())) { |
---|
268 | syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); |
---|
269 | return (NULL); |
---|
270 | } |
---|
271 | while ((nconf = getnetconfig(confighandle)) != NULL) { |
---|
272 | if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { |
---|
273 | if (strcmp(nconf->nc_proto, NC_TCP) == 0 && |
---|
274 | netid_tcp == NULL) { |
---|
275 | netid_tcp = strdup(nconf->nc_netid); |
---|
276 | if (main_thread) |
---|
277 | netid_tcp_main = netid_tcp; |
---|
278 | else |
---|
279 | thr_setspecific(tcp_key, |
---|
280 | (void *) netid_tcp); |
---|
281 | } else |
---|
282 | if (strcmp(nconf->nc_proto, NC_UDP) == 0 && |
---|
283 | netid_udp == NULL) { |
---|
284 | netid_udp = strdup(nconf->nc_netid); |
---|
285 | if (main_thread) |
---|
286 | netid_udp_main = netid_udp; |
---|
287 | else |
---|
288 | thr_setspecific(udp_key, |
---|
289 | (void *) netid_udp); |
---|
290 | } |
---|
291 | } |
---|
292 | } |
---|
293 | endnetconfig(confighandle); |
---|
294 | } |
---|
295 | if (strcmp(nettype, "udp") == 0) |
---|
296 | netid = netid_udp; |
---|
297 | else if (strcmp(nettype, "tcp") == 0) |
---|
298 | netid = netid_tcp; |
---|
299 | else { |
---|
300 | return (NULL); |
---|
301 | } |
---|
302 | if ((netid == NULL) || (netid[0] == 0)) { |
---|
303 | return (NULL); |
---|
304 | } |
---|
305 | dummy = getnetconfigent(netid); |
---|
306 | return (dummy); |
---|
307 | } |
---|
308 | |
---|
309 | /* |
---|
310 | * Returns the type of the nettype, which should then be used with |
---|
311 | * __rpc_getconf(). |
---|
312 | */ |
---|
313 | void * |
---|
314 | __rpc_setconf(nettype) |
---|
315 | const char *nettype; |
---|
316 | { |
---|
317 | struct handle *handle; |
---|
318 | |
---|
319 | handle = (struct handle *) malloc(sizeof (struct handle)); |
---|
320 | if (handle == NULL) { |
---|
321 | return (NULL); |
---|
322 | } |
---|
323 | switch (handle->nettype = getnettype(nettype)) { |
---|
324 | case _RPC_NETPATH: |
---|
325 | case _RPC_CIRCUIT_N: |
---|
326 | case _RPC_DATAGRAM_N: |
---|
327 | if (!(handle->nhandle = setnetpath())) |
---|
328 | goto failed; |
---|
329 | handle->nflag = TRUE; |
---|
330 | break; |
---|
331 | case _RPC_VISIBLE: |
---|
332 | case _RPC_CIRCUIT_V: |
---|
333 | case _RPC_DATAGRAM_V: |
---|
334 | case _RPC_TCP: |
---|
335 | case _RPC_UDP: |
---|
336 | if (!(handle->nhandle = setnetconfig())) { |
---|
337 | syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); |
---|
338 | goto failed; |
---|
339 | } |
---|
340 | handle->nflag = FALSE; |
---|
341 | break; |
---|
342 | default: |
---|
343 | goto failed; |
---|
344 | } |
---|
345 | |
---|
346 | return (handle); |
---|
347 | |
---|
348 | failed: |
---|
349 | free(handle); |
---|
350 | return (NULL); |
---|
351 | } |
---|
352 | |
---|
353 | /* |
---|
354 | * Returns the next netconfig struct for the given "net" type. |
---|
355 | * __rpc_setconf() should have been called previously. |
---|
356 | */ |
---|
357 | struct netconfig * |
---|
358 | __rpc_getconf(vhandle) |
---|
359 | void *vhandle; |
---|
360 | { |
---|
361 | struct handle *handle; |
---|
362 | struct netconfig *nconf; |
---|
363 | |
---|
364 | handle = (struct handle *)vhandle; |
---|
365 | if (handle == NULL) { |
---|
366 | return (NULL); |
---|
367 | } |
---|
368 | for (;;) { |
---|
369 | if (handle->nflag) |
---|
370 | nconf = getnetpath(handle->nhandle); |
---|
371 | else |
---|
372 | nconf = getnetconfig(handle->nhandle); |
---|
373 | if (nconf == NULL) |
---|
374 | break; |
---|
375 | if ((nconf->nc_semantics != NC_TPI_CLTS) && |
---|
376 | (nconf->nc_semantics != NC_TPI_COTS) && |
---|
377 | (nconf->nc_semantics != NC_TPI_COTS_ORD)) |
---|
378 | continue; |
---|
379 | switch (handle->nettype) { |
---|
380 | case _RPC_VISIBLE: |
---|
381 | if (!(nconf->nc_flag & NC_VISIBLE)) |
---|
382 | continue; |
---|
383 | /* FALLTHROUGH */ |
---|
384 | case _RPC_NETPATH: /* Be happy */ |
---|
385 | break; |
---|
386 | case _RPC_CIRCUIT_V: |
---|
387 | if (!(nconf->nc_flag & NC_VISIBLE)) |
---|
388 | continue; |
---|
389 | /* FALLTHROUGH */ |
---|
390 | case _RPC_CIRCUIT_N: |
---|
391 | if ((nconf->nc_semantics != NC_TPI_COTS) && |
---|
392 | (nconf->nc_semantics != NC_TPI_COTS_ORD)) |
---|
393 | continue; |
---|
394 | break; |
---|
395 | case _RPC_DATAGRAM_V: |
---|
396 | if (!(nconf->nc_flag & NC_VISIBLE)) |
---|
397 | continue; |
---|
398 | /* FALLTHROUGH */ |
---|
399 | case _RPC_DATAGRAM_N: |
---|
400 | if (nconf->nc_semantics != NC_TPI_CLTS) |
---|
401 | continue; |
---|
402 | break; |
---|
403 | case _RPC_TCP: |
---|
404 | if (((nconf->nc_semantics != NC_TPI_COTS) && |
---|
405 | (nconf->nc_semantics != NC_TPI_COTS_ORD)) || |
---|
406 | (strcmp(nconf->nc_protofmly, NC_INET) |
---|
407 | #ifdef INET6 |
---|
408 | && strcmp(nconf->nc_protofmly, NC_INET6)) |
---|
409 | #else |
---|
410 | ) |
---|
411 | #endif |
---|
412 | || |
---|
413 | strcmp(nconf->nc_proto, NC_TCP)) |
---|
414 | continue; |
---|
415 | break; |
---|
416 | case _RPC_UDP: |
---|
417 | if ((nconf->nc_semantics != NC_TPI_CLTS) || |
---|
418 | (strcmp(nconf->nc_protofmly, NC_INET) |
---|
419 | #ifdef INET6 |
---|
420 | && strcmp(nconf->nc_protofmly, NC_INET6)) |
---|
421 | #else |
---|
422 | ) |
---|
423 | #endif |
---|
424 | || |
---|
425 | strcmp(nconf->nc_proto, NC_UDP)) |
---|
426 | continue; |
---|
427 | break; |
---|
428 | } |
---|
429 | break; |
---|
430 | } |
---|
431 | return (nconf); |
---|
432 | } |
---|
433 | |
---|
434 | void |
---|
435 | __rpc_endconf(vhandle) |
---|
436 | void * vhandle; |
---|
437 | { |
---|
438 | struct handle *handle; |
---|
439 | |
---|
440 | handle = (struct handle *) vhandle; |
---|
441 | if (handle == NULL) { |
---|
442 | return; |
---|
443 | } |
---|
444 | if (handle->nflag) { |
---|
445 | endnetpath(handle->nhandle); |
---|
446 | } else { |
---|
447 | endnetconfig(handle->nhandle); |
---|
448 | } |
---|
449 | free(handle); |
---|
450 | } |
---|
451 | |
---|
452 | /* |
---|
453 | * Used to ping the NULL procedure for clnt handle. |
---|
454 | * Returns NULL if fails, else a non-NULL pointer. |
---|
455 | */ |
---|
456 | void * |
---|
457 | rpc_nullproc(clnt) |
---|
458 | CLIENT *clnt; |
---|
459 | { |
---|
460 | struct timeval TIMEOUT = {25, 0}; |
---|
461 | |
---|
462 | if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL, |
---|
463 | (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) { |
---|
464 | return (NULL); |
---|
465 | } |
---|
466 | return ((void *) clnt); |
---|
467 | } |
---|
468 | |
---|
469 | /* |
---|
470 | * Try all possible transports until |
---|
471 | * one succeeds in finding the netconf for the given fd. |
---|
472 | */ |
---|
473 | struct netconfig * |
---|
474 | __rpcgettp(fd) |
---|
475 | int fd; |
---|
476 | { |
---|
477 | const char *netid; |
---|
478 | struct __rpc_sockinfo si; |
---|
479 | |
---|
480 | if (!__rpc_fd2sockinfo(fd, &si)) |
---|
481 | return NULL; |
---|
482 | |
---|
483 | if (!__rpc_sockinfo2netid(&si, &netid)) |
---|
484 | return NULL; |
---|
485 | |
---|
486 | /*LINTED const castaway*/ |
---|
487 | return getnetconfigent((char *)netid); |
---|
488 | } |
---|
489 | |
---|
490 | int |
---|
491 | __rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip) |
---|
492 | { |
---|
493 | socklen_t len; |
---|
494 | int type, proto; |
---|
495 | struct sockaddr_storage ss; |
---|
496 | |
---|
497 | len = sizeof ss; |
---|
498 | if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0) |
---|
499 | return 0; |
---|
500 | sip->si_alen = len; |
---|
501 | |
---|
502 | len = sizeof type; |
---|
503 | if (_getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0) |
---|
504 | return 0; |
---|
505 | |
---|
506 | /* XXX */ |
---|
507 | if (ss.ss_family != AF_LOCAL) { |
---|
508 | if (type == SOCK_STREAM) |
---|
509 | proto = IPPROTO_TCP; |
---|
510 | else if (type == SOCK_DGRAM) |
---|
511 | proto = IPPROTO_UDP; |
---|
512 | else |
---|
513 | return 0; |
---|
514 | } else |
---|
515 | proto = 0; |
---|
516 | |
---|
517 | sip->si_af = ss.ss_family; |
---|
518 | sip->si_proto = proto; |
---|
519 | sip->si_socktype = type; |
---|
520 | |
---|
521 | return 1; |
---|
522 | } |
---|
523 | |
---|
524 | /* |
---|
525 | * Linear search, but the number of entries is small. |
---|
526 | */ |
---|
527 | int |
---|
528 | __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip) |
---|
529 | { |
---|
530 | int i; |
---|
531 | |
---|
532 | for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) |
---|
533 | if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || ( |
---|
534 | strcmp(nconf->nc_netid, "unix") == 0 && |
---|
535 | strcmp(na_cvt[i].netid, "local") == 0)) { |
---|
536 | sip->si_af = na_cvt[i].af; |
---|
537 | sip->si_proto = na_cvt[i].protocol; |
---|
538 | sip->si_socktype = |
---|
539 | __rpc_seman2socktype((int)nconf->nc_semantics); |
---|
540 | if (sip->si_socktype == -1) |
---|
541 | return 0; |
---|
542 | sip->si_alen = __rpc_get_a_size(sip->si_af); |
---|
543 | return 1; |
---|
544 | } |
---|
545 | |
---|
546 | return 0; |
---|
547 | } |
---|
548 | |
---|
549 | int |
---|
550 | __rpc_nconf2fd(const struct netconfig *nconf) |
---|
551 | { |
---|
552 | struct __rpc_sockinfo si; |
---|
553 | |
---|
554 | if (!__rpc_nconf2sockinfo(nconf, &si)) |
---|
555 | return 0; |
---|
556 | |
---|
557 | return _socket(si.si_af, si.si_socktype, si.si_proto); |
---|
558 | } |
---|
559 | |
---|
560 | int |
---|
561 | __rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid) |
---|
562 | { |
---|
563 | int i; |
---|
564 | struct netconfig *nconf; |
---|
565 | |
---|
566 | nconf = getnetconfigent("local"); |
---|
567 | |
---|
568 | for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) { |
---|
569 | if (na_cvt[i].af == sip->si_af && |
---|
570 | na_cvt[i].protocol == sip->si_proto) { |
---|
571 | if (strcmp(na_cvt[i].netid, "local") == 0 && nconf == NULL) { |
---|
572 | if (netid) |
---|
573 | *netid = "unix"; |
---|
574 | } else { |
---|
575 | if (netid) |
---|
576 | *netid = na_cvt[i].netid; |
---|
577 | } |
---|
578 | if (nconf != NULL) |
---|
579 | freenetconfigent(nconf); |
---|
580 | return 1; |
---|
581 | } |
---|
582 | } |
---|
583 | if (nconf != NULL) |
---|
584 | freenetconfigent(nconf); |
---|
585 | |
---|
586 | return 0; |
---|
587 | } |
---|
588 | |
---|
589 | char * |
---|
590 | taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf) |
---|
591 | { |
---|
592 | struct __rpc_sockinfo si; |
---|
593 | |
---|
594 | if (!__rpc_nconf2sockinfo(nconf, &si)) |
---|
595 | return NULL; |
---|
596 | return __rpc_taddr2uaddr_af(si.si_af, nbuf); |
---|
597 | } |
---|
598 | |
---|
599 | struct netbuf * |
---|
600 | uaddr2taddr(const struct netconfig *nconf, const char *uaddr) |
---|
601 | { |
---|
602 | struct __rpc_sockinfo si; |
---|
603 | |
---|
604 | if (!__rpc_nconf2sockinfo(nconf, &si)) |
---|
605 | return NULL; |
---|
606 | return __rpc_uaddr2taddr_af(si.si_af, uaddr); |
---|
607 | } |
---|
608 | |
---|
609 | char * |
---|
610 | __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) |
---|
611 | { |
---|
612 | char *ret; |
---|
613 | struct sockaddr_in *sin; |
---|
614 | struct sockaddr_un *sun; |
---|
615 | char namebuf[INET_ADDRSTRLEN]; |
---|
616 | #ifdef INET6 |
---|
617 | struct sockaddr_in6 *sin6; |
---|
618 | char namebuf6[INET6_ADDRSTRLEN]; |
---|
619 | #endif |
---|
620 | u_int16_t port; |
---|
621 | |
---|
622 | switch (af) { |
---|
623 | case AF_INET: |
---|
624 | sin = nbuf->buf; |
---|
625 | if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf) |
---|
626 | == NULL) |
---|
627 | return NULL; |
---|
628 | port = ntohs(sin->sin_port); |
---|
629 | if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8, |
---|
630 | port & 0xff) < 0) |
---|
631 | return NULL; |
---|
632 | break; |
---|
633 | #ifdef INET6 |
---|
634 | case AF_INET6: |
---|
635 | sin6 = nbuf->buf; |
---|
636 | if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6) |
---|
637 | == NULL) |
---|
638 | return NULL; |
---|
639 | port = ntohs(sin6->sin6_port); |
---|
640 | if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8, |
---|
641 | port & 0xff) < 0) |
---|
642 | return NULL; |
---|
643 | break; |
---|
644 | #endif |
---|
645 | case AF_LOCAL: |
---|
646 | sun = nbuf->buf; |
---|
647 | if (asprintf(&ret, "%.*s", (int)(sun->sun_len - |
---|
648 | offsetof(struct sockaddr_un, sun_path)), |
---|
649 | sun->sun_path) < 0) |
---|
650 | return (NULL); |
---|
651 | break; |
---|
652 | default: |
---|
653 | return NULL; |
---|
654 | } |
---|
655 | |
---|
656 | return ret; |
---|
657 | } |
---|
658 | |
---|
659 | struct netbuf * |
---|
660 | __rpc_uaddr2taddr_af(int af, const char *uaddr) |
---|
661 | { |
---|
662 | struct netbuf *ret = NULL; |
---|
663 | char *addrstr, *p; |
---|
664 | unsigned port, portlo, porthi; |
---|
665 | struct sockaddr_in *sin; |
---|
666 | #ifdef INET6 |
---|
667 | struct sockaddr_in6 *sin6; |
---|
668 | #endif |
---|
669 | struct sockaddr_un *sun; |
---|
670 | |
---|
671 | port = 0; |
---|
672 | sin = NULL; |
---|
673 | addrstr = strdup(uaddr); |
---|
674 | if (addrstr == NULL) |
---|
675 | return NULL; |
---|
676 | |
---|
677 | /* |
---|
678 | * AF_LOCAL addresses are expected to be absolute |
---|
679 | * pathnames, anything else will be AF_INET or AF_INET6. |
---|
680 | */ |
---|
681 | if (*addrstr != '/') { |
---|
682 | p = strrchr(addrstr, '.'); |
---|
683 | if (p == NULL) |
---|
684 | goto out; |
---|
685 | portlo = (unsigned)atoi(p + 1); |
---|
686 | *p = '\0'; |
---|
687 | |
---|
688 | p = strrchr(addrstr, '.'); |
---|
689 | if (p == NULL) |
---|
690 | goto out; |
---|
691 | porthi = (unsigned)atoi(p + 1); |
---|
692 | *p = '\0'; |
---|
693 | port = (porthi << 8) | portlo; |
---|
694 | } |
---|
695 | |
---|
696 | ret = (struct netbuf *)malloc(sizeof *ret); |
---|
697 | if (ret == NULL) |
---|
698 | goto out; |
---|
699 | |
---|
700 | switch (af) { |
---|
701 | case AF_INET: |
---|
702 | sin = (struct sockaddr_in *)malloc(sizeof *sin); |
---|
703 | if (sin == NULL) |
---|
704 | goto out; |
---|
705 | memset(sin, 0, sizeof *sin); |
---|
706 | sin->sin_family = AF_INET; |
---|
707 | sin->sin_port = htons(port); |
---|
708 | if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) { |
---|
709 | free(sin); |
---|
710 | free(ret); |
---|
711 | ret = NULL; |
---|
712 | goto out; |
---|
713 | } |
---|
714 | sin->sin_len = ret->maxlen = ret->len = sizeof *sin; |
---|
715 | ret->buf = sin; |
---|
716 | break; |
---|
717 | #ifdef INET6 |
---|
718 | case AF_INET6: |
---|
719 | sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6); |
---|
720 | if (sin6 == NULL) |
---|
721 | goto out; |
---|
722 | memset(sin6, 0, sizeof *sin6); |
---|
723 | sin6->sin6_family = AF_INET6; |
---|
724 | sin6->sin6_port = htons(port); |
---|
725 | if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) { |
---|
726 | free(sin6); |
---|
727 | free(ret); |
---|
728 | ret = NULL; |
---|
729 | goto out; |
---|
730 | } |
---|
731 | sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6; |
---|
732 | ret->buf = sin6; |
---|
733 | break; |
---|
734 | #endif |
---|
735 | case AF_LOCAL: |
---|
736 | sun = (struct sockaddr_un *)malloc(sizeof *sun); |
---|
737 | if (sun == NULL) |
---|
738 | goto out; |
---|
739 | memset(sun, 0, sizeof *sun); |
---|
740 | sun->sun_family = AF_LOCAL; |
---|
741 | strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1); |
---|
742 | ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun); |
---|
743 | ret->buf = sun; |
---|
744 | break; |
---|
745 | default: |
---|
746 | break; |
---|
747 | } |
---|
748 | out: |
---|
749 | free(addrstr); |
---|
750 | return ret; |
---|
751 | } |
---|
752 | |
---|
753 | int |
---|
754 | __rpc_seman2socktype(int semantics) |
---|
755 | { |
---|
756 | switch (semantics) { |
---|
757 | case NC_TPI_CLTS: |
---|
758 | return SOCK_DGRAM; |
---|
759 | case NC_TPI_COTS_ORD: |
---|
760 | return SOCK_STREAM; |
---|
761 | case NC_TPI_RAW: |
---|
762 | return SOCK_RAW; |
---|
763 | default: |
---|
764 | break; |
---|
765 | } |
---|
766 | |
---|
767 | return -1; |
---|
768 | } |
---|
769 | |
---|
770 | int |
---|
771 | __rpc_socktype2seman(int socktype) |
---|
772 | { |
---|
773 | switch (socktype) { |
---|
774 | case SOCK_DGRAM: |
---|
775 | return NC_TPI_CLTS; |
---|
776 | case SOCK_STREAM: |
---|
777 | return NC_TPI_COTS_ORD; |
---|
778 | case SOCK_RAW: |
---|
779 | return NC_TPI_RAW; |
---|
780 | default: |
---|
781 | break; |
---|
782 | } |
---|
783 | |
---|
784 | return -1; |
---|
785 | } |
---|
786 | |
---|
787 | /* |
---|
788 | * XXXX - IPv6 scope IDs can't be handled in universal addresses. |
---|
789 | * Here, we compare the original server address to that of the RPC |
---|
790 | * service we just received back from a call to rpcbind on the remote |
---|
791 | * machine. If they are both "link local" or "site local", copy |
---|
792 | * the scope id of the server address over to the service address. |
---|
793 | */ |
---|
794 | int |
---|
795 | __rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc) |
---|
796 | { |
---|
797 | #ifdef INET6 |
---|
798 | struct sockaddr *sa_new, *sa_svc; |
---|
799 | struct sockaddr_in6 *sin6_new, *sin6_svc; |
---|
800 | |
---|
801 | sa_svc = (struct sockaddr *)svc->buf; |
---|
802 | sa_new = (struct sockaddr *)new->buf; |
---|
803 | |
---|
804 | if (sa_new->sa_family == sa_svc->sa_family && |
---|
805 | sa_new->sa_family == AF_INET6) { |
---|
806 | sin6_new = (struct sockaddr_in6 *)new->buf; |
---|
807 | sin6_svc = (struct sockaddr_in6 *)svc->buf; |
---|
808 | |
---|
809 | if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) && |
---|
810 | IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) || |
---|
811 | (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) && |
---|
812 | IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) { |
---|
813 | sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id; |
---|
814 | } |
---|
815 | } |
---|
816 | #endif |
---|
817 | return 1; |
---|
818 | } |
---|
819 | |
---|
820 | int |
---|
821 | __rpc_sockisbound(int fd) |
---|
822 | { |
---|
823 | struct sockaddr_storage ss; |
---|
824 | socklen_t slen; |
---|
825 | |
---|
826 | slen = sizeof (struct sockaddr_storage); |
---|
827 | if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) |
---|
828 | return 0; |
---|
829 | |
---|
830 | switch (ss.ss_family) { |
---|
831 | case AF_INET: |
---|
832 | return (((struct sockaddr_in *) |
---|
833 | (void *)&ss)->sin_port != 0); |
---|
834 | #ifdef INET6 |
---|
835 | case AF_INET6: |
---|
836 | return (((struct sockaddr_in6 *) |
---|
837 | (void *)&ss)->sin6_port != 0); |
---|
838 | #endif |
---|
839 | case AF_LOCAL: |
---|
840 | /* XXX check this */ |
---|
841 | return (((struct sockaddr_un *) |
---|
842 | (void *)&ss)->sun_path[0] != '\0'); |
---|
843 | default: |
---|
844 | break; |
---|
845 | } |
---|
846 | |
---|
847 | return 0; |
---|
848 | } |
---|