asppp2pppd revision 7c478bd95313f5f23a4c958a745db2134aa03244
# This utility translates from aspppd configuration to Solaris PPP 4.0
# (or ANU ppp-2.4.0; aka pppd). It can also revert to previous aspppd
# configuration (discarding the pppd configuration), but does not
# translate new configuration files into old.
#
# This script provides only a suggested translation for your existing
# aspppd configuration. You will need to evaluate for yourself
# whether the translation is appropriate for your operating
# environment.
# Copyright (c) 2000 by Sun Microsystems, Inc.
# All rights reserved.
#
#ident "%Z%%M% %I% %E% SMI"
# Steps in translation:
# - read list of configured serial ports from pmadm
# - read in UUCP configuration files
# - create translated configuration
# - write files back out
# Known issues:
# - translation with point-to-multipoint is incomplete
use Fcntl;
# Secure the path if we're running under RBAC.
if $< != $>;
# General path names that can be configured.
local($rootetc) = "/etc/";
local($sedpasswd) = "/tmp/sed-passwd";
# Fake asppp keyword used to keep track of dial-in paths.
local($isdialin) = "-is-dial-in";
# Limits and Sysfiles are keyed on "service=".
# Devconfig is keyed on "service=" and "device=".
# Dialcodes, Dialers, Systems, and Devices are single keyword files.
# Devices alone may have multiple entries for a given key.
# Internal data structures
"msgtime=-1" );
# List of keywords for which ifconfig takes an additional parameter.
local($ifconfigtakes) = (
addif => 1,
removeif => 1,
auth_algs => 1,
encr_algs => 1,
encr_auth_algs => 1,
broadcast => 1,
destination => 1,
index => 1,
metric => 1,
modinsert => 1,
modremove => 1,
mtu => 1,
netmask => 1,
set => 1,
subnet => 1,
tdst => 1,
tsrc => 1,
wait => 1,
# These are keywords, but do not take an additional parameter.
ether => 0,
inet => 0,
inet6 => 0,
arp => 0,
-arp => 0,
modlist => 0,
plumb => 0,
unplumb => 0,
private => 0,
-private => 0,
nud => 0,
-nud => 0,
trailers => 0,
-trailers => 0,
up => 0,
down => 0,
xmit => 0,
-xmit => 0,
dhcp => 0,
primary => 0,
drop => 0,
extend => 0,
inform => 0,
ping => 0,
release => 0,
start => 0,
status => 0
);
# print number of something in English.
sub nof
{
}
# ask a yes or no question.
sub yesno
{
while (1) {
print "Please enter 'y' or 'n'.\n";
}
}
# Put quotes around a string, if necessary.
# The tests here aren't perfect -- they think that \\\' isn't an
# escaped quote -- but they're good enough.
sub requote
{
local($_) = @_;
if (/^$/) {
"\"\"";
} elsif (/^'/ || /[^\\]'/ || /\\\\'/) {
# Has unescaped quotes; must use " or redo quoting.
if (/^"/ || /[^\\]"/ || /\\\\"/) {
# Both kinds of quotes; redo the quoting.
s/^"/\\"/;
s/([^\\]|\\\\)"/$1\\"/g;
}
"\"" . $_ . "\"";
} elsif (/^"/ || /[^\\]"/ || /\\\\"/) {
"'" . $_ . "'";
} elsif (/\s/) {
"\"" . $_ . "\"";
} else {
$_;
}
}
# Get a single line from a UUCP configuration file and return as a
# reference to an array of words. Removes comments and escapes.
# (This is a modified version of the standard Perl shellwords function
# that understands C escape sequences and continuation lines.)
# Optionally returns lead-in, source text, and trailing component
# for editing.
sub uucpline
{
local($input, $file, $triplet) = @_;
local(@words,$snippet,$field,$havefield,$cont,@triparray,$maytrail);
$cont = "";
$maytrail = "";
while (<$input>) {
# remove leading whitespace
if (s/^(\s+)//) {
$maytrail .= $1;
}
if ($cont eq "") {
if (s/^(\#(.|\n)*)$//) {
$triparray[0] .= $maytrail . $1;
$maytrail = "";
next;
}
if (s/^(\\?\n?)$//) {
$triparray[0] .= $maytrail . $1;
$maytrail = "";
next;
}
$triparray[0] .= $maytrail;
$maytrail = "";
}
$snippet = $_;
if (s/^(([^\#\\]|\\.)*)\\\n$//) {
$maytrail .= $snippet;
$cont .= $1;
next;
}
if (/^(([^\\\#]|\\[^\#])*)(\#?(.|\n)*)$/) {
$_ = $maytrail . $1;
$maytrail = $3;
if (s/((\s|\n)*)$//) {
$maytrail = $1 . $maytrail;
}
$triparray[1] = $_;
}
$_ = $cont . $snippet;
$cont = "";
s/\n$//;
while ($_ ne '') {
for (;;) {
if (s/^#.*//) {
last;
} elsif (s/^"(([^"\\]|\\.)*)"//) {
$snippet = $1;
} elsif (s/^"//) {
warn "Unmatched double quote in $file: \"$_\n";
} elsif (s/^'(([^'\\]|\\.)*)'//) {
$snippet = $1;
} elsif (s/^'//) {
warn "Unmatched single quote in $file: '$_\n";
} elsif (s/^\\s//) {
# \s works in chat, but not in the pppd option files
$snippet = " ";
} elsif (s/^(\\.)//) {
$snippet = $1;
} elsif (s/^([^\s\\'"#]+)//) {
$snippet = $1;
} else {
s/^\s+//;
last;
}
$havefield = 1;
}
$havefield = 0;
}
last;
}
$triparray[2] .= $maytrail;
\@words;
}
# Given a logical UUCP file name, return a list of all of the files
# that should be read.
sub uucpfiles
{
}
last;
}
}
@flist;
}
# Given a file name and some key words, parse the contents of the file
# and return a reference to a hash constructed from this. All keys
# except the last must match exactly. The last is used to order the
# hash.
sub uucpkeyfile
{
$flag = 1;
$flag = 0;
$i = 0;
$flag = 1;
last;
}
$i++;
}
}
$byservice{$1} = $words;
last;
}
}
}
\%byservice;
}
# This reads a UUCP file that is keyed on the first token on each
# line. Duplicates are not permitted; the first encountered is used
# and the rest are silently discarded. A hash indexed on the first
# token and containing an array of tokens in each bucket is returned.
# Used for Dialcodes, Dialers, and Systems.
sub uucpposfiles
{
next;
}
next if $keyeddata{$keyval};
$keyeddata{$keyval} = $words;
}
}
\%keyeddata;
}
# This reads a UUCP file that is keyed on the first token on each line
# and may have duplicate entries. Each entry of the hash contains an
# array. Each entry of that array points to an array of tokens
# representing one parsed line. Used for the Devices file.
sub uucpdevices
{
next;
}
push @{$keyeddata{$keyval}}, $words;
}
}
\%keyeddata;
}
# For a path defined in asppp.cf, copy over defaults, validate the
# required options, and save in the hash to be returned.
sub savepath
{
}
}
# Parse through asppp.cf. Unlike the UUCP files, lines don't matter
# here. The parsing is modal, with "path" introducing a PPP session
# description and "defaults" reverting back to global definitions.
sub readaspppcf
{
chap_name => 1,
chap_peer_secret => 1,
chap_peer_name => 1,
chap_secret => 1,
debug_level => 1,
default_route => 0,
ifconfig => -1,
inactivity_timeout => 1,
interface => 1,
# sic; aspppd is seriously confused! ACCM isn't in IPCP.
ipcp_async_map => 1,
ipcp_compression => 1,
lcp_compression => 1,
lcp_mru => 1,
negotiate_address => 1,
pap_id => 1,
pap_password => 1,
pap_peer_id => 1,
pap_peer_password => 1,
peer_ip_address => 1,
peer_system_name => 1,
require_authentication => 2,
version => 1,
);
$defaults{inactivity_timeout} = 120;
shift @$words; # discard 'ifconfig' keyword
next;
}
$_ = $word;
next ;
}
next;
}
if ++$errors > 5;
next;
}
last if $i == -1;
$$options{$_} = 1 if $i == 0;
next if $i == 0;
if ($i == 2) {
} else {
}
}
}
}
}
if $prevword;
}
}
# the default shell is aspppls. Each hash entry contains the user's
# home directory path.
sub readpasswd
{
}
if $opt_v;
\%users;
}
# Parse through pmadm output to find enabled serial ports.
# Field 9 has 'I' (modem dial-out only or initialize only), 'b'
# (bidirectional) or is blank (modem dial-in only or terminal-hardwired).
# For that latter case, field 18 (software-carrier) has 'y'.
# Field 3 has 'x' if disabled.
sub getserialports
{
split /:/;
if ($_[3] !~ /x/) {
}
}
}
# Convert an ifconfig statement into a local and remote address pair.
sub ifconf_addr
{
shift @$ifconf; # lose the interface name
$narg = shift @$ifconf if $ifconfigtakes{$arg};
}
}
}
}
# Convert a hash of aspppd options into an array of pppd options. The
# third argument ($chatpath) is undef for dial-in or a path to the
# chat script file otherwise.
sub convert_options
{
# Do the pppd option conversions.
if $$opts{inactivity_timeout} != 0;
if $$opts{ipcp_async_map};
$peer = $$opts{chap_peer_name};
} else {
$peer = $$opts{pap_peer_id};
}
# mixed authentication; must use wrapper script.
$dialinshell{$user} = $sfile;
}
}
if $$opts{negotiate_address};
$csecret = $$opts{chap_secret};
}
} else {
}
$psecret = $$opts{pap_password};
}
if ($chatpath &&
($$opts{will_do_authentication} !~ /chap/i ||
$$opts{will_do_authentication} !~ /pap/i ||
$passopt = 1;
}
if $peer && !$$opts{require_authentication};
} else {
}
} else {
}
$str = $$opts{peer_ip_address} if $$opts{peer_ip_address};
} else {
}
} else {
}
}
# Convert the secrets
} else {
}
$secret = $$opts{chap_peer_secret};
$authf = \%chapsecrets;
} else {
$authf = \%papsecrets;
}
}
}
}
# Translate options for a dial-in user.
sub translatedialin
{
$optname = $$dialinusers{$peer};
return;
}
}
# Translate ifconfig entries in asppp.cf into either an ifconfig
# script for strict translation or a set of per-port IP addresses
# for normal translation. Also translate ipdX interfaces into
# Ethernet aliases to make routing daemon happy.
{
}
shift @$ifconf;
}
}
}
}
} else {
print "No ifconfigs for ";
}
" (too few dial-in ports)\n";
} else {
print "Ignoring all ";
}
}
# Strict translation uses pre-plumbed interfaces.
} else {
last if !@ifconfiglist;
$port =~ s+/+.+g;
$optfile = $ttyprefix . $port;
$ifconf = pop @ifconfiglist;
}
}
}
# Attempt to modify global passwd file using sed script stored in
# the $sedpasswd temporary file.
sub rewrite_passwd
{
} else {
eval {
die "alarm while locking password file\n"
};
alarm 15;
alarm 0;
};
if ($@) {
warn $@;
} else {
warn "Password update failed.\n"
}
}
}
} else {
}
} else {
}
} else {
}
} else {
}
}
}
# Show usage message.
sub usage
{
print "Usage:\n\n";
print "\t$0 [-rsvy]\n\n";
print " -n - non-interactive mode.\n";
print " -r - revert back to aspppd configuration.\n";
print " -s - use strict translation.\n";
print " -v - print more detail of the operations performed.\n";
print " -y - assume 'yes' as default answer where reasonable.\n";
exit;
}
# Correct an environment variable so that it points at either a useful
# executable program, or nothing at all.
sub fixpath
{
split /:/;
foreach (@_) {
}
}
}
die "Need permission to modify system files.\n"
# Revert to previous configuration. Just rename the aspppd file back
# and undo changes to the passwd file.
}
$intemp = 0;
die "Not modifying configuration.\n"
$intemp = 1;
}
} else {
if $intemp;
}
$( = $);
$< = $>;
# remove pppd autostart files.
$escdir =~ s+/+\\/+g;
exit 0;
}
die "No aspppd configuration exists; nothing to convert.\n"
die "No changes made.\n"
}
print "This script provides only a suggested translation for your existing aspppd\n";
print "configuration. You will need to evaluate for yourself whether the translation\n";
print "is appropriate for your operating environment.\n";
die "No changes made.\n"
# Read in the asppp.cf file first; there's no reason to continue on to
# the UUCP files if this file isn't readable or has no paths defined.
# Loop over the ifconfigs and build a list of the down ones.
shift @words if $ifconfigtakes{$word};
last;
}
}
}
# Read in existing pppd configuration. All we really care about
# is the setting of the "auth" option.
$authoption = $_ if /auth/i;
}
}
}
$dialin_auth = 0;
$dialin_auth = 1;
$dialin_auth = 2;
$dialin_auth = 3;
}
# Check that there's a path for each dial in user
" does not have a corresponding dial-in path.\n";
next;
}
next;
}
} else {
next;
}
}
# 0 - no info (no options file, "noauth" on call)
# 1 - all auth ("auth" in options, "noauth" on call)
# 2 - all noauth ("noauth" in options)
# 3 - mixed; use auth ("noauth" in options, wrapper script for "auth")
$dialin_auth = 3;
$dialin_auth = 1;
}
} else {
$dialin_auth = 3;
$dialin_auth = 2;
}
}
}
# Get lists of usable dial-in and dial-out ports.
# Read and parse the UUCP Sysfiles, Devconfig, and Limits files.
# These are keyed with the "service=" string. The Sysfiles file can
# augment or override the list of files read for a given service.
# Now read in the UUCP files corresponding to this service.
# just to make sure
# Loop over paths. Dial-out only paths are translated into demand-dial
# configurations. Dial-in only paths are translated into appropriate
# log-in entries.
} else {
print "We never call $peer, and he never calls us.\n"
if $opt_v;
}
next;
}
print "Ignoring time restriction on $peer\n"
$i = 0;
next;
}
$i++;
# Make sure that classes match.
# Prepend "/dev/" if it's not present in the device name.
# This just seems odd.
} else {
}
# Skip devices that aren't supposed to be used for dial-out.
# Make sure this is a character device and we have access to it.
# Expand keywords from Dialcodes file. Should have \T or \D.
# Make a copy of the dialing script.
# Translate dial tone and wait characters from Dialers file.
$_ = shift @dials;
s[(.)(.)]{
}ge;
# Translate escapes in dial specification. Chat has a \T,
# but uses \U instead of \D.
}
} else {
}
}
}
# Pad out dial list if we're missing a "send" string and tack
# on the chat list from the Systems file.
}
} else {
for ($n = 0; ; $n++) {
}
$chatfiles{$chatfile} = \@chats;
}
} else {
$overwrite{$chatfile} = 1;
$chatfiles{$chatfile} = \@chats;
}
} else {
$chatfiles{$chatfile} = \@chats;
}
} else {
for ($n = 0; ; $n++) {
}
}
} else {
$overwrite{$optname} = 1;
}
} else {
}
last;
}
} else {
}
}
print "\nWarning: The following paths are bidirectional:\n";
print "\t@bidirectional\n\n";
print "Bidirectional paths (with entries in both Systems and passwd) do not translate\n";
print "into Solaris PPP 4.0 semantics in an exact manner. The dial-out portion will\n";
print "use the designated interface, but the dial-in portion will use any available\n";
print "interface.\n";
}
}
}
# Translate option files to plain text.
}
} else {
}
} else {
}
$authoption = $_ if /auth/i;
}
}
}
# Create a sed script to fix the users' shell paths.
}
}
print "\nPreparing to write out translated configuration:\n";
# Enumerate the files we'll write.
$nfiles = 0;
print " ";
$nfiles++;
}
}
}
print " ";
$nfiles++;
}
}
print " ";
$nfiles++;
}
}
# Merge new secrets needed with existing ones, if any.
sub merge_secrets
{
$nfiles++;
$newsecret = $ {$$addsecrets{$$words[0]}}{$$words[1]};
delete $ {$$addsecrets{$$words[0]}}{$$words[1]};
} else {
}
}
}
}
}
}
print " ";
}
END {
}
}
{
print "\nEnter option number:\n";
print "\t1 - view contents of file on standard output\n";
print "\t5 - rename file in list\n";
print "\t6 - show file list again\n";
print "\t7 - escape to shell (or \"!cmd\")\n";
print "\t8 - abort without saving anything\n";
print "\t9 - save all files and exit (default)\n";
}
# If interactive, then allow user to view and modify converted data.
while (1) {
print "Option: ";
next;
}
next;
}
} else {
print("Interactive shell access not permitted here.\n"), next
if $< != $>;
}
}
$fnum = 0;
next;
}
$fnum--;
}
print "New name: ";
}
}
next;
}
$i = 0;
do {
if (++$i > 5) {
last;
}
next if !$tempname;
$i = 0;
do {
if (++$i > 5) {
last;
}
next if !$tempname;
if ($i == 0) {
}
} else {
print "Editor dropped core.\n" if $? & 128;
print "Editor terminated on signal ", $? & 127, "\n"
if $? & 127;
print "Editor returned error ", $? >> 8, "\n"
if $? >> 8;
}
}
}
}
}
print "\n";
# Interactive part is over. Become real.
$( = $);
$< = $>;
delete $scriptfiles{$$filerec[0]};
next;
}
# this is ok; just a top level file
} elsif (!(-d $1)) {
$exdir = $1;
}
next;
}
if ($! != 0) {
next;
}
next;
}
} else {
next;
}
}
print "$fname already exists.\n"
next;
}
}
} else {
$fileerr = $!;
}
}
}
# clean up after a previous translation.
# use Dumpvalue;
# my $dumper = new Dumpvalue;
# $dumper->set(globPrint => 1);
# $dumper->dumpValue($ifconfig);