1*ba96d07fShrs /*-
2*ba96d07fShrs * Copyright (c) 2009, Sun Microsystems, Inc.
3*ba96d07fShrs * All rights reserved.
4ce0e08e2SPeter Avalos *
5*ba96d07fShrs * Redistribution and use in source and binary forms, with or without
6*ba96d07fShrs * modification, are permitted provided that the following conditions are met:
7*ba96d07fShrs * - Redistributions of source code must retain the above copyright notice,
8*ba96d07fShrs * this list of conditions and the following disclaimer.
9*ba96d07fShrs * - Redistributions in binary form must reproduce the above copyright notice,
10*ba96d07fShrs * this list of conditions and the following disclaimer in the documentation
11*ba96d07fShrs * and/or other materials provided with the distribution.
12*ba96d07fShrs * - Neither the name of Sun Microsystems, Inc. nor the names of its
13*ba96d07fShrs * contributors may be used to endorse or promote products derived
14*ba96d07fShrs * from this software without specific prior written permission.
15ce0e08e2SPeter Avalos *
16*ba96d07fShrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17*ba96d07fShrs * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*ba96d07fShrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*ba96d07fShrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20*ba96d07fShrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*ba96d07fShrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*ba96d07fShrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*ba96d07fShrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*ba96d07fShrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*ba96d07fShrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*ba96d07fShrs * POSSIBILITY OF SUCH DAMAGE.
27ce0e08e2SPeter Avalos *
28ce0e08e2SPeter Avalos * @(#)getnetconfig.c 1.12 91/12/19 SMI
29ce0e08e2SPeter Avalos * $NetBSD: getnetconfig.c,v 1.3 2000/07/06 03:10:34 christos Exp $
30ce0e08e2SPeter Avalos * $FreeBSD: src/lib/libc/rpc/getnetconfig.c,v 1.14 2007/09/20 22:35:24 matteo Exp $
31ce0e08e2SPeter Avalos */
32ce0e08e2SPeter Avalos
33ce0e08e2SPeter Avalos /*
34ce0e08e2SPeter Avalos * Copyright (c) 1989 by Sun Microsystems, Inc.
35ce0e08e2SPeter Avalos */
36ce0e08e2SPeter Avalos
37ce0e08e2SPeter Avalos #include "namespace.h"
38ce0e08e2SPeter Avalos #include "reentrant.h"
39ce0e08e2SPeter Avalos #include <stdio.h>
40ce0e08e2SPeter Avalos #include <errno.h>
41ce0e08e2SPeter Avalos #include <netconfig.h>
42ce0e08e2SPeter Avalos #include <stddef.h>
43ce0e08e2SPeter Avalos #include <stdlib.h>
44ce0e08e2SPeter Avalos #include <string.h>
45ce0e08e2SPeter Avalos #include <rpc/rpc.h>
46ce0e08e2SPeter Avalos #include <unistd.h>
47ce0e08e2SPeter Avalos #include "un-namespace.h"
48ce0e08e2SPeter Avalos #include "rpc_com.h"
49ce0e08e2SPeter Avalos
50ce0e08e2SPeter Avalos /*
51ce0e08e2SPeter Avalos * The five library routines in this file provide application access to the
52ce0e08e2SPeter Avalos * system network configuration database, /etc/netconfig. In addition to the
53ce0e08e2SPeter Avalos * netconfig database and the routines for accessing it, the environment
54ce0e08e2SPeter Avalos * variable NETPATH and its corresponding routines in getnetpath.c may also be
55ce0e08e2SPeter Avalos * used to specify the network transport to be used.
56ce0e08e2SPeter Avalos */
57ce0e08e2SPeter Avalos
58ce0e08e2SPeter Avalos
59ce0e08e2SPeter Avalos /*
60ce0e08e2SPeter Avalos * netconfig errors
61ce0e08e2SPeter Avalos */
62ce0e08e2SPeter Avalos
63ce0e08e2SPeter Avalos #define NC_NONETCONFIG ENOENT
64ce0e08e2SPeter Avalos #define NC_NOMEM ENOMEM
65ce0e08e2SPeter Avalos #define NC_NOTINIT EINVAL /* setnetconfig was not called first */
66ce0e08e2SPeter Avalos #define NC_BADFILE EBADF /* format for netconfig file is bad */
67ce0e08e2SPeter Avalos #define NC_NOTFOUND ENOPROTOOPT /* specified netid was not found */
68ce0e08e2SPeter Avalos
69ce0e08e2SPeter Avalos /*
70ce0e08e2SPeter Avalos * semantics as strings (should be in netconfig.h)
71ce0e08e2SPeter Avalos */
72ce0e08e2SPeter Avalos #define NC_TPI_CLTS_S "tpi_clts"
73ce0e08e2SPeter Avalos #define NC_TPI_COTS_S "tpi_cots"
74ce0e08e2SPeter Avalos #define NC_TPI_COTS_ORD_S "tpi_cots_ord"
75ce0e08e2SPeter Avalos #define NC_TPI_RAW_S "tpi_raw"
76ce0e08e2SPeter Avalos
77ce0e08e2SPeter Avalos /*
78ce0e08e2SPeter Avalos * flags as characters (also should be in netconfig.h)
79ce0e08e2SPeter Avalos */
80ce0e08e2SPeter Avalos #define NC_NOFLAG_C '-'
81ce0e08e2SPeter Avalos #define NC_VISIBLE_C 'v'
82ce0e08e2SPeter Avalos #define NC_BROADCAST_C 'b'
83ce0e08e2SPeter Avalos
84ce0e08e2SPeter Avalos /*
85ce0e08e2SPeter Avalos * Character used to indicate there is no name-to-address lookup library
86ce0e08e2SPeter Avalos */
87ce0e08e2SPeter Avalos #define NC_NOLOOKUP "-"
88ce0e08e2SPeter Avalos
89ce0e08e2SPeter Avalos static const char * const _nc_errors[] = {
90ce0e08e2SPeter Avalos "Netconfig database not found",
91ce0e08e2SPeter Avalos "Not enough memory",
92ce0e08e2SPeter Avalos "Not initialized",
93ce0e08e2SPeter Avalos "Netconfig database has invalid format",
94ce0e08e2SPeter Avalos "Netid not found in netconfig database"
95ce0e08e2SPeter Avalos };
96ce0e08e2SPeter Avalos
97ce0e08e2SPeter Avalos struct netconfig_info {
98ce0e08e2SPeter Avalos int eof; /* all entries has been read */
99ce0e08e2SPeter Avalos int ref; /* # of times setnetconfig() has been called */
100ce0e08e2SPeter Avalos struct netconfig_list *head; /* head of the list */
101ce0e08e2SPeter Avalos struct netconfig_list *tail; /* last of the list */
102ce0e08e2SPeter Avalos };
103ce0e08e2SPeter Avalos
104ce0e08e2SPeter Avalos struct netconfig_list {
105ce0e08e2SPeter Avalos char *linep; /* hold line read from netconfig */
106ce0e08e2SPeter Avalos struct netconfig *ncp;
107ce0e08e2SPeter Avalos struct netconfig_list *next;
108ce0e08e2SPeter Avalos };
109ce0e08e2SPeter Avalos
110ce0e08e2SPeter Avalos struct netconfig_vars {
111ce0e08e2SPeter Avalos int valid; /* token that indicates a valid netconfig_vars */
112ce0e08e2SPeter Avalos int flag; /* first time flag */
113ce0e08e2SPeter Avalos struct netconfig_list *nc_configs; /* pointer to the current netconfig entry */
114ce0e08e2SPeter Avalos };
115ce0e08e2SPeter Avalos
116ce0e08e2SPeter Avalos #define NC_VALID 0xfeed
117ce0e08e2SPeter Avalos #define NC_STORAGE 0xf00d
118ce0e08e2SPeter Avalos #define NC_INVALID 0
119ce0e08e2SPeter Avalos
120ce0e08e2SPeter Avalos
121ce0e08e2SPeter Avalos static int *__nc_error(void);
122ce0e08e2SPeter Avalos static int parse_ncp(char *, struct netconfig *);
123ce0e08e2SPeter Avalos static struct netconfig *dup_ncp(struct netconfig *);
124ce0e08e2SPeter Avalos
125ce0e08e2SPeter Avalos
126ce0e08e2SPeter Avalos static FILE *nc_file; /* for netconfig db */
127ce0e08e2SPeter Avalos static struct netconfig_info ni = { 0, 0, NULL, NULL};
128ce0e08e2SPeter Avalos
129ce0e08e2SPeter Avalos #define MAXNETCONFIGLINE 1000
130ce0e08e2SPeter Avalos
131ce0e08e2SPeter Avalos static int *
__nc_error(void)132ce0e08e2SPeter Avalos __nc_error(void)
133ce0e08e2SPeter Avalos {
134ce0e08e2SPeter Avalos static pthread_mutex_t nc_lock = PTHREAD_MUTEX_INITIALIZER;
135ce0e08e2SPeter Avalos static thread_key_t nc_key = 0;
136ce0e08e2SPeter Avalos static int nc_error = 0;
137ce0e08e2SPeter Avalos int error, *nc_addr;
138ce0e08e2SPeter Avalos
139ce0e08e2SPeter Avalos /*
140ce0e08e2SPeter Avalos * Use the static `nc_error' if we are the main thread
141ce0e08e2SPeter Avalos * (including non-threaded programs), or if an allocation
142ce0e08e2SPeter Avalos * fails.
143ce0e08e2SPeter Avalos */
144ce0e08e2SPeter Avalos if (thr_main())
145ce0e08e2SPeter Avalos return (&nc_error);
146ce0e08e2SPeter Avalos if (nc_key == 0) {
147ce0e08e2SPeter Avalos error = 0;
148ce0e08e2SPeter Avalos mutex_lock(&nc_lock);
149ce0e08e2SPeter Avalos if (nc_key == 0)
150ce0e08e2SPeter Avalos error = thr_keycreate(&nc_key, free);
151ce0e08e2SPeter Avalos mutex_unlock(&nc_lock);
152ce0e08e2SPeter Avalos if (error)
153ce0e08e2SPeter Avalos return (&nc_error);
154ce0e08e2SPeter Avalos }
155ce0e08e2SPeter Avalos if ((nc_addr = (int *)thr_getspecific(nc_key)) == NULL) {
156ce0e08e2SPeter Avalos nc_addr = (int *)malloc(sizeof (int));
157ce0e08e2SPeter Avalos if (thr_setspecific(nc_key, (void *) nc_addr) != 0) {
158ce0e08e2SPeter Avalos if (nc_addr)
159ce0e08e2SPeter Avalos free(nc_addr);
160ce0e08e2SPeter Avalos return (&nc_error);
161ce0e08e2SPeter Avalos }
162ce0e08e2SPeter Avalos *nc_addr = 0;
163ce0e08e2SPeter Avalos }
164ce0e08e2SPeter Avalos return (nc_addr);
165ce0e08e2SPeter Avalos }
166ce0e08e2SPeter Avalos
167ce0e08e2SPeter Avalos #define nc_error (*(__nc_error()))
168ce0e08e2SPeter Avalos /*
169ce0e08e2SPeter Avalos * A call to setnetconfig() establishes a /etc/netconfig "session". A session
170ce0e08e2SPeter Avalos * "handle" is returned on a successful call. At the start of a session (after
171ce0e08e2SPeter Avalos * a call to setnetconfig()) searches through the /etc/netconfig database will
172ce0e08e2SPeter Avalos * proceed from the start of the file. The session handle must be passed to
173ce0e08e2SPeter Avalos * getnetconfig() to parse the file. Each call to getnetconfig() using the
174ce0e08e2SPeter Avalos * current handle will process one subsequent entry in /etc/netconfig.
175ce0e08e2SPeter Avalos * setnetconfig() must be called before the first call to getnetconfig().
176ce0e08e2SPeter Avalos * (Handles are used to allow for nested calls to setnetpath()).
177ce0e08e2SPeter Avalos *
178ce0e08e2SPeter Avalos * A new session is established with each call to setnetconfig(), with a new
179ce0e08e2SPeter Avalos * handle being returned on each call. Previously established sessions remain
180ce0e08e2SPeter Avalos * active until endnetconfig() is called with that session's handle as an
181ce0e08e2SPeter Avalos * argument.
182ce0e08e2SPeter Avalos *
183ce0e08e2SPeter Avalos * setnetconfig() need *not* be called before a call to getnetconfigent().
184ce0e08e2SPeter Avalos * setnetconfig() returns a NULL pointer on failure (for example, if
185ce0e08e2SPeter Avalos * the netconfig database is not present).
186ce0e08e2SPeter Avalos */
187ce0e08e2SPeter Avalos void *
setnetconfig(void)188ce0e08e2SPeter Avalos setnetconfig(void)
189ce0e08e2SPeter Avalos {
190ce0e08e2SPeter Avalos struct netconfig_vars *nc_vars;
191ce0e08e2SPeter Avalos
192ce0e08e2SPeter Avalos if ((nc_vars = (struct netconfig_vars *)malloc(sizeof
193ce0e08e2SPeter Avalos (struct netconfig_vars))) == NULL) {
194ce0e08e2SPeter Avalos return(NULL);
195ce0e08e2SPeter Avalos }
196ce0e08e2SPeter Avalos
197ce0e08e2SPeter Avalos /*
198ce0e08e2SPeter Avalos * For multiple calls, i.e. nc_file is not NULL, we just return the
199ce0e08e2SPeter Avalos * handle without reopening the netconfig db.
200ce0e08e2SPeter Avalos */
201ce0e08e2SPeter Avalos ni.ref++;
202ce0e08e2SPeter Avalos if ((nc_file != NULL) || (nc_file = fopen(NETCONFIG, "r")) != NULL) {
203ce0e08e2SPeter Avalos nc_vars->valid = NC_VALID;
204ce0e08e2SPeter Avalos nc_vars->flag = 0;
205ce0e08e2SPeter Avalos nc_vars->nc_configs = ni.head;
206ce0e08e2SPeter Avalos return ((void *)nc_vars);
207ce0e08e2SPeter Avalos }
208ce0e08e2SPeter Avalos ni.ref--;
209ce0e08e2SPeter Avalos nc_error = NC_NONETCONFIG;
210ce0e08e2SPeter Avalos free(nc_vars);
211ce0e08e2SPeter Avalos return (NULL);
212ce0e08e2SPeter Avalos }
213ce0e08e2SPeter Avalos
214ce0e08e2SPeter Avalos
215ce0e08e2SPeter Avalos /*
216ce0e08e2SPeter Avalos * When first called, getnetconfig() returns a pointer to the first entry in
217ce0e08e2SPeter Avalos * the netconfig database, formatted as a struct netconfig. On each subsequent
218ce0e08e2SPeter Avalos * call, getnetconfig() returns a pointer to the next entry in the database.
219ce0e08e2SPeter Avalos * getnetconfig() can thus be used to search the entire netconfig file.
220ce0e08e2SPeter Avalos * getnetconfig() returns NULL at end of file.
221ce0e08e2SPeter Avalos */
222ce0e08e2SPeter Avalos
223ce0e08e2SPeter Avalos struct netconfig *
getnetconfig(void * handlep)224ce0e08e2SPeter Avalos getnetconfig(void *handlep)
225ce0e08e2SPeter Avalos {
226ce0e08e2SPeter Avalos struct netconfig_vars *ncp = (struct netconfig_vars *)handlep;
227ce0e08e2SPeter Avalos char *stringp; /* tmp string pointer */
228ce0e08e2SPeter Avalos struct netconfig_list *list;
229ce0e08e2SPeter Avalos struct netconfig *np;
230ce0e08e2SPeter Avalos
231ce0e08e2SPeter Avalos /*
232ce0e08e2SPeter Avalos * Verify that handle is valid
233ce0e08e2SPeter Avalos */
234ce0e08e2SPeter Avalos if (ncp == NULL || nc_file == NULL) {
235ce0e08e2SPeter Avalos nc_error = NC_NOTINIT;
236ce0e08e2SPeter Avalos return (NULL);
237ce0e08e2SPeter Avalos }
238ce0e08e2SPeter Avalos
239ce0e08e2SPeter Avalos switch (ncp->valid) {
240ce0e08e2SPeter Avalos case NC_VALID:
241ce0e08e2SPeter Avalos /*
242ce0e08e2SPeter Avalos * If entry has already been read into the list,
243ce0e08e2SPeter Avalos * we return the entry in the linked list.
244ce0e08e2SPeter Avalos * If this is the first time call, check if there are any entries in
245ce0e08e2SPeter Avalos * linked list. If no entries, we need to read the netconfig db.
246ce0e08e2SPeter Avalos * If we have been here and the next entry is there, we just return
247ce0e08e2SPeter Avalos * it.
248ce0e08e2SPeter Avalos */
249ce0e08e2SPeter Avalos if (ncp->flag == 0) { /* first time */
250ce0e08e2SPeter Avalos ncp->flag = 1;
251ce0e08e2SPeter Avalos ncp->nc_configs = ni.head;
252ce0e08e2SPeter Avalos if (ncp->nc_configs != NULL) /* entry already exist */
253ce0e08e2SPeter Avalos return(ncp->nc_configs->ncp);
254ce0e08e2SPeter Avalos }
255ce0e08e2SPeter Avalos else if (ncp->nc_configs != NULL && ncp->nc_configs->next != NULL) {
256ce0e08e2SPeter Avalos ncp->nc_configs = ncp->nc_configs->next;
257ce0e08e2SPeter Avalos return(ncp->nc_configs->ncp);
258ce0e08e2SPeter Avalos }
259ce0e08e2SPeter Avalos
260ce0e08e2SPeter Avalos /*
261ce0e08e2SPeter Avalos * If we cannot find the entry in the list and is end of file,
262ce0e08e2SPeter Avalos * we give up.
263ce0e08e2SPeter Avalos */
264ce0e08e2SPeter Avalos if (ni.eof == 1) return(NULL);
265ce0e08e2SPeter Avalos break;
266ce0e08e2SPeter Avalos default:
267ce0e08e2SPeter Avalos nc_error = NC_NOTINIT;
268ce0e08e2SPeter Avalos return (NULL);
269ce0e08e2SPeter Avalos }
270ce0e08e2SPeter Avalos
271ce0e08e2SPeter Avalos stringp = (char *) malloc(MAXNETCONFIGLINE);
272ce0e08e2SPeter Avalos if (stringp == NULL)
273ce0e08e2SPeter Avalos return (NULL);
274ce0e08e2SPeter Avalos
275ce0e08e2SPeter Avalos #ifdef MEM_CHK
276ce0e08e2SPeter Avalos if (malloc_verify() == 0) {
277ce0e08e2SPeter Avalos fprintf(stderr, "memory heap corrupted in getnetconfig\n");
278ce0e08e2SPeter Avalos exit(1);
279ce0e08e2SPeter Avalos }
280ce0e08e2SPeter Avalos #endif
281ce0e08e2SPeter Avalos
282ce0e08e2SPeter Avalos /*
283ce0e08e2SPeter Avalos * Read a line from netconfig file.
284ce0e08e2SPeter Avalos */
285ce0e08e2SPeter Avalos do {
286ce0e08e2SPeter Avalos if (fgets(stringp, MAXNETCONFIGLINE, nc_file) == NULL) {
287ce0e08e2SPeter Avalos free(stringp);
288ce0e08e2SPeter Avalos ni.eof = 1;
289ce0e08e2SPeter Avalos return (NULL);
290ce0e08e2SPeter Avalos }
291ce0e08e2SPeter Avalos } while (*stringp == '#');
292ce0e08e2SPeter Avalos
293ce0e08e2SPeter Avalos list = (struct netconfig_list *) malloc(sizeof (struct netconfig_list));
294ce0e08e2SPeter Avalos if (list == NULL) {
295ce0e08e2SPeter Avalos free(stringp);
296ce0e08e2SPeter Avalos return(NULL);
297ce0e08e2SPeter Avalos }
298ce0e08e2SPeter Avalos np = (struct netconfig *) malloc(sizeof (struct netconfig));
299ce0e08e2SPeter Avalos if (np == NULL) {
300ce0e08e2SPeter Avalos free(stringp);
301ce0e08e2SPeter Avalos free(list);
302ce0e08e2SPeter Avalos return(NULL);
303ce0e08e2SPeter Avalos }
304ce0e08e2SPeter Avalos list->ncp = np;
305ce0e08e2SPeter Avalos list->next = NULL;
306ce0e08e2SPeter Avalos list->ncp->nc_lookups = NULL;
307ce0e08e2SPeter Avalos list->linep = stringp;
308ce0e08e2SPeter Avalos if (parse_ncp(stringp, list->ncp) == -1) {
309ce0e08e2SPeter Avalos free(stringp);
310ce0e08e2SPeter Avalos free(np);
311ce0e08e2SPeter Avalos free(list);
312ce0e08e2SPeter Avalos return (NULL);
313ce0e08e2SPeter Avalos }
314ce0e08e2SPeter Avalos else {
315ce0e08e2SPeter Avalos /*
316ce0e08e2SPeter Avalos * If this is the first entry that's been read, it is the head of
317ce0e08e2SPeter Avalos * the list. If not, put the entry at the end of the list.
318ce0e08e2SPeter Avalos * Reposition the current pointer of the handle to the last entry
319ce0e08e2SPeter Avalos * in the list.
320ce0e08e2SPeter Avalos */
321ce0e08e2SPeter Avalos if (ni.head == NULL) { /* first entry */
322ce0e08e2SPeter Avalos ni.head = ni.tail = list;
323ce0e08e2SPeter Avalos }
324ce0e08e2SPeter Avalos else {
325ce0e08e2SPeter Avalos ni.tail->next = list;
326ce0e08e2SPeter Avalos ni.tail = ni.tail->next;
327ce0e08e2SPeter Avalos }
328ce0e08e2SPeter Avalos ncp->nc_configs = ni.tail;
329ce0e08e2SPeter Avalos return(ni.tail->ncp);
330ce0e08e2SPeter Avalos }
331ce0e08e2SPeter Avalos }
332ce0e08e2SPeter Avalos
333ce0e08e2SPeter Avalos /*
334ce0e08e2SPeter Avalos * endnetconfig() may be called to "unbind" or "close" the netconfig database
335ce0e08e2SPeter Avalos * when processing is complete, releasing resources for reuse. endnetconfig()
336ce0e08e2SPeter Avalos * may not be called before setnetconfig(). endnetconfig() returns 0 on
337ce0e08e2SPeter Avalos * success and -1 on failure (for example, if setnetconfig() was not called
338ce0e08e2SPeter Avalos * previously).
339ce0e08e2SPeter Avalos */
340ce0e08e2SPeter Avalos int
endnetconfig(void * handlep)341ce0e08e2SPeter Avalos endnetconfig(void *handlep)
342ce0e08e2SPeter Avalos {
343ce0e08e2SPeter Avalos struct netconfig_vars *nc_handlep = (struct netconfig_vars *)handlep;
344ce0e08e2SPeter Avalos
345ce0e08e2SPeter Avalos struct netconfig_list *q, *p;
346ce0e08e2SPeter Avalos
347ce0e08e2SPeter Avalos /*
348ce0e08e2SPeter Avalos * Verify that handle is valid
349ce0e08e2SPeter Avalos */
350ce0e08e2SPeter Avalos if (nc_handlep == NULL || (nc_handlep->valid != NC_VALID &&
351ce0e08e2SPeter Avalos nc_handlep->valid != NC_STORAGE)) {
352ce0e08e2SPeter Avalos nc_error = NC_NOTINIT;
353ce0e08e2SPeter Avalos return (-1);
354ce0e08e2SPeter Avalos }
355ce0e08e2SPeter Avalos
356ce0e08e2SPeter Avalos /*
357ce0e08e2SPeter Avalos * Return 0 if anyone still needs it.
358ce0e08e2SPeter Avalos */
359ce0e08e2SPeter Avalos nc_handlep->valid = NC_INVALID;
360ce0e08e2SPeter Avalos nc_handlep->flag = 0;
361ce0e08e2SPeter Avalos nc_handlep->nc_configs = NULL;
362ce0e08e2SPeter Avalos if (--ni.ref > 0) {
363ce0e08e2SPeter Avalos free(nc_handlep);
364ce0e08e2SPeter Avalos return(0);
365ce0e08e2SPeter Avalos }
366ce0e08e2SPeter Avalos
367ce0e08e2SPeter Avalos /*
368ce0e08e2SPeter Avalos * Noone needs these entries anymore, then frees them.
369ce0e08e2SPeter Avalos * Make sure all info in netconfig_info structure has been reinitialized.
370ce0e08e2SPeter Avalos */
371ce0e08e2SPeter Avalos q = p = ni.head;
372ce0e08e2SPeter Avalos ni.eof = ni.ref = 0;
373ce0e08e2SPeter Avalos ni.head = NULL;
374ce0e08e2SPeter Avalos ni.tail = NULL;
375ce0e08e2SPeter Avalos while (q) {
376ce0e08e2SPeter Avalos p = q->next;
377ce0e08e2SPeter Avalos if (q->ncp->nc_lookups != NULL) free(q->ncp->nc_lookups);
378ce0e08e2SPeter Avalos free(q->ncp);
379ce0e08e2SPeter Avalos free(q->linep);
380ce0e08e2SPeter Avalos free(q);
381ce0e08e2SPeter Avalos q = p;
382ce0e08e2SPeter Avalos }
383ce0e08e2SPeter Avalos free(nc_handlep);
384ce0e08e2SPeter Avalos
385ce0e08e2SPeter Avalos fclose(nc_file);
386ce0e08e2SPeter Avalos nc_file = NULL;
387ce0e08e2SPeter Avalos return (0);
388ce0e08e2SPeter Avalos }
389ce0e08e2SPeter Avalos
390ce0e08e2SPeter Avalos /*
391ce0e08e2SPeter Avalos * getnetconfigent(netid) returns a pointer to the struct netconfig structure
392ce0e08e2SPeter Avalos * corresponding to netid. It returns NULL if netid is invalid (that is, does
393ce0e08e2SPeter Avalos * not name an entry in the netconfig database). It returns NULL and sets
394ce0e08e2SPeter Avalos * errno in case of failure (for example, if the netconfig database cannot be
395ce0e08e2SPeter Avalos * opened).
396ce0e08e2SPeter Avalos */
397ce0e08e2SPeter Avalos
398ce0e08e2SPeter Avalos struct netconfig *
getnetconfigent(const char * netid)399ce0e08e2SPeter Avalos getnetconfigent(const char *netid)
400ce0e08e2SPeter Avalos {
401ce0e08e2SPeter Avalos FILE *file; /* NETCONFIG db's file pointer */
402ce0e08e2SPeter Avalos char *linep; /* holds current netconfig line */
403ce0e08e2SPeter Avalos char *stringp; /* temporary string pointer */
404ce0e08e2SPeter Avalos struct netconfig *ncp = NULL; /* returned value */
405ce0e08e2SPeter Avalos struct netconfig_list *list; /* pointer to cache list */
406ce0e08e2SPeter Avalos
407ce0e08e2SPeter Avalos nc_error = NC_NOTFOUND; /* default error. */
408ce0e08e2SPeter Avalos if (netid == NULL || strlen(netid) == 0) {
409ce0e08e2SPeter Avalos return (NULL);
410ce0e08e2SPeter Avalos }
411ce0e08e2SPeter Avalos
412ce0e08e2SPeter Avalos /*
413ce0e08e2SPeter Avalos * Look up table if the entries have already been read and parsed in
414ce0e08e2SPeter Avalos * getnetconfig(), then copy this entry into a buffer and return it.
415ce0e08e2SPeter Avalos * If we cannot find the entry in the current list and there are more
416ce0e08e2SPeter Avalos * entries in the netconfig db that has not been read, we then read the
417ce0e08e2SPeter Avalos * db and try find the match netid.
418ce0e08e2SPeter Avalos * If all the netconfig db has been read and placed into the list and
419ce0e08e2SPeter Avalos * there is no match for the netid, return NULL.
420ce0e08e2SPeter Avalos */
421ce0e08e2SPeter Avalos if (ni.head != NULL) {
422ce0e08e2SPeter Avalos for (list = ni.head; list; list = list->next) {
423ce0e08e2SPeter Avalos if (strcmp(list->ncp->nc_netid, netid) == 0) {
424ce0e08e2SPeter Avalos return(dup_ncp(list->ncp));
425ce0e08e2SPeter Avalos }
426ce0e08e2SPeter Avalos }
427ce0e08e2SPeter Avalos if (ni.eof == 1) /* that's all the entries */
428ce0e08e2SPeter Avalos return(NULL);
429ce0e08e2SPeter Avalos }
430ce0e08e2SPeter Avalos
431ce0e08e2SPeter Avalos
432ce0e08e2SPeter Avalos if ((file = fopen(NETCONFIG, "r")) == NULL) {
433ce0e08e2SPeter Avalos nc_error = NC_NONETCONFIG;
434ce0e08e2SPeter Avalos return (NULL);
435ce0e08e2SPeter Avalos }
436ce0e08e2SPeter Avalos
437ce0e08e2SPeter Avalos if ((linep = malloc(MAXNETCONFIGLINE)) == NULL) {
438ce0e08e2SPeter Avalos fclose(file);
439ce0e08e2SPeter Avalos nc_error = NC_NOMEM;
440ce0e08e2SPeter Avalos return (NULL);
441ce0e08e2SPeter Avalos }
442ce0e08e2SPeter Avalos do {
443ce0e08e2SPeter Avalos ptrdiff_t len;
444ce0e08e2SPeter Avalos char *tmpp; /* tmp string pointer */
445ce0e08e2SPeter Avalos
446ce0e08e2SPeter Avalos do {
447ce0e08e2SPeter Avalos if ((stringp = fgets(linep, MAXNETCONFIGLINE, file)) == NULL) {
448ce0e08e2SPeter Avalos break;
449ce0e08e2SPeter Avalos }
450ce0e08e2SPeter Avalos } while (*stringp == '#');
451ce0e08e2SPeter Avalos if (stringp == NULL) { /* eof */
452ce0e08e2SPeter Avalos break;
453ce0e08e2SPeter Avalos }
454ce0e08e2SPeter Avalos if ((tmpp = strpbrk(stringp, "\t ")) == NULL) { /* can't parse file */
455ce0e08e2SPeter Avalos nc_error = NC_BADFILE;
456ce0e08e2SPeter Avalos break;
457ce0e08e2SPeter Avalos }
458ce0e08e2SPeter Avalos if (strlen(netid) == (size_t) (len = tmpp - stringp) && /* a match */
459ce0e08e2SPeter Avalos strncmp(stringp, netid, (size_t)len) == 0) {
460ce0e08e2SPeter Avalos if ((ncp = (struct netconfig *)
461ce0e08e2SPeter Avalos malloc(sizeof (struct netconfig))) == NULL) {
462ce0e08e2SPeter Avalos break;
463ce0e08e2SPeter Avalos }
464ce0e08e2SPeter Avalos ncp->nc_lookups = NULL;
465ce0e08e2SPeter Avalos if (parse_ncp(linep, ncp) == -1) {
466ce0e08e2SPeter Avalos free(ncp);
467ce0e08e2SPeter Avalos ncp = NULL;
468ce0e08e2SPeter Avalos }
469ce0e08e2SPeter Avalos break;
470ce0e08e2SPeter Avalos }
471ce0e08e2SPeter Avalos } while (stringp != NULL);
472ce0e08e2SPeter Avalos if (ncp == NULL) {
473ce0e08e2SPeter Avalos free(linep);
474ce0e08e2SPeter Avalos }
475ce0e08e2SPeter Avalos fclose(file);
476ce0e08e2SPeter Avalos return(ncp);
477ce0e08e2SPeter Avalos }
478ce0e08e2SPeter Avalos
479ce0e08e2SPeter Avalos /*
480ce0e08e2SPeter Avalos * freenetconfigent(netconfigp) frees the netconfig structure pointed to by
481ce0e08e2SPeter Avalos * netconfigp (previously returned by getnetconfigent()).
482ce0e08e2SPeter Avalos */
483ce0e08e2SPeter Avalos
484ce0e08e2SPeter Avalos void
freenetconfigent(struct netconfig * netconfigp)485ce0e08e2SPeter Avalos freenetconfigent(struct netconfig *netconfigp)
486ce0e08e2SPeter Avalos {
487ce0e08e2SPeter Avalos if (netconfigp != NULL) {
488ce0e08e2SPeter Avalos free(netconfigp->nc_netid); /* holds all netconfigp's strings */
489ce0e08e2SPeter Avalos if (netconfigp->nc_lookups != NULL)
490ce0e08e2SPeter Avalos free(netconfigp->nc_lookups);
491ce0e08e2SPeter Avalos free(netconfigp);
492ce0e08e2SPeter Avalos }
493ce0e08e2SPeter Avalos return;
494ce0e08e2SPeter Avalos }
495ce0e08e2SPeter Avalos
496ce0e08e2SPeter Avalos /*
497ce0e08e2SPeter Avalos * Parse line and stuff it in a struct netconfig
498ce0e08e2SPeter Avalos * Typical line might look like:
499ce0e08e2SPeter Avalos * udp tpi_cots vb inet udp /dev/udp /usr/lib/ip.so,/usr/local/ip.so
500ce0e08e2SPeter Avalos *
501ce0e08e2SPeter Avalos * We return -1 if any of the tokens don't parse, or malloc fails.
502ce0e08e2SPeter Avalos *
503ce0e08e2SPeter Avalos * Note that we modify stringp (putting NULLs after tokens) and
504ce0e08e2SPeter Avalos * we set the ncp's string field pointers to point to these tokens within
505ce0e08e2SPeter Avalos * stringp.
506ce0e08e2SPeter Avalos */
507ce0e08e2SPeter Avalos
508ce0e08e2SPeter Avalos static int
parse_ncp(char * stringp,struct netconfig * ncp)509ce0e08e2SPeter Avalos parse_ncp(char *stringp, /* string to parse */
510ce0e08e2SPeter Avalos struct netconfig *ncp) /* where to put results */
511ce0e08e2SPeter Avalos {
512ce0e08e2SPeter Avalos char *tokenp; /* for processing tokens */
513ce0e08e2SPeter Avalos char *lasts;
514ce0e08e2SPeter Avalos char **nc_lookups;
515ce0e08e2SPeter Avalos
516ce0e08e2SPeter Avalos nc_error = NC_BADFILE; /* nearly anything that breaks is for this reason */
517ce0e08e2SPeter Avalos stringp[strlen(stringp)-1] = '\0'; /* get rid of newline */
518ce0e08e2SPeter Avalos /* netid */
519ce0e08e2SPeter Avalos if ((ncp->nc_netid = strtok_r(stringp, "\t ", &lasts)) == NULL) {
520ce0e08e2SPeter Avalos return (-1);
521ce0e08e2SPeter Avalos }
522ce0e08e2SPeter Avalos
523ce0e08e2SPeter Avalos /* semantics */
524ce0e08e2SPeter Avalos if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) {
525ce0e08e2SPeter Avalos return (-1);
526ce0e08e2SPeter Avalos }
527ce0e08e2SPeter Avalos if (strcmp(tokenp, NC_TPI_COTS_ORD_S) == 0)
528ce0e08e2SPeter Avalos ncp->nc_semantics = NC_TPI_COTS_ORD;
529ce0e08e2SPeter Avalos else if (strcmp(tokenp, NC_TPI_COTS_S) == 0)
530ce0e08e2SPeter Avalos ncp->nc_semantics = NC_TPI_COTS;
531ce0e08e2SPeter Avalos else if (strcmp(tokenp, NC_TPI_CLTS_S) == 0)
532ce0e08e2SPeter Avalos ncp->nc_semantics = NC_TPI_CLTS;
533ce0e08e2SPeter Avalos else if (strcmp(tokenp, NC_TPI_RAW_S) == 0)
534ce0e08e2SPeter Avalos ncp->nc_semantics = NC_TPI_RAW;
535ce0e08e2SPeter Avalos else
536ce0e08e2SPeter Avalos return (-1);
537ce0e08e2SPeter Avalos
538ce0e08e2SPeter Avalos /* flags */
539ce0e08e2SPeter Avalos if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) {
540ce0e08e2SPeter Avalos return (-1);
541ce0e08e2SPeter Avalos }
542ce0e08e2SPeter Avalos for (ncp->nc_flag = NC_NOFLAG; *tokenp != '\0';
543ce0e08e2SPeter Avalos tokenp++) {
544ce0e08e2SPeter Avalos switch (*tokenp) {
545ce0e08e2SPeter Avalos case NC_NOFLAG_C:
546ce0e08e2SPeter Avalos break;
547ce0e08e2SPeter Avalos case NC_VISIBLE_C:
548ce0e08e2SPeter Avalos ncp->nc_flag |= NC_VISIBLE;
549ce0e08e2SPeter Avalos break;
550ce0e08e2SPeter Avalos case NC_BROADCAST_C:
551ce0e08e2SPeter Avalos ncp->nc_flag |= NC_BROADCAST;
552ce0e08e2SPeter Avalos break;
553ce0e08e2SPeter Avalos default:
554ce0e08e2SPeter Avalos return (-1);
555ce0e08e2SPeter Avalos }
556ce0e08e2SPeter Avalos }
557ce0e08e2SPeter Avalos /* protocol family */
558ce0e08e2SPeter Avalos if ((ncp->nc_protofmly = strtok_r(NULL, "\t ", &lasts)) == NULL) {
559ce0e08e2SPeter Avalos return (-1);
560ce0e08e2SPeter Avalos }
561ce0e08e2SPeter Avalos /* protocol name */
562ce0e08e2SPeter Avalos if ((ncp->nc_proto = strtok_r(NULL, "\t ", &lasts)) == NULL) {
563ce0e08e2SPeter Avalos return (-1);
564ce0e08e2SPeter Avalos }
565ce0e08e2SPeter Avalos /* network device */
566ce0e08e2SPeter Avalos if ((ncp->nc_device = strtok_r(NULL, "\t ", &lasts)) == NULL) {
567ce0e08e2SPeter Avalos return (-1);
568ce0e08e2SPeter Avalos }
569ce0e08e2SPeter Avalos if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) {
570ce0e08e2SPeter Avalos return (-1);
571ce0e08e2SPeter Avalos }
572ce0e08e2SPeter Avalos if (strcmp(tokenp, NC_NOLOOKUP) == 0) {
573ce0e08e2SPeter Avalos ncp->nc_nlookups = 0;
574ce0e08e2SPeter Avalos ncp->nc_lookups = NULL;
575ce0e08e2SPeter Avalos } else {
576ce0e08e2SPeter Avalos char *cp; /* tmp string */
577ce0e08e2SPeter Avalos
578ce0e08e2SPeter Avalos if (ncp->nc_lookups != NULL) /* from last visit */
579ce0e08e2SPeter Avalos free(ncp->nc_lookups);
580ce0e08e2SPeter Avalos ncp->nc_lookups = NULL;
581ce0e08e2SPeter Avalos ncp->nc_nlookups = 0;
582ce0e08e2SPeter Avalos while ((cp = tokenp) != NULL) {
583ce0e08e2SPeter Avalos if ((nc_lookups = realloc(ncp->nc_lookups,
584ce0e08e2SPeter Avalos (ncp->nc_nlookups + 1) * sizeof *ncp->nc_lookups)) == NULL) {
585ce0e08e2SPeter Avalos free(ncp->nc_lookups);
586ce0e08e2SPeter Avalos ncp->nc_lookups = NULL;
587ce0e08e2SPeter Avalos return (-1);
588ce0e08e2SPeter Avalos }
589ce0e08e2SPeter Avalos tokenp = _get_next_token(cp, ',');
590ce0e08e2SPeter Avalos ncp->nc_lookups = nc_lookups;
591ce0e08e2SPeter Avalos ncp->nc_lookups[ncp->nc_nlookups++] = cp;
592ce0e08e2SPeter Avalos }
593ce0e08e2SPeter Avalos }
594ce0e08e2SPeter Avalos return (0);
595ce0e08e2SPeter Avalos }
596ce0e08e2SPeter Avalos
597ce0e08e2SPeter Avalos
598ce0e08e2SPeter Avalos /*
599ce0e08e2SPeter Avalos * Returns a string describing the reason for failure.
600ce0e08e2SPeter Avalos */
601ce0e08e2SPeter Avalos char *
nc_sperror(void)602ce0e08e2SPeter Avalos nc_sperror(void)
603ce0e08e2SPeter Avalos {
604ce0e08e2SPeter Avalos const char *message;
605ce0e08e2SPeter Avalos
606ce0e08e2SPeter Avalos switch(nc_error) {
607ce0e08e2SPeter Avalos case NC_NONETCONFIG:
608ce0e08e2SPeter Avalos message = _nc_errors[0];
609ce0e08e2SPeter Avalos break;
610ce0e08e2SPeter Avalos case NC_NOMEM:
611ce0e08e2SPeter Avalos message = _nc_errors[1];
612ce0e08e2SPeter Avalos break;
613ce0e08e2SPeter Avalos case NC_NOTINIT:
614ce0e08e2SPeter Avalos message = _nc_errors[2];
615ce0e08e2SPeter Avalos break;
616ce0e08e2SPeter Avalos case NC_BADFILE:
617ce0e08e2SPeter Avalos message = _nc_errors[3];
618ce0e08e2SPeter Avalos break;
619ce0e08e2SPeter Avalos case NC_NOTFOUND:
620ce0e08e2SPeter Avalos message = _nc_errors[4];
621ce0e08e2SPeter Avalos break;
622ce0e08e2SPeter Avalos default:
623ce0e08e2SPeter Avalos message = "Unknown network selection error";
624ce0e08e2SPeter Avalos }
625ce0e08e2SPeter Avalos /* LINTED const castaway */
626ce0e08e2SPeter Avalos return ((char *)message);
627ce0e08e2SPeter Avalos }
628ce0e08e2SPeter Avalos
629ce0e08e2SPeter Avalos /*
630ce0e08e2SPeter Avalos * Prints a message onto standard error describing the reason for failure.
631ce0e08e2SPeter Avalos */
632ce0e08e2SPeter Avalos void
nc_perror(const char * s)633ce0e08e2SPeter Avalos nc_perror(const char *s)
634ce0e08e2SPeter Avalos {
635ce0e08e2SPeter Avalos fprintf(stderr, "%s: %s\n", s, nc_sperror());
636ce0e08e2SPeter Avalos }
637ce0e08e2SPeter Avalos
638ce0e08e2SPeter Avalos /*
639ce0e08e2SPeter Avalos * Duplicates the matched netconfig buffer.
640ce0e08e2SPeter Avalos */
641ce0e08e2SPeter Avalos static struct netconfig *
dup_ncp(struct netconfig * ncp)642ce0e08e2SPeter Avalos dup_ncp(struct netconfig *ncp)
643ce0e08e2SPeter Avalos {
644ce0e08e2SPeter Avalos struct netconfig *p;
645ce0e08e2SPeter Avalos char *tmp;
646ce0e08e2SPeter Avalos u_int i;
647ce0e08e2SPeter Avalos
648ce0e08e2SPeter Avalos if ((tmp=malloc(MAXNETCONFIGLINE)) == NULL)
649ce0e08e2SPeter Avalos return(NULL);
650ce0e08e2SPeter Avalos if ((p=(struct netconfig *)malloc(sizeof(struct netconfig))) == NULL) {
651ce0e08e2SPeter Avalos free(tmp);
652ce0e08e2SPeter Avalos return(NULL);
653ce0e08e2SPeter Avalos }
654ce0e08e2SPeter Avalos /*
655ce0e08e2SPeter Avalos * First we dup all the data from matched netconfig buffer. Then we
656ce0e08e2SPeter Avalos * adjust some of the member pointer to a pre-allocated buffer where
657ce0e08e2SPeter Avalos * contains part of the data.
658ce0e08e2SPeter Avalos * To follow the convention used in parse_ncp(), we store all the
659ce0e08e2SPeter Avalos * necessary information in the pre-allocated buffer and let each
660ce0e08e2SPeter Avalos * of the netconfig char pointer member point to the right address
661ce0e08e2SPeter Avalos * in the buffer.
662ce0e08e2SPeter Avalos */
663ce0e08e2SPeter Avalos *p = *ncp;
664ce0e08e2SPeter Avalos p->nc_netid = (char *)strcpy(tmp,ncp->nc_netid);
665ce0e08e2SPeter Avalos tmp = strchr(tmp, '\0') + 1;
666ce0e08e2SPeter Avalos p->nc_protofmly = (char *)strcpy(tmp,ncp->nc_protofmly);
667ce0e08e2SPeter Avalos tmp = strchr(tmp, '\0') + 1;
668ce0e08e2SPeter Avalos p->nc_proto = (char *)strcpy(tmp,ncp->nc_proto);
669ce0e08e2SPeter Avalos tmp = strchr(tmp, '\0') + 1;
670ce0e08e2SPeter Avalos p->nc_device = (char *)strcpy(tmp,ncp->nc_device);
671ce0e08e2SPeter Avalos p->nc_lookups = (char **)malloc((size_t)(p->nc_nlookups+1) * sizeof(char *));
672ce0e08e2SPeter Avalos if (p->nc_lookups == NULL) {
673ce0e08e2SPeter Avalos free(p->nc_netid);
674ce0e08e2SPeter Avalos free(p);
675ce0e08e2SPeter Avalos return(NULL);
676ce0e08e2SPeter Avalos }
677ce0e08e2SPeter Avalos for (i=0; i < p->nc_nlookups; i++) {
678ce0e08e2SPeter Avalos tmp = strchr(tmp, '\0') + 1;
679ce0e08e2SPeter Avalos p->nc_lookups[i] = (char *)strcpy(tmp,ncp->nc_lookups[i]);
680ce0e08e2SPeter Avalos }
681ce0e08e2SPeter Avalos return(p);
682ce0e08e2SPeter Avalos }
683