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.io.OutputStream;
033 import java.io.PrintStream;
034 import java.util.ArrayList;
035 import java.util.concurrent.atomic.AtomicInteger;
036
037 import org.opends.server.controls.PasswordPolicyErrorType;
038 import org.opends.server.controls.PasswordPolicyResponseControl;
039 import org.opends.server.controls.PasswordPolicyWarningType;
040 import org.opends.server.protocols.asn1.ASN1Element;
041 import org.opends.server.protocols.asn1.ASN1OctetString;
042 import org.opends.server.protocols.asn1.ASN1Sequence;
043 import org.opends.server.protocols.ldap.ExtendedRequestProtocolOp;
044 import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp;
045 import org.opends.server.protocols.ldap.LDAPControl;
046 import org.opends.server.protocols.ldap.LDAPMessage;
047 import org.opends.server.protocols.ldap.LDAPResultCode;
048 import org.opends.server.protocols.ldap.UnbindRequestProtocolOp;
049 import org.opends.server.types.DN;
050 import org.opends.server.types.NullOutputStream;
051 import org.opends.server.util.EmbeddedUtils;
052 import org.opends.server.util.args.ArgumentException;
053 import org.opends.server.util.args.ArgumentParser;
054 import org.opends.server.util.args.BooleanArgument;
055 import org.opends.server.util.args.FileBasedArgument;
056 import org.opends.server.util.args.IntegerArgument;
057 import org.opends.server.util.args.StringArgument;
058
059 import static org.opends.server.extensions.ExtensionsConstants.*;
060 import static org.opends.messages.ToolMessages.*;
061 import static org.opends.server.util.ServerConstants.*;
062 import static org.opends.server.util.StaticUtils.*;
063 import static org.opends.server.tools.ToolConstants.*;
064
065
066
067 /**
068 * This program provides a utility that uses the LDAP password modify extended
069 * operation to change the password for a user. It exposes the three primary
070 * options available for this operation, which are:
071 *
072 * <UL>
073 * <LI>The user identity whose password should be changed.</LI>
074 * <LI>The current password for the user.</LI>
075 * <LI>The new password for the user.
076 * </UL>
077 *
078 * All of these are optional components that may be included or omitted from the
079 * request.
080 */
081 public class LDAPPasswordModify
082 {
083 /**
084 * The fully-qualified name of this class.
085 */
086 private static final String CLASS_NAME =
087 "org.opends.server.tools.LDAPPasswordModify";
088
089
090
091
092 /**
093 * Parses the command-line arguments, establishes a connection to the
094 * Directory Server, sends the password modify request, and reads the
095 * response.
096 *
097 * @param args The command-line arguments provided to this program.
098 */
099 public static void main(String[] args)
100 {
101 int returnCode = mainPasswordModify(args, true, System.out, System.err);
102 if (returnCode != 0)
103 {
104 System.exit(filterExitCode(returnCode));
105 }
106 }
107
108
109
110 /**
111 * Parses the command-line arguments, establishes a connection to the
112 * Directory Server, sends the password modify request, and reads the
113 * response.
114 *
115 * @param args The command-line arguments provided to this program.
116 *
117 * @return An integer value of zero if everything completed successfully, or
118 * a nonzero value if an error occurred.
119 */
120 public static int mainPasswordModify(String[] args)
121 {
122 return mainPasswordModify(args, true, System.out, System.err);
123 }
124
125
126
127 /**
128 * Parses the command-line arguments, establishes a connection to the
129 * Directory Server, sends the password modify request, and reads the
130 * response.
131 *
132 * @param args The command-line arguments provided to this
133 * program.
134 * @param initializeServer Indicates whether to initialize the server.
135 * @param outStream The output stream to use for standard output.
136 * @param errStream The output stream to use for standard error.
137 *
138 * @return An integer value of zero if everything completed successfully, or
139 * a nonzero value if an error occurred.
140 */
141 public static int mainPasswordModify(String[] args, boolean initializeServer,
142 OutputStream outStream,
143 OutputStream errStream)
144 {
145 PrintStream out;
146 if (outStream == null)
147 {
148 out = NullOutputStream.printStream();
149 }
150 else
151 {
152 out = new PrintStream(outStream);
153 }
154
155 PrintStream err;
156 if (errStream == null)
157 {
158 err = NullOutputStream.printStream();
159 }
160 else
161 {
162 err = new PrintStream(errStream);
163 }
164
165
166 // Create the arguments that will be used by this program.
167 BooleanArgument provideDNForAuthzID;
168 BooleanArgument showUsage;
169 BooleanArgument sslBlindTrust;
170 BooleanArgument useSSL;
171 BooleanArgument useStartTLS;
172 FileBasedArgument bindPWFile;
173 StringArgument certNickname = null;
174 FileBasedArgument currentPWFile;
175 FileBasedArgument newPWFile;
176 FileBasedArgument sslKeyStorePINFile;
177 FileBasedArgument sslTrustStorePINFile;
178 IntegerArgument ldapPort;
179 StringArgument authzID;
180 StringArgument bindDN;
181 StringArgument bindPW;
182 StringArgument controlStr;
183 StringArgument currentPW;
184 StringArgument ldapHost;
185 StringArgument newPW;
186 StringArgument sslKeyStore;
187 StringArgument sslKeyStorePIN;
188 StringArgument sslTrustStore;
189 StringArgument sslTrustStorePIN;
190 StringArgument propertiesFileArgument;
191 BooleanArgument noPropertiesFileArgument;
192
193
194 // Initialize the argument parser.
195 Message toolDescription = INFO_LDAPPWMOD_TOOL_DESCRIPTION.get();
196 ArgumentParser argParser = new ArgumentParser(CLASS_NAME, toolDescription,
197 false);
198
199 try
200 {
201 propertiesFileArgument = new StringArgument("propertiesFilePath",
202 null, OPTION_LONG_PROP_FILE_PATH,
203 false, false, true, INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
204 INFO_DESCRIPTION_PROP_FILE_PATH.get());
205 argParser.addArgument(propertiesFileArgument);
206 argParser.setFilePropertiesArgument(propertiesFileArgument);
207
208 noPropertiesFileArgument = new BooleanArgument(
209 "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE,
210 INFO_DESCRIPTION_NO_PROP_FILE.get());
211 argParser.addArgument(noPropertiesFileArgument);
212 argParser.setNoPropertiesFileArgument(noPropertiesFileArgument);
213
214 ldapHost = new StringArgument("ldaphost", OPTION_SHORT_HOST,
215 OPTION_LONG_HOST, false, false,
216 true, INFO_HOST_PLACEHOLDER.get(),
217 "127.0.0.1", null,
218 INFO_LDAPPWMOD_DESCRIPTION_HOST.get());
219 ldapHost.setPropertyName(OPTION_LONG_HOST);
220 argParser.addArgument(ldapHost);
221
222
223 ldapPort = new IntegerArgument(
224 "ldapport", OPTION_SHORT_PORT,
225 OPTION_LONG_PORT, false, false,
226 true, INFO_PORT_PLACEHOLDER.get(), 389,
227 null, true, 1, true,
228 65535, INFO_LDAPPWMOD_DESCRIPTION_PORT.get());
229 ldapPort.setPropertyName(OPTION_LONG_PORT);
230 argParser.addArgument(ldapPort);
231
232
233 useSSL = new BooleanArgument("usessl", OPTION_SHORT_USE_SSL,
234 OPTION_LONG_USE_SSL,
235 INFO_LDAPPWMOD_DESCRIPTION_USE_SSL.get());
236 useSSL.setPropertyName(OPTION_LONG_USE_SSL);
237 argParser.addArgument(useSSL);
238
239
240 useStartTLS = new BooleanArgument("usestarttls", OPTION_SHORT_START_TLS,
241 OPTION_LONG_START_TLS,
242 INFO_LDAPPWMOD_DESCRIPTION_USE_STARTTLS.get());
243 useStartTLS.setPropertyName(OPTION_LONG_START_TLS);
244 argParser.addArgument(useStartTLS);
245
246
247 bindDN = new StringArgument("binddn", OPTION_SHORT_BINDDN,
248 OPTION_LONG_BINDDN, false, false, true,
249 INFO_BINDDN_PLACEHOLDER.get(), null, null,
250 INFO_LDAPPWMOD_DESCRIPTION_BIND_DN.get());
251 bindDN.setPropertyName(OPTION_LONG_BINDDN);
252 argParser.addArgument(bindDN);
253
254
255 bindPW = new StringArgument("bindpw", OPTION_SHORT_BINDPWD,
256 OPTION_LONG_BINDPWD, false, false,
257 true, INFO_BINDPWD_PLACEHOLDER.get(), null,
258 null,
259 INFO_LDAPPWMOD_DESCRIPTION_BIND_PW.get());
260 bindPW.setPropertyName(OPTION_LONG_BINDPWD);
261 argParser.addArgument(bindPW);
262
263
264 bindPWFile =
265 new FileBasedArgument("bindpwfile", OPTION_SHORT_BINDPWD_FILE,
266 OPTION_LONG_BINDPWD_FILE, false,
267 false, INFO_BINDPWD_FILE_PLACEHOLDER.get(),
268 null, null,
269 INFO_LDAPPWMOD_DESCRIPTION_BIND_PW_FILE.get());
270 bindPWFile.setPropertyName(OPTION_LONG_BINDPWD_FILE);
271 argParser.addArgument(bindPWFile);
272
273
274 authzID = new StringArgument("authzid", 'a', "authzID", false, false,
275 true, INFO_PROXYAUTHID_PLACEHOLDER.get(),
276 null, null,
277 INFO_LDAPPWMOD_DESCRIPTION_AUTHZID.get());
278 authzID.setPropertyName("authzID");
279 argParser.addArgument(authzID);
280
281
282 provideDNForAuthzID =
283 new BooleanArgument("providednforauthzid", 'A',"provideDNForAuthzID",
284 INFO_LDAPPWMOD_DESCRIPTION_PROVIDE_DN_FOR_AUTHZID.get());
285 provideDNForAuthzID.setPropertyName("provideDNForAuthzID");
286 argParser.addArgument(provideDNForAuthzID);
287
288
289 newPW = new StringArgument("newpw", 'n', "newPassword", false, false,
290 true, INFO_NEW_PASSWORD_PLACEHOLDER.get(),
291 null, null,
292 INFO_LDAPPWMOD_DESCRIPTION_NEWPW.get());
293 newPW.setPropertyName("newPassword");
294 argParser.addArgument(newPW);
295
296
297 newPWFile = new FileBasedArgument(
298 "newpwfile", 'N', "newPasswordFile",
299 false, false, INFO_FILE_PLACEHOLDER.get(), null, null,
300 INFO_LDAPPWMOD_DESCRIPTION_NEWPWFILE.get());
301 newPWFile.setPropertyName("newPasswordFile");
302 argParser.addArgument(newPWFile);
303
304
305 currentPW =
306 new StringArgument("currentpw", 'c', "currentPassword", false, false,
307 true, INFO_CURRENT_PASSWORD_PLACEHOLDER.get(),
308 null, null,
309 INFO_LDAPPWMOD_DESCRIPTION_CURRENTPW.get());
310 currentPW.setPropertyName("currentPassword");
311 argParser.addArgument(currentPW);
312
313
314 currentPWFile =
315 new FileBasedArgument(
316 "currentpwfile", 'C', "currentPasswordFile",
317 false, false, INFO_FILE_PLACEHOLDER.get(), null, null,
318 INFO_LDAPPWMOD_DESCRIPTION_CURRENTPWFILE.get());
319 currentPWFile.setPropertyName("currentPasswordFile");
320 argParser.addArgument(currentPWFile);
321
322
323 sslBlindTrust =
324 new BooleanArgument("blindtrust", 'X', "trustAll",
325 INFO_LDAPPWMOD_DESCRIPTION_BLIND_TRUST.get());
326 sslBlindTrust.setPropertyName("trustAll");
327 argParser.addArgument(sslBlindTrust);
328
329
330 sslKeyStore =
331 new StringArgument("keystorepath", OPTION_SHORT_KEYSTOREPATH,
332 OPTION_LONG_KEYSTOREPATH, false, false,
333 true, INFO_KEYSTOREPATH_PLACEHOLDER.get(), null,
334 null,
335 INFO_LDAPPWMOD_DESCRIPTION_KEYSTORE.get());
336 sslKeyStore.setPropertyName(OPTION_LONG_KEYSTOREPATH);
337 argParser.addArgument(sslKeyStore);
338
339
340 sslKeyStorePIN =
341 new StringArgument("keystorepassword",
342 OPTION_SHORT_KEYSTORE_PWD,
343 OPTION_LONG_KEYSTORE_PWD ,
344 false, false, true,
345 INFO_KEYSTORE_PWD_PLACEHOLDER.get(),
346 null, null,
347 INFO_LDAPPWMOD_DESCRIPTION_KEYSTORE_PIN.get());
348 sslKeyStorePIN.setPropertyName(OPTION_LONG_KEYSTORE_PWD);
349 argParser.addArgument(sslKeyStorePIN);
350
351
352 sslKeyStorePINFile =
353 new FileBasedArgument(
354 "keystorepasswordfile",
355 OPTION_SHORT_KEYSTORE_PWD_FILE,
356 OPTION_LONG_KEYSTORE_PWD_FILE,
357 false, false, INFO_KEYSTORE_PWD_FILE_PLACEHOLDER.get(),
358 null, null,
359 INFO_LDAPPWMOD_DESCRIPTION_KEYSTORE_PINFILE.get());
360 sslKeyStorePINFile.setPropertyName(OPTION_LONG_KEYSTORE_PWD_FILE);
361 argParser.addArgument(sslKeyStorePINFile);
362
363 certNickname = new StringArgument("certnickname", null, "certNickname",
364 false, false, true, INFO_NICKNAME_PLACEHOLDER.get(), null, null,
365 INFO_DESCRIPTION_CERT_NICKNAME.get());
366 certNickname.setPropertyName("certNickname");
367 argParser.addArgument(certNickname);
368
369
370
371 sslTrustStore =
372 new StringArgument("truststorepath",
373 OPTION_SHORT_TRUSTSTOREPATH,
374 OPTION_LONG_TRUSTSTOREPATH, false,
375 false, true,
376 INFO_TRUSTSTOREPATH_PLACEHOLDER.get(), null, null,
377 INFO_LDAPPWMOD_DESCRIPTION_TRUSTSTORE.get());
378 sslTrustStore.setPropertyName(OPTION_LONG_TRUSTSTOREPATH);
379 argParser.addArgument(sslTrustStore);
380
381
382 sslTrustStorePIN =
383 new StringArgument("truststorepassword", null,
384 OPTION_LONG_TRUSTSTORE_PWD,
385 false, false, true,
386 INFO_TRUSTSTORE_PWD_PLACEHOLDER.get(), null, null,
387 INFO_LDAPPWMOD_DESCRIPTION_TRUSTSTORE_PIN.get());
388 sslTrustStorePIN.setPropertyName(OPTION_LONG_TRUSTSTORE_PWD);
389 argParser.addArgument(sslTrustStorePIN);
390
391
392 sslTrustStorePINFile =
393 new FileBasedArgument("truststorepasswordfile",
394 OPTION_SHORT_TRUSTSTORE_PWD_FILE,
395 OPTION_LONG_TRUSTSTORE_PWD_FILE, false, false,
396 INFO_TRUSTSTORE_PWD_FILE_PLACEHOLDER.get(), null,
397 null, INFO_LDAPPWMOD_DESCRIPTION_TRUSTSTORE_PINFILE.get());
398 sslTrustStorePINFile.setPropertyName(OPTION_LONG_TRUSTSTORE_PWD_FILE);
399 argParser.addArgument(sslTrustStorePINFile);
400
401
402 controlStr =
403 new StringArgument("control", 'J', "control", false, true, true,
404 INFO_LDAP_CONTROL_PLACEHOLDER.get(),
405 null, null, INFO_DESCRIPTION_CONTROLS.get());
406 controlStr.setPropertyName("control");
407 argParser.addArgument(controlStr);
408
409
410 showUsage = new BooleanArgument("help", OPTION_SHORT_HELP,
411 OPTION_LONG_HELP,
412 INFO_DESCRIPTION_USAGE.get());
413 argParser.addArgument(showUsage);
414 argParser.setUsageArgument(showUsage, out);
415 }
416 catch (ArgumentException ae)
417 {
418 Message message = ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage());
419
420 err.println(wrapText(message, MAX_LINE_WIDTH));
421 return 1;
422 }
423
424
425 // Parse the command-line arguments provided to this program.
426 try
427 {
428 argParser.parseArguments(args);
429 }
430 catch (ArgumentException ae)
431 {
432 Message message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage());
433
434 err.println(wrapText(message, MAX_LINE_WIDTH));
435 err.println(argParser.getUsage());
436 return 1;
437 }
438
439
440 // If the usage or version argument was provided,
441 // then we don't need to do anything else.
442 if (argParser.usageOrVersionDisplayed())
443 {
444 return 0;
445 }
446
447
448 // Make sure that the user didn't specify any conflicting arguments.
449 if (bindPW.isPresent() && bindPWFile.isPresent())
450 {
451 Message message = ERR_LDAPPWMOD_CONFLICTING_ARGS.get(
452 bindPW.getLongIdentifier(),
453 bindPWFile.getLongIdentifier());
454 err.println(wrapText(message, MAX_LINE_WIDTH));
455 return 1;
456 }
457
458 if (newPW.isPresent() && newPWFile.isPresent())
459 {
460 Message message = ERR_LDAPPWMOD_CONFLICTING_ARGS.get(
461 newPW.getLongIdentifier(),
462 newPWFile.getLongIdentifier());
463 err.println(wrapText(message, MAX_LINE_WIDTH));
464 return 1;
465 }
466
467 if (currentPW.isPresent() && currentPWFile.isPresent())
468 {
469 Message message = ERR_LDAPPWMOD_CONFLICTING_ARGS.get(
470 currentPW.getLongIdentifier(),
471 currentPWFile.getLongIdentifier());
472 err.println(wrapText(message, MAX_LINE_WIDTH));
473 return 1;
474 }
475
476 if (useSSL.isPresent() && useStartTLS.isPresent())
477 {
478 Message message = ERR_LDAPPWMOD_CONFLICTING_ARGS.get(
479 useSSL.getLongIdentifier(),
480 useStartTLS.getLongIdentifier());
481 err.println(wrapText(message, MAX_LINE_WIDTH));
482 return 1;
483 }
484
485 if (sslKeyStorePIN.isPresent() && sslKeyStorePINFile.isPresent())
486 {
487 Message message = ERR_TOOL_CONFLICTING_ARGS.get(
488 sslKeyStorePIN.getLongIdentifier(),
489 sslKeyStorePINFile.getLongIdentifier());
490 err.println(wrapText(message, MAX_LINE_WIDTH));
491 return 1;
492 }
493
494 if (sslTrustStorePIN.isPresent() && sslTrustStorePINFile.isPresent())
495 {
496 Message message = ERR_TOOL_CONFLICTING_ARGS.get(
497 sslTrustStorePIN.getLongIdentifier(),
498 sslTrustStorePINFile.getLongIdentifier());
499 err.println(wrapText(message, MAX_LINE_WIDTH));
500 return 1;
501 }
502
503
504 // If a bind DN was provided, make sure that a password was given. If a
505 // password was given, make sure a bind DN was provided. If neither were
506 // given, then make sure that an authorization ID and the current password
507 // were provided.
508 if (bindDN.isPresent())
509 {
510 if (! (bindPW.isPresent() || bindPWFile.isPresent()))
511 {
512 Message message = ERR_LDAPPWMOD_BIND_DN_AND_PW_MUST_BE_TOGETHER.get();
513
514 err.println(wrapText(message, MAX_LINE_WIDTH));
515 err.println(argParser.getUsage());
516 return 1;
517 }
518 }
519 else if (bindPW.isPresent() || bindPWFile.isPresent())
520 {
521 Message message = ERR_LDAPPWMOD_BIND_DN_AND_PW_MUST_BE_TOGETHER.get();
522
523 err.println(wrapText(message, MAX_LINE_WIDTH));
524 err.println(argParser.getUsage());
525 return 1;
526 }
527 else
528 {
529 if (provideDNForAuthzID.isPresent())
530 {
531 Message message =
532 ERR_LDAPPWMOD_DEPENDENT_ARGS.get(
533 provideDNForAuthzID.getLongIdentifier(),
534 bindDN.getLongIdentifier());
535 err.println(wrapText(message, MAX_LINE_WIDTH));
536 err.println(argParser.getUsage());
537 return 1;
538 }
539
540 if (! (authzID.isPresent() &&
541 (currentPW.isPresent() || currentPWFile.isPresent())))
542 {
543 Message message =
544 ERR_LDAPPWMOD_ANON_REQUIRES_AUTHZID_AND_CURRENTPW.get();
545 err.println(wrapText(message, MAX_LINE_WIDTH));
546 err.println(argParser.getUsage());
547 return 1;
548 }
549 }
550
551
552 // Get the host and port.
553 String host = ldapHost.getValue();
554 int port;
555 try
556 {
557 port = ldapPort.getIntValue();
558 }
559 catch (Exception e)
560 {
561 // This should never happen.
562 err.println(e);
563 return 1;
564 }
565
566
567 // If a control string was provided, then decode the requested controls.
568 ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
569 if(controlStr.isPresent())
570 {
571 for (String ctrlString : controlStr.getValues())
572 {
573 LDAPControl ctrl = LDAPToolUtils.getControl(ctrlString, err);
574 if(ctrl == null)
575 {
576 Message message = ERR_TOOL_INVALID_CONTROL_STRING.get(ctrlString);
577 err.println(wrapText(message, MAX_LINE_WIDTH));
578 err.println(argParser.getUsage());
579 return 1;
580 }
581 controls.add(ctrl);
582 }
583 }
584
585
586 // Perform a basic Directory Server bootstrap if appropriate.
587 if (initializeServer)
588 {
589 EmbeddedUtils.initializeForClientUse();
590 }
591
592
593 // Establish a connection to the Directory Server.
594 AtomicInteger nextMessageID = new AtomicInteger(1);
595 LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions();
596 connectionOptions.setUseSSL(useSSL.isPresent());
597 connectionOptions.setStartTLS(useStartTLS.isPresent());
598 connectionOptions.setVersionNumber(3);
599 if(connectionOptions.useSSL() || connectionOptions.useStartTLS())
600 {
601 String keyPIN = null;
602 if (sslKeyStorePIN.isPresent())
603 {
604 keyPIN = sslKeyStorePIN.getValue();
605 }
606 else if (sslKeyStorePINFile.isPresent())
607 {
608 keyPIN = sslKeyStorePINFile.getValue();
609 }
610
611 String trustPIN = null;
612 if (sslTrustStorePIN.isPresent())
613 {
614 trustPIN = sslTrustStorePIN.getValue();
615 }
616 else if (sslTrustStorePINFile.isPresent())
617 {
618 trustPIN = sslTrustStorePINFile.getValue();
619 }
620
621 try
622 {
623 String clientAlias;
624 if (certNickname.isPresent())
625 {
626 clientAlias = certNickname.getValue();
627 }
628 else
629 {
630 clientAlias = null;
631 }
632 SSLConnectionFactory sslConnectionFactory = new SSLConnectionFactory();
633 sslConnectionFactory.init(sslBlindTrust.isPresent(),
634 sslKeyStore.getValue(), keyPIN, clientAlias,
635 sslTrustStore.getValue(), trustPIN);
636 connectionOptions.setSSLConnectionFactory(sslConnectionFactory);
637 }
638 catch (Exception e)
639 {
640 Message message =
641 ERR_LDAPPWMOD_ERROR_INITIALIZING_SSL.get(String.valueOf(e));
642 err.println(wrapText(message, MAX_LINE_WIDTH));
643 return 1;
644 }
645 }
646
647 LDAPConnection connection = new LDAPConnection(host, port,
648 connectionOptions, out, err);
649 String dn;
650 String pw;
651 if (bindPW.isPresent())
652 {
653 dn = bindDN.getValue();
654 pw = bindPW.getValue();
655 }
656 else if (bindPWFile.isPresent())
657 {
658 dn = bindDN.getValue();
659 pw = bindPWFile.getValue();
660 }
661 else
662 {
663 dn = null;
664 pw = null;
665 }
666
667 try
668 {
669 connection.connectToHost(dn, pw, nextMessageID);
670 }
671 catch (LDAPConnectionException lce)
672 {
673 Message message = ERR_LDAPPWMOD_CANNOT_CONNECT.get(lce.getMessage());
674 err.println(wrapText(message, MAX_LINE_WIDTH));
675 return lce.getResultCode();
676 }
677
678 LDAPReader reader = connection.getLDAPReader();
679 LDAPWriter writer = connection.getLDAPWriter();
680
681
682 // Construct the password modify request.
683 ArrayList<ASN1Element> requestElements = new ArrayList<ASN1Element>(3);
684 if (authzID.isPresent())
685 {
686 requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_USER_ID,
687 authzID.getValue()));
688 }
689 else if (provideDNForAuthzID.isPresent())
690 {
691 requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_USER_ID,
692 "dn:" + dn));
693 }
694
695 if (currentPW.isPresent())
696 {
697 requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_OLD_PASSWORD,
698 currentPW.getValue()));
699 }
700 else if (currentPWFile.isPresent())
701 {
702 requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_OLD_PASSWORD,
703 currentPWFile.getValue()));
704 }
705 else if (provideDNForAuthzID.isPresent())
706 {
707 requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_OLD_PASSWORD,
708 pw));
709 }
710
711 if (newPW.isPresent())
712 {
713 requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_NEW_PASSWORD,
714 newPW.getValue()));
715 }
716 else if (newPWFile.isPresent())
717 {
718 requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_NEW_PASSWORD,
719 newPWFile.getValue()));
720 }
721
722 ASN1OctetString requestValue =
723 new ASN1OctetString(new ASN1Sequence(requestElements).encode());
724
725 ExtendedRequestProtocolOp extendedRequest =
726 new ExtendedRequestProtocolOp(OID_PASSWORD_MODIFY_REQUEST,
727 requestValue);
728 LDAPMessage requestMessage =
729 new LDAPMessage(nextMessageID.getAndIncrement(), extendedRequest,
730 controls);
731
732
733 // Send the request to the server and read the response.
734 try
735 {
736 writer.writeMessage(requestMessage);
737 }
738 catch (Exception e)
739 {
740 Message message = ERR_LDAPPWMOD_CANNOT_SEND_PWMOD_REQUEST.get(
741 String.valueOf(e));
742 err.println(wrapText(message, MAX_LINE_WIDTH));
743
744 try
745 {
746 requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(),
747 new UnbindRequestProtocolOp());
748 writer.writeMessage(requestMessage);
749 }
750 catch (Exception e2) {}
751
752 try
753 {
754 reader.close();
755 writer.close();
756 } catch (Exception e2) {}
757
758 return 1;
759 }
760
761
762 // Read the response from the server.
763 LDAPMessage responseMessage = null;
764 try
765 {
766 responseMessage = reader.readMessage();
767 }
768 catch (Exception e)
769 {
770 Message message = ERR_LDAPPWMOD_CANNOT_READ_PWMOD_RESPONSE.get(
771 String.valueOf(e));
772 err.println(wrapText(message, MAX_LINE_WIDTH));
773
774 try
775 {
776 requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(),
777 new UnbindRequestProtocolOp());
778 writer.writeMessage(requestMessage);
779 }
780 catch (Exception e2) {}
781
782 try
783 {
784 reader.close();
785 writer.close();
786 } catch (Exception e2) {}
787
788 return 1;
789 }
790
791
792 // Make sure that the response was acceptable.
793 ExtendedResponseProtocolOp extendedResponse =
794 responseMessage.getExtendedResponseProtocolOp();
795 int resultCode = extendedResponse.getResultCode();
796 if (resultCode != LDAPResultCode.SUCCESS)
797 {
798 Message message = ERR_LDAPPWMOD_FAILED.get(resultCode);
799 err.println(wrapText(message, MAX_LINE_WIDTH));
800
801 Message errorMessage = extendedResponse.getErrorMessage();
802 if ((errorMessage != null) && (errorMessage.length() > 0))
803 {
804
805 message = ERR_LDAPPWMOD_FAILURE_ERROR_MESSAGE.get(errorMessage);
806 err.println(wrapText(message, MAX_LINE_WIDTH));
807 }
808
809 DN matchedDN = extendedResponse.getMatchedDN();
810 if (matchedDN != null)
811 {
812
813 message = ERR_LDAPPWMOD_FAILURE_MATCHED_DN.get(matchedDN.toString());
814 err.println(wrapText(message, MAX_LINE_WIDTH));
815 }
816
817 try
818 {
819 requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(),
820 new UnbindRequestProtocolOp());
821 writer.writeMessage(requestMessage);
822 }
823 catch (Exception e) {}
824
825 try
826 {
827 reader.close();
828 writer.close();
829 } catch (Exception e) {}
830
831 return resultCode;
832 }
833 else
834 {
835 Message message = INFO_LDAPPWMOD_SUCCESSFUL.get();
836 out.println(wrapText(message, MAX_LINE_WIDTH));
837
838 Message additionalInfo = extendedResponse.getErrorMessage();
839 if ((additionalInfo != null) && (additionalInfo.length() > 0))
840 {
841
842 message = INFO_LDAPPWMOD_ADDITIONAL_INFO.get(additionalInfo);
843 out.println(wrapText(message, MAX_LINE_WIDTH));
844 }
845 }
846
847
848 // See if the response included any controls that we recognize, and if so
849 // then handle them.
850 ArrayList<LDAPControl> responseControls = responseMessage.getControls();
851 if (responseControls != null)
852 {
853 for (LDAPControl c : responseControls)
854 {
855 if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
856 {
857 try
858 {
859 PasswordPolicyResponseControl pwPolicyControl =
860 PasswordPolicyResponseControl.decodeControl(c.getControl());
861
862 PasswordPolicyWarningType pwPolicyWarningType =
863 pwPolicyControl.getWarningType();
864 if (pwPolicyWarningType != null)
865 {
866 Message message = INFO_LDAPPWMOD_PWPOLICY_WARNING.get(
867 pwPolicyWarningType.toString(),
868 pwPolicyControl.getWarningValue());
869 out.println(wrapText(message, MAX_LINE_WIDTH));
870 }
871
872 PasswordPolicyErrorType pwPolicyErrorType =
873 pwPolicyControl.getErrorType();
874 if (pwPolicyErrorType != null)
875 {
876 Message message = INFO_LDAPPWMOD_PWPOLICY_ERROR.get(
877 pwPolicyErrorType.toString());
878 out.println(wrapText(message, MAX_LINE_WIDTH));
879 }
880 }
881 catch (Exception e)
882 {
883 Message message = ERR_LDAPPWMOD_CANNOT_DECODE_PWPOLICY_CONTROL.get(
884 String.valueOf(e));
885 err.println(wrapText(message, MAX_LINE_WIDTH));
886 }
887 }
888 }
889 }
890
891
892 // See if the response included a generated password.
893 ASN1OctetString responseValue = extendedResponse.getValue();
894 if (responseValue != null)
895 {
896 try
897 {
898 ASN1Sequence responseSequence =
899 ASN1Sequence.decodeAsSequence(responseValue.value());
900 for (ASN1Element e : responseSequence.elements())
901 {
902 if (e.getType() == TYPE_PASSWORD_MODIFY_GENERATED_PASSWORD)
903 {
904 Message message = INFO_LDAPPWMOD_GENERATED_PASSWORD.get(
905 e.decodeAsOctetString().stringValue());
906 out.println(wrapText(message, MAX_LINE_WIDTH));
907 }
908 else
909 {
910 Message message = ERR_LDAPPWMOD_UNRECOGNIZED_VALUE_TYPE.get(
911 byteToHex(e.getType()));
912 err.println(wrapText(message, MAX_LINE_WIDTH));
913 }
914 }
915 }
916 catch (Exception e)
917 {
918 Message message = ERR_LDAPPWMOD_COULD_NOT_DECODE_RESPONSE_VALUE.get(
919 String.valueOf(e));
920 err.println(wrapText(message, MAX_LINE_WIDTH));
921
922 try
923 {
924 requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(),
925 new UnbindRequestProtocolOp());
926 writer.writeMessage(requestMessage);
927 }
928 catch (Exception e2) {}
929
930 try
931 {
932 reader.close();
933 writer.close();
934 } catch (Exception e2) {}
935
936 return 1;
937 }
938 }
939
940
941 // Unbind from the server and close the connection.
942 try
943 {
944 requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(),
945 new UnbindRequestProtocolOp());
946 writer.writeMessage(requestMessage);
947 }
948 catch (Exception e) {}
949
950 try
951 {
952 reader.close();
953 writer.close();
954 } catch (Exception e) {}
955
956 return 0;
957 }
958 }
959