1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * main.c - Point-to-Point Protocol main module 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * Copyright 2000-2002 Sun Microsystems, Inc. All rights reserved. 5*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 6*7c478bd9Sstevel@tonic-gate * 7*7c478bd9Sstevel@tonic-gate * Permission to use, copy, modify, and distribute this software and its 8*7c478bd9Sstevel@tonic-gate * documentation is hereby granted, provided that the above copyright 9*7c478bd9Sstevel@tonic-gate * notice appears in all copies. 10*7c478bd9Sstevel@tonic-gate * 11*7c478bd9Sstevel@tonic-gate * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF 12*7c478bd9Sstevel@tonic-gate * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 13*7c478bd9Sstevel@tonic-gate * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 14*7c478bd9Sstevel@tonic-gate * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR 15*7c478bd9Sstevel@tonic-gate * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR 16*7c478bd9Sstevel@tonic-gate * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES 17*7c478bd9Sstevel@tonic-gate * 18*7c478bd9Sstevel@tonic-gate * Copyright (c) 1989 Carnegie Mellon University. 19*7c478bd9Sstevel@tonic-gate * All rights reserved. 20*7c478bd9Sstevel@tonic-gate * 21*7c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 22*7c478bd9Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are 23*7c478bd9Sstevel@tonic-gate * duplicated in all such forms and that any documentation, 24*7c478bd9Sstevel@tonic-gate * advertising materials, and other materials related to such 25*7c478bd9Sstevel@tonic-gate * distribution and use acknowledge that the software was developed 26*7c478bd9Sstevel@tonic-gate * by Carnegie Mellon University. The name of the 27*7c478bd9Sstevel@tonic-gate * University may not be used to endorse or promote products derived 28*7c478bd9Sstevel@tonic-gate * from this software without specific prior written permission. 29*7c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 30*7c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 31*7c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 32*7c478bd9Sstevel@tonic-gate */ 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 35*7c478bd9Sstevel@tonic-gate #define RCSID "$Id: main.c,v 1.97 2000/04/24 02:54:16 masputra Exp $" 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate #include <stdio.h> 38*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 39*7c478bd9Sstevel@tonic-gate #include <string.h> 40*7c478bd9Sstevel@tonic-gate #include <unistd.h> 41*7c478bd9Sstevel@tonic-gate #include <signal.h> 42*7c478bd9Sstevel@tonic-gate #include <errno.h> 43*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 44*7c478bd9Sstevel@tonic-gate #include <syslog.h> 45*7c478bd9Sstevel@tonic-gate #include <netdb.h> 46*7c478bd9Sstevel@tonic-gate #include <pwd.h> 47*7c478bd9Sstevel@tonic-gate #include <setjmp.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/wait.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/resource.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 55*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 56*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate #include "pppd.h" 59*7c478bd9Sstevel@tonic-gate #include "magic.h" 60*7c478bd9Sstevel@tonic-gate #include "fsm.h" 61*7c478bd9Sstevel@tonic-gate #include "lcp.h" 62*7c478bd9Sstevel@tonic-gate #include "ipcp.h" 63*7c478bd9Sstevel@tonic-gate #ifdef INET6 64*7c478bd9Sstevel@tonic-gate #include "ipv6cp.h" 65*7c478bd9Sstevel@tonic-gate #endif 66*7c478bd9Sstevel@tonic-gate #include "upap.h" 67*7c478bd9Sstevel@tonic-gate #include "chap.h" 68*7c478bd9Sstevel@tonic-gate #include "ccp.h" 69*7c478bd9Sstevel@tonic-gate #include "pathnames.h" 70*7c478bd9Sstevel@tonic-gate #include "patchlevel.h" 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 73*7c478bd9Sstevel@tonic-gate #include "tdb.h" 74*7c478bd9Sstevel@tonic-gate #endif 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate #ifdef CBCP_SUPPORT 77*7c478bd9Sstevel@tonic-gate #include "cbcp.h" 78*7c478bd9Sstevel@tonic-gate #endif 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate #ifdef IPX_CHANGE 81*7c478bd9Sstevel@tonic-gate #include "ipxcp.h" 82*7c478bd9Sstevel@tonic-gate #endif /* IPX_CHANGE */ 83*7c478bd9Sstevel@tonic-gate #ifdef AT_CHANGE 84*7c478bd9Sstevel@tonic-gate #include "atcp.h" 85*7c478bd9Sstevel@tonic-gate #endif 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate #if !defined(lint) && !defined(_lint) 88*7c478bd9Sstevel@tonic-gate static const char rcsid[] = RCSID; 89*7c478bd9Sstevel@tonic-gate #endif 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate /* interface vars */ 92*7c478bd9Sstevel@tonic-gate char ifname[32]; /* Interface name */ 93*7c478bd9Sstevel@tonic-gate int ifunit = -1; /* Interface unit number */ 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate char *progname; /* Name of this program */ 96*7c478bd9Sstevel@tonic-gate char hostname[MAXHOSTNAMELEN+1]; /* Our hostname */ 97*7c478bd9Sstevel@tonic-gate static char pidfilename[MAXPATHLEN]; /* name of pid file */ 98*7c478bd9Sstevel@tonic-gate static char linkpidfile[MAXPATHLEN]; /* name of linkname pid file */ 99*7c478bd9Sstevel@tonic-gate char ppp_devnam[MAXPATHLEN]; /* name of PPP tty (maybe ttypx) */ 100*7c478bd9Sstevel@tonic-gate static uid_t uid; /* Our real user-id */ 101*7c478bd9Sstevel@tonic-gate static int conn_running; /* we have a [dis]connector running */ 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate int ttyfd; /* Serial port file descriptor */ 104*7c478bd9Sstevel@tonic-gate mode_t tty_mode = (mode_t)-1; /* Original access permissions to tty */ 105*7c478bd9Sstevel@tonic-gate int baud_rate; /* Actual bits/second for serial device */ 106*7c478bd9Sstevel@tonic-gate bool hungup; /* terminal has been hung up */ 107*7c478bd9Sstevel@tonic-gate bool privileged; /* we're running as real uid root */ 108*7c478bd9Sstevel@tonic-gate bool need_holdoff; /* need holdoff period before restarting */ 109*7c478bd9Sstevel@tonic-gate bool detached; /* have detached from terminal */ 110*7c478bd9Sstevel@tonic-gate struct stat devstat; /* result of stat() on devnam */ 111*7c478bd9Sstevel@tonic-gate bool prepass = 0; /* doing prepass to find device name */ 112*7c478bd9Sstevel@tonic-gate int devnam_fixed; /* set while in options.ttyxx file */ 113*7c478bd9Sstevel@tonic-gate volatile int status; /* exit status for pppd */ 114*7c478bd9Sstevel@tonic-gate int unsuccess; /* # unsuccessful connection attempts */ 115*7c478bd9Sstevel@tonic-gate int do_callback; /* != 0 if we should do callback next */ 116*7c478bd9Sstevel@tonic-gate int doing_callback; /* != 0 if we are doing callback */ 117*7c478bd9Sstevel@tonic-gate char *callback_script; /* script for doing callback */ 118*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 119*7c478bd9Sstevel@tonic-gate TDB_CONTEXT *pppdb; /* database for storing status etc. */ 120*7c478bd9Sstevel@tonic-gate char db_key[32]; 121*7c478bd9Sstevel@tonic-gate #endif 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate /* 124*7c478bd9Sstevel@tonic-gate * For plug-in usage: 125*7c478bd9Sstevel@tonic-gate * 126*7c478bd9Sstevel@tonic-gate * holdoff_hook - Can be used to change the demand-dial hold-off 127*7c478bd9Sstevel@tonic-gate * time dynamically. This is normally set by the 128*7c478bd9Sstevel@tonic-gate * "holdoff" option, and is 30 seconds by default. 129*7c478bd9Sstevel@tonic-gate * 130*7c478bd9Sstevel@tonic-gate * new_phase_hook - This is called for each change in the PPP 131*7c478bd9Sstevel@tonic-gate * phase (per RFC 1661). This can be used to log 132*7c478bd9Sstevel@tonic-gate * progress. 133*7c478bd9Sstevel@tonic-gate * 134*7c478bd9Sstevel@tonic-gate * check_options_hook - This is called before doing sys_init() 135*7c478bd9Sstevel@tonic-gate * and allows the plugin to verify the selected options. 136*7c478bd9Sstevel@tonic-gate * 137*7c478bd9Sstevel@tonic-gate * updown_script_hook - This is called with the proposed 138*7c478bd9Sstevel@tonic-gate * command-line arguments for any of the 139*7c478bd9Sstevel@tonic-gate * /etc/ppp/{ip,ipv6,ipx,auth}-{up,down} scripts before 140*7c478bd9Sstevel@tonic-gate * fork/exec. It can be used to add or change arguments. 141*7c478bd9Sstevel@tonic-gate * 142*7c478bd9Sstevel@tonic-gate * device_pipe_hook - If this is set, then an extra fd (3) is 143*7c478bd9Sstevel@tonic-gate * passed to the connect/disconnect script. This extra 144*7c478bd9Sstevel@tonic-gate * fd is the write side of a pipe, and the read side is 145*7c478bd9Sstevel@tonic-gate * passed to this routine. This can be used to pass 146*7c478bd9Sstevel@tonic-gate * arbitrary data from the script back to pppd. 147*7c478bd9Sstevel@tonic-gate */ 148*7c478bd9Sstevel@tonic-gate int (*holdoff_hook) __P((void)) = NULL; 149*7c478bd9Sstevel@tonic-gate int (*new_phase_hook) __P((int new, int old)) = NULL; 150*7c478bd9Sstevel@tonic-gate int (*check_options_hook) __P((uid_t uid)) = NULL; 151*7c478bd9Sstevel@tonic-gate int (*updown_script_hook) __P((const char ***argsp)) = NULL; 152*7c478bd9Sstevel@tonic-gate void (*device_pipe_hook) __P((int pipefd)) = NULL; 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate static int fd_ppp = -1; /* fd for talking PPP */ 155*7c478bd9Sstevel@tonic-gate static int fd_loop; /* fd for getting demand-dial packets */ 156*7c478bd9Sstevel@tonic-gate static int pty_master; /* fd for master side of pty */ 157*7c478bd9Sstevel@tonic-gate int pty_slave = -1; /* fd for slave side of pty */ 158*7c478bd9Sstevel@tonic-gate static int real_ttyfd; /* fd for actual serial port (not pty) */ 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate int phase; /* where the link is at */ 161*7c478bd9Sstevel@tonic-gate int kill_link; 162*7c478bd9Sstevel@tonic-gate int open_ccp_flag; 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate static int waiting; /* for input from peer or timer expiration */ 165*7c478bd9Sstevel@tonic-gate static sigjmp_buf sigjmp; 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate char **script_env; /* Env. variable values for scripts */ 168*7c478bd9Sstevel@tonic-gate int s_env_nalloc; /* # words avail at script_env */ 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */ 171*7c478bd9Sstevel@tonic-gate u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */ 172*7c478bd9Sstevel@tonic-gate u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */ 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate static int n_children; /* # child processes still running */ 175*7c478bd9Sstevel@tonic-gate static bool got_sigchld; /* set if we have received a SIGCHLD */ 176*7c478bd9Sstevel@tonic-gate static sigset_t main_sigmask; /* signals blocked while dispatching */ 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate static bool locked; /* lock() has succeeded */ 179*7c478bd9Sstevel@tonic-gate static bool privopen; /* don't lock, open device as root */ 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n"; 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate GIDSET_TYPE groups[NGROUPS_MAX];/* groups the user is in */ 184*7c478bd9Sstevel@tonic-gate int ngroups; /* How many groups valid in groups */ 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate static struct timeval start_time; /* Time when link was started. */ 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate struct pppd_stats link_stats; 189*7c478bd9Sstevel@tonic-gate int link_connect_time; 190*7c478bd9Sstevel@tonic-gate bool link_stats_valid; 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate static pid_t charshunt_pid; /* Process ID for charshunt */ 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate extern option_t general_options[]; 195*7c478bd9Sstevel@tonic-gate extern option_t auth_options[]; 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate /* 198*7c478bd9Sstevel@tonic-gate * We maintain a list of child process pids and 199*7c478bd9Sstevel@tonic-gate * functions to call when they exit. 200*7c478bd9Sstevel@tonic-gate */ 201*7c478bd9Sstevel@tonic-gate struct subprocess { 202*7c478bd9Sstevel@tonic-gate pid_t pid; 203*7c478bd9Sstevel@tonic-gate char *prog; 204*7c478bd9Sstevel@tonic-gate void (*done) __P((void *, int)); 205*7c478bd9Sstevel@tonic-gate void *arg; 206*7c478bd9Sstevel@tonic-gate struct subprocess *next; 207*7c478bd9Sstevel@tonic-gate }; 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate static struct subprocess *children; 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate /* Prototypes for procedures local to this file. */ 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate static void setup_signals __P((void)); 214*7c478bd9Sstevel@tonic-gate static void create_pidfile __P((void)); 215*7c478bd9Sstevel@tonic-gate static void create_linkpidfile __P((void)); 216*7c478bd9Sstevel@tonic-gate static void cleanup __P((void)); 217*7c478bd9Sstevel@tonic-gate static void close_tty __P((void)); 218*7c478bd9Sstevel@tonic-gate static void get_input __P((void)); 219*7c478bd9Sstevel@tonic-gate static void calltimeout __P((void)); 220*7c478bd9Sstevel@tonic-gate static struct timeval *timeleft __P((struct timeval *)); 221*7c478bd9Sstevel@tonic-gate static void kill_my_pg __P((int)); 222*7c478bd9Sstevel@tonic-gate static void hup __P((int)); 223*7c478bd9Sstevel@tonic-gate static void term __P((int)); 224*7c478bd9Sstevel@tonic-gate static void chld __P((int)); 225*7c478bd9Sstevel@tonic-gate static void toggle_debug __P((int)); 226*7c478bd9Sstevel@tonic-gate static void open_ccp __P((int)); 227*7c478bd9Sstevel@tonic-gate static void bad_signal __P((int)); 228*7c478bd9Sstevel@tonic-gate static void holdoff_end __P((void *)); 229*7c478bd9Sstevel@tonic-gate static int device_script __P((char *, int, int, int, char *)); 230*7c478bd9Sstevel@tonic-gate static int reap_kids __P((int waitfor)); 231*7c478bd9Sstevel@tonic-gate static void record_child __P((pid_t, char *, void (*) (void *, int), void *)); 232*7c478bd9Sstevel@tonic-gate static int open_socket __P((char *)); 233*7c478bd9Sstevel@tonic-gate static int start_charshunt __P((int, int)); 234*7c478bd9Sstevel@tonic-gate static void charshunt_done __P((void *, int)); 235*7c478bd9Sstevel@tonic-gate static void charshunt __P((int, int, char *)); 236*7c478bd9Sstevel@tonic-gate static int record_write __P((FILE *, int code, u_char *buf, int nb, 237*7c478bd9Sstevel@tonic-gate struct timeval *)); 238*7c478bd9Sstevel@tonic-gate static void final_reap __P((void)); 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 241*7c478bd9Sstevel@tonic-gate static void update_db_entry __P((void)); 242*7c478bd9Sstevel@tonic-gate static void add_db_key __P((const char *)); 243*7c478bd9Sstevel@tonic-gate static void delete_db_key __P((const char *)); 244*7c478bd9Sstevel@tonic-gate static void cleanup_db __P((void)); 245*7c478bd9Sstevel@tonic-gate #endif 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate int main __P((int, char *[])); 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate #ifdef ultrix 250*7c478bd9Sstevel@tonic-gate #undef O_NONBLOCK 251*7c478bd9Sstevel@tonic-gate #define O_NONBLOCK O_NDELAY 252*7c478bd9Sstevel@tonic-gate #endif 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate #ifdef ULTRIX 255*7c478bd9Sstevel@tonic-gate #define setlogmask(x) 0 256*7c478bd9Sstevel@tonic-gate #endif 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate /* Backward compatibility for Linux */ 259*7c478bd9Sstevel@tonic-gate #ifndef RECMARK_TIMESTART 260*7c478bd9Sstevel@tonic-gate #define RECMARK_STARTSEND 1 261*7c478bd9Sstevel@tonic-gate #define RECMARK_STARTRECV 2 262*7c478bd9Sstevel@tonic-gate #define RECMARK_ENDSEND 3 263*7c478bd9Sstevel@tonic-gate #define RECMARK_ENDRECV 4 264*7c478bd9Sstevel@tonic-gate #define RECMARK_TIMEDELTA32 5 265*7c478bd9Sstevel@tonic-gate #define RECMARK_TIMEDELTA8 6 266*7c478bd9Sstevel@tonic-gate #define RECMARK_TIMESTART 7 267*7c478bd9Sstevel@tonic-gate #endif 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate /* 270*7c478bd9Sstevel@tonic-gate * PPP Data Link Layer "protocol" table. 271*7c478bd9Sstevel@tonic-gate * One entry per supported protocol. 272*7c478bd9Sstevel@tonic-gate * The last entry must be NULL. 273*7c478bd9Sstevel@tonic-gate */ 274*7c478bd9Sstevel@tonic-gate struct protent *protocols[] = { 275*7c478bd9Sstevel@tonic-gate &lcp_protent, 276*7c478bd9Sstevel@tonic-gate &pap_protent, 277*7c478bd9Sstevel@tonic-gate &chap_protent, 278*7c478bd9Sstevel@tonic-gate #ifdef CBCP_SUPPORT 279*7c478bd9Sstevel@tonic-gate &cbcp_protent, 280*7c478bd9Sstevel@tonic-gate #endif 281*7c478bd9Sstevel@tonic-gate &ipcp_protent, 282*7c478bd9Sstevel@tonic-gate #ifdef INET6 283*7c478bd9Sstevel@tonic-gate &ipv6cp_protent, 284*7c478bd9Sstevel@tonic-gate #endif 285*7c478bd9Sstevel@tonic-gate &ccp_protent, 286*7c478bd9Sstevel@tonic-gate #ifdef IPX_CHANGE 287*7c478bd9Sstevel@tonic-gate &ipxcp_protent, 288*7c478bd9Sstevel@tonic-gate #endif 289*7c478bd9Sstevel@tonic-gate #ifdef AT_CHANGE 290*7c478bd9Sstevel@tonic-gate &atcp_protent, 291*7c478bd9Sstevel@tonic-gate #endif 292*7c478bd9Sstevel@tonic-gate NULL 293*7c478bd9Sstevel@tonic-gate }; 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate int 296*7c478bd9Sstevel@tonic-gate main(argc, argv) 297*7c478bd9Sstevel@tonic-gate int argc; 298*7c478bd9Sstevel@tonic-gate char *argv[]; 299*7c478bd9Sstevel@tonic-gate { 300*7c478bd9Sstevel@tonic-gate int i, fdflags, t; 301*7c478bd9Sstevel@tonic-gate char *p, *connector; 302*7c478bd9Sstevel@tonic-gate struct passwd *pw; 303*7c478bd9Sstevel@tonic-gate struct timeval timo; 304*7c478bd9Sstevel@tonic-gate struct protent *protp; 305*7c478bd9Sstevel@tonic-gate struct stat statbuf; 306*7c478bd9Sstevel@tonic-gate char numbuf[16]; 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate ifname[0] = '\0'; 309*7c478bd9Sstevel@tonic-gate new_phase(PHASE_INITIALIZE); 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate /* 312*7c478bd9Sstevel@tonic-gate * Ensure that fds 0, 1, 2 are open, to /dev/null if nowhere else. 313*7c478bd9Sstevel@tonic-gate * This way we can close 0, 1, 2 in detach() without clobbering 314*7c478bd9Sstevel@tonic-gate * a fd that we are using. 315*7c478bd9Sstevel@tonic-gate */ 316*7c478bd9Sstevel@tonic-gate if ((i = open(_PATH_DEVNULL, O_RDWR)) >= 0) { 317*7c478bd9Sstevel@tonic-gate while (0 <= i && i <= 2) 318*7c478bd9Sstevel@tonic-gate i = dup(i); 319*7c478bd9Sstevel@tonic-gate if (i >= 0) 320*7c478bd9Sstevel@tonic-gate (void) close(i); 321*7c478bd9Sstevel@tonic-gate } 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate script_env = NULL; 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate /* Initialize syslog facilities */ 326*7c478bd9Sstevel@tonic-gate reopen_log(); 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate if (gethostname(hostname, MAXHOSTNAMELEN+1) < 0 ) { 329*7c478bd9Sstevel@tonic-gate option_error("Couldn't get hostname: %m"); 330*7c478bd9Sstevel@tonic-gate exit(1); 331*7c478bd9Sstevel@tonic-gate } 332*7c478bd9Sstevel@tonic-gate hostname[MAXHOSTNAMELEN] = '\0'; 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate /* make sure we don't create world or group writable files. */ 335*7c478bd9Sstevel@tonic-gate (void) umask(umask(0777) | 022); 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate uid = getuid(); 338*7c478bd9Sstevel@tonic-gate privileged = (uid == 0); 339*7c478bd9Sstevel@tonic-gate (void) slprintf(numbuf, sizeof(numbuf), "%d", uid); 340*7c478bd9Sstevel@tonic-gate script_setenv("ORIG_UID", numbuf, 0); 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate ngroups = getgroups(NGROUPS_MAX, groups); 343*7c478bd9Sstevel@tonic-gate 344*7c478bd9Sstevel@tonic-gate /* 345*7c478bd9Sstevel@tonic-gate * Initialize magic number generator now so that protocols may 346*7c478bd9Sstevel@tonic-gate * use magic numbers in initialization. 347*7c478bd9Sstevel@tonic-gate */ 348*7c478bd9Sstevel@tonic-gate magic_init(); 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate progname = *argv; 351*7c478bd9Sstevel@tonic-gate prepass = 0; 352*7c478bd9Sstevel@tonic-gate /* 353*7c478bd9Sstevel@tonic-gate * Initialize to the standard option set, then parse, in order, the 354*7c478bd9Sstevel@tonic-gate * system options file, the user's options file, the tty's options file, 355*7c478bd9Sstevel@tonic-gate * and the command line arguments. At last, install the options declared 356*7c478bd9Sstevel@tonic-gate * by each protocol into the extra_option list. 357*7c478bd9Sstevel@tonic-gate */ 358*7c478bd9Sstevel@tonic-gate for (i = 0; (protp = protocols[i]) != NULL; ++i) { 359*7c478bd9Sstevel@tonic-gate (*protp->init)(0); 360*7c478bd9Sstevel@tonic-gate if (protp->options != NULL) { 361*7c478bd9Sstevel@tonic-gate add_options(protp->options); 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate } 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate /* 366*7c478bd9Sstevel@tonic-gate * Install "generic" options into the extra_options list. 367*7c478bd9Sstevel@tonic-gate */ 368*7c478bd9Sstevel@tonic-gate add_options(auth_options); 369*7c478bd9Sstevel@tonic-gate add_options(general_options); 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate /* Install any system-specific options (or remove unusable ones) */ 372*7c478bd9Sstevel@tonic-gate sys_options(); 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate if (!options_from_file(_PATH_SYSOPTIONS, !privileged, 0, 1) 375*7c478bd9Sstevel@tonic-gate || !options_from_user()) 376*7c478bd9Sstevel@tonic-gate exit(EXIT_OPTION_ERROR); 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate /* scan command line and options files to find device name */ 379*7c478bd9Sstevel@tonic-gate prepass = 1; 380*7c478bd9Sstevel@tonic-gate (void) parse_args(argc-1, argv+1); 381*7c478bd9Sstevel@tonic-gate prepass = 0; 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate /* 384*7c478bd9Sstevel@tonic-gate * Work out the device name, if it hasn't already been specified. 385*7c478bd9Sstevel@tonic-gate */ 386*7c478bd9Sstevel@tonic-gate using_pty = notty || ptycommand != NULL || pty_socket != NULL; 387*7c478bd9Sstevel@tonic-gate if (!using_pty && default_device && !direct_tty) { 388*7c478bd9Sstevel@tonic-gate char *p; 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate if (!isatty(0) || (p = ttyname(0)) == NULL) { 391*7c478bd9Sstevel@tonic-gate option_error("no device specified and stdin is not a tty"); 392*7c478bd9Sstevel@tonic-gate exit(EXIT_OPTION_ERROR); 393*7c478bd9Sstevel@tonic-gate } 394*7c478bd9Sstevel@tonic-gate (void) strlcpy(devnam, p, sizeof(devnam)); 395*7c478bd9Sstevel@tonic-gate if (stat(devnam, &devstat) < 0) 396*7c478bd9Sstevel@tonic-gate fatal("Couldn't stat default device %s: %m", devnam); 397*7c478bd9Sstevel@tonic-gate } 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate /* 400*7c478bd9Sstevel@tonic-gate * Parse the tty options file and the command line. 401*7c478bd9Sstevel@tonic-gate * The per-tty options file should not change 402*7c478bd9Sstevel@tonic-gate * ptycommand, pty_socket, notty or devnam. 403*7c478bd9Sstevel@tonic-gate */ 404*7c478bd9Sstevel@tonic-gate devnam_fixed = 1; 405*7c478bd9Sstevel@tonic-gate if (!using_pty && !direct_tty) { 406*7c478bd9Sstevel@tonic-gate if (!options_for_tty()) 407*7c478bd9Sstevel@tonic-gate exit(EXIT_OPTION_ERROR); 408*7c478bd9Sstevel@tonic-gate } 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate devnam_fixed = 0; 411*7c478bd9Sstevel@tonic-gate if (!parse_args(argc-1, argv+1)) 412*7c478bd9Sstevel@tonic-gate exit(EXIT_OPTION_ERROR); 413*7c478bd9Sstevel@tonic-gate 414*7c478bd9Sstevel@tonic-gate /* 415*7c478bd9Sstevel@tonic-gate * Check that we are running as root. 416*7c478bd9Sstevel@tonic-gate */ 417*7c478bd9Sstevel@tonic-gate if (geteuid() != 0) { 418*7c478bd9Sstevel@tonic-gate option_error("must be root to run %s, since it is not setuid-root", 419*7c478bd9Sstevel@tonic-gate argv[0]); 420*7c478bd9Sstevel@tonic-gate exit(EXIT_NOT_ROOT); 421*7c478bd9Sstevel@tonic-gate } 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate if (!ppp_available()) { 424*7c478bd9Sstevel@tonic-gate option_error(no_ppp_msg); 425*7c478bd9Sstevel@tonic-gate exit(EXIT_NO_KERNEL_SUPPORT); 426*7c478bd9Sstevel@tonic-gate } 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate /* 429*7c478bd9Sstevel@tonic-gate * Check that the options given are valid and consistent. 430*7c478bd9Sstevel@tonic-gate */ 431*7c478bd9Sstevel@tonic-gate if (!sys_check_options()) 432*7c478bd9Sstevel@tonic-gate exit(EXIT_OPTION_ERROR); 433*7c478bd9Sstevel@tonic-gate auth_check_options(); 434*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 435*7c478bd9Sstevel@tonic-gate mp_check_options(); 436*7c478bd9Sstevel@tonic-gate #endif 437*7c478bd9Sstevel@tonic-gate for (i = 0; (protp = protocols[i]) != NULL; ++i) 438*7c478bd9Sstevel@tonic-gate if (protp->enabled_flag && protp->check_options != NULL) 439*7c478bd9Sstevel@tonic-gate (*protp->check_options)(); 440*7c478bd9Sstevel@tonic-gate if (demand && (connect_script == NULL)) { 441*7c478bd9Sstevel@tonic-gate option_error("connect script is required for demand-dialling\n"); 442*7c478bd9Sstevel@tonic-gate exit(EXIT_OPTION_ERROR); 443*7c478bd9Sstevel@tonic-gate } 444*7c478bd9Sstevel@tonic-gate if (updetach && (nodetach || demand)) { 445*7c478bd9Sstevel@tonic-gate option_error("updetach cannot be used with %s", 446*7c478bd9Sstevel@tonic-gate nodetach ? "nodetach" : "demand"); 447*7c478bd9Sstevel@tonic-gate exit(EXIT_OPTION_ERROR); 448*7c478bd9Sstevel@tonic-gate } 449*7c478bd9Sstevel@tonic-gate /* default holdoff to 0 if no connect script has been given */ 450*7c478bd9Sstevel@tonic-gate if ((connect_script == NULL) && !holdoff_specified) 451*7c478bd9Sstevel@tonic-gate holdoff = 0; 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate if (using_pty || direct_tty) { 454*7c478bd9Sstevel@tonic-gate if (!default_device) { 455*7c478bd9Sstevel@tonic-gate option_error("%s option precludes specifying device name", 456*7c478bd9Sstevel@tonic-gate notty? "notty": "pty"); 457*7c478bd9Sstevel@tonic-gate exit(EXIT_OPTION_ERROR); 458*7c478bd9Sstevel@tonic-gate } 459*7c478bd9Sstevel@tonic-gate if (ptycommand != NULL && (notty || direct_tty)) { 460*7c478bd9Sstevel@tonic-gate option_error("pty option is incompatible with notty option"); 461*7c478bd9Sstevel@tonic-gate exit(EXIT_OPTION_ERROR); 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate if (pty_socket != NULL && (ptycommand != NULL || notty || 464*7c478bd9Sstevel@tonic-gate direct_tty)) { 465*7c478bd9Sstevel@tonic-gate option_error("socket option is incompatible with pty and notty"); 466*7c478bd9Sstevel@tonic-gate exit(EXIT_OPTION_ERROR); 467*7c478bd9Sstevel@tonic-gate } 468*7c478bd9Sstevel@tonic-gate default_device = notty || direct_tty; 469*7c478bd9Sstevel@tonic-gate lockflag = 0; 470*7c478bd9Sstevel@tonic-gate modem = 0; 471*7c478bd9Sstevel@tonic-gate if (default_device && log_to_fd <= 1) 472*7c478bd9Sstevel@tonic-gate log_to_fd = -1; 473*7c478bd9Sstevel@tonic-gate } else { 474*7c478bd9Sstevel@tonic-gate /* 475*7c478bd9Sstevel@tonic-gate * If the user has specified a device which is the same as 476*7c478bd9Sstevel@tonic-gate * the one on stdin, pretend they didn't specify any. 477*7c478bd9Sstevel@tonic-gate * If the device is already open read/write on stdin, 478*7c478bd9Sstevel@tonic-gate * we assume we don't need to lock it, and we can open it as root. 479*7c478bd9Sstevel@tonic-gate */ 480*7c478bd9Sstevel@tonic-gate if (fstat(0, &statbuf) >= 0 && S_ISCHR(statbuf.st_mode) 481*7c478bd9Sstevel@tonic-gate && statbuf.st_rdev == devstat.st_rdev) { 482*7c478bd9Sstevel@tonic-gate default_device = 1; 483*7c478bd9Sstevel@tonic-gate fdflags = fcntl(0, F_GETFL); 484*7c478bd9Sstevel@tonic-gate if (fdflags != -1 && (fdflags & O_ACCMODE) == O_RDWR) 485*7c478bd9Sstevel@tonic-gate privopen = 1; 486*7c478bd9Sstevel@tonic-gate } 487*7c478bd9Sstevel@tonic-gate } 488*7c478bd9Sstevel@tonic-gate if (default_device) 489*7c478bd9Sstevel@tonic-gate nodetach = 1; 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate /* 492*7c478bd9Sstevel@tonic-gate * Don't send log messages to the serial port, it tends to 493*7c478bd9Sstevel@tonic-gate * confuse the peer. :-) 494*7c478bd9Sstevel@tonic-gate */ 495*7c478bd9Sstevel@tonic-gate if (log_to_fd >= 0 && fstat(log_to_fd, &statbuf) >= 0 496*7c478bd9Sstevel@tonic-gate && S_ISCHR(statbuf.st_mode) && statbuf.st_rdev == devstat.st_rdev) 497*7c478bd9Sstevel@tonic-gate log_to_fd = -1; 498*7c478bd9Sstevel@tonic-gate early_log = 0; 499*7c478bd9Sstevel@tonic-gate 500*7c478bd9Sstevel@tonic-gate if (debug) 501*7c478bd9Sstevel@tonic-gate (void) setlogmask(LOG_UPTO(LOG_DEBUG)); 502*7c478bd9Sstevel@tonic-gate 503*7c478bd9Sstevel@tonic-gate /* 504*7c478bd9Sstevel@tonic-gate * Initialize system-dependent stuff. 505*7c478bd9Sstevel@tonic-gate */ 506*7c478bd9Sstevel@tonic-gate if (check_options_hook != NULL && 507*7c478bd9Sstevel@tonic-gate (*check_options_hook)(uid) == -1) { 508*7c478bd9Sstevel@tonic-gate exit(EXIT_OPTION_ERROR); 509*7c478bd9Sstevel@tonic-gate } 510*7c478bd9Sstevel@tonic-gate sys_init(!devnam_info.priv && !privopen); 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 513*7c478bd9Sstevel@tonic-gate pppdb = tdb_open(_PATH_PPPDB, 0, 0, O_RDWR|O_CREAT, 0644); 514*7c478bd9Sstevel@tonic-gate if (pppdb != NULL) { 515*7c478bd9Sstevel@tonic-gate (void) slprintf(db_key, sizeof(db_key), "pppd%d", getpid()); 516*7c478bd9Sstevel@tonic-gate update_db_entry(); 517*7c478bd9Sstevel@tonic-gate } else { 518*7c478bd9Sstevel@tonic-gate warn("Warning: couldn't open ppp database %s", _PATH_PPPDB); 519*7c478bd9Sstevel@tonic-gate if (multilink) { 520*7c478bd9Sstevel@tonic-gate warn("Warning: disabling multilink"); 521*7c478bd9Sstevel@tonic-gate multilink = 0; 522*7c478bd9Sstevel@tonic-gate } 523*7c478bd9Sstevel@tonic-gate } 524*7c478bd9Sstevel@tonic-gate #endif 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate /* 527*7c478bd9Sstevel@tonic-gate * Detach ourselves from the terminal, if required, and identify 528*7c478bd9Sstevel@tonic-gate * who is running us. Printing to stderr stops here unless 529*7c478bd9Sstevel@tonic-gate * nodetach or updetach is set. 530*7c478bd9Sstevel@tonic-gate */ 531*7c478bd9Sstevel@tonic-gate if (!nodetach && !updetach) 532*7c478bd9Sstevel@tonic-gate detach(); 533*7c478bd9Sstevel@tonic-gate p = getlogin(); 534*7c478bd9Sstevel@tonic-gate if (p == NULL) { 535*7c478bd9Sstevel@tonic-gate pw = getpwuid(uid); 536*7c478bd9Sstevel@tonic-gate if (pw != NULL && pw->pw_name != NULL) 537*7c478bd9Sstevel@tonic-gate p = pw->pw_name; 538*7c478bd9Sstevel@tonic-gate else 539*7c478bd9Sstevel@tonic-gate p = "(unknown)"; 540*7c478bd9Sstevel@tonic-gate } 541*7c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, "pppd %s.%d%s started by %s, uid %d", 542*7c478bd9Sstevel@tonic-gate VERSION, PATCHLEVEL, IMPLEMENTATION, p, uid); 543*7c478bd9Sstevel@tonic-gate script_setenv("PPPLOGNAME", p, 0); 544*7c478bd9Sstevel@tonic-gate 545*7c478bd9Sstevel@tonic-gate if (devnam[0] != '\0') 546*7c478bd9Sstevel@tonic-gate script_setenv("DEVICE", devnam, 1); 547*7c478bd9Sstevel@tonic-gate (void) slprintf(numbuf, sizeof(numbuf), "%d", getpid()); 548*7c478bd9Sstevel@tonic-gate script_setenv("PPPD_PID", numbuf, 1); 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate setup_signals(); 551*7c478bd9Sstevel@tonic-gate 552*7c478bd9Sstevel@tonic-gate waiting = 0; 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate create_linkpidfile(); 555*7c478bd9Sstevel@tonic-gate 556*7c478bd9Sstevel@tonic-gate /* 557*7c478bd9Sstevel@tonic-gate * If we're doing dial-on-demand, set up the interface now. 558*7c478bd9Sstevel@tonic-gate */ 559*7c478bd9Sstevel@tonic-gate if (demand) { 560*7c478bd9Sstevel@tonic-gate /* 561*7c478bd9Sstevel@tonic-gate * Open the loopback channel and set it up to be the ppp interface. 562*7c478bd9Sstevel@tonic-gate */ 563*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 564*7c478bd9Sstevel@tonic-gate (void) tdb_writelock(pppdb); 565*7c478bd9Sstevel@tonic-gate #endif 566*7c478bd9Sstevel@tonic-gate set_ifunit(1); 567*7c478bd9Sstevel@tonic-gate fd_loop = open_ppp_loopback(); 568*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 569*7c478bd9Sstevel@tonic-gate (void) tdb_writeunlock(pppdb); 570*7c478bd9Sstevel@tonic-gate #endif 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate /* 573*7c478bd9Sstevel@tonic-gate * Configure the interface and mark it up, etc. 574*7c478bd9Sstevel@tonic-gate */ 575*7c478bd9Sstevel@tonic-gate demand_conf(); 576*7c478bd9Sstevel@tonic-gate } 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate new_phase(PHASE_INITIALIZED); 579*7c478bd9Sstevel@tonic-gate do_callback = 0; 580*7c478bd9Sstevel@tonic-gate for (;;) { 581*7c478bd9Sstevel@tonic-gate 582*7c478bd9Sstevel@tonic-gate need_holdoff = 1; 583*7c478bd9Sstevel@tonic-gate ttyfd = -1; 584*7c478bd9Sstevel@tonic-gate real_ttyfd = -1; 585*7c478bd9Sstevel@tonic-gate status = EXIT_OK; 586*7c478bd9Sstevel@tonic-gate ++unsuccess; 587*7c478bd9Sstevel@tonic-gate doing_callback = do_callback; 588*7c478bd9Sstevel@tonic-gate do_callback = 0; 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate if (demand && !doing_callback) { 591*7c478bd9Sstevel@tonic-gate /* 592*7c478bd9Sstevel@tonic-gate * Don't do anything until we see some activity. 593*7c478bd9Sstevel@tonic-gate */ 594*7c478bd9Sstevel@tonic-gate kill_link = 0; 595*7c478bd9Sstevel@tonic-gate new_phase(PHASE_DORMANT); 596*7c478bd9Sstevel@tonic-gate demand_unblock(); 597*7c478bd9Sstevel@tonic-gate add_fd(fd_loop); 598*7c478bd9Sstevel@tonic-gate for (;;) { 599*7c478bd9Sstevel@tonic-gate if (sigsetjmp(sigjmp, 1) == 0) { 600*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &main_sigmask, NULL); 601*7c478bd9Sstevel@tonic-gate if (kill_link || got_sigchld) { 602*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, &main_sigmask, NULL); 603*7c478bd9Sstevel@tonic-gate } else { 604*7c478bd9Sstevel@tonic-gate waiting = 1; 605*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, &main_sigmask, NULL); 606*7c478bd9Sstevel@tonic-gate wait_input(timeleft(&timo)); 607*7c478bd9Sstevel@tonic-gate } 608*7c478bd9Sstevel@tonic-gate } 609*7c478bd9Sstevel@tonic-gate waiting = 0; 610*7c478bd9Sstevel@tonic-gate calltimeout(); 611*7c478bd9Sstevel@tonic-gate if (kill_link) { 612*7c478bd9Sstevel@tonic-gate if (!persist) 613*7c478bd9Sstevel@tonic-gate break; 614*7c478bd9Sstevel@tonic-gate kill_link = 0; 615*7c478bd9Sstevel@tonic-gate } 616*7c478bd9Sstevel@tonic-gate if (get_loop_output()) 617*7c478bd9Sstevel@tonic-gate break; 618*7c478bd9Sstevel@tonic-gate if (got_sigchld) 619*7c478bd9Sstevel@tonic-gate (void) reap_kids(0); 620*7c478bd9Sstevel@tonic-gate } 621*7c478bd9Sstevel@tonic-gate remove_fd(fd_loop); 622*7c478bd9Sstevel@tonic-gate if (kill_link && !persist) 623*7c478bd9Sstevel@tonic-gate break; 624*7c478bd9Sstevel@tonic-gate 625*7c478bd9Sstevel@tonic-gate /* 626*7c478bd9Sstevel@tonic-gate * Now we want to bring up the link. 627*7c478bd9Sstevel@tonic-gate */ 628*7c478bd9Sstevel@tonic-gate demand_block(); 629*7c478bd9Sstevel@tonic-gate info("Starting link"); 630*7c478bd9Sstevel@tonic-gate } 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate new_phase(doing_callback ? PHASE_CALLINGBACK : PHASE_SERIALCONN); 633*7c478bd9Sstevel@tonic-gate 634*7c478bd9Sstevel@tonic-gate /* 635*7c478bd9Sstevel@tonic-gate * Get a pty master/slave pair if the pty, notty, socket, 636*7c478bd9Sstevel@tonic-gate * or record options were specified. 637*7c478bd9Sstevel@tonic-gate */ 638*7c478bd9Sstevel@tonic-gate (void) strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam)); 639*7c478bd9Sstevel@tonic-gate pty_master = -1; 640*7c478bd9Sstevel@tonic-gate pty_slave = -1; 641*7c478bd9Sstevel@tonic-gate if (using_pty || record_file != NULL) { 642*7c478bd9Sstevel@tonic-gate if (!get_pty(&pty_master, &pty_slave, ppp_devnam, uid)) { 643*7c478bd9Sstevel@tonic-gate error("Couldn't allocate pseudo-tty"); 644*7c478bd9Sstevel@tonic-gate status = EXIT_FATAL_ERROR; 645*7c478bd9Sstevel@tonic-gate goto fail; 646*7c478bd9Sstevel@tonic-gate } 647*7c478bd9Sstevel@tonic-gate set_up_tty(pty_slave, 1); 648*7c478bd9Sstevel@tonic-gate } 649*7c478bd9Sstevel@tonic-gate 650*7c478bd9Sstevel@tonic-gate /* 651*7c478bd9Sstevel@tonic-gate * Lock the device if we've been asked to. 652*7c478bd9Sstevel@tonic-gate */ 653*7c478bd9Sstevel@tonic-gate status = EXIT_LOCK_FAILED; 654*7c478bd9Sstevel@tonic-gate if (lockflag && !privopen && !direct_tty) { 655*7c478bd9Sstevel@tonic-gate if (lock(devnam) < 0) 656*7c478bd9Sstevel@tonic-gate goto fail; 657*7c478bd9Sstevel@tonic-gate locked = 1; 658*7c478bd9Sstevel@tonic-gate } 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate /* 661*7c478bd9Sstevel@tonic-gate * Open the serial device and set it up to be the ppp interface. 662*7c478bd9Sstevel@tonic-gate * First we open it in non-blocking mode so we can set the 663*7c478bd9Sstevel@tonic-gate * various termios flags appropriately. If we aren't dialling 664*7c478bd9Sstevel@tonic-gate * out and we want to use the modem lines, we reopen it later 665*7c478bd9Sstevel@tonic-gate * in order to wait for the carrier detect signal from the modem. 666*7c478bd9Sstevel@tonic-gate */ 667*7c478bd9Sstevel@tonic-gate hungup = 0; 668*7c478bd9Sstevel@tonic-gate kill_link = 0; 669*7c478bd9Sstevel@tonic-gate connector = doing_callback? callback_script: connect_script; 670*7c478bd9Sstevel@tonic-gate if (direct_tty) { 671*7c478bd9Sstevel@tonic-gate ttyfd = 0; 672*7c478bd9Sstevel@tonic-gate } else if (devnam[0] != '\0') { 673*7c478bd9Sstevel@tonic-gate for (;;) { 674*7c478bd9Sstevel@tonic-gate /* If the user specified the device name, become the 675*7c478bd9Sstevel@tonic-gate user before opening it. */ 676*7c478bd9Sstevel@tonic-gate int err; 677*7c478bd9Sstevel@tonic-gate if (!devnam_info.priv && !privopen) 678*7c478bd9Sstevel@tonic-gate (void) seteuid(uid); 679*7c478bd9Sstevel@tonic-gate if ((ttyfd = sys_extra_fd()) < 0) 680*7c478bd9Sstevel@tonic-gate ttyfd = open(devnam, O_NONBLOCK | O_RDWR); 681*7c478bd9Sstevel@tonic-gate err = errno; 682*7c478bd9Sstevel@tonic-gate if (!devnam_info.priv && !privopen) 683*7c478bd9Sstevel@tonic-gate (void) seteuid(0); 684*7c478bd9Sstevel@tonic-gate if (ttyfd >= 0) 685*7c478bd9Sstevel@tonic-gate break; 686*7c478bd9Sstevel@tonic-gate errno = err; 687*7c478bd9Sstevel@tonic-gate if (err != EINTR) { 688*7c478bd9Sstevel@tonic-gate error("Failed to open %s: %m", devnam); 689*7c478bd9Sstevel@tonic-gate status = EXIT_OPEN_FAILED; 690*7c478bd9Sstevel@tonic-gate } 691*7c478bd9Sstevel@tonic-gate if (!persist || err != EINTR) 692*7c478bd9Sstevel@tonic-gate goto fail; 693*7c478bd9Sstevel@tonic-gate } 694*7c478bd9Sstevel@tonic-gate if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1 695*7c478bd9Sstevel@tonic-gate || fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) 696*7c478bd9Sstevel@tonic-gate warn("Couldn't reset non-blocking mode on device: %m"); 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate /* 699*7c478bd9Sstevel@tonic-gate * Do the equivalent of `mesg n' to stop broadcast messages. 700*7c478bd9Sstevel@tonic-gate */ 701*7c478bd9Sstevel@tonic-gate if (fstat(ttyfd, &statbuf) < 0 702*7c478bd9Sstevel@tonic-gate || fchmod(ttyfd, statbuf.st_mode & ~(S_IWGRP | S_IWOTH)) < 0) { 703*7c478bd9Sstevel@tonic-gate warn("Couldn't restrict write permissions to %s: %m", devnam); 704*7c478bd9Sstevel@tonic-gate } else 705*7c478bd9Sstevel@tonic-gate tty_mode = statbuf.st_mode; 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate /* 708*7c478bd9Sstevel@tonic-gate * Set line speed, flow control, etc. 709*7c478bd9Sstevel@tonic-gate * If we have a non-null connection or initializer script, 710*7c478bd9Sstevel@tonic-gate * on most systems we set CLOCAL for now so that we can talk 711*7c478bd9Sstevel@tonic-gate * to the modem before carrier comes up. But this has the 712*7c478bd9Sstevel@tonic-gate * side effect that we might miss it if CD drops before we 713*7c478bd9Sstevel@tonic-gate * get to clear CLOCAL below. On systems where we can talk 714*7c478bd9Sstevel@tonic-gate * successfully to the modem with CLOCAL clear and CD down, 715*7c478bd9Sstevel@tonic-gate * we could clear CLOCAL at this point. 716*7c478bd9Sstevel@tonic-gate */ 717*7c478bd9Sstevel@tonic-gate set_up_tty(ttyfd, ((connector != NULL && connector[0] != '\0') 718*7c478bd9Sstevel@tonic-gate || initializer != NULL)); 719*7c478bd9Sstevel@tonic-gate real_ttyfd = ttyfd; 720*7c478bd9Sstevel@tonic-gate } 721*7c478bd9Sstevel@tonic-gate 722*7c478bd9Sstevel@tonic-gate /* 723*7c478bd9Sstevel@tonic-gate * If the pty, socket, notty and/or record option was specified, 724*7c478bd9Sstevel@tonic-gate * start up the character shunt now. 725*7c478bd9Sstevel@tonic-gate */ 726*7c478bd9Sstevel@tonic-gate status = EXIT_PTYCMD_FAILED; 727*7c478bd9Sstevel@tonic-gate if (ptycommand != NULL) { 728*7c478bd9Sstevel@tonic-gate if (record_file != NULL) { 729*7c478bd9Sstevel@tonic-gate int ipipe[2], opipe[2], ok; 730*7c478bd9Sstevel@tonic-gate 731*7c478bd9Sstevel@tonic-gate if (pipe(ipipe) < 0 || pipe(opipe) < 0) 732*7c478bd9Sstevel@tonic-gate fatal("Couldn't create pipes for record option: %m"); 733*7c478bd9Sstevel@tonic-gate dbglog("starting charshunt for pty option"); 734*7c478bd9Sstevel@tonic-gate ok = device_script(ptycommand, opipe[0], ipipe[1], 1, 735*7c478bd9Sstevel@tonic-gate "record") == 0 && start_charshunt(ipipe[0], opipe[1]); 736*7c478bd9Sstevel@tonic-gate (void) close(ipipe[0]); 737*7c478bd9Sstevel@tonic-gate (void) close(ipipe[1]); 738*7c478bd9Sstevel@tonic-gate (void) close(opipe[0]); 739*7c478bd9Sstevel@tonic-gate (void) close(opipe[1]); 740*7c478bd9Sstevel@tonic-gate if (!ok) 741*7c478bd9Sstevel@tonic-gate goto fail; 742*7c478bd9Sstevel@tonic-gate } else { 743*7c478bd9Sstevel@tonic-gate if (device_script(ptycommand, pty_master, pty_master, 1, 744*7c478bd9Sstevel@tonic-gate "pty") < 0) 745*7c478bd9Sstevel@tonic-gate goto fail; 746*7c478bd9Sstevel@tonic-gate ttyfd = pty_slave; 747*7c478bd9Sstevel@tonic-gate (void) close(pty_master); 748*7c478bd9Sstevel@tonic-gate pty_master = -1; 749*7c478bd9Sstevel@tonic-gate } 750*7c478bd9Sstevel@tonic-gate } else if (pty_socket != NULL) { 751*7c478bd9Sstevel@tonic-gate int fd = open_socket(pty_socket); 752*7c478bd9Sstevel@tonic-gate if (fd < 0) 753*7c478bd9Sstevel@tonic-gate goto fail; 754*7c478bd9Sstevel@tonic-gate dbglog("starting charshunt for socket option"); 755*7c478bd9Sstevel@tonic-gate if (!start_charshunt(fd, fd)) 756*7c478bd9Sstevel@tonic-gate goto fail; 757*7c478bd9Sstevel@tonic-gate } else if (notty) { 758*7c478bd9Sstevel@tonic-gate dbglog("starting charshunt for notty option"); 759*7c478bd9Sstevel@tonic-gate if (!start_charshunt(0, 1)) 760*7c478bd9Sstevel@tonic-gate goto fail; 761*7c478bd9Sstevel@tonic-gate } else if (record_file != NULL) { 762*7c478bd9Sstevel@tonic-gate dbglog("starting charshunt for record option"); 763*7c478bd9Sstevel@tonic-gate if (!start_charshunt(ttyfd, ttyfd)) 764*7c478bd9Sstevel@tonic-gate goto fail; 765*7c478bd9Sstevel@tonic-gate } 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate /* run connection script */ 768*7c478bd9Sstevel@tonic-gate if (((connector != NULL) && (connector[0] != '\0')) || initializer) { 769*7c478bd9Sstevel@tonic-gate if (real_ttyfd != -1) { 770*7c478bd9Sstevel@tonic-gate /* XXX do this if doing_callback == CALLBACK_DIALIN? */ 771*7c478bd9Sstevel@tonic-gate if (!default_device && modem && !direct_tty) { 772*7c478bd9Sstevel@tonic-gate setdtr(real_ttyfd, 0); /* in case modem is off hook */ 773*7c478bd9Sstevel@tonic-gate (void) sleep(1); 774*7c478bd9Sstevel@tonic-gate setdtr(real_ttyfd, 1); 775*7c478bd9Sstevel@tonic-gate } 776*7c478bd9Sstevel@tonic-gate } 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate if ((initializer != NULL) && (initializer[0] != '\0')) { 779*7c478bd9Sstevel@tonic-gate if (device_script(initializer, ttyfd, ttyfd, 0, "init") < 0) { 780*7c478bd9Sstevel@tonic-gate error("Initializer script failed"); 781*7c478bd9Sstevel@tonic-gate status = EXIT_INIT_FAILED; 782*7c478bd9Sstevel@tonic-gate goto fail; 783*7c478bd9Sstevel@tonic-gate } 784*7c478bd9Sstevel@tonic-gate if (kill_link) 785*7c478bd9Sstevel@tonic-gate goto disconnect; 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate info("Serial port initialized."); 788*7c478bd9Sstevel@tonic-gate } 789*7c478bd9Sstevel@tonic-gate 790*7c478bd9Sstevel@tonic-gate if ((connector != NULL) && (connector[0] != '\0')) { 791*7c478bd9Sstevel@tonic-gate if (device_script(connector, ttyfd, ttyfd, 0, "connect") < 0) { 792*7c478bd9Sstevel@tonic-gate error("Connect script failed"); 793*7c478bd9Sstevel@tonic-gate status = EXIT_CONNECT_FAILED; 794*7c478bd9Sstevel@tonic-gate goto fail; 795*7c478bd9Sstevel@tonic-gate } 796*7c478bd9Sstevel@tonic-gate if (kill_link) 797*7c478bd9Sstevel@tonic-gate goto disconnect; 798*7c478bd9Sstevel@tonic-gate 799*7c478bd9Sstevel@tonic-gate info("Serial connection established."); 800*7c478bd9Sstevel@tonic-gate } 801*7c478bd9Sstevel@tonic-gate 802*7c478bd9Sstevel@tonic-gate /* 803*7c478bd9Sstevel@tonic-gate * Clear CLOCAL if modem option -- we now have carrier 804*7c478bd9Sstevel@tonic-gate * established, and we should respect loss of carrier. 805*7c478bd9Sstevel@tonic-gate */ 806*7c478bd9Sstevel@tonic-gate if (real_ttyfd != -1) 807*7c478bd9Sstevel@tonic-gate set_up_tty(real_ttyfd, 0); 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate if (doing_callback == CALLBACK_DIALIN) 810*7c478bd9Sstevel@tonic-gate connector = NULL; 811*7c478bd9Sstevel@tonic-gate } 812*7c478bd9Sstevel@tonic-gate 813*7c478bd9Sstevel@tonic-gate /* reopen tty if necessary to wait for carrier */ 814*7c478bd9Sstevel@tonic-gate if (connector == NULL && modem && devnam[0] != '\0' && !direct_tty) { 815*7c478bd9Sstevel@tonic-gate for (;;) { 816*7c478bd9Sstevel@tonic-gate if ((i = open(devnam, O_RDWR)) >= 0) 817*7c478bd9Sstevel@tonic-gate break; 818*7c478bd9Sstevel@tonic-gate if (errno != EINTR) { 819*7c478bd9Sstevel@tonic-gate error("Failed to reopen %s: %m", devnam); 820*7c478bd9Sstevel@tonic-gate status = EXIT_OPEN_FAILED; 821*7c478bd9Sstevel@tonic-gate } 822*7c478bd9Sstevel@tonic-gate if (!persist || errno != EINTR || hungup || kill_link) 823*7c478bd9Sstevel@tonic-gate goto fail; 824*7c478bd9Sstevel@tonic-gate } 825*7c478bd9Sstevel@tonic-gate (void) close(i); 826*7c478bd9Sstevel@tonic-gate } 827*7c478bd9Sstevel@tonic-gate 828*7c478bd9Sstevel@tonic-gate (void) slprintf(numbuf, sizeof(numbuf), "%d", baud_rate); 829*7c478bd9Sstevel@tonic-gate script_setenv("SPEED", numbuf, 0); 830*7c478bd9Sstevel@tonic-gate 831*7c478bd9Sstevel@tonic-gate /* run welcome script, if any */ 832*7c478bd9Sstevel@tonic-gate if ((welcomer != NULL) && (welcomer[0] != '\0')) { 833*7c478bd9Sstevel@tonic-gate if (device_script(welcomer, ttyfd, ttyfd, 0, "welcome") < 0) 834*7c478bd9Sstevel@tonic-gate warn("Welcome script failed"); 835*7c478bd9Sstevel@tonic-gate } 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate /* set up the serial device as a ppp interface */ 838*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 839*7c478bd9Sstevel@tonic-gate (void) tdb_writelock(pppdb); 840*7c478bd9Sstevel@tonic-gate #endif 841*7c478bd9Sstevel@tonic-gate fd_ppp = establish_ppp(ttyfd); 842*7c478bd9Sstevel@tonic-gate if (fd_ppp < 0) { 843*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 844*7c478bd9Sstevel@tonic-gate (void) tdb_writeunlock(pppdb); 845*7c478bd9Sstevel@tonic-gate #endif 846*7c478bd9Sstevel@tonic-gate status = EXIT_FATAL_ERROR; 847*7c478bd9Sstevel@tonic-gate goto disconnect; 848*7c478bd9Sstevel@tonic-gate } 849*7c478bd9Sstevel@tonic-gate 850*7c478bd9Sstevel@tonic-gate if (!demand && ifunit >= 0) 851*7c478bd9Sstevel@tonic-gate set_ifunit(1); 852*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 853*7c478bd9Sstevel@tonic-gate (void) tdb_writeunlock(pppdb); 854*7c478bd9Sstevel@tonic-gate #endif 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate /* 857*7c478bd9Sstevel@tonic-gate * Start opening the connection and wait for 858*7c478bd9Sstevel@tonic-gate * incoming events (reply, timeout, etc.). 859*7c478bd9Sstevel@tonic-gate */ 860*7c478bd9Sstevel@tonic-gate notice("Connect: %s <--> %s", ifname, ppp_devnam); 861*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&start_time, NULL); 862*7c478bd9Sstevel@tonic-gate link_stats_valid = 0; 863*7c478bd9Sstevel@tonic-gate script_unsetenv("CONNECT_TIME"); 864*7c478bd9Sstevel@tonic-gate script_unsetenv("BYTES_SENT"); 865*7c478bd9Sstevel@tonic-gate script_unsetenv("BYTES_RCVD"); 866*7c478bd9Sstevel@tonic-gate lcp_lowerup(0); 867*7c478bd9Sstevel@tonic-gate 868*7c478bd9Sstevel@tonic-gate /* Mostly for accounting purposes */ 869*7c478bd9Sstevel@tonic-gate new_phase(PHASE_CONNECTED); 870*7c478bd9Sstevel@tonic-gate 871*7c478bd9Sstevel@tonic-gate /* 872*7c478bd9Sstevel@tonic-gate * If we are initiating this connection, wait for a short 873*7c478bd9Sstevel@tonic-gate * time for something from the peer. This can avoid bouncing 874*7c478bd9Sstevel@tonic-gate * our packets off his tty before he has it set up. 875*7c478bd9Sstevel@tonic-gate */ 876*7c478bd9Sstevel@tonic-gate add_fd(fd_ppp); 877*7c478bd9Sstevel@tonic-gate if (connect_delay != 0 && (connector != NULL || ptycommand != NULL)) { 878*7c478bd9Sstevel@tonic-gate struct timeval t; 879*7c478bd9Sstevel@tonic-gate t.tv_sec = connect_delay / 1000; 880*7c478bd9Sstevel@tonic-gate t.tv_usec = connect_delay % 1000; 881*7c478bd9Sstevel@tonic-gate wait_input(&t); 882*7c478bd9Sstevel@tonic-gate } 883*7c478bd9Sstevel@tonic-gate 884*7c478bd9Sstevel@tonic-gate lcp_open(0); /* Start protocol */ 885*7c478bd9Sstevel@tonic-gate open_ccp_flag = 0; 886*7c478bd9Sstevel@tonic-gate status = EXIT_NEGOTIATION_FAILED; 887*7c478bd9Sstevel@tonic-gate new_phase(PHASE_ESTABLISH); 888*7c478bd9Sstevel@tonic-gate while (phase != PHASE_DEAD) { 889*7c478bd9Sstevel@tonic-gate if (sigsetjmp(sigjmp, 1) == 0) { 890*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &main_sigmask, NULL); 891*7c478bd9Sstevel@tonic-gate if (kill_link || open_ccp_flag || got_sigchld) { 892*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, &main_sigmask, NULL); 893*7c478bd9Sstevel@tonic-gate } else { 894*7c478bd9Sstevel@tonic-gate waiting = 1; 895*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, &main_sigmask, NULL); 896*7c478bd9Sstevel@tonic-gate wait_input(timeleft(&timo)); 897*7c478bd9Sstevel@tonic-gate } 898*7c478bd9Sstevel@tonic-gate } 899*7c478bd9Sstevel@tonic-gate waiting = 0; 900*7c478bd9Sstevel@tonic-gate calltimeout(); 901*7c478bd9Sstevel@tonic-gate get_input(); 902*7c478bd9Sstevel@tonic-gate if (kill_link) { 903*7c478bd9Sstevel@tonic-gate lcp_close(0, "User request"); 904*7c478bd9Sstevel@tonic-gate kill_link = 0; 905*7c478bd9Sstevel@tonic-gate } 906*7c478bd9Sstevel@tonic-gate if (open_ccp_flag) { 907*7c478bd9Sstevel@tonic-gate if (phase == PHASE_NETWORK || phase == PHASE_RUNNING) { 908*7c478bd9Sstevel@tonic-gate /* Uncloak ourselves. */ 909*7c478bd9Sstevel@tonic-gate ccp_fsm[0].flags &= ~OPT_SILENT; 910*7c478bd9Sstevel@tonic-gate (*ccp_protent.open)(0); 911*7c478bd9Sstevel@tonic-gate } 912*7c478bd9Sstevel@tonic-gate open_ccp_flag = 0; 913*7c478bd9Sstevel@tonic-gate } 914*7c478bd9Sstevel@tonic-gate if (got_sigchld) 915*7c478bd9Sstevel@tonic-gate (void) reap_kids(0); /* Don't leave dead kids lying around */ 916*7c478bd9Sstevel@tonic-gate } 917*7c478bd9Sstevel@tonic-gate 918*7c478bd9Sstevel@tonic-gate /* 919*7c478bd9Sstevel@tonic-gate * Print connect time and statistics. 920*7c478bd9Sstevel@tonic-gate */ 921*7c478bd9Sstevel@tonic-gate if (link_stats_valid) { 922*7c478bd9Sstevel@tonic-gate int t = (link_connect_time + 5) / 6; /* 1/10ths of minutes */ 923*7c478bd9Sstevel@tonic-gate info("Connect time %d.%d minutes.", t/10, t%10); 924*7c478bd9Sstevel@tonic-gate info("Sent %" PPP_COUNTER_F " bytes (%" PPP_COUNTER_F 925*7c478bd9Sstevel@tonic-gate " packets), received %" PPP_COUNTER_F " bytes (%" PPP_COUNTER_F 926*7c478bd9Sstevel@tonic-gate " packets).", 927*7c478bd9Sstevel@tonic-gate link_stats.bytes_out, link_stats.pkts_out, 928*7c478bd9Sstevel@tonic-gate link_stats.bytes_in, link_stats.pkts_in); 929*7c478bd9Sstevel@tonic-gate } 930*7c478bd9Sstevel@tonic-gate 931*7c478bd9Sstevel@tonic-gate /* 932*7c478bd9Sstevel@tonic-gate * Delete pid file before disestablishing ppp. Otherwise it 933*7c478bd9Sstevel@tonic-gate * can happen that another pppd gets the same unit and then 934*7c478bd9Sstevel@tonic-gate * we delete its pid file. 935*7c478bd9Sstevel@tonic-gate */ 936*7c478bd9Sstevel@tonic-gate if (!demand) { 937*7c478bd9Sstevel@tonic-gate if (pidfilename[0] != '\0' 938*7c478bd9Sstevel@tonic-gate && unlink(pidfilename) < 0 && errno != ENOENT) 939*7c478bd9Sstevel@tonic-gate warn("unable to delete pid file %s: %m", pidfilename); 940*7c478bd9Sstevel@tonic-gate pidfilename[0] = '\0'; 941*7c478bd9Sstevel@tonic-gate } 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate /* 944*7c478bd9Sstevel@tonic-gate * If we may want to bring the link up again, transfer 945*7c478bd9Sstevel@tonic-gate * the ppp unit back to the loopback. Set the 946*7c478bd9Sstevel@tonic-gate * real serial device back to its normal mode of operation. 947*7c478bd9Sstevel@tonic-gate */ 948*7c478bd9Sstevel@tonic-gate remove_fd(fd_ppp); 949*7c478bd9Sstevel@tonic-gate clean_check(); 950*7c478bd9Sstevel@tonic-gate if (demand) 951*7c478bd9Sstevel@tonic-gate restore_loop(); 952*7c478bd9Sstevel@tonic-gate disestablish_ppp(ttyfd); 953*7c478bd9Sstevel@tonic-gate fd_ppp = -1; 954*7c478bd9Sstevel@tonic-gate if (!hungup) 955*7c478bd9Sstevel@tonic-gate lcp_lowerdown(0); 956*7c478bd9Sstevel@tonic-gate if (!demand) 957*7c478bd9Sstevel@tonic-gate script_unsetenv("IFNAME"); 958*7c478bd9Sstevel@tonic-gate 959*7c478bd9Sstevel@tonic-gate /* 960*7c478bd9Sstevel@tonic-gate * Run disconnector script, if requested. 961*7c478bd9Sstevel@tonic-gate * XXX we may not be able to do this if the line has hung up! 962*7c478bd9Sstevel@tonic-gate */ 963*7c478bd9Sstevel@tonic-gate disconnect: 964*7c478bd9Sstevel@tonic-gate if ((disconnect_script != NULL) && (disconnect_script[0] != '\0') && 965*7c478bd9Sstevel@tonic-gate !hungup) { 966*7c478bd9Sstevel@tonic-gate new_phase(PHASE_DISCONNECT); 967*7c478bd9Sstevel@tonic-gate if (real_ttyfd >= 0) 968*7c478bd9Sstevel@tonic-gate set_up_tty(real_ttyfd, 1); 969*7c478bd9Sstevel@tonic-gate if (device_script(disconnect_script, ttyfd, ttyfd, 0, 970*7c478bd9Sstevel@tonic-gate "disconnect") < 0) { 971*7c478bd9Sstevel@tonic-gate warn("disconnect script failed"); 972*7c478bd9Sstevel@tonic-gate } else { 973*7c478bd9Sstevel@tonic-gate info("Serial link disconnected."); 974*7c478bd9Sstevel@tonic-gate } 975*7c478bd9Sstevel@tonic-gate } 976*7c478bd9Sstevel@tonic-gate 977*7c478bd9Sstevel@tonic-gate fail: 978*7c478bd9Sstevel@tonic-gate if (pty_master >= 0) 979*7c478bd9Sstevel@tonic-gate (void) close(pty_master); 980*7c478bd9Sstevel@tonic-gate if (pty_slave >= 0) { 981*7c478bd9Sstevel@tonic-gate (void) close(pty_slave); 982*7c478bd9Sstevel@tonic-gate pty_slave = -1; 983*7c478bd9Sstevel@tonic-gate } 984*7c478bd9Sstevel@tonic-gate if (real_ttyfd >= 0) 985*7c478bd9Sstevel@tonic-gate close_tty(); 986*7c478bd9Sstevel@tonic-gate if (locked) { 987*7c478bd9Sstevel@tonic-gate locked = 0; 988*7c478bd9Sstevel@tonic-gate unlock(); 989*7c478bd9Sstevel@tonic-gate } 990*7c478bd9Sstevel@tonic-gate 991*7c478bd9Sstevel@tonic-gate if (!demand) { 992*7c478bd9Sstevel@tonic-gate if (pidfilename[0] != '\0' 993*7c478bd9Sstevel@tonic-gate && unlink(pidfilename) < 0 && errno != ENOENT) 994*7c478bd9Sstevel@tonic-gate warn("unable to delete pid file %s: %m", pidfilename); 995*7c478bd9Sstevel@tonic-gate pidfilename[0] = '\0'; 996*7c478bd9Sstevel@tonic-gate } 997*7c478bd9Sstevel@tonic-gate 998*7c478bd9Sstevel@tonic-gate if (!persist || (maxfail > 0 && unsuccess >= maxfail)) 999*7c478bd9Sstevel@tonic-gate break; 1000*7c478bd9Sstevel@tonic-gate 1001*7c478bd9Sstevel@tonic-gate kill_link = 0; 1002*7c478bd9Sstevel@tonic-gate if (demand) 1003*7c478bd9Sstevel@tonic-gate demand_discard(); 1004*7c478bd9Sstevel@tonic-gate t = need_holdoff? holdoff: 0; 1005*7c478bd9Sstevel@tonic-gate if (holdoff_hook != NULL) 1006*7c478bd9Sstevel@tonic-gate t = (*holdoff_hook)(); 1007*7c478bd9Sstevel@tonic-gate if (t > 0) { 1008*7c478bd9Sstevel@tonic-gate new_phase(PHASE_HOLDOFF); 1009*7c478bd9Sstevel@tonic-gate TIMEOUT(holdoff_end, NULL, t); 1010*7c478bd9Sstevel@tonic-gate do { 1011*7c478bd9Sstevel@tonic-gate if (sigsetjmp(sigjmp, 1) == 0) { 1012*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &main_sigmask, NULL); 1013*7c478bd9Sstevel@tonic-gate if (kill_link || got_sigchld) { 1014*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, &main_sigmask, NULL); 1015*7c478bd9Sstevel@tonic-gate } else { 1016*7c478bd9Sstevel@tonic-gate waiting = 1; 1017*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, &main_sigmask, NULL); 1018*7c478bd9Sstevel@tonic-gate wait_input(timeleft(&timo)); 1019*7c478bd9Sstevel@tonic-gate } 1020*7c478bd9Sstevel@tonic-gate } 1021*7c478bd9Sstevel@tonic-gate waiting = 0; 1022*7c478bd9Sstevel@tonic-gate calltimeout(); 1023*7c478bd9Sstevel@tonic-gate if (kill_link) { 1024*7c478bd9Sstevel@tonic-gate kill_link = 0; 1025*7c478bd9Sstevel@tonic-gate new_phase(PHASE_DORMANT); /* allow signal to end holdoff */ 1026*7c478bd9Sstevel@tonic-gate } 1027*7c478bd9Sstevel@tonic-gate if (got_sigchld) 1028*7c478bd9Sstevel@tonic-gate (void) reap_kids(0); 1029*7c478bd9Sstevel@tonic-gate } while (phase == PHASE_HOLDOFF); 1030*7c478bd9Sstevel@tonic-gate if (!persist) 1031*7c478bd9Sstevel@tonic-gate break; 1032*7c478bd9Sstevel@tonic-gate } 1033*7c478bd9Sstevel@tonic-gate } 1034*7c478bd9Sstevel@tonic-gate 1035*7c478bd9Sstevel@tonic-gate /* Wait for scripts to finish */ 1036*7c478bd9Sstevel@tonic-gate final_reap(); 1037*7c478bd9Sstevel@tonic-gate 1038*7c478bd9Sstevel@tonic-gate die(status); 1039*7c478bd9Sstevel@tonic-gate return (0); 1040*7c478bd9Sstevel@tonic-gate } 1041*7c478bd9Sstevel@tonic-gate 1042*7c478bd9Sstevel@tonic-gate /* 1043*7c478bd9Sstevel@tonic-gate * setup_signals - initialize signal handling. 1044*7c478bd9Sstevel@tonic-gate */ 1045*7c478bd9Sstevel@tonic-gate static void 1046*7c478bd9Sstevel@tonic-gate setup_signals() 1047*7c478bd9Sstevel@tonic-gate { 1048*7c478bd9Sstevel@tonic-gate struct sigaction sa; 1049*7c478bd9Sstevel@tonic-gate 1050*7c478bd9Sstevel@tonic-gate /* 1051*7c478bd9Sstevel@tonic-gate * Compute mask of all interesting signals and install signal handlers 1052*7c478bd9Sstevel@tonic-gate * for each. Only one signal handler may be active at a time. Therefore, 1053*7c478bd9Sstevel@tonic-gate * all other signals should be masked when any handler is executing. 1054*7c478bd9Sstevel@tonic-gate */ 1055*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&main_sigmask); 1056*7c478bd9Sstevel@tonic-gate (void) sigaddset(&main_sigmask, SIGHUP); 1057*7c478bd9Sstevel@tonic-gate (void) sigaddset(&main_sigmask, SIGINT); 1058*7c478bd9Sstevel@tonic-gate (void) sigaddset(&main_sigmask, SIGTERM); 1059*7c478bd9Sstevel@tonic-gate (void) sigaddset(&main_sigmask, SIGCHLD); 1060*7c478bd9Sstevel@tonic-gate (void) sigaddset(&main_sigmask, SIGUSR2); 1061*7c478bd9Sstevel@tonic-gate 1062*7c478bd9Sstevel@tonic-gate #define SIGNAL(s, handler) if (1) { \ 1063*7c478bd9Sstevel@tonic-gate sa.sa_handler = handler; \ 1064*7c478bd9Sstevel@tonic-gate if (sigaction(s, &sa, NULL) < 0) \ 1065*7c478bd9Sstevel@tonic-gate fatal("Couldn't establish signal handler (%d): %m", s); \ 1066*7c478bd9Sstevel@tonic-gate } else ((void)0) 1067*7c478bd9Sstevel@tonic-gate 1068*7c478bd9Sstevel@tonic-gate sa.sa_mask = main_sigmask; 1069*7c478bd9Sstevel@tonic-gate sa.sa_flags = 0; 1070*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGHUP, hup); /* Hangup */ 1071*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGINT, term); /* Interrupt */ 1072*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGTERM, term); /* Terminate */ 1073*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGCHLD, chld); 1074*7c478bd9Sstevel@tonic-gate 1075*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGUSR1, toggle_debug); /* Toggle debug flag */ 1076*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGUSR2, open_ccp); /* Reopen CCP */ 1077*7c478bd9Sstevel@tonic-gate 1078*7c478bd9Sstevel@tonic-gate /* 1079*7c478bd9Sstevel@tonic-gate * Install a handler for other signals which would otherwise 1080*7c478bd9Sstevel@tonic-gate * cause pppd to exit without cleaning up. 1081*7c478bd9Sstevel@tonic-gate */ 1082*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGABRT, bad_signal); 1083*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGALRM, bad_signal); 1084*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGFPE, bad_signal); 1085*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGILL, bad_signal); 1086*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGPIPE, bad_signal); 1087*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGQUIT, bad_signal); 1088*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 1089*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGSEGV, bad_signal); 1090*7c478bd9Sstevel@tonic-gate #endif 1091*7c478bd9Sstevel@tonic-gate #ifdef SIGBUS 1092*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGBUS, bad_signal); 1093*7c478bd9Sstevel@tonic-gate #endif 1094*7c478bd9Sstevel@tonic-gate #ifdef SIGEMT 1095*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGEMT, bad_signal); 1096*7c478bd9Sstevel@tonic-gate #endif 1097*7c478bd9Sstevel@tonic-gate #ifdef SIGPOLL 1098*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGPOLL, bad_signal); 1099*7c478bd9Sstevel@tonic-gate #endif 1100*7c478bd9Sstevel@tonic-gate #ifdef SIGPROF 1101*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGPROF, bad_signal); 1102*7c478bd9Sstevel@tonic-gate #endif 1103*7c478bd9Sstevel@tonic-gate #ifdef SIGSYS 1104*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGSYS, bad_signal); 1105*7c478bd9Sstevel@tonic-gate #endif 1106*7c478bd9Sstevel@tonic-gate #ifdef SIGTRAP 1107*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGTRAP, bad_signal); 1108*7c478bd9Sstevel@tonic-gate #endif 1109*7c478bd9Sstevel@tonic-gate #ifdef SIGVTALRM 1110*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGVTALRM, bad_signal); 1111*7c478bd9Sstevel@tonic-gate #endif 1112*7c478bd9Sstevel@tonic-gate #ifdef SIGXCPU 1113*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGXCPU, bad_signal); 1114*7c478bd9Sstevel@tonic-gate #endif 1115*7c478bd9Sstevel@tonic-gate #ifdef SIGXFSZ 1116*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGXFSZ, bad_signal); 1117*7c478bd9Sstevel@tonic-gate #endif 1118*7c478bd9Sstevel@tonic-gate 1119*7c478bd9Sstevel@tonic-gate /* 1120*7c478bd9Sstevel@tonic-gate * Apparently we can get a SIGPIPE when we call syslog, if 1121*7c478bd9Sstevel@tonic-gate * syslogd has died and been restarted. Ignoring it seems 1122*7c478bd9Sstevel@tonic-gate * be sufficient. 1123*7c478bd9Sstevel@tonic-gate */ 1124*7c478bd9Sstevel@tonic-gate (void) signal(SIGPIPE, SIG_IGN); 1125*7c478bd9Sstevel@tonic-gate } 1126*7c478bd9Sstevel@tonic-gate 1127*7c478bd9Sstevel@tonic-gate /* 1128*7c478bd9Sstevel@tonic-gate * set_ifunit - do things we need to do once we know which ppp 1129*7c478bd9Sstevel@tonic-gate * unit we are using. 1130*7c478bd9Sstevel@tonic-gate */ 1131*7c478bd9Sstevel@tonic-gate void 1132*7c478bd9Sstevel@tonic-gate set_ifunit(iskey) 1133*7c478bd9Sstevel@tonic-gate int iskey; 1134*7c478bd9Sstevel@tonic-gate { 1135*7c478bd9Sstevel@tonic-gate sys_ifname(); 1136*7c478bd9Sstevel@tonic-gate info("Using interface %s", ifname); 1137*7c478bd9Sstevel@tonic-gate script_setenv("IFNAME", ifname, iskey); 1138*7c478bd9Sstevel@tonic-gate if (iskey) { 1139*7c478bd9Sstevel@tonic-gate create_pidfile(); /* write pid to file */ 1140*7c478bd9Sstevel@tonic-gate create_linkpidfile(); 1141*7c478bd9Sstevel@tonic-gate } 1142*7c478bd9Sstevel@tonic-gate } 1143*7c478bd9Sstevel@tonic-gate 1144*7c478bd9Sstevel@tonic-gate /* 1145*7c478bd9Sstevel@tonic-gate * detach - detach us from the controlling terminal. 1146*7c478bd9Sstevel@tonic-gate */ 1147*7c478bd9Sstevel@tonic-gate void 1148*7c478bd9Sstevel@tonic-gate detach() 1149*7c478bd9Sstevel@tonic-gate { 1150*7c478bd9Sstevel@tonic-gate pid_t pid; 1151*7c478bd9Sstevel@tonic-gate char numbuf[16]; 1152*7c478bd9Sstevel@tonic-gate 1153*7c478bd9Sstevel@tonic-gate if (detached) 1154*7c478bd9Sstevel@tonic-gate return; 1155*7c478bd9Sstevel@tonic-gate if ((pid = fork()) == (pid_t)-1) { 1156*7c478bd9Sstevel@tonic-gate error("Couldn't detach (fork failed: %m)"); 1157*7c478bd9Sstevel@tonic-gate die(1); /* or just return? */ 1158*7c478bd9Sstevel@tonic-gate } 1159*7c478bd9Sstevel@tonic-gate if (pid != (pid_t)0) { 1160*7c478bd9Sstevel@tonic-gate /* parent */ 1161*7c478bd9Sstevel@tonic-gate if (locked) 1162*7c478bd9Sstevel@tonic-gate (void) relock(pid); 1163*7c478bd9Sstevel@tonic-gate exit(0); /* parent dies */ 1164*7c478bd9Sstevel@tonic-gate } 1165*7c478bd9Sstevel@tonic-gate (void) setsid(); 1166*7c478bd9Sstevel@tonic-gate /* 1167*7c478bd9Sstevel@tonic-gate * Fork again to relinquish session leadership. This is needed 1168*7c478bd9Sstevel@tonic-gate * to prevent the daemon from acquiring controlling terminal. 1169*7c478bd9Sstevel@tonic-gate */ 1170*7c478bd9Sstevel@tonic-gate if ((pid = fork()) == (pid_t)-1) { 1171*7c478bd9Sstevel@tonic-gate error("Couldn't detach (second fork failed: %m)"); 1172*7c478bd9Sstevel@tonic-gate die(1); /* or just return? */ 1173*7c478bd9Sstevel@tonic-gate } 1174*7c478bd9Sstevel@tonic-gate if (pid != (pid_t)0) { 1175*7c478bd9Sstevel@tonic-gate /* parent */ 1176*7c478bd9Sstevel@tonic-gate if (locked) 1177*7c478bd9Sstevel@tonic-gate (void) relock(pid); 1178*7c478bd9Sstevel@tonic-gate exit(0); /* parent dies */ 1179*7c478bd9Sstevel@tonic-gate } 1180*7c478bd9Sstevel@tonic-gate (void) chdir("/"); 1181*7c478bd9Sstevel@tonic-gate (void) close(0); 1182*7c478bd9Sstevel@tonic-gate (void) close(1); 1183*7c478bd9Sstevel@tonic-gate (void) close(2); 1184*7c478bd9Sstevel@tonic-gate detached = 1; 1185*7c478bd9Sstevel@tonic-gate if (!log_to_file && !log_to_specific_fd) 1186*7c478bd9Sstevel@tonic-gate log_to_fd = -1; 1187*7c478bd9Sstevel@tonic-gate /* update pid files if they have been written already */ 1188*7c478bd9Sstevel@tonic-gate if (pidfilename[0] != '\0') 1189*7c478bd9Sstevel@tonic-gate create_pidfile(); 1190*7c478bd9Sstevel@tonic-gate if (linkpidfile[0] != '\0') 1191*7c478bd9Sstevel@tonic-gate create_linkpidfile(); 1192*7c478bd9Sstevel@tonic-gate (void) slprintf(numbuf, sizeof(numbuf), "%d", getpid()); 1193*7c478bd9Sstevel@tonic-gate script_setenv("PPPD_PID", numbuf, 1); 1194*7c478bd9Sstevel@tonic-gate } 1195*7c478bd9Sstevel@tonic-gate 1196*7c478bd9Sstevel@tonic-gate /* 1197*7c478bd9Sstevel@tonic-gate * reopen_log - (re)open our connection to syslog. 1198*7c478bd9Sstevel@tonic-gate */ 1199*7c478bd9Sstevel@tonic-gate void 1200*7c478bd9Sstevel@tonic-gate reopen_log() 1201*7c478bd9Sstevel@tonic-gate { 1202*7c478bd9Sstevel@tonic-gate #ifdef ULTRIX 1203*7c478bd9Sstevel@tonic-gate openlog("pppd", LOG_PID); 1204*7c478bd9Sstevel@tonic-gate #else 1205*7c478bd9Sstevel@tonic-gate openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP); 1206*7c478bd9Sstevel@tonic-gate (void) setlogmask(LOG_UPTO(LOG_INFO)); 1207*7c478bd9Sstevel@tonic-gate #endif 1208*7c478bd9Sstevel@tonic-gate } 1209*7c478bd9Sstevel@tonic-gate 1210*7c478bd9Sstevel@tonic-gate /* 1211*7c478bd9Sstevel@tonic-gate * Create a file containing our process ID. 1212*7c478bd9Sstevel@tonic-gate */ 1213*7c478bd9Sstevel@tonic-gate static void 1214*7c478bd9Sstevel@tonic-gate create_pidfile() 1215*7c478bd9Sstevel@tonic-gate { 1216*7c478bd9Sstevel@tonic-gate FILE *pidfile; 1217*7c478bd9Sstevel@tonic-gate 1218*7c478bd9Sstevel@tonic-gate (void) slprintf(pidfilename, sizeof(pidfilename), "%s%s.pid", 1219*7c478bd9Sstevel@tonic-gate _PATH_VARRUN, ifname); 1220*7c478bd9Sstevel@tonic-gate if ((pidfile = fopen(pidfilename, "w")) != NULL) { 1221*7c478bd9Sstevel@tonic-gate (void) fprintf(pidfile, "%u\n", (unsigned)getpid()); 1222*7c478bd9Sstevel@tonic-gate (void) fclose(pidfile); 1223*7c478bd9Sstevel@tonic-gate } else { 1224*7c478bd9Sstevel@tonic-gate error("Failed to create pid file %s: %m", pidfilename); 1225*7c478bd9Sstevel@tonic-gate pidfilename[0] = '\0'; 1226*7c478bd9Sstevel@tonic-gate } 1227*7c478bd9Sstevel@tonic-gate } 1228*7c478bd9Sstevel@tonic-gate 1229*7c478bd9Sstevel@tonic-gate static void 1230*7c478bd9Sstevel@tonic-gate create_linkpidfile() 1231*7c478bd9Sstevel@tonic-gate { 1232*7c478bd9Sstevel@tonic-gate FILE *pidfile; 1233*7c478bd9Sstevel@tonic-gate 1234*7c478bd9Sstevel@tonic-gate if (linkname[0] == '\0') 1235*7c478bd9Sstevel@tonic-gate return; 1236*7c478bd9Sstevel@tonic-gate script_setenv("LINKNAME", linkname, 1); 1237*7c478bd9Sstevel@tonic-gate (void) slprintf(linkpidfile, sizeof(linkpidfile), "%sppp-%s.pid", 1238*7c478bd9Sstevel@tonic-gate _PATH_VARRUN, linkname); 1239*7c478bd9Sstevel@tonic-gate if ((pidfile = fopen(linkpidfile, "w")) != NULL) { 1240*7c478bd9Sstevel@tonic-gate (void) fprintf(pidfile, "%u\n", (unsigned)getpid()); 1241*7c478bd9Sstevel@tonic-gate if (ifname[0] != '\0') 1242*7c478bd9Sstevel@tonic-gate (void) fprintf(pidfile, "%s\n", ifname); 1243*7c478bd9Sstevel@tonic-gate (void) fclose(pidfile); 1244*7c478bd9Sstevel@tonic-gate } else { 1245*7c478bd9Sstevel@tonic-gate error("Failed to create pid file %s: %m", linkpidfile); 1246*7c478bd9Sstevel@tonic-gate linkpidfile[0] = '\0'; 1247*7c478bd9Sstevel@tonic-gate } 1248*7c478bd9Sstevel@tonic-gate } 1249*7c478bd9Sstevel@tonic-gate 1250*7c478bd9Sstevel@tonic-gate /* 1251*7c478bd9Sstevel@tonic-gate * holdoff_end - called via a timeout when the holdoff period ends. 1252*7c478bd9Sstevel@tonic-gate */ 1253*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1254*7c478bd9Sstevel@tonic-gate static void 1255*7c478bd9Sstevel@tonic-gate holdoff_end(arg) 1256*7c478bd9Sstevel@tonic-gate void *arg; 1257*7c478bd9Sstevel@tonic-gate { 1258*7c478bd9Sstevel@tonic-gate new_phase(PHASE_DORMANT); 1259*7c478bd9Sstevel@tonic-gate } 1260*7c478bd9Sstevel@tonic-gate 1261*7c478bd9Sstevel@tonic-gate /* List of protocol names, to make our messages a little more informative. */ 1262*7c478bd9Sstevel@tonic-gate struct protocol_list { 1263*7c478bd9Sstevel@tonic-gate u_short proto; 1264*7c478bd9Sstevel@tonic-gate const char *name; 1265*7c478bd9Sstevel@tonic-gate } protocol_list[] = { 1266*7c478bd9Sstevel@tonic-gate { 0x21, "IP" }, 1267*7c478bd9Sstevel@tonic-gate { 0x23, "OSI Network Layer" }, 1268*7c478bd9Sstevel@tonic-gate { 0x25, "Xerox NS IDP" }, 1269*7c478bd9Sstevel@tonic-gate { 0x27, "DECnet Phase IV" }, 1270*7c478bd9Sstevel@tonic-gate { 0x29, "Appletalk" }, 1271*7c478bd9Sstevel@tonic-gate { 0x2b, "Novell IPX" }, 1272*7c478bd9Sstevel@tonic-gate { 0x2d, "VJ compressed TCP/IP" }, 1273*7c478bd9Sstevel@tonic-gate { 0x2f, "VJ uncompressed TCP/IP" }, 1274*7c478bd9Sstevel@tonic-gate { 0x31, "Bridging PDU" }, 1275*7c478bd9Sstevel@tonic-gate { 0x33, "Stream Protocol ST-II" }, 1276*7c478bd9Sstevel@tonic-gate { 0x35, "Banyan Vines" }, 1277*7c478bd9Sstevel@tonic-gate { 0x37, "Old VJ compressed TCP/IP" }, 1278*7c478bd9Sstevel@tonic-gate { 0x39, "AppleTalk EDDP" }, 1279*7c478bd9Sstevel@tonic-gate { 0x3b, "AppleTalk SmartBuffered" }, 1280*7c478bd9Sstevel@tonic-gate { 0x3d, "Multilink" }, 1281*7c478bd9Sstevel@tonic-gate { 0x3f, "NetBIOS Frame" }, 1282*7c478bd9Sstevel@tonic-gate { 0x41, "Cisco LAN Extension" }, 1283*7c478bd9Sstevel@tonic-gate { 0x43, "Ascom Timeplex" }, 1284*7c478bd9Sstevel@tonic-gate { 0x45, "Fujitsu Link Backup and Load Balancing (LBLB)" }, 1285*7c478bd9Sstevel@tonic-gate { 0x47, "DCA Remote Lan" }, 1286*7c478bd9Sstevel@tonic-gate { 0x49, "Serial Data Transport Protocol (PPP-SDTP)" }, 1287*7c478bd9Sstevel@tonic-gate { 0x4b, "SNA over 802.2" }, 1288*7c478bd9Sstevel@tonic-gate { 0x4d, "SNA" }, 1289*7c478bd9Sstevel@tonic-gate { 0x4f, "IP6 Header Compression" }, 1290*7c478bd9Sstevel@tonic-gate { 0x51, "KNX Bridging" }, 1291*7c478bd9Sstevel@tonic-gate { 0x53, "Encrypted" }, 1292*7c478bd9Sstevel@tonic-gate { 0x55, "per-link encrypted" }, 1293*7c478bd9Sstevel@tonic-gate { 0x57, "IPv6" }, 1294*7c478bd9Sstevel@tonic-gate { 0x59, "PPP Muxing" }, 1295*7c478bd9Sstevel@tonic-gate { 0x6f, "Stampede Bridging" }, 1296*7c478bd9Sstevel@tonic-gate { 0x73, "MP+" }, 1297*7c478bd9Sstevel@tonic-gate { 0xc1, "STMF" }, 1298*7c478bd9Sstevel@tonic-gate { 0xfb, "per-link compressed" }, 1299*7c478bd9Sstevel@tonic-gate { 0xfd, "compressed datagram" }, 1300*7c478bd9Sstevel@tonic-gate { 0x0201, "802.1d Hello Packets" }, 1301*7c478bd9Sstevel@tonic-gate { 0x0203, "IBM Source Routing BPDU" }, 1302*7c478bd9Sstevel@tonic-gate { 0x0205, "DEC LANBridge100 Spanning Tree" }, 1303*7c478bd9Sstevel@tonic-gate { 0x0207, "Cisco Discovery Protocol" }, 1304*7c478bd9Sstevel@tonic-gate { 0x0231, "Luxcom" }, 1305*7c478bd9Sstevel@tonic-gate { 0x0233, "Sigma Network Systems" }, 1306*7c478bd9Sstevel@tonic-gate { 0x0235, "Apple Client Server Protocol" }, 1307*7c478bd9Sstevel@tonic-gate { 0x0281, "MPLS Unicast" }, 1308*7c478bd9Sstevel@tonic-gate { 0x0283, "MPLS Multicast" }, 1309*7c478bd9Sstevel@tonic-gate { 0x0285, "IEEE p1284.4" }, 1310*7c478bd9Sstevel@tonic-gate { 0x0287, "ETSI TETRA TNP1" }, 1311*7c478bd9Sstevel@tonic-gate { 0x4021, "Stacker LZS" }, 1312*7c478bd9Sstevel@tonic-gate { 0x8021, "Internet Protocol Control Protocol" }, 1313*7c478bd9Sstevel@tonic-gate { 0x8023, "OSI Network Layer Control Protocol" }, 1314*7c478bd9Sstevel@tonic-gate { 0x8025, "Xerox NS IDP Control Protocol" }, 1315*7c478bd9Sstevel@tonic-gate { 0x8027, "DECnet Phase IV Control Protocol" }, 1316*7c478bd9Sstevel@tonic-gate { 0x8029, "Appletalk Control Protocol" }, 1317*7c478bd9Sstevel@tonic-gate { 0x802b, "Novell IPX Control Protocol" }, 1318*7c478bd9Sstevel@tonic-gate { 0x8031, "Bridging Control Protocol" }, 1319*7c478bd9Sstevel@tonic-gate { 0x8033, "Stream Protocol Control Protocol" }, 1320*7c478bd9Sstevel@tonic-gate { 0x8035, "Banyan Vines Control Protocol" }, 1321*7c478bd9Sstevel@tonic-gate { 0x803f, "NetBIOS Frames Control Protocol" }, 1322*7c478bd9Sstevel@tonic-gate { 0x8041, "Cisco LAN Extension Control Protocol" }, 1323*7c478bd9Sstevel@tonic-gate { 0x8043, "Ascom Timeplex Control Protocol" }, 1324*7c478bd9Sstevel@tonic-gate { 0x8045, "Fujitsu LBLB Control Protocol" }, 1325*7c478bd9Sstevel@tonic-gate { 0x8047, "DCA Remote Lan Network Control Protocol (RLNCP)" }, 1326*7c478bd9Sstevel@tonic-gate { 0x8049, "Serial Data Control Protocol (PPP-SDCP)" }, 1327*7c478bd9Sstevel@tonic-gate { 0x804b, "SNA over 802.2 Control Protocol" }, 1328*7c478bd9Sstevel@tonic-gate { 0x804d, "SNA Control Protocol" }, 1329*7c478bd9Sstevel@tonic-gate { 0x8051, "KNX Bridging Control Protocol" }, 1330*7c478bd9Sstevel@tonic-gate { 0x8053, "Encryption Control Protocol" }, 1331*7c478bd9Sstevel@tonic-gate { 0x8055, "Per-link Encryption Control Protocol" }, 1332*7c478bd9Sstevel@tonic-gate { 0x8057, "IPv6 Control Protocol" }, 1333*7c478bd9Sstevel@tonic-gate { 0x806f, "Stampede Bridging Control Protocol" }, 1334*7c478bd9Sstevel@tonic-gate { 0x80c1, "STMF Control Protocol" }, 1335*7c478bd9Sstevel@tonic-gate { 0x80fb, "Per-link Compression Control Protocol" }, 1336*7c478bd9Sstevel@tonic-gate { 0x80fd, "Compression Control Protocol" }, 1337*7c478bd9Sstevel@tonic-gate { 0x8207, "Cisco Discovery Control Protocol" }, 1338*7c478bd9Sstevel@tonic-gate { 0x8235, "Apple Client Server Control Protocol" }, 1339*7c478bd9Sstevel@tonic-gate { 0x8281, "MPLS Control Protocol" }, 1340*7c478bd9Sstevel@tonic-gate { 0x8287, "ETSI TETRA TNP1 Control Protocol" }, 1341*7c478bd9Sstevel@tonic-gate { 0xc021, "Link Control Protocol" }, 1342*7c478bd9Sstevel@tonic-gate { 0xc023, "Password Authentication Protocol" }, 1343*7c478bd9Sstevel@tonic-gate { 0xc025, "Link Quality Report" }, 1344*7c478bd9Sstevel@tonic-gate { 0xc027, "Shiva Password Authentication Protocol" }, 1345*7c478bd9Sstevel@tonic-gate { 0xc029, "CallBack Control Protocol (CBCP)" }, 1346*7c478bd9Sstevel@tonic-gate { 0xc02b, "Bandwidth Allocation Control Protocol" }, 1347*7c478bd9Sstevel@tonic-gate { 0xc02d, "BAP" }, 1348*7c478bd9Sstevel@tonic-gate { 0xc081, "Container Control Protocol" }, 1349*7c478bd9Sstevel@tonic-gate { 0xc223, "Challenge Handshake Authentication Protocol" }, 1350*7c478bd9Sstevel@tonic-gate { 0xc227, "Extensible Authentication Protocol" }, 1351*7c478bd9Sstevel@tonic-gate { 0xc281, "Funk Proprietary Authentication Protocol" }, 1352*7c478bd9Sstevel@tonic-gate { 0, NULL }, 1353*7c478bd9Sstevel@tonic-gate }; 1354*7c478bd9Sstevel@tonic-gate 1355*7c478bd9Sstevel@tonic-gate /* 1356*7c478bd9Sstevel@tonic-gate * protocol_name - find a name for a PPP protocol. 1357*7c478bd9Sstevel@tonic-gate */ 1358*7c478bd9Sstevel@tonic-gate const char * 1359*7c478bd9Sstevel@tonic-gate protocol_name(proto) 1360*7c478bd9Sstevel@tonic-gate int proto; 1361*7c478bd9Sstevel@tonic-gate { 1362*7c478bd9Sstevel@tonic-gate struct protocol_list *lp; 1363*7c478bd9Sstevel@tonic-gate 1364*7c478bd9Sstevel@tonic-gate for (lp = protocol_list; lp->proto != 0; ++lp) 1365*7c478bd9Sstevel@tonic-gate if (proto == lp->proto) 1366*7c478bd9Sstevel@tonic-gate return (lp->name); 1367*7c478bd9Sstevel@tonic-gate return (NULL); 1368*7c478bd9Sstevel@tonic-gate } 1369*7c478bd9Sstevel@tonic-gate 1370*7c478bd9Sstevel@tonic-gate static const char *phase_names[] = { PHASE__NAMES }; 1371*7c478bd9Sstevel@tonic-gate 1372*7c478bd9Sstevel@tonic-gate const char * 1373*7c478bd9Sstevel@tonic-gate phase_name(pval) 1374*7c478bd9Sstevel@tonic-gate int pval; 1375*7c478bd9Sstevel@tonic-gate { 1376*7c478bd9Sstevel@tonic-gate static char buf[32]; 1377*7c478bd9Sstevel@tonic-gate 1378*7c478bd9Sstevel@tonic-gate if (pval < 0 || pval >= Dim(phase_names)) { 1379*7c478bd9Sstevel@tonic-gate (void) slprintf(buf, sizeof (buf), "unknown %d", pval); 1380*7c478bd9Sstevel@tonic-gate return ((const char *)buf); 1381*7c478bd9Sstevel@tonic-gate } 1382*7c478bd9Sstevel@tonic-gate return (phase_names[pval]); 1383*7c478bd9Sstevel@tonic-gate } 1384*7c478bd9Sstevel@tonic-gate 1385*7c478bd9Sstevel@tonic-gate /* 1386*7c478bd9Sstevel@tonic-gate * get_input - called when incoming data is available. 1387*7c478bd9Sstevel@tonic-gate */ 1388*7c478bd9Sstevel@tonic-gate static void 1389*7c478bd9Sstevel@tonic-gate get_input() 1390*7c478bd9Sstevel@tonic-gate { 1391*7c478bd9Sstevel@tonic-gate int len, i; 1392*7c478bd9Sstevel@tonic-gate u_char *p; 1393*7c478bd9Sstevel@tonic-gate u_short protocol; 1394*7c478bd9Sstevel@tonic-gate struct protent *protp; 1395*7c478bd9Sstevel@tonic-gate const char *pname; 1396*7c478bd9Sstevel@tonic-gate 1397*7c478bd9Sstevel@tonic-gate p = inpacket_buf; /* point to beginning of packet buffer */ 1398*7c478bd9Sstevel@tonic-gate 1399*7c478bd9Sstevel@tonic-gate len = read_packet(inpacket_buf); 1400*7c478bd9Sstevel@tonic-gate if (len < 0) 1401*7c478bd9Sstevel@tonic-gate return; 1402*7c478bd9Sstevel@tonic-gate 1403*7c478bd9Sstevel@tonic-gate if (len == 0) { 1404*7c478bd9Sstevel@tonic-gate notice("Modem hangup"); 1405*7c478bd9Sstevel@tonic-gate hungup = 1; 1406*7c478bd9Sstevel@tonic-gate status = EXIT_HANGUP; 1407*7c478bd9Sstevel@tonic-gate lcp_lowerdown(0); /* serial link is no longer available */ 1408*7c478bd9Sstevel@tonic-gate link_terminated(0); 1409*7c478bd9Sstevel@tonic-gate return; 1410*7c478bd9Sstevel@tonic-gate } 1411*7c478bd9Sstevel@tonic-gate 1412*7c478bd9Sstevel@tonic-gate if (debug /*&& (debugflags & DBG_INPACKET)*/) 1413*7c478bd9Sstevel@tonic-gate dbglog("rcvd %P", p, len); 1414*7c478bd9Sstevel@tonic-gate 1415*7c478bd9Sstevel@tonic-gate if (len < PPP_HDRLEN) { 1416*7c478bd9Sstevel@tonic-gate dbglog("Discarded short packet (%d < %d)", len, PPP_HDRLEN); 1417*7c478bd9Sstevel@tonic-gate return; 1418*7c478bd9Sstevel@tonic-gate } 1419*7c478bd9Sstevel@tonic-gate 1420*7c478bd9Sstevel@tonic-gate p += 2; /* Skip address and control */ 1421*7c478bd9Sstevel@tonic-gate GETSHORT(protocol, p); 1422*7c478bd9Sstevel@tonic-gate len -= PPP_HDRLEN; 1423*7c478bd9Sstevel@tonic-gate 1424*7c478bd9Sstevel@tonic-gate pname = debug ? NULL : protocol_name(protocol); 1425*7c478bd9Sstevel@tonic-gate 1426*7c478bd9Sstevel@tonic-gate /* 1427*7c478bd9Sstevel@tonic-gate * Toss all non-LCP packets unless LCP is in Opened state and 1428*7c478bd9Sstevel@tonic-gate * discard non-authentication protocols if we're not yet 1429*7c478bd9Sstevel@tonic-gate * authenticated. 1430*7c478bd9Sstevel@tonic-gate */ 1431*7c478bd9Sstevel@tonic-gate if ((protocol != PPP_LCP && 1432*7c478bd9Sstevel@tonic-gate (phase < PHASE_AUTHENTICATE || phase > PHASE_RUNNING)) || 1433*7c478bd9Sstevel@tonic-gate (phase <= PHASE_AUTHENTICATE && 1434*7c478bd9Sstevel@tonic-gate !(protocol == PPP_LCP || protocol == PPP_LQR || 1435*7c478bd9Sstevel@tonic-gate protocol == PPP_PAP || protocol == PPP_CHAP))) { 1436*7c478bd9Sstevel@tonic-gate if (pname == NULL) 1437*7c478bd9Sstevel@tonic-gate dbglog("Discarded proto 0x%x in %s phase", 1438*7c478bd9Sstevel@tonic-gate protocol, phase_name(phase)); 1439*7c478bd9Sstevel@tonic-gate else 1440*7c478bd9Sstevel@tonic-gate dbglog("Discarded %s (0x%x) in %s phase", 1441*7c478bd9Sstevel@tonic-gate pname, protocol, phase_name(phase)); 1442*7c478bd9Sstevel@tonic-gate return; 1443*7c478bd9Sstevel@tonic-gate } 1444*7c478bd9Sstevel@tonic-gate 1445*7c478bd9Sstevel@tonic-gate /* 1446*7c478bd9Sstevel@tonic-gate * Upcall the proper protocol input routine. 1447*7c478bd9Sstevel@tonic-gate */ 1448*7c478bd9Sstevel@tonic-gate for (i = 0; (protp = protocols[i]) != NULL; ++i) { 1449*7c478bd9Sstevel@tonic-gate if (protp->protocol == protocol && protp->enabled_flag) { 1450*7c478bd9Sstevel@tonic-gate (*protp->input)(0, p, len); 1451*7c478bd9Sstevel@tonic-gate return; 1452*7c478bd9Sstevel@tonic-gate } 1453*7c478bd9Sstevel@tonic-gate if (protocol == (protp->protocol & ~0x8000) && protp->enabled_flag 1454*7c478bd9Sstevel@tonic-gate && protp->datainput != NULL) { 1455*7c478bd9Sstevel@tonic-gate (*protp->datainput)(0, p, len); 1456*7c478bd9Sstevel@tonic-gate return; 1457*7c478bd9Sstevel@tonic-gate } 1458*7c478bd9Sstevel@tonic-gate } 1459*7c478bd9Sstevel@tonic-gate 1460*7c478bd9Sstevel@tonic-gate if (debug) { 1461*7c478bd9Sstevel@tonic-gate if (pname != NULL) 1462*7c478bd9Sstevel@tonic-gate warn("Unsupported protocol '%s' (0x%x) received", pname, protocol); 1463*7c478bd9Sstevel@tonic-gate else 1464*7c478bd9Sstevel@tonic-gate warn("Unsupported protocol 0x%x received", protocol); 1465*7c478bd9Sstevel@tonic-gate } 1466*7c478bd9Sstevel@tonic-gate lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN); 1467*7c478bd9Sstevel@tonic-gate } 1468*7c478bd9Sstevel@tonic-gate 1469*7c478bd9Sstevel@tonic-gate /* 1470*7c478bd9Sstevel@tonic-gate * new_phase - signal the start of a new phase of pppd's operation. 1471*7c478bd9Sstevel@tonic-gate */ 1472*7c478bd9Sstevel@tonic-gate void 1473*7c478bd9Sstevel@tonic-gate new_phase(p) 1474*7c478bd9Sstevel@tonic-gate int p; 1475*7c478bd9Sstevel@tonic-gate { 1476*7c478bd9Sstevel@tonic-gate if (new_phase_hook != NULL) 1477*7c478bd9Sstevel@tonic-gate (*new_phase_hook)(p, phase); 1478*7c478bd9Sstevel@tonic-gate phase = p; 1479*7c478bd9Sstevel@tonic-gate } 1480*7c478bd9Sstevel@tonic-gate 1481*7c478bd9Sstevel@tonic-gate /* 1482*7c478bd9Sstevel@tonic-gate * die - clean up state and exit with the specified status. 1483*7c478bd9Sstevel@tonic-gate */ 1484*7c478bd9Sstevel@tonic-gate void 1485*7c478bd9Sstevel@tonic-gate die(status) 1486*7c478bd9Sstevel@tonic-gate int status; 1487*7c478bd9Sstevel@tonic-gate { 1488*7c478bd9Sstevel@tonic-gate cleanup(); 1489*7c478bd9Sstevel@tonic-gate if (phase != PHASE_EXIT) { 1490*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, "Exit."); 1491*7c478bd9Sstevel@tonic-gate new_phase(PHASE_EXIT); 1492*7c478bd9Sstevel@tonic-gate } 1493*7c478bd9Sstevel@tonic-gate exit(status); 1494*7c478bd9Sstevel@tonic-gate } 1495*7c478bd9Sstevel@tonic-gate 1496*7c478bd9Sstevel@tonic-gate /* 1497*7c478bd9Sstevel@tonic-gate * cleanup - restore anything which needs to be restored before we exit 1498*7c478bd9Sstevel@tonic-gate */ 1499*7c478bd9Sstevel@tonic-gate static void 1500*7c478bd9Sstevel@tonic-gate cleanup() 1501*7c478bd9Sstevel@tonic-gate { 1502*7c478bd9Sstevel@tonic-gate sys_cleanup(); /* XXX: Need to check if this is okay after close_tty */ 1503*7c478bd9Sstevel@tonic-gate 1504*7c478bd9Sstevel@tonic-gate if (fd_ppp >= 0) { 1505*7c478bd9Sstevel@tonic-gate fd_ppp = -1; 1506*7c478bd9Sstevel@tonic-gate disestablish_ppp(ttyfd); 1507*7c478bd9Sstevel@tonic-gate } 1508*7c478bd9Sstevel@tonic-gate if (real_ttyfd >= 0) 1509*7c478bd9Sstevel@tonic-gate close_tty(); 1510*7c478bd9Sstevel@tonic-gate 1511*7c478bd9Sstevel@tonic-gate if (pidfilename[0] != '\0' && unlink(pidfilename) < 0 && errno != ENOENT) 1512*7c478bd9Sstevel@tonic-gate warn("unable to delete pid file %s: %m", pidfilename); 1513*7c478bd9Sstevel@tonic-gate pidfilename[0] = '\0'; 1514*7c478bd9Sstevel@tonic-gate if (linkpidfile[0] != '\0' && unlink(linkpidfile) < 0 && errno != ENOENT) 1515*7c478bd9Sstevel@tonic-gate warn("unable to delete pid file %s: %m", linkpidfile); 1516*7c478bd9Sstevel@tonic-gate linkpidfile[0] = '\0'; 1517*7c478bd9Sstevel@tonic-gate 1518*7c478bd9Sstevel@tonic-gate if (locked) { 1519*7c478bd9Sstevel@tonic-gate locked = 0; 1520*7c478bd9Sstevel@tonic-gate unlock(); 1521*7c478bd9Sstevel@tonic-gate } 1522*7c478bd9Sstevel@tonic-gate 1523*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 1524*7c478bd9Sstevel@tonic-gate if (pppdb != NULL) { 1525*7c478bd9Sstevel@tonic-gate cleanup_db(); 1526*7c478bd9Sstevel@tonic-gate pppdb = NULL; 1527*7c478bd9Sstevel@tonic-gate } 1528*7c478bd9Sstevel@tonic-gate #endif 1529*7c478bd9Sstevel@tonic-gate } 1530*7c478bd9Sstevel@tonic-gate 1531*7c478bd9Sstevel@tonic-gate /* 1532*7c478bd9Sstevel@tonic-gate * close_tty - restore the terminal device and close it. 1533*7c478bd9Sstevel@tonic-gate */ 1534*7c478bd9Sstevel@tonic-gate static void 1535*7c478bd9Sstevel@tonic-gate close_tty() 1536*7c478bd9Sstevel@tonic-gate { 1537*7c478bd9Sstevel@tonic-gate int fd = real_ttyfd; 1538*7c478bd9Sstevel@tonic-gate 1539*7c478bd9Sstevel@tonic-gate real_ttyfd = -1; 1540*7c478bd9Sstevel@tonic-gate 1541*7c478bd9Sstevel@tonic-gate /* drop dtr to hang up */ 1542*7c478bd9Sstevel@tonic-gate if (!default_device && modem) { 1543*7c478bd9Sstevel@tonic-gate setdtr(fd, 0); 1544*7c478bd9Sstevel@tonic-gate /* 1545*7c478bd9Sstevel@tonic-gate * This sleep is in case the serial port has CLOCAL set by default, 1546*7c478bd9Sstevel@tonic-gate * and consequently will reassert DTR when we close the device. 1547*7c478bd9Sstevel@tonic-gate */ 1548*7c478bd9Sstevel@tonic-gate (void) sleep(1); 1549*7c478bd9Sstevel@tonic-gate } 1550*7c478bd9Sstevel@tonic-gate 1551*7c478bd9Sstevel@tonic-gate restore_tty(fd); 1552*7c478bd9Sstevel@tonic-gate 1553*7c478bd9Sstevel@tonic-gate if (tty_mode != (mode_t) -1) { 1554*7c478bd9Sstevel@tonic-gate if (fchmod(fd, tty_mode) != 0) { 1555*7c478bd9Sstevel@tonic-gate /* XXX if devnam is a symlink, this will change the link */ 1556*7c478bd9Sstevel@tonic-gate if (chmod(devnam, tty_mode) != 0) { 1557*7c478bd9Sstevel@tonic-gate error("Unable to chmod file %s: %m", devnam); 1558*7c478bd9Sstevel@tonic-gate } 1559*7c478bd9Sstevel@tonic-gate } 1560*7c478bd9Sstevel@tonic-gate } 1561*7c478bd9Sstevel@tonic-gate 1562*7c478bd9Sstevel@tonic-gate (void) close(fd); 1563*7c478bd9Sstevel@tonic-gate } 1564*7c478bd9Sstevel@tonic-gate 1565*7c478bd9Sstevel@tonic-gate /* 1566*7c478bd9Sstevel@tonic-gate * update_link_stats - get stats at link termination. 1567*7c478bd9Sstevel@tonic-gate */ 1568*7c478bd9Sstevel@tonic-gate void 1569*7c478bd9Sstevel@tonic-gate update_link_stats(u) 1570*7c478bd9Sstevel@tonic-gate int u; 1571*7c478bd9Sstevel@tonic-gate { 1572*7c478bd9Sstevel@tonic-gate struct timeval now; 1573*7c478bd9Sstevel@tonic-gate char numbuf[32]; 1574*7c478bd9Sstevel@tonic-gate 1575*7c478bd9Sstevel@tonic-gate if (gettimeofday(&now, NULL) >= 0) { 1576*7c478bd9Sstevel@tonic-gate link_connect_time = now.tv_sec - start_time.tv_sec; 1577*7c478bd9Sstevel@tonic-gate (void) slprintf(numbuf, sizeof(numbuf), "%d", link_connect_time); 1578*7c478bd9Sstevel@tonic-gate script_setenv("CONNECT_TIME", numbuf, 0); 1579*7c478bd9Sstevel@tonic-gate } else { 1580*7c478bd9Sstevel@tonic-gate link_connect_time = 0; 1581*7c478bd9Sstevel@tonic-gate } 1582*7c478bd9Sstevel@tonic-gate 1583*7c478bd9Sstevel@tonic-gate if (get_ppp_stats(u, &link_stats)) { 1584*7c478bd9Sstevel@tonic-gate (void) slprintf(numbuf, sizeof(numbuf), "%" PPP_COUNTER_F, 1585*7c478bd9Sstevel@tonic-gate link_stats.bytes_out); 1586*7c478bd9Sstevel@tonic-gate script_setenv("BYTES_SENT", numbuf, 0); 1587*7c478bd9Sstevel@tonic-gate (void) slprintf(numbuf, sizeof(numbuf), "%" PPP_COUNTER_F, 1588*7c478bd9Sstevel@tonic-gate link_stats.bytes_in); 1589*7c478bd9Sstevel@tonic-gate script_setenv("BYTES_RCVD", numbuf, 0); 1590*7c478bd9Sstevel@tonic-gate (void) slprintf(numbuf, sizeof(numbuf), "%" PPP_COUNTER_F, 1591*7c478bd9Sstevel@tonic-gate link_stats.pkts_in); 1592*7c478bd9Sstevel@tonic-gate script_setenv("PKTS_RCVD", numbuf, 0); 1593*7c478bd9Sstevel@tonic-gate (void) slprintf(numbuf, sizeof(numbuf), "%" PPP_COUNTER_F, 1594*7c478bd9Sstevel@tonic-gate link_stats.pkts_out); 1595*7c478bd9Sstevel@tonic-gate script_setenv("PKTS_SENT", numbuf, 0); 1596*7c478bd9Sstevel@tonic-gate link_stats_valid = 1; 1597*7c478bd9Sstevel@tonic-gate } 1598*7c478bd9Sstevel@tonic-gate } 1599*7c478bd9Sstevel@tonic-gate 1600*7c478bd9Sstevel@tonic-gate 1601*7c478bd9Sstevel@tonic-gate struct callout { 1602*7c478bd9Sstevel@tonic-gate struct timeval c_time; /* time at which to call routine */ 1603*7c478bd9Sstevel@tonic-gate void *c_arg; /* argument to routine */ 1604*7c478bd9Sstevel@tonic-gate void (*c_func) __P((void *)); /* routine */ 1605*7c478bd9Sstevel@tonic-gate struct callout *c_next; 1606*7c478bd9Sstevel@tonic-gate }; 1607*7c478bd9Sstevel@tonic-gate 1608*7c478bd9Sstevel@tonic-gate static struct callout *callout = NULL; /* Callout list */ 1609*7c478bd9Sstevel@tonic-gate static struct timeval timenow; /* Current time */ 1610*7c478bd9Sstevel@tonic-gate 1611*7c478bd9Sstevel@tonic-gate /* 1612*7c478bd9Sstevel@tonic-gate * timeout - Schedule a timeout. 1613*7c478bd9Sstevel@tonic-gate * 1614*7c478bd9Sstevel@tonic-gate * Note that this timeout takes the number of seconds, NOT hz (as in 1615*7c478bd9Sstevel@tonic-gate * the kernel). 1616*7c478bd9Sstevel@tonic-gate */ 1617*7c478bd9Sstevel@tonic-gate void 1618*7c478bd9Sstevel@tonic-gate timeout(func, arg, time) 1619*7c478bd9Sstevel@tonic-gate void (*func) __P((void *)); 1620*7c478bd9Sstevel@tonic-gate void *arg; 1621*7c478bd9Sstevel@tonic-gate int time; 1622*7c478bd9Sstevel@tonic-gate { 1623*7c478bd9Sstevel@tonic-gate struct callout *newp, *p, **pp; 1624*7c478bd9Sstevel@tonic-gate 1625*7c478bd9Sstevel@tonic-gate MAINDEBUG(("Timeout %p:%p in %d seconds.", func, arg, time)); 1626*7c478bd9Sstevel@tonic-gate 1627*7c478bd9Sstevel@tonic-gate /* 1628*7c478bd9Sstevel@tonic-gate * Allocate timeout. 1629*7c478bd9Sstevel@tonic-gate */ 1630*7c478bd9Sstevel@tonic-gate if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL) 1631*7c478bd9Sstevel@tonic-gate novm("callout structure for timeout."); 1632*7c478bd9Sstevel@tonic-gate newp->c_arg = arg; 1633*7c478bd9Sstevel@tonic-gate newp->c_func = func; 1634*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&timenow, NULL); 1635*7c478bd9Sstevel@tonic-gate newp->c_time.tv_sec = timenow.tv_sec + time; 1636*7c478bd9Sstevel@tonic-gate newp->c_time.tv_usec = timenow.tv_usec; 1637*7c478bd9Sstevel@tonic-gate 1638*7c478bd9Sstevel@tonic-gate /* 1639*7c478bd9Sstevel@tonic-gate * Find correct place and link it in. 1640*7c478bd9Sstevel@tonic-gate */ 1641*7c478bd9Sstevel@tonic-gate for (pp = &callout; (p = *pp) != NULL; pp = &p->c_next) 1642*7c478bd9Sstevel@tonic-gate if (newp->c_time.tv_sec < p->c_time.tv_sec 1643*7c478bd9Sstevel@tonic-gate || (newp->c_time.tv_sec == p->c_time.tv_sec 1644*7c478bd9Sstevel@tonic-gate && newp->c_time.tv_usec < p->c_time.tv_usec)) 1645*7c478bd9Sstevel@tonic-gate break; 1646*7c478bd9Sstevel@tonic-gate newp->c_next = p; 1647*7c478bd9Sstevel@tonic-gate *pp = newp; 1648*7c478bd9Sstevel@tonic-gate } 1649*7c478bd9Sstevel@tonic-gate 1650*7c478bd9Sstevel@tonic-gate 1651*7c478bd9Sstevel@tonic-gate /* 1652*7c478bd9Sstevel@tonic-gate * untimeout - Unschedule a timeout. 1653*7c478bd9Sstevel@tonic-gate */ 1654*7c478bd9Sstevel@tonic-gate void 1655*7c478bd9Sstevel@tonic-gate untimeout(func, arg) 1656*7c478bd9Sstevel@tonic-gate void (*func) __P((void *)); 1657*7c478bd9Sstevel@tonic-gate void *arg; 1658*7c478bd9Sstevel@tonic-gate { 1659*7c478bd9Sstevel@tonic-gate struct callout **copp, *freep; 1660*7c478bd9Sstevel@tonic-gate 1661*7c478bd9Sstevel@tonic-gate MAINDEBUG(("Untimeout %p:%p.", func, arg)); 1662*7c478bd9Sstevel@tonic-gate 1663*7c478bd9Sstevel@tonic-gate /* 1664*7c478bd9Sstevel@tonic-gate * Find first matching timeout and remove it from the list. 1665*7c478bd9Sstevel@tonic-gate */ 1666*7c478bd9Sstevel@tonic-gate for (copp = &callout; (freep = *copp) != NULL; copp = &freep->c_next) 1667*7c478bd9Sstevel@tonic-gate if (freep->c_func == func && freep->c_arg == arg) { 1668*7c478bd9Sstevel@tonic-gate *copp = freep->c_next; 1669*7c478bd9Sstevel@tonic-gate free((char *) freep); 1670*7c478bd9Sstevel@tonic-gate break; 1671*7c478bd9Sstevel@tonic-gate } 1672*7c478bd9Sstevel@tonic-gate } 1673*7c478bd9Sstevel@tonic-gate 1674*7c478bd9Sstevel@tonic-gate 1675*7c478bd9Sstevel@tonic-gate /* 1676*7c478bd9Sstevel@tonic-gate * calltimeout - Call any timeout routines which are now due. 1677*7c478bd9Sstevel@tonic-gate */ 1678*7c478bd9Sstevel@tonic-gate static void 1679*7c478bd9Sstevel@tonic-gate calltimeout() 1680*7c478bd9Sstevel@tonic-gate { 1681*7c478bd9Sstevel@tonic-gate struct callout *p; 1682*7c478bd9Sstevel@tonic-gate 1683*7c478bd9Sstevel@tonic-gate while (callout != NULL) { 1684*7c478bd9Sstevel@tonic-gate p = callout; 1685*7c478bd9Sstevel@tonic-gate 1686*7c478bd9Sstevel@tonic-gate if (gettimeofday(&timenow, NULL) < 0) 1687*7c478bd9Sstevel@tonic-gate fatal("Failed to get time of day: %m"); 1688*7c478bd9Sstevel@tonic-gate if (!(p->c_time.tv_sec < timenow.tv_sec 1689*7c478bd9Sstevel@tonic-gate || (p->c_time.tv_sec == timenow.tv_sec 1690*7c478bd9Sstevel@tonic-gate && p->c_time.tv_usec <= timenow.tv_usec))) 1691*7c478bd9Sstevel@tonic-gate break; /* no, it's not time yet */ 1692*7c478bd9Sstevel@tonic-gate 1693*7c478bd9Sstevel@tonic-gate callout = p->c_next; 1694*7c478bd9Sstevel@tonic-gate (*p->c_func)(p->c_arg); 1695*7c478bd9Sstevel@tonic-gate 1696*7c478bd9Sstevel@tonic-gate free((char *) p); 1697*7c478bd9Sstevel@tonic-gate } 1698*7c478bd9Sstevel@tonic-gate } 1699*7c478bd9Sstevel@tonic-gate 1700*7c478bd9Sstevel@tonic-gate 1701*7c478bd9Sstevel@tonic-gate /* 1702*7c478bd9Sstevel@tonic-gate * timeleft - return the length of time until the next timeout is due. 1703*7c478bd9Sstevel@tonic-gate */ 1704*7c478bd9Sstevel@tonic-gate static struct timeval * 1705*7c478bd9Sstevel@tonic-gate timeleft(tvp) 1706*7c478bd9Sstevel@tonic-gate struct timeval *tvp; 1707*7c478bd9Sstevel@tonic-gate { 1708*7c478bd9Sstevel@tonic-gate if (callout == NULL) 1709*7c478bd9Sstevel@tonic-gate return (NULL); 1710*7c478bd9Sstevel@tonic-gate 1711*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&timenow, NULL); 1712*7c478bd9Sstevel@tonic-gate tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec; 1713*7c478bd9Sstevel@tonic-gate tvp->tv_usec = callout->c_time.tv_usec - timenow.tv_usec; 1714*7c478bd9Sstevel@tonic-gate if (tvp->tv_usec < 0) { 1715*7c478bd9Sstevel@tonic-gate tvp->tv_usec += 1000000; 1716*7c478bd9Sstevel@tonic-gate tvp->tv_sec -= 1; 1717*7c478bd9Sstevel@tonic-gate } 1718*7c478bd9Sstevel@tonic-gate if (tvp->tv_sec < 0) 1719*7c478bd9Sstevel@tonic-gate tvp->tv_sec = tvp->tv_usec = 0; 1720*7c478bd9Sstevel@tonic-gate 1721*7c478bd9Sstevel@tonic-gate return (tvp); 1722*7c478bd9Sstevel@tonic-gate } 1723*7c478bd9Sstevel@tonic-gate 1724*7c478bd9Sstevel@tonic-gate 1725*7c478bd9Sstevel@tonic-gate /* 1726*7c478bd9Sstevel@tonic-gate * kill_my_pg - send a signal to our process group, and ignore it ourselves. 1727*7c478bd9Sstevel@tonic-gate */ 1728*7c478bd9Sstevel@tonic-gate static void 1729*7c478bd9Sstevel@tonic-gate kill_my_pg(sig) 1730*7c478bd9Sstevel@tonic-gate int sig; 1731*7c478bd9Sstevel@tonic-gate { 1732*7c478bd9Sstevel@tonic-gate struct sigaction act, oldact; 1733*7c478bd9Sstevel@tonic-gate sigset_t mask; 1734*7c478bd9Sstevel@tonic-gate 1735*7c478bd9Sstevel@tonic-gate BZERO(&act, sizeof (act)); 1736*7c478bd9Sstevel@tonic-gate act.sa_handler = SIG_IGN; 1737*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&mask); 1738*7c478bd9Sstevel@tonic-gate (void) sigaddset(&mask, sig); 1739*7c478bd9Sstevel@tonic-gate /* 1740*7c478bd9Sstevel@tonic-gate * Ignore signal 'sig' temporarily, before finally re-activating the 1741*7c478bd9Sstevel@tonic-gate * original handler. We need to do it in the following sequence, since 1742*7c478bd9Sstevel@tonic-gate * otherwise the signal handler for 'sig' will be called forever. 1743*7c478bd9Sstevel@tonic-gate */ 1744*7c478bd9Sstevel@tonic-gate if (sigaction(sig, &act, &oldact) < 0) { 1745*7c478bd9Sstevel@tonic-gate fatal("kill_my_pg: couldn't establish signal handler (%d): %m", sig); 1746*7c478bd9Sstevel@tonic-gate } 1747*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, &mask, NULL); 1748*7c478bd9Sstevel@tonic-gate /* 1749*7c478bd9Sstevel@tonic-gate * Send signal 'sig' to all processes whose process group ID is equal 1750*7c478bd9Sstevel@tonic-gate * to the process group ID of the sender. 1751*7c478bd9Sstevel@tonic-gate */ 1752*7c478bd9Sstevel@tonic-gate (void) kill(0, sig); 1753*7c478bd9Sstevel@tonic-gate if (sigaction(sig, &oldact, NULL) < 0) { 1754*7c478bd9Sstevel@tonic-gate fatal("kill_my_pg: couldn't establish signal handler (%d): %m", sig); 1755*7c478bd9Sstevel@tonic-gate } 1756*7c478bd9Sstevel@tonic-gate } 1757*7c478bd9Sstevel@tonic-gate 1758*7c478bd9Sstevel@tonic-gate 1759*7c478bd9Sstevel@tonic-gate /* 1760*7c478bd9Sstevel@tonic-gate * hup - Catch SIGHUP signal. 1761*7c478bd9Sstevel@tonic-gate * 1762*7c478bd9Sstevel@tonic-gate * Indicates that the physical layer has been disconnected. 1763*7c478bd9Sstevel@tonic-gate * We don't rely on this indication; if the user has sent this 1764*7c478bd9Sstevel@tonic-gate * signal, we just take the link down. 1765*7c478bd9Sstevel@tonic-gate */ 1766*7c478bd9Sstevel@tonic-gate static void 1767*7c478bd9Sstevel@tonic-gate hup(sig) 1768*7c478bd9Sstevel@tonic-gate int sig; 1769*7c478bd9Sstevel@tonic-gate { 1770*7c478bd9Sstevel@tonic-gate info("Hangup (SIGHUP)"); 1771*7c478bd9Sstevel@tonic-gate kill_link = 1; 1772*7c478bd9Sstevel@tonic-gate if (status != EXIT_HANGUP) 1773*7c478bd9Sstevel@tonic-gate status = EXIT_USER_REQUEST; 1774*7c478bd9Sstevel@tonic-gate if (conn_running > 0) 1775*7c478bd9Sstevel@tonic-gate /* Send the signal to the [dis]connector process(es) also */ 1776*7c478bd9Sstevel@tonic-gate kill_my_pg(sig); 1777*7c478bd9Sstevel@tonic-gate if (charshunt_pid) 1778*7c478bd9Sstevel@tonic-gate (void) kill(charshunt_pid, sig); 1779*7c478bd9Sstevel@tonic-gate if (waiting) 1780*7c478bd9Sstevel@tonic-gate siglongjmp(sigjmp, 1); 1781*7c478bd9Sstevel@tonic-gate } 1782*7c478bd9Sstevel@tonic-gate 1783*7c478bd9Sstevel@tonic-gate 1784*7c478bd9Sstevel@tonic-gate /* 1785*7c478bd9Sstevel@tonic-gate * term - Catch SIGTERM signal and SIGINT signal (^C/del). 1786*7c478bd9Sstevel@tonic-gate * 1787*7c478bd9Sstevel@tonic-gate * Indicates that we should initiate a graceful disconnect and exit. 1788*7c478bd9Sstevel@tonic-gate */ 1789*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1790*7c478bd9Sstevel@tonic-gate static void 1791*7c478bd9Sstevel@tonic-gate term(sig) 1792*7c478bd9Sstevel@tonic-gate int sig; 1793*7c478bd9Sstevel@tonic-gate { 1794*7c478bd9Sstevel@tonic-gate info("Terminating on signal %d.", sig); 1795*7c478bd9Sstevel@tonic-gate persist = 0; /* don't try to restart */ 1796*7c478bd9Sstevel@tonic-gate kill_link = 1; 1797*7c478bd9Sstevel@tonic-gate status = EXIT_USER_REQUEST; 1798*7c478bd9Sstevel@tonic-gate if (conn_running > 0) 1799*7c478bd9Sstevel@tonic-gate /* Send the signal to the [dis]connector process(es) also */ 1800*7c478bd9Sstevel@tonic-gate kill_my_pg(sig); 1801*7c478bd9Sstevel@tonic-gate if (charshunt_pid) 1802*7c478bd9Sstevel@tonic-gate (void) kill(charshunt_pid, sig); 1803*7c478bd9Sstevel@tonic-gate if (waiting) 1804*7c478bd9Sstevel@tonic-gate siglongjmp(sigjmp, 1); 1805*7c478bd9Sstevel@tonic-gate } 1806*7c478bd9Sstevel@tonic-gate 1807*7c478bd9Sstevel@tonic-gate 1808*7c478bd9Sstevel@tonic-gate /* 1809*7c478bd9Sstevel@tonic-gate * chld - Catch SIGCHLD signal. 1810*7c478bd9Sstevel@tonic-gate * Sets a flag so we will call reap_kids in the mainline. 1811*7c478bd9Sstevel@tonic-gate */ 1812*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1813*7c478bd9Sstevel@tonic-gate static void 1814*7c478bd9Sstevel@tonic-gate chld(sig) 1815*7c478bd9Sstevel@tonic-gate int sig; 1816*7c478bd9Sstevel@tonic-gate { 1817*7c478bd9Sstevel@tonic-gate got_sigchld = 1; 1818*7c478bd9Sstevel@tonic-gate if (waiting) 1819*7c478bd9Sstevel@tonic-gate siglongjmp(sigjmp, 1); 1820*7c478bd9Sstevel@tonic-gate } 1821*7c478bd9Sstevel@tonic-gate 1822*7c478bd9Sstevel@tonic-gate /* 1823*7c478bd9Sstevel@tonic-gate * toggle_debug - Catch SIGUSR1 signal. 1824*7c478bd9Sstevel@tonic-gate * 1825*7c478bd9Sstevel@tonic-gate * Toggle debug flag. 1826*7c478bd9Sstevel@tonic-gate */ 1827*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1828*7c478bd9Sstevel@tonic-gate static void 1829*7c478bd9Sstevel@tonic-gate toggle_debug(sig) 1830*7c478bd9Sstevel@tonic-gate int sig; 1831*7c478bd9Sstevel@tonic-gate { 1832*7c478bd9Sstevel@tonic-gate if (debug) { 1833*7c478bd9Sstevel@tonic-gate print_ncpstate(0, NULL); 1834*7c478bd9Sstevel@tonic-gate dbglog("debug logging disabled"); 1835*7c478bd9Sstevel@tonic-gate (void) setlogmask(LOG_UPTO(LOG_WARNING)); 1836*7c478bd9Sstevel@tonic-gate debug = 0; 1837*7c478bd9Sstevel@tonic-gate } else { 1838*7c478bd9Sstevel@tonic-gate (void) setlogmask(LOG_UPTO(LOG_DEBUG)); 1839*7c478bd9Sstevel@tonic-gate dbglog("debug logging enabled"); 1840*7c478bd9Sstevel@tonic-gate print_ncpstate(0, NULL); 1841*7c478bd9Sstevel@tonic-gate debug = 1; 1842*7c478bd9Sstevel@tonic-gate } 1843*7c478bd9Sstevel@tonic-gate } 1844*7c478bd9Sstevel@tonic-gate 1845*7c478bd9Sstevel@tonic-gate 1846*7c478bd9Sstevel@tonic-gate /* 1847*7c478bd9Sstevel@tonic-gate * open_ccp - Catch SIGUSR2 signal. 1848*7c478bd9Sstevel@tonic-gate * 1849*7c478bd9Sstevel@tonic-gate * Try to (re)negotiate compression. 1850*7c478bd9Sstevel@tonic-gate */ 1851*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1852*7c478bd9Sstevel@tonic-gate static void 1853*7c478bd9Sstevel@tonic-gate open_ccp(sig) 1854*7c478bd9Sstevel@tonic-gate int sig; 1855*7c478bd9Sstevel@tonic-gate { 1856*7c478bd9Sstevel@tonic-gate open_ccp_flag = 1; 1857*7c478bd9Sstevel@tonic-gate if (waiting) 1858*7c478bd9Sstevel@tonic-gate siglongjmp(sigjmp, 1); 1859*7c478bd9Sstevel@tonic-gate } 1860*7c478bd9Sstevel@tonic-gate 1861*7c478bd9Sstevel@tonic-gate 1862*7c478bd9Sstevel@tonic-gate /* 1863*7c478bd9Sstevel@tonic-gate * bad_signal - We've caught a fatal signal. Clean up state and exit. 1864*7c478bd9Sstevel@tonic-gate */ 1865*7c478bd9Sstevel@tonic-gate static void 1866*7c478bd9Sstevel@tonic-gate bad_signal(sig) 1867*7c478bd9Sstevel@tonic-gate int sig; 1868*7c478bd9Sstevel@tonic-gate { 1869*7c478bd9Sstevel@tonic-gate static int crashed = 0; 1870*7c478bd9Sstevel@tonic-gate 1871*7c478bd9Sstevel@tonic-gate if (crashed) 1872*7c478bd9Sstevel@tonic-gate _exit(127); 1873*7c478bd9Sstevel@tonic-gate crashed = 1; 1874*7c478bd9Sstevel@tonic-gate error("Fatal signal %d", sig); 1875*7c478bd9Sstevel@tonic-gate if (conn_running > 0) 1876*7c478bd9Sstevel@tonic-gate kill_my_pg(SIGTERM); 1877*7c478bd9Sstevel@tonic-gate if (charshunt_pid) 1878*7c478bd9Sstevel@tonic-gate (void) kill(charshunt_pid, SIGTERM); 1879*7c478bd9Sstevel@tonic-gate die(127); 1880*7c478bd9Sstevel@tonic-gate } 1881*7c478bd9Sstevel@tonic-gate 1882*7c478bd9Sstevel@tonic-gate 1883*7c478bd9Sstevel@tonic-gate /* 1884*7c478bd9Sstevel@tonic-gate * device_script - run a program to talk to the serial device 1885*7c478bd9Sstevel@tonic-gate * (e.g. to run the connector or disconnector script). 1886*7c478bd9Sstevel@tonic-gate */ 1887*7c478bd9Sstevel@tonic-gate static int 1888*7c478bd9Sstevel@tonic-gate device_script(program, in, out, dont_wait, optname) 1889*7c478bd9Sstevel@tonic-gate char *program; 1890*7c478bd9Sstevel@tonic-gate int in, out; 1891*7c478bd9Sstevel@tonic-gate int dont_wait; 1892*7c478bd9Sstevel@tonic-gate char *optname; 1893*7c478bd9Sstevel@tonic-gate { 1894*7c478bd9Sstevel@tonic-gate pid_t pid; 1895*7c478bd9Sstevel@tonic-gate int status = -1; 1896*7c478bd9Sstevel@tonic-gate int errfd; 1897*7c478bd9Sstevel@tonic-gate int envpipe[2]; 1898*7c478bd9Sstevel@tonic-gate 1899*7c478bd9Sstevel@tonic-gate envpipe[0] = envpipe[1] = -1; 1900*7c478bd9Sstevel@tonic-gate if (!dont_wait && device_pipe_hook != NULL && pipe(envpipe) == -1) { 1901*7c478bd9Sstevel@tonic-gate error("Cannot create pipe for child: %m"); 1902*7c478bd9Sstevel@tonic-gate return (-1); 1903*7c478bd9Sstevel@tonic-gate } 1904*7c478bd9Sstevel@tonic-gate 1905*7c478bd9Sstevel@tonic-gate ++conn_running; 1906*7c478bd9Sstevel@tonic-gate pid = fork(); 1907*7c478bd9Sstevel@tonic-gate 1908*7c478bd9Sstevel@tonic-gate if (pid == (pid_t)-1) { 1909*7c478bd9Sstevel@tonic-gate --conn_running; 1910*7c478bd9Sstevel@tonic-gate error("Failed to create child process: %m"); 1911*7c478bd9Sstevel@tonic-gate return (-1); 1912*7c478bd9Sstevel@tonic-gate } 1913*7c478bd9Sstevel@tonic-gate 1914*7c478bd9Sstevel@tonic-gate if (pid == (pid_t)0) { 1915*7c478bd9Sstevel@tonic-gate sys_close(); 1916*7c478bd9Sstevel@tonic-gate closelog(); 1917*7c478bd9Sstevel@tonic-gate if (envpipe[0] >= 0) { 1918*7c478bd9Sstevel@tonic-gate if (envpipe[1] <= 2) 1919*7c478bd9Sstevel@tonic-gate envpipe[1] = dup(envpipe[1]); 1920*7c478bd9Sstevel@tonic-gate (void) close(envpipe[0]); 1921*7c478bd9Sstevel@tonic-gate } 1922*7c478bd9Sstevel@tonic-gate if (in == 2) { 1923*7c478bd9Sstevel@tonic-gate /* aargh!!! */ 1924*7c478bd9Sstevel@tonic-gate int newin = dup(in); 1925*7c478bd9Sstevel@tonic-gate if (in == out) 1926*7c478bd9Sstevel@tonic-gate out = newin; 1927*7c478bd9Sstevel@tonic-gate in = newin; 1928*7c478bd9Sstevel@tonic-gate } else if (out == 2) { 1929*7c478bd9Sstevel@tonic-gate out = dup(out); 1930*7c478bd9Sstevel@tonic-gate } 1931*7c478bd9Sstevel@tonic-gate if (log_to_fd >= 0) { 1932*7c478bd9Sstevel@tonic-gate if (log_to_fd != 2) { 1933*7c478bd9Sstevel@tonic-gate if (dup2(log_to_fd, 2) < 0) 1934*7c478bd9Sstevel@tonic-gate error("dup2(log_to_fd, STDERR) failed: %m"); 1935*7c478bd9Sstevel@tonic-gate } 1936*7c478bd9Sstevel@tonic-gate } else { 1937*7c478bd9Sstevel@tonic-gate (void) close(2); 1938*7c478bd9Sstevel@tonic-gate errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0600); 1939*7c478bd9Sstevel@tonic-gate if (errfd >= 0 && errfd != 2) { 1940*7c478bd9Sstevel@tonic-gate if (dup2(errfd, 2) < 0) 1941*7c478bd9Sstevel@tonic-gate error("dup2(errfd, STDERR) failed: %m"); 1942*7c478bd9Sstevel@tonic-gate (void) close(errfd); 1943*7c478bd9Sstevel@tonic-gate } 1944*7c478bd9Sstevel@tonic-gate } 1945*7c478bd9Sstevel@tonic-gate if (in != 0) { 1946*7c478bd9Sstevel@tonic-gate if (out == 0) 1947*7c478bd9Sstevel@tonic-gate out = dup(out); 1948*7c478bd9Sstevel@tonic-gate if (dup2(in, 0) < 0) 1949*7c478bd9Sstevel@tonic-gate error("dup2(in, STDIN) failed: %m"); 1950*7c478bd9Sstevel@tonic-gate } 1951*7c478bd9Sstevel@tonic-gate if (out != 1) { 1952*7c478bd9Sstevel@tonic-gate if (dup2(out, 1) < 0) 1953*7c478bd9Sstevel@tonic-gate error("dup2(out, STDOUT) failed: %m"); 1954*7c478bd9Sstevel@tonic-gate } 1955*7c478bd9Sstevel@tonic-gate if (envpipe[0] >= 0 && dup2(envpipe[1], 3) < 0) 1956*7c478bd9Sstevel@tonic-gate error("dup2(pipe, pipeout) failed: %m"); 1957*7c478bd9Sstevel@tonic-gate if (real_ttyfd > 2) 1958*7c478bd9Sstevel@tonic-gate (void) close(real_ttyfd); 1959*7c478bd9Sstevel@tonic-gate if (pty_master > 2) 1960*7c478bd9Sstevel@tonic-gate (void) close(pty_master); 1961*7c478bd9Sstevel@tonic-gate if (pty_slave > 2) { 1962*7c478bd9Sstevel@tonic-gate (void) close(pty_slave); 1963*7c478bd9Sstevel@tonic-gate pty_slave = -1; 1964*7c478bd9Sstevel@tonic-gate } 1965*7c478bd9Sstevel@tonic-gate (void) setuid(uid); 1966*7c478bd9Sstevel@tonic-gate if (getuid() != uid) { 1967*7c478bd9Sstevel@tonic-gate error("setuid failed"); 1968*7c478bd9Sstevel@tonic-gate exit(1); 1969*7c478bd9Sstevel@tonic-gate } 1970*7c478bd9Sstevel@tonic-gate (void) setgid(getgid()); 1971*7c478bd9Sstevel@tonic-gate if (script_env != NULL) { 1972*7c478bd9Sstevel@tonic-gate while (*script_env != NULL) { 1973*7c478bd9Sstevel@tonic-gate if (putenv(*script_env) == -1) 1974*7c478bd9Sstevel@tonic-gate warn("unable to set %s for %s: %m", *script_env, program); 1975*7c478bd9Sstevel@tonic-gate script_env++; 1976*7c478bd9Sstevel@tonic-gate } 1977*7c478bd9Sstevel@tonic-gate } 1978*7c478bd9Sstevel@tonic-gate (void) execl("/bin/sh", "sh", "-c", program, (char *)0); 1979*7c478bd9Sstevel@tonic-gate error("could not exec /bin/sh: %m"); 1980*7c478bd9Sstevel@tonic-gate exit(99); 1981*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1982*7c478bd9Sstevel@tonic-gate } 1983*7c478bd9Sstevel@tonic-gate 1984*7c478bd9Sstevel@tonic-gate if (debug) 1985*7c478bd9Sstevel@tonic-gate dbglog("%s option: '%s' started (pid %d)", optname, program, pid); 1986*7c478bd9Sstevel@tonic-gate if (dont_wait) { 1987*7c478bd9Sstevel@tonic-gate record_child(pid, program, NULL, NULL); 1988*7c478bd9Sstevel@tonic-gate status = 0; 1989*7c478bd9Sstevel@tonic-gate } else { 1990*7c478bd9Sstevel@tonic-gate if (envpipe[0] >= 0) { 1991*7c478bd9Sstevel@tonic-gate (void) close(envpipe[1]); 1992*7c478bd9Sstevel@tonic-gate (*device_pipe_hook)(envpipe[0]); 1993*7c478bd9Sstevel@tonic-gate } 1994*7c478bd9Sstevel@tonic-gate while (waitpid(pid, &status, 0) < 0) { 1995*7c478bd9Sstevel@tonic-gate if (errno == EINTR) 1996*7c478bd9Sstevel@tonic-gate continue; 1997*7c478bd9Sstevel@tonic-gate fatal("error waiting for (dis)connection process: %m"); 1998*7c478bd9Sstevel@tonic-gate } 1999*7c478bd9Sstevel@tonic-gate if (envpipe[0] >= 0) 2000*7c478bd9Sstevel@tonic-gate (void) close(envpipe[0]); 2001*7c478bd9Sstevel@tonic-gate --conn_running; 2002*7c478bd9Sstevel@tonic-gate } 2003*7c478bd9Sstevel@tonic-gate 2004*7c478bd9Sstevel@tonic-gate return (status == 0 ? 0 : -1); 2005*7c478bd9Sstevel@tonic-gate } 2006*7c478bd9Sstevel@tonic-gate 2007*7c478bd9Sstevel@tonic-gate 2008*7c478bd9Sstevel@tonic-gate /* 2009*7c478bd9Sstevel@tonic-gate * run-program - execute a program with given arguments, 2010*7c478bd9Sstevel@tonic-gate * but don't wait for it. 2011*7c478bd9Sstevel@tonic-gate * If the program can't be executed, logs an error unless 2012*7c478bd9Sstevel@tonic-gate * must_exist is 0 and the program file doesn't exist. 2013*7c478bd9Sstevel@tonic-gate * Returns -1 if it couldn't fork, 0 if the file doesn't exist 2014*7c478bd9Sstevel@tonic-gate * or isn't an executable plain file, or the process ID of the child. 2015*7c478bd9Sstevel@tonic-gate * If done != NULL, (*done)(arg, int) will be called later (within 2016*7c478bd9Sstevel@tonic-gate * reap_kids) if this routine returns value > 0. 2017*7c478bd9Sstevel@tonic-gate */ 2018*7c478bd9Sstevel@tonic-gate pid_t 2019*7c478bd9Sstevel@tonic-gate run_program(prog, args, must_exist, done, arg) 2020*7c478bd9Sstevel@tonic-gate char *prog; 2021*7c478bd9Sstevel@tonic-gate char **args; 2022*7c478bd9Sstevel@tonic-gate int must_exist; 2023*7c478bd9Sstevel@tonic-gate void (*done) __P((void *arg, int status)); 2024*7c478bd9Sstevel@tonic-gate void *arg; 2025*7c478bd9Sstevel@tonic-gate { 2026*7c478bd9Sstevel@tonic-gate pid_t pid; 2027*7c478bd9Sstevel@tonic-gate struct stat sbuf; 2028*7c478bd9Sstevel@tonic-gate int retv; 2029*7c478bd9Sstevel@tonic-gate 2030*7c478bd9Sstevel@tonic-gate /* 2031*7c478bd9Sstevel@tonic-gate * First check if the file exists and is executable. 2032*7c478bd9Sstevel@tonic-gate * We don't use access() because that would use the 2033*7c478bd9Sstevel@tonic-gate * real user-id, which might not be root, and the script 2034*7c478bd9Sstevel@tonic-gate * might be accessible only to root. 2035*7c478bd9Sstevel@tonic-gate */ 2036*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2037*7c478bd9Sstevel@tonic-gate if (stat(prog, &sbuf) < 0 || !S_ISREG(sbuf.st_mode) 2038*7c478bd9Sstevel@tonic-gate || (sbuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0) { 2039*7c478bd9Sstevel@tonic-gate if (must_exist || errno != ENOENT) 2040*7c478bd9Sstevel@tonic-gate warn("Can't execute %s: %m", prog); 2041*7c478bd9Sstevel@tonic-gate return (0); 2042*7c478bd9Sstevel@tonic-gate } 2043*7c478bd9Sstevel@tonic-gate 2044*7c478bd9Sstevel@tonic-gate if (updown_script_hook != NULL) { 2045*7c478bd9Sstevel@tonic-gate retv = (*updown_script_hook)((const char ***)&args); 2046*7c478bd9Sstevel@tonic-gate if (retv == -1) { 2047*7c478bd9Sstevel@tonic-gate return (-1); 2048*7c478bd9Sstevel@tonic-gate } 2049*7c478bd9Sstevel@tonic-gate } 2050*7c478bd9Sstevel@tonic-gate 2051*7c478bd9Sstevel@tonic-gate pid = fork(); 2052*7c478bd9Sstevel@tonic-gate if (pid == (pid_t)-1) { 2053*7c478bd9Sstevel@tonic-gate error("Failed to create child process for %s: %m", prog); 2054*7c478bd9Sstevel@tonic-gate return (-1); 2055*7c478bd9Sstevel@tonic-gate } 2056*7c478bd9Sstevel@tonic-gate if (pid == (pid_t)0) { 2057*7c478bd9Sstevel@tonic-gate int new_fd; 2058*7c478bd9Sstevel@tonic-gate 2059*7c478bd9Sstevel@tonic-gate /* Leave the current location */ 2060*7c478bd9Sstevel@tonic-gate (void) setsid(); /* No controlling tty. */ 2061*7c478bd9Sstevel@tonic-gate (void) umask (S_IRWXG|S_IRWXO); 2062*7c478bd9Sstevel@tonic-gate (void) chdir ("/"); /* no current directory. */ 2063*7c478bd9Sstevel@tonic-gate (void) setuid(0); /* set real UID = root */ 2064*7c478bd9Sstevel@tonic-gate (void) setgid(getegid()); 2065*7c478bd9Sstevel@tonic-gate 2066*7c478bd9Sstevel@tonic-gate /* Ensure that nothing of our device environment is inherited. */ 2067*7c478bd9Sstevel@tonic-gate sys_close(); 2068*7c478bd9Sstevel@tonic-gate closelog(); 2069*7c478bd9Sstevel@tonic-gate (void) close(0); 2070*7c478bd9Sstevel@tonic-gate (void) close(1); 2071*7c478bd9Sstevel@tonic-gate (void) close(2); 2072*7c478bd9Sstevel@tonic-gate (void) close(ttyfd); /* tty interface to the ppp device */ 2073*7c478bd9Sstevel@tonic-gate if (real_ttyfd >= 0) 2074*7c478bd9Sstevel@tonic-gate (void) close(real_ttyfd); 2075*7c478bd9Sstevel@tonic-gate 2076*7c478bd9Sstevel@tonic-gate /* Don't pass handles to the PPP device, even by accident. */ 2077*7c478bd9Sstevel@tonic-gate new_fd = open (_PATH_DEVNULL, O_RDWR); 2078*7c478bd9Sstevel@tonic-gate if (new_fd >= 0) { 2079*7c478bd9Sstevel@tonic-gate if (new_fd != 0) { 2080*7c478bd9Sstevel@tonic-gate if (dup2(new_fd, 0) < 0) /* stdin <- /dev/null */ 2081*7c478bd9Sstevel@tonic-gate error("dup2(/dev/null, STDIN) failed: %m"); 2082*7c478bd9Sstevel@tonic-gate (void) close(new_fd); 2083*7c478bd9Sstevel@tonic-gate } 2084*7c478bd9Sstevel@tonic-gate if (dup2(0, 1) < 0) /* stdout -> /dev/null */ 2085*7c478bd9Sstevel@tonic-gate error("dup2(/dev/null, STDOUT) failed: %m"); 2086*7c478bd9Sstevel@tonic-gate if (dup2(0, 2) < 0) /* stderr -> /dev/null */ 2087*7c478bd9Sstevel@tonic-gate error("dup2(/dev/null, STDERR) failed: %m"); 2088*7c478bd9Sstevel@tonic-gate } 2089*7c478bd9Sstevel@tonic-gate 2090*7c478bd9Sstevel@tonic-gate #ifdef BSD 2091*7c478bd9Sstevel@tonic-gate /* Force the priority back to zero if pppd is running higher. */ 2092*7c478bd9Sstevel@tonic-gate if (setpriority (PRIO_PROCESS, 0, 0) < 0) 2093*7c478bd9Sstevel@tonic-gate warn("can't reset priority to 0: %m"); 2094*7c478bd9Sstevel@tonic-gate #endif 2095*7c478bd9Sstevel@tonic-gate 2096*7c478bd9Sstevel@tonic-gate /* SysV recommends a second fork at this point. */ 2097*7c478bd9Sstevel@tonic-gate 2098*7c478bd9Sstevel@tonic-gate /* run the program */ 2099*7c478bd9Sstevel@tonic-gate (void) execve(prog, args, script_env); 2100*7c478bd9Sstevel@tonic-gate if (must_exist || errno != ENOENT) { 2101*7c478bd9Sstevel@tonic-gate /* have to reopen the log, there's nowhere else 2102*7c478bd9Sstevel@tonic-gate for the message to go. */ 2103*7c478bd9Sstevel@tonic-gate reopen_log(); 2104*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Can't execute %s: %m", prog); 2105*7c478bd9Sstevel@tonic-gate closelog(); 2106*7c478bd9Sstevel@tonic-gate } 2107*7c478bd9Sstevel@tonic-gate _exit(-1); 2108*7c478bd9Sstevel@tonic-gate } 2109*7c478bd9Sstevel@tonic-gate 2110*7c478bd9Sstevel@tonic-gate if (debug) 2111*7c478bd9Sstevel@tonic-gate dbglog("Script %s started (pid %d)", prog, pid); 2112*7c478bd9Sstevel@tonic-gate record_child(pid, prog, done, arg); 2113*7c478bd9Sstevel@tonic-gate 2114*7c478bd9Sstevel@tonic-gate return (pid); 2115*7c478bd9Sstevel@tonic-gate } 2116*7c478bd9Sstevel@tonic-gate 2117*7c478bd9Sstevel@tonic-gate 2118*7c478bd9Sstevel@tonic-gate /* 2119*7c478bd9Sstevel@tonic-gate * record_child - add a child process to the list for reap_kids 2120*7c478bd9Sstevel@tonic-gate * to use. 2121*7c478bd9Sstevel@tonic-gate */ 2122*7c478bd9Sstevel@tonic-gate static void 2123*7c478bd9Sstevel@tonic-gate record_child(pid, prog, done, arg) 2124*7c478bd9Sstevel@tonic-gate pid_t pid; 2125*7c478bd9Sstevel@tonic-gate char *prog; 2126*7c478bd9Sstevel@tonic-gate void (*done) __P((void *, int)); 2127*7c478bd9Sstevel@tonic-gate void *arg; 2128*7c478bd9Sstevel@tonic-gate { 2129*7c478bd9Sstevel@tonic-gate struct subprocess *chp; 2130*7c478bd9Sstevel@tonic-gate 2131*7c478bd9Sstevel@tonic-gate ++n_children; 2132*7c478bd9Sstevel@tonic-gate 2133*7c478bd9Sstevel@tonic-gate chp = (struct subprocess *) malloc(sizeof(struct subprocess)); 2134*7c478bd9Sstevel@tonic-gate if (chp == NULL) { 2135*7c478bd9Sstevel@tonic-gate warn("losing track of %s process", prog); 2136*7c478bd9Sstevel@tonic-gate } else { 2137*7c478bd9Sstevel@tonic-gate chp->pid = pid; 2138*7c478bd9Sstevel@tonic-gate chp->prog = prog; 2139*7c478bd9Sstevel@tonic-gate chp->done = done; 2140*7c478bd9Sstevel@tonic-gate chp->arg = arg; 2141*7c478bd9Sstevel@tonic-gate chp->next = children; 2142*7c478bd9Sstevel@tonic-gate children = chp; 2143*7c478bd9Sstevel@tonic-gate } 2144*7c478bd9Sstevel@tonic-gate } 2145*7c478bd9Sstevel@tonic-gate 2146*7c478bd9Sstevel@tonic-gate 2147*7c478bd9Sstevel@tonic-gate /* 2148*7c478bd9Sstevel@tonic-gate * reap_kids - get status from any dead child processes, 2149*7c478bd9Sstevel@tonic-gate * and log a message for abnormal terminations. 2150*7c478bd9Sstevel@tonic-gate */ 2151*7c478bd9Sstevel@tonic-gate static int 2152*7c478bd9Sstevel@tonic-gate reap_kids(waitfor) 2153*7c478bd9Sstevel@tonic-gate int waitfor; 2154*7c478bd9Sstevel@tonic-gate { 2155*7c478bd9Sstevel@tonic-gate pid_t pid; 2156*7c478bd9Sstevel@tonic-gate int status, i; 2157*7c478bd9Sstevel@tonic-gate struct subprocess *chp, **prevp; 2158*7c478bd9Sstevel@tonic-gate 2159*7c478bd9Sstevel@tonic-gate got_sigchld = 0; 2160*7c478bd9Sstevel@tonic-gate if (n_children == 0) 2161*7c478bd9Sstevel@tonic-gate return (0); 2162*7c478bd9Sstevel@tonic-gate 2163*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ 2164*7c478bd9Sstevel@tonic-gate while (1) { 2165*7c478bd9Sstevel@tonic-gate pid = waitpid(-1, &status, (waitfor ? 0 : WNOHANG)); 2166*7c478bd9Sstevel@tonic-gate if (pid == 0) { 2167*7c478bd9Sstevel@tonic-gate break; /* return 0 */ 2168*7c478bd9Sstevel@tonic-gate } else if (pid == -1) { 2169*7c478bd9Sstevel@tonic-gate if (errno == EINTR) 2170*7c478bd9Sstevel@tonic-gate continue; 2171*7c478bd9Sstevel@tonic-gate if (errno != ECHILD) 2172*7c478bd9Sstevel@tonic-gate error("Error waiting for child process: %m"); 2173*7c478bd9Sstevel@tonic-gate return (-1); 2174*7c478bd9Sstevel@tonic-gate } else { 2175*7c478bd9Sstevel@tonic-gate for (prevp = &children; (chp = *prevp) != NULL; 2176*7c478bd9Sstevel@tonic-gate prevp = &chp->next) { 2177*7c478bd9Sstevel@tonic-gate if (chp->pid == pid) { 2178*7c478bd9Sstevel@tonic-gate --n_children; 2179*7c478bd9Sstevel@tonic-gate *prevp = chp->next; 2180*7c478bd9Sstevel@tonic-gate break; 2181*7c478bd9Sstevel@tonic-gate } 2182*7c478bd9Sstevel@tonic-gate } 2183*7c478bd9Sstevel@tonic-gate if (WIFSIGNALED(status) || WIFSTOPPED(status)) { 2184*7c478bd9Sstevel@tonic-gate i = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status); 2185*7c478bd9Sstevel@tonic-gate warn("Child process %s (pid %d) %s with signal %d (%s)", 2186*7c478bd9Sstevel@tonic-gate (chp != NULL ? chp->prog : "??"), pid, 2187*7c478bd9Sstevel@tonic-gate (WIFSIGNALED(status) ? "terminated" : "stopped"), 2188*7c478bd9Sstevel@tonic-gate i, signal_name(i)); 2189*7c478bd9Sstevel@tonic-gate } else if (debug) { 2190*7c478bd9Sstevel@tonic-gate dbglog("Child process %s finished (pid %d), status = %d", 2191*7c478bd9Sstevel@tonic-gate (chp != NULL ? chp->prog: "??"), pid, 2192*7c478bd9Sstevel@tonic-gate WEXITSTATUS(status)); 2193*7c478bd9Sstevel@tonic-gate } 2194*7c478bd9Sstevel@tonic-gate if ((chp != NULL) && (chp->done != NULL)) 2195*7c478bd9Sstevel@tonic-gate (*chp->done)(chp->arg, status); 2196*7c478bd9Sstevel@tonic-gate if (chp != NULL) 2197*7c478bd9Sstevel@tonic-gate free(chp); 2198*7c478bd9Sstevel@tonic-gate } 2199*7c478bd9Sstevel@tonic-gate } 2200*7c478bd9Sstevel@tonic-gate return (0); 2201*7c478bd9Sstevel@tonic-gate } 2202*7c478bd9Sstevel@tonic-gate 2203*7c478bd9Sstevel@tonic-gate /* 2204*7c478bd9Sstevel@tonic-gate * infanticide - timeout while waiting for child process. 2205*7c478bd9Sstevel@tonic-gate */ 2206*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2207*7c478bd9Sstevel@tonic-gate static void 2208*7c478bd9Sstevel@tonic-gate infanticide(sig) 2209*7c478bd9Sstevel@tonic-gate int sig; 2210*7c478bd9Sstevel@tonic-gate { 2211*7c478bd9Sstevel@tonic-gate struct subprocess *chp; 2212*7c478bd9Sstevel@tonic-gate static int runcount = 0; 2213*7c478bd9Sstevel@tonic-gate 2214*7c478bd9Sstevel@tonic-gate if (runcount < 2) { 2215*7c478bd9Sstevel@tonic-gate for (chp = children; chp != NULL; chp = chp->next) 2216*7c478bd9Sstevel@tonic-gate (void) kill(chp->pid, runcount == 0 ? SIGTERM : SIGKILL); 2217*7c478bd9Sstevel@tonic-gate } else { 2218*7c478bd9Sstevel@tonic-gate kill_my_pg(SIGTERM); 2219*7c478bd9Sstevel@tonic-gate /* Quit and hope for the best. */ 2220*7c478bd9Sstevel@tonic-gate n_children = 0; 2221*7c478bd9Sstevel@tonic-gate } 2222*7c478bd9Sstevel@tonic-gate runcount++; 2223*7c478bd9Sstevel@tonic-gate } 2224*7c478bd9Sstevel@tonic-gate 2225*7c478bd9Sstevel@tonic-gate /* 2226*7c478bd9Sstevel@tonic-gate * Perform final wait before exiting. 2227*7c478bd9Sstevel@tonic-gate */ 2228*7c478bd9Sstevel@tonic-gate static void 2229*7c478bd9Sstevel@tonic-gate final_reap() 2230*7c478bd9Sstevel@tonic-gate { 2231*7c478bd9Sstevel@tonic-gate struct sigaction sa; 2232*7c478bd9Sstevel@tonic-gate struct subprocess *chp; 2233*7c478bd9Sstevel@tonic-gate 2234*7c478bd9Sstevel@tonic-gate if (n_children > 0 && debug) { 2235*7c478bd9Sstevel@tonic-gate dbglog("Waiting for %d child processes...", n_children); 2236*7c478bd9Sstevel@tonic-gate for (chp = children; chp != NULL; chp = chp->next) 2237*7c478bd9Sstevel@tonic-gate dbglog(" pid %d: %s", chp->pid, chp->prog); 2238*7c478bd9Sstevel@tonic-gate } 2239*7c478bd9Sstevel@tonic-gate BZERO(&sa, sizeof (sa)); 2240*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ SIGNAL(SIGALRM, infanticide); 2241*7c478bd9Sstevel@tonic-gate while (n_children > 0) { 2242*7c478bd9Sstevel@tonic-gate (void) alarm(7); 2243*7c478bd9Sstevel@tonic-gate if (reap_kids(1) < 0) 2244*7c478bd9Sstevel@tonic-gate break; 2245*7c478bd9Sstevel@tonic-gate } 2246*7c478bd9Sstevel@tonic-gate (void) alarm(0); 2247*7c478bd9Sstevel@tonic-gate } 2248*7c478bd9Sstevel@tonic-gate 2249*7c478bd9Sstevel@tonic-gate /* 2250*7c478bd9Sstevel@tonic-gate * novm - log an error message saying we ran out of memory, and die. 2251*7c478bd9Sstevel@tonic-gate */ 2252*7c478bd9Sstevel@tonic-gate void 2253*7c478bd9Sstevel@tonic-gate novm(msg) 2254*7c478bd9Sstevel@tonic-gate char *msg; 2255*7c478bd9Sstevel@tonic-gate { 2256*7c478bd9Sstevel@tonic-gate fatal("Virtual memory exhausted allocating %s\n", msg); 2257*7c478bd9Sstevel@tonic-gate } 2258*7c478bd9Sstevel@tonic-gate 2259*7c478bd9Sstevel@tonic-gate /* 2260*7c478bd9Sstevel@tonic-gate * script_setenv - set an environment variable value to be used 2261*7c478bd9Sstevel@tonic-gate * for scripts that we run (e.g. ip-up, auth-up, etc.) 2262*7c478bd9Sstevel@tonic-gate */ 2263*7c478bd9Sstevel@tonic-gate void 2264*7c478bd9Sstevel@tonic-gate script_setenv(var, value, iskey) 2265*7c478bd9Sstevel@tonic-gate const char *var; 2266*7c478bd9Sstevel@tonic-gate const char *value; 2267*7c478bd9Sstevel@tonic-gate int iskey; 2268*7c478bd9Sstevel@tonic-gate { 2269*7c478bd9Sstevel@tonic-gate size_t varl = strlen(var); 2270*7c478bd9Sstevel@tonic-gate size_t vl = varl + strlen(value) + 2; 2271*7c478bd9Sstevel@tonic-gate int i; 2272*7c478bd9Sstevel@tonic-gate char *p, *newstring; 2273*7c478bd9Sstevel@tonic-gate 2274*7c478bd9Sstevel@tonic-gate /* 2275*7c478bd9Sstevel@tonic-gate * XXX: Can we assert that a tdb write lock is held here ? It appears that 2276*7c478bd9Sstevel@tonic-gate * Linux's use of tdb is not safe. 2277*7c478bd9Sstevel@tonic-gate */ 2278*7c478bd9Sstevel@tonic-gate newstring = (char *) malloc(vl+1); 2279*7c478bd9Sstevel@tonic-gate if (newstring == NULL) { 2280*7c478bd9Sstevel@tonic-gate novm("script environment string"); 2281*7c478bd9Sstevel@tonic-gate return; 2282*7c478bd9Sstevel@tonic-gate } 2283*7c478bd9Sstevel@tonic-gate *newstring++ = iskey; 2284*7c478bd9Sstevel@tonic-gate (void) slprintf(newstring, vl, "%s=%s", var, value); 2285*7c478bd9Sstevel@tonic-gate 2286*7c478bd9Sstevel@tonic-gate /* check if this variable is already set */ 2287*7c478bd9Sstevel@tonic-gate if (script_env != NULL) { 2288*7c478bd9Sstevel@tonic-gate for (i = 0; (p = script_env[i]) != NULL; ++i) { 2289*7c478bd9Sstevel@tonic-gate if (strncmp(p, var, varl) == 0 && p[varl] == '=') { 2290*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 2291*7c478bd9Sstevel@tonic-gate if (p[-1] != '\0' && pppdb != NULL) 2292*7c478bd9Sstevel@tonic-gate delete_db_key(p); 2293*7c478bd9Sstevel@tonic-gate #endif 2294*7c478bd9Sstevel@tonic-gate free(p-1); 2295*7c478bd9Sstevel@tonic-gate script_env[i] = newstring; 2296*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 2297*7c478bd9Sstevel@tonic-gate if (iskey && pppdb != NULL) 2298*7c478bd9Sstevel@tonic-gate add_db_key(newstring); 2299*7c478bd9Sstevel@tonic-gate update_db_entry(); 2300*7c478bd9Sstevel@tonic-gate #endif 2301*7c478bd9Sstevel@tonic-gate return; 2302*7c478bd9Sstevel@tonic-gate } 2303*7c478bd9Sstevel@tonic-gate } 2304*7c478bd9Sstevel@tonic-gate } else { 2305*7c478bd9Sstevel@tonic-gate /* no space allocated for script env. ptrs. yet */ 2306*7c478bd9Sstevel@tonic-gate i = 0; 2307*7c478bd9Sstevel@tonic-gate script_env = (char **) malloc(16 * sizeof(char *)); 2308*7c478bd9Sstevel@tonic-gate if (script_env == NULL) { 2309*7c478bd9Sstevel@tonic-gate novm("script environment variable."); 2310*7c478bd9Sstevel@tonic-gate return; 2311*7c478bd9Sstevel@tonic-gate } 2312*7c478bd9Sstevel@tonic-gate s_env_nalloc = 16; 2313*7c478bd9Sstevel@tonic-gate } 2314*7c478bd9Sstevel@tonic-gate 2315*7c478bd9Sstevel@tonic-gate /* reallocate script_env with more space if needed */ 2316*7c478bd9Sstevel@tonic-gate if (i + 1 >= s_env_nalloc) { 2317*7c478bd9Sstevel@tonic-gate int new_n = i + 17; 2318*7c478bd9Sstevel@tonic-gate char **newenv = (char **) realloc((void *)script_env, 2319*7c478bd9Sstevel@tonic-gate new_n * sizeof(char *)); 2320*7c478bd9Sstevel@tonic-gate if (newenv == NULL) { 2321*7c478bd9Sstevel@tonic-gate novm("expanded script environment variable."); 2322*7c478bd9Sstevel@tonic-gate return; 2323*7c478bd9Sstevel@tonic-gate } 2324*7c478bd9Sstevel@tonic-gate script_env = newenv; 2325*7c478bd9Sstevel@tonic-gate s_env_nalloc = new_n; 2326*7c478bd9Sstevel@tonic-gate } 2327*7c478bd9Sstevel@tonic-gate 2328*7c478bd9Sstevel@tonic-gate script_env[i] = newstring; 2329*7c478bd9Sstevel@tonic-gate script_env[i+1] = NULL; 2330*7c478bd9Sstevel@tonic-gate 2331*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 2332*7c478bd9Sstevel@tonic-gate if (pppdb != NULL) { 2333*7c478bd9Sstevel@tonic-gate if (iskey) 2334*7c478bd9Sstevel@tonic-gate add_db_key(newstring); 2335*7c478bd9Sstevel@tonic-gate update_db_entry(); 2336*7c478bd9Sstevel@tonic-gate } 2337*7c478bd9Sstevel@tonic-gate #endif 2338*7c478bd9Sstevel@tonic-gate } 2339*7c478bd9Sstevel@tonic-gate 2340*7c478bd9Sstevel@tonic-gate /* 2341*7c478bd9Sstevel@tonic-gate * script_unsetenv - remove a variable from the environment 2342*7c478bd9Sstevel@tonic-gate * for scripts. 2343*7c478bd9Sstevel@tonic-gate */ 2344*7c478bd9Sstevel@tonic-gate void 2345*7c478bd9Sstevel@tonic-gate script_unsetenv(var) 2346*7c478bd9Sstevel@tonic-gate const char *var; 2347*7c478bd9Sstevel@tonic-gate { 2348*7c478bd9Sstevel@tonic-gate int vl = strlen(var); 2349*7c478bd9Sstevel@tonic-gate int i; 2350*7c478bd9Sstevel@tonic-gate char *p; 2351*7c478bd9Sstevel@tonic-gate 2352*7c478bd9Sstevel@tonic-gate /* 2353*7c478bd9Sstevel@tonic-gate * XXX: Can we assert that a tdb write lock is held here ? It appears that 2354*7c478bd9Sstevel@tonic-gate * Linux's use of tdb is not safe. 2355*7c478bd9Sstevel@tonic-gate */ 2356*7c478bd9Sstevel@tonic-gate if (script_env == NULL) 2357*7c478bd9Sstevel@tonic-gate return; 2358*7c478bd9Sstevel@tonic-gate for (i = 0; (p = script_env[i]) != NULL; ++i) { 2359*7c478bd9Sstevel@tonic-gate if (strncmp(p, var, vl) == 0 && p[vl] == '=') { 2360*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 2361*7c478bd9Sstevel@tonic-gate if (p[-1] != '\0' && pppdb != NULL) 2362*7c478bd9Sstevel@tonic-gate delete_db_key(p); 2363*7c478bd9Sstevel@tonic-gate #endif 2364*7c478bd9Sstevel@tonic-gate free(p-1); 2365*7c478bd9Sstevel@tonic-gate while ((script_env[i] = script_env[i+1]) != NULL) 2366*7c478bd9Sstevel@tonic-gate ++i; 2367*7c478bd9Sstevel@tonic-gate break; 2368*7c478bd9Sstevel@tonic-gate } 2369*7c478bd9Sstevel@tonic-gate } 2370*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 2371*7c478bd9Sstevel@tonic-gate if ((pppdb != NULL) && (p != NULL)) 2372*7c478bd9Sstevel@tonic-gate update_db_entry(); 2373*7c478bd9Sstevel@tonic-gate #endif 2374*7c478bd9Sstevel@tonic-gate } 2375*7c478bd9Sstevel@tonic-gate 2376*7c478bd9Sstevel@tonic-gate /* 2377*7c478bd9Sstevel@tonic-gate * script_getenv - find a variable in the script environment. 2378*7c478bd9Sstevel@tonic-gate */ 2379*7c478bd9Sstevel@tonic-gate const char * 2380*7c478bd9Sstevel@tonic-gate script_getenv(var) 2381*7c478bd9Sstevel@tonic-gate const char *var; 2382*7c478bd9Sstevel@tonic-gate { 2383*7c478bd9Sstevel@tonic-gate int vl = strlen(var); 2384*7c478bd9Sstevel@tonic-gate int i; 2385*7c478bd9Sstevel@tonic-gate char *p; 2386*7c478bd9Sstevel@tonic-gate 2387*7c478bd9Sstevel@tonic-gate if (script_env == NULL) 2388*7c478bd9Sstevel@tonic-gate return (NULL); 2389*7c478bd9Sstevel@tonic-gate for (i = 0; (p = script_env[i]) != NULL; ++i) { 2390*7c478bd9Sstevel@tonic-gate if (strncmp(p, var, vl) == 0 && p[vl] == '=') 2391*7c478bd9Sstevel@tonic-gate return ((const char *)p+vl+1); 2392*7c478bd9Sstevel@tonic-gate } 2393*7c478bd9Sstevel@tonic-gate return (NULL); 2394*7c478bd9Sstevel@tonic-gate } 2395*7c478bd9Sstevel@tonic-gate 2396*7c478bd9Sstevel@tonic-gate #ifdef HAVE_MULTILINK 2397*7c478bd9Sstevel@tonic-gate /* 2398*7c478bd9Sstevel@tonic-gate * update_db_entry - update our entry in the database. 2399*7c478bd9Sstevel@tonic-gate */ 2400*7c478bd9Sstevel@tonic-gate static void 2401*7c478bd9Sstevel@tonic-gate update_db_entry() 2402*7c478bd9Sstevel@tonic-gate { 2403*7c478bd9Sstevel@tonic-gate TDB_DATA key, dbuf; 2404*7c478bd9Sstevel@tonic-gate int vlen, i; 2405*7c478bd9Sstevel@tonic-gate char *p, *q, *vbuf; 2406*7c478bd9Sstevel@tonic-gate 2407*7c478bd9Sstevel@tonic-gate if (script_env == NULL) 2408*7c478bd9Sstevel@tonic-gate return; 2409*7c478bd9Sstevel@tonic-gate /* 2410*7c478bd9Sstevel@tonic-gate * vlen needs to be initialized as 1, or otherwise, the last string 2411*7c478bd9Sstevel@tonic-gate * is truncated by slprintf. 2412*7c478bd9Sstevel@tonic-gate */ 2413*7c478bd9Sstevel@tonic-gate vlen = 1; 2414*7c478bd9Sstevel@tonic-gate for (i = 0; (p = script_env[i]) != NULL; ++i) 2415*7c478bd9Sstevel@tonic-gate vlen += strlen(p) + 1; 2416*7c478bd9Sstevel@tonic-gate vbuf = malloc(vlen); 2417*7c478bd9Sstevel@tonic-gate if (vbuf == NULL) 2418*7c478bd9Sstevel@tonic-gate novm("database entry"); 2419*7c478bd9Sstevel@tonic-gate q = vbuf; 2420*7c478bd9Sstevel@tonic-gate for (i = 0; (p = script_env[i]) != NULL; ++i) 2421*7c478bd9Sstevel@tonic-gate q += slprintf(q, vbuf + vlen - q, "%s;", p); 2422*7c478bd9Sstevel@tonic-gate 2423*7c478bd9Sstevel@tonic-gate key.dptr = db_key; 2424*7c478bd9Sstevel@tonic-gate key.dsize = strlen(db_key); 2425*7c478bd9Sstevel@tonic-gate dbuf.dptr = vbuf; 2426*7c478bd9Sstevel@tonic-gate dbuf.dsize = vlen; 2427*7c478bd9Sstevel@tonic-gate if (tdb_store(pppdb, key, dbuf, TDB_REPLACE)) 2428*7c478bd9Sstevel@tonic-gate error("tdb_store failed: %s", tdb_error(pppdb)); 2429*7c478bd9Sstevel@tonic-gate } 2430*7c478bd9Sstevel@tonic-gate 2431*7c478bd9Sstevel@tonic-gate /* 2432*7c478bd9Sstevel@tonic-gate * add_db_key - add a key that we can use to look up our database entry. 2433*7c478bd9Sstevel@tonic-gate */ 2434*7c478bd9Sstevel@tonic-gate static void 2435*7c478bd9Sstevel@tonic-gate add_db_key(str) 2436*7c478bd9Sstevel@tonic-gate const char *str; 2437*7c478bd9Sstevel@tonic-gate { 2438*7c478bd9Sstevel@tonic-gate TDB_DATA key, dbuf; 2439*7c478bd9Sstevel@tonic-gate 2440*7c478bd9Sstevel@tonic-gate key.dptr = (char *) str; 2441*7c478bd9Sstevel@tonic-gate key.dsize = strlen(str); 2442*7c478bd9Sstevel@tonic-gate dbuf.dptr = db_key; 2443*7c478bd9Sstevel@tonic-gate dbuf.dsize = strlen(db_key); 2444*7c478bd9Sstevel@tonic-gate if (tdb_store(pppdb, key, dbuf, TDB_REPLACE)) 2445*7c478bd9Sstevel@tonic-gate error("tdb_store key failed: %s", tdb_error(pppdb)); 2446*7c478bd9Sstevel@tonic-gate } 2447*7c478bd9Sstevel@tonic-gate 2448*7c478bd9Sstevel@tonic-gate /* 2449*7c478bd9Sstevel@tonic-gate * delete_db_key - delete a key for looking up our database entry. 2450*7c478bd9Sstevel@tonic-gate */ 2451*7c478bd9Sstevel@tonic-gate static void 2452*7c478bd9Sstevel@tonic-gate delete_db_key(str) 2453*7c478bd9Sstevel@tonic-gate const char *str; 2454*7c478bd9Sstevel@tonic-gate { 2455*7c478bd9Sstevel@tonic-gate TDB_DATA key; 2456*7c478bd9Sstevel@tonic-gate 2457*7c478bd9Sstevel@tonic-gate key.dptr = (char *) str; 2458*7c478bd9Sstevel@tonic-gate key.dsize = strlen(str); 2459*7c478bd9Sstevel@tonic-gate (void) tdb_delete(pppdb, key); 2460*7c478bd9Sstevel@tonic-gate } 2461*7c478bd9Sstevel@tonic-gate 2462*7c478bd9Sstevel@tonic-gate /* 2463*7c478bd9Sstevel@tonic-gate * cleanup_db - delete all the entries we put in the database. 2464*7c478bd9Sstevel@tonic-gate */ 2465*7c478bd9Sstevel@tonic-gate static void 2466*7c478bd9Sstevel@tonic-gate cleanup_db() 2467*7c478bd9Sstevel@tonic-gate { 2468*7c478bd9Sstevel@tonic-gate TDB_DATA key; 2469*7c478bd9Sstevel@tonic-gate int i; 2470*7c478bd9Sstevel@tonic-gate char *p; 2471*7c478bd9Sstevel@tonic-gate 2472*7c478bd9Sstevel@tonic-gate key.dptr = db_key; 2473*7c478bd9Sstevel@tonic-gate key.dsize = strlen(db_key); 2474*7c478bd9Sstevel@tonic-gate (void) tdb_delete(pppdb, key); 2475*7c478bd9Sstevel@tonic-gate for (i = 0; (p = script_env[i]) != NULL; ++i) 2476*7c478bd9Sstevel@tonic-gate if (p[-1] != '\0') 2477*7c478bd9Sstevel@tonic-gate delete_db_key(p); 2478*7c478bd9Sstevel@tonic-gate } 2479*7c478bd9Sstevel@tonic-gate #endif /* HAVE_MULTILINK */ 2480*7c478bd9Sstevel@tonic-gate 2481*7c478bd9Sstevel@tonic-gate /* 2482*7c478bd9Sstevel@tonic-gate * open_socket - establish a stream socket connection to the nominated 2483*7c478bd9Sstevel@tonic-gate * host and port. 2484*7c478bd9Sstevel@tonic-gate * XXX: Need IPv6 support for those systems that support it (use getaddrinfo), 2485*7c478bd9Sstevel@tonic-gate * but requires portability changes. 2486*7c478bd9Sstevel@tonic-gate */ 2487*7c478bd9Sstevel@tonic-gate static int 2488*7c478bd9Sstevel@tonic-gate open_socket(dest) 2489*7c478bd9Sstevel@tonic-gate char *dest; 2490*7c478bd9Sstevel@tonic-gate { 2491*7c478bd9Sstevel@tonic-gate char *sep, *endp = NULL; 2492*7c478bd9Sstevel@tonic-gate int sock; 2493*7c478bd9Sstevel@tonic-gate int port = -1; 2494*7c478bd9Sstevel@tonic-gate u_int32_t host; 2495*7c478bd9Sstevel@tonic-gate struct hostent *hent = NULL; 2496*7c478bd9Sstevel@tonic-gate struct sockaddr_in sad; 2497*7c478bd9Sstevel@tonic-gate struct servent *se; 2498*7c478bd9Sstevel@tonic-gate 2499*7c478bd9Sstevel@tonic-gate /* parse host:port and resolve host to an IP address */ 2500*7c478bd9Sstevel@tonic-gate sep = strchr(dest, ':'); 2501*7c478bd9Sstevel@tonic-gate if (sep != NULL) { 2502*7c478bd9Sstevel@tonic-gate se = getservbyname((const char *)sep+1, "tcp"); 2503*7c478bd9Sstevel@tonic-gate if (se != NULL) { 2504*7c478bd9Sstevel@tonic-gate port = ntohs(se->s_port); 2505*7c478bd9Sstevel@tonic-gate } else { 2506*7c478bd9Sstevel@tonic-gate port = strtol(sep+1, &endp, 10); 2507*7c478bd9Sstevel@tonic-gate if (endp == sep+1 || *endp != '\0') { 2508*7c478bd9Sstevel@tonic-gate error("Can't parse host:port for socket destination"); 2509*7c478bd9Sstevel@tonic-gate return (-1); 2510*7c478bd9Sstevel@tonic-gate } 2511*7c478bd9Sstevel@tonic-gate } 2512*7c478bd9Sstevel@tonic-gate } 2513*7c478bd9Sstevel@tonic-gate if (port < 0 || port > 65535 || sep == dest) { 2514*7c478bd9Sstevel@tonic-gate error("Can't parse host:port for socket destination"); 2515*7c478bd9Sstevel@tonic-gate return (-1); 2516*7c478bd9Sstevel@tonic-gate } 2517*7c478bd9Sstevel@tonic-gate *sep = '\0'; 2518*7c478bd9Sstevel@tonic-gate host = inet_addr(dest); 2519*7c478bd9Sstevel@tonic-gate if (host == (u_int32_t) -1) { 2520*7c478bd9Sstevel@tonic-gate hent = gethostbyname(dest); 2521*7c478bd9Sstevel@tonic-gate if (hent == NULL) { 2522*7c478bd9Sstevel@tonic-gate error("%s: unknown host in socket option", dest); 2523*7c478bd9Sstevel@tonic-gate *sep = ':'; 2524*7c478bd9Sstevel@tonic-gate return (-1); 2525*7c478bd9Sstevel@tonic-gate } 2526*7c478bd9Sstevel@tonic-gate BCOPY(hent->h_addr_list[0], &host, sizeof(host)); 2527*7c478bd9Sstevel@tonic-gate hent->h_addr_list++; 2528*7c478bd9Sstevel@tonic-gate } 2529*7c478bd9Sstevel@tonic-gate *sep = ':'; 2530*7c478bd9Sstevel@tonic-gate 2531*7c478bd9Sstevel@tonic-gate for (;;) { 2532*7c478bd9Sstevel@tonic-gate /* get a socket and connect it to the other end */ 2533*7c478bd9Sstevel@tonic-gate sock = socket(PF_INET, SOCK_STREAM, 0); 2534*7c478bd9Sstevel@tonic-gate if (sock < 0) { 2535*7c478bd9Sstevel@tonic-gate error("Can't create socket: %m"); 2536*7c478bd9Sstevel@tonic-gate return (-1); 2537*7c478bd9Sstevel@tonic-gate } 2538*7c478bd9Sstevel@tonic-gate BZERO(&sad, sizeof(sad)); 2539*7c478bd9Sstevel@tonic-gate sad.sin_family = AF_INET; 2540*7c478bd9Sstevel@tonic-gate sad.sin_port = htons(port); 2541*7c478bd9Sstevel@tonic-gate sad.sin_addr.s_addr = host; 2542*7c478bd9Sstevel@tonic-gate if (connect(sock, (struct sockaddr *)&sad, sizeof(sad)) >= 0) { 2543*7c478bd9Sstevel@tonic-gate break; /* return sock file descriptor */ 2544*7c478bd9Sstevel@tonic-gate } 2545*7c478bd9Sstevel@tonic-gate if ((hent != NULL) && (hent->h_addr_list != NULL)) { 2546*7c478bd9Sstevel@tonic-gate BCOPY(hent->h_addr_list[0], &host, sizeof(host)); 2547*7c478bd9Sstevel@tonic-gate hent->h_addr_list++; 2548*7c478bd9Sstevel@tonic-gate (void) close(sock); 2549*7c478bd9Sstevel@tonic-gate continue; 2550*7c478bd9Sstevel@tonic-gate } 2551*7c478bd9Sstevel@tonic-gate error("Can't connect to %s: %m", dest); 2552*7c478bd9Sstevel@tonic-gate (void) close(sock); 2553*7c478bd9Sstevel@tonic-gate return (-1); 2554*7c478bd9Sstevel@tonic-gate } 2555*7c478bd9Sstevel@tonic-gate return (sock); 2556*7c478bd9Sstevel@tonic-gate } 2557*7c478bd9Sstevel@tonic-gate 2558*7c478bd9Sstevel@tonic-gate /* 2559*7c478bd9Sstevel@tonic-gate * print_ncpstate - prints out current NCP state. 2560*7c478bd9Sstevel@tonic-gate * 2561*7c478bd9Sstevel@tonic-gate * We're normally called from SIGUSR1 here, but this is safe because 2562*7c478bd9Sstevel@tonic-gate * these signals are blocked unless we're idle waiting for events. 2563*7c478bd9Sstevel@tonic-gate * There's no need to otherwise lock the data structures referenced. 2564*7c478bd9Sstevel@tonic-gate */ 2565*7c478bd9Sstevel@tonic-gate void 2566*7c478bd9Sstevel@tonic-gate print_ncpstate(unit, strptr) 2567*7c478bd9Sstevel@tonic-gate int unit; 2568*7c478bd9Sstevel@tonic-gate FILE *strptr; 2569*7c478bd9Sstevel@tonic-gate { 2570*7c478bd9Sstevel@tonic-gate struct protent *protp; 2571*7c478bd9Sstevel@tonic-gate int i; 2572*7c478bd9Sstevel@tonic-gate 2573*7c478bd9Sstevel@tonic-gate (void) flprintf(strptr, "In %s phase\n", phase_name(phase)); 2574*7c478bd9Sstevel@tonic-gate for (i = 0; (protp = protocols[i]) != NULL; ++i) { 2575*7c478bd9Sstevel@tonic-gate if (protp->print_stat != NULL) 2576*7c478bd9Sstevel@tonic-gate (*protp->print_stat)(unit, strptr); 2577*7c478bd9Sstevel@tonic-gate } 2578*7c478bd9Sstevel@tonic-gate sys_print_state(strptr); 2579*7c478bd9Sstevel@tonic-gate } 2580*7c478bd9Sstevel@tonic-gate 2581*7c478bd9Sstevel@tonic-gate /* 2582*7c478bd9Sstevel@tonic-gate * start_charshunt - create a child process to run the character shunt. 2583*7c478bd9Sstevel@tonic-gate */ 2584*7c478bd9Sstevel@tonic-gate static int 2585*7c478bd9Sstevel@tonic-gate start_charshunt(ifd, ofd) 2586*7c478bd9Sstevel@tonic-gate int ifd, ofd; 2587*7c478bd9Sstevel@tonic-gate { 2588*7c478bd9Sstevel@tonic-gate pid_t cpid; 2589*7c478bd9Sstevel@tonic-gate 2590*7c478bd9Sstevel@tonic-gate cpid = fork(); 2591*7c478bd9Sstevel@tonic-gate if (cpid == (pid_t)-1) { 2592*7c478bd9Sstevel@tonic-gate error("Can't fork process for character shunt: %m"); 2593*7c478bd9Sstevel@tonic-gate return (0); 2594*7c478bd9Sstevel@tonic-gate } 2595*7c478bd9Sstevel@tonic-gate if (cpid == (pid_t)0) { 2596*7c478bd9Sstevel@tonic-gate /* child */ 2597*7c478bd9Sstevel@tonic-gate (void) close(pty_slave); 2598*7c478bd9Sstevel@tonic-gate pty_slave = -1; 2599*7c478bd9Sstevel@tonic-gate (void) setgid(getgid()); 2600*7c478bd9Sstevel@tonic-gate (void) setuid(uid); 2601*7c478bd9Sstevel@tonic-gate if (getuid() != uid) 2602*7c478bd9Sstevel@tonic-gate fatal("setuid failed"); 2603*7c478bd9Sstevel@tonic-gate if (!nodetach) 2604*7c478bd9Sstevel@tonic-gate log_to_fd = -1; 2605*7c478bd9Sstevel@tonic-gate charshunt(ifd, ofd, record_file); 2606*7c478bd9Sstevel@tonic-gate exit(0); 2607*7c478bd9Sstevel@tonic-gate } 2608*7c478bd9Sstevel@tonic-gate charshunt_pid = cpid; 2609*7c478bd9Sstevel@tonic-gate (void) close(pty_master); 2610*7c478bd9Sstevel@tonic-gate pty_master = -1; 2611*7c478bd9Sstevel@tonic-gate ttyfd = pty_slave; 2612*7c478bd9Sstevel@tonic-gate record_child(cpid, "pppd (charshunt)", charshunt_done, NULL); 2613*7c478bd9Sstevel@tonic-gate return (1); 2614*7c478bd9Sstevel@tonic-gate } 2615*7c478bd9Sstevel@tonic-gate 2616*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2617*7c478bd9Sstevel@tonic-gate static void 2618*7c478bd9Sstevel@tonic-gate charshunt_done(arg, status) 2619*7c478bd9Sstevel@tonic-gate void *arg; 2620*7c478bd9Sstevel@tonic-gate int status; 2621*7c478bd9Sstevel@tonic-gate { 2622*7c478bd9Sstevel@tonic-gate charshunt_pid = (pid_t)0; 2623*7c478bd9Sstevel@tonic-gate } 2624*7c478bd9Sstevel@tonic-gate 2625*7c478bd9Sstevel@tonic-gate static void 2626*7c478bd9Sstevel@tonic-gate reportme(int signo) 2627*7c478bd9Sstevel@tonic-gate { 2628*7c478bd9Sstevel@tonic-gate dbglog("charshunt taking signal %d", signo); 2629*7c478bd9Sstevel@tonic-gate exit(1); 2630*7c478bd9Sstevel@tonic-gate } 2631*7c478bd9Sstevel@tonic-gate 2632*7c478bd9Sstevel@tonic-gate /* 2633*7c478bd9Sstevel@tonic-gate * charshunt - the character shunt, which passes characters between 2634*7c478bd9Sstevel@tonic-gate * the pty master side and the serial port (or stdin/stdout). 2635*7c478bd9Sstevel@tonic-gate * This runs as the user (not as root). 2636*7c478bd9Sstevel@tonic-gate * (We assume ofd >= ifd which is true the way this gets called. :-). 2637*7c478bd9Sstevel@tonic-gate */ 2638*7c478bd9Sstevel@tonic-gate static void 2639*7c478bd9Sstevel@tonic-gate charshunt(ifd, ofd, record_file) 2640*7c478bd9Sstevel@tonic-gate int ifd, ofd; 2641*7c478bd9Sstevel@tonic-gate char *record_file; 2642*7c478bd9Sstevel@tonic-gate { 2643*7c478bd9Sstevel@tonic-gate int n, nfds; 2644*7c478bd9Sstevel@tonic-gate fd_set ready, writey; 2645*7c478bd9Sstevel@tonic-gate u_char *ibufp, *obufp; 2646*7c478bd9Sstevel@tonic-gate int nibuf, nobuf; 2647*7c478bd9Sstevel@tonic-gate int flags; 2648*7c478bd9Sstevel@tonic-gate struct timeval lasttime; 2649*7c478bd9Sstevel@tonic-gate FILE *recordf = NULL; 2650*7c478bd9Sstevel@tonic-gate int ilevel, olevel, max_level; 2651*7c478bd9Sstevel@tonic-gate struct timeval levelt, tout, *top; 2652*7c478bd9Sstevel@tonic-gate 2653*7c478bd9Sstevel@tonic-gate /* 2654*7c478bd9Sstevel@tonic-gate * Reset signal handlers. 2655*7c478bd9Sstevel@tonic-gate */ 2656*7c478bd9Sstevel@tonic-gate (void) signal(SIGHUP, SIG_IGN); /* Hangup */ 2657*7c478bd9Sstevel@tonic-gate (void) signal(SIGINT, reportme); /* Interrupt */ 2658*7c478bd9Sstevel@tonic-gate (void) signal(SIGTERM, reportme); /* Terminate */ 2659*7c478bd9Sstevel@tonic-gate (void) signal(SIGCHLD, reportme); 2660*7c478bd9Sstevel@tonic-gate (void) signal(SIGUSR1, reportme); 2661*7c478bd9Sstevel@tonic-gate (void) signal(SIGUSR2, reportme); 2662*7c478bd9Sstevel@tonic-gate (void) signal(SIGABRT, reportme); 2663*7c478bd9Sstevel@tonic-gate (void) signal(SIGALRM, reportme); 2664*7c478bd9Sstevel@tonic-gate (void) signal(SIGFPE, reportme); 2665*7c478bd9Sstevel@tonic-gate (void) signal(SIGILL, reportme); 2666*7c478bd9Sstevel@tonic-gate (void) signal(SIGPIPE, reportme); 2667*7c478bd9Sstevel@tonic-gate (void) signal(SIGQUIT, reportme); 2668*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 2669*7c478bd9Sstevel@tonic-gate (void) signal(SIGSEGV, reportme); 2670*7c478bd9Sstevel@tonic-gate #endif 2671*7c478bd9Sstevel@tonic-gate #ifdef SIGBUS 2672*7c478bd9Sstevel@tonic-gate (void) signal(SIGBUS, reportme); 2673*7c478bd9Sstevel@tonic-gate #endif 2674*7c478bd9Sstevel@tonic-gate #ifdef SIGEMT 2675*7c478bd9Sstevel@tonic-gate (void) signal(SIGEMT, reportme); 2676*7c478bd9Sstevel@tonic-gate #endif 2677*7c478bd9Sstevel@tonic-gate #ifdef SIGPOLL 2678*7c478bd9Sstevel@tonic-gate (void) signal(SIGPOLL, reportme); 2679*7c478bd9Sstevel@tonic-gate #endif 2680*7c478bd9Sstevel@tonic-gate #ifdef SIGPROF 2681*7c478bd9Sstevel@tonic-gate (void) signal(SIGPROF, reportme); 2682*7c478bd9Sstevel@tonic-gate #endif 2683*7c478bd9Sstevel@tonic-gate #ifdef SIGSYS 2684*7c478bd9Sstevel@tonic-gate (void) signal(SIGSYS, reportme); 2685*7c478bd9Sstevel@tonic-gate #endif 2686*7c478bd9Sstevel@tonic-gate #ifdef SIGTRAP 2687*7c478bd9Sstevel@tonic-gate (void) signal(SIGTRAP, reportme); 2688*7c478bd9Sstevel@tonic-gate #endif 2689*7c478bd9Sstevel@tonic-gate #ifdef SIGVTALRM 2690*7c478bd9Sstevel@tonic-gate (void) signal(SIGVTALRM, reportme); 2691*7c478bd9Sstevel@tonic-gate #endif 2692*7c478bd9Sstevel@tonic-gate #ifdef SIGXCPU 2693*7c478bd9Sstevel@tonic-gate (void) signal(SIGXCPU, reportme); 2694*7c478bd9Sstevel@tonic-gate #endif 2695*7c478bd9Sstevel@tonic-gate #ifdef SIGXFSZ 2696*7c478bd9Sstevel@tonic-gate (void) signal(SIGXFSZ, reportme); 2697*7c478bd9Sstevel@tonic-gate #endif 2698*7c478bd9Sstevel@tonic-gate 2699*7c478bd9Sstevel@tonic-gate /* 2700*7c478bd9Sstevel@tonic-gate * Open the record file if required. 2701*7c478bd9Sstevel@tonic-gate */ 2702*7c478bd9Sstevel@tonic-gate if (record_file != NULL) { 2703*7c478bd9Sstevel@tonic-gate recordf = fopen(record_file, "a"); 2704*7c478bd9Sstevel@tonic-gate if (recordf == NULL) 2705*7c478bd9Sstevel@tonic-gate error("Couldn't create record file %s: %m", record_file); 2706*7c478bd9Sstevel@tonic-gate } 2707*7c478bd9Sstevel@tonic-gate 2708*7c478bd9Sstevel@tonic-gate /* set all the fds to non-blocking mode */ 2709*7c478bd9Sstevel@tonic-gate flags = fcntl(pty_master, F_GETFL); 2710*7c478bd9Sstevel@tonic-gate if (flags == -1 2711*7c478bd9Sstevel@tonic-gate || fcntl(pty_master, F_SETFL, flags | O_NONBLOCK) == -1) 2712*7c478bd9Sstevel@tonic-gate warn("couldn't set pty master to nonblock: %m"); 2713*7c478bd9Sstevel@tonic-gate flags = fcntl(ifd, F_GETFL); 2714*7c478bd9Sstevel@tonic-gate if (flags == -1 2715*7c478bd9Sstevel@tonic-gate || fcntl(ifd, F_SETFL, flags | O_NONBLOCK) == -1) 2716*7c478bd9Sstevel@tonic-gate warn("couldn't set %s to nonblock: %m", (ifd==0? "stdin": "tty")); 2717*7c478bd9Sstevel@tonic-gate if (ofd != ifd) { 2718*7c478bd9Sstevel@tonic-gate flags = fcntl(ofd, F_GETFL); 2719*7c478bd9Sstevel@tonic-gate if (flags == -1 2720*7c478bd9Sstevel@tonic-gate || fcntl(ofd, F_SETFL, flags | O_NONBLOCK) == -1) 2721*7c478bd9Sstevel@tonic-gate warn("couldn't set stdout to nonblock: %m"); 2722*7c478bd9Sstevel@tonic-gate } 2723*7c478bd9Sstevel@tonic-gate 2724*7c478bd9Sstevel@tonic-gate nibuf = nobuf = 0; 2725*7c478bd9Sstevel@tonic-gate ibufp = obufp = NULL; 2726*7c478bd9Sstevel@tonic-gate 2727*7c478bd9Sstevel@tonic-gate ilevel = olevel = 0; 2728*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&levelt, NULL); 2729*7c478bd9Sstevel@tonic-gate if (max_data_rate) { 2730*7c478bd9Sstevel@tonic-gate max_level = max_data_rate / 10; 2731*7c478bd9Sstevel@tonic-gate if (max_level < MAXLEVELMINSIZE) 2732*7c478bd9Sstevel@tonic-gate max_level = MAXLEVELMINSIZE; 2733*7c478bd9Sstevel@tonic-gate } else 2734*7c478bd9Sstevel@tonic-gate max_level = sizeof(inpacket_buf) + 1; 2735*7c478bd9Sstevel@tonic-gate 2736*7c478bd9Sstevel@tonic-gate nfds = (ofd > pty_master? ofd: pty_master) + 1; 2737*7c478bd9Sstevel@tonic-gate if (recordf != NULL) { 2738*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&lasttime, NULL); 2739*7c478bd9Sstevel@tonic-gate (void) putc(RECMARK_TIMESTART, recordf); /* put start marker */ 2740*7c478bd9Sstevel@tonic-gate (void) putc(lasttime.tv_sec >> 24, recordf); 2741*7c478bd9Sstevel@tonic-gate (void) putc(lasttime.tv_sec >> 16, recordf); 2742*7c478bd9Sstevel@tonic-gate (void) putc(lasttime.tv_sec >> 8, recordf); 2743*7c478bd9Sstevel@tonic-gate (void) putc(lasttime.tv_sec, recordf); 2744*7c478bd9Sstevel@tonic-gate lasttime.tv_usec = 0; 2745*7c478bd9Sstevel@tonic-gate } 2746*7c478bd9Sstevel@tonic-gate 2747*7c478bd9Sstevel@tonic-gate while (nibuf != 0 || nobuf != 0 || ofd >= 0 || pty_master >= 0) { 2748*7c478bd9Sstevel@tonic-gate top = 0; 2749*7c478bd9Sstevel@tonic-gate tout.tv_sec = 0; 2750*7c478bd9Sstevel@tonic-gate tout.tv_usec = 10000; 2751*7c478bd9Sstevel@tonic-gate FD_ZERO(&ready); 2752*7c478bd9Sstevel@tonic-gate FD_ZERO(&writey); 2753*7c478bd9Sstevel@tonic-gate if (nibuf != 0) { 2754*7c478bd9Sstevel@tonic-gate if (ilevel >= max_level) 2755*7c478bd9Sstevel@tonic-gate top = &tout; 2756*7c478bd9Sstevel@tonic-gate else if (pty_master >= 0) 2757*7c478bd9Sstevel@tonic-gate FD_SET(pty_master, &writey); 2758*7c478bd9Sstevel@tonic-gate } else if (ifd >= 0) 2759*7c478bd9Sstevel@tonic-gate FD_SET(ifd, &ready); 2760*7c478bd9Sstevel@tonic-gate if (nobuf != 0) { 2761*7c478bd9Sstevel@tonic-gate if (olevel >= max_level) 2762*7c478bd9Sstevel@tonic-gate top = &tout; 2763*7c478bd9Sstevel@tonic-gate else if (ofd >= 0) 2764*7c478bd9Sstevel@tonic-gate FD_SET(ofd, &writey); 2765*7c478bd9Sstevel@tonic-gate } else { 2766*7c478bd9Sstevel@tonic-gate /* Don't read from pty if it's gone or it has closed. */ 2767*7c478bd9Sstevel@tonic-gate if (pty_master >= 0 && ofd >= 0) 2768*7c478bd9Sstevel@tonic-gate FD_SET(pty_master, &ready); 2769*7c478bd9Sstevel@tonic-gate } 2770*7c478bd9Sstevel@tonic-gate if (select(nfds, &ready, &writey, NULL, top) < 0) { 2771*7c478bd9Sstevel@tonic-gate if (errno != EINTR) 2772*7c478bd9Sstevel@tonic-gate fatal("select"); 2773*7c478bd9Sstevel@tonic-gate continue; 2774*7c478bd9Sstevel@tonic-gate } 2775*7c478bd9Sstevel@tonic-gate if (max_data_rate) { 2776*7c478bd9Sstevel@tonic-gate double dt; 2777*7c478bd9Sstevel@tonic-gate int nbt; 2778*7c478bd9Sstevel@tonic-gate struct timeval now; 2779*7c478bd9Sstevel@tonic-gate 2780*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&now, NULL); 2781*7c478bd9Sstevel@tonic-gate dt = (now.tv_sec - levelt.tv_sec 2782*7c478bd9Sstevel@tonic-gate + (now.tv_usec - levelt.tv_usec) / 1e6); 2783*7c478bd9Sstevel@tonic-gate nbt = (int)(dt * max_data_rate); 2784*7c478bd9Sstevel@tonic-gate ilevel = (nbt < 0 || nbt > ilevel)? 0: ilevel - nbt; 2785*7c478bd9Sstevel@tonic-gate olevel = (nbt < 0 || nbt > olevel)? 0: olevel - nbt; 2786*7c478bd9Sstevel@tonic-gate levelt = now; 2787*7c478bd9Sstevel@tonic-gate } else 2788*7c478bd9Sstevel@tonic-gate ilevel = olevel = 0; 2789*7c478bd9Sstevel@tonic-gate if (FD_ISSET(ifd, &ready)) { 2790*7c478bd9Sstevel@tonic-gate ibufp = inpacket_buf; 2791*7c478bd9Sstevel@tonic-gate nibuf = read(ifd, ibufp, sizeof(inpacket_buf)); 2792*7c478bd9Sstevel@tonic-gate if (nibuf < 0 && errno == EIO) 2793*7c478bd9Sstevel@tonic-gate nibuf = 0; 2794*7c478bd9Sstevel@tonic-gate if (nibuf < 0 || pty_master == -1) { 2795*7c478bd9Sstevel@tonic-gate if (errno != EINTR && errno != EAGAIN) { 2796*7c478bd9Sstevel@tonic-gate error("Error reading standard input: %m"); 2797*7c478bd9Sstevel@tonic-gate break; 2798*7c478bd9Sstevel@tonic-gate } 2799*7c478bd9Sstevel@tonic-gate nibuf = 0; 2800*7c478bd9Sstevel@tonic-gate } else if (nibuf == 0) { 2801*7c478bd9Sstevel@tonic-gate /* end of file from stdin */ 2802*7c478bd9Sstevel@tonic-gate (void) close(pty_master); 2803*7c478bd9Sstevel@tonic-gate pty_master = -1; 2804*7c478bd9Sstevel@tonic-gate (void) close(ifd); 2805*7c478bd9Sstevel@tonic-gate ifd = -1; 2806*7c478bd9Sstevel@tonic-gate if (recordf) 2807*7c478bd9Sstevel@tonic-gate if (!record_write(recordf, RECMARK_ENDRECV, NULL, 0, 2808*7c478bd9Sstevel@tonic-gate &lasttime)) 2809*7c478bd9Sstevel@tonic-gate recordf = NULL; 2810*7c478bd9Sstevel@tonic-gate } else { 2811*7c478bd9Sstevel@tonic-gate FD_SET(pty_master, &writey); 2812*7c478bd9Sstevel@tonic-gate if (recordf) 2813*7c478bd9Sstevel@tonic-gate if (!record_write(recordf, RECMARK_STARTRECV, ibufp, nibuf, 2814*7c478bd9Sstevel@tonic-gate &lasttime)) 2815*7c478bd9Sstevel@tonic-gate recordf = NULL; 2816*7c478bd9Sstevel@tonic-gate } 2817*7c478bd9Sstevel@tonic-gate } 2818*7c478bd9Sstevel@tonic-gate if (ofd >= 0 && pty_master >= 0 && FD_ISSET(pty_master, &ready)) { 2819*7c478bd9Sstevel@tonic-gate obufp = outpacket_buf; 2820*7c478bd9Sstevel@tonic-gate nobuf = read(pty_master, obufp, sizeof(outpacket_buf)); 2821*7c478bd9Sstevel@tonic-gate if (nobuf < 0 && errno == EIO) 2822*7c478bd9Sstevel@tonic-gate nobuf = 0; 2823*7c478bd9Sstevel@tonic-gate if (nobuf < 0 || ofd == -1) { 2824*7c478bd9Sstevel@tonic-gate if (!(errno == EINTR || errno == EAGAIN)) { 2825*7c478bd9Sstevel@tonic-gate error("Error reading pseudo-tty master: %m"); 2826*7c478bd9Sstevel@tonic-gate break; 2827*7c478bd9Sstevel@tonic-gate } 2828*7c478bd9Sstevel@tonic-gate nobuf = 0; 2829*7c478bd9Sstevel@tonic-gate } else if (nobuf == 0) { 2830*7c478bd9Sstevel@tonic-gate /* end of file from the pty - slave side has closed */ 2831*7c478bd9Sstevel@tonic-gate nibuf = 0; 2832*7c478bd9Sstevel@tonic-gate (void) close(ofd); 2833*7c478bd9Sstevel@tonic-gate ofd = -1; 2834*7c478bd9Sstevel@tonic-gate if (recordf) 2835*7c478bd9Sstevel@tonic-gate if (!record_write(recordf, RECMARK_ENDSEND, NULL, 0, 2836*7c478bd9Sstevel@tonic-gate &lasttime)) 2837*7c478bd9Sstevel@tonic-gate recordf = NULL; 2838*7c478bd9Sstevel@tonic-gate } else { 2839*7c478bd9Sstevel@tonic-gate FD_SET(ofd, &writey); 2840*7c478bd9Sstevel@tonic-gate if (recordf) 2841*7c478bd9Sstevel@tonic-gate if (!record_write(recordf, RECMARK_STARTSEND, obufp, nobuf, 2842*7c478bd9Sstevel@tonic-gate &lasttime)) 2843*7c478bd9Sstevel@tonic-gate recordf = NULL; 2844*7c478bd9Sstevel@tonic-gate } 2845*7c478bd9Sstevel@tonic-gate } 2846*7c478bd9Sstevel@tonic-gate if (ofd == -1) 2847*7c478bd9Sstevel@tonic-gate nobuf = 0; 2848*7c478bd9Sstevel@tonic-gate else if (FD_ISSET(ofd, &writey)) { 2849*7c478bd9Sstevel@tonic-gate n = nobuf; 2850*7c478bd9Sstevel@tonic-gate if (olevel + n > max_level) 2851*7c478bd9Sstevel@tonic-gate n = max_level - olevel; 2852*7c478bd9Sstevel@tonic-gate n = write(ofd, obufp, n); 2853*7c478bd9Sstevel@tonic-gate if (n < 0) { 2854*7c478bd9Sstevel@tonic-gate if (errno == EIO) { 2855*7c478bd9Sstevel@tonic-gate (void) close(ofd); 2856*7c478bd9Sstevel@tonic-gate ofd = -1; 2857*7c478bd9Sstevel@tonic-gate nobuf = 0; 2858*7c478bd9Sstevel@tonic-gate } else if (errno != EAGAIN && errno != EINTR) { 2859*7c478bd9Sstevel@tonic-gate error("Error writing standard output: %m"); 2860*7c478bd9Sstevel@tonic-gate break; 2861*7c478bd9Sstevel@tonic-gate } 2862*7c478bd9Sstevel@tonic-gate } else { 2863*7c478bd9Sstevel@tonic-gate obufp += n; 2864*7c478bd9Sstevel@tonic-gate nobuf -= n; 2865*7c478bd9Sstevel@tonic-gate olevel += n; 2866*7c478bd9Sstevel@tonic-gate } 2867*7c478bd9Sstevel@tonic-gate } 2868*7c478bd9Sstevel@tonic-gate if (pty_master == -1) 2869*7c478bd9Sstevel@tonic-gate nibuf = 0; 2870*7c478bd9Sstevel@tonic-gate else if (FD_ISSET(pty_master, &writey)) { 2871*7c478bd9Sstevel@tonic-gate n = nibuf; 2872*7c478bd9Sstevel@tonic-gate if (ilevel + n > max_level) 2873*7c478bd9Sstevel@tonic-gate n = max_level - ilevel; 2874*7c478bd9Sstevel@tonic-gate n = write(pty_master, ibufp, n); 2875*7c478bd9Sstevel@tonic-gate if (n < 0) { 2876*7c478bd9Sstevel@tonic-gate if (errno == EAGAIN || errno == EINTR) 2877*7c478bd9Sstevel@tonic-gate continue; 2878*7c478bd9Sstevel@tonic-gate if (errno != EIO) { 2879*7c478bd9Sstevel@tonic-gate error("Error writing pseudo-tty master: %m"); 2880*7c478bd9Sstevel@tonic-gate break; 2881*7c478bd9Sstevel@tonic-gate } 2882*7c478bd9Sstevel@tonic-gate (void) close(pty_master); 2883*7c478bd9Sstevel@tonic-gate pty_master = -1; 2884*7c478bd9Sstevel@tonic-gate nibuf = 0; 2885*7c478bd9Sstevel@tonic-gate } else { 2886*7c478bd9Sstevel@tonic-gate ibufp += n; 2887*7c478bd9Sstevel@tonic-gate nibuf -= n; 2888*7c478bd9Sstevel@tonic-gate ilevel += n; 2889*7c478bd9Sstevel@tonic-gate } 2890*7c478bd9Sstevel@tonic-gate } 2891*7c478bd9Sstevel@tonic-gate } 2892*7c478bd9Sstevel@tonic-gate exit(0); 2893*7c478bd9Sstevel@tonic-gate } 2894*7c478bd9Sstevel@tonic-gate 2895*7c478bd9Sstevel@tonic-gate static int 2896*7c478bd9Sstevel@tonic-gate record_write(f, code, buf, nb, tp) 2897*7c478bd9Sstevel@tonic-gate FILE *f; 2898*7c478bd9Sstevel@tonic-gate int code; 2899*7c478bd9Sstevel@tonic-gate u_char *buf; 2900*7c478bd9Sstevel@tonic-gate int nb; 2901*7c478bd9Sstevel@tonic-gate struct timeval *tp; 2902*7c478bd9Sstevel@tonic-gate { 2903*7c478bd9Sstevel@tonic-gate struct timeval now; 2904*7c478bd9Sstevel@tonic-gate int diff; 2905*7c478bd9Sstevel@tonic-gate 2906*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&now, NULL); 2907*7c478bd9Sstevel@tonic-gate now.tv_usec /= 100000; /* actually 1/10 s, not usec now */ 2908*7c478bd9Sstevel@tonic-gate diff = (now.tv_sec - tp->tv_sec) * 10 + (now.tv_usec - tp->tv_usec); 2909*7c478bd9Sstevel@tonic-gate if (diff > 0) { 2910*7c478bd9Sstevel@tonic-gate if (diff > 255) { 2911*7c478bd9Sstevel@tonic-gate (void) putc(RECMARK_TIMEDELTA32, f); 2912*7c478bd9Sstevel@tonic-gate (void) putc(diff >> 24, f); 2913*7c478bd9Sstevel@tonic-gate (void) putc(diff >> 16, f); 2914*7c478bd9Sstevel@tonic-gate (void) putc(diff >> 8, f); 2915*7c478bd9Sstevel@tonic-gate (void) putc(diff, f); 2916*7c478bd9Sstevel@tonic-gate } else { 2917*7c478bd9Sstevel@tonic-gate (void) putc(RECMARK_TIMEDELTA8, f); 2918*7c478bd9Sstevel@tonic-gate (void) putc(diff, f); 2919*7c478bd9Sstevel@tonic-gate } 2920*7c478bd9Sstevel@tonic-gate *tp = now; 2921*7c478bd9Sstevel@tonic-gate } 2922*7c478bd9Sstevel@tonic-gate (void) putc(code, f); 2923*7c478bd9Sstevel@tonic-gate if (buf != NULL) { 2924*7c478bd9Sstevel@tonic-gate (void) putc(nb >> 8, f); 2925*7c478bd9Sstevel@tonic-gate (void) putc(nb, f); 2926*7c478bd9Sstevel@tonic-gate (void) fwrite(buf, nb, 1, f); 2927*7c478bd9Sstevel@tonic-gate } 2928*7c478bd9Sstevel@tonic-gate (void) fflush(f); 2929*7c478bd9Sstevel@tonic-gate if (ferror(f)) { 2930*7c478bd9Sstevel@tonic-gate error("Error writing record file: %m"); 2931*7c478bd9Sstevel@tonic-gate return (0); 2932*7c478bd9Sstevel@tonic-gate } 2933*7c478bd9Sstevel@tonic-gate return (1); 2934*7c478bd9Sstevel@tonic-gate } 2935