# HG changeset patch # User Matthias Förste # Date 1309929814 -7200 # Node ID 64e38b554da39e7799a04e0fec11154e9e3d8674 import diff -r 000000000000 -r 64e38b554da3 .hgignore --- /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$ diff -r 000000000000 -r 64e38b554da3 Build.PL --- /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; diff -r 000000000000 -r 64e38b554da3 bin/dav-htuseradd --- /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 . +# +# Matthias Förste + +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"; diff -r 000000000000 -r 64e38b554da3 bin/dav-htuseradd.cgi --- /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 . +# +# Matthias Förste + +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 @_; + +} diff -r 000000000000 -r 64e38b554da3 bin/dav-htuserdel --- /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 . +# +# Matthias Förste + +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; diff -r 000000000000 -r 64e38b554da3 dav-htpasswd.conf.ex --- /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) diff -r 000000000000 -r 64e38b554da3 lib/Ius/Dav/Htpasswd.pm --- /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 . +# +# Matthias Förste + +=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 < + Dav On + Order Allow,Deny + Allow From All + Deny From None + AuthType Basic + AuthName "$user" + AuthUserFile "$htpasswd_file" + Require user $master_user $user + +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 + +The name of the user to add or remove. + +=item B<-e|--expiry> I + +The time in days after which an added user will expire. Defaults to 1. + +=back + +=head1 FILES + +F + +F + +F<~/dav-htpasswd.conf> + +F<./dav-htpasswd.conf> + +F + +F + +F + +=head1 REQUIRES + +at from the 'at' job scheduler package. + +=head1 AUTHOR + +Matthias Förste + +=cut + +# vim:sts=4 sw=4 aw ai sm: