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]
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
31 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
32 /* All Rights Reserved */
38 #include <netconfig.h>
39 #include <sys/utsname.h>
40 #include <sys/param.h>
45 * The generic name to address mappings for any transport that
46 * has strings for address (e.g., ISO Starlan).
48 * Address in ISO Starlan consist of arbitrary strings of
49 * characters. Because of this, the following routines
50 * create an "address" based on two strings, one gotten
51 * from a "host" file and one gotten from a "services" file.
52 * The two strings are catenated together (with a "." between
53 * them). The hosts file is /etc/net/starlan/hosts and
54 * contain lines of the form:
56 * arbitrary_string machname
58 * To make things simple, the "arbitrary string" should be the
61 * The services file is /etc/net/starlan/services and has lines
64 * service_name arbitrary_string
66 * Again, to make things easer, the "arbitrary name" should be the
70 #define HOSTFILE "/etc/net/%s/hosts"
71 #define SERVICEFILE "/etc/net/%s/services"
74 #define LOCALHOST "localhost"
76 static int searchhost(struct netconfig
*, char *, int, char *);
77 static int searchserv(struct netconfig
*, char *, int, char *);
80 * _netdir_getbyname() returns all of the addresses for
81 * a specified host and service.
85 _netdir_getbyname(struct netconfig
*netconfigp
,
86 struct nd_hostserv
*nd_hostservp
)
88 char fulladdr
[BUFSIZ
]; /* holds the full address string */
89 struct nd_addrlist
*retp
; /* the return structure */
90 struct netbuf
*netbufp
; /* indexes through the addresses */
93 * HOST_BROADCAST is not supported.
96 if (strcmp(nd_hostservp
->h_host
, HOST_BROADCAST
) == 0) {
101 if (searchhost(netconfigp
, nd_hostservp
->h_host
, FIELD2
,
103 _nderror
= ND_NOHOST
;
108 * Now simply fill in the address by forming strings of the
109 * form "string_from_hosts.string_from_services"
112 if (nd_hostservp
->h_serv
&&
113 (strcmp(nd_hostservp
->h_serv
, "rpcbind") == 0)) {
114 (void) strcat(fulladdr
, ".");
115 (void) strcat(fulladdr
, "rpc"); /* hard coded */
118 * Get the address from the services file
121 if (nd_hostservp
->h_serv
&& (nd_hostservp
->h_serv
[0] != '\0')) {
122 (void) strcat(fulladdr
, ".");
123 if (searchserv(netconfigp
, nd_hostservp
->h_serv
, FIELD1
,
124 fulladdr
+ strlen(fulladdr
)) == 0) {
125 _nderror
= ND_NOSERV
;
131 if ((retp
= malloc(sizeof (struct nd_addrlist
))) == NULL
) {
137 * We do not worry about multiple addresses here. Loopbacks
138 * have only one interface.
142 if ((retp
->n_addrs
= malloc(sizeof (struct netbuf
))) == NULL
) {
148 netbufp
= retp
->n_addrs
;
151 * Don't include the terminating NULL character in the
155 netbufp
->len
= netbufp
->maxlen
= (int)strlen(fulladdr
);
156 if ((netbufp
->buf
= strdup(fulladdr
)) == NULL
) {
167 * _netdir_getbyaddr() takes an address (hopefully obtained from
168 * someone doing a _netdir_getbyname()) and returns all hosts with
172 struct nd_hostservlist
*
173 _netdir_getbyaddr(struct netconfig
*netconfigp
, struct netbuf
*netbufp
)
175 char fulladdr
[BUFSIZ
]; /* a copy of the address string */
176 char servbuf
[BUFSIZ
]; /* a buffer for service string */
177 char hostbuf
[BUFSIZ
]; /* points to list of host names */
178 char *hostname
; /* the "first" path of the string */
179 char *servname
; /* the "second" part of string */
180 struct nd_hostservlist
*retp
; /* the return structure */
181 char *serv
; /* resultant service name obtained */
182 int nhost
; /* the number of hosts in hostpp */
183 struct nd_hostserv
*nd_hostservp
; /* traverses the host structures */
184 char *nexttok
; /* next token to process */
187 * Separate the two parts of the address string.
190 (void) strlcpy(fulladdr
, netbufp
->buf
, sizeof (fulladdr
));
191 hostname
= strtok_r(fulladdr
, ".", &nexttok
);
192 if (hostname
== NULL
) {
193 _nderror
= ND_NOHOST
;
196 servname
= strtok_r(NULL
, " \n\t", &nexttok
);
199 * Search for all the hosts associated with the
200 * first part of the address string.
203 nhost
= searchhost(netconfigp
, hostname
, FIELD1
, hostbuf
);
205 _nderror
= ND_NOHOST
;
210 * Search for the service associated with the second
211 * path of the address string.
214 if (servname
== NULL
) {
215 _nderror
= ND_NOSERV
;
221 if (searchserv(netconfigp
, servname
, FIELD2
, servbuf
) == 0) {
222 serv
= _taddr2uaddr(netconfigp
, netbufp
);
223 (void) strcpy(servbuf
, serv
);
231 * Allocate space to hold the return structure, set the number
232 * of hosts, and allocate space to hold them.
235 if ((retp
= malloc(sizeof (struct nd_hostservlist
))) == NULL
) {
241 retp
->h_hostservs
= calloc(nhost
, sizeof (struct nd_hostserv
));
242 if (retp
->h_hostservs
== NULL
) {
249 * Loop through the host structues and fill them in with
250 * each host name (and service name).
253 nd_hostservp
= retp
->h_hostservs
;
254 hostname
= strtok_r(hostbuf
, ",", &nexttok
);
255 while (hostname
&& nhost
--) {
256 if (((nd_hostservp
->h_host
= strdup(hostname
)) == NULL
) ||
257 ((nd_hostservp
->h_serv
= strdup(serv
)) == NULL
)) {
258 netdir_free(retp
, ND_HOSTSERVLIST
);
263 hostname
= strtok_r(NULL
, ",", &nexttok
);
271 * _taddr2uaddr() translates a address into a "universal" address.
272 * Since the address is a string, simply return the string as the
273 * universal address (but replace all non-printable characters with
274 * the \ddd form, where ddd is three octal digits). The '\n' character
275 * is also replace by \ddd and the '\' character is placed as two
281 _taddr2uaddr(struct netconfig
*netconfigp
, struct netbuf
*netbufp
)
283 char *retp
; /* pointer the return string */
284 char *to
; /* traverses and populates the return string */
285 char *from
; /* traverses the string to be converted */
286 int i
; /* indexes through the given string */
289 * BUFSIZ is perhaps too big for this one and there is a better
290 * way to optimize it, but for now we will just assume BUFSIZ
292 if ((retp
= malloc(BUFSIZ
)) == NULL
) {
299 for (i
= 0; i
< netbufp
->len
; i
++) {
304 if (*from
== '\n' || !isprint((unsigned char)*from
)) {
305 (void) sprintf(to
, "\\%.3o", *from
& 0xff);
318 * _uaddr2taddr() translates a universal address back into a
319 * netaddr structure. Since the universal address is a string,
320 * put that into the TLI buffer (making sure to change all \ddd
321 * characters back and strip off the trailing \0 character).
326 _uaddr2taddr(struct netconfig
*netconfigp
, char *uaddr
)
328 struct netbuf
*retp
; /* the return structure */
329 char *holdp
; /* holds the converted address */
330 char *to
; /* traverses and populates the new address */
331 char *from
; /* traverses the universal address */
333 holdp
= malloc(strlen(uaddr
) + 1);
343 if (*(from
+1) == '\\') {
347 *to
= ((*(from
+1) - '0') << 6) +
348 ((*(from
+2) - '0') << 3) +
359 if ((retp
= malloc(sizeof (struct netbuf
))) == NULL
) {
364 retp
->maxlen
= retp
->len
= (int)(to
- holdp
);
370 * _netdir_options() is a "catch-all" routine that does
371 * transport specific things. The only thing that these
372 * routines have to worry about is ND_MERGEADDR.
377 _netdir_options(struct netconfig
*netconfigp
, int option
, int fd
, void *par
)
379 struct nd_mergearg
*argp
; /* the argument for mergeaddr */
384 * Translate the universal address into something that
385 * makes sense to the caller. This is a no-op in
386 * loopback's case, so just return the universal address.
388 argp
= (struct nd_mergearg
*)par
;
389 argp
->m_uaddr
= strdup(argp
->s_uaddr
);
390 if (argp
->m_uaddr
== NULL
) {
396 _nderror
= ND_NOCTRL
;
402 * searchhost() looks for the specified token in the host file.
403 * The "field" parameter signifies which field to compare the token
404 * on, and returns all comma separated values associated with the token.
408 searchhost(struct netconfig
*netconfigp
, char *token
, int field
, char *hostbuf
)
410 char searchfile
[MAXPATHLEN
]; /* the name of file to be opened */
411 char buf
[BUFSIZ
]; /* holds each line of the file */
412 char *fileaddr
; /* the first token in each line */
413 char *filehost
; /* the second token in each line */
414 char *cmpstr
; /* the string to compare token to */
415 char *retstr
; /* the string to return if compare succeeds */
416 char *nexttok
; /* next token to process */
417 FILE *fp
; /* the opened searchfile */
418 int nelements
= 0; /* total number of elements found */
419 struct utsname utsname
;
422 * Unless /etc/netconfig has been altered, the only transport that
423 * will use straddr.so is loopback. In this case, we always
424 * return "localhost" if either our nodename, or "localhost", or
425 * some of special-case host names were passed, or we fail.
428 if ((strcmp(token
, HOST_SELF_BIND
) == 0) ||
429 (strcmp(token
, HOST_SELF_CONNECT
) == 0) ||
430 (strcmp(token
, HOST_ANY
) == 0) ||
431 (strcmp(token
, LOCALHOST
) == 0) ||
432 (uname(&utsname
) >= 0 && strcmp(token
, utsname
.nodename
) == 0)) {
433 (void) strcpy(hostbuf
, LOCALHOST
);
437 if (strcmp(netconfigp
->nc_protofmly
, NC_LOOPBACK
) == 0)
441 * We only get here if an administrator has modified
442 * /etc/netconfig to use straddr.so for a transport other than
443 * loopback (which is questionable but something we'll need to
444 * EOL at a later point in time). In this case, we fallback to
445 * searching for the associated key in the appropriate hosts
446 * file (based on nc_netid).
449 (void) snprintf(searchfile
, sizeof (searchfile
), HOSTFILE
,
450 netconfigp
->nc_netid
);
452 fp
= fopen(searchfile
, "rF");
457 * Loop through the file looking for the tokens and creating
458 * the list of strings to be returned.
461 while (fgets(buf
, BUFSIZ
, fp
) != NULL
) {
464 * Ignore comments and bad lines.
467 fileaddr
= strtok_r(buf
, " \t\n", &nexttok
);
468 if (fileaddr
== NULL
|| *fileaddr
== '#')
471 if ((filehost
= strtok_r(NULL
, " \t\n", &nexttok
)) == NULL
)
475 * determine which to compare the token to, then
476 * compare it, and if they match, add the return
477 * string to the list.
480 cmpstr
= (field
== FIELD1
)? fileaddr
: filehost
;
481 retstr
= (field
== FIELD1
)? filehost
: fileaddr
;
483 if (strcmp(token
, cmpstr
) == 0) {
485 if (field
== FIELD2
) {
487 * called by _netdir_getbyname
490 (void) strcpy(hostbuf
, retstr
);
495 * Assuming that "," will never be a part
498 (void) strcat(hostbuf
, ",");
500 (void) strcat(hostbuf
, retstr
);
509 * searchserv() looks for the specified token in the service file.
510 * The "field" parameter signifies which field to compare the token
511 * on, and returns the string associated with the token in servname.
515 searchserv(struct netconfig
*netconfigp
, char *token
, int field
, char *servname
)
517 char searchfile
[MAXPATHLEN
]; /* the name of file to be opened */
518 char buf
[BUFSIZ
]; /* buffer space for lines in file */
519 char *fileservice
; /* the first token in each line */
520 char *fileport
; /* the second token in each line */
521 char *cmpstr
; /* the string to compare the token to */
522 char *retstr
; /* temporarily hold token in line of file */
523 char *nexttok
; /* next token to process */
524 FILE *fp
; /* the opened searchfile */
526 (void) snprintf(searchfile
, sizeof (searchfile
), SERVICEFILE
,
527 netconfigp
->nc_netid
);
529 fp
= fopen(searchfile
, "rF");
534 * Loop through the services file looking for the token.
537 while (fgets(buf
, BUFSIZ
, fp
) != NULL
) {
539 * If comment or bad line, continue.
541 fileservice
= strtok_r(buf
, " \t\n", &nexttok
);
542 if (fileservice
== NULL
|| *fileservice
== '#')
545 if ((fileport
= strtok_r(NULL
, " \t\n", &nexttok
)) == NULL
)
548 cmpstr
= (field
== FIELD1
)? fileservice
: fileport
;
549 retstr
= (field
== FIELD1
)? fileport
: fileservice
;
551 if (strcmp(token
, cmpstr
) == 0) {
552 (void) strcpy(servname
, retstr
);