cloud-mu 3.6.10 → 3.6.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/Berksfile +2 -3
  3. data/Berksfile.lock +11 -14
  4. data/bin/mu-aws-setup +16 -4
  5. data/bin/mu-configure +2 -1
  6. data/cloud-mu.gemspec +3 -3
  7. data/cookbooks/mu-firewall/Berksfile +1 -1
  8. data/cookbooks/mu-firewall/attributes/default.rb +2 -2
  9. data/cookbooks/mu-firewall/metadata.rb +3 -3
  10. data/cookbooks/mu-firewall/recipes/default.rb +11 -2
  11. data/cookbooks/mu-master/Berksfile +1 -1
  12. data/cookbooks/mu-master/attributes/default.rb +14 -1
  13. data/cookbooks/mu-master/files/default/389ds-perl/ASDialogs.pm +173 -0
  14. data/cookbooks/mu-master/files/default/389ds-perl/AdminMigration.pm +569 -0
  15. data/cookbooks/mu-master/files/default/389ds-perl/AdminServer.pm +952 -0
  16. data/cookbooks/mu-master/files/default/389ds-perl/AdminUtil.pm +983 -0
  17. data/cookbooks/mu-master/files/default/389ds-perl/ConfigDSDialogs.pm +449 -0
  18. data/cookbooks/mu-master/files/default/389ds-perl/DSCreate.pm +1551 -0
  19. data/cookbooks/mu-master/files/default/389ds-perl/DSDialogs.pm +233 -0
  20. data/cookbooks/mu-master/files/default/389ds-perl/DSMigration.pm +1175 -0
  21. data/cookbooks/mu-master/files/default/389ds-perl/DSUpdate.pm +534 -0
  22. data/cookbooks/mu-master/files/default/389ds-perl/DSUpdateDialogs.pm +152 -0
  23. data/cookbooks/mu-master/files/default/389ds-perl/DSUtil.pm +1710 -0
  24. data/cookbooks/mu-master/files/default/389ds-perl/Dialog.pm +249 -0
  25. data/cookbooks/mu-master/files/default/389ds-perl/DialogManager.pm +212 -0
  26. data/cookbooks/mu-master/files/default/389ds-perl/FileConn.pm +461 -0
  27. data/cookbooks/mu-master/files/default/389ds-perl/Inf.pm +268 -0
  28. data/cookbooks/mu-master/files/default/389ds-perl/Migration.pm +327 -0
  29. data/cookbooks/mu-master/files/default/389ds-perl/RegDSDialogs.pm +94 -0
  30. data/cookbooks/mu-master/files/default/389ds-perl/Resource.pm +137 -0
  31. data/cookbooks/mu-master/files/default/389ds-perl/Setup.pm +240 -0
  32. data/cookbooks/mu-master/files/default/389ds-perl/SetupDialogs.pm +243 -0
  33. data/cookbooks/mu-master/files/default/389ds-perl/SetupLog.pm +82 -0
  34. data/cookbooks/mu-master/files/default/setCertName.ldif +4 -0
  35. data/cookbooks/mu-master/libraries/mu.rb +2 -2
  36. data/cookbooks/mu-master/metadata.rb +1 -1
  37. data/cookbooks/mu-master/recipes/389ds.rb +71 -32
  38. data/cookbooks/mu-master/recipes/basepackages.rb +5 -0
  39. data/cookbooks/mu-master/recipes/default.rb +16 -5
  40. data/cookbooks/mu-master/recipes/init.rb +36 -3
  41. data/cookbooks/mu-master/recipes/ssl-certs.rb +6 -0
  42. data/cookbooks/mu-master/recipes/sssd.rb +85 -62
  43. data/cookbooks/mu-master/recipes/update_nagios_only.rb +7 -1
  44. data/cookbooks/mu-master/templates/default/389-directory-setup.inf.erb +11 -26
  45. data/cookbooks/mu-master/templates/default/sssd.conf.erb +18 -8
  46. data/cookbooks/mu-tools/files/default/Mu_CA.pem +33 -0
  47. data/cookbooks/mu-tools/metadata.rb +0 -1
  48. data/cookbooks/mu-tools/recipes/set_local_fw.rb +7 -1
  49. data/cookbooks/mu-tools/templates/amazon/sshd_config.erb +5 -1
  50. data/cookbooks/nagios/CHANGELOG.md +679 -0
  51. data/cookbooks/nagios/LICENSE +201 -0
  52. data/cookbooks/nagios/README.md +340 -0
  53. data/cookbooks/nagios/attributes/config.rb +163 -0
  54. data/cookbooks/nagios/attributes/default.rb +204 -0
  55. data/cookbooks/nagios/libraries/base.rb +311 -0
  56. data/cookbooks/nagios/libraries/command.rb +68 -0
  57. data/cookbooks/nagios/libraries/contact.rb +229 -0
  58. data/cookbooks/nagios/libraries/contactgroup.rb +111 -0
  59. data/cookbooks/{firewall/recipes/disable_firewall.rb → nagios/libraries/custom_option.rb} +20 -7
  60. data/cookbooks/nagios/libraries/data_bag_helper.rb +23 -0
  61. data/cookbooks/nagios/libraries/default.rb +90 -0
  62. data/cookbooks/nagios/libraries/helpers.rb +229 -0
  63. data/cookbooks/nagios/libraries/host.rb +410 -0
  64. data/cookbooks/nagios/libraries/hostdependency.rb +178 -0
  65. data/cookbooks/nagios/libraries/hostescalation.rb +170 -0
  66. data/cookbooks/nagios/libraries/hostgroup.rb +117 -0
  67. data/cookbooks/nagios/libraries/nagios.rb +277 -0
  68. data/cookbooks/nagios/libraries/resource.rb +59 -0
  69. data/cookbooks/nagios/libraries/service.rb +449 -0
  70. data/cookbooks/nagios/libraries/servicedependency.rb +213 -0
  71. data/cookbooks/nagios/libraries/serviceescalation.rb +193 -0
  72. data/cookbooks/nagios/libraries/servicegroup.rb +142 -0
  73. data/cookbooks/nagios/libraries/timeperiod.rb +159 -0
  74. data/cookbooks/nagios/libraries/users_helper.rb +54 -0
  75. data/cookbooks/nagios/metadata.json +44 -0
  76. data/cookbooks/nagios/metadata.rb +22 -0
  77. data/cookbooks/nagios/recipes/_load_databag_config.rb +153 -0
  78. data/cookbooks/nagios/recipes/_load_default_config.rb +241 -0
  79. data/cookbooks/nagios/recipes/apache.rb +114 -0
  80. data/cookbooks/nagios/recipes/default.rb +41 -0
  81. data/cookbooks/nagios/recipes/nginx.rb +114 -0
  82. data/cookbooks/nagios/recipes/pagerduty.rb +95 -0
  83. data/cookbooks/nagios/recipes/server.rb +182 -0
  84. data/cookbooks/nagios/recipes/server_package.rb +85 -0
  85. data/cookbooks/nagios/recipes/server_source.rb +137 -0
  86. data/cookbooks/nagios/resources/command.rb +34 -0
  87. data/cookbooks/nagios/resources/conf.rb +52 -0
  88. data/cookbooks/nagios/resources/contact.rb +34 -0
  89. data/cookbooks/nagios/resources/contactgroup.rb +35 -0
  90. data/cookbooks/nagios/resources/host.rb +35 -0
  91. data/cookbooks/nagios/resources/hostdependency.rb +35 -0
  92. data/cookbooks/nagios/resources/hostescalation.rb +36 -0
  93. data/cookbooks/nagios/resources/hostgroup.rb +35 -0
  94. data/cookbooks/nagios/resources/resource.rb +34 -0
  95. data/cookbooks/nagios/resources/service.rb +35 -0
  96. data/cookbooks/nagios/resources/servicedependency.rb +35 -0
  97. data/cookbooks/nagios/resources/serviceescalation.rb +35 -0
  98. data/cookbooks/nagios/resources/servicegroup.rb +35 -0
  99. data/cookbooks/nagios/resources/timeperiod.rb +35 -0
  100. data/cookbooks/nagios/templates/apache2.conf.erb +102 -0
  101. data/cookbooks/nagios/templates/cgi.cfg.erb +266 -0
  102. data/cookbooks/nagios/templates/commands.cfg.erb +13 -0
  103. data/cookbooks/nagios/templates/contacts.cfg.erb +37 -0
  104. data/cookbooks/nagios/templates/hostgroups.cfg.erb +25 -0
  105. data/cookbooks/nagios/templates/hosts.cfg.erb +15 -0
  106. data/cookbooks/nagios/templates/htpasswd.users.erb +6 -0
  107. data/cookbooks/nagios/templates/nagios.cfg.erb +22 -0
  108. data/cookbooks/nagios/templates/nginx.conf.erb +80 -0
  109. data/cookbooks/nagios/templates/pagerduty.cgi.erb +185 -0
  110. data/cookbooks/nagios/templates/resource.cfg.erb +27 -0
  111. data/cookbooks/nagios/templates/servicedependencies.cfg.erb +15 -0
  112. data/cookbooks/nagios/templates/servicegroups.cfg.erb +14 -0
  113. data/cookbooks/nagios/templates/services.cfg.erb +14 -0
  114. data/cookbooks/nagios/templates/spawn-fcgi.erb +10 -0
  115. data/cookbooks/nagios/templates/templates.cfg.erb +31 -0
  116. data/cookbooks/nagios/templates/timeperiods.cfg.erb +13 -0
  117. data/extras/platform_berksfile_base +3 -3
  118. data/extras/python_rpm/build.sh +4 -4
  119. data/extras/python_rpm/muthon.spec +2 -4
  120. data/extras/vault_tools/export_vaults.sh +11 -1
  121. data/install/installer +1 -1
  122. data/modules/mu/kittens.rb +27523 -0
  123. data/modules/mu/master/ldap.rb +48 -31
  124. data/modules/mu/master.rb +69 -0
  125. data/modules/mu/mu.yaml.rb +351 -0
  126. data/modules/mu/providers/aws/firewall_rule.rb +3 -1
  127. data/modules/mu/providers/aws.rb +11 -5
  128. data/modules/mu.rb +5 -4
  129. metadata +99 -68
  130. data/cookbooks/firewall/CHANGELOG.md +0 -488
  131. data/cookbooks/firewall/LICENSE +0 -202
  132. data/cookbooks/firewall/README.md +0 -366
  133. data/cookbooks/firewall/TODO.md +0 -6
  134. data/cookbooks/firewall/attributes/default.rb +0 -5
  135. data/cookbooks/firewall/attributes/firewalld.rb +0 -8
  136. data/cookbooks/firewall/attributes/iptables.rb +0 -17
  137. data/cookbooks/firewall/attributes/ufw.rb +0 -12
  138. data/cookbooks/firewall/attributes/windows.rb +0 -8
  139. data/cookbooks/firewall/libraries/helpers.rb +0 -105
  140. data/cookbooks/firewall/libraries/helpers_firewalld.rb +0 -116
  141. data/cookbooks/firewall/libraries/helpers_firewalld_dbus.rb +0 -72
  142. data/cookbooks/firewall/libraries/helpers_iptables.rb +0 -112
  143. data/cookbooks/firewall/libraries/helpers_nftables.rb +0 -170
  144. data/cookbooks/firewall/libraries/helpers_ufw.rb +0 -142
  145. data/cookbooks/firewall/libraries/helpers_windows.rb +0 -129
  146. data/cookbooks/firewall/libraries/provider_firewall_firewalld.rb +0 -179
  147. data/cookbooks/firewall/libraries/provider_firewall_iptables.rb +0 -171
  148. data/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu.rb +0 -200
  149. data/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu1404.rb +0 -200
  150. data/cookbooks/firewall/libraries/provider_firewall_rule.rb +0 -34
  151. data/cookbooks/firewall/libraries/provider_firewall_ufw.rb +0 -138
  152. data/cookbooks/firewall/libraries/provider_firewall_windows.rb +0 -126
  153. data/cookbooks/firewall/libraries/resource_firewall.rb +0 -26
  154. data/cookbooks/firewall/libraries/resource_firewall_rule.rb +0 -52
  155. data/cookbooks/firewall/metadata.json +0 -40
  156. data/cookbooks/firewall/metadata.rb +0 -15
  157. data/cookbooks/firewall/recipes/default.rb +0 -76
  158. data/cookbooks/firewall/recipes/firewalld.rb +0 -87
  159. data/cookbooks/firewall/resources/firewalld.rb +0 -28
  160. data/cookbooks/firewall/resources/firewalld_config.rb +0 -39
  161. data/cookbooks/firewall/resources/firewalld_helpers.rb +0 -106
  162. data/cookbooks/firewall/resources/firewalld_icmptype.rb +0 -88
  163. data/cookbooks/firewall/resources/firewalld_ipset.rb +0 -104
  164. data/cookbooks/firewall/resources/firewalld_policy.rb +0 -115
  165. data/cookbooks/firewall/resources/firewalld_service.rb +0 -98
  166. data/cookbooks/firewall/resources/firewalld_zone.rb +0 -118
  167. data/cookbooks/firewall/resources/nftables.rb +0 -71
  168. data/cookbooks/firewall/resources/nftables_rule.rb +0 -113
  169. data/cookbooks/firewall/templates/default/ufw/default.erb +0 -13
  170. /data/cookbooks/{firewall → nagios}/chefignore +0 -0
  171. /data/cookbooks/{firewall → nagios}/renovate.json +0 -0
