⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 miniserv.pl

📁 Unix下基于Web的管理工具
💻 PL
📖 第 1 页 / 共 2 页
字号:
#!/usr/local/bin/perl# A very simple perl web server used by Webmin# Require needed libraries, including SSL if availableuse Socket;use POSIX;use Sys::Hostname;eval "use Net::SSLeay";if (!$@) {	$use_ssl = 1;	# These functions only exist for SSLeay 1.0	eval "Net::SSLeay::SSLeay_add_ssl_algorithms()";	eval "Net::SSLeay::load_error_strings()";	}# Find and read config fileif (@ARGV != 1) {	die "Usage: miniserv.pl <config file>";	}if ($ARGV[0] =~ /^\//) {	$conf = $ARGV[0];	}else {	chop($pwd = `pwd`);	$conf = "$pwd/$ARGV[0]";	}open(CONF, $conf) || die "Failed to open config file $conf : $!";while(<CONF>) {	chop;	if (/^#/ || !/\S/) { next; }	/^([^=]+)=(.*)$/;	$name = $1; $val = $2;	$name =~ s/^\s+//g; $name =~ s/\s+$//g;	$val =~ s/^\s+//g; $val =~ s/\s+$//g;	$config{$name} = $val;	}close(CONF);# Check vital config options%vital = ("port", 80,	  "root", "./",	  "server", "MiniServ/0.01",	  "index_docs", "index.html index.htm index.cgi",	  "addtype_html", "text/html",	  "addtype_txt", "text/plain",	  "addtype_gif", "image/gif",	  "addtype_jpg", "image/jpeg",	  "addtype_jpeg", "image/jpeg",	  "realm", "MiniServ"	 );foreach $v (keys %vital) {	if (!$config{$v}) {		if ($vital{$v} eq "") {			die "Missing config option $v";			}		$config{$v} = $vital{$v};		}	}# init days and months for http_date@weekday = ( "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" );@month = ( "Jan", "Feb", "Mar", "Apr", "May", "Jun",	   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" );# Change dir to the server rootchdir($config{'root'});$user_homedir = (getpwuid($<))[7];# Setup SSL if possible and if requestedif (!$config{'ssl'}) { $use_ssl = 0; }if ($use_ssl) {	$ssl_ctx = Net::SSLeay::CTX_new() ||		die "Failed to create SSL context : $!";	}# Read MIME types file and add extra typesif ($config{"mimetypes"} ne "") {	open(MIME, $config{"mimetypes"});	while(<MIME>) {		chop;		/^(\S+)\s+(.*)$/;		$type = $1; @exts = split(/\s+/, $2);		foreach $ext (@exts) {			$mime{$ext} = $type;			}		}	close(MIME);	}foreach $k (keys %config) {	if ($k !~ /^addtype_(.*)$/) { next; }	$mime{$1} = $config{$k};	}# Read users fileif ($config{'userfile'}) {	open(USERS, $config{'userfile'});	while(<USERS>) {		if (/^([^:\s]+):([^:\s]+)/) { $users{$1} = $2; }		}	close(USERS);	}# Open main socket$proto = getprotobyname('tcp');socket(MAIN, PF_INET, SOCK_STREAM, $proto) ||	die "Failed to open main socket : $!";setsockopt(MAIN, SOL_SOCKET, SO_REUSEADDR, pack("l", 1));$baddr = $config{"bind"} ? inet_aton($config{"bind"}) : INADDR_ANY;bind(MAIN, sockaddr_in($config{port}, $baddr)) ||	die "Failed to bind port $config{port} : $!";listen(MAIN, SOMAXCONN);if ($config{'listen'}) {	# Open the socket that allows other webmin servers to find this one	$proto = getprotobyname('udp');	if (socket(LISTEN, PF_INET, SOCK_DGRAM, $proto)) {		setsockopt(LISTEN, SOL_SOCKET, SO_REUSEADDR, pack("l", 1));		bind(LISTEN, sockaddr_in($config{'listen'}, INADDR_ANY));		listen(LISTEN, SOMAXCONN);		}	else {		print STDERR "Failed to open listening socket : $!\n";		$config{'listen'} = 0;		}	}# Split from the controlling terminalif (fork()) { exit; }setsid();# write out the PID fileopen(PIDFILE, "> $config{'pidfile'}");printf PIDFILE "%d\n", getpid();close(PIDFILE);# Start the log-clearing process, if needed. This checks every minute# to see if the log has passed its reset time, and if so clears itif ($config{'logclear'}) {	if (!($logclearer = fork())) {		while(1) {			$write_logtime = 0;			if (open(LOGTIME, "$config{'logfile'}.time")) {				<LOGTIME> =~ /(\d+)/;				close(LOGTIME);				if ($1 && $1+$config{'logtime'}*60*60 < time()){					# need to clear log					$write_logtime = 1;					unlink($config{'logfile'});					}				}			else { $write_logtime = 1; }			if ($write_logtime) {				open(LOGTIME, ">$config{'logfile'}.time");				print LOGTIME time(),"\n";				close(LOGTIME);				}			sleep(5*60);			}		exit;		}	push(@childpids, $logclearer);	}# get the time zoneif ($config{'log'}) {	local(@gmt, @lct, $days, $hours, $mins);	@make_date_marr = ("Jan", "Feb", "Mar", "Apr", "May", "Jun",		 	   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");	@gmt = gmtime(time());	@lct = localtime(time());	$days = $lct[3] - $gmt[3];	$hours = ($days < -1 ? 24 : 1 < $days ? -24 : $days * 24) +		 $lct[2] - $gmt[2];	$mins = $hours * 60 + $lct[1] - $gmt[1];	$timezone = ($mins < 0 ? "-" : "+"); $mins = abs($mins);	$timezone .= sprintf "%2.2d%2.2d", $mins/60, $mins%60;	}# Run the main loop$SIG{'CHLD'} = 'reaper';$SIG{'HUP'} = 'trigger_restart';$SIG{'TERM'} = 'term_handler';$SIG{'PIPE'} = 'IGNORE';@deny = &to_ipaddress(split(/\s+/, $config{"deny"}));@allow = &to_ipaddress(split(/\s+/, $config{"allow"}));$p = 0;while(1) {	# wait for a new connection, or a message from a child process	undef($rmask);	vec($rmask, fileno(MAIN), 1) = 1;	if ($config{'passdelay'}) {		for($i=0; $i<@passin; $i++) {			vec($rmask, fileno($passin[$i]), 1) = 1;			}		}	vec($rmask, fileno(LISTEN), 1) = 1 if ($config{'listen'});	local $sel = select($rmask, undef, undef, undef);	if ($need_restart) { &restart_miniserv(); }	next if ($sel <= 0);	if (vec($rmask, fileno(MAIN), 1)) {		# got new connection		$acptaddr = accept(SOCK, MAIN);		if (!$acptaddr) { next; }		# create pipes		if ($config{'passdelay'}) {			$PASSINr = "PASSINr$p"; $PASSINw = "PASSINw$p";			$PASSOUTr = "PASSOUTr$p"; $PASSOUTw = "PASSOUTw$p";			$p++;			pipe($PASSINr, $PASSINw);			pipe($PASSOUTr, $PASSOUTw);			select($PASSINw); $| = 1;			select($PASSOUTw); $| = 1;			}		select(SOCK); $| = 1;		select(STDOUT);		# fork the subprocess		if (!($handpid = fork())) {			# setup signal handlers			$SIG{'TERM'} = 'DEFAULT';			$SIG{'PIPE'} = 'DEFAULT';			#$SIG{'CHLD'} = 'DEFAULT';			$SIG{'HUP'} = 'IGNORE';			# Initialize SSL for this connection			if ($use_ssl) {				$ssl_con = Net::SSLeay::new($ssl_ctx);				Net::SSLeay::set_fd($ssl_con, fileno(SOCK));				Net::SSLeay::use_RSAPrivateKey_file(					$ssl_con, $config{'keyfile'},					&Net::SSLeay::FILETYPE_PEM);				Net::SSLeay::use_certificate_file(					$ssl_con, $config{'keyfile'},					&Net::SSLeay::FILETYPE_PEM);				Net::SSLeay::accept($ssl_con) || exit;				}			# close useless pipes			if ($config{'passdelay'}) {				foreach $p (@passin) { close($p); }				foreach $p (@passout) { close($p); }				close($PASSINr); close($PASSOUTw);				}			close(MAIN);			# Work out the hostname for this web server			if (!$config{'host'}) {				($myport, $myaddr) =					unpack_sockaddr_in(getsockname(SOCK));				$myname = gethostbyaddr($myaddr, AF_INET);				if ($myname eq "") {					$myname = inet_ntoa($myaddr);					}				$host = $myname;				}			else { $host = $config{'host'}; }			$port = $config{'port'};			while(&handle_request($acptaddr)) { }			close(SOCK);			close($PASSINw); close($PASSOUTw);			exit;			}		push(@childpids, $handpid);		if ($config{'passdelay'}) {			close($PASSINw); close($PASSOUTr);			push(@passin, $PASSINr); push(@passout, $PASSOUTw);			}		close(SOCK);		}	if ($config{'listen'} && vec($rmask, fileno(LISTEN), 1)) {		# Got UDP packet from another webmin server		local $rcvbuf;		local $from = recv(LISTEN, $rcvbuf, 1024, 0);		local $fromip = inet_ntoa((unpack_sockaddr_in($from))[1]);		if ((!@deny || !&ip_match($fromip, @deny)) &&		    (!@allow || &ip_match($fromip, @allow))) {			send(LISTEN, "$config{'host'}:$config{'port'}:".				     "$config{'ssl'}", 0, $from);			}		}	# check for password-timeout messages from subprocesses	for($i=0; $i<@passin; $i++) {		if (vec($rmask, fileno($passin[$i]), 1)) {			# this sub-process is asking about a password			$infd = $passin[$i]; $outfd = $passout[$i];			if (<$infd> =~ /^(\S+)\s+(\S+)\s+(\d+)/) {				# Got a delay request from a subprocess.. for				# valid logins, there is no delay (to prevent				# denial of service attacks), but for invalid				# logins the delay increases with each failed				# attempt.				#print STDERR "got $1 $2 $3\n";				if ($3) {					# login OK.. no delay					print $outfd "0\n";					}				else {					# login failed.. 					$dl = $userdlay{$1} -					      int((time() - $userlast{$1})/50);					$dl = $dl < 0 ? 0 : $dl+1;					print $outfd "$dl\n";					$userdlay{$1} = $dl;					}				$userlast{$1} = time();				}			else {				# close pipe				close($infd); close($outfd);				$passin[$i] = $passout[$i] = undef;				}			}		}	@passin = grep { defined($_) } @passin;	@passout = grep { defined($_) } @passout;	}# handle_request(address)# Where the real work is donesub handle_request{$acptip = inet_ntoa((unpack_sockaddr_in($_[0]))[1]);$datestr = &http_date(time());# Read the HTTP request and headers($reqline = &read_line()) =~ s/\r|\n//g;if (!($reqline =~ /^(GET|POST)\s+(.*)\s+HTTP\/1\..$/)) {	&http_error(400, "Bad Request");	}$method = $1; $request_uri = $page = $2;%header = ();while(1) {	($headline = &read_line()) =~ s/\r|\n//g;	if ($headline eq "") { last; }	($headline =~ /^(\S+):\s+(.*)$/) || &http_error(400, "Bad Header");	$header{lc($1)} = $2;	}if (defined($header{'host'})) {	if ($header{'host'} =~ /^([^:]+):([0-9]+)$/) { $host = $1; $port = $2; }	else { $host = $header{'host'}; $port = 80; }	}if ($page =~ /^([^\?]+)\?(.*)$/) {	# There is some query string information	$page = $1;	$querystring = $2;	if ($querystring !~ /=/) {		$queryargs = $querystring;		$queryargs =~ s/\+/ /g;    		$queryargs =~ s/%(..)/pack("c",hex($1))/ge;		$querystring = "";		}	}# replace %XX sequences in page$page =~ s/%(..)/pack("c",hex($1))/ge;# check address against access listif (@deny && &ip_match($acptip, @deny) ||    @allow && !&ip_match($acptip, @allow)) {	&http_error(403, "Access denied for $acptip");	next;	}# check for the logout flag file, and if existant deny authentication onceif ($config{'logout'} && -r $config{'logout'}) {	&write_data("HTTP/1.0 401 Unauthorized\r\n");	&write_data("Server: $config{server}\r\n");	&write_data("Date: $datestr\r\n");	&write_data("WWW-authenticate: Basic ".		    "realm=\"$config{realm}\"\r\n");	&write_data("Content-type: text/html\r\n");	&write_keep_alive(0);	&write_data("\r\n");	&reset_byte_count();	&write_data("<title>Please Login</title>\n");	&write_data("<h1>Please Login</h1>\n");	&write_data("Please login to the server as a new user.<p>\n");	&log_request($acptip, undef, $reqline, 401, &byte_count());	unlink($config{'logout'});	return 0;	}# Check for password if neededif (%users) {	$validated = 0;	if ($header{authorization} =~ /^basic\s+(\S+)$/i) {		# authorization given..		($authuser, $authpass) = split(/:/, &b64decode($1));		if ($authuser && $users{$authuser} && $users{$authuser} eq		    crypt($authpass, $users{$authuser})) {			$validated = 1;			}		#print STDERR "checking $authuser $authpass -> $validated\n";		if ($config{'passdelay'}) {			# check with main process for delay			print $PASSINw "$authuser $acptip $validated\n";			<$PASSOUTr> =~ /(\d+)/;			#print STDERR "sleeping for $1\n";			sleep($1);			}		}	if (!$validated) {		# No password given.. ask		&write_data("HTTP/1.0 401 Unauthorized\r\n");		&write_data("Server: $config{'server'}\r\n");		&write_data("Date: $datestr\r\n");		&write_data("WWW-authenticate: Basic ".			   "realm=\"$config{'realm'}\"\r\n");		&write_data("Content-type: text/html\r\n");		&write_keep_alive(0);		&write_data("\r\n");		&reset_byte_count();		&write_data("<title>Unauthorized</title>\n");		&write_data("<h1>Unauthorized</h1>\n");		&write_data("A password is required to access this\n");		&write_data("web server. Please try again. <p>\n");		&log_request($acptip, undef, $reqline, 401, &byte_count());		return 0;		}	}# Figure out what kind of page was requested$simple = &simplify_path($page, $bogus);if ($bogus) {	&http_error(400, "Invalid path");	}$sofar = ""; $full = $config{"root"} . $sofar;$scriptname = $simple;foreach $b (split(/\//, $simple)) {	if ($b ne "") { $sofar .= "/$b"; }	$full = $config{"root"} . $sofar;	@st = stat($full);	if (!@st) { &http_error(404, "File not found"); }	# Check if this is a directory	if (-d $full) {		# It is.. go on parsing		next;		}	# Check if this is a CGI program	if (&get_type($full) eq "internal/cgi") {		$pathinfo = substr($simple, length($sofar));		$pathinfo .= "/" if ($page =~ /\/$/);		$scriptname = $sofar;		last;		}	}# Reached the end of the path OK.. see what we've gotif (-d $full) {	# See if the URL ends with a / as it should	if ($page !~ /\/$/) {		# It doesn't.. redirect		&write_data("HTTP/1.0 302 Moved Temporarily\r\n");		$portstr = $port == 80 && !$use_ssl ? "" :			   $port == 443 && $use_ssl ? "" : ":$port";		&write_data("Date: $datestr\r\n");		&write_data("Server: $config{server}\r\n");		$prot = $use_ssl ? "https" : "http";		&write_data("Location: $prot://$host$portstr$page/\r\n");		&write_keep_alive(0);		&write_data("\r\n");		&log_request($acptip, $authuser, $reqline, 302, 0);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -