174462Salfred/* $NetBSD: getnetconfig.c,v 1.3 2000/07/06 03:10:34 christos Exp $ */ 274462Salfred 3261046Smav/*- 4261046Smav * Copyright (c) 2009, Sun Microsystems, Inc. 5261046Smav * All rights reserved. 674462Salfred * 7261046Smav * Redistribution and use in source and binary forms, with or without 8261046Smav * modification, are permitted provided that the following conditions are met: 9261046Smav * - Redistributions of source code must retain the above copyright notice, 10261046Smav * this list of conditions and the following disclaimer. 11261046Smav * - Redistributions in binary form must reproduce the above copyright notice, 12261046Smav * this list of conditions and the following disclaimer in the documentation 13261046Smav * and/or other materials provided with the distribution. 14261046Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its 15261046Smav * contributors may be used to endorse or promote products derived 16261046Smav * from this software without specific prior written permission. 17261046Smav * 18261046Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19261046Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20261046Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21261046Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22261046Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23261046Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24261046Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25261046Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26261046Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27261046Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28261046Smav * POSSIBILITY OF SUCH DAMAGE. 2974462Salfred */ 30136581Sobrien 31136581Sobrien#if defined(LIBC_SCCS) && !defined(lint) 32136581Sobrienstatic char sccsid[] = "@(#)getnetconfig.c 1.12 91/12/19 SMI"; 3374462Salfred#endif 3492990Sobrien#include <sys/cdefs.h> 3592990Sobrien__FBSDID("$FreeBSD: stable/10/lib/libc/rpc/getnetconfig.c 320582 2017-07-03 02:14:42Z delphij $"); 3674462Salfred 3774462Salfred/* 3874462Salfred * Copyright (c) 1989 by Sun Microsystems, Inc. 3974462Salfred */ 4074462Salfred 4175094Siedowse#include "namespace.h" 4274462Salfred#include "reentrant.h" 4374462Salfred#include <stdio.h> 4474462Salfred#include <errno.h> 4574462Salfred#include <netconfig.h> 46109956Smbr#include <stddef.h> 4774462Salfred#include <stdlib.h> 4874462Salfred#include <string.h> 4974462Salfred#include <rpc/rpc.h> 50111010Snectar#include <unistd.h> 5174462Salfred#include "un-namespace.h" 5274462Salfred#include "rpc_com.h" 5374462Salfred 5474462Salfred/* 5574462Salfred * The five library routines in this file provide application access to the 5674462Salfred * system network configuration database, /etc/netconfig. In addition to the 5774462Salfred * netconfig database and the routines for accessing it, the environment 5874462Salfred * variable NETPATH and its corresponding routines in getnetpath.c may also be 5974462Salfred * used to specify the network transport to be used. 6074462Salfred */ 6174462Salfred 6274462Salfred 6374462Salfred/* 6474462Salfred * netconfig errors 6574462Salfred */ 6674462Salfred 6774462Salfred#define NC_NONETCONFIG ENOENT 6874462Salfred#define NC_NOMEM ENOMEM 6974462Salfred#define NC_NOTINIT EINVAL /* setnetconfig was not called first */ 7074462Salfred#define NC_BADFILE EBADF /* format for netconfig file is bad */ 7175146Siedowse#define NC_NOTFOUND ENOPROTOOPT /* specified netid was not found */ 7274462Salfred 7374462Salfred/* 7474462Salfred * semantics as strings (should be in netconfig.h) 7574462Salfred */ 7674462Salfred#define NC_TPI_CLTS_S "tpi_clts" 7774462Salfred#define NC_TPI_COTS_S "tpi_cots" 7874462Salfred#define NC_TPI_COTS_ORD_S "tpi_cots_ord" 7974462Salfred#define NC_TPI_RAW_S "tpi_raw" 8074462Salfred 8174462Salfred/* 8274462Salfred * flags as characters (also should be in netconfig.h) 8374462Salfred */ 8474462Salfred#define NC_NOFLAG_C '-' 8574462Salfred#define NC_VISIBLE_C 'v' 8674462Salfred#define NC_BROADCAST_C 'b' 8774462Salfred 8874462Salfred/* 8974462Salfred * Character used to indicate there is no name-to-address lookup library 9074462Salfred */ 9174462Salfred#define NC_NOLOOKUP "-" 9274462Salfred 9374462Salfredstatic const char * const _nc_errors[] = { 9474462Salfred "Netconfig database not found", 9574462Salfred "Not enough memory", 9674462Salfred "Not initialized", 9775146Siedowse "Netconfig database has invalid format", 9875146Siedowse "Netid not found in netconfig database" 9974462Salfred}; 10074462Salfred 10174462Salfredstruct netconfig_info { 10274462Salfred int eof; /* all entries has been read */ 10374462Salfred int ref; /* # of times setnetconfig() has been called */ 10474462Salfred struct netconfig_list *head; /* head of the list */ 10574462Salfred struct netconfig_list *tail; /* last of the list */ 10674462Salfred}; 10774462Salfred 10874462Salfredstruct netconfig_list { 10974462Salfred char *linep; /* hold line read from netconfig */ 11074462Salfred struct netconfig *ncp; 11174462Salfred struct netconfig_list *next; 11274462Salfred}; 11374462Salfred 11474462Salfredstruct netconfig_vars { 11574462Salfred int valid; /* token that indicates a valid netconfig_vars */ 11674462Salfred int flag; /* first time flag */ 11774462Salfred struct netconfig_list *nc_configs; /* pointer to the current netconfig entry */ 11874462Salfred}; 11974462Salfred 12074462Salfred#define NC_VALID 0xfeed 12174462Salfred#define NC_STORAGE 0xf00d 12274462Salfred#define NC_INVALID 0 12374462Salfred 12474462Salfred 12592905Sobrienstatic int *__nc_error(void); 12692905Sobrienstatic int parse_ncp(char *, struct netconfig *); 12792905Sobrienstatic struct netconfig *dup_ncp(struct netconfig *); 12874462Salfred 12974462Salfred 13074462Salfredstatic FILE *nc_file; /* for netconfig db */ 131204950Sjhbstatic mutex_t nc_file_lock = MUTEX_INITIALIZER; 132194932Sdelphij 13374462Salfredstatic struct netconfig_info ni = { 0, 0, NULL, NULL}; 134204950Sjhbstatic mutex_t ni_lock = MUTEX_INITIALIZER; 13574462Salfred 136204950Sjhbstatic thread_key_t nc_key; 137204950Sjhbstatic once_t nc_once = ONCE_INITIALIZER; 138204950Sjhbstatic int nc_key_error; 139194932Sdelphij 140204950Sjhbstatic void 141204950Sjhbnc_key_init(void) 142204950Sjhb{ 143204950Sjhb 144204950Sjhb nc_key_error = thr_keycreate(&nc_key, free); 145204950Sjhb} 146204950Sjhb 14774462Salfred#define MAXNETCONFIGLINE 1000 14874462Salfred 14974462Salfredstatic int * 150309487Sngie__nc_error(void) 15174462Salfred{ 15274462Salfred static int nc_error = 0; 153204950Sjhb int *nc_addr; 15474462Salfred 15575146Siedowse /* 15675146Siedowse * Use the static `nc_error' if we are the main thread 15775146Siedowse * (including non-threaded programs), or if an allocation 15875146Siedowse * fails. 15975146Siedowse */ 16075146Siedowse if (thr_main()) 16175146Siedowse return (&nc_error); 162204950Sjhb if (thr_once(&nc_once, nc_key_init) != 0 || nc_key_error != 0) 163204950Sjhb return (&nc_error); 16475146Siedowse if ((nc_addr = (int *)thr_getspecific(nc_key)) == NULL) { 16574462Salfred nc_addr = (int *)malloc(sizeof (int)); 16674462Salfred if (thr_setspecific(nc_key, (void *) nc_addr) != 0) { 167290899Sngie free(nc_addr); 16875146Siedowse return (&nc_error); 16974462Salfred } 17074462Salfred *nc_addr = 0; 17174462Salfred } 17275146Siedowse return (nc_addr); 17374462Salfred} 17474462Salfred 17574462Salfred#define nc_error (*(__nc_error())) 17674462Salfred/* 17774462Salfred * A call to setnetconfig() establishes a /etc/netconfig "session". A session 17874462Salfred * "handle" is returned on a successful call. At the start of a session (after 17974462Salfred * a call to setnetconfig()) searches through the /etc/netconfig database will 18074462Salfred * proceed from the start of the file. The session handle must be passed to 18174462Salfred * getnetconfig() to parse the file. Each call to getnetconfig() using the 18274462Salfred * current handle will process one subsequent entry in /etc/netconfig. 18374462Salfred * setnetconfig() must be called before the first call to getnetconfig(). 18474462Salfred * (Handles are used to allow for nested calls to setnetpath()). 18574462Salfred * 18674462Salfred * A new session is established with each call to setnetconfig(), with a new 18774462Salfred * handle being returned on each call. Previously established sessions remain 18874462Salfred * active until endnetconfig() is called with that session's handle as an 18974462Salfred * argument. 19074462Salfred * 19174462Salfred * setnetconfig() need *not* be called before a call to getnetconfigent(). 19274462Salfred * setnetconfig() returns a NULL pointer on failure (for example, if 19374462Salfred * the netconfig database is not present). 19474462Salfred */ 19574462Salfredvoid * 196309487Sngiesetnetconfig(void) 19774462Salfred{ 19874462Salfred struct netconfig_vars *nc_vars; 19974462Salfred 20074462Salfred if ((nc_vars = (struct netconfig_vars *)malloc(sizeof 20174462Salfred (struct netconfig_vars))) == NULL) { 20274462Salfred return(NULL); 20374462Salfred } 20474462Salfred 20574462Salfred /* 20674462Salfred * For multiple calls, i.e. nc_file is not NULL, we just return the 20774462Salfred * handle without reopening the netconfig db. 20874462Salfred */ 209194932Sdelphij mutex_lock(&ni_lock); 21074462Salfred ni.ref++; 211194932Sdelphij mutex_unlock(&ni_lock); 212194932Sdelphij 213194932Sdelphij mutex_lock(&nc_file_lock); 21474462Salfred if ((nc_file != NULL) || (nc_file = fopen(NETCONFIG, "r")) != NULL) { 21574462Salfred nc_vars->valid = NC_VALID; 21674462Salfred nc_vars->flag = 0; 21774462Salfred nc_vars->nc_configs = ni.head; 218194932Sdelphij mutex_unlock(&nc_file_lock); 21974462Salfred return ((void *)nc_vars); 22074462Salfred } 221194932Sdelphij mutex_unlock(&nc_file_lock); 222194932Sdelphij 223194932Sdelphij mutex_lock(&ni_lock); 22474462Salfred ni.ref--; 225194932Sdelphij mutex_unlock(&ni_lock); 226194932Sdelphij 22774462Salfred nc_error = NC_NONETCONFIG; 22874462Salfred free(nc_vars); 22974462Salfred return (NULL); 23074462Salfred} 23174462Salfred 23274462Salfred 23374462Salfred/* 23474462Salfred * When first called, getnetconfig() returns a pointer to the first entry in 23574462Salfred * the netconfig database, formatted as a struct netconfig. On each subsequent 23674462Salfred * call, getnetconfig() returns a pointer to the next entry in the database. 23774462Salfred * getnetconfig() can thus be used to search the entire netconfig file. 23874462Salfred * getnetconfig() returns NULL at end of file. 23974462Salfred */ 24074462Salfred 24174462Salfredstruct netconfig * 242309487Sngiegetnetconfig(void *handlep) 24374462Salfred{ 24474462Salfred struct netconfig_vars *ncp = (struct netconfig_vars *)handlep; 24574462Salfred char *stringp; /* tmp string pointer */ 24674462Salfred struct netconfig_list *list; 24774462Salfred struct netconfig *np; 248194932Sdelphij struct netconfig *result; 24974462Salfred 25074462Salfred /* 25174462Salfred * Verify that handle is valid 25274462Salfred */ 253194932Sdelphij mutex_lock(&nc_file_lock); 25474462Salfred if (ncp == NULL || nc_file == NULL) { 25574462Salfred nc_error = NC_NOTINIT; 256194932Sdelphij mutex_unlock(&nc_file_lock); 25774462Salfred return (NULL); 25874462Salfred } 259194932Sdelphij mutex_unlock(&nc_file_lock); 26074462Salfred 26174462Salfred switch (ncp->valid) { 26274462Salfred case NC_VALID: 26374462Salfred /* 26474462Salfred * If entry has already been read into the list, 26574462Salfred * we return the entry in the linked list. 26674462Salfred * If this is the first time call, check if there are any entries in 26774462Salfred * linked list. If no entries, we need to read the netconfig db. 26874462Salfred * If we have been here and the next entry is there, we just return 26974462Salfred * it. 27074462Salfred */ 27174462Salfred if (ncp->flag == 0) { /* first time */ 27274462Salfred ncp->flag = 1; 273194932Sdelphij mutex_lock(&ni_lock); 27474462Salfred ncp->nc_configs = ni.head; 275194932Sdelphij mutex_unlock(&ni_lock); 27674462Salfred if (ncp->nc_configs != NULL) /* entry already exist */ 27774462Salfred return(ncp->nc_configs->ncp); 27874462Salfred } 27974462Salfred else if (ncp->nc_configs != NULL && ncp->nc_configs->next != NULL) { 28074462Salfred ncp->nc_configs = ncp->nc_configs->next; 28174462Salfred return(ncp->nc_configs->ncp); 28274462Salfred } 28374462Salfred 28474462Salfred /* 28574462Salfred * If we cannot find the entry in the list and is end of file, 28674462Salfred * we give up. 28774462Salfred */ 288194932Sdelphij mutex_lock(&ni_lock); 289194932Sdelphij if (ni.eof == 1) { 290194932Sdelphij mutex_unlock(&ni_lock); 291194932Sdelphij return(NULL); 292194932Sdelphij } 293194932Sdelphij mutex_unlock(&ni_lock); 294194932Sdelphij 29574462Salfred break; 29674462Salfred default: 29774462Salfred nc_error = NC_NOTINIT; 29874462Salfred return (NULL); 29974462Salfred } 30074462Salfred 30174462Salfred stringp = (char *) malloc(MAXNETCONFIGLINE); 30274462Salfred if (stringp == NULL) 30374462Salfred return (NULL); 30474462Salfred 30574462Salfred#ifdef MEM_CHK 30674462Salfred if (malloc_verify() == 0) { 30774462Salfred fprintf(stderr, "memory heap corrupted in getnetconfig\n"); 30874462Salfred exit(1); 30974462Salfred } 31074462Salfred#endif 31174462Salfred 31274462Salfred /* 31374462Salfred * Read a line from netconfig file. 31474462Salfred */ 315194932Sdelphij mutex_lock(&nc_file_lock); 31674462Salfred do { 31774462Salfred if (fgets(stringp, MAXNETCONFIGLINE, nc_file) == NULL) { 31874462Salfred free(stringp); 319194932Sdelphij mutex_lock(&ni_lock); 32074462Salfred ni.eof = 1; 321194932Sdelphij mutex_unlock(&ni_lock); 322194932Sdelphij mutex_unlock(&nc_file_lock); 32374462Salfred return (NULL); 32474462Salfred } 32574462Salfred } while (*stringp == '#'); 326194932Sdelphij mutex_unlock(&nc_file_lock); 32774462Salfred 32874462Salfred list = (struct netconfig_list *) malloc(sizeof (struct netconfig_list)); 32974462Salfred if (list == NULL) { 33074462Salfred free(stringp); 33174462Salfred return(NULL); 33274462Salfred } 33374462Salfred np = (struct netconfig *) malloc(sizeof (struct netconfig)); 33474462Salfred if (np == NULL) { 33574462Salfred free(stringp); 33674462Salfred free(list); 33774462Salfred return(NULL); 33874462Salfred } 33974462Salfred list->ncp = np; 34074462Salfred list->next = NULL; 34174462Salfred list->ncp->nc_lookups = NULL; 34274462Salfred list->linep = stringp; 34374462Salfred if (parse_ncp(stringp, list->ncp) == -1) { 34474462Salfred free(stringp); 34574462Salfred free(np); 34674462Salfred free(list); 34774462Salfred return (NULL); 34874462Salfred } 34974462Salfred else { 35074462Salfred /* 35174462Salfred * If this is the first entry that's been read, it is the head of 35274462Salfred * the list. If not, put the entry at the end of the list. 35374462Salfred * Reposition the current pointer of the handle to the last entry 35474462Salfred * in the list. 35574462Salfred */ 356194932Sdelphij mutex_lock(&ni_lock); 35774462Salfred if (ni.head == NULL) { /* first entry */ 35874462Salfred ni.head = ni.tail = list; 35974462Salfred } 36074462Salfred else { 36174462Salfred ni.tail->next = list; 36274462Salfred ni.tail = ni.tail->next; 36374462Salfred } 36474462Salfred ncp->nc_configs = ni.tail; 365194932Sdelphij result = ni.tail->ncp; 366194932Sdelphij mutex_unlock(&ni_lock); 367194932Sdelphij return(result); 36874462Salfred } 36974462Salfred} 37074462Salfred 37174462Salfred/* 37274462Salfred * endnetconfig() may be called to "unbind" or "close" the netconfig database 37374462Salfred * when processing is complete, releasing resources for reuse. endnetconfig() 37474462Salfred * may not be called before setnetconfig(). endnetconfig() returns 0 on 37574462Salfred * success and -1 on failure (for example, if setnetconfig() was not called 37674462Salfred * previously). 37774462Salfred */ 37874462Salfredint 379309487Sngieendnetconfig(void *handlep) 38074462Salfred{ 38174462Salfred struct netconfig_vars *nc_handlep = (struct netconfig_vars *)handlep; 38274462Salfred 38374462Salfred struct netconfig_list *q, *p; 38474462Salfred 38574462Salfred /* 38674462Salfred * Verify that handle is valid 38774462Salfred */ 38874462Salfred if (nc_handlep == NULL || (nc_handlep->valid != NC_VALID && 38974462Salfred nc_handlep->valid != NC_STORAGE)) { 39074462Salfred nc_error = NC_NOTINIT; 39174462Salfred return (-1); 39274462Salfred } 39374462Salfred 39474462Salfred /* 39574462Salfred * Return 0 if anyone still needs it. 39674462Salfred */ 39774462Salfred nc_handlep->valid = NC_INVALID; 39874462Salfred nc_handlep->flag = 0; 39974462Salfred nc_handlep->nc_configs = NULL; 400194932Sdelphij mutex_lock(&ni_lock); 40174462Salfred if (--ni.ref > 0) { 402194932Sdelphij mutex_unlock(&ni_lock); 40374462Salfred free(nc_handlep); 40474462Salfred return(0); 40574462Salfred } 40674462Salfred 40774462Salfred /* 40874462Salfred * Noone needs these entries anymore, then frees them. 40974462Salfred * Make sure all info in netconfig_info structure has been reinitialized. 41074462Salfred */ 411199784Swollman q = ni.head; 41274462Salfred ni.eof = ni.ref = 0; 41374462Salfred ni.head = NULL; 41474462Salfred ni.tail = NULL; 415194932Sdelphij mutex_unlock(&ni_lock); 416194932Sdelphij 417199784Swollman while (q != NULL) { 41874462Salfred p = q->next; 419290899Sngie free(q->ncp->nc_lookups); 42074462Salfred free(q->ncp); 42174462Salfred free(q->linep); 42274462Salfred free(q); 42374462Salfred q = p; 42474462Salfred } 42574462Salfred free(nc_handlep); 42674462Salfred 427194932Sdelphij mutex_lock(&nc_file_lock); 42874462Salfred fclose(nc_file); 42974462Salfred nc_file = NULL; 430194932Sdelphij mutex_unlock(&nc_file_lock); 431194932Sdelphij 43274462Salfred return (0); 43374462Salfred} 43474462Salfred 43574462Salfred/* 43674462Salfred * getnetconfigent(netid) returns a pointer to the struct netconfig structure 43774462Salfred * corresponding to netid. It returns NULL if netid is invalid (that is, does 43874462Salfred * not name an entry in the netconfig database). It returns NULL and sets 43974462Salfred * errno in case of failure (for example, if the netconfig database cannot be 44074462Salfred * opened). 44174462Salfred */ 44274462Salfred 44374462Salfredstruct netconfig * 444309487Sngiegetnetconfigent(const char *netid) 44574462Salfred{ 44674462Salfred FILE *file; /* NETCONFIG db's file pointer */ 44774462Salfred char *linep; /* holds current netconfig line */ 44874462Salfred char *stringp; /* temporary string pointer */ 44974462Salfred struct netconfig *ncp = NULL; /* returned value */ 45074462Salfred struct netconfig_list *list; /* pointer to cache list */ 45174462Salfred 45275146Siedowse nc_error = NC_NOTFOUND; /* default error. */ 45374462Salfred if (netid == NULL || strlen(netid) == 0) { 45474462Salfred return (NULL); 45574462Salfred } 45674462Salfred 45774462Salfred /* 45874462Salfred * Look up table if the entries have already been read and parsed in 45974462Salfred * getnetconfig(), then copy this entry into a buffer and return it. 46074462Salfred * If we cannot find the entry in the current list and there are more 46174462Salfred * entries in the netconfig db that has not been read, we then read the 46274462Salfred * db and try find the match netid. 46374462Salfred * If all the netconfig db has been read and placed into the list and 46474462Salfred * there is no match for the netid, return NULL. 46574462Salfred */ 466194932Sdelphij mutex_lock(&ni_lock); 46774462Salfred if (ni.head != NULL) { 46874462Salfred for (list = ni.head; list; list = list->next) { 46974462Salfred if (strcmp(list->ncp->nc_netid, netid) == 0) { 470194932Sdelphij mutex_unlock(&ni_lock); 47174462Salfred return(dup_ncp(list->ncp)); 47274462Salfred } 47374462Salfred } 474194932Sdelphij if (ni.eof == 1) { /* that's all the entries */ 475194932Sdelphij mutex_unlock(&ni_lock); 47674462Salfred return(NULL); 477194932Sdelphij } 47874462Salfred } 479194932Sdelphij mutex_unlock(&ni_lock); 48074462Salfred 48174462Salfred 48274462Salfred if ((file = fopen(NETCONFIG, "r")) == NULL) { 48375146Siedowse nc_error = NC_NONETCONFIG; 48474462Salfred return (NULL); 48574462Salfred } 48674462Salfred 48774462Salfred if ((linep = malloc(MAXNETCONFIGLINE)) == NULL) { 48874462Salfred fclose(file); 48975146Siedowse nc_error = NC_NOMEM; 49074462Salfred return (NULL); 49174462Salfred } 49274462Salfred do { 493109956Smbr ptrdiff_t len; 49474462Salfred char *tmpp; /* tmp string pointer */ 49574462Salfred 49674462Salfred do { 49774462Salfred if ((stringp = fgets(linep, MAXNETCONFIGLINE, file)) == NULL) { 49874462Salfred break; 49974462Salfred } 50074462Salfred } while (*stringp == '#'); 50174462Salfred if (stringp == NULL) { /* eof */ 50274462Salfred break; 50374462Salfred } 50474462Salfred if ((tmpp = strpbrk(stringp, "\t ")) == NULL) { /* can't parse file */ 50574462Salfred nc_error = NC_BADFILE; 50674462Salfred break; 50774462Salfred } 508109956Smbr if (strlen(netid) == (size_t) (len = tmpp - stringp) && /* a match */ 50974462Salfred strncmp(stringp, netid, (size_t)len) == 0) { 51074462Salfred if ((ncp = (struct netconfig *) 51174462Salfred malloc(sizeof (struct netconfig))) == NULL) { 51274462Salfred break; 51374462Salfred } 51474462Salfred ncp->nc_lookups = NULL; 51574462Salfred if (parse_ncp(linep, ncp) == -1) { 51674462Salfred free(ncp); 51774462Salfred ncp = NULL; 51874462Salfred } 51974462Salfred break; 52074462Salfred } 52174462Salfred } while (stringp != NULL); 52274462Salfred if (ncp == NULL) { 52374462Salfred free(linep); 52474462Salfred } 52574462Salfred fclose(file); 52674462Salfred return(ncp); 52774462Salfred} 52874462Salfred 52974462Salfred/* 53074462Salfred * freenetconfigent(netconfigp) frees the netconfig structure pointed to by 53174462Salfred * netconfigp (previously returned by getnetconfigent()). 53274462Salfred */ 53374462Salfred 53474462Salfredvoid 535309487Sngiefreenetconfigent(struct netconfig *netconfigp) 53674462Salfred{ 53774462Salfred if (netconfigp != NULL) { 53874462Salfred free(netconfigp->nc_netid); /* holds all netconfigp's strings */ 539290899Sngie free(netconfigp->nc_lookups); 54074462Salfred free(netconfigp); 54174462Salfred } 54274462Salfred return; 54374462Salfred} 54474462Salfred 54574462Salfred/* 54674462Salfred * Parse line and stuff it in a struct netconfig 54774462Salfred * Typical line might look like: 54874462Salfred * udp tpi_cots vb inet udp /dev/udp /usr/lib/ip.so,/usr/local/ip.so 54974462Salfred * 55074462Salfred * We return -1 if any of the tokens don't parse, or malloc fails. 55174462Salfred * 55274462Salfred * Note that we modify stringp (putting NULLs after tokens) and 55374462Salfred * we set the ncp's string field pointers to point to these tokens within 55474462Salfred * stringp. 555309487Sngie * 556309487Sngie * stringp - string to parse 557309487Sngie * ncp - where to put results 55874462Salfred */ 55974462Salfred 56074462Salfredstatic int 561309487Sngieparse_ncp(char *stringp, struct netconfig *ncp) 56274462Salfred{ 56374462Salfred char *tokenp; /* for processing tokens */ 56474462Salfred char *lasts; 565172259Smatteo char **nc_lookups; 56674462Salfred 56774462Salfred nc_error = NC_BADFILE; /* nearly anything that breaks is for this reason */ 56874462Salfred stringp[strlen(stringp)-1] = '\0'; /* get rid of newline */ 56974462Salfred /* netid */ 57074462Salfred if ((ncp->nc_netid = strtok_r(stringp, "\t ", &lasts)) == NULL) { 57174462Salfred return (-1); 57274462Salfred } 57374462Salfred 57474462Salfred /* semantics */ 57574462Salfred if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { 57674462Salfred return (-1); 57774462Salfred } 57874462Salfred if (strcmp(tokenp, NC_TPI_COTS_ORD_S) == 0) 57974462Salfred ncp->nc_semantics = NC_TPI_COTS_ORD; 58074462Salfred else if (strcmp(tokenp, NC_TPI_COTS_S) == 0) 58174462Salfred ncp->nc_semantics = NC_TPI_COTS; 58274462Salfred else if (strcmp(tokenp, NC_TPI_CLTS_S) == 0) 58374462Salfred ncp->nc_semantics = NC_TPI_CLTS; 58474462Salfred else if (strcmp(tokenp, NC_TPI_RAW_S) == 0) 58574462Salfred ncp->nc_semantics = NC_TPI_RAW; 58674462Salfred else 58774462Salfred return (-1); 58874462Salfred 58974462Salfred /* flags */ 59074462Salfred if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { 59174462Salfred return (-1); 59274462Salfred } 59374462Salfred for (ncp->nc_flag = NC_NOFLAG; *tokenp != '\0'; 59474462Salfred tokenp++) { 59574462Salfred switch (*tokenp) { 59674462Salfred case NC_NOFLAG_C: 59774462Salfred break; 59874462Salfred case NC_VISIBLE_C: 59974462Salfred ncp->nc_flag |= NC_VISIBLE; 60074462Salfred break; 60174462Salfred case NC_BROADCAST_C: 60274462Salfred ncp->nc_flag |= NC_BROADCAST; 60374462Salfred break; 60474462Salfred default: 60574462Salfred return (-1); 60674462Salfred } 60774462Salfred } 60874462Salfred /* protocol family */ 60974462Salfred if ((ncp->nc_protofmly = strtok_r(NULL, "\t ", &lasts)) == NULL) { 61074462Salfred return (-1); 61174462Salfred } 61274462Salfred /* protocol name */ 61374462Salfred if ((ncp->nc_proto = strtok_r(NULL, "\t ", &lasts)) == NULL) { 61474462Salfred return (-1); 61574462Salfred } 61674462Salfred /* network device */ 61774462Salfred if ((ncp->nc_device = strtok_r(NULL, "\t ", &lasts)) == NULL) { 61874462Salfred return (-1); 61974462Salfred } 62074462Salfred if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { 62174462Salfred return (-1); 62274462Salfred } 62374462Salfred if (strcmp(tokenp, NC_NOLOOKUP) == 0) { 62474462Salfred ncp->nc_nlookups = 0; 62574462Salfred ncp->nc_lookups = NULL; 62674462Salfred } else { 62774462Salfred char *cp; /* tmp string */ 62874462Salfred 629290899Sngie free(ncp->nc_lookups); /* from last visit */ 630172259Smatteo ncp->nc_lookups = NULL; 63174462Salfred ncp->nc_nlookups = 0; 63274462Salfred while ((cp = tokenp) != NULL) { 633172259Smatteo if ((nc_lookups = realloc(ncp->nc_lookups, 634172259Smatteo (ncp->nc_nlookups + 1) * sizeof *ncp->nc_lookups)) == NULL) { 635172259Smatteo free(ncp->nc_lookups); 636172259Smatteo ncp->nc_lookups = NULL; 637172259Smatteo return (-1); 638172259Smatteo } 63974462Salfred tokenp = _get_next_token(cp, ','); 640172259Smatteo ncp->nc_lookups = nc_lookups; 641172259Smatteo ncp->nc_lookups[ncp->nc_nlookups++] = cp; 64274462Salfred } 64374462Salfred } 64474462Salfred return (0); 64574462Salfred} 64674462Salfred 64774462Salfred 64874462Salfred/* 64974462Salfred * Returns a string describing the reason for failure. 65074462Salfred */ 65174462Salfredchar * 652309487Sngienc_sperror(void) 65374462Salfred{ 65474462Salfred const char *message; 65574462Salfred 65674462Salfred switch(nc_error) { 65774462Salfred case NC_NONETCONFIG: 65874462Salfred message = _nc_errors[0]; 65974462Salfred break; 66074462Salfred case NC_NOMEM: 66174462Salfred message = _nc_errors[1]; 66274462Salfred break; 66374462Salfred case NC_NOTINIT: 66474462Salfred message = _nc_errors[2]; 66574462Salfred break; 66674462Salfred case NC_BADFILE: 66774462Salfred message = _nc_errors[3]; 66874462Salfred break; 66975146Siedowse case NC_NOTFOUND: 67075146Siedowse message = _nc_errors[4]; 67175146Siedowse break; 67274462Salfred default: 67374462Salfred message = "Unknown network selection error"; 67474462Salfred } 67574462Salfred /* LINTED const castaway */ 67674462Salfred return ((char *)message); 67774462Salfred} 67874462Salfred 67974462Salfred/* 68074462Salfred * Prints a message onto standard error describing the reason for failure. 68174462Salfred */ 68274462Salfredvoid 683309487Sngienc_perror(const char *s) 68474462Salfred{ 68575146Siedowse fprintf(stderr, "%s: %s\n", s, nc_sperror()); 68674462Salfred} 68774462Salfred 68874462Salfred/* 68974462Salfred * Duplicates the matched netconfig buffer. 69074462Salfred */ 69174462Salfredstatic struct netconfig * 692309487Sngiedup_ncp(struct netconfig *ncp) 69374462Salfred{ 69474462Salfred struct netconfig *p; 695320582Sdelphij char *tmp; 696109956Smbr u_int i; 69774462Salfred 69874462Salfred if ((tmp=malloc(MAXNETCONFIGLINE)) == NULL) 69974462Salfred return(NULL); 70074462Salfred if ((p=(struct netconfig *)malloc(sizeof(struct netconfig))) == NULL) { 70174462Salfred free(tmp); 70274462Salfred return(NULL); 70374462Salfred } 70474462Salfred /* 70574462Salfred * First we dup all the data from matched netconfig buffer. Then we 70674462Salfred * adjust some of the member pointer to a pre-allocated buffer where 70774462Salfred * contains part of the data. 70874462Salfred * To follow the convention used in parse_ncp(), we store all the 709109956Smbr * necessary information in the pre-allocated buffer and let each 71074462Salfred * of the netconfig char pointer member point to the right address 71174462Salfred * in the buffer. 71274462Salfred */ 71374462Salfred *p = *ncp; 71474462Salfred p->nc_netid = (char *)strcpy(tmp,ncp->nc_netid); 715126643Smarkm tmp = strchr(tmp, '\0') + 1; 71674462Salfred p->nc_protofmly = (char *)strcpy(tmp,ncp->nc_protofmly); 717126643Smarkm tmp = strchr(tmp, '\0') + 1; 71874462Salfred p->nc_proto = (char *)strcpy(tmp,ncp->nc_proto); 719126643Smarkm tmp = strchr(tmp, '\0') + 1; 72074462Salfred p->nc_device = (char *)strcpy(tmp,ncp->nc_device); 72174462Salfred p->nc_lookups = (char **)malloc((size_t)(p->nc_nlookups+1) * sizeof(char *)); 72274462Salfred if (p->nc_lookups == NULL) { 72374462Salfred free(p->nc_netid); 724162191Smbr free(p); 72574462Salfred return(NULL); 72674462Salfred } 72774462Salfred for (i=0; i < p->nc_nlookups; i++) { 728126643Smarkm tmp = strchr(tmp, '\0') + 1; 72974462Salfred p->nc_lookups[i] = (char *)strcpy(tmp,ncp->nc_lookups[i]); 73074462Salfred } 73174462Salfred return(p); 73274462Salfred} 733