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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 * 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 * 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 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 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 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 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 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 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 ** 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 ** 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 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 ** 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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