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 * @(#)getnetpath.c 1.11 91/12/19 SMI
29ce0e08e2SPeter Avalos * $NetBSD: getnetpath.c,v 1.3 2000/07/06 03:10:34 christos Exp $
30ce0e08e2SPeter Avalos * $FreeBSD: src/lib/libc/rpc/getnetpath.c,v 1.8 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 <stdio.h>
39ce0e08e2SPeter Avalos #include <errno.h>
40ce0e08e2SPeter Avalos #include <netconfig.h>
41ce0e08e2SPeter Avalos #include <stdlib.h>
42ce0e08e2SPeter Avalos #include <string.h>
43ce0e08e2SPeter Avalos #include <syslog.h>
44ce0e08e2SPeter Avalos #include "un-namespace.h"
45ce0e08e2SPeter Avalos
46ce0e08e2SPeter Avalos /*
47ce0e08e2SPeter Avalos * internal structure to keep track of a netpath "session"
48ce0e08e2SPeter Avalos */
49ce0e08e2SPeter Avalos struct netpath_chain {
50ce0e08e2SPeter Avalos struct netconfig *ncp; /* an nconf entry */
51ce0e08e2SPeter Avalos struct netpath_chain *nchain_next; /* next nconf entry allocated */
52ce0e08e2SPeter Avalos };
53ce0e08e2SPeter Avalos
54ce0e08e2SPeter Avalos
55ce0e08e2SPeter Avalos struct netpath_vars {
56ce0e08e2SPeter Avalos int valid; /* token that indicates a valid netpath_vars */
57ce0e08e2SPeter Avalos void *nc_handlep; /* handle for current netconfig "session" */
58ce0e08e2SPeter Avalos char *netpath; /* pointer to current view-point in NETPATH */
59ce0e08e2SPeter Avalos char *netpath_start; /* pointer to start of our copy of NETPATH */
60ce0e08e2SPeter Avalos struct netpath_chain *ncp_list; /* list of nconfs allocated this session*/
61ce0e08e2SPeter Avalos };
62ce0e08e2SPeter Avalos
63ce0e08e2SPeter Avalos #define NP_VALID 0xf00d
64ce0e08e2SPeter Avalos #define NP_INVALID 0
65ce0e08e2SPeter Avalos
66ce0e08e2SPeter Avalos char *_get_next_token(char *, int);
67ce0e08e2SPeter Avalos
68ce0e08e2SPeter Avalos
69ce0e08e2SPeter Avalos /*
70ce0e08e2SPeter Avalos * A call to setnetpath() establishes a NETPATH "session". setnetpath()
71ce0e08e2SPeter Avalos * must be called before the first call to getnetpath(). A "handle" is
72ce0e08e2SPeter Avalos * returned to distinguish the session; this handle should be passed
73ce0e08e2SPeter Avalos * subsequently to getnetpath(). (Handles are used to allow for nested calls
74ce0e08e2SPeter Avalos * to setnetpath()).
75ce0e08e2SPeter Avalos * If setnetpath() is unable to establish a session (due to lack of memory
76ce0e08e2SPeter Avalos * resources, or the absence of the /etc/netconfig file), a NULL pointer is
77ce0e08e2SPeter Avalos * returned.
78ce0e08e2SPeter Avalos */
79ce0e08e2SPeter Avalos
80ce0e08e2SPeter Avalos void *
setnetpath(void)81ce0e08e2SPeter Avalos setnetpath(void)
82ce0e08e2SPeter Avalos {
83ce0e08e2SPeter Avalos
84ce0e08e2SPeter Avalos struct netpath_vars *np_sessionp; /* this session's variables */
85ce0e08e2SPeter Avalos char *npp; /* NETPATH env variable */
86ce0e08e2SPeter Avalos
87ce0e08e2SPeter Avalos #ifdef MEM_CHK
88ce0e08e2SPeter Avalos malloc_debug(1);
89ce0e08e2SPeter Avalos #endif
90ce0e08e2SPeter Avalos
91ce0e08e2SPeter Avalos if ((np_sessionp =
92ce0e08e2SPeter Avalos (struct netpath_vars *)malloc(sizeof (struct netpath_vars))) == NULL) {
93ce0e08e2SPeter Avalos return (NULL);
94ce0e08e2SPeter Avalos }
95ce0e08e2SPeter Avalos if ((np_sessionp->nc_handlep = setnetconfig()) == NULL) {
96ce0e08e2SPeter Avalos syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
97ce0e08e2SPeter Avalos goto failed;
98ce0e08e2SPeter Avalos }
99ce0e08e2SPeter Avalos np_sessionp->valid = NP_VALID;
100ce0e08e2SPeter Avalos np_sessionp->ncp_list = NULL;
101ce0e08e2SPeter Avalos if ((npp = getenv(NETPATH)) == NULL) {
102ce0e08e2SPeter Avalos np_sessionp->netpath = NULL;
103ce0e08e2SPeter Avalos } else {
104ce0e08e2SPeter Avalos endnetconfig(np_sessionp->nc_handlep);/* won't need nc session*/
105ce0e08e2SPeter Avalos np_sessionp->nc_handlep = NULL;
106ce0e08e2SPeter Avalos if ((np_sessionp->netpath = malloc(strlen(npp)+1)) == NULL)
107ce0e08e2SPeter Avalos goto failed;
108ce0e08e2SPeter Avalos else {
109ce0e08e2SPeter Avalos strcpy(np_sessionp->netpath, npp);
110ce0e08e2SPeter Avalos }
111ce0e08e2SPeter Avalos }
112ce0e08e2SPeter Avalos np_sessionp->netpath_start = np_sessionp->netpath;
113ce0e08e2SPeter Avalos return ((void *)np_sessionp);
114ce0e08e2SPeter Avalos
115ce0e08e2SPeter Avalos failed:
116ce0e08e2SPeter Avalos free(np_sessionp);
117ce0e08e2SPeter Avalos return (NULL);
118ce0e08e2SPeter Avalos }
119ce0e08e2SPeter Avalos
120ce0e08e2SPeter Avalos /*
121ce0e08e2SPeter Avalos * When first called, getnetpath() returns a pointer to the netconfig
122ce0e08e2SPeter Avalos * database entry corresponding to the first valid NETPATH component. The
123ce0e08e2SPeter Avalos * netconfig entry is formatted as a struct netconfig.
124ce0e08e2SPeter Avalos * On each subsequent call, getnetpath returns a pointer to the netconfig
125ce0e08e2SPeter Avalos * entry that corresponds to the next valid NETPATH component. getnetpath
126ce0e08e2SPeter Avalos * can thus be used to search the netconfig database for all networks
127ce0e08e2SPeter Avalos * included in the NETPATH variable.
128ce0e08e2SPeter Avalos * When NETPATH has been exhausted, getnetpath() returns NULL. It returns
129ce0e08e2SPeter Avalos * NULL and sets errno in case of an error (e.g., setnetpath was not called
130ce0e08e2SPeter Avalos * previously).
131ce0e08e2SPeter Avalos * getnetpath() silently ignores invalid NETPATH components. A NETPATH
132ce0e08e2SPeter Avalos * compnent is invalid if there is no corresponding entry in the netconfig
133ce0e08e2SPeter Avalos * database.
134ce0e08e2SPeter Avalos * If the NETPATH variable is unset, getnetpath() behaves as if NETPATH
135ce0e08e2SPeter Avalos * were set to the sequence of default or visible networks in the netconfig
136ce0e08e2SPeter Avalos * database, in the order in which they are listed.
137ce0e08e2SPeter Avalos */
138ce0e08e2SPeter Avalos
139ce0e08e2SPeter Avalos struct netconfig *
getnetpath(void * handlep)140ce0e08e2SPeter Avalos getnetpath(void *handlep)
141ce0e08e2SPeter Avalos {
142ce0e08e2SPeter Avalos struct netpath_vars *np_sessionp = (struct netpath_vars *)handlep;
143ce0e08e2SPeter Avalos struct netconfig *ncp = NULL; /* temp. holds a netconfig session */
144ce0e08e2SPeter Avalos struct netpath_chain *chainp; /* holds chain of ncp's we alloc */
145ce0e08e2SPeter Avalos char *npp; /* holds current NETPATH */
146ce0e08e2SPeter Avalos
147ce0e08e2SPeter Avalos if (np_sessionp == NULL || np_sessionp->valid != NP_VALID) {
148ce0e08e2SPeter Avalos errno = EINVAL;
149ce0e08e2SPeter Avalos return (NULL);
150ce0e08e2SPeter Avalos }
151ce0e08e2SPeter Avalos if (np_sessionp->netpath_start == NULL) { /* NETPATH was not set */
152ce0e08e2SPeter Avalos do { /* select next visible network */
153ce0e08e2SPeter Avalos if (np_sessionp->nc_handlep == NULL) {
154ce0e08e2SPeter Avalos np_sessionp->nc_handlep = setnetconfig();
155ce0e08e2SPeter Avalos if (np_sessionp->nc_handlep == NULL)
156ce0e08e2SPeter Avalos syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
157ce0e08e2SPeter Avalos }
158ce0e08e2SPeter Avalos if ((ncp = getnetconfig(np_sessionp->nc_handlep)) == NULL) {
159ce0e08e2SPeter Avalos return(NULL);
160ce0e08e2SPeter Avalos }
161ce0e08e2SPeter Avalos } while ((ncp->nc_flag & NC_VISIBLE) == 0);
162ce0e08e2SPeter Avalos return (ncp);
163ce0e08e2SPeter Avalos }
164ce0e08e2SPeter Avalos /*
165ce0e08e2SPeter Avalos * Find first valid network ID in netpath.
166ce0e08e2SPeter Avalos */
167ce0e08e2SPeter Avalos while ((npp = np_sessionp->netpath) != NULL && strlen(npp) != 0) {
168ce0e08e2SPeter Avalos np_sessionp->netpath = _get_next_token(npp, ':');
169ce0e08e2SPeter Avalos /*
170ce0e08e2SPeter Avalos * npp is a network identifier.
171ce0e08e2SPeter Avalos */
172ce0e08e2SPeter Avalos if ((ncp = getnetconfigent(npp)) != NULL) {
173ce0e08e2SPeter Avalos chainp = (struct netpath_chain *) /* cobble alloc chain entry */
174ce0e08e2SPeter Avalos malloc(sizeof (struct netpath_chain));
175ce0e08e2SPeter Avalos chainp->ncp = ncp;
176ce0e08e2SPeter Avalos chainp->nchain_next = NULL;
177ce0e08e2SPeter Avalos if (np_sessionp->ncp_list == NULL) {
178ce0e08e2SPeter Avalos np_sessionp->ncp_list = chainp;
179ce0e08e2SPeter Avalos } else {
180ce0e08e2SPeter Avalos np_sessionp->ncp_list->nchain_next = chainp;
181ce0e08e2SPeter Avalos }
182ce0e08e2SPeter Avalos return (ncp);
183ce0e08e2SPeter Avalos }
184ce0e08e2SPeter Avalos /* couldn't find this token in the database; go to next one. */
185ce0e08e2SPeter Avalos }
186ce0e08e2SPeter Avalos return (NULL);
187ce0e08e2SPeter Avalos }
188ce0e08e2SPeter Avalos
189ce0e08e2SPeter Avalos /*
190ce0e08e2SPeter Avalos * endnetpath() may be called to unbind NETPATH when processing is complete,
191ce0e08e2SPeter Avalos * releasing resources for reuse. It returns 0 on success and -1 on failure
192ce0e08e2SPeter Avalos * (e.g. if setnetpath() was not called previously.
193ce0e08e2SPeter Avalos */
194ce0e08e2SPeter Avalos int
endnetpath(void * handlep)195ce0e08e2SPeter Avalos endnetpath(void *handlep)
196ce0e08e2SPeter Avalos {
197ce0e08e2SPeter Avalos struct netpath_vars *np_sessionp = (struct netpath_vars *)handlep;
198ce0e08e2SPeter Avalos struct netpath_chain *chainp, *lastp;
199ce0e08e2SPeter Avalos
200ce0e08e2SPeter Avalos if (np_sessionp == NULL || np_sessionp->valid != NP_VALID) {
201ce0e08e2SPeter Avalos errno = EINVAL;
202ce0e08e2SPeter Avalos return (-1);
203ce0e08e2SPeter Avalos }
204ce0e08e2SPeter Avalos if (np_sessionp->nc_handlep != NULL)
205ce0e08e2SPeter Avalos endnetconfig(np_sessionp->nc_handlep);
206ce0e08e2SPeter Avalos if (np_sessionp->netpath_start != NULL)
207ce0e08e2SPeter Avalos free(np_sessionp->netpath_start);
208ce0e08e2SPeter Avalos for (chainp = np_sessionp->ncp_list; chainp != NULL;
209ce0e08e2SPeter Avalos lastp=chainp, chainp=chainp->nchain_next, free(lastp)) {
210ce0e08e2SPeter Avalos freenetconfigent(chainp->ncp);
211ce0e08e2SPeter Avalos }
212ce0e08e2SPeter Avalos free(np_sessionp);
213ce0e08e2SPeter Avalos #ifdef MEM_CHK
214ce0e08e2SPeter Avalos if (malloc_verify() == 0) {
215ce0e08e2SPeter Avalos fprintf(stderr, "memory heap corrupted in endnetpath\n");
216ce0e08e2SPeter Avalos exit(1);
217ce0e08e2SPeter Avalos }
218ce0e08e2SPeter Avalos #endif
219ce0e08e2SPeter Avalos return (0);
220ce0e08e2SPeter Avalos }
221ce0e08e2SPeter Avalos
222ce0e08e2SPeter Avalos
223ce0e08e2SPeter Avalos
224ce0e08e2SPeter Avalos /*
225ce0e08e2SPeter Avalos * Returns pointer to the rest-of-the-string after the current token.
226ce0e08e2SPeter Avalos * The token itself starts at arg, and we null terminate it. We return NULL
227ce0e08e2SPeter Avalos * if either the arg is empty, or if this is the last token.
228ce0e08e2SPeter Avalos */
229ce0e08e2SPeter Avalos
230ce0e08e2SPeter Avalos char *
_get_next_token(char * npp,int token)231ce0e08e2SPeter Avalos _get_next_token(char *npp, /* string */
232ce0e08e2SPeter Avalos int token) /* char to parse string for */
233ce0e08e2SPeter Avalos {
234ce0e08e2SPeter Avalos char *cp; /* char pointer */
235ce0e08e2SPeter Avalos char *np; /* netpath pointer */
236ce0e08e2SPeter Avalos char *ep; /* escape pointer */
237ce0e08e2SPeter Avalos
238ce0e08e2SPeter Avalos if ((cp = strchr(npp, token)) == NULL) {
239ce0e08e2SPeter Avalos return (NULL);
240ce0e08e2SPeter Avalos }
241ce0e08e2SPeter Avalos /*
242ce0e08e2SPeter Avalos * did find a token, but it might be escaped.
243ce0e08e2SPeter Avalos */
244ce0e08e2SPeter Avalos if ((cp > npp) && (cp[-1] == '\\')) {
245ce0e08e2SPeter Avalos /* if slash was also escaped, carry on, otherwise find next token */
246ce0e08e2SPeter Avalos if ((cp > npp + 1) && (cp[-2] != '\\')) {
247ce0e08e2SPeter Avalos /* shift r-o-s onto the escaped token */
248ce0e08e2SPeter Avalos strcpy(&cp[-1], cp); /* XXX: overlapping string copy */
249ce0e08e2SPeter Avalos /*
250ce0e08e2SPeter Avalos * Do a recursive call.
251ce0e08e2SPeter Avalos * We don't know how many escaped tokens there might be.
252ce0e08e2SPeter Avalos */
253ce0e08e2SPeter Avalos return (_get_next_token(cp, token));
254ce0e08e2SPeter Avalos }
255ce0e08e2SPeter Avalos }
256ce0e08e2SPeter Avalos
257ce0e08e2SPeter Avalos *cp++ = '\0'; /* null-terminate token */
258ce0e08e2SPeter Avalos /* get rid of any backslash escapes */
259ce0e08e2SPeter Avalos ep = npp;
260678e8cc6SSascha Wildner while ((np = strchr(ep, '\\')) != NULL) {
261ce0e08e2SPeter Avalos if (np[1] == '\\')
262ce0e08e2SPeter Avalos np++;
263ce0e08e2SPeter Avalos strcpy(np, (ep = &np[1])); /* XXX: overlapping string copy */
264ce0e08e2SPeter Avalos }
265ce0e08e2SPeter Avalos return (cp); /* return ptr to r-o-s */
266ce0e08e2SPeter Avalos }
267