summaryrefslogtreecommitdiff
path: root/usr/src/lib/libnsl/netselect/netselect.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libnsl/netselect/netselect.c
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libnsl/netselect/netselect.c')
-rw-r--r--usr/src/lib/libnsl/netselect/netselect.c1070
1 files changed, 1070 insertions, 0 deletions
diff --git a/usr/src/lib/libnsl/netselect/netselect.c b/usr/src/lib/libnsl/netselect/netselect.c
new file mode 100644
index 0000000000..88bdf075db
--- /dev/null
+++ b/usr/src/lib/libnsl/netselect/netselect.c
@@ -0,0 +1,1070 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "mt.h"
+#include "../rpc/rpc_mt.h" /* for MT declarations only */
+#include <rpc/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <rpc/trace.h>
+#include <netconfig.h>
+#include <malloc.h>
+#include <syslog.h>
+#include "netcspace.h"
+#include "nsl_stdio_prv.h"
+
+#define FAILURE (unsigned)(-1)
+
+/*
+ * Local routines used by the library procedures
+ */
+
+static int blank();
+static int comment();
+static struct netconfig *fgetnetconfig();
+static void netconfig_free();
+static unsigned int getflag();
+static char **getlookups();
+static struct netconfig **getnetlist();
+static unsigned int getnlookups();
+static char *gettoken();
+static unsigned int getvalue();
+static void shift1left();
+static void netlist_free();
+static void free_entry();
+static struct netconfig *netconfig_dup();
+
+/*
+ * System V routines used by the library procedures.
+ */
+extern char *getenv();
+
+/* messaging stuff. */
+
+extern const char __nsl_dom[];
+extern char *dgettext(const char *, const char *);
+
+/*
+ * Static global variables used by the library procedures:
+ *
+ * netpp - points to the beginning of the list of netconfig
+ * entries used by setnetconfig() and setnetpath().
+ * Once netpp is initialized, that memory is *never*
+ * released. This was necessary to improve performance.
+ *
+ * linenum - the current line number of the /etc/netconfig
+ * file (used for debugging and for nc_perror()).
+ *
+ * fieldnum - the current field number of the current line
+ * of /etc/netconfig (used for debugging and for
+ * nc_perror()).
+ *
+ * nc_error - the error condition encountered.
+ */
+
+static struct netconfig **netpp = NULL;
+mutex_t netpp_mutex = DEFAULTMUTEX;
+/*
+ * The following two variables are used by the /etc/netconfig parsing
+ * routines, which will always be executed once, and within the netpp_mutex.
+ * They are global to allow the nc_sperror routine to provide better
+ * information to the user about /etc/netconfig file problems.
+ */
+static int linenum = 0; /* "owned" by getnetlist() */
+static int fieldnum = 0; /* "owned" by fgetnetconfig() */
+
+
+static int *
+__nc_error()
+{
+ static pthread_key_t nc_error_key = 0;
+ static int nc_error = NC_NOERROR;
+ int *ret;
+
+ if (thr_main())
+ return (&nc_error);
+ ret = thr_get_storage(&nc_error_key, sizeof (int), free);
+ /* if thr_get_storage fails we return the address of nc_error */
+ return (ret ? ret : &nc_error);
+}
+#define nc_error (*(__nc_error()))
+
+/*
+ * setnetconfig() has the effect of "initializing" the
+ * network configuration database. It reads in the
+ * netcf entries (if not already read in).
+ */
+
+void *
+setnetconfig()
+{
+ NCONF_HANDLE *retp;
+
+ trace1(TR_setnetconfig, 0);
+ mutex_lock(&netpp_mutex);
+ if ((netpp == NULL) && ((netpp = getnetlist()) == NULL)) {
+ mutex_unlock(&netpp_mutex);
+ trace1(TR_setnetconfig, 1);
+ return (NULL);
+ }
+ mutex_unlock(&netpp_mutex);
+ if ((retp = (NCONF_HANDLE *) malloc(sizeof (NCONF_HANDLE))) == NULL) {
+ nc_error = NC_NOMEM;
+ trace1(TR_setnetconfig, 1);
+ return (NULL);
+ }
+ nc_error = NC_NOERROR;
+ retp->nc_head = retp->nc_curr = netpp;
+ trace1(TR_setnetconfig, 1);
+ return ((void *)retp);
+}
+
+/*
+ * endnetconfig() frees up all data allocated by setnetconfig()
+ */
+
+int
+endnetconfig(vdata)
+void *vdata;
+{
+ NCONF_HANDLE *nconf_handlep = (NCONF_HANDLE *)vdata;
+
+ trace1(TR_endnetconfig, 0);
+ mutex_lock(&netpp_mutex);
+ if (netpp == NULL || nconf_handlep == NULL) {
+ nc_error = NC_NOSET;
+ mutex_unlock(&netpp_mutex);
+ trace1(TR_endnetconfig, 1);
+ return (-1);
+ }
+ mutex_unlock(&netpp_mutex);
+
+ nc_error = NC_NOERROR;
+ free((void *)nconf_handlep);
+ trace1(TR_endnetconfig, 1);
+ return (0);
+}
+
+/*
+ * getnetconfig() returns the current entry in the list
+ * of netconfig structures. It uses the nconf_handlep argument
+ * to determine the current entry. If setnetconfig() was not
+ * called previously to set up the list, return failure.
+ * It also check if ipv6 interface is present(ipv6_present) and
+ * skips udp6 & tcp6 entries if ipv6 is not supported.
+ */
+
+struct netconfig *
+getnetconfig(vdata)
+void *vdata;
+{
+ NCONF_HANDLE *nconf_handlep = (NCONF_HANDLE *)vdata;
+ struct netconfig *retp; /* holds the return value */
+ int ipv6_present = -1;
+
+ trace1(TR_getnetconfig, 0);
+ mutex_lock(&netpp_mutex);
+ if ((netpp == NULL) || (nconf_handlep == NULL)) {
+ nc_error = NC_NOSET;
+ mutex_unlock(&netpp_mutex);
+ trace1(TR_getnetconfig, 1);
+ return (NULL);
+ }
+ mutex_unlock(&netpp_mutex);
+ for (;;) {
+ retp = *(nconf_handlep->nc_curr);
+ if (retp && (strcmp(retp->nc_netid, "udp6") == 0 ||
+ strcmp(retp->nc_netid, "tcp6") == 0)) {
+ if (ipv6_present == -1)
+ ipv6_present = __can_use_af(AF_INET6);
+ if (!ipv6_present) {
+ ++(nconf_handlep->nc_curr);
+ continue;
+ }
+ }
+ break;
+ }
+ if (retp != NULL) {
+ ++(nconf_handlep->nc_curr);
+ nc_error = NC_NOERROR;
+ } else {
+ nc_error = NC_NOMOREENTRIES;
+ }
+ trace1(TR_getnetconfig, 1);
+ return (retp);
+}
+
+/*
+ * getnetconfig() searches the netconfig database for a
+ * given network id. Returns a pointer to the netconfig
+ * structure or a NULL if not found.
+ * It also check if ipv6 interface is present(ipv6_present) and
+ * skips udp6 & tcp6 entries if ipv6 is not supported.
+ */
+
+struct netconfig *
+getnetconfigent(netid)
+const char *netid;
+{
+ struct netconfig **tpp;
+ int ipv6_present;
+
+ trace1(TR_getnetconfigent, 0);
+ mutex_lock(&netpp_mutex);
+ if ((netpp == NULL) && ((netpp = getnetlist()) == NULL)) {
+ mutex_unlock(&netpp_mutex);
+ trace1(TR_getnetconfigent, 1);
+ return (NULL);
+ }
+ mutex_unlock(&netpp_mutex);
+ for (tpp = netpp; *tpp; tpp++) {
+ if (strcmp((*tpp)->nc_netid, netid) == 0) {
+ if (*tpp && (strcmp((*tpp)->nc_netid, "udp6") == 0 ||
+ strcmp((*tpp)->nc_netid, "tcp6") == 0)) {
+ ipv6_present = __can_use_af(AF_INET6);
+ if (!ipv6_present) {
+ nc_error = NC_NOTFOUND;
+ trace1(TR_getnetconfigent, 1);
+ return (NULL);
+ }
+ }
+ trace1(TR_getnetconfigent, 1);
+ return (netconfig_dup(*tpp));
+ }
+ }
+ nc_error = NC_NOTFOUND;
+ trace1(TR_getnetconfigent, 1);
+ return (NULL);
+}
+
+/*
+ * freenetconfigent frees the data allocated by getnetconfigent()
+ */
+
+void
+freenetconfigent(netp)
+struct netconfig *netp;
+{
+ trace1(TR_freenetconfigent, 0);
+ netconfig_free(netp);
+ trace1(TR_freenetconfigent, 1);
+}
+
+/*
+ * getnetlist() reads the netconfig file and creates a
+ * NULL-terminated list of entries.
+ * Returns the pointer to the head of the list or a NULL
+ * on failure.
+ */
+
+static struct netconfig **
+getnetlist()
+{
+ char line[BUFSIZ]; /* holds each line of NETCONFIG */
+ __NSL_FILE *fp; /* file stream for NETCONFIG */
+ struct netconfig **listpp; /* the beginning of the netconfig list */
+ struct netconfig **tpp; /* used to traverse the netconfig list */
+ int count; /* the number of entries in file */
+
+ trace1(TR_getnetlist, 0);
+ if ((fp = __nsl_fopen(NETCONFIG, "r")) == NULL) {
+ nc_error = NC_OPENFAIL;
+ trace1(TR_getnetlist, 1);
+ return (NULL);
+ }
+
+ count = 0;
+ while (__nsl_fgets(line, BUFSIZ, fp)) {
+ if (!(blank(line) || comment(line))) {
+ ++count;
+ }
+ }
+ __nsl_rewind(fp);
+
+ if (count == 0) {
+ nc_error = NC_NOTFOUND;
+ (void) __nsl_fclose(fp);
+ trace1(TR_getnetlist, 1);
+ return (NULL);
+ }
+ if ((listpp = (struct netconfig **)malloc((count + 1) *
+ sizeof (struct netconfig *))) == NULL) {
+ nc_error = NC_NOMEM;
+ (void) __nsl_fclose(fp);
+ trace1(TR_getnetlist, 1);
+ return (NULL);
+ }
+
+ /*
+ * The following loop fills in the list (loops until
+ * fgetnetconfig() returns a NULL) and counts the
+ * number of entries placed in the list. Note that
+ * when the loop is completed, the last entry in the
+ * list will contain a NULL (signifying the end of
+ * the list).
+ */
+ linenum = 0;
+ for (tpp = listpp; *tpp = fgetnetconfig(fp, NULL); tpp++)
+ ;
+ (void) __nsl_fclose(fp);
+
+ if (nc_error != NC_NOMOREENTRIES) /* Something is screwed up */
+ netlist_free(&listpp);
+ trace1(TR_getnetlist, 1);
+ return (listpp);
+}
+
+/*
+ * fgetnetconfig() parses a line of the netconfig file into
+ * a netconfig structure. It returns a pointer to the
+ * structure of success and a NULL on failure or EOF.
+ */
+
+static struct netconfig *
+fgetnetconfig(fp, netid)
+__NSL_FILE *fp;
+char *netid;
+{
+ char linep[BUFSIZ]; /* pointer to a line in the file */
+ struct netconfig *netconfigp; /* holds the new netconfig structure */
+ char *tok1, *tok2, *tok3; /* holds a token from the line */
+ char *retvalp; /* the return value of fgets() */
+ char *entnetid; /* netid for the current entry */
+
+ trace1(TR_fgetnetconfig, 0);
+ /* skip past blank lines and comments. */
+ while (retvalp = __nsl_fgets(linep, BUFSIZ, fp)) {
+ linenum++;
+ if (!(blank(linep) || comment(linep))) {
+ break;
+ }
+ retvalp = NULL;
+ }
+ if (retvalp == NULL) {
+ nc_error = NC_NOMOREENTRIES;
+ trace1(TR_fgetnetconfig, 1);
+ return (NULL);
+ }
+ fieldnum = 0;
+ if ((entnetid = gettoken(linep, FALSE)) == NULL) {
+ nc_error = NC_BADLINE;
+ trace1(TR_fgetnetconfig, 1);
+ return (NULL);
+ }
+ if (netid && (strcmp(netid, entnetid) != 0)) {
+ free(entnetid);
+ nc_error = NC_NOTFOUND;
+ trace1(TR_fgetnetconfig, 1);
+ return (NULL);
+ }
+ if ((netconfigp = (struct netconfig *)
+ calloc(1, sizeof (struct netconfig))) == NULL) {
+ free(entnetid);
+ nc_error = NC_NOMEM;
+ trace1(TR_fgetnetconfig, 1);
+ return (NULL);
+ }
+
+ tok1 = tok2 = tok3 = NULL;
+ netconfigp->nc_netid = entnetid;
+ if (((tok1 = gettoken(NULL, FALSE)) == NULL) ||
+ ((netconfigp->nc_semantics =
+ getvalue(tok1, nc_semantics)) == FAILURE) ||
+ ((tok2 = gettoken(NULL, FALSE)) == NULL) ||
+ ((netconfigp->nc_flag = getflag(tok2)) == FAILURE) ||
+ ((netconfigp->nc_protofmly = gettoken(NULL, FALSE)) == NULL) ||
+ ((netconfigp->nc_proto = gettoken(NULL, FALSE)) == NULL) ||
+ ((netconfigp->nc_device = gettoken(NULL, FALSE)) == NULL) ||
+ ((tok3 = gettoken(NULL, TRUE)) == NULL) ||
+ (((netconfigp->nc_nlookups = getnlookups(tok3)) != 0) &&
+ ((netconfigp->nc_lookups = getlookups(tok3)) == NULL))) {
+ netconfig_free(netconfigp);
+ nc_error = NC_BADLINE;
+ netconfigp = NULL;
+ }
+ free(tok1);
+ free(tok2);
+ free(tok3);
+ trace1(TR_fgetnetconfig, 1);
+ return (netconfigp);
+}
+
+/*
+ * setnetpath() has the effect of "initializing" the
+ * NETPATH variable. It reads in the netcf entries (if not
+ * already read in), creates a list corresponding to the entries
+ * in the NETPATH variable (or the "visible" entries og netconfig
+ * if NETPATH is not set).
+ */
+
+void *
+setnetpath()
+{
+ int count; /* the number of entries in NETPATH */
+ char valid_netpath[BUFSIZ]; /* holds the valid entries if NETPATH */
+ char templine[BUFSIZ]; /* has value of NETPATH when scanning */
+ struct netconfig **curr_pp; /* scans the list from NETPATH */
+ struct netconfig **tpp; /* scans the list from netconfig file */
+ struct netconfig **rnetpp; /* the list of entries from NETPATH */
+ char *netpath; /* value of NETPATH from environment */
+ char *netid; /* holds a component of NETPATH */
+ char *tp; /* used to scan NETPATH string */
+ NCONF_HANDLE *retp; /* the return value */
+
+ trace1(TR_setnetpath, 0);
+ /*
+ * Read in the netconfig database if not already read in
+ */
+ mutex_lock(&netpp_mutex);
+ if ((netpp == NULL) && ((netpp = getnetlist()) == NULL)) {
+ mutex_unlock(&netpp_mutex);
+ trace1(TR_setnetpath, 1);
+ return (NULL);
+ }
+ mutex_unlock(&netpp_mutex);
+
+ if ((retp = (NCONF_HANDLE *) malloc(sizeof (NCONF_HANDLE))) == NULL) {
+ nc_error = NC_NOMEM;
+ trace1(TR_setnetpath, 1);
+ return (NULL);
+ }
+
+ /*
+ * Get the valid entries of the NETPATH variable (and
+ * count the number of entries while doing it).
+ *
+ * This is done every time the procedure is called just
+ * in case NETPATH has changed from call to call.
+ *
+ * If NETPATH is too long, we ignore it altogether as
+ * it can only be a buffer overflow attack.
+ * Since we add one colon for each entry, but colons only
+ * need to exist between entries, we have to subtract one.
+ */
+ count = 0;
+ valid_netpath[0] = '\0';
+ if ((netpath = getenv(NETPATH)) == NULL ||
+ strlen(netpath) >= sizeof (templine) - 1) {
+ /*
+ * If NETPATH variable is not set or invalid,
+ * the valid NETPATH consist of all "visible"
+ * netids from the netconfig database.
+ */
+
+ for (tpp = netpp; *tpp; tpp++) {
+ if ((*tpp)->nc_flag & NC_VISIBLE) {
+ (void) strcat(valid_netpath, (*tpp)->nc_netid);
+ (void) strcat(valid_netpath, ":");
+ count++;
+ }
+ }
+ } else {
+
+ /*
+ * Copy the value of NETPATH (since '\0's will be
+ * put into the string) and create the valid NETPATH
+ * (by throwing away all netids not in the database).
+ * If an entry appears more than one, it *will* be
+ * listed twice in the list of valid netpath entries.
+ */
+
+ (void) strcpy(templine, netpath);
+ tp = templine;
+
+ while (*tp) {
+ /* Skip all leading ':'s */
+ while (*tp && *tp == ':')
+ tp++;
+ if (*tp == NULL)
+ break; /* last one */
+ netid = tp;
+ while (*tp && *tp != ':')
+ tp++;
+ if (*tp)
+ *tp++ = '\0'; /* isolate netid */
+
+ for (tpp = netpp; *tpp; tpp++) {
+ if (strcmp(netid, (*tpp)->nc_netid) == 0) {
+ (void) strcat(valid_netpath,
+ (*tpp)->nc_netid);
+ (void) strcat(valid_netpath, ":");
+ count++;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Get space to hold the valid list (+1 for the NULL) */
+
+ if ((rnetpp = (struct netconfig **)malloc((count + 1) *
+ sizeof (struct netconfig *))) == NULL) {
+ free((void *) retp);
+ nc_error = NC_NOMEM;
+ trace1(TR_setnetpath, 1);
+ return (NULL);
+ }
+
+ /*
+ * Populate the NETPATH list, ending it with a NULL.
+ * Each entry in the list points to the structure in the
+ * "netpp" list (the entry must exist in the list, otherwise
+ * it wouldn't appear in valid_netpath[]).
+ */
+
+ curr_pp = rnetpp;
+ netid = tp = valid_netpath;
+ while (*tp) {
+ netid = tp;
+ while (*tp && *tp != ':')
+ tp++;
+ if (*tp)
+ *tp++ = '\0';
+ for (tpp = netpp; *tpp; tpp++) {
+ if (strcmp(netid, (*tpp)->nc_netid) == 0) {
+ *curr_pp++ = *tpp;
+ break;
+ }
+ }
+ }
+ *curr_pp = NULL;
+
+ retp->nc_curr = retp->nc_head = rnetpp;
+ trace1(TR_setnetpath, 1);
+ return ((void *)retp);
+}
+
+/*
+ * endnetpath() frees up all of the memory allocated by setnetpath().
+ * It returns -1 (error) if setnetpath was never called.
+ */
+
+int
+endnetpath(vdata)
+void *vdata;
+{
+ /* The argument is really a NCONF_HANDLE; cast it here */
+ NCONF_HANDLE *nconf_handlep = (NCONF_HANDLE *)vdata;
+
+ trace1(TR_endnetpath, 0);
+ mutex_lock(&netpp_mutex);
+ if (netpp == NULL || nconf_handlep == NULL) {
+ nc_error = NC_NOSET;
+ mutex_unlock(&netpp_mutex);
+ trace1(TR_endnetpath, 1);
+ return (-1);
+ }
+ mutex_unlock(&netpp_mutex);
+
+ free(nconf_handlep->nc_head);
+ free(nconf_handlep);
+ trace1(TR_endnetpath, 1);
+ return (0);
+}
+
+/*
+ * getnetpath() returns the current entry in the list
+ * from the NETPATH variable. If setnetpath() was not called
+ * previously to set up the list, return NULL.
+ */
+
+struct netconfig *
+getnetpath(vdata)
+void *vdata;
+{
+ /* The argument is really a NCONF_HANDLE; cast it here */
+ NCONF_HANDLE *nconf_handlep = (NCONF_HANDLE *)vdata;
+ struct netconfig *retp; /* holds the return value */
+ int ipv6_present = -1;
+
+ trace1(TR_getnetpath, 0);
+ mutex_lock(&netpp_mutex);
+ if (netpp == NULL) {
+ nc_error = NC_NOSET;
+ mutex_unlock(&netpp_mutex);
+ trace1(TR_getnetpath, 1);
+ return (NULL);
+ }
+ mutex_unlock(&netpp_mutex);
+ for (;;) {
+ retp = *(nconf_handlep->nc_curr);
+ if (retp && (strcmp(retp->nc_netid, "udp6") == 0 ||
+ strcmp(retp->nc_netid, "tcp6") == 0)) {
+ if (ipv6_present == -1)
+ ipv6_present = __can_use_af(AF_INET6);
+ if (!ipv6_present) {
+ ++(nconf_handlep->nc_curr);
+ continue;
+ }
+ }
+ break;
+ }
+ if (retp) {
+ ++(nconf_handlep->nc_curr);
+ nc_error = NC_NOERROR;
+ } else {
+ nc_error = NC_NOMOREENTRIES;
+ }
+
+ trace1(TR_getnetpath, 1);
+ return (retp);
+}
+
+/*
+ * blank() returns true if the line is a blank line, 0 otherwise
+ */
+
+static int
+blank(cp)
+char *cp;
+{
+ trace1(TR_blank, 0);
+ while (*cp && isspace(*cp)) {
+ cp++;
+ }
+ trace1(TR_blank, 1);
+ return (*cp == '\0');
+}
+
+/*
+ * comment() returns true if the line is a comment, 0 otherwise.
+ */
+
+static int
+comment(cp)
+char *cp;
+{
+ trace1(TR_comment, 0);
+ while (*cp && isspace(*cp)) {
+ cp++;
+ }
+ trace1(TR_comment, 1);
+ return (*cp == '#');
+}
+
+/*
+ * getvalue() searches for the given string in the given array,
+ * and return the integer value associated with the string.
+ */
+
+static unsigned int
+getvalue(cp, nc_data)
+char *cp;
+struct nc_data nc_data[];
+{
+ int i; /* used to index through the given struct nc_data array */
+
+ trace1(TR_getvalue, 0);
+ for (i = 0; nc_data[i].string; i++) {
+ if (strcmp(nc_data[i].string, cp) == 0) {
+ break;
+ }
+ }
+ trace1(TR_getvalue, 1);
+ return (nc_data[i].value);
+}
+
+/*
+ * getflag() creates a bitmap of the one-character flags in
+ * the given string. It uses nc_flags array to get the values.
+ */
+
+static unsigned int
+getflag(cp)
+char *cp;
+{
+ int i; /* indexs through the nc_flag array */
+ unsigned int mask = 0; /* holds bitmask of flags */
+
+ trace1(TR_getflag, 0);
+ while (*cp) {
+ for (i = 0; nc_flag[i].string; i++) {
+ if (*nc_flag[i].string == *cp) {
+ mask |= nc_flag[i].value;
+ break;
+ }
+ }
+ cp++;
+ }
+ trace1(TR_getflag, 1);
+ return (mask);
+}
+
+/*
+ * getlookups() creates and returns an array of string representing
+ * the directory lookup libraries, given as a comma-seperated list
+ * in the argument "cp".
+ */
+
+static char **
+getlookups(cp)
+char *cp;
+{
+ unsigned int num; /* holds the number of entries in the list */
+ char **listpp; /* the beginning of the list of dir routines */
+ char **tpp; /* traverses the list, populating it */
+ char *start;
+
+ trace1(TR_getlookups, 0);
+ num = getnlookups(cp);
+ if (num == 0) {
+ trace1(TR_getlookups, 1);
+ return (NULL);
+ }
+ if ((listpp = (char **)malloc((num + 1) * sizeof (char *))) == NULL) {
+ trace1(TR_getlookups, 1);
+ return (NULL);
+ }
+
+ tpp = listpp;
+ while (num--) {
+ start = cp;
+
+ /*
+ * Traverse the string looking for the next entry
+ * of the list (i.e, where the ',' or end of the
+ * string appears). If a "\" is found, shift the
+ * token over 1 to the left (taking the next char
+ * literally).
+ */
+
+ while (*cp && *cp != ',') {
+ if (*cp == '\\' && *(cp + 1)) {
+ shift1left(cp);
+ }
+ cp++;
+ }
+ if (*cp)
+ *cp++ = '\0';
+ if ((*tpp++ = strdup(start)) == NULL) {
+ for (tpp = listpp; *tpp; tpp++)
+ free(*tpp);
+ free(listpp);
+ trace1(TR_getlookups, 1);
+ return (NULL);
+ }
+ }
+ *tpp = NULL;
+ trace1(TR_getlookups, 1);
+ return (listpp);
+}
+
+/*
+ * getnlookups() returns the number of entries in a comma-separated
+ * string of tokens. A "-" means no strings are present.
+ */
+
+static unsigned int
+getnlookups(cp)
+char *cp;
+{
+ unsigned int count; /* the number of tokens in the string */
+
+ trace1(TR_getnlookups, 0);
+ if (strcmp(cp, "-") == 0) {
+ trace1(TR_getnlookups, 1);
+ return (0);
+ }
+
+ count = 1;
+ while (*cp) {
+ if (*cp == ',') {
+ count++;
+ }
+
+ /*
+ * If a "\" is in the string, take the next character
+ * literally. Onlly skip the character if "\" is
+ * not the last character of the token.
+ */
+ if (*cp == '\\' && *(cp + 1)) {
+ cp++;
+ }
+ cp++;
+ }
+ trace1(TR_getnlookups, 1);
+ return (count);
+}
+
+/*
+ * gettoken() behaves much like strtok(), except that
+ * it knows about escaped space characters (i.e., space characters
+ * preceeded by a '\' are taken literally).
+ */
+
+static char *
+gettoken(cp, skip)
+char *cp;
+int skip;
+{
+ static char *savep; /* the place where we left off */
+ char *p; /* the beginning of the new token */
+ char *retp; /* the token to be returned */
+
+ trace1(TR_gettoken, 0);
+ fieldnum++;
+
+ /* Determine if first or subsequent call */
+ p = (cp == NULL)? savep: cp;
+
+ /* Return if no tokens remain. */
+ if (p == 0) {
+ trace1(TR_gettoken, 1);
+ return (NULL);
+ }
+
+ while (isspace(*p))
+ p++;
+
+ if (*p == '\0') {
+ trace1(TR_gettoken, 1);
+ return (NULL);
+ }
+
+ /*
+ * Save the location of the token and then skip past it
+ */
+
+ retp = p;
+ while (*p) {
+ if (isspace(*p))
+ if (skip == TRUE) {
+ shift1left(p);
+ continue;
+ } else
+ break;
+ /*
+ * Only process the escape of the space seperator;
+ * since the token may contain other separators,
+ * let the other routines handle the escape of
+ * specific characters in the token.
+ */
+
+ if (*p == '\\' && *(p + 1) != '\n' && isspace(*(p + 1))) {
+ shift1left(p);
+ }
+ p++;
+ }
+ if (*p == '\0') {
+ savep = 0; /* indicate this is last token */
+ } else {
+ *p = '\0';
+ savep = ++p;
+ }
+ trace1(TR_gettoken, 1);
+ return (strdup(retp));
+}
+
+/*
+ * shift1left() moves all characters in the string over 1 to
+ * the left.
+ */
+
+static void
+shift1left(p)
+char *p;
+{
+ trace1(TR_shift1left, 0);
+ for (; *p; p++)
+ *p = *(p + 1);
+ trace1(TR_shift1left, 1);
+}
+
+char *
+nc_sperror()
+{
+ static char buf_main[BUFSIZ];
+ static pthread_key_t perror_key;
+ char *retstr = thr_main()?
+ buf_main :
+ thr_get_storage(&perror_key, BUFSIZ, free);
+
+ trace1(TR_nc_sperror, 0);
+
+ if (retstr == NULL) {
+ syslog(LOG_WARNING,
+ "nc_sperror: malloc failed when trying to create buffer\n");
+ return (NULL);
+ }
+
+ switch (nc_error) {
+ case NC_NOERROR:
+ (void) strlcpy(retstr, dgettext(__nsl_dom, "no error"), BUFSIZ);
+ break;
+ case NC_NOMEM:
+ (void) strlcpy(retstr, dgettext(__nsl_dom, "out of memory"),
+ BUFSIZ);
+ break;
+ case NC_NOSET:
+ (void) strlcpy(retstr, dgettext(__nsl_dom,
+ "routine called before calling \
+ setnetpath() or setnetconfig()"), BUFSIZ);
+ break;
+ case NC_OPENFAIL:
+ (void) strlcpy(retstr,
+ dgettext(__nsl_dom, "cannot open /etc/netconfig"),
+ BUFSIZ);
+ break;
+ case NC_BADLINE:
+ (void) snprintf(retstr, BUFSIZ, dgettext(__nsl_dom,
+ "error in /etc/netconfig: field %d of line %d\n"),
+ fieldnum, linenum);
+ break;
+ case NC_NOTFOUND:
+ (void) snprintf(retstr, BUFSIZ,
+ dgettext(__nsl_dom,
+ "netid not found in /etc/netconfig"));
+ break;
+ case NC_NOMOREENTRIES:
+ (void) snprintf(retstr, BUFSIZ,
+ dgettext(__nsl_dom,
+ "no more entries in /etc/netconfig"));
+ break;
+ default:
+ (void) strlcpy(retstr, dgettext(__nsl_dom, "unknown error"),
+ BUFSIZ);
+ break;
+ }
+ trace1(TR_nc_sperror, 1);
+ return (retstr);
+}
+
+void
+nc_perror(const char *string)
+{
+ trace1(TR_nc_perror, 0);
+ if (string)
+ fprintf(stderr, "%s: %s\n", string, nc_sperror());
+ else
+ fprintf(stderr, "%s\n", nc_sperror());
+ trace1(TR_nc_perror, 1);
+}
+
+static void
+netlist_free(netppp)
+ struct netconfig ***netppp;
+{
+ struct netconfig **tpp;
+
+ trace1(TR_netlist_free, 0);
+ for (tpp = *netppp; *tpp; tpp++) {
+ netconfig_free(*tpp);
+ }
+ free(*netppp);
+ *netppp = NULL;
+ trace1(TR_netlist_free, 1);
+}
+
+static void
+netconfig_free(netconfigp)
+struct netconfig *netconfigp;
+{
+ int i;
+
+ trace1(TR_netconfig_free, 0);
+ if (netconfigp == NULL) {
+ trace1(TR_netconfig_free, 1);
+ return;
+ }
+ free_entry(netconfigp->nc_netid);
+ free_entry(netconfigp->nc_protofmly);
+ free_entry(netconfigp->nc_proto);
+ free_entry(netconfigp->nc_device);
+ if (netconfigp->nc_lookups)
+ for (i = 0; i < netconfigp->nc_nlookups; i++)
+ free_entry(netconfigp->nc_lookups[i]);
+ free_entry(netconfigp->nc_lookups);
+ free(netconfigp);
+ trace1(TR_netconfig_free, 1);
+}
+
+static struct netconfig *
+netconfig_dup(netconfigp)
+struct netconfig *netconfigp;
+{
+ struct netconfig *nconf;
+ int i;
+
+ trace1(TR_netconfig_dup, 0);
+ nconf = (struct netconfig *)calloc(1, sizeof (struct netconfig));
+ if (nconf == NULL) {
+ trace1(TR_netconfig_dup, 1);
+ nc_error = NC_NOMEM;
+ return (NULL);
+ }
+ nconf->nc_netid = strdup(netconfigp->nc_netid);
+ nconf->nc_protofmly = strdup(netconfigp->nc_protofmly);
+ nconf->nc_proto = strdup(netconfigp->nc_proto);
+ nconf->nc_device = strdup(netconfigp->nc_device);
+ nconf->nc_lookups = (char **)malloc((netconfigp->nc_nlookups + 1)
+ * sizeof (char *));
+ if (!(nconf->nc_lookups && nconf->nc_netid &&
+ nconf->nc_protofmly && nconf->nc_proto &&
+ nconf->nc_device)) {
+ nc_error = NC_NOMEM;
+ netconfig_free(nconf);
+ trace1(TR_netconfig_dup, 1);
+ return (NULL);
+ }
+
+ for (i = 0; i < netconfigp->nc_nlookups; i++) {
+ nconf->nc_lookups[i] = strdup(netconfigp->nc_lookups[i]);
+ if (nconf->nc_lookups[i] == NULL) {
+ nconf->nc_nlookups = i;
+ netconfig_free(nconf);
+ nc_error = NC_NOMEM;
+ trace1(TR_netconfig_dup, 1);
+ return (NULL);
+ }
+ }
+ nconf->nc_lookups[i] = NULL;
+ nconf->nc_nlookups = netconfigp->nc_nlookups;
+ nconf->nc_flag = netconfigp->nc_flag;
+ nconf->nc_semantics = netconfigp->nc_semantics;
+ trace1(TR_netconfig_dup, 1);
+ return (nconf);
+}
+
+static void
+free_entry(foo)
+ void *foo;
+{
+ trace1(TR_free_entry, 0);
+ if (foo)
+ free(foo);
+ trace1(TR_free_entry, 1);
+}