89 if not defined $opt_user |
92 if not defined $opt_user |
90 and not defined $opt_kill; |
93 and not defined $opt_kill; |
91 |
94 |
92 $opt_verbose += $opt_debug; |
95 $opt_verbose += $opt_debug; |
93 |
96 |
94 untaint($opt_linkname) or die ME . ": linkname didn't pass verification\n"; |
97 untaint($opt_linkname) or ohshit "linkname didn't pass verification\n"; |
95 untaint($opt_script) |
98 untaint($opt_script) |
96 or die ME . ": script name didn't pass verification\n" |
99 or ohshit "script name didn't pass verification\n" |
97 if $opt_script; |
100 if $opt_script; |
98 map { untaint } @ppp_opts; |
101 map { untaint } @ppp_opts; |
99 |
102 |
100 die ME . ": need to run with root permissions!\n" |
103 ohshit "need to run with root permissions!\n" |
101 if not $EUID == 0 || $UID == 0; |
104 if not $EUID == 0 || $UID == 0; |
102 |
105 |
103 exit do_kill($opt_linkname) if $opt_kill; |
106 exit do_kill($opt_linkname) if $opt_kill; |
104 |
107 |
105 untaint($opt_user) |
108 untaint($opt_user) |
106 or die ME . ": username didn't pass verification\n"; |
109 or ohshit "username didn't pass verification\n"; |
107 |
110 |
108 if (not defined $opt_passcode) { |
111 if (not defined $opt_passcode) { |
109 chomp(my $settings = qx{stty "-g"}); |
112 chomp(my $settings = qx{stty "-g"}); |
110 open(IN, "/dev/tty") or die ME . ": Can't open /dev/tty: $!\n"; |
113 open(IN, "/dev/tty") or ohshit "Can't open /dev/tty: $!\n"; |
111 print "Passcode for $opt_user: "; |
114 print "Passcode for $opt_user: "; |
112 system stty => "-echo"; |
115 system stty => "-echo"; |
113 chomp($opt_passcode = <IN>); |
116 chomp($opt_passcode = <IN>); |
114 system stty => $settings; |
117 system stty => $settings; |
115 print "\n"; |
118 print "\n"; |
116 } |
119 } |
117 untaint($opt_passcode) or die ME . ": passcode didn't pass verification\n"; |
120 untaint($opt_passcode) or ohshit "passcode didn't pass verification\n"; |
118 pod2usage(-verbose => 0, -exitval => 0) if not defined $opt_passcode; |
121 pod2usage(-verbose => 0, -exitval => 0) if not defined $opt_passcode; |
119 |
122 |
120 -x $opt_script |
123 -x $opt_script |
121 or die ME . ": Script $opt_script is not executable: $!\n" |
124 or ohshit "Script $opt_script is not executable: $!\n" |
122 if defined $opt_script; |
125 if defined $opt_script; |
123 |
126 |
124 push @ppp_opts, $opt_debug ? qw(nodetach debug dump) : qw(nolog updetach); |
127 push @ppp_opts, $opt_debug ? qw(nodetach debug dump) : qw(nolog updetach); |
125 push @ppp_opts, "nodefaultroute" if not grep /^defaultroute$/, @ppp_opts; |
128 push @ppp_opts, "nodefaultroute" if not grep /^defaultroute$/, @ppp_opts; |
126 push @ppp_opts, "logfd", 2 if $opt_verbose; |
129 push @ppp_opts, "logfd", 2 if $opt_verbose; |
136 . (-d "/etc/ssl/certs" ? " -CApath /etc/ssl/certs" : "") |
139 . (-d "/etc/ssl/certs" ? " -CApath /etc/ssl/certs" : "") |
137 . " -ign_eof -quiet -connect ${opt_host}:443"; |
140 . " -ign_eof -quiet -connect ${opt_host}:443"; |
138 |
141 |
139 # Make initial request to get client_data |
142 # Make initial request to get client_data |
140 verbose "% initial request\n"; |
143 verbose "% initial request\n"; |
141 $request = |
144 |
142 "GET /my.logon.php3?check=1 HTTP/1.0\r\n" |
145 my $client_data; |
143 . "Content-Type: application/x-www-form-urlencoded\r\n" |
146 my $ua; |
144 . "Connection: close\r\n" . "\r\n"; |
147 my $cookies; |
145 |
148 |
146 $response = qx(echo "${request}" | ${openssl} 2>/dev/null) |
149 if (!$use_lwp) { |
147 or die ME . ": Invalid Host specified or not reachable: $opt_host\n"; |
150 $request = |
|
151 "GET /my.logon.php3?check=1 HTTP/1.0\r\n" |
|
152 . "Content-Type: application/x-www-form-urlencoded\r\n" |
|
153 . "Connection: close\r\n" . "\r\n"; |
|
154 |
|
155 $response = qx(echo "${request}" | ${openssl} 2>/dev/null) |
|
156 or ohshit "Invalid Host specified or not reachable: $opt_host\n"; |
|
157 |
|
158 } |
|
159 else { |
|
160 use LWP::UserAgent; |
|
161 use HTTP::Request::Common; |
|
162 use HTTP::Status; |
|
163 use HTTP::Cookies; |
|
164 #use LWP::Debug qw(+); |
|
165 $cookies = new HTTP::Cookies; |
|
166 $ua = new LWP::UserAgent; |
|
167 $ua->agent(""); |
|
168 $ua->env_proxy; |
|
169 $ua->cookie_jar($cookies); |
|
170 $response = $ua->get("https://$opt_host:443/my.logon.php3?check=1"); |
|
171 |
|
172 ohshit "initial failed with http code @{[$response->message]}\n" |
|
173 unless $response->is_success; |
|
174 |
|
175 $response = $response->as_string; |
|
176 } |
148 |
177 |
149 $response =~ s/<INPUT type="hidden" name="client_data" value="(.*)">/$1/; |
178 $response =~ s/<INPUT type="hidden" name="client_data" value="(.*)">/$1/; |
150 my $client_data = $1; |
179 $client_data = $1; |
151 |
180 |
152 ### |
181 ### |
153 ### STEP 2 :: Log in to FirePass. |
182 ### STEP 2 :: Log in to FirePass. |
154 ### |
183 ### |
155 |
184 |
157 |
186 |
158 # This is the bare minimum required in order to successfully log in. A normal |
187 # This is the bare minimum required in order to successfully log in. A normal |
159 # browser will make many more requests than this to complete the log in |
188 # browser will make many more requests than this to complete the log in |
160 # sequence, but all that is required is this POST with our credentails. This |
189 # sequence, but all that is required is this POST with our credentails. This |
161 # may fail if the FirePass has End-Point Security Policies configured. |
190 # may fail if the FirePass has End-Point Security Policies configured. |
162 $request = |
191 |
|
192 if (!$use_lwp) { |
|
193 $request = |
163 "check=1&username=${opt_user}&password=${opt_passcode}&mrhlogonform=1&client_data=${client_data}"; |
194 "check=1&username=${opt_user}&password=${opt_passcode}&mrhlogonform=1&client_data=${client_data}"; |
164 |
195 |
165 $request = |
196 $request = |
166 "POST /my.activation.php3 HTTP/1.0\r\n" |
197 "POST /my.activation.php3 HTTP/1.0\r\n" |
167 . "Host: ${opt_host}\r\n" |
198 . "Host: ${opt_host}\r\n" |
168 . "Content-Type: application/x-www-form-urlencoded\r\n" |
199 . "Content-Type: application/x-www-form-urlencoded\r\n" |
169 . "Content-Length: " |
200 . "Content-Length: " |
170 . length($request) . "\r\n" |
201 . length($request) . "\r\n" |
171 . "Connection: close\r\n" . "\r\n" |
202 . "Connection: close\r\n" . "\r\n" |
172 . "${request}\r\n"; |
203 . "${request}\r\n"; |
173 |
204 |
174 $response = qx(echo "${request}" | ${openssl} 2>/dev/null); |
205 $response = qx(echo "${request}" | ${openssl} 2>/dev/null); |
|
206 } |
|
207 else { |
|
208 $response = $ua->post( |
|
209 "https://$opt_host:443/my.activation.php3", |
|
210 check => 1, |
|
211 username => $opt_user, |
|
212 password => $opt_passcode, |
|
213 mrhlogonform => 1, |
|
214 client_data => $client_data |
|
215 ); |
|
216 |
|
217 ohshit "login failed with http code @{[$response->message]}\n" |
|
218 unless $response->is_success; |
|
219 |
|
220 $response = $response->as_string; |
|
221 } |
175 |
222 |
176 # We can then parse the response for the MRHSession Cookie, which contains our |
223 # We can then parse the response for the MRHSession Cookie, which contains our |
177 # SessionID. In this example, we print out the SessionID in order to verify |
224 # SessionID. In this example, we print out the SessionID in order to verify |
178 # that our log in attempt worked. |
225 # that our log in attempt worked. |
|
226 |
179 $response =~ /MRHSession=(\w+);/; |
227 $response =~ /MRHSession=(\w+);/; |
180 $sessionid = $1; |
228 $sessionid = $1; |
181 verbose "% session id ${sessionid}\n"; |
229 verbose "% session id ${sessionid}\n"; |
182 |
230 |
|
231 $cookies->set_cookie(0, MRHSession => $sessionid, "/", $opt_host, 443, 1, 0, 10, 0, {}); |
|
232 #warn $cookies->as_string; |
|
233 |
183 ### |
234 ### |
184 ### STEP 3 :: Create the SSL VPN tunnel. |
235 ### STEP 3 :: Create the SSL VPN tunnel. |
185 ### |
236 ### |
186 |
237 |
187 verbose "% creating the ssl tunnel\n"; |
238 verbose "% creating the ssl tunnel\n"; |
188 |
239 |
189 # Now that we are authenticated and have a valid SessionID, we must request |
240 # Now that we are authenticated and have a valid SessionID, we must request |
190 # specific pages/objects in order to initiate a SSL VPN tunnel. Before we do |
241 # specific pages/objects in order to initiate a SSL VPN tunnel. Before we do |
191 # this, let's determine the resource locator for our Network Access favorite. |
242 # this, let's determine the resource locator for our Network Access favorite. |
192 $request = "GET /vdesk/vpn/index.php3?outform=xml HTTP/1.0\r\n" |
243 #if (!$use_lwp) { |
193 . "Cookie: MRHSession=${sessionid}\r\n" . "\r\n"; |
244 if (1) { |
194 $response = qx(echo "${request}" | ${openssl} 2>/dev/null); |
245 $request = "GET /vdesk/vpn/index.php3?outform=xml HTTP/1.0\r\n" |
|
246 . "Cookie: MRHSession=${sessionid}\r\n" . "\r\n"; |
|
247 $response = qx(echo "${request}" | ${openssl} 2>/dev/null); |
|
248 } |
|
249 else { |
|
250 $response = $ua->get("https://$opt_host:443/vdesk/vpn/index.php3?outform=xml"); |
|
251 |
|
252 ohshit "creating tunnel failed with http code @{[$response->message]}\n" |
|
253 unless $response->is_success; |
|
254 |
|
255 $response = $response->as_string; |
|
256 } |
195 |
257 |
196 # The response is XML, so we can safely grab what we are looking for using some |
258 # The response is XML, so we can safely grab what we are looking for using some |
197 # regular expression magic. Same with the SessionID, we're printing out the |
259 # regular expression magic. Same with the SessionID, we're printing out the |
198 # final value to make sure we're on the right track. |
260 # final value to make sure we're on the right track. |
|
261 open(X, ">response.out") or die; |
|
262 print X $response; |
|
263 |
199 $response =~ /${opt_name}[^\n]+\n[^Z]+Z=\d+,(\d+)/; |
264 $response =~ /${opt_name}[^\n]+\n[^Z]+Z=\d+,(\d+)/; |
200 $favorite = $1; |
265 $favorite = $1; |
201 verbose "% favorite ${favorite}\n"; |
266 verbose "% favorite ${favorite}\n"; |
|
267 |
|
268 exit; |
202 |
269 |
203 # We're all set! Let's visit the necessary pages/objects to notify FirePass |
270 # We're all set! Let's visit the necessary pages/objects to notify FirePass |
204 # that we wish to open a SSL VPN tunnel. |
271 # that we wish to open a SSL VPN tunnel. |
205 foreach my $uri ("/vdesk/", "/vdesk/vpn/connect.php3?Z=0,${favorite}",) { |
272 foreach my $uri ("/vdesk/", "/vdesk/vpn/connect.php3?Z=0,${favorite}",) { |
206 $request = "GET ${uri} HTTP/1.0\r\n" |
273 $request = "GET ${uri} HTTP/1.0\r\n" |
215 . "Cookie: MRHSession=${sessionid}\r\n" . "\r\n"; |
282 . "Cookie: MRHSession=${sessionid}\r\n" . "\r\n"; |
216 $request = "chat -v '' '${request}'"; |
283 $request = "chat -v '' '${request}'"; |
217 |
284 |
218 { |
285 { |
219 my $pid = fork(); # this way we've better control |
286 my $pid = fork(); # this way we've better control |
220 die ME . ": can't fork: $!\n" if not defined $pid; |
287 ohshit "can't fork: $!\n" if not defined $pid; |
221 |
288 |
222 if ($pid == 0) { |
289 if ($pid == 0) { |
223 $EUID = $UID; # get ROOT, the pppd want's to see |
290 $EUID = $UID; # get ROOT, the pppd want's to see |
224 # the UID and the EUID to be ROOT |
291 # the UID and the EUID to be ROOT |
225 exec( |
292 exec( |
226 pppd => @ppp_opts, |
293 pppd => @ppp_opts, |
227 pty => ${openssl}, |
294 pty => ${openssl}, |
228 connect => ${request}, |
295 connect => ${request}, |
229 linkname => $opt_linkname, |
296 linkname => $opt_linkname, |
230 qw(noauth crtscts passive noproxyarp local) |
297 qw(noauth crtscts passive noproxyarp local) |
231 ) or die ME . ": Can't exec: $!\n"; |
298 ) or ohshit "Can't exec: $!\n"; |
232 |
299 |
233 } |
300 } |
234 wait; |
301 wait; |
235 die ME . ": pppd didn't return sucessfully (rc: @{[$? >> 8]})\n" if $?; |
302 ohshit "pppd didn't return sucessfully (rc: @{[$? >> 8]})\n" if $?; |
236 } |
303 } |
237 |
304 |
238 # now executing the script |
305 # now executing the script |
239 # if there is some script name supplied |
306 # if there is some script name supplied |
240 |
307 |
241 if (defined $opt_script and not $opt_debug) { |
308 if (defined $opt_script and not $opt_debug) { |
242 |
309 |
243 my $pid = fork(); |
310 my $pid = fork(); |
244 die ME . ": Can't fork: $!\n" if not defined $pid; |
311 ohshit "Can't fork: $!\n" if not defined $pid; |
245 |
312 |
246 if ($pid == 0) { # child |
313 if ($pid == 0) { # child |
247 |
314 |
248 if ($UID != $EUID) { |
315 if ($UID != $EUID) { |
249 my ($owner, $group) = (stat $opt_script)[ 4, 5 ]; |
316 my ($owner, $group) = (stat $opt_script)[ 4, 5 ]; |
250 die ME . ": can't stat $opt_script\n" if not defined $owner; |
317 ohshit "can't stat $opt_script\n" if not defined $owner; |
251 |
318 |
252 $UID = $EUID = $owner; |
319 $UID = $EUID = $owner; |
253 $GID = $EGID = $group; |
320 $GID = $EGID = $group; |
254 } |
321 } |
255 |
322 |
256 verbose |
323 verbose |
257 "% executing script $opt_script with uid $UID and gid $GID\n"; |
324 "% executing script $opt_script with uid $UID and gid $GID\n"; |
258 |
325 |
259 exec $opt_script |
326 exec $opt_script |
260 or die ME . ": Can't exec $opt_script: $!\n"; |
327 or ohshit "Can't exec $opt_script: $!\n"; |
261 } |
328 } |
262 $pid = wait; |
329 $pid = wait; |
263 verbose "% script returned $?\n"; |
330 verbose "% script returned $?\n"; |
264 exit; |
331 exit; |
265 } |
332 } |
273 } |
340 } |
274 |
341 |
275 sub do_kill($) { |
342 sub do_kill($) { |
276 my $linkname = shift; |
343 my $linkname = shift; |
277 open((my $fh), $_ = "/var/run/ppp-$linkname.pid") |
344 open((my $fh), $_ = "/var/run/ppp-$linkname.pid") |
278 or die ME . ": Can't open the link file \"$_\": $!\n"; |
345 or ohshit "Can't open the link file \"$_\": $!\n"; |
279 |
346 |
280 my $pid = <$fh>; |
347 my $pid = <$fh>; |
281 my $iface = <$fh>; |
348 my $iface = <$fh>; |
282 |
349 |
283 map { chomp; untaint } $pid, $iface; |
350 map { chomp; untaint } $pid, $iface; |
284 |
351 |
285 # become root doesn't seem to be necessary, as long as our |
352 # become root doesn't seem to be necessary, as long as our |
286 # real uid is 0 |
353 # real uid is 0 |
287 kill 15, $pid or die ME . ": Can't kill pid $pid: $!\n"; |
354 kill 15, $pid or ohshit "Can't kill pid $pid: $!\n"; |
288 |
355 |
289 waitpid $pid, 0 != -1 |
356 waitpid $pid, 0 != -1 |
290 or die ME . ": was not able to wait for the ppp process: $!\n"; |
357 or ohshit "was not able to wait for the ppp process: $!\n"; |
291 |
358 |
292 verbose "% process killed, rc: " |
359 verbose "% process killed, rc: " |
293 . ($? >> 8) |
360 . ($? >> 8) |
294 . ", sig: " |
361 . ", sig: " |
295 . ($? & 0xff) . "\n"; |
362 . ($? & 0xff) . "\n"; |