1#!/usr/local/bin/perl
2##
3## @PACKAGE@ @VERSION@
4@copyright@
5#
6#  RANCID - Really Awesome New Cisco confIg Differ
7#
8#  plogin - poly-login; use router.db files and rancid.{base,types}.conf
9#	    configurations to determine which login script to execute.
10#
11use 5.0010;
12use strict 'vars';
13use warnings;
14no warnings 'uninitialized';
15use Exporter;
16use Getopt::Long;
17#  use Getopt::Long qw(:config no_ignore_case bundling);
18Getopt::Long::Configure ("bundling", "no_ignore_case");
19our($opt_d, $opt_S, $opt_V, $opt_autoenable, $opt_noenable, $opt_c, @opt_E,
20    $opt_e, $opt_f, $opt_h, $opt_i, $opt_m, $opt_M, $opt_p, $opt_r, $opt_s,
21    $opt_t, $opt_u, $opt_v, $opt_w, $opt_x, $opt_y, $opt_z);
22GetOptions('d' => \$opt_d, 'S' => \$opt_S, 'V' => \$opt_V,
23	'autoenable' => \$opt_autoenable, 'noenable' => \$opt_noenable,
24	'c=s' => \$opt_c, "E=s@" => \@opt_E, 'e=s' => \$opt_e, 'f=s' => \$opt_f,
25	'h' => \$opt_h, 'i' => \$opt_i, 'm' => \$opt_m, 'M' => \$opt_M,
26	'p=s' => \$opt_p, 'r=s' => \$opt_r, 's=s' => \$opt_s, 't=s' => \$opt_t,
27	'u=s' => \$opt_u, 'v=s' => \$opt_v, 'w=s' => \$opt_w, 'x=s' => \$opt_x,
28	'y=s' => \$opt_y, 'z=s' => \$opt_z);
29my($BASEDIR, $LIST_OF_GROUPS, $cmd, $i, $j, @routers);
30BEGIN {
31    push(@INC, "@pkglibdir@");
32}
33use rancid;
34our @ISA = qw(Exporter rancid);
35
36sub usage()
37{
38    print STDERR "plogin [-dSV] [-autoenable] [-noenable] [-c command] [-Evar=x] [-e enable-password] [-f cloginrc-file] [-p user-password] [-r passphrase] [-s script-file] [-t timeout] [-u username] [-v vty-password] [-w enable-username] [-x command-file] [-y ssh_cypher_type] [-z device_type] router [router...]\n";
39    exit 64;
40}
41
42# make OUTPUT unbuffered if debugging
43if ($opt_d) { $| = 1; }
44
45if ($opt_h) {
46    usage();
47}
48
49# option handling initialization
50if ($opt_V) {
51    print "plogin: @PACKAGE@ @VERSION@\n";
52    # do not exit; exec the script with -V and it will exit
53}
54$cmd .= " -d" if ($opt_d);
55$cmd .= " -i" if ($opt_i);
56$cmd .= " -m" if ($opt_m);
57$cmd .= " -M" if ($opt_M);
58$cmd .= " -S" if ($opt_S);
59$cmd .= " -V" if ($opt_V);
60$cmd .= " -autoenable" if ($opt_autoenable);
61$cmd .= " -noenable" if ($opt_noenable);
62$cmd .= " -c '$opt_c'" if (length($opt_c));
63foreach $i (@opt_E) {
64    $cmd .= " -E$i";
65}
66$cmd .= " -e '$opt_e'" if (length($opt_e));
67$cmd .= " -f '$opt_f'" if (length($opt_f));
68$cmd .= " -p '$opt_p'" if (length($opt_p));
69$cmd .= " -r '$opt_r'" if (length($opt_r));
70$cmd .= " -s '$opt_s'" if (length($opt_s));
71$cmd .= " -t $opt_s" if (length($opt_t));
72$cmd .= " -u '$opt_u'" if (length($opt_u));
73$cmd .= " -v '$opt_v'" if (length($opt_v));
74$cmd .= " -w '$opt_w'" if (length($opt_w));
75$cmd .= " -x '$opt_x'" if (length($opt_x));
76$cmd .= " -y '$opt_y'" if (length($opt_y));
77$devtype = $opt_z;
78foreach $i (@ARGV) {
79    $cmd .= " $i";
80    push(@routers, $i);
81}
82
83# what is the device type, supplied or looked-up
84if ($opt_z) {
85    $devtype = $opt_z;
86} else {
87    # Look in router.dbs for device type.
88    # read rancid.conf for BASEDIR and LIST_OF_GROUPS?
89    my($ENVFILE) = "@sysconfdir@/rancid.conf";
90    open(INPUT, "< $ENVFILE") || die "Could not open $ENVFILE: $!";
91    close(INPUT);
92    open(INPUT,
93	 "sh -c \'. $ENVFILE; echo \"BASEDIR=\$BASEDIR\"; echo \"LIST_OF_GROUPS=\$LIST_OF_GROUPS\"\' |") ||
94	 die "Could not open $ENVFILE: $!";
95    while (<INPUT>) {
96        chomp;
97	s/#.$//;
98	s/^\s+//;
99        my($varname, $value) = split('=');
100	if ($varname eq "BASEDIR") {
101	    $BASEDIR = $value;
102	}
103	if ($varname eq "LIST_OF_GROUPS") {
104	    $LIST_OF_GROUPS = $value;
105	    $LIST_OF_GROUPS =~ s/^\s+//;
106	    $LIST_OF_GROUPS =~ s/\s+$//;
107	}
108    }
109    close(INPUT);
110
111    # read each router.db for the routername and thus the devtype
112    foreach $i (split(/\s+/, $LIST_OF_GROUPS)) {
113	if (!open(INPUT, "< $BASEDIR/$i/router.db")) {
114	    warn "Could not open $BASEDIR/$i/router.db: $!";
115	    next;
116	}
117	while (<INPUT>) {
118	    chomp;
119	    s/#.$//;
120	    s/^\s+//;
121            my($router, $type, $state) = split('\;');
122	    foreach $j (@routers) {
123		if ($router eq $j) {
124		    $devtype = $type;
125		    close(INPUT);
126		    goto FOUND;
127		}
128	    }
129	}
130	close(INPUT);
131    }
132}
133
134FOUND:
135if (length($devtype) < 1) {
136    die "Couldn't find device type by hostname in router.dbs\n";
137}
138
139# load device type spec, build @commandtable and load modules
140if (loadtype($devtype)) {
141    die "Couldn't load device type spec for $rancid::devtype\n";
142}
143if (! defined($lscript)) {
144    die "login script not defined for device type $rancid::devtype\n";
145}
146exec($lscript . " $cmd") ||
147printf(STDERR "exec($lscript) failed router manufacturer $devtype: $!\n");
148exit(-1);
149