@@ -0,0 +1,1710 @@
1
+ # BEGIN COPYRIGHT BLOCK
2
+ # Copyright (C) 2007 Red Hat, Inc.
3
+ # All rights reserved.
4
+ #
5
+ # License: GPL (version 3 or any later version).
6
+ # See LICENSE for details.
7
+ # END COPYRIGHT BLOCK
8
+ #
9
+
10
+ package DSUtil;
11
+
12
+ use Mozilla::LDAP::Conn;
13
+ use Mozilla::LDAP::Utils qw(normalizeDN);
14
+ use Mozilla::LDAP::API qw(:constant ldap_explode_dn ldap_err2string) ; # Direct access to C API
15
+ use Mozilla::LDAP::LDIF;
16
+ use File::Spec::Functions qw(rel2abs);
17
+ use File::Spec;
18
+ use File::Basename;
19
+
20
+ require Exporter;
21
+ @ISA = qw(Exporter);
22
+ @EXPORT = qw(portAvailable getAvailablePort isValidDN addSuffix getMappedEntries
23
+ process_maptbl check_and_add_entry getMappedEntries addErr
24
+ getHashedPassword debug createInfFromConfig shellEscape
25
+ isValidServerID isValidUser isValidGroup makePaths getLogin getGroup
26
+ remove_tree remove_pidfile setDebugLog checkHostname serverIsRunning);
27
+ @EXPORT_OK = qw(portAvailable getAvailablePort isValidDN addSuffix getMappedEntries
28
+ process_maptbl check_and_add_entry getMappedEntries addErr
29
+ getHashedPassword debug createInfFromConfig shellEscape
30
+ isValidServerID isValidUser isValidGroup makePaths getLogin getGroup
31
+ remove_tree remove_pidfile setDebugLog checkHostname serverIsRunning);
32
+
33
+ use strict;
34
+
35
+ my $sockVersion;
36
+ BEGIN {
37
+ use Socket;
38
+ $sockVersion = Socket->VERSION;
39
+ if ($sockVersion >= 2.000) {
40
+ import Socket qw ( :addrinfo inet_ntoa
41
+ unpack_sockaddr_in unpack_sockaddr_in6
42
+ AF_INET INADDR_ANY
43
+ PF_INET SO_REUSEADDR SOCK_STREAM SOL_SOCKET );
44
+ } elsif (eval {require Socket6; 1}) {
45
+ import Socket6 qw (getaddrinfo getnameinfo unpack_sockaddr_in6);
46
+ }
47
+ }
48
+ $sockVersion = Socket->VERSION;
49
+ use NetAddr::IP::Util qw( ipv6_n2x );
50
+
51
+ use File::Temp qw(tempfile tempdir);
52
+ use File::Basename qw(dirname);
53
+ use File::Path qw(rmtree);
54
+
55
+ use Carp;
56
+
57
+ $DSUtil::debuglevel = 0;
58
+ $DSUtil::log = 0;
59
+
60
+ # use like this:
61
+ # debug(3, "message");
62
+ # this will only print "message" if $debuglevel is 3 or higher (-ddd on the command line)
63
+ sub debug {
64
+ my ($level, @rest) = @_;
65
+ if ($level <= $DSUtil::debuglevel) {
66
+ print STDERR "+" x $level, @rest;
67
+ if ($DSUtil::log) {
68
+ $DSUtil::log->logDebug(@rest);
69
+ }
70
+ }
71
+ }
72
+
73
+ sub setDebugLog {
74
+ $DSUtil::log = shift;
75
+ }
76
+
77
+ # return true if the given port number is available, false otherwise
78
+ sub portAvailable {
79
+ my $port = shift;
80
+ my $proto = getprotobyname('tcp');
81
+ my $rc = socket(SOCK, PF_INET, SOCK_STREAM, $proto);
82
+ if ($rc == 1) {
83
+ setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, 1);
84
+ $rc = bind(SOCK, sockaddr_in($port, INADDR_ANY));
85
+ }
86
+ close(SOCK);
87
+ return $rc and ($rc == 1);
88
+ }
89
+
90
+ # returns a randomly assigned port number, or -1
91
+ # if not able to find an available port
92
+ sub getAvailablePort {
93
+ my $MINPORT = 1024;
94
+ my $MAXPORT = 65535;
95
+
96
+ srand( time() ^ ($$ + ($$ << 15)) );
97
+ while (1) {
98
+ my $port = $MINPORT + int(rand($MAXPORT-$MINPORT));
99
+
100
+ if (portAvailable($port)) {
101
+ return $port;
102
+ }
103
+ }
104
+ }
105
+
106
+ sub isValidDN {
107
+ my $dn = shift;
108
+ return ($dn =~ /^[0-9a-zA-Z_-]+=.*$/);
109
+ }
110
+
111
+ sub isValidServerID {
112
+ my $servid = shift;
113
+ my $validchars = '#%:\w@_-';
114
+ if($servid eq "admin"){
115
+ # "admin" is reserved for the admin server
116
+ return 0;
117
+ } else {
118
+ return $servid =~ /^[$validchars]+$/o;
119
+ }
120
+ }
121
+
122
+ # we want the name of the effective user id of this process e.g. if someone did
123
+ # an su root, we want getLogin to return "root" not the originating id (getlogin)
124
+ # in perl, $> is the effective numeric user id - we need to turn it into a string
125
+ # use confess here because if we cannot determine the user, something is really,
126
+ # really wrong and we need to abort immediately
127
+ sub getLogin {
128
+ return (getpwuid($>))[0] || $ENV{USER} || confess "Error: could not determine the current user ID: $!";
129
+ }
130
+
131
+ # Look up the primary group name for the supplied user
132
+ sub getGroup {
133
+ my $user = shift;
134
+ my @userinfo = getpwnam($user);
135
+
136
+ if(!@userinfo){
137
+ confess "Error: could not find user ID ($user): $!";
138
+ }
139
+
140
+ return (getgrgid($userinfo[3]))[0] || confess "Error: could not determine the current group name from gid ($userinfo[3]): $!";
141
+ }
142
+
143
+ sub isValidUser {
144
+ my $user = shift;
145
+ # convert numeric uid to string
146
+ my $strans = $user;
147
+ if ($user =~ /^\d+$/) { # numeric - convert to string
148
+ $strans = getpwuid $user;
149
+ if (!$strans) {
150
+ return ("dialog_ssuser_error", $user);
151
+ }
152
+ }
153
+ if ($> != 0) { # if not root, the user must be our uid
154
+ my $username = getLogin;
155
+ if ($strans ne $username) {
156
+ return ("dialog_ssuser_must_be_same", $username);
157
+ }
158
+ } else { # user is root - verify id
159
+ my $nuid = getpwnam $strans;
160
+ if (!defined($nuid)) {
161
+ return ("dialog_ssuser_error", $user);
162
+ }
163
+ if (!$nuid) {
164
+ debug(0, "Warning: using root as the server user id. You are strongly encouraged to use a non-root user.\n");
165
+ }
166
+ }
167
+
168
+ return ();
169
+ }
170
+
171
+ sub isValidGroup {
172
+ my $group = shift;
173
+ my $ngid;
174
+ # convert numeric gid to string
175
+ my $strans = $group;
176
+ if ($group =~ /^\d+$/) { # numeric - convert to string
177
+ $strans = (getgrgid($group))[0];
178
+ if (!$strans) {
179
+ return ("dialog_ssgroup_error", $group);
180
+ }
181
+ }
182
+ # ensure the specified group is a defined group
183
+ $ngid = getgrnam $strans;
184
+ if (!defined($ngid)) {
185
+ return ("dialog_ssgroup_error", $group);
186
+ }
187
+
188
+ return ();
189
+ }
190
+
191
+ # arguments
192
+ # - hostname - the hostname to look for
193
+ # - res - the Resource object to use to construct messages
194
+ # returns - the error message string, or "" upon success if $res exists
195
+ # - the error message array, or () upon success otherwise
196
+ sub checkHostname {
197
+ my $hn = shift;
198
+ my $res = shift;
199
+
200
+ # see if hostname is an fqdn
201
+ if ($hn !~ /\./) {
202
+ if ($res) {
203
+ return $res->getText('warning_hostname_not_fully_qualified', $hn);
204
+ } else {
205
+ return ('warning_hostname_not_fully_qualified', $hn);
206
+ }
207
+ }
208
+
209
+ # see if we can resolve the hostname (IPv6 supported)
210
+ my $found = 0;
211
+ my @hostip = ();
212
+ if ($sockVersion >= 2.000) {
213
+ debug(1, "Socket version $sockVersion\n");
214
+ my %hints = (socktype => SOCK_STREAM);
215
+ my ($err, @aires) = getaddrinfo($hn, "ldap", \%hints);
216
+ if ($err) {
217
+ if ($res) {
218
+ return $res->getText('warning_no_such_hostname', $hn);
219
+ } else {
220
+ return ('warning_no_such_hostname', $hn);
221
+ }
222
+ }
223
+ while (my $ai = shift @aires) {
224
+ debug(1, "found for hostname $hn\n");
225
+ my $ip;
226
+ if ($ai->{family} == AF_INET) {
227
+ my ( $port, $ipaddr ) = unpack_sockaddr_in( $ai->{addr} );
228
+ $ip = inet_ntoa($ipaddr);
229
+ } else {
230
+ my ( $port, $ipaddr ) = unpack_sockaddr_in6( $ai->{addr} );
231
+ $ip = ipv6_n2x($ipaddr);
232
+ }
233
+ debug(1, "ipaddr=", $ip, "\n");
234
+ # see if reverse resolution works
235
+ my ($err, $hn2, $service) = getnameinfo($ai->{addr});
236
+ if (!$err) {
237
+ push @hostip, [$hn2, $ip];
238
+ if (lc($hn) eq lc($hn2)) {
239
+ $found = 1;
240
+ last;
241
+ }
242
+ }
243
+ }
244
+ if (!$found) {
245
+ system("/usr/bin/host -t CNAME $hn 2>&1 1> /dev/null");
246
+ if ($? == 0){
247
+ $found = 1;
248
+ }
249
+ }
250
+ } elsif (eval {require Socket6; 1}) {
251
+ debug(1, "Socket6\n");
252
+ my @aires = getaddrinfo($hn, "ldap", AF_UNSPEC, SOCK_STREAM);
253
+ if (scalar(@aires) < 5) {
254
+ if ($res) {
255
+ return $res->getText('warning_no_such_hostname', $hn);
256
+ } else {
257
+ return ('warning_no_such_hostname', $hn);
258
+ }
259
+ }
260
+ my $ailen = scalar(@aires);
261
+ while ($ailen >= 5) {
262
+ debug(1, "found for hostname $hn\n");
263
+ my $family = shift @aires;
264
+ my $socktype = shift @aires;
265
+ my $proto = shift @aires;
266
+ my $saddr = shift @aires;
267
+ my $canonname = shift @aires;
268
+ $ailen = scalar(@aires);
269
+ my $ip;
270
+ if ($family == AF_INET) {
271
+ my ($port, $ipaddr) = unpack_sockaddr_in($saddr);
272
+ $ip = inet_ntoa($ipaddr);
273
+ } else {
274
+ my ($port, $ipaddr) = unpack_sockaddr_in6($saddr);
275
+ $ip = ipv6_n2x($ipaddr);
276
+ }
277
+ debug(1, "ipaddr=", $ip, "\n");
278
+ # see if reverse resolution works
279
+ my ($hn2, $service) = getnameinfo($saddr);
280
+ if ($hn2) {
281
+ push @hostip, [$hn2, $ip];
282
+ if (lc($hn) eq lc($hn2)) {
283
+ $found = 1;
284
+ }
285
+ }
286
+ }
287
+ } else {
288
+ debug(1, "gethostbyname ...\n");
289
+ # see if we can resolve the hostname
290
+ my ($name, $aliases, $addrtype, $length, @addrs) = gethostbyname($hn);
291
+ if (!$name) {
292
+ if ($res) {
293
+ return $res->getText('warning_no_such_hostname', $hn);
294
+ } else {
295
+ return ('warning_no_such_hostname', $hn);
296
+ }
297
+ }
298
+ debug(1, "found for hostname $hn: name=$name\n");
299
+ debug(1, "aliases=$aliases\n");
300
+ debug(1, "addrtype=$addrtype\n");
301
+ # see if reverse resolution works
302
+ foreach my $ii (@addrs) {
303
+ my $hn2 = gethostbyaddr($ii, $addrtype);
304
+ my $ip = join('.', unpack('C4', $ii));
305
+ debug(1, "\thost=$hn2 ip=$ip\n");
306
+ push @hostip, [$hn2, $ip];
307
+ if (lc($hn) eq lc($hn2)) {
308
+ $found = 1;
309
+ last;
310
+ }
311
+ }
312
+ }
313
+
314
+ if (!$found) {
315
+ if ($res) {
316
+ my $retstr = "";
317
+ $retstr = $res->getText('warning_reverse_resolve', $hn, $hn);
318
+ for my $ii (@hostip) {
319
+ $retstr .= $res->getText('warning_reverse_resolve_sub', $ii->[1], $ii->[0]);
320
+ }
321
+ return $retstr;
322
+ } else {
323
+ my @reterrs = ();
324
+ push @reterrs, [ 'warning_reverse_resolve', $hn, $hn ];
325
+ for my $ii (@hostip) {
326
+ push @reterrs, [ 'warning_reverse_resolve_sub', $ii->[1], $ii->[0] ];
327
+ }
328
+ return @reterrs;
329
+ }
330
+ }
331
+
332
+ debug(1, "hostname $hn resolves correctly\n");
333
+ if ($res) {
334
+ return '';
335
+ } else {
336
+ return ();
337
+ }
338
+ }
339
+
340
+ # delete the subtree starting from the passed entry
341
+ sub delete_all
342
+ {
343
+ my ($conn, $bentry) = @_;
344
+ my $sentry = $conn->search($bentry->{dn},
345
+ "subtree", "(objectclass=*)", 0, ("dn"));
346
+ my @mystack = ();
347
+ while ($sentry) {
348
+ push @mystack, $sentry->getDN();
349
+ $sentry = $conn->nextEntry();
350
+ }
351
+ # reverse order
352
+ my $dn = pop @mystack;
353
+ while ($dn) {
354
+ $conn->delete($dn);
355
+ my $rc = $conn->getErrorCode();
356
+ if ( $rc != 0 ) {
357
+ debug(1, "ERROR: unable to delete entry $dn, error code: $rc:" . $conn->getErrorString() . "\n");
358
+ return 1;
359
+ }
360
+ $dn = pop @mystack;
361
+ }
362
+ return 0;
363
+ }
364
+
365
+ # if the entry does not exist on the server, add the entry.
366
+ # otherwise, do nothing
367
+ # you can use this as the callback to getMappedEntries, so
368
+ # that for each entry in the ldif file being processed, you
369
+ # can call this subroutine to add or update the entry
370
+ # use like this:
371
+ # getMappedEntries($mapper, \@ldiffiles, \&check_and_add_entry,
372
+ # [$conn, $fresh, $verbose]);
373
+ # where $conn is a perldap Conn
374
+ # $fresh if true will update the entry if it exists
375
+ # $verbose prints out more info
376
+ sub check_and_add_entry
377
+ {
378
+ my ($context, $aentry, $errs) = @_;
379
+ my $conn = $context->[0];
380
+ my $fresh = $context->[1];
381
+ my $verbose = $context->[2];
382
+ my @ctypes = $aentry->getValues("changetype");
383
+ my $sentry = $conn->search($aentry->{dn}, "base", "(objectclass=*)", 0, ("*", "aci"));
384
+ if ($sentry) {
385
+ debug(3, "check_and_add_entry: Found entry " . $sentry->getDN() . "\n");
386
+ if ( (! @ctypes) or ("add" eq lc($ctypes[0])) ) { # entry exists, and this is not a modify op
387
+ # or add is explicitely specified
388
+ debug(3, "check_and_add_entry: skipping entry " . $sentry->getDN() . "\n");
389
+ return 1; # ignore - return success
390
+ }
391
+ } else {
392
+ debug(3, "check_and_add_entry: Entry not found " . $aentry->{dn} .
393
+ " error " . $conn->getErrorString() . "\n");
394
+ if (@ctypes and !("add" eq lc($ctypes[0]))) { # uh oh - attempt to del/mod an entry that doesn't exist
395
+ debug(3, "check_and_add_entry: attepting to @ctypes the entry " . $aentry->{dn} .
396
+ " that does not exist\n");
397
+ return 1; # ignore - return success
398
+ }
399
+ }
400
+ do
401
+ {
402
+ my @addtypes; # list of attr types for mod add
403
+ my @reptypes; # list of attr types for mod replace
404
+ my @deltypes; # list of attr types for mod delete
405
+ my $OP_NONE = 0;
406
+ my $OP_ADD = 1;
407
+ my $OP_MOD = 2;
408
+ my $OP_DEL = 3;
409
+ # $op stores either of the above $OP_ values
410
+ my $op = $OP_NONE;
411
+ if ( (0 > $#ctypes) or ("add" eq lc($ctypes[0])) ) # aentry: complete entry
412
+ {
413
+ $op = $OP_ADD; # just add the entry
414
+ }
415
+ else # aentry: modify format
416
+ {
417
+ if ( $sentry )
418
+ {
419
+ if ( "delete" eq lc($ctypes[0]) )
420
+ {
421
+ $op = $OP_DEL;
422
+ }
423
+ else
424
+ {
425
+ @addtypes = $aentry->getValues("add");
426
+ @reptypes = $aentry->getValues("replace");
427
+ @deltypes = $aentry->getValues("delete");
428
+ $op = $OP_MOD;
429
+ }
430
+ }
431
+ else
432
+ {
433
+ $op = $OP_NONE;
434
+ }
435
+ }
436
+
437
+ if ( $OP_ADD == $op )
438
+ {
439
+ if ("add" eq lc($ctypes[0])) {
440
+ # remove the changetype: add from the entry
441
+ $aentry->remove('changetype');
442
+ }
443
+ $conn->add($aentry);
444
+ my $rc = $conn->getErrorCode();
445
+ if ( $rc != 0 )
446
+ {
447
+ my $string = $conn->getErrorString();
448
+ push @{$errs}, 'error_adding_entry', $aentry->{dn}, $string;
449
+ debug(1, "ERROR: adding an entry $aentry->{dn} failed, error: $string\n");
450
+ $aentry->printLDIF();
451
+ $conn->close();
452
+ return 0;
453
+ }
454
+ debug(1, "Entry $aentry->{dn} is added\n");
455
+ }
456
+ elsif ( $OP_DEL == $op )
457
+ {
458
+ my $rc = delete_all($conn, $sentry);
459
+ if ( 0 != $rc )
460
+ {
461
+ push @{$errs}, 'error_deleteall_entries', $sentry->{dn}, $conn->getErrorString();
462
+ debug(1, "Error deleting $sentry->{dn}\n");
463
+ return 0;
464
+ }
465
+ debug(1, "Entry $aentry->{dn} is deleted\n");
466
+ $sentry = undef;
467
+ }
468
+ elsif ( 0 < $op ) # modify op
469
+ {
470
+ my $attr;
471
+ my @errsToIgnore;
472
+ if (@addtypes) {
473
+ push @errsToIgnore, LDAP_TYPE_OR_VALUE_EXISTS;
474
+ }
475
+ foreach $attr ( @addtypes )
476
+ {
477
+ foreach my $val ($aentry->getValues($attr))
478
+ {
479
+ debug(3, "Adding attr=$attr value=$val to entry $aentry->{dn}\n");
480
+ $sentry->addValue( $attr, $val );
481
+ }
482
+ }
483
+ foreach $attr ( @reptypes )
484
+ {
485
+ my @vals = $aentry->getValues($attr);
486
+ debug(3, "Replacing attr=$attr values=" . $aentry->getValues($attr) . " to entry $aentry->{dn}\n");
487
+ $sentry->setValues($attr, @vals);
488
+ }
489
+ if (@deltypes) {
490
+ push @errsToIgnore, LDAP_NO_SUCH_ATTRIBUTE;
491
+ }
492
+ foreach $attr ( @deltypes )
493
+ {
494
+ # removeValue takes a single value only
495
+ if (!$aentry->size($attr))
496
+ {
497
+ debug(3, "Deleting attr=$attr from entry $aentry->{dn}\n");
498
+ $sentry->remove($attr); # just delete the attribute
499
+ }
500
+ else
501
+ {
502
+ debug(3, "Deleting attr=$attr values=" . $aentry->getValues($attr) . " from entry $aentry->{dn}\n");
503
+ foreach my $val ($aentry->getValues($attr))
504
+ {
505
+ $sentry->removeValue($attr, $val);
506
+ }
507
+ }
508
+ }
509
+ $conn->update($sentry);
510
+ my $rc = $conn->getErrorCode();
511
+ if ( $rc != 0 )
512
+ {
513
+ my $string = $conn->getErrorString();
514
+ debug(1, "ERROR: updating an entry $sentry->{dn} failed, error: $string\n");
515
+ if (grep /^$rc$/, @errsToIgnore) {
516
+ debug(1, "Ignoring error $rc returned by adding @addtypes deleting @deltypes\n");
517
+ } else {
518
+ push @{$errs}, 'error_updating_entry', $sentry->{dn}, $string;
519
+ $aentry->printLDIF();
520
+ $conn->close();
521
+ return 0;
522
+ }
523
+ }
524
+ }
525
+ if ( $sentry )
526
+ {
527
+ $sentry = $conn->nextEntry(); # supposed to have no more entries
528
+ }
529
+ } until ( !$sentry );
530
+ out:
531
+ return 1;
532
+ }
533
+
534
+ # the default callback used with getMappedEntries
535
+ # just adds the given entry to the given list
536
+ sub cbaddent {
537
+ my $list = shift;
538
+ my $ent = shift;
539
+ push @{$list}, $ent;
540
+ return 1;
541
+ }
542
+
543
+ # given a mapper and a list of LDIF files, produce a list of
544
+ # perldap Entry objects which have had their tokens subst-ed
545
+ # with values from the mapper
546
+ # An optional callback can be supplied. Each entry will be
547
+ # given to this callback. The callback should return a list
548
+ # of localizable errors. If no callback is supplied, the
549
+ # entries will be returned in a list.
550
+ # Arguments:
551
+ # mapper - a hash ref - the keys are the tokens to replace
552
+ # and the values are the replacements
553
+ # ldiffiles - an array ref - the list of LDIF files to
554
+ # operate on
555
+ # errs - an array ref - this is filled in with the
556
+ # errors encountered in processing - this is
557
+ # suitable for passing to setup->msg or
558
+ # Resource->getText
559
+ # callback (optional) - a code ref - a ref to a subroutine
560
+ # that will be called with each entry - see below
561
+ # context (optional) - this will be passed as the first
562
+ # argument to your given callback - see below
563
+ # Callback:
564
+ # The callback sub will be called for each entry after
565
+ # the entry has been converted. The callback will be
566
+ # called with the given context as the first argument
567
+ # and the Mozilla::LDAP::Entry as the second argument,
568
+ # and an errs array ref as the third argument. The
569
+ # callback should return true to continue processing,
570
+ # or false if a fatal error was encountered that should
571
+ # abort processing of any further.
572
+ # Errors:
573
+ # This function should return an array of errors in the
574
+ # format described below, for use with Resource::getText()
575
+ # or Setup::msg()
576
+ # Return:
577
+ # The return value is a list of entries.
578
+ # Example usage:
579
+ # sub handle_entries {
580
+ # my $context = shift;
581
+ # my $entry = shift;
582
+ # my $errs = shift;
583
+ # .... do something with entry ....
584
+ # .... if $context is Mozilla::LDAP::Conn, $conn->add($entry); ...
585
+ # .... report errors ....
586
+ # if ($fatalerror) {
587
+ # push @{$errs}, 'error_token', arg1, arg2, ...;
588
+ # return 0;
589
+ # } else {
590
+ # return 1;
591
+ # }
592
+ # }
593
+ # $mapper = {foo => 'bar', baz => 'biff'};
594
+ # @ldiffiles = ('foo.ldif', 'bar.ldif', ..., 'biff.ldif');
595
+ # $conn = new Mozilla::LDAP::Conn(...);
596
+ # my @errs;
597
+ # @entries = getMappedEntries($mapper, \@ldiffiles, \@errs, \&handle_entries, $conn);
598
+ # Note that this will return 0 entries since a callback was used.
599
+ # The simpler example is this:
600
+ # @entries = getMappedEntries($mapper, \@ldiffiles, \@errs);
601
+ #
602
+ sub getMappedEntries {
603
+ my $mapper = shift;
604
+ my $ldiffiles = shift;
605
+ my $errs = shift;
606
+ my $callback = shift || \&cbaddent; # default - just add entry to @entries
607
+ my @entries = ();
608
+ my $context = shift || \@entries;
609
+ my $error;
610
+
611
+ if (!ref($ldiffiles)) {
612
+ $ldiffiles = [ $ldiffiles ];
613
+ }
614
+
615
+ foreach my $ldiffile (@{$ldiffiles}) {
616
+ if (!open(MYLDIF, "< $ldiffile")) {
617
+ push @{$errs}, "error_opening_ldiftmpl", $ldiffile, $!;
618
+ return 0;
619
+ }
620
+ my $in = new Mozilla::LDAP::LDIF(*MYLDIF);
621
+ debug(1, "Processing $ldiffile ...\n");
622
+ ENTRY: while (my $entry = Mozilla::LDAP::LDIF::readOneEntry($in)) {
623
+ # first, fix the DN
624
+ my $dn = $entry->getDN();
625
+ my $origdn = $dn;
626
+ while ( $dn =~ /%([\w_-]+)%/ ) {
627
+ if (exists($mapper->{$1})) {
628
+ $dn =~ s{%([\w_-]+)%}{$mapper->{$1}}ge;
629
+ } else {
630
+ push @{$errs}, 'error_mapping_token_ldiftmpl', $dn, $ldiffile, $1;
631
+ $error = 1;
632
+ last ENTRY;
633
+ }
634
+ }
635
+ $entry->setDN($dn);
636
+ # next, fix all of the values in all of the attributes
637
+ foreach my $attr (keys %{$entry}) {
638
+ my @newvalues = ();
639
+ foreach my $value ($entry->getValues($attr)) {
640
+ # Need to repeat to handle nested subst
641
+ my $origvalue = $value;
642
+ while ( $value =~ /%([\w_-]+)%/ ) {
643
+ if (exists($mapper->{$1})) {
644
+ $value =~ s{%([\w_-]+)%}{$mapper->{$1}}ge;
645
+ } else {
646
+ push @{$errs}, 'error_mapping_token_ldiftmpl', $dn, $ldiffile, $1;
647
+ debug(1, "ERROR: \"$origvalue\" mapped to \"$value\".\n");
648
+ $error = 1;
649
+ last ENTRY;
650
+ }
651
+ }
652
+ push @newvalues, $value;
653
+ }
654
+ $entry->setValues( $attr, @newvalues );
655
+ }
656
+
657
+ if (!&{$callback}($context, $entry, $errs)) {
658
+ debug(1, "ERROR: There was an error processing entry ". $entry->getDN(). "\n");
659
+ debug(1, "Cannot continue processing entries.\n");
660
+ $error = 1;
661
+ last ENTRY;
662
+ }
663
+
664
+ }
665
+ close(MYLDIF);
666
+ last if ($error); # do not process any more ldiffiles if an error occurred
667
+ }
668
+
669
+ return @entries;
670
+ }
671
+
672
+ # you should only use this function if you know for sure
673
+ # that the suffix and backend do not already exist
674
+ # use addSuffix instead
675
+ sub newSuffixAndBackend {
676
+ my $context = shift;
677
+ my $suffix = shift;
678
+ my $bename = shift;
679
+ my $nsuffix = normalizeDN($suffix);
680
+ my @errs;
681
+
682
+ my $dn = "cn=$bename, cn=ldbm database, cn=plugins, cn=config";
683
+ my $entry = new Mozilla::LDAP::Entry();
684
+ $entry->setDN($dn);
685
+ $entry->setValues('objectclass', 'top', 'extensibleObject', 'nsBackendInstance');
686
+ $entry->setValues('cn', $bename);
687
+ $entry->setValues('nsslapd-suffix', $nsuffix);
688
+ $context->add($entry);
689
+ my $rc = $context->getErrorCode();
690
+ if ($rc) {
691
+ return ('error_creating_suffix_backend', $suffix, $bename, $context->getErrorString());
692
+ }
693
+
694
+ $entry = new Mozilla::LDAP::Entry();
695
+ $dn = "cn=\"$nsuffix\", cn=mapping tree, cn=config";
696
+ $entry->setDN($dn);
697
+ $entry->setValues('objectclass', 'top', 'extensibleObject', 'nsMappingTree');
698
+ $entry->setValues('cn', "\"$nsuffix\"");
699
+ $entry->setValues('nsslapd-state', 'backend');
700
+ $entry->setValues('nsslapd-backend', $bename);
701
+ $context->add($entry);
702
+ $rc = $context->getErrorCode();
703
+ if ($rc) {
704
+ return ('error_creating_suffix', $suffix, $context->getErrorString());
705
+ }
706
+
707
+ return ();
708
+ }
709
+
710
+ sub findbecb {
711
+ my $entry = shift;
712
+ my $attrs = shift;
713
+ return $entry->hasValue('objectclass', $attrs->[0], 1) &&
714
+ $entry->hasValue('cn', $attrs->[1], 1);
715
+ }
716
+
717
+ sub findBackend {
718
+ my $context = shift;
719
+ my $bename = shift;
720
+ my $ent;
721
+ if (ref($context) eq 'Mozilla::LDAP::Conn') {
722
+ $ent = $context->search("cn=ldbm database,cn=plugins,cn=config", "one",
723
+ "(&(objectclass=nsBackendInstance)(cn=$bename)")
724
+ } else {
725
+ $ent = $context->search("cn=ldbm database,cn=plugins,cn=config", "one",
726
+ \&findbecb, ['nsBackendInstance', $bename])
727
+ }
728
+ }
729
+
730
+ sub findsuffixcb {
731
+ my $entry = shift;
732
+ my $attrs = shift;
733
+ return $entry->hasValue('cn', $attrs->[0], 1) ||
734
+ $entry->hasValue('cn', $attrs->[1], 1);
735
+ }
736
+
737
+ sub findSuffix {
738
+ my $context = shift;
739
+ my $suffix = shift;
740
+ my $nsuffix = normalizeDN($suffix);
741
+ my $ent;
742
+ if (ref($context) eq 'Mozilla::LDAP::Conn') {
743
+ $ent = $context->search("cn=mapping tree,cn=config", "one",
744
+ "(|(cn=\"$suffix\")(cn=\"$nsuffix\"))");
745
+ } else {
746
+ $ent = $context->search("cn=mapping tree,cn=config", "one",
747
+ \&findsuffixcb, ["\"$suffix\"", "\"$nsuffix\""])
748
+ }
749
+ }
750
+
751
+ sub getUniqueBackendName {
752
+ my $context = shift;
753
+ my $bename = "backend";
754
+ my $index = 0;
755
+ my $ent = findBackend($context, ($bename . $index));
756
+ while ($ent) {
757
+ ++$index;
758
+ $ent = findBackend($context, ($bename . $index));
759
+ }
760
+
761
+ return $bename.$index;
762
+ }
763
+
764
+ sub addSuffix {
765
+ my $context = shift; # Conn
766
+ my $suffix = shift;
767
+ my $bename = shift; # optional
768
+ my $ent;
769
+
770
+ if ($bename && ($ent = findBackend($context, $bename))) {
771
+ return ('backend_already_exists', $bename, $ent->getDN());
772
+ }
773
+
774
+ if ($ent = findSuffix($context, $suffix)) {
775
+ return ('suffix_already_exists', $suffix, $ent->getDN());
776
+ }
777
+
778
+ if (!$bename) {
779
+ $bename = getUniqueBackendName($context);
780
+ }
781
+
782
+ my @errs = newSuffixAndBackend($context, $suffix, $bename);
783
+
784
+ return @errs;
785
+ }
786
+
787
+ # process map table
788
+ # [map table sample]
789
+ # fqdn = FullMachineName
790
+ # hostname = `use Sys::Hostname; $returnvalue = hostname();`
791
+ # ds_console_jar ="%normbrand%-ds-%ds_version%.jar"
792
+ #
793
+ # * If the right-hand value is in ` (backquote), the value is eval'ed by perl.
794
+ # The output should be stored in $returnvalue to pass to the internal hash.
795
+ # * If the right-hand value is in " (doublequote), the value is passed as is.
796
+ # * If the right-hand value is not in any quote, the value should be found
797
+ # in either of the setup inf file (static) or the install inf file (dynamic).
798
+ # * Variables surrounded by @ (e.g., @admin_confdir@) are replaced with the
799
+ # system path at the compile time.
800
+ # * The right-hand value can contain variables surrounded by % (e.g., %asid%)
801
+ # which refers the right-hand value (key) of this map file.
802
+ # The %token% tokens are replaced in getMappedEntries
803
+ sub process_maptbl
804
+ {
805
+ my ($mapper, $errs, @infdata) = @_;
806
+ my @deferredkeys = ();
807
+
808
+ if (defined($mapper->{""})) {
809
+ $mapper = $mapper->{""}; # side effect of Inf with no sections
810
+ }
811
+
812
+ KEY: foreach my $key (keys %{$mapper})
813
+ {
814
+ my $value = $mapper->{$key};
815
+ if ($value =~ /^\"/)
816
+ {
817
+ $value =~ tr/\"//d; # value is a regular double quoted string - remove quotes
818
+ $mapper->{$key} = $value;
819
+ }
820
+ elsif ($value =~ /^\`/)
821
+ {
822
+ push @deferredkeys, $key; # process these last
823
+ }
824
+ else
825
+ {
826
+ # get the value from one of the Inf passed in
827
+ # they $value could be pure Key or Key:"default_value"
828
+ my ($key_value, $default_value) = split(/:/, $value, 2);
829
+ my $infsection;
830
+ foreach my $thisinf (@infdata)
831
+ {
832
+ foreach my $section0 (keys %{$thisinf})
833
+ {
834
+ $infsection = $thisinf->{$section0};
835
+ next if (!ref($infsection));
836
+ if (defined($infsection->{$key_value}))
837
+ {
838
+ $mapper->{$key} = $infsection->{$key_value};
839
+ next KEY;
840
+ }
841
+ }
842
+ }
843
+ if ($default_value ne "")
844
+ {
845
+ $default_value =~ tr/\"//d; # default_value is a regular double quoted string - remove quotes
846
+ $mapper->{$key} = $default_value;
847
+ }
848
+ else
849
+ {
850
+ push @{$errs}, ['no_mapvalue_for_key', $value, $key];
851
+ return {};
852
+ }
853
+ }
854
+ }
855
+
856
+ # we have to process the perl expressions to eval last, because those
857
+ # expressions may use mappings defined elsewhere in the file, and we are not
858
+ # guaranteed of the order in which hash keys are enumerated
859
+ foreach my $key (@deferredkeys) {
860
+ my $value = $mapper->{$key};
861
+ $value =~ tr/\`//d; # value is a perl expression to eval
862
+ my $returnvalue; # set in eval expression
863
+ eval $value;
864
+ $mapper->{$key} = $returnvalue; # perl expression sets $returnvalue
865
+ }
866
+
867
+ return $mapper;
868
+ }
869
+
870
+ # given a string, escape the characters in the string
871
+ # so that it can be safely passed to the shell via
872
+ # the system() call or `` backticks
873
+ sub shellEscape {
874
+ my $val = shift;
875
+ # first, escape the double quotes and slashes
876
+ $val =~ s/([\\"])/\\$1/g; # " font lock fun
877
+ # next, escape the rest of the special chars
878
+ my $special = '!$\' @#%^&*()|[\]{};:<>?/`';
879
+ $val =~ s/([$special])/\\$1/g;
880
+
881
+ return $val;
882
+ }
883
+
884
+ # given a string, escape the special characters in the string.
885
+ # the characters are defined in RFC 4514.
886
+ # special = escaped / SPACE / SHARP / EQUALS
887
+ # escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE
888
+ # hex string "# HEX HEX" is unlikely appearing in the installation.
889
+ # thus, it won't be supported for now.
890
+ my %dnspecial = (
891
+ '"' => '\\"', # '\\22'
892
+ '\+' => '\\+', # '\\2B'
893
+ ',' => '\\,', # '\\2C'
894
+ ';' => '\\;', # '\\3B'
895
+ '<' => '\\<', # '\\3C'
896
+ '>' => '\\>', # '\\3E'
897
+ '=' => '\\=' # '\\3D'
898
+ );
899
+
900
+ sub dnEscape {
901
+ my $val = shift;
902
+ # first, remove spaces surrounding ',' and leading/trailing spaces
903
+ $val =~ s/^\s*//;
904
+ $val =~ s/\s*$//;
905
+ $val =~ s/\s*,\s*/,/g;
906
+ # next, replace the special characters
907
+ foreach my $idx (keys %dnspecial) {
908
+ $val =~ s/$idx/$dnspecial{$idx}/g;
909
+ }
910
+ $val =~ s/\s*,\s*/,/g;
911
+
912
+ return $val;
913
+ }
914
+
915
+ sub getHashedPassword {
916
+ my $pwd = shift;
917
+ my $alg = shift;
918
+
919
+ if ($pwd =~ /^\{\w+\}.+/) {
920
+ return $pwd; # already hashed
921
+ }
922
+
923
+ my $cmd = "/usr/bin/pwdhash";
924
+ if ($alg) {
925
+ $cmd .= " -s $alg";
926
+ }
927
+ $cmd .= " -- " . shellEscape($pwd);
928
+ my $hashedpwd = `$cmd`;
929
+ chomp($hashedpwd);
930
+
931
+ return $hashedpwd;
932
+ }
933
+
934
+ # this creates an Inf suitable for passing to createDSInstance
935
+ # except that it has a bogus suffix
936
+ sub createInfFromConfig {
937
+ my $configdir = shift;
938
+ my $inst = shift;
939
+ my $errs = shift;
940
+ my $fname = "$configdir/dse.ldif";
941
+ my $id;
942
+ ($id = $inst) =~ s/^slapd-//;
943
+ if (! -f $fname || ! -r $fname) {
944
+ push @{$errs}, "error_opening_dseldif", $fname, $!;
945
+ return 0;
946
+ }
947
+ my $conn = new FileConn($fname, 1);
948
+ if (!$conn) {
949
+ push @{$errs}, "error_opening_dseldif", $fname, $!;
950
+ return 0;
951
+ }
952
+
953
+ my $ent = $conn->search("cn=config", "base", "(objectclass=*)");
954
+ if (!$ent) {
955
+ push @{$errs}, "error_opening_dseldif", $fname, $!;
956
+ $conn->close();
957
+ return 0;
958
+ }
959
+
960
+ my $inf = new Inf();
961
+ $inf->{General}->{FullMachineName} = $ent->getValues('nsslapd-localhost');
962
+ $inf->{General}->{SuiteSpotUserID} = $ent->getValues('nsslapd-localuser');
963
+ $inf->{slapd}->{RootDN} = $ent->getValues('nsslapd-rootdn');
964
+ $inf->{slapd}->{RootDNPwd} = $ent->getValues('nsslapd-rootpw');
965
+ $inf->{slapd}->{ServerPort} = $ent->getValues('nsslapd-port');
966
+ $inf->{slapd}->{ServerIdentifier} = $id;
967
+
968
+ my $suffix = "";
969
+ $ent = $conn->search("cn=ldbm database,cn=plugins,cn=config",
970
+ "one", "(objectclass=*)");
971
+ if (!$ent) {
972
+ push @{$errs}, "error_opening_dseldif", $fname, $!;
973
+ $conn->close();
974
+ return 0;
975
+ }
976
+ # use the userRoot suffix if available
977
+ while ($ent) {
978
+ if ($ent->getValues('nsslapd-suffix')) {
979
+ $suffix = $ent->getValues('nsslapd-suffix');
980
+ }
981
+ last if ($ent->hasValue('cn', 'userRoot', 1));
982
+ $ent = $conn->nextEntry();
983
+ }
984
+ if ( "" eq "$suffix" )
985
+ {
986
+ push @{$errs}, "error_opening_dseldif", $fname, $!;
987
+ $conn->close();
988
+ return 0;
989
+ }
990
+
991
+ # we also need the instance dir
992
+ $ent = $conn->search("cn=config", "base", "(objectclass=*)");
993
+ if (!$ent) {
994
+ push @{$errs}, "error_opening_dseldif", $fname, $!;
995
+ $conn->close();
996
+ return 0;
997
+ }
998
+ my $inst_dir = $ent->getValue('nsslapd-instancedir');
999
+
1000
+ $conn->close();
1001
+
1002
+ if ($inst_dir) {
1003
+ $inf->{slapd}->{inst_dir} = $inst_dir;
1004
+ }
1005
+ $inf->{slapd}->{Suffix} = $suffix;
1006
+
1007
+ return $inf;
1008
+ }
1009
+
1010
+ # like File::Path mkpath, except we can set the owner and perm
1011
+ # of each new path and parent path created
1012
+ sub makePaths {
1013
+ my ($path, $mode, $user, $group) = @_;
1014
+ my $uid = getpwnam $user;
1015
+ my $gid = -1; # default to leave it alone
1016
+ my $mode_string = "";
1017
+
1018
+ if ($group) {
1019
+ $gid = getgrnam $group;
1020
+ }
1021
+ my @dirnames = ($path);
1022
+ my $parent = $path;
1023
+ for ($parent = dirname($parent);
1024
+ $parent and ($parent ne "/");
1025
+ $parent = dirname($parent)) {
1026
+ unshift @dirnames, $parent;
1027
+ }
1028
+ for my $dir (@dirnames) {
1029
+ next if (-d $dir);
1030
+ $! = 0; # clear
1031
+ mkdir $dir, $mode;
1032
+ if ($!) {
1033
+ return ('error_creating_directory', $dir, $!);
1034
+ }
1035
+ chown $uid, $gid, $dir;
1036
+ if ($!) {
1037
+ return ('error_chowning_directory', $dir, $!);
1038
+ }
1039
+ chmod $mode, $dir;
1040
+ $mode_string = sprintf "%lo", $mode;
1041
+ debug(1, "makePaths: created directory $dir mode $mode_string user $user group $group\n");
1042
+ debug(2, "\t" . `ls -ld $dir`);
1043
+ }
1044
+
1045
+ return ();
1046
+ }
1047
+
1048
+ # remove_tree($centry, $key, $instname, [$isparent, [$dontremove]])
1049
+ # $centry: entry to look for the path to be removed
1050
+ # $key: key to look for the path in the entry
1051
+ # $instname: instance name "slapd-<ID>" to check the path
1052
+ # $isparent: specify 1 to remove from the parent dir
1053
+ # $dontremove: pattern not to be removed (e.g., ".db$")
1054
+ sub remove_tree
1055
+ {
1056
+ my $centry = shift;
1057
+ my $key = shift;
1058
+ my $instname = shift;
1059
+ my $isparent = shift;
1060
+ my $dontremove = shift;
1061
+ my @errs = (); # a list of array refs - each array ref is suitable for passing to Resource::getText
1062
+
1063
+ foreach my $path ( @{$centry->{$key}} )
1064
+ {
1065
+ my $rmdir = "";
1066
+ my $rc = 0;
1067
+ if ( 1 == $isparent )
1068
+ {
1069
+ $rmdir = dirname($path);
1070
+ }
1071
+ else
1072
+ {
1073
+ $rmdir = $path;
1074
+ }
1075
+ if ( -d $rmdir && $rmdir =~ /$instname/ )
1076
+ {
1077
+ if ( "" eq "$dontremove" )
1078
+ {
1079
+ $rc = rmtree($rmdir);
1080
+ if ( 0 == $rc )
1081
+ {
1082
+ push @errs, [ 'error_removing_path', $rmdir, $! ];
1083
+ debug(1, "Warning: $rmdir was not removed. Error: $!\n");
1084
+ }
1085
+ }
1086
+ else
1087
+ {
1088
+ # Skip the dontremove files
1089
+ $rc = opendir(DIR, $rmdir);
1090
+ if ($rc)
1091
+ {
1092
+ while (defined(my $file = readdir(DIR)))
1093
+ {
1094
+ next if ( "$file" =~ /$dontremove/ );
1095
+ next if ( "$file" eq "." );
1096
+ next if ( "$file" eq ".." );
1097
+ my $rmfile = $rmdir . "/" . $file;
1098
+ my $rc0 = rmtree($rmfile);
1099
+ if ( 0 == $rc0 )
1100
+ {
1101
+ push @errs, [ 'error_removing_path', $rmfile, $! ];
1102
+ debug(1, "Warning: $rmfile was not removed. Error: $!\n");
1103
+ }
1104
+ }
1105
+ closedir(DIR);
1106
+ }
1107
+ my $newrmdir = $rmdir . ".removed";
1108
+ my $rc1 = 1;
1109
+ if ( -d $newrmdir )
1110
+ {
1111
+ $rc1 = rmtree($newrmdir);
1112
+ if ( 0 == $rc1 )
1113
+ {
1114
+ push @errs, [ 'error_removing_path', $newrmdir, $! ];
1115
+ debug(1, "Warning: $newrmdir was not removed. Error: $!\n");
1116
+ }
1117
+ }
1118
+ if ( 0 < $rc1 )
1119
+ {
1120
+ rename($rmdir, $newrmdir);
1121
+ }
1122
+ }
1123
+ }
1124
+ }
1125
+
1126
+ return @errs; # a list of array refs - if (!@errs) then success
1127
+ }
1128
+
1129
+ sub remove_pidfile
1130
+ {
1131
+ my ($type, $serv_id, $instdir, $instname, $run_dir, $product_name) = @_;
1132
+ my $pidfile;
1133
+
1134
+ # Construct the pidfile name as follows:
1135
+ # PIDFILE=$RUN_DIR/$PRODUCT_NAME-$SERV_ID.pid
1136
+ # STARTPIDFILE=$RUN_DIR/$PRODUCT_NAME-$SERV_ID.startpid
1137
+ if ($type eq "PIDFILE") {
1138
+ $pidfile = $run_dir . "/" . $product_name . "-" . $serv_id . ".pid";
1139
+ } elsif ($type eq "STARTPIDFILE") {
1140
+ $pidfile = $run_dir . "/" . $product_name . "-" . $serv_id . ".startpid";
1141
+ }
1142
+
1143
+ if ( -e $pidfile && $pidfile =~ /$instname/ )
1144
+ {
1145
+ unlink($pidfile);
1146
+ }
1147
+ }
1148
+
1149
+ sub serverIsRunning
1150
+ {
1151
+ my ($run_dir, $inst) = @_;
1152
+ my $pidfile = $run_dir . "/" . $inst . ".pid";
1153
+ if ( -e $pidfile ) {
1154
+ if (!open(PIDFILE, $pidfile)) {
1155
+ debug(3, "Could not open pidfile $pidfile - $! - assume server is not running\n");
1156
+ return 0; # could not open pid file - assume server is not running
1157
+ }
1158
+ my $pid = <PIDFILE>;
1159
+ chomp($pid);
1160
+ close(PIDFILE);
1161
+ if (!$pid) {
1162
+ debug(3, "Bogus pid $pid found in pidfile $pidfile - assume server is not running\n");
1163
+ return 0; # could not open pid file - assume server is not running
1164
+ }
1165
+ if (kill(0, $pid)) {
1166
+ debug(3, "pid $pid from file $pidfile is running\n");
1167
+ return 1; # server is running
1168
+ }
1169
+ debug(3, "pid $pid from file $pidfile is not running - could not kill 0 - $!\n");
1170
+ } else {
1171
+ debug(3, "No such file pidfile $pidfile - $! - assume server is not running\n");
1172
+ }
1173
+
1174
+ return 0; # no pid file - assume not running
1175
+ }
1176
+
1177
+ sub libpath_add {
1178
+ my $libpath = shift;
1179
+
1180
+ if ($libpath) {
1181
+ if ($ENV{'LD_LIBRARY_PATH'}) {
1182
+ $ENV{'LD_LIBRARY_PATH'} = "$ENV{'LD_LIBRARY_PATH'}:$libpath";
1183
+ } else {
1184
+ $ENV{'LD_LIBRARY_PATH'} = "$libpath";
1185
+ }
1186
+ }
1187
+ }
1188
+
1189
+ #
1190
+ # get_info()
1191
+ #
1192
+ # Grab all the config settings we need from the dse.ldif
1193
+ #
1194
+ sub get_info {
1195
+ my %info = ();
1196
+ my $dir = shift;
1197
+ $info{host} = shift;
1198
+ $info{port} = shift;
1199
+ $info{rootdn} = shift;
1200
+ my $dse_file = "$dir/dse.ldif";
1201
+ my $foundcfg = "no";
1202
+ my $value;
1203
+ my $entry;
1204
+ my $ldif;
1205
+
1206
+ #
1207
+ # Are we using openLDAP or Mozilla?
1208
+ #
1209
+ my $toollib = `ldapsearch -V 2>&1`;
1210
+ if ($toollib =~ /OpenLDAP/) {
1211
+ $info{openldap} = "yes";
1212
+ $info{nofold} = "-o ldif-wrap=no";
1213
+ } else {
1214
+ $info{openldap} = "no";
1215
+ $info{nofold} = "-T";
1216
+ }
1217
+
1218
+ #
1219
+ # Open dse.ldif and grab the cn=config entry
1220
+ #
1221
+ open(DSE, "$dse_file") || die "Failed to open config file $dse_file $!\n";
1222
+ $ldif = new Mozilla::LDAP::LDIF(*DSE);
1223
+ while($entry = readOneEntry $ldif){
1224
+ if($entry->getDN() eq "cn=config"){
1225
+ $foundcfg = "yes";
1226
+ last;
1227
+ }
1228
+ }
1229
+ if($foundcfg eq "no"){
1230
+ print (STDERR "Failed to find \"cn=config\" entry from $dse_file\n");
1231
+ close (DSE);
1232
+ exit 1;
1233
+ }
1234
+
1235
+ #
1236
+ # Get missing info
1237
+ #
1238
+ if($info{host} eq ""){
1239
+ $info{host} = $entry->getValues("nsslapd-localhost");
1240
+ }
1241
+ if($info{port} eq ""){
1242
+ $info{port} = $entry->getValues("nsslapd-port") || "389";
1243
+ }
1244
+ if($info{rootdn} eq ""){
1245
+ $info{rootdn} = $entry->getValues("nsslapd-rootdn");
1246
+ }
1247
+
1248
+ #
1249
+ # Get SSL and LDAPI settings
1250
+ #
1251
+ $info{certdir} = $entry->getValues("nsslapd-certdir");
1252
+ if($info{openldap} eq "yes"){
1253
+ $ENV{LDAPTLS_CACERTDIR}=$info{certdir};
1254
+ }
1255
+ $info{security} = $entry->getValues("nsslapd-security");
1256
+ $info{secure_port} = $entry->getValues("nsslapd-securePort") || "636";
1257
+ $info{ldapi} = $entry->getValues("nsslapd-ldapilisten");
1258
+ $info{autobind} = $entry->getValues("nsslapd-ldapiautobind");
1259
+ $value = $entry->getValues("nsslapd-ldapifilepath");
1260
+ if ($value){
1261
+ $value =~ s/\//%2f/g;
1262
+ $info{ldapiURL} = "ldapi://" . $value;
1263
+ }
1264
+
1265
+ while($entry = readOneEntry $ldif){
1266
+ if($entry->getDN() eq "cn=encryption,cn=config"){
1267
+ $foundcfg = "yes";
1268
+ last;
1269
+ }
1270
+ }
1271
+ if($foundcfg eq "yes" && $entry){
1272
+ $info{cacertfile} = $entry->getValues("CACertExtractFile");
1273
+ if ($info{cacertfile}) {
1274
+ $ENV{LDAPTLS_CACERT}=$info{cacertfile};
1275
+ }
1276
+ }
1277
+
1278
+ close (DSE);
1279
+ return %info;
1280
+ }
1281
+
1282
+ #
1283
+ # return the normalized server id and the server config dir (contains dse.ldif)
1284
+ #
1285
+ sub get_server_id {
1286
+ my $servid = shift;
1287
+ my $dir = shift;
1288
+ my $instance_count = 0;
1289
+ my $first = "yes";
1290
+ my $instances = "<none>";
1291
+ my $name;
1292
+ my $inst;
1293
+ my $file;
1294
+ my @extra = ();
1295
+ my $extradir = "";
1296
+
1297
+ if (getLogin ne 'root') {
1298
+ $extradir = "$ENV{HOME}/.dirsrv";
1299
+ if (-d $extradir) {
1300
+ opendir(EXTRADIR, $extradir);
1301
+ @extra = map {$_ = "$extradir/$_"} readdir(EXTRADIR);
1302
+ closedir(EXTRADIR);
1303
+ }
1304
+ }
1305
+
1306
+ if (defined $ENV{INITCONFIGDIR}) {
1307
+ $dir = $ENV{INITCONFIGDIR};
1308
+ @extra = (); # only use what was provided
1309
+ $extradir = "";
1310
+ }
1311
+
1312
+ # normalize the given servid
1313
+ if (!$servid) {
1314
+ # not given
1315
+ } elsif ($servid =~ /^dirsrv-/){
1316
+ # strip off "dirsrv-"
1317
+ $servid =~ s/^dirsrv-//;
1318
+ } elsif ($servid =~ /^slapd-/){
1319
+ # strip off "slapd-"
1320
+ $servid =~ s/^slapd-//;
1321
+ } # else assume already normalized
1322
+
1323
+ opendir(DIR, "$dir");
1324
+ my @files = map {$_ = "$dir/$_"} readdir(DIR);
1325
+ closedir(DIR);
1326
+ push @files, @extra;
1327
+ my $found = 0;
1328
+ foreach $file (@files){
1329
+ next if(! -r $file); # skip unreadable files
1330
+ # skip admin server
1331
+ if($file =~ m,/dirsrv-([^/]+)$, && $file !~ m,/dirsrv-admin$,){
1332
+ $name = $file;
1333
+ $inst = $1;
1334
+ $instance_count++;
1335
+ if ($servid && ($servid eq $inst)) {
1336
+ $found = 1;
1337
+ last;
1338
+ }
1339
+ if($first eq "yes"){
1340
+ $instances=$inst;
1341
+ $first = "no";
1342
+ } else {
1343
+ $instances=$instances . ", $inst";
1344
+ }
1345
+ }
1346
+ }
1347
+
1348
+ if ($servid && !$found) { # if we got here, did not find given serverid
1349
+ print (STDERR "Invalid server identifer: $servid\n");
1350
+ print (STDERR "Available instances in $dir $extradir: $instances\n");
1351
+ exit (1);
1352
+ }
1353
+
1354
+ if ($instance_count == 0){
1355
+ print "No instances found in $dir\n";
1356
+ exit (1);
1357
+ }
1358
+
1359
+ if (!$servid && $instance_count > 1){
1360
+ print "You must supply a valid server instance identifier. Use -Z to specify instance name\n";
1361
+ print "Available instances: $instances\n";
1362
+ exit (1);
1363
+ }
1364
+ unless ( -e "$name" ){
1365
+ print (STDERR "Invalid server identifer: $servid\n");
1366
+ print (STDERR "Available instances in $dir $extradir: $instances\n");
1367
+ exit (1);
1368
+ }
1369
+
1370
+ # now grab the CONFIG_DIR from the file $name
1371
+ if (!open(INSTFILE, "$name")) {
1372
+ print (STDERR "Error: could not open $name: ");
1373
+ exit (1);
1374
+ }
1375
+
1376
+ my $confdir;
1377
+ while (<INSTFILE>) {
1378
+ if (/^CONFIG_DIR=/) {
1379
+ s/^CONFIG_DIR=//;
1380
+ s/ ; export CONFIG_DIR//;
1381
+ $confdir = $_;
1382
+ chomp($confdir);
1383
+ last;
1384
+ }
1385
+ }
1386
+ close INSTFILE;
1387
+
1388
+ if (!$confdir) {
1389
+ print (STDERR "Error: no CONFIG_DIR found in $name\n");
1390
+ exit (1);
1391
+ }
1392
+
1393
+ return ($inst, $confdir);
1394
+ }
1395
+
1396
+ #
1397
+ # Get the root DN password from the file, or command line input
1398
+ #
1399
+ sub get_password_from_file {
1400
+ my $passwd = shift;
1401
+ my $passwdfile = shift;
1402
+
1403
+ if ($passwdfile ne ""){
1404
+ # Open file and get the password
1405
+ unless (open (RPASS, $passwdfile)) {
1406
+ die "Error, cannot open password file $passwdfile\n";
1407
+ }
1408
+ $passwd = <RPASS>;
1409
+ chomp($passwd);
1410
+ close(RPASS);
1411
+ } elsif ($passwd eq "-"){
1412
+ # Read the password from terminal
1413
+ print "Bind Password: ";
1414
+ # Disable console echo
1415
+ system("/bin/stty -echo") if -t STDIN;
1416
+ # read the answer
1417
+ $passwd = <STDIN>;
1418
+ # Enable console echo
1419
+ system("/bin/stty echo") if -t STDIN;
1420
+ print "\n";
1421
+ chop($passwd); # trim trailing newline
1422
+ }
1423
+
1424
+ return $passwd;
1425
+ }
1426
+
1427
+ #
1428
+ # Execute the ldapmodify
1429
+ #
1430
+ sub ldapmod {
1431
+ my $entry = shift;
1432
+ my %info = @_;
1433
+ my $file = "/tmp/DSUtil-$$.txt";
1434
+ my $protocol_error;
1435
+ my $result;
1436
+ my $rc;
1437
+ my $myrootdnpw = shellEscape($info{rootdnpw});
1438
+
1439
+ #
1440
+ # write the entry to file so we can grab the result code after running ldapmodify(-f)
1441
+ #
1442
+ if(!open (FILE, ">$file") ){
1443
+ print (STDERR "DSUtil::ldapmod() failed to create tmp file ($!)\n");
1444
+ return 1;
1445
+ } else {
1446
+ print (FILE "$entry\n");
1447
+ close (FILE);
1448
+ }
1449
+
1450
+ if ($info{redirect} eq ""){
1451
+ $info{redirect} = "> /dev/null";
1452
+ }
1453
+
1454
+ #
1455
+ # Check the protocol, and reset it if it's invalid
1456
+ #
1457
+ $result = check_protocol(%info);
1458
+ if($result == 1){
1459
+ $protocol_error = "yes";
1460
+ $info{protocol} = "";
1461
+ } elsif( $result == 2){
1462
+ unlink ($file);
1463
+ return 1;
1464
+ }
1465
+
1466
+ #
1467
+ # Execute ldapmodify using the specified/most secure protocol
1468
+ #
1469
+ if (($info{security} eq "on" && $info{protocol} eq "") || ($info{security} eq "on" && $info{protocol} =~ m/STARTTLS/i) ){
1470
+ #
1471
+ # STARTTLS
1472
+ #
1473
+ if($protocol_error eq "yes"){
1474
+ print "STARTTLS)\n";
1475
+ }
1476
+ if($info{openldap} eq "yes"){
1477
+ system "ldapmodify -x -ZZ -h $info{host} -p $info{port} -D \"$info{rootdn}\" -w $myrootdnpw $info{args} -f \"$file\" $info{redirect}";
1478
+ } else {
1479
+ system "ldapmodify -ZZZ -P \"$info{certdir}\" -h $info{host} -p $info{port} -D \"$info{rootdn}\" -w $myrootdnpw $info{args} -f \"$file\" $info{redirect}";
1480
+ }
1481
+ } elsif (($info{security} eq "on" && $info{protocol} eq "") || ($info{security} eq "on" && $info{protocol} =~ m/LDAPS/i) ){
1482
+ #
1483
+ # LDAPS
1484
+ #
1485
+ if($protocol_error eq "yes"){
1486
+ print "LDAPS)\n";
1487
+ }
1488
+ if($info{openldap} eq "yes"){
1489
+ system "ldapmodify -x -H \"ldaps://$info{host}:$info{secure_port}\" -D \"$info{rootdn}\" -w $myrootdnpw $info{args} -f \"$file\" $info{redirect}";
1490
+ } else {
1491
+ system "ldapmodify -Z -P \"$info{certdir}\" -p $info{secure_port} -D \"$info{rootdn}\" -w $myrootdnpw $info{args} -f \"$file\" $info{redirect}";
1492
+ }
1493
+ } elsif (($info{openldap} eq "yes") && (($info{ldapi} eq "on" && $info{protocol} eq "") || ($info{ldapi} eq "on" && $info{protocol} =~ m/LDAPI/i)) ){
1494
+ #
1495
+ # LDAPI
1496
+ #
1497
+ if ($< == 0 && $info{autobind} eq "on"){
1498
+ if($protocol_error eq "yes"){
1499
+ print "LDAPI/AUTOBIND)\n";
1500
+ }
1501
+ system "ldapmodify -H \"$info{ldapiURL}\" -Y EXTERNAL $info{args} -f \"$file\" > /dev/null 2>&1";
1502
+ } else {
1503
+ if($protocol_error eq "yes"){
1504
+ print "LDAPI)\n";
1505
+ }
1506
+ system "ldapmodify -x -H \"$info{ldapiURL}\" -D \"$info{rootdn}\" -w $myrootdnpw $info{args} -f \"$file\" $info{redirect}";
1507
+ }
1508
+ } else {
1509
+ #
1510
+ # LDAP
1511
+ #
1512
+ if($protocol_error eq "yes"){
1513
+ print "LDAP)\n";
1514
+ }
1515
+ if($info{openldap} eq "yes"){
1516
+ system "ldapmodify -x -h $info{host} -p $info{port} -D \"$info{rootdn}\" -w $myrootdnpw $info{args} -f \"$file\" $info{redirect}";
1517
+ } else {
1518
+ system "ldapmodify -h $info{host} -p $info{port} -D \"$info{rootdn}\" -w $myrootdnpw $info{args} -f \"$file\" $info{redirect}";
1519
+ }
1520
+ }
1521
+ unlink ($file);
1522
+ if ($? != 0){
1523
+ my $retCode=$?>>8;
1524
+ return $retCode;
1525
+ }
1526
+ return 0;
1527
+ }
1528
+
1529
+ #
1530
+ # Build the ldapsearch
1531
+ #
1532
+ sub ldapsrch {
1533
+ my %info = @_;
1534
+ my $protocol_error;
1535
+ my $search;
1536
+ my $result;
1537
+ my $myrootdnpw = shellEscape($info{rootdnpw});
1538
+
1539
+ $result = check_protocol(%info);
1540
+ if($result == 1){
1541
+ $protocol_error = "yes";
1542
+ $info{protocol} = "";
1543
+ } elsif( $result == 2){
1544
+ return "";
1545
+ }
1546
+ if (($info{security} eq "on" && $info{protocol} eq "") || ($info{security} eq "on" && $info{protocol} =~ m/STARTTLS/i) ){
1547
+ #
1548
+ # STARTTLS
1549
+ #
1550
+ if($protocol_error eq "yes"){
1551
+ print "STARTTLS)\n";
1552
+ }
1553
+ if($info{openldap} eq "yes"){
1554
+ $search = "ldapsearch -x -LLL -ZZ -p $info{port} -h $info{host} -D \"$info{rootdn}\" -w $myrootdnpw $info{nofold} " .
1555
+ "$info{srch_args} -b \"$info{base}\" -s $info{scope} \"$info{filter}\" $info{attrs}";
1556
+ } else {
1557
+ $search = "ldapsearch -ZZZ -P \"$info{certdir}\" -p $info{port} -h $info{host} -D \"$info{rootdn}\" $info{nofold} " .
1558
+ "-w $myrootdnpw $info{srch_args} -b \"$info{base}\" -s $info{scope} \"$info{filter}\" $info{attrs}";
1559
+ }
1560
+ } elsif (($info{security} eq "on" && $info{protocol} eq "") || ($info{security} eq "on" && $info{protocol} =~ m/LDAPS/i) ){
1561
+ #
1562
+ # LDAPS
1563
+ #
1564
+ if($protocol_error eq "yes"){
1565
+ print "LDAPS)\n";
1566
+ }
1567
+ if($info{openldap} eq "yes"){
1568
+ $search = "ldapsearch -x -LLL -H \"ldaps://$info{host}:$info{secure_port}\" -D \"$info{rootdn}\" $info{nofold} " .
1569
+ "-w $myrootdnpw $info{srch_args} -b \"$info{base}\" -s $info{scope} \"$info{filter}\" $info{attrs}";
1570
+ } else {
1571
+ $search = "ldapsearch -Z -P \"$info{certdir}\" -p $info{secure_port} -h $info{host} -D \"$info{rootdn}\" $info{nofold} " .
1572
+ "-w $myrootdnpw $info{srch_args} -b \"$info{base}\" -s $info{scope} \"$info{filter}\" $info{attrs}";
1573
+ }
1574
+ } elsif (($info{openldap} eq "yes") && (($info{ldapi} eq "on" && $info{protocol} eq "") || ($info{ldapi} eq "on" && $info{protocol} =~ m/LDAPI/i)) ){
1575
+ #
1576
+ # LDAPI
1577
+ #
1578
+ if ($< == 0 && $info{autobind} eq "on"){
1579
+ $search = "ldapsearch -LLL -H \"$info{ldapiURL}\" -Y EXTERNAL $info{nofold} " .
1580
+ "$info{srch_args} -b \"$info{base}\" -s $info{scope} \"$info{filter}\" $info{attrs} 2>/dev/null";
1581
+ } else {
1582
+ $search = "ldapsearch -x -LLL -H \"$info{ldapiURL}\" -D \"$info{rootdn}\" -w $myrootdnpw $info{nofold} " .
1583
+ "$info{srch_args} -b \"$info{base}\" -s $info{scope} \"$info{filter}\" $info{attrs}";
1584
+ }
1585
+ } else {
1586
+ #
1587
+ # LDAP
1588
+ #
1589
+ if($protocol_error eq "yes"){
1590
+ print "LDAP)\n";
1591
+ }
1592
+ if($info{openldap} eq "yes"){
1593
+ $search = "ldapsearch -x -LLL -p $info{port} -h $info{host} -D \"$info{rootdn}\" -w $myrootdnpw $info{nofold} " .
1594
+ "$info{srch_args} -b \"$info{base}\" -s $info{scope} \"$info{filter}\" $info{attrs}";
1595
+ } else {
1596
+ $search = "ldapsearch -p $info{port} -h $info{host} -D \"$info{rootdn}\" -w $myrootdnpw $info{nofold} " .
1597
+ "$info{srch_args} -b \"$info{base}\" -s $info{scope} \"$info{filter}\" $info{attrs}";
1598
+ }
1599
+ }
1600
+ return $search;
1601
+ }
1602
+
1603
+ #
1604
+ # Execute the search
1605
+ #
1606
+ sub ldapsrch_ext {
1607
+ my %info = @_;
1608
+ my $protocol_error;
1609
+ my $result;
1610
+ my $txt;
1611
+ my $myrootdnpw = shellEscape($info{rootdnpw});
1612
+
1613
+ $result = check_protocol(%info);
1614
+ if($result == 1){
1615
+ $protocol_error = "yes";
1616
+ $info{protocol} = "";
1617
+ } elsif($result == 2){
1618
+ return 1;
1619
+ }
1620
+ if (($info{security} eq "on" && $info{protocol} eq "") || ($info{security} eq "on" && $info{protocol} =~ m/STARTTLS/i) ){
1621
+ #
1622
+ # STARTTLS
1623
+ #
1624
+ if($protocol_error eq "yes"){
1625
+ print "STARTTLS)\n";
1626
+ }
1627
+ if($info{openldap} eq "yes"){
1628
+ return `ldapsearch -x -LLL -ZZ -p $info{port} -h $info{host} -D \"$info{rootdn}\" -w $myrootdnpw $info{nofold} $info{srch_args} -b \"$info{base}\" -s $info{scope} \"$info{filter}\" $info{attrs} $info{redirect}`;
1629
+ } else {
1630
+ return `ldapsearch -ZZZ -P $info{certdir} -p $info{port} -h $info{host} -D \"$info{rootdn}\" -w $myrootdnpw $info{nofold} $info{srch_args} -b \"$info{base}\" -s $info{scope} \"$info{filter}\" $info{attrs} $info{redirect}`;
1631
+ }
1632
+ } elsif (($info{security} eq "on" && $info{protocol} eq "") || ($info{security} eq "on" && $info{protocol} =~ m/LDAPS/i) ){
1633
+ #
1634
+ # LDAPS
1635
+ #
1636
+ if($protocol_error eq "yes"){
1637
+ print "LDAPS)\n";
1638
+ }
1639
+ if($info{openldap} eq "yes"){
1640
+ return `ldapsearch -x -LLL -H ldaps://$info{host}:$info{secure_port} -D \"$info{rootdn}\" -w $myrootdnpw $info{nofold} $info{srch_args} -b \"$info{base}\" -s $info{scope} \"$info{filter}\" $info{attrs} $info{redirect}`;
1641
+ } else {
1642
+ return `ldapsearch -Z -P $info{certdir} -p $info{secure_port} -D \"$info{rootdn}\" -w $myrootdnpw $info{nofold} $info{srch_args} -b \"$info{base}\" -s $info{scope} \"$info{filter}\" $info{attrs} $info{redirect}`;
1643
+ }
1644
+ } elsif (($info{openldap} eq "yes") && (($info{ldapi} eq "on" && $info{protocol} eq "") || ($info{ldapi} eq "on" && $info{protocol} =~ m/LDAPI/i)) ){
1645
+ #
1646
+ # LDAPI
1647
+ #
1648
+ if ($< == 0 && $info{autobind} eq "on"){
1649
+ return `ldapsearch -LLL -H \"$info{ldapiURL}\" -Y EXTERNAL $info{nofold} $info{srch_args} -b \"$info{base}\" -s $info{scope} \"$info{filter}\" $info{attrs} $info{redirect} 2>/dev/null`;
1650
+ } else {
1651
+ return `ldapsearch -x -LLL -H \"$info{ldapiURL}\" -D \"$info{rootdn}\" -w $myrootdnpw $info{nofold} $info{srch_args} -b \"$info{base}\" -s $info{scope} \"$info{filter}\" $info{attrs} $info{redirect}`;
1652
+ }
1653
+ } else {
1654
+ #
1655
+ # LDAP
1656
+ #
1657
+ if($protocol_error eq "yes"){
1658
+ print "LDAP)\n";
1659
+ }
1660
+ if($info{openldap} eq "yes"){
1661
+ return `ldapsearch -x -LLL -p $info{port} -h $info{host} -D \"$info{rootdn}\" -w $myrootdnpw $info{nofold} $info{srch_args} -b \"$info{base}\" -s $info{scope} \"$info{filter}\" $info{attrs} $info{redirect}`;
1662
+ } else {
1663
+ return `ldapsearch -p $info{port} -h $info{host} -D \"$info{rootdn}\" -w $myrootdnpw $info{nofold} $info{srch_args} -b \"$info{base}\" -s $info{scope} \"$info{filter}\" $info{attrs} $info{redirect}`;
1664
+ }
1665
+ }
1666
+ }
1667
+
1668
+ #
1669
+ # Check to see if the protocol is supported.
1670
+ #
1671
+ # If it's not supported, start logging the error message - the
1672
+ # message will be completed by the calling function.
1673
+ #
1674
+ sub check_protocol {
1675
+ my %info = @_;
1676
+ my $txt;
1677
+
1678
+ if(($info{protocol} eq "LDAPI" && $info{openldap} eq "no") ||
1679
+ ($info{protocol} eq "LDAPI" && $info{ldapi} eq "off") ||
1680
+ ($info{protocol} eq "STARTTLS" && ($info{security} eq "" || $info{security} eq "off")) ||
1681
+ ($info{protocol} eq "LDAPS" && ($info{security} eq "" || $info{security} eq "off"))
1682
+ ){
1683
+ if($info{protocol} eq "LDAPI" && $info{openldap} eq "no"){
1684
+ $txt = " by the Mozilla LDAP client";
1685
+ } else {
1686
+ $txt = " by the Directory Server";
1687
+ }
1688
+ print (STDERR "Protocol $info{protocol} requested, but this protocol is not supported" . $txt . ".\n" .
1689
+ "Using the next most secure protocol (" ); # completed by the caller
1690
+ return 1;
1691
+ }
1692
+ if( ($info{protocol} ne "") && ($info{protocol} ne "STARTTLS" &&
1693
+ $info{protocol} ne "LDAPS" &&
1694
+ $info{protocol} ne "LDAPI" &&
1695
+ $info{protocol} ne "LDAP") )
1696
+ {
1697
+ print (STDERR "Unknown protocol: $info{protocol}\n");
1698
+ return 2;
1699
+ }
1700
+ return 0;
1701
+ }
1702
+
1703
+ 1;
1704
+
1705
+ # emacs settings
1706
+ # Local Variables:
1707
+ # mode:perl
1708
+ # indent-tabs-mode: nil
1709
+ # tab-width: 4
1710
+ # End: