10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
22*132Srobinson 
230Sstevel@tonic-gate /*
24*132Srobinson  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
250Sstevel@tonic-gate  * Use is subject to license terms.
260Sstevel@tonic-gate  */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
290Sstevel@tonic-gate /*	  All Rights Reserved  	*/
300Sstevel@tonic-gate 
310Sstevel@tonic-gate /*
320Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
330Sstevel@tonic-gate  * under license from the Regents of the University of California.
340Sstevel@tonic-gate  */
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include "mt.h"
390Sstevel@tonic-gate #include "../rpc/rpc_mt.h"		/* for MT declarations only */
400Sstevel@tonic-gate #include <rpc/types.h>
410Sstevel@tonic-gate #include <stdio.h>
42*132Srobinson #include <stdlib.h>
430Sstevel@tonic-gate #include <string.h>
440Sstevel@tonic-gate #include <ctype.h>
450Sstevel@tonic-gate #include <netconfig.h>
460Sstevel@tonic-gate #include <malloc.h>
47*132Srobinson #include <libintl.h>
480Sstevel@tonic-gate #include <syslog.h>
490Sstevel@tonic-gate #include "netcspace.h"
500Sstevel@tonic-gate #include "nsl_stdio_prv.h"
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #define	FAILURE  (unsigned)(-1)
530Sstevel@tonic-gate 
540Sstevel@tonic-gate /*
550Sstevel@tonic-gate  *	Local routines used by the library procedures
560Sstevel@tonic-gate  */
570Sstevel@tonic-gate 
58*132Srobinson static int blank(char *);
59*132Srobinson static int comment(char *);
60*132Srobinson static struct netconfig *fgetnetconfig(__NSL_FILE *, char *);
61*132Srobinson static void netconfig_free(struct netconfig *);
62*132Srobinson static unsigned int getflag(char *);
63*132Srobinson static char **getlookups(char *);
64*132Srobinson static struct netconfig **getnetlist(void);
65*132Srobinson static unsigned int getnlookups(char *);
66*132Srobinson static char *gettoken(char *, int);
67*132Srobinson static unsigned int getvalue(char *, struct nc_data nc_data[]);
68*132Srobinson static void shift1left(char *);
69*132Srobinson static void netlist_free(struct netconfig ***);
70*132Srobinson static void free_entry(void *);
71*132Srobinson static struct netconfig *netconfig_dup(struct netconfig *);
720Sstevel@tonic-gate 
730Sstevel@tonic-gate extern const char __nsl_dom[];
740Sstevel@tonic-gate 
750Sstevel@tonic-gate /*
760Sstevel@tonic-gate  *	Static global variables used by the library procedures:
770Sstevel@tonic-gate  *
780Sstevel@tonic-gate  *	netpp - points to the beginning of the list of netconfig
790Sstevel@tonic-gate  *		entries used by setnetconfig() and setnetpath().
800Sstevel@tonic-gate  *		Once netpp is initialized, that memory is *never*
810Sstevel@tonic-gate  *		released.  This was necessary to improve performance.
820Sstevel@tonic-gate  *
830Sstevel@tonic-gate  *	linenum - the current line number of the /etc/netconfig
840Sstevel@tonic-gate  *		  file (used for debugging and for nc_perror()).
850Sstevel@tonic-gate  *
860Sstevel@tonic-gate  *	fieldnum - the current field number of the current line
870Sstevel@tonic-gate  *		   of /etc/netconfig (used for debugging and for
880Sstevel@tonic-gate  *		   nc_perror()).
890Sstevel@tonic-gate  *
900Sstevel@tonic-gate  *	nc_error - the error condition encountered.
910Sstevel@tonic-gate  */
920Sstevel@tonic-gate 
930Sstevel@tonic-gate static struct netconfig **netpp = NULL;
940Sstevel@tonic-gate mutex_t netpp_mutex = DEFAULTMUTEX;
950Sstevel@tonic-gate /*
960Sstevel@tonic-gate  * The following two variables are used by the /etc/netconfig parsing
970Sstevel@tonic-gate  * routines, which will always be executed once, and within the netpp_mutex.
980Sstevel@tonic-gate  * They are global to allow the nc_sperror routine to provide better
990Sstevel@tonic-gate  * information to the user about /etc/netconfig file problems.
1000Sstevel@tonic-gate  */
1010Sstevel@tonic-gate static int linenum = 0;			/* "owned" by getnetlist() */
1020Sstevel@tonic-gate static int fieldnum = 0;		/* "owned" by fgetnetconfig() */
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate static int *
106*132Srobinson __nc_error(void)
1070Sstevel@tonic-gate {
1080Sstevel@tonic-gate 	static pthread_key_t nc_error_key = 0;
1090Sstevel@tonic-gate 	static int nc_error = NC_NOERROR;
1100Sstevel@tonic-gate 	int *ret;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	if (thr_main())
1130Sstevel@tonic-gate 		return (&nc_error);
1140Sstevel@tonic-gate 	ret = thr_get_storage(&nc_error_key, sizeof (int), free);
1150Sstevel@tonic-gate 	/* if thr_get_storage fails we return the address of nc_error */
1160Sstevel@tonic-gate 	return (ret ? ret : &nc_error);
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate #define	nc_error	(*(__nc_error()))
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate /*
1210Sstevel@tonic-gate  *	setnetconfig() has the effect of "initializing" the
1220Sstevel@tonic-gate  *	network configuration database.   It reads in the
1230Sstevel@tonic-gate  *	netcf entries (if not already read in).
1240Sstevel@tonic-gate  */
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate void *
127*132Srobinson setnetconfig(void)
1280Sstevel@tonic-gate {
1290Sstevel@tonic-gate 	NCONF_HANDLE *retp;
1300Sstevel@tonic-gate 
131*132Srobinson 	(void) mutex_lock(&netpp_mutex);
1320Sstevel@tonic-gate 	if ((netpp == NULL) && ((netpp = getnetlist()) == NULL)) {
133*132Srobinson 		(void) mutex_unlock(&netpp_mutex);
1340Sstevel@tonic-gate 		return (NULL);
1350Sstevel@tonic-gate 	}
136*132Srobinson 	(void) mutex_unlock(&netpp_mutex);
137*132Srobinson 	if ((retp = malloc(sizeof (NCONF_HANDLE))) == NULL) {
1380Sstevel@tonic-gate 		nc_error = NC_NOMEM;
1390Sstevel@tonic-gate 		return (NULL);
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate 	nc_error = NC_NOERROR;
1420Sstevel@tonic-gate 	retp->nc_head = retp->nc_curr = netpp;
1430Sstevel@tonic-gate 	return ((void *)retp);
1440Sstevel@tonic-gate }
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate /*
1470Sstevel@tonic-gate  *	endnetconfig() frees up all data allocated by setnetconfig()
1480Sstevel@tonic-gate  */
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate int
151*132Srobinson endnetconfig(void *vdata)
1520Sstevel@tonic-gate {
1530Sstevel@tonic-gate 	NCONF_HANDLE *nconf_handlep = (NCONF_HANDLE *)vdata;
1540Sstevel@tonic-gate 
155*132Srobinson 	(void) mutex_lock(&netpp_mutex);
1560Sstevel@tonic-gate 	if (netpp == NULL || nconf_handlep == NULL) {
1570Sstevel@tonic-gate 		nc_error = NC_NOSET;
158*132Srobinson 		(void) mutex_unlock(&netpp_mutex);
1590Sstevel@tonic-gate 		return (-1);
1600Sstevel@tonic-gate 	}
161*132Srobinson 	(void) mutex_unlock(&netpp_mutex);
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	nc_error = NC_NOERROR;
164*132Srobinson 	free(nconf_handlep);
1650Sstevel@tonic-gate 	return (0);
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate /*
1690Sstevel@tonic-gate  *	getnetconfig() returns the current entry in the list
1700Sstevel@tonic-gate  *	of netconfig structures.  It uses the nconf_handlep argument
1710Sstevel@tonic-gate  *	to determine the current entry. If setnetconfig() was not
1720Sstevel@tonic-gate  *	called previously to set up the list, return failure.
1730Sstevel@tonic-gate  *      It also check if ipv6 interface is present(ipv6_present) and
1740Sstevel@tonic-gate  *	skips udp6 & tcp6 entries if ipv6 is not supported.
1750Sstevel@tonic-gate  */
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate struct netconfig *
178*132Srobinson getnetconfig(void *vdata)
1790Sstevel@tonic-gate {
1800Sstevel@tonic-gate 	NCONF_HANDLE *nconf_handlep = (NCONF_HANDLE *)vdata;
1810Sstevel@tonic-gate 	struct netconfig *retp;  /* holds the return value */
1820Sstevel@tonic-gate 	int ipv6_present = -1;
1830Sstevel@tonic-gate 
184*132Srobinson 	(void) mutex_lock(&netpp_mutex);
1850Sstevel@tonic-gate 	if ((netpp == NULL) || (nconf_handlep == NULL)) {
1860Sstevel@tonic-gate 		nc_error = NC_NOSET;
187*132Srobinson 		(void) mutex_unlock(&netpp_mutex);
1880Sstevel@tonic-gate 		return (NULL);
1890Sstevel@tonic-gate 	}
190*132Srobinson 	(void) mutex_unlock(&netpp_mutex);
1910Sstevel@tonic-gate 	for (;;) {
1920Sstevel@tonic-gate 		retp = *(nconf_handlep->nc_curr);
1930Sstevel@tonic-gate 		if (retp && (strcmp(retp->nc_netid, "udp6") == 0 ||
1940Sstevel@tonic-gate 		    strcmp(retp->nc_netid, "tcp6") == 0)) {
1950Sstevel@tonic-gate 			if (ipv6_present == -1)
1960Sstevel@tonic-gate 				ipv6_present = __can_use_af(AF_INET6);
1970Sstevel@tonic-gate 			if (!ipv6_present) {
1980Sstevel@tonic-gate 				++(nconf_handlep->nc_curr);
1990Sstevel@tonic-gate 				continue;
2000Sstevel@tonic-gate 			}
2010Sstevel@tonic-gate 		}
2020Sstevel@tonic-gate 		break;
2030Sstevel@tonic-gate 	}
2040Sstevel@tonic-gate 	if (retp != NULL) {
2050Sstevel@tonic-gate 		++(nconf_handlep->nc_curr);
2060Sstevel@tonic-gate 		nc_error = NC_NOERROR;
2070Sstevel@tonic-gate 	} else {
2080Sstevel@tonic-gate 		nc_error = NC_NOMOREENTRIES;
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate 	return (retp);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate /*
2140Sstevel@tonic-gate  *	getnetconfig() searches the netconfig database for a
2150Sstevel@tonic-gate  *	given network id.  Returns a pointer to the netconfig
2160Sstevel@tonic-gate  *	structure or a NULL if not found.
2170Sstevel@tonic-gate  *      It also check if ipv6 interface is present(ipv6_present) and
2180Sstevel@tonic-gate  *	skips udp6 & tcp6 entries if ipv6 is not supported.
2190Sstevel@tonic-gate  */
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate struct netconfig *
222*132Srobinson getnetconfigent(const char *netid)
2230Sstevel@tonic-gate {
2240Sstevel@tonic-gate 	struct netconfig **tpp;
2250Sstevel@tonic-gate 	int ipv6_present;
2260Sstevel@tonic-gate 
227*132Srobinson 	(void) mutex_lock(&netpp_mutex);
2280Sstevel@tonic-gate 	if ((netpp == NULL) && ((netpp = getnetlist()) == NULL)) {
229*132Srobinson 		(void) mutex_unlock(&netpp_mutex);
2300Sstevel@tonic-gate 		return (NULL);
2310Sstevel@tonic-gate 	}
232*132Srobinson 	(void) mutex_unlock(&netpp_mutex);
2330Sstevel@tonic-gate 	for (tpp = netpp; *tpp; tpp++) {
2340Sstevel@tonic-gate 		if (strcmp((*tpp)->nc_netid, netid) == 0) {
2350Sstevel@tonic-gate 			if (*tpp && (strcmp((*tpp)->nc_netid, "udp6") == 0 ||
2360Sstevel@tonic-gate 			    strcmp((*tpp)->nc_netid, "tcp6") == 0)) {
2370Sstevel@tonic-gate 				ipv6_present = __can_use_af(AF_INET6);
2380Sstevel@tonic-gate 				if (!ipv6_present) {
2390Sstevel@tonic-gate 					nc_error = NC_NOTFOUND;
2400Sstevel@tonic-gate 					return (NULL);
2410Sstevel@tonic-gate 				}
2420Sstevel@tonic-gate 			}
2430Sstevel@tonic-gate 			return (netconfig_dup(*tpp));
2440Sstevel@tonic-gate 		}
2450Sstevel@tonic-gate 	}
2460Sstevel@tonic-gate 	nc_error = NC_NOTFOUND;
2470Sstevel@tonic-gate 	return (NULL);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate /*
2510Sstevel@tonic-gate  *	freenetconfigent frees the data allocated by getnetconfigent()
2520Sstevel@tonic-gate  */
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate void
255*132Srobinson freenetconfigent(struct netconfig *netp)
2560Sstevel@tonic-gate {
2570Sstevel@tonic-gate 	netconfig_free(netp);
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate /*
2610Sstevel@tonic-gate  *	getnetlist() reads the netconfig file and creates a
2620Sstevel@tonic-gate  *	NULL-terminated list of entries.
2630Sstevel@tonic-gate  *	Returns the pointer to the head of the list or a NULL
2640Sstevel@tonic-gate  *	on failure.
2650Sstevel@tonic-gate  */
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate static struct netconfig **
268*132Srobinson getnetlist(void)
2690Sstevel@tonic-gate {
2700Sstevel@tonic-gate 	char line[BUFSIZ];	/* holds each line of NETCONFIG */
2710Sstevel@tonic-gate 	__NSL_FILE *fp;		/* file stream for NETCONFIG */
2720Sstevel@tonic-gate 	struct netconfig **listpp; /* the beginning of the netconfig list */
2730Sstevel@tonic-gate 	struct netconfig **tpp;	/* used to traverse the netconfig list */
2740Sstevel@tonic-gate 	int count;		/* the number of entries in file */
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	if ((fp = __nsl_fopen(NETCONFIG, "r")) == NULL) {
2770Sstevel@tonic-gate 		nc_error = NC_OPENFAIL;
2780Sstevel@tonic-gate 		return (NULL);
2790Sstevel@tonic-gate 	}
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	count = 0;
2820Sstevel@tonic-gate 	while (__nsl_fgets(line, BUFSIZ, fp)) {
2830Sstevel@tonic-gate 		if (!(blank(line) || comment(line))) {
2840Sstevel@tonic-gate 			++count;
2850Sstevel@tonic-gate 		}
2860Sstevel@tonic-gate 	}
2870Sstevel@tonic-gate 	__nsl_rewind(fp);
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	if (count == 0) {
2900Sstevel@tonic-gate 		nc_error = NC_NOTFOUND;
2910Sstevel@tonic-gate 		(void) __nsl_fclose(fp);
2920Sstevel@tonic-gate 		return (NULL);
2930Sstevel@tonic-gate 	}
294*132Srobinson 	if ((listpp = malloc((count + 1) *
2950Sstevel@tonic-gate 	    sizeof (struct netconfig *))) == NULL) {
2960Sstevel@tonic-gate 		nc_error = NC_NOMEM;
2970Sstevel@tonic-gate 		(void) __nsl_fclose(fp);
2980Sstevel@tonic-gate 		return (NULL);
2990Sstevel@tonic-gate 	}
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	/*
3020Sstevel@tonic-gate 	 *	The following loop fills in the list (loops until
3030Sstevel@tonic-gate 	 *	fgetnetconfig() returns a NULL) and counts the
3040Sstevel@tonic-gate 	 *	number of entries placed in the list.  Note that
3050Sstevel@tonic-gate 	 *	when the loop is completed, the last entry in the
3060Sstevel@tonic-gate 	 *	list will contain a NULL (signifying the end of
3070Sstevel@tonic-gate 	 *	the list).
3080Sstevel@tonic-gate 	 */
3090Sstevel@tonic-gate 	linenum = 0;
3100Sstevel@tonic-gate 	for (tpp = listpp; *tpp = fgetnetconfig(fp, NULL); tpp++)
3110Sstevel@tonic-gate 		;
3120Sstevel@tonic-gate 	(void) __nsl_fclose(fp);
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	if (nc_error != NC_NOMOREENTRIES) /* Something is screwed up */
3150Sstevel@tonic-gate 		netlist_free(&listpp);
3160Sstevel@tonic-gate 	return (listpp);
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate /*
3200Sstevel@tonic-gate  *	fgetnetconfig() parses a line of the netconfig file into
3210Sstevel@tonic-gate  *	a netconfig structure.  It returns a pointer to the
3220Sstevel@tonic-gate  *	structure of success and a NULL on failure or EOF.
3230Sstevel@tonic-gate  */
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate static struct netconfig *
326*132Srobinson fgetnetconfig(__NSL_FILE *fp, char *netid)
3270Sstevel@tonic-gate {
3280Sstevel@tonic-gate 	char linep[BUFSIZ];	/* pointer to a line in the file */
3290Sstevel@tonic-gate 	struct netconfig *netconfigp; /* holds the new netconfig structure */
3300Sstevel@tonic-gate 	char  *tok1, *tok2, *tok3; /* holds a token from the line */
3310Sstevel@tonic-gate 	char  *retvalp;		/* the return value of fgets() */
3320Sstevel@tonic-gate 	char *entnetid;		/* netid for the current entry */
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	/* skip past blank lines and comments. */
3350Sstevel@tonic-gate 	while (retvalp = __nsl_fgets(linep, BUFSIZ, fp)) {
3360Sstevel@tonic-gate 		linenum++;
3370Sstevel@tonic-gate 		if (!(blank(linep) || comment(linep))) {
3380Sstevel@tonic-gate 			break;
3390Sstevel@tonic-gate 		}
3400Sstevel@tonic-gate 		retvalp = NULL;
3410Sstevel@tonic-gate 	}
3420Sstevel@tonic-gate 	if (retvalp == NULL) {
3430Sstevel@tonic-gate 		nc_error = NC_NOMOREENTRIES;
3440Sstevel@tonic-gate 		return (NULL);
3450Sstevel@tonic-gate 	}
3460Sstevel@tonic-gate 	fieldnum = 0;
3470Sstevel@tonic-gate 	if ((entnetid = gettoken(linep, FALSE)) == NULL) {
3480Sstevel@tonic-gate 		nc_error = NC_BADLINE;
3490Sstevel@tonic-gate 		return (NULL);
3500Sstevel@tonic-gate 	}
3510Sstevel@tonic-gate 	if (netid && (strcmp(netid, entnetid) != 0)) {
3520Sstevel@tonic-gate 		free(entnetid);
3530Sstevel@tonic-gate 		nc_error = NC_NOTFOUND;
3540Sstevel@tonic-gate 		return (NULL);
3550Sstevel@tonic-gate 	}
356*132Srobinson 	if ((netconfigp = calloc(1, sizeof (struct netconfig))) == NULL) {
3570Sstevel@tonic-gate 		free(entnetid);
3580Sstevel@tonic-gate 		nc_error = NC_NOMEM;
3590Sstevel@tonic-gate 		return (NULL);
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	tok1 = tok2 = tok3 = NULL;
3630Sstevel@tonic-gate 	netconfigp->nc_netid = entnetid;
3640Sstevel@tonic-gate 	if (((tok1 = gettoken(NULL, FALSE)) == NULL) ||
3650Sstevel@tonic-gate 	    ((netconfigp->nc_semantics =
3660Sstevel@tonic-gate 		getvalue(tok1, nc_semantics)) == FAILURE) ||
3670Sstevel@tonic-gate 	    ((tok2 = gettoken(NULL, FALSE)) == NULL) ||
3680Sstevel@tonic-gate 	    ((netconfigp->nc_flag = getflag(tok2)) == FAILURE) ||
3690Sstevel@tonic-gate 	    ((netconfigp->nc_protofmly = gettoken(NULL, FALSE)) == NULL) ||
3700Sstevel@tonic-gate 	    ((netconfigp->nc_proto = gettoken(NULL, FALSE)) == NULL) ||
3710Sstevel@tonic-gate 	    ((netconfigp->nc_device = gettoken(NULL, FALSE)) == NULL) ||
3720Sstevel@tonic-gate 	    ((tok3 = gettoken(NULL, TRUE)) == NULL) ||
3730Sstevel@tonic-gate 	    (((netconfigp->nc_nlookups = getnlookups(tok3)) != 0) &&
3740Sstevel@tonic-gate 		((netconfigp->nc_lookups = getlookups(tok3)) == NULL))) {
3750Sstevel@tonic-gate 		netconfig_free(netconfigp);
3760Sstevel@tonic-gate 		nc_error = NC_BADLINE;
3770Sstevel@tonic-gate 		netconfigp = NULL;
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 	free(tok1);
3800Sstevel@tonic-gate 	free(tok2);
3810Sstevel@tonic-gate 	free(tok3);
3820Sstevel@tonic-gate 	return (netconfigp);
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate /*
3860Sstevel@tonic-gate  *	setnetpath() has the effect of "initializing" the
3870Sstevel@tonic-gate  *	NETPATH variable.  It reads in the netcf entries (if not
3880Sstevel@tonic-gate  *	already read in), creates a list corresponding to the entries
3890Sstevel@tonic-gate  *	in the NETPATH variable (or the "visible" entries og netconfig
3900Sstevel@tonic-gate  *	if NETPATH is not set).
3910Sstevel@tonic-gate  */
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate void *
394*132Srobinson setnetpath(void)
3950Sstevel@tonic-gate {
3960Sstevel@tonic-gate 	int count;		    /* the number of entries in NETPATH	    */
3970Sstevel@tonic-gate 	char valid_netpath[BUFSIZ]; /* holds the valid entries if NETPATH   */
3980Sstevel@tonic-gate 	char templine[BUFSIZ];	    /* has value of NETPATH when scanning   */
3990Sstevel@tonic-gate 	struct netconfig **curr_pp; /* scans the list from NETPATH	    */
4000Sstevel@tonic-gate 	struct netconfig **tpp;	    /* scans the list from netconfig file   */
4010Sstevel@tonic-gate 	struct netconfig **rnetpp;  /* the list of entries from NETPATH	    */
4020Sstevel@tonic-gate 	char *netpath;		    /* value of NETPATH from environment    */
4030Sstevel@tonic-gate 	char *netid;		    /* holds a component of NETPATH	    */
4040Sstevel@tonic-gate 	char *tp;		    /* used to scan NETPATH string	    */
4050Sstevel@tonic-gate 	NCONF_HANDLE *retp;	    /* the return value			    */
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	/*
4080Sstevel@tonic-gate 	 *	Read in the netconfig database if not already read in
4090Sstevel@tonic-gate 	 */
410*132Srobinson 	(void) mutex_lock(&netpp_mutex);
4110Sstevel@tonic-gate 	if ((netpp == NULL) && ((netpp = getnetlist()) == NULL)) {
412*132Srobinson 		(void) mutex_unlock(&netpp_mutex);
4130Sstevel@tonic-gate 		return (NULL);
4140Sstevel@tonic-gate 	}
415*132Srobinson 	(void) mutex_unlock(&netpp_mutex);
4160Sstevel@tonic-gate 
417*132Srobinson 	if ((retp = malloc(sizeof (NCONF_HANDLE))) == NULL) {
4180Sstevel@tonic-gate 		nc_error = NC_NOMEM;
4190Sstevel@tonic-gate 		return (NULL);
4200Sstevel@tonic-gate 	}
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	/*
4230Sstevel@tonic-gate 	 *	Get the valid entries of the NETPATH variable (and
4240Sstevel@tonic-gate 	 *	count the number of entries while doing it).
4250Sstevel@tonic-gate 	 *
4260Sstevel@tonic-gate 	 *	This is done every time the procedure is called just
4270Sstevel@tonic-gate 	 *	in case NETPATH has changed from call to call.
4280Sstevel@tonic-gate 	 *
4290Sstevel@tonic-gate 	 * 	If NETPATH is too long, we ignore it altogether as
4300Sstevel@tonic-gate 	 *	it can only be a buffer overflow attack.
4310Sstevel@tonic-gate 	 *	Since we add one colon for each entry, but colons only
4320Sstevel@tonic-gate 	 *	need to exist between entries, we have to subtract one.
4330Sstevel@tonic-gate 	 */
4340Sstevel@tonic-gate 	count = 0;
4350Sstevel@tonic-gate 	valid_netpath[0] = '\0';
4360Sstevel@tonic-gate 	if ((netpath = getenv(NETPATH)) == NULL ||
4370Sstevel@tonic-gate 	    strlen(netpath) >= sizeof (templine) - 1) {
4380Sstevel@tonic-gate 		/*
4390Sstevel@tonic-gate 		 *	If NETPATH variable is not set or invalid,
4400Sstevel@tonic-gate 		 *	the valid NETPATH consist of all "visible"
4410Sstevel@tonic-gate 		 *	netids from the netconfig database.
4420Sstevel@tonic-gate 		 */
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 		for (tpp = netpp; *tpp; tpp++) {
4450Sstevel@tonic-gate 			if ((*tpp)->nc_flag & NC_VISIBLE) {
4460Sstevel@tonic-gate 				(void) strcat(valid_netpath, (*tpp)->nc_netid);
4470Sstevel@tonic-gate 				(void) strcat(valid_netpath, ":");
4480Sstevel@tonic-gate 				count++;
4490Sstevel@tonic-gate 			}
4500Sstevel@tonic-gate 		}
4510Sstevel@tonic-gate 	} else {
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 		/*
4540Sstevel@tonic-gate 		 *	Copy the value of NETPATH (since '\0's will be
4550Sstevel@tonic-gate 		 *	put into the string) and create the valid NETPATH
4560Sstevel@tonic-gate 		 *	(by throwing away all netids not in the database).
4570Sstevel@tonic-gate 		 *	If an entry appears more than one, it *will* be
4580Sstevel@tonic-gate 		 *	listed twice in the list of valid netpath entries.
4590Sstevel@tonic-gate 		 */
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 		(void) strcpy(templine, netpath);
4620Sstevel@tonic-gate 		tp = templine;
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 		while (*tp) {
4650Sstevel@tonic-gate 			/* Skip all leading ':'s */
4660Sstevel@tonic-gate 			while (*tp && *tp == ':')
4670Sstevel@tonic-gate 				tp++;
4680Sstevel@tonic-gate 			if (*tp == NULL)
4690Sstevel@tonic-gate 				break;  /* last one */
4700Sstevel@tonic-gate 			netid = tp;
4710Sstevel@tonic-gate 			while (*tp && *tp != ':')
4720Sstevel@tonic-gate 				tp++;
4730Sstevel@tonic-gate 			if (*tp)
4740Sstevel@tonic-gate 				*tp++ = '\0'; /* isolate netid */
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 			for (tpp = netpp; *tpp; tpp++) {
4770Sstevel@tonic-gate 				if (strcmp(netid, (*tpp)->nc_netid) == 0) {
4780Sstevel@tonic-gate 					(void) strcat(valid_netpath,
4790Sstevel@tonic-gate 						(*tpp)->nc_netid);
4800Sstevel@tonic-gate 					(void) strcat(valid_netpath, ":");
4810Sstevel@tonic-gate 					count++;
4820Sstevel@tonic-gate 					break;
4830Sstevel@tonic-gate 				}
4840Sstevel@tonic-gate 			}
4850Sstevel@tonic-gate 		}
4860Sstevel@tonic-gate 	}
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	/* Get space to hold the valid list (+1 for the NULL) */
4890Sstevel@tonic-gate 
490*132Srobinson 	if ((rnetpp = malloc((count + 1) *
4910Sstevel@tonic-gate 			sizeof (struct netconfig *))) == NULL) {
492*132Srobinson 		free(retp);
4930Sstevel@tonic-gate 		nc_error = NC_NOMEM;
4940Sstevel@tonic-gate 		return (NULL);
4950Sstevel@tonic-gate 	}
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	/*
4980Sstevel@tonic-gate 	 *	Populate the NETPATH list, ending it with a NULL.
4990Sstevel@tonic-gate 	 *	Each entry in the list points to the structure in the
5000Sstevel@tonic-gate 	 *	"netpp" list (the entry must exist in the list, otherwise
5010Sstevel@tonic-gate 	 *	it wouldn't appear in valid_netpath[]).
5020Sstevel@tonic-gate 	 */
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	curr_pp = rnetpp;
5050Sstevel@tonic-gate 	netid = tp = valid_netpath;
5060Sstevel@tonic-gate 	while (*tp) {
5070Sstevel@tonic-gate 		netid = tp;
5080Sstevel@tonic-gate 		while (*tp && *tp != ':')
5090Sstevel@tonic-gate 			tp++;
5100Sstevel@tonic-gate 		if (*tp)
5110Sstevel@tonic-gate 			*tp++ = '\0';
5120Sstevel@tonic-gate 		for (tpp = netpp; *tpp; tpp++) {
5130Sstevel@tonic-gate 			if (strcmp(netid, (*tpp)->nc_netid) == 0) {
5140Sstevel@tonic-gate 				*curr_pp++ = *tpp;
5150Sstevel@tonic-gate 				break;
5160Sstevel@tonic-gate 			}
5170Sstevel@tonic-gate 		}
5180Sstevel@tonic-gate 	}
5190Sstevel@tonic-gate 	*curr_pp = NULL;
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	retp->nc_curr = retp->nc_head = rnetpp;
5220Sstevel@tonic-gate 	return ((void *)retp);
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate /*
5260Sstevel@tonic-gate  *	endnetpath() frees up all of the memory allocated by setnetpath().
5270Sstevel@tonic-gate  *	It returns -1 (error) if setnetpath was never called.
5280Sstevel@tonic-gate  */
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate int
531*132Srobinson endnetpath(void *vdata)
5320Sstevel@tonic-gate {
5330Sstevel@tonic-gate 	/* The argument is really a NCONF_HANDLE;  cast it here */
5340Sstevel@tonic-gate 	NCONF_HANDLE *nconf_handlep = (NCONF_HANDLE *)vdata;
5350Sstevel@tonic-gate 
536*132Srobinson 	(void) mutex_lock(&netpp_mutex);
5370Sstevel@tonic-gate 	if (netpp == NULL || nconf_handlep == NULL) {
5380Sstevel@tonic-gate 		nc_error = NC_NOSET;
539*132Srobinson 		(void) mutex_unlock(&netpp_mutex);
5400Sstevel@tonic-gate 		return (-1);
5410Sstevel@tonic-gate 	}
542*132Srobinson 	(void) mutex_unlock(&netpp_mutex);
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	free(nconf_handlep->nc_head);
5450Sstevel@tonic-gate 	free(nconf_handlep);
5460Sstevel@tonic-gate 	return (0);
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate /*
5500Sstevel@tonic-gate  *	getnetpath() returns the current entry in the list
5510Sstevel@tonic-gate  *	from the NETPATH variable.  If setnetpath() was not called
5520Sstevel@tonic-gate  *	previously to set up the list, return NULL.
5530Sstevel@tonic-gate  */
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate struct netconfig *
556*132Srobinson getnetpath(void *vdata)
5570Sstevel@tonic-gate {
5580Sstevel@tonic-gate 	/* The argument is really a NCONF_HANDLE;  cast it here */
5590Sstevel@tonic-gate 	NCONF_HANDLE *nconf_handlep = (NCONF_HANDLE *)vdata;
5600Sstevel@tonic-gate 	struct netconfig *retp;  /* holds the return value */
5610Sstevel@tonic-gate 	int ipv6_present = -1;
5620Sstevel@tonic-gate 
563*132Srobinson 	(void) mutex_lock(&netpp_mutex);
5640Sstevel@tonic-gate 	if (netpp == NULL) {
5650Sstevel@tonic-gate 		nc_error = NC_NOSET;
566*132Srobinson 		(void) mutex_unlock(&netpp_mutex);
5670Sstevel@tonic-gate 		return (NULL);
5680Sstevel@tonic-gate 	}
569*132Srobinson 	(void) mutex_unlock(&netpp_mutex);
5700Sstevel@tonic-gate 	for (;;) {
5710Sstevel@tonic-gate 		retp = *(nconf_handlep->nc_curr);
5720Sstevel@tonic-gate 		if (retp && (strcmp(retp->nc_netid, "udp6") == 0 ||
5730Sstevel@tonic-gate 		    strcmp(retp->nc_netid, "tcp6") == 0)) {
5740Sstevel@tonic-gate 			if (ipv6_present == -1)
5750Sstevel@tonic-gate 				ipv6_present = __can_use_af(AF_INET6);
5760Sstevel@tonic-gate 			if (!ipv6_present) {
5770Sstevel@tonic-gate 				++(nconf_handlep->nc_curr);
5780Sstevel@tonic-gate 				continue;
5790Sstevel@tonic-gate 			}
5800Sstevel@tonic-gate 		}
5810Sstevel@tonic-gate 		break;
5820Sstevel@tonic-gate 	}
5830Sstevel@tonic-gate 	if (retp) {
5840Sstevel@tonic-gate 		++(nconf_handlep->nc_curr);
5850Sstevel@tonic-gate 		nc_error = NC_NOERROR;
5860Sstevel@tonic-gate 	} else {
5870Sstevel@tonic-gate 		nc_error = NC_NOMOREENTRIES;
5880Sstevel@tonic-gate 	}
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	return (retp);
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate /*
5940Sstevel@tonic-gate  *	blank() returns true if the line is a blank line, 0 otherwise
5950Sstevel@tonic-gate  */
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate static int
598*132Srobinson blank(char *cp)
5990Sstevel@tonic-gate {
6000Sstevel@tonic-gate 	while (*cp && isspace(*cp)) {
6010Sstevel@tonic-gate 		cp++;
6020Sstevel@tonic-gate 	}
6030Sstevel@tonic-gate 	return (*cp == '\0');
6040Sstevel@tonic-gate }
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate /*
6070Sstevel@tonic-gate  *	comment() returns true if the line is a comment, 0 otherwise.
6080Sstevel@tonic-gate  */
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate static int
611*132Srobinson comment(char *cp)
6120Sstevel@tonic-gate {
6130Sstevel@tonic-gate 	while (*cp && isspace(*cp)) {
6140Sstevel@tonic-gate 		cp++;
6150Sstevel@tonic-gate 	}
6160Sstevel@tonic-gate 	return (*cp == '#');
6170Sstevel@tonic-gate }
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate /*
6200Sstevel@tonic-gate  *	getvalue() searches for the given string in the given array,
6210Sstevel@tonic-gate  *	and return the integer value associated with the string.
6220Sstevel@tonic-gate  */
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate static unsigned int
625*132Srobinson getvalue(char *cp, struct nc_data nc_data[])
6260Sstevel@tonic-gate {
6270Sstevel@tonic-gate 	int i;	/* used to index through the given struct nc_data array */
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	for (i = 0; nc_data[i].string; i++) {
6300Sstevel@tonic-gate 		if (strcmp(nc_data[i].string, cp) == 0) {
6310Sstevel@tonic-gate 			break;
6320Sstevel@tonic-gate 		}
6330Sstevel@tonic-gate 	}
6340Sstevel@tonic-gate 	return (nc_data[i].value);
6350Sstevel@tonic-gate }
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate /*
6380Sstevel@tonic-gate  *	getflag() creates a bitmap of the one-character flags in
6390Sstevel@tonic-gate  *	the given string.  It uses nc_flags array to get the values.
6400Sstevel@tonic-gate  */
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate static unsigned int
643*132Srobinson getflag(char *cp)
6440Sstevel@tonic-gate {
6450Sstevel@tonic-gate 	int i;			/* indexs through the nc_flag array */
6460Sstevel@tonic-gate 	unsigned int mask = 0; /* holds bitmask of flags */
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	while (*cp) {
6490Sstevel@tonic-gate 		for (i = 0; nc_flag[i].string; i++) {
6500Sstevel@tonic-gate 			if (*nc_flag[i].string == *cp) {
6510Sstevel@tonic-gate 				mask |= nc_flag[i].value;
6520Sstevel@tonic-gate 				break;
6530Sstevel@tonic-gate 			}
6540Sstevel@tonic-gate 		}
6550Sstevel@tonic-gate 		cp++;
6560Sstevel@tonic-gate 	}
6570Sstevel@tonic-gate 	return (mask);
6580Sstevel@tonic-gate }
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate /*
6610Sstevel@tonic-gate  *	getlookups() creates and returns an array of string representing
6620Sstevel@tonic-gate  *	the directory lookup libraries, given as a comma-seperated list
6630Sstevel@tonic-gate  *	in the argument "cp".
6640Sstevel@tonic-gate  */
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate static char **
667*132Srobinson getlookups(char *cp)
6680Sstevel@tonic-gate {
6690Sstevel@tonic-gate 	unsigned int num;	/* holds the number of entries in the list   */
6700Sstevel@tonic-gate 	char **listpp;		/* the beginning of the list of dir routines */
6710Sstevel@tonic-gate 	char **tpp;		/* traverses the list, populating it */
6720Sstevel@tonic-gate 	char *start;
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	num = getnlookups(cp);
675*132Srobinson 	if (num == 0)
6760Sstevel@tonic-gate 		return (NULL);
677*132Srobinson 	if ((listpp = malloc((num + 1) * sizeof (char *))) == NULL)
6780Sstevel@tonic-gate 		return (NULL);
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 	tpp = listpp;
6810Sstevel@tonic-gate 	while (num--) {
6820Sstevel@tonic-gate 		start  = cp;
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 		/*
6850Sstevel@tonic-gate 		 *	Traverse the string looking for the next entry
6860Sstevel@tonic-gate 		 *	of the list (i.e, where the ',' or end of the
6870Sstevel@tonic-gate 		 *	string appears).  If a "\" is found, shift the
6880Sstevel@tonic-gate 		 *	token over 1 to the left (taking the next char
6890Sstevel@tonic-gate 		 *	literally).
6900Sstevel@tonic-gate 		 */
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 		while (*cp && *cp != ',') {
6930Sstevel@tonic-gate 			if (*cp == '\\' && *(cp + 1)) {
6940Sstevel@tonic-gate 				shift1left(cp);
6950Sstevel@tonic-gate 			}
6960Sstevel@tonic-gate 			cp++;
6970Sstevel@tonic-gate 		}
6980Sstevel@tonic-gate 		if (*cp)
6990Sstevel@tonic-gate 			*cp++ = '\0';
7000Sstevel@tonic-gate 		if ((*tpp++ = strdup(start)) == NULL) {
7010Sstevel@tonic-gate 			for (tpp = listpp; *tpp; tpp++)
7020Sstevel@tonic-gate 				free(*tpp);
7030Sstevel@tonic-gate 			free(listpp);
7040Sstevel@tonic-gate 			return (NULL);
7050Sstevel@tonic-gate 		}
7060Sstevel@tonic-gate 	}
7070Sstevel@tonic-gate 	*tpp = NULL;
7080Sstevel@tonic-gate 	return (listpp);
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate /*
7120Sstevel@tonic-gate  *	getnlookups() returns the number of entries in a comma-separated
7130Sstevel@tonic-gate  *	string of tokens.  A "-" means no strings are present.
7140Sstevel@tonic-gate  */
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate static unsigned int
717*132Srobinson getnlookups(char *cp)
7180Sstevel@tonic-gate {
7190Sstevel@tonic-gate 	unsigned int count;	/* the number of tokens in the string */
7200Sstevel@tonic-gate 
721*132Srobinson 	if (strcmp(cp, "-") == 0)
7220Sstevel@tonic-gate 		return (0);
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	count = 1;
7250Sstevel@tonic-gate 	while (*cp) {
7260Sstevel@tonic-gate 		if (*cp == ',') {
7270Sstevel@tonic-gate 			count++;
7280Sstevel@tonic-gate 		}
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 		/*
7310Sstevel@tonic-gate 		 *	If a "\" is in the string, take the next character
7320Sstevel@tonic-gate 		 *	literally.  Onlly skip the character if "\" is
7330Sstevel@tonic-gate 		 *	not the last character of the token.
7340Sstevel@tonic-gate 		 */
7350Sstevel@tonic-gate 		if (*cp == '\\' && *(cp + 1)) {
7360Sstevel@tonic-gate 			cp++;
7370Sstevel@tonic-gate 		}
7380Sstevel@tonic-gate 		cp++;
7390Sstevel@tonic-gate 	}
7400Sstevel@tonic-gate 	return (count);
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate /*
7440Sstevel@tonic-gate  *	gettoken() behaves much like strtok(), except that
7450Sstevel@tonic-gate  *	it knows about escaped space characters (i.e., space characters
7460Sstevel@tonic-gate  *	preceeded by a '\' are taken literally).
7470Sstevel@tonic-gate  */
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate static char *
750*132Srobinson gettoken(char *cp, int skip)
7510Sstevel@tonic-gate {
7520Sstevel@tonic-gate 	static char	*savep;	/* the place where we left off    */
7530Sstevel@tonic-gate 	char	*p;		/* the beginning of the new token */
7540Sstevel@tonic-gate 	char	*retp;		/* the token to be returned	  */
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	fieldnum++;
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 	/* Determine if first or subsequent call  */
7590Sstevel@tonic-gate 	p = (cp == NULL)? savep: cp;
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	/* Return if no tokens remain.  */
762*132Srobinson 	if (p == 0)
7630Sstevel@tonic-gate 		return (NULL);
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	while (isspace(*p))
7660Sstevel@tonic-gate 		p++;
7670Sstevel@tonic-gate 
768*132Srobinson 	if (*p == '\0')
7690Sstevel@tonic-gate 		return (NULL);
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	/*
7720Sstevel@tonic-gate 	 *	Save the location of the token and then skip past it
7730Sstevel@tonic-gate 	 */
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	retp = p;
7760Sstevel@tonic-gate 	while (*p) {
7770Sstevel@tonic-gate 		if (isspace(*p))
7780Sstevel@tonic-gate 			if (skip == TRUE) {
7790Sstevel@tonic-gate 				shift1left(p);
7800Sstevel@tonic-gate 				continue;
7810Sstevel@tonic-gate 			} else
7820Sstevel@tonic-gate 				break;
7830Sstevel@tonic-gate 		/*
7840Sstevel@tonic-gate 		 *	Only process the escape of the space seperator;
7850Sstevel@tonic-gate 		 *	since the token may contain other separators,
7860Sstevel@tonic-gate 		 *	let the other routines handle the escape of
7870Sstevel@tonic-gate 		 *	specific characters in the token.
7880Sstevel@tonic-gate 		 */
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 		if (*p == '\\' && *(p + 1) != '\n' && isspace(*(p + 1))) {
7910Sstevel@tonic-gate 			shift1left(p);
7920Sstevel@tonic-gate 		}
7930Sstevel@tonic-gate 		p++;
7940Sstevel@tonic-gate 	}
7950Sstevel@tonic-gate 	if (*p == '\0') {
7960Sstevel@tonic-gate 		savep = 0;	/* indicate this is last token */
7970Sstevel@tonic-gate 	} else {
7980Sstevel@tonic-gate 		*p = '\0';
7990Sstevel@tonic-gate 		savep = ++p;
8000Sstevel@tonic-gate 	}
8010Sstevel@tonic-gate 	return (strdup(retp));
8020Sstevel@tonic-gate }
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate /*
8050Sstevel@tonic-gate  *	shift1left() moves all characters in the string over 1 to
8060Sstevel@tonic-gate  *	the left.
8070Sstevel@tonic-gate  */
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate static void
810*132Srobinson shift1left(char *p)
8110Sstevel@tonic-gate {
8120Sstevel@tonic-gate 	for (; *p; p++)
8130Sstevel@tonic-gate 		*p = *(p + 1);
8140Sstevel@tonic-gate }
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate char *
817*132Srobinson nc_sperror(void)
8180Sstevel@tonic-gate {
8190Sstevel@tonic-gate 	static char buf_main[BUFSIZ];
8200Sstevel@tonic-gate 	static pthread_key_t perror_key;
8210Sstevel@tonic-gate 	char *retstr = thr_main()?
8220Sstevel@tonic-gate 		buf_main :
8230Sstevel@tonic-gate 		thr_get_storage(&perror_key, BUFSIZ, free);
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 	if (retstr == NULL) {
8260Sstevel@tonic-gate 		syslog(LOG_WARNING,
8270Sstevel@tonic-gate 		"nc_sperror: malloc failed when trying to create buffer\n");
8280Sstevel@tonic-gate 		return (NULL);
8290Sstevel@tonic-gate 	}
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	switch (nc_error) {
8320Sstevel@tonic-gate 	case NC_NOERROR:
8330Sstevel@tonic-gate 		(void) strlcpy(retstr, dgettext(__nsl_dom, "no error"), BUFSIZ);
8340Sstevel@tonic-gate 		break;
8350Sstevel@tonic-gate 	case NC_NOMEM:
8360Sstevel@tonic-gate 		(void) strlcpy(retstr, dgettext(__nsl_dom, "out of memory"),
8370Sstevel@tonic-gate 		    BUFSIZ);
8380Sstevel@tonic-gate 		break;
8390Sstevel@tonic-gate 	case NC_NOSET:
8400Sstevel@tonic-gate 		(void) strlcpy(retstr, dgettext(__nsl_dom,
8410Sstevel@tonic-gate 		    "routine called before calling \
8420Sstevel@tonic-gate 		    setnetpath() or setnetconfig()"), BUFSIZ);
8430Sstevel@tonic-gate 		break;
8440Sstevel@tonic-gate 	case NC_OPENFAIL:
8450Sstevel@tonic-gate 		(void) strlcpy(retstr,
8460Sstevel@tonic-gate 			dgettext(__nsl_dom, "cannot open /etc/netconfig"),
8470Sstevel@tonic-gate 			BUFSIZ);
8480Sstevel@tonic-gate 		break;
8490Sstevel@tonic-gate 	case NC_BADLINE:
8500Sstevel@tonic-gate 		(void) snprintf(retstr, BUFSIZ, dgettext(__nsl_dom,
8510Sstevel@tonic-gate 			"error in /etc/netconfig: field %d of line %d\n"),
8520Sstevel@tonic-gate 				fieldnum, linenum);
8530Sstevel@tonic-gate 		break;
8540Sstevel@tonic-gate 	case NC_NOTFOUND:
8550Sstevel@tonic-gate 		(void) snprintf(retstr, BUFSIZ,
8560Sstevel@tonic-gate 			dgettext(__nsl_dom,
8570Sstevel@tonic-gate 				"netid not found in /etc/netconfig"));
8580Sstevel@tonic-gate 		break;
8590Sstevel@tonic-gate 	case NC_NOMOREENTRIES:
8600Sstevel@tonic-gate 		(void) snprintf(retstr, BUFSIZ,
8610Sstevel@tonic-gate 			dgettext(__nsl_dom,
8620Sstevel@tonic-gate 				"no more entries in /etc/netconfig"));
8630Sstevel@tonic-gate 		break;
8640Sstevel@tonic-gate 	default:
8650Sstevel@tonic-gate 		(void) strlcpy(retstr, dgettext(__nsl_dom, "unknown error"),
8660Sstevel@tonic-gate 		    BUFSIZ);
8670Sstevel@tonic-gate 		break;
8680Sstevel@tonic-gate 	}
8690Sstevel@tonic-gate 	return (retstr);
8700Sstevel@tonic-gate }
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate void
8730Sstevel@tonic-gate nc_perror(const char *string)
8740Sstevel@tonic-gate {
8750Sstevel@tonic-gate 	if (string)
876*132Srobinson 		(void) fprintf(stderr, "%s: %s\n", string, nc_sperror());
8770Sstevel@tonic-gate 	else
878*132Srobinson 		(void) fprintf(stderr, "%s\n", nc_sperror());
8790Sstevel@tonic-gate }
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate static void
882*132Srobinson netlist_free(struct netconfig ***netppp)
8830Sstevel@tonic-gate {
8840Sstevel@tonic-gate 	struct netconfig **tpp;
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 	for (tpp = *netppp; *tpp; tpp++) {
8870Sstevel@tonic-gate 		netconfig_free(*tpp);
8880Sstevel@tonic-gate 	}
8890Sstevel@tonic-gate 	free(*netppp);
8900Sstevel@tonic-gate 	*netppp = NULL;
8910Sstevel@tonic-gate }
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate static void
894*132Srobinson netconfig_free(struct netconfig *netconfigp)
8950Sstevel@tonic-gate {
8960Sstevel@tonic-gate 	int i;
8970Sstevel@tonic-gate 
898*132Srobinson 	if (netconfigp == NULL)
8990Sstevel@tonic-gate 		return;
9000Sstevel@tonic-gate 	free_entry(netconfigp->nc_netid);
9010Sstevel@tonic-gate 	free_entry(netconfigp->nc_protofmly);
9020Sstevel@tonic-gate 	free_entry(netconfigp->nc_proto);
9030Sstevel@tonic-gate 	free_entry(netconfigp->nc_device);
9040Sstevel@tonic-gate 	if (netconfigp->nc_lookups)
9050Sstevel@tonic-gate 		for (i = 0; i < netconfigp->nc_nlookups; i++)
9060Sstevel@tonic-gate 			free_entry(netconfigp->nc_lookups[i]);
9070Sstevel@tonic-gate 	free_entry(netconfigp->nc_lookups);
9080Sstevel@tonic-gate 	free(netconfigp);
9090Sstevel@tonic-gate }
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate static struct netconfig *
912*132Srobinson netconfig_dup(struct netconfig *netconfigp)
9130Sstevel@tonic-gate {
9140Sstevel@tonic-gate 	struct netconfig *nconf;
9150Sstevel@tonic-gate 	int i;
9160Sstevel@tonic-gate 
917*132Srobinson 	nconf = calloc(1, sizeof (struct netconfig));
9180Sstevel@tonic-gate 	if (nconf == NULL) {
9190Sstevel@tonic-gate 		nc_error = NC_NOMEM;
9200Sstevel@tonic-gate 		return (NULL);
9210Sstevel@tonic-gate 	}
9220Sstevel@tonic-gate 	nconf->nc_netid = strdup(netconfigp->nc_netid);
9230Sstevel@tonic-gate 	nconf->nc_protofmly = strdup(netconfigp->nc_protofmly);
9240Sstevel@tonic-gate 	nconf->nc_proto = strdup(netconfigp->nc_proto);
9250Sstevel@tonic-gate 	nconf->nc_device = strdup(netconfigp->nc_device);
926*132Srobinson 	nconf->nc_lookups = malloc((netconfigp->nc_nlookups + 1)
9270Sstevel@tonic-gate 					* sizeof (char *));
9280Sstevel@tonic-gate 	if (!(nconf->nc_lookups && nconf->nc_netid &&
9290Sstevel@tonic-gate 		nconf->nc_protofmly && nconf->nc_proto &&
9300Sstevel@tonic-gate 		nconf->nc_device)) {
9310Sstevel@tonic-gate 		nc_error = NC_NOMEM;
9320Sstevel@tonic-gate 		netconfig_free(nconf);
9330Sstevel@tonic-gate 		return (NULL);
9340Sstevel@tonic-gate 	}
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	for (i = 0; i < netconfigp->nc_nlookups; i++) {
9370Sstevel@tonic-gate 		nconf->nc_lookups[i] = strdup(netconfigp->nc_lookups[i]);
9380Sstevel@tonic-gate 		if (nconf->nc_lookups[i] == NULL) {
9390Sstevel@tonic-gate 			nconf->nc_nlookups = i;
9400Sstevel@tonic-gate 			netconfig_free(nconf);
9410Sstevel@tonic-gate 			nc_error = NC_NOMEM;
9420Sstevel@tonic-gate 			return (NULL);
9430Sstevel@tonic-gate 		}
9440Sstevel@tonic-gate 	}
9450Sstevel@tonic-gate 	nconf->nc_lookups[i] = NULL;
9460Sstevel@tonic-gate 	nconf->nc_nlookups = netconfigp->nc_nlookups;
9470Sstevel@tonic-gate 	nconf->nc_flag = netconfigp->nc_flag;
9480Sstevel@tonic-gate 	nconf->nc_semantics = netconfigp->nc_semantics;
9490Sstevel@tonic-gate 	return (nconf);
9500Sstevel@tonic-gate }
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate static void
953*132Srobinson free_entry(void *foo)
9540Sstevel@tonic-gate {
9550Sstevel@tonic-gate 	if (foo)
9560Sstevel@tonic-gate 		free(foo);
9570Sstevel@tonic-gate }
958