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 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
36 #include "rpc_mt.h" /* for MT declarations only */
37 #include <rpc/types.h>
42 #include <netconfig.h>
46 #include "netcspace.h"
48 #define FAILURE (unsigned)(-1)
51 * Local routines used by the library procedures
54 static int blank(char *);
55 static int comment(char *);
56 static struct netconfig
*fgetnetconfig(FILE *, char *);
57 static void netconfig_free(struct netconfig
*);
58 static unsigned int getflag(char *);
59 static char **getlookups(char *);
60 static struct netconfig
**getnetlist(void);
61 static unsigned int getnlookups(char *);
62 static char *gettoken(char *, int);
63 static unsigned int getvalue(char *, struct nc_data nc_data
[]);
64 static void shift1left(char *);
65 static void netlist_free(struct netconfig
***);
66 static void free_entry(void *);
67 static struct netconfig
*netconfig_dup(struct netconfig
*);
69 extern const char __nsl_dom
[];
72 * Static global variables used by the library procedures:
74 * netpp - points to the beginning of the list of netconfig
75 * entries used by setnetconfig() and setnetpath().
76 * Once netpp is initialized, that memory is *never*
77 * released. This was necessary to improve performance.
79 * linenum - the current line number of the /etc/netconfig
80 * file (used for debugging and for nc_perror()).
82 * fieldnum - the current field number of the current line
83 * of /etc/netconfig (used for debugging and for
86 * nc_error - the error condition encountered.
89 static struct netconfig
**netpp
= NULL
;
90 mutex_t netpp_mutex
= DEFAULTMUTEX
;
92 * The following two variables are used by the /etc/netconfig parsing
93 * routines, which will always be executed once, and within the netpp_mutex.
94 * They are global to allow the nc_sperror routine to provide better
95 * information to the user about /etc/netconfig file problems.
97 static int linenum
= 0; /* "owned" by getnetlist() */
98 static int fieldnum
= 0; /* "owned" by fgetnetconfig() */
104 static pthread_key_t nc_error_key
= PTHREAD_ONCE_KEY_NP
;
105 static int nc_error
= NC_NOERROR
;
110 ret
= thr_get_storage(&nc_error_key
, sizeof (int), free
);
111 /* if thr_get_storage fails we return the address of nc_error */
112 return (ret
? ret
: &nc_error
);
114 #define nc_error (*(__nc_error()))
117 * setnetconfig() has the effect of "initializing" the
118 * network configuration database. It reads in the
119 * netcf entries (if not already read in).
127 (void) mutex_lock(&netpp_mutex
);
128 if ((netpp
== NULL
) && ((netpp
= getnetlist()) == NULL
)) {
129 (void) mutex_unlock(&netpp_mutex
);
132 (void) mutex_unlock(&netpp_mutex
);
133 if ((retp
= malloc(sizeof (NCONF_HANDLE
))) == NULL
) {
137 nc_error
= NC_NOERROR
;
138 retp
->nc_head
= retp
->nc_curr
= netpp
;
139 return ((void *)retp
);
143 * endnetconfig() frees up all data allocated by setnetconfig()
147 endnetconfig(void *vdata
)
149 NCONF_HANDLE
*nconf_handlep
= (NCONF_HANDLE
*)vdata
;
151 (void) mutex_lock(&netpp_mutex
);
152 if (netpp
== NULL
|| nconf_handlep
== NULL
) {
154 (void) mutex_unlock(&netpp_mutex
);
157 (void) mutex_unlock(&netpp_mutex
);
159 nc_error
= NC_NOERROR
;
165 * getnetconfig() returns the current entry in the list
166 * of netconfig structures. It uses the nconf_handlep argument
167 * to determine the current entry. If setnetconfig() was not
168 * called previously to set up the list, return failure.
169 * It also check if ipv6 interface is present(ipv6_present) and
170 * skips udp6 & tcp6 entries if ipv6 is not supported.
174 getnetconfig(void *vdata
)
176 NCONF_HANDLE
*nconf_handlep
= (NCONF_HANDLE
*)vdata
;
177 struct netconfig
*retp
; /* holds the return value */
178 int ipv6_present
= -1;
180 (void) mutex_lock(&netpp_mutex
);
181 if ((netpp
== NULL
) || (nconf_handlep
== NULL
)) {
183 (void) mutex_unlock(&netpp_mutex
);
186 (void) mutex_unlock(&netpp_mutex
);
188 retp
= *(nconf_handlep
->nc_curr
);
189 if (retp
&& (strcmp(retp
->nc_netid
, "udp6") == 0 ||
190 strcmp(retp
->nc_netid
, "tcp6") == 0)) {
191 if (ipv6_present
== -1)
192 ipv6_present
= __can_use_af(AF_INET6
);
194 ++(nconf_handlep
->nc_curr
);
201 ++(nconf_handlep
->nc_curr
);
202 nc_error
= NC_NOERROR
;
204 nc_error
= NC_NOMOREENTRIES
;
210 * getnetconfig() searches the netconfig database for a
211 * given network id. Returns a pointer to the netconfig
212 * structure or a NULL if not found.
213 * It also check if ipv6 interface is present(ipv6_present) and
214 * skips udp6 & tcp6 entries if ipv6 is not supported.
218 getnetconfigent(const char *netid
)
220 struct netconfig
**tpp
;
223 (void) mutex_lock(&netpp_mutex
);
224 if ((netpp
== NULL
) && ((netpp
= getnetlist()) == NULL
)) {
225 (void) mutex_unlock(&netpp_mutex
);
228 (void) mutex_unlock(&netpp_mutex
);
229 for (tpp
= netpp
; *tpp
; tpp
++) {
230 if (strcmp((*tpp
)->nc_netid
, netid
) == 0) {
231 if (*tpp
&& (strcmp((*tpp
)->nc_netid
, "udp6") == 0 ||
232 strcmp((*tpp
)->nc_netid
, "tcp6") == 0)) {
233 ipv6_present
= __can_use_af(AF_INET6
);
235 nc_error
= NC_NOTFOUND
;
239 return (netconfig_dup(*tpp
));
242 nc_error
= NC_NOTFOUND
;
247 * freenetconfigent frees the data allocated by getnetconfigent()
251 freenetconfigent(struct netconfig
*netp
)
253 netconfig_free(netp
);
257 * getnetlist() reads the netconfig file and creates a
258 * NULL-terminated list of entries.
259 * Returns the pointer to the head of the list or a NULL
263 static struct netconfig
**
266 char line
[BUFSIZ
]; /* holds each line of NETCONFIG */
267 FILE *fp
; /* file stream for NETCONFIG */
268 struct netconfig
**listpp
; /* the beginning of the netconfig list */
269 struct netconfig
**tpp
; /* used to traverse the netconfig list */
270 int count
; /* the number of entries in file */
272 if ((fp
= fopen(NETCONFIG
, "rF")) == NULL
) {
273 nc_error
= NC_OPENFAIL
;
278 while (fgets(line
, BUFSIZ
, fp
)) {
279 if (!(blank(line
) || comment(line
))) {
286 nc_error
= NC_NOTFOUND
;
290 if ((listpp
= malloc((count
+ 1) *
291 sizeof (struct netconfig
*))) == NULL
) {
298 * The following loop fills in the list (loops until
299 * fgetnetconfig() returns a NULL) and counts the
300 * number of entries placed in the list. Note that
301 * when the loop is completed, the last entry in the
302 * list will contain a NULL (signifying the end of
306 for (tpp
= listpp
; *tpp
= fgetnetconfig(fp
, NULL
); tpp
++)
310 if (nc_error
!= NC_NOMOREENTRIES
) /* Something is screwed up */
311 netlist_free(&listpp
);
316 * fgetnetconfig() parses a line of the netconfig file into
317 * a netconfig structure. It returns a pointer to the
318 * structure of success and a NULL on failure or EOF.
321 static struct netconfig
*
322 fgetnetconfig(FILE *fp
, char *netid
)
324 char linep
[BUFSIZ
]; /* pointer to a line in the file */
325 struct netconfig
*netconfigp
; /* holds the new netconfig structure */
326 char *tok1
, *tok2
, *tok3
; /* holds a token from the line */
327 char *retvalp
; /* the return value of fgets() */
328 char *entnetid
; /* netid for the current entry */
330 /* skip past blank lines and comments. */
331 while (retvalp
= fgets(linep
, BUFSIZ
, fp
)) {
333 if (!(blank(linep
) || comment(linep
))) {
338 if (retvalp
== NULL
) {
339 nc_error
= NC_NOMOREENTRIES
;
343 if ((entnetid
= gettoken(linep
, FALSE
)) == NULL
) {
344 nc_error
= NC_BADLINE
;
347 if (netid
&& (strcmp(netid
, entnetid
) != 0)) {
349 nc_error
= NC_NOTFOUND
;
352 if ((netconfigp
= calloc(1, sizeof (struct netconfig
))) == NULL
) {
358 tok1
= tok2
= tok3
= NULL
;
359 netconfigp
->nc_netid
= entnetid
;
360 if (((tok1
= gettoken(NULL
, FALSE
)) == NULL
) ||
361 ((netconfigp
->nc_semantics
=
362 getvalue(tok1
, nc_semantics
)) == FAILURE
) ||
363 ((tok2
= gettoken(NULL
, FALSE
)) == NULL
) ||
364 ((netconfigp
->nc_flag
= getflag(tok2
)) == FAILURE
) ||
365 ((netconfigp
->nc_protofmly
= gettoken(NULL
, FALSE
)) == NULL
) ||
366 ((netconfigp
->nc_proto
= gettoken(NULL
, FALSE
)) == NULL
) ||
367 ((netconfigp
->nc_device
= gettoken(NULL
, FALSE
)) == NULL
) ||
368 ((tok3
= gettoken(NULL
, TRUE
)) == NULL
) ||
369 (((netconfigp
->nc_nlookups
= getnlookups(tok3
)) != 0) &&
370 ((netconfigp
->nc_lookups
= getlookups(tok3
)) == NULL
))) {
371 netconfig_free(netconfigp
);
372 nc_error
= NC_BADLINE
;
382 * setnetpath() has the effect of "initializing" the
383 * NETPATH variable. It reads in the netcf entries (if not
384 * already read in), creates a list corresponding to the entries
385 * in the NETPATH variable (or the "visible" entries og netconfig
386 * if NETPATH is not set).
392 int count
; /* the number of entries in NETPATH */
393 char valid_netpath
[BUFSIZ
]; /* holds the valid entries if NETPATH */
394 char templine
[BUFSIZ
]; /* has value of NETPATH when scanning */
395 struct netconfig
**curr_pp
; /* scans the list from NETPATH */
396 struct netconfig
**tpp
; /* scans the list from netconfig file */
397 struct netconfig
**rnetpp
; /* the list of entries from NETPATH */
398 char *netpath
; /* value of NETPATH from environment */
399 char *netid
; /* holds a component of NETPATH */
400 char *tp
; /* used to scan NETPATH string */
401 NCONF_HANDLE
*retp
; /* the return value */
404 * Read in the netconfig database if not already read in
406 (void) mutex_lock(&netpp_mutex
);
407 if ((netpp
== NULL
) && ((netpp
= getnetlist()) == NULL
)) {
408 (void) mutex_unlock(&netpp_mutex
);
411 (void) mutex_unlock(&netpp_mutex
);
413 if ((retp
= malloc(sizeof (NCONF_HANDLE
))) == NULL
) {
419 * Get the valid entries of the NETPATH variable (and
420 * count the number of entries while doing it).
422 * This is done every time the procedure is called just
423 * in case NETPATH has changed from call to call.
425 * If NETPATH is too long, we ignore it altogether as
426 * it can only be a buffer overflow attack.
427 * Since we add one colon for each entry, but colons only
428 * need to exist between entries, we have to subtract one.
431 valid_netpath
[0] = '\0';
432 if ((netpath
= getenv(NETPATH
)) == NULL
||
433 strlen(netpath
) >= sizeof (templine
) - 1) {
435 * If NETPATH variable is not set or invalid,
436 * the valid NETPATH consist of all "visible"
437 * netids from the netconfig database.
440 for (tpp
= netpp
; *tpp
; tpp
++) {
441 if ((*tpp
)->nc_flag
& NC_VISIBLE
) {
442 (void) strcat(valid_netpath
, (*tpp
)->nc_netid
);
443 (void) strcat(valid_netpath
, ":");
450 * Copy the value of NETPATH (since '\0's will be
451 * put into the string) and create the valid NETPATH
452 * (by throwing away all netids not in the database).
453 * If an entry appears more than one, it *will* be
454 * listed twice in the list of valid netpath entries.
457 (void) strcpy(templine
, netpath
);
461 /* Skip all leading ':'s */
462 while (*tp
&& *tp
== ':')
465 break; /* last one */
467 while (*tp
&& *tp
!= ':')
470 *tp
++ = '\0'; /* isolate netid */
472 for (tpp
= netpp
; *tpp
; tpp
++) {
473 if (strcmp(netid
, (*tpp
)->nc_netid
) == 0) {
474 (void) strcat(valid_netpath
,
476 (void) strcat(valid_netpath
, ":");
484 /* Get space to hold the valid list (+1 for the NULL) */
486 if ((rnetpp
= malloc((count
+ 1) *
487 sizeof (struct netconfig
*))) == NULL
) {
494 * Populate the NETPATH list, ending it with a NULL.
495 * Each entry in the list points to the structure in the
496 * "netpp" list (the entry must exist in the list, otherwise
497 * it wouldn't appear in valid_netpath[]).
501 netid
= tp
= valid_netpath
;
504 while (*tp
&& *tp
!= ':')
508 for (tpp
= netpp
; *tpp
; tpp
++) {
509 if (strcmp(netid
, (*tpp
)->nc_netid
) == 0) {
517 retp
->nc_curr
= retp
->nc_head
= rnetpp
;
518 return ((void *)retp
);
522 * endnetpath() frees up all of the memory allocated by setnetpath().
523 * It returns -1 (error) if setnetpath was never called.
527 endnetpath(void *vdata
)
529 /* The argument is really a NCONF_HANDLE; cast it here */
530 NCONF_HANDLE
*nconf_handlep
= (NCONF_HANDLE
*)vdata
;
532 (void) mutex_lock(&netpp_mutex
);
533 if (netpp
== NULL
|| nconf_handlep
== NULL
) {
535 (void) mutex_unlock(&netpp_mutex
);
538 (void) mutex_unlock(&netpp_mutex
);
540 free(nconf_handlep
->nc_head
);
546 * getnetpath() returns the current entry in the list
547 * from the NETPATH variable. If setnetpath() was not called
548 * previously to set up the list, return NULL.
552 getnetpath(void *vdata
)
554 /* The argument is really a NCONF_HANDLE; cast it here */
555 NCONF_HANDLE
*nconf_handlep
= (NCONF_HANDLE
*)vdata
;
556 struct netconfig
*retp
; /* holds the return value */
557 int ipv6_present
= -1;
559 (void) mutex_lock(&netpp_mutex
);
562 (void) mutex_unlock(&netpp_mutex
);
565 (void) mutex_unlock(&netpp_mutex
);
567 retp
= *(nconf_handlep
->nc_curr
);
568 if (retp
&& (strcmp(retp
->nc_netid
, "udp6") == 0 ||
569 strcmp(retp
->nc_netid
, "tcp6") == 0)) {
570 if (ipv6_present
== -1)
571 ipv6_present
= __can_use_af(AF_INET6
);
573 ++(nconf_handlep
->nc_curr
);
580 ++(nconf_handlep
->nc_curr
);
581 nc_error
= NC_NOERROR
;
583 nc_error
= NC_NOMOREENTRIES
;
590 * blank() returns true if the line is a blank line, 0 otherwise
596 while (*cp
&& isspace(*cp
)) {
599 return (*cp
== '\0');
603 * comment() returns true if the line is a comment, 0 otherwise.
609 while (*cp
&& isspace(*cp
)) {
616 * getvalue() searches for the given string in the given array,
617 * and return the integer value associated with the string.
621 getvalue(char *cp
, struct nc_data nc_data
[])
623 int i
; /* used to index through the given struct nc_data array */
625 for (i
= 0; nc_data
[i
].string
; i
++) {
626 if (strcmp(nc_data
[i
].string
, cp
) == 0) {
630 return (nc_data
[i
].value
);
634 * getflag() creates a bitmap of the one-character flags in
635 * the given string. It uses nc_flags array to get the values.
641 int i
; /* indexs through the nc_flag array */
642 unsigned int mask
= 0; /* holds bitmask of flags */
645 for (i
= 0; nc_flag
[i
].string
; i
++) {
646 if (*nc_flag
[i
].string
== *cp
) {
647 mask
|= nc_flag
[i
].value
;
657 * getlookups() creates and returns an array of string representing
658 * the directory lookup libraries, given as a comma-seperated list
659 * in the argument "cp".
665 unsigned int num
; /* holds the number of entries in the list */
666 char **listpp
; /* the beginning of the list of dir routines */
667 char **tpp
; /* traverses the list, populating it */
670 num
= getnlookups(cp
);
673 if ((listpp
= malloc((num
+ 1) * sizeof (char *))) == NULL
)
681 * Traverse the string looking for the next entry
682 * of the list (i.e, where the ',' or end of the
683 * string appears). If a "\" is found, shift the
684 * token over 1 to the left (taking the next char
688 while (*cp
&& *cp
!= ',') {
689 if (*cp
== '\\' && *(cp
+ 1)) {
696 if ((*tpp
++ = strdup(start
)) == NULL
) {
697 for (tpp
= listpp
; *tpp
; tpp
++)
708 * getnlookups() returns the number of entries in a comma-separated
709 * string of tokens. A "-" means no strings are present.
713 getnlookups(char *cp
)
715 unsigned int count
; /* the number of tokens in the string */
717 if (strcmp(cp
, "-") == 0)
727 * If a "\" is in the string, take the next character
728 * literally. Onlly skip the character if "\" is
729 * not the last character of the token.
731 if (*cp
== '\\' && *(cp
+ 1)) {
740 * gettoken() behaves much like strtok(), except that
741 * it knows about escaped space characters (i.e., space characters
742 * preceeded by a '\' are taken literally).
746 gettoken(char *cp
, int skip
)
748 static char *savep
; /* the place where we left off */
749 char *p
; /* the beginning of the new token */
750 char *retp
; /* the token to be returned */
754 /* Determine if first or subsequent call */
755 p
= (cp
== NULL
)? savep
: cp
;
757 /* Return if no tokens remain. */
768 * Save the location of the token and then skip past it
780 * Only process the escape of the space seperator;
781 * since the token may contain other separators,
782 * let the other routines handle the escape of
783 * specific characters in the token.
786 if (*p
== '\\' && *(p
+ 1) != '\n' && isspace(*(p
+ 1))) {
792 savep
= 0; /* indicate this is last token */
797 return (strdup(retp
));
801 * shift1left() moves all characters in the string over 1 to
815 static char buf_main
[BUFSIZ
];
816 static pthread_key_t perror_key
= PTHREAD_ONCE_KEY_NP
;
817 char *retstr
= thr_main()?
818 buf_main
: thr_get_storage(&perror_key
, BUFSIZ
, free
);
820 if (retstr
== NULL
) {
822 "nc_sperror: malloc failed when trying to create buffer\n");
828 (void) strlcpy(retstr
, dgettext(__nsl_dom
, "no error"), BUFSIZ
);
831 (void) strlcpy(retstr
, dgettext(__nsl_dom
, "out of memory"),
835 (void) strlcpy(retstr
, dgettext(__nsl_dom
,
836 "routine called before calling \
837 setnetpath() or setnetconfig()"), BUFSIZ
);
840 (void) strlcpy(retstr
,
841 dgettext(__nsl_dom
, "cannot open /etc/netconfig"),
845 (void) snprintf(retstr
, BUFSIZ
, dgettext(__nsl_dom
,
846 "error in /etc/netconfig: field %d of line %d\n"),
850 (void) snprintf(retstr
, BUFSIZ
,
852 "netid not found in /etc/netconfig"));
854 case NC_NOMOREENTRIES
:
855 (void) snprintf(retstr
, BUFSIZ
,
857 "no more entries in /etc/netconfig"));
860 (void) strlcpy(retstr
, dgettext(__nsl_dom
, "unknown error"),
868 nc_perror(const char *string
)
871 (void) fprintf(stderr
, "%s: %s\n", string
, nc_sperror());
873 (void) fprintf(stderr
, "%s\n", nc_sperror());
877 netlist_free(struct netconfig
***netppp
)
879 struct netconfig
**tpp
;
881 for (tpp
= *netppp
; *tpp
; tpp
++) {
882 netconfig_free(*tpp
);
889 netconfig_free(struct netconfig
*netconfigp
)
893 if (netconfigp
== NULL
)
895 free_entry(netconfigp
->nc_netid
);
896 free_entry(netconfigp
->nc_protofmly
);
897 free_entry(netconfigp
->nc_proto
);
898 free_entry(netconfigp
->nc_device
);
899 if (netconfigp
->nc_lookups
)
900 for (i
= 0; i
< netconfigp
->nc_nlookups
; i
++)
901 free_entry(netconfigp
->nc_lookups
[i
]);
902 free_entry(netconfigp
->nc_lookups
);
906 static struct netconfig
*
907 netconfig_dup(struct netconfig
*netconfigp
)
909 struct netconfig
*nconf
;
912 nconf
= calloc(1, sizeof (struct netconfig
));
917 nconf
->nc_netid
= strdup(netconfigp
->nc_netid
);
918 nconf
->nc_protofmly
= strdup(netconfigp
->nc_protofmly
);
919 nconf
->nc_proto
= strdup(netconfigp
->nc_proto
);
920 nconf
->nc_device
= strdup(netconfigp
->nc_device
);
921 nconf
->nc_lookups
= malloc((netconfigp
->nc_nlookups
+ 1)
923 if (!(nconf
->nc_lookups
&& nconf
->nc_netid
&&
924 nconf
->nc_protofmly
&& nconf
->nc_proto
&&
927 netconfig_free(nconf
);
931 for (i
= 0; i
< netconfigp
->nc_nlookups
; i
++) {
932 nconf
->nc_lookups
[i
] = strdup(netconfigp
->nc_lookups
[i
]);
933 if (nconf
->nc_lookups
[i
] == NULL
) {
934 nconf
->nc_nlookups
= i
;
935 netconfig_free(nconf
);
940 nconf
->nc_lookups
[i
] = NULL
;
941 nconf
->nc_nlookups
= netconfigp
->nc_nlookups
;
942 nconf
->nc_flag
= netconfigp
->nc_flag
;
943 nconf
->nc_semantics
= netconfigp
->nc_semantics
;
948 free_entry(void *foo
)