31 # name of our Network Access favorite, and our username/pasword. All of these |
32 # name of our Network Access favorite, and our username/pasword. All of these |
32 # can be passed as arguments, if desired. |
33 # can be passed as arguments, if desired. |
33 |
34 |
34 my $user; |
35 my $user; |
35 my $passcode; |
36 my $passcode; |
36 my $host = 'connectwdf.sap.com'; |
37 my $opt_host = 'connectwdf.sap.com'; |
37 my $name = 'SAP Network Access'; |
38 my $opt_name = 'SAP Network Access'; |
38 my $opt_help = 0; |
39 my $opt_help = 0; |
39 my $opt_man = 0; |
40 my $opt_man = 0; |
40 my $debug; |
41 my @ppp_opts = (); |
41 my $ppp_opts = []; |
42 my $opt_debug; |
42 my $opt_script; |
43 my $opt_script; |
43 |
44 |
44 MAIN: { |
45 MAIN: { |
45 |
46 |
46 GetOptions( |
47 GetOptions( |
47 "u|user=s" => \$user, |
48 "u|user=s" => \$user, |
48 "p|passcode=s" => \$passcode, |
49 "p|passcode=s" => \$passcode, |
49 "H|host=s" => \$host, |
50 "H|host=s" => \$opt_host, |
50 "n|favorite=s" => \$name, |
51 "n|favorite=s" => \$opt_name, |
51 "d|debug" => \$debug, |
52 "d|debug" => \$opt_debug, |
52 "o|opts=s" => $ppp_opts, |
53 "o|opts=s" => \@ppp_opts, |
53 "h|help" => \$opt_help, |
54 "h|help" => \$opt_help, |
54 "m|man" => \$opt_man, |
55 "m|man" => \$opt_man, |
55 "s|script" => \$opt_script, |
56 "s|script" => \$opt_script, |
56 ) or pod2usage(); |
57 ) or pod2usage(); |
57 |
58 |
58 die ME . ": need to run with root permissions!\n" if $> != 0; |
59 die ME . ": need to run with root permissions!\n" if $> != 0; |
59 |
60 |
60 pod2usage(-verbose => 1, -exitval => 0) if $opt_help; |
61 pod2usage(-verbose => 1, -exitval => 0) if $opt_help; |
61 pod2usage(-verbose => 2, -exitval => 0) if $opt_man; |
62 pod2usage(-verbose => 2, -exitval => 0) if $opt_man; |
62 pod2usage(-verbose => 0, -exitval => 0) if not defined $user; |
63 pod2usage(-verbose => 0, -exitval => 0) if not defined $user; |
63 |
64 |
64 if (not defined $passcode) { |
65 if (not defined $passcode) { |
65 chomp(my $settings = qx{stty "-g"}); |
66 chomp(my $settings = qx{stty "-g"}); |
66 open(IN, "/dev/tty") or die "Can't open /dev/tty: $!\n"; |
67 open(IN, "/dev/tty") or die ME . ": Can't open /dev/tty: $!\n"; |
67 print "Passcode: "; |
68 print "Passcode: "; |
68 system stty => "-echo"; |
69 system stty => "-echo"; |
69 chomp($passcode = <IN>); |
70 chomp($passcode = <IN>); |
70 system stty => $settings; |
71 system stty => $settings; |
71 print "\n"; |
72 print "\n"; |
72 } |
73 } |
73 |
74 |
74 pod2usage(-verbose => 0, -exitval => 0) if not defined $passcode; |
75 pod2usage(-verbose => 0, -exitval => 0) if not defined $passcode; |
75 |
76 -x $opt_script |
76 push @$ppp_opts, "nodetach" if !@$ppp_opts; |
77 or die ME . ": Script $opt_script is not executable: $!\n" |
77 push @$ppp_opts, $debug ? "debug" : "nolog"; |
78 if defined $opt_script; |
78 push @$ppp_opts, "nodefaultroute" if not grep /^defaultroute$/, @$ppp_opts; |
79 |
79 $ppp_opts = join(" ", @$ppp_opts); |
80 push @ppp_opts, "nodetach" if $opt_debug; |
80 print "\nPPP-Options: $ppp_opts\n" if $debug; |
81 push @ppp_opts, $opt_debug ? "debug" : "nolog"; |
|
82 push @ppp_opts, "nodefaultroute" if not grep /^defaultroute$/, @ppp_opts; |
|
83 print "\nPPP-Options: @ppp_opts\n" if $opt_debug; |
81 |
84 |
82 # Declare variables used throughout the rest of the script. |
85 # Declare variables used throughout the rest of the script. |
83 my ($request, $response, $sessionid, $favorite); |
86 my ($request, $response, $sessionid, $favorite); |
84 |
87 |
85 # Store the OpenSSL command in a variable for convienence. |
88 # Store the OpenSSL command in a variable for convienence. |
86 my $openssl = |
89 my $openssl = |
87 "openssl s_client" |
90 "openssl s_client" |
88 . (-d "/etc/ssl/certs" ? " -CApath /etc/ssl/certs" : "") |
91 . (-d "/etc/ssl/certs" ? " -CApath /etc/ssl/certs" : "") |
89 . " -ign_eof -quiet -connect ${host}:443"; |
92 . " -ign_eof -quiet -connect ${opt_host}:443"; |
90 |
93 |
91 # Make initial request to get client_data |
94 # Make initial request to get client_data |
92 $request = |
95 $request = |
93 "GET /my.logon.php3?check=1 HTTP/1.0\r\n" |
96 "GET /my.logon.php3?check=1 HTTP/1.0\r\n" |
94 . "Content-Type: application/x-www-form-urlencoded\r\n" |
97 . "Content-Type: application/x-www-form-urlencoded\r\n" |
95 . "Connection: close\r\n" . "\r\n"; |
98 . "Connection: close\r\n" . "\r\n"; |
96 |
99 |
97 $response = qx(echo "${request}" | ${openssl} 2>/dev/null) |
100 $response = qx(echo "${request}" | ${openssl} 2>/dev/null) |
98 or die "Invalid Host spezified or not reachable: $host\n"; |
101 or die ME . ": Invalid Host specified or not reachable: $opt_host\n"; |
99 |
102 |
100 $response =~ s/<INPUT type="hidden" name="client_data" value="(.*)">/$1/; |
103 $response =~ s/<INPUT type="hidden" name="client_data" value="(.*)">/$1/; |
101 my $client_data = $1; |
104 my $client_data = $1; |
102 |
105 |
103 ### |
106 ### |
108 # browser will make many more requests than this to complete the log in |
111 # browser will make many more requests than this to complete the log in |
109 # sequence, but all that is required is this POST with our credentails. This |
112 # sequence, but all that is required is this POST with our credentails. This |
110 # may fail if the FirePass has End-Point Security Policies configured. |
113 # may fail if the FirePass has End-Point Security Policies configured. |
111 $request = |
114 $request = |
112 "check=1&username=${user}&password=${passcode}&mrhlogonform=1&client_data=${client_data}"; |
115 "check=1&username=${user}&password=${passcode}&mrhlogonform=1&client_data=${client_data}"; |
|
116 |
113 $request = |
117 $request = |
114 "POST /my.activation.php3 HTTP/1.0\r\n" |
118 "POST /my.activation.php3 HTTP/1.0\r\n" |
115 . "Host: ${host}\r\n" |
119 . "Host: ${opt_host}\r\n" |
116 . "Content-Type: application/x-www-form-urlencoded\r\n" |
120 . "Content-Type: application/x-www-form-urlencoded\r\n" |
117 . "Content-Length: " |
121 . "Content-Length: " |
118 . length($request) . "\r\n" |
122 . length($request) . "\r\n" |
119 . "Connection: close\r\n" . "\r\n" |
123 . "Connection: close\r\n" . "\r\n" |
120 . "${request}\r\n"; |
124 . "${request}\r\n"; |
|
125 |
121 $response = qx(echo "${request}" | ${openssl} 2>/dev/null); |
126 $response = qx(echo "${request}" | ${openssl} 2>/dev/null); |
122 |
127 |
123 # We can then parse the response for the MRHSession Cookie, which contains our |
128 # We can then parse the response for the MRHSession Cookie, which contains our |
124 # SessionID. In this example, we print out the SessionID in order to verify |
129 # SessionID. In this example, we print out the SessionID in order to verify |
125 # that our log in attempt worked. |
130 # that our log in attempt worked. |
126 $response =~ /MRHSession=(\w+);/; |
131 $response =~ /MRHSession=(\w+);/; |
127 $sessionid = $1; |
132 $sessionid = $1; |
128 print "SessionID: ${sessionid}\n" if $debug; |
133 print "SessionID: ${sessionid}\n" if $opt_debug; |
129 |
134 |
130 ### |
135 ### |
131 ### STEP 3 :: Create the SSL VPN tunnel. |
136 ### STEP 3 :: Create the SSL VPN tunnel. |
132 ### |
137 ### |
133 |
138 |
134 # Now that we are authenticated and have a valid SessionID, we must request |
139 # Now that we are authenticated and have a valid SessionID, we must request |
135 # specific pages/objects in order to initiate a SSL VPN tunnel. Before we do |
140 # specific pages/objects in order to initiate a SSL VPN tunnel. Before we do |
136 # this, let's determine the resource locator for our Network Access favorite. |
141 # this, let's determine the resource locator for our Network Access favorite. |
137 $request = "GET /vdesk/vpn/index.php3?outform=xml HTTP/1.0\r\n" |
142 $request = "GET /vdesk/vpn/index.php3?outform=xml HTTP/1.0\r\n" |
138 . "Cookie: MRHSession=${sessionid}\r\n\r\n"; |
143 . "Cookie: MRHSession=${sessionid}\r\n" . "\r\n"; |
139 $response = qx(echo "${request}" | ${openssl} 2>/dev/null); |
144 $response = qx(echo "${request}" | ${openssl} 2>/dev/null); |
140 |
145 |
141 # The response is XML, so we can safely grab what we are looking for using some |
146 # The response is XML, so we can safely grab what we are looking for using some |
142 # regular expression magic. Same with the SessionID, we're printing out the |
147 # regular expression magic. Same with the SessionID, we're printing out the |
143 # final value to make sure we're on the right track. |
148 # final value to make sure we're on the right track. |
144 $response =~ /${name}[^\n]+\n[^Z]+Z=\d+,(\d+)/; |
149 $response =~ /${opt_name}[^\n]+\n[^Z]+Z=\d+,(\d+)/; |
145 $favorite = $1; |
150 $favorite = $1; |
146 print "Favorite: ${favorite}\n" if $debug; |
151 print "Favorite: ${favorite}\n" if $opt_debug; |
147 |
152 |
148 # We're all set! Let's visit the necessary pages/objects to notify FirePass |
153 # We're all set! Let's visit the necessary pages/objects to notify FirePass |
149 # that we wish to open a SSL VPN tunnel. |
154 # that we wish to open a SSL VPN tunnel. |
150 foreach my $uri ("/vdesk/", "/vdesk/vpn/connect.php3?Z=0,${favorite}",) { |
155 foreach my $uri ("/vdesk/", "/vdesk/vpn/connect.php3?Z=0,${favorite}",) { |
151 $request = "GET ${uri} HTTP/1.0\r\n" |
156 $request = "GET ${uri} HTTP/1.0\r\n" |
158 # simply calling PPPD, and having it use OpenSSL as a psuedo terminal device. |
163 # simply calling PPPD, and having it use OpenSSL as a psuedo terminal device. |
159 $request = "GET /myvpn?sess=${sessionid} HTTP/1.0\r\n" |
164 $request = "GET /myvpn?sess=${sessionid} HTTP/1.0\r\n" |
160 . "Cookie: MRHSession=${sessionid}\r\n" . "\r\n"; |
165 . "Cookie: MRHSession=${sessionid}\r\n" . "\r\n"; |
161 $request = "chat -v '' '${request}'"; |
166 $request = "chat -v '' '${request}'"; |
162 system( |
167 system( |
163 "pppd ${ppp_opts} noauth crtscts passive noproxyarp local pty \"${openssl}\" connect \"${request}\"" |
168 pppd => @ppp_opts, |
|
169 pty => ${openssl}, |
|
170 connect => ${request}, |
|
171 linkname => "sap-vpn", |
|
172 qw(noauth crtscts passive noproxyarp |
|
173 local), |
164 ); |
174 ); |
165 |
175 |
166 # Voila! We should now have a PPP connection running over SSL. We can exit |
176 # Voila! We should now have a PPP connection running over SSL. We can exit |
167 # from this script cleanly, and move on to setting up routes to the remote |
177 # from this script cleanly, and move on to setting up routes to the remote |
168 # network using our favorite networking tools. Happy hacking! |
178 # network using our favorite networking tools. Happy hacking! |
183 vpn [-m|--man] |
193 vpn [-m|--man] |
184 |
194 |
185 =head1 DESCRIPTION |
195 =head1 DESCRIPTION |
186 |
196 |
187 Ths script establishes a VPN connecttion to a FirePass server. |
197 Ths script establishes a VPN connecttion to a FirePass server. |
188 B<Note:> This script requires root privileges and should be run via sudo. |
198 B<Note:> This script requires root privileges and should be run via sudo |
|
199 or some other approbiate mechanism. |
189 |
200 |
190 =head1 OPTIONS |
201 =head1 OPTIONS |
191 |
202 |
192 |
|
193 =over |
203 =over |
194 |
204 |
195 =item B<-u>|B<--user> I<user> |
205 =item B<-d> |
196 |
206 |
197 Your D|C|I user, not really optional. (no default) |
207 Print debug output from pppd. In this mode the script (and the pppd) |
198 |
208 will not detach from your terminal and the script code will not be |
199 =item B<-p>|B<--passcode> I<passcode> |
209 executed. (default: 0) |
200 |
210 |
201 Your passcode, if not supplied, F</dev/tty> is opened for reading |
211 =item B<-h>|B<--help> |
202 the passcode. (no default) |
212 |
|
213 A short help. (defualt: off) |
203 |
214 |
204 =item B<-H>|B<--host> I<host> |
215 =item B<-H>|B<--host> I<host> |
205 |
216 |
206 Host to connect to. (defaults to C<connectwdf.sap.corp>) |
217 Host to connect to. (defaults to C<connectwdf.sap.corp>) |
207 |
218 |
|
219 =item B<-m>|B<--man> |
|
220 |
|
221 This man page. (default: off) |
|
222 |
208 =item B<-n>|B<--name> I<name> |
223 =item B<-n>|B<--name> I<name> |
209 |
224 |
210 Name of the service(?). (default: to 'SAP Network Access') |
225 Name of the service(?). (default: to 'SAP Network Access') |
211 |
|
212 =item B<-d> |
|
213 |
|
214 Print debug output from pppd. (default: 0) |
|
215 |
226 |
216 =item B<-o>|B<--opts> I<ppp options> |
227 =item B<-o>|B<--opts> I<ppp options> |
217 |
228 |
218 Additional options for ppp. Can be specified multiple times. (default: nodetach) |
229 Additional options for ppp. Can be specified multiple times. (default: nodetach) |
219 Good choices are C<detach>, or C<updetach>. |
230 Good choices are C<detach>, or C<updetach>. |
220 B<Note:> The C<nodefaultroute> is set automatically. |
231 B<Note:> The C<nodefaultroute> is set automatically. |
221 |
232 |
|
233 =item B<-p>|B<--passcode> I<passcode> |
|
234 |
|
235 Your passcode, if not supplied, F</dev/tty> is opened for reading |
|
236 the passcode. (no default) |
|
237 |
|
238 =item B<-s>|B<--script> I<script> |
|
239 |
|
240 Script to execute after establishing the IP link. (See the B<-d> option |
|
241 above!). (no default) |
|
242 |
|
243 B<Note:> You should consider using the F</etc/ppp/ip-up.d/> scripts. |
|
244 (see below) |
|
245 |
|
246 B<Note2:> NOT IMPLEMENTED YET! |
|
247 |
|
248 |
|
249 =item B<-u>|B<--user> I<user> |
|
250 |
|
251 Your D|C|I user, not really optional. (no default) |
|
252 |
222 =back |
253 =back |
223 |
254 |
224 =cut |
255 =cut |
225 |
256 |
226 ### |
257 ### |