xref: /netbsd-src/lib/libc/rpc/getnetconfig.c (revision b48a2efd04e7ab0174e5814a3bdb3bdff58ecc29)
1*b48a2efdSchristos /*	$NetBSD: getnetconfig.c,v 1.25 2017/06/30 10:03:34 christos Exp $	*/
27df0ccbaSfvdl 
37df0ccbaSfvdl /*
447c0e0c3Stron  * Copyright (c) 2010, Oracle America, Inc.
57df0ccbaSfvdl  *
647c0e0c3Stron  * Redistribution and use in source and binary forms, with or without
747c0e0c3Stron  * modification, are permitted provided that the following conditions are
847c0e0c3Stron  * met:
97df0ccbaSfvdl  *
1047c0e0c3Stron  *     * Redistributions of source code must retain the above copyright
1147c0e0c3Stron  *       notice, this list of conditions and the following disclaimer.
1247c0e0c3Stron  *     * Redistributions in binary form must reproduce the above
1347c0e0c3Stron  *       copyright notice, this list of conditions and the following
1447c0e0c3Stron  *       disclaimer in the documentation and/or other materials
1547c0e0c3Stron  *       provided with the distribution.
1647c0e0c3Stron  *     * Neither the name of the "Oracle America, Inc." nor the names of its
1747c0e0c3Stron  *       contributors may be used to endorse or promote products derived
1847c0e0c3Stron  *       from this software without specific prior written permission.
197df0ccbaSfvdl  *
2047c0e0c3Stron  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2147c0e0c3Stron  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2247c0e0c3Stron  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2347c0e0c3Stron  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2447c0e0c3Stron  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
2547c0e0c3Stron  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2647c0e0c3Stron  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2747c0e0c3Stron  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2847c0e0c3Stron  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2947c0e0c3Stron  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3047c0e0c3Stron  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3147c0e0c3Stron  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
327df0ccbaSfvdl  */
335c945215Sitojun 
345c945215Sitojun #include <sys/cdefs.h>
355c945215Sitojun #if defined(LIBC_SCCS) && !defined(lint)
365c945215Sitojun #if 0
377df0ccbaSfvdl static        char sccsid[] = "@(#)getnetconfig.c	1.12 91/12/19 SMI";
385c945215Sitojun #else
39*b48a2efdSchristos __RCSID("$NetBSD: getnetconfig.c,v 1.25 2017/06/30 10:03:34 christos Exp $");
407df0ccbaSfvdl #endif
415c945215Sitojun #endif
427df0ccbaSfvdl 
437df0ccbaSfvdl /*
447df0ccbaSfvdl  * Copyright (c) 1989 by Sun Microsystems, Inc.
457df0ccbaSfvdl  */
467df0ccbaSfvdl 
477df0ccbaSfvdl #include "namespace.h"
483fdac2b8Sthorpej #include "reentrant.h"
497df0ccbaSfvdl #include <stdio.h>
500e8cfd8fSlukem #include <assert.h>
517df0ccbaSfvdl #include <errno.h>
527df0ccbaSfvdl #include <netconfig.h>
53045cceecSthorpej #include <stddef.h>
547df0ccbaSfvdl #include <stdlib.h>
557df0ccbaSfvdl #include <string.h>
56deb154d2Schristos #include <rpc/rpc.h>
5779d5b270Sfvdl #include "rpc_internal.h"
587df0ccbaSfvdl 
597df0ccbaSfvdl #ifdef __weak_alias
607df0ccbaSfvdl __weak_alias(getnetconfig,_getnetconfig)
617df0ccbaSfvdl __weak_alias(setnetconfig,_setnetconfig)
627df0ccbaSfvdl __weak_alias(endnetconfig,_endnetconfig)
637df0ccbaSfvdl __weak_alias(getnetconfigent,_getnetconfigent)
647df0ccbaSfvdl __weak_alias(freenetconfigent,_freenetconfigent)
657df0ccbaSfvdl __weak_alias(nc_perror,_nc_perror)
667df0ccbaSfvdl __weak_alias(nc_sperror,_nc_sperror)
677df0ccbaSfvdl #endif
687df0ccbaSfvdl 
697df0ccbaSfvdl /*
707df0ccbaSfvdl  * The five library routines in this file provide application access to the
717df0ccbaSfvdl  * system network configuration database, /etc/netconfig.  In addition to the
727df0ccbaSfvdl  * netconfig database and the routines for accessing it, the environment
737df0ccbaSfvdl  * variable NETPATH and its corresponding routines in getnetpath.c may also be
747df0ccbaSfvdl  * used to specify the network transport to be used.
757df0ccbaSfvdl  */
767df0ccbaSfvdl 
777df0ccbaSfvdl 
787df0ccbaSfvdl /*
797df0ccbaSfvdl  * netconfig errors
807df0ccbaSfvdl  */
817df0ccbaSfvdl 
827df0ccbaSfvdl #define NC_NONETCONFIG	ENOENT
837df0ccbaSfvdl #define NC_NOMEM	ENOMEM
847df0ccbaSfvdl #define NC_NOTINIT	EINVAL	    /* setnetconfig was not called first */
857df0ccbaSfvdl #define NC_BADFILE	EBADF	    /* format for netconfig file is bad */
867df0ccbaSfvdl 
877df0ccbaSfvdl /*
887df0ccbaSfvdl  * semantics as strings (should be in netconfig.h)
897df0ccbaSfvdl  */
907df0ccbaSfvdl #define NC_TPI_CLTS_S	    "tpi_clts"
917df0ccbaSfvdl #define	NC_TPI_COTS_S	    "tpi_cots"
927df0ccbaSfvdl #define	NC_TPI_COTS_ORD_S   "tpi_cots_ord"
937df0ccbaSfvdl #define	NC_TPI_RAW_S        "tpi_raw"
947df0ccbaSfvdl 
957df0ccbaSfvdl /*
967df0ccbaSfvdl  * flags as characters (also should be in netconfig.h)
977df0ccbaSfvdl  */
987df0ccbaSfvdl #define	NC_NOFLAG_C	'-'
997df0ccbaSfvdl #define	NC_VISIBLE_C	'v'
1007df0ccbaSfvdl #define	NC_BROADCAST_C	'b'
1017df0ccbaSfvdl 
1027df0ccbaSfvdl /*
1037df0ccbaSfvdl  * Character used to indicate there is no name-to-address lookup library
1047df0ccbaSfvdl  */
1057df0ccbaSfvdl #define NC_NOLOOKUP	"-"
1067df0ccbaSfvdl 
107ca797c3cSjdolecek static const char * const _nc_errors[] = {
1087df0ccbaSfvdl 	"Netconfig database not found",
1097df0ccbaSfvdl 	"Not enough memory",
1107df0ccbaSfvdl 	"Not initialized",
1117df0ccbaSfvdl 	"Netconfig database has invalid format"
1127df0ccbaSfvdl };
1137df0ccbaSfvdl 
1147df0ccbaSfvdl struct netconfig_info {
1157df0ccbaSfvdl 	int		eof;	/* all entries has been read */
1167df0ccbaSfvdl 	int		ref;	/* # of times setnetconfig() has been called */
1177df0ccbaSfvdl 	struct netconfig_list	*head;	/* head of the list */
1187df0ccbaSfvdl 	struct netconfig_list	*tail;	/* last of the list */
1197df0ccbaSfvdl };
1207df0ccbaSfvdl 
1217df0ccbaSfvdl struct netconfig_list {
1227df0ccbaSfvdl 	char			*linep;	/* hold line read from netconfig */
1237df0ccbaSfvdl 	struct netconfig	*ncp;
1247df0ccbaSfvdl 	struct netconfig_list	*next;
1257df0ccbaSfvdl };
1267df0ccbaSfvdl 
1277df0ccbaSfvdl struct netconfig_vars {
1280d2d9accSlukem 	    int   valid;	/* token that indicates valid netconfig_vars */
1297df0ccbaSfvdl 	    int   flag;		/* first time flag */
1300d2d9accSlukem 	    struct netconfig_list *nc_configs;
1310d2d9accSlukem 	   			 /* pointer to the current netconfig entry */
1327df0ccbaSfvdl };
1337df0ccbaSfvdl 
1347df0ccbaSfvdl #define NC_VALID	0xfeed
1357df0ccbaSfvdl #define NC_STORAGE	0xf00d
1367df0ccbaSfvdl #define NC_INVALID	0
1377df0ccbaSfvdl 
1387df0ccbaSfvdl 
139adb74221Smatt static int *__nc_error(void);
140adb74221Smatt static int parse_ncp(char *, struct netconfig *);
141adb74221Smatt static struct netconfig *dup_ncp(struct netconfig *);
1427df0ccbaSfvdl 
1437df0ccbaSfvdl 
1447df0ccbaSfvdl static FILE *nc_file;		/* for netconfig db */
1457df0ccbaSfvdl static struct netconfig_info	ni = { 0, 0, NULL, NULL};
1467df0ccbaSfvdl 
1477df0ccbaSfvdl #define MAXNETCONFIGLINE    1000
1487df0ccbaSfvdl 
1493fdac2b8Sthorpej #ifdef _REENTRANT
1503fdac2b8Sthorpej static thread_key_t nc_key;
1513fdac2b8Sthorpej static once_t nc_once = ONCE_INITIALIZER;
1523fdac2b8Sthorpej 
1533fdac2b8Sthorpej static void
__nc_error_setup(void)1543fdac2b8Sthorpej __nc_error_setup(void)
1553fdac2b8Sthorpej {
1563fdac2b8Sthorpej 	thr_keycreate(&nc_key, free);
1573fdac2b8Sthorpej }
1583fdac2b8Sthorpej #endif
1593fdac2b8Sthorpej 
1607df0ccbaSfvdl static int *
__nc_error(void)161adb74221Smatt __nc_error(void)
1627df0ccbaSfvdl {
1633fdac2b8Sthorpej #ifdef _REENTRANT
1647df0ccbaSfvdl 	int *nc_addr = NULL;
1657df0ccbaSfvdl #endif
1667df0ccbaSfvdl 	static int nc_error = 0;
1677df0ccbaSfvdl 
1683fdac2b8Sthorpej #ifdef _REENTRANT
1693fdac2b8Sthorpej 	if (__isthreaded == 0)
1703fdac2b8Sthorpej 		return &nc_error;
1713fdac2b8Sthorpej 	thr_once(&nc_once, __nc_error_setup);
1723fdac2b8Sthorpej 	nc_addr = thr_getspecific(nc_key) ;
1737df0ccbaSfvdl 	if (nc_addr == NULL) {
174c9cdc302Schristos 		nc_addr = malloc(sizeof (int));
175c9cdc302Schristos 		if (nc_addr == NULL)
176c9cdc302Schristos 			return &nc_error;
1774384a68cSchristos 		if (thr_setspecific(nc_key, nc_addr) != 0) {
1787df0ccbaSfvdl 			if (nc_addr)
1797df0ccbaSfvdl 				free(nc_addr);
1807df0ccbaSfvdl 			return &nc_error;
1817df0ccbaSfvdl 		}
1827df0ccbaSfvdl 		*nc_addr = 0;
1837df0ccbaSfvdl 	}
1847df0ccbaSfvdl 	return nc_addr;
1857df0ccbaSfvdl #else
1867df0ccbaSfvdl 	return &nc_error;
1877df0ccbaSfvdl #endif
1887df0ccbaSfvdl }
1897df0ccbaSfvdl 
1907df0ccbaSfvdl #define nc_error        (*(__nc_error()))
1917df0ccbaSfvdl /*
1927df0ccbaSfvdl  * A call to setnetconfig() establishes a /etc/netconfig "session".  A session
1937df0ccbaSfvdl  * "handle" is returned on a successful call.  At the start of a session (after
1947df0ccbaSfvdl  * a call to setnetconfig()) searches through the /etc/netconfig database will
1957df0ccbaSfvdl  * proceed from the start of the file.  The session handle must be passed to
1967df0ccbaSfvdl  * getnetconfig() to parse the file.  Each call to getnetconfig() using the
1977df0ccbaSfvdl  * current handle will process one subsequent entry in /etc/netconfig.
1987df0ccbaSfvdl  * setnetconfig() must be called before the first call to getnetconfig().
1997df0ccbaSfvdl  * (Handles are used to allow for nested calls to setnetpath()).
2007df0ccbaSfvdl  *
2017df0ccbaSfvdl  * A new session is established with each call to setnetconfig(), with a new
2027df0ccbaSfvdl  * handle being returned on each call.  Previously established sessions remain
2037df0ccbaSfvdl  * active until endnetconfig() is called with that session's handle as an
2047df0ccbaSfvdl  * argument.
2057df0ccbaSfvdl  *
2067df0ccbaSfvdl  * setnetconfig() need *not* be called before a call to getnetconfigent().
2077df0ccbaSfvdl  * setnetconfig() returns a NULL pointer on failure (for example, if
2087df0ccbaSfvdl  * the netconfig database is not present).
2097df0ccbaSfvdl  */
2107df0ccbaSfvdl void *
setnetconfig(void)211adb74221Smatt setnetconfig(void)
2127df0ccbaSfvdl {
2137df0ccbaSfvdl 	struct netconfig_vars *nc_vars;
2147df0ccbaSfvdl 
215c9cdc302Schristos 	if ((nc_vars = malloc(sizeof(*nc_vars))) == NULL) {
2164384a68cSchristos 		return NULL;
2177df0ccbaSfvdl 	}
2187df0ccbaSfvdl 
2197df0ccbaSfvdl 	/*
2207df0ccbaSfvdl 	 * For multiple calls, i.e. nc_file is not NULL, we just return the
2217df0ccbaSfvdl 	 * handle without reopening the netconfig db.
2227df0ccbaSfvdl 	 */
2237df0ccbaSfvdl 	ni.ref++;
2249292cfb2Schristos 	if ((nc_file != NULL) || (nc_file = fopen(NETCONFIG, "re")) != NULL) {
2257df0ccbaSfvdl 		nc_vars->valid = NC_VALID;
2267df0ccbaSfvdl 		nc_vars->flag = 0;
2277df0ccbaSfvdl 		nc_vars->nc_configs = ni.head;
2284384a68cSchristos 		return nc_vars;
2297df0ccbaSfvdl 	}
2307df0ccbaSfvdl 	ni.ref--;
2317df0ccbaSfvdl 	nc_error = NC_NONETCONFIG;
2327df0ccbaSfvdl 	free(nc_vars);
2334384a68cSchristos 	return NULL;
2347df0ccbaSfvdl }
2357df0ccbaSfvdl 
2367df0ccbaSfvdl 
2377df0ccbaSfvdl /*
2387df0ccbaSfvdl  * When first called, getnetconfig() returns a pointer to the first entry in
2397df0ccbaSfvdl  * the netconfig database, formatted as a struct netconfig.  On each subsequent
2407df0ccbaSfvdl  * call, getnetconfig() returns a pointer to the next entry in the database.
2417df0ccbaSfvdl  * getnetconfig() can thus be used to search the entire netconfig file.
2427df0ccbaSfvdl  * getnetconfig() returns NULL at end of file.
2437df0ccbaSfvdl  */
2447df0ccbaSfvdl 
2457df0ccbaSfvdl struct netconfig *
getnetconfig(void * handlep)246adb74221Smatt getnetconfig(void *handlep)
2477df0ccbaSfvdl {
2484384a68cSchristos 	struct netconfig_vars *ncp = handlep;
2497df0ccbaSfvdl 	char *stringp;		/* tmp string pointer */
2507df0ccbaSfvdl 	struct netconfig_list	*list;
2517df0ccbaSfvdl 	struct netconfig *np;
2527df0ccbaSfvdl 
2537df0ccbaSfvdl 	/*
2547df0ccbaSfvdl 	 * Verify that handle is valid
2557df0ccbaSfvdl 	 */
2567df0ccbaSfvdl 	if (ncp == NULL || nc_file == NULL) {
2577df0ccbaSfvdl 		nc_error = NC_NOTINIT;
2584384a68cSchristos 		return NULL;
2597df0ccbaSfvdl 	}
2607df0ccbaSfvdl 
2617df0ccbaSfvdl 	switch (ncp->valid) {
2627df0ccbaSfvdl 	case NC_VALID:
2637df0ccbaSfvdl 		/*
2647df0ccbaSfvdl 		 * If entry has already been read into the list,
2657df0ccbaSfvdl 		 * we return the entry in the linked list.
2660d2d9accSlukem 		 * If this is the first time call, check if there are any
2670d2d9accSlukem 		 * entries in linked list.  If no entries, we need to read the
2680d2d9accSlukem 		 * netconfig db.
2690d2d9accSlukem 		 * If we have been here and the next entry is there, we just
2700d2d9accSlukem 		 * return it.
2717df0ccbaSfvdl 		 */
2727df0ccbaSfvdl 		if (ncp->flag == 0) {	/* first time */
2737df0ccbaSfvdl 			ncp->flag = 1;
2747df0ccbaSfvdl 			ncp->nc_configs = ni.head;
2757df0ccbaSfvdl 			if (ncp->nc_configs != NULL) /* entry already exist */
2764384a68cSchristos 				return ncp->nc_configs->ncp;
2777df0ccbaSfvdl 		}
2780d2d9accSlukem 		else if (ncp->nc_configs != NULL &&
2790d2d9accSlukem 		    ncp->nc_configs->next != NULL) {
2807df0ccbaSfvdl 			ncp->nc_configs = ncp->nc_configs->next;
2814384a68cSchristos 			return ncp->nc_configs->ncp;
2827df0ccbaSfvdl 		}
2837df0ccbaSfvdl 
2847df0ccbaSfvdl 		/*
2857df0ccbaSfvdl 		 * If we cannot find the entry in the list and is end of file,
2867df0ccbaSfvdl 		 * we give up.
2877df0ccbaSfvdl 		 */
2880d2d9accSlukem 		if (ni.eof == 1)
2894384a68cSchristos 			return NULL;
2907df0ccbaSfvdl 		break;
2917df0ccbaSfvdl 	default:
2927df0ccbaSfvdl 		nc_error = NC_NOTINIT;
2934384a68cSchristos 		return NULL;
2947df0ccbaSfvdl 	}
2957df0ccbaSfvdl 
296c9cdc302Schristos 	stringp = malloc(MAXNETCONFIGLINE);
2977df0ccbaSfvdl 	if (stringp == NULL)
2984384a68cSchristos 		return NULL;
2997df0ccbaSfvdl 
3007df0ccbaSfvdl #ifdef MEM_CHK
3017df0ccbaSfvdl 	if (malloc_verify() == 0) {
3027df0ccbaSfvdl 		fprintf(stderr, "memory heap corrupted in getnetconfig\n");
3037df0ccbaSfvdl 		exit(1);
3047df0ccbaSfvdl 	}
3057df0ccbaSfvdl #endif
3067df0ccbaSfvdl 
3077df0ccbaSfvdl 	/*
3087df0ccbaSfvdl 	 * Read a line from netconfig file.
3097df0ccbaSfvdl 	 */
3107df0ccbaSfvdl 	do {
3117df0ccbaSfvdl 		if (fgets(stringp, MAXNETCONFIGLINE, nc_file) == NULL) {
3127df0ccbaSfvdl 			free(stringp);
3137df0ccbaSfvdl 			ni.eof = 1;
3144384a68cSchristos 			return NULL;
3157df0ccbaSfvdl 		}
3167df0ccbaSfvdl 	} while (*stringp == '#');
3177df0ccbaSfvdl 
318c9cdc302Schristos 	list = malloc(sizeof(*list));
3197df0ccbaSfvdl 	if (list == NULL) {
3207df0ccbaSfvdl 		free(stringp);
3214384a68cSchristos 		return NULL;
3227df0ccbaSfvdl 	}
323c9cdc302Schristos 	np = malloc(sizeof(*np));
3247df0ccbaSfvdl 	if (np == NULL) {
3257df0ccbaSfvdl 		free(stringp);
3267df0ccbaSfvdl 		free(list);
3274384a68cSchristos 		return NULL;
3287df0ccbaSfvdl 	}
3297df0ccbaSfvdl 	list->ncp = np;
3307df0ccbaSfvdl 	list->next = NULL;
3317df0ccbaSfvdl 	list->ncp->nc_lookups = NULL;
3327df0ccbaSfvdl 	list->linep = stringp;
3337df0ccbaSfvdl 	if (parse_ncp(stringp, list->ncp) == -1) {
3347df0ccbaSfvdl 		free(stringp);
3357df0ccbaSfvdl 		free(np);
3367df0ccbaSfvdl 		free(list);
3374384a68cSchristos 		return NULL;
3380d2d9accSlukem 	} else {
3397df0ccbaSfvdl 		/*
3400d2d9accSlukem 		 * If this is the first entry that's been read, it is the
3410d2d9accSlukem 		 * head of the list.  If not, put the entry at the end of
3420d2d9accSlukem 		 * the list.  Reposition the current pointer of the handle to
3430d2d9accSlukem 		 * the last entry in the list.
3447df0ccbaSfvdl 		 */
3450d2d9accSlukem 		if (ni.head == NULL)		/* first entry */
3467df0ccbaSfvdl 			ni.head = ni.tail = list;
3477df0ccbaSfvdl 		else {
3487df0ccbaSfvdl 			ni.tail->next = list;
3497df0ccbaSfvdl 			ni.tail = ni.tail->next;
3507df0ccbaSfvdl 		}
3517df0ccbaSfvdl 		ncp->nc_configs = ni.tail;
3524384a68cSchristos 		return ni.tail->ncp;
3537df0ccbaSfvdl 	}
3547df0ccbaSfvdl }
3557df0ccbaSfvdl 
3567df0ccbaSfvdl /*
3577df0ccbaSfvdl  * endnetconfig() may be called to "unbind" or "close" the netconfig database
3587df0ccbaSfvdl  * when processing is complete, releasing resources for reuse.  endnetconfig()
3597df0ccbaSfvdl  * may not be called before setnetconfig().  endnetconfig() returns 0 on
3607df0ccbaSfvdl  * success and -1 on failure (for example, if setnetconfig() was not called
3617df0ccbaSfvdl  * previously).
3627df0ccbaSfvdl  */
3637df0ccbaSfvdl int
endnetconfig(void * handlep)364adb74221Smatt endnetconfig(void *handlep)
3657df0ccbaSfvdl {
3664384a68cSchristos 	struct netconfig_vars *nc_handlep = handlep;
3677df0ccbaSfvdl 
3687df0ccbaSfvdl 	struct netconfig_list *q, *p;
3697df0ccbaSfvdl 
3707df0ccbaSfvdl 	/*
3717df0ccbaSfvdl 	 * Verify that handle is valid
3727df0ccbaSfvdl 	 */
3737df0ccbaSfvdl 	if (nc_handlep == NULL || (nc_handlep->valid != NC_VALID &&
3747df0ccbaSfvdl 	    nc_handlep->valid != NC_STORAGE)) {
3757df0ccbaSfvdl 		nc_error = NC_NOTINIT;
3764384a68cSchristos 		return -1;
3777df0ccbaSfvdl 	}
3787df0ccbaSfvdl 
3797df0ccbaSfvdl 	/*
3807df0ccbaSfvdl 	 * Return 0 if anyone still needs it.
3817df0ccbaSfvdl 	 */
3827df0ccbaSfvdl 	nc_handlep->valid = NC_INVALID;
3837df0ccbaSfvdl 	nc_handlep->flag = 0;
3847df0ccbaSfvdl 	nc_handlep->nc_configs = NULL;
3857df0ccbaSfvdl 	if (--ni.ref > 0) {
3867df0ccbaSfvdl 		free(nc_handlep);
3874384a68cSchristos 		return 0;
3887df0ccbaSfvdl 	}
3897df0ccbaSfvdl 
3907df0ccbaSfvdl 	/*
3917df0ccbaSfvdl 	 * Noone needs these entries anymore, then frees them.
3920d2d9accSlukem 	 * Make sure all info in netconfig_info structure has been
3930d2d9accSlukem 	 * reinitialized.
3947df0ccbaSfvdl 	 */
3957df0ccbaSfvdl 	q = p = ni.head;
3967df0ccbaSfvdl 	ni.eof = ni.ref = 0;
3977df0ccbaSfvdl 	ni.head = NULL;
3987df0ccbaSfvdl 	ni.tail = NULL;
3997df0ccbaSfvdl 	while (q) {
4007df0ccbaSfvdl 		p = q->next;
4017df0ccbaSfvdl 		if (q->ncp->nc_lookups != NULL) free(q->ncp->nc_lookups);
4027df0ccbaSfvdl 		free(q->ncp);
4037df0ccbaSfvdl 		free(q->linep);
4047df0ccbaSfvdl 		free(q);
4057df0ccbaSfvdl 		q = p;
4067df0ccbaSfvdl 	}
4077df0ccbaSfvdl 	free(nc_handlep);
4087df0ccbaSfvdl 
4097df0ccbaSfvdl 	fclose(nc_file);
4107df0ccbaSfvdl 	nc_file = NULL;
4114384a68cSchristos 	return 0;
4127df0ccbaSfvdl }
4137df0ccbaSfvdl 
4147df0ccbaSfvdl /*
4157df0ccbaSfvdl  * getnetconfigent(netid) returns a pointer to the struct netconfig structure
4167df0ccbaSfvdl  * corresponding to netid.  It returns NULL if netid is invalid (that is, does
4177df0ccbaSfvdl  * not name an entry in the netconfig database).  It returns NULL and sets
4187df0ccbaSfvdl  * errno in case of failure (for example, if the netconfig database cannot be
4197df0ccbaSfvdl  * opened).
4207df0ccbaSfvdl  */
4217df0ccbaSfvdl 
4227df0ccbaSfvdl struct netconfig *
getnetconfigent(const char * netid)423adb74221Smatt getnetconfigent(const char *netid)
4247df0ccbaSfvdl {
4257df0ccbaSfvdl 	FILE *file;			/* NETCONFIG db's file pointer */
4267df0ccbaSfvdl 	char *linep;			/* holds current netconfig line */
4277df0ccbaSfvdl 	char *stringp;			/* temporary string pointer */
4287df0ccbaSfvdl 	struct netconfig *ncp = NULL;   /* returned value */
4297df0ccbaSfvdl 	struct netconfig_list *list;	/* pointer to cache list */
4307df0ccbaSfvdl 
4310d2d9accSlukem 	if (netid == NULL || strlen(netid) == 0)
4324384a68cSchristos 		return NULL;
4337df0ccbaSfvdl 
4347df0ccbaSfvdl 	/*
4357df0ccbaSfvdl 	 * Look up table if the entries have already been read and parsed in
4367df0ccbaSfvdl 	 * getnetconfig(), then copy this entry into a buffer and return it.
4377df0ccbaSfvdl 	 * If we cannot find the entry in the current list and there are more
4387df0ccbaSfvdl 	 * entries in the netconfig db that has not been read, we then read the
4397df0ccbaSfvdl 	 * db and try find the match netid.
4407df0ccbaSfvdl 	 * If all the netconfig db has been read and placed into the list and
4417df0ccbaSfvdl 	 * there is no match for the netid, return NULL.
4427df0ccbaSfvdl 	 */
4437df0ccbaSfvdl 	if (ni.head != NULL) {
4447df0ccbaSfvdl 		for (list = ni.head; list; list = list->next) {
4450d2d9accSlukem 			if (strcmp(list->ncp->nc_netid, netid) == 0)
4464384a68cSchristos 				return dup_ncp(list->ncp);
4477df0ccbaSfvdl 		}
4487df0ccbaSfvdl 		if (ni.eof == 1)	/* that's all the entries */
4494384a68cSchristos 			return NULL;
4507df0ccbaSfvdl 	}
4517df0ccbaSfvdl 
4529a513d96Schristos 	if ((file = fopen(NETCONFIG, "re")) == NULL)
4534384a68cSchristos 	    return NULL;
4547df0ccbaSfvdl 
4557df0ccbaSfvdl 	if ((linep = malloc(MAXNETCONFIGLINE)) == NULL) {
4567df0ccbaSfvdl 		fclose(file);
4574384a68cSchristos 		return NULL;
4587df0ccbaSfvdl 	}
4597df0ccbaSfvdl 	do {
4604384a68cSchristos 		size_t len;
4617df0ccbaSfvdl 		char *tmpp;	/* tmp string pointer */
4627df0ccbaSfvdl 
4637df0ccbaSfvdl 		do {
4640d2d9accSlukem 			if ((stringp = fgets(linep, MAXNETCONFIGLINE, file))
4650d2d9accSlukem 			    == NULL)
4667df0ccbaSfvdl 				break;
4677df0ccbaSfvdl 		} while (*stringp == '#');
4680d2d9accSlukem 		if (stringp == NULL)	/* eof */
4697df0ccbaSfvdl 			break;
4700d2d9accSlukem 		if ((tmpp = strpbrk(stringp, "\t ")) == NULL) {
4710d2d9accSlukem 					/* can't parse file */
4727df0ccbaSfvdl 			nc_error = NC_BADFILE;
4737df0ccbaSfvdl 			break;
4747df0ccbaSfvdl 		}
4754384a68cSchristos 		if (strlen(netid) == (len = (size_t)(tmpp - stringp)) &&
4764384a68cSchristos 		    strncmp(stringp, netid, len) == 0) {
4774384a68cSchristos 		    /* a match */
478c9cdc302Schristos 			if ((ncp = malloc(sizeof(*ncp))) == NULL)
4797df0ccbaSfvdl 				break;
4807df0ccbaSfvdl 			ncp->nc_lookups = NULL;
4817df0ccbaSfvdl 			if (parse_ncp(linep, ncp) == -1) {
4827df0ccbaSfvdl 				free(ncp);
4837df0ccbaSfvdl 				ncp = NULL;
4847df0ccbaSfvdl 			}
4857df0ccbaSfvdl 			break;
4867df0ccbaSfvdl 		}
4877df0ccbaSfvdl 	} while (stringp != NULL);
4880d2d9accSlukem 	if (ncp == NULL)
4897df0ccbaSfvdl 		free(linep);
4907df0ccbaSfvdl 	fclose(file);
4914384a68cSchristos 	return ncp;
4927df0ccbaSfvdl }
4937df0ccbaSfvdl 
4947df0ccbaSfvdl /*
4957df0ccbaSfvdl  * freenetconfigent(netconfigp) frees the netconfig structure pointed to by
4967df0ccbaSfvdl  * netconfigp (previously returned by getnetconfigent()).
4977df0ccbaSfvdl  */
4987df0ccbaSfvdl 
4997df0ccbaSfvdl void
freenetconfigent(struct netconfig * netconfigp)500adb74221Smatt freenetconfigent(struct netconfig *netconfigp)
5017df0ccbaSfvdl {
5027df0ccbaSfvdl 	if (netconfigp != NULL) {
5030d2d9accSlukem 				/* holds all netconfigp's strings */
5040d2d9accSlukem 		free(netconfigp->nc_netid);
5057df0ccbaSfvdl 		if (netconfigp->nc_lookups != NULL)
5067df0ccbaSfvdl 			free(netconfigp->nc_lookups);
5077df0ccbaSfvdl 		free(netconfigp);
5087df0ccbaSfvdl 	}
5097df0ccbaSfvdl }
5107df0ccbaSfvdl 
5117df0ccbaSfvdl /*
5127df0ccbaSfvdl  * Parse line and stuff it in a struct netconfig
5137df0ccbaSfvdl  * Typical line might look like:
5147df0ccbaSfvdl  *	udp tpi_cots vb inet udp /dev/udp /usr/lib/ip.so,/usr/local/ip.so
5157df0ccbaSfvdl  *
5167df0ccbaSfvdl  * We return -1 if any of the tokens don't parse, or malloc fails.
5177df0ccbaSfvdl  *
5187df0ccbaSfvdl  * Note that we modify stringp (putting NULLs after tokens) and
5197df0ccbaSfvdl  * we set the ncp's string field pointers to point to these tokens within
5207df0ccbaSfvdl  * stringp.
5217df0ccbaSfvdl  */
5227df0ccbaSfvdl 
5237df0ccbaSfvdl static int
parse_ncp(char * stringp,struct netconfig * ncp)524adb74221Smatt parse_ncp(
525adb74221Smatt 	char *stringp,		/* string to parse */
526adb74221Smatt 	struct netconfig *ncp)	/* where to put results */
5277df0ccbaSfvdl {
5287df0ccbaSfvdl 	char    *tokenp;	/* for processing tokens */
5294af2eb72Schristos 	char    *lasts;
5307df0ccbaSfvdl 
5310e8cfd8fSlukem 	_DIAGASSERT(stringp != NULL);
5320e8cfd8fSlukem 	_DIAGASSERT(ncp != NULL);
5330e8cfd8fSlukem 
5340d2d9accSlukem 	nc_error = NC_BADFILE;
5350d2d9accSlukem 			/* nearly anything that breaks is for this reason */
5367df0ccbaSfvdl 	stringp[strlen(stringp)-1] = '\0';	/* get rid of newline */
5377df0ccbaSfvdl 	/* netid */
5380d2d9accSlukem 	if ((ncp->nc_netid = strtok_r(stringp, "\t ", &lasts)) == NULL)
5394384a68cSchristos 		return -1;
5407df0ccbaSfvdl 
5417df0ccbaSfvdl 	/* semantics */
5420d2d9accSlukem 	if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL)
5434384a68cSchristos 		return -1;
5447df0ccbaSfvdl 	if (strcmp(tokenp, NC_TPI_COTS_ORD_S) == 0)
5457df0ccbaSfvdl 		ncp->nc_semantics = NC_TPI_COTS_ORD;
5467df0ccbaSfvdl 	else if (strcmp(tokenp, NC_TPI_COTS_S) == 0)
5477df0ccbaSfvdl 		ncp->nc_semantics = NC_TPI_COTS;
5487df0ccbaSfvdl 	else if (strcmp(tokenp, NC_TPI_CLTS_S) == 0)
5497df0ccbaSfvdl 		ncp->nc_semantics = NC_TPI_CLTS;
5507df0ccbaSfvdl 	else if (strcmp(tokenp, NC_TPI_RAW_S) == 0)
5517df0ccbaSfvdl 		ncp->nc_semantics = NC_TPI_RAW;
5527df0ccbaSfvdl 	else
5534384a68cSchristos 		return -1;
5547df0ccbaSfvdl 
5557df0ccbaSfvdl 	/* flags */
5560d2d9accSlukem 	if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL)
5574384a68cSchristos 		return -1;
5580d2d9accSlukem 	for (ncp->nc_flag = NC_NOFLAG; *tokenp != '\0'; tokenp++) {
5597df0ccbaSfvdl 		switch (*tokenp) {
5607df0ccbaSfvdl 		case NC_NOFLAG_C:
5617df0ccbaSfvdl 			break;
5627df0ccbaSfvdl 		case NC_VISIBLE_C:
5637df0ccbaSfvdl 			ncp->nc_flag |= NC_VISIBLE;
5647df0ccbaSfvdl 			break;
5657df0ccbaSfvdl 		case NC_BROADCAST_C:
5667df0ccbaSfvdl 			ncp->nc_flag |= NC_BROADCAST;
5677df0ccbaSfvdl 			break;
5687df0ccbaSfvdl 		default:
5694384a68cSchristos 			return -1;
5707df0ccbaSfvdl 		}
5717df0ccbaSfvdl 	}
5727df0ccbaSfvdl 	/* protocol family */
5730d2d9accSlukem 	if ((ncp->nc_protofmly = strtok_r(NULL, "\t ", &lasts)) == NULL)
5744384a68cSchristos 		return -1;
5757df0ccbaSfvdl 	/* protocol name */
5760d2d9accSlukem 	if ((ncp->nc_proto = strtok_r(NULL, "\t ", &lasts)) == NULL)
5774384a68cSchristos 		return -1;
5787df0ccbaSfvdl 	/* network device */
5790d2d9accSlukem 	if ((ncp->nc_device = strtok_r(NULL, "\t ", &lasts)) == NULL)
5804384a68cSchristos 		return -1;
5810d2d9accSlukem 	if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL)
5824384a68cSchristos 		return -1;
5837df0ccbaSfvdl 	if (strcmp(tokenp, NC_NOLOOKUP) == 0) {
5847df0ccbaSfvdl 		ncp->nc_nlookups = 0;
5857df0ccbaSfvdl 		ncp->nc_lookups = NULL;
5867df0ccbaSfvdl 	} else {
5877df0ccbaSfvdl 		char *cp;	    /* tmp string */
5887df0ccbaSfvdl 
5897df0ccbaSfvdl 		if (ncp->nc_lookups != NULL)	/* from last visit */
5907df0ccbaSfvdl 			free(ncp->nc_lookups);
5917df0ccbaSfvdl 		/* preallocate one string pointer */
592c9cdc302Schristos 		ncp->nc_lookups = malloc(sizeof(*ncp->nc_lookups));
5937df0ccbaSfvdl 		ncp->nc_nlookups = 0;
5947df0ccbaSfvdl 		while ((cp = tokenp) != NULL) {
5957df0ccbaSfvdl 			tokenp = _get_next_token(cp, ',');
596deb154d2Schristos 			ncp->nc_lookups[(size_t)ncp->nc_nlookups++] = cp;
5970d2d9accSlukem 			ncp->nc_lookups = (char **)
5980d2d9accSlukem 			    realloc(ncp->nc_lookups,
5990d2d9accSlukem 			    (size_t)(ncp->nc_nlookups+1) *sizeof(char *));
6000d2d9accSlukem 						/* for next loop */
6017df0ccbaSfvdl 		}
6027df0ccbaSfvdl 	}
6034384a68cSchristos 	return 0;
6047df0ccbaSfvdl }
6057df0ccbaSfvdl 
6067df0ccbaSfvdl /*
6077df0ccbaSfvdl  * Returns a string describing the reason for failure.
6087df0ccbaSfvdl  */
6097df0ccbaSfvdl char *
nc_sperror(void)610adb74221Smatt nc_sperror(void)
6117df0ccbaSfvdl {
612ca797c3cSjdolecek 	const char *message;
6137df0ccbaSfvdl 
6147df0ccbaSfvdl 	switch(nc_error) {
6157df0ccbaSfvdl 	case NC_NONETCONFIG:
6167df0ccbaSfvdl 		message = _nc_errors[0];
6177df0ccbaSfvdl 		break;
6187df0ccbaSfvdl 	case NC_NOMEM:
6197df0ccbaSfvdl 		message = _nc_errors[1];
6207df0ccbaSfvdl 		break;
6217df0ccbaSfvdl 	case NC_NOTINIT:
6227df0ccbaSfvdl 		message = _nc_errors[2];
6237df0ccbaSfvdl 		break;
6247df0ccbaSfvdl 	case NC_BADFILE:
6257df0ccbaSfvdl 		message = _nc_errors[3];
6267df0ccbaSfvdl 		break;
6277df0ccbaSfvdl 	default:
6287df0ccbaSfvdl 		message = "Unknown network selection error";
6297df0ccbaSfvdl 	}
63003256c6eSchristos 	return __UNCONST(message);
6317df0ccbaSfvdl }
6327df0ccbaSfvdl 
6337df0ccbaSfvdl /*
6347df0ccbaSfvdl  * Prints a message onto standard error describing the reason for failure.
6357df0ccbaSfvdl  */
6367df0ccbaSfvdl void
nc_perror(const char * s)637adb74221Smatt nc_perror(const char *s)
6387df0ccbaSfvdl {
6390e8cfd8fSlukem 
6400e8cfd8fSlukem 	_DIAGASSERT(s != NULL);
6410e8cfd8fSlukem 
6427df0ccbaSfvdl 	fprintf(stderr, "%s: %s", s, nc_sperror());
6437df0ccbaSfvdl }
6447df0ccbaSfvdl 
6457df0ccbaSfvdl /*
6467df0ccbaSfvdl  * Duplicates the matched netconfig buffer.
6477df0ccbaSfvdl  */
6487df0ccbaSfvdl static struct netconfig *
dup_ncp(struct netconfig * ncp)649adb74221Smatt dup_ncp(struct netconfig *ncp)
6507df0ccbaSfvdl {
6517df0ccbaSfvdl 	struct netconfig	*p;
652*b48a2efdSchristos 	char	*tmp;
653045cceecSthorpej 	u_int	i;
6547df0ccbaSfvdl 
6550e8cfd8fSlukem 	_DIAGASSERT(ncp != NULL);
6560e8cfd8fSlukem 
657*b48a2efdSchristos 	if ((tmp = malloc(MAXNETCONFIGLINE)) == NULL)
6584384a68cSchristos 		return NULL;
659c9cdc302Schristos 	if ((p = malloc(sizeof(*p))) == NULL) {
6607df0ccbaSfvdl 		free(tmp);
6614384a68cSchristos 		return NULL;
6627df0ccbaSfvdl 	}
6637df0ccbaSfvdl 	/*
6647df0ccbaSfvdl 	 * First we dup all the data from matched netconfig buffer.  Then we
6657df0ccbaSfvdl 	 * adjust some of the member pointer to a pre-allocated buffer where
6667df0ccbaSfvdl 	 * contains part of the data.
6677df0ccbaSfvdl 	 * To follow the convention used in parse_ncp(), we store all the
66830b2bf87Swiz 	 * necessary information in the pre-allocated buffer and let each
6697df0ccbaSfvdl 	 * of the netconfig char pointer member point to the right address
6707df0ccbaSfvdl 	 * in the buffer.
6717df0ccbaSfvdl 	 */
6727df0ccbaSfvdl 	*p = *ncp;
6734384a68cSchristos 	p->nc_netid = strcpy(tmp, ncp->nc_netid);
674c7dadf50Sscw 	tmp = strchr(tmp, '\0') + 1;
6754384a68cSchristos 	p->nc_protofmly = strcpy(tmp, ncp->nc_protofmly);
676c7dadf50Sscw 	tmp = strchr(tmp, '\0') + 1;
6774384a68cSchristos 	p->nc_proto = strcpy(tmp, ncp->nc_proto);
678c7dadf50Sscw 	tmp = strchr(tmp, '\0') + 1;
6794384a68cSchristos 	p->nc_device = strcpy(tmp, ncp->nc_device);
6804384a68cSchristos 	p->nc_lookups = calloc((size_t)(p->nc_nlookups + 1), sizeof(char *));
6817df0ccbaSfvdl 	if (p->nc_lookups == NULL) {
6827df0ccbaSfvdl 		free(p->nc_netid);
683039456c0Schristos 		free(p);
6844384a68cSchristos 		return NULL;
6857df0ccbaSfvdl 	}
6867df0ccbaSfvdl 	for (i = 0; i < p->nc_nlookups; i++) {
687c7dadf50Sscw 		tmp = strchr(tmp, '\0') + 1;
688c9cdc302Schristos 		p->nc_lookups[i] = strcpy(tmp, ncp->nc_lookups[i]);
6897df0ccbaSfvdl 	}
6904384a68cSchristos 	return p;
6917df0ccbaSfvdl }
692