--- a/sap-vpn.pl Fri Nov 14 23:07:00 2008 +0000
+++ b/sap-vpn.pl Tue Jan 06 07:27:55 2009 +0000
@@ -11,13 +11,15 @@
use Pod::Usage;
use File::Basename;
use English qw(-no_match_vars);
+use lib ".";
+
+my $use_lwp = -f "lwp";
($EUID, $UID) = ($UID, $EUID); # release ROOT, doesn't harm, if not suid
($0) = ($0 =~ /([.\/\w-]+)/); # untaint $0
use constant ME => basename $0;
-
delete @ENV{ grep /PATH/, keys %ENV };
$ENV{PATH} = "/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/sbin:/bin";
@@ -63,6 +65,7 @@
sub verbose(@) { print STDERR @_ if $opt_verbose }
sub debug(@) { warn @_ if $opt_debug }
+sub ohshit(@) { die ME . ": ", @_ }
sub do_kill($);
MAIN: {
@@ -91,34 +94,34 @@
$opt_verbose += $opt_debug;
- untaint($opt_linkname) or die ME . ": linkname didn't pass verification\n";
+ untaint($opt_linkname) or ohshit "linkname didn't pass verification\n";
untaint($opt_script)
- or die ME . ": script name didn't pass verification\n"
+ or ohshit "script name didn't pass verification\n"
if $opt_script;
map { untaint } @ppp_opts;
- die ME . ": need to run with root permissions!\n"
+ ohshit "need to run with root permissions!\n"
if not $EUID == 0 || $UID == 0;
exit do_kill($opt_linkname) if $opt_kill;
untaint($opt_user)
- or die ME . ": username didn't pass verification\n";
+ or ohshit "username didn't pass verification\n";
if (not defined $opt_passcode) {
chomp(my $settings = qx{stty "-g"});
- open(IN, "/dev/tty") or die ME . ": Can't open /dev/tty: $!\n";
+ open(IN, "/dev/tty") or ohshit "Can't open /dev/tty: $!\n";
print "Passcode for $opt_user: ";
system stty => "-echo";
chomp($opt_passcode = <IN>);
system stty => $settings;
print "\n";
}
- untaint($opt_passcode) or die ME . ": passcode didn't pass verification\n";
+ untaint($opt_passcode) or ohshit "passcode didn't pass verification\n";
pod2usage(-verbose => 0, -exitval => 0) if not defined $opt_passcode;
-x $opt_script
- or die ME . ": Script $opt_script is not executable: $!\n"
+ or ohshit "Script $opt_script is not executable: $!\n"
if defined $opt_script;
push @ppp_opts, $opt_debug ? qw(nodetach debug dump) : qw(nolog updetach);
@@ -138,16 +141,42 @@
# Make initial request to get client_data
verbose "% initial request\n";
- $request =
- "GET /my.logon.php3?check=1 HTTP/1.0\r\n"
- . "Content-Type: application/x-www-form-urlencoded\r\n"
- . "Connection: close\r\n" . "\r\n";
+
+ my $client_data;
+ my $ua;
+ my $cookies;
+
+ if (!$use_lwp) {
+ $request =
+ "GET /my.logon.php3?check=1 HTTP/1.0\r\n"
+ . "Content-Type: application/x-www-form-urlencoded\r\n"
+ . "Connection: close\r\n" . "\r\n";
+
+ $response = qx(echo "${request}" | ${openssl} 2>/dev/null)
+ or ohshit "Invalid Host specified or not reachable: $opt_host\n";
- $response = qx(echo "${request}" | ${openssl} 2>/dev/null)
- or die ME . ": Invalid Host specified or not reachable: $opt_host\n";
+ }
+ else {
+ use LWP::UserAgent;
+ use HTTP::Request::Common;
+ use HTTP::Status;
+ use HTTP::Cookies;
+ #use LWP::Debug qw(+);
+ $cookies = new HTTP::Cookies;
+ $ua = new LWP::UserAgent;
+ $ua->agent("");
+ $ua->env_proxy;
+ $ua->cookie_jar($cookies);
+ $response = $ua->get("https://$opt_host:443/my.logon.php3?check=1");
+
+ ohshit "initial failed with http code @{[$response->message]}\n"
+ unless $response->is_success;
+
+ $response = $response->as_string;
+ }
$response =~ s/<INPUT type="hidden" name="client_data" value="(.*)">/$1/;
- my $client_data = $1;
+ $client_data = $1;
###
### STEP 2 :: Log in to FirePass.
@@ -159,27 +188,49 @@
# browser will make many more requests than this to complete the log in
# sequence, but all that is required is this POST with our credentails. This
# may fail if the FirePass has End-Point Security Policies configured.
- $request =
+
+ if (!$use_lwp) {
+ $request =
"check=1&username=${opt_user}&password=${opt_passcode}&mrhlogonform=1&client_data=${client_data}";
- $request =
- "POST /my.activation.php3 HTTP/1.0\r\n"
- . "Host: ${opt_host}\r\n"
- . "Content-Type: application/x-www-form-urlencoded\r\n"
- . "Content-Length: "
- . length($request) . "\r\n"
- . "Connection: close\r\n" . "\r\n"
- . "${request}\r\n";
+ $request =
+ "POST /my.activation.php3 HTTP/1.0\r\n"
+ . "Host: ${opt_host}\r\n"
+ . "Content-Type: application/x-www-form-urlencoded\r\n"
+ . "Content-Length: "
+ . length($request) . "\r\n"
+ . "Connection: close\r\n" . "\r\n"
+ . "${request}\r\n";
- $response = qx(echo "${request}" | ${openssl} 2>/dev/null);
+ $response = qx(echo "${request}" | ${openssl} 2>/dev/null);
+ }
+ else {
+ $response = $ua->post(
+ "https://$opt_host:443/my.activation.php3",
+ check => 1,
+ username => $opt_user,
+ password => $opt_passcode,
+ mrhlogonform => 1,
+ client_data => $client_data
+ );
+
+ ohshit "login failed with http code @{[$response->message]}\n"
+ unless $response->is_success;
+
+ $response = $response->as_string;
+ }
# We can then parse the response for the MRHSession Cookie, which contains our
# SessionID. In this example, we print out the SessionID in order to verify
# that our log in attempt worked.
+
$response =~ /MRHSession=(\w+);/;
$sessionid = $1;
verbose "% session id ${sessionid}\n";
+ $cookies->set_cookie(0, MRHSession => $sessionid, "/", $opt_host, 443, 1, 0, 10, 0, {});
+ #warn $cookies->as_string;
+
###
### STEP 3 :: Create the SSL VPN tunnel.
###
@@ -189,17 +240,33 @@
# Now that we are authenticated and have a valid SessionID, we must request
# specific pages/objects in order to initiate a SSL VPN tunnel. Before we do
# this, let's determine the resource locator for our Network Access favorite.
- $request = "GET /vdesk/vpn/index.php3?outform=xml HTTP/1.0\r\n"
- . "Cookie: MRHSession=${sessionid}\r\n" . "\r\n";
- $response = qx(echo "${request}" | ${openssl} 2>/dev/null);
+ #if (!$use_lwp) {
+ if (1) {
+ $request = "GET /vdesk/vpn/index.php3?outform=xml HTTP/1.0\r\n"
+ . "Cookie: MRHSession=${sessionid}\r\n" . "\r\n";
+ $response = qx(echo "${request}" | ${openssl} 2>/dev/null);
+ }
+ else {
+ $response = $ua->get("https://$opt_host:443/vdesk/vpn/index.php3?outform=xml");
+
+ ohshit "creating tunnel failed with http code @{[$response->message]}\n"
+ unless $response->is_success;
+
+ $response = $response->as_string;
+ }
# The response is XML, so we can safely grab what we are looking for using some
# regular expression magic. Same with the SessionID, we're printing out the
# final value to make sure we're on the right track.
+ open(X, ">response.out") or die;
+ print X $response;
+
$response =~ /${opt_name}[^\n]+\n[^Z]+Z=\d+,(\d+)/;
$favorite = $1;
verbose "% favorite ${favorite}\n";
+ exit;
+
# We're all set! Let's visit the necessary pages/objects to notify FirePass
# that we wish to open a SSL VPN tunnel.
foreach my $uri ("/vdesk/", "/vdesk/vpn/connect.php3?Z=0,${favorite}",) {
@@ -217,7 +284,7 @@
{
my $pid = fork(); # this way we've better control
- die ME . ": can't fork: $!\n" if not defined $pid;
+ ohshit "can't fork: $!\n" if not defined $pid;
if ($pid == 0) {
$EUID = $UID; # get ROOT, the pppd want's to see
@@ -228,11 +295,11 @@
connect => ${request},
linkname => $opt_linkname,
qw(noauth crtscts passive noproxyarp local)
- ) or die ME . ": Can't exec: $!\n";
+ ) or ohshit "Can't exec: $!\n";
}
wait;
- die ME . ": pppd didn't return sucessfully (rc: @{[$? >> 8]})\n" if $?;
+ ohshit "pppd didn't return sucessfully (rc: @{[$? >> 8]})\n" if $?;
}
# now executing the script
@@ -241,13 +308,13 @@
if (defined $opt_script and not $opt_debug) {
my $pid = fork();
- die ME . ": Can't fork: $!\n" if not defined $pid;
+ ohshit "Can't fork: $!\n" if not defined $pid;
if ($pid == 0) { # child
if ($UID != $EUID) {
my ($owner, $group) = (stat $opt_script)[ 4, 5 ];
- die ME . ": can't stat $opt_script\n" if not defined $owner;
+ ohshit "can't stat $opt_script\n" if not defined $owner;
$UID = $EUID = $owner;
$GID = $EGID = $group;
@@ -257,7 +324,7 @@
"% executing script $opt_script with uid $UID and gid $GID\n";
exec $opt_script
- or die ME . ": Can't exec $opt_script: $!\n";
+ or ohshit "Can't exec $opt_script: $!\n";
}
$pid = wait;
verbose "% script returned $?\n";
@@ -275,7 +342,7 @@
sub do_kill($) {
my $linkname = shift;
open((my $fh), $_ = "/var/run/ppp-$linkname.pid")
- or die ME . ": Can't open the link file \"$_\": $!\n";
+ or ohshit "Can't open the link file \"$_\": $!\n";
my $pid = <$fh>;
my $iface = <$fh>;
@@ -284,10 +351,10 @@
# become root doesn't seem to be necessary, as long as our
# real uid is 0
- kill 15, $pid or die ME . ": Can't kill pid $pid: $!\n";
+ kill 15, $pid or ohshit "Can't kill pid $pid: $!\n";
waitpid $pid, 0 != -1
- or die ME . ": was not able to wait for the ppp process: $!\n";
+ or ohshit "was not able to wait for the ppp process: $!\n";
verbose "% process killed, rc: "
. ($? >> 8)
@@ -308,8 +375,8 @@
sap-vpn [-l|--linkname <link name>] -k|--kill
- sap-vpn [-h|--help]
- sap-vpn [-m|--man]
+ sap-vpn -h|--help
+ sap-vpn -m|--man
=head1 DESCRIPTION