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