xref: /freebsd/lib/libc/rpc/getnetconfig.c (revision 8360efbd6c932013ffdb2f83d2f2de4278febb5e)
18360efbdSAlfred Perlstein /*	$NetBSD: getnetconfig.c,v 1.3 2000/07/06 03:10:34 christos Exp $	*/
28360efbdSAlfred Perlstein /*	$FreeBSD$ */
38360efbdSAlfred Perlstein 
48360efbdSAlfred Perlstein /*
58360efbdSAlfred Perlstein  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
68360efbdSAlfred Perlstein  * unrestricted use provided that this legend is included on all tape
78360efbdSAlfred Perlstein  * media and as a part of the software program in whole or part.  Users
88360efbdSAlfred Perlstein  * may copy or modify Sun RPC without charge, but are not authorized
98360efbdSAlfred Perlstein  * to license or distribute it to anyone else except as part of a product or
108360efbdSAlfred Perlstein  * program developed by the user or with the express written consent of
118360efbdSAlfred Perlstein  * Sun Microsystems, Inc.
128360efbdSAlfred Perlstein  *
138360efbdSAlfred Perlstein  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
148360efbdSAlfred Perlstein  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
158360efbdSAlfred Perlstein  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
168360efbdSAlfred Perlstein  *
178360efbdSAlfred Perlstein  * Sun RPC is provided with no support and without any obligation on the
188360efbdSAlfred Perlstein  * part of Sun Microsystems, Inc. to assist in its use, correction,
198360efbdSAlfred Perlstein  * modification or enhancement.
208360efbdSAlfred Perlstein  *
218360efbdSAlfred Perlstein  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
228360efbdSAlfred Perlstein  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
238360efbdSAlfred Perlstein  * OR ANY PART THEREOF.
248360efbdSAlfred Perlstein  *
258360efbdSAlfred Perlstein  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
268360efbdSAlfred Perlstein  * or profits or other special, indirect and consequential damages, even if
278360efbdSAlfred Perlstein  * Sun has been advised of the possibility of such damages.
288360efbdSAlfred Perlstein  *
298360efbdSAlfred Perlstein  * Sun Microsystems, Inc.
308360efbdSAlfred Perlstein  * 2550 Garcia Avenue
318360efbdSAlfred Perlstein  * Mountain View, California  94043
328360efbdSAlfred Perlstein  */
338360efbdSAlfred Perlstein /*
348360efbdSAlfred Perlstein #ifndef lint
358360efbdSAlfred Perlstein static        char sccsid[] = "@(#)getnetconfig.c	1.12 91/12/19 SMI";
368360efbdSAlfred Perlstein #endif
378360efbdSAlfred Perlstein */
388360efbdSAlfred Perlstein 
398360efbdSAlfred Perlstein /*
408360efbdSAlfred Perlstein  * Copyright (c) 1989 by Sun Microsystems, Inc.
418360efbdSAlfred Perlstein  */
428360efbdSAlfred Perlstein 
438360efbdSAlfred Perlstein #include "reentrant.h"
448360efbdSAlfred Perlstein #include "namespace.h"
458360efbdSAlfred Perlstein #include <sys/cdefs.h>
468360efbdSAlfred Perlstein #include <stdio.h>
478360efbdSAlfred Perlstein #include <errno.h>
488360efbdSAlfred Perlstein #include <netconfig.h>
498360efbdSAlfred Perlstein #include <stdlib.h>
508360efbdSAlfred Perlstein #include <string.h>
518360efbdSAlfred Perlstein #include <rpc/rpc.h>
528360efbdSAlfred Perlstein #include "un-namespace.h"
538360efbdSAlfred Perlstein #include "rpc_com.h"
548360efbdSAlfred Perlstein 
558360efbdSAlfred Perlstein /*
568360efbdSAlfred Perlstein  * The five library routines in this file provide application access to the
578360efbdSAlfred Perlstein  * system network configuration database, /etc/netconfig.  In addition to the
588360efbdSAlfred Perlstein  * netconfig database and the routines for accessing it, the environment
598360efbdSAlfred Perlstein  * variable NETPATH and its corresponding routines in getnetpath.c may also be
608360efbdSAlfred Perlstein  * used to specify the network transport to be used.
618360efbdSAlfred Perlstein  */
628360efbdSAlfred Perlstein 
638360efbdSAlfred Perlstein 
648360efbdSAlfred Perlstein /*
658360efbdSAlfred Perlstein  * netconfig errors
668360efbdSAlfred Perlstein  */
678360efbdSAlfred Perlstein 
688360efbdSAlfred Perlstein #define NC_NONETCONFIG	ENOENT
698360efbdSAlfred Perlstein #define NC_NOMEM	ENOMEM
708360efbdSAlfred Perlstein #define NC_NOTINIT	EINVAL	    /* setnetconfig was not called first */
718360efbdSAlfred Perlstein #define NC_BADFILE	EBADF	    /* format for netconfig file is bad */
728360efbdSAlfred Perlstein 
738360efbdSAlfred Perlstein /*
748360efbdSAlfred Perlstein  * semantics as strings (should be in netconfig.h)
758360efbdSAlfred Perlstein  */
768360efbdSAlfred Perlstein #define NC_TPI_CLTS_S	    "tpi_clts"
778360efbdSAlfred Perlstein #define	NC_TPI_COTS_S	    "tpi_cots"
788360efbdSAlfred Perlstein #define	NC_TPI_COTS_ORD_S   "tpi_cots_ord"
798360efbdSAlfred Perlstein #define	NC_TPI_RAW_S        "tpi_raw"
808360efbdSAlfred Perlstein 
818360efbdSAlfred Perlstein /*
828360efbdSAlfred Perlstein  * flags as characters (also should be in netconfig.h)
838360efbdSAlfred Perlstein  */
848360efbdSAlfred Perlstein #define	NC_NOFLAG_C	'-'
858360efbdSAlfred Perlstein #define	NC_VISIBLE_C	'v'
868360efbdSAlfred Perlstein #define	NC_BROADCAST_C	'b'
878360efbdSAlfred Perlstein 
888360efbdSAlfred Perlstein /*
898360efbdSAlfred Perlstein  * Character used to indicate there is no name-to-address lookup library
908360efbdSAlfred Perlstein  */
918360efbdSAlfred Perlstein #define NC_NOLOOKUP	"-"
928360efbdSAlfred Perlstein 
938360efbdSAlfred Perlstein static const char * const _nc_errors[] = {
948360efbdSAlfred Perlstein     "Netconfig database not found",
958360efbdSAlfred Perlstein     "Not enough memory",
968360efbdSAlfred Perlstein     "Not initialized",
978360efbdSAlfred Perlstein     "Netconfig database has invalid format"
988360efbdSAlfred Perlstein };
998360efbdSAlfred Perlstein 
1008360efbdSAlfred Perlstein struct netconfig_info {
1018360efbdSAlfred Perlstein     int		eof;	/* all entries has been read */
1028360efbdSAlfred Perlstein     int		ref;	/* # of times setnetconfig() has been called */
1038360efbdSAlfred Perlstein     struct netconfig_list	*head;	/* head of the list */
1048360efbdSAlfred Perlstein     struct netconfig_list	*tail;	/* last of the list */
1058360efbdSAlfred Perlstein };
1068360efbdSAlfred Perlstein 
1078360efbdSAlfred Perlstein struct netconfig_list {
1088360efbdSAlfred Perlstein     char			*linep;	/* hold line read from netconfig */
1098360efbdSAlfred Perlstein     struct netconfig		*ncp;
1108360efbdSAlfred Perlstein     struct netconfig_list	*next;
1118360efbdSAlfred Perlstein };
1128360efbdSAlfred Perlstein 
1138360efbdSAlfred Perlstein struct netconfig_vars {
1148360efbdSAlfred Perlstein     int   valid;	/* token that indicates a valid netconfig_vars */
1158360efbdSAlfred Perlstein     int   flag;		/* first time flag */
1168360efbdSAlfred Perlstein     struct netconfig_list *nc_configs;  /* pointer to the current netconfig entry */
1178360efbdSAlfred Perlstein };
1188360efbdSAlfred Perlstein 
1198360efbdSAlfred Perlstein #define NC_VALID	0xfeed
1208360efbdSAlfred Perlstein #define NC_STORAGE	0xf00d
1218360efbdSAlfred Perlstein #define NC_INVALID	0
1228360efbdSAlfred Perlstein 
1238360efbdSAlfred Perlstein 
1248360efbdSAlfred Perlstein static int *__nc_error __P((void));
1258360efbdSAlfred Perlstein static int parse_ncp __P((char *, struct netconfig *));
1268360efbdSAlfred Perlstein static struct netconfig *dup_ncp __P((struct netconfig *));
1278360efbdSAlfred Perlstein 
1288360efbdSAlfred Perlstein 
1298360efbdSAlfred Perlstein static FILE *nc_file;		/* for netconfig db */
1308360efbdSAlfred Perlstein static struct netconfig_info	ni = { 0, 0, NULL, NULL};
1318360efbdSAlfred Perlstein 
1328360efbdSAlfred Perlstein #define MAXNETCONFIGLINE    1000
1338360efbdSAlfred Perlstein 
1348360efbdSAlfred Perlstein static int *
1358360efbdSAlfred Perlstein __nc_error()
1368360efbdSAlfred Perlstein {
1378360efbdSAlfred Perlstein 	extern pthread_mutex_t nc_lock;
1388360efbdSAlfred Perlstein 	static thread_key_t nc_key = 0;
1398360efbdSAlfred Perlstein 	static thread_key_t rce_key = 0;
1408360efbdSAlfred Perlstein 	int *nc_addr = NULL;
1418360efbdSAlfred Perlstein 	static int nc_error = 0;
1428360efbdSAlfred Perlstein 
1438360efbdSAlfred Perlstein 	if ((nc_addr = (int *)thr_getspecific(nc_key)) != 0) {
1448360efbdSAlfred Perlstein 		mutex_lock(&nc_lock);
1458360efbdSAlfred Perlstein 		if (thr_keycreate(&rce_key, free) != 0) {
1468360efbdSAlfred Perlstein 			mutex_unlock(&nc_lock);
1478360efbdSAlfred Perlstein 			return nc_addr;
1488360efbdSAlfred Perlstein 		}
1498360efbdSAlfred Perlstein 		mutex_unlock(&nc_lock);
1508360efbdSAlfred Perlstein 	}
1518360efbdSAlfred Perlstein 	if (nc_addr == NULL) {
1528360efbdSAlfred Perlstein 		nc_addr = (int *)malloc(sizeof (int));
1538360efbdSAlfred Perlstein 		if (thr_setspecific(nc_key, (void *) nc_addr) != 0) {
1548360efbdSAlfred Perlstein 			if (nc_addr)
1558360efbdSAlfred Perlstein 				free(nc_addr);
1568360efbdSAlfred Perlstein 			return &nc_error;
1578360efbdSAlfred Perlstein 		}
1588360efbdSAlfred Perlstein 		*nc_addr = 0;
1598360efbdSAlfred Perlstein 		return nc_addr;
1608360efbdSAlfred Perlstein 	}
1618360efbdSAlfred Perlstein 	return nc_addr;
1628360efbdSAlfred Perlstein }
1638360efbdSAlfred Perlstein 
1648360efbdSAlfred Perlstein #define nc_error        (*(__nc_error()))
1658360efbdSAlfred Perlstein /*
1668360efbdSAlfred Perlstein  * A call to setnetconfig() establishes a /etc/netconfig "session".  A session
1678360efbdSAlfred Perlstein  * "handle" is returned on a successful call.  At the start of a session (after
1688360efbdSAlfred Perlstein  * a call to setnetconfig()) searches through the /etc/netconfig database will
1698360efbdSAlfred Perlstein  * proceed from the start of the file.  The session handle must be passed to
1708360efbdSAlfred Perlstein  * getnetconfig() to parse the file.  Each call to getnetconfig() using the
1718360efbdSAlfred Perlstein  * current handle will process one subsequent entry in /etc/netconfig.
1728360efbdSAlfred Perlstein  * setnetconfig() must be called before the first call to getnetconfig().
1738360efbdSAlfred Perlstein  * (Handles are used to allow for nested calls to setnetpath()).
1748360efbdSAlfred Perlstein  *
1758360efbdSAlfred Perlstein  * A new session is established with each call to setnetconfig(), with a new
1768360efbdSAlfred Perlstein  * handle being returned on each call.  Previously established sessions remain
1778360efbdSAlfred Perlstein  * active until endnetconfig() is called with that session's handle as an
1788360efbdSAlfred Perlstein  * argument.
1798360efbdSAlfred Perlstein  *
1808360efbdSAlfred Perlstein  * setnetconfig() need *not* be called before a call to getnetconfigent().
1818360efbdSAlfred Perlstein  * setnetconfig() returns a NULL pointer on failure (for example, if
1828360efbdSAlfred Perlstein  * the netconfig database is not present).
1838360efbdSAlfred Perlstein  */
1848360efbdSAlfred Perlstein void *
1858360efbdSAlfred Perlstein setnetconfig()
1868360efbdSAlfred Perlstein {
1878360efbdSAlfred Perlstein     struct netconfig_vars *nc_vars;
1888360efbdSAlfred Perlstein 
1898360efbdSAlfred Perlstein     if ((nc_vars = (struct netconfig_vars *)malloc(sizeof
1908360efbdSAlfred Perlstein 		(struct netconfig_vars))) == NULL) {
1918360efbdSAlfred Perlstein 	return(NULL);
1928360efbdSAlfred Perlstein     }
1938360efbdSAlfred Perlstein 
1948360efbdSAlfred Perlstein     /*
1958360efbdSAlfred Perlstein      * For multiple calls, i.e. nc_file is not NULL, we just return the
1968360efbdSAlfred Perlstein      * handle without reopening the netconfig db.
1978360efbdSAlfred Perlstein      */
1988360efbdSAlfred Perlstein     ni.ref++;
1998360efbdSAlfred Perlstein     if ((nc_file != NULL) || (nc_file = fopen(NETCONFIG, "r")) != NULL) {
2008360efbdSAlfred Perlstein 	nc_vars->valid = NC_VALID;
2018360efbdSAlfred Perlstein 	nc_vars->flag = 0;
2028360efbdSAlfred Perlstein 	nc_vars->nc_configs = ni.head;
2038360efbdSAlfred Perlstein 	return ((void *)nc_vars);
2048360efbdSAlfred Perlstein     }
2058360efbdSAlfred Perlstein     ni.ref--;
2068360efbdSAlfred Perlstein     nc_error = NC_NONETCONFIG;
2078360efbdSAlfred Perlstein     free(nc_vars);
2088360efbdSAlfred Perlstein     return (NULL);
2098360efbdSAlfred Perlstein }
2108360efbdSAlfred Perlstein 
2118360efbdSAlfred Perlstein 
2128360efbdSAlfred Perlstein /*
2138360efbdSAlfred Perlstein  * When first called, getnetconfig() returns a pointer to the first entry in
2148360efbdSAlfred Perlstein  * the netconfig database, formatted as a struct netconfig.  On each subsequent
2158360efbdSAlfred Perlstein  * call, getnetconfig() returns a pointer to the next entry in the database.
2168360efbdSAlfred Perlstein  * getnetconfig() can thus be used to search the entire netconfig file.
2178360efbdSAlfred Perlstein  * getnetconfig() returns NULL at end of file.
2188360efbdSAlfred Perlstein  */
2198360efbdSAlfred Perlstein 
2208360efbdSAlfred Perlstein struct netconfig *
2218360efbdSAlfred Perlstein getnetconfig(handlep)
2228360efbdSAlfred Perlstein void *handlep;
2238360efbdSAlfred Perlstein {
2248360efbdSAlfred Perlstein     struct netconfig_vars *ncp = (struct netconfig_vars *)handlep;
2258360efbdSAlfred Perlstein     char *stringp;		/* tmp string pointer */
2268360efbdSAlfred Perlstein     struct netconfig_list	*list;
2278360efbdSAlfred Perlstein     struct netconfig *np;
2288360efbdSAlfred Perlstein 
2298360efbdSAlfred Perlstein     /*
2308360efbdSAlfred Perlstein      * Verify that handle is valid
2318360efbdSAlfred Perlstein      */
2328360efbdSAlfred Perlstein     if (ncp == NULL || nc_file == NULL) {
2338360efbdSAlfred Perlstein 	nc_error = NC_NOTINIT;
2348360efbdSAlfred Perlstein 	return (NULL);
2358360efbdSAlfred Perlstein     }
2368360efbdSAlfred Perlstein 
2378360efbdSAlfred Perlstein     switch (ncp->valid) {
2388360efbdSAlfred Perlstein     case NC_VALID:
2398360efbdSAlfred Perlstein 	/*
2408360efbdSAlfred Perlstein 	 * If entry has already been read into the list,
2418360efbdSAlfred Perlstein 	 * we return the entry in the linked list.
2428360efbdSAlfred Perlstein 	 * If this is the first time call, check if there are any entries in
2438360efbdSAlfred Perlstein 	 * linked list.  If no entries, we need to read the netconfig db.
2448360efbdSAlfred Perlstein 	 * If we have been here and the next entry is there, we just return
2458360efbdSAlfred Perlstein 	 * it.
2468360efbdSAlfred Perlstein 	 */
2478360efbdSAlfred Perlstein 	if (ncp->flag == 0) {	/* first time */
2488360efbdSAlfred Perlstein 	    ncp->flag = 1;
2498360efbdSAlfred Perlstein 	    ncp->nc_configs = ni.head;
2508360efbdSAlfred Perlstein 	    if (ncp->nc_configs != NULL)	/* entry already exist */
2518360efbdSAlfred Perlstein 		return(ncp->nc_configs->ncp);
2528360efbdSAlfred Perlstein 	}
2538360efbdSAlfred Perlstein 	else if (ncp->nc_configs != NULL && ncp->nc_configs->next != NULL) {
2548360efbdSAlfred Perlstein 	    ncp->nc_configs = ncp->nc_configs->next;
2558360efbdSAlfred Perlstein 	    return(ncp->nc_configs->ncp);
2568360efbdSAlfred Perlstein 	}
2578360efbdSAlfred Perlstein 
2588360efbdSAlfred Perlstein 	/*
2598360efbdSAlfred Perlstein 	 * If we cannot find the entry in the list and is end of file,
2608360efbdSAlfred Perlstein 	 * we give up.
2618360efbdSAlfred Perlstein 	 */
2628360efbdSAlfred Perlstein 	if (ni.eof == 1)	return(NULL);
2638360efbdSAlfred Perlstein 	break;
2648360efbdSAlfred Perlstein     default:
2658360efbdSAlfred Perlstein 	nc_error = NC_NOTINIT;
2668360efbdSAlfred Perlstein 	return (NULL);
2678360efbdSAlfred Perlstein     }
2688360efbdSAlfred Perlstein 
2698360efbdSAlfred Perlstein     stringp = (char *) malloc(MAXNETCONFIGLINE);
2708360efbdSAlfred Perlstein     if (stringp == NULL)
2718360efbdSAlfred Perlstein     	return (NULL);
2728360efbdSAlfred Perlstein 
2738360efbdSAlfred Perlstein #ifdef MEM_CHK
2748360efbdSAlfred Perlstein     if (malloc_verify() == 0) {
2758360efbdSAlfred Perlstein 	fprintf(stderr, "memory heap corrupted in getnetconfig\n");
2768360efbdSAlfred Perlstein 	exit(1);
2778360efbdSAlfred Perlstein     }
2788360efbdSAlfred Perlstein #endif
2798360efbdSAlfred Perlstein 
2808360efbdSAlfred Perlstein     /*
2818360efbdSAlfred Perlstein      * Read a line from netconfig file.
2828360efbdSAlfred Perlstein      */
2838360efbdSAlfred Perlstein     do {
2848360efbdSAlfred Perlstein 	if (fgets(stringp, MAXNETCONFIGLINE, nc_file) == NULL) {
2858360efbdSAlfred Perlstein 	    free(stringp);
2868360efbdSAlfred Perlstein 	    ni.eof = 1;
2878360efbdSAlfred Perlstein 	    return (NULL);
2888360efbdSAlfred Perlstein         }
2898360efbdSAlfred Perlstein     } while (*stringp == '#');
2908360efbdSAlfred Perlstein 
2918360efbdSAlfred Perlstein     list = (struct netconfig_list *) malloc(sizeof (struct netconfig_list));
2928360efbdSAlfred Perlstein     if (list == NULL) {
2938360efbdSAlfred Perlstein     	free(stringp);
2948360efbdSAlfred Perlstein     	return(NULL);
2958360efbdSAlfred Perlstein     }
2968360efbdSAlfred Perlstein     np = (struct netconfig *) malloc(sizeof (struct netconfig));
2978360efbdSAlfred Perlstein     if (np == NULL) {
2988360efbdSAlfred Perlstein     	free(stringp);
2998360efbdSAlfred Perlstein 	free(list);
3008360efbdSAlfred Perlstein     	return(NULL);
3018360efbdSAlfred Perlstein     }
3028360efbdSAlfred Perlstein     list->ncp = np;
3038360efbdSAlfred Perlstein     list->next = NULL;
3048360efbdSAlfred Perlstein     list->ncp->nc_lookups = NULL;
3058360efbdSAlfred Perlstein     list->linep = stringp;
3068360efbdSAlfred Perlstein     if (parse_ncp(stringp, list->ncp) == -1) {
3078360efbdSAlfred Perlstein 	free(stringp);
3088360efbdSAlfred Perlstein 	free(np);
3098360efbdSAlfred Perlstein 	free(list);
3108360efbdSAlfred Perlstein 	return (NULL);
3118360efbdSAlfred Perlstein     }
3128360efbdSAlfred Perlstein     else {
3138360efbdSAlfred Perlstein 	/*
3148360efbdSAlfred Perlstein 	 * If this is the first entry that's been read, it is the head of
3158360efbdSAlfred Perlstein 	 * the list.  If not, put the entry at the end of the list.
3168360efbdSAlfred Perlstein 	 * Reposition the current pointer of the handle to the last entry
3178360efbdSAlfred Perlstein 	 * in the list.
3188360efbdSAlfred Perlstein 	 */
3198360efbdSAlfred Perlstein 	if (ni.head == NULL) {	/* first entry */
3208360efbdSAlfred Perlstein 	    ni.head = ni.tail = list;
3218360efbdSAlfred Perlstein 	}
3228360efbdSAlfred Perlstein     	else {
3238360efbdSAlfred Perlstein     	    ni.tail->next = list;
3248360efbdSAlfred Perlstein     	    ni.tail = ni.tail->next;
3258360efbdSAlfred Perlstein     	}
3268360efbdSAlfred Perlstein 	ncp->nc_configs = ni.tail;
3278360efbdSAlfred Perlstein 	return(ni.tail->ncp);
3288360efbdSAlfred Perlstein     }
3298360efbdSAlfred Perlstein }
3308360efbdSAlfred Perlstein 
3318360efbdSAlfred Perlstein /*
3328360efbdSAlfred Perlstein  * endnetconfig() may be called to "unbind" or "close" the netconfig database
3338360efbdSAlfred Perlstein  * when processing is complete, releasing resources for reuse.  endnetconfig()
3348360efbdSAlfred Perlstein  * may not be called before setnetconfig().  endnetconfig() returns 0 on
3358360efbdSAlfred Perlstein  * success and -1 on failure (for example, if setnetconfig() was not called
3368360efbdSAlfred Perlstein  * previously).
3378360efbdSAlfred Perlstein  */
3388360efbdSAlfred Perlstein int
3398360efbdSAlfred Perlstein endnetconfig(handlep)
3408360efbdSAlfred Perlstein void *handlep;
3418360efbdSAlfred Perlstein {
3428360efbdSAlfred Perlstein     struct netconfig_vars *nc_handlep = (struct netconfig_vars *)handlep;
3438360efbdSAlfred Perlstein 
3448360efbdSAlfred Perlstein     struct netconfig_list *q, *p;
3458360efbdSAlfred Perlstein 
3468360efbdSAlfred Perlstein     /*
3478360efbdSAlfred Perlstein      * Verify that handle is valid
3488360efbdSAlfred Perlstein      */
3498360efbdSAlfred Perlstein     if (nc_handlep == NULL || (nc_handlep->valid != NC_VALID &&
3508360efbdSAlfred Perlstein 	    nc_handlep->valid != NC_STORAGE)) {
3518360efbdSAlfred Perlstein 	nc_error = NC_NOTINIT;
3528360efbdSAlfred Perlstein 	return (-1);
3538360efbdSAlfred Perlstein     }
3548360efbdSAlfred Perlstein 
3558360efbdSAlfred Perlstein     /*
3568360efbdSAlfred Perlstein      * Return 0 if anyone still needs it.
3578360efbdSAlfred Perlstein      */
3588360efbdSAlfred Perlstein     nc_handlep->valid = NC_INVALID;
3598360efbdSAlfred Perlstein     nc_handlep->flag = 0;
3608360efbdSAlfred Perlstein     nc_handlep->nc_configs = NULL;
3618360efbdSAlfred Perlstein     if (--ni.ref > 0) {
3628360efbdSAlfred Perlstein     	free(nc_handlep);
3638360efbdSAlfred Perlstein 	return(0);
3648360efbdSAlfred Perlstein     }
3658360efbdSAlfred Perlstein 
3668360efbdSAlfred Perlstein     /*
3678360efbdSAlfred Perlstein      * Noone needs these entries anymore, then frees them.
3688360efbdSAlfred Perlstein      * Make sure all info in netconfig_info structure has been reinitialized.
3698360efbdSAlfred Perlstein      */
3708360efbdSAlfred Perlstein     q = p = ni.head;
3718360efbdSAlfred Perlstein     ni.eof = ni.ref = 0;
3728360efbdSAlfred Perlstein     ni.head = NULL;
3738360efbdSAlfred Perlstein     ni.tail = NULL;
3748360efbdSAlfred Perlstein     while (q) {
3758360efbdSAlfred Perlstein 	p = q->next;
3768360efbdSAlfred Perlstein 	if (q->ncp->nc_lookups != NULL) free(q->ncp->nc_lookups);
3778360efbdSAlfred Perlstein 	free(q->ncp);
3788360efbdSAlfred Perlstein 	free(q->linep);
3798360efbdSAlfred Perlstein 	free(q);
3808360efbdSAlfred Perlstein 	q = p;
3818360efbdSAlfred Perlstein     }
3828360efbdSAlfred Perlstein     free(nc_handlep);
3838360efbdSAlfred Perlstein 
3848360efbdSAlfred Perlstein     fclose(nc_file);
3858360efbdSAlfred Perlstein     nc_file = NULL;
3868360efbdSAlfred Perlstein     return (0);
3878360efbdSAlfred Perlstein }
3888360efbdSAlfred Perlstein 
3898360efbdSAlfred Perlstein /*
3908360efbdSAlfred Perlstein  * getnetconfigent(netid) returns a pointer to the struct netconfig structure
3918360efbdSAlfred Perlstein  * corresponding to netid.  It returns NULL if netid is invalid (that is, does
3928360efbdSAlfred Perlstein  * not name an entry in the netconfig database).  It returns NULL and sets
3938360efbdSAlfred Perlstein  * errno in case of failure (for example, if the netconfig database cannot be
3948360efbdSAlfred Perlstein  * opened).
3958360efbdSAlfred Perlstein  */
3968360efbdSAlfred Perlstein 
3978360efbdSAlfred Perlstein struct netconfig *
3988360efbdSAlfred Perlstein getnetconfigent(netid)
3998360efbdSAlfred Perlstein 	char *netid;
4008360efbdSAlfred Perlstein {
4018360efbdSAlfred Perlstein     FILE *file;		/* NETCONFIG db's file pointer */
4028360efbdSAlfred Perlstein     char *linep;	/* holds current netconfig line */
4038360efbdSAlfred Perlstein     char *stringp;	/* temporary string pointer */
4048360efbdSAlfred Perlstein     struct netconfig *ncp = NULL;   /* returned value */
4058360efbdSAlfred Perlstein     struct netconfig_list *list;	/* pointer to cache list */
4068360efbdSAlfred Perlstein 
4078360efbdSAlfred Perlstein     if (netid == NULL || strlen(netid) == 0) {
4088360efbdSAlfred Perlstein 	return (NULL);
4098360efbdSAlfred Perlstein     }
4108360efbdSAlfred Perlstein 
4118360efbdSAlfred Perlstein     /*
4128360efbdSAlfred Perlstein      * Look up table if the entries have already been read and parsed in
4138360efbdSAlfred Perlstein      * getnetconfig(), then copy this entry into a buffer and return it.
4148360efbdSAlfred Perlstein      * If we cannot find the entry in the current list and there are more
4158360efbdSAlfred Perlstein      * entries in the netconfig db that has not been read, we then read the
4168360efbdSAlfred Perlstein      * db and try find the match netid.
4178360efbdSAlfred Perlstein      * If all the netconfig db has been read and placed into the list and
4188360efbdSAlfred Perlstein      * there is no match for the netid, return NULL.
4198360efbdSAlfred Perlstein      */
4208360efbdSAlfred Perlstein     if (ni.head != NULL) {
4218360efbdSAlfred Perlstein 	for (list = ni.head; list; list = list->next) {
4228360efbdSAlfred Perlstein 	    if (strcmp(list->ncp->nc_netid, netid) == 0) {
4238360efbdSAlfred Perlstein 	        return(dup_ncp(list->ncp));
4248360efbdSAlfred Perlstein 	    }
4258360efbdSAlfred Perlstein 	}
4268360efbdSAlfred Perlstein 	if (ni.eof == 1)	/* that's all the entries */
4278360efbdSAlfred Perlstein 		return(NULL);
4288360efbdSAlfred Perlstein     }
4298360efbdSAlfred Perlstein 
4308360efbdSAlfred Perlstein 
4318360efbdSAlfred Perlstein     if ((file = fopen(NETCONFIG, "r")) == NULL) {
4328360efbdSAlfred Perlstein 	return (NULL);
4338360efbdSAlfred Perlstein     }
4348360efbdSAlfred Perlstein 
4358360efbdSAlfred Perlstein     if ((linep = malloc(MAXNETCONFIGLINE)) == NULL) {
4368360efbdSAlfred Perlstein 	fclose(file);
4378360efbdSAlfred Perlstein 	return (NULL);
4388360efbdSAlfred Perlstein     }
4398360efbdSAlfred Perlstein     do {
4408360efbdSAlfred Perlstein 	int len;
4418360efbdSAlfred Perlstein 	char *tmpp;	/* tmp string pointer */
4428360efbdSAlfred Perlstein 
4438360efbdSAlfred Perlstein 	do {
4448360efbdSAlfred Perlstein 	    if ((stringp = fgets(linep, MAXNETCONFIGLINE, file)) == NULL) {
4458360efbdSAlfred Perlstein 		break;
4468360efbdSAlfred Perlstein 	    }
4478360efbdSAlfred Perlstein 	} while (*stringp == '#');
4488360efbdSAlfred Perlstein 	if (stringp == NULL) {	    /* eof */
4498360efbdSAlfred Perlstein 	    break;
4508360efbdSAlfred Perlstein 	}
4518360efbdSAlfred Perlstein 	if ((tmpp = strpbrk(stringp, "\t ")) == NULL) {	/* can't parse file */
4528360efbdSAlfred Perlstein 	    nc_error = NC_BADFILE;
4538360efbdSAlfred Perlstein 	    break;
4548360efbdSAlfred Perlstein 	}
4558360efbdSAlfred Perlstein 	if (strlen(netid) == (len = tmpp - stringp) &&	/* a match */
4568360efbdSAlfred Perlstein 		strncmp(stringp, netid, (size_t)len) == 0) {
4578360efbdSAlfred Perlstein 	    if ((ncp = (struct netconfig *)
4588360efbdSAlfred Perlstein 		    malloc(sizeof (struct netconfig))) == NULL) {
4598360efbdSAlfred Perlstein 		break;
4608360efbdSAlfred Perlstein 	    }
4618360efbdSAlfred Perlstein 	    ncp->nc_lookups = NULL;
4628360efbdSAlfred Perlstein 	    if (parse_ncp(linep, ncp) == -1) {
4638360efbdSAlfred Perlstein 		free(ncp);
4648360efbdSAlfred Perlstein 		ncp = NULL;
4658360efbdSAlfred Perlstein 	    }
4668360efbdSAlfred Perlstein 	    break;
4678360efbdSAlfred Perlstein 	}
4688360efbdSAlfred Perlstein     } while (stringp != NULL);
4698360efbdSAlfred Perlstein     if (ncp == NULL) {
4708360efbdSAlfred Perlstein 	free(linep);
4718360efbdSAlfred Perlstein     }
4728360efbdSAlfred Perlstein     fclose(file);
4738360efbdSAlfred Perlstein     return(ncp);
4748360efbdSAlfred Perlstein }
4758360efbdSAlfred Perlstein 
4768360efbdSAlfred Perlstein /*
4778360efbdSAlfred Perlstein  * freenetconfigent(netconfigp) frees the netconfig structure pointed to by
4788360efbdSAlfred Perlstein  * netconfigp (previously returned by getnetconfigent()).
4798360efbdSAlfred Perlstein  */
4808360efbdSAlfred Perlstein 
4818360efbdSAlfred Perlstein void
4828360efbdSAlfred Perlstein freenetconfigent(netconfigp)
4838360efbdSAlfred Perlstein 	struct netconfig *netconfigp;
4848360efbdSAlfred Perlstein {
4858360efbdSAlfred Perlstein     if (netconfigp != NULL) {
4868360efbdSAlfred Perlstein 	free(netconfigp->nc_netid);	/* holds all netconfigp's strings */
4878360efbdSAlfred Perlstein 	if (netconfigp->nc_lookups != NULL)
4888360efbdSAlfred Perlstein 	    free(netconfigp->nc_lookups);
4898360efbdSAlfred Perlstein 	free(netconfigp);
4908360efbdSAlfred Perlstein     }
4918360efbdSAlfred Perlstein     return;
4928360efbdSAlfred Perlstein }
4938360efbdSAlfred Perlstein 
4948360efbdSAlfred Perlstein /*
4958360efbdSAlfred Perlstein  * Parse line and stuff it in a struct netconfig
4968360efbdSAlfred Perlstein  * Typical line might look like:
4978360efbdSAlfred Perlstein  *	udp tpi_cots vb inet udp /dev/udp /usr/lib/ip.so,/usr/local/ip.so
4988360efbdSAlfred Perlstein  *
4998360efbdSAlfred Perlstein  * We return -1 if any of the tokens don't parse, or malloc fails.
5008360efbdSAlfred Perlstein  *
5018360efbdSAlfred Perlstein  * Note that we modify stringp (putting NULLs after tokens) and
5028360efbdSAlfred Perlstein  * we set the ncp's string field pointers to point to these tokens within
5038360efbdSAlfred Perlstein  * stringp.
5048360efbdSAlfred Perlstein  */
5058360efbdSAlfred Perlstein 
5068360efbdSAlfred Perlstein static int
5078360efbdSAlfred Perlstein parse_ncp(stringp, ncp)
5088360efbdSAlfred Perlstein char *stringp;		/* string to parse */
5098360efbdSAlfred Perlstein struct netconfig *ncp;	/* where to put results */
5108360efbdSAlfred Perlstein {
5118360efbdSAlfred Perlstein     char    *tokenp;	/* for processing tokens */
5128360efbdSAlfred Perlstein     char    *lasts;
5138360efbdSAlfred Perlstein 
5148360efbdSAlfred Perlstein     nc_error = NC_BADFILE;	/* nearly anything that breaks is for this reason */
5158360efbdSAlfred Perlstein     stringp[strlen(stringp)-1] = '\0';	/* get rid of newline */
5168360efbdSAlfred Perlstein     /* netid */
5178360efbdSAlfred Perlstein     if ((ncp->nc_netid = strtok_r(stringp, "\t ", &lasts)) == NULL) {
5188360efbdSAlfred Perlstein 	return (-1);
5198360efbdSAlfred Perlstein     }
5208360efbdSAlfred Perlstein 
5218360efbdSAlfred Perlstein     /* semantics */
5228360efbdSAlfred Perlstein     if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) {
5238360efbdSAlfred Perlstein 	return (-1);
5248360efbdSAlfred Perlstein     }
5258360efbdSAlfred Perlstein     if (strcmp(tokenp, NC_TPI_COTS_ORD_S) == 0)
5268360efbdSAlfred Perlstein 	ncp->nc_semantics = NC_TPI_COTS_ORD;
5278360efbdSAlfred Perlstein     else if (strcmp(tokenp, NC_TPI_COTS_S) == 0)
5288360efbdSAlfred Perlstein 	ncp->nc_semantics = NC_TPI_COTS;
5298360efbdSAlfred Perlstein     else if (strcmp(tokenp, NC_TPI_CLTS_S) == 0)
5308360efbdSAlfred Perlstein 	ncp->nc_semantics = NC_TPI_CLTS;
5318360efbdSAlfred Perlstein     else if (strcmp(tokenp, NC_TPI_RAW_S) == 0)
5328360efbdSAlfred Perlstein 	ncp->nc_semantics = NC_TPI_RAW;
5338360efbdSAlfred Perlstein     else
5348360efbdSAlfred Perlstein 	return (-1);
5358360efbdSAlfred Perlstein 
5368360efbdSAlfred Perlstein     /* flags */
5378360efbdSAlfred Perlstein     if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) {
5388360efbdSAlfred Perlstein 	return (-1);
5398360efbdSAlfred Perlstein     }
5408360efbdSAlfred Perlstein     for (ncp->nc_flag = NC_NOFLAG; *tokenp != '\0';
5418360efbdSAlfred Perlstein 	    tokenp++) {
5428360efbdSAlfred Perlstein 	switch (*tokenp) {
5438360efbdSAlfred Perlstein 	case NC_NOFLAG_C:
5448360efbdSAlfred Perlstein 	    break;
5458360efbdSAlfred Perlstein 	case NC_VISIBLE_C:
5468360efbdSAlfred Perlstein 	    ncp->nc_flag |= NC_VISIBLE;
5478360efbdSAlfred Perlstein 	    break;
5488360efbdSAlfred Perlstein 	case NC_BROADCAST_C:
5498360efbdSAlfred Perlstein 	    ncp->nc_flag |= NC_BROADCAST;
5508360efbdSAlfred Perlstein 	    break;
5518360efbdSAlfred Perlstein 	default:
5528360efbdSAlfred Perlstein 	    return (-1);
5538360efbdSAlfred Perlstein 	}
5548360efbdSAlfred Perlstein     }
5558360efbdSAlfred Perlstein     /* protocol family */
5568360efbdSAlfred Perlstein     if ((ncp->nc_protofmly = strtok_r(NULL, "\t ", &lasts)) == NULL) {
5578360efbdSAlfred Perlstein 	return (-1);
5588360efbdSAlfred Perlstein     }
5598360efbdSAlfred Perlstein     /* protocol name */
5608360efbdSAlfred Perlstein     if ((ncp->nc_proto = strtok_r(NULL, "\t ", &lasts)) == NULL) {
5618360efbdSAlfred Perlstein 	return (-1);
5628360efbdSAlfred Perlstein     }
5638360efbdSAlfred Perlstein     /* network device */
5648360efbdSAlfred Perlstein     if ((ncp->nc_device = strtok_r(NULL, "\t ", &lasts)) == NULL) {
5658360efbdSAlfred Perlstein 	return (-1);
5668360efbdSAlfred Perlstein     }
5678360efbdSAlfred Perlstein     if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) {
5688360efbdSAlfred Perlstein 	return (-1);
5698360efbdSAlfred Perlstein     }
5708360efbdSAlfred Perlstein     if (strcmp(tokenp, NC_NOLOOKUP) == 0) {
5718360efbdSAlfred Perlstein 	ncp->nc_nlookups = 0;
5728360efbdSAlfred Perlstein 	ncp->nc_lookups = NULL;
5738360efbdSAlfred Perlstein     } else {
5748360efbdSAlfred Perlstein 	char *cp;	    /* tmp string */
5758360efbdSAlfred Perlstein 
5768360efbdSAlfred Perlstein 	if (ncp->nc_lookups != NULL)	/* from last visit */
5778360efbdSAlfred Perlstein 	    free(ncp->nc_lookups);
5788360efbdSAlfred Perlstein 	/* preallocate one string pointer */
5798360efbdSAlfred Perlstein 	ncp->nc_lookups = (char **)malloc(sizeof (char *));
5808360efbdSAlfred Perlstein 	ncp->nc_nlookups = 0;
5818360efbdSAlfred Perlstein 	while ((cp = tokenp) != NULL) {
5828360efbdSAlfred Perlstein 	    tokenp = _get_next_token(cp, ',');
5838360efbdSAlfred Perlstein 	    ncp->nc_lookups[(size_t)ncp->nc_nlookups++] = cp;
5848360efbdSAlfred Perlstein 	    ncp->nc_lookups = (char **)realloc(ncp->nc_lookups,
5858360efbdSAlfred Perlstein 		(size_t)(ncp->nc_nlookups+1) *sizeof(char *));	/* for next loop */
5868360efbdSAlfred Perlstein 	}
5878360efbdSAlfred Perlstein     }
5888360efbdSAlfred Perlstein     return (0);
5898360efbdSAlfred Perlstein }
5908360efbdSAlfred Perlstein 
5918360efbdSAlfred Perlstein 
5928360efbdSAlfred Perlstein /*
5938360efbdSAlfred Perlstein  * Returns a string describing the reason for failure.
5948360efbdSAlfred Perlstein  */
5958360efbdSAlfred Perlstein char *
5968360efbdSAlfred Perlstein nc_sperror()
5978360efbdSAlfred Perlstein {
5988360efbdSAlfred Perlstein     const char *message;
5998360efbdSAlfred Perlstein 
6008360efbdSAlfred Perlstein     switch(nc_error) {
6018360efbdSAlfred Perlstein     case NC_NONETCONFIG:
6028360efbdSAlfred Perlstein 	message = _nc_errors[0];
6038360efbdSAlfred Perlstein 	break;
6048360efbdSAlfred Perlstein     case NC_NOMEM:
6058360efbdSAlfred Perlstein 	message = _nc_errors[1];
6068360efbdSAlfred Perlstein 	break;
6078360efbdSAlfred Perlstein     case NC_NOTINIT:
6088360efbdSAlfred Perlstein 	message = _nc_errors[2];
6098360efbdSAlfred Perlstein 	break;
6108360efbdSAlfred Perlstein     case NC_BADFILE:
6118360efbdSAlfred Perlstein 	message = _nc_errors[3];
6128360efbdSAlfred Perlstein 	break;
6138360efbdSAlfred Perlstein     default:
6148360efbdSAlfred Perlstein 	message = "Unknown network selection error";
6158360efbdSAlfred Perlstein     }
6168360efbdSAlfred Perlstein     /* LINTED const castaway */
6178360efbdSAlfred Perlstein     return ((char *)message);
6188360efbdSAlfred Perlstein }
6198360efbdSAlfred Perlstein 
6208360efbdSAlfred Perlstein /*
6218360efbdSAlfred Perlstein  * Prints a message onto standard error describing the reason for failure.
6228360efbdSAlfred Perlstein  */
6238360efbdSAlfred Perlstein void
6248360efbdSAlfred Perlstein nc_perror(s)
6258360efbdSAlfred Perlstein 	const char *s;
6268360efbdSAlfred Perlstein {
6278360efbdSAlfred Perlstein     fprintf(stderr, "%s: %s", s, nc_sperror());
6288360efbdSAlfred Perlstein }
6298360efbdSAlfred Perlstein 
6308360efbdSAlfred Perlstein /*
6318360efbdSAlfred Perlstein  * Duplicates the matched netconfig buffer.
6328360efbdSAlfred Perlstein  */
6338360efbdSAlfred Perlstein static struct netconfig *
6348360efbdSAlfred Perlstein dup_ncp(ncp)
6358360efbdSAlfred Perlstein struct netconfig	*ncp;
6368360efbdSAlfred Perlstein {
6378360efbdSAlfred Perlstein     struct netconfig	*p;
6388360efbdSAlfred Perlstein     char	*tmp;
6398360efbdSAlfred Perlstein     int	i;
6408360efbdSAlfred Perlstein 
6418360efbdSAlfred Perlstein     if ((tmp=malloc(MAXNETCONFIGLINE)) == NULL)
6428360efbdSAlfred Perlstein 	return(NULL);
6438360efbdSAlfred Perlstein     if ((p=(struct netconfig *)malloc(sizeof(struct netconfig))) == NULL) {
6448360efbdSAlfred Perlstein 	free(tmp);
6458360efbdSAlfred Perlstein 	return(NULL);
6468360efbdSAlfred Perlstein     }
6478360efbdSAlfred Perlstein     /*
6488360efbdSAlfred Perlstein      * First we dup all the data from matched netconfig buffer.  Then we
6498360efbdSAlfred Perlstein      * adjust some of the member pointer to a pre-allocated buffer where
6508360efbdSAlfred Perlstein      * contains part of the data.
6518360efbdSAlfred Perlstein      * To follow the convention used in parse_ncp(), we store all the
6528360efbdSAlfred Perlstein      * neccessary information in the pre-allocated buffer and let each
6538360efbdSAlfred Perlstein      * of the netconfig char pointer member point to the right address
6548360efbdSAlfred Perlstein      * in the buffer.
6558360efbdSAlfred Perlstein      */
6568360efbdSAlfred Perlstein     *p = *ncp;
6578360efbdSAlfred Perlstein     p->nc_netid = (char *)strcpy(tmp,ncp->nc_netid);
6588360efbdSAlfred Perlstein     tmp = strchr(tmp, NULL) + 1;
6598360efbdSAlfred Perlstein     p->nc_protofmly = (char *)strcpy(tmp,ncp->nc_protofmly);
6608360efbdSAlfred Perlstein     tmp = strchr(tmp, NULL) + 1;
6618360efbdSAlfred Perlstein     p->nc_proto = (char *)strcpy(tmp,ncp->nc_proto);
6628360efbdSAlfred Perlstein     tmp = strchr(tmp, NULL) + 1;
6638360efbdSAlfred Perlstein     p->nc_device = (char *)strcpy(tmp,ncp->nc_device);
6648360efbdSAlfred Perlstein     p->nc_lookups = (char **)malloc((size_t)(p->nc_nlookups+1) * sizeof(char *));
6658360efbdSAlfred Perlstein     if (p->nc_lookups == NULL) {
6668360efbdSAlfred Perlstein 	free(p->nc_netid);
6678360efbdSAlfred Perlstein 	return(NULL);
6688360efbdSAlfred Perlstein     }
6698360efbdSAlfred Perlstein     for (i=0; i < p->nc_nlookups; i++) {
6708360efbdSAlfred Perlstein     	tmp = strchr(tmp, NULL) + 1;
6718360efbdSAlfred Perlstein     	p->nc_lookups[i] = (char *)strcpy(tmp,ncp->nc_lookups[i]);
6728360efbdSAlfred Perlstein     }
6738360efbdSAlfred Perlstein     return(p);
6748360efbdSAlfred Perlstein }
675