xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.bin/pppd/asppp2pppd (revision 11262:b7ebfbf2359e)
10Sstevel@tonic-gate#!/usr/bin/perl
20Sstevel@tonic-gate
30Sstevel@tonic-gate# This utility translates from aspppd configuration to Solaris PPP 4.0
40Sstevel@tonic-gate# (or ANU ppp-2.4.0; aka pppd).  It can also revert to previous aspppd
50Sstevel@tonic-gate# configuration (discarding the pppd configuration), but does not
60Sstevel@tonic-gate# translate new configuration files into old.
70Sstevel@tonic-gate#
80Sstevel@tonic-gate# This script provides only a suggested translation for your existing
90Sstevel@tonic-gate# aspppd configuration.  You will need to evaluate for yourself
100Sstevel@tonic-gate# whether the translation is appropriate for your operating
110Sstevel@tonic-gate# environment.
120Sstevel@tonic-gate
13*11262SRajagopal.Andra@Sun.COM# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
14*11262SRajagopal.Andra@Sun.COM# Use is subject to license terms.
150Sstevel@tonic-gate#
160Sstevel@tonic-gate
170Sstevel@tonic-gate# Steps in translation:
180Sstevel@tonic-gate#	- parse /etc/asppp.cf
19*11262SRajagopal.Andra@Sun.COM#	- check for aspppls in /etc/passwd (or NIS)
200Sstevel@tonic-gate#	- read in current /etc/ppp/options configuration file
210Sstevel@tonic-gate#	- read list of configured serial ports from pmadm
220Sstevel@tonic-gate#	- read in UUCP configuration files
230Sstevel@tonic-gate#	- create translated configuration
240Sstevel@tonic-gate#	- write files back out
250Sstevel@tonic-gate
260Sstevel@tonic-gate# Known issues:
270Sstevel@tonic-gate#	- translation with point-to-multipoint is incomplete
280Sstevel@tonic-gate
290Sstevel@tonic-gateuse Getopt::Std;
300Sstevel@tonic-gateuse Fcntl;
310Sstevel@tonic-gateuse POSIX qw(tmpnam ENOSYS);
320Sstevel@tonic-gateuse Sys::Hostname;
330Sstevel@tonic-gate
340Sstevel@tonic-gate# Secure the path if we're running under RBAC.
350Sstevel@tonic-gate$ENV{PATH} = ( "/bin", "/sbin", "/usr/bin", "/usr/sbin", "/usr/ucb" )
360Sstevel@tonic-gate    if $< != $>;
370Sstevel@tonic-gate
380Sstevel@tonic-gate# General path names that can be configured.
390Sstevel@tonic-gatelocal($rootetc) =	"/etc/";
400Sstevel@tonic-gatelocal($passwd) =	$rootetc . "passwd";
410Sstevel@tonic-gatelocal($passwdlck) =	$rootetc . ".pwd.lock";
420Sstevel@tonic-gatelocal($asfile) =	$rootetc . "asppp.cf";
430Sstevel@tonic-gatelocal($astemp) =	$rootetc . "asppp.temp.cf";
440Sstevel@tonic-gatelocal($asmoved) =	$rootetc . "asppp.saved.cf";
450Sstevel@tonic-gatelocal($uucpdir) =	$rootetc . "uucp/";
460Sstevel@tonic-gatelocal($Devices) =	$uucpdir . "Devices";
470Sstevel@tonic-gatelocal($Devconfig) =	$uucpdir . "Devconfig";
480Sstevel@tonic-gatelocal($Dialers) =	$uucpdir . "Dialers";
490Sstevel@tonic-gatelocal($Dialcodes) =	$uucpdir . "Dialcodes";
500Sstevel@tonic-gatelocal($Limits) =	$uucpdir . "Limits";
510Sstevel@tonic-gatelocal($Sysfiles) =	$uucpdir . "Sysfiles";
520Sstevel@tonic-gatelocal($Systems) =	$uucpdir . "Systems";
530Sstevel@tonic-gatelocal($pppdir) =	$rootetc . "ppp/";
540Sstevel@tonic-gatelocal($options) =	$pppdir . "options";
550Sstevel@tonic-gatelocal($ttyprefix) =	$pppdir . "options.";
560Sstevel@tonic-gatelocal($peersdir) =	$pppdir . "peers/";
570Sstevel@tonic-gatelocal($initd) =		$rootetc . "init.d/";
580Sstevel@tonic-gatelocal($asctl) =		$initd . "asppp";
590Sstevel@tonic-gatelocal($pppdctl) =	$initd . "pppd";
600Sstevel@tonic-gatelocal($sedpasswd) =	"/tmp/sed-passwd";
610Sstevel@tonic-gate
620Sstevel@tonic-gate# Fake asppp keyword used to keep track of dial-in paths.
630Sstevel@tonic-gatelocal($isdialin) = "-is-dial-in";
640Sstevel@tonic-gate
650Sstevel@tonic-gate# Limits and Sysfiles are keyed on "service=".
660Sstevel@tonic-gate# Devconfig is keyed on "service=" and "device=".
670Sstevel@tonic-gate# Dialcodes, Dialers, Systems, and Devices are single keyword files.
680Sstevel@tonic-gate# Devices alone may have multiple entries for a given key.
690Sstevel@tonic-gate
700Sstevel@tonic-gate# Internal data structures
710Sstevel@tonic-gatelocal(@sysfiles,@limits,@devconfig);
720Sstevel@tonic-gatelocal(@sysdefault) = ( "systems=" . $Systems, "dialers=" . $Dialers,
730Sstevel@tonic-gate		       "devices=" . $Devices );
740Sstevel@tonic-gatelocal(@limitdefault) = ( "max=-1" );
750Sstevel@tonic-gatelocal(@devdefault) = ( "pop=", "push=", "connecttime=-1", "expecttime=-1",
760Sstevel@tonic-gate		       "msgtime=-1" );
770Sstevel@tonic-gate
780Sstevel@tonic-gate# List of keywords for which ifconfig takes an additional parameter.
790Sstevel@tonic-gatelocal($ifconfigtakes) = (
800Sstevel@tonic-gate	addif => 1,
810Sstevel@tonic-gate	removeif => 1,
820Sstevel@tonic-gate	auth_algs => 1,
830Sstevel@tonic-gate	encr_algs => 1,
840Sstevel@tonic-gate	encr_auth_algs => 1,
850Sstevel@tonic-gate	broadcast => 1,
860Sstevel@tonic-gate	destination => 1,
870Sstevel@tonic-gate	index => 1,
880Sstevel@tonic-gate	metric => 1,
890Sstevel@tonic-gate	modinsert => 1,
900Sstevel@tonic-gate	modremove => 1,
910Sstevel@tonic-gate	mtu => 1,
920Sstevel@tonic-gate	netmask => 1,
930Sstevel@tonic-gate	set => 1,
940Sstevel@tonic-gate	subnet => 1,
950Sstevel@tonic-gate	tdst => 1,
960Sstevel@tonic-gate	tsrc => 1,
970Sstevel@tonic-gate	wait => 1,
980Sstevel@tonic-gate
990Sstevel@tonic-gate# These are keywords, but do not take an additional parameter.
1000Sstevel@tonic-gate	ether => 0,
1010Sstevel@tonic-gate	inet => 0,
1020Sstevel@tonic-gate	inet6 => 0,
1030Sstevel@tonic-gate	arp => 0,
1040Sstevel@tonic-gate	-arp => 0,
1050Sstevel@tonic-gate	auto-revarp => 0,
1060Sstevel@tonic-gate	modlist => 0,
1070Sstevel@tonic-gate	plumb => 0,
1080Sstevel@tonic-gate	unplumb => 0,
1090Sstevel@tonic-gate	private => 0,
1100Sstevel@tonic-gate	-private => 0,
1110Sstevel@tonic-gate	nud => 0,
1120Sstevel@tonic-gate	-nud => 0,
1130Sstevel@tonic-gate	trailers => 0,
1140Sstevel@tonic-gate	-trailers => 0,
1150Sstevel@tonic-gate	up => 0,
1160Sstevel@tonic-gate	down => 0,
1170Sstevel@tonic-gate	xmit => 0,
1180Sstevel@tonic-gate	-xmit => 0,
1190Sstevel@tonic-gate	auto-dhcp => 0,
1200Sstevel@tonic-gate	dhcp => 0,
1210Sstevel@tonic-gate	primary => 0,
1220Sstevel@tonic-gate	drop => 0,
1230Sstevel@tonic-gate	extend => 0,
1240Sstevel@tonic-gate	inform => 0,
1250Sstevel@tonic-gate	ping => 0,
1260Sstevel@tonic-gate	release => 0,
1270Sstevel@tonic-gate	start => 0,
1280Sstevel@tonic-gate	status => 0
1290Sstevel@tonic-gate);
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate# print number of something in English.
1320Sstevel@tonic-gatesub nof
1330Sstevel@tonic-gate{
1340Sstevel@tonic-gate    local($num, $item, @rest) = @_;
1350Sstevel@tonic-gate    print "No ", $item, "s", @rest if $num == 0;
1360Sstevel@tonic-gate    print "1 ", $item, @rest if $num == 1;
1370Sstevel@tonic-gate    print $num, " ", $item, "s", @rest if $num > 1;
1380Sstevel@tonic-gate}
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate# ask a yes or no question.
1410Sstevel@tonic-gatesub yesno
1420Sstevel@tonic-gate{
1430Sstevel@tonic-gate    local ($query, $default) = @_;
1440Sstevel@tonic-gate    local ($ans, $defans);
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate    return $default unless (-t STDIN) && (-t STDOUT) && !$opt_n;
1470Sstevel@tonic-gate    $defans = $default ? "Yn" : "yN";
1480Sstevel@tonic-gate    while (1) {
1490Sstevel@tonic-gate	print $query, " [", $defans, "]? ";
1500Sstevel@tonic-gate	chomp($ans = <STDIN>);
1510Sstevel@tonic-gate	return $default unless $ans;
1520Sstevel@tonic-gate	return 1 if $ans =~ /^[Yy1Tt]/;
1530Sstevel@tonic-gate	return 0 if $ans =~ /^[Nn0Ff]/;
1540Sstevel@tonic-gate	print "Please enter 'y' or 'n'.\n";
1550Sstevel@tonic-gate    }
1560Sstevel@tonic-gate}
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate# Put quotes around a string, if necessary.
1590Sstevel@tonic-gate# The tests here aren't perfect -- they think that \\\' isn't an
1600Sstevel@tonic-gate# escaped quote -- but they're good enough.
1610Sstevel@tonic-gatesub requote
1620Sstevel@tonic-gate{
1630Sstevel@tonic-gate    local($_) = @_;
1640Sstevel@tonic-gate    if (/^$/) {
1650Sstevel@tonic-gate	"\"\"";
1660Sstevel@tonic-gate    } elsif (/^'/ || /[^\\]'/ || /\\\\'/) {
1670Sstevel@tonic-gate# Has unescaped quotes; must use " or redo quoting.
1680Sstevel@tonic-gate	if (/^"/ || /[^\\]"/ || /\\\\"/) {
1690Sstevel@tonic-gate# Both kinds of quotes; redo the quoting.
1700Sstevel@tonic-gate	    s/^"/\\"/;
1710Sstevel@tonic-gate	    s/([^\\]|\\\\)"/$1\\"/g;
1720Sstevel@tonic-gate	}
1730Sstevel@tonic-gate	"\"" . $_ . "\"";
1740Sstevel@tonic-gate    } elsif (/^"/ || /[^\\]"/ || /\\\\"/) {
1750Sstevel@tonic-gate	"'" . $_ . "'";
1760Sstevel@tonic-gate    } elsif (/\s/) {
1770Sstevel@tonic-gate	"\"" . $_ . "\"";
1780Sstevel@tonic-gate    } else {
1790Sstevel@tonic-gate	$_;
1800Sstevel@tonic-gate    }
1810Sstevel@tonic-gate}
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate# Get a single line from a UUCP configuration file and return as a
1840Sstevel@tonic-gate# reference to an array of words.  Removes comments and escapes.
1850Sstevel@tonic-gate# (This is a modified version of the standard Perl shellwords function
1860Sstevel@tonic-gate# that understands C escape sequences and continuation lines.)
1870Sstevel@tonic-gate# Optionally returns lead-in, source text, and trailing component
1880Sstevel@tonic-gate# for editing.
1890Sstevel@tonic-gatesub uucpline
1900Sstevel@tonic-gate{
1910Sstevel@tonic-gate    local($input, $file, $triplet) = @_;
1920Sstevel@tonic-gate    local(@words,$snippet,$field,$havefield,$cont,@triparray,$maytrail);
1930Sstevel@tonic-gate
1940Sstevel@tonic-gate    $cont = "";
1950Sstevel@tonic-gate    $maytrail = "";
1960Sstevel@tonic-gate    while (<$input>) {
1970Sstevel@tonic-gate	# remove leading whitespace
1980Sstevel@tonic-gate	if (s/^(\s+)//) {
1990Sstevel@tonic-gate	    $maytrail .= $1;
2000Sstevel@tonic-gate	}
2010Sstevel@tonic-gate	if ($cont eq "") {
2020Sstevel@tonic-gate	    if (s/^(\#(.|\n)*)$//) {
2030Sstevel@tonic-gate		$triparray[0] .= $maytrail . $1;
2040Sstevel@tonic-gate		$maytrail = "";
2050Sstevel@tonic-gate		next;
2060Sstevel@tonic-gate	    }
2070Sstevel@tonic-gate	    if (s/^(\\?\n?)$//) {
2080Sstevel@tonic-gate		$triparray[0] .= $maytrail . $1;
2090Sstevel@tonic-gate		$maytrail = "";
2100Sstevel@tonic-gate		next;
2110Sstevel@tonic-gate	    }
2120Sstevel@tonic-gate	    $triparray[0] .= $maytrail;
2130Sstevel@tonic-gate	    $maytrail = "";
2140Sstevel@tonic-gate	}
2150Sstevel@tonic-gate	$snippet = $_;
2160Sstevel@tonic-gate	if (s/^(([^\#\\]|\\.)*)\\\n$//) {
2170Sstevel@tonic-gate	    $maytrail .= $snippet;
2180Sstevel@tonic-gate	    $cont .= $1;
2190Sstevel@tonic-gate	    next;
2200Sstevel@tonic-gate	}
2210Sstevel@tonic-gate	if (/^(([^\\\#]|\\[^\#])*)(\#?(.|\n)*)$/) {
2220Sstevel@tonic-gate	    $_ = $maytrail . $1;
2230Sstevel@tonic-gate	    $maytrail = $3;
2240Sstevel@tonic-gate	    if (s/((\s|\n)*)$//) {
2250Sstevel@tonic-gate		$maytrail = $1 . $maytrail;
2260Sstevel@tonic-gate	    }
2270Sstevel@tonic-gate	    $triparray[1] = $_;
2280Sstevel@tonic-gate	}
2290Sstevel@tonic-gate	$_ = $cont . $snippet;
2300Sstevel@tonic-gate	$cont = "";
2310Sstevel@tonic-gate	s/\n$//;
2320Sstevel@tonic-gate	while ($_ ne '') {
2330Sstevel@tonic-gate	    for (;;) {
2340Sstevel@tonic-gate		if (s/^#.*//) {
2350Sstevel@tonic-gate		    last;
2360Sstevel@tonic-gate		} elsif (s/^"(([^"\\]|\\.)*)"//) {
2370Sstevel@tonic-gate		    $snippet = $1;
2380Sstevel@tonic-gate		} elsif (s/^"//) {
2390Sstevel@tonic-gate		    warn "Unmatched double quote in $file: \"$_\n";
2400Sstevel@tonic-gate		} elsif (s/^'(([^'\\]|\\.)*)'//) {
2410Sstevel@tonic-gate		    $snippet = $1;
2420Sstevel@tonic-gate		} elsif (s/^'//) {
2430Sstevel@tonic-gate		    warn "Unmatched single quote in $file: '$_\n";
2440Sstevel@tonic-gate		} elsif (s/^\\s//) {
2450Sstevel@tonic-gate# \s works in chat, but not in the pppd option files
2460Sstevel@tonic-gate		    $snippet = " ";
2470Sstevel@tonic-gate		} elsif (s/^(\\.)//) {
2480Sstevel@tonic-gate		    $snippet = $1;
2490Sstevel@tonic-gate		} elsif (s/^([^\s\\'"#]+)//) {
2500Sstevel@tonic-gate		    $snippet = $1;
2510Sstevel@tonic-gate		} else {
2520Sstevel@tonic-gate		    s/^\s+//;
2530Sstevel@tonic-gate		    last;
2540Sstevel@tonic-gate		}
2550Sstevel@tonic-gate		$havefield = 1;
2560Sstevel@tonic-gate		$field .= $snippet;
2570Sstevel@tonic-gate	    }
2580Sstevel@tonic-gate	    push(@words, $field) if $havefield;
2590Sstevel@tonic-gate	    $havefield = 0;
2600Sstevel@tonic-gate	    $field = '';
2610Sstevel@tonic-gate	}
2620Sstevel@tonic-gate	last;
2630Sstevel@tonic-gate    }
2640Sstevel@tonic-gate    $triparray[2] .= $maytrail;
2650Sstevel@tonic-gate    @$triplet = @triparray;
2660Sstevel@tonic-gate    warn "Bad continuation line in $file: $cont\n" if $cont ne '';
2670Sstevel@tonic-gate    \@words;
2680Sstevel@tonic-gate}
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate# Given a logical UUCP file name, return a list of all of the files
2710Sstevel@tonic-gate# that should be read.
2720Sstevel@tonic-gatesub uucpfiles
2730Sstevel@tonic-gate{
2740Sstevel@tonic-gate    local ($file) = @_;
2750Sstevel@tonic-gate    local (@flist, $value) = ();
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate    for $value (@sysfiles, @sysdefault) {
2780Sstevel@tonic-gate	if ($value =~ /^$file=/i) {
2790Sstevel@tonic-gate	    $value =~ s/^$file=//i;
2800Sstevel@tonic-gate	    for $file (split /:/, $value) {
2810Sstevel@tonic-gate		$file = $uucpdir . $file if $file !~ /^\//;
2820Sstevel@tonic-gate		push @flist, $file;
2830Sstevel@tonic-gate	    }
2840Sstevel@tonic-gate	    last;
2850Sstevel@tonic-gate	}
2860Sstevel@tonic-gate    }
2870Sstevel@tonic-gate    @flist;
2880Sstevel@tonic-gate}
2890Sstevel@tonic-gate
2900Sstevel@tonic-gate# Given a file name and some key words, parse the contents of the file
2910Sstevel@tonic-gate# and return a reference to a hash constructed from this.  All keys
2920Sstevel@tonic-gate# except the last must match exactly.  The last is used to order the
2930Sstevel@tonic-gate# hash.
2940Sstevel@tonic-gatesub uucpkeyfile
2950Sstevel@tonic-gate{
2960Sstevel@tonic-gate    local($file,@keylist) = @_;
2970Sstevel@tonic-gate    local($lastkey,$keyval,$words,$i,$flag,%byservice);
2980Sstevel@tonic-gate
2990Sstevel@tonic-gate    open(SVCFILE, '<' . $file) || return undef;
3000Sstevel@tonic-gate    $lastkey = pop @keylist;
3010Sstevel@tonic-gate    while (@{$words = uucpline(SVCFILE, $file)}) {
3020Sstevel@tonic-gate	$flag = 1;
3030Sstevel@tonic-gate	foreach $keyval (@keylist) {
3040Sstevel@tonic-gate	    $flag = 0;
3050Sstevel@tonic-gate	    $i = 0;
3060Sstevel@tonic-gate	    while ($i < @$words) {
3070Sstevel@tonic-gate		if ($$words[$i] eq $keyval) {
3080Sstevel@tonic-gate		    splice @$words, $i, 1;
3090Sstevel@tonic-gate		    $flag = 1;
3100Sstevel@tonic-gate		    last;
3110Sstevel@tonic-gate		}
3120Sstevel@tonic-gate		$i++;
3130Sstevel@tonic-gate	    }
3140Sstevel@tonic-gate	    last unless $flag;
3150Sstevel@tonic-gate	}
3160Sstevel@tonic-gate	next unless $flag;
3170Sstevel@tonic-gate	foreach $i (0 .. @{$words}) {
3180Sstevel@tonic-gate	    if (@{$words}[$i] =~ /^$lastkey(.*)/i) {
3190Sstevel@tonic-gate		splice @{$words}, $i, 1;
3200Sstevel@tonic-gate		$byservice{$1} = $words;
3210Sstevel@tonic-gate		last;
3220Sstevel@tonic-gate	    }
3230Sstevel@tonic-gate	}
3240Sstevel@tonic-gate    }
3250Sstevel@tonic-gate    close SVCFILE;
3260Sstevel@tonic-gate    \%byservice;
3270Sstevel@tonic-gate}
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate# This reads a UUCP file that is keyed on the first token on each
3300Sstevel@tonic-gate# line.  Duplicates are not permitted; the first encountered is used
3310Sstevel@tonic-gate# and the rest are silently discarded.  A hash indexed on the first
3320Sstevel@tonic-gate# token and containing an array of tokens in each bucket is returned.
3330Sstevel@tonic-gate# Used for Dialcodes, Dialers, and Systems.
3340Sstevel@tonic-gatesub uucpposfiles
3350Sstevel@tonic-gate{
3360Sstevel@tonic-gate    local(@files) = @_;
3370Sstevel@tonic-gate    local($keyval,$words,%keyeddata);
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate    foreach $file (@files) {
3400Sstevel@tonic-gate	if (!open(POSFILE, '<' . $file)) {
3410Sstevel@tonic-gate	    warn "$file: $!\n";
3420Sstevel@tonic-gate	    next;
3430Sstevel@tonic-gate	}
3440Sstevel@tonic-gate	while (@{$words = uucpline(POSFILE, $file)}) {
3450Sstevel@tonic-gate	    $keyval = shift @{$words};
3460Sstevel@tonic-gate	    next if $keyeddata{$keyval};
3470Sstevel@tonic-gate	    $keyeddata{$keyval} = $words;
3480Sstevel@tonic-gate	}
3490Sstevel@tonic-gate	close POSFILE;
3500Sstevel@tonic-gate    }
3510Sstevel@tonic-gate    \%keyeddata;
3520Sstevel@tonic-gate}
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate# This reads a UUCP file that is keyed on the first token on each line
3550Sstevel@tonic-gate# and may have duplicate entries.  Each entry of the hash contains an
3560Sstevel@tonic-gate# array.  Each entry of that array points to an array of tokens
3570Sstevel@tonic-gate# representing one parsed line.  Used for the Devices file.
3580Sstevel@tonic-gatesub uucpdevices
3590Sstevel@tonic-gate{
3600Sstevel@tonic-gate    local(@files) = @_;
3610Sstevel@tonic-gate    local($keyval,$words,%keyeddata);
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate    foreach $file (@files) {
3640Sstevel@tonic-gate	if (!open(POSFILE, '<' . $file)) {
3650Sstevel@tonic-gate	    warn "$file: $!\n";
3660Sstevel@tonic-gate	    next;
3670Sstevel@tonic-gate	}
3680Sstevel@tonic-gate	while (@{$words = uucpline(POSFILE, $file)}) {
3690Sstevel@tonic-gate	    $keyval = shift @{$words};
3700Sstevel@tonic-gate	    push @{$keyeddata{$keyval}}, $words;
3710Sstevel@tonic-gate	}
3720Sstevel@tonic-gate	close POSFILE;
3730Sstevel@tonic-gate    }
3740Sstevel@tonic-gate    \%keyeddata;
3750Sstevel@tonic-gate}
3760Sstevel@tonic-gate
3770Sstevel@tonic-gate# For a path defined in asppp.cf, copy over defaults, validate the
3780Sstevel@tonic-gate# required options, and save in the hash to be returned.
3790Sstevel@tonic-gatesub savepath
3800Sstevel@tonic-gate{
3810Sstevel@tonic-gate    local($paths, $options, $defref) = @_;
3820Sstevel@tonic-gate    local($peer,$intf);
3830Sstevel@tonic-gate
3840Sstevel@tonic-gate    return if $options == $defref;
3850Sstevel@tonic-gate    foreach $key (keys %$defref) {
3860Sstevel@tonic-gate	$$options{$key} = $$defref{$key} unless defined($$options{$key});
3870Sstevel@tonic-gate    }
3880Sstevel@tonic-gate    $peer = $$options{"peer_system_name"};
3890Sstevel@tonic-gate    warn("Discarded path with no peer system name.\n"), return
3900Sstevel@tonic-gate	unless defined($peer);
3910Sstevel@tonic-gate    $intf = $$options{"interface"};
3920Sstevel@tonic-gate    warn("Missing interface on path to peer \"$peer\".\n"), return
3930Sstevel@tonic-gate	unless defined($intf);
3940Sstevel@tonic-gate    warn("Bad interface $intf on path to peer \"$peer\".\n"), return
3950Sstevel@tonic-gate	unless $intf =~ /^ipd([0-9]+|ptp[0-9]+|ptp\*)$/;
3960Sstevel@tonic-gate    warn("Missing peer IP address for point-to-multipoint path to \"",
3970Sstevel@tonic-gate	$peer, "\".\n"), return
3980Sstevel@tonic-gate	if $intf =~ /^ipd[0-9]+$/ && !defined($$options{"peer_ip_address"});
3990Sstevel@tonic-gate    warn "Multiple definitions of path to peer \"$peer\".\n",
4000Sstevel@tonic-gate	if defined($paths{$peer});
4010Sstevel@tonic-gate    warn "Odd version number ", $$options{"version"},
4020Sstevel@tonic-gate	" encountered in path to peer \"", $peer, "\" (ignored).\n"
4030Sstevel@tonic-gate	if defined($$options{"version"}) && $$options{"version"} != 1;
4040Sstevel@tonic-gate    $paths{$peer} = $options;
4050Sstevel@tonic-gate}
4060Sstevel@tonic-gate
4070Sstevel@tonic-gate# Parse through asppp.cf. Unlike the UUCP files, lines don't matter
4080Sstevel@tonic-gate# here.  The parsing is modal, with "path" introducing a PPP session
4090Sstevel@tonic-gate# description and "defaults" reverting back to global definitions.
4100Sstevel@tonic-gatesub readaspppcf
4110Sstevel@tonic-gate{
4120Sstevel@tonic-gate    local($aspppcf) = @_;
4130Sstevel@tonic-gate    local(%aspppdkey) = (
4140Sstevel@tonic-gate	chap_name		=> 1,
4150Sstevel@tonic-gate	chap_peer_secret	=> 1,
4160Sstevel@tonic-gate	chap_peer_name		=> 1,
4170Sstevel@tonic-gate	chap_secret		=> 1,
4180Sstevel@tonic-gate	debug_level		=> 1,
4190Sstevel@tonic-gate	default_route		=> 0,
4200Sstevel@tonic-gate	ifconfig		=> -1,
4210Sstevel@tonic-gate	inactivity_timeout	=> 1,
4220Sstevel@tonic-gate	interface		=> 1,
4230Sstevel@tonic-gate# sic; aspppd is seriously confused!  ACCM isn't in IPCP.
4240Sstevel@tonic-gate	ipcp_async_map		=> 1,
4250Sstevel@tonic-gate	ipcp_compression	=> 1,
4260Sstevel@tonic-gate	lcp_compression		=> 1,
4270Sstevel@tonic-gate	lcp_mru			=> 1,
4280Sstevel@tonic-gate	negotiate_address	=> 1,
4290Sstevel@tonic-gate	pap_id			=> 1,
4300Sstevel@tonic-gate	pap_password		=> 1,
4310Sstevel@tonic-gate	pap_peer_id		=> 1,
4320Sstevel@tonic-gate	pap_peer_password	=> 1,
4330Sstevel@tonic-gate	peer_ip_address		=> 1,
4340Sstevel@tonic-gate	peer_system_name	=> 1,
4350Sstevel@tonic-gate	require_authentication	=> 2,
4360Sstevel@tonic-gate	version			=> 1,
4370Sstevel@tonic-gate	will_do_authentication	=> 2
4380Sstevel@tonic-gate    );
4390Sstevel@tonic-gate    local($words,$word,$prevword,$i,$errors,%defaults,%ifconfig,%paths);
4400Sstevel@tonic-gate    local($options);
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate    open ASPPPD, "<" . $aspppcf || die "$aspppcf: $!\n";
4430Sstevel@tonic-gate    print "Reading configuration from $aspppcf\n" if $opt_v;
4440Sstevel@tonic-gate    $defaults{inactivity_timeout} = 120;
4450Sstevel@tonic-gate    $defaults{ipcp_compression} = "vj";
4460Sstevel@tonic-gate    $defaults{lcp_compression} = "on";
4470Sstevel@tonic-gate    $options = \%defaults;
4480Sstevel@tonic-gate    while (@{$words = uucpline(ASPPPD, $aspppcf)}) {
4490Sstevel@tonic-gate	if ($$words[0] =~ /^ifconfig$/i) {
4500Sstevel@tonic-gate	    warn "$prevword with missing argument ignored.\n"
4510Sstevel@tonic-gate		if defined($prevword);
4520Sstevel@tonic-gate	    undef $prevword;
4530Sstevel@tonic-gate	    shift @$words;	# discard 'ifconfig' keyword
4540Sstevel@tonic-gate	    $word = shift @$words;
4550Sstevel@tonic-gate	    warn("Bad interface on ifconfig $word.\n"), next
4560Sstevel@tonic-gate		unless $word =~ /^ipd([0-9]+|ptp[0-9]+)$/;
4570Sstevel@tonic-gate	    $ifconfig{$word} = \@$words;
4580Sstevel@tonic-gate	    next;
4590Sstevel@tonic-gate	}
4600Sstevel@tonic-gate	unshift @{$words}, $prevword if defined($prevword);
4610Sstevel@tonic-gate	undef $prevword;
4620Sstevel@tonic-gate	while ($word = lc(shift @{$words})) {
4630Sstevel@tonic-gate	    $_ = $word;
4640Sstevel@tonic-gate	    if (/^defaults$/i) {
4650Sstevel@tonic-gate		savepath(\%paths, $options, \%defaults);
4660Sstevel@tonic-gate		$options = \%defaults;
4670Sstevel@tonic-gate		next ;
4680Sstevel@tonic-gate	    }
4690Sstevel@tonic-gate	    if (/^path$/i) {
4700Sstevel@tonic-gate		local(%pathopts);
4710Sstevel@tonic-gate		savepath(\%paths, $options, \%defaults);
4720Sstevel@tonic-gate		$options = \%pathopts;
4730Sstevel@tonic-gate		next;
4740Sstevel@tonic-gate	    }
4750Sstevel@tonic-gate	    if (!defined($i = $aspppdkey{$word})) {
4760Sstevel@tonic-gate		die "Too many errors in $aspppcf; aborting.\n"
4770Sstevel@tonic-gate		    if ++$errors > 5;
4780Sstevel@tonic-gate		warn "Ignoring unknown keyword $word in $aspppcf\n";
4790Sstevel@tonic-gate		next;
4800Sstevel@tonic-gate	    }
4810Sstevel@tonic-gate	    warn("$_ unexpected; remainder of line ignored.\n"),
4820Sstevel@tonic-gate		last if $i == -1;
4830Sstevel@tonic-gate	    warn("Duplicate $_ in path ignored.\n"), next
4840Sstevel@tonic-gate		if $options != \%defaults && defined($$options{$_});
4850Sstevel@tonic-gate	    $$options{$_} = 1 if $i == 0;
4860Sstevel@tonic-gate	    next if $i == 0;
4870Sstevel@tonic-gate	    $prevword = $_, last unless defined($word = shift @{$words});
4880Sstevel@tonic-gate	    $$options{$_} = $word if $i == 1;
4890Sstevel@tonic-gate	    if ($i == 2) {
4900Sstevel@tonic-gate		undef $$options{$_}, next if $word =~ /^off$/;
4910Sstevel@tonic-gate		$$options{$_} = $word;
4920Sstevel@tonic-gate		if ($word = shift @{$words}) {
4930Sstevel@tonic-gate		    if ($word =~ /^(p|ch)ap$/) {
4940Sstevel@tonic-gate			$$options{$_} .= " " . $word;
4950Sstevel@tonic-gate		    } else {
4960Sstevel@tonic-gate			unshift @{$words}, $word;
4970Sstevel@tonic-gate		    }
4980Sstevel@tonic-gate		}
4990Sstevel@tonic-gate	    }
5000Sstevel@tonic-gate	}
5010Sstevel@tonic-gate    }
5020Sstevel@tonic-gate    warn "Odd trailing keyword \"$prevword\" ignored in $aspppcf\n"
5030Sstevel@tonic-gate	if $prevword;
5040Sstevel@tonic-gate    savepath(\%paths, $options, \%defaults);
5050Sstevel@tonic-gate    die "No paths defined for aspppd.\n" if 0+(keys %paths) == 0;
5060Sstevel@tonic-gate    die "No interfaces defined for aspppd.\n" if 0+(keys %ifconfig) == 0;
5070Sstevel@tonic-gate    if ($opt_v) {
5080Sstevel@tonic-gate	nof 0+(keys %paths), "path", " and ";
5090Sstevel@tonic-gate	nof 0+(keys %ifconfig), "interface", " defined for aspppd.\n";
5100Sstevel@tonic-gate    }
5110Sstevel@tonic-gate    close ASPPPD;
5120Sstevel@tonic-gate    ( \%ifconfig, \%paths );
5130Sstevel@tonic-gate}
5140Sstevel@tonic-gate
515*11262SRajagopal.Andra@Sun.COM# Read /etc/passwd (or NIS) and return hash of users for whom
5160Sstevel@tonic-gate# the default shell is aspppls.  Each hash entry contains the user's
5170Sstevel@tonic-gate# home directory path.
5180Sstevel@tonic-gatesub readpasswd
5190Sstevel@tonic-gate{
5200Sstevel@tonic-gate    local(%users,@pwe);
5210Sstevel@tonic-gate
5220Sstevel@tonic-gate    setpwent();
5230Sstevel@tonic-gate    while (@pwe = getpwent()) {
5240Sstevel@tonic-gate	$users{$pwe[0]} = $pwe[7] if $pwe[8] =~ /\/aspppls$/;
5250Sstevel@tonic-gate    }
5260Sstevel@tonic-gate    endpwent();
5270Sstevel@tonic-gate    nof 0+(keys %users), "aspppd dial in user", " found.\n"
5280Sstevel@tonic-gate	if $opt_v;
5290Sstevel@tonic-gate    \%users;
5300Sstevel@tonic-gate}
5310Sstevel@tonic-gate
5320Sstevel@tonic-gate# Parse through pmadm output to find enabled serial ports.
5330Sstevel@tonic-gate# Field 9 has 'I' (modem dial-out only or initialize only), 'b'
5340Sstevel@tonic-gate# (bidirectional) or is blank (modem dial-in only or terminal-hardwired).
5350Sstevel@tonic-gate# For that latter case, field 18 (software-carrier) has 'y'.
5360Sstevel@tonic-gate# Field 3 has 'x' if disabled.
5370Sstevel@tonic-gatesub getserialports
5380Sstevel@tonic-gate{
5390Sstevel@tonic-gate    local(%dialin, %dialout);
5400Sstevel@tonic-gate
5410Sstevel@tonic-gate    open PMADM, "pmadm -L|" || (warn "pmadm: $!\n", return undef);
5420Sstevel@tonic-gate    while (<PMADM>) {
5430Sstevel@tonic-gate	split /:/;
5440Sstevel@tonic-gate	if ($_[3] !~ /x/) {
5450Sstevel@tonic-gate	    $dialin{$_[2]} = $_[8] if $_[9] ne "I";
5460Sstevel@tonic-gate	    $dialout{$_[2]} = $_[8] if $_[9] ne "";
5470Sstevel@tonic-gate	}
5480Sstevel@tonic-gate    }
5490Sstevel@tonic-gate    close PMADM;
5500Sstevel@tonic-gate    ( \%dialin, \%dialout );
5510Sstevel@tonic-gate}
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate# Convert an ifconfig statement into a local and remote address pair.
5540Sstevel@tonic-gatesub ifconf_addr
5550Sstevel@tonic-gate{
5560Sstevel@tonic-gate    local($ifconf) = @_;
5570Sstevel@tonic-gate    local($arg, $narg, $lcladdr, $remaddr);
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate    shift @$ifconf;	# lose the interface name
5600Sstevel@tonic-gate    while (@$ifconf) {
5610Sstevel@tonic-gate	local($arg, $narg);
5620Sstevel@tonic-gate	$arg = shift @$ifconf;
5630Sstevel@tonic-gate	$narg = shift @$ifconf if $ifconfigtakes{$arg};
5640Sstevel@tonic-gate	if (exists($ifconfigtakes{$arg})) {
5650Sstevel@tonic-gate	    if ($arg eq "set") {
5660Sstevel@tonic-gate		$lcladdr = $narg;
5670Sstevel@tonic-gate	    } elsif ($arg eq "destination") {
5680Sstevel@tonic-gate		$remaddr = $narg;
5690Sstevel@tonic-gate	    }
5700Sstevel@tonic-gate	} elsif (!defined($lcladdr)) {
5710Sstevel@tonic-gate	    $lcladdr = $arg;
5720Sstevel@tonic-gate	} elsif (!defined($remaddr)) {
5730Sstevel@tonic-gate	    $remaddr = $arg;
5740Sstevel@tonic-gate	}
5750Sstevel@tonic-gate    }
5760Sstevel@tonic-gate    ( $lcladdr, $remaddr );
5770Sstevel@tonic-gate}
5780Sstevel@tonic-gate
5790Sstevel@tonic-gate# Convert a hash of aspppd options into an array of pppd options.  The
5800Sstevel@tonic-gate# third argument ($chatpath) is undef for dial-in or a path to the
5810Sstevel@tonic-gate# chat script file otherwise.
5820Sstevel@tonic-gatesub convert_options
5830Sstevel@tonic-gate{
5840Sstevel@tonic-gate    local ($pppdargs, $opts, $chatpath, $user) = @_;
5850Sstevel@tonic-gate
5860Sstevel@tonic-gate# Do the pppd option conversions.
5870Sstevel@tonic-gate    push(@$pppdargs, "defaultroute") if $$opts{default_route};
5880Sstevel@tonic-gate    push(@$pppdargs, "idle " . $$opts{inactivity_timeout})
5890Sstevel@tonic-gate	if $$opts{inactivity_timeout} != 0;
5900Sstevel@tonic-gate    push(@$pppdargs, "asyncmap " . $$opts{ipcp_async_map})
5910Sstevel@tonic-gate	if $$opts{ipcp_async_map};
5920Sstevel@tonic-gate    push(@$pppdargs, "novj") if !$$opts{ipcp_compression};
5930Sstevel@tonic-gate    local($peer);
5940Sstevel@tonic-gate    if ($$opts{require_authentication}) {
5950Sstevel@tonic-gate	local (@authopts);
5960Sstevel@tonic-gate	if ($$opts{require_authentication} =~ /chap/) {
5970Sstevel@tonic-gate	    push(@authopts, "require-chap");
5980Sstevel@tonic-gate	    $peer = $$opts{chap_peer_name};
5990Sstevel@tonic-gate	} else {
6000Sstevel@tonic-gate	    push(@authopts, "require-pap");
6010Sstevel@tonic-gate	    $peer = $$opts{pap_peer_id};
6020Sstevel@tonic-gate	}
6030Sstevel@tonic-gate	push(@authopts, "remotename " . requote($peer)) if $peer;
6040Sstevel@tonic-gate	push(@authopts, "auth");
6050Sstevel@tonic-gate	if ($chatpath) {
6060Sstevel@tonic-gate	    push(@$pppdargs, @authopts);
6070Sstevel@tonic-gate	} elsif ($dialin_auth == 3) {
6080Sstevel@tonic-gate# mixed authentication; must use wrapper script.
6090Sstevel@tonic-gate	    local($sfile) = $pppdir . "dial-in." . $user;
6100Sstevel@tonic-gate	    $scriptfiles{$sfile}  = "#!/bin/sh\n";
6110Sstevel@tonic-gate	    $scriptfiles{$sfile} .= "exec /usr/bin/pppd @authopts\n";
6120Sstevel@tonic-gate	    $dialinshell{$user} = $sfile;
6130Sstevel@tonic-gate	}
6140Sstevel@tonic-gate    } elsif ($dialin_auth < 2) {
6150Sstevel@tonic-gate	push(@$pppdargs, "noauth");
6160Sstevel@tonic-gate    }
6170Sstevel@tonic-gate    push(@$pppdargs, "noaccomp nopcomp") if !$$opts{lcp_compression};
6180Sstevel@tonic-gate    push(@$pppdargs, "mru " . $$opts{lcp_mru}) if $$opts{lcp_mru};
6190Sstevel@tonic-gate    push(@$pppdargs, "noipdefault ipcp-accept-local")
6200Sstevel@tonic-gate	if $$opts{negotiate_address};
6210Sstevel@tonic-gate    local($myname,$csecret,$psecret,$passopt);
6220Sstevel@tonic-gate    if ($$opts{will_do_authentication} =~ /chap/i) {
6230Sstevel@tonic-gate	$myname = $$opts{chap_name};
6240Sstevel@tonic-gate	$csecret = $$opts{chap_secret};
6250Sstevel@tonic-gate    }
6260Sstevel@tonic-gate    $myname = "" if !$myname;
6270Sstevel@tonic-gate    if ($$opts{will_do_authentication} =~ /pap/i) {
6280Sstevel@tonic-gate	if ($myname ne "" && $$opts{pap_id} ne "" &&
6290Sstevel@tonic-gate	    $myname ne $$opts{pap_id}) {
6300Sstevel@tonic-gate	    warn "pppd cannot have separate local names for PAP and CHAP; using CHAP name:\n";
6310Sstevel@tonic-gate	    warn "\t\"$myname\"\n";
6320Sstevel@tonic-gate	} else {
6330Sstevel@tonic-gate	    $myname = $$opts{pap_id} if $$opts{pap_id} ne "";
6340Sstevel@tonic-gate	}
6350Sstevel@tonic-gate	$psecret = $$opts{pap_password};
6360Sstevel@tonic-gate    }
6370Sstevel@tonic-gate    if ($$opts{will_do_authentication}) {
6380Sstevel@tonic-gate	if ($chatpath &&
6390Sstevel@tonic-gate	    ($$opts{will_do_authentication} !~ /chap/i ||
6400Sstevel@tonic-gate	     $$opts{will_do_authentication} !~ /pap/i ||
6410Sstevel@tonic-gate	     $csecret eq $psecret)) {
6420Sstevel@tonic-gate	    push(@$pppdargs,
6430Sstevel@tonic-gate		"password " . requote($csecret ? $csecret : $psecret));
6440Sstevel@tonic-gate	    $passopt = 1;
6450Sstevel@tonic-gate	}
6460Sstevel@tonic-gate	push @$pppdargs, "user " . requote($myname);
6470Sstevel@tonic-gate	push(@$pppdargs, "remotename " . requote($peer))
6480Sstevel@tonic-gate	  if $peer && !$$opts{require_authentication};
6490Sstevel@tonic-gate    } else {
6500Sstevel@tonic-gate	$myname = "NeverAuthenticate";
6510Sstevel@tonic-gate    }
6520Sstevel@tonic-gate
6530Sstevel@tonic-gate    push(@$pppdargs, "debug") if $$opts{debug_level} >= 8;
6540Sstevel@tonic-gate    push(@$pppdargs, "kdebug 3") if $$opts{debug_level} >= 9;
6550Sstevel@tonic-gate    local($lcladdr, $remaddr) = ifconf_addr($$ifconfig{$$opts{interface}});
6560Sstevel@tonic-gate    if ($chatpath) {
6570Sstevel@tonic-gate	if ($$opts{debug_level} >= 4) {
6580Sstevel@tonic-gate	    push(@pppdargs, "connect \"/usr/bin/chat -vf $chatpath\"");
6590Sstevel@tonic-gate	} else {
6600Sstevel@tonic-gate	    push(@pppdargs, "connect \"/usr/bin/chat -f $chatpath\"");
6610Sstevel@tonic-gate	}
6620Sstevel@tonic-gate	push(@$pppdargs, "user " . requote($myname));
6630Sstevel@tonic-gate	local($str) = $remaddr;
6640Sstevel@tonic-gate	$str = $$opts{peer_ip_address} if $$opts{peer_ip_address};
6650Sstevel@tonic-gate	push(@$pppdargs, $lcladdr . ":" . $str)
6660Sstevel@tonic-gate	    if !$opt_s && ($lcladdr || $str);
6670Sstevel@tonic-gate    } else {
6680Sstevel@tonic-gate	push(@$pppdargs, "user " . requote($myname))
6690Sstevel@tonic-gate	    if $myname eq "NeverAuthenticate";
6700Sstevel@tonic-gate    }
6710Sstevel@tonic-gate    if ($$opts{interface} && $opt_s) {
6720Sstevel@tonic-gate	if ($$opts{interface} =~ /^ipd[0-9]+$/) {
6730Sstevel@tonic-gate	    push(@$pppdargs, $lcladdr . ":") if $lcladdr;
6740Sstevel@tonic-gate	} elsif ($$opts{interface} =~ /^ipd(|ptp)([0-9]+)$/) {
6750Sstevel@tonic-gate	    push(@pppdargs, "unit " . $2);
6760Sstevel@tonic-gate	} else {
6770Sstevel@tonic-gate	    push(@pppdargs, "plumbed");
6780Sstevel@tonic-gate	}
6790Sstevel@tonic-gate    }
6800Sstevel@tonic-gate
6810Sstevel@tonic-gate# Convert the secrets
6820Sstevel@tonic-gate    if ($chatpath) {
6830Sstevel@tonic-gate	$addsecret = "";
6840Sstevel@tonic-gate    } elsif ($$opts{peer_ip_address}) {
6850Sstevel@tonic-gate	$addsecret = " " . $$opts{peer_ip_address};
6860Sstevel@tonic-gate    } else {
6870Sstevel@tonic-gate	$addsecret = " *";
6880Sstevel@tonic-gate    }
6890Sstevel@tonic-gate    if ($$opts{require_authentication}) {
6900Sstevel@tonic-gate	local($lclname, $secret, $authf);
6910Sstevel@tonic-gate	$lclname = $$opts{will_do_authentication} ? $myname : hostname();
6920Sstevel@tonic-gate	if ($$opts{require_authentication} =~ /chap/) {
6930Sstevel@tonic-gate	    $secret = $$opts{chap_peer_secret};
6940Sstevel@tonic-gate	    $authf = \%chapsecrets;
6950Sstevel@tonic-gate	} else {
6960Sstevel@tonic-gate	    $secret = $$opts{pap_peer_password};
6970Sstevel@tonic-gate	    $authf = \%papsecrets;
6980Sstevel@tonic-gate	}
6990Sstevel@tonic-gate	${$$authf{$peer}}{$lclname} = requote($secret) . $addsecret;
7000Sstevel@tonic-gate    }
7010Sstevel@tonic-gate    if ($$opts{will_do_authentication} && !$passopt) {
7020Sstevel@tonic-gate	${$chapsecrets{$myname}}{$peer} = requote($csecret) if $csecret;
7030Sstevel@tonic-gate	${$papsecrets{$myname}}{$peer} = requote($psecret) if $psecret;
7040Sstevel@tonic-gate    }
7050Sstevel@tonic-gate}
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate# Translate options for a dial-in user.
7080Sstevel@tonic-gatesub translatedialin
7090Sstevel@tonic-gate{
7100Sstevel@tonic-gate    local($peer) = @_;
7110Sstevel@tonic-gate
7120Sstevel@tonic-gate    $optname = $$dialinusers{$peer};
7130Sstevel@tonic-gate    $optname .= "/" if $optname !~ /\/$/;
7140Sstevel@tonic-gate    $optname .= ".ppprc";
7150Sstevel@tonic-gate    if (exists($optfiles{$optname})) {
7160Sstevel@tonic-gate	warn "Home directories of $peer and $optuser{$optname} are the same ($optfiles{$optname}\n";
7170Sstevel@tonic-gate	warn "Ignoring configuration for $peer.\n";
7180Sstevel@tonic-gate	return;
7190Sstevel@tonic-gate    }
7200Sstevel@tonic-gate    $optuser{$optname} = $peer;
7210Sstevel@tonic-gate    $dialinshell{$peer} = "/usr/bin/pppd";
7220Sstevel@tonic-gate    local (@pppdargs);
7230Sstevel@tonic-gate    convert_options(\@pppdargs, $$paths{$peer}, undef, $peer);
7240Sstevel@tonic-gate    push @pppdargs, "nologfd";
7250Sstevel@tonic-gate    $optfiles{$optname} = \@pppdargs;
7260Sstevel@tonic-gate}
7270Sstevel@tonic-gate
7280Sstevel@tonic-gate# Translate ifconfig entries in asppp.cf into either an ifconfig
7290Sstevel@tonic-gate# script for strict translation or a set of per-port IP addresses
7300Sstevel@tonic-gate# for normal translation.  Also translate ipdX interfaces into
7310Sstevel@tonic-gate# Ethernet aliases to make routing daemon happy.
7320Sstevel@tonic-gatesub translateifconfig
7330Sstevel@tonic-gate{
7340Sstevel@tonic-gate    local (@ifconfiglist,$cstr,$etherif,$intf,$ifconf,$addstr,$port);
7350Sstevel@tonic-gate
7360Sstevel@tonic-gate    open IFLIST, "/usr/sbin/ifconfig -au4|" || die "cannot run ifconfig: $!\n";
7370Sstevel@tonic-gate    while (<IFLIST>) {
7380Sstevel@tonic-gate	$etherif = $1 if !$etherif && /^([^:]*).*UP.*BROADCAST/;
7390Sstevel@tonic-gate    }
7400Sstevel@tonic-gate    close IFLIST;
7410Sstevel@tonic-gate    $etherif = $1 if !$etherif && glob("/etc/hostname.*") =~ /[^\.]*.(.*)/;
7420Sstevel@tonic-gate    $etherif = $1 if !$etherif && glob("/etc/dhcp.*") =~ /[^\.]*.(.*)/;
7430Sstevel@tonic-gate    $etherif = "hme0" if !$etherif;
7440Sstevel@tonic-gate
7450Sstevel@tonic-gate    $cstr = "";
7460Sstevel@tonic-gate    foreach $intf (keys %$ifconfig) {
7470Sstevel@tonic-gate	$ifconf = $$ifconfig{$intf};
7480Sstevel@tonic-gate	if ($intf =~ /ipd[0-9]+/) {
7490Sstevel@tonic-gate	    shift @$ifconf;
7500Sstevel@tonic-gate	    $cstr .= "ifconfig $etherif addif @$ifconf\n";
7510Sstevel@tonic-gate	}
7520Sstevel@tonic-gate    }
7530Sstevel@tonic-gate
7540Sstevel@tonic-gate    $ndialin = 0+(keys %$dialin);
7550Sstevel@tonic-gate    $addstr = "";
7560Sstevel@tonic-gate    foreach $intf (keys %downif) {
7570Sstevel@tonic-gate	$ifconf = $downif{$intf};
7580Sstevel@tonic-gate	if ($intf =~ /ipdptp([0-9]+)/ && --$ndialin >= 0) {
7590Sstevel@tonic-gate	    push @ifconfiglist, $ifconf;
7600Sstevel@tonic-gate	    $addstr .= "ifconfig sppp" . $1 . " @$ifconf\n";
7610Sstevel@tonic-gate	}
7620Sstevel@tonic-gate    }
7630Sstevel@tonic-gate    if ($ndialin > 0) {
7640Sstevel@tonic-gate	if (@ifconfiglist) {
7650Sstevel@tonic-gate	    print "Fewer ifconfigs (", $#ifconfiglist+1,
7660Sstevel@tonic-gate	    ") than dial-in lines (", $ndialin+$#ifconfiglist+1, ")\n";
7670Sstevel@tonic-gate	} else {
7680Sstevel@tonic-gate	    print "No ifconfigs for ";
7690Sstevel@tonic-gate	    nof $ndialin, "dial-in port", ".\n";
7700Sstevel@tonic-gate	}
7710Sstevel@tonic-gate    } elsif ($ndialin < 0) {
7720Sstevel@tonic-gate	if (@ifconfiglist) {
7730Sstevel@tonic-gate	    print "Ignoring ", -$ndialin, " of ";
7740Sstevel@tonic-gate	    nof $#ifconfiglist-$ndialin+1, "ifconfig",
7750Sstevel@tonic-gate	    " (too few dial-in ports)\n";
7760Sstevel@tonic-gate	} else {
7770Sstevel@tonic-gate	    print "Ignoring all ";
7780Sstevel@tonic-gate	    nof -$ndialin, "ifconfig line", " (no dial-in ports)\n";
7790Sstevel@tonic-gate	}
7800Sstevel@tonic-gate    }
7810Sstevel@tonic-gate
7820Sstevel@tonic-gate    if ($opt_s) {
7830Sstevel@tonic-gate	# Strict translation uses pre-plumbed interfaces.
7840Sstevel@tonic-gate	$cstr .= $addstr;
7850Sstevel@tonic-gate    } else {
7860Sstevel@tonic-gate	foreach $port (values %$dialin) {
7870Sstevel@tonic-gate	    last if !@ifconfiglist;
7880Sstevel@tonic-gate	    $port =~ s+/dev/++;
7890Sstevel@tonic-gate	    $port =~ s+/+.+g;
7900Sstevel@tonic-gate	    $optfile = $ttyprefix . $port;
7910Sstevel@tonic-gate	    $ifconf = pop @ifconfiglist;
7920Sstevel@tonic-gate	    local ($lcladdr, $remaddr) = ifconf_addr($ifconf);
7930Sstevel@tonic-gate	    next if !defined($lcladdr) || !defined($remaddr);
7940Sstevel@tonic-gate	    local (@pppdargs) = $lcladdr . ":" . $remaddr;
7950Sstevel@tonic-gate	    $optfiles{$optfile} = \@pppdargs;
7960Sstevel@tonic-gate	}
7970Sstevel@tonic-gate    }
7980Sstevel@tonic-gate    $scriptfiles{$pppdir . "ifconfig"} = $cstr if $cstr;
7990Sstevel@tonic-gate}
8000Sstevel@tonic-gate
8010Sstevel@tonic-gate# Attempt to modify global passwd file using sed script stored in
8020Sstevel@tonic-gate# the $sedpasswd temporary file.
8030Sstevel@tonic-gatesub rewrite_passwd
8040Sstevel@tonic-gate{
8050Sstevel@tonic-gate    print "Updating local passwd file (if any).\n" if $opt_v;
8060Sstevel@tonic-gate    if (!sysopen(PWDLCK, $passwdlck, O_WRONLY|O_CREAT, 0600)) {
8070Sstevel@tonic-gate	warn "Unable to lock password file: $!\n";
8080Sstevel@tonic-gate    } else {
8090Sstevel@tonic-gate	$lockstr = pack "ssLLiiLLLL", F_WRLCK, 0, 0, 0, 0, 0, 0, 0, 0, 0;
8100Sstevel@tonic-gate	eval {
8110Sstevel@tonic-gate	    local $SIG{ARLM} = sub {
8120Sstevel@tonic-gate		die "alarm while locking password file\n"
8130Sstevel@tonic-gate	    };
8140Sstevel@tonic-gate	    alarm 15;
8150Sstevel@tonic-gate	    fcntl PWDLCK, F_SETLKW, $lockstr ||
8160Sstevel@tonic-gate	      die "cannot lock password file: $!\n";
8170Sstevel@tonic-gate	    alarm 0;
8180Sstevel@tonic-gate	};
8190Sstevel@tonic-gate	if ($@) {
8200Sstevel@tonic-gate	    warn $@;
8210Sstevel@tonic-gate	} else {
8220Sstevel@tonic-gate	    warn "Password update failed.\n"
8230Sstevel@tonic-gate	      if (system("sed -f $sedpasswd < $passwd > ${passwd}.new") ||
8240Sstevel@tonic-gate		  !(rename "${passwd}.new", $passwd));
8250Sstevel@tonic-gate	}
8260Sstevel@tonic-gate	$lockstr = pack "ssLLiiLLLL", F_UNLCK, 0, 0, 0, 0, 0, 0, 0, 0, 0;
8270Sstevel@tonic-gate	fcntl PWDLCK, F_SETLK, $lockstr;
8280Sstevel@tonic-gate	close PWDLCK;
8290Sstevel@tonic-gate    }
830*11262SRajagopal.Andra@Sun.COM    if (($ypmaster = `/usr/bin/ypwhich 2>/dev/null`) && $? == 0) {
8310Sstevel@tonic-gate	$ypmaster =~ /(.*)\n/;
8320Sstevel@tonic-gate	($ypmaster) = gethostbyname($1);
8330Sstevel@tonic-gate	($thishost) = gethostbyname(hostname);
8340Sstevel@tonic-gate	if ($ypmaster eq $thishost) {
8350Sstevel@tonic-gate	    system("cd /var/yp && make")
8360Sstevel@tonic-gate	      if yesno("Rebuild NIS/YP maps", $opt_y);
8370Sstevel@tonic-gate	} else {
8380Sstevel@tonic-gate	    warn "Not running on NIS/YP master $1; unable to update user shells\n";
8390Sstevel@tonic-gate	    print "Use 'sed -f $sedpasswd <$passwd >${passwd}.new' on the master\n";
8400Sstevel@tonic-gate	    print "and then remake the NIS/YP database.\n";
8410Sstevel@tonic-gate	    undef $sedpasswd;
8420Sstevel@tonic-gate	}
8430Sstevel@tonic-gate    }
8440Sstevel@tonic-gate    unlink $sedpasswd if $sedpasswd;
8450Sstevel@tonic-gate}
8460Sstevel@tonic-gate
8470Sstevel@tonic-gate# Show usage message.
8480Sstevel@tonic-gatesub usage
8490Sstevel@tonic-gate{
8500Sstevel@tonic-gate    print "Usage:\n\n";
8510Sstevel@tonic-gate    print "\t$0 [-rsvy]\n\n";
8520Sstevel@tonic-gate    print "    -n - non-interactive mode.\n";
8530Sstevel@tonic-gate    print "    -r - revert back to aspppd configuration.\n";
8540Sstevel@tonic-gate    print "    -s - use strict translation.\n";
8550Sstevel@tonic-gate    print "    -v - print more detail of the operations performed.\n";
8560Sstevel@tonic-gate    print "    -y - assume 'yes' as default answer where reasonable.\n";
8570Sstevel@tonic-gate    exit;
8580Sstevel@tonic-gate}
8590Sstevel@tonic-gate
8600Sstevel@tonic-gate# Correct an environment variable so that it points at either a useful
8610Sstevel@tonic-gate# executable program, or nothing at all.
8620Sstevel@tonic-gatesub fixpath
8630Sstevel@tonic-gate{
8640Sstevel@tonic-gate    local ($prog, $deflt) = @_;
8650Sstevel@tonic-gate
8660Sstevel@tonic-gate    $prog = $deflt if $prog eq "";
8670Sstevel@tonic-gate    if ($prog !~ /^(\.\/|\/)/) {
8680Sstevel@tonic-gate	local ($_) = $ENV{PATH};
8690Sstevel@tonic-gate	$_ = "/bin:/usr/bin:/sbin:/usr/sbin" if $_ eq "";
8700Sstevel@tonic-gate	split /:/;
8710Sstevel@tonic-gate	foreach (@_) {
8720Sstevel@tonic-gate	    $prog = $_ . "/" . $prog, last if -x $_ . "/" . $prog;
8730Sstevel@tonic-gate	}
8740Sstevel@tonic-gate    }
8750Sstevel@tonic-gate    $prog = "" if !(-x $prog);
8760Sstevel@tonic-gate    $prog;
8770Sstevel@tonic-gate}
8780Sstevel@tonic-gate
8790Sstevel@tonic-gategetopts('nrsvy') || usage;
8800Sstevel@tonic-gate
8810Sstevel@tonic-gatedie "Need permission to modify system files.\n"
8820Sstevel@tonic-gate    unless ($> == 0 || yesno "This script should be run as root.  Continue");
8830Sstevel@tonic-gate
8840Sstevel@tonic-gateif ($opt_r) {
8850Sstevel@tonic-gate    local ($intemp);
8860Sstevel@tonic-gate
8870Sstevel@tonic-gate# Revert to previous configuration.  Just rename the aspppd file back
8880Sstevel@tonic-gate# and undo changes to the passwd file.
8890Sstevel@tonic-gate
8900Sstevel@tonic-gate    die "No saved aspppd configuration exists.\n" unless -f $asmoved;
8910Sstevel@tonic-gate    if (-e $astemp) {
8920Sstevel@tonic-gate	die "$astemp is not a file\n" unless -f $asfile;
8930Sstevel@tonic-gate	unlink $astemp || die "Cannot remove temporary $astemp: $!\n";
8940Sstevel@tonic-gate    }
8950Sstevel@tonic-gate    $intemp = 0;
8960Sstevel@tonic-gate    if (-e $asfile) {
8970Sstevel@tonic-gate	die "$asfile is not a file\n" unless -f $asfile;
8980Sstevel@tonic-gate	die "Not modifying configuration.\n"
8990Sstevel@tonic-gate	    unless yesno "Remove existing $asfile", $opt_y;
9000Sstevel@tonic-gate	rename $asfile, $astemp || die "Cannot rename existing $asfile: $!\n";
9010Sstevel@tonic-gate	$intemp = 1;
9020Sstevel@tonic-gate    }
9030Sstevel@tonic-gate
9040Sstevel@tonic-gate    if (rename $asmoved, $asfile) {
9050Sstevel@tonic-gate	unlink $astemp || warn "$astemp: $!\n" if $intemp;
9060Sstevel@tonic-gate    } else {
9070Sstevel@tonic-gate	$failure = "Cannot rename $asmoved to $asfile: $!\n";
9080Sstevel@tonic-gate	rename $astemp, $asfile ||
9090Sstevel@tonic-gate	    die "$failure\nand cannot recover: $!\n" .
9100Sstevel@tonic-gate		"Saved current asppp.cf in $astemp\n"
9110Sstevel@tonic-gate		    if $intemp;
9120Sstevel@tonic-gate	die $failure;
9130Sstevel@tonic-gate    }
9140Sstevel@tonic-gate
9150Sstevel@tonic-gate    $( = $);
9160Sstevel@tonic-gate    $< = $>;
9170Sstevel@tonic-gate
9180Sstevel@tonic-gate    system($pppdctl, "stop") if -x $pppdctl;
9190Sstevel@tonic-gate    # remove pppd autostart files.
9200Sstevel@tonic-gate    unlink $pppdir . "ifconfig";
9210Sstevel@tonic-gate    unlink $pppdir . "demand";
9220Sstevel@tonic-gate
9230Sstevel@tonic-gate    system($asctl, "start") if -x $asctl;
9240Sstevel@tonic-gate
9250Sstevel@tonic-gate    open SEDFILE, ">$sedpasswd" || die "Cannot write $sedpasswd: $!\n";
9260Sstevel@tonic-gate    local ($escdir) = $pppdir;
9270Sstevel@tonic-gate    $escdir =~ s+/+\\/+g;
9280Sstevel@tonic-gate    print SEDFILE "/${escdir}dial-in\\./s+[^:]*\$+/usr/sbin/aspppls+\n";
9290Sstevel@tonic-gate    print SEDFILE "/\\/usr\\/bin\\/pppd/s+[^:]*\$+/usr/sbin/aspppls+\n";
9300Sstevel@tonic-gate    close SEDFILE;
9310Sstevel@tonic-gate
9320Sstevel@tonic-gate    rewrite_passwd;
9330Sstevel@tonic-gate
9340Sstevel@tonic-gate    exit 0;
9350Sstevel@tonic-gate}
9360Sstevel@tonic-gate
9370Sstevel@tonic-gate$aspppcf = $asfile;
9380Sstevel@tonic-gateif (!(-f $asfile)) {
9390Sstevel@tonic-gate    die "No aspppd configuration exists; nothing to convert.\n"
9400Sstevel@tonic-gate	unless -f $asmoved;
9410Sstevel@tonic-gate    die "No changes made.\n"
9420Sstevel@tonic-gate	unless yesno "Already converted; rerun anyway";
9430Sstevel@tonic-gate    $aspppcf = $asmoved;
9440Sstevel@tonic-gate}
9450Sstevel@tonic-gate
9460Sstevel@tonic-gateprint "This script provides only a suggested translation for your existing aspppd\n";
9470Sstevel@tonic-gateprint "configuration.  You will need to evaluate for yourself whether the translation\n";
9480Sstevel@tonic-gateprint "is appropriate for your operating environment.\n";
9490Sstevel@tonic-gatedie "No changes made.\n"
9500Sstevel@tonic-gate  unless yesno "Continue", 1;
9510Sstevel@tonic-gate
9520Sstevel@tonic-gate# Read in the asppp.cf file first; there's no reason to continue on to
9530Sstevel@tonic-gate# the UUCP files if this file isn't readable or has no paths defined.
9540Sstevel@tonic-gatelocal($ifconfig, $paths) = readaspppcf($aspppcf);
9550Sstevel@tonic-gate
9560Sstevel@tonic-gate# Loop over the ifconfigs and build a list of the down ones.
9570Sstevel@tonic-gateforeach $intf (keys %$ifconfig) {
9580Sstevel@tonic-gate    local(@words) = @{$$ifconfig{$intf}};
9590Sstevel@tonic-gate    while ($word = shift @words) {
9600Sstevel@tonic-gate	shift @words if $ifconfigtakes{$word};
9610Sstevel@tonic-gate	if ($word =~ /^down$/) {
9620Sstevel@tonic-gate	    warn("Why is $intf declared down?\n"), last
9630Sstevel@tonic-gate		if $intf =~ /^ipd[0-9]+$/;
9640Sstevel@tonic-gate	    $downif{$intf} = $$ifconfig{$intf};
9650Sstevel@tonic-gate	    delete $$ifconfig{$intf};
9660Sstevel@tonic-gate	    last;
9670Sstevel@tonic-gate	}
9680Sstevel@tonic-gate    }
9690Sstevel@tonic-gate}
9700Sstevel@tonic-gate
9710Sstevel@tonic-gate# Read /etc/passwd for dial-in users configured for aspppd.
9720Sstevel@tonic-gatelocal($dialinusers) = readpasswd;
9730Sstevel@tonic-gate
9740Sstevel@tonic-gate# Read in existing pppd configuration.  All we really care about
9750Sstevel@tonic-gate# is the setting of the "auth" option.
9760Sstevel@tonic-gateundef $authoption;
9770Sstevel@tonic-gateif (open(OPTIONS,"<" . $options)) {
9780Sstevel@tonic-gate    while (@{$words = uucpline(OPTIONS, $options)}) {
9790Sstevel@tonic-gate	while ($_ = pop @$words) {
9800Sstevel@tonic-gate	    $authoption = $_ if /auth/i;
9810Sstevel@tonic-gate	}
9820Sstevel@tonic-gate    }
9830Sstevel@tonic-gate    close OPTIONS;
9840Sstevel@tonic-gate    $authoption = "unknown" if !defined($authoption);
9850Sstevel@tonic-gate}
9860Sstevel@tonic-gate
9870Sstevel@tonic-gate$dialin_auth = 0;
9880Sstevel@tonic-gateif ($authoption =~ /^auth$/i) {
9890Sstevel@tonic-gate    $dialin_auth = 1;
9900Sstevel@tonic-gate} elsif ($authoption =~ /^noauth$/i) {
9910Sstevel@tonic-gate    $dialin_auth = 2;
9920Sstevel@tonic-gate} elsif (defined($authoption)) {
9930Sstevel@tonic-gate    $dialin_auth = 3;
9940Sstevel@tonic-gate}
9950Sstevel@tonic-gate
9960Sstevel@tonic-gate# Check that there's a path for each dial in user
9970Sstevel@tonic-gateforeach $user (keys %$dialinusers) {
9980Sstevel@tonic-gate    if (!defined($$paths{$user})) {
9990Sstevel@tonic-gate	warn "Dial-in user ", $user,
10000Sstevel@tonic-gate	    " does not have a corresponding dial-in path.\n";
10010Sstevel@tonic-gate	delete $$dialinusers{$user};
10020Sstevel@tonic-gate	next;
10030Sstevel@tonic-gate    }
10040Sstevel@tonic-gate    $intf = ${$$paths{$user}}{"interface"};
10050Sstevel@tonic-gate    if ($intf eq "ipdptp*") {
10060Sstevel@tonic-gate	if (0+keys(%downif) == 0) {
10070Sstevel@tonic-gate	    warn "Dial-in user $path has no available \"down\" interfaces.\n";
10080Sstevel@tonic-gate	    delete $$dialinusers{$user};
10090Sstevel@tonic-gate	    next;
10100Sstevel@tonic-gate	}
10110Sstevel@tonic-gate    } else {
10120Sstevel@tonic-gate	if (!defined($downif{$intf}) && !defined($$ifconfig{$intf})) {
10130Sstevel@tonic-gate	    warn "Dial-in path $user has undefined $intf; deleted.\n";
10140Sstevel@tonic-gate	    delete $$dialinusers{$user};
10150Sstevel@tonic-gate	    next;
10160Sstevel@tonic-gate	}
10170Sstevel@tonic-gate    }
10180Sstevel@tonic-gate    ${$$paths{$user}}{$isdialin} = 1;
10190Sstevel@tonic-gate# 0 - no info (no options file, "noauth" on call)
10200Sstevel@tonic-gate# 1 - all auth ("auth" in options, "noauth" on call)
10210Sstevel@tonic-gate# 2 - all noauth ("noauth" in options)
10220Sstevel@tonic-gate# 3 - mixed; use auth ("noauth" in options, wrapper script for "auth")
10230Sstevel@tonic-gate    if (${$$paths{$user}}{require_authentication}) {
10240Sstevel@tonic-gate	if ($dialin_auth == 2) {
10250Sstevel@tonic-gate	    $dialin_auth = 3;
10260Sstevel@tonic-gate	} elsif ($dialin_auth == 0) {
10270Sstevel@tonic-gate	    $dialin_auth = 1;
10280Sstevel@tonic-gate	}
10290Sstevel@tonic-gate    } else {
10300Sstevel@tonic-gate	if ($dialin_auth == 1) {
10310Sstevel@tonic-gate	    $dialin_auth = 3;
10320Sstevel@tonic-gate	} elsif ($dialin_auth == 0) {
10330Sstevel@tonic-gate	    $dialin_auth = 2;
10340Sstevel@tonic-gate	}
10350Sstevel@tonic-gate    }
10360Sstevel@tonic-gate}
10370Sstevel@tonic-gate
10380Sstevel@tonic-gate# Get lists of usable dial-in and dial-out ports.
10390Sstevel@tonic-gatelocal($dialin,$dialout) = getserialports;
10400Sstevel@tonic-gate
10410Sstevel@tonic-gate# Read and parse the UUCP Sysfiles, Devconfig, and Limits files.
10420Sstevel@tonic-gate# These are keyed with the "service=" string.  The Sysfiles file can
10430Sstevel@tonic-gate# augment or override the list of files read for a given service.
10440Sstevel@tonic-gateprint "Reading UUCP configuration.\n" if $opt_v;
10450Sstevel@tonic-gate@sysfiles = @{${uucpkeyfile($Sysfiles,"service=")}{"ppp"}};
10460Sstevel@tonic-gate@limits = @{${uucpkeyfile($Limits,"service=")}{"ppp"}};
10470Sstevel@tonic-gate%devconfig = %{uucpkeyfile($Devconfig,"service=ppp","device=")};
10480Sstevel@tonic-gate
10490Sstevel@tonic-gate# Now read in the UUCP files corresponding to this service.
10500Sstevel@tonic-gate$systems = uucpposfiles(uucpfiles("systems"));
10510Sstevel@tonic-gate$dialers = uucpposfiles(uucpfiles("dialers"));
10520Sstevel@tonic-gate$dialcodes = uucpposfiles($Dialcodes);
10530Sstevel@tonic-gate$devices = uucpdevices(uucpfiles("devices"));
10540Sstevel@tonic-gate
10550Sstevel@tonic-gate# just to make sure
10560Sstevel@tonic-gate$$dialcodes{""} = ();
10570Sstevel@tonic-gate
10580Sstevel@tonic-gate# Loop over paths.  Dial-out only paths are translated into demand-dial
10590Sstevel@tonic-gate# configurations.  Dial-in only paths are translated into appropriate
10600Sstevel@tonic-gate# log-in entries.
10610Sstevel@tonic-gatelocal (@bidirectional);
10620Sstevel@tonic-gateforeach $peer (keys %$paths) {
10630Sstevel@tonic-gate    if (exists($$systems{$peer})) {
10640Sstevel@tonic-gate	$sline = $$systems{$peer};
10650Sstevel@tonic-gate	if ($$sline[0] eq "Never") {
10660Sstevel@tonic-gate	    if (${$$paths{$peer}}{$isdialin}) {
10670Sstevel@tonic-gate		translatedialin($peer);
10680Sstevel@tonic-gate	    } else {
10690Sstevel@tonic-gate		print "We never call $peer, and he never calls us.\n"
10700Sstevel@tonic-gate		    if $opt_v;
10710Sstevel@tonic-gate	    }
10720Sstevel@tonic-gate	    delete $$paths{$peer};
10730Sstevel@tonic-gate	    next;
10740Sstevel@tonic-gate	}
10750Sstevel@tonic-gate	push @bidirectional, $peer if ${$$paths{$peer}}{$isdialin};
10760Sstevel@tonic-gate	print "Ignoring time restriction on $peer\n"
10770Sstevel@tonic-gate	    if $$sline[0] ne "Any";
10780Sstevel@tonic-gate	$dlist = $$devices{$$sline[1]};
10790Sstevel@tonic-gate	$class = $$sline[2];
10800Sstevel@tonic-gate	$i = 0;
10810Sstevel@tonic-gate	while ($i < @$dlist) {
10820Sstevel@tonic-gate	    local($dev) = $$dlist[$i];
10830Sstevel@tonic-gate	    if ($$dev[1] ne "-") {
10840Sstevel@tonic-gate		print "Ignoring device $$dev[0]; 801-type not supported.\n";
10850Sstevel@tonic-gate		splice @$dlist, $i, 1;
10860Sstevel@tonic-gate		next;
10870Sstevel@tonic-gate	    }
10880Sstevel@tonic-gate	    $i++;
10890Sstevel@tonic-gate
10900Sstevel@tonic-gate	    # Make sure that classes match.
10910Sstevel@tonic-gate	    next if $$dev[2] ne "Any" && $class ne "Any" && $$dev[2] ne $class;
10920Sstevel@tonic-gate	    # Prepend "/dev/" if it's not present in the device name.
10930Sstevel@tonic-gate	    if (exists($$dialout{$$dev[0]})) {
10940Sstevel@tonic-gate		# This just seems odd.
10950Sstevel@tonic-gate		$dname = $$dialout{$$dev[0]};
10960Sstevel@tonic-gate		$dname =~ s+/dev/term/+/dev/cua/+;
10970Sstevel@tonic-gate	    } else {
10980Sstevel@tonic-gate		$dname = ($$dev[0] =~ m+^/+ ? $$dev[0] : ("/dev/" . $$dev[0]));
10990Sstevel@tonic-gate	    }
11000Sstevel@tonic-gate	    # Skip devices that aren't supposed to be used for dial-out.
11010Sstevel@tonic-gate	    next if $dname =~ m+^/dev/term/+;
11020Sstevel@tonic-gate	    next if $dname =~ m+^/dev/tty[a-z]$+;
11030Sstevel@tonic-gate	    # Make sure this is a character device and we have access to it.
11040Sstevel@tonic-gate	    next unless -w $dname && -c $dname;
11050Sstevel@tonic-gate	    warn "Dialer for $$dev[3] is missing.\n"
11060Sstevel@tonic-gate		unless exists($warned{$$dev[3]}) ||
11070Sstevel@tonic-gate		    exists($$dialers{$$dev[3]});
11080Sstevel@tonic-gate	    $warned{$$dev[3]} = 1;
11090Sstevel@tonic-gate
11100Sstevel@tonic-gate	    # Expand keywords from Dialcodes file.  Should have \T or \D.
11110Sstevel@tonic-gate	    $phone = $$sline[3];
11120Sstevel@tonic-gate	    $xphone = ($$dev[4] eq "\\T" && $phone =~ /^([A-Za-z]*)(.*)$/ ?
11130Sstevel@tonic-gate	        "@{$$dialcodes{$1}}" . $2 : $phone);
11140Sstevel@tonic-gate
11150Sstevel@tonic-gate	    # Make a copy of the dialing script.
11160Sstevel@tonic-gate	    local(@dials) = @{$$dialers{$$dev[3]}};
11170Sstevel@tonic-gate
11180Sstevel@tonic-gate	    # Translate dial tone and wait characters from Dialers file.
11190Sstevel@tonic-gate	    $_ = shift @dials;
11200Sstevel@tonic-gate	    s[(.)(.)]{
11210Sstevel@tonic-gate		local($from,$to) = ($1,$2);
11220Sstevel@tonic-gate		$phone =~ s+(^|[^\\])$from+$1$to+gx;
11230Sstevel@tonic-gate		$xphone =~ s+(^|[^\\])$from+$1$to+gx;
11240Sstevel@tonic-gate	    }ge;
11250Sstevel@tonic-gate
11260Sstevel@tonic-gate	    # Translate escapes in dial specification.  Chat has a \T,
11270Sstevel@tonic-gate	    # but uses \U instead of \D.
11280Sstevel@tonic-gate	    local($needt, $needu, $isexpect, @chats) = ("", "", 1);
11290Sstevel@tonic-gate	    foreach $str (@dials) {
11300Sstevel@tonic-gate		push(@chats, "") if $str eq "";
11310Sstevel@tonic-gate		local ($ostr) = "";
11320Sstevel@tonic-gate		if ($isexpect) {
11330Sstevel@tonic-gate		    while ($str =~ s/([^\\]*)\\(.)//) {
11340Sstevel@tonic-gate			local($lead, $_) = ($1, $2);
11350Sstevel@tonic-gate			/[Mm]/ ? ($ostr .= $lead) :
11360Sstevel@tonic-gate			/[Ee]/ ? ($sorrye = 1, $ostr .= $lead) :
11370Sstevel@tonic-gate			($ostr .= $lead . "\\" . $_);
11380Sstevel@tonic-gate		    }
11390Sstevel@tonic-gate		} else {
11400Sstevel@tonic-gate		    while ($str =~ s/([^\\]*)\\(.)//) {
11410Sstevel@tonic-gate			local($lead, $_) = ($1, $2);
11420Sstevel@tonic-gate			/T/ ? ($needt = " -T '$xphone'",
11430Sstevel@tonic-gate			       $ostr .= $lead . "\\T") :
11440Sstevel@tonic-gate			/D/ ? ($needu = " -U '$phone'",
11450Sstevel@tonic-gate			       $ostr .= $lead . "\\U") :
11460Sstevel@tonic-gate			/M/ ? ($ostr .= $lead,
11470Sstevel@tonic-gate			       ($ostr ne "" ? push(@chats, $ostr, "\\c"):0),
11480Sstevel@tonic-gate			       push(@chats, "HANGUP", "OFF"), $ostr = "") :
11490Sstevel@tonic-gate			/m/ ? ($ostr .= $lead,
11500Sstevel@tonic-gate			       ($ostr ne "" ? push(@chats, $ostr, "\\c"):0),
11510Sstevel@tonic-gate			       push(@chats, "HANGUP", "ON"), $ostr = "") :
11520Sstevel@tonic-gate			/[Ee]/ ? ($sorrye = 1, $ostr .= $lead) :
11530Sstevel@tonic-gate			/[dp]/ ? ($ostr .= $lead . "\\" . $_ . "\\" . $_) :
11540Sstevel@tonic-gate			/c/ ? ($str eq "" ? ($ostr .= $lead . "\\c") : 0) :
11550Sstevel@tonic-gate			($ostr .= $lead . "\\" . $_);
11560Sstevel@tonic-gate		    }
11570Sstevel@tonic-gate		}
11580Sstevel@tonic-gate		$ostr .= $str;
11590Sstevel@tonic-gate		push @chats, $ostr if $ostr ne "";
11600Sstevel@tonic-gate		$isexpect = !$isexpect;
11610Sstevel@tonic-gate	    }
11620Sstevel@tonic-gate
11630Sstevel@tonic-gate	    # Pad out dial list if we're missing a "send" string and tack
11640Sstevel@tonic-gate	    # on the chat list from the Systems file.
11650Sstevel@tonic-gate	    if (defined $$sline[4]) {
11660Sstevel@tonic-gate		push @chats, "\\c" if !$isexpect;
11670Sstevel@tonic-gate		push @chats, (splice @$sline, 4);
11680Sstevel@tonic-gate	    }
11690Sstevel@tonic-gate
11700Sstevel@tonic-gate	    $chatfile = $pppdir . "chat.$peer.$$dev[3]";
11710Sstevel@tonic-gate	    if (-e $chatfile) {
11720Sstevel@tonic-gate		print "$chatfile already exists.\n";
11730Sstevel@tonic-gate		if (!yesno("Should it be overwritten",$opt_y)) {
11740Sstevel@tonic-gate		    if (yesno("Should it be used as-is")) {
11750Sstevel@tonic-gate			warn "Using $chatfile as-is; it may not be correct.\n";
11760Sstevel@tonic-gate		    } else {
11770Sstevel@tonic-gate			for ($n = 0; ; $n++) {
11780Sstevel@tonic-gate			    last if !(-e $chatfile . "." . $n);
11790Sstevel@tonic-gate			}
11800Sstevel@tonic-gate			$chatfile .= "." . $n;
11810Sstevel@tonic-gate			print "Using $chatfile instead.\n";
11820Sstevel@tonic-gate			$chatfiles{$chatfile} = \@chats;
11830Sstevel@tonic-gate		    }
11840Sstevel@tonic-gate		} else {
11850Sstevel@tonic-gate		    $overwrite{$chatfile} = 1;
11860Sstevel@tonic-gate		    $chatfiles{$chatfile} = \@chats;
11870Sstevel@tonic-gate		}
11880Sstevel@tonic-gate	    } else {
11890Sstevel@tonic-gate		$chatfiles{$chatfile} = \@chats;
11900Sstevel@tonic-gate	    }
11910Sstevel@tonic-gate
11920Sstevel@tonic-gate	    push @pppdargs, $dname;
11930Sstevel@tonic-gate	    push @pppdargs, $class if $class =~ /^[0-9]+$/;
11940Sstevel@tonic-gate	    push @pppdargs, "demand";
11950Sstevel@tonic-gate	    convert_options(\@pppdargs,$$paths{$peer},
11960Sstevel@tonic-gate		$chatfile . $needt . $needu, undef);
11970Sstevel@tonic-gate
11980Sstevel@tonic-gate	    $optname = $peersdir . $peer;
11990Sstevel@tonic-gate	    if (-e $optname) {
12000Sstevel@tonic-gate		print "$optname already exists.\n";
12010Sstevel@tonic-gate		if (!yesno("Should it be overwritten", $opt_y)) {
12020Sstevel@tonic-gate		    if (yesno("Should it be used as-is")) {
12030Sstevel@tonic-gate			warn "Using $optname as-is; it may not be correct.\n";
12040Sstevel@tonic-gate		    } else {
12050Sstevel@tonic-gate			for ($n = 0; ; $n++) {
12060Sstevel@tonic-gate			    last if !(-e $optname . "." . $n);
12070Sstevel@tonic-gate			}
12080Sstevel@tonic-gate			$optname .= "." . $n;
12090Sstevel@tonic-gate			print "Using $optname instead.\n";
12100Sstevel@tonic-gate			$optfiles{$optname} = \@pppdargs;
12110Sstevel@tonic-gate		    }
12120Sstevel@tonic-gate		} else {
12130Sstevel@tonic-gate		    $overwrite{$optname} = 1;
12140Sstevel@tonic-gate		    $optfiles{$optname} = \@pppdargs;
12150Sstevel@tonic-gate		}
12160Sstevel@tonic-gate	    } else {
12170Sstevel@tonic-gate		$optfiles{$optname} = \@pppdargs;
12180Sstevel@tonic-gate	    }
12190Sstevel@tonic-gate	    $scriptfiles{$pppdir . "demand"} .= "/usr/bin/pppd file $optname\n";
12200Sstevel@tonic-gate	    last;
12210Sstevel@tonic-gate	}
12220Sstevel@tonic-gate    } elsif (${$$paths{$peer}}{$isdialin}) {
12230Sstevel@tonic-gate    	translatedialin($peer);
12240Sstevel@tonic-gate    } else {
12250Sstevel@tonic-gate	warn "Path $peer has no dial-in user nor Systems file entry.\n";
12260Sstevel@tonic-gate	delete $$paths{$peer};
12270Sstevel@tonic-gate    }
12280Sstevel@tonic-gate}
12290Sstevel@tonic-gate
12300Sstevel@tonic-gatewarn "Chat cannot do echo checking; requests for this removed.\n" if $sorrye;
12310Sstevel@tonic-gate
12320Sstevel@tonic-gateif (@bidirectional) {
12330Sstevel@tonic-gate    print "\nWarning:  The following paths are bidirectional:\n";
12340Sstevel@tonic-gate    print "\t@bidirectional\n\n";
12350Sstevel@tonic-gate    print "Bidirectional paths (with entries in both Systems and passwd) do not translate\n";
12360Sstevel@tonic-gate    print "into Solaris PPP 4.0 semantics in an exact manner.  The dial-out portion will\n";
12370Sstevel@tonic-gate    print "use the designated interface, but the dial-in portion will use any available\n";
12380Sstevel@tonic-gate    print "interface.\n";
12390Sstevel@tonic-gate    while ($peer = pop @bidirectional) {
12400Sstevel@tonic-gate	delete $ {$$paths{$peer}}{interface};
12410Sstevel@tonic-gate	translatedialin($peer);
12420Sstevel@tonic-gate    }
12430Sstevel@tonic-gate}
12440Sstevel@tonic-gate
12450Sstevel@tonic-gatetranslateifconfig;
12460Sstevel@tonic-gate
12470Sstevel@tonic-gate# Create an /etc/ppp/options if we need to.
12480Sstevel@tonic-gateif (!defined($authoption) && $dialin_auth > 0) {
12490Sstevel@tonic-gate    local (@pppdopts);
12500Sstevel@tonic-gate    push @pppdopts, "lock";
12510Sstevel@tonic-gate    push @pppdopts, "auth" if $dialin_auth == 1;
12520Sstevel@tonic-gate    push @pppdopts, "noauth" if $dialin_auth > 1;
12530Sstevel@tonic-gate    $optfiles{$options} = \@pppdopts;
12540Sstevel@tonic-gate}
12550Sstevel@tonic-gate# Translate option files to plain text.
12560Sstevel@tonic-gateforeach $file (keys %optfiles) {
12570Sstevel@tonic-gate    local ($opts) = $optfiles{$file};
12580Sstevel@tonic-gate    local ($cstr) = "";
12590Sstevel@tonic-gate    $cstr .= shift(@$opts) . "\n" while @$opts;
12600Sstevel@tonic-gate    $optfiles{$file} = $cstr;
12610Sstevel@tonic-gate}
12620Sstevel@tonic-gate# Change "auth" to "noauth" or add "noauth" to /etc/ppp/options.
12630Sstevel@tonic-gateif (defined($authoption) && $authoption ne "noauth" && $dialin_auth == 3) {
12640Sstevel@tonic-gate    local(@triplet, $cstr);
12650Sstevel@tonic-gate    if ($authoption eq "unknown") {
12660Sstevel@tonic-gate	warn "Adding 'noauth' to $options\n";
12670Sstevel@tonic-gate    } else {
12680Sstevel@tonic-gate	warn "Changing 'auth' in $options to 'noauth'\n";
12690Sstevel@tonic-gate    }
12700Sstevel@tonic-gate    open(OPTIONS,"<" . $options) || die "$options disappeared: $!\n";
12710Sstevel@tonic-gate    while (@{$words = uucpline(OPTIONS, $options, \@triplet)}) {
12720Sstevel@tonic-gate	$cstr .= $triplet[0];
12730Sstevel@tonic-gate	if (grep(/auth/, @$words)) {
12740Sstevel@tonic-gate	    local(@newwords) = map { $_ = "noauth" if /auth/; $_ } @$words;
12750Sstevel@tonic-gate	    $cstr .= "@newwords";
12760Sstevel@tonic-gate	} else {
12770Sstevel@tonic-gate	    $cstr .= $triplet[1];
12780Sstevel@tonic-gate	}
12790Sstevel@tonic-gate	while (pop @$words) {
12800Sstevel@tonic-gate	    $authoption = $_ if /auth/i;
12810Sstevel@tonic-gate	}
12820Sstevel@tonic-gate	$cstr .= $triplet[2];
12830Sstevel@tonic-gate    }
12840Sstevel@tonic-gate    $cstr .= $triplet[0] . $triplet[2];
12850Sstevel@tonic-gate    close OPTIONS;
12860Sstevel@tonic-gate    $cstr .= "\n" if $cstr !~ /\n$/;
12870Sstevel@tonic-gate    $cstr .= "noauth\n" if $authoption eq "unknown";
12880Sstevel@tonic-gate    $optfiles{$options} = $cstr;
12890Sstevel@tonic-gate}
12900Sstevel@tonic-gate
12910Sstevel@tonic-gate# Create a sed script to fix the users' shell paths.
12920Sstevel@tonic-gateif (0+(keys %dialinshell) != 0) {
12930Sstevel@tonic-gate    $cstr = "";
12940Sstevel@tonic-gate    foreach $peer (keys %dialinshell) {
12950Sstevel@tonic-gate	$cstr .= "/^$peer:/s+[^:]*/aspppls\$+$dialinshell{$peer}+\n";
12960Sstevel@tonic-gate    }
12970Sstevel@tonic-gate    $scriptfiles{$sedpasswd} = $cstr;
12980Sstevel@tonic-gate}
12990Sstevel@tonic-gate
13000Sstevel@tonic-gateprint "\nPreparing to write out translated configuration:\n";
13010Sstevel@tonic-gate
13020Sstevel@tonic-gate# Enumerate the files we'll write.
13030Sstevel@tonic-gate$nfiles = 0;
13040Sstevel@tonic-gateif (0+(keys %chatfiles) != 0) {
13050Sstevel@tonic-gate    print "    ";
13060Sstevel@tonic-gate    nof 0+(keys %chatfiles), "chat file", ":\n";
13070Sstevel@tonic-gate    foreach $file (keys %chatfiles) {
13080Sstevel@tonic-gate	$nfiles++;
13090Sstevel@tonic-gate	print "\t$nfiles.  $file\n";
13100Sstevel@tonic-gate	local ($chats) = $chatfiles{$file};
13110Sstevel@tonic-gate	local ($cstr) = "";
13120Sstevel@tonic-gate	while (@$chats) {
13130Sstevel@tonic-gate	    $cstr .= requote(shift(@$chats));
13140Sstevel@tonic-gate	    $cstr .= " " . requote(shift(@$chats)) if @$chats;
13150Sstevel@tonic-gate	    $cstr .= "\n";
13160Sstevel@tonic-gate	}
13170Sstevel@tonic-gate	local (@filerec) = ( $file, $cstr );
13180Sstevel@tonic-gate	push @allfiles, \@filerec;
13190Sstevel@tonic-gate    }
13200Sstevel@tonic-gate}
13210Sstevel@tonic-gateif (0+(keys %optfiles) != 0) {
13220Sstevel@tonic-gate    print "    ";
13230Sstevel@tonic-gate    nof 0+(keys %optfiles), "option file", ":\n";
13240Sstevel@tonic-gate    foreach $file (keys %optfiles) {
13250Sstevel@tonic-gate	$nfiles++;
13260Sstevel@tonic-gate	print "\t$nfiles.  $file\n";
13270Sstevel@tonic-gate	local (@filerec) = ( $file, $optfiles{$file} );
13280Sstevel@tonic-gate	push @allfiles, \@filerec;
13290Sstevel@tonic-gate    }
13300Sstevel@tonic-gate}
13310Sstevel@tonic-gateif (0+(keys %scriptfiles) != 0) {
13320Sstevel@tonic-gate    print "    ";
13330Sstevel@tonic-gate    nof 0+(keys %scriptfiles), "script file", ":\n";
13340Sstevel@tonic-gate    foreach $file (keys %scriptfiles) {
13350Sstevel@tonic-gate	$nfiles++;
13360Sstevel@tonic-gate	print "\t$nfiles.  $file\n";
13370Sstevel@tonic-gate	local (@filerec) = ( $file, $scriptfiles{$file} );
13380Sstevel@tonic-gate	push @allfiles, \@filerec;
13390Sstevel@tonic-gate    }
13400Sstevel@tonic-gate}
13410Sstevel@tonic-gate
13420Sstevel@tonic-gate# Merge new secrets needed with existing ones, if any.
13430Sstevel@tonic-gatesub merge_secrets
13440Sstevel@tonic-gate{
13450Sstevel@tonic-gate    local ($addsecrets, $fname) = @_;
13460Sstevel@tonic-gate    local ($file, $cstr, @triplet, $newsecret);
13470Sstevel@tonic-gate
13480Sstevel@tonic-gate    $nfiles++;
13490Sstevel@tonic-gate    $file = $pppdir . $fname;
13500Sstevel@tonic-gate    print "\t$nfiles.  $file\n";
13510Sstevel@tonic-gate    if (open(SECRETS, '<' . $pppdir . $fname)) {
13520Sstevel@tonic-gate	while (@{$words = uucpline(SECRETS, $pppdir . $fname, \@triplet)}) {
13530Sstevel@tonic-gate	    $cstr .= $triplet[0];
13540Sstevel@tonic-gate	    $newsecret = $ {$$addsecrets{$$words[0]}}{$$words[1]};
13550Sstevel@tonic-gate	    if (defined $newsecret) {
13560Sstevel@tonic-gate		$cstr .= requote($$words[0]) . " " . requote($$words[1]) .
13570Sstevel@tonic-gate		  " " . $newsecret;
13580Sstevel@tonic-gate		delete $ {$$addsecrets{$$words[0]}}{$$words[1]};
13590Sstevel@tonic-gate	    } else {
13600Sstevel@tonic-gate		$cstr .= $triplet[1];
13610Sstevel@tonic-gate	    }
13620Sstevel@tonic-gate	    $cstr .= $triplet[2];
13630Sstevel@tonic-gate	}
13640Sstevel@tonic-gate	close SECRETS;
13650Sstevel@tonic-gate	$cstr .= $triplet[0] . $triplet[2];
13660Sstevel@tonic-gate    }
13670Sstevel@tonic-gate    foreach $key1 (keys (%$addsecrets)) {
13680Sstevel@tonic-gate	foreach $key2 (keys (%{$$addsecrets{$key1}})) {
13690Sstevel@tonic-gate	    $cstr .= requote($key1) . " " . requote($key2) . " " .
13700Sstevel@tonic-gate	      $ {$$addsecrets{$key1}}{$key2} . "\n";
13710Sstevel@tonic-gate	}
13720Sstevel@tonic-gate    }
13730Sstevel@tonic-gate    local (@filerec) = ( $file, $cstr );
13740Sstevel@tonic-gate    push @allfiles, \@filerec;
13750Sstevel@tonic-gate}
13760Sstevel@tonic-gate
13770Sstevel@tonic-gate$nchap = 0+(keys %chapsecrets) != 0;
13780Sstevel@tonic-gate$npap = 0+(keys %papsecrets) != 0;
13790Sstevel@tonic-gateif ($nchap != 0 || $npap != 0) {
13800Sstevel@tonic-gate    print "    ";
13810Sstevel@tonic-gate    nof $nchap + $npap, "secrets file", ":\n";
13820Sstevel@tonic-gate    merge_secrets(\%chapsecrets, "chap-secrets") if $nchap != 0;
13830Sstevel@tonic-gate    merge_secrets(\%papsecrets, "pap-secrets") if $npap != 0;
13840Sstevel@tonic-gate}
13850Sstevel@tonic-gate
13860Sstevel@tonic-gatedie "Nothing to write back; I'm done.\n" if $nfiles == 0;
13870Sstevel@tonic-gate
13880Sstevel@tonic-gate$PAGER = fixpath($ENV{PAGER}, "/usr/bin/less");
13890Sstevel@tonic-gate$EDITOR = fixpath($ENV{EDITOR}, "/usr/bin/vi");
13900Sstevel@tonic-gate$SHELL = fixpath($ENV{SHELL}, "/usr/bin/ksh");
13910Sstevel@tonic-gate
13920Sstevel@tonic-gateEND {
13930Sstevel@tonic-gate    if ($tempname) {
13940Sstevel@tonic-gate	unlink($tempname) or
13950Sstevel@tonic-gate	    die "Cannot remove temporary file $tempname: $!\n";
13960Sstevel@tonic-gate    }
13970Sstevel@tonic-gate}
13980Sstevel@tonic-gate
13990Sstevel@tonic-gatesub show_file_options
14000Sstevel@tonic-gate{
14010Sstevel@tonic-gate    print "\nEnter option number:\n";
14020Sstevel@tonic-gate    print "\t1 - view contents of file on standard output\n";
14030Sstevel@tonic-gate    print "\t2 - view contents of file using $PAGER\n" if $PAGER ne "";
14040Sstevel@tonic-gate    print "\t3 - edit contents of file using $EDITOR\n" if $EDITOR ne "";
14050Sstevel@tonic-gate    print "\t4 - delete/undelete file from list\n";
14060Sstevel@tonic-gate    print "\t5 - rename file in list\n";
14070Sstevel@tonic-gate    print "\t6 - show file list again\n";
14080Sstevel@tonic-gate    print "\t7 - escape to shell (or \"!cmd\")\n";
14090Sstevel@tonic-gate    print "\t8 - abort without saving anything\n";
14100Sstevel@tonic-gate    print "\t9 - save all files and exit (default)\n";
14110Sstevel@tonic-gate}
14120Sstevel@tonic-gate
14130Sstevel@tonic-gate# If interactive, then allow user to view and modify converted data.
14140Sstevel@tonic-gateif ((-t STDIN) && (-t STDOUT) && !$opt_n) {
14150Sstevel@tonic-gate    show_file_options();
14160Sstevel@tonic-gate    while (1) {
14170Sstevel@tonic-gate	print "Option:  ";
14180Sstevel@tonic-gate	chomp($ans = <STDIN>);
14190Sstevel@tonic-gate	if ($ans eq "?" || $ans =~ /^h/i) {
14200Sstevel@tonic-gate	    show_file_options();
14210Sstevel@tonic-gate	    next;
14220Sstevel@tonic-gate	}
14230Sstevel@tonic-gate	if ($ans eq "") {
14240Sstevel@tonic-gate	    last if yesno "Saving all files.  Are you sure";
14250Sstevel@tonic-gate	    next;
14260Sstevel@tonic-gate	}
14270Sstevel@tonic-gate	last if $ans == 9;
14280Sstevel@tonic-gate	print("Aborted.\n"), exit if $ans == 8;
14290Sstevel@tonic-gate	if ($ans =~ /^!/ || $ans == 7) {
14300Sstevel@tonic-gate	    if ($ans =~ /^!(.+)/) {
14310Sstevel@tonic-gate		system($1);
14320Sstevel@tonic-gate	    } else {
14330Sstevel@tonic-gate		print("Interactive shell access not permitted here.\n"), next
14340Sstevel@tonic-gate		    if $< != $>;
14350Sstevel@tonic-gate		system($SHELL);
14360Sstevel@tonic-gate	    }
14370Sstevel@tonic-gate	} elsif ($ans == 6) {
14380Sstevel@tonic-gate	    for ($i = 0; $i < $nfiles; $i++) {
14390Sstevel@tonic-gate		print "\t", $i+1, ".  $allfiles[$i][0]",
14400Sstevel@tonic-gate		    ($deleted[$i] ? "   (deleted)" : ""), "\n";
14410Sstevel@tonic-gate	    }
14420Sstevel@tonic-gate	} elsif ($ans > 0 && $ans < 6) {
14430Sstevel@tonic-gate	    $fnum = 0;
14440Sstevel@tonic-gate	    if ($nfiles > 1) {
14450Sstevel@tonic-gate		print "File number (1 .. $nfiles):  ";
14460Sstevel@tonic-gate		chomp($fnum = <STDIN>);
14470Sstevel@tonic-gate		if ($fnum < 1 || $fnum > $nfiles) {
14480Sstevel@tonic-gate		    print "Unknown file (must be 1 to $nfiles).\n";
14490Sstevel@tonic-gate		    next;
14500Sstevel@tonic-gate		}
14510Sstevel@tonic-gate		$fnum--;
14520Sstevel@tonic-gate	    }
14530Sstevel@tonic-gate	    if ($ans == 5) {
14540Sstevel@tonic-gate		print "Current name is $allfiles[$fnum][0]\n";
14550Sstevel@tonic-gate		print "New name:  ";
14560Sstevel@tonic-gate		chomp($fname = <STDIN>);
14570Sstevel@tonic-gate		print("Unchanged\n"), next if $fname eq "";
14580Sstevel@tonic-gate		$allfiles[$fnum][0] = $fname;
14590Sstevel@tonic-gate	    }
14600Sstevel@tonic-gate	    if ($deleted[$fnum]) {
14610Sstevel@tonic-gate		if (yesno("File " . $fnum+1 .
14620Sstevel@tonic-gate		   " ($allfiles[$fnum][0]) is deleted; undelete",1)) {
14630Sstevel@tonic-gate		    undef $deleted[$fnum];
14640Sstevel@tonic-gate		}
14650Sstevel@tonic-gate		next;
14660Sstevel@tonic-gate	    }
14670Sstevel@tonic-gate	    if ($ans == 1) {
14680Sstevel@tonic-gate		print $allfiles[$fnum][1];
14690Sstevel@tonic-gate	    } elsif ($ans == 2 && $PAGER ne "") {
14700Sstevel@tonic-gate		$i = 0;
14710Sstevel@tonic-gate		do {
14720Sstevel@tonic-gate		    if (++$i > 5) {
14730Sstevel@tonic-gate			warn "Unable to open temporary file: $!";
14740Sstevel@tonic-gate			undef $tempname;
14750Sstevel@tonic-gate			last;
14760Sstevel@tonic-gate		    }
14770Sstevel@tonic-gate		    $tempname = tmpnam();
14780Sstevel@tonic-gate		} until sysopen(FH, $tempname, O_RDWR|O_CREAT|O_EXCL);
14790Sstevel@tonic-gate		next if !$tempname;
14800Sstevel@tonic-gate		print FH $allfiles[$fnum][1];
14810Sstevel@tonic-gate		close FH;
14820Sstevel@tonic-gate		system($PAGER, $tempname);
14830Sstevel@tonic-gate		unlink($tempname) ||
14840Sstevel@tonic-gate		    warn "Trouble removing temporary file: $!";
14850Sstevel@tonic-gate		undef $tempname;
14860Sstevel@tonic-gate	    } elsif ($ans == 3 && $EDITOR ne "") {
14870Sstevel@tonic-gate		$i = 0;
14880Sstevel@tonic-gate		do {
14890Sstevel@tonic-gate		    if (++$i > 5) {
14900Sstevel@tonic-gate			warn "Unable to open temporary file: $!";
14910Sstevel@tonic-gate			undef $tempname;
14920Sstevel@tonic-gate			last;
14930Sstevel@tonic-gate		    }
14940Sstevel@tonic-gate		    $tempname = tmpnam();
14950Sstevel@tonic-gate		} until sysopen(FH, $tempname, O_RDWR|O_CREAT|O_EXCL);
14960Sstevel@tonic-gate		next if !$tempname;
14970Sstevel@tonic-gate		chown $<, $(, $tempname;
14980Sstevel@tonic-gate		print FH $allfiles[$fnum][1];
14990Sstevel@tonic-gate		close FH;
15000Sstevel@tonic-gate		$i = system($EDITOR, $tempname);
15010Sstevel@tonic-gate		if ($i == 0) {
15020Sstevel@tonic-gate		    if (open FH, "<" . $tempname) {
15030Sstevel@tonic-gate			read FH, $allfiles[$fnum][1], (-s $tempname);
15040Sstevel@tonic-gate			close FH;
15050Sstevel@tonic-gate		    }
15060Sstevel@tonic-gate		} else {
15070Sstevel@tonic-gate		    print "Editor dropped core.\n" if $? & 128;
15080Sstevel@tonic-gate		    print "Editor terminated on signal ", $? & 127, "\n"
15090Sstevel@tonic-gate			if $? & 127;
15100Sstevel@tonic-gate		    print "Editor returned error ", $? >> 8, "\n"
15110Sstevel@tonic-gate			if $? >> 8;
15120Sstevel@tonic-gate		}
15130Sstevel@tonic-gate		unlink($tempname) ||
15140Sstevel@tonic-gate		    warn "Trouble removing temporary file: $!";
15150Sstevel@tonic-gate		undef $tempname;
15160Sstevel@tonic-gate	    } elsif ($ans == 4) {
15170Sstevel@tonic-gate		$deleted[$fnum] = 1;
15180Sstevel@tonic-gate	    }
15190Sstevel@tonic-gate	}
15200Sstevel@tonic-gate    }
15210Sstevel@tonic-gate}
15220Sstevel@tonic-gate
15230Sstevel@tonic-gateprint "\n";
15240Sstevel@tonic-gate
15250Sstevel@tonic-gate# Interactive part is over.  Become real.
15260Sstevel@tonic-gate$( = $);
15270Sstevel@tonic-gate$< = $>;
15280Sstevel@tonic-gate
15290Sstevel@tonic-gateprint "Stopping aspppd\n" if $opt_v;
15300Sstevel@tonic-gatesystem($asctl, "stop") if -x $asctl;
15310Sstevel@tonic-gate
15320Sstevel@tonic-gateprint "Saving all files\n" if $opt_v;
15330Sstevel@tonic-gatefor ($i = 0; $i < $nfiles; $i++) {
15340Sstevel@tonic-gate    $filerec = $allfiles[$i];
15350Sstevel@tonic-gate    if ($deleted[$i]) {
15360Sstevel@tonic-gate	delete $scriptfiles{$$filerec[0]};
15370Sstevel@tonic-gate	next;
15380Sstevel@tonic-gate    }
15390Sstevel@tonic-gate    print "Saving $$filerec[0]\n" if $opt_v;
15400Sstevel@tonic-gate    $$filerec[0] =~ m+(.*)/+;
15410Sstevel@tonic-gate    if ($1 eq "") {
15420Sstevel@tonic-gate	# this is ok; just a top level file
15430Sstevel@tonic-gate    } elsif (!(-d $1)) {
15440Sstevel@tonic-gate	local ($exdir) = $1;
15450Sstevel@tonic-gate	while ($exdir && !(-d $exdir)) {
15460Sstevel@tonic-gate	    $exdir =~ m+(.*)/+;
15470Sstevel@tonic-gate	    $exdir = $1;
15480Sstevel@tonic-gate	}
15490Sstevel@tonic-gate	if ($exdir) {
15500Sstevel@tonic-gate	    local ($dir) = $1;
15510Sstevel@tonic-gate	    $dir =~ m+$exdir/([^/]*)(.*)+;
15520Sstevel@tonic-gate	    local ($tomake, $rest) = ($1, $2);
15530Sstevel@tonic-gate	    mkdir $exdir . "/" . $tomake, 0775;
15540Sstevel@tonic-gate	    if ($! == ENOSYS) {
15550Sstevel@tonic-gate		warn "Unable to make directory $exdir/$tomake; automount point.\n";
15560Sstevel@tonic-gate		next;
15570Sstevel@tonic-gate	    }
15580Sstevel@tonic-gate	    if ($! != 0) {
15590Sstevel@tonic-gate		warn "Unable to make directory $exdir/$tomake: $!\n";
15600Sstevel@tonic-gate		next;
15610Sstevel@tonic-gate	    }
15620Sstevel@tonic-gate	    if (system("mkdir", "-p", $dir) != 0) {
15630Sstevel@tonic-gate		warn "Failed to make $dir\n";
15640Sstevel@tonic-gate		next;
15650Sstevel@tonic-gate	    }
15660Sstevel@tonic-gate	} else {
15670Sstevel@tonic-gate	    warn "$1 doesn't appear to have a useful path.\n";
15680Sstevel@tonic-gate	    next;
15690Sstevel@tonic-gate	}
15700Sstevel@tonic-gate    }
15710Sstevel@tonic-gate    undef $fileerr;
15720Sstevel@tonic-gate    local ($fname) = $$filerec[0];
15730Sstevel@tonic-gate    if (-e $fname && !$overwrite{$chatfile}) {
15740Sstevel@tonic-gate	print "$fname already exists.\n"
15750Sstevel@tonic-gate	  if (-t STDIN) && (-t STDOUT) && !$opt_n;
15760Sstevel@tonic-gate	if (!yesno("Should it be overwritten",$opt_y)) {
15770Sstevel@tonic-gate	    warn "Using $fname as-is; it may not be correct.\n";
15780Sstevel@tonic-gate	    next;
15790Sstevel@tonic-gate	}
15800Sstevel@tonic-gate    }
15810Sstevel@tonic-gate    if (sysopen(OUTFILE, $$filerec[0], O_WRONLY|O_CREAT|O_TRUNC, 0600)) {
15820Sstevel@tonic-gate	print OUTFILE $$filerec[1] || ($fileerr = $!);
15830Sstevel@tonic-gate	close OUTFILE || ($fileerr = $!);
15840Sstevel@tonic-gate    } else {
15850Sstevel@tonic-gate	$fileerr = $!;
15860Sstevel@tonic-gate    }
15870Sstevel@tonic-gate    warn "Unable to write $$filerec[0]: $fileerr\n" if $fileerr;
15880Sstevel@tonic-gate}
15890Sstevel@tonic-gate
15900Sstevel@tonic-gatelocal(@scripts) = keys %scriptfiles;
15910Sstevel@tonic-gateif (@scripts) {
15920Sstevel@tonic-gate    print "Making scripts executable\n" if $opt_v;
15930Sstevel@tonic-gate    system("chmod", "u+x", @scripts);
15940Sstevel@tonic-gate}
15950Sstevel@tonic-gate
15960Sstevel@tonic-gaterewrite_passwd if exists($scriptfiles{$sedpasswd});
15970Sstevel@tonic-gate
15980Sstevel@tonic-gate# clean up after a previous translation.
15990Sstevel@tonic-gateunlink $pppdir . "ifconfig" if !$scriptfiles{$pppdir . "ifconfig"};
16000Sstevel@tonic-gateunlink $pppdir . "demand" if !$scriptfiles{$pppdir . "demand"};
16010Sstevel@tonic-gate
16020Sstevel@tonic-gate(rename($asfile, $asmoved) || warn "Cannot move $asfile: $!\n")
16030Sstevel@tonic-gate  if $aspppcf ne $astemp;
16040Sstevel@tonic-gate
16050Sstevel@tonic-gatesystem($pppdctl, "start") if -x $pppdctl;
16060Sstevel@tonic-gate
16070Sstevel@tonic-gate# use Dumpvalue;
16080Sstevel@tonic-gate# my $dumper = new Dumpvalue;
16090Sstevel@tonic-gate# $dumper->set(globPrint => 1);
16100Sstevel@tonic-gate# $dumper->dumpValue($ifconfig);
1611