1*0a6a1f1dSLionel Sambuc /* $NetBSD: getnetconfig.c,v 1.22 2014/09/18 13:58:20 christos Exp $ */
22fe8fb19SBen Gras
32fe8fb19SBen Gras /*
484d9c625SLionel Sambuc * Copyright (c) 2010, Oracle America, Inc.
52fe8fb19SBen Gras *
684d9c625SLionel Sambuc * Redistribution and use in source and binary forms, with or without
784d9c625SLionel Sambuc * modification, are permitted provided that the following conditions are
884d9c625SLionel Sambuc * met:
92fe8fb19SBen Gras *
1084d9c625SLionel Sambuc * * Redistributions of source code must retain the above copyright
1184d9c625SLionel Sambuc * notice, this list of conditions and the following disclaimer.
1284d9c625SLionel Sambuc * * Redistributions in binary form must reproduce the above
1384d9c625SLionel Sambuc * copyright notice, this list of conditions and the following
1484d9c625SLionel Sambuc * disclaimer in the documentation and/or other materials
1584d9c625SLionel Sambuc * provided with the distribution.
1684d9c625SLionel Sambuc * * Neither the name of the "Oracle America, Inc." nor the names of its
1784d9c625SLionel Sambuc * contributors may be used to endorse or promote products derived
1884d9c625SLionel Sambuc * from this software without specific prior written permission.
192fe8fb19SBen Gras *
2084d9c625SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2184d9c625SLionel Sambuc * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2284d9c625SLionel Sambuc * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2384d9c625SLionel Sambuc * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2484d9c625SLionel Sambuc * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
2584d9c625SLionel Sambuc * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2684d9c625SLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2784d9c625SLionel Sambuc * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2884d9c625SLionel Sambuc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2984d9c625SLionel Sambuc * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3084d9c625SLionel Sambuc * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3184d9c625SLionel Sambuc * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
322fe8fb19SBen Gras */
332fe8fb19SBen Gras
342fe8fb19SBen Gras #include <sys/cdefs.h>
352fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
362fe8fb19SBen Gras #if 0
372fe8fb19SBen Gras static char sccsid[] = "@(#)getnetconfig.c 1.12 91/12/19 SMI";
382fe8fb19SBen Gras #else
39*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: getnetconfig.c,v 1.22 2014/09/18 13:58:20 christos Exp $");
402fe8fb19SBen Gras #endif
412fe8fb19SBen Gras #endif
422fe8fb19SBen Gras
432fe8fb19SBen Gras /*
442fe8fb19SBen Gras * Copyright (c) 1989 by Sun Microsystems, Inc.
452fe8fb19SBen Gras */
462fe8fb19SBen Gras
472fe8fb19SBen Gras #include "namespace.h"
482fe8fb19SBen Gras #include "reentrant.h"
492fe8fb19SBen Gras #include <stdio.h>
502fe8fb19SBen Gras #include <assert.h>
512fe8fb19SBen Gras #include <errno.h>
522fe8fb19SBen Gras #include <netconfig.h>
532fe8fb19SBen Gras #include <stddef.h>
542fe8fb19SBen Gras #include <stdlib.h>
552fe8fb19SBen Gras #include <string.h>
562fe8fb19SBen Gras #include <rpc/rpc.h>
572fe8fb19SBen Gras #include "rpc_internal.h"
582fe8fb19SBen Gras
592fe8fb19SBen Gras #ifdef __weak_alias
602fe8fb19SBen Gras __weak_alias(getnetconfig,_getnetconfig)
612fe8fb19SBen Gras __weak_alias(setnetconfig,_setnetconfig)
622fe8fb19SBen Gras __weak_alias(endnetconfig,_endnetconfig)
632fe8fb19SBen Gras __weak_alias(getnetconfigent,_getnetconfigent)
642fe8fb19SBen Gras __weak_alias(freenetconfigent,_freenetconfigent)
652fe8fb19SBen Gras __weak_alias(nc_perror,_nc_perror)
662fe8fb19SBen Gras __weak_alias(nc_sperror,_nc_sperror)
672fe8fb19SBen Gras #endif
682fe8fb19SBen Gras
692fe8fb19SBen Gras /*
702fe8fb19SBen Gras * The five library routines in this file provide application access to the
712fe8fb19SBen Gras * system network configuration database, /etc/netconfig. In addition to the
722fe8fb19SBen Gras * netconfig database and the routines for accessing it, the environment
732fe8fb19SBen Gras * variable NETPATH and its corresponding routines in getnetpath.c may also be
742fe8fb19SBen Gras * used to specify the network transport to be used.
752fe8fb19SBen Gras */
762fe8fb19SBen Gras
772fe8fb19SBen Gras
782fe8fb19SBen Gras /*
792fe8fb19SBen Gras * netconfig errors
802fe8fb19SBen Gras */
812fe8fb19SBen Gras
822fe8fb19SBen Gras #define NC_NONETCONFIG ENOENT
832fe8fb19SBen Gras #define NC_NOMEM ENOMEM
842fe8fb19SBen Gras #define NC_NOTINIT EINVAL /* setnetconfig was not called first */
852fe8fb19SBen Gras #define NC_BADFILE EBADF /* format for netconfig file is bad */
862fe8fb19SBen Gras
872fe8fb19SBen Gras /*
882fe8fb19SBen Gras * semantics as strings (should be in netconfig.h)
892fe8fb19SBen Gras */
902fe8fb19SBen Gras #define NC_TPI_CLTS_S "tpi_clts"
912fe8fb19SBen Gras #define NC_TPI_COTS_S "tpi_cots"
922fe8fb19SBen Gras #define NC_TPI_COTS_ORD_S "tpi_cots_ord"
932fe8fb19SBen Gras #define NC_TPI_RAW_S "tpi_raw"
942fe8fb19SBen Gras
952fe8fb19SBen Gras /*
962fe8fb19SBen Gras * flags as characters (also should be in netconfig.h)
972fe8fb19SBen Gras */
982fe8fb19SBen Gras #define NC_NOFLAG_C '-'
992fe8fb19SBen Gras #define NC_VISIBLE_C 'v'
1002fe8fb19SBen Gras #define NC_BROADCAST_C 'b'
1012fe8fb19SBen Gras
1022fe8fb19SBen Gras /*
1032fe8fb19SBen Gras * Character used to indicate there is no name-to-address lookup library
1042fe8fb19SBen Gras */
1052fe8fb19SBen Gras #define NC_NOLOOKUP "-"
1062fe8fb19SBen Gras
1072fe8fb19SBen Gras static const char * const _nc_errors[] = {
1082fe8fb19SBen Gras "Netconfig database not found",
1092fe8fb19SBen Gras "Not enough memory",
1102fe8fb19SBen Gras "Not initialized",
1112fe8fb19SBen Gras "Netconfig database has invalid format"
1122fe8fb19SBen Gras };
1132fe8fb19SBen Gras
1142fe8fb19SBen Gras struct netconfig_info {
1152fe8fb19SBen Gras int eof; /* all entries has been read */
1162fe8fb19SBen Gras int ref; /* # of times setnetconfig() has been called */
1172fe8fb19SBen Gras struct netconfig_list *head; /* head of the list */
1182fe8fb19SBen Gras struct netconfig_list *tail; /* last of the list */
1192fe8fb19SBen Gras };
1202fe8fb19SBen Gras
1212fe8fb19SBen Gras struct netconfig_list {
1222fe8fb19SBen Gras char *linep; /* hold line read from netconfig */
1232fe8fb19SBen Gras struct netconfig *ncp;
1242fe8fb19SBen Gras struct netconfig_list *next;
1252fe8fb19SBen Gras };
1262fe8fb19SBen Gras
1272fe8fb19SBen Gras struct netconfig_vars {
1282fe8fb19SBen Gras int valid; /* token that indicates valid netconfig_vars */
1292fe8fb19SBen Gras int flag; /* first time flag */
1302fe8fb19SBen Gras struct netconfig_list *nc_configs;
1312fe8fb19SBen Gras /* pointer to the current netconfig entry */
1322fe8fb19SBen Gras };
1332fe8fb19SBen Gras
1342fe8fb19SBen Gras #define NC_VALID 0xfeed
1352fe8fb19SBen Gras #define NC_STORAGE 0xf00d
1362fe8fb19SBen Gras #define NC_INVALID 0
1372fe8fb19SBen Gras
1382fe8fb19SBen Gras
139f14fb602SLionel Sambuc static int *__nc_error(void);
140f14fb602SLionel Sambuc static int parse_ncp(char *, struct netconfig *);
141f14fb602SLionel Sambuc static struct netconfig *dup_ncp(struct netconfig *);
1422fe8fb19SBen Gras
1432fe8fb19SBen Gras
1442fe8fb19SBen Gras static FILE *nc_file; /* for netconfig db */
1452fe8fb19SBen Gras static struct netconfig_info ni = { 0, 0, NULL, NULL};
1462fe8fb19SBen Gras
1472fe8fb19SBen Gras #define MAXNETCONFIGLINE 1000
1482fe8fb19SBen Gras
1492fe8fb19SBen Gras #ifdef _REENTRANT
1502fe8fb19SBen Gras static thread_key_t nc_key;
1512fe8fb19SBen Gras static once_t nc_once = ONCE_INITIALIZER;
1522fe8fb19SBen Gras
1532fe8fb19SBen Gras static void
__nc_error_setup(void)1542fe8fb19SBen Gras __nc_error_setup(void)
1552fe8fb19SBen Gras {
1562fe8fb19SBen Gras thr_keycreate(&nc_key, free);
1572fe8fb19SBen Gras }
1582fe8fb19SBen Gras #endif
1592fe8fb19SBen Gras
1602fe8fb19SBen Gras static int *
__nc_error(void)161f14fb602SLionel Sambuc __nc_error(void)
1622fe8fb19SBen Gras {
1632fe8fb19SBen Gras #ifdef _REENTRANT
1642fe8fb19SBen Gras int *nc_addr = NULL;
1652fe8fb19SBen Gras #endif
1662fe8fb19SBen Gras static int nc_error = 0;
1672fe8fb19SBen Gras
1682fe8fb19SBen Gras #ifdef _REENTRANT
1692fe8fb19SBen Gras if (__isthreaded == 0)
1702fe8fb19SBen Gras return &nc_error;
1712fe8fb19SBen Gras thr_once(&nc_once, __nc_error_setup);
1722fe8fb19SBen Gras nc_addr = thr_getspecific(nc_key) ;
1732fe8fb19SBen Gras if (nc_addr == NULL) {
1742fe8fb19SBen Gras nc_addr = malloc(sizeof (int));
1752fe8fb19SBen Gras if (nc_addr == NULL)
1762fe8fb19SBen Gras return &nc_error;
1772fe8fb19SBen Gras if (thr_setspecific(nc_key, (void *) nc_addr) != 0) {
1782fe8fb19SBen Gras if (nc_addr)
1792fe8fb19SBen Gras free(nc_addr);
1802fe8fb19SBen Gras return &nc_error;
1812fe8fb19SBen Gras }
1822fe8fb19SBen Gras *nc_addr = 0;
1832fe8fb19SBen Gras }
1842fe8fb19SBen Gras return nc_addr;
1852fe8fb19SBen Gras #else
1862fe8fb19SBen Gras return &nc_error;
1872fe8fb19SBen Gras #endif
1882fe8fb19SBen Gras }
1892fe8fb19SBen Gras
1902fe8fb19SBen Gras #define nc_error (*(__nc_error()))
1912fe8fb19SBen Gras /*
1922fe8fb19SBen Gras * A call to setnetconfig() establishes a /etc/netconfig "session". A session
1932fe8fb19SBen Gras * "handle" is returned on a successful call. At the start of a session (after
1942fe8fb19SBen Gras * a call to setnetconfig()) searches through the /etc/netconfig database will
1952fe8fb19SBen Gras * proceed from the start of the file. The session handle must be passed to
1962fe8fb19SBen Gras * getnetconfig() to parse the file. Each call to getnetconfig() using the
1972fe8fb19SBen Gras * current handle will process one subsequent entry in /etc/netconfig.
1982fe8fb19SBen Gras * setnetconfig() must be called before the first call to getnetconfig().
1992fe8fb19SBen Gras * (Handles are used to allow for nested calls to setnetpath()).
2002fe8fb19SBen Gras *
2012fe8fb19SBen Gras * A new session is established with each call to setnetconfig(), with a new
2022fe8fb19SBen Gras * handle being returned on each call. Previously established sessions remain
2032fe8fb19SBen Gras * active until endnetconfig() is called with that session's handle as an
2042fe8fb19SBen Gras * argument.
2052fe8fb19SBen Gras *
2062fe8fb19SBen Gras * setnetconfig() need *not* be called before a call to getnetconfigent().
2072fe8fb19SBen Gras * setnetconfig() returns a NULL pointer on failure (for example, if
2082fe8fb19SBen Gras * the netconfig database is not present).
2092fe8fb19SBen Gras */
2102fe8fb19SBen Gras void *
setnetconfig(void)211f14fb602SLionel Sambuc setnetconfig(void)
2122fe8fb19SBen Gras {
2132fe8fb19SBen Gras struct netconfig_vars *nc_vars;
2142fe8fb19SBen Gras
2152fe8fb19SBen Gras if ((nc_vars = malloc(sizeof(*nc_vars))) == NULL) {
2162fe8fb19SBen Gras return(NULL);
2172fe8fb19SBen Gras }
2182fe8fb19SBen Gras
2192fe8fb19SBen Gras /*
2202fe8fb19SBen Gras * For multiple calls, i.e. nc_file is not NULL, we just return the
2212fe8fb19SBen Gras * handle without reopening the netconfig db.
2222fe8fb19SBen Gras */
2232fe8fb19SBen Gras ni.ref++;
224f14fb602SLionel Sambuc if ((nc_file != NULL) || (nc_file = fopen(NETCONFIG, "re")) != NULL) {
2252fe8fb19SBen Gras nc_vars->valid = NC_VALID;
2262fe8fb19SBen Gras nc_vars->flag = 0;
2272fe8fb19SBen Gras nc_vars->nc_configs = ni.head;
2282fe8fb19SBen Gras return ((void *)nc_vars);
2292fe8fb19SBen Gras }
2302fe8fb19SBen Gras ni.ref--;
2312fe8fb19SBen Gras nc_error = NC_NONETCONFIG;
2322fe8fb19SBen Gras free(nc_vars);
2332fe8fb19SBen Gras return (NULL);
2342fe8fb19SBen Gras }
2352fe8fb19SBen Gras
2362fe8fb19SBen Gras
2372fe8fb19SBen Gras /*
2382fe8fb19SBen Gras * When first called, getnetconfig() returns a pointer to the first entry in
2392fe8fb19SBen Gras * the netconfig database, formatted as a struct netconfig. On each subsequent
2402fe8fb19SBen Gras * call, getnetconfig() returns a pointer to the next entry in the database.
2412fe8fb19SBen Gras * getnetconfig() can thus be used to search the entire netconfig file.
2422fe8fb19SBen Gras * getnetconfig() returns NULL at end of file.
2432fe8fb19SBen Gras */
2442fe8fb19SBen Gras
2452fe8fb19SBen Gras struct netconfig *
getnetconfig(void * handlep)246f14fb602SLionel Sambuc getnetconfig(void *handlep)
2472fe8fb19SBen Gras {
2482fe8fb19SBen Gras struct netconfig_vars *ncp = (struct netconfig_vars *)handlep;
2492fe8fb19SBen Gras char *stringp; /* tmp string pointer */
2502fe8fb19SBen Gras struct netconfig_list *list;
2512fe8fb19SBen Gras struct netconfig *np;
2522fe8fb19SBen Gras
2532fe8fb19SBen Gras /*
2542fe8fb19SBen Gras * Verify that handle is valid
2552fe8fb19SBen Gras */
2562fe8fb19SBen Gras if (ncp == NULL || nc_file == NULL) {
2572fe8fb19SBen Gras nc_error = NC_NOTINIT;
2582fe8fb19SBen Gras return (NULL);
2592fe8fb19SBen Gras }
2602fe8fb19SBen Gras
2612fe8fb19SBen Gras switch (ncp->valid) {
2622fe8fb19SBen Gras case NC_VALID:
2632fe8fb19SBen Gras /*
2642fe8fb19SBen Gras * If entry has already been read into the list,
2652fe8fb19SBen Gras * we return the entry in the linked list.
2662fe8fb19SBen Gras * If this is the first time call, check if there are any
2672fe8fb19SBen Gras * entries in linked list. If no entries, we need to read the
2682fe8fb19SBen Gras * netconfig db.
2692fe8fb19SBen Gras * If we have been here and the next entry is there, we just
2702fe8fb19SBen Gras * return it.
2712fe8fb19SBen Gras */
2722fe8fb19SBen Gras if (ncp->flag == 0) { /* first time */
2732fe8fb19SBen Gras ncp->flag = 1;
2742fe8fb19SBen Gras ncp->nc_configs = ni.head;
2752fe8fb19SBen Gras if (ncp->nc_configs != NULL) /* entry already exist */
2762fe8fb19SBen Gras return(ncp->nc_configs->ncp);
2772fe8fb19SBen Gras }
2782fe8fb19SBen Gras else if (ncp->nc_configs != NULL &&
2792fe8fb19SBen Gras ncp->nc_configs->next != NULL) {
2802fe8fb19SBen Gras ncp->nc_configs = ncp->nc_configs->next;
2812fe8fb19SBen Gras return(ncp->nc_configs->ncp);
2822fe8fb19SBen Gras }
2832fe8fb19SBen Gras
2842fe8fb19SBen Gras /*
2852fe8fb19SBen Gras * If we cannot find the entry in the list and is end of file,
2862fe8fb19SBen Gras * we give up.
2872fe8fb19SBen Gras */
2882fe8fb19SBen Gras if (ni.eof == 1)
2892fe8fb19SBen Gras return(NULL);
2902fe8fb19SBen Gras break;
2912fe8fb19SBen Gras default:
2922fe8fb19SBen Gras nc_error = NC_NOTINIT;
2932fe8fb19SBen Gras return (NULL);
2942fe8fb19SBen Gras }
2952fe8fb19SBen Gras
2962fe8fb19SBen Gras stringp = malloc(MAXNETCONFIGLINE);
2972fe8fb19SBen Gras if (stringp == NULL)
2982fe8fb19SBen Gras return (NULL);
2992fe8fb19SBen Gras
3002fe8fb19SBen Gras #ifdef MEM_CHK
3012fe8fb19SBen Gras if (malloc_verify() == 0) {
3022fe8fb19SBen Gras fprintf(stderr, "memory heap corrupted in getnetconfig\n");
3032fe8fb19SBen Gras exit(1);
3042fe8fb19SBen Gras }
3052fe8fb19SBen Gras #endif
3062fe8fb19SBen Gras
3072fe8fb19SBen Gras /*
3082fe8fb19SBen Gras * Read a line from netconfig file.
3092fe8fb19SBen Gras */
3102fe8fb19SBen Gras do {
3112fe8fb19SBen Gras if (fgets(stringp, MAXNETCONFIGLINE, nc_file) == NULL) {
3122fe8fb19SBen Gras free(stringp);
3132fe8fb19SBen Gras ni.eof = 1;
3142fe8fb19SBen Gras return (NULL);
3152fe8fb19SBen Gras }
3162fe8fb19SBen Gras } while (*stringp == '#');
3172fe8fb19SBen Gras
3182fe8fb19SBen Gras list = malloc(sizeof(*list));
3192fe8fb19SBen Gras if (list == NULL) {
3202fe8fb19SBen Gras free(stringp);
3212fe8fb19SBen Gras return(NULL);
3222fe8fb19SBen Gras }
3232fe8fb19SBen Gras np = malloc(sizeof(*np));
3242fe8fb19SBen Gras if (np == NULL) {
3252fe8fb19SBen Gras free(stringp);
3262fe8fb19SBen Gras free(list);
3272fe8fb19SBen Gras return(NULL);
3282fe8fb19SBen Gras }
3292fe8fb19SBen Gras list->ncp = np;
3302fe8fb19SBen Gras list->next = NULL;
3312fe8fb19SBen Gras list->ncp->nc_lookups = NULL;
3322fe8fb19SBen Gras list->linep = stringp;
3332fe8fb19SBen Gras if (parse_ncp(stringp, list->ncp) == -1) {
3342fe8fb19SBen Gras free(stringp);
3352fe8fb19SBen Gras free(np);
3362fe8fb19SBen Gras free(list);
3372fe8fb19SBen Gras return (NULL);
3382fe8fb19SBen Gras } else {
3392fe8fb19SBen Gras /*
3402fe8fb19SBen Gras * If this is the first entry that's been read, it is the
3412fe8fb19SBen Gras * head of the list. If not, put the entry at the end of
3422fe8fb19SBen Gras * the list. Reposition the current pointer of the handle to
3432fe8fb19SBen Gras * the last entry in the list.
3442fe8fb19SBen Gras */
3452fe8fb19SBen Gras if (ni.head == NULL) /* first entry */
3462fe8fb19SBen Gras ni.head = ni.tail = list;
3472fe8fb19SBen Gras else {
3482fe8fb19SBen Gras ni.tail->next = list;
3492fe8fb19SBen Gras ni.tail = ni.tail->next;
3502fe8fb19SBen Gras }
3512fe8fb19SBen Gras ncp->nc_configs = ni.tail;
3522fe8fb19SBen Gras return(ni.tail->ncp);
3532fe8fb19SBen Gras }
3542fe8fb19SBen Gras }
3552fe8fb19SBen Gras
3562fe8fb19SBen Gras /*
3572fe8fb19SBen Gras * endnetconfig() may be called to "unbind" or "close" the netconfig database
3582fe8fb19SBen Gras * when processing is complete, releasing resources for reuse. endnetconfig()
3592fe8fb19SBen Gras * may not be called before setnetconfig(). endnetconfig() returns 0 on
3602fe8fb19SBen Gras * success and -1 on failure (for example, if setnetconfig() was not called
3612fe8fb19SBen Gras * previously).
3622fe8fb19SBen Gras */
3632fe8fb19SBen Gras int
endnetconfig(void * handlep)364f14fb602SLionel Sambuc endnetconfig(void *handlep)
3652fe8fb19SBen Gras {
3662fe8fb19SBen Gras struct netconfig_vars *nc_handlep = (struct netconfig_vars *)handlep;
3672fe8fb19SBen Gras
3682fe8fb19SBen Gras struct netconfig_list *q, *p;
3692fe8fb19SBen Gras
3702fe8fb19SBen Gras /*
3712fe8fb19SBen Gras * Verify that handle is valid
3722fe8fb19SBen Gras */
3732fe8fb19SBen Gras if (nc_handlep == NULL || (nc_handlep->valid != NC_VALID &&
3742fe8fb19SBen Gras nc_handlep->valid != NC_STORAGE)) {
3752fe8fb19SBen Gras nc_error = NC_NOTINIT;
3762fe8fb19SBen Gras return (-1);
3772fe8fb19SBen Gras }
3782fe8fb19SBen Gras
3792fe8fb19SBen Gras /*
3802fe8fb19SBen Gras * Return 0 if anyone still needs it.
3812fe8fb19SBen Gras */
3822fe8fb19SBen Gras nc_handlep->valid = NC_INVALID;
3832fe8fb19SBen Gras nc_handlep->flag = 0;
3842fe8fb19SBen Gras nc_handlep->nc_configs = NULL;
3852fe8fb19SBen Gras if (--ni.ref > 0) {
3862fe8fb19SBen Gras free(nc_handlep);
3872fe8fb19SBen Gras return(0);
3882fe8fb19SBen Gras }
3892fe8fb19SBen Gras
3902fe8fb19SBen Gras /*
3912fe8fb19SBen Gras * Noone needs these entries anymore, then frees them.
3922fe8fb19SBen Gras * Make sure all info in netconfig_info structure has been
3932fe8fb19SBen Gras * reinitialized.
3942fe8fb19SBen Gras */
3952fe8fb19SBen Gras q = p = ni.head;
3962fe8fb19SBen Gras ni.eof = ni.ref = 0;
3972fe8fb19SBen Gras ni.head = NULL;
3982fe8fb19SBen Gras ni.tail = NULL;
3992fe8fb19SBen Gras while (q) {
4002fe8fb19SBen Gras p = q->next;
4012fe8fb19SBen Gras if (q->ncp->nc_lookups != NULL) free(q->ncp->nc_lookups);
4022fe8fb19SBen Gras free(q->ncp);
4032fe8fb19SBen Gras free(q->linep);
4042fe8fb19SBen Gras free(q);
4052fe8fb19SBen Gras q = p;
4062fe8fb19SBen Gras }
4072fe8fb19SBen Gras free(nc_handlep);
4082fe8fb19SBen Gras
4092fe8fb19SBen Gras fclose(nc_file);
4102fe8fb19SBen Gras nc_file = NULL;
4112fe8fb19SBen Gras return (0);
4122fe8fb19SBen Gras }
4132fe8fb19SBen Gras
4142fe8fb19SBen Gras /*
4152fe8fb19SBen Gras * getnetconfigent(netid) returns a pointer to the struct netconfig structure
4162fe8fb19SBen Gras * corresponding to netid. It returns NULL if netid is invalid (that is, does
4172fe8fb19SBen Gras * not name an entry in the netconfig database). It returns NULL and sets
4182fe8fb19SBen Gras * errno in case of failure (for example, if the netconfig database cannot be
4192fe8fb19SBen Gras * opened).
4202fe8fb19SBen Gras */
4212fe8fb19SBen Gras
4222fe8fb19SBen Gras struct netconfig *
getnetconfigent(const char * netid)423f14fb602SLionel Sambuc getnetconfigent(const char *netid)
4242fe8fb19SBen Gras {
4252fe8fb19SBen Gras FILE *file; /* NETCONFIG db's file pointer */
4262fe8fb19SBen Gras char *linep; /* holds current netconfig line */
4272fe8fb19SBen Gras char *stringp; /* temporary string pointer */
4282fe8fb19SBen Gras struct netconfig *ncp = NULL; /* returned value */
4292fe8fb19SBen Gras struct netconfig_list *list; /* pointer to cache list */
4302fe8fb19SBen Gras
4312fe8fb19SBen Gras if (netid == NULL || strlen(netid) == 0)
4322fe8fb19SBen Gras return (NULL);
4332fe8fb19SBen Gras
4342fe8fb19SBen Gras /*
4352fe8fb19SBen Gras * Look up table if the entries have already been read and parsed in
4362fe8fb19SBen Gras * getnetconfig(), then copy this entry into a buffer and return it.
4372fe8fb19SBen Gras * If we cannot find the entry in the current list and there are more
4382fe8fb19SBen Gras * entries in the netconfig db that has not been read, we then read the
4392fe8fb19SBen Gras * db and try find the match netid.
4402fe8fb19SBen Gras * If all the netconfig db has been read and placed into the list and
4412fe8fb19SBen Gras * there is no match for the netid, return NULL.
4422fe8fb19SBen Gras */
4432fe8fb19SBen Gras if (ni.head != NULL) {
4442fe8fb19SBen Gras for (list = ni.head; list; list = list->next) {
4452fe8fb19SBen Gras if (strcmp(list->ncp->nc_netid, netid) == 0)
4462fe8fb19SBen Gras return(dup_ncp(list->ncp));
4472fe8fb19SBen Gras }
4482fe8fb19SBen Gras if (ni.eof == 1) /* that's all the entries */
4492fe8fb19SBen Gras return(NULL);
4502fe8fb19SBen Gras }
4512fe8fb19SBen Gras
452*0a6a1f1dSLionel Sambuc if ((file = fopen(NETCONFIG, "re")) == NULL)
4532fe8fb19SBen Gras return (NULL);
4542fe8fb19SBen Gras
4552fe8fb19SBen Gras if ((linep = malloc(MAXNETCONFIGLINE)) == NULL) {
4562fe8fb19SBen Gras fclose(file);
4572fe8fb19SBen Gras return (NULL);
4582fe8fb19SBen Gras }
4592fe8fb19SBen Gras do {
4602fe8fb19SBen Gras ptrdiff_t len;
4612fe8fb19SBen Gras char *tmpp; /* tmp string pointer */
4622fe8fb19SBen Gras
4632fe8fb19SBen Gras do {
4642fe8fb19SBen Gras if ((stringp = fgets(linep, MAXNETCONFIGLINE, file))
4652fe8fb19SBen Gras == NULL)
4662fe8fb19SBen Gras break;
4672fe8fb19SBen Gras } while (*stringp == '#');
4682fe8fb19SBen Gras if (stringp == NULL) /* eof */
4692fe8fb19SBen Gras break;
4702fe8fb19SBen Gras if ((tmpp = strpbrk(stringp, "\t ")) == NULL) {
4712fe8fb19SBen Gras /* can't parse file */
4722fe8fb19SBen Gras nc_error = NC_BADFILE;
4732fe8fb19SBen Gras break;
4742fe8fb19SBen Gras }
4752fe8fb19SBen Gras if (strlen(netid) == (size_t) (len = tmpp - stringp) && /* a match */
4762fe8fb19SBen Gras strncmp(stringp, netid, (size_t)len) == 0) {
4772fe8fb19SBen Gras if ((ncp = malloc(sizeof(*ncp))) == NULL)
4782fe8fb19SBen Gras break;
4792fe8fb19SBen Gras ncp->nc_lookups = NULL;
4802fe8fb19SBen Gras if (parse_ncp(linep, ncp) == -1) {
4812fe8fb19SBen Gras free(ncp);
4822fe8fb19SBen Gras ncp = NULL;
4832fe8fb19SBen Gras }
4842fe8fb19SBen Gras break;
4852fe8fb19SBen Gras }
4862fe8fb19SBen Gras } while (stringp != NULL);
4872fe8fb19SBen Gras if (ncp == NULL)
4882fe8fb19SBen Gras free(linep);
4892fe8fb19SBen Gras fclose(file);
4902fe8fb19SBen Gras return(ncp);
4912fe8fb19SBen Gras }
4922fe8fb19SBen Gras
4932fe8fb19SBen Gras /*
4942fe8fb19SBen Gras * freenetconfigent(netconfigp) frees the netconfig structure pointed to by
4952fe8fb19SBen Gras * netconfigp (previously returned by getnetconfigent()).
4962fe8fb19SBen Gras */
4972fe8fb19SBen Gras
4982fe8fb19SBen Gras void
freenetconfigent(struct netconfig * netconfigp)499f14fb602SLionel Sambuc freenetconfigent(struct netconfig *netconfigp)
5002fe8fb19SBen Gras {
5012fe8fb19SBen Gras if (netconfigp != NULL) {
5022fe8fb19SBen Gras /* holds all netconfigp's strings */
5032fe8fb19SBen Gras free(netconfigp->nc_netid);
5042fe8fb19SBen Gras if (netconfigp->nc_lookups != NULL)
5052fe8fb19SBen Gras free(netconfigp->nc_lookups);
5062fe8fb19SBen Gras free(netconfigp);
5072fe8fb19SBen Gras }
5082fe8fb19SBen Gras }
5092fe8fb19SBen Gras
5102fe8fb19SBen Gras /*
5112fe8fb19SBen Gras * Parse line and stuff it in a struct netconfig
5122fe8fb19SBen Gras * Typical line might look like:
5132fe8fb19SBen Gras * udp tpi_cots vb inet udp /dev/udp /usr/lib/ip.so,/usr/local/ip.so
5142fe8fb19SBen Gras *
5152fe8fb19SBen Gras * We return -1 if any of the tokens don't parse, or malloc fails.
5162fe8fb19SBen Gras *
5172fe8fb19SBen Gras * Note that we modify stringp (putting NULLs after tokens) and
5182fe8fb19SBen Gras * we set the ncp's string field pointers to point to these tokens within
5192fe8fb19SBen Gras * stringp.
5202fe8fb19SBen Gras */
5212fe8fb19SBen Gras
5222fe8fb19SBen Gras static int
parse_ncp(char * stringp,struct netconfig * ncp)523f14fb602SLionel Sambuc parse_ncp(
524f14fb602SLionel Sambuc char *stringp, /* string to parse */
525f14fb602SLionel Sambuc struct netconfig *ncp) /* where to put results */
5262fe8fb19SBen Gras {
5272fe8fb19SBen Gras char *tokenp; /* for processing tokens */
5282fe8fb19SBen Gras char *lasts;
5292fe8fb19SBen Gras
5302fe8fb19SBen Gras _DIAGASSERT(stringp != NULL);
5312fe8fb19SBen Gras _DIAGASSERT(ncp != NULL);
5322fe8fb19SBen Gras
5332fe8fb19SBen Gras nc_error = NC_BADFILE;
5342fe8fb19SBen Gras /* nearly anything that breaks is for this reason */
5352fe8fb19SBen Gras stringp[strlen(stringp)-1] = '\0'; /* get rid of newline */
5362fe8fb19SBen Gras /* netid */
5372fe8fb19SBen Gras if ((ncp->nc_netid = strtok_r(stringp, "\t ", &lasts)) == NULL)
5382fe8fb19SBen Gras return (-1);
5392fe8fb19SBen Gras
5402fe8fb19SBen Gras /* semantics */
5412fe8fb19SBen Gras if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL)
5422fe8fb19SBen Gras return (-1);
5432fe8fb19SBen Gras if (strcmp(tokenp, NC_TPI_COTS_ORD_S) == 0)
5442fe8fb19SBen Gras ncp->nc_semantics = NC_TPI_COTS_ORD;
5452fe8fb19SBen Gras else if (strcmp(tokenp, NC_TPI_COTS_S) == 0)
5462fe8fb19SBen Gras ncp->nc_semantics = NC_TPI_COTS;
5472fe8fb19SBen Gras else if (strcmp(tokenp, NC_TPI_CLTS_S) == 0)
5482fe8fb19SBen Gras ncp->nc_semantics = NC_TPI_CLTS;
5492fe8fb19SBen Gras else if (strcmp(tokenp, NC_TPI_RAW_S) == 0)
5502fe8fb19SBen Gras ncp->nc_semantics = NC_TPI_RAW;
5512fe8fb19SBen Gras else
5522fe8fb19SBen Gras return (-1);
5532fe8fb19SBen Gras
5542fe8fb19SBen Gras /* flags */
5552fe8fb19SBen Gras if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL)
5562fe8fb19SBen Gras return (-1);
5572fe8fb19SBen Gras for (ncp->nc_flag = NC_NOFLAG; *tokenp != '\0'; tokenp++) {
5582fe8fb19SBen Gras switch (*tokenp) {
5592fe8fb19SBen Gras case NC_NOFLAG_C:
5602fe8fb19SBen Gras break;
5612fe8fb19SBen Gras case NC_VISIBLE_C:
5622fe8fb19SBen Gras ncp->nc_flag |= NC_VISIBLE;
5632fe8fb19SBen Gras break;
5642fe8fb19SBen Gras case NC_BROADCAST_C:
5652fe8fb19SBen Gras ncp->nc_flag |= NC_BROADCAST;
5662fe8fb19SBen Gras break;
5672fe8fb19SBen Gras default:
5682fe8fb19SBen Gras return (-1);
5692fe8fb19SBen Gras }
5702fe8fb19SBen Gras }
5712fe8fb19SBen Gras /* protocol family */
5722fe8fb19SBen Gras if ((ncp->nc_protofmly = strtok_r(NULL, "\t ", &lasts)) == NULL)
5732fe8fb19SBen Gras return (-1);
5742fe8fb19SBen Gras /* protocol name */
5752fe8fb19SBen Gras if ((ncp->nc_proto = strtok_r(NULL, "\t ", &lasts)) == NULL)
5762fe8fb19SBen Gras return (-1);
5772fe8fb19SBen Gras /* network device */
5782fe8fb19SBen Gras if ((ncp->nc_device = strtok_r(NULL, "\t ", &lasts)) == NULL)
5792fe8fb19SBen Gras return (-1);
5802fe8fb19SBen Gras if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL)
5812fe8fb19SBen Gras return (-1);
5822fe8fb19SBen Gras if (strcmp(tokenp, NC_NOLOOKUP) == 0) {
5832fe8fb19SBen Gras ncp->nc_nlookups = 0;
5842fe8fb19SBen Gras ncp->nc_lookups = NULL;
5852fe8fb19SBen Gras } else {
5862fe8fb19SBen Gras char *cp; /* tmp string */
5872fe8fb19SBen Gras
5882fe8fb19SBen Gras if (ncp->nc_lookups != NULL) /* from last visit */
5892fe8fb19SBen Gras free(ncp->nc_lookups);
5902fe8fb19SBen Gras /* preallocate one string pointer */
5912fe8fb19SBen Gras ncp->nc_lookups = malloc(sizeof(*ncp->nc_lookups));
5922fe8fb19SBen Gras ncp->nc_nlookups = 0;
5932fe8fb19SBen Gras while ((cp = tokenp) != NULL) {
5942fe8fb19SBen Gras tokenp = _get_next_token(cp, ',');
5952fe8fb19SBen Gras ncp->nc_lookups[(size_t)ncp->nc_nlookups++] = cp;
5962fe8fb19SBen Gras ncp->nc_lookups = (char **)
5972fe8fb19SBen Gras realloc(ncp->nc_lookups,
5982fe8fb19SBen Gras (size_t)(ncp->nc_nlookups+1) *sizeof(char *));
5992fe8fb19SBen Gras /* for next loop */
6002fe8fb19SBen Gras }
6012fe8fb19SBen Gras }
6022fe8fb19SBen Gras return (0);
6032fe8fb19SBen Gras }
6042fe8fb19SBen Gras
6052fe8fb19SBen Gras /*
6062fe8fb19SBen Gras * Returns a string describing the reason for failure.
6072fe8fb19SBen Gras */
6082fe8fb19SBen Gras char *
nc_sperror(void)609f14fb602SLionel Sambuc nc_sperror(void)
6102fe8fb19SBen Gras {
6112fe8fb19SBen Gras const char *message;
6122fe8fb19SBen Gras
6132fe8fb19SBen Gras switch(nc_error) {
6142fe8fb19SBen Gras case NC_NONETCONFIG:
6152fe8fb19SBen Gras message = _nc_errors[0];
6162fe8fb19SBen Gras break;
6172fe8fb19SBen Gras case NC_NOMEM:
6182fe8fb19SBen Gras message = _nc_errors[1];
6192fe8fb19SBen Gras break;
6202fe8fb19SBen Gras case NC_NOTINIT:
6212fe8fb19SBen Gras message = _nc_errors[2];
6222fe8fb19SBen Gras break;
6232fe8fb19SBen Gras case NC_BADFILE:
6242fe8fb19SBen Gras message = _nc_errors[3];
6252fe8fb19SBen Gras break;
6262fe8fb19SBen Gras default:
6272fe8fb19SBen Gras message = "Unknown network selection error";
6282fe8fb19SBen Gras }
6292fe8fb19SBen Gras return __UNCONST(message);
6302fe8fb19SBen Gras }
6312fe8fb19SBen Gras
6322fe8fb19SBen Gras /*
6332fe8fb19SBen Gras * Prints a message onto standard error describing the reason for failure.
6342fe8fb19SBen Gras */
6352fe8fb19SBen Gras void
nc_perror(const char * s)636f14fb602SLionel Sambuc nc_perror(const char *s)
6372fe8fb19SBen Gras {
6382fe8fb19SBen Gras
6392fe8fb19SBen Gras _DIAGASSERT(s != NULL);
6402fe8fb19SBen Gras
6412fe8fb19SBen Gras fprintf(stderr, "%s: %s", s, nc_sperror());
6422fe8fb19SBen Gras }
6432fe8fb19SBen Gras
6442fe8fb19SBen Gras /*
6452fe8fb19SBen Gras * Duplicates the matched netconfig buffer.
6462fe8fb19SBen Gras */
6472fe8fb19SBen Gras static struct netconfig *
dup_ncp(struct netconfig * ncp)648f14fb602SLionel Sambuc dup_ncp(struct netconfig *ncp)
6492fe8fb19SBen Gras {
6502fe8fb19SBen Gras struct netconfig *p;
6512fe8fb19SBen Gras char *tmp;
6522fe8fb19SBen Gras u_int i;
6532fe8fb19SBen Gras
6542fe8fb19SBen Gras _DIAGASSERT(ncp != NULL);
6552fe8fb19SBen Gras
6562fe8fb19SBen Gras if ((tmp = malloc(MAXNETCONFIGLINE)) == NULL)
6572fe8fb19SBen Gras return(NULL);
6582fe8fb19SBen Gras if ((p = malloc(sizeof(*p))) == NULL) {
6592fe8fb19SBen Gras free(tmp);
6602fe8fb19SBen Gras return(NULL);
6612fe8fb19SBen Gras }
6622fe8fb19SBen Gras /*
6632fe8fb19SBen Gras * First we dup all the data from matched netconfig buffer. Then we
6642fe8fb19SBen Gras * adjust some of the member pointer to a pre-allocated buffer where
6652fe8fb19SBen Gras * contains part of the data.
6662fe8fb19SBen Gras * To follow the convention used in parse_ncp(), we store all the
6672fe8fb19SBen Gras * necessary information in the pre-allocated buffer and let each
6682fe8fb19SBen Gras * of the netconfig char pointer member point to the right address
6692fe8fb19SBen Gras * in the buffer.
6702fe8fb19SBen Gras */
6712fe8fb19SBen Gras *p = *ncp;
6722fe8fb19SBen Gras p->nc_netid = (char *)strcpy(tmp,ncp->nc_netid);
6732fe8fb19SBen Gras tmp = strchr(tmp, '\0') + 1;
6742fe8fb19SBen Gras p->nc_protofmly = (char *)strcpy(tmp,ncp->nc_protofmly);
6752fe8fb19SBen Gras tmp = strchr(tmp, '\0') + 1;
6762fe8fb19SBen Gras p->nc_proto = (char *)strcpy(tmp,ncp->nc_proto);
6772fe8fb19SBen Gras tmp = strchr(tmp, '\0') + 1;
6782fe8fb19SBen Gras p->nc_device = (char *)strcpy(tmp,ncp->nc_device);
6792fe8fb19SBen Gras p->nc_lookups = malloc((size_t)(p->nc_nlookups+1) * sizeof(char *));
6802fe8fb19SBen Gras if (p->nc_lookups == NULL) {
6812fe8fb19SBen Gras free(p->nc_netid);
6822fe8fb19SBen Gras free(p);
6832fe8fb19SBen Gras return(NULL);
6842fe8fb19SBen Gras }
6852fe8fb19SBen Gras for (i=0; i < p->nc_nlookups; i++) {
6862fe8fb19SBen Gras tmp = strchr(tmp, '\0') + 1;
6872fe8fb19SBen Gras p->nc_lookups[i] = strcpy(tmp,ncp->nc_lookups[i]);
6882fe8fb19SBen Gras }
6892fe8fb19SBen Gras return(p);
6902fe8fb19SBen Gras }
691