lib/Ius/Dav/Htpasswd.pm
changeset 0 64e38b554da3
child 1 f395a912407a
equal deleted inserted replaced
-1:000000000000 0:64e38b554da3
       
     1 
       
     2 #    Copyright (C) 2011 Matthias Förste
       
     3 #
       
     4 #    This program is free software: you can redistribute it and/or modify
       
     5 #    it under the terms of the GNU General Public License as published by
       
     6 #    the Free Software Foundation, either version 3 of the License, or
       
     7 #    (at your option) any later version.
       
     8 #
       
     9 #    This program is distributed in the hope that it will be useful,
       
    10 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12 #    GNU General Public License for more details.
       
    13 #
       
    14 #    You should have received a copy of the GNU General Public License
       
    15 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
       
    16 #
       
    17 #    Matthias Förste <foerste@schlittermann.de>
       
    18 
       
    19 =encoding utf8
       
    20 =cut
       
    21 
       
    22 package Ius::Dav::Htpasswd;
       
    23 
       
    24 use strict;
       
    25 use warnings;
       
    26 
       
    27 use Apache::Htpasswd;
       
    28 use AppConfig;
       
    29 use File::Path qw(rmtree);
       
    30 use POSIX;
       
    31 use String::MkPasswd qw(mkpasswd);
       
    32 
       
    33 BEGIN {
       
    34 
       
    35     our ($VERSION, @ISA, @EXPORT_OK);
       
    36     use Exporter;
       
    37 
       
    38     # set the version for version checking
       
    39     $VERSION = 0.1;
       
    40 
       
    41     @ISA    = qw(Exporter);
       
    42     @EXPORT_OK = qw(readconfig useradd userdel usage);
       
    43 }
       
    44 
       
    45 sub usage {
       
    46 
       
    47     use Pod::Usage;
       
    48     use Pod::Find qw(pod_where);
       
    49 
       
    50     pod2usage( -input => pod_where({-inc => 1}, __PACKAGE__), @_ );
       
    51 
       
    52 }
       
    53 
       
    54 sub readconfig {
       
    55 
       
    56     my $conf = new AppConfig(qw(
       
    57         expiry=i
       
    58         expiry_min=i
       
    59         expiry_max=i
       
    60         dav_base=s
       
    61         htpasswd=s
       
    62         conf_d=s
       
    63         www_user=s
       
    64         www_group=s
       
    65         master_user=s)
       
    66     ) or die 'Failed to read config!';
       
    67     $conf->file($_) for grep -e, map "$_/dav-htpasswd.conf", qw(/etc /usr/local/etc ~ .);
       
    68     return { $conf->varlist('.') };
       
    69 
       
    70 }
       
    71 
       
    72 sub validate {
       
    73 
       
    74     my ($conf, $user, $expiry) = @_;
       
    75 
       
    76     return unless $user =~ /^[[:alpha:]_]+$/; 
       
    77 
       
    78     if (defined $expiry) {
       
    79         return unless $expiry =~ /^[0-9]+$/;
       
    80         return unless $expiry >= $conf->{expiry_min} and $expiry <= $conf->{expiry_max};
       
    81     }
       
    82 
       
    83     return 1;
       
    84 
       
    85 }
       
    86 
       
    87 sub useradd {
       
    88 
       
    89     my ($conf, $user, $expiry) = @_;
       
    90 
       
    91     for (qw(expiry expiry_min expiry_max dav_base htpasswd conf_d www_user www_group)) {
       
    92         die "Can't determine '$_' - please check configuration"
       
    93             unless defined $conf->{$_};
       
    94     }
       
    95 
       
    96     $expiry = $conf->{expiry} unless defined $expiry;
       
    97     die 'Invalid input' unless validate $conf, $user, $expiry;
       
    98 
       
    99     my $at_cmd = "at now + " . 24 * 60 * $expiry . " minutes";
       
   100     open AT, "|$at_cmd"
       
   101         or die "Can't open AT, '|$at_cmd': $!";
       
   102     print AT "dav-htuserdel";
       
   103     close AT;
       
   104 
       
   105     my $user_dir = "$conf->{dav_base}/$user";
       
   106     mkdir "$user_dir" or die "Can't mkdir '$user_dir': $!";
       
   107 
       
   108     my ($www_user, $www_group) = @{$conf}{qw(www_user www_group)};
       
   109     my $www_uid = getpwnam $www_user or die "Can't getpwnam '$www_user'";
       
   110     my $www_gid = getgrnam $www_group or die "Can't getgrnam '$www_group'";
       
   111     chown $www_uid, $www_gid, "$user_dir" or die "Can't chown, '$www_uid', '$www_gid', '$user_dir': $!";
       
   112 
       
   113     my $pass = mkpasswd;
       
   114     my $htpasswd_file = $conf->{htpasswd};
       
   115     unless (-e $htpasswd_file ) {
       
   116         open H, '>>', $htpasswd_file or die "Can't create '$htpasswd_file': $!";
       
   117         close H;
       
   118     }
       
   119     my $htpasswd = new Apache::Htpasswd $htpasswd_file;
       
   120     $htpasswd->htpasswd($user, $pass)
       
   121         or die $htpasswd->error;
       
   122 
       
   123     my $master_user = $conf->{master_user};
       
   124     my $conf_file = "$conf->{conf_d}/$user.conf";
       
   125     open C, '>', $conf_file or die "Can't open '$conf_file': $!";
       
   126     print C <<EOC;
       
   127 <Directory "$user_dir">
       
   128     Dav On
       
   129     Order Allow,Deny
       
   130     Allow From All
       
   131     Deny From None
       
   132     AuthType Basic
       
   133     AuthName "$user"
       
   134     AuthUserFile "$htpasswd_file"
       
   135     Require user $master_user $user
       
   136 </Directory>
       
   137 EOC
       
   138     close C;
       
   139 
       
   140     0 == system qw(apache2ctl graceful)
       
   141         or die "Can't 'apache2ctl graceful'!";
       
   142 
       
   143     return $pass;
       
   144 
       
   145 }
       
   146 
       
   147 sub userdel {
       
   148 
       
   149     my ($conf, $user) = @_;
       
   150 
       
   151     my $rc;
       
   152 
       
   153     for (qw(dav_base htpasswd conf_d)) {
       
   154         die "Can't determine '$_' - please check configuration"
       
   155             unless defined $conf->{$_};
       
   156     }
       
   157 
       
   158     # avoid 'Found = in conditional, should be ==' warnings
       
   159     no warnings qw(syntax);
       
   160     my $user_dir = "$conf->{dav_base}/$user";
       
   161     my $err;
       
   162     rmtree($user_dir, error => $err)
       
   163         or $rc = -1 and warn "Errors occurred during rmtree '$user_dir': ", @{$err};
       
   164 
       
   165     my $htpasswd_file = $conf->{htpasswd};
       
   166     my $htpasswd = new Apache::Htpasswd $htpasswd_file;
       
   167     $htpasswd->htDelete($user)
       
   168         or $rc = -1 and warn "Can't htdelete '$user': ", $htpasswd->error;
       
   169 
       
   170     my $conf_file = "$conf->{conf_d}/$user.conf";
       
   171     unlink $conf_file
       
   172         or $rc = -1 and warn "Can't unlink '$conf_file': $!";
       
   173 
       
   174     # maybe TODO: remove at job if it still exists (record job# during #
       
   175     # 'useradd'?)
       
   176 
       
   177     0 == system qw(apache2ctl graceful)
       
   178         or $rc =-1 and warn "Can't 'apache2ctl graceful'!";
       
   179 
       
   180 }
       
   181 
       
   182 1;
       
   183 
       
   184 __END__
       
   185 
       
   186 =pod
       
   187 
       
   188 =head1 NAME
       
   189 
       
   190     dav-useradd
       
   191     dav-useradd.cgi
       
   192     dav-userdel
       
   193 
       
   194 =head1 SYNOPSIS
       
   195 
       
   196     dav-useradd  -u|--user user
       
   197                 [-e|--expiry expiry]
       
   198 
       
   199     dav-userdel -u|--user user
       
   200 
       
   201     common options
       
   202 
       
   203                 -m|--man
       
   204                 -h|--help
       
   205 
       
   206 =head1 DESCRIPTION
       
   207 
       
   208 =head2 dav-useradd
       
   209 
       
   210 Add an at job to remove the user later. Make a directory for the user. Chown
       
   211 that directory to the webserver user and group. Add the user to an htpasswd
       
   212 file. Place a config snippet for the users directory inside a directory (which
       
   213 is included from the apache config, other webservers may also work). Reload
       
   214 apache (or maybe restart is required).
       
   215 
       
   216 =head2 dav-useradd.cgi
       
   217 
       
   218 Is supposed to do the same as dav-useradd.
       
   219 
       
   220 =head2 dav-userdel
       
   221 
       
   222 Removes the directory of the user. Removes the user from the htpasswd file.
       
   223 Removes the config snippet for the users directory. Removes the at job that is
       
   224 supposed to remove the user if it still exists. Reload apache (or maybe restart
       
   225 is required).
       
   226 
       
   227 =head1 OPTIONS
       
   228 
       
   229 =over
       
   230 
       
   231 =item B<-u|--user> I<user>
       
   232 
       
   233 The name of the user to add or remove.
       
   234 
       
   235 =item B<-e|--expiry> I<expiry>
       
   236 
       
   237 The time in days after which an added user will expire. Defaults to 1.
       
   238 
       
   239 =back
       
   240 
       
   241 =head1 FILES
       
   242 
       
   243 F</etc/dav-htpasswd.conf>
       
   244 
       
   245 F</usr/local/etc/dav-htpasswd.conf>
       
   246 
       
   247 F<~/dav-htpasswd.conf>
       
   248 
       
   249 F<./dav-htpasswd.conf>
       
   250 
       
   251 F</srv/dav>
       
   252 
       
   253 F</etc/apache2/htpasswd>
       
   254 
       
   255 F</etc/apache2/dav.d>
       
   256 
       
   257 =head1 REQUIRES
       
   258 
       
   259 at from the 'at' job scheduler package.
       
   260 
       
   261 =head1 AUTHOR
       
   262 
       
   263 Matthias Förste <foerste@schlittermann.de>
       
   264 
       
   265 =cut
       
   266 
       
   267 # vim:sts=4 sw=4 aw ai sm: