xref: /dragonfly/lib/libc/rpc/getnetpath.c (revision ba96d07f)
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