1 |
jpp |
1.1 |
diff -Nur e-smith-base-5.8.0.old/root/etc/e-smith/events/actions/adjust-services e-smith-base-5.8.0/root/etc/e-smith/events/actions/adjust-services |
2 |
|
|
--- e-smith-base-5.8.0.old/root/etc/e-smith/events/actions/adjust-services 1969-12-31 19:00:00.000000000 -0500 |
3 |
|
|
+++ e-smith-base-5.8.0/root/etc/e-smith/events/actions/adjust-services 2020-11-16 01:15:19.192000000 -0500 |
4 |
|
|
@@ -0,0 +1,146 @@ |
5 |
|
|
+#!/usr/bin/perl -w |
6 |
|
|
+#---------------------------------------------------------------------- |
7 |
|
|
+# copyright (C) 2005 Mitel Networks Corporation |
8 |
|
|
+# |
9 |
|
|
+# This program is free software; you can redistribute it and/or modify |
10 |
|
|
+# it under the terms of the GNU General Public License as published by |
11 |
|
|
+# the Free Software Foundation; either version 2 of the License, or |
12 |
|
|
+# (at your option) any later version. |
13 |
|
|
+# |
14 |
|
|
+# This program is distributed in the hope that it will be useful, |
15 |
|
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
|
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 |
|
|
+# GNU General Public License for more details. |
18 |
|
|
+# |
19 |
|
|
+# You should have received a copy of the GNU General Public License |
20 |
|
|
+# along with this program; if not, write to the Free Software |
21 |
|
|
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 |
|
|
+# |
23 |
|
|
+#---------------------------------------------------------------------- |
24 |
|
|
+package esmith; |
25 |
|
|
+ |
26 |
|
|
+use strict; |
27 |
|
|
+use Errno; |
28 |
|
|
+use DirHandle; |
29 |
|
|
+ |
30 |
|
|
+my $event = shift || die "must give event name parameter"; |
31 |
|
|
+chdir "/etc/e-smith/events/$event" or die "Couldn't chdir to event directory /etc/e-smith/events/$event: $!"; |
32 |
|
|
+my $dh = DirHandle->new("services2adjust"); |
33 |
|
|
+ |
34 |
|
|
+exit(0) unless $dh; # Nothing to do |
35 |
|
|
+ |
36 |
|
|
+use esmith::ConfigDB; |
37 |
|
|
+use esmith::util; |
38 |
|
|
+ |
39 |
|
|
+my %param2char = ( |
40 |
|
|
+ down => 'd', |
41 |
|
|
+ stop => 'd', |
42 |
|
|
+ up => 'u', |
43 |
|
|
+ start => 'u', |
44 |
|
|
+ restart => 't', |
45 |
|
|
+ sigterm => 't', |
46 |
|
|
+ adjust => 'h', |
47 |
|
|
+ reload => 'h', |
48 |
|
|
+ sighup => 'h', |
49 |
|
|
+ sigusr1 => '1', |
50 |
|
|
+ sigusr2 => '2', |
51 |
|
|
+ once => 'o', |
52 |
|
|
+ pause => 'p', |
53 |
|
|
+ alarm => 'a', |
54 |
|
|
+ interrupt => 'i', |
55 |
|
|
+ quit => 'q', |
56 |
|
|
+ kill => 'k', |
57 |
|
|
+ exit => 'x', |
58 |
|
|
+ ); |
59 |
|
|
+ |
60 |
|
|
+sub adjust_supervised_service |
61 |
|
|
+{ |
62 |
|
|
+ my ($s, @actions) = @_; |
63 |
|
|
+ my $m = "control fifo for service $s: "; |
64 |
|
|
+ unless (open(C, ">/service/$s/supervise/control")) |
65 |
|
|
+ { |
66 |
|
|
+ warn "Couldn't open $m$!"; |
67 |
|
|
+ return; |
68 |
|
|
+ } |
69 |
|
|
+ foreach my $p (@actions) |
70 |
|
|
+ { |
71 |
|
|
+ my $c = $param2char{$p}; |
72 |
|
|
+ unless ($c) |
73 |
|
|
+ { |
74 |
|
|
+ warn "Unrecognised param $p for service $s\n"; |
75 |
|
|
+ next; |
76 |
|
|
+ } |
77 |
|
|
+ warn "adjusting supervised $s ($p)\n"; |
78 |
|
|
+ unless (print C $c) |
79 |
|
|
+ { |
80 |
|
|
+ warn "Couldn't write to $m$!"; |
81 |
|
|
+ return; |
82 |
|
|
+ } |
83 |
|
|
+ } |
84 |
|
|
+ warn "Couldn't close $m$!" unless close(C); |
85 |
|
|
+} |
86 |
|
|
+ |
87 |
|
|
+my $conf = esmith::ConfigDB->open_ro || die "Couldn't open config db"; |
88 |
|
|
+ |
89 |
|
|
+foreach my $service (grep { !/^\./ } $dh->read()) |
90 |
|
|
+{ |
91 |
|
|
+ my $s = $conf->get($service); |
92 |
|
|
+ unless ($s) |
93 |
|
|
+ { |
94 |
|
|
+ warn "No conf db entry for service $service\n"; |
95 |
|
|
+ next; |
96 |
|
|
+ } |
97 |
|
|
+ my $f = "services2adjust/$service"; |
98 |
|
|
+ |
99 |
|
|
+ my @actions; |
100 |
|
|
+ if (-l "$f") |
101 |
|
|
+ { |
102 |
|
|
+ @actions = ( readlink "$f" ); |
103 |
|
|
+ } |
104 |
|
|
+ else |
105 |
|
|
+ { |
106 |
|
|
+ if (open(F, $f)) |
107 |
|
|
+ { |
108 |
|
|
+ # Read list of actions from the file, and untaint |
109 |
|
|
+ @actions = map { chomp; /([a-z]+[12]?)/ ; $1 } <F>; |
110 |
|
|
+ close(F); |
111 |
|
|
+ } |
112 |
|
|
+ else |
113 |
|
|
+ { |
114 |
|
|
+ warn "Could not open $f: $!"; |
115 |
|
|
+ } |
116 |
|
|
+ } |
117 |
|
|
+ |
118 |
|
|
+ # if service is supervised and not handled by systemd |
119 |
|
|
+ if (-d "/service/$service" && glob("/etc/rc7.d/S??$service")) |
120 |
|
|
+ { |
121 |
|
|
+ my $enabled = ($s->prop('status') || 'disabled') eq 'enabled'; |
122 |
|
|
+ adjust_supervised_service($service, |
123 |
|
|
+ # stop the service if it is now disabled |
124 |
|
|
+ $enabled ? () : 'down', |
125 |
|
|
+ # Send the specified signal(s) to the running daemon |
126 |
|
|
+ @actions, |
127 |
|
|
+ # bring the service up if it is enabled (and we're not |
128 |
|
|
+ # stopping it or running it once) |
129 |
|
|
+ ($enabled && !grep { /^(down|stop|d|once|o)$/ } @actions) ? 'up' : (), |
130 |
|
|
+ ); |
131 |
|
|
+ } |
132 |
|
|
+ # for service handled by former sysvinit or directly with systemd |
133 |
|
|
+ else |
134 |
|
|
+ { |
135 |
|
|
+ my $enabled = ($s->prop('status') || 'disabled') eq 'enabled'; |
136 |
|
|
+ # stop the service if it is now disabled |
137 |
|
|
+ unshift(@actions,'stop') unless $enabled; |
138 |
|
|
+ # bring the service up if it is enabled (and we're not stopping it or running it once) |
139 |
|
|
+ push(@actions,'start') if ($enabled && !grep { /^(down|stop|d|once|o|start|restart|reload-or-restart)$/ } @actions) ; |
140 |
|
|
+ foreach (@actions) |
141 |
|
|
+ { |
142 |
|
|
+ warn "adjusting non-supervised $service ($_)\n"; |
143 |
|
|
+ esmith::util::serviceControl( |
144 |
|
|
+ NAME => $service, |
145 |
|
|
+ ACTION => $_, |
146 |
|
|
+ ); |
147 |
|
|
+ } |
148 |
|
|
+ } |
149 |
|
|
+} |
150 |
|
|
+ |
151 |
|
|
diff -Nur e-smith-base-5.8.0.old/root/sbin/e-smith/service-status e-smith-base-5.8.0/root/sbin/e-smith/service-status |
152 |
|
|
--- e-smith-base-5.8.0.old/root/sbin/e-smith/service-status 2020-11-16 01:04:00.182000000 -0500 |
153 |
|
|
+++ e-smith-base-5.8.0/root/sbin/e-smith/service-status 2020-11-16 21:55:20.898000000 -0500 |
154 |
|
|
@@ -22,8 +22,9 @@ |
155 |
|
|
|
156 |
|
|
if [[ "$STATUS" != 'enabled' ]] |
157 |
|
|
then |
158 |
|
|
- echo "$SERVICE will not start (service status not enabled)" |
159 |
|
|
- exit 5 |
160 |
|
|
+ echo "$SERVICE status not enabled in configuration db." |
161 |
|
|
+ exit 0 |
162 |
|
|
+ # change this one to 5 if you want systemd to fail on ExecStartPre |
163 |
|
|
fi |
164 |
|
|
|
165 |
|
|
exit 0 |
166 |
|
|
diff -Nur e-smith-base-5.8.0.old/root/usr/share/perl5/vendor_perl/esmith/util.pm e-smith-base-5.8.0/root/usr/share/perl5/vendor_perl/esmith/util.pm |
167 |
|
|
--- e-smith-base-5.8.0.old/root/usr/share/perl5/vendor_perl/esmith/util.pm 1969-12-31 19:00:00.000000000 -0500 |
168 |
|
|
+++ e-smith-base-5.8.0/root/usr/share/perl5/vendor_perl/esmith/util.pm 2020-11-16 01:05:33.057000000 -0500 |
169 |
|
|
@@ -0,0 +1,1404 @@ |
170 |
|
|
+#---------------------------------------------------------------------- |
171 |
|
|
+# Copyright 1999-2003 Mitel Networks Corporation |
172 |
|
|
+# This program is free software; you can redistribute it and/or |
173 |
|
|
+# modify it under the same terms as Perl itself. |
174 |
|
|
+#---------------------------------------------------------------------- |
175 |
|
|
+ |
176 |
|
|
+package esmith::util; |
177 |
|
|
+ |
178 |
|
|
+use strict; |
179 |
|
|
+ |
180 |
|
|
+use Text::Template 'fill_in_file'; |
181 |
|
|
+use POSIX qw (setsid); |
182 |
|
|
+use Errno; |
183 |
|
|
+use Carp; |
184 |
|
|
+use esmith::config; |
185 |
|
|
+use esmith::db; |
186 |
|
|
+use esmith::DB; |
187 |
|
|
+use esmith::ConfigDB; |
188 |
|
|
+use Net::IPv4Addr qw(:all); |
189 |
|
|
+use Taint::Util; |
190 |
|
|
+use File::Basename; |
191 |
|
|
+use File::stat; |
192 |
|
|
+use FileHandle; |
193 |
|
|
+use Data::UUID; |
194 |
|
|
+=pod |
195 |
|
|
+ |
196 |
|
|
+=head1 NAME |
197 |
|
|
+ |
198 |
|
|
+esmith::util - Utilities for e-smith server and gateway development |
199 |
|
|
+ |
200 |
|
|
+=head1 VERSION |
201 |
|
|
+ |
202 |
|
|
+This file documents C<esmith::util> version B<1.4.0> |
203 |
|
|
+ |
204 |
|
|
+=head1 SYNOPSIS |
205 |
|
|
+ |
206 |
|
|
+ use esmith::util; |
207 |
|
|
+ |
208 |
|
|
+=head1 DESCRIPTION |
209 |
|
|
+ |
210 |
|
|
+This module provides general utilities of use to developers of the |
211 |
|
|
+e-smith server and gateway. |
212 |
|
|
+ |
213 |
|
|
+=head1 GENERAL UTILITIES |
214 |
|
|
+ |
215 |
|
|
+=head2 setRealToEffective() |
216 |
|
|
+ |
217 |
|
|
+Sets the real UID to the effective UID and the real GID to the effective |
218 |
|
|
+GID. |
219 |
|
|
+ |
220 |
|
|
+=begin testing |
221 |
|
|
+ |
222 |
|
|
+use_ok('esmith::util'); |
223 |
|
|
+ |
224 |
|
|
+=end testing |
225 |
|
|
+ |
226 |
|
|
+=cut |
227 |
|
|
+ |
228 |
|
|
+sub setRealToEffective () |
229 |
|
|
+{ |
230 |
|
|
+ $< = $>; |
231 |
|
|
+ $( = $); |
232 |
|
|
+} |
233 |
|
|
+ |
234 |
|
|
+=pod |
235 |
|
|
+ |
236 |
|
|
+=head2 processTemplate({ CONFREF => $conf, TEMPLATE_PATH => $path }) |
237 |
|
|
+ |
238 |
|
|
+B<Depreacted> interface to esmith::templates::processTemplate(). |
239 |
|
|
+ |
240 |
|
|
+=cut |
241 |
|
|
+ |
242 |
|
|
+sub processTemplate |
243 |
|
|
+{ |
244 |
|
|
+ require esmith::templates; |
245 |
|
|
+ goto &esmith::templates::processTemplate; |
246 |
|
|
+} |
247 |
|
|
+ |
248 |
|
|
+#------------------------------------------------------------ |
249 |
|
|
+ |
250 |
|
|
+=pod |
251 |
|
|
+ |
252 |
|
|
+=head2 chownfile($user, $group, $file) |
253 |
|
|
+ |
254 |
|
|
+This routine changes the ownership of a file, automatically converting |
255 |
|
|
+usernames and groupnames to UIDs and GIDs respectively. |
256 |
|
|
+ |
257 |
|
|
+=cut |
258 |
|
|
+ |
259 |
|
|
+sub chownFile ($$$) |
260 |
|
|
+{ |
261 |
|
|
+ my ( $user, $group, $file ) = @_; |
262 |
|
|
+ |
263 |
|
|
+ unless ( -e $file ) |
264 |
|
|
+ { |
265 |
|
|
+ warn("can't chownFile $file: $!\n"); |
266 |
|
|
+ return; |
267 |
|
|
+ } |
268 |
|
|
+ my $uid = defined $user ? getpwnam($user) : stat($file)->uid; |
269 |
|
|
+ my $gid = defined $group ? getgrnam($group) : stat($file)->gid; |
270 |
|
|
+ |
271 |
|
|
+ chown( $uid, $gid, $file ); |
272 |
|
|
+} |
273 |
|
|
+ |
274 |
|
|
+=pod |
275 |
|
|
+ |
276 |
|
|
+=head2 determineRelease() |
277 |
|
|
+ |
278 |
|
|
+Returns the current release version of the software. |
279 |
|
|
+ |
280 |
|
|
+=cut |
281 |
|
|
+ |
282 |
|
|
+sub determineRelease() |
283 |
|
|
+{ |
284 |
|
|
+ my $unknown = "(unknown version)"; |
285 |
|
|
+ |
286 |
|
|
+ my $db = esmith::ConfigDB->open() or return $unknown; |
287 |
|
|
+ |
288 |
|
|
+ my $sysconfig = $db->get("sysconfig") or return $unknown; |
289 |
|
|
+ |
290 |
|
|
+ my $release = $sysconfig->prop("ReleaseVersion") || $unknown; |
291 |
|
|
+ |
292 |
|
|
+ return $release; |
293 |
|
|
+} |
294 |
|
|
+ |
295 |
|
|
+=pod |
296 |
|
|
+ |
297 |
|
|
+=head1 NETWORK ADDRESS TRANSLATION UTILITIES |
298 |
|
|
+ |
299 |
|
|
+=head2 IPquadToAddr($ip) |
300 |
|
|
+ |
301 |
|
|
+Convert IP address from "xxx.xxx.xxx.xxx" notation to a 32-bit |
302 |
|
|
+integer. |
303 |
|
|
+ |
304 |
|
|
+=cut |
305 |
|
|
+ |
306 |
|
|
+sub IPquadToAddr ($) |
307 |
|
|
+{ |
308 |
|
|
+ my ($quad) = @_; |
309 |
|
|
+ return 0 unless defined $quad; |
310 |
|
|
+ if ( $quad =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ ) |
311 |
|
|
+ { |
312 |
|
|
+ return ( $1 << 24 ) + ( $2 << 16 ) + ( $3 << 8 ) + $4; |
313 |
|
|
+ } |
314 |
|
|
+ return 0; |
315 |
|
|
+} |
316 |
|
|
+ |
317 |
|
|
+=pod |
318 |
|
|
+ |
319 |
|
|
+=head2 IPaddrToQuad($address) |
320 |
|
|
+ |
321 |
|
|
+Convert IP address from a 32-bit integer to "xxx.xxx.xxx.xxx" |
322 |
|
|
+notation. |
323 |
|
|
+ |
324 |
|
|
+=cut |
325 |
|
|
+ |
326 |
|
|
+sub IPaddrToQuad ($) |
327 |
|
|
+{ |
328 |
|
|
+ my ($addrBits) = @_; |
329 |
|
|
+ return sprintf( "%d.%d.%d.%d", |
330 |
|
|
+ ( $addrBits >> 24 ) & 0xff, |
331 |
|
|
+ ( $addrBits >> 16 ) & 0xff, |
332 |
|
|
+ ( $addrBits >> 8 ) & 0xff, |
333 |
|
|
+ $addrBits & 0xff ); |
334 |
|
|
+} |
335 |
|
|
+ |
336 |
|
|
+=pod |
337 |
|
|
+ |
338 |
|
|
+=head2 IPaddrToBackwardQuad($address) |
339 |
|
|
+ |
340 |
|
|
+Convert IP address from a 32-bit integer to reversed |
341 |
|
|
+"xxx.xxx.xxx.xxx.in-addr.arpa" notation for BIND files. |
342 |
|
|
+ |
343 |
|
|
+=cut |
344 |
|
|
+ |
345 |
|
|
+sub IPaddrToBackwardQuad ($) |
346 |
|
|
+{ |
347 |
|
|
+ my ($addrBits) = @_; |
348 |
|
|
+ return sprintf( |
349 |
|
|
+ "%d.%d.%d.%d.in-addr.arpa.", |
350 |
|
|
+ $addrBits & 0xff, |
351 |
|
|
+ ( $addrBits >> 8 ) & 0xff, |
352 |
|
|
+ ( $addrBits >> 16 ) & 0xff, |
353 |
|
|
+ ( $addrBits >> 24 ) & 0xff |
354 |
|
|
+ ); |
355 |
|
|
+} |
356 |
|
|
+ |
357 |
|
|
+=pod |
358 |
|
|
+ |
359 |
|
|
+=head2 computeNetworkAndBroadcast($ipaddr, $netmask) |
360 |
|
|
+ |
361 |
|
|
+Given an IP address and netmask (both in "xxx.xxx.xxx.xxx" format) |
362 |
|
|
+compute the network and broadcast addresses and output them in the |
363 |
|
|
+same format. |
364 |
|
|
+ |
365 |
|
|
+=cut |
366 |
|
|
+ |
367 |
|
|
+sub computeNetworkAndBroadcast ($$) |
368 |
|
|
+{ |
369 |
|
|
+ my ( $ipaddr, $netmask ) = @_; |
370 |
|
|
+ |
371 |
|
|
+ my ( $network, $msk ) = ipv4_network( $ipaddr, $netmask ); |
372 |
|
|
+ my $broadcast = ipv4_broadcast( $ipaddr, $netmask ); |
373 |
|
|
+ |
374 |
|
|
+ return ( $network, $broadcast ); |
375 |
|
|
+} |
376 |
|
|
+ |
377 |
|
|
+=pod |
378 |
|
|
+ |
379 |
|
|
+=head2 computeLocalNetworkPrefix($ipaddr, $netmask) |
380 |
|
|
+ |
381 |
|
|
+Given an IP address and netmask, the computeLocalNetworkPrefix |
382 |
|
|
+function computes the network prefix for local machines. |
383 |
|
|
+ |
384 |
|
|
+i.e. for an IP address of 192.168.8.4 and netmask of 255.255.255.0, |
385 |
|
|
+this function will return "192.168.8.". |
386 |
|
|
+ |
387 |
|
|
+This string is suitable for use in configuration files (such as |
388 |
|
|
+/etc/proftpd.conf) when the more precise notation |
389 |
|
|
+ |
390 |
|
|
+ xxx.xxx.xxx.xxx/yyy.yyy.yyy.yyy |
391 |
|
|
+ |
392 |
|
|
+is not supported. |
393 |
|
|
+ |
394 |
|
|
+=cut |
395 |
|
|
+ |
396 |
|
|
+sub computeLocalNetworkPrefix ($$) |
397 |
|
|
+{ |
398 |
|
|
+ my ( $ipaddr, $netmask ) = @_; |
399 |
|
|
+ |
400 |
|
|
+ my ( $net, $msk ) = ipv4_network( $ipaddr, $netmask ); |
401 |
|
|
+ $net =~ s/(\d{1,3}\.\d{1,3}\.\d{1,3}\.)(\d{1,3})/$1/; |
402 |
|
|
+ |
403 |
|
|
+ return $net; |
404 |
|
|
+} |
405 |
|
|
+ |
406 |
|
|
+=pod |
407 |
|
|
+ |
408 |
|
|
+=head2 computeAllLocalNetworkPrefixes ($ipaddress, $netmask) |
409 |
|
|
+ |
410 |
|
|
+ Given an IP address and netmask, the computeAllLocalNetworkPrefixes |
411 |
|
|
+ function computes the network prefix or list of prefixes that |
412 |
|
|
+ fully describe the network to which the IP address belongs. |
413 |
|
|
+ |
414 |
|
|
+ examples: |
415 |
|
|
+ |
416 |
|
|
+ - for an IP address of 192.168.8.4 and netmask of 255.255.255.0, |
417 |
|
|
+ will return an array with a first (and only) element of "192.168.8". |
418 |
|
|
+ |
419 |
|
|
+ - for an IP address of 192.168.8.4 and netmask of 255.255.254.0, |
420 |
|
|
+ will return the array [ '192.168.8', '192.168.9' ]. |
421 |
|
|
+ |
422 |
|
|
+ This array is suitable for use in configuration of tools such as |
423 |
|
|
+ djbdns where other network notations are not supported. |
424 |
|
|
+ |
425 |
|
|
+=begin testing |
426 |
|
|
+ |
427 |
|
|
+is_deeply( |
428 |
|
|
+ [esmith::util::computeAllLocalNetworkPrefixes("192.168.8.4", |
429 |
|
|
+ "255.255.254.0")], |
430 |
|
|
+ ['192.168.8', '192.168.9' ], |
431 |
|
|
+ "/23 network" |
432 |
|
|
+ ); |
433 |
|
|
+ |
434 |
|
|
+is_deeply( |
435 |
|
|
+ [esmith::util::computeAllLocalNetworkPrefixes("192.168.8.4", |
436 |
|
|
+ "255.255.255.255")], |
437 |
|
|
+ ['192.168.8.4'], |
438 |
|
|
+ "/32 network" |
439 |
|
|
+ ); |
440 |
|
|
+ |
441 |
|
|
+is_deeply( |
442 |
|
|
+ [esmith::util::computeAllLocalNetworkPrefixes("192.168.8.4", |
443 |
|
|
+ "255.255.255.0")], |
444 |
|
|
+ ['192.168.8'], |
445 |
|
|
+ "/24 network" |
446 |
|
|
+ ); |
447 |
|
|
+ |
448 |
|
|
+=end testing |
449 |
|
|
+ |
450 |
|
|
+=cut |
451 |
|
|
+ |
452 |
|
|
+sub computeAllLocalNetworkPrefixes |
453 |
|
|
+{ |
454 |
|
|
+ my ( $ipaddr, $netmask ) = @_; |
455 |
|
|
+ |
456 |
|
|
+ my $ipaddrBits = IPquadToAddr($ipaddr); |
457 |
|
|
+ my $netmaskBits = IPquadToAddr($netmask); |
458 |
|
|
+ my $networkBits = $ipaddrBits & $netmaskBits; |
459 |
|
|
+ |
460 |
|
|
+ # first, calculate the prefix (/??) given the netmask |
461 |
|
|
+ my $len = 0; |
462 |
|
|
+ for ( my $bits = $netmaskBits ; $bits & 0xFFFFFFFF ; $bits <<= 1 ) |
463 |
|
|
+ { |
464 |
|
|
+ $len++; |
465 |
|
|
+ } |
466 |
|
|
+ |
467 |
|
|
+ # Here's where the magic starts... |
468 |
|
|
+ # |
469 |
|
|
+ # next, calculate the number of networks we expect to generate and |
470 |
|
|
+ # the incrementing value for each network. |
471 |
|
|
+ my $number_of_nets = 1 << ( ( 32 - $len ) % 8 ); |
472 |
|
|
+ my $one_net = 1 << ( 3 - ( int $len / 8 ) ) * 8; |
473 |
|
|
+ my @networks; |
474 |
|
|
+ while ( $number_of_nets-- ) |
475 |
|
|
+ { |
476 |
|
|
+ my $network = IPaddrToQuad($networkBits); |
477 |
|
|
+ |
478 |
|
|
+ # we want to strip off the trailing ``.0'' for /24 or larger networks |
479 |
|
|
+ if ( $len <= 24 ) |
480 |
|
|
+ { |
481 |
|
|
+ $network =~ s/\.0$//; |
482 |
|
|
+ } |
483 |
|
|
+ |
484 |
|
|
+ # we want to continue to strip off trailing ``.0'', one more for |
485 |
|
|
+ # /9 to /16, two more for /1 to /8 |
486 |
|
|
+ $network =~ s/\.0$// if ( $len <= 16 ); |
487 |
|
|
+ $network =~ s/\.0$// if ( $len <= 8 ); |
488 |
|
|
+ |
489 |
|
|
+ # push the resulting network into an array that we'll return; |
490 |
|
|
+ push @networks, $network; |
491 |
|
|
+ |
492 |
|
|
+ # increment the network by ``one'', relative to the size of networks |
493 |
|
|
+ # we're dealing with |
494 |
|
|
+ $networkBits += $one_net; |
495 |
|
|
+ } |
496 |
|
|
+ return (@networks); |
497 |
|
|
+} |
498 |
|
|
+ |
499 |
|
|
+=pod |
500 |
|
|
+ |
501 |
|
|
+=head2 computeLocalNetworkShortSpec($ipaddr, $netmask) |
502 |
|
|
+ |
503 |
|
|
+Given an IP address and netmask, the computeLocalNetworkShortSpec |
504 |
|
|
+function computes a valid xxx.xxx.xxx.xxx/yyy specifier where yyy |
505 |
|
|
+is the number of bits specifying the network. |
506 |
|
|
+ |
507 |
|
|
+i.e. for an IP address of 192.168.8.4 and netmask of 255.255.255.0, |
508 |
|
|
+this function will return "192.168.8.0/24". |
509 |
|
|
+ |
510 |
|
|
+This string is suitable for use in configuration files (such as |
511 |
|
|
+/etc/proftpd.conf) when the more precise notation |
512 |
|
|
+ |
513 |
|
|
+ xxx.xxx.xxx.xxx/yyy.yyy.yyy.yyy |
514 |
|
|
+ |
515 |
|
|
+is not supported. |
516 |
|
|
+ |
517 |
|
|
+=cut |
518 |
|
|
+ |
519 |
|
|
+sub computeLocalNetworkShortSpec ($$) |
520 |
|
|
+{ |
521 |
|
|
+ my ( $ipaddr, $netmask ) = @_; |
522 |
|
|
+ my ( $net, $mask ) = ipv4_network( $ipaddr, $netmask ); |
523 |
|
|
+ return "$net/$mask"; |
524 |
|
|
+} |
525 |
|
|
+ |
526 |
|
|
+=pod |
527 |
|
|
+ |
528 |
|
|
+=head2 computeLocalNetworkSpec($ipaddr, $netmask) |
529 |
|
|
+ |
530 |
|
|
+Given an IP address and netmask, the computeLocalNetworkSpec function |
531 |
|
|
+computes a valid xxx.xxx.xxx.xxx/yyy.yyy.yyy.yyy specifier. |
532 |
|
|
+ |
533 |
|
|
+=cut |
534 |
|
|
+ |
535 |
|
|
+sub computeLocalNetworkSpec ($$) |
536 |
|
|
+{ |
537 |
|
|
+ my ( $ipaddr, $netmask ) = @_; |
538 |
|
|
+ my ( $net, $mask ) = ipv4_network( $ipaddr, $netmask ); |
539 |
|
|
+ $mask = ipv4_cidr2msk($mask); |
540 |
|
|
+ return "$net/$mask"; |
541 |
|
|
+} |
542 |
|
|
+ |
543 |
|
|
+=pod |
544 |
|
|
+ |
545 |
|
|
+=head2 computeNetmaskFromBits ($bits) |
546 |
|
|
+ |
547 |
|
|
+Given a number of bits of network address, calculate the appropriate |
548 |
|
|
+netmask. |
549 |
|
|
+ |
550 |
|
|
+=cut |
551 |
|
|
+ |
552 |
|
|
+sub computeNetmaskFromBits ($) |
553 |
|
|
+{ |
554 |
|
|
+ my ($ones) = @_; |
555 |
|
|
+ |
556 |
|
|
+ return ipv4_cidr2msk($ones); |
557 |
|
|
+} |
558 |
|
|
+ |
559 |
|
|
+=pod |
560 |
|
|
+ |
561 |
|
|
+=head2 computeLocalNetworkReversed($ipaddr, $netmask) |
562 |
|
|
+ |
563 |
|
|
+Given an IP address and netmask, the computeLocalNetworkReversed |
564 |
|
|
+function computes the appropriate DNS domain field. |
565 |
|
|
+ |
566 |
|
|
+NOTE: The return value is aligned to the next available byte boundary, i.e. |
567 |
|
|
+ |
568 |
|
|
+ 192.168.8.4/255.255.255.0 returns "8.168.192.in-addr.arpa." |
569 |
|
|
+ 192.168.8.4/255.255.252.0 returns "168.192.in-addr.arpa." |
570 |
|
|
+ 192.168.8.4/255.255.0.0 returns "168.192.in-addr.arpa." |
571 |
|
|
+ 192.168.8.4/255.252.0.0 returns "192.in-addr.arpa." |
572 |
|
|
+ 192.168.8.4/255.0.0.0 returns "192.in-addr.arpa." |
573 |
|
|
+ |
574 |
|
|
+This string is suitable for use in BIND configuration files. |
575 |
|
|
+ |
576 |
|
|
+=cut |
577 |
|
|
+ |
578 |
|
|
+sub computeLocalNetworkReversed ($$) |
579 |
|
|
+{ |
580 |
|
|
+ my ( $ipaddr, $netmask ) = @_; |
581 |
|
|
+ |
582 |
|
|
+ my @addressBytes = split ( /\./, $ipaddr ); |
583 |
|
|
+ my @maskBytes = split ( /\./, $netmask ); |
584 |
|
|
+ |
585 |
|
|
+ my @result; |
586 |
|
|
+ |
587 |
|
|
+ push ( @result, "in-addr.arpa." ); |
588 |
|
|
+ |
589 |
|
|
+ foreach (@maskBytes) |
590 |
|
|
+ { |
591 |
|
|
+ last unless ( $_ eq "255" ); |
592 |
|
|
+ |
593 |
|
|
+ unshift ( @result, shift (@addressBytes) ); |
594 |
|
|
+ } |
595 |
|
|
+ |
596 |
|
|
+ return join ( '.', @result ); |
597 |
|
|
+} |
598 |
|
|
+ |
599 |
|
|
+=pod |
600 |
|
|
+ |
601 |
|
|
+=head2 computeHostRange($ipaddr, $netmask) |
602 |
|
|
+ |
603 |
|
|
+Given a network specification (IP address and netmask), compute |
604 |
|
|
+the total number of hosts in that network, as well as the first |
605 |
|
|
+and last IP addresses in the range. |
606 |
|
|
+ |
607 |
|
|
+=cut |
608 |
|
|
+ |
609 |
|
|
+sub computeHostRange ($$) |
610 |
|
|
+{ |
611 |
|
|
+ my ( $ipaddr, $netmask ) = @_; |
612 |
|
|
+ |
613 |
|
|
+ my $ipaddrBits = IPquadToAddr($ipaddr); |
614 |
|
|
+ my $netmaskBits = IPquadToAddr($netmask); |
615 |
|
|
+ my $hostmaskBits = ( ( ~$netmaskBits ) & 0xffffffff ); |
616 |
|
|
+ |
617 |
|
|
+ my $firstAddrBits = $ipaddrBits & $netmaskBits; |
618 |
|
|
+ my $lastAddrBits = $ipaddrBits | $hostmaskBits; |
619 |
|
|
+ |
620 |
|
|
+ my $totalHosts = 1; |
621 |
|
|
+ |
622 |
|
|
+ for ( ; $hostmaskBits ; $hostmaskBits /= 2 ) |
623 |
|
|
+ { |
624 |
|
|
+ if ( ( $hostmaskBits & 0x1 ) == 0x1 ) |
625 |
|
|
+ { |
626 |
|
|
+ $totalHosts *= 2; |
627 |
|
|
+ } |
628 |
|
|
+ } |
629 |
|
|
+ |
630 |
|
|
+ return ( $totalHosts, IPaddrToQuad($firstAddrBits), |
631 |
|
|
+ IPaddrToQuad($lastAddrBits) ); |
632 |
|
|
+} |
633 |
|
|
+ |
634 |
|
|
+=pod |
635 |
|
|
+ |
636 |
|
|
+=head2 ldapBase($domain) |
637 |
|
|
+ |
638 |
|
|
+Given a domain name such as foo.bar.com, generate the |
639 |
|
|
+LDAP base name "dc=foo,dc=bar,dc=com". |
640 |
|
|
+ |
641 |
|
|
+=cut |
642 |
|
|
+ |
643 |
|
|
+sub ldapBase ($) |
644 |
|
|
+{ |
645 |
|
|
+ my ($domainName) = @_; |
646 |
|
|
+ $domainName =~ s/\./,dc=/g; |
647 |
|
|
+ return "dc=" . $domainName; |
648 |
|
|
+} |
649 |
|
|
+ |
650 |
|
|
+=pod |
651 |
|
|
+ |
652 |
|
|
+=head2 backgroundCommand($delaySec, @command) |
653 |
|
|
+ |
654 |
|
|
+Run command in background after a specified delay. |
655 |
|
|
+ |
656 |
|
|
+=cut |
657 |
|
|
+ |
658 |
|
|
+sub backgroundCommand ($@) |
659 |
|
|
+{ |
660 |
|
|
+ my ( $delaySec, @command ) = @_; |
661 |
|
|
+ |
662 |
|
|
+ # now would be a good time to flush output buffers, so the partial |
663 |
|
|
+ # buffers don't get copied |
664 |
|
|
+ |
665 |
|
|
+ $| = 1; |
666 |
|
|
+ print ""; |
667 |
|
|
+ |
668 |
|
|
+ # create child process |
669 |
|
|
+ my $pid = fork; |
670 |
|
|
+ |
671 |
|
|
+ # if fork failed, bail out |
672 |
|
|
+ die "Cannot fork: $!" unless defined($pid); |
673 |
|
|
+ |
674 |
|
|
+ # If fork succeeded, make parent process return immediately. |
675 |
|
|
+ # We are not waiting on the child, so it will become a zombie |
676 |
|
|
+ # process when it completes. However, this subroutine is only |
677 |
|
|
+ # intended for use by the e-smith signal-event program, which |
678 |
|
|
+ # doesn't run very long. Once the parent terminates, the zombie |
679 |
|
|
+ # will become owned by "init" and will be reaped automatically. |
680 |
|
|
+ |
681 |
|
|
+ return if ($pid); |
682 |
|
|
+ |
683 |
|
|
+ # detach ourselves from the terminal |
684 |
|
|
+ setsid || die "Cannot start a new session: $!"; |
685 |
|
|
+ |
686 |
|
|
+ # change working directory |
687 |
|
|
+ chdir "/"; |
688 |
|
|
+ |
689 |
|
|
+ # clear file creation mask |
690 |
|
|
+ umask 0; |
691 |
|
|
+ |
692 |
|
|
+ # close STDIN, STDOUT, and STDERR |
693 |
|
|
+ close STDIN; |
694 |
|
|
+ close STDOUT; |
695 |
|
|
+ close STDERR; |
696 |
|
|
+ |
697 |
|
|
+ # reopen stderr, stdout, stdin |
698 |
|
|
+ open( STDIN, '/dev/null' ); |
699 |
|
|
+ |
700 |
|
|
+ my $loggerPid = open( STDOUT, "|-" ); |
701 |
|
|
+ die "Can't fork: $!\n" unless defined $loggerPid; |
702 |
|
|
+ |
703 |
|
|
+ unless ($loggerPid) |
704 |
|
|
+ { |
705 |
|
|
+ exec qw(/usr/bin/logger -p local1.info -t e-smith-bg); |
706 |
|
|
+ } |
707 |
|
|
+ |
708 |
|
|
+ open( STDERR, '>&STDOUT' ); |
709 |
|
|
+ |
710 |
|
|
+ # make child wait for specified delay. |
711 |
|
|
+ sleep $delaySec; |
712 |
|
|
+ |
713 |
|
|
+ # execute command |
714 |
|
|
+ exec { $command[0] } @command or warn "Can't @command : $!\n"; |
715 |
|
|
+} |
716 |
|
|
+ |
717 |
|
|
+=pod |
718 |
|
|
+ |
719 |
|
|
+=head1 PASSWORD UTILITIES |
720 |
|
|
+ |
721 |
|
|
+Low-level password-changing utilities. These utilities each |
722 |
|
|
+change passwords for a single underlying password database, |
723 |
|
|
+for example /etc/passwd, /etc/samba/smbpasswd, etc. |
724 |
|
|
+ |
725 |
|
|
+=head2 validatePassword($password, $strength) |
726 |
|
|
+ |
727 |
|
|
+Validate Unix password. |
728 |
|
|
+ |
729 |
|
|
+=cut |
730 |
|
|
+ |
731 |
|
|
+sub validatePassword($$) |
732 |
|
|
+{ |
733 |
|
|
+ my ( $password, $strength ) = @_; |
734 |
|
|
+ use Crypt::Cracklib; |
735 |
|
|
+ |
736 |
|
|
+ $strength ||= 'normal'; |
737 |
|
|
+ |
738 |
|
|
+ my $reason = 'ok'; |
739 |
|
|
+ $reason = 'it is too short' unless (length($password) > 6); |
740 |
|
|
+ return $reason if ($reason ne 'ok' || $strength eq 'none'); |
741 |
|
|
+ |
742 |
|
|
+ $reason = 'it does not contain numbers' if (not $password =~ /\d/); |
743 |
|
|
+ $reason = 'it does not contain uppercase characters' if (not $password =~ /[A-Z]/); |
744 |
|
|
+ $reason = 'it does not contain lowercase characters' if (not $password =~ /[a-z]/); |
745 |
|
|
+ $reason = 'it does not contain special characters' if (not $password =~ /\W|_/); |
746 |
|
|
+ return $reason if ($reason ne 'ok' && $strength eq 'strong'); |
747 |
|
|
+ |
748 |
|
|
+ if ( -f '/usr/lib64/cracklib_dict.pwd' ) { |
749 |
|
|
+ $reason = fascist_check($password, '/usr/lib64/cracklib_dict'); |
750 |
|
|
+ } else { |
751 |
|
|
+ $reason = fascist_check($password, '/usr/lib/cracklib_dict'); |
752 |
|
|
+ } |
753 |
|
|
+ $reason ||= 'the password check failed'; |
754 |
|
|
+ |
755 |
|
|
+ return 'ok' if (lc($reason) eq 'ok'); |
756 |
|
|
+ return $reason; |
757 |
|
|
+} |
758 |
|
|
+ |
759 |
|
|
+=pod |
760 |
|
|
+ |
761 |
|
|
+=head2 setUnixPassword($username, $password) |
762 |
|
|
+ |
763 |
|
|
+Set Unix password |
764 |
|
|
+ |
765 |
|
|
+=cut |
766 |
|
|
+ |
767 |
|
|
+sub setUnixPassword($$) |
768 |
|
|
+{ |
769 |
|
|
+ my ( $username, $password ) = @_; |
770 |
|
|
+ setUnixPasswordRequirePrevious( $username, undef, $password ); |
771 |
|
|
+} |
772 |
|
|
+ |
773 |
|
|
+=pod |
774 |
|
|
+ |
775 |
|
|
+=head2 authenticateUnixPassword ($username, $password) |
776 |
|
|
+ |
777 |
|
|
+Check if the given username/password pair is correct. |
778 |
|
|
+Return 1 if they are correct, return 0 otherwise. |
779 |
|
|
+ |
780 |
|
|
+=cut |
781 |
|
|
+ |
782 |
|
|
+sub authenticateUnixPassword ($$) |
783 |
|
|
+{ |
784 |
|
|
+ my ( $username, $password ) = @_; |
785 |
|
|
+ |
786 |
|
|
+ my $pam_auth_func = sub { |
787 |
|
|
+ return ( PAM_SUCCESS(), $password, PAM_SUCCESS() ); |
788 |
|
|
+ }; |
789 |
|
|
+ my $pamh = new Authen::PAM( 'passwd', $username, $pam_auth_func ); |
790 |
|
|
+ |
791 |
|
|
+ unless ( ref($pamh) ) |
792 |
|
|
+ { |
793 |
|
|
+ warn "WARN: Couldn't open Authen::PAM handle for user $username"; |
794 |
|
|
+ return 0; |
795 |
|
|
+ } |
796 |
|
|
+ my $res = $pamh->pam_authenticate(); |
797 |
|
|
+ return ( $res == PAM_SUCCESS() ) || 0; |
798 |
|
|
+} |
799 |
|
|
+ |
800 |
|
|
+=pod |
801 |
|
|
+ |
802 |
|
|
+=head2 setUnixPasswordRequirePrevious($username, $oldpassword, $newpassword) |
803 |
|
|
+ |
804 |
|
|
+Set Unix password but require previous password for authentication. |
805 |
|
|
+ |
806 |
|
|
+=cut |
807 |
|
|
+ |
808 |
|
|
+# setUnixPasswordRequirePrevious is left as an exercise for the reader :-) |
809 |
|
|
+sub setUnixPasswordRequirePrevious ($$$) |
810 |
|
|
+{ |
811 |
|
|
+ my ( $username, $oldpassword, $newpassword ) = @_; |
812 |
|
|
+ use Authen::PAM; |
813 |
|
|
+ my $state; |
814 |
|
|
+ |
815 |
|
|
+ my $my_conv_func = sub { |
816 |
|
|
+ my @res; |
817 |
|
|
+ while (@_) |
818 |
|
|
+ { |
819 |
|
|
+ my $code = shift; |
820 |
|
|
+ my $msg = shift; |
821 |
|
|
+ my $ans = ""; |
822 |
|
|
+ |
823 |
|
|
+ $ans = $username if ( $code == PAM_PROMPT_ECHO_ON() ); |
824 |
|
|
+ if ( $code == PAM_PROMPT_ECHO_OFF() ) |
825 |
|
|
+ { |
826 |
|
|
+ if ( $< == 0 || $state >= 1 ) |
827 |
|
|
+ { |
828 |
|
|
+ # are we asked for a new password |
829 |
|
|
+ $ans = $newpassword; |
830 |
|
|
+ } |
831 |
|
|
+ else |
832 |
|
|
+ { |
833 |
|
|
+ # asked for old password before we can set a new one. |
834 |
|
|
+ $ans = $oldpassword; |
835 |
|
|
+ } |
836 |
|
|
+ $state++; |
837 |
|
|
+ } |
838 |
|
|
+ |
839 |
|
|
+ #print("code is $code, ans is $ans, msg is $msg, state is $state\n"); |
840 |
|
|
+ push @res, ( PAM_SUCCESS(), $ans ); |
841 |
|
|
+ } |
842 |
|
|
+ push @res, PAM_SUCCESS(); |
843 |
|
|
+ return @res; |
844 |
|
|
+ }; |
845 |
|
|
+ |
846 |
|
|
+ my $pamh = new Authen::PAM( "passwd", $username, $my_conv_func ); |
847 |
|
|
+ unless ( ref($pamh) ) |
848 |
|
|
+ { |
849 |
|
|
+ warn "Autopasswd: error code $pamh during PAM init!"; |
850 |
|
|
+ warn "Failed to set Unix password for account $username.\n"; |
851 |
|
|
+ return 0; |
852 |
|
|
+ } |
853 |
|
|
+ |
854 |
|
|
+ # Require the old password to be correct before proceeding to set a new |
855 |
|
|
+ # one. |
856 |
|
|
+ # This does that, except if you're already root, such as from the |
857 |
|
|
+ # bootstrap-console |
858 |
|
|
+ $state = 0; |
859 |
|
|
+ unless ( $< == 0 or $pamh->pam_authenticate == 0 ) |
860 |
|
|
+ { |
861 |
|
|
+ warn |
862 |
|
|
+"PAM authentication failed for user \"$username\", old password invalid!\n"; |
863 |
|
|
+ return 0; |
864 |
|
|
+ } |
865 |
|
|
+ |
866 |
|
|
+ $state = 0; |
867 |
|
|
+ my $res = $pamh->pam_chauthtok; |
868 |
|
|
+ unless ( $res == PAM_SUCCESS() ) |
869 |
|
|
+ { |
870 |
|
|
+ my $err = $pamh->pam_strerror($res); |
871 |
|
|
+ warn "Failed to set Unix password for account $username: $err\n"; |
872 |
|
|
+ return 0; |
873 |
|
|
+ } |
874 |
|
|
+ return 1; # success |
875 |
|
|
+} |
876 |
|
|
+ |
877 |
|
|
+=pod |
878 |
|
|
+ |
879 |
|
|
+=head2 setSambaPassword($username, $password) |
880 |
|
|
+ |
881 |
|
|
+Set Samba password |
882 |
|
|
+ |
883 |
|
|
+=cut |
884 |
|
|
+ |
885 |
|
|
+sub setSambaPassword ($$) |
886 |
|
|
+{ |
887 |
|
|
+ my ( $username, $password ) = @_; |
888 |
|
|
+ |
889 |
|
|
+ #---------------------------------------- |
890 |
|
|
+ # then set the password |
891 |
|
|
+ #---------------------------------------- |
892 |
|
|
+ |
893 |
|
|
+ my $smbPasswdProg = '/usr/bin/smbpasswd'; |
894 |
|
|
+ |
895 |
|
|
+ # see perldoc perlipc (search for 'Safe Pipe Opens') |
896 |
|
|
+ my $pid = open( DISCARD, "|-" ); |
897 |
|
|
+ |
898 |
|
|
+ if ($pid) # parent |
899 |
|
|
+ { |
900 |
|
|
+ print DISCARD "$password\n$password\n"; |
901 |
|
|
+ close(DISCARD) || die "Child exited early."; |
902 |
|
|
+ } |
903 |
|
|
+ else # child |
904 |
|
|
+ { |
905 |
|
|
+ my $retval = system("$smbPasswdProg -a -s $username >/dev/null"); |
906 |
|
|
+ ( $retval / 256 ) |
907 |
|
|
+ && die "Failed to set Samba password for account $username.\n"; |
908 |
|
|
+ exit 0; |
909 |
|
|
+ } |
910 |
|
|
+ # Now we enable the account |
911 |
|
|
+ return system("$smbPasswdProg -e $username >/dev/null") ? 0 : 1; |
912 |
|
|
+} |
913 |
|
|
+ |
914 |
|
|
+=pod |
915 |
|
|
+ |
916 |
|
|
+=head2 cancelSambaPassword($username) |
917 |
|
|
+ |
918 |
|
|
+Cancel Samba password |
919 |
|
|
+ |
920 |
|
|
+=cut |
921 |
|
|
+ |
922 |
|
|
+sub cancelSambaPassword ($) |
923 |
|
|
+{ |
924 |
|
|
+ my ($username) = @_; |
925 |
|
|
+ |
926 |
|
|
+ #---------------------------------------- |
927 |
|
|
+ # Gordon Rowell <gordonr@e-smith.com> June 7, 2000 |
928 |
|
|
+ # We really should maintain old users, which would mean we can just use |
929 |
|
|
+ # smbpasswd -d, but the current policy is to remove them. If we are |
930 |
|
|
+ # doing that (see below), there is no need to disable them first. |
931 |
|
|
+ #---------------------------------------- |
932 |
|
|
+ # my $discard = `/usr/bin/smbpasswd -d -s $username`; |
933 |
|
|
+ # if ($? != 0) |
934 |
|
|
+ # { |
935 |
|
|
+ # die "Failed to disable Samba account $username.\n"; |
936 |
|
|
+ # } |
937 |
|
|
+ |
938 |
|
|
+ #---------------------------------------- |
939 |
|
|
+ # Delete the smbpasswd entry. If we don't, re-adding the same |
940 |
|
|
+ # username will result in a mismatch of UIDs between /etc/passwd |
941 |
|
|
+ # and /etc/smbpasswd |
942 |
|
|
+ #---------------------------------------- |
943 |
|
|
+ # Michael Brader <mbrader@stoic.com.au> June 2, 2000 |
944 |
|
|
+ # We have a locking problem here. |
945 |
|
|
+ # If two copies of this are run at once you could see your entry reappear |
946 |
|
|
+ # Proposed solution (file locking): |
947 |
|
|
+ |
948 |
|
|
+ # If we do a 'use Fcntl, we'll probably get the locking constants |
949 |
|
|
+ # defined, but for now: |
950 |
|
|
+ |
951 |
|
|
+ # NB. hard to test |
952 |
|
|
+ |
953 |
|
|
+ my $LOCK_EX = 2; |
954 |
|
|
+ my $LOCK_UN = 8; |
955 |
|
|
+ |
956 |
|
|
+ my $smbPasswdFile = '/etc/samba/smbpasswd'; |
957 |
|
|
+ |
958 |
|
|
+ open( RDWR, "+<$smbPasswdFile" ) || # +< == fopen(path, "r+",... |
959 |
|
|
+ die "Cannot open file $smbPasswdFile: $!\n"; |
960 |
|
|
+ |
961 |
|
|
+ my $nolock = 1; |
962 |
|
|
+ my $attempts; |
963 |
|
|
+ for ( $attempts = 1 ; ( $attempts <= 5 && $nolock ) ; $attempts++ ) |
964 |
|
|
+ { |
965 |
|
|
+ if ( flock( RDWR, $LOCK_EX ) ) |
966 |
|
|
+ { |
967 |
|
|
+ $nolock = 0; |
968 |
|
|
+ } |
969 |
|
|
+ else |
970 |
|
|
+ { |
971 |
|
|
+ sleep $attempts; |
972 |
|
|
+ } |
973 |
|
|
+ } |
974 |
|
|
+ |
975 |
|
|
+ $nolock && die "Could not get exclusive lock on $smbPasswdFile\n"; |
976 |
|
|
+ |
977 |
|
|
+ my $outputString = ''; |
978 |
|
|
+ while (<RDWR>) |
979 |
|
|
+ { |
980 |
|
|
+ (/^$username:/) || ( $outputString .= $_ ); |
981 |
|
|
+ } |
982 |
|
|
+ |
983 |
|
|
+ # clear file and go to beginning |
984 |
|
|
+ truncate( RDWR, 0 ) || die "truncate failed"; # not 'strict' safe why??? |
985 |
|
|
+ seek( RDWR, 0, 0 ) || die "seek failed"; |
986 |
|
|
+ print RDWR $outputString; |
987 |
|
|
+ flock( RDWR, $LOCK_UN ) |
988 |
|
|
+ || warn "Couldn't remove exclusive lock on $smbPasswdFile\n"; |
989 |
|
|
+ close RDWR || die "close failed"; |
990 |
|
|
+ |
991 |
|
|
+ chmod 0600, $smbPasswdFile; |
992 |
|
|
+ |
993 |
|
|
+ return 1; # success |
994 |
|
|
+} |
995 |
|
|
+ |
996 |
|
|
+=pod |
997 |
|
|
+ |
998 |
|
|
+=head2 LdapPassword() |
999 |
|
|
+ |
1000 |
|
|
+Returns the LDAP password from the file C</etc/openldap/ldap.pw>. |
1001 |
|
|
+If the file does not exist, a suitable password is created, stored |
1002 |
|
|
+in the file, then returned to the caller. |
1003 |
|
|
+ |
1004 |
|
|
+Returns undef if the password could not be generated/retrieved. |
1005 |
|
|
+ |
1006 |
|
|
+=cut |
1007 |
|
|
+ |
1008 |
|
|
+sub genLdapPassword () |
1009 |
|
|
+{ |
1010 |
|
|
+ |
1011 |
|
|
+ # Otherwise generate a suitable new password, store it in the |
1012 |
|
|
+ # correct file, and return it to the caller. |
1013 |
|
|
+ |
1014 |
|
|
+ use MIME::Base64 qw(encode_base64); |
1015 |
|
|
+ |
1016 |
|
|
+ unless ( open( RANDOM, "/dev/urandom" ) ) |
1017 |
|
|
+ { |
1018 |
|
|
+ warn "Could not open /dev/urandom: $!"; |
1019 |
|
|
+ return undef; |
1020 |
|
|
+ } |
1021 |
|
|
+ |
1022 |
|
|
+ my $buf = "not set"; |
1023 |
|
|
+ |
1024 |
|
|
+ # 57 bytes is a full line of Base64 coding, and contains |
1025 |
|
|
+ # 456 bits of randomness - given a perfectly random /dev/urandom |
1026 |
|
|
+ if ( read( RANDOM, $buf, 57 ) != 57 ) |
1027 |
|
|
+ { |
1028 |
|
|
+ warn("Short read from /dev/urandom: $!"); |
1029 |
|
|
+ return undef; |
1030 |
|
|
+ } |
1031 |
|
|
+ close RANDOM; |
1032 |
|
|
+ |
1033 |
|
|
+ my $umask = umask 0077; |
1034 |
|
|
+ my $password = encode_base64($buf, ""); |
1035 |
|
|
+ |
1036 |
|
|
+ unless ( open( WR, ">/etc/openldap/ldap.pw" ) ) |
1037 |
|
|
+ { |
1038 |
|
|
+ warn "Could not write LDAP password file.\n"; |
1039 |
|
|
+ return undef; |
1040 |
|
|
+ } |
1041 |
|
|
+ |
1042 |
|
|
+ print WR "$password\n"; |
1043 |
|
|
+ close WR; |
1044 |
|
|
+ umask $umask; |
1045 |
|
|
+ |
1046 |
|
|
+ chmod 0600, "/etc/openldap/ldap.pw"; |
1047 |
|
|
+ |
1048 |
|
|
+ return $password; |
1049 |
|
|
+} |
1050 |
|
|
+ |
1051 |
|
|
+sub LdapPassword () |
1052 |
|
|
+{ |
1053 |
|
|
+ |
1054 |
|
|
+ # Read the password from the file /etc/openldap/ldap.pw if it |
1055 |
|
|
+ # exists. |
1056 |
|
|
+ if ( -f "/etc/openldap/ldap.pw" ) |
1057 |
|
|
+ { |
1058 |
|
|
+ open( LDAPPW, "</etc/openldap/ldap.pw" ) |
1059 |
|
|
+ || die "Could not open LDAP password file.\n"; |
1060 |
|
|
+ my $password = <LDAPPW>; |
1061 |
|
|
+ chomp $password; |
1062 |
|
|
+ close LDAPPW; |
1063 |
|
|
+ return $password; |
1064 |
|
|
+ } |
1065 |
|
|
+ else |
1066 |
|
|
+ { |
1067 |
|
|
+ return genLdapPassword(); |
1068 |
|
|
+ } |
1069 |
|
|
+} |
1070 |
|
|
+ |
1071 |
|
|
+=pod |
1072 |
|
|
+ |
1073 |
|
|
+=head2 set_secret() |
1074 |
|
|
+ |
1075 |
|
|
+Shortcut method to create and set a password property on a record without having to extract the record first. |
1076 |
|
|
+ |
1077 |
|
|
+The password creation is based on an UID of 64 bits (Data::UUID). If the optional type option is passed, |
1078 |
|
|
+it will be used to create the record if it does not already exist. Otherwise, a default 'service' type |
1079 |
|
|
+will be used to create the record. |
1080 |
|
|
+ |
1081 |
|
|
+The $DB is expected to be an already open esmith::DB object, so that an open DB in the caller can be re-used. |
1082 |
|
|
+Therefore in a migrate fragment you could just use $DB. |
1083 |
|
|
+ |
1084 |
|
|
+ esmith::util::set_secret($DB, '$key','$property'[,type=>'$type']); |
1085 |
|
|
+ |
1086 |
|
|
+For example in /etc/e-smith/db/configuration/migrate/90roundcube |
1087 |
|
|
+ { |
1088 |
|
|
+ esmith::util::set_secret($DB, 'foo','DbPassword',type=>'service'); |
1089 |
|
|
+ } |
1090 |
|
|
+ |
1091 |
|
|
+The password will be generated to the property 'DbPassword' in the 'foo' key. |
1092 |
|
|
+ |
1093 |
|
|
+If you want to change the database then you must open another esmith::DB objet |
1094 |
|
|
+ { |
1095 |
|
|
+ my $database = esmith::ConfigDB->open('accounts') or |
1096 |
|
|
+ die esmith::DB->error; |
1097 |
|
|
+ esmith::util::set_secret($database, 'foo','DbPassword',type=>'user'); |
1098 |
|
|
+ } |
1099 |
|
|
+ |
1100 |
|
|
+=cut |
1101 |
|
|
+ |
1102 |
|
|
+sub set_secret |
1103 |
|
|
+ |
1104 |
|
|
+{ |
1105 |
|
|
+ my ($db, $key, $prop, %options) = @_; |
1106 |
|
|
+ %options = (type => 'service', %options); |
1107 |
|
|
+ |
1108 |
|
|
+ my $record = $db->get($key) || |
1109 |
|
|
+ $db->new_record($key, \%options) or |
1110 |
|
|
+ die "Error creating new record"; |
1111 |
|
|
+ |
1112 |
|
|
+ return if $db->get_prop($key,$prop); |
1113 |
|
|
+ |
1114 |
|
|
+ $record->merge_props(%options, $prop => |
1115 |
|
|
+ Data::UUID->new->create_b64()); |
1116 |
|
|
+} |
1117 |
|
|
+ |
1118 |
|
|
+ |
1119 |
|
|
+ |
1120 |
|
|
+=pod |
1121 |
|
|
+ |
1122 |
|
|
+=head1 HIGH LEVEL PASSWORD UTILITIES |
1123 |
|
|
+ |
1124 |
|
|
+High-level password-changing utilities. These utilities |
1125 |
|
|
+each change passwords for a single e-smith entity (system, |
1126 |
|
|
+user or ibay). Each one works by calling the appropriate |
1127 |
|
|
+low-level password changing utilities. |
1128 |
|
|
+ |
1129 |
|
|
+=head2 setUnixSystemPassword($password) |
1130 |
|
|
+ |
1131 |
|
|
+Set the e-smith system password |
1132 |
|
|
+ |
1133 |
|
|
+=cut |
1134 |
|
|
+ |
1135 |
|
|
+sub setUnixSystemPassword ($) |
1136 |
|
|
+{ |
1137 |
|
|
+ my ($password) = @_; |
1138 |
|
|
+ |
1139 |
|
|
+ setUnixPassword( "root", $password ); |
1140 |
|
|
+ setUnixPassword( "admin", $password ); |
1141 |
|
|
+} |
1142 |
|
|
+ |
1143 |
|
|
+=pod |
1144 |
|
|
+ |
1145 |
|
|
+=head2 setServerSystemPassword($password) |
1146 |
|
|
+ |
1147 |
|
|
+Set the samba administrator password. |
1148 |
|
|
+ |
1149 |
|
|
+=cut |
1150 |
|
|
+ |
1151 |
|
|
+sub setServerSystemPassword ($) |
1152 |
|
|
+{ |
1153 |
|
|
+ my ($password) = @_; |
1154 |
|
|
+ |
1155 |
|
|
+ setSambaPassword( "admin", $password ); |
1156 |
|
|
+} |
1157 |
|
|
+ |
1158 |
|
|
+=pod |
1159 |
|
|
+ |
1160 |
|
|
+=head2 setUserPassword($username, $password) |
1161 |
|
|
+ |
1162 |
|
|
+Set e-smith user password |
1163 |
|
|
+ |
1164 |
|
|
+=cut |
1165 |
|
|
+ |
1166 |
|
|
+sub setUserPassword ($$) |
1167 |
|
|
+{ |
1168 |
|
|
+ my ( $username, $password ) = @_; |
1169 |
|
|
+ |
1170 |
|
|
+ setUnixPassword( $username, $password ); |
1171 |
|
|
+ setSambaPassword( $username, $password ); |
1172 |
|
|
+} |
1173 |
|
|
+ |
1174 |
|
|
+=pod |
1175 |
|
|
+ |
1176 |
|
|
+=head2 setUserPasswordRequirePrevious($username, $oldpassword, $newpassword) |
1177 |
|
|
+ |
1178 |
|
|
+Set e-smith user password - require previous password |
1179 |
|
|
+ |
1180 |
|
|
+=cut |
1181 |
|
|
+ |
1182 |
|
|
+sub setUserPasswordRequirePrevious ($$$) |
1183 |
|
|
+{ |
1184 |
|
|
+ my ( $username, $oldpassword, $newpassword ) = @_; |
1185 |
|
|
+ |
1186 |
|
|
+ # We need to suid to the user, instead of root, so that PAM will |
1187 |
|
|
+ # prompt us for the old password. |
1188 |
|
|
+ my @pwent = getpwnam($username); |
1189 |
|
|
+ return 0 unless ( $pwent[2] > 0 ); # uid must be non-zero |
1190 |
|
|
+ my $uid = $<; |
1191 |
|
|
+ $< = $pwent[2]; |
1192 |
|
|
+ |
1193 |
|
|
+ # Return if this function call fails, we didn't change passwords |
1194 |
|
|
+ # successfully. |
1195 |
|
|
+ my $ret = |
1196 |
|
|
+ setUnixPasswordRequirePrevious( $username, $oldpassword, $newpassword ); |
1197 |
|
|
+ $< = $uid; |
1198 |
|
|
+ return 0 unless $ret; |
1199 |
|
|
+ |
1200 |
|
|
+ # if we get this far, the old password must have been valid |
1201 |
|
|
+ setSambaPassword( $username, $newpassword ); |
1202 |
|
|
+} |
1203 |
|
|
+ |
1204 |
|
|
+=pod |
1205 |
|
|
+ |
1206 |
|
|
+=head2 cancelUserPassword |
1207 |
|
|
+ |
1208 |
|
|
+Cancel user password. This is called when a user is deleted from the |
1209 |
|
|
+system. We assume that the Unix "useradd/userdel" programs are |
1210 |
|
|
+called separately. Since "userdel" automatically removes the |
1211 |
|
|
+/etc/passwd entry, we only need to worry about the /etc/samba/smbpasswd |
1212 |
|
|
+entry. |
1213 |
|
|
+ |
1214 |
|
|
+=cut |
1215 |
|
|
+ |
1216 |
|
|
+sub cancelUserPassword ($) |
1217 |
|
|
+{ |
1218 |
|
|
+ my ($username) = @_; |
1219 |
|
|
+ |
1220 |
|
|
+ cancelSambaPassword($username); |
1221 |
|
|
+} |
1222 |
|
|
+ |
1223 |
|
|
+=pod |
1224 |
|
|
+ |
1225 |
|
|
+=head2 setIbayPassword($ibayname, $password) |
1226 |
|
|
+ |
1227 |
|
|
+Set ibay password |
1228 |
|
|
+ |
1229 |
|
|
+=cut |
1230 |
|
|
+ |
1231 |
|
|
+sub setIbayPassword ($$) |
1232 |
|
|
+{ |
1233 |
|
|
+ my ( $ibayname, $password ) = @_; |
1234 |
|
|
+ |
1235 |
|
|
+ setUnixPassword( $ibayname, $password ); |
1236 |
|
|
+} |
1237 |
|
|
+ |
1238 |
|
|
+=pod |
1239 |
|
|
+ |
1240 |
|
|
+=head1 SERVICE MANAGEMENT UTILITIES |
1241 |
|
|
+ |
1242 |
|
|
+=head2 serviceControl() |
1243 |
|
|
+ |
1244 |
|
|
+Manage services - stop/start/restart/reload/graceful |
1245 |
|
|
+ |
1246 |
|
|
+Returns 1 for success, 0 if something went wrong, fatal exception on bad |
1247 |
|
|
+arguments. |
1248 |
|
|
+ |
1249 |
|
|
+ serviceControl( |
1250 |
|
|
+ NAME=>serviceName, |
1251 |
|
|
+ ACTION=>start|stop|restart|reload|graceful |
1252 |
|
|
+ [ BACKGROUND=>true|false (default is false) ] |
1253 |
|
|
+ ); |
1254 |
|
|
+ |
1255 |
|
|
+EXAMPLE: |
1256 |
|
|
+ |
1257 |
|
|
+ serviceControl( NAME=>'httpd-e-smith', ACTION=>'reload' ); |
1258 |
|
|
+ |
1259 |
|
|
+NOTES: |
1260 |
|
|
+ |
1261 |
|
|
+The BACKGROUND parameter is optional and can be set to true if |
1262 |
|
|
+start/stop/restart/etc. is to be done in the background (with |
1263 |
|
|
+backgroundCommand()) rather than synchronously. |
1264 |
|
|
+ |
1265 |
|
|
+CONVENTIONS: |
1266 |
|
|
+ |
1267 |
|
|
+This command is the supported method for action scripts, blade handlers, etc., |
1268 |
|
|
+to start/stop/restart their services. Currently this is done via the rc7 |
1269 |
|
|
+symlinks, but this may change one day. Using this function gives us one |
1270 |
|
|
+location to change this behaviour if desired, instead of hunting all over |
1271 |
|
|
+every scrap of code. Please use it. |
1272 |
|
|
+ |
1273 |
|
|
+=cut |
1274 |
|
|
+ |
1275 |
|
|
+sub serviceControl |
1276 |
|
|
+{ |
1277 |
|
|
+ my %params = @_; |
1278 |
|
|
+ |
1279 |
|
|
+ my $serviceName = $params{NAME}; |
1280 |
|
|
+ unless ( defined $serviceName ) |
1281 |
|
|
+ { |
1282 |
|
|
+ die "serviceControl: NAME must be specified"; |
1283 |
|
|
+ } |
1284 |
|
|
+ |
1285 |
|
|
+ my $serviceAction = $params{ACTION}; |
1286 |
|
|
+ unless (defined $serviceAction) |
1287 |
|
|
+ { |
1288 |
|
|
+ die "serviceControl: ACTION must be specified"; |
1289 |
|
|
+ } |
1290 |
|
|
+ |
1291 |
|
|
+ if ( $serviceAction =~ /^(start|stop|restart|reload|graceful|adjust|svdisable|reload-or-restart|try-restart|try-reload-or-restart|enable -now|sigterm|sighup|sigusr1|sigusr2)$/ ) |
1292 |
|
|
+ { |
1293 |
|
|
+ my ($startScript) = glob("/etc/rc.d/rc7.d/S*$serviceName") ||'' ; |
1294 |
|
|
+ my ($systemdScript) = "/usr/lib/systemd/system/$serviceName.service" ||''; |
1295 |
|
|
+ |
1296 |
|
|
+ unless ( -e $startScript or -e $systemdScript) |
1297 |
|
|
+ { |
1298 |
|
|
+ warn "serviceControl: startScript not found " |
1299 |
|
|
+ . "for service $serviceName\n"; |
1300 |
|
|
+ return 0; |
1301 |
|
|
+ } |
1302 |
|
|
+ |
1303 |
|
|
+ if (-e $systemdScript and ! -e $startScript){ |
1304 |
|
|
+ # systemd is not aware of adjust, sigusr1, sigusr2, sigterm, sighup |
1305 |
|
|
+ $serviceAction = ( $serviceAction =~/^(adjust|graceful|sighup|sigusr1|sigusr2)$/ ) ? "reload" : $serviceAction; |
1306 |
|
|
+ $serviceAction = ( $serviceAction eq "sigterm" ) ? "restart" : $serviceAction; |
1307 |
|
|
+ if ($serviceAction =~/^(start|stop|restart|reload|reload-or-restart|try-restart|try-reload-or-restart|enable -now)$/) { |
1308 |
|
|
+ system('/usr/bin/systemctl',"$serviceAction","$serviceName.service") == '0' |
1309 |
|
|
+ || warn "serviceControl: Couldn't " . |
1310 |
|
|
+ "system( /usr/bin/systemctl $serviceAction $serviceName.service): $!\n"; |
1311 |
|
|
+ } |
1312 |
|
|
+ else { |
1313 |
|
|
+ die "serviceControl: systemd doesn't know : systemctl $serviceAction $serviceName.service"; |
1314 |
|
|
+ } |
1315 |
|
|
+ } |
1316 |
|
|
+ |
1317 |
|
|
+ elsif (-e $startScript) { |
1318 |
|
|
+ my $background = $params{'BACKGROUND'} || 'false'; |
1319 |
|
|
+ |
1320 |
|
|
+ die "serviceControl: Unknown serviceAction $serviceAction" if ($serviceAction =~/^(reload-or-restart|try-restart|try-reload-or-restart|enable -now|sigterm|sighup|sigusr1|sigusr2)$/); |
1321 |
|
|
+ if ( $background eq 'true' ) |
1322 |
|
|
+ { |
1323 |
|
|
+ backgroundCommand( 0, $startScript, $serviceAction ); |
1324 |
|
|
+ } |
1325 |
|
|
+ elsif ( $background eq 'false' ) |
1326 |
|
|
+ { |
1327 |
|
|
+ unless ( system( $startScript, $serviceAction ) == 0 ) |
1328 |
|
|
+ { |
1329 |
|
|
+ warn "serviceControl: " |
1330 |
|
|
+ . "Couldn't system($startScript, $serviceAction): $!\n"; |
1331 |
|
|
+ return 0; |
1332 |
|
|
+ } |
1333 |
|
|
+ } |
1334 |
|
|
+ else |
1335 |
|
|
+ { |
1336 |
|
|
+ die "serviceControl: Unsupported BACKGROUND=>$background"; |
1337 |
|
|
+ } |
1338 |
|
|
+ } |
1339 |
|
|
+ } |
1340 |
|
|
+ else |
1341 |
|
|
+ { |
1342 |
|
|
+ die "serviceControl: Unknown serviceAction $serviceAction"; |
1343 |
|
|
+ } |
1344 |
|
|
+ return 1; |
1345 |
|
|
+} |
1346 |
|
|
+ |
1347 |
|
|
+=head2 getLicenses() |
1348 |
|
|
+ |
1349 |
|
|
+Return all available licenses |
1350 |
|
|
+ |
1351 |
|
|
+In scalar context, returns one string combining all licenses |
1352 |
|
|
+In array context, returns an array of individual licenses |
1353 |
|
|
+ |
1354 |
|
|
+Optionally takes a language tag to be used for retrieving the licenses, |
1355 |
|
|
+defaulting to the locale of the server. |
1356 |
|
|
+ |
1357 |
|
|
+=for testing |
1358 |
|
|
+$ENV{ESMITH_LICENSE_DIR} = "10e-smith-lib/licenses"; |
1359 |
|
|
+ok(-d $ENV{ESMITH_LICENSE_DIR}, "License dir for testing exists"); |
1360 |
|
|
+like($l = esmith::util::getLicenses("fr_CA"), qr/Je suis/, "Found french license"); |
1361 |
|
|
+like($l = esmith::util::getLicenses("en_US"), qr/I am/, "Found english license"); |
1362 |
|
|
+ |
1363 |
|
|
+=cut |
1364 |
|
|
+ |
1365 |
|
|
+sub getLicenses |
1366 |
|
|
+{ |
1367 |
|
|
+ my ($locale) = @_; |
1368 |
|
|
+ |
1369 |
|
|
+ if ($locale) |
1370 |
|
|
+ { |
1371 |
|
|
+ $locale =~ s/-(\S\S)/_\U$1/; |
1372 |
|
|
+ } |
1373 |
|
|
+ else |
1374 |
|
|
+ { |
1375 |
|
|
+ my $db = esmith::ConfigDB->open(); |
1376 |
|
|
+ |
1377 |
|
|
+ my ( $lang, @rest ) = $db->getLocale(); |
1378 |
|
|
+ |
1379 |
|
|
+ $lang = $lang || "en_US"; |
1380 |
|
|
+ |
1381 |
|
|
+ $locale = $lang; |
1382 |
|
|
+ } |
1383 |
|
|
+ |
1384 |
|
|
+ my $base_dir = $ENV{ESMITH_LICENSE_DIR} || "/etc/e-smith/licenses"; |
1385 |
|
|
+ |
1386 |
|
|
+ $locale = "en_US" unless ( -d "${base_dir}/${locale}" ); |
1387 |
|
|
+ |
1388 |
|
|
+ my $dir = "${base_dir}/${locale}"; |
1389 |
|
|
+ |
1390 |
|
|
+ my @licenses; |
1391 |
|
|
+ |
1392 |
|
|
+ opendir( DIR, $dir ) || die "Couldn't open licenses directory\n"; |
1393 |
|
|
+ |
1394 |
|
|
+ foreach my $license ( readdir(DIR) ) |
1395 |
|
|
+ { |
1396 |
|
|
+ my $file = "${dir}/${license}"; |
1397 |
|
|
+ |
1398 |
|
|
+ next unless ( -f $file ); |
1399 |
|
|
+ |
1400 |
|
|
+ open( LICENSE, $file ) || die "Couldn't open license $file\n"; |
1401 |
|
|
+ |
1402 |
|
|
+ push @licenses, <LICENSE>; |
1403 |
|
|
+ |
1404 |
|
|
+ close LICENSE; |
1405 |
|
|
+ } |
1406 |
|
|
+ |
1407 |
|
|
+ return wantarray ? @licenses : "@licenses"; |
1408 |
|
|
+} |
1409 |
|
|
+ |
1410 |
|
|
+=head2 getLicenseFile() |
1411 |
|
|
+ |
1412 |
|
|
+Return the license filename. |
1413 |
|
|
+ |
1414 |
|
|
+Optionally takes a language tag to be used for retrieving the license, |
1415 |
|
|
+defaulting to the locale of the server. |
1416 |
|
|
+ |
1417 |
|
|
+If more than one license file than return the first alphabetically. |
1418 |
|
|
+ |
1419 |
|
|
+=cut |
1420 |
|
|
+ |
1421 |
|
|
+sub getLicenseFile |
1422 |
|
|
+{ |
1423 |
|
|
+ my ($locale) = @_; |
1424 |
|
|
+ |
1425 |
|
|
+ if ($locale) |
1426 |
|
|
+ { |
1427 |
|
|
+ $locale =~ s/-(\S\S)/_\U$1/s; |
1428 |
|
|
+ } |
1429 |
|
|
+ else |
1430 |
|
|
+ { |
1431 |
|
|
+ my $db = esmith::ConfigDB->open(); |
1432 |
|
|
+ |
1433 |
|
|
+ my ( $lang, @rest ) = $db->getLocale(); |
1434 |
|
|
+ |
1435 |
|
|
+ $lang = $lang || 'en_US'; |
1436 |
|
|
+ |
1437 |
|
|
+ $locale = $lang; |
1438 |
|
|
+ } |
1439 |
|
|
+ |
1440 |
|
|
+ my $base_dir = $ENV{ESMITH_LICENSE_DIR} || '/etc/e-smith/licenses'; |
1441 |
|
|
+ |
1442 |
|
|
+ $locale = 'en_US' unless ( -d "${base_dir}/${locale}" ); |
1443 |
|
|
+ |
1444 |
|
|
+ my $dir = "${base_dir}/${locale}"; |
1445 |
|
|
+ |
1446 |
|
|
+ opendir( DIR, $dir ) || die "Couldn't open licenses directory\n"; |
1447 |
|
|
+ |
1448 |
|
|
+ my @licenses; |
1449 |
|
|
+ foreach my $license ( readdir DIR ) |
1450 |
|
|
+ { |
1451 |
|
|
+ untaint ($license); |
1452 |
|
|
+ my $file = "${dir}/${license}"; |
1453 |
|
|
+ next unless ( -f $file ); |
1454 |
|
|
+ push @licenses, $file; |
1455 |
|
|
+ } |
1456 |
|
|
+ |
1457 |
|
|
+ @licenses = sort @licenses; |
1458 |
|
|
+ |
1459 |
|
|
+ return shift @licenses; |
1460 |
|
|
+} |
1461 |
|
|
+ |
1462 |
|
|
+ |
1463 |
|
|
+=item B<initialize_default_databases> |
1464 |
|
|
+ |
1465 |
|
|
+Initialize all databases located at /etc/e-smith/db. |
1466 |
|
|
+ |
1467 |
|
|
+=cut |
1468 |
|
|
+ |
1469 |
|
|
+sub initialize_default_databases |
1470 |
|
|
+{ |
1471 |
|
|
+ |
1472 |
|
|
+ # Optionally take an argument to the db root, for testing purposes. |
1473 |
|
|
+ my %defaults = ( |
1474 |
|
|
+ dbroot => '/etc/e-smith/db', |
1475 |
|
|
+ dbhome => '/home/e-smith/db', |
1476 |
|
|
+ old_dbhome => '/home/e-smith', |
1477 |
|
|
+ ); |
1478 |
|
|
+ my %args = ( %defaults, @_ ); |
1479 |
|
|
+ my $dbroot = $args{dbroot}; |
1480 |
|
|
+ my $dbhome = $args{dbhome}; |
1481 |
|
|
+ my $old_dbhome = $args{old_dbhome}; |
1482 |
|
|
+ |
1483 |
|
|
+ local *DH; |
1484 |
|
|
+ opendir DH, $dbroot |
1485 |
|
|
+ or die "Could not open $dbroot: $!"; |
1486 |
|
|
+ |
1487 |
|
|
+ my @dirs = readdir(DH); |
1488 |
|
|
+ |
1489 |
|
|
+ # Move all databases to new home first them migrate data |
1490 |
|
|
+ # Untaint db names while we are at it. |
1491 |
|
|
+ foreach my $file ( map { /(.+)/ ; $1 } grep !/^\./, @dirs ) |
1492 |
|
|
+ { |
1493 |
|
|
+ if (-f "${old_dbhome}/$file") |
1494 |
|
|
+ { |
1495 |
|
|
+ if (-l "${old_dbhome}/$file") |
1496 |
|
|
+ { |
1497 |
|
|
+ warn "symlink called ${old_dbhome}/$file exists\n"; |
1498 |
|
|
+ next; |
1499 |
|
|
+ } |
1500 |
|
|
+ |
1501 |
|
|
+ if (-s "${dbhome}/$file") |
1502 |
|
|
+ { |
1503 |
|
|
+ warn "${old_dbhome}/$file and ${dbhome}/$file exist\n"; |
1504 |
|
|
+ rename "${dbhome}/$file", "${dbhome}/$file." . time; |
1505 |
|
|
+ } |
1506 |
|
|
+ |
1507 |
|
|
+ warn "Rename ${old_dbhome}/$file => ${dbhome}/$file\n"; |
1508 |
|
|
+ rename "${old_dbhome}/$file", "${dbhome}/$file"; |
1509 |
|
|
+ } |
1510 |
|
|
+ } |
1511 |
|
|
+ |
1512 |
|
|
+ foreach my $file ( grep !/^\./, @dirs ) |
1513 |
|
|
+ { |
1514 |
|
|
+ # Untaint the result of readdir. As we're expecting filenames like |
1515 |
|
|
+ # 'configuration' and 'ipphones', lets restrict input to those. |
1516 |
|
|
+ if ($file =~ /(^[A-Za-z0-9_\.-]+$)/) |
1517 |
|
|
+ { |
1518 |
|
|
+ $file = $1; |
1519 |
|
|
+ } |
1520 |
|
|
+ else |
1521 |
|
|
+ { |
1522 |
|
|
+ warn "Not processing unexpected file $file\n"; |
1523 |
|
|
+ next; |
1524 |
|
|
+ } |
1525 |
|
|
+ |
1526 |
|
|
+ eval |
1527 |
|
|
+ { |
1528 |
|
|
+ my $h = esmith::ConfigDB->open($file); |
1529 |
|
|
+ if ($h) |
1530 |
|
|
+ { |
1531 |
|
|
+ warn "Migrating existing database $file\n"; |
1532 |
|
|
+ |
1533 |
|
|
+ # Convert old data to new format, and add any new defaults. Note |
1534 |
|
|
+ # that migrate returns FALSE on fatal errors. Report those to |
1535 |
|
|
+ # syslog. The error should still be in $@. |
1536 |
|
|
+ unless ( $h->migrate() ) |
1537 |
|
|
+ { |
1538 |
|
|
+ warn "Migration of db $file failed: " . esmith::DB->error; |
1539 |
|
|
+ } |
1540 |
|
|
+ } |
1541 |
|
|
+ else |
1542 |
|
|
+ { |
1543 |
|
|
+ warn "Creating database $file and setting defaults\n"; |
1544 |
|
|
+ |
1545 |
|
|
+ # create() and load defaults |
1546 |
|
|
+ unless ( $h = esmith::ConfigDB->create($file) ) |
1547 |
|
|
+ { |
1548 |
|
|
+ warn "Could not create $file db: " . esmith::DB->error; |
1549 |
|
|
+ } |
1550 |
|
|
+ } |
1551 |
|
|
+ |
1552 |
|
|
+ $h->close; |
1553 |
|
|
+ |
1554 |
|
|
+ esmith::util::chownFile( "root", "admin", "$dbhome/$file" ); |
1555 |
|
|
+ }; |
1556 |
|
|
+ if ($@) |
1557 |
|
|
+ { |
1558 |
|
|
+ warn "Fatal error while processing db $file: $@\n"; |
1559 |
|
|
+ } |
1560 |
|
|
+ } |
1561 |
|
|
+ return 1; |
1562 |
|
|
+} |
1563 |
|
|
+ |
1564 |
|
|
+ |
1565 |
|
|
+=head1 AUTHOR |
1566 |
|
|
+ |
1567 |
|
|
+Mitel Networks Corp. |
1568 |
|
|
+ |
1569 |
|
|
+For more information, see http://www.e-smith.org/ |
1570 |
|
|
+ |
1571 |
|
|
+=cut |
1572 |
|
|
+ |
1573 |
|
|
+1; |