/[smeserver]/rpms/e-smith-base/sme10/e-smith-base-5.8.0-bz11177-systemd.patch
ViewVC logotype

Annotation of /rpms/e-smith-base/sme10/e-smith-base-5.8.0-bz11177-systemd.patch

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (hide annotations) (download)
Tue Nov 17 02:56:00 2020 UTC (3 years, 7 months ago) by jpp
Branch: MAIN
CVS Tags: e-smith-base-5_8_0-52_el7_sme
* Mon Nov 16 2020 Jean-Philipe Pialasse <tests@pialasse.com> 5.8.0-52.sme
- allow more systemctl controls [SME: 11177]
  convert unrecognized signals from service2adjust in events for systemd
  handle unsupervised services the same way supervised were in adjust-services
  make service-status only log when service disabled and not fail it

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;

admin@koozali.org
ViewVC Help
Powered by ViewVC 1.2.1 RSS 2.0 feed