17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5f48205beScasper * Common Development and Distribution License (the "License").
6f48205beScasper * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
227c478bd9Sstevel@tonic-gate * PPPoE Server-mode daemon option parsing.
237c478bd9Sstevel@tonic-gate *
24*f53eecf5SJames Carlson * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
257c478bd9Sstevel@tonic-gate * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <unistd.h>
317c478bd9Sstevel@tonic-gate #include <assert.h>
327c478bd9Sstevel@tonic-gate #include <ctype.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <fcntl.h>
367c478bd9Sstevel@tonic-gate #include <pwd.h>
377c478bd9Sstevel@tonic-gate #include <grp.h>
387c478bd9Sstevel@tonic-gate #include <errno.h>
397c478bd9Sstevel@tonic-gate #include <netdb.h>
407c478bd9Sstevel@tonic-gate #include <stropts.h>
417c478bd9Sstevel@tonic-gate #include <sys/stat.h>
427c478bd9Sstevel@tonic-gate #include <sys/socket.h>
437c478bd9Sstevel@tonic-gate #include <net/if.h>
447c478bd9Sstevel@tonic-gate #include <netinet/in.h>
457c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h>
467c478bd9Sstevel@tonic-gate #include <net/sppptun.h>
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate #include "common.h"
497c478bd9Sstevel@tonic-gate #include "logging.h"
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate #define MAX_KEYWORD 4096 /* Maximum token length */
527c478bd9Sstevel@tonic-gate #define MAX_NEST 32 /* Maximum ${$sub} nesting */
537c478bd9Sstevel@tonic-gate #define MAXARGS 256 /* Maximum number of pppd arguments */
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gate /*
567c478bd9Sstevel@tonic-gate * Client filter entry. These are linked in *reverse* order so that
577c478bd9Sstevel@tonic-gate * the DAG created by file inclusion nesting works as expected. Since
587c478bd9Sstevel@tonic-gate * the administrator who wrote the configuration expects "first
597c478bd9Sstevel@tonic-gate * match," this means that tests against the filter list must actually
607c478bd9Sstevel@tonic-gate * use "last match."
617c478bd9Sstevel@tonic-gate */
627c478bd9Sstevel@tonic-gate struct filter_entry {
637c478bd9Sstevel@tonic-gate struct filter_entry *fe_prev; /* Previous filter in list */
647c478bd9Sstevel@tonic-gate struct ether_addr fe_mac; /* MAC address */
657c478bd9Sstevel@tonic-gate struct ether_addr fe_mask; /* Mask for above address test */
667c478bd9Sstevel@tonic-gate uchar_t fe_isexcept; /* invert sense; exclude matching clients */
677c478bd9Sstevel@tonic-gate uchar_t fe_prevcopy; /* fe_prev points to copied list */
687c478bd9Sstevel@tonic-gate uchar_t fe_unused[2]; /* padding */
697c478bd9Sstevel@tonic-gate };
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate * Note: I would like to make the strings and filters here const, but
737c478bd9Sstevel@tonic-gate * I can't because they have to be passed to free() during parsing. I
747c478bd9Sstevel@tonic-gate * could work around this with offsetof() or data copies, but it's not
757c478bd9Sstevel@tonic-gate * worth the effort.
767c478bd9Sstevel@tonic-gate */
777c478bd9Sstevel@tonic-gate struct service_entry {
787c478bd9Sstevel@tonic-gate const char *se_name; /* Name of service */
797c478bd9Sstevel@tonic-gate struct filter_entry *se_flist; /* Pointer to list of client filters */
807c478bd9Sstevel@tonic-gate uint_t se_flags; /* SEF_* flags (below) */
817c478bd9Sstevel@tonic-gate int se_debug; /* Debug level (0=nodebug) */
827c478bd9Sstevel@tonic-gate char *se_server; /* Server (AC) name */
837c478bd9Sstevel@tonic-gate char *se_pppd; /* Options for pppd */
847c478bd9Sstevel@tonic-gate char *se_path; /* Path to pppd executable */
857c478bd9Sstevel@tonic-gate char *se_extra; /* Extra options */
867c478bd9Sstevel@tonic-gate char *se_log; /* Log file */
877c478bd9Sstevel@tonic-gate uid_t se_uid; /* User ID */
887c478bd9Sstevel@tonic-gate gid_t se_gid; /* Group ID */
897c478bd9Sstevel@tonic-gate };
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate #define SEF_WILD 0x00000001 /* Offer in wildcard reply */
927c478bd9Sstevel@tonic-gate #define SEF_NOWILD 0x00000002 /* Don't offer in wildcard */
937c478bd9Sstevel@tonic-gate #define SEF_CFLIST 0x00000004 /* se_flist copied from global */
947c478bd9Sstevel@tonic-gate #define SEF_CSERVER 0x00000008 /* se_server copied from global */
957c478bd9Sstevel@tonic-gate #define SEF_CPPPD 0x00000010 /* se_pppd copied from global */
967c478bd9Sstevel@tonic-gate #define SEF_CPATH 0x00000020 /* se_path copied from global */
977c478bd9Sstevel@tonic-gate #define SEF_CEXTRA 0x00000040 /* se_extra copied from global */
987c478bd9Sstevel@tonic-gate #define SEF_CLOG 0x00000080 /* se_log copied from global */
997c478bd9Sstevel@tonic-gate #define SEF_UIDSET 0x00000100 /* se_uid has been set */
1007c478bd9Sstevel@tonic-gate #define SEF_GIDSET 0x00000200 /* se_gid has been set */
1017c478bd9Sstevel@tonic-gate #define SEF_DEBUGCLR 0x00000400 /* do not add se_debug from global */
1027c478bd9Sstevel@tonic-gate #define SEF_CDEV 0x00000800 /* copied devs (parse only) */
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate * One of these is allocated per lower-level stream (device) that is
1067c478bd9Sstevel@tonic-gate * referenced by the configuration files. The queries are received
1077c478bd9Sstevel@tonic-gate * per device, and this structure allows us to find all of the
1087c478bd9Sstevel@tonic-gate * services that correspond to that device.
1097c478bd9Sstevel@tonic-gate */
1107c478bd9Sstevel@tonic-gate struct device_entry {
1117c478bd9Sstevel@tonic-gate const char *de_name;
1127c478bd9Sstevel@tonic-gate const struct service_entry **de_services;
1137c478bd9Sstevel@tonic-gate int de_nservices;
1147c478bd9Sstevel@tonic-gate };
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate /*
1177c478bd9Sstevel@tonic-gate * This is the parsed configuration. While a new configuration is
1187c478bd9Sstevel@tonic-gate * being read, this is kept around until the new configuration is
1197c478bd9Sstevel@tonic-gate * ready, and then it is discarded in one operation. It has an array
1207c478bd9Sstevel@tonic-gate * of device entries (as above) -- one per referenced lower stream --
1217c478bd9Sstevel@tonic-gate * and a pointer to the allocated parser information. The latter is
1227c478bd9Sstevel@tonic-gate * kept around because we reuse pointers rather than reallocating and
1237c478bd9Sstevel@tonic-gate * copying the data. There are thus multiple aliases to the dynamic
1247c478bd9Sstevel@tonic-gate * data, and the "owner" (for purposes of freeing the storage) is
1257c478bd9Sstevel@tonic-gate * considered to be this 'junk' list.
1267c478bd9Sstevel@tonic-gate */
1277c478bd9Sstevel@tonic-gate struct option_state {
1287c478bd9Sstevel@tonic-gate const struct device_entry *os_devices;
1297c478bd9Sstevel@tonic-gate int os_ndevices;
1307c478bd9Sstevel@tonic-gate struct per_file *os_pfjunk; /* Kept for deallocation */
1317c478bd9Sstevel@tonic-gate char **os_evjunk; /* ditto */
1327c478bd9Sstevel@tonic-gate };
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate /*
1357c478bd9Sstevel@tonic-gate * This is the root pointer to the current parsed options.
1367c478bd9Sstevel@tonic-gate * This cannot be const because it's passed to free() when reparsing
1377c478bd9Sstevel@tonic-gate * options.
1387c478bd9Sstevel@tonic-gate */
1397c478bd9Sstevel@tonic-gate static struct option_state *cur_options;
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate /* Global settings for module-wide options. */
1427c478bd9Sstevel@tonic-gate static struct service_entry glob_svc;
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate /*
1457c478bd9Sstevel@tonic-gate * *******************************************************************
1467c478bd9Sstevel@tonic-gate * Data structures generated during parsing.
1477c478bd9Sstevel@tonic-gate */
1487c478bd9Sstevel@tonic-gate
1497c478bd9Sstevel@tonic-gate /* List of device names attached to one service */
1507c478bd9Sstevel@tonic-gate struct device_list {
1517c478bd9Sstevel@tonic-gate struct device_list *dl_next;
1527c478bd9Sstevel@tonic-gate const char *dl_name; /* Name of one device */
1537c478bd9Sstevel@tonic-gate };
1547c478bd9Sstevel@tonic-gate
1557c478bd9Sstevel@tonic-gate /* Entry for a single defined service. */
1567c478bd9Sstevel@tonic-gate struct service_list {
1577c478bd9Sstevel@tonic-gate struct service_entry sl_entry; /* Parsed service data */
1587c478bd9Sstevel@tonic-gate struct service_list *sl_next; /* Next service entry */
1597c478bd9Sstevel@tonic-gate struct parse_state *sl_parse; /* Back pointer to state */
1607c478bd9Sstevel@tonic-gate struct device_list *sl_dev; /* List of devices */
1617c478bd9Sstevel@tonic-gate int sl_serial; /* Serial number (conflict resolve) */
1627c478bd9Sstevel@tonic-gate };
1637c478bd9Sstevel@tonic-gate #define SESERIAL(x) ((struct service_list *)&(x))->sl_serial
1647c478bd9Sstevel@tonic-gate #define ISGLOBAL(x) ((x) == &(x)->sl_parse->ps_cfile->pf_global)
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate * Structure allocated for each file opened. File nesting is chained
1687c478bd9Sstevel@tonic-gate * in reverse order so that global option scoping works as expected.
1697c478bd9Sstevel@tonic-gate */
1707c478bd9Sstevel@tonic-gate struct per_file {
1717c478bd9Sstevel@tonic-gate struct per_file *pf_prev; /* Back chain */
1727c478bd9Sstevel@tonic-gate struct service_list pf_global; /* Global (default) service context */
1737c478bd9Sstevel@tonic-gate struct service_list *pf_svc; /* List of services */
1747c478bd9Sstevel@tonic-gate struct service_list *pf_svc_last;
1757c478bd9Sstevel@tonic-gate FILE *pf_input; /* File for input */
1767c478bd9Sstevel@tonic-gate const char *pf_name; /* File name */
1777c478bd9Sstevel@tonic-gate int pf_nsvc; /* Count of services */
1787c478bd9Sstevel@tonic-gate };
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate /* State of parser */
1817c478bd9Sstevel@tonic-gate enum key_state {
1827c478bd9Sstevel@tonic-gate ksDefault, ksService, ksDevice, ksClient, ksClientE, ksServer,
1837c478bd9Sstevel@tonic-gate ksPppd, ksFile, ksPath, ksExtra, ksLog, ksUser, ksGroup
1847c478bd9Sstevel@tonic-gate };
1857c478bd9Sstevel@tonic-gate
1867c478bd9Sstevel@tonic-gate /*
1877c478bd9Sstevel@tonic-gate * Global parser state. There is one of these structures, and it
1887c478bd9Sstevel@tonic-gate * exists only while actively parsing configuration files.
1897c478bd9Sstevel@tonic-gate */
1907c478bd9Sstevel@tonic-gate struct parse_state {
1917c478bd9Sstevel@tonic-gate enum key_state ps_state; /* Parser state */
1927c478bd9Sstevel@tonic-gate int ps_serial; /* Service serial number */
1937c478bd9Sstevel@tonic-gate struct per_file *ps_files; /* Parsed files */
1947c478bd9Sstevel@tonic-gate struct per_file *ps_cfile; /* Current file */
1957c478bd9Sstevel@tonic-gate struct service_list *ps_csvc; /* Current service */
1967c478bd9Sstevel@tonic-gate struct device_list *ps_star; /* Wildcard device */
1977c478bd9Sstevel@tonic-gate int ps_flags; /* PSF_* below */
1987c478bd9Sstevel@tonic-gate char **ps_evlist; /* allocated environment variables */
1997c478bd9Sstevel@tonic-gate int ps_evsize; /* max length; for realloc */
2007c478bd9Sstevel@tonic-gate };
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate #define PSF_PERDEV 0x0001 /* In a per-device file */
2037c478bd9Sstevel@tonic-gate #define PSF_SETLEVEL 0x0002 /* Set log level along the way */
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate /* Should be in a library somewhere. */
2067c478bd9Sstevel@tonic-gate static char *
strsave(const char * str)2077c478bd9Sstevel@tonic-gate strsave(const char *str)
2087c478bd9Sstevel@tonic-gate {
2097c478bd9Sstevel@tonic-gate char *newstr;
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate if (str == NULL)
2127c478bd9Sstevel@tonic-gate return (NULL);
2137c478bd9Sstevel@tonic-gate newstr = (char *)malloc(strlen(str) + 1);
2147c478bd9Sstevel@tonic-gate if (newstr != NULL)
2157c478bd9Sstevel@tonic-gate (void) strcpy(newstr, str);
2167c478bd9Sstevel@tonic-gate return (newstr);
2177c478bd9Sstevel@tonic-gate }
2187c478bd9Sstevel@tonic-gate
2197c478bd9Sstevel@tonic-gate /*
2207c478bd9Sstevel@tonic-gate * Stop defining current service and revert to global definition.
2217c478bd9Sstevel@tonic-gate * This resolves any implicit references to global options by copying
2227c478bd9Sstevel@tonic-gate * ("inheriting") from the current global state.
2237c478bd9Sstevel@tonic-gate */
2247c478bd9Sstevel@tonic-gate static void
close_service(struct service_list * slp)2257c478bd9Sstevel@tonic-gate close_service(struct service_list *slp)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate struct parse_state *psp;
2287c478bd9Sstevel@tonic-gate struct per_file *cfile;
2297c478bd9Sstevel@tonic-gate struct service_entry *sep;
2307c478bd9Sstevel@tonic-gate struct service_entry *sedefp;
2317c478bd9Sstevel@tonic-gate struct filter_entry *fep;
2327c478bd9Sstevel@tonic-gate
2337c478bd9Sstevel@tonic-gate assert(slp != NULL);
2347c478bd9Sstevel@tonic-gate psp = slp->sl_parse;
2357c478bd9Sstevel@tonic-gate cfile = psp->ps_cfile;
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate /* If no current file, then nothing to close. */
2387c478bd9Sstevel@tonic-gate if (cfile == NULL)
2397c478bd9Sstevel@tonic-gate return;
2407c478bd9Sstevel@tonic-gate
2417c478bd9Sstevel@tonic-gate sep = &slp->sl_entry;
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate /*
2447c478bd9Sstevel@tonic-gate * Fix up filter pointers to make DAG. First, locate
2457c478bd9Sstevel@tonic-gate * the end of the filter list.
2467c478bd9Sstevel@tonic-gate */
2477c478bd9Sstevel@tonic-gate if (sep->se_flags & SEF_CFLIST) {
2487c478bd9Sstevel@tonic-gate sep->se_flist = fep = NULL;
2497c478bd9Sstevel@tonic-gate } else {
2507c478bd9Sstevel@tonic-gate for (fep = sep->se_flist; fep != NULL; fep = fep->fe_prev)
2517c478bd9Sstevel@tonic-gate if (fep->fe_prev == NULL || fep->fe_prevcopy) {
2527c478bd9Sstevel@tonic-gate fep->fe_prev = NULL;
2537c478bd9Sstevel@tonic-gate break;
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate if (slp == &cfile->pf_global) {
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate * If we're in a global context, then we're about to
2597c478bd9Sstevel@tonic-gate * open a new service, so it's time to fix up the
2607c478bd9Sstevel@tonic-gate * filter list so that it's usable as a reference.
2617c478bd9Sstevel@tonic-gate * Loop through files from which we were included, and
2627c478bd9Sstevel@tonic-gate * link up filters. Note: closure may occur more than
2637c478bd9Sstevel@tonic-gate * once here.
2647c478bd9Sstevel@tonic-gate */
2657c478bd9Sstevel@tonic-gate /* We don't inherit from ourselves. */
2667c478bd9Sstevel@tonic-gate cfile = cfile->pf_prev;
2677c478bd9Sstevel@tonic-gate while (cfile != NULL) {
2687c478bd9Sstevel@tonic-gate if (fep == NULL) {
2697c478bd9Sstevel@tonic-gate sep->se_flist = fep =
2707c478bd9Sstevel@tonic-gate cfile->pf_global.sl_entry.se_flist;
2717c478bd9Sstevel@tonic-gate sep->se_flags |= SEF_CFLIST;
2727c478bd9Sstevel@tonic-gate } else if (fep->fe_prev == NULL) {
2737c478bd9Sstevel@tonic-gate fep->fe_prev =
2747c478bd9Sstevel@tonic-gate cfile->pf_global.sl_entry.se_flist;
2757c478bd9Sstevel@tonic-gate fep->fe_prevcopy = 1;
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate cfile = cfile->pf_prev;
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate } else {
2807c478bd9Sstevel@tonic-gate /*
2817c478bd9Sstevel@tonic-gate * Loop through default options in current and all
2827c478bd9Sstevel@tonic-gate * enclosing include files. Inherit options.
2837c478bd9Sstevel@tonic-gate */
2847c478bd9Sstevel@tonic-gate logdbg("service %s ends", slp->sl_entry.se_name);
2857c478bd9Sstevel@tonic-gate while (cfile != NULL) {
2867c478bd9Sstevel@tonic-gate /* Inherit from global service options. */
2877c478bd9Sstevel@tonic-gate if (slp->sl_dev == NULL) {
2887c478bd9Sstevel@tonic-gate slp->sl_dev = cfile->pf_global.sl_dev;
2897c478bd9Sstevel@tonic-gate sep->se_flags |= SEF_CDEV;
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate sedefp = &cfile->pf_global.sl_entry;
2927c478bd9Sstevel@tonic-gate if (fep == NULL) {
2937c478bd9Sstevel@tonic-gate sep->se_flist = fep = sedefp->se_flist;
2947c478bd9Sstevel@tonic-gate sep->se_flags |= SEF_CFLIST;
2957c478bd9Sstevel@tonic-gate } else if (fep->fe_prev == NULL) {
2967c478bd9Sstevel@tonic-gate fep->fe_prev = sedefp->se_flist;
2977c478bd9Sstevel@tonic-gate fep->fe_prevcopy = 1;
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate if (sep->se_server == NULL) {
3007c478bd9Sstevel@tonic-gate sep->se_server = sedefp->se_server;
3017c478bd9Sstevel@tonic-gate sep->se_flags |= SEF_CSERVER;
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate if (sep->se_pppd == NULL) {
3047c478bd9Sstevel@tonic-gate sep->se_pppd = sedefp->se_pppd;
3057c478bd9Sstevel@tonic-gate sep->se_flags |= SEF_CPPPD;
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate if (sep->se_path == NULL) {
3087c478bd9Sstevel@tonic-gate sep->se_path = sedefp->se_path;
3097c478bd9Sstevel@tonic-gate sep->se_flags |= SEF_CPATH;
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate if (sep->se_extra == NULL) {
3127c478bd9Sstevel@tonic-gate sep->se_extra = sedefp->se_extra;
3137c478bd9Sstevel@tonic-gate sep->se_flags |= SEF_CEXTRA;
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate if (sep->se_log == NULL) {
3167c478bd9Sstevel@tonic-gate sep->se_log = sedefp->se_log;
3177c478bd9Sstevel@tonic-gate sep->se_flags |= SEF_CLOG;
3187c478bd9Sstevel@tonic-gate }
3197c478bd9Sstevel@tonic-gate if (!(sep->se_flags & SEF_UIDSET) &&
3207c478bd9Sstevel@tonic-gate (sedefp->se_flags & SEF_UIDSET)) {
3217c478bd9Sstevel@tonic-gate sep->se_uid = sedefp->se_uid;
3227c478bd9Sstevel@tonic-gate sep->se_flags |= SEF_UIDSET;
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate if (!(sep->se_flags & SEF_GIDSET) &&
3257c478bd9Sstevel@tonic-gate (sedefp->se_flags & SEF_GIDSET)) {
3267c478bd9Sstevel@tonic-gate sep->se_gid = sedefp->se_gid;
3277c478bd9Sstevel@tonic-gate sep->se_flags |= SEF_GIDSET;
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate if (!(sep->se_flags & (SEF_WILD|SEF_NOWILD)))
3307c478bd9Sstevel@tonic-gate sep->se_flags |= sedefp->se_flags &
3317c478bd9Sstevel@tonic-gate (SEF_WILD|SEF_NOWILD);
3327c478bd9Sstevel@tonic-gate if (!(sep->se_flags & SEF_DEBUGCLR)) {
3337c478bd9Sstevel@tonic-gate sep->se_debug += sedefp->se_debug;
3347c478bd9Sstevel@tonic-gate sep->se_flags |= sedefp->se_flags &
3357c478bd9Sstevel@tonic-gate SEF_DEBUGCLR;
3367c478bd9Sstevel@tonic-gate }
3377c478bd9Sstevel@tonic-gate cfile = cfile->pf_prev;
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate /* Revert to global definitions. */
3417c478bd9Sstevel@tonic-gate psp->ps_csvc = &psp->ps_cfile->pf_global;
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate /* Discard a dynamic device list */
3457c478bd9Sstevel@tonic-gate static void
free_device_list(struct device_list * dlp)3467c478bd9Sstevel@tonic-gate free_device_list(struct device_list *dlp)
3477c478bd9Sstevel@tonic-gate {
3487c478bd9Sstevel@tonic-gate struct device_list *dln;
3497c478bd9Sstevel@tonic-gate
3507c478bd9Sstevel@tonic-gate while (dlp != NULL) {
3517c478bd9Sstevel@tonic-gate dln = dlp->dl_next;
3527c478bd9Sstevel@tonic-gate free(dlp);
3537c478bd9Sstevel@tonic-gate dlp = dln;
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate * Handle "service <name>" -- finish up previous service definition
3597c478bd9Sstevel@tonic-gate * (if any) by copying from global state where necessary, and start
3607c478bd9Sstevel@tonic-gate * defining new service.
3617c478bd9Sstevel@tonic-gate */
3627c478bd9Sstevel@tonic-gate static int
set_service(struct service_list * slp,const char * str)3637c478bd9Sstevel@tonic-gate set_service(struct service_list *slp, const char *str)
3647c478bd9Sstevel@tonic-gate {
3657c478bd9Sstevel@tonic-gate struct parse_state *psp;
3667c478bd9Sstevel@tonic-gate struct per_file *cfile;
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate /* Finish current service */
3697c478bd9Sstevel@tonic-gate close_service(slp);
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate /* Start new service */
3727c478bd9Sstevel@tonic-gate psp = slp->sl_parse;
3737c478bd9Sstevel@tonic-gate slp = (struct service_list *)calloc(sizeof (*slp) + strlen(str) + 1,
3747c478bd9Sstevel@tonic-gate 1);
3757c478bd9Sstevel@tonic-gate if (slp == NULL) {
3767c478bd9Sstevel@tonic-gate logerr("no memory for service \"%s\"", str);
3777c478bd9Sstevel@tonic-gate return (-1);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate /* Add to end of list */
3817c478bd9Sstevel@tonic-gate cfile = psp->ps_cfile;
3827c478bd9Sstevel@tonic-gate if (cfile->pf_svc_last == NULL)
3837c478bd9Sstevel@tonic-gate cfile->pf_svc = slp;
3847c478bd9Sstevel@tonic-gate else
3857c478bd9Sstevel@tonic-gate cfile->pf_svc_last->sl_next = slp;
3867c478bd9Sstevel@tonic-gate cfile->pf_svc_last = slp;
3877c478bd9Sstevel@tonic-gate cfile->pf_nsvc++;
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate /* Fill in initial service entry */
3907c478bd9Sstevel@tonic-gate slp->sl_entry.se_name = (const char *)(slp+1);
3917c478bd9Sstevel@tonic-gate (void) strcpy((char *)(slp+1), str);
3927c478bd9Sstevel@tonic-gate logdbg("service %s begins", slp->sl_entry.se_name);
3937c478bd9Sstevel@tonic-gate slp->sl_serial = psp->ps_serial++;
3947c478bd9Sstevel@tonic-gate slp->sl_parse = psp;
3957c478bd9Sstevel@tonic-gate
3967c478bd9Sstevel@tonic-gate /* This is now the current service that we're defining. */
3977c478bd9Sstevel@tonic-gate psp->ps_csvc = slp;
3987c478bd9Sstevel@tonic-gate return (0);
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate /*
4027c478bd9Sstevel@tonic-gate * Handle both "wildcard" and "nowildcard" options.
4037c478bd9Sstevel@tonic-gate */
4047c478bd9Sstevel@tonic-gate static int
set_wildcard(struct service_list * slp,const char * str)4057c478bd9Sstevel@tonic-gate set_wildcard(struct service_list *slp, const char *str)
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate /* Allow global context to switch back and forth without error. */
4087c478bd9Sstevel@tonic-gate if (!ISGLOBAL(slp) &&
4097c478bd9Sstevel@tonic-gate (slp->sl_entry.se_flags & (SEF_WILD|SEF_NOWILD))) {
4107c478bd9Sstevel@tonic-gate logdbg("%s: extra \"%s\" ignored",
4117c478bd9Sstevel@tonic-gate slp->sl_parse->ps_cfile->pf_name, str);
4127c478bd9Sstevel@tonic-gate return (0);
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate slp->sl_entry.se_flags =
4157c478bd9Sstevel@tonic-gate (slp->sl_entry.se_flags & ~(SEF_WILD|SEF_NOWILD)) |
4167c478bd9Sstevel@tonic-gate (*str == 'n' ? SEF_NOWILD : SEF_WILD);
4177c478bd9Sstevel@tonic-gate return (0);
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate /*
4217c478bd9Sstevel@tonic-gate * Handle "debug" option.
4227c478bd9Sstevel@tonic-gate */
4237c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4247c478bd9Sstevel@tonic-gate static int
set_debug(struct service_list * slp,const char * str)4257c478bd9Sstevel@tonic-gate set_debug(struct service_list *slp, const char *str)
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate slp->sl_entry.se_debug++;
4287c478bd9Sstevel@tonic-gate if (ISGLOBAL(slp) && (slp->sl_parse->ps_flags & PSF_SETLEVEL)) {
4297c478bd9Sstevel@tonic-gate log_level = slp->sl_entry.se_debug;
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate return (0);
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate /*
4357c478bd9Sstevel@tonic-gate * Handle "nodebug" option.
4367c478bd9Sstevel@tonic-gate */
4377c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4387c478bd9Sstevel@tonic-gate static int
set_nodebug(struct service_list * slp,const char * str)4397c478bd9Sstevel@tonic-gate set_nodebug(struct service_list *slp, const char *str)
4407c478bd9Sstevel@tonic-gate {
4417c478bd9Sstevel@tonic-gate slp->sl_entry.se_flags |= SEF_DEBUGCLR;
4427c478bd9Sstevel@tonic-gate slp->sl_entry.se_debug = 0;
4437c478bd9Sstevel@tonic-gate if (ISGLOBAL(slp) && (slp->sl_parse->ps_flags & PSF_SETLEVEL)) {
4447c478bd9Sstevel@tonic-gate log_level = slp->sl_entry.se_debug;
4457c478bd9Sstevel@tonic-gate }
4467c478bd9Sstevel@tonic-gate return (0);
4477c478bd9Sstevel@tonic-gate }
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate /*
4507c478bd9Sstevel@tonic-gate * Handle all plain string options; "server", "pppd", "path", "extra",
4517c478bd9Sstevel@tonic-gate * and "log".
4527c478bd9Sstevel@tonic-gate */
4537c478bd9Sstevel@tonic-gate static int
set_string(struct service_list * slp,const char * str)4547c478bd9Sstevel@tonic-gate set_string(struct service_list *slp, const char *str)
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate char **cpp;
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate assert(!(slp->sl_entry.se_flags &
4597c478bd9Sstevel@tonic-gate (SEF_CSERVER|SEF_CPPPD|SEF_CPATH|SEF_CEXTRA|SEF_CLOG)));
4607c478bd9Sstevel@tonic-gate switch (slp->sl_parse->ps_state) {
4617c478bd9Sstevel@tonic-gate case ksServer:
4627c478bd9Sstevel@tonic-gate cpp = &slp->sl_entry.se_server;
4637c478bd9Sstevel@tonic-gate break;
4647c478bd9Sstevel@tonic-gate case ksPppd:
4657c478bd9Sstevel@tonic-gate cpp = &slp->sl_entry.se_pppd;
4667c478bd9Sstevel@tonic-gate break;
4677c478bd9Sstevel@tonic-gate case ksPath:
4687c478bd9Sstevel@tonic-gate cpp = &slp->sl_entry.se_path;
4697c478bd9Sstevel@tonic-gate break;
4707c478bd9Sstevel@tonic-gate case ksExtra:
4717c478bd9Sstevel@tonic-gate cpp = &slp->sl_entry.se_extra;
4727c478bd9Sstevel@tonic-gate break;
4737c478bd9Sstevel@tonic-gate case ksLog:
4747c478bd9Sstevel@tonic-gate cpp = &slp->sl_entry.se_log;
4757c478bd9Sstevel@tonic-gate break;
4767c478bd9Sstevel@tonic-gate default:
4777c478bd9Sstevel@tonic-gate assert(0);
4787c478bd9Sstevel@tonic-gate return (-1);
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate if (*cpp != NULL)
4817c478bd9Sstevel@tonic-gate free(*cpp);
4827c478bd9Sstevel@tonic-gate *cpp = strsave(str);
4837c478bd9Sstevel@tonic-gate return (0);
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate /*
4877c478bd9Sstevel@tonic-gate * Handle "file <name>" option. Close out current service (if any)
4887c478bd9Sstevel@tonic-gate * and begin parsing from new file.
4897c478bd9Sstevel@tonic-gate */
4907c478bd9Sstevel@tonic-gate static int
set_file(struct service_list * slp,const char * str)4917c478bd9Sstevel@tonic-gate set_file(struct service_list *slp, const char *str)
4927c478bd9Sstevel@tonic-gate {
4937c478bd9Sstevel@tonic-gate FILE *fp;
4947c478bd9Sstevel@tonic-gate struct per_file *pfp;
4957c478bd9Sstevel@tonic-gate struct parse_state *psp;
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate close_service(slp);
4987c478bd9Sstevel@tonic-gate
4997c478bd9Sstevel@tonic-gate if ((fp = fopen(str, "r")) == NULL) {
5007c478bd9Sstevel@tonic-gate logwarn("%s: %s: %s", slp->sl_parse->ps_cfile->pf_name, str,
5017c478bd9Sstevel@tonic-gate mystrerror(errno));
5027c478bd9Sstevel@tonic-gate return (-1);
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate pfp = (struct per_file *)calloc(sizeof (*pfp) + strlen(str) + 1, 1);
5057c478bd9Sstevel@tonic-gate if (pfp == NULL) {
5067c478bd9Sstevel@tonic-gate logerr("no memory for parsing file %s", str);
5077c478bd9Sstevel@tonic-gate (void) fclose(fp);
5087c478bd9Sstevel@tonic-gate return (-1);
5097c478bd9Sstevel@tonic-gate }
5107c478bd9Sstevel@tonic-gate logdbg("config file %s open", str);
5117c478bd9Sstevel@tonic-gate
5127c478bd9Sstevel@tonic-gate /* Fill in new file structure. */
5137c478bd9Sstevel@tonic-gate pfp->pf_name = (const char *)(pfp+1);
5147c478bd9Sstevel@tonic-gate (void) strcpy((char *)(pfp+1), str);
5157c478bd9Sstevel@tonic-gate pfp->pf_input = fp;
5167c478bd9Sstevel@tonic-gate psp = slp->sl_parse;
5177c478bd9Sstevel@tonic-gate pfp->pf_prev = psp->ps_cfile;
5187c478bd9Sstevel@tonic-gate psp->ps_cfile = pfp;
5197c478bd9Sstevel@tonic-gate
5207c478bd9Sstevel@tonic-gate /* Start off in global context for this file. */
5217c478bd9Sstevel@tonic-gate psp->ps_csvc = &pfp->pf_global;
5227c478bd9Sstevel@tonic-gate pfp->pf_global.sl_parse = psp;
5237c478bd9Sstevel@tonic-gate pfp->pf_global.sl_entry.se_name = "<global>";
5247c478bd9Sstevel@tonic-gate return (0);
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate /*
5287c478bd9Sstevel@tonic-gate * Handle "device <list>" option.
5297c478bd9Sstevel@tonic-gate */
5307c478bd9Sstevel@tonic-gate static int
set_device(struct service_list * slp,const char * str)5317c478bd9Sstevel@tonic-gate set_device(struct service_list *slp, const char *str)
5327c478bd9Sstevel@tonic-gate {
5337c478bd9Sstevel@tonic-gate struct parse_state *psp = slp->sl_parse;
5347c478bd9Sstevel@tonic-gate struct device_list *dlp;
5357c478bd9Sstevel@tonic-gate struct device_list *dln;
5367c478bd9Sstevel@tonic-gate struct device_list **dlpp;
5377c478bd9Sstevel@tonic-gate const char *cp;
5387c478bd9Sstevel@tonic-gate int len;
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate /* Can't use this option in the per-device files. */
5417c478bd9Sstevel@tonic-gate if (psp->ps_flags & PSF_PERDEV) {
5427c478bd9Sstevel@tonic-gate logerr("\"device %s\" ignored in %s", str,
5437c478bd9Sstevel@tonic-gate psp->ps_cfile->pf_name);
5447c478bd9Sstevel@tonic-gate return (0);
5457c478bd9Sstevel@tonic-gate }
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gate if (strcmp(str, "*") == 0 || strcmp(str, "all") == 0) {
5487c478bd9Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CDEV))
5497c478bd9Sstevel@tonic-gate free_device_list(slp->sl_dev);
5507c478bd9Sstevel@tonic-gate slp->sl_dev = psp->ps_star;
5517c478bd9Sstevel@tonic-gate slp->sl_entry.se_flags |= SEF_CDEV;
5527c478bd9Sstevel@tonic-gate } else {
5537c478bd9Sstevel@tonic-gate dlpp = &dlp;
5547c478bd9Sstevel@tonic-gate for (;;) {
5557c478bd9Sstevel@tonic-gate while (isspace(*str) || *str == ',')
5567c478bd9Sstevel@tonic-gate str++;
5577c478bd9Sstevel@tonic-gate if (*str == '\0')
5587c478bd9Sstevel@tonic-gate break;
5597c478bd9Sstevel@tonic-gate cp = str;
5607c478bd9Sstevel@tonic-gate while (*str != '\0' && !isspace(*str) && *str != ',')
5617c478bd9Sstevel@tonic-gate str++;
5627c478bd9Sstevel@tonic-gate len = str - cp;
5637c478bd9Sstevel@tonic-gate if ((len == 1 && *cp == '*') ||
5647c478bd9Sstevel@tonic-gate (len == 3 && strncmp(cp, "all", 3) == 0)) {
5657c478bd9Sstevel@tonic-gate logerr("%s: cannot use %.*s in device list",
5667c478bd9Sstevel@tonic-gate psp->ps_cfile->pf_name, len, cp);
5677c478bd9Sstevel@tonic-gate continue;
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate dln = (struct device_list *)malloc(sizeof (*dln) +
5707c478bd9Sstevel@tonic-gate len + 1);
5717c478bd9Sstevel@tonic-gate if (dln == NULL) {
5727c478bd9Sstevel@tonic-gate logerr("no memory for device name");
5737c478bd9Sstevel@tonic-gate break;
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate dln->dl_name = (const char *)(dln + 1);
5767c478bd9Sstevel@tonic-gate /* Cannot use strcpy because cp isn't terminated. */
5777c478bd9Sstevel@tonic-gate (void) memcpy(dln + 1, cp, len);
5787c478bd9Sstevel@tonic-gate ((char *)(dln + 1))[len] = '\0';
5797c478bd9Sstevel@tonic-gate logdbg("%s: device %s", psp->ps_cfile->pf_name,
5807c478bd9Sstevel@tonic-gate dln->dl_name);
5817c478bd9Sstevel@tonic-gate *dlpp = dln;
5827c478bd9Sstevel@tonic-gate dlpp = &dln->dl_next;
5837c478bd9Sstevel@tonic-gate }
5847c478bd9Sstevel@tonic-gate *dlpp = NULL;
5857c478bd9Sstevel@tonic-gate
5867c478bd9Sstevel@tonic-gate dlpp = &slp->sl_dev;
5877c478bd9Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CDEV))
5887c478bd9Sstevel@tonic-gate while (*dlpp != NULL)
5897c478bd9Sstevel@tonic-gate dlpp = &(*dlpp)->dl_next;
5907c478bd9Sstevel@tonic-gate *dlpp = dlp;
5917c478bd9Sstevel@tonic-gate slp->sl_entry.se_flags &= ~SEF_CDEV;
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate
5947c478bd9Sstevel@tonic-gate return (0);
5957c478bd9Sstevel@tonic-gate }
5967c478bd9Sstevel@tonic-gate
5977c478bd9Sstevel@tonic-gate /*
5987c478bd9Sstevel@tonic-gate * Handle <list> portion of "client [except] <list>" option. Attach
5997c478bd9Sstevel@tonic-gate * to list of filters in reverse order.
6007c478bd9Sstevel@tonic-gate */
6017c478bd9Sstevel@tonic-gate static int
set_client(struct service_list * slp,const char * str)6027c478bd9Sstevel@tonic-gate set_client(struct service_list *slp, const char *str)
6037c478bd9Sstevel@tonic-gate {
6047c478bd9Sstevel@tonic-gate struct parse_state *psp = slp->sl_parse;
6057c478bd9Sstevel@tonic-gate struct filter_entry *fep;
6067c478bd9Sstevel@tonic-gate struct filter_entry *fen;
6077c478bd9Sstevel@tonic-gate const char *cp;
6087c478bd9Sstevel@tonic-gate int len;
6097c478bd9Sstevel@tonic-gate char hbuf[MAXHOSTNAMELEN];
6107c478bd9Sstevel@tonic-gate struct ether_addr ea;
6117c478bd9Sstevel@tonic-gate struct ether_addr mask;
6127c478bd9Sstevel@tonic-gate uchar_t *ucp;
6137c478bd9Sstevel@tonic-gate uchar_t *mcp;
6147c478bd9Sstevel@tonic-gate
6157c478bd9Sstevel@tonic-gate /* Head of list. */
6167c478bd9Sstevel@tonic-gate fep = slp->sl_entry.se_flist;
6177c478bd9Sstevel@tonic-gate for (;;) {
6187c478bd9Sstevel@tonic-gate while (isspace(*str) || *str == ',')
6197c478bd9Sstevel@tonic-gate str++;
6207c478bd9Sstevel@tonic-gate if (*str == '\0')
6217c478bd9Sstevel@tonic-gate break;
6227c478bd9Sstevel@tonic-gate cp = str;
6237c478bd9Sstevel@tonic-gate while (*str != '\0' && !isspace(*str) && *str != ',')
6247c478bd9Sstevel@tonic-gate str++;
6257c478bd9Sstevel@tonic-gate len = str - cp;
6267c478bd9Sstevel@tonic-gate (void) memcpy(hbuf, cp, len);
6277c478bd9Sstevel@tonic-gate hbuf[len] = '\0';
6287c478bd9Sstevel@tonic-gate mcp = mask.ether_addr_octet;
6297c478bd9Sstevel@tonic-gate mcp[0] = mcp[1] = mcp[2] = mcp[3] = mcp[4] = mcp[5] = 0xFF;
6307c478bd9Sstevel@tonic-gate if (ether_hostton(hbuf, &ea) != 0) {
6317c478bd9Sstevel@tonic-gate ucp = ea.ether_addr_octet;
6327c478bd9Sstevel@tonic-gate while (cp < str) {
6337c478bd9Sstevel@tonic-gate if (ucp >= ea.ether_addr_octet + sizeof (ea))
6347c478bd9Sstevel@tonic-gate break;
6357c478bd9Sstevel@tonic-gate if (*cp == '*') {
6367c478bd9Sstevel@tonic-gate *mcp++ = *ucp++ = 0;
6377c478bd9Sstevel@tonic-gate cp++;
6387c478bd9Sstevel@tonic-gate } else {
6397c478bd9Sstevel@tonic-gate if (!isxdigit(*cp))
6407c478bd9Sstevel@tonic-gate break;
6417c478bd9Sstevel@tonic-gate *ucp = hexdecode(*cp++);
6427c478bd9Sstevel@tonic-gate if (cp < str && isxdigit(*cp)) {
6437c478bd9Sstevel@tonic-gate *ucp = (*ucp << 4) |
6447c478bd9Sstevel@tonic-gate hexdecode(*cp++);
6457c478bd9Sstevel@tonic-gate }
6467c478bd9Sstevel@tonic-gate ucp++;
6477c478bd9Sstevel@tonic-gate *mcp++ = 0xFF;
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate if (cp < str) {
6507c478bd9Sstevel@tonic-gate if (*cp != ':' || cp + 1 == str)
6517c478bd9Sstevel@tonic-gate break;
6527c478bd9Sstevel@tonic-gate cp++;
6537c478bd9Sstevel@tonic-gate }
6547c478bd9Sstevel@tonic-gate }
6557c478bd9Sstevel@tonic-gate if (cp < str) {
6567c478bd9Sstevel@tonic-gate logerr("%s: illegal Ethernet address %.*s",
6577c478bd9Sstevel@tonic-gate psp->ps_cfile->pf_name, len, cp);
6587c478bd9Sstevel@tonic-gate continue;
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate }
6617c478bd9Sstevel@tonic-gate fen = (struct filter_entry *)malloc(sizeof (*fen));
6627c478bd9Sstevel@tonic-gate if (fen == NULL) {
6637c478bd9Sstevel@tonic-gate logerr("unable to allocate memory for filter");
6647c478bd9Sstevel@tonic-gate break;
6657c478bd9Sstevel@tonic-gate }
6667c478bd9Sstevel@tonic-gate fen->fe_isexcept = psp->ps_state == ksClientE;
6677c478bd9Sstevel@tonic-gate fen->fe_prevcopy = 0;
6687c478bd9Sstevel@tonic-gate (void) memcpy(&fen->fe_mac, &ea, sizeof (fen->fe_mac));
6697c478bd9Sstevel@tonic-gate (void) memcpy(&fen->fe_mask, &mask, sizeof (fen->fe_mask));
6707c478bd9Sstevel@tonic-gate fen->fe_prev = fep;
6717c478bd9Sstevel@tonic-gate fep = fen;
6727c478bd9Sstevel@tonic-gate }
6737c478bd9Sstevel@tonic-gate slp->sl_entry.se_flist = fep;
6747c478bd9Sstevel@tonic-gate return (0);
6757c478bd9Sstevel@tonic-gate }
6767c478bd9Sstevel@tonic-gate
6777c478bd9Sstevel@tonic-gate /*
6787c478bd9Sstevel@tonic-gate * Handle "user <name>" option.
6797c478bd9Sstevel@tonic-gate */
6807c478bd9Sstevel@tonic-gate static int
set_user(struct service_list * slp,const char * str)6817c478bd9Sstevel@tonic-gate set_user(struct service_list *slp, const char *str)
6827c478bd9Sstevel@tonic-gate {
6837c478bd9Sstevel@tonic-gate struct passwd *pw;
6847c478bd9Sstevel@tonic-gate char *cp;
6857c478bd9Sstevel@tonic-gate uid_t myuid, uid;
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate if ((pw = getpwnam(str)) == NULL) {
6887c478bd9Sstevel@tonic-gate uid = (uid_t)strtol(str, &cp, 0);
6897c478bd9Sstevel@tonic-gate if (str == cp || *cp != '\0') {
6907c478bd9Sstevel@tonic-gate logerr("%s: bad user name \"%s\"",
6917c478bd9Sstevel@tonic-gate slp->sl_parse->ps_cfile->pf_name, str);
6927c478bd9Sstevel@tonic-gate return (0);
6937c478bd9Sstevel@tonic-gate }
6947c478bd9Sstevel@tonic-gate } else {
6957c478bd9Sstevel@tonic-gate uid = pw->pw_uid;
6967c478bd9Sstevel@tonic-gate }
6977c478bd9Sstevel@tonic-gate slp->sl_entry.se_uid = uid;
6987c478bd9Sstevel@tonic-gate myuid = getuid();
6997c478bd9Sstevel@tonic-gate if (myuid != 0) {
7007c478bd9Sstevel@tonic-gate if (myuid == uid)
7017c478bd9Sstevel@tonic-gate return (0);
7027c478bd9Sstevel@tonic-gate logdbg("%s: not root; ignoring attempt to set UID %d (%s)",
7037c478bd9Sstevel@tonic-gate slp->sl_parse->ps_cfile->pf_name, uid, str);
7047c478bd9Sstevel@tonic-gate return (0);
7057c478bd9Sstevel@tonic-gate }
7067c478bd9Sstevel@tonic-gate slp->sl_entry.se_flags |= SEF_UIDSET;
7077c478bd9Sstevel@tonic-gate return (0);
7087c478bd9Sstevel@tonic-gate }
7097c478bd9Sstevel@tonic-gate
7107c478bd9Sstevel@tonic-gate /*
7117c478bd9Sstevel@tonic-gate * Handle "group <name>" option.
7127c478bd9Sstevel@tonic-gate */
7137c478bd9Sstevel@tonic-gate static int
set_group(struct service_list * slp,const char * str)7147c478bd9Sstevel@tonic-gate set_group(struct service_list *slp, const char *str)
7157c478bd9Sstevel@tonic-gate {
7167c478bd9Sstevel@tonic-gate struct group *gr;
7177c478bd9Sstevel@tonic-gate char *cp;
7187c478bd9Sstevel@tonic-gate gid_t gid;
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate if ((gr = getgrnam(str)) == NULL) {
7217c478bd9Sstevel@tonic-gate gid = (gid_t)strtol(str, &cp, 0);
7227c478bd9Sstevel@tonic-gate if (str == cp || *cp != '\0') {
7237c478bd9Sstevel@tonic-gate logerr("%s: bad group name \"%s\"",
7247c478bd9Sstevel@tonic-gate slp->sl_parse->ps_cfile->pf_name, str);
7257c478bd9Sstevel@tonic-gate return (0);
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate } else {
7287c478bd9Sstevel@tonic-gate gid = gr->gr_gid;
7297c478bd9Sstevel@tonic-gate }
7307c478bd9Sstevel@tonic-gate slp->sl_entry.se_gid = gid;
7317c478bd9Sstevel@tonic-gate if (getuid() != 0) {
7327c478bd9Sstevel@tonic-gate logdbg("%s: not root; ignoring attempt to set GID %d (%s)",
7337c478bd9Sstevel@tonic-gate slp->sl_parse->ps_cfile->pf_name, gid, str);
7347c478bd9Sstevel@tonic-gate return (0);
7357c478bd9Sstevel@tonic-gate }
7367c478bd9Sstevel@tonic-gate slp->sl_entry.se_flags |= SEF_GIDSET;
7377c478bd9Sstevel@tonic-gate return (0);
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate
7407c478bd9Sstevel@tonic-gate /*
7417c478bd9Sstevel@tonic-gate * This state machine is used to parse the configuration files. The
7427c478bd9Sstevel@tonic-gate * "kwe_in" is the state in which the keyword is recognized. The
7437c478bd9Sstevel@tonic-gate * "kwe_out" is the state that the keyword produces.
7447c478bd9Sstevel@tonic-gate */
7457c478bd9Sstevel@tonic-gate struct kw_entry {
7467c478bd9Sstevel@tonic-gate const char *kwe_word;
7477c478bd9Sstevel@tonic-gate enum key_state kwe_in;
7487c478bd9Sstevel@tonic-gate enum key_state kwe_out;
7497c478bd9Sstevel@tonic-gate int (*kwe_func)(struct service_list *slp, const char *str);
7507c478bd9Sstevel@tonic-gate };
7517c478bd9Sstevel@tonic-gate
7527c478bd9Sstevel@tonic-gate static const struct kw_entry key_list[] = {
7537c478bd9Sstevel@tonic-gate { "service", ksDefault, ksService, NULL },
7547c478bd9Sstevel@tonic-gate { "device", ksDefault, ksDevice, NULL },
7557c478bd9Sstevel@tonic-gate { "client", ksDefault, ksClient, NULL },
7567c478bd9Sstevel@tonic-gate { "except", ksClient, ksClientE, NULL },
7577c478bd9Sstevel@tonic-gate { "wildcard", ksDefault, ksDefault, set_wildcard },
7587c478bd9Sstevel@tonic-gate { "nowildcard", ksDefault, ksDefault, set_wildcard },
7597c478bd9Sstevel@tonic-gate { "server", ksDefault, ksServer, NULL },
7607c478bd9Sstevel@tonic-gate { "pppd", ksDefault, ksPppd, NULL },
7617c478bd9Sstevel@tonic-gate { "debug", ksDefault, ksDefault, set_debug },
7627c478bd9Sstevel@tonic-gate { "nodebug", ksDefault, ksDefault, set_nodebug },
7637c478bd9Sstevel@tonic-gate { "file", ksDefault, ksFile, NULL },
7647c478bd9Sstevel@tonic-gate { "path", ksDefault, ksPath, NULL },
7657c478bd9Sstevel@tonic-gate { "extra", ksDefault, ksExtra, NULL },
7667c478bd9Sstevel@tonic-gate { "log", ksDefault, ksLog, NULL },
7677c478bd9Sstevel@tonic-gate { "user", ksDefault, ksUser, NULL },
7687c478bd9Sstevel@tonic-gate { "group", ksDefault, ksGroup, NULL },
7697c478bd9Sstevel@tonic-gate /* Wildcards only past this point. */
7707c478bd9Sstevel@tonic-gate { "", ksService, ksDefault, set_service },
7717c478bd9Sstevel@tonic-gate { "", ksDevice, ksDefault, set_device },
7727c478bd9Sstevel@tonic-gate { "", ksClient, ksDefault, set_client },
7737c478bd9Sstevel@tonic-gate { "", ksClientE, ksDefault, set_client },
7747c478bd9Sstevel@tonic-gate { "", ksServer, ksDefault, set_string },
7757c478bd9Sstevel@tonic-gate { "", ksPppd, ksDefault, set_string },
7767c478bd9Sstevel@tonic-gate { "", ksFile, ksDefault, set_file },
7777c478bd9Sstevel@tonic-gate { "", ksPath, ksDefault, set_string },
7787c478bd9Sstevel@tonic-gate { "", ksExtra, ksDefault, set_string },
7797c478bd9Sstevel@tonic-gate { "", ksLog, ksDefault, set_string },
7807c478bd9Sstevel@tonic-gate { "", ksUser, ksDefault, set_user },
7817c478bd9Sstevel@tonic-gate { "", ksGroup, ksDefault, set_group },
7827c478bd9Sstevel@tonic-gate { NULL, ksDefault, ksDefault, NULL }
7837c478bd9Sstevel@tonic-gate };
7847c478bd9Sstevel@tonic-gate
7857c478bd9Sstevel@tonic-gate /*
7867c478bd9Sstevel@tonic-gate * Produce a string for the keyword that would have gotten us into the
7877c478bd9Sstevel@tonic-gate * current state.
7887c478bd9Sstevel@tonic-gate */
7897c478bd9Sstevel@tonic-gate static const char *
after_key(enum key_state kstate)7907c478bd9Sstevel@tonic-gate after_key(enum key_state kstate)
7917c478bd9Sstevel@tonic-gate {
7927c478bd9Sstevel@tonic-gate const struct kw_entry *kep;
7937c478bd9Sstevel@tonic-gate
7947c478bd9Sstevel@tonic-gate for (kep = key_list; kep->kwe_word != NULL; kep++)
7957c478bd9Sstevel@tonic-gate if (kep->kwe_out == kstate)
7967c478bd9Sstevel@tonic-gate return (kep->kwe_word);
7977c478bd9Sstevel@tonic-gate return ("nothing");
7987c478bd9Sstevel@tonic-gate }
7997c478bd9Sstevel@tonic-gate
8007c478bd9Sstevel@tonic-gate /*
8017c478bd9Sstevel@tonic-gate * Handle end-of-file processing -- close service, close file, revert
8027c478bd9Sstevel@tonic-gate * to global context in previous include file nest level.
8037c478bd9Sstevel@tonic-gate */
8047c478bd9Sstevel@tonic-gate static void
file_end(struct parse_state * psp)8057c478bd9Sstevel@tonic-gate file_end(struct parse_state *psp)
8067c478bd9Sstevel@tonic-gate {
8077c478bd9Sstevel@tonic-gate struct per_file *pfp;
8087c478bd9Sstevel@tonic-gate
8097c478bd9Sstevel@tonic-gate /* Must not be in the middle of parsing a multi-word sequence now. */
8107c478bd9Sstevel@tonic-gate if (psp->ps_state != ksDefault) {
8117c478bd9Sstevel@tonic-gate logerr("%s ends with \"%s\"", psp->ps_cfile->pf_name,
8127c478bd9Sstevel@tonic-gate after_key(psp->ps_state));
8137c478bd9Sstevel@tonic-gate psp->ps_state = ksDefault;
8147c478bd9Sstevel@tonic-gate }
8157c478bd9Sstevel@tonic-gate close_service(psp->ps_csvc);
8167c478bd9Sstevel@tonic-gate if ((pfp = psp->ps_cfile) != NULL) {
8177c478bd9Sstevel@tonic-gate /* Put this file on the list of finished files. */
8187c478bd9Sstevel@tonic-gate psp->ps_cfile = pfp->pf_prev;
8197c478bd9Sstevel@tonic-gate pfp->pf_prev = psp->ps_files;
8207c478bd9Sstevel@tonic-gate psp->ps_files = pfp;
8217c478bd9Sstevel@tonic-gate if (pfp->pf_input != NULL) {
8227c478bd9Sstevel@tonic-gate logdbg("file %s closed", pfp->pf_name);
8237c478bd9Sstevel@tonic-gate (void) fclose(pfp->pf_input);
8247c478bd9Sstevel@tonic-gate pfp->pf_input = NULL;
8257c478bd9Sstevel@tonic-gate }
8267c478bd9Sstevel@tonic-gate
8277c478bd9Sstevel@tonic-gate /* Back up to previous file, if any, and set global context. */
8287c478bd9Sstevel@tonic-gate if ((pfp = psp->ps_cfile) != NULL)
8297c478bd9Sstevel@tonic-gate psp->ps_csvc = &pfp->pf_global;
8307c478bd9Sstevel@tonic-gate }
8317c478bd9Sstevel@tonic-gate }
8327c478bd9Sstevel@tonic-gate
8337c478bd9Sstevel@tonic-gate /*
8347c478bd9Sstevel@tonic-gate * Dispatch a single keyword against the parser state machine or
8357c478bd9Sstevel@tonic-gate * handle an environment variable assignment. The input is a string
8367c478bd9Sstevel@tonic-gate * containing the single word to be dispatched.
8377c478bd9Sstevel@tonic-gate */
8387c478bd9Sstevel@tonic-gate static int
dispatch_keyword(struct parse_state * psp,const char * keybuf)8397c478bd9Sstevel@tonic-gate dispatch_keyword(struct parse_state *psp, const char *keybuf)
8407c478bd9Sstevel@tonic-gate {
8417c478bd9Sstevel@tonic-gate const struct kw_entry *kep;
8427c478bd9Sstevel@tonic-gate int retv;
8437c478bd9Sstevel@tonic-gate char *cp;
8447c478bd9Sstevel@tonic-gate char *env;
8457c478bd9Sstevel@tonic-gate char **evlist;
8467c478bd9Sstevel@tonic-gate int len;
8477c478bd9Sstevel@tonic-gate
8487c478bd9Sstevel@tonic-gate retv = 0;
8497c478bd9Sstevel@tonic-gate for (kep = key_list; kep->kwe_word != NULL; kep++) {
8507c478bd9Sstevel@tonic-gate if (kep->kwe_in == psp->ps_state &&
8517c478bd9Sstevel@tonic-gate (*kep->kwe_word == '\0' ||
8527c478bd9Sstevel@tonic-gate strcasecmp(kep->kwe_word, keybuf) == 0)) {
8537c478bd9Sstevel@tonic-gate if (kep->kwe_func != NULL)
8547c478bd9Sstevel@tonic-gate retv = (*kep->kwe_func)(psp->ps_csvc, keybuf);
8557c478bd9Sstevel@tonic-gate psp->ps_state = kep->kwe_out;
8567c478bd9Sstevel@tonic-gate return (retv);
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate }
8597c478bd9Sstevel@tonic-gate if (strchr(keybuf, '=') != NULL) {
8607c478bd9Sstevel@tonic-gate if ((cp = strsave(keybuf)) == NULL) {
8617c478bd9Sstevel@tonic-gate logerr("no memory to save %s", keybuf);
8627c478bd9Sstevel@tonic-gate return (0);
8637c478bd9Sstevel@tonic-gate }
8647c478bd9Sstevel@tonic-gate len = (strchr(cp, '=') - cp) + 1;
8657c478bd9Sstevel@tonic-gate if ((evlist = psp->ps_evlist) == NULL) {
8667c478bd9Sstevel@tonic-gate psp->ps_evlist = evlist =
8677c478bd9Sstevel@tonic-gate (char **)malloc(8 * sizeof (*evlist));
8687c478bd9Sstevel@tonic-gate if (evlist == NULL) {
8697c478bd9Sstevel@tonic-gate logerr("no memory for evlist");
8707c478bd9Sstevel@tonic-gate free(cp);
8717c478bd9Sstevel@tonic-gate return (0);
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate psp->ps_evsize = 8;
8747c478bd9Sstevel@tonic-gate evlist[0] = evlist[1] = NULL;
8757c478bd9Sstevel@tonic-gate } else {
8767c478bd9Sstevel@tonic-gate while ((env = *evlist) != NULL) {
8777c478bd9Sstevel@tonic-gate if (strncmp(cp, env, len) == 0)
8787c478bd9Sstevel@tonic-gate break;
8797c478bd9Sstevel@tonic-gate evlist++;
8807c478bd9Sstevel@tonic-gate }
8817c478bd9Sstevel@tonic-gate if (env == NULL &&
8827c478bd9Sstevel@tonic-gate evlist-psp->ps_evlist >= psp->ps_evsize-1) {
8837c478bd9Sstevel@tonic-gate evlist = (char **)realloc(psp->ps_evlist,
8847c478bd9Sstevel@tonic-gate (psp->ps_evsize + 8) * sizeof (*evlist));
8857c478bd9Sstevel@tonic-gate if (evlist == NULL) {
8867c478bd9Sstevel@tonic-gate logerr("cannot realloc evlist to %d",
8877c478bd9Sstevel@tonic-gate psp->ps_evsize + 8);
8887c478bd9Sstevel@tonic-gate free(cp);
8897c478bd9Sstevel@tonic-gate return (0);
8907c478bd9Sstevel@tonic-gate }
8917c478bd9Sstevel@tonic-gate psp->ps_evlist = evlist;
8927c478bd9Sstevel@tonic-gate evlist += psp->ps_evsize - 1;
8937c478bd9Sstevel@tonic-gate psp->ps_evsize += 8;
8947c478bd9Sstevel@tonic-gate evlist[1] = NULL;
8957c478bd9Sstevel@tonic-gate }
8967c478bd9Sstevel@tonic-gate }
8977c478bd9Sstevel@tonic-gate logdbg("setenv \"%s\"", cp);
8987c478bd9Sstevel@tonic-gate if (*evlist != NULL)
8997c478bd9Sstevel@tonic-gate free(*evlist);
9007c478bd9Sstevel@tonic-gate *evlist = cp;
9017c478bd9Sstevel@tonic-gate return (0);
9027c478bd9Sstevel@tonic-gate }
9037c478bd9Sstevel@tonic-gate logerr("%s: unknown keyword '%s'", psp->ps_cfile->pf_name, keybuf);
9047c478bd9Sstevel@tonic-gate return (-1);
9057c478bd9Sstevel@tonic-gate }
9067c478bd9Sstevel@tonic-gate
9077c478bd9Sstevel@tonic-gate /*
9087c478bd9Sstevel@tonic-gate * Modified version of standard getenv; looks in locally-stored
9097c478bd9Sstevel@tonic-gate * environment first. This function exists because we need to be able
9107c478bd9Sstevel@tonic-gate * to revert to the original environment during a reread (SIGHUP), and
9117c478bd9Sstevel@tonic-gate * the putenv() function overwrites that environment.
9127c478bd9Sstevel@tonic-gate */
9137c478bd9Sstevel@tonic-gate static char *
my_getenv(struct parse_state * psp,char * estr)9147c478bd9Sstevel@tonic-gate my_getenv(struct parse_state *psp, char *estr)
9157c478bd9Sstevel@tonic-gate {
9167c478bd9Sstevel@tonic-gate char **evlist, *ent;
9177c478bd9Sstevel@tonic-gate int elen;
9187c478bd9Sstevel@tonic-gate
9197c478bd9Sstevel@tonic-gate if (psp != NULL && (evlist = psp->ps_evlist) != NULL) {
9207c478bd9Sstevel@tonic-gate elen = strlen(estr);
9217c478bd9Sstevel@tonic-gate while ((ent = *evlist++) != NULL) {
9227c478bd9Sstevel@tonic-gate if (strncmp(ent, estr, elen) == 0 &&
9237c478bd9Sstevel@tonic-gate ent[elen] == '=')
9247c478bd9Sstevel@tonic-gate return (ent + elen + 1);
9257c478bd9Sstevel@tonic-gate }
9267c478bd9Sstevel@tonic-gate }
9277c478bd9Sstevel@tonic-gate return (getenv(estr));
9287c478bd9Sstevel@tonic-gate }
9297c478bd9Sstevel@tonic-gate
9307c478bd9Sstevel@tonic-gate /*
9317c478bd9Sstevel@tonic-gate * Expand an environment variable at the end of current buffer and
9327c478bd9Sstevel@tonic-gate * return pointer to next spot in buffer for character append. psp
9337c478bd9Sstevel@tonic-gate * context may be null.
9347c478bd9Sstevel@tonic-gate */
9357c478bd9Sstevel@tonic-gate static char *
env_replace(struct parse_state * psp,char * keybuf,char kwstate)9367c478bd9Sstevel@tonic-gate env_replace(struct parse_state *psp, char *keybuf, char kwstate)
9377c478bd9Sstevel@tonic-gate {
9387c478bd9Sstevel@tonic-gate char *cpe;
9397c478bd9Sstevel@tonic-gate char *cp;
9407c478bd9Sstevel@tonic-gate
9417c478bd9Sstevel@tonic-gate if ((cp = strrchr(keybuf, kwstate)) != NULL) {
9427c478bd9Sstevel@tonic-gate if ((cpe = my_getenv(psp, cp + 1)) != NULL) {
9437c478bd9Sstevel@tonic-gate *cp = '\0';
9447c478bd9Sstevel@tonic-gate (void) strncat(cp, cpe,
9457c478bd9Sstevel@tonic-gate MAX_KEYWORD - (cp - keybuf) - 1);
9467c478bd9Sstevel@tonic-gate keybuf[MAX_KEYWORD - 1] = '\0';
9477c478bd9Sstevel@tonic-gate cp += strlen(cp);
9487c478bd9Sstevel@tonic-gate } else {
9497c478bd9Sstevel@tonic-gate logerr("unknown variable \"%s\"", cp + 1);
9507c478bd9Sstevel@tonic-gate }
9517c478bd9Sstevel@tonic-gate } else {
9527c478bd9Sstevel@tonic-gate /* Should not occur. */
9537c478bd9Sstevel@tonic-gate cp = keybuf + strlen(keybuf);
9547c478bd9Sstevel@tonic-gate }
9557c478bd9Sstevel@tonic-gate return (cp);
9567c478bd9Sstevel@tonic-gate }
9577c478bd9Sstevel@tonic-gate
9587c478bd9Sstevel@tonic-gate /*
9597c478bd9Sstevel@tonic-gate * Given a character-at-a-time input function, get a delimited keyword
9607c478bd9Sstevel@tonic-gate * from the input. This function handles the usual escape sequences,
9617c478bd9Sstevel@tonic-gate * quoting, commenting, and environment variable expansion.
9627c478bd9Sstevel@tonic-gate *
9637c478bd9Sstevel@tonic-gate * The standard wordexp(3C) function isn't used here because the POSIX
9647c478bd9Sstevel@tonic-gate * definition is hard to use, and the Solaris implementation is
9657c478bd9Sstevel@tonic-gate * resource-intensive and insecure. The "hard-to-use" part is that
9667c478bd9Sstevel@tonic-gate * wordexp expands only variables from the environment, and can't
9677c478bd9Sstevel@tonic-gate * handle an environment overlay. Instead, the caller must use the
9687c478bd9Sstevel@tonic-gate * feeble putenv/getenv interface, and rewinding to the initial
9697c478bd9Sstevel@tonic-gate * environment without leaking storage is hard. The Solaris
9707c478bd9Sstevel@tonic-gate * implementation invokes an undocumented extensions via
9717c478bd9Sstevel@tonic-gate * fork/exec("/bin/ksh -\005 %s") for every invocation, and gathers
9727c478bd9Sstevel@tonic-gate * the expanded result with pipe. This makes it slow to execute and
9737c478bd9Sstevel@tonic-gate * exposes the string being expanded to users with access to "ps -f."
9747c478bd9Sstevel@tonic-gate *
9757c478bd9Sstevel@tonic-gate * psp may be null; it's used only for environment variable expansion.
9767c478bd9Sstevel@tonic-gate * Input "flag" is 1 to ignore EOL, '#', and '$'; 0 for normal file parsing.
9777c478bd9Sstevel@tonic-gate *
9787c478bd9Sstevel@tonic-gate * Returns:
9797c478bd9Sstevel@tonic-gate * 0 - keyword parsed.
9807c478bd9Sstevel@tonic-gate * 1 - end of file; no keyword.
9817c478bd9Sstevel@tonic-gate * 2 - end of file after this keyword.
9827c478bd9Sstevel@tonic-gate */
9837c478bd9Sstevel@tonic-gate static int
getkeyword(struct parse_state * psp,char * keybuf,int keymax,int (* nextchr)(void *),void * arg,int flag)9847c478bd9Sstevel@tonic-gate getkeyword(struct parse_state *psp, char *keybuf, int keymax,
9857c478bd9Sstevel@tonic-gate int (*nextchr)(void *), void *arg, int flag)
9867c478bd9Sstevel@tonic-gate {
9877c478bd9Sstevel@tonic-gate char varnest[MAX_NEST];
9887c478bd9Sstevel@tonic-gate char *kbp;
9897c478bd9Sstevel@tonic-gate char *vnp;
9907c478bd9Sstevel@tonic-gate char chr;
9917c478bd9Sstevel@tonic-gate int ichr;
9927c478bd9Sstevel@tonic-gate char kwstate;
9937c478bd9Sstevel@tonic-gate static const char escstr[] = "a\ab\bf\fn\nr\r";
9947c478bd9Sstevel@tonic-gate const char *cp;
9957c478bd9Sstevel@tonic-gate
9967c478bd9Sstevel@tonic-gate keymax--; /* Account for trailing NUL byte */
9977c478bd9Sstevel@tonic-gate
9987c478bd9Sstevel@tonic-gate kwstate = '\0';
9997c478bd9Sstevel@tonic-gate kbp = keybuf;
10007c478bd9Sstevel@tonic-gate vnp = varnest;
10017c478bd9Sstevel@tonic-gate for (;;) {
10027c478bd9Sstevel@tonic-gate ichr = (*nextchr)(arg);
10037c478bd9Sstevel@tonic-gate chr = (char)ichr;
10047c478bd9Sstevel@tonic-gate tryagain:
10057c478bd9Sstevel@tonic-gate switch (kwstate) {
10067c478bd9Sstevel@tonic-gate case '\\': /* Start of unquoted escape sequence */
10077c478bd9Sstevel@tonic-gate case '|': /* Start of escape sequence in double quotes */
10087c478bd9Sstevel@tonic-gate case '~': /* Start of escape sequence in single quotes */
10097c478bd9Sstevel@tonic-gate /* Convert the character if we can. */
10107c478bd9Sstevel@tonic-gate if (chr == '\n')
10117c478bd9Sstevel@tonic-gate chr = '\0';
10127c478bd9Sstevel@tonic-gate else if (isalpha(chr) &&
10137c478bd9Sstevel@tonic-gate (cp = strchr(escstr, chr)) != NULL)
10147c478bd9Sstevel@tonic-gate chr = cp[1];
10157c478bd9Sstevel@tonic-gate /* Revert to previous state */
10167c478bd9Sstevel@tonic-gate switch (kwstate) {
10177c478bd9Sstevel@tonic-gate case '\\':
10187c478bd9Sstevel@tonic-gate kwstate = 'A';
10197c478bd9Sstevel@tonic-gate break;
10207c478bd9Sstevel@tonic-gate case '|':
10217c478bd9Sstevel@tonic-gate kwstate = '"';
10227c478bd9Sstevel@tonic-gate break;
10237c478bd9Sstevel@tonic-gate case '~':
10247c478bd9Sstevel@tonic-gate kwstate = '\'';
10257c478bd9Sstevel@tonic-gate break;
10267c478bd9Sstevel@tonic-gate }
10277c478bd9Sstevel@tonic-gate break;
10287c478bd9Sstevel@tonic-gate case '"': /* In double-quote string */
10297c478bd9Sstevel@tonic-gate if (!flag && chr == '$') {
10307c478bd9Sstevel@tonic-gate /* Handle variable expansion. */
10317c478bd9Sstevel@tonic-gate kwstate = '%';
10327c478bd9Sstevel@tonic-gate chr = '\0';
10337c478bd9Sstevel@tonic-gate break;
10347c478bd9Sstevel@tonic-gate }
10357c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
10367c478bd9Sstevel@tonic-gate case '\'': /* In single-quote string */
10377c478bd9Sstevel@tonic-gate if (chr == '\\') {
10387c478bd9Sstevel@tonic-gate /* Handle start of escape sequence */
10397c478bd9Sstevel@tonic-gate kwstate = kwstate == '"' ? '|' : '~';
10407c478bd9Sstevel@tonic-gate chr = '\0';
10417c478bd9Sstevel@tonic-gate break;
10427c478bd9Sstevel@tonic-gate }
10437c478bd9Sstevel@tonic-gate if (chr == kwstate) {
10447c478bd9Sstevel@tonic-gate /* End of quoted string; revert to normal */
10457c478bd9Sstevel@tonic-gate kwstate = 'A';
10467c478bd9Sstevel@tonic-gate chr = '\0';
10477c478bd9Sstevel@tonic-gate }
10487c478bd9Sstevel@tonic-gate break;
10497c478bd9Sstevel@tonic-gate case '$': /* Start of unquoted variable name */
10507c478bd9Sstevel@tonic-gate case '%': /* Start of variable name in quoted string */
10517c478bd9Sstevel@tonic-gate if (chr == '{') {
10527c478bd9Sstevel@tonic-gate /* Variable name is bracketed. */
10537c478bd9Sstevel@tonic-gate kwstate = chr =
10547c478bd9Sstevel@tonic-gate kwstate == '$' ? '{' : '[';
10557c478bd9Sstevel@tonic-gate break;
10567c478bd9Sstevel@tonic-gate }
10577c478bd9Sstevel@tonic-gate *kbp++ = kwstate = kwstate == '$' ? '+' : '*';
10587c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
10597c478bd9Sstevel@tonic-gate case '+': /* Gathering unquoted variable name */
10607c478bd9Sstevel@tonic-gate case '*': /* Gathering variable name in quoted string */
10617c478bd9Sstevel@tonic-gate if (chr == '$' &&
10627c478bd9Sstevel@tonic-gate vnp < varnest + sizeof (varnest)) {
10637c478bd9Sstevel@tonic-gate *vnp++ = kwstate;
10647c478bd9Sstevel@tonic-gate kwstate = '$';
10657c478bd9Sstevel@tonic-gate chr = '\0';
10667c478bd9Sstevel@tonic-gate break;
10677c478bd9Sstevel@tonic-gate }
10687c478bd9Sstevel@tonic-gate if (!isalnum(chr) && chr != '_' &&
10697c478bd9Sstevel@tonic-gate chr != '.' && chr != '-') {
10707c478bd9Sstevel@tonic-gate *kbp = '\0';
10717c478bd9Sstevel@tonic-gate kbp = env_replace(psp, keybuf, kwstate);
10727c478bd9Sstevel@tonic-gate if (vnp > varnest)
10737c478bd9Sstevel@tonic-gate kwstate = *--vnp;
10747c478bd9Sstevel@tonic-gate else
10757c478bd9Sstevel@tonic-gate kwstate = kwstate == '+' ?
10767c478bd9Sstevel@tonic-gate 'A' : '"';
10777c478bd9Sstevel@tonic-gate /* Go reinterpret in new context */
10787c478bd9Sstevel@tonic-gate goto tryagain;
10797c478bd9Sstevel@tonic-gate }
10807c478bd9Sstevel@tonic-gate break;
10817c478bd9Sstevel@tonic-gate case '{': /* Gathering bracketed, unquoted var name */
10827c478bd9Sstevel@tonic-gate case '[': /* Gathering bracketed, quoted var name */
10837c478bd9Sstevel@tonic-gate if (chr == '}') {
10847c478bd9Sstevel@tonic-gate *kbp = '\0';
10857c478bd9Sstevel@tonic-gate kbp = env_replace(psp, keybuf, kwstate);
10867c478bd9Sstevel@tonic-gate kwstate = kwstate == '{' ? 'A' : '"';
10877c478bd9Sstevel@tonic-gate chr = '\0';
10887c478bd9Sstevel@tonic-gate }
10897c478bd9Sstevel@tonic-gate break;
10907c478bd9Sstevel@tonic-gate case '#': /* Comment before word state */
10917c478bd9Sstevel@tonic-gate case '@': /* Comment after word state */
10927c478bd9Sstevel@tonic-gate if (chr == '\n' || chr == '\r' || ichr == EOF) {
10937c478bd9Sstevel@tonic-gate /* At end of line, revert to previous state */
10947c478bd9Sstevel@tonic-gate kwstate = kwstate == '#' ? '\0' : ' ';
10957c478bd9Sstevel@tonic-gate chr = '\0';
10967c478bd9Sstevel@tonic-gate break;
10977c478bd9Sstevel@tonic-gate }
10987c478bd9Sstevel@tonic-gate chr = '\0';
10997c478bd9Sstevel@tonic-gate break;
11007c478bd9Sstevel@tonic-gate case '\0': /* Initial state; no word seen yet. */
11017c478bd9Sstevel@tonic-gate if (ichr == EOF || isspace(chr)) {
11027c478bd9Sstevel@tonic-gate chr = '\0'; /* Skip over leading spaces */
11037c478bd9Sstevel@tonic-gate break;
11047c478bd9Sstevel@tonic-gate }
11057c478bd9Sstevel@tonic-gate if (chr == '#') {
11067c478bd9Sstevel@tonic-gate kwstate = '#';
11077c478bd9Sstevel@tonic-gate chr = '\0'; /* Skip over comments */
11087c478bd9Sstevel@tonic-gate break;
11097c478bd9Sstevel@tonic-gate }
11107c478bd9Sstevel@tonic-gate /* Start of keyword seen. */
11117c478bd9Sstevel@tonic-gate kwstate = 'A';
11127c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
11137c478bd9Sstevel@tonic-gate default: /* Middle of keyword parsing. */
11147c478bd9Sstevel@tonic-gate if (ichr == EOF)
11157c478bd9Sstevel@tonic-gate break;
11167c478bd9Sstevel@tonic-gate if (isspace(chr)) { /* Space terminates word */
11177c478bd9Sstevel@tonic-gate kwstate = ' ';
11187c478bd9Sstevel@tonic-gate break;
11197c478bd9Sstevel@tonic-gate }
11207c478bd9Sstevel@tonic-gate if (chr == '"' || chr == '\'' || chr == '\\') {
11217c478bd9Sstevel@tonic-gate kwstate = chr; /* Begin quote or escape */
11227c478bd9Sstevel@tonic-gate chr = '\0';
11237c478bd9Sstevel@tonic-gate break;
11247c478bd9Sstevel@tonic-gate }
11257c478bd9Sstevel@tonic-gate if (flag) /* Allow ignore; for string reparse */
11267c478bd9Sstevel@tonic-gate break;
11277c478bd9Sstevel@tonic-gate if (chr == '#') { /* Comment terminates word */
11287c478bd9Sstevel@tonic-gate kwstate = '@'; /* Must consume comment also */
11297c478bd9Sstevel@tonic-gate chr = '\0';
11307c478bd9Sstevel@tonic-gate break;
11317c478bd9Sstevel@tonic-gate }
11327c478bd9Sstevel@tonic-gate if (chr == '$') {
11337c478bd9Sstevel@tonic-gate kwstate = '$'; /* Begin variable expansion */
11347c478bd9Sstevel@tonic-gate chr = '\0';
11357c478bd9Sstevel@tonic-gate }
11367c478bd9Sstevel@tonic-gate break;
11377c478bd9Sstevel@tonic-gate }
11387c478bd9Sstevel@tonic-gate /*
11397c478bd9Sstevel@tonic-gate * If we've reached a space at the end of the word,
11407c478bd9Sstevel@tonic-gate * then we're done.
11417c478bd9Sstevel@tonic-gate */
11427c478bd9Sstevel@tonic-gate if (ichr == EOF || kwstate == ' ')
11437c478bd9Sstevel@tonic-gate break;
11447c478bd9Sstevel@tonic-gate /*
11457c478bd9Sstevel@tonic-gate * If there's a character to store and space
11467c478bd9Sstevel@tonic-gate * available, then add it to the string
11477c478bd9Sstevel@tonic-gate */
11487c478bd9Sstevel@tonic-gate if (chr != '\0' && kbp < keybuf + keymax)
11497c478bd9Sstevel@tonic-gate *kbp++ = (char)chr;
11507c478bd9Sstevel@tonic-gate }
11517c478bd9Sstevel@tonic-gate
11527c478bd9Sstevel@tonic-gate *kbp = '\0';
11537c478bd9Sstevel@tonic-gate
11547c478bd9Sstevel@tonic-gate if (ichr == EOF) {
11557c478bd9Sstevel@tonic-gate return (kwstate == '\0' ? 1 : 2);
11567c478bd9Sstevel@tonic-gate }
11577c478bd9Sstevel@tonic-gate return (0);
11587c478bd9Sstevel@tonic-gate }
11597c478bd9Sstevel@tonic-gate
11607c478bd9Sstevel@tonic-gate /*
11617c478bd9Sstevel@tonic-gate * Fetch words from current file until all files are closed. Handles
11627c478bd9Sstevel@tonic-gate * include files.
11637c478bd9Sstevel@tonic-gate */
11647c478bd9Sstevel@tonic-gate static void
parse_from_file(struct parse_state * psp)11657c478bd9Sstevel@tonic-gate parse_from_file(struct parse_state *psp)
11667c478bd9Sstevel@tonic-gate {
11677c478bd9Sstevel@tonic-gate char keybuf[MAX_KEYWORD];
11687c478bd9Sstevel@tonic-gate int retv;
11697c478bd9Sstevel@tonic-gate
11707c478bd9Sstevel@tonic-gate while (psp->ps_cfile != NULL && psp->ps_cfile->pf_input != NULL) {
11717c478bd9Sstevel@tonic-gate retv = getkeyword(psp, keybuf, sizeof (keybuf),
11727c478bd9Sstevel@tonic-gate (int (*)(void *))fgetc, (void *)psp->ps_cfile->pf_input,
11737c478bd9Sstevel@tonic-gate 0);
11747c478bd9Sstevel@tonic-gate
11757c478bd9Sstevel@tonic-gate if (retv != 1)
11767c478bd9Sstevel@tonic-gate (void) dispatch_keyword(psp, keybuf);
11777c478bd9Sstevel@tonic-gate
11787c478bd9Sstevel@tonic-gate if (retv != 0)
11797c478bd9Sstevel@tonic-gate file_end(psp);
11807c478bd9Sstevel@tonic-gate }
11817c478bd9Sstevel@tonic-gate }
11827c478bd9Sstevel@tonic-gate
11837c478bd9Sstevel@tonic-gate /*
11847c478bd9Sstevel@tonic-gate * Open and parse named file. This is for the predefined
11857c478bd9Sstevel@tonic-gate * configuration files in /etc/ppp -- it's not an error if any of
11867c478bd9Sstevel@tonic-gate * these are missing.
11877c478bd9Sstevel@tonic-gate */
11887c478bd9Sstevel@tonic-gate static void
parse_file(struct parse_state * psp,const char * fname)11897c478bd9Sstevel@tonic-gate parse_file(struct parse_state *psp, const char *fname)
11907c478bd9Sstevel@tonic-gate {
11917c478bd9Sstevel@tonic-gate struct stat sb;
11927c478bd9Sstevel@tonic-gate
11937c478bd9Sstevel@tonic-gate /* It's ok if any of these files are missing. */
11947c478bd9Sstevel@tonic-gate if (stat(fname, &sb) == -1 && errno == ENOENT)
11957c478bd9Sstevel@tonic-gate return;
11967c478bd9Sstevel@tonic-gate if (set_file(psp->ps_csvc, fname) == 0)
11977c478bd9Sstevel@tonic-gate parse_from_file(psp);
11987c478bd9Sstevel@tonic-gate }
11997c478bd9Sstevel@tonic-gate
12007c478bd9Sstevel@tonic-gate /*
12017c478bd9Sstevel@tonic-gate * Dispatch keywords from command line. Handles any files included
12027c478bd9Sstevel@tonic-gate * from there.
12037c478bd9Sstevel@tonic-gate */
12047c478bd9Sstevel@tonic-gate static void
parse_arg_list(struct parse_state * psp,int argc,char ** argv)12057c478bd9Sstevel@tonic-gate parse_arg_list(struct parse_state *psp, int argc, char **argv)
12067c478bd9Sstevel@tonic-gate {
12077c478bd9Sstevel@tonic-gate /* The first argument (program name) can be null. */
12087c478bd9Sstevel@tonic-gate if (--argc <= 0)
12097c478bd9Sstevel@tonic-gate return;
12107c478bd9Sstevel@tonic-gate while (--argc >= 0) {
12117c478bd9Sstevel@tonic-gate (void) dispatch_keyword(psp, *++argv);
12127c478bd9Sstevel@tonic-gate if (psp->ps_cfile->pf_input != NULL)
12137c478bd9Sstevel@tonic-gate parse_from_file(psp);
12147c478bd9Sstevel@tonic-gate }
12157c478bd9Sstevel@tonic-gate }
12167c478bd9Sstevel@tonic-gate
12177c478bd9Sstevel@tonic-gate /* Count length of dynamic device list */
12187c478bd9Sstevel@tonic-gate static int
count_devs(struct device_list * dlp)12197c478bd9Sstevel@tonic-gate count_devs(struct device_list *dlp)
12207c478bd9Sstevel@tonic-gate {
12217c478bd9Sstevel@tonic-gate int ndevs;
12227c478bd9Sstevel@tonic-gate
12237c478bd9Sstevel@tonic-gate ndevs = 0;
12247c478bd9Sstevel@tonic-gate for (; dlp != NULL; dlp = dlp->dl_next)
12257c478bd9Sstevel@tonic-gate ndevs++;
12267c478bd9Sstevel@tonic-gate return (ndevs);
12277c478bd9Sstevel@tonic-gate }
12287c478bd9Sstevel@tonic-gate
12297c478bd9Sstevel@tonic-gate /* Count number of devices named in entire file. */
12307c478bd9Sstevel@tonic-gate static int
count_per_file(struct per_file * pfp)12317c478bd9Sstevel@tonic-gate count_per_file(struct per_file *pfp)
12327c478bd9Sstevel@tonic-gate {
12337c478bd9Sstevel@tonic-gate struct service_list *slp;
12347c478bd9Sstevel@tonic-gate int ndevs = 0;
12357c478bd9Sstevel@tonic-gate
12367c478bd9Sstevel@tonic-gate for (; pfp != NULL; pfp = pfp->pf_prev) {
12377c478bd9Sstevel@tonic-gate ndevs += count_devs(pfp->pf_global.sl_dev);
12387c478bd9Sstevel@tonic-gate for (slp = pfp->pf_svc; slp != NULL; slp = slp->sl_next)
12397c478bd9Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CDEV))
12407c478bd9Sstevel@tonic-gate ndevs += count_devs(slp->sl_dev);
12417c478bd9Sstevel@tonic-gate }
12427c478bd9Sstevel@tonic-gate return (ndevs);
12437c478bd9Sstevel@tonic-gate }
12447c478bd9Sstevel@tonic-gate
12457c478bd9Sstevel@tonic-gate /* Write device names into linear array. */
12467c478bd9Sstevel@tonic-gate static const char **
devs_to_list(struct device_list * dlp,const char ** dnames)12477c478bd9Sstevel@tonic-gate devs_to_list(struct device_list *dlp, const char **dnames)
12487c478bd9Sstevel@tonic-gate {
12497c478bd9Sstevel@tonic-gate for (; dlp != NULL; dlp = dlp->dl_next)
12507c478bd9Sstevel@tonic-gate *dnames++ = dlp->dl_name;
12517c478bd9Sstevel@tonic-gate return (dnames);
12527c478bd9Sstevel@tonic-gate }
12537c478bd9Sstevel@tonic-gate
12547c478bd9Sstevel@tonic-gate /* Write all device names from file into a linear array. */
12557c478bd9Sstevel@tonic-gate static const char **
per_file_to_list(struct per_file * pfp,const char ** dnames)12567c478bd9Sstevel@tonic-gate per_file_to_list(struct per_file *pfp, const char **dnames)
12577c478bd9Sstevel@tonic-gate {
12587c478bd9Sstevel@tonic-gate struct service_list *slp;
12597c478bd9Sstevel@tonic-gate
12607c478bd9Sstevel@tonic-gate for (; pfp != NULL; pfp = pfp->pf_prev) {
12617c478bd9Sstevel@tonic-gate dnames = devs_to_list(pfp->pf_global.sl_dev, dnames);
12627c478bd9Sstevel@tonic-gate for (slp = pfp->pf_svc; slp != NULL; slp = slp->sl_next)
12637c478bd9Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CDEV))
12647c478bd9Sstevel@tonic-gate dnames = devs_to_list(slp->sl_dev, dnames);
12657c478bd9Sstevel@tonic-gate }
12667c478bd9Sstevel@tonic-gate return (dnames);
12677c478bd9Sstevel@tonic-gate }
12687c478bd9Sstevel@tonic-gate
12697c478bd9Sstevel@tonic-gate /* Compare device names; used with qsort */
12707c478bd9Sstevel@tonic-gate static int
devcmp(const void * d1,const void * d2)12717c478bd9Sstevel@tonic-gate devcmp(const void *d1, const void *d2)
12727c478bd9Sstevel@tonic-gate {
12737c478bd9Sstevel@tonic-gate return (strcmp(*(const char **)d1, *(const char **)d2));
12747c478bd9Sstevel@tonic-gate }
12757c478bd9Sstevel@tonic-gate
12767c478bd9Sstevel@tonic-gate /*
12777c478bd9Sstevel@tonic-gate * Get sorted list of unique device names among all defined and
12787c478bd9Sstevel@tonic-gate * partially defined services in all files.
12797c478bd9Sstevel@tonic-gate */
12807c478bd9Sstevel@tonic-gate static const char **
get_unique_devs(struct parse_state * psp)12817c478bd9Sstevel@tonic-gate get_unique_devs(struct parse_state *psp)
12827c478bd9Sstevel@tonic-gate {
12837c478bd9Sstevel@tonic-gate int ndevs;
12847c478bd9Sstevel@tonic-gate const char **dnames;
12857c478bd9Sstevel@tonic-gate const char **dnp;
12867c478bd9Sstevel@tonic-gate const char **dnf;
12877c478bd9Sstevel@tonic-gate
12887c478bd9Sstevel@tonic-gate /*
12897c478bd9Sstevel@tonic-gate * Count number of explicitly referenced devices among all
12907c478bd9Sstevel@tonic-gate * services (including duplicates).
12917c478bd9Sstevel@tonic-gate */
12927c478bd9Sstevel@tonic-gate ndevs = count_per_file(psp->ps_files);
12937c478bd9Sstevel@tonic-gate ndevs += count_per_file(psp->ps_cfile);
12947c478bd9Sstevel@tonic-gate if (ndevs <= 0) {
12957c478bd9Sstevel@tonic-gate return (NULL);
12967c478bd9Sstevel@tonic-gate }
12977c478bd9Sstevel@tonic-gate
12987c478bd9Sstevel@tonic-gate /* Sort and trim out duplicate devices. */
12997c478bd9Sstevel@tonic-gate dnames = (const char **)malloc((ndevs+1) * sizeof (const char *));
13007c478bd9Sstevel@tonic-gate if (dnames == NULL) {
13017c478bd9Sstevel@tonic-gate logerr("unable to allocate space for %d devices", ndevs + 1);
13027c478bd9Sstevel@tonic-gate return (NULL);
13037c478bd9Sstevel@tonic-gate }
13047c478bd9Sstevel@tonic-gate dnp = per_file_to_list(psp->ps_files, dnames);
13057c478bd9Sstevel@tonic-gate (void) per_file_to_list(psp->ps_cfile, dnp);
13067c478bd9Sstevel@tonic-gate qsort(dnames, ndevs, sizeof (const char *), devcmp);
13077c478bd9Sstevel@tonic-gate for (dnf = (dnp = dnames) + 1; dnf < dnames+ndevs; dnf++)
13087c478bd9Sstevel@tonic-gate if (strcmp(*dnf, *dnp) != 0)
13097c478bd9Sstevel@tonic-gate *++dnp = *dnf;
13107c478bd9Sstevel@tonic-gate *++dnp = NULL;
13117c478bd9Sstevel@tonic-gate
13127c478bd9Sstevel@tonic-gate /* Return array of pointers to names. */
13137c478bd9Sstevel@tonic-gate return (dnames);
13147c478bd9Sstevel@tonic-gate }
13157c478bd9Sstevel@tonic-gate
13167c478bd9Sstevel@tonic-gate /*
13177c478bd9Sstevel@tonic-gate * Convert data structures created by parsing process into data
13187c478bd9Sstevel@tonic-gate * structures used by service dispatch. This gathers the unique
13197c478bd9Sstevel@tonic-gate * device (lower stream) names and attaches the services available on
13207c478bd9Sstevel@tonic-gate * each device to a list while triming duplicate services.
13217c478bd9Sstevel@tonic-gate */
13227c478bd9Sstevel@tonic-gate static struct option_state *
organize_state(struct parse_state * psp)13237c478bd9Sstevel@tonic-gate organize_state(struct parse_state *psp)
13247c478bd9Sstevel@tonic-gate {
13257c478bd9Sstevel@tonic-gate struct per_file *pfp;
13267c478bd9Sstevel@tonic-gate struct per_file *pftopp;
13277c478bd9Sstevel@tonic-gate struct service_list *slp;
13287c478bd9Sstevel@tonic-gate struct device_list *dlp;
13297c478bd9Sstevel@tonic-gate int ndevs;
13307c478bd9Sstevel@tonic-gate int nsvcs;
13317c478bd9Sstevel@tonic-gate const char **dnames;
13327c478bd9Sstevel@tonic-gate const char **dnp;
13337c478bd9Sstevel@tonic-gate struct device_entry *dep;
13347c478bd9Sstevel@tonic-gate struct option_state *osp;
13357c478bd9Sstevel@tonic-gate struct service_entry **sepp;
13367c478bd9Sstevel@tonic-gate struct service_entry **sebpp;
13377c478bd9Sstevel@tonic-gate struct service_entry **se2pp;
13387c478bd9Sstevel@tonic-gate
13397c478bd9Sstevel@tonic-gate /*
13407c478bd9Sstevel@tonic-gate * Parsing is now done.
13417c478bd9Sstevel@tonic-gate */
13427c478bd9Sstevel@tonic-gate close_service(psp->ps_csvc);
13437c478bd9Sstevel@tonic-gate psp->ps_csvc = NULL;
13447c478bd9Sstevel@tonic-gate if ((pfp = psp->ps_cfile) != NULL) {
13457c478bd9Sstevel@tonic-gate pfp->pf_prev = psp->ps_files;
13467c478bd9Sstevel@tonic-gate psp->ps_files = pfp;
13477c478bd9Sstevel@tonic-gate psp->ps_cfile = NULL;
13487c478bd9Sstevel@tonic-gate }
13497c478bd9Sstevel@tonic-gate
13507c478bd9Sstevel@tonic-gate /* Link the services from all files together for easy referencing. */
13517c478bd9Sstevel@tonic-gate pftopp = psp->ps_files;
13527c478bd9Sstevel@tonic-gate for (pfp = pftopp->pf_prev; pfp != NULL; pfp = pfp->pf_prev)
13537c478bd9Sstevel@tonic-gate if (pfp->pf_svc != NULL) {
13547c478bd9Sstevel@tonic-gate if (pftopp->pf_svc_last == NULL)
13557c478bd9Sstevel@tonic-gate pftopp->pf_svc = pfp->pf_svc;
13567c478bd9Sstevel@tonic-gate else
13577c478bd9Sstevel@tonic-gate pftopp->pf_svc_last->sl_next = pfp->pf_svc;
13587c478bd9Sstevel@tonic-gate pftopp->pf_svc_last = pfp->pf_svc_last;
13597c478bd9Sstevel@tonic-gate pfp->pf_svc = pfp->pf_svc_last = NULL;
13607c478bd9Sstevel@tonic-gate }
13617c478bd9Sstevel@tonic-gate
13627c478bd9Sstevel@tonic-gate /*
13637c478bd9Sstevel@tonic-gate * Count up number of services per device, including
13647c478bd9Sstevel@tonic-gate * duplicates but not including defaults.
13657c478bd9Sstevel@tonic-gate */
13667c478bd9Sstevel@tonic-gate nsvcs = 0;
13677c478bd9Sstevel@tonic-gate for (slp = psp->ps_files->pf_svc; slp != NULL; slp = slp->sl_next)
13687c478bd9Sstevel@tonic-gate for (dlp = slp->sl_dev; dlp != NULL; dlp = dlp->dl_next)
13697c478bd9Sstevel@tonic-gate nsvcs++;
13707c478bd9Sstevel@tonic-gate
13717c478bd9Sstevel@tonic-gate /*
13727c478bd9Sstevel@tonic-gate * Get the unique devices referenced by all services.
13737c478bd9Sstevel@tonic-gate */
13747c478bd9Sstevel@tonic-gate dnames = get_unique_devs(psp);
13757c478bd9Sstevel@tonic-gate if (dnames == NULL) {
13767c478bd9Sstevel@tonic-gate logdbg("no devices referenced by any service");
13777c478bd9Sstevel@tonic-gate return (NULL);
13787c478bd9Sstevel@tonic-gate }
13797c478bd9Sstevel@tonic-gate ndevs = 0;
13807c478bd9Sstevel@tonic-gate for (dnp = dnames; *dnp != NULL; dnp++)
13817c478bd9Sstevel@tonic-gate ndevs++;
13827c478bd9Sstevel@tonic-gate
13837c478bd9Sstevel@tonic-gate /*
13847c478bd9Sstevel@tonic-gate * Allocate room for main structure, device records, and
13857c478bd9Sstevel@tonic-gate * per-device lists. Worst case is all devices having all
13867c478bd9Sstevel@tonic-gate * services; that's why we allocate for nsvcs * ndevs.
13877c478bd9Sstevel@tonic-gate */
13887c478bd9Sstevel@tonic-gate osp = (struct option_state *)malloc(sizeof (*osp) +
13897c478bd9Sstevel@tonic-gate ndevs * sizeof (*dep) + nsvcs * ndevs * sizeof (*sepp));
13907c478bd9Sstevel@tonic-gate if (osp == NULL) {
13917c478bd9Sstevel@tonic-gate logerr("unable to allocate option state structure");
13927c478bd9Sstevel@tonic-gate free(dnames);
13937c478bd9Sstevel@tonic-gate return (NULL);
13947c478bd9Sstevel@tonic-gate }
13957c478bd9Sstevel@tonic-gate
13967c478bd9Sstevel@tonic-gate /* We're going to succeed now, so steal these over. */
13977c478bd9Sstevel@tonic-gate osp->os_devices = dep = (struct device_entry *)(osp+1);
13987c478bd9Sstevel@tonic-gate osp->os_pfjunk = psp->ps_files;
13997c478bd9Sstevel@tonic-gate psp->ps_files = NULL;
14007c478bd9Sstevel@tonic-gate osp->os_evjunk = psp->ps_evlist;
14017c478bd9Sstevel@tonic-gate psp->ps_evlist = NULL;
14027c478bd9Sstevel@tonic-gate
14037c478bd9Sstevel@tonic-gate /* Loop over devices, install services, remove duplicates. */
14047c478bd9Sstevel@tonic-gate sepp = (struct service_entry **)(dep + ndevs);
14057c478bd9Sstevel@tonic-gate for (dnp = dnames; *dnp != NULL; dnp++) {
14067c478bd9Sstevel@tonic-gate dep->de_name = *dnp;
14077c478bd9Sstevel@tonic-gate dep->de_services = (const struct service_entry **)sepp;
14087c478bd9Sstevel@tonic-gate sebpp = sepp;
14097c478bd9Sstevel@tonic-gate for (slp = osp->os_pfjunk->pf_svc; slp != NULL;
14107c478bd9Sstevel@tonic-gate slp = slp->sl_next)
14117c478bd9Sstevel@tonic-gate for (dlp = slp->sl_dev; dlp != NULL;
14127c478bd9Sstevel@tonic-gate dlp = dlp->dl_next) {
14137c478bd9Sstevel@tonic-gate if (dlp->dl_name == *dnp ||
14147c478bd9Sstevel@tonic-gate strcmp(dlp->dl_name, *dnp) == 0) {
14157c478bd9Sstevel@tonic-gate for (se2pp = sebpp; se2pp < sepp;
14167c478bd9Sstevel@tonic-gate se2pp++)
14177c478bd9Sstevel@tonic-gate if ((*se2pp)->se_name ==
14187c478bd9Sstevel@tonic-gate slp->sl_entry.se_name ||
14197c478bd9Sstevel@tonic-gate strcmp((*se2pp)->
1420*f53eecf5SJames Carlson se_name, slp->sl_entry.
14217c478bd9Sstevel@tonic-gate se_name) == 0)
14227c478bd9Sstevel@tonic-gate break;
14237c478bd9Sstevel@tonic-gate /*
14247c478bd9Sstevel@tonic-gate * We retain a service if it's
14257c478bd9Sstevel@tonic-gate * unique or if its serial
14267c478bd9Sstevel@tonic-gate * number (position in the
14277c478bd9Sstevel@tonic-gate * file) is greater than than
14287c478bd9Sstevel@tonic-gate * any other.
14297c478bd9Sstevel@tonic-gate */
14307c478bd9Sstevel@tonic-gate if (se2pp >= sepp)
14317c478bd9Sstevel@tonic-gate *sepp++ = &slp->sl_entry;
14327c478bd9Sstevel@tonic-gate else if (SESERIAL(**se2pp) <
14337c478bd9Sstevel@tonic-gate SESERIAL(slp->sl_entry))
14347c478bd9Sstevel@tonic-gate *se2pp = &slp->sl_entry;
14357c478bd9Sstevel@tonic-gate }
14367c478bd9Sstevel@tonic-gate }
14377c478bd9Sstevel@tonic-gate /* Count up the services on this device. */
14387c478bd9Sstevel@tonic-gate dep->de_nservices = (const struct service_entry **)sepp -
14397c478bd9Sstevel@tonic-gate dep->de_services;
14407c478bd9Sstevel@tonic-gate /* Ignore devices having no services at all. */
14417c478bd9Sstevel@tonic-gate if (dep->de_nservices > 0)
14427c478bd9Sstevel@tonic-gate dep++;
14437c478bd9Sstevel@tonic-gate }
14447c478bd9Sstevel@tonic-gate /* Count up the devices. */
14457c478bd9Sstevel@tonic-gate osp->os_ndevices = dep - osp->os_devices;
14467c478bd9Sstevel@tonic-gate /* Free the list of device names */
14477c478bd9Sstevel@tonic-gate free(dnames);
14487c478bd9Sstevel@tonic-gate return (osp);
14497c478bd9Sstevel@tonic-gate }
14507c478bd9Sstevel@tonic-gate
14517c478bd9Sstevel@tonic-gate /*
14527c478bd9Sstevel@tonic-gate * Free storage unique to a given service. Pointers copied from other
14537c478bd9Sstevel@tonic-gate * services are ignored.
14547c478bd9Sstevel@tonic-gate */
14557c478bd9Sstevel@tonic-gate static void
free_service(struct service_list * slp)14567c478bd9Sstevel@tonic-gate free_service(struct service_list *slp)
14577c478bd9Sstevel@tonic-gate {
14587c478bd9Sstevel@tonic-gate struct filter_entry *fep;
14597c478bd9Sstevel@tonic-gate struct filter_entry *fen;
14607c478bd9Sstevel@tonic-gate
14617c478bd9Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CDEV))
14627c478bd9Sstevel@tonic-gate free_device_list(slp->sl_dev);
14637c478bd9Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CFLIST)) {
14647c478bd9Sstevel@tonic-gate fep = slp->sl_entry.se_flist;
14657c478bd9Sstevel@tonic-gate while (fep != NULL) {
14667c478bd9Sstevel@tonic-gate fen = fep->fe_prevcopy ? NULL : fep->fe_prev;
14677c478bd9Sstevel@tonic-gate free(fep);
14687c478bd9Sstevel@tonic-gate fep = fen;
14697c478bd9Sstevel@tonic-gate }
14707c478bd9Sstevel@tonic-gate }
14717c478bd9Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CPPPD) &&
14727c478bd9Sstevel@tonic-gate slp->sl_entry.se_pppd != NULL)
14737c478bd9Sstevel@tonic-gate free(slp->sl_entry.se_pppd);
14747c478bd9Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CSERVER) &&
14757c478bd9Sstevel@tonic-gate slp->sl_entry.se_server != NULL)
14767c478bd9Sstevel@tonic-gate free(slp->sl_entry.se_server);
14777c478bd9Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CPATH) &&
14787c478bd9Sstevel@tonic-gate slp->sl_entry.se_path != NULL)
14797c478bd9Sstevel@tonic-gate free(slp->sl_entry.se_path);
14807c478bd9Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CEXTRA) &&
14817c478bd9Sstevel@tonic-gate slp->sl_entry.se_extra != NULL)
14827c478bd9Sstevel@tonic-gate free(slp->sl_entry.se_extra);
14837c478bd9Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CLOG) &&
14847c478bd9Sstevel@tonic-gate slp->sl_entry.se_log != NULL)
14857c478bd9Sstevel@tonic-gate free(slp->sl_entry.se_log);
14867c478bd9Sstevel@tonic-gate }
14877c478bd9Sstevel@tonic-gate
14887c478bd9Sstevel@tonic-gate /*
14897c478bd9Sstevel@tonic-gate * Free a linked list of services.
14907c478bd9Sstevel@tonic-gate */
14917c478bd9Sstevel@tonic-gate static void
free_service_list(struct service_list * slp)14927c478bd9Sstevel@tonic-gate free_service_list(struct service_list *slp)
14937c478bd9Sstevel@tonic-gate {
14947c478bd9Sstevel@tonic-gate struct service_list *sln;
14957c478bd9Sstevel@tonic-gate
14967c478bd9Sstevel@tonic-gate while (slp != NULL) {
14977c478bd9Sstevel@tonic-gate free_service(slp);
14987c478bd9Sstevel@tonic-gate sln = slp->sl_next;
14997c478bd9Sstevel@tonic-gate free(slp);
15007c478bd9Sstevel@tonic-gate slp = sln;
15017c478bd9Sstevel@tonic-gate }
15027c478bd9Sstevel@tonic-gate }
15037c478bd9Sstevel@tonic-gate
15047c478bd9Sstevel@tonic-gate /*
15057c478bd9Sstevel@tonic-gate * Free a linked list of files and all services in those files.
15067c478bd9Sstevel@tonic-gate */
15077c478bd9Sstevel@tonic-gate static void
free_file_list(struct per_file * pfp)15087c478bd9Sstevel@tonic-gate free_file_list(struct per_file *pfp)
15097c478bd9Sstevel@tonic-gate {
15107c478bd9Sstevel@tonic-gate struct per_file *pfn;
15117c478bd9Sstevel@tonic-gate
15127c478bd9Sstevel@tonic-gate while (pfp != NULL) {
15137c478bd9Sstevel@tonic-gate free_service(&pfp->pf_global);
15147c478bd9Sstevel@tonic-gate free_service_list(pfp->pf_svc);
15157c478bd9Sstevel@tonic-gate pfn = pfp->pf_prev;
15167c478bd9Sstevel@tonic-gate free(pfp);
15177c478bd9Sstevel@tonic-gate pfp = pfn;
15187c478bd9Sstevel@tonic-gate }
15197c478bd9Sstevel@tonic-gate }
15207c478bd9Sstevel@tonic-gate
15217c478bd9Sstevel@tonic-gate /*
15227c478bd9Sstevel@tonic-gate * Free an array of local environment variables.
15237c478bd9Sstevel@tonic-gate */
15247c478bd9Sstevel@tonic-gate static void
free_env_list(char ** evlist)15257c478bd9Sstevel@tonic-gate free_env_list(char **evlist)
15267c478bd9Sstevel@tonic-gate {
15277c478bd9Sstevel@tonic-gate char **evp;
15287c478bd9Sstevel@tonic-gate char *env;
15297c478bd9Sstevel@tonic-gate
15307c478bd9Sstevel@tonic-gate if ((evp = evlist) != NULL) {
15317c478bd9Sstevel@tonic-gate while ((env = *evp++) != NULL)
15327c478bd9Sstevel@tonic-gate free(env);
15337c478bd9Sstevel@tonic-gate free(evlist);
15347c478bd9Sstevel@tonic-gate }
15357c478bd9Sstevel@tonic-gate }
15367c478bd9Sstevel@tonic-gate
15377c478bd9Sstevel@tonic-gate /*
15387c478bd9Sstevel@tonic-gate * Add a new device (lower stream) to the list for which we're the
15397c478bd9Sstevel@tonic-gate * PPPoE server.
15407c478bd9Sstevel@tonic-gate */
15417c478bd9Sstevel@tonic-gate static void
add_new_dev(int tunfd,const char * dname)15427c478bd9Sstevel@tonic-gate add_new_dev(int tunfd, const char *dname)
15437c478bd9Sstevel@tonic-gate {
15447c478bd9Sstevel@tonic-gate union ppptun_name ptn;
15457c478bd9Sstevel@tonic-gate
15467c478bd9Sstevel@tonic-gate (void) snprintf(ptn.ptn_name, sizeof (ptn.ptn_name), "%s:pppoed",
15477c478bd9Sstevel@tonic-gate dname);
15487c478bd9Sstevel@tonic-gate if (strioctl(tunfd, PPPTUN_SCTL, &ptn, sizeof (ptn), 0) < 0) {
15497c478bd9Sstevel@tonic-gate logerr("PPPTUN_SCTL %s: %s", ptn.ptn_name, mystrerror(errno));
15507c478bd9Sstevel@tonic-gate } else {
15517c478bd9Sstevel@tonic-gate logdbg("added %s", ptn.ptn_name);
15527c478bd9Sstevel@tonic-gate }
15537c478bd9Sstevel@tonic-gate }
15547c478bd9Sstevel@tonic-gate
15557c478bd9Sstevel@tonic-gate /*
15567c478bd9Sstevel@tonic-gate * Remove an existing device (lower stream) from the list for which we
15577c478bd9Sstevel@tonic-gate * were the PPPoE server.
15587c478bd9Sstevel@tonic-gate */
15597c478bd9Sstevel@tonic-gate static void
rem_old_dev(int tunfd,const char * dname)15607c478bd9Sstevel@tonic-gate rem_old_dev(int tunfd, const char *dname)
15617c478bd9Sstevel@tonic-gate {
15627c478bd9Sstevel@tonic-gate union ppptun_name ptn;
15637c478bd9Sstevel@tonic-gate
15647c478bd9Sstevel@tonic-gate (void) snprintf(ptn.ptn_name, sizeof (ptn.ptn_name), "%s:pppoed",
15657c478bd9Sstevel@tonic-gate dname);
15667c478bd9Sstevel@tonic-gate if (strioctl(tunfd, PPPTUN_DCTL, &ptn, sizeof (ptn), 0) < 0) {
15677c478bd9Sstevel@tonic-gate logerr("PPPTUN_DCTL %s: %s", ptn.ptn_name, mystrerror(errno));
15687c478bd9Sstevel@tonic-gate } else {
15697c478bd9Sstevel@tonic-gate logdbg("removed %s", ptn.ptn_name);
15707c478bd9Sstevel@tonic-gate }
15717c478bd9Sstevel@tonic-gate }
15727c478bd9Sstevel@tonic-gate
15737c478bd9Sstevel@tonic-gate /*
15747c478bd9Sstevel@tonic-gate * Get a list of all of the devices currently plumbed for PPPoE. This
15757c478bd9Sstevel@tonic-gate * is used for supporting the "*" and "all" device aliases.
15767c478bd9Sstevel@tonic-gate */
15777c478bd9Sstevel@tonic-gate static void
get_device_list(struct parse_state * psp,int tunfd)15787c478bd9Sstevel@tonic-gate get_device_list(struct parse_state *psp, int tunfd)
15797c478bd9Sstevel@tonic-gate {
15807c478bd9Sstevel@tonic-gate struct device_list *dlp;
15817c478bd9Sstevel@tonic-gate struct device_list **dlpp;
15827c478bd9Sstevel@tonic-gate struct device_list *dlalt;
15837c478bd9Sstevel@tonic-gate struct device_list **dl2pp;
15847c478bd9Sstevel@tonic-gate struct device_list *dla;
15857c478bd9Sstevel@tonic-gate int i;
15867c478bd9Sstevel@tonic-gate union ppptun_name ptn;
15877c478bd9Sstevel@tonic-gate char *cp;
15887c478bd9Sstevel@tonic-gate
15897c478bd9Sstevel@tonic-gate /* First pass; just allocate space for all *:pppoe* devices */
15907c478bd9Sstevel@tonic-gate dlpp = &psp->ps_star;
15917c478bd9Sstevel@tonic-gate dl2pp = &dlalt;
15927c478bd9Sstevel@tonic-gate for (i = 0; ; i++) {
15937c478bd9Sstevel@tonic-gate ptn.ptn_index = i;
15947c478bd9Sstevel@tonic-gate if (strioctl(tunfd, PPPTUN_GNNAME, &ptn, sizeof (ptn),
15957c478bd9Sstevel@tonic-gate sizeof (ptn)) < 0) {
15967c478bd9Sstevel@tonic-gate logerr("PPPTUN_GNNAME %d: %s", i, mystrerror(errno));
15977c478bd9Sstevel@tonic-gate break;
15987c478bd9Sstevel@tonic-gate }
15997c478bd9Sstevel@tonic-gate if (ptn.ptn_name[0] == '\0')
16007c478bd9Sstevel@tonic-gate break;
16017c478bd9Sstevel@tonic-gate if ((cp = strchr(ptn.ptn_name, ':')) == NULL ||
16027c478bd9Sstevel@tonic-gate strncmp(cp, ":pppoe", 6) != 0 ||
16037c478bd9Sstevel@tonic-gate (cp[6] != '\0' && strcmp(cp+6, "d") != 0))
16047c478bd9Sstevel@tonic-gate continue;
16057c478bd9Sstevel@tonic-gate *cp = '\0';
16067c478bd9Sstevel@tonic-gate dlp = (struct device_list *)malloc(sizeof (*dlp) +
16077c478bd9Sstevel@tonic-gate strlen(ptn.ptn_name) + 1);
16087c478bd9Sstevel@tonic-gate if (dlp == NULL)
16097c478bd9Sstevel@tonic-gate break;
16107c478bd9Sstevel@tonic-gate dlp->dl_name = (const char *)(dlp + 1);
16117c478bd9Sstevel@tonic-gate (void) strcpy((char *)(dlp + 1), ptn.ptn_name);
16127c478bd9Sstevel@tonic-gate if (cp[6] == '\0') {
16137c478bd9Sstevel@tonic-gate *dlpp = dlp;
16147c478bd9Sstevel@tonic-gate dlpp = &dlp->dl_next;
16157c478bd9Sstevel@tonic-gate } else {
16167c478bd9Sstevel@tonic-gate *dl2pp = dlp;
16177c478bd9Sstevel@tonic-gate dl2pp = &dlp->dl_next;
16187c478bd9Sstevel@tonic-gate }
16197c478bd9Sstevel@tonic-gate }
16207c478bd9Sstevel@tonic-gate *dlpp = NULL;
16217c478bd9Sstevel@tonic-gate *dl2pp = NULL;
16227c478bd9Sstevel@tonic-gate
16237c478bd9Sstevel@tonic-gate /* Second pass; eliminate improperly plumbed devices */
16247c478bd9Sstevel@tonic-gate for (dlpp = &psp->ps_star; (dlp = *dlpp) != NULL; ) {
16257c478bd9Sstevel@tonic-gate for (dla = dlalt; dla != NULL; dla = dla->dl_next)
16267c478bd9Sstevel@tonic-gate if (strcmp(dla->dl_name, dlp->dl_name) == 0)
16277c478bd9Sstevel@tonic-gate break;
16287c478bd9Sstevel@tonic-gate if (dla == NULL) {
16297c478bd9Sstevel@tonic-gate *dlpp = dlp->dl_next;
16307c478bd9Sstevel@tonic-gate free(dlp);
16317c478bd9Sstevel@tonic-gate } else {
16327c478bd9Sstevel@tonic-gate dlpp = &dlp->dl_next;
16337c478bd9Sstevel@tonic-gate }
16347c478bd9Sstevel@tonic-gate }
16357c478bd9Sstevel@tonic-gate free_device_list(dlalt);
16367c478bd9Sstevel@tonic-gate
16377c478bd9Sstevel@tonic-gate /* Add in "*" so we can always handle dynamic plumbing. */
16387c478bd9Sstevel@tonic-gate dlp = (struct device_list *)malloc(sizeof (*dlp) + 2);
16397c478bd9Sstevel@tonic-gate if (dlp != NULL) {
16407c478bd9Sstevel@tonic-gate dlp->dl_name = (const char *)(dlp + 1);
16417c478bd9Sstevel@tonic-gate (void) strcpy((char *)(dlp + 1), "*");
16427c478bd9Sstevel@tonic-gate dlp->dl_next = psp->ps_star;
16437c478bd9Sstevel@tonic-gate psp->ps_star = dlp;
16447c478bd9Sstevel@tonic-gate }
16457c478bd9Sstevel@tonic-gate }
16467c478bd9Sstevel@tonic-gate
16477c478bd9Sstevel@tonic-gate /*
16487c478bd9Sstevel@tonic-gate * Set logging subsystem back to configured global default values.
16497c478bd9Sstevel@tonic-gate */
16507c478bd9Sstevel@tonic-gate void
global_logging(void)16517c478bd9Sstevel@tonic-gate global_logging(void)
16527c478bd9Sstevel@tonic-gate {
16537c478bd9Sstevel@tonic-gate log_for_service(glob_svc.se_log, glob_svc.se_debug);
16547c478bd9Sstevel@tonic-gate }
16557c478bd9Sstevel@tonic-gate
16567c478bd9Sstevel@tonic-gate /*
16577c478bd9Sstevel@tonic-gate * Handle SIGHUP -- reparse command line and all configuration files.
16587c478bd9Sstevel@tonic-gate * When reparsing is complete, free old parsed data and replace with
16597c478bd9Sstevel@tonic-gate * new.
16607c478bd9Sstevel@tonic-gate */
16617c478bd9Sstevel@tonic-gate void
parse_options(int tunfd,int argc,char ** argv)16627c478bd9Sstevel@tonic-gate parse_options(int tunfd, int argc, char **argv)
16637c478bd9Sstevel@tonic-gate {
16647c478bd9Sstevel@tonic-gate struct parse_state pstate;
16657c478bd9Sstevel@tonic-gate struct per_file *argpf;
16667c478bd9Sstevel@tonic-gate struct option_state *newopt;
16677c478bd9Sstevel@tonic-gate const char **dnames;
16687c478bd9Sstevel@tonic-gate const char **dnp;
16697c478bd9Sstevel@tonic-gate const struct device_entry *newdep, *newmax;
16707c478bd9Sstevel@tonic-gate const struct device_entry *olddep, *oldmax;
16717c478bd9Sstevel@tonic-gate int cmpval;
16727c478bd9Sstevel@tonic-gate struct service_entry newglobsvc, *mainsvc;
16737c478bd9Sstevel@tonic-gate
16747c478bd9Sstevel@tonic-gate /* Note that all per_file structures must be freeable */
16757c478bd9Sstevel@tonic-gate argpf = (struct per_file *)calloc(sizeof (*argpf), 1);
16767c478bd9Sstevel@tonic-gate if (argpf == NULL) {
16777c478bd9Sstevel@tonic-gate return;
16787c478bd9Sstevel@tonic-gate }
16797c478bd9Sstevel@tonic-gate (void) memset(&pstate, '\0', sizeof (pstate));
16807c478bd9Sstevel@tonic-gate pstate.ps_state = ksDefault;
16817c478bd9Sstevel@tonic-gate pstate.ps_cfile = argpf;
16827c478bd9Sstevel@tonic-gate pstate.ps_csvc = &argpf->pf_global;
16837c478bd9Sstevel@tonic-gate argpf->pf_global.sl_parse = &pstate;
16847c478bd9Sstevel@tonic-gate argpf->pf_name = "command line";
16857c478bd9Sstevel@tonic-gate
16867c478bd9Sstevel@tonic-gate /* Default is 1 -- errors only */
16877c478bd9Sstevel@tonic-gate argpf->pf_global.sl_entry.se_debug++;
16887c478bd9Sstevel@tonic-gate argpf->pf_global.sl_entry.se_name = "<global>";
16897c478bd9Sstevel@tonic-gate
16907c478bd9Sstevel@tonic-gate /* Get list of all devices */
16917c478bd9Sstevel@tonic-gate get_device_list(&pstate, tunfd);
16927c478bd9Sstevel@tonic-gate
16937c478bd9Sstevel@tonic-gate /* Parse options from command line and main configuration file. */
16947c478bd9Sstevel@tonic-gate pstate.ps_flags |= PSF_SETLEVEL;
16957c478bd9Sstevel@tonic-gate parse_arg_list(&pstate, argc, argv);
16967c478bd9Sstevel@tonic-gate parse_file(&pstate, "/etc/ppp/pppoe");
16977c478bd9Sstevel@tonic-gate pstate.ps_flags &= ~PSF_SETLEVEL;
16987c478bd9Sstevel@tonic-gate
16997c478bd9Sstevel@tonic-gate /*
17007c478bd9Sstevel@tonic-gate * At this point, global options from the main configuration
17017c478bd9Sstevel@tonic-gate * file are pointed to by ps_files, and options from command
17027c478bd9Sstevel@tonic-gate * line are in argpf. We need to pull three special options
17037c478bd9Sstevel@tonic-gate * from these -- wildcard, debug, and log. Note that the main
17047c478bd9Sstevel@tonic-gate * options file overrides the command line. This is
17057c478bd9Sstevel@tonic-gate * intentional. The semantics are such that the system
17067c478bd9Sstevel@tonic-gate * behaves as though the main configuration file were
17077c478bd9Sstevel@tonic-gate * "included" from the command line, and thus options there
17087c478bd9Sstevel@tonic-gate * override the command line. This may seem odd, but at least
17097c478bd9Sstevel@tonic-gate * it's self-consistent.
17107c478bd9Sstevel@tonic-gate */
17117c478bd9Sstevel@tonic-gate newglobsvc = argpf->pf_global.sl_entry;
17127c478bd9Sstevel@tonic-gate if (pstate.ps_files != NULL) {
17137c478bd9Sstevel@tonic-gate mainsvc = &pstate.ps_files->pf_global.sl_entry;
17147c478bd9Sstevel@tonic-gate if (mainsvc->se_log != NULL)
17157c478bd9Sstevel@tonic-gate newglobsvc.se_log = mainsvc->se_log;
17167c478bd9Sstevel@tonic-gate if (mainsvc->se_flags & (SEF_WILD|SEF_NOWILD))
17177c478bd9Sstevel@tonic-gate newglobsvc.se_flags =
17187c478bd9Sstevel@tonic-gate (newglobsvc.se_flags & ~(SEF_WILD|SEF_NOWILD)) |
17197c478bd9Sstevel@tonic-gate (mainsvc->se_flags & (SEF_WILD|SEF_NOWILD));
17207c478bd9Sstevel@tonic-gate if (mainsvc->se_flags & SEF_DEBUGCLR)
17217c478bd9Sstevel@tonic-gate newglobsvc.se_debug = 0;
17227c478bd9Sstevel@tonic-gate newglobsvc.se_debug += mainsvc->se_debug;
17237c478bd9Sstevel@tonic-gate }
17247c478bd9Sstevel@tonic-gate glob_svc = newglobsvc;
17257c478bd9Sstevel@tonic-gate global_logging();
17267c478bd9Sstevel@tonic-gate
17277c478bd9Sstevel@tonic-gate /* Get the list of devices referenced by configuration above. */
17287c478bd9Sstevel@tonic-gate dnames = get_unique_devs(&pstate);
17297c478bd9Sstevel@tonic-gate if (dnames != NULL) {
17307c478bd9Sstevel@tonic-gate /* Read per-device configuration files. */
17317c478bd9Sstevel@tonic-gate pstate.ps_flags |= PSF_PERDEV;
17327c478bd9Sstevel@tonic-gate for (dnp = dnames; *dnp != NULL; dnp++)
17337c478bd9Sstevel@tonic-gate parse_file(&pstate, *dnp);
17347c478bd9Sstevel@tonic-gate pstate.ps_flags &= ~PSF_PERDEV;
17357c478bd9Sstevel@tonic-gate free(dnames);
17367c478bd9Sstevel@tonic-gate }
17377c478bd9Sstevel@tonic-gate file_end(&pstate);
17387c478bd9Sstevel@tonic-gate
17397c478bd9Sstevel@tonic-gate /*
17407c478bd9Sstevel@tonic-gate * Convert parsed data structures into per-device structures.
17417c478bd9Sstevel@tonic-gate * (Invert the table.)
17427c478bd9Sstevel@tonic-gate */
17437c478bd9Sstevel@tonic-gate newopt = organize_state(&pstate);
17447c478bd9Sstevel@tonic-gate
17457c478bd9Sstevel@tonic-gate /* If we're going to free the file name, then stop logging there. */
17467c478bd9Sstevel@tonic-gate if (newopt == NULL && glob_svc.se_log != NULL) {
17477c478bd9Sstevel@tonic-gate glob_svc.se_log = NULL;
17487c478bd9Sstevel@tonic-gate global_logging();
17497c478bd9Sstevel@tonic-gate }
17507c478bd9Sstevel@tonic-gate
17517c478bd9Sstevel@tonic-gate /*
17527c478bd9Sstevel@tonic-gate * Unless an error has occurred, these pointers are normally
17537c478bd9Sstevel@tonic-gate * all NULL. Nothing is freed until the file is re-read.
17547c478bd9Sstevel@tonic-gate */
17557c478bd9Sstevel@tonic-gate free_file_list(pstate.ps_files);
17567c478bd9Sstevel@tonic-gate free_file_list(pstate.ps_cfile);
17577c478bd9Sstevel@tonic-gate free_device_list(pstate.ps_star);
17587c478bd9Sstevel@tonic-gate free_env_list(pstate.ps_evlist);
17597c478bd9Sstevel@tonic-gate
17607c478bd9Sstevel@tonic-gate /*
17617c478bd9Sstevel@tonic-gate * Match up entries on device list. Detach devices no longer
17627c478bd9Sstevel@tonic-gate * referenced. Attach ones now referenced. (The use of null
17637c478bd9Sstevel@tonic-gate * pointers here may look fishy, but it actually works.
17647c478bd9Sstevel@tonic-gate * NULL>=NULL is always true.)
17657c478bd9Sstevel@tonic-gate */
17667c478bd9Sstevel@tonic-gate if (newopt != NULL) {
17677c478bd9Sstevel@tonic-gate newdep = newopt->os_devices;
17687c478bd9Sstevel@tonic-gate newmax = newdep + newopt->os_ndevices;
17697c478bd9Sstevel@tonic-gate } else {
17707c478bd9Sstevel@tonic-gate newdep = newmax = NULL;
17717c478bd9Sstevel@tonic-gate }
17727c478bd9Sstevel@tonic-gate if (cur_options != NULL) {
17737c478bd9Sstevel@tonic-gate olddep = cur_options->os_devices;
17747c478bd9Sstevel@tonic-gate oldmax = olddep + cur_options->os_ndevices;
17757c478bd9Sstevel@tonic-gate } else {
17767c478bd9Sstevel@tonic-gate olddep = oldmax = NULL;
17777c478bd9Sstevel@tonic-gate }
17787c478bd9Sstevel@tonic-gate while ((newdep != NULL && newdep < newmax) ||
17797c478bd9Sstevel@tonic-gate (olddep != NULL && olddep < oldmax)) {
17807c478bd9Sstevel@tonic-gate if (newdep < newmax) {
17817c478bd9Sstevel@tonic-gate if (olddep >= oldmax) {
17827c478bd9Sstevel@tonic-gate add_new_dev(tunfd, newdep->de_name);
17837c478bd9Sstevel@tonic-gate newdep++;
17847c478bd9Sstevel@tonic-gate } else {
17857c478bd9Sstevel@tonic-gate cmpval = strcmp(newdep->de_name,
17867c478bd9Sstevel@tonic-gate olddep->de_name);
17877c478bd9Sstevel@tonic-gate if (cmpval < 0) {
17887c478bd9Sstevel@tonic-gate /* Brand new device seen. */
17897c478bd9Sstevel@tonic-gate add_new_dev(tunfd, newdep->de_name);
17907c478bd9Sstevel@tonic-gate newdep++;
17917c478bd9Sstevel@tonic-gate } else if (cmpval == 0) {
17927c478bd9Sstevel@tonic-gate /* Existing device; skip it. */
17937c478bd9Sstevel@tonic-gate newdep++;
17947c478bd9Sstevel@tonic-gate olddep++;
17957c478bd9Sstevel@tonic-gate }
17967c478bd9Sstevel@tonic-gate /* No else clause -- removal is below */
17977c478bd9Sstevel@tonic-gate }
17987c478bd9Sstevel@tonic-gate }
17997c478bd9Sstevel@tonic-gate if (olddep < oldmax) {
18007c478bd9Sstevel@tonic-gate if (newdep >= newmax) {
18017c478bd9Sstevel@tonic-gate rem_old_dev(tunfd, olddep->de_name);
18027c478bd9Sstevel@tonic-gate olddep++;
18037c478bd9Sstevel@tonic-gate } else {
18047c478bd9Sstevel@tonic-gate cmpval = strcmp(newdep->de_name,
18057c478bd9Sstevel@tonic-gate olddep->de_name);
18067c478bd9Sstevel@tonic-gate if (cmpval > 0) {
18077c478bd9Sstevel@tonic-gate /* Old device is gone */
18087c478bd9Sstevel@tonic-gate rem_old_dev(tunfd, olddep->de_name);
18097c478bd9Sstevel@tonic-gate olddep++;
18107c478bd9Sstevel@tonic-gate } else if (cmpval == 0) {
18117c478bd9Sstevel@tonic-gate /* Existing device; skip it. */
18127c478bd9Sstevel@tonic-gate newdep++;
18137c478bd9Sstevel@tonic-gate olddep++;
18147c478bd9Sstevel@tonic-gate }
18157c478bd9Sstevel@tonic-gate /* No else clause -- insert handled above */
18167c478bd9Sstevel@tonic-gate }
18177c478bd9Sstevel@tonic-gate }
18187c478bd9Sstevel@tonic-gate }
18197c478bd9Sstevel@tonic-gate
18207c478bd9Sstevel@tonic-gate /* Discard existing parsed data storage. */
18217c478bd9Sstevel@tonic-gate if (cur_options != NULL) {
18227c478bd9Sstevel@tonic-gate free_file_list(cur_options->os_pfjunk);
18237c478bd9Sstevel@tonic-gate free_env_list(cur_options->os_evjunk);
18247c478bd9Sstevel@tonic-gate free(cur_options);
18257c478bd9Sstevel@tonic-gate }
18267c478bd9Sstevel@tonic-gate /* Install new. */
18277c478bd9Sstevel@tonic-gate cur_options = newopt;
18287c478bd9Sstevel@tonic-gate }
18297c478bd9Sstevel@tonic-gate
18307c478bd9Sstevel@tonic-gate /*
18317c478bd9Sstevel@tonic-gate * Check if configured filters permit requesting client to use a given
18327c478bd9Sstevel@tonic-gate * service. Note -- filters are stored in reverse order in order to
18337c478bd9Sstevel@tonic-gate * make file-inclusion work as expected. Thus, the "first match"
18347c478bd9Sstevel@tonic-gate * filter rule becomes "last match" here.
18357c478bd9Sstevel@tonic-gate */
18367c478bd9Sstevel@tonic-gate static boolean_t
allow_service(const struct service_entry * sep,const ppptun_atype * pap)18377c478bd9Sstevel@tonic-gate allow_service(const struct service_entry *sep, const ppptun_atype *pap)
18387c478bd9Sstevel@tonic-gate {
18397c478bd9Sstevel@tonic-gate const struct filter_entry *fep;
18407c478bd9Sstevel@tonic-gate const struct filter_entry *lmatch;
18417c478bd9Sstevel@tonic-gate boolean_t anynonexcept = B_FALSE;
18427c478bd9Sstevel@tonic-gate const uchar_t *upt;
18437c478bd9Sstevel@tonic-gate const uchar_t *macp;
18447c478bd9Sstevel@tonic-gate const uchar_t *maskp;
18457c478bd9Sstevel@tonic-gate int i;
18467c478bd9Sstevel@tonic-gate
18477c478bd9Sstevel@tonic-gate lmatch = NULL;
18487c478bd9Sstevel@tonic-gate for (fep = sep->se_flist; fep != NULL; fep = fep->fe_prev) {
18497c478bd9Sstevel@tonic-gate anynonexcept |= !fep->fe_isexcept;
18507c478bd9Sstevel@tonic-gate upt = pap->pta_pppoe.ptma_mac;
18517c478bd9Sstevel@tonic-gate macp = fep->fe_mac.ether_addr_octet;
18527c478bd9Sstevel@tonic-gate maskp = fep->fe_mask.ether_addr_octet;
18537c478bd9Sstevel@tonic-gate for (i = sizeof (pap->pta_pppoe.ptma_mac); i > 0; i--)
18547c478bd9Sstevel@tonic-gate if (((*macp++ ^ *upt++) & *maskp++) != 0)
18557c478bd9Sstevel@tonic-gate break;
18567c478bd9Sstevel@tonic-gate if (i <= 0)
18577c478bd9Sstevel@tonic-gate lmatch = fep;
18587c478bd9Sstevel@tonic-gate }
18597c478bd9Sstevel@tonic-gate
18607c478bd9Sstevel@tonic-gate if (lmatch == NULL) {
18617c478bd9Sstevel@tonic-gate /*
18627c478bd9Sstevel@tonic-gate * Assume reject by default if any positive-match
18637c478bd9Sstevel@tonic-gate * (non-except) filters are given. Otherwise, if
18647c478bd9Sstevel@tonic-gate * there are no positive-match filters, then
18657c478bd9Sstevel@tonic-gate * non-matching means accept by default.
18667c478bd9Sstevel@tonic-gate */
18677c478bd9Sstevel@tonic-gate return (!anynonexcept);
18687c478bd9Sstevel@tonic-gate }
18697c478bd9Sstevel@tonic-gate return (!lmatch->fe_isexcept);
18707c478bd9Sstevel@tonic-gate }
18717c478bd9Sstevel@tonic-gate
18727c478bd9Sstevel@tonic-gate /*
18737c478bd9Sstevel@tonic-gate * Locate available service(s) based on client request. Assumes that
18747c478bd9Sstevel@tonic-gate * outp points to a buffer of at least size PPPOE_MSGMAX. Creates a
18757c478bd9Sstevel@tonic-gate * PPPoE response message in outp. Returns count of matched services
18767c478bd9Sstevel@tonic-gate * and (through *srvp) a pointer to the last (or only) service. If
18777c478bd9Sstevel@tonic-gate * some error is found in the request, an error string is added and -1
18787c478bd9Sstevel@tonic-gate * is returned; the caller should just send the message without
18797c478bd9Sstevel@tonic-gate * alteration.
18807c478bd9Sstevel@tonic-gate */
18817c478bd9Sstevel@tonic-gate int
locate_service(poep_t * poep,int plen,const char * iname,ppptun_atype * pap,uint32_t * outp,void ** srvp)18827c478bd9Sstevel@tonic-gate locate_service(poep_t *poep, int plen, const char *iname, ppptun_atype *pap,
18837c478bd9Sstevel@tonic-gate uint32_t *outp, void **srvp)
18847c478bd9Sstevel@tonic-gate {
18857c478bd9Sstevel@tonic-gate poep_t *opoe;
18867c478bd9Sstevel@tonic-gate const uint8_t *tagp;
18877c478bd9Sstevel@tonic-gate const char *cp;
18887c478bd9Sstevel@tonic-gate int ttyp;
18897c478bd9Sstevel@tonic-gate int tlen;
18907c478bd9Sstevel@tonic-gate int nsvcs;
18917c478bd9Sstevel@tonic-gate const struct device_entry *dep, *depe;
18927c478bd9Sstevel@tonic-gate const struct device_entry *wdep;
18937c478bd9Sstevel@tonic-gate const struct service_entry **sepp, **seppe;
18947c478bd9Sstevel@tonic-gate const struct service_entry *sep;
18957c478bd9Sstevel@tonic-gate char *str;
18967c478bd9Sstevel@tonic-gate boolean_t ispadi;
18977c478bd9Sstevel@tonic-gate
18987c478bd9Sstevel@tonic-gate ispadi = poep->poep_code == POECODE_PADI;
18997c478bd9Sstevel@tonic-gate opoe = poe_mkheader(outp, ispadi ? POECODE_PADO : POECODE_PADS, 0);
19007c478bd9Sstevel@tonic-gate
19017c478bd9Sstevel@tonic-gate *srvp = NULL;
19027c478bd9Sstevel@tonic-gate if (cur_options == NULL)
19037c478bd9Sstevel@tonic-gate return (0);
19047c478bd9Sstevel@tonic-gate
19057c478bd9Sstevel@tonic-gate /* Search for named device (lower stream) in tables. */
19067c478bd9Sstevel@tonic-gate dep = cur_options->os_devices;
19077c478bd9Sstevel@tonic-gate depe = dep + cur_options->os_ndevices;
19087c478bd9Sstevel@tonic-gate wdep = NULL;
19097c478bd9Sstevel@tonic-gate if ((cp = strchr(iname, ':')) != NULL)
19107c478bd9Sstevel@tonic-gate tlen = cp - iname;
19117c478bd9Sstevel@tonic-gate else
19127c478bd9Sstevel@tonic-gate tlen = strlen(iname);
19137c478bd9Sstevel@tonic-gate for (; dep < depe; dep++)
19147c478bd9Sstevel@tonic-gate if (strncmp(iname, dep->de_name, tlen) == 0 &&
19157c478bd9Sstevel@tonic-gate dep->de_name[tlen] == '\0')
19167c478bd9Sstevel@tonic-gate break;
19177c478bd9Sstevel@tonic-gate else if (dep->de_name[0] == '*' && dep->de_name[1] == '\0')
19187c478bd9Sstevel@tonic-gate wdep = dep;
19197c478bd9Sstevel@tonic-gate if (dep >= depe)
19207c478bd9Sstevel@tonic-gate dep = wdep;
19217c478bd9Sstevel@tonic-gate /*
19227c478bd9Sstevel@tonic-gate * Return if interface not found. Zero-service case can't
19237c478bd9Sstevel@tonic-gate * occur, since devices with no services aren't included in
19247c478bd9Sstevel@tonic-gate * the list, but the code is just being safe here.
19257c478bd9Sstevel@tonic-gate */
19267c478bd9Sstevel@tonic-gate if (dep == NULL || dep->de_services == NULL || dep->de_nservices <= 0)
19277c478bd9Sstevel@tonic-gate return (0);
19287c478bd9Sstevel@tonic-gate
19297c478bd9Sstevel@tonic-gate /*
19307c478bd9Sstevel@tonic-gate * Loop over tags in client message and process them.
19317c478bd9Sstevel@tonic-gate * Services must be matched against our list. Host-Uniq and
19327c478bd9Sstevel@tonic-gate * Relay-Session-Id must be copied to the reply. All others
19337c478bd9Sstevel@tonic-gate * must be discarded.
19347c478bd9Sstevel@tonic-gate */
19357c478bd9Sstevel@tonic-gate nsvcs = 0;
19367c478bd9Sstevel@tonic-gate sepp = dep->de_services;
19377c478bd9Sstevel@tonic-gate tagp = (const uint8_t *)(poep + 1);
19387c478bd9Sstevel@tonic-gate while (poe_tagcheck(poep, plen, tagp)) {
19397c478bd9Sstevel@tonic-gate ttyp = POET_GET_TYPE(tagp);
19407c478bd9Sstevel@tonic-gate if (ttyp == POETT_END)
19417c478bd9Sstevel@tonic-gate break;
19427c478bd9Sstevel@tonic-gate tlen = POET_GET_LENG(tagp);
19437c478bd9Sstevel@tonic-gate switch (ttyp) {
19447c478bd9Sstevel@tonic-gate case POETT_SERVICE: /* Service-Name */
19457c478bd9Sstevel@tonic-gate /*
19467c478bd9Sstevel@tonic-gate * Allow only one. (Note that this test works
19477c478bd9Sstevel@tonic-gate * because there's always at least one service
19487c478bd9Sstevel@tonic-gate * per device; otherwise, the device is
19497c478bd9Sstevel@tonic-gate * removed from the list.)
19507c478bd9Sstevel@tonic-gate */
19517c478bd9Sstevel@tonic-gate if (sepp != dep->de_services) {
19527c478bd9Sstevel@tonic-gate if (nsvcs != -1)
19537c478bd9Sstevel@tonic-gate (void) poe_add_str(opoe, POETT_NAMERR,
19547c478bd9Sstevel@tonic-gate "Too many Service-Name tags");
19557c478bd9Sstevel@tonic-gate nsvcs = -1;
19567c478bd9Sstevel@tonic-gate break;
19577c478bd9Sstevel@tonic-gate }
19587c478bd9Sstevel@tonic-gate seppe = sepp + dep->de_nservices;
19597c478bd9Sstevel@tonic-gate if (tlen == 0) {
19607c478bd9Sstevel@tonic-gate /*
19617c478bd9Sstevel@tonic-gate * If config specifies "nowild" in a
19627c478bd9Sstevel@tonic-gate * global context, then we don't
19637c478bd9Sstevel@tonic-gate * respond to wildcard PADRs. The
19647c478bd9Sstevel@tonic-gate * client must know the exact service
19657c478bd9Sstevel@tonic-gate * name to get access.
19667c478bd9Sstevel@tonic-gate */
19677c478bd9Sstevel@tonic-gate
19687c478bd9Sstevel@tonic-gate if (!ispadi && (glob_svc.se_flags & SEF_NOWILD))
19697c478bd9Sstevel@tonic-gate sepp = seppe;
19707c478bd9Sstevel@tonic-gate while (sepp < seppe) {
19717c478bd9Sstevel@tonic-gate sep = *sepp++;
1972*f53eecf5SJames Carlson if (sep->se_name[0] == '\0' ||
1973*f53eecf5SJames Carlson (sep->se_flags & SEF_NOWILD) ||
1974*f53eecf5SJames Carlson !allow_service(sep, pap))
19757c478bd9Sstevel@tonic-gate continue;
1976*f53eecf5SJames Carlson *srvp = (void *)sep;
1977*f53eecf5SJames Carlson /*
1978*f53eecf5SJames Carlson * RFC requires that PADO includes the
1979*f53eecf5SJames Carlson * wildcard service request in response
1980*f53eecf5SJames Carlson * to PADI.
1981*f53eecf5SJames Carlson */
1982*f53eecf5SJames Carlson if (ispadi && nsvcs == 0 &&
1983*f53eecf5SJames Carlson !(glob_svc.se_flags & SEF_NOWILD))
1984*f53eecf5SJames Carlson (void) poe_tag_copy(opoe, tagp);
1985*f53eecf5SJames Carlson nsvcs++;
1986*f53eecf5SJames Carlson (void) poe_add_str(opoe, POETT_SERVICE,
19877c478bd9Sstevel@tonic-gate sep->se_name);
1988*f53eecf5SJames Carlson /* If PADR, then one is enough */
1989*f53eecf5SJames Carlson if (!ispadi)
1990*f53eecf5SJames Carlson break;
19917c478bd9Sstevel@tonic-gate }
1992*f53eecf5SJames Carlson /* Just for generating error messages */
1993*f53eecf5SJames Carlson if (nsvcs == 0)
1994*f53eecf5SJames Carlson (void) poe_tag_copy(opoe, tagp);
19957c478bd9Sstevel@tonic-gate } else {
1996*f53eecf5SJames Carlson /*
1997*f53eecf5SJames Carlson * Clients's requested service must appear in
1998*f53eecf5SJames Carlson * reply.
1999*f53eecf5SJames Carlson */
2000*f53eecf5SJames Carlson (void) poe_tag_copy(opoe, tagp);
2001*f53eecf5SJames Carlson
20027c478bd9Sstevel@tonic-gate /* Requested specific service; find it. */
20037c478bd9Sstevel@tonic-gate cp = (char *)POET_DATA(tagp);
20047c478bd9Sstevel@tonic-gate while (sepp < seppe) {
20057c478bd9Sstevel@tonic-gate sep = *sepp++;
20067c478bd9Sstevel@tonic-gate if (strlen(sep->se_name) == tlen &&
20077c478bd9Sstevel@tonic-gate strncasecmp(sep->se_name, cp,
20087c478bd9Sstevel@tonic-gate tlen) == 0) {
20097c478bd9Sstevel@tonic-gate if (allow_service(sep, pap)) {
20107c478bd9Sstevel@tonic-gate nsvcs++;
20117c478bd9Sstevel@tonic-gate *srvp = (void *)sep;
20127c478bd9Sstevel@tonic-gate }
20137c478bd9Sstevel@tonic-gate break;
20147c478bd9Sstevel@tonic-gate }
20157c478bd9Sstevel@tonic-gate }
20167c478bd9Sstevel@tonic-gate }
20177c478bd9Sstevel@tonic-gate /*
20187c478bd9Sstevel@tonic-gate * Allow service definition to override
20197c478bd9Sstevel@tonic-gate * AC-Name (concentrator [server] name) field.
20207c478bd9Sstevel@tonic-gate */
20217c478bd9Sstevel@tonic-gate if (*srvp != NULL) {
20227c478bd9Sstevel@tonic-gate sep = (const struct service_entry *)*srvp;
20237c478bd9Sstevel@tonic-gate log_for_service(sep->se_log, sep->se_debug);
20247c478bd9Sstevel@tonic-gate str = "Solaris PPPoE";
20257c478bd9Sstevel@tonic-gate if (sep->se_server != NULL)
20267c478bd9Sstevel@tonic-gate str = sep->se_server;
20277c478bd9Sstevel@tonic-gate (void) poe_add_str(opoe, POETT_ACCESS, str);
20287c478bd9Sstevel@tonic-gate }
20297c478bd9Sstevel@tonic-gate break;
20307c478bd9Sstevel@tonic-gate /* Ones we should discard */
20317c478bd9Sstevel@tonic-gate case POETT_ACCESS: /* AC-Name */
20327c478bd9Sstevel@tonic-gate case POETT_COOKIE: /* AC-Cookie */
20337c478bd9Sstevel@tonic-gate case POETT_NAMERR: /* Service-Name-Error */
20347c478bd9Sstevel@tonic-gate case POETT_SYSERR: /* AC-System-Error */
20357c478bd9Sstevel@tonic-gate case POETT_GENERR: /* Generic-Error */
20367c478bd9Sstevel@tonic-gate case POETT_HURL: /* Host-URL */
20377c478bd9Sstevel@tonic-gate case POETT_MOTM: /* Message-Of-The-Minute */
20387c478bd9Sstevel@tonic-gate case POETT_RTEADD: /* IP-Route-Add */
20397c478bd9Sstevel@tonic-gate case POETT_VENDOR: /* Vendor-Specific */
20407c478bd9Sstevel@tonic-gate case POETT_MULTI: /* Multicast-Capable */
20417c478bd9Sstevel@tonic-gate default:
20427c478bd9Sstevel@tonic-gate break;
20437c478bd9Sstevel@tonic-gate /* Ones we should copy */
20447c478bd9Sstevel@tonic-gate case POETT_UNIQ: /* Host-Uniq */
20457c478bd9Sstevel@tonic-gate case POETT_RELAY: /* Relay-Session-Id */
20467c478bd9Sstevel@tonic-gate (void) poe_tag_copy(opoe, tagp);
20477c478bd9Sstevel@tonic-gate break;
20487c478bd9Sstevel@tonic-gate }
20497c478bd9Sstevel@tonic-gate tagp = POET_NEXT(tagp);
20507c478bd9Sstevel@tonic-gate }
20517c478bd9Sstevel@tonic-gate return (nsvcs);
20527c478bd9Sstevel@tonic-gate }
20537c478bd9Sstevel@tonic-gate
20547c478bd9Sstevel@tonic-gate /*
20557c478bd9Sstevel@tonic-gate * Like fgetc, but reads from a string.
20567c478bd9Sstevel@tonic-gate */
20577c478bd9Sstevel@tonic-gate static int
sgetc(void * arg)20587c478bd9Sstevel@tonic-gate sgetc(void *arg)
20597c478bd9Sstevel@tonic-gate {
20607c478bd9Sstevel@tonic-gate char **cpp = (char **)arg;
20617c478bd9Sstevel@tonic-gate if (**cpp == '\0')
20627c478bd9Sstevel@tonic-gate return (EOF);
20637c478bd9Sstevel@tonic-gate return (*(*cpp)++);
20647c478bd9Sstevel@tonic-gate }
20657c478bd9Sstevel@tonic-gate
20667c478bd9Sstevel@tonic-gate /*
20677c478bd9Sstevel@tonic-gate * Given a service structure, launch pppd. Called by handle_input()
20687c478bd9Sstevel@tonic-gate * in pppoed.c if locate_service() [above] finds exactly one service
20697c478bd9Sstevel@tonic-gate * matching a PADR.
20707c478bd9Sstevel@tonic-gate */
20717c478bd9Sstevel@tonic-gate int
launch_service(int tunfd,poep_t * poep,void * srvp,struct ppptun_control * ptc)20727c478bd9Sstevel@tonic-gate launch_service(int tunfd, poep_t *poep, void *srvp, struct ppptun_control *ptc)
20737c478bd9Sstevel@tonic-gate {
20747c478bd9Sstevel@tonic-gate const struct service_entry *sep = (const struct service_entry *)srvp;
20757c478bd9Sstevel@tonic-gate const char *path;
20767c478bd9Sstevel@tonic-gate const char *extra;
20777c478bd9Sstevel@tonic-gate const char *pppd;
20787c478bd9Sstevel@tonic-gate const char *cp;
20797c478bd9Sstevel@tonic-gate pid_t pidv;
20807c478bd9Sstevel@tonic-gate int newtun;
20817c478bd9Sstevel@tonic-gate struct ppptun_peer ptp;
20827c478bd9Sstevel@tonic-gate union ppptun_name ptn;
20837c478bd9Sstevel@tonic-gate const char *args[MAXARGS];
20847c478bd9Sstevel@tonic-gate struct strbuf ctrl;
20857c478bd9Sstevel@tonic-gate struct strbuf data;
20867c478bd9Sstevel@tonic-gate const char **cpp;
20877c478bd9Sstevel@tonic-gate char *sptr;
20887c478bd9Sstevel@tonic-gate char *spv;
20897c478bd9Sstevel@tonic-gate int slen;
20907c478bd9Sstevel@tonic-gate int retv;
20917c478bd9Sstevel@tonic-gate char keybuf[MAX_KEYWORD];
20927c478bd9Sstevel@tonic-gate
20937c478bd9Sstevel@tonic-gate assert(sep != NULL);
20947c478bd9Sstevel@tonic-gate
20957c478bd9Sstevel@tonic-gate /* Get tunnel driver connection for new PPP session. */
20967c478bd9Sstevel@tonic-gate newtun = open(tunnam, O_RDWR);
20977c478bd9Sstevel@tonic-gate if (newtun == -1)
20987c478bd9Sstevel@tonic-gate goto syserr;
20997c478bd9Sstevel@tonic-gate
21007c478bd9Sstevel@tonic-gate /* Set this session up for standard PPP and client's address. */
21017c478bd9Sstevel@tonic-gate (void) memset(&ptp, '\0', sizeof (ptp));
21027c478bd9Sstevel@tonic-gate ptp.ptp_style = PTS_PPPOE;
21037c478bd9Sstevel@tonic-gate ptp.ptp_address = ptc->ptc_address;
21047c478bd9Sstevel@tonic-gate if (strioctl(newtun, PPPTUN_SPEER, &ptp, sizeof (ptp), sizeof (ptp)) <
21057c478bd9Sstevel@tonic-gate 0)
21067c478bd9Sstevel@tonic-gate goto syserr;
21077c478bd9Sstevel@tonic-gate ptp.ptp_rsessid = ptp.ptp_lsessid;
21087c478bd9Sstevel@tonic-gate if (strioctl(newtun, PPPTUN_SPEER, &ptp, sizeof (ptp), sizeof (ptp)) <
21097c478bd9Sstevel@tonic-gate 0)
21107c478bd9Sstevel@tonic-gate goto syserr;
21117c478bd9Sstevel@tonic-gate
21127c478bd9Sstevel@tonic-gate /* Attach the requested lower stream. */
21137c478bd9Sstevel@tonic-gate cp = strchr(ptc->ptc_name, ':');
21147c478bd9Sstevel@tonic-gate if (cp == NULL)
21157c478bd9Sstevel@tonic-gate cp = ptc->ptc_name + strlen(ptc->ptc_name);
21167c478bd9Sstevel@tonic-gate (void) snprintf(ptn.ptn_name, sizeof (ptn.ptn_name), "%.*s:pppoe",
21177c478bd9Sstevel@tonic-gate cp-ptc->ptc_name, ptc->ptc_name);
21187c478bd9Sstevel@tonic-gate if (strioctl(newtun, PPPTUN_SDATA, &ptn, sizeof (ptn), 0) < 0)
21197c478bd9Sstevel@tonic-gate goto syserr;
21207c478bd9Sstevel@tonic-gate (void) snprintf(ptn.ptn_name, sizeof (ptn.ptn_name), "%.*s:pppoed",
21217c478bd9Sstevel@tonic-gate cp-ptc->ptc_name, ptc->ptc_name);
21227c478bd9Sstevel@tonic-gate if (strioctl(newtun, PPPTUN_SCTL, &ptn, sizeof (ptn), 0) < 0)
21237c478bd9Sstevel@tonic-gate goto syserr;
21247c478bd9Sstevel@tonic-gate
21257c478bd9Sstevel@tonic-gate pidv = fork();
21267c478bd9Sstevel@tonic-gate if (pidv == (pid_t)-1)
21277c478bd9Sstevel@tonic-gate goto syserr;
21287c478bd9Sstevel@tonic-gate
21297c478bd9Sstevel@tonic-gate if (pidv == (pid_t)0) {
21307c478bd9Sstevel@tonic-gate /*
21317c478bd9Sstevel@tonic-gate * Use syslog only in order to avoid mixing log messages
21327c478bd9Sstevel@tonic-gate * in regular files.
21337c478bd9Sstevel@tonic-gate */
21347c478bd9Sstevel@tonic-gate close_log_files();
21357c478bd9Sstevel@tonic-gate
21367c478bd9Sstevel@tonic-gate if ((path = sep->se_path) == NULL)
21377c478bd9Sstevel@tonic-gate path = "/usr/bin/pppd";
21387c478bd9Sstevel@tonic-gate if ((extra = sep->se_extra) == NULL)
21397c478bd9Sstevel@tonic-gate extra = "plugin pppoe.so directtty";
21407c478bd9Sstevel@tonic-gate if ((pppd = sep->se_pppd) == NULL)
21417c478bd9Sstevel@tonic-gate pppd = "";
21427c478bd9Sstevel@tonic-gate
21437c478bd9Sstevel@tonic-gate /* Concatenate these. */
21447c478bd9Sstevel@tonic-gate slen = strlen(path) + strlen(extra) + strlen(pppd) + 3;
21457c478bd9Sstevel@tonic-gate if ((sptr = (char *)malloc(slen)) == NULL)
21467c478bd9Sstevel@tonic-gate goto bail_out;
21477c478bd9Sstevel@tonic-gate (void) strcpy(sptr, path);
21487c478bd9Sstevel@tonic-gate (void) strcat(sptr, " ");
21497c478bd9Sstevel@tonic-gate (void) strcat(sptr, extra);
21507c478bd9Sstevel@tonic-gate (void) strcat(sptr, " ");
21517c478bd9Sstevel@tonic-gate (void) strcat(sptr, pppd);
21527c478bd9Sstevel@tonic-gate
21537c478bd9Sstevel@tonic-gate /* Parse out into arguments */
21547c478bd9Sstevel@tonic-gate cpp = args;
21557c478bd9Sstevel@tonic-gate spv = sptr;
21567c478bd9Sstevel@tonic-gate while (cpp < args + MAXARGS - 1) {
21577c478bd9Sstevel@tonic-gate retv = getkeyword(NULL, keybuf, sizeof (keybuf), sgetc,
21587c478bd9Sstevel@tonic-gate (void *)&spv, 1);
21597c478bd9Sstevel@tonic-gate if (retv != 1)
21607c478bd9Sstevel@tonic-gate *cpp++ = strsave(keybuf);
21617c478bd9Sstevel@tonic-gate if (retv != 0)
21627c478bd9Sstevel@tonic-gate break;
21637c478bd9Sstevel@tonic-gate }
21647c478bd9Sstevel@tonic-gate *cpp = NULL;
21657c478bd9Sstevel@tonic-gate if (cpp == args)
21667c478bd9Sstevel@tonic-gate goto bail_out;
21677c478bd9Sstevel@tonic-gate
21687c478bd9Sstevel@tonic-gate /*
21697c478bd9Sstevel@tonic-gate * Fix tunnel device on stdin/stdout and error file on
21707c478bd9Sstevel@tonic-gate * stderr.
21717c478bd9Sstevel@tonic-gate */
21727c478bd9Sstevel@tonic-gate if (newtun != 0 && dup2(newtun, 0) < 0)
21737c478bd9Sstevel@tonic-gate goto bail_out;
21747c478bd9Sstevel@tonic-gate if (newtun != 1 && dup2(newtun, 1) < 0)
21757c478bd9Sstevel@tonic-gate goto bail_out;
21767c478bd9Sstevel@tonic-gate if (newtun > 1)
21777c478bd9Sstevel@tonic-gate (void) close(newtun);
21787c478bd9Sstevel@tonic-gate if (tunfd > 1)
21797c478bd9Sstevel@tonic-gate (void) close(tunfd);
21807c478bd9Sstevel@tonic-gate (void) close(2);
21817c478bd9Sstevel@tonic-gate (void) open("/etc/ppp/pppoe-errors", O_WRONLY | O_APPEND |
21827c478bd9Sstevel@tonic-gate O_CREAT, 0600);
21837c478bd9Sstevel@tonic-gate
21847c478bd9Sstevel@tonic-gate /*
21857c478bd9Sstevel@tonic-gate * Change GID first, for obvious reasons. Note that
21867c478bd9Sstevel@tonic-gate * we log any problems to syslog, not the errors file.
21877c478bd9Sstevel@tonic-gate * The errors file is intended for problems in the
21887c478bd9Sstevel@tonic-gate * exec'd program.
21897c478bd9Sstevel@tonic-gate */
21907c478bd9Sstevel@tonic-gate if ((sep->se_flags & SEF_GIDSET) &&
21917c478bd9Sstevel@tonic-gate setgid(sep->se_gid) == -1) {
21927c478bd9Sstevel@tonic-gate cp = mystrerror(errno);
21937c478bd9Sstevel@tonic-gate reopen_log();
21947c478bd9Sstevel@tonic-gate logerr("setgid(%d): %s", sep->se_gid, cp);
21957c478bd9Sstevel@tonic-gate goto logged;
21967c478bd9Sstevel@tonic-gate }
21977c478bd9Sstevel@tonic-gate if ((sep->se_flags & SEF_UIDSET) &&
21987c478bd9Sstevel@tonic-gate setuid(sep->se_uid) == -1) {
21997c478bd9Sstevel@tonic-gate cp = mystrerror(errno);
22007c478bd9Sstevel@tonic-gate reopen_log();
22017c478bd9Sstevel@tonic-gate logerr("setuid(%d): %s", sep->se_uid, cp);
22027c478bd9Sstevel@tonic-gate goto logged;
22037c478bd9Sstevel@tonic-gate }
22047c478bd9Sstevel@tonic-gate
22057c478bd9Sstevel@tonic-gate /* Run pppd */
22067c478bd9Sstevel@tonic-gate path = args[0];
22077c478bd9Sstevel@tonic-gate cp = strrchr(args[0], '/');
22087c478bd9Sstevel@tonic-gate if (cp != NULL && cp[1] != '\0')
22097c478bd9Sstevel@tonic-gate args[0] = cp+1;
22107c478bd9Sstevel@tonic-gate errno = 0;
22117c478bd9Sstevel@tonic-gate (void) execv(path, (char * const *)args);
22127c478bd9Sstevel@tonic-gate newtun = 0;
22137c478bd9Sstevel@tonic-gate
22147c478bd9Sstevel@tonic-gate /*
22157c478bd9Sstevel@tonic-gate * Exec failure; attempt to log the problem and send a
22167c478bd9Sstevel@tonic-gate * PADT to the client so that he knows the session
22177c478bd9Sstevel@tonic-gate * went south.
22187c478bd9Sstevel@tonic-gate */
22197c478bd9Sstevel@tonic-gate bail_out:
22207c478bd9Sstevel@tonic-gate cp = mystrerror(errno);
22217c478bd9Sstevel@tonic-gate reopen_log();
22227c478bd9Sstevel@tonic-gate logerr("\"%s\": %s", (sptr == NULL ? path : sptr), cp);
22237c478bd9Sstevel@tonic-gate logged:
22247c478bd9Sstevel@tonic-gate poep = poe_mkheader(pkt_output, POECODE_PADT, ptp.ptp_lsessid);
22257c478bd9Sstevel@tonic-gate poep->poep_session_id = htons(ptp.ptp_lsessid);
22267c478bd9Sstevel@tonic-gate (void) poe_add_str(poep, POETT_SYSERR, cp);
22277c478bd9Sstevel@tonic-gate (void) sleep(1);
22287c478bd9Sstevel@tonic-gate ctrl.len = sizeof (*ptc);
22297c478bd9Sstevel@tonic-gate ctrl.buf = (caddr_t)ptc;
22307c478bd9Sstevel@tonic-gate data.len = poe_length(poep) + sizeof (*poep);
22317c478bd9Sstevel@tonic-gate data.buf = (caddr_t)poep;
22327c478bd9Sstevel@tonic-gate if (putmsg(newtun, &ctrl, &data, 0) < 0) {
22337c478bd9Sstevel@tonic-gate logerr("putmsg %s: %s", ptc->ptc_name,
22347c478bd9Sstevel@tonic-gate mystrerror(errno));
22357c478bd9Sstevel@tonic-gate }
22367c478bd9Sstevel@tonic-gate exit(1);
22377c478bd9Sstevel@tonic-gate }
22387c478bd9Sstevel@tonic-gate
22397c478bd9Sstevel@tonic-gate (void) close(newtun);
22407c478bd9Sstevel@tonic-gate
22417c478bd9Sstevel@tonic-gate /* Give session ID to client in reply. */
22427c478bd9Sstevel@tonic-gate poep->poep_session_id = htons(ptp.ptp_lsessid);
22437c478bd9Sstevel@tonic-gate return (1);
22447c478bd9Sstevel@tonic-gate
22457c478bd9Sstevel@tonic-gate syserr:
22467c478bd9Sstevel@tonic-gate /* Peer doesn't know session ID yet; hope for the best. */
22477c478bd9Sstevel@tonic-gate retv = errno;
22487c478bd9Sstevel@tonic-gate if (newtun >= 0)
22497c478bd9Sstevel@tonic-gate (void) close(newtun);
22507c478bd9Sstevel@tonic-gate (void) poe_add_str(poep, POETT_SYSERR, mystrerror(retv));
22517c478bd9Sstevel@tonic-gate return (0);
22527c478bd9Sstevel@tonic-gate }
22537c478bd9Sstevel@tonic-gate
22547c478bd9Sstevel@tonic-gate /*
22557c478bd9Sstevel@tonic-gate * This is pretty awful -- it uses recursion to print a simple list.
22567c478bd9Sstevel@tonic-gate * It's just for debug, though, and does a reasonable job of printing
22577c478bd9Sstevel@tonic-gate * the filters in the right order.
22587c478bd9Sstevel@tonic-gate */
22597c478bd9Sstevel@tonic-gate static void
print_filter_list(FILE * fp,struct filter_entry * fep)22607c478bd9Sstevel@tonic-gate print_filter_list(FILE *fp, struct filter_entry *fep)
22617c478bd9Sstevel@tonic-gate {
22627c478bd9Sstevel@tonic-gate if (fep->fe_prev != NULL)
22637c478bd9Sstevel@tonic-gate print_filter_list(fp, fep->fe_prev);
22647c478bd9Sstevel@tonic-gate (void) fprintf(fp, "\t\t MAC %s", ehost2(&fep->fe_mac));
22657c478bd9Sstevel@tonic-gate (void) fprintf(fp, ", mask %s%s\n", ehost2(&fep->fe_mask),
22667c478bd9Sstevel@tonic-gate (fep->fe_isexcept ? ", except" : ""));
22677c478bd9Sstevel@tonic-gate }
22687c478bd9Sstevel@tonic-gate
22697c478bd9Sstevel@tonic-gate /*
22707c478bd9Sstevel@tonic-gate * Write summary of parsed configuration data to given file.
22717c478bd9Sstevel@tonic-gate */
22727c478bd9Sstevel@tonic-gate void
dump_configuration(FILE * fp)22737c478bd9Sstevel@tonic-gate dump_configuration(FILE *fp)
22747c478bd9Sstevel@tonic-gate {
22757c478bd9Sstevel@tonic-gate const struct device_entry *dep;
22767c478bd9Sstevel@tonic-gate const struct service_entry *sep, **sepp;
22777c478bd9Sstevel@tonic-gate struct per_file *pfp;
22787c478bd9Sstevel@tonic-gate int i, j;
22797c478bd9Sstevel@tonic-gate
22807c478bd9Sstevel@tonic-gate (void) fprintf(fp, "Will%s respond to wildcard queries.\n",
22817c478bd9Sstevel@tonic-gate (glob_svc.se_flags & SEF_NOWILD) ? " not" : "");
22827c478bd9Sstevel@tonic-gate (void) fprintf(fp,
22837c478bd9Sstevel@tonic-gate "Global debug level %d, log to %s; current level %d\n",
22847c478bd9Sstevel@tonic-gate glob_svc.se_debug,
22857c478bd9Sstevel@tonic-gate ((glob_svc.se_log == NULL || *glob_svc.se_log == '\0') ?
22867c478bd9Sstevel@tonic-gate "syslog" : glob_svc.se_log),
22877c478bd9Sstevel@tonic-gate log_level);
22887c478bd9Sstevel@tonic-gate if (cur_options == NULL) {
22897c478bd9Sstevel@tonic-gate (void) fprintf(fp, "No current configuration.\n");
22907c478bd9Sstevel@tonic-gate return;
22917c478bd9Sstevel@tonic-gate }
22927c478bd9Sstevel@tonic-gate (void) fprintf(fp, "Current configuration:\n");
22937c478bd9Sstevel@tonic-gate (void) fprintf(fp, " %d device(s):\n", cur_options->os_ndevices);
22947c478bd9Sstevel@tonic-gate dep = cur_options->os_devices;
22957c478bd9Sstevel@tonic-gate for (i = 0; i < cur_options->os_ndevices; i++, dep++) {
22967c478bd9Sstevel@tonic-gate (void) fprintf(fp, "\t%s: %d service(s):\n",
22977c478bd9Sstevel@tonic-gate dep->de_name, dep->de_nservices);
22987c478bd9Sstevel@tonic-gate sepp = dep->de_services;
22997c478bd9Sstevel@tonic-gate for (j = 0; j < dep->de_nservices; j++, sepp++) {
23007c478bd9Sstevel@tonic-gate sep = *sepp;
23017c478bd9Sstevel@tonic-gate (void) fprintf(fp, "\t %s: debug level %d",
23027c478bd9Sstevel@tonic-gate sep->se_name, sep->se_debug);
23037c478bd9Sstevel@tonic-gate if (sep->se_flags & SEF_UIDSET)
2304f48205beScasper (void) fprintf(fp, ", UID %u", sep->se_uid);
23057c478bd9Sstevel@tonic-gate if (sep->se_flags & SEF_GIDSET)
2306f48205beScasper (void) fprintf(fp, ", GID %u", sep->se_gid);
23077c478bd9Sstevel@tonic-gate if (sep->se_flags & SEF_WILD)
23087c478bd9Sstevel@tonic-gate (void) fprintf(fp, ", wildcard");
23097c478bd9Sstevel@tonic-gate else if (sep->se_flags & SEF_NOWILD)
23107c478bd9Sstevel@tonic-gate (void) fprintf(fp, ", nowildcard");
23117c478bd9Sstevel@tonic-gate else
23127c478bd9Sstevel@tonic-gate (void) fprintf(fp, ", wildcard (default)");
23137c478bd9Sstevel@tonic-gate (void) putc('\n', fp);
23147c478bd9Sstevel@tonic-gate if (sep->se_server != NULL)
23157c478bd9Sstevel@tonic-gate (void) fprintf(fp, "\t\tserver \"%s\"\n",
23167c478bd9Sstevel@tonic-gate sep->se_server);
23177c478bd9Sstevel@tonic-gate if (sep->se_pppd != NULL)
23187c478bd9Sstevel@tonic-gate (void) fprintf(fp, "\t\tpppd \"%s\"\n",
23197c478bd9Sstevel@tonic-gate sep->se_pppd);
23207c478bd9Sstevel@tonic-gate if (sep->se_path != NULL)
23217c478bd9Sstevel@tonic-gate (void) fprintf(fp, "\t\tpath \"%s\"\n",
23227c478bd9Sstevel@tonic-gate sep->se_path);
23237c478bd9Sstevel@tonic-gate if (sep->se_extra != NULL)
23247c478bd9Sstevel@tonic-gate (void) fprintf(fp, "\t\textra \"%s\"\n",
23257c478bd9Sstevel@tonic-gate sep->se_extra);
23267c478bd9Sstevel@tonic-gate if (sep->se_log != NULL)
23277c478bd9Sstevel@tonic-gate (void) fprintf(fp, "\t\tlog \"%s\"\n",
23287c478bd9Sstevel@tonic-gate sep->se_log);
23297c478bd9Sstevel@tonic-gate if (sep->se_flist != NULL) {
23307c478bd9Sstevel@tonic-gate (void) fprintf(fp, "\t\tfilter list:\n");
23317c478bd9Sstevel@tonic-gate print_filter_list(fp, sep->se_flist);
23327c478bd9Sstevel@tonic-gate }
23337c478bd9Sstevel@tonic-gate }
23347c478bd9Sstevel@tonic-gate }
23357c478bd9Sstevel@tonic-gate (void) fprintf(fp, "\nConfiguration read from:\n");
23367c478bd9Sstevel@tonic-gate for (pfp = cur_options->os_pfjunk; pfp != NULL; pfp = pfp->pf_prev) {
23377c478bd9Sstevel@tonic-gate (void) fprintf(fp, " %s: %d service(s)\n", pfp->pf_name,
23387c478bd9Sstevel@tonic-gate pfp->pf_nsvc);
23397c478bd9Sstevel@tonic-gate }
23407c478bd9Sstevel@tonic-gate }
2341