| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475 |
- # BEGIN COPYRIGHT BLOCK
- # This Program is free software; you can redistribute it and/or modify it under
- # the terms of the GNU General Public License as published by the Free Software
- # Foundation; version 2 of the License.
- #
- # This Program is distributed in the hope that it will be useful, but WITHOUT
- # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License along with
- # this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
- # Place, Suite 330, Boston, MA 02111-1307 USA.
- #
- # In addition, as a special exception, Red Hat, Inc. gives You the additional
- # right to link the code of this Program with code not covered under the GNU
- # General Public License ("Non-GPL Code") and to distribute linked combinations
- # including the two, subject to the limitations in this paragraph. Non-GPL Code
- # permitted under this exception must only link to the code of this Program
- # through those well defined interfaces identified in the file named EXCEPTION
- # found in the source code files (the "Approved Interfaces"). The files of
- # Non-GPL Code may instantiate templates or use macros or inline functions from
- # the Approved Interfaces without causing the resulting work to be covered by
- # the GNU General Public License. Only Red Hat, Inc. may make changes or
- # additions to the list of Approved Interfaces. You must obey the GNU General
- # Public License in all respects for all of the Program code and other code used
- # in conjunction with the Program except the Non-GPL Code covered by this
- # exception. If you modify this file, you may extend this exception to your
- # version of the file, but you are not obligated to do so. If you do not wish to
- # provide this exception without modification, you must delete this exception
- # statement from your version and license this file solely under the GPL without
- # exception.
- #
- #
- # Copyright (C) 2013 Red Hat, Inc.
- # All rights reserved.
- # END COPYRIGHT BLOCK
- #
- ###########################
- #
- # This perl module provides a way to create a new instance of
- # directory server.
- #
- ##########################
- package DSCreate;
- use DSUtil;
- use Inf;
- use FileConn;
- use Net::Domain qw(hostfqdn);
- # tempfiles
- use File::Temp qw(tempfile tempdir);
- use File::Path;
- use File::Copy;
- use File::Basename qw(basename dirname);
- use POSIX qw(:errno_h);
- # load perldap
- use Mozilla::LDAP::Conn;
- use Mozilla::LDAP::Utils qw(normalizeDN);
- use Mozilla::LDAP::API qw(ldap_explode_dn);
- use Mozilla::LDAP::LDIF;
- use Exporter;
- @ISA = qw(Exporter);
- @EXPORT = qw(createDSInstance removeDSInstance setDefaults createInstanceScripts
- makeOtherConfigFiles installSchema updateSelinuxPolicy updateTmpfilesDotD
- get_initconfigdir updateSystemD makeDSDirs);
- @EXPORT_OK = qw(createDSInstance removeDSInstance setDefaults createInstanceScripts
- makeOtherConfigFiles installSchema updateSelinuxPolicy updateTmpfilesDotD
- get_initconfigdir updateSystemD makeDSDirs);
- use strict;
- use SetupLog;
- sub get_initconfigdir {
- my $prefix = shift;
-
- # determine initconfig_dir
- if (getLogin eq 'root') {
- return "$prefix@initconfigdir@";
- } else {
- return "$ENV{HOME}/.@package_name@";
- }
- }
- sub checkPort {
- my $inf = shift;
- # allow port 0 if ldapi is used
- if ("@enable_ldapi@") {
- if ($inf->{slapd}->{ldapifilepath} &&
- ($inf->{slapd}->{ServerPort} == 0)) {
- return ();
- }
- }
- if ($inf->{slapd}->{ServerPort} !~ /^\d+$/) {
- return ('error_port_invalid', $inf->{slapd}->{ServerPort});
- }
- if (!portAvailable($inf->{slapd}->{ServerPort})) {
- return ('error_port_available', $inf->{slapd}->{ServerPort}, $!);
- }
- return ();
- }
- # checks the parameters in $inf to make sure the supplied values
- # are valid
- # returns null if successful, or an error string for use with getText()
- sub sanityCheckParams {
- my $inf = shift;
- my @errs = ();
- # if we don't need to start the server right away, we can skip the
- # port number checks
- if (!defined($inf->{slapd}->{start_server}) or
- ($inf->{slapd}->{start_server} == 1)) {
- if (@errs = checkPort($inf)) {
- return @errs;
- }
- }
- if($inf->{slapd}->{ServerIdentifier} eq "admin"){
- return ('error_reserved_serverid' ,"admin");
- } elsif (!isValidServerID($inf->{slapd}->{ServerIdentifier})) {
- return ('error_invalid_serverid', $inf->{slapd}->{ServerIdentifier});
- } elsif (-d $inf->{slapd}->{config_dir}) {
- return ('error_server_already_exists', $inf->{slapd}->{config_dir});
- }
- if (@errs = isValidUser($inf->{General}->{SuiteSpotUserID})) {
- return @errs;
- }
- if (@errs = isValidGroup($inf->{General}->{SuiteSpotGroup})) {
- return @errs;
- }
- if (!isValidDN($inf->{slapd}->{Suffix})) {
- return ('dialog_dssuffix_error', $inf->{slapd}->{Suffix});
- }
- if (!isValidDN($inf->{slapd}->{RootDN})) {
- return ('dialog_dsrootdn_error', $inf->{slapd}->{RootDN});
- }
- if ($inf->{slapd}->{RootDNPwd} =~ /^\{\w+\}.+/) {
- debug(1, "The root password is already hashed - no checking will be performed\n");
- } elsif (length($inf->{slapd}->{RootDNPwd}) < 8) {
- debug(0, "WARNING: The root password is less than 8 characters long. You should choose a longer one.\n");
- }
- if (@errs = checkHostname($inf->{General}->{FullMachineName}, 0)) {
- debug(1, @errs);
- return @errs;
- }
- return ();
- }
- sub getMode {
- my $inf = shift;
- my $mode = shift;
- my $rest = shift;
- if (!$rest) {
- $rest = "0";
- }
- if (defined($inf->{General}->{SuiteSpotGroup})) {
- $mode = "0" . $mode . $mode . $rest;
- } else {
- $mode = "0" . $mode . $rest . $rest;
- }
- return oct($mode);
- }
- # This is used to change the ownership and permissions of files and directories
- # The mode is just a single digit octal number (e.g. 4 6 7)
- # If there is a group, the ownership and permissions will allow group access
- # otherwise, only the owner will be allowed access
- sub changeOwnerMode {
- my $inf = shift;
- my $mode = shift;
- my $it = shift;
- my $gidonly = shift;
- my $othermode = shift;
- my $uid = getpwnam $inf->{General}->{SuiteSpotUserID};
- my $gid = -1; # default to leave it alone
- my $mode_string = "";
- if (defined($inf->{General}->{SuiteSpotGroup})) {
- $gid = getgrnam $inf->{General}->{SuiteSpotGroup};
- }
- $mode = getMode($inf, $mode, $othermode);
- $! = 0; # clear errno
- chmod $mode, $it;
- if ($!) {
- return ('error_chmoding_file', $it, $!);
- }
- $mode_string = sprintf "%lo", $mode;
- debug(1, "changeOwnerMode: changed mode of $it to $mode_string\n");
- $! = 0; # clear errno
- if ( $gidonly ) {
- chown -1, $gid, $it;
- } else {
- chown $uid, $gid, $it;
- }
- if ($!) {
- return ('error_chowning_file', $it, $inf->{General}->{SuiteSpotUserID}, $!);
- }
- if ( $gidonly ) {
- debug(1, "changeOwnerMode: changed group ownership of $it to group $gid\n");
- } else {
- debug(1, "changeOwnerMode: changed ownership of $it to user $uid group $gid\n");
- }
- return ();
- }
- sub makeDSDirs {
- my $inf = shift;
- my $verbose = ($DSUtil::debuglevel > 0);
- my $mode = getMode($inf, 7);
- my @errs;
- # These paths are owned by the SuiteSpotGroup
- # This allows the admin server to run as a different,
- # more privileged user than the directory server, but
- # still allows the admin server to manage directory
- # server files/dirs without being root
- for my $kw (qw(inst_dir config_dir schema_dir log_dir lock_dir run_dir tmp_dir
- cert_dir db_dir ldif_dir bak_dir)) {
- my $dir = $inf->{slapd}->{$kw};
- @errs = makePaths($dir, $mode, $inf->{General}->{SuiteSpotUserID},
- $inf->{General}->{SuiteSpotGroup});
- if (@errs) {
- return @errs;
- }
- }
- # run_dir is a special case because it is usually shared among
- # all instances and the admin server
- # all instances must be able to write to it
- # if the SuiteSpotUserID is root or 0, we can just skip
- # this because root will have access to it - we really
- # shouldn't be using root anyway, primarily just for
- # legacy migration support
- # if there are two different user IDs that need access
- # to this directory, then SuiteSpotGroup must be defined,
- # and both users must be members of the SuiteSpotGroup
- if (($inf->{General}->{SuiteSpotUserID} eq 'root') ||
- (defined($inf->{General}->{SuiteSpotUserID}) &&
- ($inf->{General}->{SuiteSpotUserID} =~ /^0$/))) {
- # skip
- debug(3, "Root user " . $inf->{General}->{SuiteSpotUserID} . " already has access to $inf->{slapd}->{run_dir} - skipping\n");
- } else {
- my $dir = $inf->{slapd}->{run_dir};
- # rwx by user only, or by user & group if a group is defined. Also only change the group ownership.
- @errs = changeOwnerMode($inf, 7, $dir, 1);
- debug(3, "\t" . `/bin/ls -ld $dir`);
- }
- # set the group of the parent dir of config_dir and inst_dir
- if (defined($inf->{General}->{SuiteSpotGroup})) {
- for my $kw (qw(inst_dir config_dir)) {
- my $dir = $inf->{slapd}->{$kw};
- my $parent = dirname($dir);
- # changeOwnerMode(inf, mode, file, gidonly, othermode);
- @errs = changeOwnerMode($inf, 7, $parent, 1, 5);
- if (@errs) {
- return @errs;
- }
- }
- }
- return @errs;
- }
- sub createInstanceScripts {
- my $inf = shift;
- my $skip = shift;
- my $perlexec = "@perlexec@" || "/usr/bin/env perl";
- my $myperl = "!$perlexec";
- my $mydevnull = (-f "/dev/null" ? " /dev/null " : " NUL ");
- # determine initconfig_dir
- my $initconfig_dir = $inf->{slapd}->{initconfig_dir} || get_initconfigdir($inf->{General}->{prefix});
- my %maptable = (
- "DS-ROOT" => $inf->{General}->{prefix},
- "SEP" => "/", # works on all platforms
- "SERVER-NAME" => $inf->{General}->{FullMachineName},
- "SERVER-PORT" => $inf->{slapd}->{ServerPort},
- "PERL-EXEC" => $myperl,
- "DEV-NULL" => $mydevnull,
- "ROOT-DN" => $inf->{slapd}->{RootDN},
- "LDIF-DIR" => $inf->{slapd}->{ldif_dir},
- "SERV-ID" => $inf->{slapd}->{ServerIdentifier},
- "BAK-DIR" => $inf->{slapd}->{bak_dir},
- "SERVER-DIR" => $inf->{General}->{ServerRoot},
- "CONFIG-DIR" => $inf->{slapd}->{config_dir},
- "INITCONFIG-DIR" => $initconfig_dir,
- "INST-DIR" => $inf->{slapd}->{inst_dir},
- "RUN-DIR" => $inf->{slapd}->{run_dir},
- "PRODUCT-NAME" => "slapd",
- "SERVERBIN-DIR" => $inf->{slapd}->{sbindir},
- "DB-DIR" => $inf->{slapd}->{db_dir}
- );
- my $dir = "$inf->{General}->{prefix}@taskdir@";
- for my $file (glob("$dir/template-*")) {
- my $basename = $file;
- $basename =~ s/^.*template-//;
- my $destfile = "$inf->{slapd}->{inst_dir}/$basename";
- next if ($skip and -f $destfile); # in skip mode, skip files that already exist
- if (!open(SRC, "< $file")) {
- return ("error_opening_scripttmpl", $file, $!);
- }
- if (!open(DEST, "> $destfile")) {
- return ("error_opening_scripttmpl", $destfile, $!);
- }
- my $contents; # slurp entire file into memory
- read SRC, $contents, int(-s $file);
- close(SRC);
- while (my ($key, $val) = each %maptable) {
- $contents =~ s/\{\{$key\}\}/$val/g;
- }
- print DEST $contents;
- close(DEST);
- my @errs = changeOwnerMode($inf, 5, $destfile);
- if (@errs) {
- return @errs;
- }
- }
- return ();
- }
- sub createConfigFile {
- my $inf = shift;
- my $conffile = "$inf->{slapd}->{config_dir}/dse.ldif";
- my $conn = new FileConn;
- my @errs;
- # first, create the basic config
- my $mapper = new Inf("$inf->{General}->{prefix}@infdir@/dscreate.map");
- my $dsinf = new Inf("$inf->{General}->{prefix}@infdir@/slapd.inf");
- if (!$inf->{slapd}->{ds_bename}) {
- $inf->{slapd}->{ds_bename} = "userRoot"; # for suffix-db
- }
- $mapper = process_maptbl($mapper, \@errs, $inf, $dsinf);
- if (!$mapper or @errs) {
- $conn->close();
- if (!@errs) {
- @errs = ('error_creating_file', $conffile, $!);
- }
- return @errs;
- }
- my @ldiffiles = ("$inf->{General}->{prefix}@templatedir@/template-dse.ldif",
- "$inf->{General}->{prefix}@templatedir@/template-suffix-db.ldif",
- "$inf->{General}->{prefix}@templatedir@/template-sasl.ldif");
- if ("@enable_pam_passthru@") {
- push @ldiffiles, "$inf->{General}->{prefix}@templatedir@/template-pampta.ldif";
- }
- if ("@enable_bitwise@") {
- push @ldiffiles, "$inf->{General}->{prefix}@templatedir@/template-bitwise.ldif";
- }
- if ("@enable_dna@") {
- push @ldiffiles, "$inf->{General}->{prefix}@templatedir@/template-dnaplugin.ldif";
- }
- if (-f "$inf->{General}->{prefix}@updatedir@/50replication-plugins.ldif") {
- push @ldiffiles, "$inf->{General}->{prefix}@updatedir@/50replication-plugins.ldif";
- }
- if (-f "$inf->{General}->{prefix}@updatedir@/50posix-winsync-plugin.ldif") {
- push @ldiffiles, "$inf->{General}->{prefix}@updatedir@/50posix-winsync-plugin.ldif";
- }
- if (-f "$inf->{General}->{prefix}@templatedir@/90betxn-plugins.ldif") {
- push @ldiffiles, "$inf->{General}->{prefix}@templatedir@/90betxn-plugins.ldif";
- }
- # additional configuration LDIF files
- if (exists($inf->{slapd}->{ConfigFile})) {
- if (ref($inf->{slapd}->{ConfigFile})) {
- push @ldiffiles, @{$inf->{slapd}->{ConfigFile}};
- } else {
- push @ldiffiles, $inf->{slapd}->{ConfigFile};
- }
- }
- getMappedEntries($mapper, \@ldiffiles, \@errs, \&check_and_add_entry,
- [$conn]);
- if (@errs) {
- $conn->close();
- return @errs;
- }
- if ("@enable_ldapi@") {
- my $ent = $conn->search("cn=config", "base", "(objectclass=*)");
- if (defined($inf->{slapd}->{ldapifilepath})) {
- $ent->setValues("nsslapd-ldapifilepath", $inf->{slapd}->{ldapifilepath});
- $ent->setValues("nsslapd-ldapilisten", "on");
- } else {
- my $parent = dirname($inf->{slapd}->{run_dir});
- $ent->setValues("nsslapd-ldapifilepath",
- "$parent/slapd-$inf->{slapd}->{ServerIdentifier}.socket");
- $ent->setValues("nsslapd-ldapilisten", "off");
- }
- if ("@enable_autobind@") {
- $ent->setValues("nsslapd-ldapiautobind", "off");
- $ent->setValues("nsslapd-ldapimaprootdn", $inf->{slapd}->{RootDN});
- $ent->setValues("nsslapd-ldapimaptoentries", "off");
- $ent->setValues("nsslapd-ldapiuidnumbertype", "uidNumber");
- $ent->setValues("nsslapd-ldapigidnumbertype", "gidNumber");
- $ent->setValues("nsslapd-ldapientrysearchbase", $inf->{slapd}->{Suffix});
- if ("@enable_auto_dn_suffix@") {
- $ent->setValues("nsslapd-ldapiautodnsuffix", "cn=peercred,cn=external,cn=auth");
- }
- }
- $ent->setValues("nsslapd-defaultNamingContext", $inf->{slapd}->{Suffix});
- if (!$conn->update($ent)) {
- $conn->close();
- return ("error_enabling_feature", "ldapi", $conn->getErrorString());
- }
- }
- if ($inf->{slapd}->{sasl_path}) {
- my $ent = $conn->search("cn=config", "base", "(objectclass=*)");
- $ent->setValues("nsslapd-saslpath", $inf->{slapd}->{sasl_path});
- if (!$conn->update($ent)) {
- $conn->close();
- return ("error_enabling_feature", "sasl_path", $conn->getErrorString());
- }
- }
- if (!$conn->write($conffile)) {
- $conn->close();
- return ("error_writing_ldif", $conffile, $!);
- }
- $conn->close();
- if (@errs = changeOwnerMode($inf, 6, $conffile)) {
- return @errs;
- }
- # make a copy
- my $origconf = "$inf->{slapd}->{config_dir}/dse_original.ldif";
- $! = 0; # clear errno
- copy($conffile, $origconf);
- if ($!) {
- return ('error_copying_file', $conffile, $origconf, $!);
- }
- if (@errs = changeOwnerMode($inf, 4, $origconf)) {
- return @errs;
- }
-
- return @errs;
- }
- sub makeOtherConfigFiles {
- my $inf = shift;
- my $skip = shift;
- my @errs;
- my %maptable = (
- "DS-ROOT" => $inf->{General}->{prefix},
- "SERVER-DIR" => $inf->{General}->{ServerRoot},
- "CONFIG-DIR" => $inf->{slapd}->{config_dir},
- "INST-DIR" => $inf->{slapd}->{inst_dir},
- "RUN-DIR" => $inf->{slapd}->{run_dir},
- "PRODUCT-NAME" => "slapd",
- "SERVERBIN-DIR" => $inf->{slapd}->{sbindir},
- );
- # install certmap.conf at <configdir>
- my $src = "$inf->{General}->{prefix}@configdir@/certmap.conf";
- my $dest = "$inf->{slapd}->{config_dir}/certmap.conf";
- $! = 0; # clear errno
- #in skip mode, skip files that already exist
- unless ($skip and -f $dest) {
- copy($src, $dest);
- if ($!) {
- return ('error_copying_file', $src, $dest, $!);
- }
- if (@errs = changeOwnerMode($inf, 4, $dest)) {
- return @errs;
- }
- }
- $src = "$inf->{General}->{prefix}@configdir@/slapd-collations.conf";
- $dest = "$inf->{slapd}->{config_dir}/slapd-collations.conf";
- $! = 0; # clear errno
- #in skip mode, skip files that already exist
- unless ($skip and -f $dest) {
- copy($src, $dest);
- if ($!) {
- return ('error_copying_file', $src, $dest, $!);
- }
- if (@errs = changeOwnerMode($inf, 4, $dest)) {
- return @errs;
- }
- }
- # determine initconfig_dir
- my $initconfig_dir = $inf->{slapd}->{initconfig_dir} || get_initconfigdir($inf->{General}->{prefix});
- # install instance specific initconfig script
- $src = "$inf->{General}->{prefix}@configdir@/template-initconfig";
- $dest = "$initconfig_dir/@package_name@-$inf->{slapd}->{ServerIdentifier}";
- $! = 0; # clear errno
- # in skip mode, skip files that already exist
- unless ($skip and -f $dest) {
- if (!open(SRC, "< $src")) {
- return ("error_opening_scripttmpl", $src, $!);
- }
- if (!open(DEST, "> $dest")) {
- return ("error_opening_scripttmpl", $dest, $!);
- }
- my $contents; # slurp entire file into memory
- read SRC, $contents, int(-s $src);
- close(SRC);
- while (my ($key, $val) = each %maptable) {
- $contents =~ s/\{\{$key\}\}/$val/g;
- }
- print DEST $contents;
- close(DEST);
- if (@errs = changeOwnerMode($inf, 4, $dest)) {
- return @errs;
- }
- }
- return ();
- }
- sub installSchema {
- my $inf = shift;
- my $skip = shift;
- my @errs;
- my @schemafiles = ();
- if (!defined($inf->{slapd}->{install_full_schema}) or
- $inf->{slapd}->{install_full_schema}) {
- push @schemafiles, glob("$inf->{General}->{prefix}@schemadir@/*");
- } else {
- push @schemafiles, "$inf->{General}->{prefix}@schemadir@/00core.ldif",
- "$inf->{General}->{prefix}@schemadir@/01core389.ldif";
- }
- # additional schema files
- if (exists($inf->{slapd}->{SchemaFile})) {
- if (ref($inf->{slapd}->{SchemaFile})) {
- push @schemafiles, @{$inf->{slapd}->{SchemaFile}};
- } else {
- push @schemafiles, $inf->{slapd}->{SchemaFile};
- }
- }
- for my $file (@schemafiles) {
- my $src = $file;
- my $basename = basename($src);
- my $dest = "$inf->{slapd}->{schema_dir}/$basename";
- next if ($skip and -f $dest); # skip files that already exist
- $! = 0; # clear errno
- copy($src, $dest);
- if ($!) {
- return ('error_copying_file', $src, $dest, $!);
- }
- my $mode = 4; # default read only
- if ($basename eq "99user.ldif") {
- $mode = 6; # read write
- }
- if (@errs = changeOwnerMode($inf, $mode, $dest)) {
- return @errs;
- }
- }
- return ();
- }
- # maps the suffix attr to the filename to use
- my %suffixTable = (
- 'o' => "@templatedir@/template-org.ldif",
- 'dc' => "@templatedir@/template-domain.ldif",
- 'ou' => "@templatedir@/template-orgunit.ldif",
- 'st' => "@templatedir@/template-state.ldif",
- 'l' => "@templatedir@/template-locality.ldif",
- 'c' => "@templatedir@/template-country.ldif"
- );
- sub initDatabase {
- my $inf = shift;
- my $istempldif = 0;
- # If the user has specified an LDIF file to use to initialize the database,
- # load it now
- my $ldiffile = $inf->{slapd}->{InstallLdifFile};
- if ($ldiffile =~ /none/i) {
- debug(1, "No ldif file or org entries specified - no initial database will be created\n");
- return ();
- } elsif ($ldiffile && ($ldiffile !~ /suggest/i)) {
- debug(1, "Loading initial ldif file $ldiffile\n");
- if (! -r $ldiffile) {
- return ('error_opening_init_ldif', $ldiffile);
- }
- } elsif (($inf->{slapd}->{Suffix} =~ /^(.*?)=/) && $suffixTable{$1}) {
- my @errs;
- my $template = $inf->{General}->{prefix} . $suffixTable{$1};
- my $mapper = new Inf("$inf->{General}->{prefix}@infdir@/dsorgentries.map");
- my $dsinf = new Inf("$inf->{General}->{prefix}@infdir@/slapd.inf");
- my @rdns = ldap_explode_dn($inf->{slapd}->{Suffix}, 1);
- $inf->{slapd}->{naming_value} = $rdns[0];
- $mapper = process_maptbl($mapper, \@errs, $inf, $dsinf);
- if (!$mapper or @errs) {
- return @errs;
- }
-
- my @ldiffiles = ($template, "$inf->{General}->{prefix}@templatedir@/template-baseacis.ldif");
- # default is to create org entries unless explicitly set to none
- if (!exists($inf->{slapd}->{InstallLdifFile}) or
- ($inf->{slapd}->{InstallLdifFile} =~ /suggest/i)) {
- push @ldiffiles, "$inf->{General}->{prefix}@templatedir@/template.ldif";
- }
-
- my ($fh, $templdif) = tempfile("ldifXXXXXX", SUFFIX => ".ldif", OPEN => 0,
- DIR => File::Spec->tmpdir);
- if (!$templdif) {
- return ('error_creating_templdif', $!);
- }
- my $conn = new FileConn;
- $conn->setNamingContext($inf->{slapd}->{Suffix});
- getMappedEntries($mapper, \@ldiffiles, \@errs, \&check_and_add_entry,
- [$conn]);
- if (@errs) {
- $conn->close();
- return @errs;
- }
- if (!$conn->write($templdif)) {
- $conn->close();
- return ('error_writing_ldif', $templdif, $!);
- }
- $conn->close();
- if (@errs) {
- return @errs;
- }
- if (@errs = changeOwnerMode($inf, 4, $templdif)) {
- unlink($ldiffile);
- return @errs;
- }
- # $templdif now contains the ldif to import
- $ldiffile = $templdif;
- $istempldif = 1;
- }
- if (!$ldiffile) {
- return ();
- }
- my $cmd = "$inf->{slapd}->{inst_dir}/ldif2db -n $inf->{slapd}->{ds_bename} -i \'$ldiffile\'";
- $? = 0; # clear error condition
- my $output = `$cmd 2>&1`;
- my $result = $?;
- if ($istempldif) {
- unlink($ldiffile);
- }
- if ($result) {
- return ('error_importing_ldif', $ldiffile, $result, $output);
- }
- debug(1, $output);
- return ();
- }
- sub startServer {
- my $inf = shift;
- return () if (defined($inf->{slapd}->{start_server}) && !$inf->{slapd}->{start_server});
- my @errs;
- # get error log
- my $errLog = "$inf->{slapd}->{log_dir}/errors";
- my $startcmd = "$inf->{slapd}->{inst_dir}/start-slapd";
- if ("@systemdsystemunitdir@" and (getLogin() eq 'root')) {
- $startcmd = "/bin/systemctl start @package_name@\@$inf->{slapd}->{ServerIdentifier}.service";
- }
- # emulate tail -f
- # if the last line we see does not contain "slapd started", try again
- my $done = 0;
- my $started = 0;
- my $code = 0;
- my $lastLine = "";
- my $cmdPat = 'slapd started\.';
- my $timeout = $inf->{slapd}->{startup_timeout};
- $timeout = $timeout?$timeout:600; # default is 10 minutes
- $timeout = time + $timeout;
- debug(1, "Starting the server: $startcmd\n");
- $? = 0; # clear error condition
- my $output = `$startcmd 2>&1`;
- $code = $?;
- debug(1, "Started the server: code $code\n");
- if ($code) {
- debug(0, $output);
- } else {
- debug(1, $output);
- }
- # try to open the server error log
- my $ii = 0;
- while (time < $timeout) {
- if (open(IN, $errLog)) {
- last;
- }
- sleep(1);
- if (!($ii % 10)) {
- debug(0, "Attempting to obtain server status . . .\n");
- }
- ++$ii;
- }
- if (! -f $errLog) {
- debug(0, "Error: Could not read error log $errLog to get server startup status. Error: $!\n");
- return ('error_starting_server', $startcmd, "no status", $!);
- }
- if (time >= $timeout) {
- debug(0, "Error: timed out waiting for the server to start and write to $errLog");
- return ('error_starting_server', $startcmd, "timeout", 0);
- }
-
- my $pos = tell(IN);
- my $line;
- while (($done == 0) && (time < $timeout)) {
- for (; ($done == 0) && ($line = <IN>); $pos = tell(IN)) {
- $lastLine = $line;
- debug(1, $line);
- if ($line =~ /$cmdPat/) {
- $done = 1;
- $started = 1;
- } elsif ($line =~ /Initialization Failed/) {
- debug(1, "Server failed to start, retrying . . .\n");
- $code = system($startcmd);
- } elsif ($line =~ /exiting\./) {
- debug(1, "Server failed to start, retrying . . .\n");
- $code = system($startcmd);
- }
- }
- if ($lastLine =~ /PR_Bind/) {
- # server port conflicts with another one, just report and punt
- debug(0, $lastLine);
- @errs = ('error_port_available', $inf->{slapd}->{ServerPort}, $!);
- $done = 1;
- }
- if ($done == 0) {
- # rest a bit, then . . .
- sleep(2);
- # . . . reset the EOF status of the file desc
- seek(IN, $pos, 0);
- }
- }
- close(IN);
- if (!$started) {
- $! = $code;
- my $now = time;
- if ($now > $timeout) {
- debug(0, "Possible timeout starting server: timeout=$timeout now=$now\n");
- }
- @errs = ('error_starting_server', $startcmd, $lastLine, $!);
- } else {
- debug(1, "Your new directory server has been started.\n");
- }
-
- return @errs;
- }
- sub set_path_attribute {
- my $val = shift;
- my $defaultval = shift;
- my $prefix = shift;
- if ($val) {
- return "$prefix" . "$val";
- } else {
- return "$prefix" . "$defaultval";
- }
- }
- sub setDefaults {
- my $inf = shift;
- # set default values
- # this turns off the warnings
- if (!defined($inf->{General}->{prefix})) {
- $inf->{General}->{prefix} = "";
- }
- if (!$inf->{General}->{FullMachineName}) {
- $inf->{General}->{FullMachineName} = hostfqdn;
- }
- if (!$inf->{General}->{SuiteSpotUserID}) {
- if ($> != 0) { # if not root, use the user's uid
- $inf->{General}->{SuiteSpotUserID} = getLogin;
- }
- # otherwise, the uid must be specified
- }
- if (!$inf->{General}->{SuiteSpotGroup}) {
- # If the group wasn't specified, use the primary group
- # of the SuiteSpot user
- $inf->{General}->{SuiteSpotGroup} = getGroup($inf->{General}->{SuiteSpotUserID});
- }
- if (!$inf->{slapd}->{RootDN}) {
- $inf->{slapd}->{RootDN} = "cn=Directory Manager";
- }
- if (!$inf->{slapd}->{Suffix}) {
- my $suffix = $inf->{General}->{FullMachineName};
- # convert fqdn to dc= domain components
- $suffix =~ s/^[^\.]*\.//; # just the domain part
- $suffix = "dc=$suffix";
- $suffix =~ s/\./,dc=/g;
- $inf->{slapd}->{Suffix} = $suffix;
- }
- $inf->{slapd}->{Suffix} = normalizeDN($inf->{slapd}->{Suffix});
- if (!$inf->{slapd}->{ServerIdentifier}) {
- my $servid = $inf->{General}->{FullMachineName};
- # strip out the leftmost domain component
- $servid =~ s/\..*$//;
- $inf->{slapd}->{ServerIdentifier} = $servid;
- }
- if ("@with_fhs_opt@") {
- $inf->{General}->{ServerRoot} = "$inf->{General}->{prefix}/opt/@PACKAGE_NAME@";
- } else {
- $inf->{General}->{ServerRoot} = "$inf->{General}->{prefix}@serverdir@";
- }
- if (!defined($inf->{slapd}->{sasl_path})) {
- if ($ ne "linux") {
- $inf->{slapd}->{sasl_path} = "$inf->{General}->{prefix}@libdir@/sasl2";
- }
- }
- if (!defined($inf->{slapd}->{ServerPort}) and
- !defined($inf->{slapd}->{ldapifilepath})) {
- if ("@enable_ldapi@") {
- return ('error_missing_port_and_ldapi');
- } else {
- return ('error_missing_port');
- }
- }
- if (!defined($inf->{slapd}->{ServerPort})) {
- $inf->{slapd}->{ServerPort} = 0;
- }
- $inf->{slapd}->{HashedRootDNPwd} = getHashedPassword($inf->{slapd}->{RootDNPwd});
- $inf->{slapd}->{localstatedir} = set_path_attribute($inf->{slapd}->{localstatedir},
- "@localstatedir@",
- $inf->{General}->{prefix});
- my $localstatedir = $inf->{slapd}->{localstatedir};
- my $servid = $inf->{slapd}->{ServerIdentifier};
- $inf->{slapd}->{sysconfdir} = set_path_attribute($inf->{slapd}->{sysconfdir},
- "@sysconfdir@",
- $inf->{General}->{prefix});
- my $sysconfdir = $inf->{slapd}->{sysconfdir};
- $inf->{slapd}->{bindir} = set_path_attribute($inf->{slapd}->{bindir},
- "@bindir@",
- $inf->{General}->{prefix});
- $inf->{slapd}->{sbindir} = set_path_attribute($inf->{slapd}->{sbindir},
- "@sbindir@",
- $inf->{General}->{prefix});
- $inf->{slapd}->{datadir} = set_path_attribute($inf->{slapd}->{datadir},
- "@datadir@",
- $inf->{General}->{prefix});
- if (!defined($inf->{slapd}->{inst_dir})) {
- $inf->{slapd}->{inst_dir} = "$inf->{General}->{ServerRoot}/slapd-$servid";
- }
- if (!defined($inf->{slapd}->{config_dir})) {
- $inf->{slapd}->{config_dir} = "$inf->{General}->{prefix}@instconfigdir@/slapd-$servid";
- }
- $ENV{DS_CONFIG_DIR} = $inf->{slapd}->{config_dir};
- if (!defined($inf->{slapd}->{schema_dir})) {
- $inf->{slapd}->{schema_dir} = "$sysconfdir/@PACKAGE_NAME@/slapd-$servid/schema";
- }
- if (!defined($inf->{slapd}->{lock_dir})) {
- if ("@with_fhs_opt@") {
- $inf->{slapd}->{lock_dir} = "$localstatedir/@PACKAGE_NAME@/slapd-$servid/lock";
- } else {
- $inf->{slapd}->{lock_dir} = "$localstatedir/lock/@PACKAGE_NAME@/slapd-$servid";
- }
- }
- if (!defined($inf->{slapd}->{log_dir})) {
- if ("@with_fhs_opt@") {
- $inf->{slapd}->{log_dir} = "$localstatedir/@PACKAGE_NAME@/slapd-$servid/log";
- } else {
- $inf->{slapd}->{log_dir} = "$localstatedir/log/@PACKAGE_NAME@/slapd-$servid";
- }
- }
- if (!defined($inf->{slapd}->{run_dir})) {
- if ("@with_fhs_opt@") {
- $inf->{slapd}->{run_dir} = "$localstatedir/@PACKAGE_NAME@/slapd-$servid/run";
- } else {
- $inf->{slapd}->{run_dir} = "$localstatedir/run/@PACKAGE_NAME@";
- }
- }
- $ENV{DS_RUN_DIR} = $inf->{slapd}->{run_dir};
- if (!defined($inf->{slapd}->{db_dir})) {
- if ("@with_fhs_opt@") {
- $inf->{slapd}->{db_dir} = "$localstatedir/@PACKAGE_NAME@/slapd-$servid/db";
- } else {
- $inf->{slapd}->{db_dir} = "$localstatedir/lib/@PACKAGE_NAME@/slapd-$servid/db";
- }
- }
- if (!defined($inf->{slapd}->{bak_dir})) {
- if ("@with_fhs_opt@") {
- $inf->{slapd}->{bak_dir} = "$localstatedir/@PACKAGE_NAME@/slapd-$servid/bak";
- } else {
- $inf->{slapd}->{bak_dir} = "$localstatedir/lib/@PACKAGE_NAME@/slapd-$servid/bak";
- }
- }
- $ENV{DS_BAK_DIR} = $inf->{slapd}->{bak_dir};
- if (!defined($inf->{slapd}->{ldif_dir})) {
- if ("@with_fhs_opt@") {
- $inf->{slapd}->{ldif_dir} = "$localstatedir/@PACKAGE_NAME@/slapd-$servid/ldif";
- } else {
- $inf->{slapd}->{ldif_dir} = "$localstatedir/lib/@PACKAGE_NAME@/slapd-$servid/ldif";
- }
- }
- if (!defined($inf->{slapd}->{tmp_dir})) {
- if ("@with_fhs_opt@") {
- $inf->{slapd}->{tmp_dir} = "/tmp";
- } else {
- $inf->{slapd}->{tmp_dir} = "/tmp";
- }
- }
- $ENV{DS_TMP_DIR} = $inf->{slapd}->{tmp_dir};
- if (!defined($inf->{slapd}->{cert_dir})) {
- $inf->{slapd}->{cert_dir} = $inf->{slapd}->{config_dir};
- }
- return ();
- }
- sub updateSelinuxPolicy {
- my $inf = shift;
- # if selinux is not available, do nothing
- if ("@with_selinux@") {
- my $localstatedir = $inf->{slapd}->{localstatedir};
- # run restorecon on all of the parent directories we
- # may have created (this only happens if this is the
- # first instance created).
- if ("@with_fhs_opt@") {
- system("restorecon -R $localstatedir/@PACKAGE_NAME@");
- } else {
- system("restorecon -R $localstatedir/lock/@PACKAGE_NAME@");
- system("restorecon -R $localstatedir/log/@PACKAGE_NAME@");
- system("restorecon -R $localstatedir/run/@PACKAGE_NAME@");
- system("restorecon -R $localstatedir/lib/@PACKAGE_NAME@");
- }
- # run restorecon on all instance directories we created
- for my $kw (qw(inst_dir config_dir schema_dir log_dir lock_dir run_dir tmp_dir
- cert_dir db_dir ldif_dir bak_dir)) {
- my $dir = $inf->{slapd}->{$kw};
- system("restorecon -R $dir");
- }
- # label the selected port as ldap_port_t
- if ($inf->{slapd}->{ServerPort} != 0) {
- my $need_label = 1;
- # check if the port is already labeled properly
- my $portline = `semanage port -l | grep ldap_port_t | grep tcp`;
- chomp($portline);
- $portline =~ s/ldap_port_t\s+tcp\s+//g;
- my @labeledports = split(/,\s+/, $portline);
- foreach my $labeledport (@labeledports) {
- if (index($labeledport, "-") == -1) {
- # this is not a range of ports
- if ($inf->{slapd}->{ServerPort} == $labeledport) {
- $need_label = 0;
- last;
- }
- } else {
- # this is a range of ports like '<portMin>-<portMax>'
- my @range = split(/-/, $labeledport);
- if ((@range[0] <= $inf->{slapd}->{ServerPort}) && ($inf->{slapd}->{ServerPort} <= @range[1])) {
- $need_label = 0;
- last;
- }
- }
- }
- if ($need_label == 1) {
- my $semanage_err;
- my $rc;
- my $retry = 60;
- $ENV{LANG} = "C";
- while (($retry > 0) && ($semanage_err = `semanage port -a -t ldap_port_t -p tcp $inf->{slapd}->{ServerPort} 2>&1`) && ($rc = $?)) {
- debug(1, "Adding port $inf->{slapd}->{ServerPort} to selinux policy failed - $semanage_err (return code: $rc).\n");
- debug(1, "Retrying in 5 seconds\n");
- sleep(5);
- $retry--;
- }
- if (0 == $retry) {
- debug(1, "Adding port $inf->{slapd}->{ServerPort} to selinux policy failed - $semanage_err (return code: $rc).\n");
- debug(1, "Reached time limit.\n");
- }
- }
- }
- }
- }
- sub updateTmpfilesDotD {
- my $inf = shift;
- my $dir = "@with_tmpfiles_d@";
- # if tmpfiles.d is not available, do nothing
- if ($dir and -d $dir) {
- my $filename = "$dir/@package_name@-$inf->{slapd}->{ServerIdentifier}.conf";
- if (-f $filename) {
- debug(3, "Removing the old tmpfile: $filename\n");
- if (!unlink($filename)){
- debug(1, "Can not delete old tmpfile $filename ($!)\n");
- return();
- }
- }
- debug(3, "Creating $filename\n");
- my $username = "";
- my $groupname = "";
- my $conffile = "$inf->{slapd}->{config_dir}/dse.ldif";
- # use the owner:group from the dse.ldif for the instance
- if (-f $conffile) {
- my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
- $atime,$mtime,$ctime,$blksize,$blocks)
- = stat(_);
- $username = getpwuid($uid);
- if (!$username) {
- debug(1, "Error: could not get username from uid $uid\n");
- }
- $groupname = getgrgid($gid);
- }
- # else, see if we were passed in values to use
- if (!$username) {
- $username = $inf->{General}->{SuiteSpotUserID};
- }
- if (!$groupname) {
- if (defined($inf->{General}->{SuiteSpotGroup})) {
- $groupname = $inf->{General}->{SuiteSpotGroup};
- } else { # $groupname
- $groupname = "-"; # use default
- }
- }
- my $parent = dirname($inf->{slapd}->{lock_dir});
- if (!open(DOTDFILE, ">$filename")) {
- return ( [ 'error_creating_file', $filename, $! ] );
- }
- # Type Path Mode UID GID Age
- # d /var/run/user 0755 root root 10d
- # we don't use age
- print DOTDFILE "d $inf->{slapd}->{run_dir} 0770 $username $groupname\n";
- print DOTDFILE "d $parent 0770 $username $groupname\n";
- print DOTDFILE "d $inf->{slapd}->{lock_dir} 0770 $username $groupname\n";
- close DOTDFILE;
- } else {
- debug(3, "no tmpfiles.d - skipping\n");
- }
- return ();
- }
- sub updateSystemD {
- my $inf = shift;
- my $unitdir = "@systemdsystemunitdir@";
- my $confbasedir = "@systemdsystemconfdir@";
- my $confdir = "$confbasedir/@[email protected]";
- if (!$unitdir or !$confdir or ! -d $unitdir or ! -d $confdir) {
- debug(3, "no systemd - skipping\n");
- return ();
- }
- my @errs = ();
- my $initconfigdir = $inf->{slapd}->{initconfigdir} || get_initconfigdir($inf->{General}->{prefix});
- debug(1, "updating systemd files in $unitdir and $confdir for all directory server instances in $initconfigdir\n");
- my $pkgname = "@package_name@";
- my $changes = 0;
- # installation should already have put down the files and
- # directories - we just need to update the symlinks
- my $servicefile = "$unitdir/$pkgname\@.service";
- # first, look for new instances
- for my $file (glob("$initconfigdir/$pkgname-*")) {
- my $inst = $file;
- $inst =~ s/^.*$pkgname-//;
- # see if this is the admin or snmp or some other service
- if (-f "$unitdir/$pkgname-$inst.service") {
- debug(1, "$unitdir/$pkgname-$inst.service already exists - skipping\n");
- next;
- } elsif (-f "$confbasedir/$pkgname-$inst.service") {
- debug(1, "$confbasedir/$pkgname-$inst.service already exists - skipping\n");
- next;
- } else {
- my $servicelink = "$confdir/$pkgname\@$inst.service";
- if (! -l $servicelink) {
- if (!symlink($servicefile, $servicelink)) {
- debug(1, "error updating link $servicelink to $servicefile - $!\n");
- push @errs, [ 'error_linking_file', $servicefile, $servicelink, $! ];
- } else {
- debug(2, "updated link $servicelink to $servicefile\n");
- }
- $changes++;
- }
- }
- }
- # next, look for instances that have been removed
- for my $file (glob("$confdir/$pkgname\@*.service")) {
- my $inst = $file;
- $inst =~ s/^.*$pkgname\@(.*?).service$/$1/;
- if (! -f "$initconfigdir/$pkgname-$inst") {
- if (!unlink($file)) {
- debug(1, "error removing $file - $!\n");
- push @errs, [ 'error_removing_path', $file, $! ];
- } else {
- debug(2, "removed systemd file $file for removed instance $inst\n");
- }
- $changes++;
- }
- }
- if ($changes > 0) {
- $? = 0;
- my $cmd = '/bin/systemctl --system daemon-reload';
- # run the reload command
- my $output = `$cmd 2>&1`;
- my $status = $?;
- if ($status) {
- debug(1, "Error: $cmd failed - output $output: $!\n");
- push @errs, [ 'error_running_command', $cmd, $output, $! ];
- } else {
- debug(2, "$cmd succeeded\n");
- }
- } else {
- debug(1, "No changes to $unitdir or $confdir\n");
- }
-
- return @errs;
- }
- sub createDSInstance {
- my $inf = shift;
- my @errs;
- if (@errs = setDefaults($inf)) {
- return @errs;
- }
- if (@errs = sanityCheckParams($inf)) {
- return @errs;
- }
- if (@errs = makeDSDirs($inf)) {
- return @errs;
- }
- if (@errs = createConfigFile($inf)) {
- return @errs;
- }
- if (@errs = makeOtherConfigFiles($inf)) {
- return @errs;
- }
- if (@errs = createInstanceScripts($inf)) {
- return @errs;
- }
- if (@errs = installSchema($inf)) {
- return @errs;
- }
- if (@errs = initDatabase($inf)) {
- return @errs;
- }
- updateSelinuxPolicy($inf);
- if (@errs = updateTmpfilesDotD($inf)) {
- return @errs;
- }
- if (@errs = updateSystemD($inf)) {
- return @errs;
- }
- if (@errs = startServer($inf)) {
- return @errs;
- }
- return @errs;
- }
- sub stopServer {
- my $instancedir = shift;
- my $prog = $instancedir . "/stop-slapd";
- if (-x $prog) {
- $? = 0;
- # run the stop command
- my $output = `$prog 2>&1`;
- my $status = $?;
- debug(3, "stopping server $instancedir returns status $status: output $output\n");
- if ($status) {
- debug(1,"Warning: Could not stop directory server: status $status: output $output\n");
- # if the server is not running, that's ok
- if ($output =~ /not running/) {
- $! = ENOENT;
- return 1;
- }
- # else, some other error (e.g. permission) - return false for error
- return;
- }
- } else {
- debug(1, "stopping server: no such program $prog: cannot stop server\n");
- return;
- }
- debug(1, "Successfully stopped server $instancedir\n");
- return 1;
- }
- # NOTE: Returns a list of array ref - each array ref is suitable for passing
- # to Resource::getText
- sub removeDSInstance {
- my $inst = shift;
- my $force = shift;
- my $all = shift;
- my $initconfig_dir = shift || get_initconfigdir();
- my $baseconfigdir = $ENV{DS_CONFIG_DIR} || "@instconfigdir@";
- my $instname = "slapd-$inst";
- my $configdir;
- my $rundir;
- my $product_name;
- my @errs;
- my $initconfig = "$initconfig_dir/@package_name@-$inst";
- # Get the configdir, rundir and product_name from the instance initconfig script.
- unless(open(INFILE, $initconfig)) {
- return ( [ 'error_no_such_instance', $instname, $! ] );
- }
- my $line;
- while($line = <INFILE>) {
- if ($line =~ /CONFIG_DIR=(.*) ; export CONFIG_DIR/) {
- $configdir = $1;
- } elsif ($line =~ /CONFIG_DIR=(.*)$/) {
- $configdir = $1;
- } elsif ($line =~ /RUN_DIR=(.*) ; export RUN_DIR/) {
- $rundir = $1;
- } elsif ($line =~ /RUN_DIR=(.*)$/) {
- $rundir = $1;
- } elsif ($line =~ /PRODUCT_NAME=(.*) ; export PRODUCT_NAME/) {
- $product_name = $1;
- } elsif ($line =~ /PRODUCT_NAME=(.*)$/) {
- $product_name = $1;
- }
- }
- close(INFILE);
- if ( ! -d $configdir )
- {
- debug(1, "Error: $configdir does not exist: $!\n");
- return ( [ 'error_no_such_instance', $configdir, $! ] );
- }
- # read the config file to find out the paths
- my $dseldif = "$configdir/dse.ldif";
- my $conn = new FileConn($dseldif, 1);
- if (!$conn) {
- debug(1, "Error: Could not open config file $dseldif: Error $!\n");
- return ( [ 'error_opening_dseldif', $dseldif, $! ] );
- }
- my $dn = "cn=config";
- my $entry = $conn->search($dn, "base", "(cn=*)", 0);
- if (!$entry)
- {
- debug(1, "Error: Search $dn in $dseldif failed: $entry\n");
- push @errs, [ 'error_finding_config_entry', $dn, $dseldif, $conn->getErrorString() ];
- }
- $dn = "cn=config,cn=ldbm database,cn=plugins,cn=config";
- my $dbentry = $conn->search($dn, "base", "(cn=*)", 0);
- if (!$dbentry)
- {
- debug(1, "Error: Search $dn in $dseldif failed: $dbentry\n");
- push @errs, [ 'error_finding_config_entry', $dn, $dseldif, $conn->getErrorString() ];
- }
- $conn->close();
- # stop the server
- my $instdir = "";
- if ($entry) {
- foreach my $path ( @{$entry->{"nsslapd-instancedir"}} )
- {
- if (!stopServer($path)) {
- if ($force) {
- debug(1, "Warning: Could not stop directory server - Error: $! - forcing continue\n");
- } elsif ($! == ENOENT) { # stop script not found or server not running
- debug(1, "Warning: Could not stop directory server: already removed or not running\n");
- push @errs, [ 'error_stopping_server', $path, $! ];
- } else { # real error
- debug(1, "Error: Could not stop directory server - aborting - use -f flag to force removal\n");
- push @errs, [ 'error_stopping_server', $path, $! ];
- return @errs;
- }
- }
- $instdir = $path;
- }
- }
- # remove physical dirs/files
- if ($dbentry) {
- push @errs, remove_tree($dbentry, "nsslapd-directory", $instname, 1);
- push @errs, remove_tree($dbentry, "nsslapd-db-logdirectory", $instname, 1);
- }
- if ($entry) {
- push @errs, remove_tree($entry, "nsslapd-lockdir", $instname, 0);
- push @errs, remove_tree($entry, "nsslapd-tmpdir", $instname, 0);
- push @errs, remove_tree($entry, "nsslapd-bakdir", $instname, 1);
- push @errs, remove_tree($entry, "nsslapd-errorlog", $instname, 1);
- }
- # instance dir
- if ( -d $instdir && $instdir =~ /$instname/ )
- {
- # clean up pid files (if any)
- remove_pidfile("STARTPIDFILE", $inst, $instdir, $instname, $rundir, $product_name);
- remove_pidfile("PIDFILE", $inst, $instdir, $instname, $rundir, $product_name);
- my $rc = rmtree($instdir);
- if ( 0 == $rc )
- {
- push @errs, [ 'error_removing_path', $instdir, $! ];
- debug(1, "Warning: $instdir was not removed. Error: $!\n");
- }
- }
- # Finally, config dir
- if ($all) {
- push @errs, remove_tree($entry, "nsslapd-schemadir", $instname, 1);
- } else {
- push @errs, remove_tree($entry, "nsslapd-schemadir", $instname, 1, "\.db\$");
- }
- # Remove the instance specific initconfig script
- if ( -f $initconfig ) {
- my $rc = unlink($initconfig);
- if ( 0 == $rc )
- {
- push @errs, [ 'error_removing_path', $initconfig, $! ];
- debug(1, "Warning: $initconfig was not removed. Error: $!\n");
- }
- }
- my $tmpfilesdir = "@with_tmpfiles_d@";
- my $tmpfilesname = "$tmpfilesdir/@package_name@-$inst.conf";
- if ($tmpfilesdir && -d $tmpfilesdir && -f $tmpfilesname) {
- my $rc = unlink($tmpfilesname);
- if ( 0 == $rc )
- {
- push @errs, [ 'error_removing_path', $tmpfilesname, $! ];
- debug(1, "Warning: $tmpfilesname was not removed. Error: $!\n");
- }
- }
- # remove the selinux label from the ports if needed
- if ("@with_selinux@") {
- foreach my $port (@{$entry->{"nsslapd-port"}})
- {
- my $semanage_err;
- my $rc;
- my $retry = 60;
- $ENV{LANG} = "C";
- while (($retry > 0) && ($semanage_err = `semanage port -d -t ldap_port_t -p tcp $port 2>&1`) && ($rc = $?)) {
- if (($semanage_err =~ /defined in policy, cannot be deleted/) || ($semanage_err =~ /is not defined/)) {
- $retry = -1;
- } else {
- debug(1, "Warning: Port $port not removed from selinux policy correctly. Error: $semanage_err\n");
- debug(1, "Retrying in 5 seconds\n");
- sleep(5);
- $retry--;
- }
- }
- if (0 == $retry) {
- push @errs, [ 'error_removing_port_label', $port, $semanage_err];
- debug(1, "Warning: Port $port not removed from selinux policy correctly. Error: $semanage_err\n");
- debug(1, "Reached time limit.\n");
- }
- }
- foreach my $secureport (@{$entry->{"nsslapd-secureport"}})
- {
- my $semanage_err;
- my $rc;
- my $retry = 60;
- $ENV{LANG} = "C";
- while (($retry > 0) && ($semanage_err = `semanage port -d -t ldap_port_t -p tcp $secureport 2>&1`) && ($rc = $?)) {
- if (($semanage_err =~ /defined in policy, cannot be deleted/) || ($semanage_err =~ /is not defined/)) {
- $retry = -1;
- } else {
- debug(1, "Warning: Port $secureport not removed from selinux policy correctly. Error: $semanage_err\n");
- debug(1, "Retrying in 5 seconds\n");
- sleep(5);
- $retry--;
- }
- }
- if (0 == $retry) {
- push @errs, [ 'error_removing_port_label', $secureport, $semanage_err];
- debug(1, "Warning: Port $secureport not removed from selinux policy correctly. Error: $semanage_err\n");
- debug(1, "Reached time limit.\n");
- }
- }
- }
- # update systemd files
- push @errs, updateSystemD();
- # if we got here, report success
- if (@errs) {
- debug(1, "Could not successfully remove $instname\n");
- } else {
- debug(1, "Instance $instname removed.\n");
- }
- return @errs;
- }
- 1;
- # emacs settings
- # Local Variables:
- # mode:perl
- # indent-tabs-mode: nil
- # tab-width: 4
- # End:
|