1#!/usr/bin/env perl
2#***************************************************************************
3#                                  _   _ ____  _
4#  Project                     ___| | | |  _ \| |
5#                             / __| | | | |_) | |
6#                            | (__| |_| |  _ <| |___
7#                             \___|\___/|_| \_\_____|
8#
9# Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
10#
11# This software is licensed as described in the file COPYING, which
12# you should have received as part of this distribution. The terms
13# are also available at http://curl.haxx.se/docs/copyright.html.
14#
15# You may opt to use, copy, modify, merge, publish, distribute and/or sell
16# copies of the Software, and permit persons to whom the Software is
17# furnished to do so, under the terms of the COPYING file.
18#
19# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20# KIND, either express or implied.
21#
22#***************************************************************************
23
24# This is the HTTPS, FTPS, POP3S, IMAPS, SMTPS, server used for curl test
25# harness. Actually just a layer that runs stunnel properly using the
26# non-secure test harness servers.
27
28BEGIN {
29    @INC=(@INC, $ENV{'srcdir'}, '.');
30}
31
32use strict;
33use warnings;
34use Cwd;
35
36use serverhelp qw(
37    server_pidfilename
38    server_logfilename
39    );
40
41my $stunnel = "stunnel";
42
43my $verbose=0; # set to 1 for debugging
44
45my $accept_port = 8991; # just our default, weird enough
46my $target_port = 8999; # default test http-server port
47
48my $stuncert;
49
50my $ver_major;
51my $ver_minor;
52my $stunnel_version;
53my $socketopt;
54my $cmd;
55
56my $pidfile;          # stunnel pid file
57my $logfile;          # stunnel log file
58my $loglevel = 5;     # stunnel log level
59my $ipvnum = 4;       # default IP version of stunneled server
60my $idnum = 1;        # dafault stunneled server instance number
61my $proto = 'https';  # default secure server protocol
62my $conffile;         # stunnel configuration file
63my $certfile;         # certificate chain PEM file
64
65#***************************************************************************
66# stunnel requires full path specification for several files.
67#
68my $path   = getcwd();
69my $srcdir = $path;
70my $logdir = $path .'/log';
71
72#***************************************************************************
73# Signal handler to remove our stunnel 4.00 and newer configuration file.
74#
75sub exit_signal_handler {
76    my $signame = shift;
77    local $!; # preserve errno
78    local $?; # preserve exit status
79    unlink($conffile) if($conffile && (-f $conffile));
80    exit;
81}
82
83#***************************************************************************
84# Process command line options
85#
86while(@ARGV) {
87    if($ARGV[0] eq '--verbose') {
88        $verbose = 1;
89    }
90    elsif($ARGV[0] eq '--proto') {
91        if($ARGV[1]) {
92            $proto = $ARGV[1];
93            shift @ARGV;
94        }
95    }
96    elsif($ARGV[0] eq '--accept') {
97        if($ARGV[1]) {
98            if($ARGV[1] =~ /^(\d+)$/) {
99                $accept_port = $1;
100                shift @ARGV;
101            }
102        }
103    }
104    elsif($ARGV[0] eq '--connect') {
105        if($ARGV[1]) {
106            if($ARGV[1] =~ /^(\d+)$/) {
107                $target_port = $1;
108                shift @ARGV;
109            }
110        }
111    }
112    elsif($ARGV[0] eq '--stunnel') {
113        if($ARGV[1]) {
114            $stunnel = $ARGV[1];
115            shift @ARGV;
116        }
117    }
118    elsif($ARGV[0] eq '--srcdir') {
119        if($ARGV[1]) {
120            $srcdir = $ARGV[1];
121            shift @ARGV;
122        }
123    }
124    elsif($ARGV[0] eq '--certfile') {
125        if($ARGV[1]) {
126            $stuncert = $ARGV[1];
127            shift @ARGV;
128        }
129    }
130    elsif($ARGV[0] eq '--id') {
131        if($ARGV[1]) {
132            if($ARGV[1] =~ /^(\d+)$/) {
133                $idnum = $1 if($1 > 0);
134                shift @ARGV;
135            }
136        }
137    }
138    elsif($ARGV[0] eq '--ipv4') {
139        $ipvnum = 4;
140    }
141    elsif($ARGV[0] eq '--ipv6') {
142        $ipvnum = 6;
143    }
144    elsif($ARGV[0] eq '--pidfile') {
145        if($ARGV[1]) {
146            $pidfile = "$path/". $ARGV[1];
147            shift @ARGV;
148        }
149    }
150    elsif($ARGV[0] eq '--logfile') {
151        if($ARGV[1]) {
152            $logfile = "$path/". $ARGV[1];
153            shift @ARGV;
154        }
155    }
156    else {
157        print STDERR "\nWarning: secureserver.pl unknown parameter: $ARGV[0]\n";
158    }
159    shift @ARGV;
160}
161
162#***************************************************************************
163# Initialize command line option dependant variables
164#
165if(!$pidfile) {
166    $pidfile = "$path/". server_pidfilename($proto, $ipvnum, $idnum);
167}
168if(!$logfile) {
169    $logfile = server_logfilename($logdir, $proto, $ipvnum, $idnum);
170}
171
172$conffile = "$path/stunnel.conf";
173
174$certfile = "$srcdir/". ($stuncert?"certs/$stuncert":"stunnel.pem");
175
176my $ssltext = uc($proto) ." SSL/TLS:";
177
178#***************************************************************************
179# Find out version info for the given stunnel binary
180#
181foreach my $veropt (('-version', '-V')) {
182    foreach my $verstr (qx($stunnel $veropt 2>&1)) {
183        if($verstr =~ /^stunnel (\d+)\.(\d+) on /) {
184            $ver_major = $1;
185            $ver_minor = $2;
186            last;
187        }
188    }
189    last if($ver_major);
190}
191if((!$ver_major) || (!$ver_minor)) {
192    if(-x "$stunnel" && ! -d "$stunnel") {
193        print "$ssltext Unknown stunnel version\n";
194    }
195    else {
196        print "$ssltext No stunnel\n";
197    }
198    exit 1;
199}
200$stunnel_version = (100*$ver_major) + $ver_minor;
201
202#***************************************************************************
203# Verify minimmum stunnel required version
204#
205if($stunnel_version < 310) {
206    print "$ssltext Unsupported stunnel version $ver_major.$ver_minor\n";
207    exit 1;
208}
209
210#***************************************************************************
211# Build command to execute for stunnel 3.X versions
212#
213if($stunnel_version < 400) {
214    if($stunnel_version >= 319) {
215        $socketopt = "-O a:SO_REUSEADDR=1";
216    }
217    $cmd  = "$stunnel -p $certfile -P $pidfile ";
218    $cmd .= "-d $accept_port -r $target_port -f -D $loglevel ";
219    $cmd .= ($socketopt) ? "$socketopt " : "";
220    $cmd .= ">$logfile 2>&1";
221    if($verbose) {
222        print uc($proto) ." server (stunnel $ver_major.$ver_minor)\n";
223        print "cmd: $cmd\n";
224        print "pem cert file: $certfile\n";
225        print "pid file: $pidfile\n";
226        print "log file: $logfile\n";
227        print "log level: $loglevel\n";
228        print "listen on port: $accept_port\n";
229        print "connect to port: $target_port\n";
230    }
231}
232
233#***************************************************************************
234# Build command to execute for stunnel 4.00 and newer
235#
236if($stunnel_version >= 400) {
237    $socketopt = "a:SO_REUSEADDR=1";
238    $cmd  = "$stunnel $conffile ";
239    $cmd .= ">$logfile 2>&1";
240    # setup signal handler
241    $SIG{INT} = \&exit_signal_handler;
242    $SIG{TERM} = \&exit_signal_handler;
243    # stunnel configuration file
244    if(open(STUNCONF, ">$conffile")) {
245	print STUNCONF "
246	CApath = $path
247	cert = $certfile
248	pid = $pidfile
249	debug = $loglevel
250	output = $logfile
251	socket = $socketopt
252	foreground = yes
253
254	[curltest]
255	accept = $accept_port
256	connect = $target_port
257	";
258        if(!close(STUNCONF)) {
259            print "$ssltext Error closing file $conffile\n";
260            exit 1;
261        }
262    }
263    else {
264        print "$ssltext Error writing file $conffile\n";
265        exit 1;
266    }
267    if($verbose) {
268        print uc($proto) ." server (stunnel $ver_major.$ver_minor)\n";
269        print "cmd: $cmd\n";
270        print "CApath = $path\n";
271        print "cert = $certfile\n";
272        print "pid = $pidfile\n";
273        print "debug = $loglevel\n";
274        print "output = $logfile\n";
275        print "socket = $socketopt\n";
276        print "foreground = yes\n";
277        print "\n";
278        print "[curltest]\n";
279        print "accept = $accept_port\n";
280        print "connect = $target_port\n";
281    }
282}
283
284#***************************************************************************
285# Set file permissions on certificate pem file.
286#
287chmod(0600, $certfile) if(-f $certfile);
288
289#***************************************************************************
290# Run stunnel.
291#
292my $rc = system($cmd);
293
294$rc >>= 8;
295
296unlink($conffile) if($conffile && -f $conffile);
297
298exit $rc;
299