import
authorMatthias Förste <foerste@schlittermann.de>
Wed, 06 Jul 2011 07:23:34 +0200
changeset 0 64e38b554da3
child 1 f395a912407a
import
.hgignore
Build.PL
bin/dav-htuseradd
bin/dav-htuseradd.cgi
bin/dav-htuserdel
dav-htpasswd.conf.ex
lib/Ius/Dav/Htpasswd.pm
--- /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: