--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore Wed Jul 06 07:23:34 2011 +0200
@@ -0,0 +1,4 @@
+syntax regexp:
+
+^TODO$
+^dav-htpasswd.conf$
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Build.PL Wed Jul 06 07:23:34 2011 +0200
@@ -0,0 +1,20 @@
+#!/usr/bin/perl
+
+use Module::Build;
+my $build = Module::Build->new
+(
+ module_name => 'Ius::Dav::Htpasswd',
+ dist_version => '0.1',
+ license => 'gpl',
+ create_license => 1,
+ requires => {
+ 'Apache::Htpasswd' => 0,
+ 'AppConfig' => 0,
+ 'CGI::Fast' => 0,
+ 'File::Path' => 0,
+ 'POSIX' => 0,
+ 'String::MkPasswd' => 0
+ },
+ script_files => [glob 'bin/*']
+);
+$build->create_build_script;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/dav-htuseradd Wed Jul 06 07:23:34 2011 +0200
@@ -0,0 +1,48 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2011 Matthias Förste
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Matthias Förste <foerste@schlittermann.de>
+
+use strict;
+use warnings;
+
+use Ius::Dav::Htpasswd qw(readconfig useradd usage);
+
+use Getopt::Long;
+use Pod::Usage;
+
+my ($user, $expiry, $pass);
+
+GetOptions(
+ 'u|user=s' => \$user,
+ 'e|expiry=i' => \$expiry,
+ 'h|help' => sub { usage(-exit => 0, -verbose => 1) },
+ 'm|man' => sub {
+ usage(
+ -exit => 0,
+
+ # "system('perldoc -V &>/dev/null')" appears shorter, but may not
+ # do what you expect ( it still returns 0 on debian squeeze with
+ # dash as system shell even if cannot find the command in $PATH)
+ -noperldoc => system('perldoc -V >/dev/null 2>&1'),
+ -verbose => 2
+ );
+ },
+) and defined $user or usage;
+
+$pass = useradd readconfig, $user, $expiry;
+print "[$pass]\n";
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/dav-htuseradd.cgi Wed Jul 06 07:23:34 2011 +0200
@@ -0,0 +1,80 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2011 Matthias Förste
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Matthias Förste <foerste@schlittermann.de>
+
+use warnings;
+
+#use CGI::Fast;
+#use POSIX;
+
+while (my $q = new CGI::Fast) {
+
+ print $q->header(-charset => 'UTF-8');
+ print $q->start_html(
+ -title => $0,
+ -bgcolor => "white",
+ );
+
+ my ($user, $expiry) = (
+ $q->param('user'),
+ $q->param('expiry')
+ );
+
+ print $q->start_form, 'New User' => $q->textfield('user'), 'Expiry' => $q->textfield('expiry'), $q->submit, $q->end_form
+ unless defined $user or defined $expiry;
+
+ $expiry ||= $defaults->{expiry};
+ if (_validate $q, $user, $expiry) {
+
+ my $t = POSIX::strftime '%Y%m%d%H%M%S', time + 86400 * $expiry;
+ my @at_cmd = ('at', $t
+
+
+ } else {
+ _error ($q, 'invalid input');
+ }
+
+ print $q->end_html;
+
+}
+
+sub _validate {
+
+ my ($u, $e) = @_;
+
+ return unless $u =~ /^[[:alpha:]_]+$/;
+ return unless $e =~ /^[0-9]+$/;
+ return unless $e >= $defaults->{expiry_min} and $e <= $defaults->{expiry_max};
+
+ return 1;
+
+}
+
+sub _notice {
+
+ my ($q, @n) = @_;
+ print @_;
+
+}
+
+sub _error {
+
+ my ($q, @n) = @_;
+ print @_;
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/dav-htuserdel Wed Jul 06 07:23:34 2011 +0200
@@ -0,0 +1,40 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2011 Matthias Förste
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Matthias Förste <foerste@schlittermann.de>
+
+use strict;
+use warnings;
+
+use Getopt::Long;
+use Ius::Dav::Htpasswd qw(readconfig userdel usage);
+
+my $user;
+
+GetOptions(
+ 'u|user=s' => \$user,
+ "h|help" => sub { usage( -verbose => 0, -exitval => 0 ) },
+ "m|man" => sub {
+ usage(
+ -verbose => 2,
+ -exitval => 0,
+ -noperldoc => ( `perldoc -V 2>/dev/null`, $? != 0 )[-1]
+ );
+ },
+) and defined $user or usage();
+
+exit userdel readconfig, $user;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dav-htpasswd.conf.ex Wed Jul 06 07:23:34 2011 +0200
@@ -0,0 +1,12 @@
+expiry = 1 # expire user after this many days per default
+expiry_min = 1 # don't accept arguments less than expiry_min to the --expiry option
+expiry_max = 56 # don't accept arguments greater than expiry_max to the --expiry option
+
+dav_base = /srv/dav # user directories will be placed below dav_base
+htpasswd = /etc/apache2/htpasswd # where to place/look for the htpasswd
+conf_d = /etc/apache2/dav.d # where to place/look for configuration snippets
+
+www_user = www-data # webserver user
+www_group = www-data # webserver group
+
+master_user = david # master user with access to all directories (optional)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Ius/Dav/Htpasswd.pm Wed Jul 06 07:23:34 2011 +0200
@@ -0,0 +1,267 @@
+
+# Copyright (C) 2011 Matthias Förste
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Matthias Förste <foerste@schlittermann.de>
+
+=encoding utf8
+=cut
+
+package Ius::Dav::Htpasswd;
+
+use strict;
+use warnings;
+
+use Apache::Htpasswd;
+use AppConfig;
+use File::Path qw(rmtree);
+use POSIX;
+use String::MkPasswd qw(mkpasswd);
+
+BEGIN {
+
+ our ($VERSION, @ISA, @EXPORT_OK);
+ use Exporter;
+
+ # set the version for version checking
+ $VERSION = 0.1;
+
+ @ISA = qw(Exporter);
+ @EXPORT_OK = qw(readconfig useradd userdel usage);
+}
+
+sub usage {
+
+ use Pod::Usage;
+ use Pod::Find qw(pod_where);
+
+ pod2usage( -input => pod_where({-inc => 1}, __PACKAGE__), @_ );
+
+}
+
+sub readconfig {
+
+ my $conf = new AppConfig(qw(
+ expiry=i
+ expiry_min=i
+ expiry_max=i
+ dav_base=s
+ htpasswd=s
+ conf_d=s
+ www_user=s
+ www_group=s
+ master_user=s)
+ ) or die 'Failed to read config!';
+ $conf->file($_) for grep -e, map "$_/dav-htpasswd.conf", qw(/etc /usr/local/etc ~ .);
+ return { $conf->varlist('.') };
+
+}
+
+sub validate {
+
+ my ($conf, $user, $expiry) = @_;
+
+ return unless $user =~ /^[[:alpha:]_]+$/;
+
+ if (defined $expiry) {
+ return unless $expiry =~ /^[0-9]+$/;
+ return unless $expiry >= $conf->{expiry_min} and $expiry <= $conf->{expiry_max};
+ }
+
+ return 1;
+
+}
+
+sub useradd {
+
+ my ($conf, $user, $expiry) = @_;
+
+ for (qw(expiry expiry_min expiry_max dav_base htpasswd conf_d www_user www_group)) {
+ die "Can't determine '$_' - please check configuration"
+ unless defined $conf->{$_};
+ }
+
+ $expiry = $conf->{expiry} unless defined $expiry;
+ die 'Invalid input' unless validate $conf, $user, $expiry;
+
+ my $at_cmd = "at now + " . 24 * 60 * $expiry . " minutes";
+ open AT, "|$at_cmd"
+ or die "Can't open AT, '|$at_cmd': $!";
+ print AT "dav-htuserdel";
+ close AT;
+
+ my $user_dir = "$conf->{dav_base}/$user";
+ mkdir "$user_dir" or die "Can't mkdir '$user_dir': $!";
+
+ my ($www_user, $www_group) = @{$conf}{qw(www_user www_group)};
+ my $www_uid = getpwnam $www_user or die "Can't getpwnam '$www_user'";
+ my $www_gid = getgrnam $www_group or die "Can't getgrnam '$www_group'";
+ chown $www_uid, $www_gid, "$user_dir" or die "Can't chown, '$www_uid', '$www_gid', '$user_dir': $!";
+
+ my $pass = mkpasswd;
+ my $htpasswd_file = $conf->{htpasswd};
+ unless (-e $htpasswd_file ) {
+ open H, '>>', $htpasswd_file or die "Can't create '$htpasswd_file': $!";
+ close H;
+ }
+ my $htpasswd = new Apache::Htpasswd $htpasswd_file;
+ $htpasswd->htpasswd($user, $pass)
+ or die $htpasswd->error;
+
+ my $master_user = $conf->{master_user};
+ my $conf_file = "$conf->{conf_d}/$user.conf";
+ open C, '>', $conf_file or die "Can't open '$conf_file': $!";
+ print C <<EOC;
+<Directory "$user_dir">
+ Dav On
+ Order Allow,Deny
+ Allow From All
+ Deny From None
+ AuthType Basic
+ AuthName "$user"
+ AuthUserFile "$htpasswd_file"
+ Require user $master_user $user
+</Directory>
+EOC
+ close C;
+
+ 0 == system qw(apache2ctl graceful)
+ or die "Can't 'apache2ctl graceful'!";
+
+ return $pass;
+
+}
+
+sub userdel {
+
+ my ($conf, $user) = @_;
+
+ my $rc;
+
+ for (qw(dav_base htpasswd conf_d)) {
+ die "Can't determine '$_' - please check configuration"
+ unless defined $conf->{$_};
+ }
+
+ # avoid 'Found = in conditional, should be ==' warnings
+ no warnings qw(syntax);
+ my $user_dir = "$conf->{dav_base}/$user";
+ my $err;
+ rmtree($user_dir, error => $err)
+ or $rc = -1 and warn "Errors occurred during rmtree '$user_dir': ", @{$err};
+
+ my $htpasswd_file = $conf->{htpasswd};
+ my $htpasswd = new Apache::Htpasswd $htpasswd_file;
+ $htpasswd->htDelete($user)
+ or $rc = -1 and warn "Can't htdelete '$user': ", $htpasswd->error;
+
+ my $conf_file = "$conf->{conf_d}/$user.conf";
+ unlink $conf_file
+ or $rc = -1 and warn "Can't unlink '$conf_file': $!";
+
+ # maybe TODO: remove at job if it still exists (record job# during #
+ # 'useradd'?)
+
+ 0 == system qw(apache2ctl graceful)
+ or $rc =-1 and warn "Can't 'apache2ctl graceful'!";
+
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+ dav-useradd
+ dav-useradd.cgi
+ dav-userdel
+
+=head1 SYNOPSIS
+
+ dav-useradd -u|--user user
+ [-e|--expiry expiry]
+
+ dav-userdel -u|--user user
+
+ common options
+
+ -m|--man
+ -h|--help
+
+=head1 DESCRIPTION
+
+=head2 dav-useradd
+
+Add an at job to remove the user later. Make a directory for the user. Chown
+that directory to the webserver user and group. Add the user to an htpasswd
+file. Place a config snippet for the users directory inside a directory (which
+is included from the apache config, other webservers may also work). Reload
+apache (or maybe restart is required).
+
+=head2 dav-useradd.cgi
+
+Is supposed to do the same as dav-useradd.
+
+=head2 dav-userdel
+
+Removes the directory of the user. Removes the user from the htpasswd file.
+Removes the config snippet for the users directory. Removes the at job that is
+supposed to remove the user if it still exists. Reload apache (or maybe restart
+is required).
+
+=head1 OPTIONS
+
+=over
+
+=item B<-u|--user> I<user>
+
+The name of the user to add or remove.
+
+=item B<-e|--expiry> I<expiry>
+
+The time in days after which an added user will expire. Defaults to 1.
+
+=back
+
+=head1 FILES
+
+F</etc/dav-htpasswd.conf>
+
+F</usr/local/etc/dav-htpasswd.conf>
+
+F<~/dav-htpasswd.conf>
+
+F<./dav-htpasswd.conf>
+
+F</srv/dav>
+
+F</etc/apache2/htpasswd>
+
+F</etc/apache2/dav.d>
+
+=head1 REQUIRES
+
+at from the 'at' job scheduler package.
+
+=head1 AUTHOR
+
+Matthias Förste <foerste@schlittermann.de>
+
+=cut
+
+# vim:sts=4 sw=4 aw ai sm: