commit d0007f09ffdb74a0584d0f3a38c3a983aea1b189
parent 5d6620e98e6ef1fb8cfc76c58b8052dc31d2386a
Author: Kyle Milz <kyle@getaddrinfo.net>
Date: Sun, 1 Feb 2015 19:10:36 -0700
search: chroot, simplifications
- chroot when started, drop privileges
- move some hard coded variables to the config file
- add verbose debugging print outs
- open all resources after privilege drop
Diffstat:
M | PriceChart.pm | | | 17 | +++++++++++++---- |
M | search.pl | | | 111 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
2 files changed, 74 insertions(+), 54 deletions(-)
diff --git a/PriceChart.pm b/PriceChart.pm
@@ -10,12 +10,21 @@ use Exporter;
sub get_config
{
my $parser = Config::Grammar->new({
- _sections => ["general", "vendors"],
+ _sections => ["general", "http", "vendors"],
general => {
_vars => [
'user_agent',
'email',
- 'smtp'
+ 'smtp',
+ ],
+ },
+ http => {
+ _vars => [
+ "socket_file",
+ "uid",
+ "gid",
+ "chroot",
+ "db_dir",
],
},
vendors => {
@@ -41,8 +50,8 @@ sub get_config
sub get_dbh
{
# XXX: needs to be changed in production!
- # my $db_dir = "/var/www/db";
- my $db_dir = "./";
+ my $db_dir = shift || "/var/www/db";
+ # my $db_dir = "./";
mkdir $db_dir;
my $dbh = DBI->connect(
diff --git a/search.pl b/search.pl
@@ -3,84 +3,82 @@
use strict;
use warnings;
+# because we chroot all dependencies must be explicitly listed
+use Config::Grammar;
+use DBD::SQLite;
+use Encode;
use FCGI;
use Getopt::Std;
use Template;
+use Template::Context;
+use Template::Filters;
+use Template::Iterator;
+use Template::Parser;
+use Template::Plugins;
+use Template::Stash::XS;
use PriceChart;
use Unix::Syslog qw(:macros :subs);
use URI::Escape;
my %args;
-getopts("d", \%args);
+getopts("v", \%args);
-my $socket_file = "/var/www/run/search.sock";
-if (-e $socket_file) {
- print "Not starting, socket $socket_file exists\n";
- exit;
-}
-
-if (!$args{d} && fork()) {
- exit;
+# fork into background unless verbose
+unless ($args{v}) {
+ if (fork()) {
+ exit;
+ }
}
-openlog("pricechart_search", LOG_PID, LOG_DAEMON);
+my $cfg = get_config();
+my $db_dir = $cfg->{"http"}{"db_dir"};
+my $socket_file = $cfg->{"http"}{"socket_file"};
+my $uid_name = $cfg->{"http"}{"uid"};
+my $gid_name = $cfg->{"http"}{"gid"};
-my $socket = FCGI::OpenSocket($socket_file, 1024);
-syslog(LOG_DEBUG, "$socket_file created");
+# this looks up information in /etc
+my $uid = getpwnam($uid_name) or die "error: uid does not exist";
+my $gid = getgrnam($gid_name) or die "error: gid does not exist";
+print "info: $uid_name:$gid_name -> $uid:$gid\n" if ($args{v});;
-if (my $child_pid = fork()) {
- # keep the parent around to clean up the socket after we're done
+chroot($cfg->{"http"}{"chroot"});
+chdir("/");
+print "info: chroot done\n" if ($args{v});
- $SIG{INT} = \&parent_sig;
- $SIG{TERM} = \&parent_sig;
- sub parent_sig
- {
- my $signal = shift;
- kill $signal, $child_pid;
- }
+# XXX: verify we have indeed dropped privileges?
+$< = $> = $uid;
+$( = $) = "$gid $gid";
+print "info: uid:gid set to $<:$(\n" if ($args{v});
- # wait for the child to finish
- waitpid($child_pid, 0);
+openlog("pricechart_fcgi", LOG_PID, LOG_DAEMON);
+print "info: open syslog ok\n" if ($args{v});
- FCGI::CloseSocket($socket);
- unlink($socket_file) or
- syslog(LOG_WARNING, "could not unlink $socket_file: $!");
- closelog();
+if (-e $socket_file) {
+ my $msg = "socket file $socket_file exists\n";
+ print "error: $msg\n" if ($args{v});
+ syslog(LOG_ERR, $msg);
exit;
}
-my $uid = getpwnam("www");
-my $gid = getgrnam("daemon");
-
-# change ownership on socket otherwise httpd can't talk to us
-chown $uid, $gid, $socket_file;
+# XXX: i need to be sudo for this to work? after we've dropped privileges?
+my $socket = FCGI::OpenSocket($socket_file, 1024);
+print "info: open $socket_file ok\n" if ($args{v});
-# drop privileges
-$< = $> = $uid;
-$( = $) = "$gid $gid";
+my $dbh = get_dbh($db_dir);
+print "info: open $db_dir/pricechart.db ok\n" if ($args{v});
my $request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV,
$socket, FCGI::FAIL_ACCEPT_ON_INTR);
$SIG{INT} = \&child_sig;
$SIG{TERM} = \&child_sig;
-sub child_sig
-{
- my $signame = shift;
-
- $request->LastCall();
- syslog(LOG_DEBUG, "caught SIG$signame");
-}
my $config = {
- # XXX: this needs to be fixed
- INCLUDE_PATH => "/home/kyle/src/pricechart/html"
+ INCLUDE_PATH => "/htdocs/pricechart/templates"
};
-my $template = Template->new($config);
-
-my $dbh = get_dbh();
-syslog(LOG_DEBUG, "database opened");
+my $template = Template->new($config) || die $Template::ERROR . "\n";
+print "info: template config ok\n" if ($args{v});
my $sql = "select part_num, manufacturer, description from products " .
"where description like ? or part_num like ? or manufacturer like ?";
@@ -103,7 +101,20 @@ while ($request->Accept() >= 0) {
results => $products
};
- $template->process("search.html", $vars) || print $template->error();
+ $template->process("search.html", $vars) or print $template->error();
}
-syslog(LOG_INFO, "shut down");
+syslog(LOG_INFO, "shutdown");
+closelog();
+
$dbh->disconnect();
+
+FCGI::CloseSocket($socket);
+unlink($socket_file) or print "error: could not unlink $socket_file: $!";
+
+sub child_sig
+{
+ my $signame = shift;
+
+ $request->LastCall();
+ print "info: caught SIG$signame\n" if ($args{v});
+}