4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
35 #include <sys/param.h>
40 #include <sys/pathconf.h>
42 #include <netconfig.h>
43 #include <sys/sockio.h>
46 #include <netinet/in.h>
47 #include <nfs/nfs_sec.h>
49 #include <sys/nsctl/rdc_prot.h>
56 /* number of transports to try */
57 #define MNT_PREF_LISTLEN 2
69 sock
= socket(AF_INET6
, SOCK_DGRAM
, 0);
73 lifn
.lifn_family
= AF_INET6
;
75 if (ioctl(sock
, SIOCGLIFNUM
, (char *)&lifn
) < 0) {
80 if (lifn
.lifn_count
== 0)
89 * The following is stolen from autod_nfs.c
92 getmyaddrs(struct ifconf
*ifc
)
107 if ((sock
= socket(family
, SOCK_DGRAM
, 0)) < 0) {
109 perror("getmyaddrs(): socket");
114 if (ioctl(sock
, SIOCGIFNUM
, (char *)&numifs
) < 0) {
116 perror("getmyaddrs(): SIOCGIFNUM");
121 buf
= (char *)malloc(numifs
* sizeof (struct ifreq
));
124 fprintf(stderr
, "getmyaddrs(): malloc failed\n");
131 ifc
->ifc_len
= numifs
* sizeof (struct ifreq
);
133 if (ioctl(sock
, SIOCGIFCONF
, (char *)ifc
) < 0) {
135 perror("getmyaddrs(): SIOCGIFCONF");
146 self_check(char *hostname
)
149 struct sockaddr_in
*s1
, *s2
;
151 struct nd_hostserv hs
;
152 struct nd_addrlist
*retaddrs
;
153 struct netconfig
*nconfp
;
157 ifc
= malloc(sizeof (struct ifconf
));
160 memset((char *)ifc
, 0, sizeof (struct ifconf
));
163 * Get the IP address for hostname
165 nconfp
= getnetconfigent("udp");
166 if (nconfp
== NULL
) {
168 fprintf(stderr
, "self_check(): getnetconfigent failed\n");
173 hs
.h_host
= hostname
;
174 hs
.h_serv
= "rpcbind";
175 if (netdir_getbyname(nconfp
, &hs
, &retaddrs
) != ND_OK
) {
176 freenetconfigent(nconfp
);
180 freenetconfigent(nconfp
);
181 /* LINTED pointer alignment */
182 s1
= (struct sockaddr_in
*)retaddrs
->n_addrs
->buf
;
185 * Now compare it against the list of
186 * addresses for the interfaces on this
190 n
= ifc
->ifc_len
/ sizeof (struct ifreq
);
192 for (; n
> 0; n
--, ifr
++) {
193 if (ifr
->ifr_addr
.sa_family
!= AF_INET
)
196 /* LINTED pointer alignment */
197 s2
= (struct sockaddr_in
*)&ifr
->ifr_addr
;
199 if (memcmp((char *)&s2
->sin_addr
,
200 (char *)&s1
->sin_addr
, sizeof (s1
->sin_addr
)) == 0) {
201 netdir_free((void *)retaddrs
, ND_ADDRLIST
);
203 goto out
; /* it's me */
206 netdir_free((void *)retaddrs
, ND_ADDRLIST
);
210 if (ifc
->ifc_buf
!= NULL
)
218 convert_nconf_to_knconf(struct netconfig
*nconf
, struct knetconfig
*knconf
)
222 if (stat(nconf
->nc_device
, &sb
) < 0) {
223 (void) syslog(LOG_ERR
, "can't find device for transport %s\n",
228 printf("lib knconf %x %s %s %x\n", nconf
->nc_semantics
,
229 nconf
->nc_protofmly
, nconf
->nc_proto
, sb
.st_rdev
);
232 knconf
->knc_semantics
= nconf
->nc_semantics
;
233 knconf
->knc_protofmly
= nconf
->nc_protofmly
;
234 knconf
->knc_proto
= nconf
->nc_proto
;
235 knconf
->knc_rdev
= sb
.st_rdev
;
241 gethost_byname(const char *name
)
245 return (getipnodebyname(name
, AF_INET6
, AI_DEFAULT
, &errnum
));
246 #else /* !AF_INET6 */
247 return (gethostbyname(name
));
248 #endif /* AF_INET6 */
252 gethost_netaddrs(char *fromhost
, char *tohost
,
253 char *fromnetaddr
, char *tonetaddr
)
255 struct hostent
*host
;
260 host
= getipnodebyname(fromhost
, AF_INET6
, AI_DEFAULT
, &errnum
);
263 (void) fprintf(stderr
, dgettext("sndr",
264 "Could not find host %s"), fromhost
);
268 for (j
= 0; j
< host
->h_length
; j
++)
269 fromnetaddr
[j
] = host
->h_addr
[j
];
271 #else /* !AF_INET6 */
272 host
= gethostbyname(fromhost
);
275 (void) fprintf(stderr
, dgettext("sndr",
276 "Could not find host %s"), fromhost
);
281 if (host
->h_length
< 4) {
283 fprintf(stderr
, "host->h_length(%d) < 4!\n", host
->h_length
);
288 for (j
= 0; j
< host
->h_length
; j
++)
289 fromnetaddr
[j
] = host
->h_addr
[j
];
290 #endif /* AF_INET6 */
293 host
= getipnodebyname(tohost
, AF_INET6
, AI_DEFAULT
, &errnum
);
296 (void) fprintf(stderr
, dgettext("sndr",
297 "Could not find host %s"), tohost
);
301 for (j
= 0; j
< host
->h_length
; j
++)
302 tonetaddr
[j
] = host
->h_addr
[j
];
304 #else /* !AF_INET6 */
305 host
= gethostbyname(tohost
);
308 (void) fprintf(stderr
, dgettext("sndr",
309 "Could not find host %s"), tohost
);
314 if (host
->h_length
< 4) {
316 fprintf(stderr
, "host->h_length(%d) < 4!\n", host
->h_length
);
321 for (j
= 0; j
< host
->h_length
; j
++)
322 tonetaddr
[j
] = host
->h_addr
[j
];
323 #endif /* AF_INET6 */
328 * Get the network address on "hostname" for program "prog"
329 * with version "vers" by using the nconf configuration data
332 * If the address of a netconfig pointer is null then
333 * information is not sufficient and no netbuf will be returned.
335 * Finally, ping the null procedure of that service.
338 static struct netbuf
*
339 get_the_addr(char *hostname
, ulong_t prog
, ulong_t vers
,
340 struct netconfig
*nconf
, ushort_t port
, struct t_info
*tinfo
,
343 struct netbuf
*nb
= NULL
;
344 struct t_bind
*tbind
= NULL
;
353 if ((fd
= t_open(nconf
->nc_device
, O_RDWR
, tinfo
)) == -1)
356 /* LINTED pointer alignment */
357 if ((tbind
= (struct t_bind
*)t_alloc(fd
, T_BIND
, T_ADDR
)) == NULL
)
360 if (portmap
) { /* contact rpcbind */
361 if (rpcb_getaddr(prog
, vers
, nconf
, &tbind
->addr
,
362 hostname
) == FALSE
) {
367 if (strcmp(nconf
->nc_protofmly
, NC_INET
) == 0)
368 /* LINTED pointer alignment */
369 ((struct sockaddr_in
*)tbind
->addr
.buf
)->sin_port
372 else if (strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0)
373 /* LINTED pointer alignment */
374 ((struct sockaddr_in6
*)tbind
->addr
.buf
)->sin6_port
379 /* Simon -- we never use the client we create?! */
380 cl
= clnt_tli_create(fd
, nconf
, &tbind
->addr
, prog
, vers
, 0, 0);
384 ah
= authsys_create_default();
391 (void) clnt_control(cl
, CLSET_TIMEOUT
, (char *)&tv
);
392 } else { /* create our own address and skip rpcbind */
397 unsigned short family
;
401 if (strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0) {
402 hp
= getipnodebyname(hostname
, AF_INET6
, 0, &errnum
);
404 nb
->len
= nb
->maxlen
= sizeof (struct sockaddr_in6
);
406 hp
= getipnodebyname(hostname
, AF_INET
, 0, &errnum
);
408 nb
->len
= nb
->maxlen
= sizeof (struct sockaddr_in
);
412 (void) fprintf(stderr
, dgettext("sndr",
413 "Could not find host %s\n"), hostname
);
417 nb
->buf
= (char *)calloc(1, nb
->maxlen
);
418 if (nb
->buf
== NULL
) {
419 (void) printf(dgettext("sndr", "no memory\n"));
423 if (family
== AF_INET
) {
424 for (j
= 0; j
< hp
->h_length
; j
++)
425 nb
->buf
[j
+4] = hp
->h_addr
[j
];
426 /* LINTED pointer alignment */
427 ((struct sockaddr_in
*)(nb
->buf
))->sin_port
= port
;
428 /* LINTED pointer alignment */
429 ((struct sockaddr_in
*)(nb
->buf
))->sin_family
= AF_INET
;
431 for (j
= 0; j
< hp
->h_length
; j
++)
432 nb
->buf
[j
+8] = hp
->h_addr
[j
];
433 /* LINTED pointer alignment */
434 ((struct sockaddr_in6
*)(nb
->buf
))->sin6_port
= port
;
435 /* LINTED pointer alignment */
436 ((struct sockaddr_in6
*)(nb
->buf
))->sin6_family
=
441 hp
= gethostbyname(hostname
);
444 (void) fprintf(stderr
, dgettext("sndr",
445 "Could not find host %s"), hostname
);
450 nb
->len
= nb
->maxlen
= sizeof (struct sockaddr_in
);
451 nb
->buf
= (char *)calloc(1, nb
->maxlen
);
452 if (nb
->buf
== NULL
) {
453 (void) printf(dgettext("sndr", "no memory\n"));
459 for (j
= 0; j
< hp
->h_length
; j
++)
460 nb
->buf
[j
+4] = hp
->h_addr
[j
];
462 if (hp
->h_addrtype
== AF_INET
) {
463 ((struct sockaddr_in
*)(nb
->buf
))->sin_port
= port
;
464 ((struct sockaddr_in
*)(nb
->buf
))->sin_family
= AF_INET
;
470 * Make a copy of the netbuf to return
472 nb
= (struct netbuf
*)calloc(1, sizeof (*nb
));
474 (void) printf(dgettext("sndr", "no memory\n"));
478 *nb
= tbind
->addr
; /* structure copy */
480 nb
->buf
= (char *)calloc(1, nb
->maxlen
);
481 if (nb
->buf
== NULL
) {
482 (void) printf(dgettext("sndr", "no memory\n"));
488 (void) memcpy(nb
->buf
, tbind
->addr
.buf
, tbind
->addr
.len
);
493 AUTH_DESTROY(cl
->cl_auth
);
502 t_free((char *)tbind
, T_BIND
);
512 * Get a network address on "hostname" for program "prog"
513 * with version "vers". If the port number is specified (non zero)
514 * then try for a TCP/UDP transport and set the port number of the
515 * resulting IP address.
517 * If the address of a netconfig pointer was passed and
518 * if it's not null, use it as the netconfig otherwise
519 * assign the address of the netconfig that was used to
520 * establish contact with the service.
521 * If portmap is false, we return a similiar address and we do not
526 get_addr(char *hostname
, ulong_t prog
, ulong_t vers
, struct netconfig
**nconfp
,
527 char *proto
, char *srvport
, struct t_info
*tinfo
, int portmap
)
529 struct netbuf
*nb
= NULL
;
530 struct netconfig
*nconf
= NULL
;
531 NCONF_HANDLE
*nc
= NULL
;
532 int nthtry
= FIRST_TRY
;
537 * First lets get the requested port
540 if ((svp
= getservbyname(srvport
, proto
)) == NULL
)
544 * No nconf passed in.
546 * Try to get a nconf from /etc/netconfig filtered by
547 * the NETPATH environment variable.
548 * First search for COTS, second for CLTS unless proto
549 * is specified. When we retry, we reset the
550 * netconfig list so that we would search the whole list
553 if ((nc
= setnetpath()) == NULL
)
557 * If proto is specified, then only search for the match,
558 * otherwise try COTS first, if failed, try CLTS.
561 while (nconf
= getnetpath(nc
)) {
562 if (strcmp(nconf
->nc_netid
, proto
) == 0) {
564 * If the port number is specified then TCP/UDP
565 * is needed. Otherwise any cots/clts will do.
570 if ((strcmp(nconf
->nc_protofmly
, NC_INET
) == 0
573 || strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0
577 (strcmp(nconf
->nc_proto
, NC_TCP
) == 0 ||
578 strcmp(nconf
->nc_proto
, NC_UDP
) == 0))
588 if ((nb
= get_the_addr(hostname
, prog
, vers
, nconf
, port
,
589 tinfo
, portmap
)) == NULL
) {
594 while (nconf
= getnetpath(nc
)) {
595 if (nconf
->nc_flag
& NC_VISIBLE
) {
596 if (nthtry
== FIRST_TRY
) {
597 if ((nconf
->nc_semantics
== NC_TPI_COTS_ORD
) ||
598 (nconf
->nc_semantics
== NC_TPI_COTS
)) {
601 if ((strcmp(nconf
->nc_protofmly
,
605 || strcmp(nconf
->nc_protofmly
,
610 (strcmp(nconf
->nc_proto
, NC_TCP
) == 0))
617 if (++nthtry
<= MNT_PREF_LISTLEN
) {
619 if ((nc
= setnetpath()) == NULL
)
625 if ((nb
= get_the_addr(hostname
, prog
, vers
, nconf
,
626 port
, tinfo
, portmap
)) == NULL
) {
628 * Continue the same search path in the
629 * netconfig db until no more matched
630 * nconf (nconf == NULL).
635 if ((nb
->len
== 8) &&
636 (strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0)) {
638 * We have a mismatch in the netconfig retry
648 * Got nconf and nb. Now dup the netconfig structure (nconf)
649 * and return it thru nconfp.
651 *nconfp
= getnetconfigent(nconf
->nc_netid
);
652 if (*nconfp
== NULL
) {
653 syslog(LOG_ERR
, "no memory\n");
664 /* return values as for nsc_check_release() */
666 rdc_check_release(char **reqd
)
668 /* librdc.so must be built on the runtime OS release */
669 return (nsc_check_release(BUILD_REV_STR
, NULL
, reqd
));