174462Salfred/*	$NetBSD: getnetpath.c,v 1.3 2000/07/06 03:10:34 christos Exp $	*/
274462Salfred
3261057Smav/*-
4261057Smav * Copyright (c) 2009, Sun Microsystems, Inc.
5261057Smav * All rights reserved.
674462Salfred *
7261057Smav * Redistribution and use in source and binary forms, with or without
8261057Smav * modification, are permitted provided that the following conditions are met:
9261057Smav * - Redistributions of source code must retain the above copyright notice,
10261057Smav *   this list of conditions and the following disclaimer.
11261057Smav * - Redistributions in binary form must reproduce the above copyright notice,
12261057Smav *   this list of conditions and the following disclaimer in the documentation
13261057Smav *   and/or other materials provided with the distribution.
14261057Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its
15261057Smav *   contributors may be used to endorse or promote products derived
16261057Smav *   from this software without specific prior written permission.
17261057Smav *
18261057Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19261057Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20261057Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21261057Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22261057Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23261057Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24261057Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25261057Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26261057Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27261057Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28261057Smav * POSSIBILITY OF SUCH DAMAGE.
2974462Salfred */
30136581Sobrien
31136581Sobrien#if defined(LIBC_SCCS) && !defined(lint)
32136581Sobrienstatic char sccsid[] = "@(#)getnetpath.c	1.11 91/12/19 SMI";
3374462Salfred#endif
3492990Sobrien#include <sys/cdefs.h>
3592990Sobrien__FBSDID("$FreeBSD$");
3674462Salfred
3774462Salfred/*
3874462Salfred * Copyright (c) 1989 by Sun Microsystems, Inc.
3974462Salfred */
4074462Salfred
4174462Salfred#include "namespace.h"
4274462Salfred#include <stdio.h>
4374462Salfred#include <errno.h>
4474462Salfred#include <netconfig.h>
4574462Salfred#include <stdlib.h>
4674462Salfred#include <string.h>
4774462Salfred#include <syslog.h>
4874462Salfred#include "un-namespace.h"
4974462Salfred
5074462Salfred/*
5174462Salfred * internal structure to keep track of a netpath "session"
5274462Salfred */
5374462Salfredstruct netpath_chain {
5474462Salfred    struct netconfig *ncp;  /* an nconf entry */
5574462Salfred    struct netpath_chain *nchain_next;	/* next nconf entry allocated */
5674462Salfred};
5774462Salfred
5874462Salfred
5974462Salfredstruct netpath_vars {
6074462Salfred    int   valid;	    /* token that indicates a valid netpath_vars */
6174462Salfred    void *nc_handlep;	    /* handle for current netconfig "session" */
6274462Salfred    char *netpath;	    /* pointer to current view-point in NETPATH */
6374462Salfred    char *netpath_start;    /* pointer to start of our copy of NETPATH */
6474462Salfred    struct netpath_chain *ncp_list;  /* list of nconfs allocated this session*/
6574462Salfred};
6674462Salfred
6774462Salfred#define NP_VALID	0xf00d
6874462Salfred#define NP_INVALID	0
6974462Salfred
7092905Sobrienchar *_get_next_token(char *, int);
7174462Salfred
7274462Salfred
7374462Salfred/*
7474462Salfred * A call to setnetpath() establishes a NETPATH "session".  setnetpath()
7574462Salfred * must be called before the first call to getnetpath().  A "handle" is
7674462Salfred * returned to distinguish the session; this handle should be passed
7774462Salfred * subsequently to getnetpath().  (Handles are used to allow for nested calls
7874462Salfred * to setnetpath()).
7974462Salfred * If setnetpath() is unable to establish a session (due to lack of memory
8074462Salfred * resources, or the absence of the /etc/netconfig file), a NULL pointer is
8174462Salfred * returned.
8274462Salfred */
8374462Salfred
8474462Salfredvoid *
8574462Salfredsetnetpath()
8674462Salfred{
8774462Salfred
8874462Salfred    struct netpath_vars *np_sessionp;   /* this session's variables */
8974462Salfred    char *npp;				/* NETPATH env variable */
9074462Salfred
9174462Salfred#ifdef MEM_CHK
9274462Salfred    malloc_debug(1);
9374462Salfred#endif
9474462Salfred
9574462Salfred    if ((np_sessionp =
9674462Salfred	(struct netpath_vars *)malloc(sizeof (struct netpath_vars))) == NULL) {
9774462Salfred	return (NULL);
9874462Salfred    }
9974462Salfred    if ((np_sessionp->nc_handlep = setnetconfig()) == NULL) {
100162192Smbr	free(np_sessionp);
10174462Salfred	syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
102201603Sbrueffer    	return (NULL);
10374462Salfred    }
10474462Salfred    np_sessionp->valid = NP_VALID;
10574462Salfred    np_sessionp->ncp_list = NULL;
10674462Salfred    if ((npp = getenv(NETPATH)) == NULL) {
10774462Salfred	np_sessionp->netpath = NULL;
10874462Salfred    } else {
10974462Salfred	(void) endnetconfig(np_sessionp->nc_handlep);/* won't need nc session*/
11074462Salfred	np_sessionp->nc_handlep = NULL;
111172259Smatteo	if ((np_sessionp->netpath = malloc(strlen(npp)+1)) == NULL)
112172259Smatteo		goto failed;
113172259Smatteo	else {
11474462Salfred	    (void) strcpy(np_sessionp->netpath, npp);
11574462Salfred	}
11674462Salfred    }
11774462Salfred    np_sessionp->netpath_start = np_sessionp->netpath;
11874462Salfred    return ((void *)np_sessionp);
119172259Smatteo
120172259Smatteofailed:
121172259Smatteo    free(np_sessionp);
122172259Smatteo    return (NULL);
12374462Salfred}
12474462Salfred
12574462Salfred/*
12674462Salfred * When first called, getnetpath() returns a pointer to the netconfig
12774462Salfred * database entry corresponding to the first valid NETPATH component.  The
12874462Salfred * netconfig entry is formatted as a struct netconfig.
12974462Salfred * On each subsequent call, getnetpath returns a pointer to the netconfig
13074462Salfred * entry that corresponds to the next valid NETPATH component.  getnetpath
13174462Salfred * can thus be used to search the netconfig database for all networks
13274462Salfred * included in the NETPATH variable.
13374462Salfred * When NETPATH has been exhausted, getnetpath() returns NULL.  It returns
13474462Salfred * NULL and sets errno in case of an error (e.g., setnetpath was not called
13574462Salfred * previously).
13674462Salfred * getnetpath() silently ignores invalid NETPATH components.  A NETPATH
13774462Salfred * compnent is invalid if there is no corresponding entry in the netconfig
13874462Salfred * database.
13974462Salfred * If the NETPATH variable is unset, getnetpath() behaves as if NETPATH
14074462Salfred * were set to the sequence of default or visible networks in the netconfig
14174462Salfred * database, in the order in which they are listed.
14274462Salfred */
14374462Salfred
14474462Salfredstruct netconfig *
14574462Salfredgetnetpath(handlep)
14674462Salfred    void *handlep;
14774462Salfred{
14874462Salfred    struct netpath_vars *np_sessionp = (struct netpath_vars *)handlep;
14974462Salfred    struct netconfig *ncp = NULL;   /* temp. holds a netconfig session */
15074462Salfred    struct netpath_chain *chainp;   /* holds chain of ncp's we alloc */
15174462Salfred    char  *npp;		/* holds current NETPATH */
15274462Salfred
15374462Salfred    if (np_sessionp == NULL || np_sessionp->valid != NP_VALID) {
15474462Salfred	errno = EINVAL;
15574462Salfred	return (NULL);
15674462Salfred    }
15774462Salfred    if (np_sessionp->netpath_start == NULL) {	/* NETPATH was not set */
15874462Salfred	do {                /* select next visible network */
15974462Salfred	    if (np_sessionp->nc_handlep == NULL) {
16074462Salfred		np_sessionp->nc_handlep = setnetconfig();
16174462Salfred		if (np_sessionp->nc_handlep == NULL)
16274462Salfred		    syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
16374462Salfred	    }
16474462Salfred	    if ((ncp = getnetconfig(np_sessionp->nc_handlep)) == NULL) {
16574462Salfred		return(NULL);
16674462Salfred	    }
16774462Salfred	} while ((ncp->nc_flag & NC_VISIBLE) == 0);
16874462Salfred	return (ncp);
16974462Salfred    }
17074462Salfred    /*
17174462Salfred     * Find first valid network ID in netpath.
17274462Salfred     */
17374462Salfred    while ((npp = np_sessionp->netpath) != NULL && strlen(npp) != 0) {
17474462Salfred	np_sessionp->netpath = _get_next_token(npp, ':');
17574462Salfred    	/*
17674462Salfred    	 * npp is a network identifier.
17774462Salfred	 */
17874462Salfred	if ((ncp = getnetconfigent(npp)) != NULL) {
17974462Salfred	    chainp = (struct netpath_chain *)	/* cobble alloc chain entry */
18074462Salfred		    malloc(sizeof (struct netpath_chain));
18174462Salfred	    chainp->ncp = ncp;
18274462Salfred	    chainp->nchain_next = NULL;
18374462Salfred	    if (np_sessionp->ncp_list == NULL) {
18474462Salfred		np_sessionp->ncp_list = chainp;
18574462Salfred	    } else {
18674462Salfred		np_sessionp->ncp_list->nchain_next = chainp;
18774462Salfred	    }
18874462Salfred	    return (ncp);
18974462Salfred	}
19074462Salfred	/* couldn't find this token in the database; go to next one. */
19174462Salfred    }
19274462Salfred    return (NULL);
19374462Salfred}
19474462Salfred
19574462Salfred/*
19674462Salfred * endnetpath() may be called to unbind NETPATH when processing is complete,
19774462Salfred * releasing resources for reuse.  It returns 0 on success and -1 on failure
19874462Salfred * (e.g. if setnetpath() was not called previously.
19974462Salfred */
20074462Salfredint
20174462Salfredendnetpath(handlep)
20274462Salfred    void *handlep;
20374462Salfred{
20474462Salfred    struct netpath_vars *np_sessionp = (struct netpath_vars *)handlep;
20574462Salfred    struct netpath_chain *chainp, *lastp;
20674462Salfred
20774462Salfred    if (np_sessionp == NULL || np_sessionp->valid != NP_VALID) {
20874462Salfred	errno = EINVAL;
20974462Salfred	return (-1);
21074462Salfred    }
21174462Salfred    if (np_sessionp->nc_handlep != NULL)
21274462Salfred	endnetconfig(np_sessionp->nc_handlep);
21374462Salfred    if (np_sessionp->netpath_start != NULL)
21474462Salfred	free(np_sessionp->netpath_start);
21574462Salfred    for (chainp = np_sessionp->ncp_list; chainp != NULL;
21674462Salfred	    lastp=chainp, chainp=chainp->nchain_next, free(lastp)) {
21774462Salfred	freenetconfigent(chainp->ncp);
21874462Salfred    }
21974462Salfred    free(np_sessionp);
22074462Salfred#ifdef MEM_CHK
22174462Salfred    if (malloc_verify() == 0) {
22274462Salfred	fprintf(stderr, "memory heap corrupted in endnetpath\n");
22374462Salfred	exit(1);
22474462Salfred    }
22574462Salfred#endif
22674462Salfred    return (0);
22774462Salfred}
22874462Salfred
22974462Salfred
23074462Salfred
23174462Salfred/*
23274462Salfred * Returns pointer to the rest-of-the-string after the current token.
23374462Salfred * The token itself starts at arg, and we null terminate it.  We return NULL
23474462Salfred * if either the arg is empty, or if this is the last token.
23574462Salfred */
23674462Salfred
23774462Salfredchar *
23874462Salfred_get_next_token(npp, token)
23974462Salfredchar *npp;		/* string */
24074462Salfredint token;		/* char to parse string for */
24174462Salfred{
24274462Salfred    char  *cp;		/* char pointer */
24374462Salfred    char  *np;		/* netpath pointer */
24474462Salfred    char  *ep;		/* escape pointer */
24574462Salfred
24674462Salfred    if ((cp = strchr(npp, token)) == NULL) {
24774462Salfred	return (NULL);
24874462Salfred    }
24974462Salfred    /*
25074462Salfred     * did find a token, but it might be escaped.
25174462Salfred     */
252109953Smbr    if ((cp > npp) && (cp[-1] == '\\')) {
25374462Salfred        /* if slash was also escaped, carry on, otherwise find next token */
254109953Smbr	if ((cp > npp + 1) && (cp[-2] != '\\')) {
25574462Salfred	    /* shift r-o-s  onto the escaped token */
25674462Salfred	    strcpy(&cp[-1], cp);    /* XXX: overlapping string copy */
25774462Salfred	    /*
25874462Salfred	     * Do a recursive call.
25974462Salfred	     * We don't know how many escaped tokens there might be.
26074462Salfred	     */
26174462Salfred	    return (_get_next_token(cp, token));
26274462Salfred	}
26374462Salfred    }
26474462Salfred
26574462Salfred    *cp++ = '\0';		/* null-terminate token */
26674462Salfred    /* get rid of any backslash escapes */
26774462Salfred    ep = npp;
26874462Salfred    while ((np = strchr(ep, '\\')) != 0) {
26974462Salfred	if (np[1] == '\\')
27074462Salfred	    np++;
27174462Salfred	strcpy(np, (ep = &np[1]));  /* XXX: overlapping string copy */
27274462Salfred    }
27374462Salfred    return (cp);		/* return ptr to r-o-s */
27474462Salfred}
275