|
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: |