1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * PPPoE Server-mode daemon option parsing. 24*0Sstevel@tonic-gate * 25*0Sstevel@tonic-gate * Copyright 2000-2002 Sun Microsystems, Inc. All rights reserved. 26*0Sstevel@tonic-gate * Use is subject to license terms. 27*0Sstevel@tonic-gate */ 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #include <stdio.h> 32*0Sstevel@tonic-gate #include <stdlib.h> 33*0Sstevel@tonic-gate #include <unistd.h> 34*0Sstevel@tonic-gate #include <assert.h> 35*0Sstevel@tonic-gate #include <ctype.h> 36*0Sstevel@tonic-gate #include <string.h> 37*0Sstevel@tonic-gate #include <sys/types.h> 38*0Sstevel@tonic-gate #include <fcntl.h> 39*0Sstevel@tonic-gate #include <pwd.h> 40*0Sstevel@tonic-gate #include <grp.h> 41*0Sstevel@tonic-gate #include <errno.h> 42*0Sstevel@tonic-gate #include <netdb.h> 43*0Sstevel@tonic-gate #include <stropts.h> 44*0Sstevel@tonic-gate #include <sys/stat.h> 45*0Sstevel@tonic-gate #include <sys/socket.h> 46*0Sstevel@tonic-gate #include <net/if.h> 47*0Sstevel@tonic-gate #include <netinet/in.h> 48*0Sstevel@tonic-gate #include <netinet/if_ether.h> 49*0Sstevel@tonic-gate #include <net/sppptun.h> 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate #include "common.h" 52*0Sstevel@tonic-gate #include "logging.h" 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate #define MAX_KEYWORD 4096 /* Maximum token length */ 55*0Sstevel@tonic-gate #define MAX_NEST 32 /* Maximum ${$sub} nesting */ 56*0Sstevel@tonic-gate #define MAXARGS 256 /* Maximum number of pppd arguments */ 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate /* 59*0Sstevel@tonic-gate * Client filter entry. These are linked in *reverse* order so that 60*0Sstevel@tonic-gate * the DAG created by file inclusion nesting works as expected. Since 61*0Sstevel@tonic-gate * the administrator who wrote the configuration expects "first 62*0Sstevel@tonic-gate * match," this means that tests against the filter list must actually 63*0Sstevel@tonic-gate * use "last match." 64*0Sstevel@tonic-gate */ 65*0Sstevel@tonic-gate struct filter_entry { 66*0Sstevel@tonic-gate struct filter_entry *fe_prev; /* Previous filter in list */ 67*0Sstevel@tonic-gate struct ether_addr fe_mac; /* MAC address */ 68*0Sstevel@tonic-gate struct ether_addr fe_mask; /* Mask for above address test */ 69*0Sstevel@tonic-gate uchar_t fe_isexcept; /* invert sense; exclude matching clients */ 70*0Sstevel@tonic-gate uchar_t fe_prevcopy; /* fe_prev points to copied list */ 71*0Sstevel@tonic-gate uchar_t fe_unused[2]; /* padding */ 72*0Sstevel@tonic-gate }; 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate /* 75*0Sstevel@tonic-gate * Note: I would like to make the strings and filters here const, but 76*0Sstevel@tonic-gate * I can't because they have to be passed to free() during parsing. I 77*0Sstevel@tonic-gate * could work around this with offsetof() or data copies, but it's not 78*0Sstevel@tonic-gate * worth the effort. 79*0Sstevel@tonic-gate */ 80*0Sstevel@tonic-gate struct service_entry { 81*0Sstevel@tonic-gate const char *se_name; /* Name of service */ 82*0Sstevel@tonic-gate struct filter_entry *se_flist; /* Pointer to list of client filters */ 83*0Sstevel@tonic-gate uint_t se_flags; /* SEF_* flags (below) */ 84*0Sstevel@tonic-gate int se_debug; /* Debug level (0=nodebug) */ 85*0Sstevel@tonic-gate char *se_server; /* Server (AC) name */ 86*0Sstevel@tonic-gate char *se_pppd; /* Options for pppd */ 87*0Sstevel@tonic-gate char *se_path; /* Path to pppd executable */ 88*0Sstevel@tonic-gate char *se_extra; /* Extra options */ 89*0Sstevel@tonic-gate char *se_log; /* Log file */ 90*0Sstevel@tonic-gate uid_t se_uid; /* User ID */ 91*0Sstevel@tonic-gate gid_t se_gid; /* Group ID */ 92*0Sstevel@tonic-gate }; 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate #define SEF_WILD 0x00000001 /* Offer in wildcard reply */ 95*0Sstevel@tonic-gate #define SEF_NOWILD 0x00000002 /* Don't offer in wildcard */ 96*0Sstevel@tonic-gate #define SEF_CFLIST 0x00000004 /* se_flist copied from global */ 97*0Sstevel@tonic-gate #define SEF_CSERVER 0x00000008 /* se_server copied from global */ 98*0Sstevel@tonic-gate #define SEF_CPPPD 0x00000010 /* se_pppd copied from global */ 99*0Sstevel@tonic-gate #define SEF_CPATH 0x00000020 /* se_path copied from global */ 100*0Sstevel@tonic-gate #define SEF_CEXTRA 0x00000040 /* se_extra copied from global */ 101*0Sstevel@tonic-gate #define SEF_CLOG 0x00000080 /* se_log copied from global */ 102*0Sstevel@tonic-gate #define SEF_UIDSET 0x00000100 /* se_uid has been set */ 103*0Sstevel@tonic-gate #define SEF_GIDSET 0x00000200 /* se_gid has been set */ 104*0Sstevel@tonic-gate #define SEF_DEBUGCLR 0x00000400 /* do not add se_debug from global */ 105*0Sstevel@tonic-gate #define SEF_CDEV 0x00000800 /* copied devs (parse only) */ 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate /* 108*0Sstevel@tonic-gate * One of these is allocated per lower-level stream (device) that is 109*0Sstevel@tonic-gate * referenced by the configuration files. The queries are received 110*0Sstevel@tonic-gate * per device, and this structure allows us to find all of the 111*0Sstevel@tonic-gate * services that correspond to that device. 112*0Sstevel@tonic-gate */ 113*0Sstevel@tonic-gate struct device_entry { 114*0Sstevel@tonic-gate const char *de_name; 115*0Sstevel@tonic-gate const struct service_entry **de_services; 116*0Sstevel@tonic-gate int de_nservices; 117*0Sstevel@tonic-gate }; 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate /* 120*0Sstevel@tonic-gate * This is the parsed configuration. While a new configuration is 121*0Sstevel@tonic-gate * being read, this is kept around until the new configuration is 122*0Sstevel@tonic-gate * ready, and then it is discarded in one operation. It has an array 123*0Sstevel@tonic-gate * of device entries (as above) -- one per referenced lower stream -- 124*0Sstevel@tonic-gate * and a pointer to the allocated parser information. The latter is 125*0Sstevel@tonic-gate * kept around because we reuse pointers rather than reallocating and 126*0Sstevel@tonic-gate * copying the data. There are thus multiple aliases to the dynamic 127*0Sstevel@tonic-gate * data, and the "owner" (for purposes of freeing the storage) is 128*0Sstevel@tonic-gate * considered to be this 'junk' list. 129*0Sstevel@tonic-gate */ 130*0Sstevel@tonic-gate struct option_state { 131*0Sstevel@tonic-gate const struct device_entry *os_devices; 132*0Sstevel@tonic-gate int os_ndevices; 133*0Sstevel@tonic-gate struct per_file *os_pfjunk; /* Kept for deallocation */ 134*0Sstevel@tonic-gate char **os_evjunk; /* ditto */ 135*0Sstevel@tonic-gate }; 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate /* 138*0Sstevel@tonic-gate * This is the root pointer to the current parsed options. 139*0Sstevel@tonic-gate * This cannot be const because it's passed to free() when reparsing 140*0Sstevel@tonic-gate * options. 141*0Sstevel@tonic-gate */ 142*0Sstevel@tonic-gate static struct option_state *cur_options; 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate /* Global settings for module-wide options. */ 145*0Sstevel@tonic-gate static struct service_entry glob_svc; 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate /* 148*0Sstevel@tonic-gate * ******************************************************************* 149*0Sstevel@tonic-gate * Data structures generated during parsing. 150*0Sstevel@tonic-gate */ 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate /* List of device names attached to one service */ 153*0Sstevel@tonic-gate struct device_list { 154*0Sstevel@tonic-gate struct device_list *dl_next; 155*0Sstevel@tonic-gate const char *dl_name; /* Name of one device */ 156*0Sstevel@tonic-gate }; 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate /* Entry for a single defined service. */ 159*0Sstevel@tonic-gate struct service_list { 160*0Sstevel@tonic-gate struct service_entry sl_entry; /* Parsed service data */ 161*0Sstevel@tonic-gate struct service_list *sl_next; /* Next service entry */ 162*0Sstevel@tonic-gate struct parse_state *sl_parse; /* Back pointer to state */ 163*0Sstevel@tonic-gate struct device_list *sl_dev; /* List of devices */ 164*0Sstevel@tonic-gate int sl_serial; /* Serial number (conflict resolve) */ 165*0Sstevel@tonic-gate }; 166*0Sstevel@tonic-gate #define SESERIAL(x) ((struct service_list *)&(x))->sl_serial 167*0Sstevel@tonic-gate #define ISGLOBAL(x) ((x) == &(x)->sl_parse->ps_cfile->pf_global) 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate /* 170*0Sstevel@tonic-gate * Structure allocated for each file opened. File nesting is chained 171*0Sstevel@tonic-gate * in reverse order so that global option scoping works as expected. 172*0Sstevel@tonic-gate */ 173*0Sstevel@tonic-gate struct per_file { 174*0Sstevel@tonic-gate struct per_file *pf_prev; /* Back chain */ 175*0Sstevel@tonic-gate struct service_list pf_global; /* Global (default) service context */ 176*0Sstevel@tonic-gate struct service_list *pf_svc; /* List of services */ 177*0Sstevel@tonic-gate struct service_list *pf_svc_last; 178*0Sstevel@tonic-gate FILE *pf_input; /* File for input */ 179*0Sstevel@tonic-gate const char *pf_name; /* File name */ 180*0Sstevel@tonic-gate int pf_nsvc; /* Count of services */ 181*0Sstevel@tonic-gate }; 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate /* State of parser */ 184*0Sstevel@tonic-gate enum key_state { 185*0Sstevel@tonic-gate ksDefault, ksService, ksDevice, ksClient, ksClientE, ksServer, 186*0Sstevel@tonic-gate ksPppd, ksFile, ksPath, ksExtra, ksLog, ksUser, ksGroup 187*0Sstevel@tonic-gate }; 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate /* 190*0Sstevel@tonic-gate * Global parser state. There is one of these structures, and it 191*0Sstevel@tonic-gate * exists only while actively parsing configuration files. 192*0Sstevel@tonic-gate */ 193*0Sstevel@tonic-gate struct parse_state { 194*0Sstevel@tonic-gate enum key_state ps_state; /* Parser state */ 195*0Sstevel@tonic-gate int ps_serial; /* Service serial number */ 196*0Sstevel@tonic-gate struct per_file *ps_files; /* Parsed files */ 197*0Sstevel@tonic-gate struct per_file *ps_cfile; /* Current file */ 198*0Sstevel@tonic-gate struct service_list *ps_csvc; /* Current service */ 199*0Sstevel@tonic-gate struct device_list *ps_star; /* Wildcard device */ 200*0Sstevel@tonic-gate int ps_flags; /* PSF_* below */ 201*0Sstevel@tonic-gate char **ps_evlist; /* allocated environment variables */ 202*0Sstevel@tonic-gate int ps_evsize; /* max length; for realloc */ 203*0Sstevel@tonic-gate }; 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate #define PSF_PERDEV 0x0001 /* In a per-device file */ 206*0Sstevel@tonic-gate #define PSF_SETLEVEL 0x0002 /* Set log level along the way */ 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate /* Should be in a library somewhere. */ 209*0Sstevel@tonic-gate static char * 210*0Sstevel@tonic-gate strsave(const char *str) 211*0Sstevel@tonic-gate { 212*0Sstevel@tonic-gate char *newstr; 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate if (str == NULL) 215*0Sstevel@tonic-gate return (NULL); 216*0Sstevel@tonic-gate newstr = (char *)malloc(strlen(str) + 1); 217*0Sstevel@tonic-gate if (newstr != NULL) 218*0Sstevel@tonic-gate (void) strcpy(newstr, str); 219*0Sstevel@tonic-gate return (newstr); 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate /* 223*0Sstevel@tonic-gate * Stop defining current service and revert to global definition. 224*0Sstevel@tonic-gate * This resolves any implicit references to global options by copying 225*0Sstevel@tonic-gate * ("inheriting") from the current global state. 226*0Sstevel@tonic-gate */ 227*0Sstevel@tonic-gate static void 228*0Sstevel@tonic-gate close_service(struct service_list *slp) 229*0Sstevel@tonic-gate { 230*0Sstevel@tonic-gate struct parse_state *psp; 231*0Sstevel@tonic-gate struct per_file *cfile; 232*0Sstevel@tonic-gate struct service_entry *sep; 233*0Sstevel@tonic-gate struct service_entry *sedefp; 234*0Sstevel@tonic-gate struct filter_entry *fep; 235*0Sstevel@tonic-gate 236*0Sstevel@tonic-gate assert(slp != NULL); 237*0Sstevel@tonic-gate psp = slp->sl_parse; 238*0Sstevel@tonic-gate cfile = psp->ps_cfile; 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate /* If no current file, then nothing to close. */ 241*0Sstevel@tonic-gate if (cfile == NULL) 242*0Sstevel@tonic-gate return; 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate sep = &slp->sl_entry; 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate /* 247*0Sstevel@tonic-gate * Fix up filter pointers to make DAG. First, locate 248*0Sstevel@tonic-gate * the end of the filter list. 249*0Sstevel@tonic-gate */ 250*0Sstevel@tonic-gate if (sep->se_flags & SEF_CFLIST) { 251*0Sstevel@tonic-gate sep->se_flist = fep = NULL; 252*0Sstevel@tonic-gate } else { 253*0Sstevel@tonic-gate for (fep = sep->se_flist; fep != NULL; fep = fep->fe_prev) 254*0Sstevel@tonic-gate if (fep->fe_prev == NULL || fep->fe_prevcopy) { 255*0Sstevel@tonic-gate fep->fe_prev = NULL; 256*0Sstevel@tonic-gate break; 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate } 259*0Sstevel@tonic-gate if (slp == &cfile->pf_global) { 260*0Sstevel@tonic-gate /* 261*0Sstevel@tonic-gate * If we're in a global context, then we're about to 262*0Sstevel@tonic-gate * open a new service, so it's time to fix up the 263*0Sstevel@tonic-gate * filter list so that it's usable as a reference. 264*0Sstevel@tonic-gate * Loop through files from which we were included, and 265*0Sstevel@tonic-gate * link up filters. Note: closure may occur more than 266*0Sstevel@tonic-gate * once here. 267*0Sstevel@tonic-gate */ 268*0Sstevel@tonic-gate /* We don't inherit from ourselves. */ 269*0Sstevel@tonic-gate cfile = cfile->pf_prev; 270*0Sstevel@tonic-gate while (cfile != NULL) { 271*0Sstevel@tonic-gate if (fep == NULL) { 272*0Sstevel@tonic-gate sep->se_flist = fep = 273*0Sstevel@tonic-gate cfile->pf_global.sl_entry.se_flist; 274*0Sstevel@tonic-gate sep->se_flags |= SEF_CFLIST; 275*0Sstevel@tonic-gate } else if (fep->fe_prev == NULL) { 276*0Sstevel@tonic-gate fep->fe_prev = 277*0Sstevel@tonic-gate cfile->pf_global.sl_entry.se_flist; 278*0Sstevel@tonic-gate fep->fe_prevcopy = 1; 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate cfile = cfile->pf_prev; 281*0Sstevel@tonic-gate } 282*0Sstevel@tonic-gate } else { 283*0Sstevel@tonic-gate /* 284*0Sstevel@tonic-gate * Loop through default options in current and all 285*0Sstevel@tonic-gate * enclosing include files. Inherit options. 286*0Sstevel@tonic-gate */ 287*0Sstevel@tonic-gate logdbg("service %s ends", slp->sl_entry.se_name); 288*0Sstevel@tonic-gate while (cfile != NULL) { 289*0Sstevel@tonic-gate /* Inherit from global service options. */ 290*0Sstevel@tonic-gate if (slp->sl_dev == NULL) { 291*0Sstevel@tonic-gate slp->sl_dev = cfile->pf_global.sl_dev; 292*0Sstevel@tonic-gate sep->se_flags |= SEF_CDEV; 293*0Sstevel@tonic-gate } 294*0Sstevel@tonic-gate sedefp = &cfile->pf_global.sl_entry; 295*0Sstevel@tonic-gate if (fep == NULL) { 296*0Sstevel@tonic-gate sep->se_flist = fep = sedefp->se_flist; 297*0Sstevel@tonic-gate sep->se_flags |= SEF_CFLIST; 298*0Sstevel@tonic-gate } else if (fep->fe_prev == NULL) { 299*0Sstevel@tonic-gate fep->fe_prev = sedefp->se_flist; 300*0Sstevel@tonic-gate fep->fe_prevcopy = 1; 301*0Sstevel@tonic-gate } 302*0Sstevel@tonic-gate if (sep->se_server == NULL) { 303*0Sstevel@tonic-gate sep->se_server = sedefp->se_server; 304*0Sstevel@tonic-gate sep->se_flags |= SEF_CSERVER; 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate if (sep->se_pppd == NULL) { 307*0Sstevel@tonic-gate sep->se_pppd = sedefp->se_pppd; 308*0Sstevel@tonic-gate sep->se_flags |= SEF_CPPPD; 309*0Sstevel@tonic-gate } 310*0Sstevel@tonic-gate if (sep->se_path == NULL) { 311*0Sstevel@tonic-gate sep->se_path = sedefp->se_path; 312*0Sstevel@tonic-gate sep->se_flags |= SEF_CPATH; 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate if (sep->se_extra == NULL) { 315*0Sstevel@tonic-gate sep->se_extra = sedefp->se_extra; 316*0Sstevel@tonic-gate sep->se_flags |= SEF_CEXTRA; 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate if (sep->se_log == NULL) { 319*0Sstevel@tonic-gate sep->se_log = sedefp->se_log; 320*0Sstevel@tonic-gate sep->se_flags |= SEF_CLOG; 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate if (!(sep->se_flags & SEF_UIDSET) && 323*0Sstevel@tonic-gate (sedefp->se_flags & SEF_UIDSET)) { 324*0Sstevel@tonic-gate sep->se_uid = sedefp->se_uid; 325*0Sstevel@tonic-gate sep->se_flags |= SEF_UIDSET; 326*0Sstevel@tonic-gate } 327*0Sstevel@tonic-gate if (!(sep->se_flags & SEF_GIDSET) && 328*0Sstevel@tonic-gate (sedefp->se_flags & SEF_GIDSET)) { 329*0Sstevel@tonic-gate sep->se_gid = sedefp->se_gid; 330*0Sstevel@tonic-gate sep->se_flags |= SEF_GIDSET; 331*0Sstevel@tonic-gate } 332*0Sstevel@tonic-gate if (!(sep->se_flags & (SEF_WILD|SEF_NOWILD))) 333*0Sstevel@tonic-gate sep->se_flags |= sedefp->se_flags & 334*0Sstevel@tonic-gate (SEF_WILD|SEF_NOWILD); 335*0Sstevel@tonic-gate if (!(sep->se_flags & SEF_DEBUGCLR)) { 336*0Sstevel@tonic-gate sep->se_debug += sedefp->se_debug; 337*0Sstevel@tonic-gate sep->se_flags |= sedefp->se_flags & 338*0Sstevel@tonic-gate SEF_DEBUGCLR; 339*0Sstevel@tonic-gate } 340*0Sstevel@tonic-gate cfile = cfile->pf_prev; 341*0Sstevel@tonic-gate } 342*0Sstevel@tonic-gate } 343*0Sstevel@tonic-gate /* Revert to global definitions. */ 344*0Sstevel@tonic-gate psp->ps_csvc = &psp->ps_cfile->pf_global; 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate /* Discard a dynamic device list */ 348*0Sstevel@tonic-gate static void 349*0Sstevel@tonic-gate free_device_list(struct device_list *dlp) 350*0Sstevel@tonic-gate { 351*0Sstevel@tonic-gate struct device_list *dln; 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate while (dlp != NULL) { 354*0Sstevel@tonic-gate dln = dlp->dl_next; 355*0Sstevel@tonic-gate free(dlp); 356*0Sstevel@tonic-gate dlp = dln; 357*0Sstevel@tonic-gate } 358*0Sstevel@tonic-gate } 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate /* 361*0Sstevel@tonic-gate * Handle "service <name>" -- finish up previous service definition 362*0Sstevel@tonic-gate * (if any) by copying from global state where necessary, and start 363*0Sstevel@tonic-gate * defining new service. 364*0Sstevel@tonic-gate */ 365*0Sstevel@tonic-gate static int 366*0Sstevel@tonic-gate set_service(struct service_list *slp, const char *str) 367*0Sstevel@tonic-gate { 368*0Sstevel@tonic-gate struct parse_state *psp; 369*0Sstevel@tonic-gate struct per_file *cfile; 370*0Sstevel@tonic-gate 371*0Sstevel@tonic-gate /* Finish current service */ 372*0Sstevel@tonic-gate close_service(slp); 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate /* Start new service */ 375*0Sstevel@tonic-gate psp = slp->sl_parse; 376*0Sstevel@tonic-gate slp = (struct service_list *)calloc(sizeof (*slp) + strlen(str) + 1, 377*0Sstevel@tonic-gate 1); 378*0Sstevel@tonic-gate if (slp == NULL) { 379*0Sstevel@tonic-gate logerr("no memory for service \"%s\"", str); 380*0Sstevel@tonic-gate return (-1); 381*0Sstevel@tonic-gate } 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate /* Add to end of list */ 384*0Sstevel@tonic-gate cfile = psp->ps_cfile; 385*0Sstevel@tonic-gate if (cfile->pf_svc_last == NULL) 386*0Sstevel@tonic-gate cfile->pf_svc = slp; 387*0Sstevel@tonic-gate else 388*0Sstevel@tonic-gate cfile->pf_svc_last->sl_next = slp; 389*0Sstevel@tonic-gate cfile->pf_svc_last = slp; 390*0Sstevel@tonic-gate cfile->pf_nsvc++; 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate /* Fill in initial service entry */ 393*0Sstevel@tonic-gate slp->sl_entry.se_name = (const char *)(slp+1); 394*0Sstevel@tonic-gate (void) strcpy((char *)(slp+1), str); 395*0Sstevel@tonic-gate logdbg("service %s begins", slp->sl_entry.se_name); 396*0Sstevel@tonic-gate slp->sl_serial = psp->ps_serial++; 397*0Sstevel@tonic-gate slp->sl_parse = psp; 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate /* This is now the current service that we're defining. */ 400*0Sstevel@tonic-gate psp->ps_csvc = slp; 401*0Sstevel@tonic-gate return (0); 402*0Sstevel@tonic-gate } 403*0Sstevel@tonic-gate 404*0Sstevel@tonic-gate /* 405*0Sstevel@tonic-gate * Handle both "wildcard" and "nowildcard" options. 406*0Sstevel@tonic-gate */ 407*0Sstevel@tonic-gate static int 408*0Sstevel@tonic-gate set_wildcard(struct service_list *slp, const char *str) 409*0Sstevel@tonic-gate { 410*0Sstevel@tonic-gate /* Allow global context to switch back and forth without error. */ 411*0Sstevel@tonic-gate if (!ISGLOBAL(slp) && 412*0Sstevel@tonic-gate (slp->sl_entry.se_flags & (SEF_WILD|SEF_NOWILD))) { 413*0Sstevel@tonic-gate logdbg("%s: extra \"%s\" ignored", 414*0Sstevel@tonic-gate slp->sl_parse->ps_cfile->pf_name, str); 415*0Sstevel@tonic-gate return (0); 416*0Sstevel@tonic-gate } 417*0Sstevel@tonic-gate slp->sl_entry.se_flags = 418*0Sstevel@tonic-gate (slp->sl_entry.se_flags & ~(SEF_WILD|SEF_NOWILD)) | 419*0Sstevel@tonic-gate (*str == 'n' ? SEF_NOWILD : SEF_WILD); 420*0Sstevel@tonic-gate return (0); 421*0Sstevel@tonic-gate } 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate /* 424*0Sstevel@tonic-gate * Handle "debug" option. 425*0Sstevel@tonic-gate */ 426*0Sstevel@tonic-gate /*ARGSUSED*/ 427*0Sstevel@tonic-gate static int 428*0Sstevel@tonic-gate set_debug(struct service_list *slp, const char *str) 429*0Sstevel@tonic-gate { 430*0Sstevel@tonic-gate slp->sl_entry.se_debug++; 431*0Sstevel@tonic-gate if (ISGLOBAL(slp) && (slp->sl_parse->ps_flags & PSF_SETLEVEL)) { 432*0Sstevel@tonic-gate log_level = slp->sl_entry.se_debug; 433*0Sstevel@tonic-gate } 434*0Sstevel@tonic-gate return (0); 435*0Sstevel@tonic-gate } 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate /* 438*0Sstevel@tonic-gate * Handle "nodebug" option. 439*0Sstevel@tonic-gate */ 440*0Sstevel@tonic-gate /*ARGSUSED*/ 441*0Sstevel@tonic-gate static int 442*0Sstevel@tonic-gate set_nodebug(struct service_list *slp, const char *str) 443*0Sstevel@tonic-gate { 444*0Sstevel@tonic-gate slp->sl_entry.se_flags |= SEF_DEBUGCLR; 445*0Sstevel@tonic-gate slp->sl_entry.se_debug = 0; 446*0Sstevel@tonic-gate if (ISGLOBAL(slp) && (slp->sl_parse->ps_flags & PSF_SETLEVEL)) { 447*0Sstevel@tonic-gate log_level = slp->sl_entry.se_debug; 448*0Sstevel@tonic-gate } 449*0Sstevel@tonic-gate return (0); 450*0Sstevel@tonic-gate } 451*0Sstevel@tonic-gate 452*0Sstevel@tonic-gate /* 453*0Sstevel@tonic-gate * Handle all plain string options; "server", "pppd", "path", "extra", 454*0Sstevel@tonic-gate * and "log". 455*0Sstevel@tonic-gate */ 456*0Sstevel@tonic-gate static int 457*0Sstevel@tonic-gate set_string(struct service_list *slp, const char *str) 458*0Sstevel@tonic-gate { 459*0Sstevel@tonic-gate char **cpp; 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate assert(!(slp->sl_entry.se_flags & 462*0Sstevel@tonic-gate (SEF_CSERVER|SEF_CPPPD|SEF_CPATH|SEF_CEXTRA|SEF_CLOG))); 463*0Sstevel@tonic-gate switch (slp->sl_parse->ps_state) { 464*0Sstevel@tonic-gate case ksServer: 465*0Sstevel@tonic-gate cpp = &slp->sl_entry.se_server; 466*0Sstevel@tonic-gate break; 467*0Sstevel@tonic-gate case ksPppd: 468*0Sstevel@tonic-gate cpp = &slp->sl_entry.se_pppd; 469*0Sstevel@tonic-gate break; 470*0Sstevel@tonic-gate case ksPath: 471*0Sstevel@tonic-gate cpp = &slp->sl_entry.se_path; 472*0Sstevel@tonic-gate break; 473*0Sstevel@tonic-gate case ksExtra: 474*0Sstevel@tonic-gate cpp = &slp->sl_entry.se_extra; 475*0Sstevel@tonic-gate break; 476*0Sstevel@tonic-gate case ksLog: 477*0Sstevel@tonic-gate cpp = &slp->sl_entry.se_log; 478*0Sstevel@tonic-gate break; 479*0Sstevel@tonic-gate default: 480*0Sstevel@tonic-gate assert(0); 481*0Sstevel@tonic-gate return (-1); 482*0Sstevel@tonic-gate } 483*0Sstevel@tonic-gate if (*cpp != NULL) 484*0Sstevel@tonic-gate free(*cpp); 485*0Sstevel@tonic-gate *cpp = strsave(str); 486*0Sstevel@tonic-gate return (0); 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate /* 490*0Sstevel@tonic-gate * Handle "file <name>" option. Close out current service (if any) 491*0Sstevel@tonic-gate * and begin parsing from new file. 492*0Sstevel@tonic-gate */ 493*0Sstevel@tonic-gate static int 494*0Sstevel@tonic-gate set_file(struct service_list *slp, const char *str) 495*0Sstevel@tonic-gate { 496*0Sstevel@tonic-gate FILE *fp; 497*0Sstevel@tonic-gate struct per_file *pfp; 498*0Sstevel@tonic-gate struct parse_state *psp; 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate close_service(slp); 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate if ((fp = fopen(str, "r")) == NULL) { 503*0Sstevel@tonic-gate logwarn("%s: %s: %s", slp->sl_parse->ps_cfile->pf_name, str, 504*0Sstevel@tonic-gate mystrerror(errno)); 505*0Sstevel@tonic-gate return (-1); 506*0Sstevel@tonic-gate } 507*0Sstevel@tonic-gate pfp = (struct per_file *)calloc(sizeof (*pfp) + strlen(str) + 1, 1); 508*0Sstevel@tonic-gate if (pfp == NULL) { 509*0Sstevel@tonic-gate logerr("no memory for parsing file %s", str); 510*0Sstevel@tonic-gate (void) fclose(fp); 511*0Sstevel@tonic-gate return (-1); 512*0Sstevel@tonic-gate } 513*0Sstevel@tonic-gate logdbg("config file %s open", str); 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate /* Fill in new file structure. */ 516*0Sstevel@tonic-gate pfp->pf_name = (const char *)(pfp+1); 517*0Sstevel@tonic-gate (void) strcpy((char *)(pfp+1), str); 518*0Sstevel@tonic-gate pfp->pf_input = fp; 519*0Sstevel@tonic-gate psp = slp->sl_parse; 520*0Sstevel@tonic-gate pfp->pf_prev = psp->ps_cfile; 521*0Sstevel@tonic-gate psp->ps_cfile = pfp; 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate /* Start off in global context for this file. */ 524*0Sstevel@tonic-gate psp->ps_csvc = &pfp->pf_global; 525*0Sstevel@tonic-gate pfp->pf_global.sl_parse = psp; 526*0Sstevel@tonic-gate pfp->pf_global.sl_entry.se_name = "<global>"; 527*0Sstevel@tonic-gate return (0); 528*0Sstevel@tonic-gate } 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate /* 531*0Sstevel@tonic-gate * Handle "device <list>" option. 532*0Sstevel@tonic-gate */ 533*0Sstevel@tonic-gate static int 534*0Sstevel@tonic-gate set_device(struct service_list *slp, const char *str) 535*0Sstevel@tonic-gate { 536*0Sstevel@tonic-gate struct parse_state *psp = slp->sl_parse; 537*0Sstevel@tonic-gate struct device_list *dlp; 538*0Sstevel@tonic-gate struct device_list *dln; 539*0Sstevel@tonic-gate struct device_list **dlpp; 540*0Sstevel@tonic-gate const char *cp; 541*0Sstevel@tonic-gate int len; 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate /* Can't use this option in the per-device files. */ 544*0Sstevel@tonic-gate if (psp->ps_flags & PSF_PERDEV) { 545*0Sstevel@tonic-gate logerr("\"device %s\" ignored in %s", str, 546*0Sstevel@tonic-gate psp->ps_cfile->pf_name); 547*0Sstevel@tonic-gate return (0); 548*0Sstevel@tonic-gate } 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate if (strcmp(str, "*") == 0 || strcmp(str, "all") == 0) { 551*0Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CDEV)) 552*0Sstevel@tonic-gate free_device_list(slp->sl_dev); 553*0Sstevel@tonic-gate slp->sl_dev = psp->ps_star; 554*0Sstevel@tonic-gate slp->sl_entry.se_flags |= SEF_CDEV; 555*0Sstevel@tonic-gate } else { 556*0Sstevel@tonic-gate dlpp = &dlp; 557*0Sstevel@tonic-gate for (;;) { 558*0Sstevel@tonic-gate while (isspace(*str) || *str == ',') 559*0Sstevel@tonic-gate str++; 560*0Sstevel@tonic-gate if (*str == '\0') 561*0Sstevel@tonic-gate break; 562*0Sstevel@tonic-gate cp = str; 563*0Sstevel@tonic-gate while (*str != '\0' && !isspace(*str) && *str != ',') 564*0Sstevel@tonic-gate str++; 565*0Sstevel@tonic-gate len = str - cp; 566*0Sstevel@tonic-gate if ((len == 1 && *cp == '*') || 567*0Sstevel@tonic-gate (len == 3 && strncmp(cp, "all", 3) == 0)) { 568*0Sstevel@tonic-gate logerr("%s: cannot use %.*s in device list", 569*0Sstevel@tonic-gate psp->ps_cfile->pf_name, len, cp); 570*0Sstevel@tonic-gate continue; 571*0Sstevel@tonic-gate } 572*0Sstevel@tonic-gate dln = (struct device_list *)malloc(sizeof (*dln) + 573*0Sstevel@tonic-gate len + 1); 574*0Sstevel@tonic-gate if (dln == NULL) { 575*0Sstevel@tonic-gate logerr("no memory for device name"); 576*0Sstevel@tonic-gate break; 577*0Sstevel@tonic-gate } 578*0Sstevel@tonic-gate dln->dl_name = (const char *)(dln + 1); 579*0Sstevel@tonic-gate /* Cannot use strcpy because cp isn't terminated. */ 580*0Sstevel@tonic-gate (void) memcpy(dln + 1, cp, len); 581*0Sstevel@tonic-gate ((char *)(dln + 1))[len] = '\0'; 582*0Sstevel@tonic-gate logdbg("%s: device %s", psp->ps_cfile->pf_name, 583*0Sstevel@tonic-gate dln->dl_name); 584*0Sstevel@tonic-gate *dlpp = dln; 585*0Sstevel@tonic-gate dlpp = &dln->dl_next; 586*0Sstevel@tonic-gate } 587*0Sstevel@tonic-gate *dlpp = NULL; 588*0Sstevel@tonic-gate 589*0Sstevel@tonic-gate dlpp = &slp->sl_dev; 590*0Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CDEV)) 591*0Sstevel@tonic-gate while (*dlpp != NULL) 592*0Sstevel@tonic-gate dlpp = &(*dlpp)->dl_next; 593*0Sstevel@tonic-gate *dlpp = dlp; 594*0Sstevel@tonic-gate slp->sl_entry.se_flags &= ~SEF_CDEV; 595*0Sstevel@tonic-gate } 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate return (0); 598*0Sstevel@tonic-gate } 599*0Sstevel@tonic-gate 600*0Sstevel@tonic-gate /* 601*0Sstevel@tonic-gate * Handle <list> portion of "client [except] <list>" option. Attach 602*0Sstevel@tonic-gate * to list of filters in reverse order. 603*0Sstevel@tonic-gate */ 604*0Sstevel@tonic-gate static int 605*0Sstevel@tonic-gate set_client(struct service_list *slp, const char *str) 606*0Sstevel@tonic-gate { 607*0Sstevel@tonic-gate struct parse_state *psp = slp->sl_parse; 608*0Sstevel@tonic-gate struct filter_entry *fep; 609*0Sstevel@tonic-gate struct filter_entry *fen; 610*0Sstevel@tonic-gate const char *cp; 611*0Sstevel@tonic-gate int len; 612*0Sstevel@tonic-gate char hbuf[MAXHOSTNAMELEN]; 613*0Sstevel@tonic-gate struct ether_addr ea; 614*0Sstevel@tonic-gate struct ether_addr mask; 615*0Sstevel@tonic-gate uchar_t *ucp; 616*0Sstevel@tonic-gate uchar_t *mcp; 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate /* Head of list. */ 619*0Sstevel@tonic-gate fep = slp->sl_entry.se_flist; 620*0Sstevel@tonic-gate for (;;) { 621*0Sstevel@tonic-gate while (isspace(*str) || *str == ',') 622*0Sstevel@tonic-gate str++; 623*0Sstevel@tonic-gate if (*str == '\0') 624*0Sstevel@tonic-gate break; 625*0Sstevel@tonic-gate cp = str; 626*0Sstevel@tonic-gate while (*str != '\0' && !isspace(*str) && *str != ',') 627*0Sstevel@tonic-gate str++; 628*0Sstevel@tonic-gate len = str - cp; 629*0Sstevel@tonic-gate (void) memcpy(hbuf, cp, len); 630*0Sstevel@tonic-gate hbuf[len] = '\0'; 631*0Sstevel@tonic-gate mcp = mask.ether_addr_octet; 632*0Sstevel@tonic-gate mcp[0] = mcp[1] = mcp[2] = mcp[3] = mcp[4] = mcp[5] = 0xFF; 633*0Sstevel@tonic-gate if (ether_hostton(hbuf, &ea) != 0) { 634*0Sstevel@tonic-gate ucp = ea.ether_addr_octet; 635*0Sstevel@tonic-gate while (cp < str) { 636*0Sstevel@tonic-gate if (ucp >= ea.ether_addr_octet + sizeof (ea)) 637*0Sstevel@tonic-gate break; 638*0Sstevel@tonic-gate if (*cp == '*') { 639*0Sstevel@tonic-gate *mcp++ = *ucp++ = 0; 640*0Sstevel@tonic-gate cp++; 641*0Sstevel@tonic-gate } else { 642*0Sstevel@tonic-gate if (!isxdigit(*cp)) 643*0Sstevel@tonic-gate break; 644*0Sstevel@tonic-gate *ucp = hexdecode(*cp++); 645*0Sstevel@tonic-gate if (cp < str && isxdigit(*cp)) { 646*0Sstevel@tonic-gate *ucp = (*ucp << 4) | 647*0Sstevel@tonic-gate hexdecode(*cp++); 648*0Sstevel@tonic-gate } 649*0Sstevel@tonic-gate ucp++; 650*0Sstevel@tonic-gate *mcp++ = 0xFF; 651*0Sstevel@tonic-gate } 652*0Sstevel@tonic-gate if (cp < str) { 653*0Sstevel@tonic-gate if (*cp != ':' || cp + 1 == str) 654*0Sstevel@tonic-gate break; 655*0Sstevel@tonic-gate cp++; 656*0Sstevel@tonic-gate } 657*0Sstevel@tonic-gate } 658*0Sstevel@tonic-gate if (cp < str) { 659*0Sstevel@tonic-gate logerr("%s: illegal Ethernet address %.*s", 660*0Sstevel@tonic-gate psp->ps_cfile->pf_name, len, cp); 661*0Sstevel@tonic-gate continue; 662*0Sstevel@tonic-gate } 663*0Sstevel@tonic-gate } 664*0Sstevel@tonic-gate fen = (struct filter_entry *)malloc(sizeof (*fen)); 665*0Sstevel@tonic-gate if (fen == NULL) { 666*0Sstevel@tonic-gate logerr("unable to allocate memory for filter"); 667*0Sstevel@tonic-gate break; 668*0Sstevel@tonic-gate } 669*0Sstevel@tonic-gate fen->fe_isexcept = psp->ps_state == ksClientE; 670*0Sstevel@tonic-gate fen->fe_prevcopy = 0; 671*0Sstevel@tonic-gate (void) memcpy(&fen->fe_mac, &ea, sizeof (fen->fe_mac)); 672*0Sstevel@tonic-gate (void) memcpy(&fen->fe_mask, &mask, sizeof (fen->fe_mask)); 673*0Sstevel@tonic-gate fen->fe_prev = fep; 674*0Sstevel@tonic-gate fep = fen; 675*0Sstevel@tonic-gate } 676*0Sstevel@tonic-gate slp->sl_entry.se_flist = fep; 677*0Sstevel@tonic-gate return (0); 678*0Sstevel@tonic-gate } 679*0Sstevel@tonic-gate 680*0Sstevel@tonic-gate /* 681*0Sstevel@tonic-gate * Handle "user <name>" option. 682*0Sstevel@tonic-gate */ 683*0Sstevel@tonic-gate static int 684*0Sstevel@tonic-gate set_user(struct service_list *slp, const char *str) 685*0Sstevel@tonic-gate { 686*0Sstevel@tonic-gate struct passwd *pw; 687*0Sstevel@tonic-gate char *cp; 688*0Sstevel@tonic-gate uid_t myuid, uid; 689*0Sstevel@tonic-gate 690*0Sstevel@tonic-gate if ((pw = getpwnam(str)) == NULL) { 691*0Sstevel@tonic-gate uid = (uid_t)strtol(str, &cp, 0); 692*0Sstevel@tonic-gate if (str == cp || *cp != '\0') { 693*0Sstevel@tonic-gate logerr("%s: bad user name \"%s\"", 694*0Sstevel@tonic-gate slp->sl_parse->ps_cfile->pf_name, str); 695*0Sstevel@tonic-gate return (0); 696*0Sstevel@tonic-gate } 697*0Sstevel@tonic-gate } else { 698*0Sstevel@tonic-gate uid = pw->pw_uid; 699*0Sstevel@tonic-gate } 700*0Sstevel@tonic-gate slp->sl_entry.se_uid = uid; 701*0Sstevel@tonic-gate myuid = getuid(); 702*0Sstevel@tonic-gate if (myuid != 0) { 703*0Sstevel@tonic-gate if (myuid == uid) 704*0Sstevel@tonic-gate return (0); 705*0Sstevel@tonic-gate logdbg("%s: not root; ignoring attempt to set UID %d (%s)", 706*0Sstevel@tonic-gate slp->sl_parse->ps_cfile->pf_name, uid, str); 707*0Sstevel@tonic-gate return (0); 708*0Sstevel@tonic-gate } 709*0Sstevel@tonic-gate slp->sl_entry.se_flags |= SEF_UIDSET; 710*0Sstevel@tonic-gate return (0); 711*0Sstevel@tonic-gate } 712*0Sstevel@tonic-gate 713*0Sstevel@tonic-gate /* 714*0Sstevel@tonic-gate * Handle "group <name>" option. 715*0Sstevel@tonic-gate */ 716*0Sstevel@tonic-gate static int 717*0Sstevel@tonic-gate set_group(struct service_list *slp, const char *str) 718*0Sstevel@tonic-gate { 719*0Sstevel@tonic-gate struct group *gr; 720*0Sstevel@tonic-gate char *cp; 721*0Sstevel@tonic-gate gid_t gid; 722*0Sstevel@tonic-gate 723*0Sstevel@tonic-gate if ((gr = getgrnam(str)) == NULL) { 724*0Sstevel@tonic-gate gid = (gid_t)strtol(str, &cp, 0); 725*0Sstevel@tonic-gate if (str == cp || *cp != '\0') { 726*0Sstevel@tonic-gate logerr("%s: bad group name \"%s\"", 727*0Sstevel@tonic-gate slp->sl_parse->ps_cfile->pf_name, str); 728*0Sstevel@tonic-gate return (0); 729*0Sstevel@tonic-gate } 730*0Sstevel@tonic-gate } else { 731*0Sstevel@tonic-gate gid = gr->gr_gid; 732*0Sstevel@tonic-gate } 733*0Sstevel@tonic-gate slp->sl_entry.se_gid = gid; 734*0Sstevel@tonic-gate if (getuid() != 0) { 735*0Sstevel@tonic-gate logdbg("%s: not root; ignoring attempt to set GID %d (%s)", 736*0Sstevel@tonic-gate slp->sl_parse->ps_cfile->pf_name, gid, str); 737*0Sstevel@tonic-gate return (0); 738*0Sstevel@tonic-gate } 739*0Sstevel@tonic-gate slp->sl_entry.se_flags |= SEF_GIDSET; 740*0Sstevel@tonic-gate return (0); 741*0Sstevel@tonic-gate } 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate /* 744*0Sstevel@tonic-gate * This state machine is used to parse the configuration files. The 745*0Sstevel@tonic-gate * "kwe_in" is the state in which the keyword is recognized. The 746*0Sstevel@tonic-gate * "kwe_out" is the state that the keyword produces. 747*0Sstevel@tonic-gate */ 748*0Sstevel@tonic-gate struct kw_entry { 749*0Sstevel@tonic-gate const char *kwe_word; 750*0Sstevel@tonic-gate enum key_state kwe_in; 751*0Sstevel@tonic-gate enum key_state kwe_out; 752*0Sstevel@tonic-gate int (*kwe_func)(struct service_list *slp, const char *str); 753*0Sstevel@tonic-gate }; 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate static const struct kw_entry key_list[] = { 756*0Sstevel@tonic-gate { "service", ksDefault, ksService, NULL }, 757*0Sstevel@tonic-gate { "device", ksDefault, ksDevice, NULL }, 758*0Sstevel@tonic-gate { "client", ksDefault, ksClient, NULL }, 759*0Sstevel@tonic-gate { "except", ksClient, ksClientE, NULL }, 760*0Sstevel@tonic-gate { "wildcard", ksDefault, ksDefault, set_wildcard }, 761*0Sstevel@tonic-gate { "nowildcard", ksDefault, ksDefault, set_wildcard }, 762*0Sstevel@tonic-gate { "server", ksDefault, ksServer, NULL }, 763*0Sstevel@tonic-gate { "pppd", ksDefault, ksPppd, NULL }, 764*0Sstevel@tonic-gate { "debug", ksDefault, ksDefault, set_debug }, 765*0Sstevel@tonic-gate { "nodebug", ksDefault, ksDefault, set_nodebug }, 766*0Sstevel@tonic-gate { "file", ksDefault, ksFile, NULL }, 767*0Sstevel@tonic-gate { "path", ksDefault, ksPath, NULL }, 768*0Sstevel@tonic-gate { "extra", ksDefault, ksExtra, NULL }, 769*0Sstevel@tonic-gate { "log", ksDefault, ksLog, NULL }, 770*0Sstevel@tonic-gate { "user", ksDefault, ksUser, NULL }, 771*0Sstevel@tonic-gate { "group", ksDefault, ksGroup, NULL }, 772*0Sstevel@tonic-gate /* Wildcards only past this point. */ 773*0Sstevel@tonic-gate { "", ksService, ksDefault, set_service }, 774*0Sstevel@tonic-gate { "", ksDevice, ksDefault, set_device }, 775*0Sstevel@tonic-gate { "", ksClient, ksDefault, set_client }, 776*0Sstevel@tonic-gate { "", ksClientE, ksDefault, set_client }, 777*0Sstevel@tonic-gate { "", ksServer, ksDefault, set_string }, 778*0Sstevel@tonic-gate { "", ksPppd, ksDefault, set_string }, 779*0Sstevel@tonic-gate { "", ksFile, ksDefault, set_file }, 780*0Sstevel@tonic-gate { "", ksPath, ksDefault, set_string }, 781*0Sstevel@tonic-gate { "", ksExtra, ksDefault, set_string }, 782*0Sstevel@tonic-gate { "", ksLog, ksDefault, set_string }, 783*0Sstevel@tonic-gate { "", ksUser, ksDefault, set_user }, 784*0Sstevel@tonic-gate { "", ksGroup, ksDefault, set_group }, 785*0Sstevel@tonic-gate { NULL, ksDefault, ksDefault, NULL } 786*0Sstevel@tonic-gate }; 787*0Sstevel@tonic-gate 788*0Sstevel@tonic-gate /* 789*0Sstevel@tonic-gate * Produce a string for the keyword that would have gotten us into the 790*0Sstevel@tonic-gate * current state. 791*0Sstevel@tonic-gate */ 792*0Sstevel@tonic-gate static const char * 793*0Sstevel@tonic-gate after_key(enum key_state kstate) 794*0Sstevel@tonic-gate { 795*0Sstevel@tonic-gate const struct kw_entry *kep; 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate for (kep = key_list; kep->kwe_word != NULL; kep++) 798*0Sstevel@tonic-gate if (kep->kwe_out == kstate) 799*0Sstevel@tonic-gate return (kep->kwe_word); 800*0Sstevel@tonic-gate return ("nothing"); 801*0Sstevel@tonic-gate } 802*0Sstevel@tonic-gate 803*0Sstevel@tonic-gate /* 804*0Sstevel@tonic-gate * Handle end-of-file processing -- close service, close file, revert 805*0Sstevel@tonic-gate * to global context in previous include file nest level. 806*0Sstevel@tonic-gate */ 807*0Sstevel@tonic-gate static void 808*0Sstevel@tonic-gate file_end(struct parse_state *psp) 809*0Sstevel@tonic-gate { 810*0Sstevel@tonic-gate struct per_file *pfp; 811*0Sstevel@tonic-gate 812*0Sstevel@tonic-gate /* Must not be in the middle of parsing a multi-word sequence now. */ 813*0Sstevel@tonic-gate if (psp->ps_state != ksDefault) { 814*0Sstevel@tonic-gate logerr("%s ends with \"%s\"", psp->ps_cfile->pf_name, 815*0Sstevel@tonic-gate after_key(psp->ps_state)); 816*0Sstevel@tonic-gate psp->ps_state = ksDefault; 817*0Sstevel@tonic-gate } 818*0Sstevel@tonic-gate close_service(psp->ps_csvc); 819*0Sstevel@tonic-gate if ((pfp = psp->ps_cfile) != NULL) { 820*0Sstevel@tonic-gate /* Put this file on the list of finished files. */ 821*0Sstevel@tonic-gate psp->ps_cfile = pfp->pf_prev; 822*0Sstevel@tonic-gate pfp->pf_prev = psp->ps_files; 823*0Sstevel@tonic-gate psp->ps_files = pfp; 824*0Sstevel@tonic-gate if (pfp->pf_input != NULL) { 825*0Sstevel@tonic-gate logdbg("file %s closed", pfp->pf_name); 826*0Sstevel@tonic-gate (void) fclose(pfp->pf_input); 827*0Sstevel@tonic-gate pfp->pf_input = NULL; 828*0Sstevel@tonic-gate } 829*0Sstevel@tonic-gate 830*0Sstevel@tonic-gate /* Back up to previous file, if any, and set global context. */ 831*0Sstevel@tonic-gate if ((pfp = psp->ps_cfile) != NULL) 832*0Sstevel@tonic-gate psp->ps_csvc = &pfp->pf_global; 833*0Sstevel@tonic-gate } 834*0Sstevel@tonic-gate } 835*0Sstevel@tonic-gate 836*0Sstevel@tonic-gate /* 837*0Sstevel@tonic-gate * Dispatch a single keyword against the parser state machine or 838*0Sstevel@tonic-gate * handle an environment variable assignment. The input is a string 839*0Sstevel@tonic-gate * containing the single word to be dispatched. 840*0Sstevel@tonic-gate */ 841*0Sstevel@tonic-gate static int 842*0Sstevel@tonic-gate dispatch_keyword(struct parse_state *psp, const char *keybuf) 843*0Sstevel@tonic-gate { 844*0Sstevel@tonic-gate const struct kw_entry *kep; 845*0Sstevel@tonic-gate int retv; 846*0Sstevel@tonic-gate char *cp; 847*0Sstevel@tonic-gate char *env; 848*0Sstevel@tonic-gate char **evlist; 849*0Sstevel@tonic-gate int len; 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate retv = 0; 852*0Sstevel@tonic-gate for (kep = key_list; kep->kwe_word != NULL; kep++) { 853*0Sstevel@tonic-gate if (kep->kwe_in == psp->ps_state && 854*0Sstevel@tonic-gate (*kep->kwe_word == '\0' || 855*0Sstevel@tonic-gate strcasecmp(kep->kwe_word, keybuf) == 0)) { 856*0Sstevel@tonic-gate if (kep->kwe_func != NULL) 857*0Sstevel@tonic-gate retv = (*kep->kwe_func)(psp->ps_csvc, keybuf); 858*0Sstevel@tonic-gate psp->ps_state = kep->kwe_out; 859*0Sstevel@tonic-gate return (retv); 860*0Sstevel@tonic-gate } 861*0Sstevel@tonic-gate } 862*0Sstevel@tonic-gate if (strchr(keybuf, '=') != NULL) { 863*0Sstevel@tonic-gate if ((cp = strsave(keybuf)) == NULL) { 864*0Sstevel@tonic-gate logerr("no memory to save %s", keybuf); 865*0Sstevel@tonic-gate return (0); 866*0Sstevel@tonic-gate } 867*0Sstevel@tonic-gate len = (strchr(cp, '=') - cp) + 1; 868*0Sstevel@tonic-gate if ((evlist = psp->ps_evlist) == NULL) { 869*0Sstevel@tonic-gate psp->ps_evlist = evlist = 870*0Sstevel@tonic-gate (char **)malloc(8 * sizeof (*evlist)); 871*0Sstevel@tonic-gate if (evlist == NULL) { 872*0Sstevel@tonic-gate logerr("no memory for evlist"); 873*0Sstevel@tonic-gate free(cp); 874*0Sstevel@tonic-gate return (0); 875*0Sstevel@tonic-gate } 876*0Sstevel@tonic-gate psp->ps_evsize = 8; 877*0Sstevel@tonic-gate evlist[0] = evlist[1] = NULL; 878*0Sstevel@tonic-gate } else { 879*0Sstevel@tonic-gate while ((env = *evlist) != NULL) { 880*0Sstevel@tonic-gate if (strncmp(cp, env, len) == 0) 881*0Sstevel@tonic-gate break; 882*0Sstevel@tonic-gate evlist++; 883*0Sstevel@tonic-gate } 884*0Sstevel@tonic-gate if (env == NULL && 885*0Sstevel@tonic-gate evlist-psp->ps_evlist >= psp->ps_evsize-1) { 886*0Sstevel@tonic-gate evlist = (char **)realloc(psp->ps_evlist, 887*0Sstevel@tonic-gate (psp->ps_evsize + 8) * sizeof (*evlist)); 888*0Sstevel@tonic-gate if (evlist == NULL) { 889*0Sstevel@tonic-gate logerr("cannot realloc evlist to %d", 890*0Sstevel@tonic-gate psp->ps_evsize + 8); 891*0Sstevel@tonic-gate free(cp); 892*0Sstevel@tonic-gate return (0); 893*0Sstevel@tonic-gate } 894*0Sstevel@tonic-gate psp->ps_evlist = evlist; 895*0Sstevel@tonic-gate evlist += psp->ps_evsize - 1; 896*0Sstevel@tonic-gate psp->ps_evsize += 8; 897*0Sstevel@tonic-gate evlist[1] = NULL; 898*0Sstevel@tonic-gate } 899*0Sstevel@tonic-gate } 900*0Sstevel@tonic-gate logdbg("setenv \"%s\"", cp); 901*0Sstevel@tonic-gate if (*evlist != NULL) 902*0Sstevel@tonic-gate free(*evlist); 903*0Sstevel@tonic-gate *evlist = cp; 904*0Sstevel@tonic-gate return (0); 905*0Sstevel@tonic-gate } 906*0Sstevel@tonic-gate logerr("%s: unknown keyword '%s'", psp->ps_cfile->pf_name, keybuf); 907*0Sstevel@tonic-gate return (-1); 908*0Sstevel@tonic-gate } 909*0Sstevel@tonic-gate 910*0Sstevel@tonic-gate /* 911*0Sstevel@tonic-gate * Modified version of standard getenv; looks in locally-stored 912*0Sstevel@tonic-gate * environment first. This function exists because we need to be able 913*0Sstevel@tonic-gate * to revert to the original environment during a reread (SIGHUP), and 914*0Sstevel@tonic-gate * the putenv() function overwrites that environment. 915*0Sstevel@tonic-gate */ 916*0Sstevel@tonic-gate static char * 917*0Sstevel@tonic-gate my_getenv(struct parse_state *psp, char *estr) 918*0Sstevel@tonic-gate { 919*0Sstevel@tonic-gate char **evlist, *ent; 920*0Sstevel@tonic-gate int elen; 921*0Sstevel@tonic-gate 922*0Sstevel@tonic-gate if (psp != NULL && (evlist = psp->ps_evlist) != NULL) { 923*0Sstevel@tonic-gate elen = strlen(estr); 924*0Sstevel@tonic-gate while ((ent = *evlist++) != NULL) { 925*0Sstevel@tonic-gate if (strncmp(ent, estr, elen) == 0 && 926*0Sstevel@tonic-gate ent[elen] == '=') 927*0Sstevel@tonic-gate return (ent + elen + 1); 928*0Sstevel@tonic-gate } 929*0Sstevel@tonic-gate } 930*0Sstevel@tonic-gate return (getenv(estr)); 931*0Sstevel@tonic-gate } 932*0Sstevel@tonic-gate 933*0Sstevel@tonic-gate /* 934*0Sstevel@tonic-gate * Expand an environment variable at the end of current buffer and 935*0Sstevel@tonic-gate * return pointer to next spot in buffer for character append. psp 936*0Sstevel@tonic-gate * context may be null. 937*0Sstevel@tonic-gate */ 938*0Sstevel@tonic-gate static char * 939*0Sstevel@tonic-gate env_replace(struct parse_state *psp, char *keybuf, char kwstate) 940*0Sstevel@tonic-gate { 941*0Sstevel@tonic-gate char *cpe; 942*0Sstevel@tonic-gate char *cp; 943*0Sstevel@tonic-gate 944*0Sstevel@tonic-gate if ((cp = strrchr(keybuf, kwstate)) != NULL) { 945*0Sstevel@tonic-gate if ((cpe = my_getenv(psp, cp + 1)) != NULL) { 946*0Sstevel@tonic-gate *cp = '\0'; 947*0Sstevel@tonic-gate (void) strncat(cp, cpe, 948*0Sstevel@tonic-gate MAX_KEYWORD - (cp - keybuf) - 1); 949*0Sstevel@tonic-gate keybuf[MAX_KEYWORD - 1] = '\0'; 950*0Sstevel@tonic-gate cp += strlen(cp); 951*0Sstevel@tonic-gate } else { 952*0Sstevel@tonic-gate logerr("unknown variable \"%s\"", cp + 1); 953*0Sstevel@tonic-gate } 954*0Sstevel@tonic-gate } else { 955*0Sstevel@tonic-gate /* Should not occur. */ 956*0Sstevel@tonic-gate cp = keybuf + strlen(keybuf); 957*0Sstevel@tonic-gate } 958*0Sstevel@tonic-gate return (cp); 959*0Sstevel@tonic-gate } 960*0Sstevel@tonic-gate 961*0Sstevel@tonic-gate /* 962*0Sstevel@tonic-gate * Given a character-at-a-time input function, get a delimited keyword 963*0Sstevel@tonic-gate * from the input. This function handles the usual escape sequences, 964*0Sstevel@tonic-gate * quoting, commenting, and environment variable expansion. 965*0Sstevel@tonic-gate * 966*0Sstevel@tonic-gate * The standard wordexp(3C) function isn't used here because the POSIX 967*0Sstevel@tonic-gate * definition is hard to use, and the Solaris implementation is 968*0Sstevel@tonic-gate * resource-intensive and insecure. The "hard-to-use" part is that 969*0Sstevel@tonic-gate * wordexp expands only variables from the environment, and can't 970*0Sstevel@tonic-gate * handle an environment overlay. Instead, the caller must use the 971*0Sstevel@tonic-gate * feeble putenv/getenv interface, and rewinding to the initial 972*0Sstevel@tonic-gate * environment without leaking storage is hard. The Solaris 973*0Sstevel@tonic-gate * implementation invokes an undocumented extensions via 974*0Sstevel@tonic-gate * fork/exec("/bin/ksh -\005 %s") for every invocation, and gathers 975*0Sstevel@tonic-gate * the expanded result with pipe. This makes it slow to execute and 976*0Sstevel@tonic-gate * exposes the string being expanded to users with access to "ps -f." 977*0Sstevel@tonic-gate * 978*0Sstevel@tonic-gate * psp may be null; it's used only for environment variable expansion. 979*0Sstevel@tonic-gate * Input "flag" is 1 to ignore EOL, '#', and '$'; 0 for normal file parsing. 980*0Sstevel@tonic-gate * 981*0Sstevel@tonic-gate * Returns: 982*0Sstevel@tonic-gate * 0 - keyword parsed. 983*0Sstevel@tonic-gate * 1 - end of file; no keyword. 984*0Sstevel@tonic-gate * 2 - end of file after this keyword. 985*0Sstevel@tonic-gate */ 986*0Sstevel@tonic-gate static int 987*0Sstevel@tonic-gate getkeyword(struct parse_state *psp, char *keybuf, int keymax, 988*0Sstevel@tonic-gate int (*nextchr)(void *), void *arg, int flag) 989*0Sstevel@tonic-gate { 990*0Sstevel@tonic-gate char varnest[MAX_NEST]; 991*0Sstevel@tonic-gate char *kbp; 992*0Sstevel@tonic-gate char *vnp; 993*0Sstevel@tonic-gate char chr; 994*0Sstevel@tonic-gate int ichr; 995*0Sstevel@tonic-gate char kwstate; 996*0Sstevel@tonic-gate static const char escstr[] = "a\ab\bf\fn\nr\r"; 997*0Sstevel@tonic-gate const char *cp; 998*0Sstevel@tonic-gate 999*0Sstevel@tonic-gate keymax--; /* Account for trailing NUL byte */ 1000*0Sstevel@tonic-gate 1001*0Sstevel@tonic-gate kwstate = '\0'; 1002*0Sstevel@tonic-gate kbp = keybuf; 1003*0Sstevel@tonic-gate vnp = varnest; 1004*0Sstevel@tonic-gate for (;;) { 1005*0Sstevel@tonic-gate ichr = (*nextchr)(arg); 1006*0Sstevel@tonic-gate chr = (char)ichr; 1007*0Sstevel@tonic-gate tryagain: 1008*0Sstevel@tonic-gate switch (kwstate) { 1009*0Sstevel@tonic-gate case '\\': /* Start of unquoted escape sequence */ 1010*0Sstevel@tonic-gate case '|': /* Start of escape sequence in double quotes */ 1011*0Sstevel@tonic-gate case '~': /* Start of escape sequence in single quotes */ 1012*0Sstevel@tonic-gate /* Convert the character if we can. */ 1013*0Sstevel@tonic-gate if (chr == '\n') 1014*0Sstevel@tonic-gate chr = '\0'; 1015*0Sstevel@tonic-gate else if (isalpha(chr) && 1016*0Sstevel@tonic-gate (cp = strchr(escstr, chr)) != NULL) 1017*0Sstevel@tonic-gate chr = cp[1]; 1018*0Sstevel@tonic-gate /* Revert to previous state */ 1019*0Sstevel@tonic-gate switch (kwstate) { 1020*0Sstevel@tonic-gate case '\\': 1021*0Sstevel@tonic-gate kwstate = 'A'; 1022*0Sstevel@tonic-gate break; 1023*0Sstevel@tonic-gate case '|': 1024*0Sstevel@tonic-gate kwstate = '"'; 1025*0Sstevel@tonic-gate break; 1026*0Sstevel@tonic-gate case '~': 1027*0Sstevel@tonic-gate kwstate = '\''; 1028*0Sstevel@tonic-gate break; 1029*0Sstevel@tonic-gate } 1030*0Sstevel@tonic-gate break; 1031*0Sstevel@tonic-gate case '"': /* In double-quote string */ 1032*0Sstevel@tonic-gate if (!flag && chr == '$') { 1033*0Sstevel@tonic-gate /* Handle variable expansion. */ 1034*0Sstevel@tonic-gate kwstate = '%'; 1035*0Sstevel@tonic-gate chr = '\0'; 1036*0Sstevel@tonic-gate break; 1037*0Sstevel@tonic-gate } 1038*0Sstevel@tonic-gate /* FALLTHROUGH */ 1039*0Sstevel@tonic-gate case '\'': /* In single-quote string */ 1040*0Sstevel@tonic-gate if (chr == '\\') { 1041*0Sstevel@tonic-gate /* Handle start of escape sequence */ 1042*0Sstevel@tonic-gate kwstate = kwstate == '"' ? '|' : '~'; 1043*0Sstevel@tonic-gate chr = '\0'; 1044*0Sstevel@tonic-gate break; 1045*0Sstevel@tonic-gate } 1046*0Sstevel@tonic-gate if (chr == kwstate) { 1047*0Sstevel@tonic-gate /* End of quoted string; revert to normal */ 1048*0Sstevel@tonic-gate kwstate = 'A'; 1049*0Sstevel@tonic-gate chr = '\0'; 1050*0Sstevel@tonic-gate } 1051*0Sstevel@tonic-gate break; 1052*0Sstevel@tonic-gate case '$': /* Start of unquoted variable name */ 1053*0Sstevel@tonic-gate case '%': /* Start of variable name in quoted string */ 1054*0Sstevel@tonic-gate if (chr == '{') { 1055*0Sstevel@tonic-gate /* Variable name is bracketed. */ 1056*0Sstevel@tonic-gate kwstate = chr = 1057*0Sstevel@tonic-gate kwstate == '$' ? '{' : '['; 1058*0Sstevel@tonic-gate break; 1059*0Sstevel@tonic-gate } 1060*0Sstevel@tonic-gate *kbp++ = kwstate = kwstate == '$' ? '+' : '*'; 1061*0Sstevel@tonic-gate /* FALLTHROUGH */ 1062*0Sstevel@tonic-gate case '+': /* Gathering unquoted variable name */ 1063*0Sstevel@tonic-gate case '*': /* Gathering variable name in quoted string */ 1064*0Sstevel@tonic-gate if (chr == '$' && 1065*0Sstevel@tonic-gate vnp < varnest + sizeof (varnest)) { 1066*0Sstevel@tonic-gate *vnp++ = kwstate; 1067*0Sstevel@tonic-gate kwstate = '$'; 1068*0Sstevel@tonic-gate chr = '\0'; 1069*0Sstevel@tonic-gate break; 1070*0Sstevel@tonic-gate } 1071*0Sstevel@tonic-gate if (!isalnum(chr) && chr != '_' && 1072*0Sstevel@tonic-gate chr != '.' && chr != '-') { 1073*0Sstevel@tonic-gate *kbp = '\0'; 1074*0Sstevel@tonic-gate kbp = env_replace(psp, keybuf, kwstate); 1075*0Sstevel@tonic-gate if (vnp > varnest) 1076*0Sstevel@tonic-gate kwstate = *--vnp; 1077*0Sstevel@tonic-gate else 1078*0Sstevel@tonic-gate kwstate = kwstate == '+' ? 1079*0Sstevel@tonic-gate 'A' : '"'; 1080*0Sstevel@tonic-gate /* Go reinterpret in new context */ 1081*0Sstevel@tonic-gate goto tryagain; 1082*0Sstevel@tonic-gate } 1083*0Sstevel@tonic-gate break; 1084*0Sstevel@tonic-gate case '{': /* Gathering bracketed, unquoted var name */ 1085*0Sstevel@tonic-gate case '[': /* Gathering bracketed, quoted var name */ 1086*0Sstevel@tonic-gate if (chr == '}') { 1087*0Sstevel@tonic-gate *kbp = '\0'; 1088*0Sstevel@tonic-gate kbp = env_replace(psp, keybuf, kwstate); 1089*0Sstevel@tonic-gate kwstate = kwstate == '{' ? 'A' : '"'; 1090*0Sstevel@tonic-gate chr = '\0'; 1091*0Sstevel@tonic-gate } 1092*0Sstevel@tonic-gate break; 1093*0Sstevel@tonic-gate case '#': /* Comment before word state */ 1094*0Sstevel@tonic-gate case '@': /* Comment after word state */ 1095*0Sstevel@tonic-gate if (chr == '\n' || chr == '\r' || ichr == EOF) { 1096*0Sstevel@tonic-gate /* At end of line, revert to previous state */ 1097*0Sstevel@tonic-gate kwstate = kwstate == '#' ? '\0' : ' '; 1098*0Sstevel@tonic-gate chr = '\0'; 1099*0Sstevel@tonic-gate break; 1100*0Sstevel@tonic-gate } 1101*0Sstevel@tonic-gate chr = '\0'; 1102*0Sstevel@tonic-gate break; 1103*0Sstevel@tonic-gate case '\0': /* Initial state; no word seen yet. */ 1104*0Sstevel@tonic-gate if (ichr == EOF || isspace(chr)) { 1105*0Sstevel@tonic-gate chr = '\0'; /* Skip over leading spaces */ 1106*0Sstevel@tonic-gate break; 1107*0Sstevel@tonic-gate } 1108*0Sstevel@tonic-gate if (chr == '#') { 1109*0Sstevel@tonic-gate kwstate = '#'; 1110*0Sstevel@tonic-gate chr = '\0'; /* Skip over comments */ 1111*0Sstevel@tonic-gate break; 1112*0Sstevel@tonic-gate } 1113*0Sstevel@tonic-gate /* Start of keyword seen. */ 1114*0Sstevel@tonic-gate kwstate = 'A'; 1115*0Sstevel@tonic-gate /* FALLTHROUGH */ 1116*0Sstevel@tonic-gate default: /* Middle of keyword parsing. */ 1117*0Sstevel@tonic-gate if (ichr == EOF) 1118*0Sstevel@tonic-gate break; 1119*0Sstevel@tonic-gate if (isspace(chr)) { /* Space terminates word */ 1120*0Sstevel@tonic-gate kwstate = ' '; 1121*0Sstevel@tonic-gate break; 1122*0Sstevel@tonic-gate } 1123*0Sstevel@tonic-gate if (chr == '"' || chr == '\'' || chr == '\\') { 1124*0Sstevel@tonic-gate kwstate = chr; /* Begin quote or escape */ 1125*0Sstevel@tonic-gate chr = '\0'; 1126*0Sstevel@tonic-gate break; 1127*0Sstevel@tonic-gate } 1128*0Sstevel@tonic-gate if (flag) /* Allow ignore; for string reparse */ 1129*0Sstevel@tonic-gate break; 1130*0Sstevel@tonic-gate if (chr == '#') { /* Comment terminates word */ 1131*0Sstevel@tonic-gate kwstate = '@'; /* Must consume comment also */ 1132*0Sstevel@tonic-gate chr = '\0'; 1133*0Sstevel@tonic-gate break; 1134*0Sstevel@tonic-gate } 1135*0Sstevel@tonic-gate if (chr == '$') { 1136*0Sstevel@tonic-gate kwstate = '$'; /* Begin variable expansion */ 1137*0Sstevel@tonic-gate chr = '\0'; 1138*0Sstevel@tonic-gate } 1139*0Sstevel@tonic-gate break; 1140*0Sstevel@tonic-gate } 1141*0Sstevel@tonic-gate /* 1142*0Sstevel@tonic-gate * If we've reached a space at the end of the word, 1143*0Sstevel@tonic-gate * then we're done. 1144*0Sstevel@tonic-gate */ 1145*0Sstevel@tonic-gate if (ichr == EOF || kwstate == ' ') 1146*0Sstevel@tonic-gate break; 1147*0Sstevel@tonic-gate /* 1148*0Sstevel@tonic-gate * If there's a character to store and space 1149*0Sstevel@tonic-gate * available, then add it to the string 1150*0Sstevel@tonic-gate */ 1151*0Sstevel@tonic-gate if (chr != '\0' && kbp < keybuf + keymax) 1152*0Sstevel@tonic-gate *kbp++ = (char)chr; 1153*0Sstevel@tonic-gate } 1154*0Sstevel@tonic-gate 1155*0Sstevel@tonic-gate *kbp = '\0'; 1156*0Sstevel@tonic-gate 1157*0Sstevel@tonic-gate if (ichr == EOF) { 1158*0Sstevel@tonic-gate return (kwstate == '\0' ? 1 : 2); 1159*0Sstevel@tonic-gate } 1160*0Sstevel@tonic-gate return (0); 1161*0Sstevel@tonic-gate } 1162*0Sstevel@tonic-gate 1163*0Sstevel@tonic-gate /* 1164*0Sstevel@tonic-gate * Fetch words from current file until all files are closed. Handles 1165*0Sstevel@tonic-gate * include files. 1166*0Sstevel@tonic-gate */ 1167*0Sstevel@tonic-gate static void 1168*0Sstevel@tonic-gate parse_from_file(struct parse_state *psp) 1169*0Sstevel@tonic-gate { 1170*0Sstevel@tonic-gate char keybuf[MAX_KEYWORD]; 1171*0Sstevel@tonic-gate int retv; 1172*0Sstevel@tonic-gate 1173*0Sstevel@tonic-gate while (psp->ps_cfile != NULL && psp->ps_cfile->pf_input != NULL) { 1174*0Sstevel@tonic-gate retv = getkeyword(psp, keybuf, sizeof (keybuf), 1175*0Sstevel@tonic-gate (int (*)(void *))fgetc, (void *)psp->ps_cfile->pf_input, 1176*0Sstevel@tonic-gate 0); 1177*0Sstevel@tonic-gate 1178*0Sstevel@tonic-gate if (retv != 1) 1179*0Sstevel@tonic-gate (void) dispatch_keyword(psp, keybuf); 1180*0Sstevel@tonic-gate 1181*0Sstevel@tonic-gate if (retv != 0) 1182*0Sstevel@tonic-gate file_end(psp); 1183*0Sstevel@tonic-gate } 1184*0Sstevel@tonic-gate } 1185*0Sstevel@tonic-gate 1186*0Sstevel@tonic-gate /* 1187*0Sstevel@tonic-gate * Open and parse named file. This is for the predefined 1188*0Sstevel@tonic-gate * configuration files in /etc/ppp -- it's not an error if any of 1189*0Sstevel@tonic-gate * these are missing. 1190*0Sstevel@tonic-gate */ 1191*0Sstevel@tonic-gate static void 1192*0Sstevel@tonic-gate parse_file(struct parse_state *psp, const char *fname) 1193*0Sstevel@tonic-gate { 1194*0Sstevel@tonic-gate struct stat sb; 1195*0Sstevel@tonic-gate 1196*0Sstevel@tonic-gate /* It's ok if any of these files are missing. */ 1197*0Sstevel@tonic-gate if (stat(fname, &sb) == -1 && errno == ENOENT) 1198*0Sstevel@tonic-gate return; 1199*0Sstevel@tonic-gate if (set_file(psp->ps_csvc, fname) == 0) 1200*0Sstevel@tonic-gate parse_from_file(psp); 1201*0Sstevel@tonic-gate } 1202*0Sstevel@tonic-gate 1203*0Sstevel@tonic-gate /* 1204*0Sstevel@tonic-gate * Dispatch keywords from command line. Handles any files included 1205*0Sstevel@tonic-gate * from there. 1206*0Sstevel@tonic-gate */ 1207*0Sstevel@tonic-gate static void 1208*0Sstevel@tonic-gate parse_arg_list(struct parse_state *psp, int argc, char **argv) 1209*0Sstevel@tonic-gate { 1210*0Sstevel@tonic-gate /* The first argument (program name) can be null. */ 1211*0Sstevel@tonic-gate if (--argc <= 0) 1212*0Sstevel@tonic-gate return; 1213*0Sstevel@tonic-gate while (--argc >= 0) { 1214*0Sstevel@tonic-gate (void) dispatch_keyword(psp, *++argv); 1215*0Sstevel@tonic-gate if (psp->ps_cfile->pf_input != NULL) 1216*0Sstevel@tonic-gate parse_from_file(psp); 1217*0Sstevel@tonic-gate } 1218*0Sstevel@tonic-gate } 1219*0Sstevel@tonic-gate 1220*0Sstevel@tonic-gate /* Count length of dynamic device list */ 1221*0Sstevel@tonic-gate static int 1222*0Sstevel@tonic-gate count_devs(struct device_list *dlp) 1223*0Sstevel@tonic-gate { 1224*0Sstevel@tonic-gate int ndevs; 1225*0Sstevel@tonic-gate 1226*0Sstevel@tonic-gate ndevs = 0; 1227*0Sstevel@tonic-gate for (; dlp != NULL; dlp = dlp->dl_next) 1228*0Sstevel@tonic-gate ndevs++; 1229*0Sstevel@tonic-gate return (ndevs); 1230*0Sstevel@tonic-gate } 1231*0Sstevel@tonic-gate 1232*0Sstevel@tonic-gate /* Count number of devices named in entire file. */ 1233*0Sstevel@tonic-gate static int 1234*0Sstevel@tonic-gate count_per_file(struct per_file *pfp) 1235*0Sstevel@tonic-gate { 1236*0Sstevel@tonic-gate struct service_list *slp; 1237*0Sstevel@tonic-gate int ndevs = 0; 1238*0Sstevel@tonic-gate 1239*0Sstevel@tonic-gate for (; pfp != NULL; pfp = pfp->pf_prev) { 1240*0Sstevel@tonic-gate ndevs += count_devs(pfp->pf_global.sl_dev); 1241*0Sstevel@tonic-gate for (slp = pfp->pf_svc; slp != NULL; slp = slp->sl_next) 1242*0Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CDEV)) 1243*0Sstevel@tonic-gate ndevs += count_devs(slp->sl_dev); 1244*0Sstevel@tonic-gate } 1245*0Sstevel@tonic-gate return (ndevs); 1246*0Sstevel@tonic-gate } 1247*0Sstevel@tonic-gate 1248*0Sstevel@tonic-gate /* Write device names into linear array. */ 1249*0Sstevel@tonic-gate static const char ** 1250*0Sstevel@tonic-gate devs_to_list(struct device_list *dlp, const char **dnames) 1251*0Sstevel@tonic-gate { 1252*0Sstevel@tonic-gate for (; dlp != NULL; dlp = dlp->dl_next) 1253*0Sstevel@tonic-gate *dnames++ = dlp->dl_name; 1254*0Sstevel@tonic-gate return (dnames); 1255*0Sstevel@tonic-gate } 1256*0Sstevel@tonic-gate 1257*0Sstevel@tonic-gate /* Write all device names from file into a linear array. */ 1258*0Sstevel@tonic-gate static const char ** 1259*0Sstevel@tonic-gate per_file_to_list(struct per_file *pfp, const char **dnames) 1260*0Sstevel@tonic-gate { 1261*0Sstevel@tonic-gate struct service_list *slp; 1262*0Sstevel@tonic-gate 1263*0Sstevel@tonic-gate for (; pfp != NULL; pfp = pfp->pf_prev) { 1264*0Sstevel@tonic-gate dnames = devs_to_list(pfp->pf_global.sl_dev, dnames); 1265*0Sstevel@tonic-gate for (slp = pfp->pf_svc; slp != NULL; slp = slp->sl_next) 1266*0Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CDEV)) 1267*0Sstevel@tonic-gate dnames = devs_to_list(slp->sl_dev, dnames); 1268*0Sstevel@tonic-gate } 1269*0Sstevel@tonic-gate return (dnames); 1270*0Sstevel@tonic-gate } 1271*0Sstevel@tonic-gate 1272*0Sstevel@tonic-gate /* Compare device names; used with qsort */ 1273*0Sstevel@tonic-gate static int 1274*0Sstevel@tonic-gate devcmp(const void *d1, const void *d2) 1275*0Sstevel@tonic-gate { 1276*0Sstevel@tonic-gate return (strcmp(*(const char **)d1, *(const char **)d2)); 1277*0Sstevel@tonic-gate } 1278*0Sstevel@tonic-gate 1279*0Sstevel@tonic-gate /* 1280*0Sstevel@tonic-gate * Get sorted list of unique device names among all defined and 1281*0Sstevel@tonic-gate * partially defined services in all files. 1282*0Sstevel@tonic-gate */ 1283*0Sstevel@tonic-gate static const char ** 1284*0Sstevel@tonic-gate get_unique_devs(struct parse_state *psp) 1285*0Sstevel@tonic-gate { 1286*0Sstevel@tonic-gate int ndevs; 1287*0Sstevel@tonic-gate const char **dnames; 1288*0Sstevel@tonic-gate const char **dnp; 1289*0Sstevel@tonic-gate const char **dnf; 1290*0Sstevel@tonic-gate 1291*0Sstevel@tonic-gate /* 1292*0Sstevel@tonic-gate * Count number of explicitly referenced devices among all 1293*0Sstevel@tonic-gate * services (including duplicates). 1294*0Sstevel@tonic-gate */ 1295*0Sstevel@tonic-gate ndevs = count_per_file(psp->ps_files); 1296*0Sstevel@tonic-gate ndevs += count_per_file(psp->ps_cfile); 1297*0Sstevel@tonic-gate if (ndevs <= 0) { 1298*0Sstevel@tonic-gate return (NULL); 1299*0Sstevel@tonic-gate } 1300*0Sstevel@tonic-gate 1301*0Sstevel@tonic-gate /* Sort and trim out duplicate devices. */ 1302*0Sstevel@tonic-gate dnames = (const char **)malloc((ndevs+1) * sizeof (const char *)); 1303*0Sstevel@tonic-gate if (dnames == NULL) { 1304*0Sstevel@tonic-gate logerr("unable to allocate space for %d devices", ndevs + 1); 1305*0Sstevel@tonic-gate return (NULL); 1306*0Sstevel@tonic-gate } 1307*0Sstevel@tonic-gate dnp = per_file_to_list(psp->ps_files, dnames); 1308*0Sstevel@tonic-gate (void) per_file_to_list(psp->ps_cfile, dnp); 1309*0Sstevel@tonic-gate qsort(dnames, ndevs, sizeof (const char *), devcmp); 1310*0Sstevel@tonic-gate for (dnf = (dnp = dnames) + 1; dnf < dnames+ndevs; dnf++) 1311*0Sstevel@tonic-gate if (strcmp(*dnf, *dnp) != 0) 1312*0Sstevel@tonic-gate *++dnp = *dnf; 1313*0Sstevel@tonic-gate *++dnp = NULL; 1314*0Sstevel@tonic-gate 1315*0Sstevel@tonic-gate /* Return array of pointers to names. */ 1316*0Sstevel@tonic-gate return (dnames); 1317*0Sstevel@tonic-gate } 1318*0Sstevel@tonic-gate 1319*0Sstevel@tonic-gate /* 1320*0Sstevel@tonic-gate * Convert data structures created by parsing process into data 1321*0Sstevel@tonic-gate * structures used by service dispatch. This gathers the unique 1322*0Sstevel@tonic-gate * device (lower stream) names and attaches the services available on 1323*0Sstevel@tonic-gate * each device to a list while triming duplicate services. 1324*0Sstevel@tonic-gate */ 1325*0Sstevel@tonic-gate static struct option_state * 1326*0Sstevel@tonic-gate organize_state(struct parse_state *psp) 1327*0Sstevel@tonic-gate { 1328*0Sstevel@tonic-gate struct per_file *pfp; 1329*0Sstevel@tonic-gate struct per_file *pftopp; 1330*0Sstevel@tonic-gate struct service_list *slp; 1331*0Sstevel@tonic-gate struct device_list *dlp; 1332*0Sstevel@tonic-gate int ndevs; 1333*0Sstevel@tonic-gate int nsvcs; 1334*0Sstevel@tonic-gate const char **dnames; 1335*0Sstevel@tonic-gate const char **dnp; 1336*0Sstevel@tonic-gate struct device_entry *dep; 1337*0Sstevel@tonic-gate struct option_state *osp; 1338*0Sstevel@tonic-gate struct service_entry **sepp; 1339*0Sstevel@tonic-gate struct service_entry **sebpp; 1340*0Sstevel@tonic-gate struct service_entry **se2pp; 1341*0Sstevel@tonic-gate 1342*0Sstevel@tonic-gate /* 1343*0Sstevel@tonic-gate * Parsing is now done. 1344*0Sstevel@tonic-gate */ 1345*0Sstevel@tonic-gate close_service(psp->ps_csvc); 1346*0Sstevel@tonic-gate psp->ps_csvc = NULL; 1347*0Sstevel@tonic-gate if ((pfp = psp->ps_cfile) != NULL) { 1348*0Sstevel@tonic-gate pfp->pf_prev = psp->ps_files; 1349*0Sstevel@tonic-gate psp->ps_files = pfp; 1350*0Sstevel@tonic-gate psp->ps_cfile = NULL; 1351*0Sstevel@tonic-gate } 1352*0Sstevel@tonic-gate 1353*0Sstevel@tonic-gate /* Link the services from all files together for easy referencing. */ 1354*0Sstevel@tonic-gate pftopp = psp->ps_files; 1355*0Sstevel@tonic-gate for (pfp = pftopp->pf_prev; pfp != NULL; pfp = pfp->pf_prev) 1356*0Sstevel@tonic-gate if (pfp->pf_svc != NULL) { 1357*0Sstevel@tonic-gate if (pftopp->pf_svc_last == NULL) 1358*0Sstevel@tonic-gate pftopp->pf_svc = pfp->pf_svc; 1359*0Sstevel@tonic-gate else 1360*0Sstevel@tonic-gate pftopp->pf_svc_last->sl_next = pfp->pf_svc; 1361*0Sstevel@tonic-gate pftopp->pf_svc_last = pfp->pf_svc_last; 1362*0Sstevel@tonic-gate pfp->pf_svc = pfp->pf_svc_last = NULL; 1363*0Sstevel@tonic-gate } 1364*0Sstevel@tonic-gate 1365*0Sstevel@tonic-gate /* 1366*0Sstevel@tonic-gate * Count up number of services per device, including 1367*0Sstevel@tonic-gate * duplicates but not including defaults. 1368*0Sstevel@tonic-gate */ 1369*0Sstevel@tonic-gate nsvcs = 0; 1370*0Sstevel@tonic-gate for (slp = psp->ps_files->pf_svc; slp != NULL; slp = slp->sl_next) 1371*0Sstevel@tonic-gate for (dlp = slp->sl_dev; dlp != NULL; dlp = dlp->dl_next) 1372*0Sstevel@tonic-gate nsvcs++; 1373*0Sstevel@tonic-gate 1374*0Sstevel@tonic-gate /* 1375*0Sstevel@tonic-gate * Get the unique devices referenced by all services. 1376*0Sstevel@tonic-gate */ 1377*0Sstevel@tonic-gate dnames = get_unique_devs(psp); 1378*0Sstevel@tonic-gate if (dnames == NULL) { 1379*0Sstevel@tonic-gate logdbg("no devices referenced by any service"); 1380*0Sstevel@tonic-gate return (NULL); 1381*0Sstevel@tonic-gate } 1382*0Sstevel@tonic-gate ndevs = 0; 1383*0Sstevel@tonic-gate for (dnp = dnames; *dnp != NULL; dnp++) 1384*0Sstevel@tonic-gate ndevs++; 1385*0Sstevel@tonic-gate 1386*0Sstevel@tonic-gate /* 1387*0Sstevel@tonic-gate * Allocate room for main structure, device records, and 1388*0Sstevel@tonic-gate * per-device lists. Worst case is all devices having all 1389*0Sstevel@tonic-gate * services; that's why we allocate for nsvcs * ndevs. 1390*0Sstevel@tonic-gate */ 1391*0Sstevel@tonic-gate osp = (struct option_state *)malloc(sizeof (*osp) + 1392*0Sstevel@tonic-gate ndevs * sizeof (*dep) + nsvcs * ndevs * sizeof (*sepp)); 1393*0Sstevel@tonic-gate if (osp == NULL) { 1394*0Sstevel@tonic-gate logerr("unable to allocate option state structure"); 1395*0Sstevel@tonic-gate free(dnames); 1396*0Sstevel@tonic-gate return (NULL); 1397*0Sstevel@tonic-gate } 1398*0Sstevel@tonic-gate 1399*0Sstevel@tonic-gate /* We're going to succeed now, so steal these over. */ 1400*0Sstevel@tonic-gate osp->os_devices = dep = (struct device_entry *)(osp+1); 1401*0Sstevel@tonic-gate osp->os_pfjunk = psp->ps_files; 1402*0Sstevel@tonic-gate psp->ps_files = NULL; 1403*0Sstevel@tonic-gate osp->os_evjunk = psp->ps_evlist; 1404*0Sstevel@tonic-gate psp->ps_evlist = NULL; 1405*0Sstevel@tonic-gate 1406*0Sstevel@tonic-gate /* Loop over devices, install services, remove duplicates. */ 1407*0Sstevel@tonic-gate sepp = (struct service_entry **)(dep + ndevs); 1408*0Sstevel@tonic-gate for (dnp = dnames; *dnp != NULL; dnp++) { 1409*0Sstevel@tonic-gate dep->de_name = *dnp; 1410*0Sstevel@tonic-gate dep->de_services = (const struct service_entry **)sepp; 1411*0Sstevel@tonic-gate sebpp = sepp; 1412*0Sstevel@tonic-gate for (slp = osp->os_pfjunk->pf_svc; slp != NULL; 1413*0Sstevel@tonic-gate slp = slp->sl_next) 1414*0Sstevel@tonic-gate for (dlp = slp->sl_dev; dlp != NULL; 1415*0Sstevel@tonic-gate dlp = dlp->dl_next) { 1416*0Sstevel@tonic-gate if (dlp->dl_name == *dnp || 1417*0Sstevel@tonic-gate strcmp(dlp->dl_name, *dnp) == 0) { 1418*0Sstevel@tonic-gate for (se2pp = sebpp; se2pp < sepp; 1419*0Sstevel@tonic-gate se2pp++) 1420*0Sstevel@tonic-gate if ((*se2pp)->se_name == 1421*0Sstevel@tonic-gate slp->sl_entry.se_name || 1422*0Sstevel@tonic-gate strcmp((*se2pp)-> 1423*0Sstevel@tonic-gate se_name, 1424*0Sstevel@tonic-gate slp->sl_entry. 1425*0Sstevel@tonic-gate se_name) == 0) 1426*0Sstevel@tonic-gate break; 1427*0Sstevel@tonic-gate /* 1428*0Sstevel@tonic-gate * We retain a service if it's 1429*0Sstevel@tonic-gate * unique or if its serial 1430*0Sstevel@tonic-gate * number (position in the 1431*0Sstevel@tonic-gate * file) is greater than than 1432*0Sstevel@tonic-gate * any other. 1433*0Sstevel@tonic-gate */ 1434*0Sstevel@tonic-gate if (se2pp >= sepp) 1435*0Sstevel@tonic-gate *sepp++ = &slp->sl_entry; 1436*0Sstevel@tonic-gate else if (SESERIAL(**se2pp) < 1437*0Sstevel@tonic-gate SESERIAL(slp->sl_entry)) 1438*0Sstevel@tonic-gate *se2pp = &slp->sl_entry; 1439*0Sstevel@tonic-gate } 1440*0Sstevel@tonic-gate } 1441*0Sstevel@tonic-gate /* Count up the services on this device. */ 1442*0Sstevel@tonic-gate dep->de_nservices = (const struct service_entry **)sepp - 1443*0Sstevel@tonic-gate dep->de_services; 1444*0Sstevel@tonic-gate /* Ignore devices having no services at all. */ 1445*0Sstevel@tonic-gate if (dep->de_nservices > 0) 1446*0Sstevel@tonic-gate dep++; 1447*0Sstevel@tonic-gate } 1448*0Sstevel@tonic-gate /* Count up the devices. */ 1449*0Sstevel@tonic-gate osp->os_ndevices = dep - osp->os_devices; 1450*0Sstevel@tonic-gate /* Free the list of device names */ 1451*0Sstevel@tonic-gate free(dnames); 1452*0Sstevel@tonic-gate return (osp); 1453*0Sstevel@tonic-gate } 1454*0Sstevel@tonic-gate 1455*0Sstevel@tonic-gate /* 1456*0Sstevel@tonic-gate * Free storage unique to a given service. Pointers copied from other 1457*0Sstevel@tonic-gate * services are ignored. 1458*0Sstevel@tonic-gate */ 1459*0Sstevel@tonic-gate static void 1460*0Sstevel@tonic-gate free_service(struct service_list *slp) 1461*0Sstevel@tonic-gate { 1462*0Sstevel@tonic-gate struct filter_entry *fep; 1463*0Sstevel@tonic-gate struct filter_entry *fen; 1464*0Sstevel@tonic-gate 1465*0Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CDEV)) 1466*0Sstevel@tonic-gate free_device_list(slp->sl_dev); 1467*0Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CFLIST)) { 1468*0Sstevel@tonic-gate fep = slp->sl_entry.se_flist; 1469*0Sstevel@tonic-gate while (fep != NULL) { 1470*0Sstevel@tonic-gate fen = fep->fe_prevcopy ? NULL : fep->fe_prev; 1471*0Sstevel@tonic-gate free(fep); 1472*0Sstevel@tonic-gate fep = fen; 1473*0Sstevel@tonic-gate } 1474*0Sstevel@tonic-gate } 1475*0Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CPPPD) && 1476*0Sstevel@tonic-gate slp->sl_entry.se_pppd != NULL) 1477*0Sstevel@tonic-gate free(slp->sl_entry.se_pppd); 1478*0Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CSERVER) && 1479*0Sstevel@tonic-gate slp->sl_entry.se_server != NULL) 1480*0Sstevel@tonic-gate free(slp->sl_entry.se_server); 1481*0Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CPATH) && 1482*0Sstevel@tonic-gate slp->sl_entry.se_path != NULL) 1483*0Sstevel@tonic-gate free(slp->sl_entry.se_path); 1484*0Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CEXTRA) && 1485*0Sstevel@tonic-gate slp->sl_entry.se_extra != NULL) 1486*0Sstevel@tonic-gate free(slp->sl_entry.se_extra); 1487*0Sstevel@tonic-gate if (!(slp->sl_entry.se_flags & SEF_CLOG) && 1488*0Sstevel@tonic-gate slp->sl_entry.se_log != NULL) 1489*0Sstevel@tonic-gate free(slp->sl_entry.se_log); 1490*0Sstevel@tonic-gate } 1491*0Sstevel@tonic-gate 1492*0Sstevel@tonic-gate /* 1493*0Sstevel@tonic-gate * Free a linked list of services. 1494*0Sstevel@tonic-gate */ 1495*0Sstevel@tonic-gate static void 1496*0Sstevel@tonic-gate free_service_list(struct service_list *slp) 1497*0Sstevel@tonic-gate { 1498*0Sstevel@tonic-gate struct service_list *sln; 1499*0Sstevel@tonic-gate 1500*0Sstevel@tonic-gate while (slp != NULL) { 1501*0Sstevel@tonic-gate free_service(slp); 1502*0Sstevel@tonic-gate sln = slp->sl_next; 1503*0Sstevel@tonic-gate free(slp); 1504*0Sstevel@tonic-gate slp = sln; 1505*0Sstevel@tonic-gate } 1506*0Sstevel@tonic-gate } 1507*0Sstevel@tonic-gate 1508*0Sstevel@tonic-gate /* 1509*0Sstevel@tonic-gate * Free a linked list of files and all services in those files. 1510*0Sstevel@tonic-gate */ 1511*0Sstevel@tonic-gate static void 1512*0Sstevel@tonic-gate free_file_list(struct per_file *pfp) 1513*0Sstevel@tonic-gate { 1514*0Sstevel@tonic-gate struct per_file *pfn; 1515*0Sstevel@tonic-gate 1516*0Sstevel@tonic-gate while (pfp != NULL) { 1517*0Sstevel@tonic-gate free_service(&pfp->pf_global); 1518*0Sstevel@tonic-gate free_service_list(pfp->pf_svc); 1519*0Sstevel@tonic-gate pfn = pfp->pf_prev; 1520*0Sstevel@tonic-gate free(pfp); 1521*0Sstevel@tonic-gate pfp = pfn; 1522*0Sstevel@tonic-gate } 1523*0Sstevel@tonic-gate } 1524*0Sstevel@tonic-gate 1525*0Sstevel@tonic-gate /* 1526*0Sstevel@tonic-gate * Free an array of local environment variables. 1527*0Sstevel@tonic-gate */ 1528*0Sstevel@tonic-gate static void 1529*0Sstevel@tonic-gate free_env_list(char **evlist) 1530*0Sstevel@tonic-gate { 1531*0Sstevel@tonic-gate char **evp; 1532*0Sstevel@tonic-gate char *env; 1533*0Sstevel@tonic-gate 1534*0Sstevel@tonic-gate if ((evp = evlist) != NULL) { 1535*0Sstevel@tonic-gate while ((env = *evp++) != NULL) 1536*0Sstevel@tonic-gate free(env); 1537*0Sstevel@tonic-gate free(evlist); 1538*0Sstevel@tonic-gate } 1539*0Sstevel@tonic-gate } 1540*0Sstevel@tonic-gate 1541*0Sstevel@tonic-gate /* 1542*0Sstevel@tonic-gate * Add a new device (lower stream) to the list for which we're the 1543*0Sstevel@tonic-gate * PPPoE server. 1544*0Sstevel@tonic-gate */ 1545*0Sstevel@tonic-gate static void 1546*0Sstevel@tonic-gate add_new_dev(int tunfd, const char *dname) 1547*0Sstevel@tonic-gate { 1548*0Sstevel@tonic-gate union ppptun_name ptn; 1549*0Sstevel@tonic-gate 1550*0Sstevel@tonic-gate (void) snprintf(ptn.ptn_name, sizeof (ptn.ptn_name), "%s:pppoed", 1551*0Sstevel@tonic-gate dname); 1552*0Sstevel@tonic-gate if (strioctl(tunfd, PPPTUN_SCTL, &ptn, sizeof (ptn), 0) < 0) { 1553*0Sstevel@tonic-gate logerr("PPPTUN_SCTL %s: %s", ptn.ptn_name, mystrerror(errno)); 1554*0Sstevel@tonic-gate } else { 1555*0Sstevel@tonic-gate logdbg("added %s", ptn.ptn_name); 1556*0Sstevel@tonic-gate } 1557*0Sstevel@tonic-gate } 1558*0Sstevel@tonic-gate 1559*0Sstevel@tonic-gate /* 1560*0Sstevel@tonic-gate * Remove an existing device (lower stream) from the list for which we 1561*0Sstevel@tonic-gate * were the PPPoE server. 1562*0Sstevel@tonic-gate */ 1563*0Sstevel@tonic-gate static void 1564*0Sstevel@tonic-gate rem_old_dev(int tunfd, const char *dname) 1565*0Sstevel@tonic-gate { 1566*0Sstevel@tonic-gate union ppptun_name ptn; 1567*0Sstevel@tonic-gate 1568*0Sstevel@tonic-gate (void) snprintf(ptn.ptn_name, sizeof (ptn.ptn_name), "%s:pppoed", 1569*0Sstevel@tonic-gate dname); 1570*0Sstevel@tonic-gate if (strioctl(tunfd, PPPTUN_DCTL, &ptn, sizeof (ptn), 0) < 0) { 1571*0Sstevel@tonic-gate logerr("PPPTUN_DCTL %s: %s", ptn.ptn_name, mystrerror(errno)); 1572*0Sstevel@tonic-gate } else { 1573*0Sstevel@tonic-gate logdbg("removed %s", ptn.ptn_name); 1574*0Sstevel@tonic-gate } 1575*0Sstevel@tonic-gate } 1576*0Sstevel@tonic-gate 1577*0Sstevel@tonic-gate /* 1578*0Sstevel@tonic-gate * Get a list of all of the devices currently plumbed for PPPoE. This 1579*0Sstevel@tonic-gate * is used for supporting the "*" and "all" device aliases. 1580*0Sstevel@tonic-gate */ 1581*0Sstevel@tonic-gate static void 1582*0Sstevel@tonic-gate get_device_list(struct parse_state *psp, int tunfd) 1583*0Sstevel@tonic-gate { 1584*0Sstevel@tonic-gate struct device_list *dlp; 1585*0Sstevel@tonic-gate struct device_list **dlpp; 1586*0Sstevel@tonic-gate struct device_list *dlalt; 1587*0Sstevel@tonic-gate struct device_list **dl2pp; 1588*0Sstevel@tonic-gate struct device_list *dla; 1589*0Sstevel@tonic-gate int i; 1590*0Sstevel@tonic-gate union ppptun_name ptn; 1591*0Sstevel@tonic-gate char *cp; 1592*0Sstevel@tonic-gate 1593*0Sstevel@tonic-gate /* First pass; just allocate space for all *:pppoe* devices */ 1594*0Sstevel@tonic-gate dlpp = &psp->ps_star; 1595*0Sstevel@tonic-gate dl2pp = &dlalt; 1596*0Sstevel@tonic-gate for (i = 0; ; i++) { 1597*0Sstevel@tonic-gate ptn.ptn_index = i; 1598*0Sstevel@tonic-gate if (strioctl(tunfd, PPPTUN_GNNAME, &ptn, sizeof (ptn), 1599*0Sstevel@tonic-gate sizeof (ptn)) < 0) { 1600*0Sstevel@tonic-gate logerr("PPPTUN_GNNAME %d: %s", i, mystrerror(errno)); 1601*0Sstevel@tonic-gate break; 1602*0Sstevel@tonic-gate } 1603*0Sstevel@tonic-gate if (ptn.ptn_name[0] == '\0') 1604*0Sstevel@tonic-gate break; 1605*0Sstevel@tonic-gate if ((cp = strchr(ptn.ptn_name, ':')) == NULL || 1606*0Sstevel@tonic-gate strncmp(cp, ":pppoe", 6) != 0 || 1607*0Sstevel@tonic-gate (cp[6] != '\0' && strcmp(cp+6, "d") != 0)) 1608*0Sstevel@tonic-gate continue; 1609*0Sstevel@tonic-gate *cp = '\0'; 1610*0Sstevel@tonic-gate dlp = (struct device_list *)malloc(sizeof (*dlp) + 1611*0Sstevel@tonic-gate strlen(ptn.ptn_name) + 1); 1612*0Sstevel@tonic-gate if (dlp == NULL) 1613*0Sstevel@tonic-gate break; 1614*0Sstevel@tonic-gate dlp->dl_name = (const char *)(dlp + 1); 1615*0Sstevel@tonic-gate (void) strcpy((char *)(dlp + 1), ptn.ptn_name); 1616*0Sstevel@tonic-gate if (cp[6] == '\0') { 1617*0Sstevel@tonic-gate *dlpp = dlp; 1618*0Sstevel@tonic-gate dlpp = &dlp->dl_next; 1619*0Sstevel@tonic-gate } else { 1620*0Sstevel@tonic-gate *dl2pp = dlp; 1621*0Sstevel@tonic-gate dl2pp = &dlp->dl_next; 1622*0Sstevel@tonic-gate } 1623*0Sstevel@tonic-gate } 1624*0Sstevel@tonic-gate *dlpp = NULL; 1625*0Sstevel@tonic-gate *dl2pp = NULL; 1626*0Sstevel@tonic-gate 1627*0Sstevel@tonic-gate /* Second pass; eliminate improperly plumbed devices */ 1628*0Sstevel@tonic-gate for (dlpp = &psp->ps_star; (dlp = *dlpp) != NULL; ) { 1629*0Sstevel@tonic-gate for (dla = dlalt; dla != NULL; dla = dla->dl_next) 1630*0Sstevel@tonic-gate if (strcmp(dla->dl_name, dlp->dl_name) == 0) 1631*0Sstevel@tonic-gate break; 1632*0Sstevel@tonic-gate if (dla == NULL) { 1633*0Sstevel@tonic-gate *dlpp = dlp->dl_next; 1634*0Sstevel@tonic-gate free(dlp); 1635*0Sstevel@tonic-gate } else { 1636*0Sstevel@tonic-gate dlpp = &dlp->dl_next; 1637*0Sstevel@tonic-gate } 1638*0Sstevel@tonic-gate } 1639*0Sstevel@tonic-gate free_device_list(dlalt); 1640*0Sstevel@tonic-gate 1641*0Sstevel@tonic-gate /* Add in "*" so we can always handle dynamic plumbing. */ 1642*0Sstevel@tonic-gate dlp = (struct device_list *)malloc(sizeof (*dlp) + 2); 1643*0Sstevel@tonic-gate if (dlp != NULL) { 1644*0Sstevel@tonic-gate dlp->dl_name = (const char *)(dlp + 1); 1645*0Sstevel@tonic-gate (void) strcpy((char *)(dlp + 1), "*"); 1646*0Sstevel@tonic-gate dlp->dl_next = psp->ps_star; 1647*0Sstevel@tonic-gate psp->ps_star = dlp; 1648*0Sstevel@tonic-gate } 1649*0Sstevel@tonic-gate } 1650*0Sstevel@tonic-gate 1651*0Sstevel@tonic-gate /* 1652*0Sstevel@tonic-gate * Set logging subsystem back to configured global default values. 1653*0Sstevel@tonic-gate */ 1654*0Sstevel@tonic-gate void 1655*0Sstevel@tonic-gate global_logging(void) 1656*0Sstevel@tonic-gate { 1657*0Sstevel@tonic-gate log_for_service(glob_svc.se_log, glob_svc.se_debug); 1658*0Sstevel@tonic-gate } 1659*0Sstevel@tonic-gate 1660*0Sstevel@tonic-gate /* 1661*0Sstevel@tonic-gate * Handle SIGHUP -- reparse command line and all configuration files. 1662*0Sstevel@tonic-gate * When reparsing is complete, free old parsed data and replace with 1663*0Sstevel@tonic-gate * new. 1664*0Sstevel@tonic-gate */ 1665*0Sstevel@tonic-gate void 1666*0Sstevel@tonic-gate parse_options(int tunfd, int argc, char **argv) 1667*0Sstevel@tonic-gate { 1668*0Sstevel@tonic-gate struct parse_state pstate; 1669*0Sstevel@tonic-gate struct per_file *argpf; 1670*0Sstevel@tonic-gate struct option_state *newopt; 1671*0Sstevel@tonic-gate const char **dnames; 1672*0Sstevel@tonic-gate const char **dnp; 1673*0Sstevel@tonic-gate const struct device_entry *newdep, *newmax; 1674*0Sstevel@tonic-gate const struct device_entry *olddep, *oldmax; 1675*0Sstevel@tonic-gate int cmpval; 1676*0Sstevel@tonic-gate struct service_entry newglobsvc, *mainsvc; 1677*0Sstevel@tonic-gate 1678*0Sstevel@tonic-gate /* Note that all per_file structures must be freeable */ 1679*0Sstevel@tonic-gate argpf = (struct per_file *)calloc(sizeof (*argpf), 1); 1680*0Sstevel@tonic-gate if (argpf == NULL) { 1681*0Sstevel@tonic-gate return; 1682*0Sstevel@tonic-gate } 1683*0Sstevel@tonic-gate (void) memset(&pstate, '\0', sizeof (pstate)); 1684*0Sstevel@tonic-gate pstate.ps_state = ksDefault; 1685*0Sstevel@tonic-gate pstate.ps_cfile = argpf; 1686*0Sstevel@tonic-gate pstate.ps_csvc = &argpf->pf_global; 1687*0Sstevel@tonic-gate argpf->pf_global.sl_parse = &pstate; 1688*0Sstevel@tonic-gate argpf->pf_name = "command line"; 1689*0Sstevel@tonic-gate 1690*0Sstevel@tonic-gate /* Default is 1 -- errors only */ 1691*0Sstevel@tonic-gate argpf->pf_global.sl_entry.se_debug++; 1692*0Sstevel@tonic-gate argpf->pf_global.sl_entry.se_name = "<global>"; 1693*0Sstevel@tonic-gate 1694*0Sstevel@tonic-gate /* Get list of all devices */ 1695*0Sstevel@tonic-gate get_device_list(&pstate, tunfd); 1696*0Sstevel@tonic-gate 1697*0Sstevel@tonic-gate /* Parse options from command line and main configuration file. */ 1698*0Sstevel@tonic-gate pstate.ps_flags |= PSF_SETLEVEL; 1699*0Sstevel@tonic-gate parse_arg_list(&pstate, argc, argv); 1700*0Sstevel@tonic-gate parse_file(&pstate, "/etc/ppp/pppoe"); 1701*0Sstevel@tonic-gate pstate.ps_flags &= ~PSF_SETLEVEL; 1702*0Sstevel@tonic-gate 1703*0Sstevel@tonic-gate /* 1704*0Sstevel@tonic-gate * At this point, global options from the main configuration 1705*0Sstevel@tonic-gate * file are pointed to by ps_files, and options from command 1706*0Sstevel@tonic-gate * line are in argpf. We need to pull three special options 1707*0Sstevel@tonic-gate * from these -- wildcard, debug, and log. Note that the main 1708*0Sstevel@tonic-gate * options file overrides the command line. This is 1709*0Sstevel@tonic-gate * intentional. The semantics are such that the system 1710*0Sstevel@tonic-gate * behaves as though the main configuration file were 1711*0Sstevel@tonic-gate * "included" from the command line, and thus options there 1712*0Sstevel@tonic-gate * override the command line. This may seem odd, but at least 1713*0Sstevel@tonic-gate * it's self-consistent. 1714*0Sstevel@tonic-gate */ 1715*0Sstevel@tonic-gate newglobsvc = argpf->pf_global.sl_entry; 1716*0Sstevel@tonic-gate if (pstate.ps_files != NULL) { 1717*0Sstevel@tonic-gate mainsvc = &pstate.ps_files->pf_global.sl_entry; 1718*0Sstevel@tonic-gate if (mainsvc->se_log != NULL) 1719*0Sstevel@tonic-gate newglobsvc.se_log = mainsvc->se_log; 1720*0Sstevel@tonic-gate if (mainsvc->se_flags & (SEF_WILD|SEF_NOWILD)) 1721*0Sstevel@tonic-gate newglobsvc.se_flags = 1722*0Sstevel@tonic-gate (newglobsvc.se_flags & ~(SEF_WILD|SEF_NOWILD)) | 1723*0Sstevel@tonic-gate (mainsvc->se_flags & (SEF_WILD|SEF_NOWILD)); 1724*0Sstevel@tonic-gate if (mainsvc->se_flags & SEF_DEBUGCLR) 1725*0Sstevel@tonic-gate newglobsvc.se_debug = 0; 1726*0Sstevel@tonic-gate newglobsvc.se_debug += mainsvc->se_debug; 1727*0Sstevel@tonic-gate } 1728*0Sstevel@tonic-gate glob_svc = newglobsvc; 1729*0Sstevel@tonic-gate global_logging(); 1730*0Sstevel@tonic-gate 1731*0Sstevel@tonic-gate /* Get the list of devices referenced by configuration above. */ 1732*0Sstevel@tonic-gate dnames = get_unique_devs(&pstate); 1733*0Sstevel@tonic-gate if (dnames != NULL) { 1734*0Sstevel@tonic-gate /* Read per-device configuration files. */ 1735*0Sstevel@tonic-gate pstate.ps_flags |= PSF_PERDEV; 1736*0Sstevel@tonic-gate for (dnp = dnames; *dnp != NULL; dnp++) 1737*0Sstevel@tonic-gate parse_file(&pstate, *dnp); 1738*0Sstevel@tonic-gate pstate.ps_flags &= ~PSF_PERDEV; 1739*0Sstevel@tonic-gate free(dnames); 1740*0Sstevel@tonic-gate } 1741*0Sstevel@tonic-gate file_end(&pstate); 1742*0Sstevel@tonic-gate 1743*0Sstevel@tonic-gate /* 1744*0Sstevel@tonic-gate * Convert parsed data structures into per-device structures. 1745*0Sstevel@tonic-gate * (Invert the table.) 1746*0Sstevel@tonic-gate */ 1747*0Sstevel@tonic-gate newopt = organize_state(&pstate); 1748*0Sstevel@tonic-gate 1749*0Sstevel@tonic-gate /* If we're going to free the file name, then stop logging there. */ 1750*0Sstevel@tonic-gate if (newopt == NULL && glob_svc.se_log != NULL) { 1751*0Sstevel@tonic-gate glob_svc.se_log = NULL; 1752*0Sstevel@tonic-gate global_logging(); 1753*0Sstevel@tonic-gate } 1754*0Sstevel@tonic-gate 1755*0Sstevel@tonic-gate /* 1756*0Sstevel@tonic-gate * Unless an error has occurred, these pointers are normally 1757*0Sstevel@tonic-gate * all NULL. Nothing is freed until the file is re-read. 1758*0Sstevel@tonic-gate */ 1759*0Sstevel@tonic-gate free_file_list(pstate.ps_files); 1760*0Sstevel@tonic-gate free_file_list(pstate.ps_cfile); 1761*0Sstevel@tonic-gate free_device_list(pstate.ps_star); 1762*0Sstevel@tonic-gate free_env_list(pstate.ps_evlist); 1763*0Sstevel@tonic-gate 1764*0Sstevel@tonic-gate /* 1765*0Sstevel@tonic-gate * Match up entries on device list. Detach devices no longer 1766*0Sstevel@tonic-gate * referenced. Attach ones now referenced. (The use of null 1767*0Sstevel@tonic-gate * pointers here may look fishy, but it actually works. 1768*0Sstevel@tonic-gate * NULL>=NULL is always true.) 1769*0Sstevel@tonic-gate */ 1770*0Sstevel@tonic-gate if (newopt != NULL) { 1771*0Sstevel@tonic-gate newdep = newopt->os_devices; 1772*0Sstevel@tonic-gate newmax = newdep + newopt->os_ndevices; 1773*0Sstevel@tonic-gate } else { 1774*0Sstevel@tonic-gate newdep = newmax = NULL; 1775*0Sstevel@tonic-gate } 1776*0Sstevel@tonic-gate if (cur_options != NULL) { 1777*0Sstevel@tonic-gate olddep = cur_options->os_devices; 1778*0Sstevel@tonic-gate oldmax = olddep + cur_options->os_ndevices; 1779*0Sstevel@tonic-gate } else { 1780*0Sstevel@tonic-gate olddep = oldmax = NULL; 1781*0Sstevel@tonic-gate } 1782*0Sstevel@tonic-gate while ((newdep != NULL && newdep < newmax) || 1783*0Sstevel@tonic-gate (olddep != NULL && olddep < oldmax)) { 1784*0Sstevel@tonic-gate if (newdep < newmax) { 1785*0Sstevel@tonic-gate if (olddep >= oldmax) { 1786*0Sstevel@tonic-gate add_new_dev(tunfd, newdep->de_name); 1787*0Sstevel@tonic-gate newdep++; 1788*0Sstevel@tonic-gate } else { 1789*0Sstevel@tonic-gate cmpval = strcmp(newdep->de_name, 1790*0Sstevel@tonic-gate olddep->de_name); 1791*0Sstevel@tonic-gate if (cmpval < 0) { 1792*0Sstevel@tonic-gate /* Brand new device seen. */ 1793*0Sstevel@tonic-gate add_new_dev(tunfd, newdep->de_name); 1794*0Sstevel@tonic-gate newdep++; 1795*0Sstevel@tonic-gate } else if (cmpval == 0) { 1796*0Sstevel@tonic-gate /* Existing device; skip it. */ 1797*0Sstevel@tonic-gate newdep++; 1798*0Sstevel@tonic-gate olddep++; 1799*0Sstevel@tonic-gate } 1800*0Sstevel@tonic-gate /* No else clause -- removal is below */ 1801*0Sstevel@tonic-gate } 1802*0Sstevel@tonic-gate } 1803*0Sstevel@tonic-gate if (olddep < oldmax) { 1804*0Sstevel@tonic-gate if (newdep >= newmax) { 1805*0Sstevel@tonic-gate rem_old_dev(tunfd, olddep->de_name); 1806*0Sstevel@tonic-gate olddep++; 1807*0Sstevel@tonic-gate } else { 1808*0Sstevel@tonic-gate cmpval = strcmp(newdep->de_name, 1809*0Sstevel@tonic-gate olddep->de_name); 1810*0Sstevel@tonic-gate if (cmpval > 0) { 1811*0Sstevel@tonic-gate /* Old device is gone */ 1812*0Sstevel@tonic-gate rem_old_dev(tunfd, olddep->de_name); 1813*0Sstevel@tonic-gate olddep++; 1814*0Sstevel@tonic-gate } else if (cmpval == 0) { 1815*0Sstevel@tonic-gate /* Existing device; skip it. */ 1816*0Sstevel@tonic-gate newdep++; 1817*0Sstevel@tonic-gate olddep++; 1818*0Sstevel@tonic-gate } 1819*0Sstevel@tonic-gate /* No else clause -- insert handled above */ 1820*0Sstevel@tonic-gate } 1821*0Sstevel@tonic-gate } 1822*0Sstevel@tonic-gate } 1823*0Sstevel@tonic-gate 1824*0Sstevel@tonic-gate /* Discard existing parsed data storage. */ 1825*0Sstevel@tonic-gate if (cur_options != NULL) { 1826*0Sstevel@tonic-gate free_file_list(cur_options->os_pfjunk); 1827*0Sstevel@tonic-gate free_env_list(cur_options->os_evjunk); 1828*0Sstevel@tonic-gate free(cur_options); 1829*0Sstevel@tonic-gate } 1830*0Sstevel@tonic-gate /* Install new. */ 1831*0Sstevel@tonic-gate cur_options = newopt; 1832*0Sstevel@tonic-gate } 1833*0Sstevel@tonic-gate 1834*0Sstevel@tonic-gate /* 1835*0Sstevel@tonic-gate * Check if configured filters permit requesting client to use a given 1836*0Sstevel@tonic-gate * service. Note -- filters are stored in reverse order in order to 1837*0Sstevel@tonic-gate * make file-inclusion work as expected. Thus, the "first match" 1838*0Sstevel@tonic-gate * filter rule becomes "last match" here. 1839*0Sstevel@tonic-gate */ 1840*0Sstevel@tonic-gate static boolean_t 1841*0Sstevel@tonic-gate allow_service(const struct service_entry *sep, const ppptun_atype *pap) 1842*0Sstevel@tonic-gate { 1843*0Sstevel@tonic-gate const struct filter_entry *fep; 1844*0Sstevel@tonic-gate const struct filter_entry *lmatch; 1845*0Sstevel@tonic-gate boolean_t anynonexcept = B_FALSE; 1846*0Sstevel@tonic-gate const uchar_t *upt; 1847*0Sstevel@tonic-gate const uchar_t *macp; 1848*0Sstevel@tonic-gate const uchar_t *maskp; 1849*0Sstevel@tonic-gate int i; 1850*0Sstevel@tonic-gate 1851*0Sstevel@tonic-gate lmatch = NULL; 1852*0Sstevel@tonic-gate for (fep = sep->se_flist; fep != NULL; fep = fep->fe_prev) { 1853*0Sstevel@tonic-gate anynonexcept |= !fep->fe_isexcept; 1854*0Sstevel@tonic-gate upt = pap->pta_pppoe.ptma_mac; 1855*0Sstevel@tonic-gate macp = fep->fe_mac.ether_addr_octet; 1856*0Sstevel@tonic-gate maskp = fep->fe_mask.ether_addr_octet; 1857*0Sstevel@tonic-gate for (i = sizeof (pap->pta_pppoe.ptma_mac); i > 0; i--) 1858*0Sstevel@tonic-gate if (((*macp++ ^ *upt++) & *maskp++) != 0) 1859*0Sstevel@tonic-gate break; 1860*0Sstevel@tonic-gate if (i <= 0) 1861*0Sstevel@tonic-gate lmatch = fep; 1862*0Sstevel@tonic-gate } 1863*0Sstevel@tonic-gate 1864*0Sstevel@tonic-gate if (lmatch == NULL) { 1865*0Sstevel@tonic-gate /* 1866*0Sstevel@tonic-gate * Assume reject by default if any positive-match 1867*0Sstevel@tonic-gate * (non-except) filters are given. Otherwise, if 1868*0Sstevel@tonic-gate * there are no positive-match filters, then 1869*0Sstevel@tonic-gate * non-matching means accept by default. 1870*0Sstevel@tonic-gate */ 1871*0Sstevel@tonic-gate return (!anynonexcept); 1872*0Sstevel@tonic-gate } 1873*0Sstevel@tonic-gate return (!lmatch->fe_isexcept); 1874*0Sstevel@tonic-gate } 1875*0Sstevel@tonic-gate 1876*0Sstevel@tonic-gate /* 1877*0Sstevel@tonic-gate * Locate available service(s) based on client request. Assumes that 1878*0Sstevel@tonic-gate * outp points to a buffer of at least size PPPOE_MSGMAX. Creates a 1879*0Sstevel@tonic-gate * PPPoE response message in outp. Returns count of matched services 1880*0Sstevel@tonic-gate * and (through *srvp) a pointer to the last (or only) service. If 1881*0Sstevel@tonic-gate * some error is found in the request, an error string is added and -1 1882*0Sstevel@tonic-gate * is returned; the caller should just send the message without 1883*0Sstevel@tonic-gate * alteration. 1884*0Sstevel@tonic-gate */ 1885*0Sstevel@tonic-gate int 1886*0Sstevel@tonic-gate locate_service(poep_t *poep, int plen, const char *iname, ppptun_atype *pap, 1887*0Sstevel@tonic-gate uint32_t *outp, void **srvp) 1888*0Sstevel@tonic-gate { 1889*0Sstevel@tonic-gate poep_t *opoe; 1890*0Sstevel@tonic-gate const uint8_t *tagp; 1891*0Sstevel@tonic-gate const char *cp; 1892*0Sstevel@tonic-gate int ttyp; 1893*0Sstevel@tonic-gate int tlen; 1894*0Sstevel@tonic-gate int nsvcs; 1895*0Sstevel@tonic-gate const struct device_entry *dep, *depe; 1896*0Sstevel@tonic-gate const struct device_entry *wdep; 1897*0Sstevel@tonic-gate const struct service_entry **sepp, **seppe; 1898*0Sstevel@tonic-gate const struct service_entry *sep; 1899*0Sstevel@tonic-gate char *str; 1900*0Sstevel@tonic-gate boolean_t ispadi; 1901*0Sstevel@tonic-gate 1902*0Sstevel@tonic-gate ispadi = poep->poep_code == POECODE_PADI; 1903*0Sstevel@tonic-gate opoe = poe_mkheader(outp, ispadi ? POECODE_PADO : POECODE_PADS, 0); 1904*0Sstevel@tonic-gate 1905*0Sstevel@tonic-gate *srvp = NULL; 1906*0Sstevel@tonic-gate if (cur_options == NULL) 1907*0Sstevel@tonic-gate return (0); 1908*0Sstevel@tonic-gate 1909*0Sstevel@tonic-gate /* Search for named device (lower stream) in tables. */ 1910*0Sstevel@tonic-gate dep = cur_options->os_devices; 1911*0Sstevel@tonic-gate depe = dep + cur_options->os_ndevices; 1912*0Sstevel@tonic-gate wdep = NULL; 1913*0Sstevel@tonic-gate if ((cp = strchr(iname, ':')) != NULL) 1914*0Sstevel@tonic-gate tlen = cp - iname; 1915*0Sstevel@tonic-gate else 1916*0Sstevel@tonic-gate tlen = strlen(iname); 1917*0Sstevel@tonic-gate for (; dep < depe; dep++) 1918*0Sstevel@tonic-gate if (strncmp(iname, dep->de_name, tlen) == 0 && 1919*0Sstevel@tonic-gate dep->de_name[tlen] == '\0') 1920*0Sstevel@tonic-gate break; 1921*0Sstevel@tonic-gate else if (dep->de_name[0] == '*' && dep->de_name[1] == '\0') 1922*0Sstevel@tonic-gate wdep = dep; 1923*0Sstevel@tonic-gate if (dep >= depe) 1924*0Sstevel@tonic-gate dep = wdep; 1925*0Sstevel@tonic-gate /* 1926*0Sstevel@tonic-gate * Return if interface not found. Zero-service case can't 1927*0Sstevel@tonic-gate * occur, since devices with no services aren't included in 1928*0Sstevel@tonic-gate * the list, but the code is just being safe here. 1929*0Sstevel@tonic-gate */ 1930*0Sstevel@tonic-gate if (dep == NULL || dep->de_services == NULL || dep->de_nservices <= 0) 1931*0Sstevel@tonic-gate return (0); 1932*0Sstevel@tonic-gate 1933*0Sstevel@tonic-gate /* 1934*0Sstevel@tonic-gate * Loop over tags in client message and process them. 1935*0Sstevel@tonic-gate * Services must be matched against our list. Host-Uniq and 1936*0Sstevel@tonic-gate * Relay-Session-Id must be copied to the reply. All others 1937*0Sstevel@tonic-gate * must be discarded. 1938*0Sstevel@tonic-gate */ 1939*0Sstevel@tonic-gate nsvcs = 0; 1940*0Sstevel@tonic-gate sepp = dep->de_services; 1941*0Sstevel@tonic-gate tagp = (const uint8_t *)(poep + 1); 1942*0Sstevel@tonic-gate while (poe_tagcheck(poep, plen, tagp)) { 1943*0Sstevel@tonic-gate ttyp = POET_GET_TYPE(tagp); 1944*0Sstevel@tonic-gate if (ttyp == POETT_END) 1945*0Sstevel@tonic-gate break; 1946*0Sstevel@tonic-gate tlen = POET_GET_LENG(tagp); 1947*0Sstevel@tonic-gate switch (ttyp) { 1948*0Sstevel@tonic-gate case POETT_SERVICE: /* Service-Name */ 1949*0Sstevel@tonic-gate /* 1950*0Sstevel@tonic-gate * Allow only one. (Note that this test works 1951*0Sstevel@tonic-gate * because there's always at least one service 1952*0Sstevel@tonic-gate * per device; otherwise, the device is 1953*0Sstevel@tonic-gate * removed from the list.) 1954*0Sstevel@tonic-gate */ 1955*0Sstevel@tonic-gate if (sepp != dep->de_services) { 1956*0Sstevel@tonic-gate if (nsvcs != -1) 1957*0Sstevel@tonic-gate (void) poe_add_str(opoe, POETT_NAMERR, 1958*0Sstevel@tonic-gate "Too many Service-Name tags"); 1959*0Sstevel@tonic-gate nsvcs = -1; 1960*0Sstevel@tonic-gate break; 1961*0Sstevel@tonic-gate } 1962*0Sstevel@tonic-gate seppe = sepp + dep->de_nservices; 1963*0Sstevel@tonic-gate /* Clients's requested service must appear in reply. */ 1964*0Sstevel@tonic-gate if (tlen != 0 || (ispadi && 1965*0Sstevel@tonic-gate !(glob_svc.se_flags & SEF_NOWILD))) 1966*0Sstevel@tonic-gate (void) poe_tag_copy(opoe, tagp); 1967*0Sstevel@tonic-gate if (tlen == 0) { 1968*0Sstevel@tonic-gate /* 1969*0Sstevel@tonic-gate * If config specifies "nowild" in a 1970*0Sstevel@tonic-gate * global context, then we don't 1971*0Sstevel@tonic-gate * respond to wildcard PADRs. The 1972*0Sstevel@tonic-gate * client must know the exact service 1973*0Sstevel@tonic-gate * name to get access. 1974*0Sstevel@tonic-gate */ 1975*0Sstevel@tonic-gate 1976*0Sstevel@tonic-gate if (!ispadi && (glob_svc.se_flags & SEF_NOWILD)) 1977*0Sstevel@tonic-gate sepp = seppe; 1978*0Sstevel@tonic-gate while (sepp < seppe) { 1979*0Sstevel@tonic-gate sep = *sepp++; 1980*0Sstevel@tonic-gate if ((ispadi || !(sep->se_flags & 1981*0Sstevel@tonic-gate SEF_NOWILD)) && 1982*0Sstevel@tonic-gate allow_service(sep, pap)) { 1983*0Sstevel@tonic-gate nsvcs++; 1984*0Sstevel@tonic-gate *srvp = (void *)sep; 1985*0Sstevel@tonic-gate if (poep->poep_code == 1986*0Sstevel@tonic-gate POECODE_PADR) 1987*0Sstevel@tonic-gate break; 1988*0Sstevel@tonic-gate if (sep->se_name[0] == '\0') 1989*0Sstevel@tonic-gate continue; 1990*0Sstevel@tonic-gate (void) poe_add_str(opoe, 1991*0Sstevel@tonic-gate POETT_SERVICE, 1992*0Sstevel@tonic-gate sep->se_name); 1993*0Sstevel@tonic-gate } 1994*0Sstevel@tonic-gate } 1995*0Sstevel@tonic-gate } else { 1996*0Sstevel@tonic-gate /* Requested specific service; find it. */ 1997*0Sstevel@tonic-gate cp = (char *)POET_DATA(tagp); 1998*0Sstevel@tonic-gate while (sepp < seppe) { 1999*0Sstevel@tonic-gate sep = *sepp++; 2000*0Sstevel@tonic-gate if (strlen(sep->se_name) == tlen && 2001*0Sstevel@tonic-gate strncasecmp(sep->se_name, cp, 2002*0Sstevel@tonic-gate tlen) == 0) { 2003*0Sstevel@tonic-gate if (allow_service(sep, pap)) { 2004*0Sstevel@tonic-gate nsvcs++; 2005*0Sstevel@tonic-gate *srvp = (void *)sep; 2006*0Sstevel@tonic-gate } 2007*0Sstevel@tonic-gate break; 2008*0Sstevel@tonic-gate } 2009*0Sstevel@tonic-gate } 2010*0Sstevel@tonic-gate } 2011*0Sstevel@tonic-gate /* 2012*0Sstevel@tonic-gate * Allow service definition to override 2013*0Sstevel@tonic-gate * AC-Name (concentrator [server] name) field. 2014*0Sstevel@tonic-gate */ 2015*0Sstevel@tonic-gate if (*srvp != NULL) { 2016*0Sstevel@tonic-gate sep = (const struct service_entry *)*srvp; 2017*0Sstevel@tonic-gate log_for_service(sep->se_log, sep->se_debug); 2018*0Sstevel@tonic-gate str = "Solaris PPPoE"; 2019*0Sstevel@tonic-gate if (sep->se_server != NULL) 2020*0Sstevel@tonic-gate str = sep->se_server; 2021*0Sstevel@tonic-gate (void) poe_add_str(opoe, POETT_ACCESS, str); 2022*0Sstevel@tonic-gate } 2023*0Sstevel@tonic-gate break; 2024*0Sstevel@tonic-gate /* Ones we should discard */ 2025*0Sstevel@tonic-gate case POETT_ACCESS: /* AC-Name */ 2026*0Sstevel@tonic-gate case POETT_COOKIE: /* AC-Cookie */ 2027*0Sstevel@tonic-gate case POETT_NAMERR: /* Service-Name-Error */ 2028*0Sstevel@tonic-gate case POETT_SYSERR: /* AC-System-Error */ 2029*0Sstevel@tonic-gate case POETT_GENERR: /* Generic-Error */ 2030*0Sstevel@tonic-gate case POETT_HURL: /* Host-URL */ 2031*0Sstevel@tonic-gate case POETT_MOTM: /* Message-Of-The-Minute */ 2032*0Sstevel@tonic-gate case POETT_RTEADD: /* IP-Route-Add */ 2033*0Sstevel@tonic-gate case POETT_VENDOR: /* Vendor-Specific */ 2034*0Sstevel@tonic-gate case POETT_MULTI: /* Multicast-Capable */ 2035*0Sstevel@tonic-gate default: 2036*0Sstevel@tonic-gate break; 2037*0Sstevel@tonic-gate /* Ones we should copy */ 2038*0Sstevel@tonic-gate case POETT_UNIQ: /* Host-Uniq */ 2039*0Sstevel@tonic-gate case POETT_RELAY: /* Relay-Session-Id */ 2040*0Sstevel@tonic-gate (void) poe_tag_copy(opoe, tagp); 2041*0Sstevel@tonic-gate break; 2042*0Sstevel@tonic-gate } 2043*0Sstevel@tonic-gate tagp = POET_NEXT(tagp); 2044*0Sstevel@tonic-gate } 2045*0Sstevel@tonic-gate return (nsvcs); 2046*0Sstevel@tonic-gate } 2047*0Sstevel@tonic-gate 2048*0Sstevel@tonic-gate /* 2049*0Sstevel@tonic-gate * Like fgetc, but reads from a string. 2050*0Sstevel@tonic-gate */ 2051*0Sstevel@tonic-gate static int 2052*0Sstevel@tonic-gate sgetc(void *arg) 2053*0Sstevel@tonic-gate { 2054*0Sstevel@tonic-gate char **cpp = (char **)arg; 2055*0Sstevel@tonic-gate if (**cpp == '\0') 2056*0Sstevel@tonic-gate return (EOF); 2057*0Sstevel@tonic-gate return (*(*cpp)++); 2058*0Sstevel@tonic-gate } 2059*0Sstevel@tonic-gate 2060*0Sstevel@tonic-gate /* 2061*0Sstevel@tonic-gate * Given a service structure, launch pppd. Called by handle_input() 2062*0Sstevel@tonic-gate * in pppoed.c if locate_service() [above] finds exactly one service 2063*0Sstevel@tonic-gate * matching a PADR. 2064*0Sstevel@tonic-gate */ 2065*0Sstevel@tonic-gate int 2066*0Sstevel@tonic-gate launch_service(int tunfd, poep_t *poep, void *srvp, struct ppptun_control *ptc) 2067*0Sstevel@tonic-gate { 2068*0Sstevel@tonic-gate const struct service_entry *sep = (const struct service_entry *)srvp; 2069*0Sstevel@tonic-gate const char *path; 2070*0Sstevel@tonic-gate const char *extra; 2071*0Sstevel@tonic-gate const char *pppd; 2072*0Sstevel@tonic-gate const char *cp; 2073*0Sstevel@tonic-gate pid_t pidv; 2074*0Sstevel@tonic-gate int newtun; 2075*0Sstevel@tonic-gate struct ppptun_peer ptp; 2076*0Sstevel@tonic-gate union ppptun_name ptn; 2077*0Sstevel@tonic-gate const char *args[MAXARGS]; 2078*0Sstevel@tonic-gate struct strbuf ctrl; 2079*0Sstevel@tonic-gate struct strbuf data; 2080*0Sstevel@tonic-gate const char **cpp; 2081*0Sstevel@tonic-gate char *sptr; 2082*0Sstevel@tonic-gate char *spv; 2083*0Sstevel@tonic-gate int slen; 2084*0Sstevel@tonic-gate int retv; 2085*0Sstevel@tonic-gate char keybuf[MAX_KEYWORD]; 2086*0Sstevel@tonic-gate 2087*0Sstevel@tonic-gate assert(sep != NULL); 2088*0Sstevel@tonic-gate 2089*0Sstevel@tonic-gate /* Get tunnel driver connection for new PPP session. */ 2090*0Sstevel@tonic-gate newtun = open(tunnam, O_RDWR); 2091*0Sstevel@tonic-gate if (newtun == -1) 2092*0Sstevel@tonic-gate goto syserr; 2093*0Sstevel@tonic-gate 2094*0Sstevel@tonic-gate /* Set this session up for standard PPP and client's address. */ 2095*0Sstevel@tonic-gate (void) memset(&ptp, '\0', sizeof (ptp)); 2096*0Sstevel@tonic-gate ptp.ptp_style = PTS_PPPOE; 2097*0Sstevel@tonic-gate ptp.ptp_address = ptc->ptc_address; 2098*0Sstevel@tonic-gate if (strioctl(newtun, PPPTUN_SPEER, &ptp, sizeof (ptp), sizeof (ptp)) < 2099*0Sstevel@tonic-gate 0) 2100*0Sstevel@tonic-gate goto syserr; 2101*0Sstevel@tonic-gate ptp.ptp_rsessid = ptp.ptp_lsessid; 2102*0Sstevel@tonic-gate if (strioctl(newtun, PPPTUN_SPEER, &ptp, sizeof (ptp), sizeof (ptp)) < 2103*0Sstevel@tonic-gate 0) 2104*0Sstevel@tonic-gate goto syserr; 2105*0Sstevel@tonic-gate 2106*0Sstevel@tonic-gate /* Attach the requested lower stream. */ 2107*0Sstevel@tonic-gate cp = strchr(ptc->ptc_name, ':'); 2108*0Sstevel@tonic-gate if (cp == NULL) 2109*0Sstevel@tonic-gate cp = ptc->ptc_name + strlen(ptc->ptc_name); 2110*0Sstevel@tonic-gate (void) snprintf(ptn.ptn_name, sizeof (ptn.ptn_name), "%.*s:pppoe", 2111*0Sstevel@tonic-gate cp-ptc->ptc_name, ptc->ptc_name); 2112*0Sstevel@tonic-gate if (strioctl(newtun, PPPTUN_SDATA, &ptn, sizeof (ptn), 0) < 0) 2113*0Sstevel@tonic-gate goto syserr; 2114*0Sstevel@tonic-gate (void) snprintf(ptn.ptn_name, sizeof (ptn.ptn_name), "%.*s:pppoed", 2115*0Sstevel@tonic-gate cp-ptc->ptc_name, ptc->ptc_name); 2116*0Sstevel@tonic-gate if (strioctl(newtun, PPPTUN_SCTL, &ptn, sizeof (ptn), 0) < 0) 2117*0Sstevel@tonic-gate goto syserr; 2118*0Sstevel@tonic-gate 2119*0Sstevel@tonic-gate pidv = fork(); 2120*0Sstevel@tonic-gate if (pidv == (pid_t)-1) 2121*0Sstevel@tonic-gate goto syserr; 2122*0Sstevel@tonic-gate 2123*0Sstevel@tonic-gate if (pidv == (pid_t)0) { 2124*0Sstevel@tonic-gate /* 2125*0Sstevel@tonic-gate * Use syslog only in order to avoid mixing log messages 2126*0Sstevel@tonic-gate * in regular files. 2127*0Sstevel@tonic-gate */ 2128*0Sstevel@tonic-gate close_log_files(); 2129*0Sstevel@tonic-gate 2130*0Sstevel@tonic-gate if ((path = sep->se_path) == NULL) 2131*0Sstevel@tonic-gate path = "/usr/bin/pppd"; 2132*0Sstevel@tonic-gate if ((extra = sep->se_extra) == NULL) 2133*0Sstevel@tonic-gate extra = "plugin pppoe.so directtty"; 2134*0Sstevel@tonic-gate if ((pppd = sep->se_pppd) == NULL) 2135*0Sstevel@tonic-gate pppd = ""; 2136*0Sstevel@tonic-gate 2137*0Sstevel@tonic-gate /* Concatenate these. */ 2138*0Sstevel@tonic-gate slen = strlen(path) + strlen(extra) + strlen(pppd) + 3; 2139*0Sstevel@tonic-gate if ((sptr = (char *)malloc(slen)) == NULL) 2140*0Sstevel@tonic-gate goto bail_out; 2141*0Sstevel@tonic-gate (void) strcpy(sptr, path); 2142*0Sstevel@tonic-gate (void) strcat(sptr, " "); 2143*0Sstevel@tonic-gate (void) strcat(sptr, extra); 2144*0Sstevel@tonic-gate (void) strcat(sptr, " "); 2145*0Sstevel@tonic-gate (void) strcat(sptr, pppd); 2146*0Sstevel@tonic-gate 2147*0Sstevel@tonic-gate /* Parse out into arguments */ 2148*0Sstevel@tonic-gate cpp = args; 2149*0Sstevel@tonic-gate spv = sptr; 2150*0Sstevel@tonic-gate while (cpp < args + MAXARGS - 1) { 2151*0Sstevel@tonic-gate retv = getkeyword(NULL, keybuf, sizeof (keybuf), sgetc, 2152*0Sstevel@tonic-gate (void *)&spv, 1); 2153*0Sstevel@tonic-gate if (retv != 1) 2154*0Sstevel@tonic-gate *cpp++ = strsave(keybuf); 2155*0Sstevel@tonic-gate if (retv != 0) 2156*0Sstevel@tonic-gate break; 2157*0Sstevel@tonic-gate } 2158*0Sstevel@tonic-gate *cpp = NULL; 2159*0Sstevel@tonic-gate if (cpp == args) 2160*0Sstevel@tonic-gate goto bail_out; 2161*0Sstevel@tonic-gate 2162*0Sstevel@tonic-gate /* 2163*0Sstevel@tonic-gate * Fix tunnel device on stdin/stdout and error file on 2164*0Sstevel@tonic-gate * stderr. 2165*0Sstevel@tonic-gate */ 2166*0Sstevel@tonic-gate if (newtun != 0 && dup2(newtun, 0) < 0) 2167*0Sstevel@tonic-gate goto bail_out; 2168*0Sstevel@tonic-gate if (newtun != 1 && dup2(newtun, 1) < 0) 2169*0Sstevel@tonic-gate goto bail_out; 2170*0Sstevel@tonic-gate if (newtun > 1) 2171*0Sstevel@tonic-gate (void) close(newtun); 2172*0Sstevel@tonic-gate if (tunfd > 1) 2173*0Sstevel@tonic-gate (void) close(tunfd); 2174*0Sstevel@tonic-gate (void) close(2); 2175*0Sstevel@tonic-gate (void) open("/etc/ppp/pppoe-errors", O_WRONLY | O_APPEND | 2176*0Sstevel@tonic-gate O_CREAT, 0600); 2177*0Sstevel@tonic-gate 2178*0Sstevel@tonic-gate /* 2179*0Sstevel@tonic-gate * Change GID first, for obvious reasons. Note that 2180*0Sstevel@tonic-gate * we log any problems to syslog, not the errors file. 2181*0Sstevel@tonic-gate * The errors file is intended for problems in the 2182*0Sstevel@tonic-gate * exec'd program. 2183*0Sstevel@tonic-gate */ 2184*0Sstevel@tonic-gate if ((sep->se_flags & SEF_GIDSET) && 2185*0Sstevel@tonic-gate setgid(sep->se_gid) == -1) { 2186*0Sstevel@tonic-gate cp = mystrerror(errno); 2187*0Sstevel@tonic-gate reopen_log(); 2188*0Sstevel@tonic-gate logerr("setgid(%d): %s", sep->se_gid, cp); 2189*0Sstevel@tonic-gate goto logged; 2190*0Sstevel@tonic-gate } 2191*0Sstevel@tonic-gate if ((sep->se_flags & SEF_UIDSET) && 2192*0Sstevel@tonic-gate setuid(sep->se_uid) == -1) { 2193*0Sstevel@tonic-gate cp = mystrerror(errno); 2194*0Sstevel@tonic-gate reopen_log(); 2195*0Sstevel@tonic-gate logerr("setuid(%d): %s", sep->se_uid, cp); 2196*0Sstevel@tonic-gate goto logged; 2197*0Sstevel@tonic-gate } 2198*0Sstevel@tonic-gate 2199*0Sstevel@tonic-gate /* Run pppd */ 2200*0Sstevel@tonic-gate path = args[0]; 2201*0Sstevel@tonic-gate cp = strrchr(args[0], '/'); 2202*0Sstevel@tonic-gate if (cp != NULL && cp[1] != '\0') 2203*0Sstevel@tonic-gate args[0] = cp+1; 2204*0Sstevel@tonic-gate errno = 0; 2205*0Sstevel@tonic-gate (void) execv(path, (char * const *)args); 2206*0Sstevel@tonic-gate newtun = 0; 2207*0Sstevel@tonic-gate 2208*0Sstevel@tonic-gate /* 2209*0Sstevel@tonic-gate * Exec failure; attempt to log the problem and send a 2210*0Sstevel@tonic-gate * PADT to the client so that he knows the session 2211*0Sstevel@tonic-gate * went south. 2212*0Sstevel@tonic-gate */ 2213*0Sstevel@tonic-gate bail_out: 2214*0Sstevel@tonic-gate cp = mystrerror(errno); 2215*0Sstevel@tonic-gate reopen_log(); 2216*0Sstevel@tonic-gate logerr("\"%s\": %s", (sptr == NULL ? path : sptr), cp); 2217*0Sstevel@tonic-gate logged: 2218*0Sstevel@tonic-gate poep = poe_mkheader(pkt_output, POECODE_PADT, ptp.ptp_lsessid); 2219*0Sstevel@tonic-gate poep->poep_session_id = htons(ptp.ptp_lsessid); 2220*0Sstevel@tonic-gate (void) poe_add_str(poep, POETT_SYSERR, cp); 2221*0Sstevel@tonic-gate (void) sleep(1); 2222*0Sstevel@tonic-gate ctrl.len = sizeof (*ptc); 2223*0Sstevel@tonic-gate ctrl.buf = (caddr_t)ptc; 2224*0Sstevel@tonic-gate data.len = poe_length(poep) + sizeof (*poep); 2225*0Sstevel@tonic-gate data.buf = (caddr_t)poep; 2226*0Sstevel@tonic-gate if (putmsg(newtun, &ctrl, &data, 0) < 0) { 2227*0Sstevel@tonic-gate logerr("putmsg %s: %s", ptc->ptc_name, 2228*0Sstevel@tonic-gate mystrerror(errno)); 2229*0Sstevel@tonic-gate } 2230*0Sstevel@tonic-gate exit(1); 2231*0Sstevel@tonic-gate } 2232*0Sstevel@tonic-gate 2233*0Sstevel@tonic-gate (void) close(newtun); 2234*0Sstevel@tonic-gate 2235*0Sstevel@tonic-gate /* Give session ID to client in reply. */ 2236*0Sstevel@tonic-gate poep->poep_session_id = htons(ptp.ptp_lsessid); 2237*0Sstevel@tonic-gate return (1); 2238*0Sstevel@tonic-gate 2239*0Sstevel@tonic-gate syserr: 2240*0Sstevel@tonic-gate /* Peer doesn't know session ID yet; hope for the best. */ 2241*0Sstevel@tonic-gate retv = errno; 2242*0Sstevel@tonic-gate if (newtun >= 0) 2243*0Sstevel@tonic-gate (void) close(newtun); 2244*0Sstevel@tonic-gate (void) poe_add_str(poep, POETT_SYSERR, mystrerror(retv)); 2245*0Sstevel@tonic-gate return (0); 2246*0Sstevel@tonic-gate } 2247*0Sstevel@tonic-gate 2248*0Sstevel@tonic-gate /* 2249*0Sstevel@tonic-gate * This is pretty awful -- it uses recursion to print a simple list. 2250*0Sstevel@tonic-gate * It's just for debug, though, and does a reasonable job of printing 2251*0Sstevel@tonic-gate * the filters in the right order. 2252*0Sstevel@tonic-gate */ 2253*0Sstevel@tonic-gate static void 2254*0Sstevel@tonic-gate print_filter_list(FILE *fp, struct filter_entry *fep) 2255*0Sstevel@tonic-gate { 2256*0Sstevel@tonic-gate if (fep->fe_prev != NULL) 2257*0Sstevel@tonic-gate print_filter_list(fp, fep->fe_prev); 2258*0Sstevel@tonic-gate (void) fprintf(fp, "\t\t MAC %s", ehost2(&fep->fe_mac)); 2259*0Sstevel@tonic-gate (void) fprintf(fp, ", mask %s%s\n", ehost2(&fep->fe_mask), 2260*0Sstevel@tonic-gate (fep->fe_isexcept ? ", except" : "")); 2261*0Sstevel@tonic-gate } 2262*0Sstevel@tonic-gate 2263*0Sstevel@tonic-gate /* 2264*0Sstevel@tonic-gate * Write summary of parsed configuration data to given file. 2265*0Sstevel@tonic-gate */ 2266*0Sstevel@tonic-gate void 2267*0Sstevel@tonic-gate dump_configuration(FILE *fp) 2268*0Sstevel@tonic-gate { 2269*0Sstevel@tonic-gate const struct device_entry *dep; 2270*0Sstevel@tonic-gate const struct service_entry *sep, **sepp; 2271*0Sstevel@tonic-gate struct per_file *pfp; 2272*0Sstevel@tonic-gate int i, j; 2273*0Sstevel@tonic-gate 2274*0Sstevel@tonic-gate (void) fprintf(fp, "Will%s respond to wildcard queries.\n", 2275*0Sstevel@tonic-gate (glob_svc.se_flags & SEF_NOWILD) ? " not" : ""); 2276*0Sstevel@tonic-gate (void) fprintf(fp, 2277*0Sstevel@tonic-gate "Global debug level %d, log to %s; current level %d\n", 2278*0Sstevel@tonic-gate glob_svc.se_debug, 2279*0Sstevel@tonic-gate ((glob_svc.se_log == NULL || *glob_svc.se_log == '\0') ? 2280*0Sstevel@tonic-gate "syslog" : glob_svc.se_log), 2281*0Sstevel@tonic-gate log_level); 2282*0Sstevel@tonic-gate if (cur_options == NULL) { 2283*0Sstevel@tonic-gate (void) fprintf(fp, "No current configuration.\n"); 2284*0Sstevel@tonic-gate return; 2285*0Sstevel@tonic-gate } 2286*0Sstevel@tonic-gate (void) fprintf(fp, "Current configuration:\n"); 2287*0Sstevel@tonic-gate (void) fprintf(fp, " %d device(s):\n", cur_options->os_ndevices); 2288*0Sstevel@tonic-gate dep = cur_options->os_devices; 2289*0Sstevel@tonic-gate for (i = 0; i < cur_options->os_ndevices; i++, dep++) { 2290*0Sstevel@tonic-gate (void) fprintf(fp, "\t%s: %d service(s):\n", 2291*0Sstevel@tonic-gate dep->de_name, dep->de_nservices); 2292*0Sstevel@tonic-gate sepp = dep->de_services; 2293*0Sstevel@tonic-gate for (j = 0; j < dep->de_nservices; j++, sepp++) { 2294*0Sstevel@tonic-gate sep = *sepp; 2295*0Sstevel@tonic-gate (void) fprintf(fp, "\t %s: debug level %d", 2296*0Sstevel@tonic-gate sep->se_name, sep->se_debug); 2297*0Sstevel@tonic-gate if (sep->se_flags & SEF_UIDSET) 2298*0Sstevel@tonic-gate (void) fprintf(fp, ", UID %ld", sep->se_uid); 2299*0Sstevel@tonic-gate if (sep->se_flags & SEF_GIDSET) 2300*0Sstevel@tonic-gate (void) fprintf(fp, ", GID %ld", sep->se_gid); 2301*0Sstevel@tonic-gate if (sep->se_flags & SEF_WILD) 2302*0Sstevel@tonic-gate (void) fprintf(fp, ", wildcard"); 2303*0Sstevel@tonic-gate else if (sep->se_flags & SEF_NOWILD) 2304*0Sstevel@tonic-gate (void) fprintf(fp, ", nowildcard"); 2305*0Sstevel@tonic-gate else 2306*0Sstevel@tonic-gate (void) fprintf(fp, ", wildcard (default)"); 2307*0Sstevel@tonic-gate (void) putc('\n', fp); 2308*0Sstevel@tonic-gate if (sep->se_server != NULL) 2309*0Sstevel@tonic-gate (void) fprintf(fp, "\t\tserver \"%s\"\n", 2310*0Sstevel@tonic-gate sep->se_server); 2311*0Sstevel@tonic-gate if (sep->se_pppd != NULL) 2312*0Sstevel@tonic-gate (void) fprintf(fp, "\t\tpppd \"%s\"\n", 2313*0Sstevel@tonic-gate sep->se_pppd); 2314*0Sstevel@tonic-gate if (sep->se_path != NULL) 2315*0Sstevel@tonic-gate (void) fprintf(fp, "\t\tpath \"%s\"\n", 2316*0Sstevel@tonic-gate sep->se_path); 2317*0Sstevel@tonic-gate if (sep->se_extra != NULL) 2318*0Sstevel@tonic-gate (void) fprintf(fp, "\t\textra \"%s\"\n", 2319*0Sstevel@tonic-gate sep->se_extra); 2320*0Sstevel@tonic-gate if (sep->se_log != NULL) 2321*0Sstevel@tonic-gate (void) fprintf(fp, "\t\tlog \"%s\"\n", 2322*0Sstevel@tonic-gate sep->se_log); 2323*0Sstevel@tonic-gate if (sep->se_flist != NULL) { 2324*0Sstevel@tonic-gate (void) fprintf(fp, "\t\tfilter list:\n"); 2325*0Sstevel@tonic-gate print_filter_list(fp, sep->se_flist); 2326*0Sstevel@tonic-gate } 2327*0Sstevel@tonic-gate } 2328*0Sstevel@tonic-gate } 2329*0Sstevel@tonic-gate (void) fprintf(fp, "\nConfiguration read from:\n"); 2330*0Sstevel@tonic-gate for (pfp = cur_options->os_pfjunk; pfp != NULL; pfp = pfp->pf_prev) { 2331*0Sstevel@tonic-gate (void) fprintf(fp, " %s: %d service(s)\n", pfp->pf_name, 2332*0Sstevel@tonic-gate pfp->pf_nsvc); 2333*0Sstevel@tonic-gate } 2334*0Sstevel@tonic-gate } 2335