001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.tools;
028    import org.opends.messages.Message;
029    
030    
031    
032    import java.security.GeneralSecurityException;
033    import java.util.Collection;
034    import java.util.HashSet;
035    import java.util.LinkedList;
036    import java.util.Set;
037    import java.io.File;
038    
039    import javax.crypto.Cipher;
040    
041    import org.opends.server.admin.DefaultBehaviorProvider;
042    import org.opends.server.admin.DefinedDefaultBehaviorProvider;
043    import org.opends.server.admin.StringPropertyDefinition;
044    import org.opends.server.admin.std.meta.CryptoManagerCfgDefn;
045    import org.opends.server.api.ConfigHandler;
046    import org.opends.server.config.BooleanConfigAttribute;
047    import org.opends.server.config.ConfigEntry;
048    import org.opends.server.config.DNConfigAttribute;
049    import org.opends.server.config.IntegerConfigAttribute;
050    import org.opends.server.config.StringConfigAttribute;
051    import org.opends.server.core.DirectoryServer;
052    import org.opends.server.core.LockFileManager;
053    import org.opends.server.extensions.ConfigFileHandler;
054    import org.opends.server.extensions.SaltedSHA512PasswordStorageScheme;
055    import org.opends.server.protocols.ldap.LDAPResultCode;
056    import org.opends.server.types.DirectoryException;
057    import org.opends.server.types.DN;
058    import org.opends.server.types.DirectoryEnvironmentConfig;
059    import org.opends.server.types.InitializationException;
060    import org.opends.server.util.SetupUtils;
061    import org.opends.server.util.args.ArgumentException;
062    import org.opends.server.util.args.ArgumentParser;
063    import org.opends.server.util.args.BooleanArgument;
064    import org.opends.server.util.args.FileBasedArgument;
065    import org.opends.server.util.args.IntegerArgument;
066    import org.opends.server.util.args.StringArgument;
067    
068    import static org.opends.server.config.ConfigConstants.*;
069    import static org.opends.messages.ConfigMessages.*;
070    import static org.opends.messages.ExtensionMessages.*;
071    import static org.opends.messages.ProtocolMessages.*;
072    import static org.opends.messages.ToolMessages.*;
073    import static org.opends.server.util.ServerConstants.*;
074    import static org.opends.server.util.StaticUtils.*;
075    import static org.opends.server.tools.ToolConstants.*;
076    
077    
078    
079    /**
080     * This class provides a very basic tool that can be used to configure some of
081     * the most important settings in the Directory Server.  This configuration is
082     * performed by editing the server's configuration files and therefore the
083     * Directory Server must be offline.  This utility will be used during the
084     * Directory Server installation process.
085     * <BR><BR>
086     * The options that this tool can currently set include:
087     * <BR>
088     * <UL>
089     *   <LI>The port on which the server will listen for LDAP communication</LI>
090     *   <LI>The DN and password for the initial root user.
091     *   <LI>The set of base DNs for user data</LI>
092     * </UL>
093     */
094    public class ConfigureDS
095    {
096      /**
097       * The fully-qualified name of this class.
098       */
099      private static final String CLASS_NAME =
100           "org.opends.server.tools.ConfigureDS";
101    
102    
103    
104      /**
105       * The DN of the configuration entry defining the JE database backend.
106       */
107      private static final String DN_JE_BACKEND =
108           ATTR_BACKEND_ID + "=userRoot," + DN_BACKEND_BASE;
109    
110    
111    
112      /**
113       * The DN of the configuration entry defining the LDAP connection handler.
114       */
115      private static final String DN_LDAP_CONNECTION_HANDLER =
116           "cn=LDAP Connection Handler," + DN_CONNHANDLER_BASE;
117    
118    
119      /**
120       * The DN of the configuration entry defining the LDAPS connection handler.
121       */
122      private static final String DN_LDAPS_CONNECTION_HANDLER =
123           "cn=LDAPS Connection Handler," + DN_CONNHANDLER_BASE;
124    
125      /**
126       * The DN of the configuration entry defining the JMX connection handler.
127       */
128      private static final String DN_JMX_CONNECTION_HANDLER =
129           "cn=JMX Connection Handler," + DN_CONNHANDLER_BASE;
130    
131    
132      /**
133       * The DN of the configuration entry defining the initial root user.
134       */
135      private static final String DN_ROOT_USER =
136           "cn=Directory Manager," + DN_ROOT_DN_CONFIG_BASE;
137    
138      /**
139       * The DN of the Crypto Manager.
140       */
141      private static final String DN_CRYPTO_MANAGER = "cn=Crypto Manager,cn=config";
142    
143    
144    
145      /**
146       * Provides the command-line arguments to the <CODE>configMain</CODE> method
147       * for processing.
148       *
149       * @param  args  The set of command-line arguments provided to this program.
150       */
151      public static void main(String[] args)
152      {
153        int exitCode = configMain(args);
154        if (exitCode != 0)
155        {
156          System.exit(filterExitCode(exitCode));
157        }
158      }
159    
160    
161    
162      /**
163       * Parses the provided command-line arguments and makes the appropriate
164       * changes to the Directory Server configuration.
165       *
166       * @param  args  The command-line arguments provided to this program.
167       *
168       * @return  The exit code from the configuration processing.  A nonzero value
169       *          indicates that there was some kind of problem during the
170       *          configuration processing.
171       */
172      public static int configMain(String[] args)
173      {
174        BooleanArgument   showUsage;
175        BooleanArgument   enableStartTLS;
176        FileBasedArgument rootPasswordFile;
177        IntegerArgument   ldapPort;
178        IntegerArgument   ldapsPort;
179        IntegerArgument   jmxPort;
180        StringArgument    baseDNString;
181        StringArgument    configClass;
182        StringArgument    configFile;
183        StringArgument    rootDNString;
184        StringArgument    rootPassword;
185        StringArgument    keyManagerProviderDN;
186        StringArgument    trustManagerProviderDN;
187        StringArgument    certNickName;
188        StringArgument    keyManagerPath;
189        StringArgument    serverRoot;
190    
191        Message toolDescription = INFO_CONFIGDS_TOOL_DESCRIPTION.get();
192        ArgumentParser argParser = new ArgumentParser(CLASS_NAME, toolDescription,
193                                                      false);
194        try
195        {
196          configFile = new StringArgument("configfile", 'c', "configFile", true,
197                                          false, true,
198                                          INFO_CONFIGFILE_PLACEHOLDER.get(), null,
199                                          null,
200                                          INFO_DESCRIPTION_CONFIG_FILE.get());
201          configFile.setHidden(true);
202          argParser.addArgument(configFile);
203    
204          configClass = new StringArgument("configclass", OPTION_SHORT_CONFIG_CLASS,
205                                 OPTION_LONG_CONFIG_CLASS, false,
206                                 false, true, INFO_CONFIGCLASS_PLACEHOLDER.get(),
207                                 ConfigFileHandler.class.getName(), null,
208                                 INFO_DESCRIPTION_CONFIG_CLASS.get());
209          configClass.setHidden(true);
210          argParser.addArgument(configClass);
211    
212          ldapPort = new IntegerArgument("ldapport", OPTION_SHORT_PORT,
213                                        "ldapPort", false, false,
214                                         true, INFO_LDAPPORT_PLACEHOLDER.get(), 389,
215                                         null, true, 1,
216                                         true, 65535,
217                                         INFO_CONFIGDS_DESCRIPTION_LDAP_PORT.get());
218          argParser.addArgument(ldapPort);
219    
220          ldapsPort = new IntegerArgument("ldapsPort", 'P', "ldapsPort", false,
221              false, true, INFO_LDAPPORT_PLACEHOLDER.get(), 636, null, true, 1,
222              true, 65535,
223              INFO_CONFIGDS_DESCRIPTION_LDAPS_PORT.get());
224          argParser.addArgument(ldapsPort);
225    
226          enableStartTLS = new BooleanArgument("enableStartTLS",
227              OPTION_SHORT_START_TLS, "enableStartTLS",
228              INFO_CONFIGDS_DESCRIPTION_ENABLE_START_TLS.get());
229          argParser.addArgument(enableStartTLS);
230    
231          jmxPort = new IntegerArgument("jmxport", 'x', "jmxPort", false, false,
232              true, INFO_JMXPORT_PLACEHOLDER.get(), SetupUtils.getDefaultJMXPort(),
233              null, true, 1,
234              true, 65535,
235              INFO_CONFIGDS_DESCRIPTION_JMX_PORT.get());
236          argParser.addArgument(jmxPort);
237    
238          keyManagerProviderDN = new StringArgument("keymanagerproviderdn",
239              'k',
240              "keyManagerProviderDN",
241              false, false,
242              true, INFO_KEY_MANAGER_PROVIDER_DN_PLACEHOLDER.get(),
243              null,
244              null,
245              INFO_CONFIGDS_DESCRIPTION_KEYMANAGER_PROVIDER_DN.get());
246          argParser.addArgument(keyManagerProviderDN);
247    
248          trustManagerProviderDN = new StringArgument("trustmanagerproviderdn",
249              't',
250              "trustManagerProviderDN",
251              false, false,
252              true, INFO_TRUST_MANAGER_PROVIDER_DN_PLACEHOLDER.get(),
253              null,
254              null,
255              INFO_CONFIGDS_DESCRIPTION_TRUSTMANAGER_PROVIDER_DN.get());
256          argParser.addArgument(trustManagerProviderDN);
257    
258          keyManagerPath = new StringArgument("keymanagerpath",
259              'm',
260              "keyManagerPath",
261              false, false, true,
262              INFO_KEY_MANAGER_PATH_PLACEHOLDER.get(),
263              null,
264              null,
265              INFO_CONFIGDS_DESCRIPTION_KEYMANAGER_PATH.get());
266          argParser.addArgument(keyManagerPath);
267    
268          certNickName = new StringArgument("certnickname",
269              'a',
270              "certNickName",
271              false, false,
272              true, INFO_NICKNAME_PLACEHOLDER.get(),
273              null,
274              null,
275              INFO_CONFIGDS_DESCRIPTION_CERTNICKNAME.get());
276          argParser.addArgument(certNickName);
277    
278          baseDNString = new StringArgument(
279              "basedn", OPTION_SHORT_BASEDN,
280              OPTION_LONG_BASEDN, false, true,
281              true, INFO_BASEDN_PLACEHOLDER.get(),
282              "dc=example,dc=com",
283              null,
284              INFO_CONFIGDS_DESCRIPTION_BASE_DN.get());
285          argParser.addArgument(baseDNString);
286    
287          rootDNString = new StringArgument(
288              "rootdn", OPTION_SHORT_ROOT_USER_DN,
289              OPTION_LONG_ROOT_USER_DN, false, false,
290              true, INFO_ROOT_USER_DN_PLACEHOLDER.get(),
291              "cn=Directory Manager", null,
292              INFO_CONFIGDS_DESCRIPTION_ROOT_DN.get());
293          argParser.addArgument(rootDNString);
294    
295          rootPassword = new StringArgument(
296              "rootpw", OPTION_SHORT_BINDPWD,
297              "rootPassword", false,
298              false, true, INFO_ROOT_USER_PWD_PLACEHOLDER.get(), null, null,
299              INFO_CONFIGDS_DESCRIPTION_ROOT_PW.get());
300          argParser.addArgument(rootPassword);
301    
302          rootPasswordFile = new FileBasedArgument(
303              "rootpwfile",
304              OPTION_SHORT_BINDPWD_FILE,
305              "rootPasswordFile", false, false,
306              INFO_FILE_PLACEHOLDER.get(), null, null,
307              INFO_CONFIGDS_DESCRIPTION_ROOT_PW_FILE.get());
308          argParser.addArgument(rootPasswordFile);
309    
310          showUsage = new BooleanArgument("showusage", OPTION_SHORT_HELP,
311                                          OPTION_LONG_HELP,
312                                          INFO_DESCRIPTION_USAGE.get());
313          argParser.addArgument(showUsage);
314          argParser.setUsageArgument(showUsage);
315    
316          serverRoot = new StringArgument("serverRoot",
317                  ToolConstants.OPTION_SHORT_SERVER_ROOT,
318                  ToolConstants.OPTION_LONG_SERVER_ROOT,
319                  false, false, true, INFO_SERVER_ROOT_DIR_PLACEHOLDER.get(), null,
320                  null, null);
321          serverRoot.setHidden(true);
322          argParser.addArgument(serverRoot);
323        }
324        catch (ArgumentException ae)
325        {
326          Message message = ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage());
327          System.err.println(wrapText(message, MAX_LINE_WIDTH));
328          return 1;
329        }
330    
331    
332        // Parse the command-line arguments provided to the program.
333        try
334        {
335          argParser.parseArguments(args);
336        }
337        catch (ArgumentException ae)
338        {
339          Message message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage());
340    
341          System.err.println(wrapText(message, MAX_LINE_WIDTH));
342          System.err.println(argParser.getUsage());
343          return LDAPResultCode.CLIENT_SIDE_PARAM_ERROR;
344        }
345    
346    
347        // If we should just display usage or version information,
348        // then print it and exit.
349        if (argParser.usageOrVersionDisplayed())
350        {
351          return 0;
352        }
353    
354    
355        // Make sure that the user actually tried to configure something.
356        if (! (baseDNString.isPresent() || ldapPort.isPresent() ||
357            jmxPort.isPresent() || rootDNString.isPresent()))
358        {
359          Message message = ERR_CONFIGDS_NO_CONFIG_CHANGES.get();
360          System.err.println(wrapText(message, MAX_LINE_WIDTH));
361          System.err.println(argParser.getUsage());
362          return 1;
363        }
364    
365        try
366        {
367          Set<Integer> ports = new HashSet<Integer>();
368          if (ldapPort.isPresent())
369          {
370            ports.add(ldapPort.getIntValue());
371          }
372          if (ldapsPort.isPresent())
373          {
374            if (ports.contains(ldapsPort.getIntValue()))
375            {
376              Message message = ERR_CONFIGDS_PORT_ALREADY_SPECIFIED.get(
377                      String.valueOf(ldapsPort.getIntValue()));
378              System.err.println(wrapText(message, MAX_LINE_WIDTH));
379              System.err.println(argParser.getUsage());
380              return 1;
381            }
382            else
383            {
384              ports.add(ldapsPort.getIntValue());
385            }
386          }
387          if (jmxPort.isPresent())
388          {
389            if (ports.contains(jmxPort.getIntValue()))
390            {
391              Message message = ERR_CONFIGDS_PORT_ALREADY_SPECIFIED.get(
392                      String.valueOf(jmxPort.getIntValue()));
393              System.err.println(wrapText(message, MAX_LINE_WIDTH));
394              System.err.println(argParser.getUsage());
395              return 1;
396            }
397            else
398            {
399              ports.add(jmxPort.getIntValue());
400            }
401          }
402        }
403        catch (ArgumentException ae)
404        {
405          Message message = ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage());
406          System.err.println(wrapText(message, MAX_LINE_WIDTH));
407          return 1;
408        }
409    
410        if (serverRoot.isPresent()) {
411          DirectoryEnvironmentConfig env = DirectoryServer.getEnvironmentConfig();
412          String root = serverRoot.getValue();
413          try {
414            env.setServerRoot(new File(serverRoot.getValue()));
415          } catch (InitializationException e) {
416            ERR_INITIALIZE_SERVER_ROOT.get(root, e.getMessageObject());
417          }
418        }
419    
420        // Initialize the Directory Server configuration handler using the
421        // information that was provided.
422        DirectoryServer directoryServer = DirectoryServer.getInstance();
423        directoryServer.bootstrapClient();
424    
425        try
426        {
427          directoryServer.initializeJMX();
428        }
429        catch (Exception e)
430        {
431          Message message = ERR_CONFIGDS_CANNOT_INITIALIZE_JMX.get(
432                  String.valueOf(configFile.getValue()),
433                  e.getMessage());
434          System.err.println(wrapText(message, MAX_LINE_WIDTH));
435          return 1;
436        }
437    
438        try
439        {
440          directoryServer.initializeConfiguration(configClass.getValue(),
441                                                  configFile.getValue());
442        }
443        catch (Exception e)
444        {
445          Message message = ERR_CONFIGDS_CANNOT_INITIALIZE_CONFIG.get(
446                  String.valueOf(configFile.getValue()),
447                  e.getMessage());
448          System.err.println(wrapText(message, MAX_LINE_WIDTH));
449          return 1;
450        }
451    
452        try
453        {
454          directoryServer.initializeSchema();
455        }
456        catch (Exception e)
457        {
458          Message message = ERR_CONFIGDS_CANNOT_INITIALIZE_SCHEMA.get(
459                  String.valueOf(configFile.getValue()),
460                  e.getMessage());
461          System.err.println(wrapText(message, MAX_LINE_WIDTH));
462          return 1;
463        }
464    
465    
466        // Make sure that we can get an exclusive lock for the Directory Server, so
467        // that no other operation will be allowed while this is in progress.
468        String serverLockFileName = LockFileManager.getServerLockFileName();
469        StringBuilder failureReason = new StringBuilder();
470        if (! LockFileManager.acquireExclusiveLock(serverLockFileName,
471                                                   failureReason))
472        {
473          Message message = ERR_CONFIGDS_CANNOT_ACQUIRE_SERVER_LOCK.get(
474                  String.valueOf(serverLockFileName),
475                  String.valueOf(failureReason));
476          System.err.println(wrapText(message, MAX_LINE_WIDTH));
477          return 1;
478        }
479    
480    
481        try
482        {
483          // If one or more base DNs were provided, then make sure that they can be
484          // parsed as valid DNs.
485          LinkedList<DN> baseDNs = null;
486          if (baseDNString.isPresent())
487          {
488            baseDNs = new LinkedList<DN>();
489            for (String dnString : baseDNString.getValues())
490            {
491              try
492              {
493                baseDNs.add(DN.decode(dnString));
494              }
495              catch (DirectoryException de)
496              {
497                Message message = ERR_CONFIGDS_CANNOT_PARSE_BASE_DN.get(
498                        String.valueOf(dnString),
499                        de.getMessageObject());
500                System.err.println(wrapText(message, MAX_LINE_WIDTH));
501                return 1;
502              }
503            }
504          }
505    
506    
507          // If a root user DN was provided, then make sure it can be parsed.  Also,
508          // make sure that either a password or password file was specified.
509          DN     rootDN = null;
510          String rootPW = null;
511          if (rootDNString.isPresent())
512          {
513            try
514            {
515              rootDN = DN.decode(rootDNString.getValue());
516            }
517            catch (DirectoryException de)
518            {
519              Message message = ERR_CONFIGDS_CANNOT_PARSE_ROOT_DN.get(
520                      String.valueOf(rootDNString.getValue()),
521                      de.getMessageObject());
522              System.err.println(wrapText(message, MAX_LINE_WIDTH));
523              return 1;
524            }
525    
526            if (rootPassword.isPresent())
527            {
528              rootPW = rootPassword.getValue();
529            }
530            else if (rootPasswordFile.isPresent())
531            {
532              rootPW = rootPasswordFile.getValue();
533            }
534            else
535            {
536              Message message = ERR_CONFIGDS_NO_ROOT_PW.get();
537              System.err.println(wrapText(message, MAX_LINE_WIDTH));
538              return 1;
539            }
540          }
541    
542    
543          // Get the Directory Server configuration handler and use it to make the
544          // appropriate configuration changes.
545          ConfigHandler configHandler = directoryServer.getConfigHandler();
546    
547    
548          // Check that the key manager provided is valid.
549          if (keyManagerProviderDN.isPresent())
550          {
551            DN dn = null;
552            try
553            {
554              dn = DN.decode(keyManagerProviderDN.getValue());
555            }
556            catch (DirectoryException de)
557            {
558              Message message =
559                      ERR_CONFIGDS_CANNOT_PARSE_KEYMANAGER_PROVIDER_DN.get(
560                              keyManagerProviderDN.getValue(),
561                              de.getMessageObject());
562              System.err.println(wrapText(message, MAX_LINE_WIDTH));
563              return 1;
564            }
565    
566            try
567            {
568              configHandler.getConfigEntry(dn);
569            }
570            catch (Exception e)
571            {
572              Message message = ERR_CONFIG_KEYMANAGER_CANNOT_GET_BASE.get(
573                  String.valueOf(e));
574              System.err.println(wrapText(message, MAX_LINE_WIDTH));
575              return 1;
576            }
577          }
578    
579          // Check that the trust manager provided is valid.
580          if (trustManagerProviderDN.isPresent())
581          {
582            DN dn = null;
583            try
584            {
585              dn = DN.decode(trustManagerProviderDN.getValue());
586            }
587            catch (DirectoryException de)
588            {
589              Message message = ERR_CONFIGDS_CANNOT_PARSE_TRUSTMANAGER_PROVIDER_DN.
590                      get(trustManagerProviderDN.getValue(), de.getMessageObject());
591              System.err.println(wrapText(message, MAX_LINE_WIDTH));
592              return 1;
593            }
594    
595            try
596            {
597              configHandler.getConfigEntry(dn);
598            }
599            catch (Exception e)
600            {
601              Message message = ERR_CONFIG_TRUSTMANAGER_CANNOT_GET_BASE.get(
602                    String.valueOf(e));
603              System.err.println(wrapText(message, MAX_LINE_WIDTH));
604              return 1;
605            }
606          }
607    
608          // Check that the keystore path values are valid.
609          if (keyManagerPath.isPresent())
610          {
611            if (!keyManagerProviderDN.isPresent())
612            {
613              Message message = ERR_CONFIGDS_KEYMANAGER_PROVIDER_DN_REQUIRED.get(
614                      keyManagerProviderDN.getLongIdentifier(),
615                  keyManagerPath.getLongIdentifier());
616              System.err.println(wrapText(message, MAX_LINE_WIDTH));
617              return 1;
618            }
619          }
620    
621          // If one or more base DNs were specified, then update the config
622          // accordingly.
623          if (baseDNs != null)
624          {
625            try
626            {
627              DN jeBackendDN = DN.decode(DN_JE_BACKEND);
628              ConfigEntry configEntry = configHandler.getConfigEntry(jeBackendDN);
629    
630              DNConfigAttribute baseDNAttr =
631                   new DNConfigAttribute(
632                           ATTR_BACKEND_BASE_DN,
633                           INFO_CONFIG_BACKEND_ATTR_DESCRIPTION_BASE_DNS.get(),
634                                         true, true, false, baseDNs);
635              configEntry.putConfigAttribute(baseDNAttr);
636            }
637            catch (Exception e)
638            {
639              Message message = ERR_CONFIGDS_CANNOT_UPDATE_BASE_DN.get(
640                      String.valueOf(e));
641              System.err.println(wrapText(message, MAX_LINE_WIDTH));
642              return 1;
643            }
644          }
645    
646    
647          // If an LDAP port was specified, then update the config accordingly.
648          if (ldapPort.isPresent())
649          {
650            try
651            {
652              DN ldapListenerDN = DN.decode(DN_LDAP_CONNECTION_HANDLER);
653              ConfigEntry configEntry =
654                   configHandler.getConfigEntry(ldapListenerDN);
655    
656    
657              IntegerConfigAttribute portAttr =
658                   new IntegerConfigAttribute(ATTR_LISTEN_PORT,
659                           INFO_LDAP_CONNHANDLER_DESCRIPTION_LISTEN_PORT.get(),
660                                              true, false, true, true, 1, true,
661                                              65535, ldapPort.getIntValue());
662              configEntry.putConfigAttribute(portAttr);
663            }
664            catch (Exception e)
665            {
666              Message message = ERR_CONFIGDS_CANNOT_UPDATE_LDAP_PORT.get(
667                      String.valueOf(e));
668              System.err.println(wrapText(message, MAX_LINE_WIDTH));
669              return 1;
670            }
671          }
672    
673    //    If an LDAPS port was specified, then update the config accordingly.
674          if (ldapsPort.isPresent())
675          {
676            try
677            {
678              DN ldapListenerDN = DN.decode(DN_LDAPS_CONNECTION_HANDLER);
679              ConfigEntry configEntry =
680                   configHandler.getConfigEntry(ldapListenerDN);
681    
682    
683              IntegerConfigAttribute portAttr =
684                   new IntegerConfigAttribute(ATTR_LISTEN_PORT,
685                           INFO_LDAP_CONNHANDLER_DESCRIPTION_LISTEN_PORT.get(),
686                                              true, false, true, true, 1, true,
687                                              65535, ldapsPort.getIntValue());
688              configEntry.putConfigAttribute(portAttr);
689    
690              BooleanConfigAttribute enablePortAttr =
691                new BooleanConfigAttribute(ATTR_CONNECTION_HANDLER_ENABLED,
692                    INFO_LDAPS_CONNHANDLER_DESCRIPTION_ENABLE.get(),
693                        true, true);
694              configEntry.putConfigAttribute(enablePortAttr);
695            }
696            catch (Exception e)
697            {
698              Message message = ERR_CONFIGDS_CANNOT_UPDATE_LDAPS_PORT.get(
699                      String.valueOf(e));
700              System.err.println(wrapText(message, MAX_LINE_WIDTH));
701              return 1;
702            }
703          }
704    
705    //    If an JMX port was specified, then update the config accordingly.
706          if (jmxPort.isPresent())
707          {
708            try
709            {
710              DN jmxListenerDN = DN.decode(DN_JMX_CONNECTION_HANDLER);
711              ConfigEntry configEntry =
712                   configHandler.getConfigEntry(jmxListenerDN);
713    
714              IntegerConfigAttribute portAttr =
715                   new IntegerConfigAttribute(
716                           ATTR_LISTEN_PORT,
717                           INFO_JMX_CONNHANDLER_DESCRIPTION_LISTEN_PORT.get(),
718                           true, false, true, true, 1, true,
719                           65535, jmxPort.getIntValue());
720              configEntry.putConfigAttribute(portAttr);
721    
722              BooleanConfigAttribute enablePortAttr =
723                new BooleanConfigAttribute(ATTR_CONNECTION_HANDLER_ENABLED,
724                    INFO_JMX_CONNHANDLER_DESCRIPTION_ENABLE.get(),
725                        true, true);
726              configEntry.putConfigAttribute(enablePortAttr);
727            }
728            catch (Exception e)
729            {
730              Message message = ERR_CONFIGDS_CANNOT_UPDATE_JMX_PORT.get(
731                      String.valueOf(e));
732              System.err.println(wrapText(message, MAX_LINE_WIDTH));
733              return 1;
734            }
735          }
736    
737          // Start TLS configuration
738          if (enableStartTLS.isPresent())
739          {
740            try
741            {
742              DN ldapListenerDN = DN.decode(DN_LDAP_CONNECTION_HANDLER);
743              ConfigEntry configEntry =
744                   configHandler.getConfigEntry(ldapListenerDN);
745    
746    
747              BooleanConfigAttribute startTLS =
748                new BooleanConfigAttribute(ATTR_ALLOW_STARTTLS,
749                    INFO_LDAP_CONNHANDLER_DESCRIPTION_ALLOW_STARTTLS.get(),
750                        true, true);
751              configEntry.putConfigAttribute(startTLS);
752            }
753            catch (Exception e)
754            {
755              Message message = ERR_CONFIGDS_CANNOT_ENABLE_STARTTLS.get(
756                      String.valueOf(e));
757              System.err.println(wrapText(message, MAX_LINE_WIDTH));
758              return 1;
759            }
760          }
761    
762          // Key manager provider
763          if (keyManagerProviderDN.isPresent())
764          {
765            if (enableStartTLS.isPresent() || ldapsPort.isPresent())
766            {
767              try
768              {
769                // Enable the key manager
770                DN dn = DN.decode(keyManagerProviderDN.getValue());
771                ConfigEntry configEntry = configHandler.getConfigEntry(dn);
772    
773                BooleanConfigAttribute enableAttr =
774                  new BooleanConfigAttribute(ATTR_KEYMANAGER_ENABLED,
775                      INFO_CONFIG_KEYMANAGER_DESCRIPTION_ENABLED.get(),
776                          true, true);
777                configEntry.putConfigAttribute(enableAttr);
778              }
779              catch (Exception e)
780              {
781                Message message = ERR_CONFIGDS_CANNOT_ENABLE_KEYMANAGER.get(
782                        String.valueOf(e));
783                System.err.println(wrapText(message, MAX_LINE_WIDTH));
784                return 1;
785              }
786            }
787    
788            try
789            {
790              if (enableStartTLS.isPresent())
791              {
792                // Use the key manager specified for the LDAP connection handler.
793                DN ldapListenerDN = DN.decode(DN_LDAP_CONNECTION_HANDLER);
794                ConfigEntry configEntry =
795                  configHandler.getConfigEntry(ldapListenerDN);
796    
797                StringConfigAttribute keyManagerProviderAttr =
798                  new StringConfigAttribute(ATTR_KEYMANAGER_DN,
799                          INFO_LDAP_CONNHANDLER_DESCRIPTION_KEYMANAGER_DN.get(),
800                      false, false, true, keyManagerProviderDN.getValue());
801                configEntry.putConfigAttribute(keyManagerProviderAttr);
802              }
803    
804              if (ldapsPort.isPresent())
805              {
806                // Use the key manager specified for the LDAPS connection handler.
807                DN ldapsListenerDN = DN.decode(DN_LDAPS_CONNECTION_HANDLER);
808                ConfigEntry configEntry =
809                  configHandler.getConfigEntry(ldapsListenerDN);
810    
811                StringConfigAttribute keyManagerProviderAttr =
812                  new StringConfigAttribute(ATTR_KEYMANAGER_DN,
813                      INFO_LDAP_CONNHANDLER_DESCRIPTION_KEYMANAGER_DN.get(),
814                          false, false,
815                      true, keyManagerProviderDN.getValue());
816                configEntry.putConfigAttribute(keyManagerProviderAttr);
817              }
818            }
819            catch (Exception e)
820            {
821              Message message = ERR_CONFIGDS_CANNOT_UPDATE_KEYMANAGER_REFERENCE.get(
822                      String.valueOf(e));
823              System.err.println(wrapText(message, MAX_LINE_WIDTH));
824              return 1;
825            }
826    
827            if (keyManagerPath.isPresent())
828            {
829              try
830              {
831                // Enable the key manager
832                DN dn = DN.decode(keyManagerProviderDN.getValue());
833                ConfigEntry configEntry = configHandler.getConfigEntry(dn);
834    
835                StringConfigAttribute pathAttr =
836                  new StringConfigAttribute(ATTR_KEYSTORE_FILE,
837                      INFO_FILE_KEYMANAGER_DESCRIPTION_FILE.get(), true, true, true,
838                      keyManagerPath.getValue());
839                configEntry.putConfigAttribute(pathAttr);
840              }
841              catch (Exception e)
842              {
843                String message = String.valueOf(e);
844                System.err.println(wrapText(message, MAX_LINE_WIDTH));
845                return 1;
846              }
847            }
848          }
849          if (trustManagerProviderDN.isPresent())
850          {
851            if (enableStartTLS.isPresent() || ldapsPort.isPresent())
852            {
853              // Enable the trust manager
854              try
855              {
856                DN dn = DN.decode(trustManagerProviderDN.getValue());
857                ConfigEntry configEntry = configHandler.getConfigEntry(dn);
858    
859                BooleanConfigAttribute enableAttr =
860                  new BooleanConfigAttribute(ATTR_TRUSTMANAGER_ENABLED,
861                      ERR_CONFIG_TRUSTMANAGER_DESCRIPTION_ENABLED.get(),
862                          true, true);
863                configEntry.putConfigAttribute(enableAttr);
864              }
865              catch (Exception e)
866              {
867                Message message = ERR_CONFIGDS_CANNOT_ENABLE_TRUSTMANAGER.get(
868                        String.valueOf(e));
869                System.err.println(wrapText(message, MAX_LINE_WIDTH));
870                return 1;
871              }
872            }
873    
874            try
875            {
876              if (enableStartTLS.isPresent())
877              {
878                // Use the trust manager specified for the LDAP connection handler.
879                DN ldapListenerDN = DN.decode(DN_LDAP_CONNECTION_HANDLER);
880                ConfigEntry configEntry =
881                  configHandler.getConfigEntry(ldapListenerDN);
882    
883                StringConfigAttribute trustManagerProviderAttr =
884                  new StringConfigAttribute(ATTR_TRUSTMANAGER_DN,
885                      INFO_LDAP_CONNHANDLER_DESCRIPTION_TRUSTMANAGER_DN.get(),
886                          false, false,
887                      true, trustManagerProviderDN.getValue());
888                configEntry.putConfigAttribute(trustManagerProviderAttr);
889              }
890    
891              if (ldapsPort.isPresent())
892              {
893                // Use the trust manager specified for the LDAPS connection handler.
894                DN ldapsListenerDN = DN.decode(DN_LDAPS_CONNECTION_HANDLER);
895                ConfigEntry configEntry =
896                  configHandler.getConfigEntry(ldapsListenerDN);
897    
898                StringConfigAttribute trustManagerProviderAttr =
899                  new StringConfigAttribute(ATTR_TRUSTMANAGER_DN,
900                      INFO_LDAP_CONNHANDLER_DESCRIPTION_TRUSTMANAGER_DN.get(),
901                          false, false,
902                      true, trustManagerProviderDN.getValue());
903                configEntry.putConfigAttribute(trustManagerProviderAttr);
904              }
905            }
906            catch (Exception e)
907            {
908              Message message =
909                      ERR_CONFIGDS_CANNOT_UPDATE_TRUSTMANAGER_REFERENCE.get(
910                              String.valueOf(e));
911              System.err.println(wrapText(message, MAX_LINE_WIDTH));
912              return 1;
913            }
914          }
915    
916          if (certNickName.isPresent())
917          {
918            try
919            {
920              StringConfigAttribute certNickNameAttr =
921                new StringConfigAttribute(
922                        ATTR_SSL_CERT_NICKNAME,
923                        INFO_LDAP_CONNHANDLER_DESCRIPTION_SSL_CERT_NICKNAME.get(),
924                    false, false, true, certNickName.getValue());
925    
926              if (ldapPort.isPresent())
927              {
928                // Use the key manager specified for the LDAP connection handler.
929                DN ldapListenerDN = DN.decode(DN_LDAP_CONNECTION_HANDLER);
930                ConfigEntry configEntry =
931                  configHandler.getConfigEntry(ldapListenerDN);
932    
933                configEntry.putConfigAttribute(certNickNameAttr);
934              }
935    
936              if (ldapsPort.isPresent())
937              {
938                // Use the key manager specified for the LDAPS connection handler.
939                DN ldapsListenerDN = DN.decode(DN_LDAPS_CONNECTION_HANDLER);
940                ConfigEntry configEntry =
941                  configHandler.getConfigEntry(ldapsListenerDN);
942    
943                configEntry.putConfigAttribute(certNickNameAttr);
944              }
945    
946              if (jmxPort.isPresent())
947              {
948                certNickNameAttr = new StringConfigAttribute(ATTR_SSL_CERT_NICKNAME,
949                    INFO_JMX_CONNHANDLER_DESCRIPTION_SSL_CERT_NICKNAME.get(),
950                        false, false, true, certNickName.getValue());
951    
952                // Use the key manager specified for the JMX connection handler.
953                DN jmxListenerDN = DN.decode(DN_JMX_CONNECTION_HANDLER);
954                ConfigEntry configEntry =
955                  configHandler.getConfigEntry(jmxListenerDN);
956    
957                configEntry.putConfigAttribute(certNickNameAttr);
958              }
959            }
960            catch (Exception e)
961            {
962              Message message = ERR_CONFIGDS_CANNOT_UPDATE_CERT_NICKNAME.get(
963                      String.valueOf(e));
964              System.err.println(wrapText(message, MAX_LINE_WIDTH));
965              return 1;
966            }
967          }
968    
969          // If a root user DN and password were specified, then update the config
970          // accordingly.
971          if (rootDN != null)
972          {
973            try
974            {
975              DN rootUserDN = DN.decode(DN_ROOT_USER);
976              ConfigEntry configEntry = configHandler.getConfigEntry(rootUserDN);
977    
978              DNConfigAttribute bindDNAttr =
979                   new DNConfigAttribute(
980                           ATTR_ROOTDN_ALTERNATE_BIND_DN,
981                           INFO_CONFIG_ROOTDN_DESCRIPTION_ALTERNATE_BIND_DN.get(),
982                           false, true, false,
983                                         rootDN);
984              configEntry.putConfigAttribute(bindDNAttr);
985    
986              byte[] rootPWBytes = getBytes(rootPW);
987              String encodedPassword =
988                   SaltedSHA512PasswordStorageScheme.encodeOffline(rootPWBytes);
989              StringConfigAttribute bindPWAttr =
990                   new StringConfigAttribute(ATTR_USER_PASSWORD, Message.EMPTY,
991                                             false, false, false, encodedPassword);
992              configEntry.putConfigAttribute(bindPWAttr);
993            }
994            catch (Exception e)
995            {
996              Message message = ERR_CONFIGDS_CANNOT_UPDATE_ROOT_USER.get(
997                      String.valueOf(e));
998              System.err.println(wrapText(message, MAX_LINE_WIDTH));
999              return 1;
1000            }
1001          }
1002    
1003    
1004          // Check that the cipher specified is supported.  This is intended to
1005          // fix issues with JVM that do not support the default cipher (see
1006          // issue 3075 for instance).
1007          CryptoManagerCfgDefn cryptoManager = CryptoManagerCfgDefn.getInstance();
1008          StringPropertyDefinition prop =
1009            cryptoManager.getKeyWrappingTransformationPropertyDefinition();
1010          String defaultCipher = null;
1011          DefaultBehaviorProvider p = prop.getDefaultBehaviorProvider();
1012          if (p instanceof DefinedDefaultBehaviorProvider)
1013          {
1014            Collection<?> defaultValues =
1015              ((DefinedDefaultBehaviorProvider)p).getDefaultValues();
1016            if (!defaultValues.isEmpty())
1017            {
1018              defaultCipher = defaultValues.iterator().next().toString();
1019            }
1020          }
1021          if (defaultCipher != null)
1022          {
1023            // Check that the default cipher is supported by the JVM.
1024            try
1025            {
1026              Cipher.getInstance(defaultCipher);
1027            }
1028            catch (GeneralSecurityException ex)
1029            {
1030              // The cipher is not supported: try to find an alternative one.
1031              String alternativeCipher = getAlternativeCipher();
1032              if (alternativeCipher != null)
1033              {
1034                try
1035                {
1036                  DN cipherDN = DN.decode(DN_CRYPTO_MANAGER);
1037                  ConfigEntry configEntry = configHandler.getConfigEntry(cipherDN);
1038    
1039                  // Set the alternative cipher
1040                  StringConfigAttribute keyWrappingTransformation =
1041                    new StringConfigAttribute(
1042                        ATTR_CRYPTO_CIPHER_KEY_WRAPPING_TRANSFORMATION,
1043                        Message.EMPTY, false, false, true, alternativeCipher);
1044                  configEntry.putConfigAttribute(keyWrappingTransformation);
1045                }
1046                catch (Exception e)
1047                {
1048                  Message message = ERR_CONFIGDS_CANNOT_UPDATE_CRYPTO_MANAGER.get(
1049                      String.valueOf(e));
1050                  System.err.println(wrapText(message, MAX_LINE_WIDTH));
1051                  return 1;
1052                }
1053              }
1054            }
1055          }
1056    
1057          // Write the updated configuration.
1058          try
1059          {
1060            configHandler.writeUpdatedConfig();
1061    
1062            Message message = INFO_CONFIGDS_WROTE_UPDATED_CONFIG.get();
1063            System.out.println(wrapText(message, MAX_LINE_WIDTH));
1064          }
1065          catch (DirectoryException de)
1066          {
1067            Message message = ERR_CONFIGDS_CANNOT_WRITE_UPDATED_CONFIG.get(
1068                    de.getMessageObject());
1069            System.err.println(wrapText(message, MAX_LINE_WIDTH));
1070            return 1;
1071          }
1072        }
1073        finally
1074        {
1075          LockFileManager.releaseLock(serverLockFileName, failureReason);
1076        }
1077    
1078    
1079        // If we've gotten here, then everything was successful.
1080        return 0;
1081      }
1082    
1083      /**
1084       * Returns a cipher that is supported by the JVM we are running at.
1085       * Returns <CODE>null</CODE> if no alternative cipher could be found.
1086       * @return a cipher that is supported by the JVM we are running at.
1087       */
1088      private static String getAlternativeCipher()
1089      {
1090        final String[] preferredAlternativeCiphers =
1091        {
1092            "RSA/ECB/OAEPWITHSHA1ANDMGF1PADDING",
1093            "RSA/ECB/PKCS1Padding"
1094        };
1095        String alternativeCipher = null;
1096        for (String cipher : preferredAlternativeCiphers)
1097        {
1098          try
1099          {
1100            Cipher.getInstance(cipher);
1101            alternativeCipher = cipher;
1102            break;
1103          }
1104          catch (Throwable t)
1105          {
1106          }
1107        }
1108        return alternativeCipher;
1109      }
1110    }
1111