1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package com.sun.jndi.ldap;
27
28 import javax.naming.*;
29 import javax.naming.directory.*;
30 import javax.naming.spi.*;
31 import javax.naming.event.*;
32 import javax.naming.ldap.*;
33 import javax.naming.ldap.LdapName;
34 import javax.naming.ldap.Rdn;
35
36 import java.util.Locale;
37 import java.util.Vector;
38 import java.util.Hashtable;
39 import java.util.List;
40 import java.util.StringTokenizer;
41 import java.util.Enumeration;
42
43 import java.io.IOException;
44 import java.io.OutputStream;
45
46 import com.sun.jndi.toolkit.ctx.*;
47 import com.sun.jndi.toolkit.dir.HierMemDirCtx;
48 import com.sun.jndi.toolkit.dir.SearchFilter;
49 import com.sun.jndi.ldap.ext.StartTlsResponseImpl;
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 final public class LdapCtx extends ComponentDirContext
93 implements EventDirContext, LdapContext {
94
95
96
97
98 final static class SearchArgs {
99 Name name;
100 String filter;
101 SearchControls cons;
102 String[] reqAttrs;
103
104 SearchArgs(Name name, String filter, SearchControls cons, String[] ra) {
105 this.name = name;
106 this.filter = filter;
107 this.cons = cons;
108 this.reqAttrs = ra;
109 }
110 }
111
112 private static final boolean debug = false;
113
114 private static final boolean HARD_CLOSE = true;
115 private static final boolean SOFT_CLOSE = false;
116
117
118
119 public static final int DEFAULT_PORT = 389;
120 public static final int DEFAULT_SSL_PORT = 636;
121 public static final String DEFAULT_HOST = "localhost";
122
123 private static final boolean DEFAULT_DELETE_RDN = true;
124 private static final boolean DEFAULT_TYPES_ONLY = false;
125 private static final int DEFAULT_DEREF_ALIASES = 3;
126 private static final int DEFAULT_LDAP_VERSION = LdapClient.LDAP_VERSION3_VERSION2;
127 private static final int DEFAULT_BATCH_SIZE = 1;
128 private static final int DEFAULT_REFERRAL_MODE = LdapClient.LDAP_REF_IGNORE;
129 private static final char DEFAULT_REF_SEPARATOR = '#';
130
131
132 static final String DEFAULT_SSL_FACTORY =
133 "javax.net.ssl.SSLSocketFactory";
134 private static final int DEFAULT_REFERRAL_LIMIT = 10;
135 private static final String STARTTLS_REQ_OID = "1.3.6.1.4.1.1466.20037";
136
137
138 private static final String[] SCHEMA_ATTRIBUTES =
139 { "objectClasses", "attributeTypes", "matchingRules", "ldapSyntaxes" };
140
141
142
143
144 private static final String VERSION = "java.naming.ldap.version";
145
146
147 private static final String BINARY_ATTRIBUTES =
148 "java.naming.ldap.attributes.binary";
149
150
151 private static final String DELETE_RDN = "java.naming.ldap.deleteRDN";
152
153
154 private static final String DEREF_ALIASES = "java.naming.ldap.derefAliases";
155
156
157 private static final String TYPES_ONLY = "java.naming.ldap.typesOnly";
158
159
160 private static final String REF_SEPARATOR = "java.naming.ldap.ref.separator";
161
162
163 private static final String SOCKET_FACTORY = "java.naming.ldap.factory.socket";
164
165
166 static final String BIND_CONTROLS = "java.naming.ldap.control.connect";
167
168 private static final String REFERRAL_LIMIT =
169 "java.naming.ldap.referral.limit";
170
171
172 private static final String TRACE_BER = "com.sun.jndi.ldap.trace.ber";
173
174
175 private static final String NETSCAPE_SCHEMA_BUG =
176 "com.sun.jndi.ldap.netscape.schemaBugs";
177
178 private static final String OLD_NETSCAPE_SCHEMA_BUG =
179 "com.sun.naming.netscape.schemaBugs";
180
181
182 private static final String CONNECT_TIMEOUT =
183 "com.sun.jndi.ldap.connect.timeout";
184
185
186 private static final String READ_TIMEOUT =
187 "com.sun.jndi.ldap.read.timeout";
188
189
190 private static final String ENABLE_POOL = "com.sun.jndi.ldap.connect.pool";
191
192
193 private static final String DOMAIN_NAME = "com.sun.jndi.ldap.domainname";
194
195
196 private static final String WAIT_FOR_REPLY =
197 "com.sun.jndi.ldap.search.waitForReply";
198
199
200 private static final String REPLY_QUEUE_SIZE =
201 "com.sun.jndi.ldap.search.replyQueueSize";
202
203
204 private static final NameParser parser = new LdapNameParser();
205
206
207 private static final ControlFactory myResponseControlFactory =
208 new DefaultResponseControlFactory();
209 private static final Control manageReferralControl =
210 new ManageReferralControl(false);
211
212 private static final HierMemDirCtx EMPTY_SCHEMA = new HierMemDirCtx();
213 static {
214 EMPTY_SCHEMA.setReadOnly(
215 new SchemaViolationException("Cannot update schema object"));
216 }
217
218
219
220
221
222
223 int port_number;
224 String hostname = null;
225
226 LdapClient clnt = null;
227 private boolean reconnect = false;
228 Hashtable<String, java.lang.Object> envprops = null;
229 int handleReferrals = DEFAULT_REFERRAL_MODE;
230 boolean hasLdapsScheme = false;
231
232
233
234
235 String currentDN;
236 Name currentParsedDN;
237 Vector<Control> respCtls = null;
238 Control[] reqCtls = null;
239
240
241
242
243
244
245 private OutputStream trace = null;
246 private boolean netscapeSchemaBug = false;
247 private Control[] bindCtls = null;
248 private int referralHopLimit = DEFAULT_REFERRAL_LIMIT;
249 private Hashtable<String, DirContext> schemaTrees = null;
250 private int batchSize = DEFAULT_BATCH_SIZE;
251 private boolean deleteRDN = DEFAULT_DELETE_RDN;
252 private boolean typesOnly = DEFAULT_TYPES_ONLY;
253 private int derefAliases = DEFAULT_DEREF_ALIASES;
254 private char addrEncodingSeparator = DEFAULT_REF_SEPARATOR;
255
256 private Hashtable<String, Boolean> binaryAttrs = null;
257 private int connectTimeout = -1;
258 private int readTimeout = -1;
259 private boolean waitForReply = true;
260 private int replyQueueSize = -1;
261 private boolean useSsl = false;
262 private boolean useDefaultPortNumber = false;
263
264
265
266
267 private boolean parentIsLdapCtx = false;
268
269 private int hopCount = 1;
270 private String url = null;
271 private EventSupport eventSupport;
272 private boolean unsolicited = false;
273 private boolean sharable = true;
274
275
276
277 @SuppressWarnings("unchecked")
278 public LdapCtx(String dn, String host, int port_number,
279 Hashtable<?,?> props,
280 boolean useSsl) throws NamingException {
281
282 this.useSsl = this.hasLdapsScheme = useSsl;
283
284 if (props != null) {
285 envprops = (Hashtable<String, java.lang.Object>) props.clone();
286
287
288 if ("ssl".equals(envprops.get(Context.SECURITY_PROTOCOL))) {
289 this.useSsl = true;
290 }
291
292
293
294 trace = (OutputStream)envprops.get(TRACE_BER);
295
296 if (props.get(NETSCAPE_SCHEMA_BUG) != null ||
297 props.get(OLD_NETSCAPE_SCHEMA_BUG) != null) {
298 netscapeSchemaBug = true;
299 }
300 }
301
302 currentDN = (dn != null) ? dn : "";
303 currentParsedDN = parser.parse(currentDN);
304
305 hostname = (host != null && host.length() > 0) ? host : DEFAULT_HOST;
306 if (hostname.charAt(0) == '[') {
307 hostname = hostname.substring(1, hostname.length() - 1);
308 }
309
310 if (port_number > 0) {
311 this.port_number = port_number;
312 } else {
313 this.port_number = this.useSsl ? DEFAULT_SSL_PORT : DEFAULT_PORT;
314 this.useDefaultPortNumber = true;
315 }
316
317 schemaTrees = new Hashtable<>(11, 0.75f);
318 initEnv();
319 try {
320 connect(false);
321 } catch (NamingException e) {
322 try {
323 close();
324 } catch (Exception e2) {
325
326 }
327 throw e;
328 }
329 }
330
331 LdapCtx(LdapCtx existing, String newDN) throws NamingException {
332 useSsl = existing.useSsl;
333 hasLdapsScheme = existing.hasLdapsScheme;
334 useDefaultPortNumber = existing.useDefaultPortNumber;
335
336 hostname = existing.hostname;
337 port_number = existing.port_number;
338 currentDN = newDN;
339 if (existing.currentDN == currentDN) {
340 currentParsedDN = existing.currentParsedDN;
341 } else {
342 currentParsedDN = parser.parse(currentDN);
343 }
344
345 envprops = existing.envprops;
346 schemaTrees = existing.schemaTrees;
347
348 clnt = existing.clnt;
349 clnt.incRefCount();
350
351 parentIsLdapCtx = ((newDN == null || newDN.equals(existing.currentDN))
352 ? existing.parentIsLdapCtx
353 : true);
354
355
356 trace = existing.trace;
357 netscapeSchemaBug = existing.netscapeSchemaBug;
358
359 initEnv();
360 }
361
362 public LdapContext newInstance(Control[] reqCtls) throws NamingException {
363
364 LdapContext clone = new LdapCtx(this, currentDN);
365
366
367
368
369
370 clone.setRequestControls(reqCtls);
371 return clone;
372 }
373
374
375
376
377
378
379 protected void c_bind(Name name, Object obj, Continuation cont)
380 throws NamingException {
381 c_bind(name, obj, null, cont);
382 }
383
384
385
386
387
388
389
390
391
392
393
394
395
396 protected void c_bind(Name name, Object obj, Attributes attrs,
397 Continuation cont)
398 throws NamingException {
399
400 cont.setError(this, name);
401
402 Attributes inputAttrs = attrs;
403 try {
404 ensureOpen();
405
406 if (obj == null) {
407 if (attrs == null) {
408 throw new IllegalArgumentException(
409 "cannot bind null object with no attributes");
410 }
411 } else {
412 attrs = Obj.determineBindAttrs(addrEncodingSeparator, obj, attrs,
413 false, name, this, envprops);
414 }
415
416 String newDN = fullyQualifiedName(name);
417 attrs = addRdnAttributes(newDN, attrs, inputAttrs != attrs);
418 LdapEntry entry = new LdapEntry(newDN, attrs);
419
420 LdapResult answer = clnt.add(entry, reqCtls);
421 respCtls = answer.resControls;
422
423 if (answer.status != LdapClient.LDAP_SUCCESS) {
424 processReturnCode(answer, name);
425 }
426
427 } catch (LdapReferralException e) {
428 if (handleReferrals == LdapClient.LDAP_REF_THROW)
429 throw cont.fillInException(e);
430
431
432 while (true) {
433
434 LdapReferralContext refCtx =
435 (LdapReferralContext)e.getReferralContext(envprops, bindCtls);
436
437
438 try {
439
440 refCtx.bind(name, obj, inputAttrs);
441 return;
442
443 } catch (LdapReferralException re) {
444 e = re;
445 continue;
446
447 } finally {
448
449 refCtx.close();
450 }
451 }
452
453 } catch (IOException e) {
454 NamingException e2 = new CommunicationException(e.getMessage());
455 e2.setRootCause(e);
456 throw cont.fillInException(e2);
457
458 } catch (NamingException e) {
459 throw cont.fillInException(e);
460 }
461 }
462
463 protected void c_rebind(Name name, Object obj, Continuation cont)
464 throws NamingException {
465 c_rebind(name, obj, null, cont);
466 }
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484 protected void c_rebind(Name name, Object obj, Attributes attrs,
485 Continuation cont) throws NamingException {
486
487 cont.setError(this, name);
488
489 Attributes inputAttrs = attrs;
490
491 try {
492 Attributes origAttrs = null;
493
494
495 try {
496 origAttrs = c_getAttributes(name, null, cont);
497 } catch (NameNotFoundException e) {}
498
499
500 if (origAttrs == null) {
501 c_bind(name, obj, attrs, cont);
502 return;
503 }
504
505
506
507
508 if (attrs == null && obj instanceof DirContext) {
509 attrs = ((DirContext)obj).getAttributes("");
510 }
511 Attributes keepAttrs = (Attributes)origAttrs.clone();
512
513 if (attrs == null) {
514
515
516
517 Attribute origObjectClass =
518 origAttrs.get(Obj.JAVA_ATTRIBUTES[Obj.OBJECT_CLASS]);
519
520 if (origObjectClass != null) {
521
522 origObjectClass = (Attribute)origObjectClass.clone();
523 for (int i = 0; i < Obj.JAVA_OBJECT_CLASSES.length; i++) {
524 origObjectClass.remove(Obj.JAVA_OBJECT_CLASSES_LOWER[i]);
525 origObjectClass.remove(Obj.JAVA_OBJECT_CLASSES[i]);
526 }
527
528 origAttrs.put(origObjectClass);
529 }
530
531
532 for (int i = 1; i < Obj.JAVA_ATTRIBUTES.length; i++) {
533 origAttrs.remove(Obj.JAVA_ATTRIBUTES[i]);
534 }
535
536 attrs = origAttrs;
537 }
538 if (obj != null) {
539 attrs =
540 Obj.determineBindAttrs(addrEncodingSeparator, obj, attrs,
541 inputAttrs != attrs, name, this, envprops);
542 }
543
544 String newDN = fullyQualifiedName(name);
545
546 LdapResult answer = clnt.delete(newDN, reqCtls);
547 respCtls = answer.resControls;
548
549 if (answer.status != LdapClient.LDAP_SUCCESS) {
550 processReturnCode(answer, name);
551 return;
552 }
553
554 Exception addEx = null;
555 try {
556 attrs = addRdnAttributes(newDN, attrs, inputAttrs != attrs);
557
558
559 LdapEntry entry = new LdapEntry(newDN, attrs);
560 answer = clnt.add(entry, reqCtls);
561 if (answer.resControls != null) {
562 respCtls = appendVector(respCtls, answer.resControls);
563 }
564 } catch (NamingException | IOException ae) {
565 addEx = ae;
566 }
567
568 if ((addEx != null && !(addEx instanceof LdapReferralException)) ||
569 answer.status != LdapClient.LDAP_SUCCESS) {
570
571 LdapResult answer2 =
572 clnt.add(new LdapEntry(newDN, keepAttrs), reqCtls);
573 if (answer2.resControls != null) {
574 respCtls = appendVector(respCtls, answer2.resControls);
575 }
576
577 if (addEx == null) {
578 processReturnCode(answer, name);
579 }
580 }
581
582
583 if (addEx instanceof NamingException) {
584 throw (NamingException)addEx;
585 } else if (addEx instanceof IOException) {
586 throw (IOException)addEx;
587 }
588
589 } catch (LdapReferralException e) {
590 if (handleReferrals == LdapClient.LDAP_REF_THROW)
591 throw cont.fillInException(e);
592
593
594 while (true) {
595
596 LdapReferralContext refCtx =
597 (LdapReferralContext)e.getReferralContext(envprops, bindCtls);
598
599
600 try {
601
602 refCtx.rebind(name, obj, inputAttrs);
603 return;
604
605 } catch (LdapReferralException re) {
606 e = re;
607 continue;
608
609 } finally {
610
611 refCtx.close();
612 }
613 }
614
615 } catch (IOException e) {
616 NamingException e2 = new CommunicationException(e.getMessage());
617 e2.setRootCause(e);
618 throw cont.fillInException(e2);
619
620 } catch (NamingException e) {
621 throw cont.fillInException(e);
622 }
623 }
624
625 protected void c_unbind(Name name, Continuation cont)
626 throws NamingException {
627 cont.setError(this, name);
628
629 try {
630 ensureOpen();
631
632 String fname = fullyQualifiedName(name);
633 LdapResult answer = clnt.delete(fname, reqCtls);
634 respCtls = answer.resControls;
635
636 adjustDeleteStatus(fname, answer);
637
638 if (answer.status != LdapClient.LDAP_SUCCESS) {
639 processReturnCode(answer, name);
640 }
641
642 } catch (LdapReferralException e) {
643 if (handleReferrals == LdapClient.LDAP_REF_THROW)
644 throw cont.fillInException(e);
645
646
647 while (true) {
648
649 LdapReferralContext refCtx =
650 (LdapReferralContext)e.getReferralContext(envprops, bindCtls);
651
652
653 try {
654
655 refCtx.unbind(name);
656 return;
657
658 } catch (LdapReferralException re) {
659 e = re;
660 continue;
661
662 } finally {
663
664 refCtx.close();
665 }
666 }
667
668 } catch (IOException e) {
669 NamingException e2 = new CommunicationException(e.getMessage());
670 e2.setRootCause(e);
671 throw cont.fillInException(e2);
672
673 } catch (NamingException e) {
674 throw cont.fillInException(e);
675 }
676 }
677
678 protected void c_rename(Name oldName, Name newName, Continuation cont)
679 throws NamingException
680 {
681 Name oldParsed, newParsed;
682 Name oldParent, newParent;
683 String newRDN = null;
684 String newSuperior = null;
685
686
687
688 cont.setError(this, oldName);
689
690 try {
691 ensureOpen();
692
693
694 if (oldName.isEmpty()) {
695 oldParent = parser.parse("");
696 } else {
697 oldParsed = parser.parse(oldName.get(0));
698 oldParent = oldParsed.getPrefix(oldParsed.size() - 1);
699 }
700
701 if (newName instanceof CompositeName) {
702 newParsed = parser.parse(newName.get(0));
703 } else {
704 newParsed = newName;
705 }
706 newParent = newParsed.getPrefix(newParsed.size() - 1);
707
708 if(!oldParent.equals(newParent)) {
709 if (!clnt.isLdapv3) {
710 throw new InvalidNameException(
711 "LDAPv2 doesn't support changing " +
712 "the parent as a result of a rename");
713 } else {
714 newSuperior = fullyQualifiedName(newParent.toString());
715 }
716 }
717
718 newRDN = newParsed.get(newParsed.size() - 1);
719
720 LdapResult answer = clnt.moddn(fullyQualifiedName(oldName),
721 newRDN,
722 deleteRDN,
723 newSuperior,
724 reqCtls);
725 respCtls = answer.resControls;
726
727 if (answer.status != LdapClient.LDAP_SUCCESS) {
728 processReturnCode(answer, oldName);
729 }
730
731 } catch (LdapReferralException e) {
732
733
734 e.setNewRdn(newRDN);
735
736
737
738
739 if (newSuperior != null) {
740 PartialResultException pre = new PartialResultException(
741 "Cannot continue referral processing when newSuperior is " +
742 "nonempty: " + newSuperior);
743 pre.setRootCause(cont.fillInException(e));
744 throw cont.fillInException(pre);
745 }
746
747 if (handleReferrals == LdapClient.LDAP_REF_THROW)
748 throw cont.fillInException(e);
749
750
751 while (true) {
752
753 LdapReferralContext refCtx =
754 (LdapReferralContext)e.getReferralContext(envprops, bindCtls);
755
756
757 try {
758
759 refCtx.rename(oldName, newName);
760 return;
761
762 } catch (LdapReferralException re) {
763 e = re;
764 continue;
765
766 } finally {
767
768 refCtx.close();
769 }
770 }
771
772 } catch (IOException e) {
773 NamingException e2 = new CommunicationException(e.getMessage());
774 e2.setRootCause(e);
775 throw cont.fillInException(e2);
776
777 } catch (NamingException e) {
778 throw cont.fillInException(e);
779 }
780 }
781
782 protected Context c_createSubcontext(Name name, Continuation cont)
783 throws NamingException {
784 return c_createSubcontext(name, null, cont);
785 }
786
787 protected DirContext c_createSubcontext(Name name, Attributes attrs,
788 Continuation cont)
789 throws NamingException {
790 cont.setError(this, name);
791
792 Attributes inputAttrs = attrs;
793 try {
794 ensureOpen();
795 if (attrs == null) {
796
797 Attribute oc = new BasicAttribute(
798 Obj.JAVA_ATTRIBUTES[Obj.OBJECT_CLASS],
799 Obj.JAVA_OBJECT_CLASSES[Obj.STRUCTURAL]);
800 oc.add("top");
801 attrs = new BasicAttributes(true);
802 attrs.put(oc);
803 }
804 String newDN = fullyQualifiedName(name);
805 attrs = addRdnAttributes(newDN, attrs, inputAttrs != attrs);
806
807 LdapEntry entry = new LdapEntry(newDN, attrs);
808
809 LdapResult answer = clnt.add(entry, reqCtls);
810 respCtls = answer.resControls;
811
812 if (answer.status != LdapClient.LDAP_SUCCESS) {
813 processReturnCode(answer, name);
814 return null;
815 }
816
817
818 return new LdapCtx(this, newDN);
819
820 } catch (LdapReferralException e) {
821 if (handleReferrals == LdapClient.LDAP_REF_THROW)
822 throw cont.fillInException(e);
823
824
825 while (true) {
826
827 LdapReferralContext refCtx =
828 (LdapReferralContext)e.getReferralContext(envprops, bindCtls);
829
830
831 try {
832
833 return refCtx.createSubcontext(name, inputAttrs);
834
835 } catch (LdapReferralException re) {
836 e = re;
837 continue;
838
839 } finally {
840
841 refCtx.close();
842 }
843 }
844
845 } catch (IOException e) {
846 NamingException e2 = new CommunicationException(e.getMessage());
847 e2.setRootCause(e);
848 throw cont.fillInException(e2);
849
850 } catch (NamingException e) {
851 throw cont.fillInException(e);
852 }
853 }
854
855 protected void c_destroySubcontext(Name name, Continuation cont)
856 throws NamingException {
857 cont.setError(this, name);
858
859 try {
860 ensureOpen();
861
862 String fname = fullyQualifiedName(name);
863 LdapResult answer = clnt.delete(fname, reqCtls);
864 respCtls = answer.resControls;
865
866 adjustDeleteStatus(fname, answer);
867
868 if (answer.status != LdapClient.LDAP_SUCCESS) {
869 processReturnCode(answer, name);
870 }
871
872 } catch (LdapReferralException e) {
873 if (handleReferrals == LdapClient.LDAP_REF_THROW)
874 throw cont.fillInException(e);
875
876
877 while (true) {
878
879 LdapReferralContext refCtx =
880 (LdapReferralContext)e.getReferralContext(envprops, bindCtls);
881
882
883 try {
884
885 refCtx.destroySubcontext(name);
886 return;
887 } catch (LdapReferralException re) {
888 e = re;
889 continue;
890 } finally {
891
892 refCtx.close();
893 }
894 }
895 } catch (IOException e) {
896 NamingException e2 = new CommunicationException(e.getMessage());
897 e2.setRootCause(e);
898 throw cont.fillInException(e2);
899 } catch (NamingException e) {
900 throw cont.fillInException(e);
901 }
902 }
903
904
905
906
907
908
909
910
911
912
913
914 private static Attributes addRdnAttributes(String dn, Attributes attrs,
915 boolean directUpdate) throws NamingException {
916
917
918 if (dn.equals("")) {
919 return attrs;
920 }
921
922
923 List<Rdn> rdnList = (new LdapName(dn)).getRdns();
924
925
926 Rdn rdn = rdnList.get(rdnList.size() - 1);
927 Attributes nameAttrs = rdn.toAttributes();
928
929
930 NamingEnumeration<? extends Attribute> enum_ = nameAttrs.getAll();
931 Attribute nameAttr;
932 while (enum_.hasMore()) {
933 nameAttr = enum_.next();
934
935
936 if (attrs.get(nameAttr.getID()) == null) {
937
938
939
940
941
942
943
944
945
946
947 if (!attrs.isCaseIgnored() &&
948 containsIgnoreCase(attrs.getIDs(), nameAttr.getID())) {
949 continue;
950 }
951
952 if (!directUpdate) {
953 attrs = (Attributes)attrs.clone();
954 directUpdate = true;
955 }
956 attrs.put(nameAttr);
957 }
958 }
959
960 return attrs;
961 }
962
963
964 private static boolean containsIgnoreCase(NamingEnumeration<String> enumStr,
965 String str) throws NamingException {
966 String strEntry;
967
968 while (enumStr.hasMore()) {
969 strEntry = enumStr.next();
970 if (strEntry.equalsIgnoreCase(str)) {
971 return true;
972 }
973 }
974 return false;
975 }
976
977
978 private void adjustDeleteStatus(String fname, LdapResult answer) {
979 if (answer.status == LdapClient.LDAP_NO_SUCH_OBJECT &&
980 answer.matchedDN != null) {
981 try {
982
983
984 Name orig = parser.parse(fname);
985 Name matched = parser.parse(answer.matchedDN);
986 if ((orig.size() - matched.size()) == 1)
987 answer.status = LdapClient.LDAP_SUCCESS;
988 } catch (NamingException e) {}
989 }
990 }
991
992
993
994
995
996 private static <T> Vector<T> appendVector(Vector<T> v1, Vector<T> v2) {
997 if (v1 == null) {
998 v1 = v2;
999 } else {
1000 for (int i = 0; i < v2.size(); i++) {
1001 v1.addElement(v2.elementAt(i));
1002 }
1003 }
1004 return v1;
1005 }
1006
1007
1008
1009
1010
1011 protected Object c_lookupLink(Name name, Continuation cont)
1012 throws NamingException {
1013 return c_lookup(name, cont);
1014 }
1015
1016 protected Object c_lookup(Name name, Continuation cont)
1017 throws NamingException {
1018 cont.setError(this, name);
1019 Object obj = null;
1020 Attributes attrs;
1021
1022 try {
1023 SearchControls cons = new SearchControls();
1024 cons.setSearchScope(SearchControls.OBJECT_SCOPE);
1025 cons.setReturningAttributes(null);
1026 cons.setReturningObjFlag(true);
1027
1028 LdapResult answer = doSearchOnce(name, "(objectClass=*)", cons, true);
1029 respCtls = answer.resControls;
1030
1031
1032
1033 if (answer.status != LdapClient.LDAP_SUCCESS) {
1034 processReturnCode(answer, name);
1035 }
1036
1037 if (answer.entries == null || answer.entries.size() != 1) {
1038
1039 attrs = new BasicAttributes(LdapClient.caseIgnore);
1040 } else {
1041 LdapEntry entry = answer.entries.elementAt(0);
1042 attrs = entry.attributes;
1043
1044 Vector<Control> entryCtls = entry.respCtls;
1045 if (entryCtls != null) {
1046 appendVector(respCtls, entryCtls);
1047 }
1048 }
1049
1050 if (attrs.get(Obj.JAVA_ATTRIBUTES[Obj.CLASSNAME]) != null) {
1051
1052 obj = Obj.decodeObject(attrs);
1053 }
1054 if (obj == null) {
1055 obj = new LdapCtx(this, fullyQualifiedName(name));
1056 }
1057 } catch (LdapReferralException e) {
1058 if (handleReferrals == LdapClient.LDAP_REF_THROW)
1059 throw cont.fillInException(e);
1060
1061
1062 while (true) {
1063
1064 LdapReferralContext refCtx =
1065 (LdapReferralContext)e.getReferralContext(envprops, bindCtls);
1066
1067 try {
1068
1069 return refCtx.lookup(name);
1070
1071 } catch (LdapReferralException re) {
1072 e = re;
1073 continue;
1074
1075 } finally {
1076
1077 refCtx.close();
1078 }
1079 }
1080
1081 } catch (NamingException e) {
1082 throw cont.fillInException(e);
1083 }
1084
1085 try {
1086 return DirectoryManager.getObjectInstance(obj, name,
1087 this, envprops, attrs);
1088
1089 } catch (NamingException e) {
1090 throw cont.fillInException(e);
1091
1092 } catch (Exception e) {
1093 NamingException e2 = new NamingException(
1094 "problem generating object using object factory");
1095 e2.setRootCause(e);
1096 throw cont.fillInException(e2);
1097 }
1098 }
1099
1100 protected NamingEnumeration<NameClassPair> c_list(Name name, Continuation cont)
1101 throws NamingException {
1102 SearchControls cons = new SearchControls();
1103 String[] classAttrs = new String[2];
1104
1105 classAttrs[0] = Obj.JAVA_ATTRIBUTES[Obj.OBJECT_CLASS];
1106 classAttrs[1] = Obj.JAVA_ATTRIBUTES[Obj.CLASSNAME];
1107 cons.setReturningAttributes(classAttrs);
1108
1109
1110 cons.setReturningObjFlag(true);
1111
1112 cont.setError(this, name);
1113
1114 LdapResult answer = null;
1115
1116 try {
1117 answer = doSearch(name, "(objectClass=*)", cons, true, true);
1118
1119
1120 if ((answer.status != LdapClient.LDAP_SUCCESS) ||
1121 (answer.referrals != null)) {
1122 processReturnCode(answer, name);
1123 }
1124
1125 return new LdapNamingEnumeration(this, answer, name, cont);
1126
1127 } catch (LdapReferralException e) {
1128 if (handleReferrals == LdapClient.LDAP_REF_THROW)
1129 throw cont.fillInException(e);
1130
1131
1132 while (true) {
1133
1134 LdapReferralContext refCtx =
1135 (LdapReferralContext)e.getReferralContext(envprops, bindCtls);
1136
1137
1138 try {
1139
1140 return refCtx.list(name);
1141
1142 } catch (LdapReferralException re) {
1143 e = re;
1144 continue;
1145
1146 } finally {
1147
1148 refCtx.close();
1149 }
1150 }
1151
1152 } catch (LimitExceededException e) {
1153 LdapNamingEnumeration res =
1154 new LdapNamingEnumeration(this, answer, name, cont);
1155
1156 res.setNamingException(
1157 (LimitExceededException)cont.fillInException(e));
1158 return res;
1159
1160 } catch (PartialResultException e) {
1161 LdapNamingEnumeration res =
1162 new LdapNamingEnumeration(this, answer, name, cont);
1163
1164 res.setNamingException(
1165 (PartialResultException)cont.fillInException(e));
1166 return res;
1167
1168 } catch (NamingException e) {
1169 throw cont.fillInException(e);
1170 }
1171 }
1172
1173 protected NamingEnumeration<Binding> c_listBindings(Name name, Continuation cont)
1174 throws NamingException {
1175
1176 SearchControls cons = new SearchControls();
1177 cons.setReturningAttributes(null);
1178 cons.setReturningObjFlag(true);
1179
1180 cont.setError(this, name);
1181
1182 LdapResult answer = null;
1183
1184 try {
1185 answer = doSearch(name, "(objectClass=*)", cons, true, true);
1186
1187
1188 if ((answer.status != LdapClient.LDAP_SUCCESS) ||
1189 (answer.referrals != null)) {
1190 processReturnCode(answer, name);
1191 }
1192
1193 return new LdapBindingEnumeration(this, answer, name, cont);
1194
1195 } catch (LdapReferralException e) {
1196 if (handleReferrals == LdapClient.LDAP_REF_THROW)
1197 throw cont.fillInException(e);
1198
1199
1200 while (true) {
1201 @SuppressWarnings("unchecked")
1202 LdapReferralContext refCtx =
1203 (LdapReferralContext)e.getReferralContext(envprops, bindCtls);
1204
1205
1206 try {
1207
1208 return refCtx.listBindings(name);
1209
1210 } catch (LdapReferralException re) {
1211 e = re;
1212 continue;
1213
1214 } finally {
1215
1216 refCtx.close();
1217 }
1218 }
1219 } catch (LimitExceededException e) {
1220 LdapBindingEnumeration res =
1221 new LdapBindingEnumeration(this, answer, name, cont);
1222
1223 res.setNamingException(cont.fillInException(e));
1224 return res;
1225
1226 } catch (PartialResultException e) {
1227 LdapBindingEnumeration res =
1228 new LdapBindingEnumeration(this, answer, name, cont);
1229
1230 res.setNamingException(cont.fillInException(e));
1231 return res;
1232
1233 } catch (NamingException e) {
1234 throw cont.fillInException(e);
1235 }
1236 }
1237
1238
1239
1240
1241 protected NameParser c_getNameParser(Name name, Continuation cont)
1242 throws NamingException
1243 {
1244
1245 cont.setSuccess();
1246 return parser;
1247 }
1248
1249 public String getNameInNamespace() {
1250 return currentDN;
1251 }
1252
1253 public Name composeName(Name name, Name prefix)
1254 throws NamingException
1255 {
1256 Name result;
1257
1258
1259 if ((name instanceof LdapName) && (prefix instanceof LdapName)) {
1260 result = (Name)(prefix.clone());
1261 result.addAll(name);
1262 return new CompositeName().add(result.toString());
1263 }
1264 if (!(name instanceof CompositeName)) {
1265 name = new CompositeName().add(name.toString());
1266 }
1267 if (!(prefix instanceof CompositeName)) {
1268 prefix = new CompositeName().add(prefix.toString());
1269 }
1270
1271 int prefixLast = prefix.size() - 1;
1272
1273 if (name.isEmpty() || prefix.isEmpty() ||
1274 name.get(0).equals("") || prefix.get(prefixLast).equals("")) {
1275 return super.composeName(name, prefix);
1276 }
1277
1278 result = (Name)(prefix.clone());
1279 result.addAll(name);
1280
1281 if (parentIsLdapCtx) {
1282 String ldapComp = concatNames(result.get(prefixLast + 1),
1283 result.get(prefixLast));
1284 result.remove(prefixLast + 1);
1285 result.remove(prefixLast);
1286 result.add(prefixLast, ldapComp);
1287 }
1288 return result;
1289 }
1290
1291 private String fullyQualifiedName(Name rel) {
1292 return rel.isEmpty()
1293 ? currentDN
1294 : fullyQualifiedName(rel.get(0));
1295 }
1296
1297 private String fullyQualifiedName(String rel) {
1298 return (concatNames(rel, currentDN));
1299 }
1300
1301
1302 private static String concatNames(String lesser, String greater) {
1303 if (lesser == null || lesser.equals("")) {
1304 return greater;
1305 } else if (greater == null || greater.equals("")) {
1306 return lesser;
1307 } else {
1308 return (lesser + "," + greater);
1309 }
1310 }
1311
1312
1313
1314
1315 protected Attributes c_getAttributes(Name name, String[] attrIds,
1316 Continuation cont)
1317 throws NamingException {
1318 cont.setError(this, name);
1319
1320 SearchControls cons = new SearchControls();
1321 cons.setSearchScope(SearchControls.OBJECT_SCOPE);
1322 cons.setReturningAttributes(attrIds);
1323
1324 try {
1325 LdapResult answer =
1326 doSearchOnce(name, "(objectClass=*)", cons, true);
1327 respCtls = answer.resControls;
1328
1329 if (answer.status != LdapClient.LDAP_SUCCESS) {
1330 processReturnCode(answer, name);
1331 }
1332
1333 if (answer.entries == null || answer.entries.size() != 1) {
1334 return new BasicAttributes(LdapClient.caseIgnore);
1335 }
1336
1337
1338 LdapEntry entry = answer.entries.elementAt(0);
1339
1340 Vector<Control> entryCtls = entry.respCtls;
1341 if (entryCtls != null) {
1342 appendVector(respCtls, entryCtls);
1343 }
1344
1345
1346 setParents(entry.attributes, (Name) name.clone());
1347
1348 return (entry.attributes);
1349
1350 } catch (LdapReferralException e) {
1351 if (handleReferrals == LdapClient.LDAP_REF_THROW)
1352 throw cont.fillInException(e);
1353
1354
1355 while (true) {
1356
1357 LdapReferralContext refCtx =
1358 (LdapReferralContext)e.getReferralContext(envprops, bindCtls);
1359
1360
1361 try {
1362
1363 return refCtx.getAttributes(name, attrIds);
1364
1365 } catch (LdapReferralException re) {
1366 e = re;
1367 continue;
1368
1369 } finally {
1370
1371 refCtx.close();
1372 }
1373 }
1374
1375 } catch (NamingException e) {
1376 throw cont.fillInException(e);
1377 }
1378 }
1379
1380 protected void c_modifyAttributes(Name name, int mod_op, Attributes attrs,
1381 Continuation cont)
1382 throws NamingException {
1383
1384 cont.setError(this, name);
1385
1386 try {
1387 ensureOpen();
1388
1389 if (attrs == null || attrs.size() == 0) {
1390 return;
1391 }
1392 String newDN = fullyQualifiedName(name);
1393 int jmod_op = convertToLdapModCode(mod_op);
1394
1395
1396 int[] jmods = new int[attrs.size()];
1397 Attribute[] jattrs = new Attribute[attrs.size()];
1398
1399 NamingEnumeration<? extends Attribute> ae = attrs.getAll();
1400 for(int i = 0; i < jmods.length && ae.hasMore(); i++) {
1401 jmods[i] = jmod_op;
1402 jattrs[i] = ae.next();
1403 }
1404
1405 LdapResult answer = clnt.modify(newDN, jmods, jattrs, reqCtls);
1406 respCtls = answer.resControls;
1407
1408 if (answer.status != LdapClient.LDAP_SUCCESS) {
1409 processReturnCode(answer, name);
1410 return;
1411 }
1412
1413 } catch (LdapReferralException e) {
1414 if (handleReferrals == LdapClient.LDAP_REF_THROW)
1415 throw cont.fillInException(e);
1416
1417
1418 while (true) {
1419
1420 LdapReferralContext refCtx =
1421 (LdapReferralContext)e.getReferralContext(envprops, bindCtls);
1422
1423
1424 try {
1425
1426 refCtx.modifyAttributes(name, mod_op, attrs);
1427 return;
1428
1429 } catch (LdapReferralException re) {
1430 e = re;
1431 continue;
1432
1433 } finally {
1434
1435 refCtx.close();
1436 }
1437 }
1438
1439 } catch (IOException e) {
1440 NamingException e2 = new CommunicationException(e.getMessage());
1441 e2.setRootCause(e);
1442 throw cont.fillInException(e2);
1443
1444 } catch (NamingException e) {
1445 throw cont.fillInException(e);
1446 }
1447 }
1448
1449 protected void c_modifyAttributes(Name name, ModificationItem[] mods,
1450 Continuation cont)
1451 throws NamingException {
1452 cont.setError(this, name);
1453
1454 try {
1455 ensureOpen();
1456
1457 if (mods == null || mods.length == 0) {
1458 return;
1459 }
1460 String newDN = fullyQualifiedName(name);
1461
1462
1463 int[] jmods = new int[mods.length];
1464 Attribute[] jattrs = new Attribute[mods.length];
1465 ModificationItem mod;
1466 for (int i = 0; i < jmods.length; i++) {
1467 mod = mods[i];
1468 jmods[i] = convertToLdapModCode(mod.getModificationOp());
1469 jattrs[i] = mod.getAttribute();
1470 }
1471
1472 LdapResult answer = clnt.modify(newDN, jmods, jattrs, reqCtls);
1473 respCtls = answer.resControls;
1474
1475 if (answer.status != LdapClient.LDAP_SUCCESS) {
1476 processReturnCode(answer, name);
1477 }
1478
1479 } catch (LdapReferralException e) {
1480 if (handleReferrals == LdapClient.LDAP_REF_THROW)
1481 throw cont.fillInException(e);
1482
1483
1484 while (true) {
1485
1486 LdapReferralContext refCtx =
1487 (LdapReferralContext)e.getReferralContext(envprops, bindCtls);
1488
1489
1490 try {
1491
1492 refCtx.modifyAttributes(name, mods);
1493 return;
1494
1495 } catch (LdapReferralException re) {
1496 e = re;
1497 continue;
1498
1499 } finally {
1500
1501 refCtx.close();
1502 }
1503 }
1504
1505 } catch (IOException e) {
1506 NamingException e2 = new CommunicationException(e.getMessage());
1507 e2.setRootCause(e);
1508 throw cont.fillInException(e2);
1509
1510 } catch (NamingException e) {
1511 throw cont.fillInException(e);
1512 }
1513 }
1514
1515 private static int convertToLdapModCode(int mod_op) {
1516 switch (mod_op) {
1517 case DirContext.ADD_ATTRIBUTE:
1518 return(LdapClient.ADD);
1519
1520 case DirContext.REPLACE_ATTRIBUTE:
1521 return (LdapClient.REPLACE);
1522
1523 case DirContext.REMOVE_ATTRIBUTE:
1524 return (LdapClient.DELETE);
1525
1526 default:
1527 throw new IllegalArgumentException("Invalid modification code");
1528 }
1529 }
1530
1531
1532
1533 protected DirContext c_getSchema(Name name, Continuation cont)
1534 throws NamingException {
1535 cont.setError(this, name);
1536 try {
1537 return getSchemaTree(name);
1538
1539 } catch (NamingException e) {
1540 throw cont.fillInException(e);
1541 }
1542 }
1543
1544 protected DirContext c_getSchemaClassDefinition(Name name,
1545 Continuation cont)
1546 throws NamingException {
1547 cont.setError(this, name);
1548
1549 try {
1550
1551 Attribute objectClassAttr = c_getAttributes(name,
1552 new String[]{"objectclass"}, cont).get("objectclass");
1553 if (objectClassAttr == null || objectClassAttr.size() == 0) {
1554 return EMPTY_SCHEMA;
1555 }
1556
1557
1558 Context ocSchema = (Context) c_getSchema(name, cont).lookup(
1559 LdapSchemaParser.OBJECTCLASS_DEFINITION_NAME);
1560
1561
1562
1563 HierMemDirCtx objectClassCtx = new HierMemDirCtx();
1564 DirContext objectClassDef;
1565 String objectClassName;
1566 for (Enumeration<?> objectClasses = objectClassAttr.getAll();
1567 objectClasses.hasMoreElements(); ) {
1568 objectClassName = (String)objectClasses.nextElement();
1569
1570 objectClassDef = (DirContext)ocSchema.lookup(objectClassName);
1571 objectClassCtx.bind(objectClassName, objectClassDef);
1572 }
1573
1574
1575 objectClassCtx.setReadOnly(
1576 new SchemaViolationException("Cannot update schema object"));
1577 return (DirContext)objectClassCtx;
1578
1579 } catch (NamingException e) {
1580 throw cont.fillInException(e);
1581 }
1582 }
1583
1584
1585
1586
1587
1588
1589 private DirContext getSchemaTree(Name name) throws NamingException {
1590 String subschemasubentry = getSchemaEntry(name, true);
1591
1592 DirContext schemaTree = schemaTrees.get(subschemasubentry);
1593
1594 if(schemaTree==null) {
1595 if(debug){System.err.println("LdapCtx: building new schema tree " + this);}
1596 schemaTree = buildSchemaTree(subschemasubentry);
1597 schemaTrees.put(subschemasubentry, schemaTree);
1598 }
1599
1600 return schemaTree;
1601 }
1602
1603
1604
1605
1606
1607 private DirContext buildSchemaTree(String subschemasubentry)
1608 throws NamingException {
1609
1610
1611
1612
1613
1614 SearchControls constraints = new
1615 SearchControls(SearchControls.OBJECT_SCOPE,
1616 0, 0,
1617 SCHEMA_ATTRIBUTES ,
1618 true ,
1619 false );
1620
1621 Name sse = (new CompositeName()).add(subschemasubentry);
1622 NamingEnumeration<SearchResult> results =
1623 searchAux(sse, "(objectClass=subschema)", constraints,
1624 false, true, new Continuation());
1625
1626 if(!results.hasMore()) {
1627 throw new OperationNotSupportedException(
1628 "Cannot get read subschemasubentry: " + subschemasubentry);
1629 }
1630 SearchResult result = results.next();
1631 results.close();
1632
1633 Object obj = result.getObject();
1634 if(!(obj instanceof LdapCtx)) {
1635 throw new NamingException(
1636 "Cannot get schema object as DirContext: " + subschemasubentry);
1637 }
1638
1639 return LdapSchemaCtx.createSchemaTree(envprops, subschemasubentry,
1640 (LdapCtx)obj ,
1641 result.getAttributes() ,
1642 netscapeSchemaBug);
1643 }
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665 private String getSchemaEntry(Name name, boolean relative)
1666 throws NamingException {
1667
1668
1669 SearchControls constraints = new SearchControls(SearchControls.OBJECT_SCOPE,
1670 0, 0,
1671 new String[]{"subschemasubentry"} ,
1672 false ,
1673 false );
1674
1675 NamingEnumeration<SearchResult> results;
1676 try {
1677 results = searchAux(name, "objectclass=*", constraints, relative,
1678 true, new Continuation());
1679
1680 } catch (NamingException ne) {
1681 if (!clnt.isLdapv3 && currentDN.length() == 0 && name.isEmpty()) {
1682
1683
1684 throw new OperationNotSupportedException(
1685 "Cannot get schema information from server");
1686 } else {
1687 throw ne;
1688 }
1689 }
1690
1691 if (!results.hasMoreElements()) {
1692 throw new ConfigurationException(
1693 "Requesting schema of nonexistent entry: " + name);
1694 }
1695
1696 SearchResult result = results.next();
1697 results.close();
1698
1699 Attribute schemaEntryAttr =
1700 result.getAttributes().get("subschemasubentry");
1701
1702
1703 if (schemaEntryAttr == null || schemaEntryAttr.size() < 0) {
1704 if (currentDN.length() == 0 && name.isEmpty()) {
1705
1706
1707 throw new OperationNotSupportedException(
1708 "Cannot read subschemasubentry of root DSE");
1709 } else {
1710 return getSchemaEntry(new CompositeName(), false);
1711 }
1712 }
1713
1714 return (String)(schemaEntryAttr.get());
1715 }
1716
1717
1718
1719
1720 void setParents(Attributes attrs, Name name) throws NamingException {
1721 NamingEnumeration<? extends Attribute> ae = attrs.getAll();
1722 while(ae.hasMore()) {
1723 ((LdapAttribute) ae.next()).setParent(this, name);
1724 }
1725 }
1726
1727
1728
1729
1730
1731 String getURL() {
1732 if (url == null) {
1733 url = LdapURL.toUrlString(hostname, port_number, currentDN,
1734 hasLdapsScheme);
1735 }
1736
1737 return url;
1738 }
1739
1740
1741 protected NamingEnumeration<SearchResult> c_search(Name name,
1742 Attributes matchingAttributes,
1743 Continuation cont)
1744 throws NamingException {
1745 return c_search(name, matchingAttributes, null, cont);
1746 }
1747
1748 protected NamingEnumeration<SearchResult> c_search(Name name,
1749 Attributes matchingAttributes,
1750 String[] attributesToReturn,
1751 Continuation cont)
1752 throws NamingException {
1753 SearchControls cons = new SearchControls();
1754 cons.setReturningAttributes(attributesToReturn);
1755 String filter;
1756 try {
1757 filter = SearchFilter.format(matchingAttributes);
1758 } catch (NamingException e) {
1759 cont.setError(this, name);
1760 throw cont.fillInException(e);
1761 }
1762 return c_search(name, filter, cons, cont);
1763 }
1764
1765 protected NamingEnumeration<SearchResult> c_search(Name name,
1766 String filter,
1767 SearchControls cons,
1768 Continuation cont)
1769 throws NamingException {
1770 return searchAux(name, filter, cloneSearchControls(cons), true,
1771 waitForReply, cont);
1772 }
1773
1774 protected NamingEnumeration<SearchResult> c_search(Name name,
1775 String filterExpr,
1776 Object[] filterArgs,
1777 SearchControls cons,
1778 Continuation cont)
1779 throws NamingException {
1780 String strfilter;
1781 try {
1782 strfilter = SearchFilter.format(filterExpr, filterArgs);
1783 } catch (NamingException e) {
1784 cont.setError(this, name);
1785 throw cont.fillInException(e);
1786 }
1787 return c_search(name, strfilter, cons, cont);
1788 }
1789
1790
1791 NamingEnumeration<SearchResult> searchAux(Name name,
1792 String filter,
1793 SearchControls cons,
1794 boolean relative,
1795 boolean waitForReply, Continuation cont) throws NamingException {
1796
1797 LdapResult answer = null;
1798 String[] tokens = new String[2];
1799 String[] reqAttrs;
1800
1801 if (cons == null) {
1802 cons = new SearchControls();
1803 }
1804 reqAttrs = cons.getReturningAttributes();
1805
1806
1807
1808 if (cons.getReturningObjFlag()) {
1809 if (reqAttrs != null) {
1810
1811
1812 boolean hasWildcard = false;
1813 for (int i = reqAttrs.length - 1; i >= 0; i--) {
1814 if (reqAttrs[i].equals("*")) {
1815 hasWildcard = true;
1816 break;
1817 }
1818 }
1819 if (! hasWildcard) {
1820 String[] totalAttrs =
1821 new String[reqAttrs.length +Obj.JAVA_ATTRIBUTES.length];
1822 System.arraycopy(reqAttrs, 0, totalAttrs, 0,
1823 reqAttrs.length);
1824 System.arraycopy(Obj.JAVA_ATTRIBUTES, 0, totalAttrs,
1825 reqAttrs.length, Obj.JAVA_ATTRIBUTES.length);
1826
1827 cons.setReturningAttributes(totalAttrs);
1828 }
1829 }
1830 }
1831
1832 LdapCtx.SearchArgs args =
1833 new LdapCtx.SearchArgs(name, filter, cons, reqAttrs);
1834
1835 cont.setError(this, name);
1836 try {
1837
1838 if (searchToCompare(filter, cons, tokens)){
1839
1840 answer = compare(name, tokens[0], tokens[1]);
1841 if (! (answer.compareToSearchResult(fullyQualifiedName(name)))){
1842 processReturnCode(answer, name);
1843 }
1844 } else {
1845 answer = doSearch(name, filter, cons, relative, waitForReply);
1846
1847 processReturnCode(answer, name);
1848 }
1849 return new LdapSearchEnumeration(this, answer,
1850 fullyQualifiedName(name),
1851 args, cont);
1852
1853 } catch (LdapReferralException e) {
1854 if (handleReferrals == LdapClient.LDAP_REF_THROW)
1855 throw cont.fillInException(e);
1856
1857
1858 while (true) {
1859
1860 @SuppressWarnings("unchecked")
1861 LdapReferralContext refCtx = (LdapReferralContext)
1862 e.getReferralContext(envprops, bindCtls);
1863
1864
1865 try {
1866
1867 return refCtx.search(name, filter, cons);
1868
1869 } catch (LdapReferralException re) {
1870 e = re;
1871 continue;
1872
1873 } finally {
1874
1875 refCtx.close();
1876 }
1877 }
1878
1879 } catch (LimitExceededException e) {
1880 LdapSearchEnumeration res =
1881 new LdapSearchEnumeration(this, answer, fullyQualifiedName(name),
1882 args, cont);
1883 res.setNamingException(e);
1884 return res;
1885
1886 } catch (PartialResultException e) {
1887 LdapSearchEnumeration res =
1888 new LdapSearchEnumeration(this, answer, fullyQualifiedName(name),
1889 args, cont);
1890
1891 res.setNamingException(e);
1892 return res;
1893
1894 } catch (IOException e) {
1895 NamingException e2 = new CommunicationException(e.getMessage());
1896 e2.setRootCause(e);
1897 throw cont.fillInException(e2);
1898
1899 } catch (NamingException e) {
1900 throw cont.fillInException(e);
1901 }
1902 }
1903
1904
1905 LdapResult getSearchReply(LdapClient eClnt, LdapResult res)
1906 throws NamingException {
1907
1908
1909
1910
1911
1912
1913 if (clnt != eClnt) {
1914 throw new CommunicationException(
1915 "Context's connection changed; unable to continue enumeration");
1916 }
1917
1918 try {
1919 return eClnt.getSearchReply(batchSize, res, binaryAttrs);
1920 } catch (IOException e) {
1921 NamingException e2 = new CommunicationException(e.getMessage());
1922 e2.setRootCause(e);
1923 throw e2;
1924 }
1925 }
1926
1927
1928 private LdapResult doSearchOnce(Name name, String filter,
1929 SearchControls cons, boolean relative) throws NamingException {
1930
1931 int savedBatchSize = batchSize;
1932 batchSize = 2;
1933
1934 LdapResult answer = doSearch(name, filter, cons, relative, true);
1935
1936 batchSize = savedBatchSize;
1937 return answer;
1938 }
1939
1940 private LdapResult doSearch(Name name, String filter, SearchControls cons,
1941 boolean relative, boolean waitForReply) throws NamingException {
1942 ensureOpen();
1943 try {
1944 int scope;
1945
1946 switch (cons.getSearchScope()) {
1947 case SearchControls.OBJECT_SCOPE:
1948 scope = LdapClient.SCOPE_BASE_OBJECT;
1949 break;
1950 default:
1951 case SearchControls.ONELEVEL_SCOPE:
1952 scope = LdapClient.SCOPE_ONE_LEVEL;
1953 break;
1954 case SearchControls.SUBTREE_SCOPE:
1955 scope = LdapClient.SCOPE_SUBTREE;
1956 break;
1957 }
1958
1959
1960
1961
1962 String[] retattrs = cons.getReturningAttributes();
1963 if (retattrs != null && retattrs.length == 0) {
1964
1965
1966 retattrs = new String[1];
1967 retattrs[0] = "1.1";
1968 }
1969
1970 String nm = (relative
1971 ? fullyQualifiedName(name)
1972 : (name.isEmpty()
1973 ? ""
1974 : name.get(0)));
1975
1976
1977
1978 int msecLimit = cons.getTimeLimit();
1979 int secLimit = 0;
1980
1981 if (msecLimit > 0) {
1982 secLimit = (msecLimit / 1000) + 1;
1983 }
1984
1985 LdapResult answer =
1986 clnt.search(nm,
1987 scope,
1988 derefAliases,
1989 (int)cons.getCountLimit(),
1990 secLimit,
1991 cons.getReturningObjFlag() ? false : typesOnly,
1992 retattrs,
1993 filter,
1994 batchSize,
1995 reqCtls,
1996 binaryAttrs,
1997 waitForReply,
1998 replyQueueSize);
1999 respCtls = answer.resControls;
2000 return answer;
2001
2002 } catch (IOException e) {
2003 NamingException e2 = new CommunicationException(e.getMessage());
2004 e2.setRootCause(e);
2005 throw e2;
2006 }
2007 }
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026 private static boolean searchToCompare(
2027 String filter,
2028 SearchControls cons,
2029 String tokens[]) {
2030
2031
2032 if (cons.getSearchScope() != SearchControls.OBJECT_SCOPE) {
2033 return false;
2034 }
2035
2036
2037 String[] attrs = cons.getReturningAttributes();
2038 if (attrs == null || attrs.length != 0) {
2039 return false;
2040 }
2041
2042
2043 if (! filterToAssertion(filter, tokens)) {
2044 return false;
2045 }
2046
2047
2048 return true;
2049 }
2050
2051
2052
2053
2054
2055
2056
2057 private static boolean filterToAssertion(String filter, String tokens[]) {
2058
2059
2060 StringTokenizer assertionTokenizer = new StringTokenizer(filter, "=");
2061
2062 if (assertionTokenizer.countTokens() != 2) {
2063 return false;
2064 }
2065
2066 tokens[0] = assertionTokenizer.nextToken();
2067 tokens[1] = assertionTokenizer.nextToken();
2068
2069
2070 if (tokens[1].indexOf('*') != -1) {
2071 return false;
2072 }
2073
2074
2075 boolean hasParens = false;
2076 int len = tokens[1].length();
2077
2078 if ((tokens[0].charAt(0) == '(') &&
2079 (tokens[1].charAt(len - 1) == ')')) {
2080 hasParens = true;
2081
2082 } else if ((tokens[0].charAt(0) == '(') ||
2083 (tokens[1].charAt(len - 1) == ')')) {
2084 return false;
2085 }
2086
2087
2088 StringTokenizer illegalCharsTokenizer =
2089 new StringTokenizer(tokens[0], "()&|!=~><*", true);
2090
2091 if (illegalCharsTokenizer.countTokens() != (hasParens ? 2 : 1)) {
2092 return false;
2093 }
2094
2095 illegalCharsTokenizer =
2096 new StringTokenizer(tokens[1], "()&|!=~><*", true);
2097
2098 if (illegalCharsTokenizer.countTokens() != (hasParens ? 2 : 1)) {
2099 return false;
2100 }
2101
2102
2103 if (hasParens) {
2104 tokens[0] = tokens[0].substring(1);
2105 tokens[1] = tokens[1].substring(0, len - 1);
2106 }
2107
2108 return true;
2109 }
2110
2111 private LdapResult compare(Name name, String type, String value)
2112 throws IOException, NamingException {
2113
2114 ensureOpen();
2115 String nm = fullyQualifiedName(name);
2116
2117 LdapResult answer = clnt.compare(nm, type, value, reqCtls);
2118 respCtls = answer.resControls;
2119
2120 return answer;
2121 }
2122
2123 private static SearchControls cloneSearchControls(SearchControls cons) {
2124 if (cons == null) {
2125 return null;
2126 }
2127 String[] retAttrs = cons.getReturningAttributes();
2128 if (retAttrs != null) {
2129 String[] attrs = new String[retAttrs.length];
2130 System.arraycopy(retAttrs, 0, attrs, 0, retAttrs.length);
2131 retAttrs = attrs;
2132 }
2133 return new SearchControls(cons.getSearchScope(),
2134 cons.getCountLimit(),
2135 cons.getTimeLimit(),
2136 retAttrs,
2137 cons.getReturningObjFlag(),
2138 cons.getDerefLinkFlag());
2139 }
2140
2141
2142
2143
2144
2145
2146 protected Hashtable<String, Object> p_getEnvironment() {
2147 return envprops;
2148 }
2149
2150 @SuppressWarnings("unchecked")
2151 public Hashtable<String, Object> getEnvironment() throws NamingException {
2152 return (envprops == null
2153 ? new Hashtable<String, Object>(5, 0.75f)
2154 : (Hashtable<String, Object>)envprops.clone());
2155 }
2156
2157 @SuppressWarnings("unchecked")
2158 public Object removeFromEnvironment(String propName)
2159 throws NamingException {
2160
2161
2162 if (envprops == null || envprops.get(propName) == null) {
2163 return null;
2164 }
2165 switch (propName) {
2166 case REF_SEPARATOR:
2167 addrEncodingSeparator = DEFAULT_REF_SEPARATOR;
2168 break;
2169 case TYPES_ONLY:
2170 typesOnly = DEFAULT_TYPES_ONLY;
2171 break;
2172 case DELETE_RDN:
2173 deleteRDN = DEFAULT_DELETE_RDN;
2174 break;
2175 case DEREF_ALIASES:
2176 derefAliases = DEFAULT_DEREF_ALIASES;
2177 break;
2178 case Context.BATCHSIZE:
2179 batchSize = DEFAULT_BATCH_SIZE;
2180 break;
2181 case REFERRAL_LIMIT:
2182 referralHopLimit = DEFAULT_REFERRAL_LIMIT;
2183 break;
2184 case Context.REFERRAL:
2185 setReferralMode(null, true);
2186 break;
2187 case BINARY_ATTRIBUTES:
2188 setBinaryAttributes(null);
2189 break;
2190 case CONNECT_TIMEOUT:
2191 connectTimeout = -1;
2192 break;
2193 case READ_TIMEOUT:
2194 readTimeout = -1;
2195 break;
2196 case WAIT_FOR_REPLY:
2197 waitForReply = true;
2198 break;
2199 case REPLY_QUEUE_SIZE:
2200 replyQueueSize = -1;
2201 break;
2202
2203
2204
2205 case Context.SECURITY_PROTOCOL:
2206 closeConnection(SOFT_CLOSE);
2207
2208 if (useSsl && !hasLdapsScheme) {
2209 useSsl = false;
2210 url = null;
2211 if (useDefaultPortNumber) {
2212 port_number = DEFAULT_PORT;
2213 }
2214 }
2215 break;
2216 case VERSION:
2217 case SOCKET_FACTORY:
2218 closeConnection(SOFT_CLOSE);
2219 break;
2220 case Context.SECURITY_AUTHENTICATION:
2221 case Context.SECURITY_PRINCIPAL:
2222 case Context.SECURITY_CREDENTIALS:
2223 sharable = false;
2224 break;
2225 }
2226
2227
2228 envprops = (Hashtable<String, Object>)envprops.clone();
2229 return envprops.remove(propName);
2230 }
2231
2232 @SuppressWarnings("unchecked")
2233 public Object addToEnvironment(String propName, Object propVal)
2234 throws NamingException {
2235
2236
2237 if (propVal == null) {
2238 return removeFromEnvironment(propName);
2239 }
2240 switch (propName) {
2241 case REF_SEPARATOR:
2242 setRefSeparator((String)propVal);
2243 break;
2244 case TYPES_ONLY:
2245 setTypesOnly((String)propVal);
2246 break;
2247 case DELETE_RDN:
2248 setDeleteRDN((String)propVal);
2249 break;
2250 case DEREF_ALIASES:
2251 setDerefAliases((String)propVal);
2252 break;
2253 case Context.BATCHSIZE:
2254 setBatchSize((String)propVal);
2255 break;
2256 case REFERRAL_LIMIT:
2257 setReferralLimit((String)propVal);
2258 break;
2259 case Context.REFERRAL:
2260 setReferralMode((String)propVal, true);
2261 break;
2262 case BINARY_ATTRIBUTES:
2263 setBinaryAttributes((String)propVal);
2264 break;
2265 case CONNECT_TIMEOUT:
2266 setConnectTimeout((String)propVal);
2267 break;
2268 case READ_TIMEOUT:
2269 setReadTimeout((String)propVal);
2270 break;
2271 case WAIT_FOR_REPLY:
2272 setWaitForReply((String)propVal);
2273 break;
2274 case REPLY_QUEUE_SIZE:
2275 setReplyQueueSize((String)propVal);
2276 break;
2277
2278
2279
2280 case Context.SECURITY_PROTOCOL:
2281 closeConnection(SOFT_CLOSE);
2282
2283 if ("ssl".equals(propVal)) {
2284 useSsl = true;
2285 url = null;
2286 if (useDefaultPortNumber) {
2287 port_number = DEFAULT_SSL_PORT;
2288 }
2289 }
2290 break;
2291 case VERSION:
2292 case SOCKET_FACTORY:
2293 closeConnection(SOFT_CLOSE);
2294 break;
2295 case Context.SECURITY_AUTHENTICATION:
2296 case Context.SECURITY_PRINCIPAL:
2297 case Context.SECURITY_CREDENTIALS:
2298 sharable = false;
2299 break;
2300 }
2301
2302
2303 envprops = (envprops == null
2304 ? new Hashtable<String, Object>(5, 0.75f)
2305 : (Hashtable<String, Object>)envprops.clone());
2306 return envprops.put(propName, propVal);
2307 }
2308
2309
2310
2311
2312
2313 void setProviderUrl(String providerUrl) {
2314 if (envprops != null) {
2315 envprops.put(Context.PROVIDER_URL, providerUrl);
2316 }
2317 }
2318
2319
2320
2321
2322
2323
2324 void setDomainName(String domainName) {
2325 if (envprops != null) {
2326 envprops.put(DOMAIN_NAME, domainName);
2327 }
2328 }
2329
2330 private void initEnv() throws NamingException {
2331 if (envprops == null) {
2332
2333 setReferralMode(null, false);
2334 return;
2335 }
2336
2337
2338 setBatchSize((String)envprops.get(Context.BATCHSIZE));
2339
2340
2341 setRefSeparator((String)envprops.get(REF_SEPARATOR));
2342
2343
2344 setDeleteRDN((String)envprops.get(DELETE_RDN));
2345
2346
2347 setTypesOnly((String)envprops.get(TYPES_ONLY));
2348
2349
2350 setDerefAliases((String)envprops.get(DEREF_ALIASES));
2351
2352
2353 setReferralLimit((String)envprops.get(REFERRAL_LIMIT));
2354
2355 setBinaryAttributes((String)envprops.get(BINARY_ATTRIBUTES));
2356
2357 bindCtls = cloneControls((Control[]) envprops.get(BIND_CONTROLS));
2358
2359
2360 setReferralMode((String)envprops.get(Context.REFERRAL), false);
2361
2362
2363 setConnectTimeout((String)envprops.get(CONNECT_TIMEOUT));
2364
2365
2366 setReadTimeout((String)envprops.get(READ_TIMEOUT));
2367
2368
2369
2370 setWaitForReply((String)envprops.get(WAIT_FOR_REPLY));
2371
2372
2373 setReplyQueueSize((String)envprops.get(REPLY_QUEUE_SIZE));
2374
2375
2376
2377 }
2378
2379 private void setDeleteRDN(String deleteRDNProp) {
2380 if ((deleteRDNProp != null) &&
2381 (deleteRDNProp.equalsIgnoreCase("false"))) {
2382 deleteRDN = false;
2383 } else {
2384 deleteRDN = DEFAULT_DELETE_RDN;
2385 }
2386 }
2387
2388 private void setTypesOnly(String typesOnlyProp) {
2389 if ((typesOnlyProp != null) &&
2390 (typesOnlyProp.equalsIgnoreCase("true"))) {
2391 typesOnly = true;
2392 } else {
2393 typesOnly = DEFAULT_TYPES_ONLY;
2394 }
2395 }
2396
2397
2398
2399
2400 private void setBatchSize(String batchSizeProp) {
2401
2402 if (batchSizeProp != null) {
2403 batchSize = Integer.parseInt(batchSizeProp);
2404 } else {
2405 batchSize = DEFAULT_BATCH_SIZE;
2406 }
2407 }
2408
2409
2410
2411
2412
2413 private void setReferralMode(String ref, boolean update) {
2414
2415 if (ref != null) {
2416 switch (ref) {
2417 case "follow-scheme":
2418 handleReferrals = LdapClient.LDAP_REF_FOLLOW_SCHEME;
2419 break;
2420 case "follow":
2421 handleReferrals = LdapClient.LDAP_REF_FOLLOW;
2422 break;
2423 case "throw":
2424 handleReferrals = LdapClient.LDAP_REF_THROW;
2425 break;
2426 case "ignore":
2427 handleReferrals = LdapClient.LDAP_REF_IGNORE;
2428 break;
2429 default:
2430 throw new IllegalArgumentException(
2431 "Illegal value for " + Context.REFERRAL + " property.");
2432 }
2433 } else {
2434 handleReferrals = DEFAULT_REFERRAL_MODE;
2435 }
2436
2437 if (handleReferrals == LdapClient.LDAP_REF_IGNORE) {
2438
2439 reqCtls = addControl(reqCtls, manageReferralControl);
2440
2441 } else if (update) {
2442
2443
2444 reqCtls = removeControl(reqCtls, manageReferralControl);
2445
2446 }
2447 }
2448
2449
2450
2451
2452 private void setDerefAliases(String deref) {
2453 if (deref != null) {
2454 switch (deref) {
2455 case "never":
2456 derefAliases = 0;
2457 break;
2458 case "searching":
2459 derefAliases = 1;
2460 break;
2461 case "finding":
2462 derefAliases = 2;
2463 break;
2464 case "always":
2465 derefAliases = 3;
2466 break;
2467 default:
2468 throw new IllegalArgumentException("Illegal value for " +
2469 DEREF_ALIASES + " property.");
2470 }
2471 } else {
2472 derefAliases = DEFAULT_DEREF_ALIASES;
2473 }
2474 }
2475
2476 private void setRefSeparator(String sepStr) throws NamingException {
2477 if (sepStr != null && sepStr.length() > 0) {
2478 addrEncodingSeparator = sepStr.charAt(0);
2479 } else {
2480 addrEncodingSeparator = DEFAULT_REF_SEPARATOR;
2481 }
2482 }
2483
2484
2485
2486
2487 private void setReferralLimit(String referralLimitProp) {
2488
2489 if (referralLimitProp != null) {
2490 referralHopLimit = Integer.parseInt(referralLimitProp);
2491
2492
2493 if (referralHopLimit == 0)
2494 referralHopLimit = Integer.MAX_VALUE;
2495 } else {
2496 referralHopLimit = DEFAULT_REFERRAL_LIMIT;
2497 }
2498 }
2499
2500
2501 void setHopCount(int hopCount) {
2502 this.hopCount = hopCount;
2503 }
2504
2505
2506
2507
2508 private void setConnectTimeout(String connectTimeoutProp) {
2509 if (connectTimeoutProp != null) {
2510 connectTimeout = Integer.parseInt(connectTimeoutProp);
2511 } else {
2512 connectTimeout = -1;
2513 }
2514 }
2515
2516
2517
2518
2519 private void setReplyQueueSize(String replyQueueSizeProp) {
2520 if (replyQueueSizeProp != null) {
2521 replyQueueSize = Integer.parseInt(replyQueueSizeProp);
2522
2523 if (replyQueueSize <= 0) {
2524 replyQueueSize = -1;
2525 }
2526 } else {
2527 replyQueueSize = -1;
2528 }
2529 }
2530
2531
2532
2533
2534
2535 private void setWaitForReply(String waitForReplyProp) {
2536 if (waitForReplyProp != null &&
2537 (waitForReplyProp.equalsIgnoreCase("false"))) {
2538 waitForReply = false;
2539 } else {
2540 waitForReply = true;
2541 }
2542 }
2543
2544
2545
2546
2547 private void setReadTimeout(String readTimeoutProp) {
2548 if (readTimeoutProp != null) {
2549 readTimeout = Integer.parseInt(readTimeoutProp);
2550 } else {
2551 readTimeout = -1;
2552 }
2553 }
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565 private static Vector<Vector<String>> extractURLs(String refString) {
2566
2567 int separator = 0;
2568 int urlCount = 0;
2569
2570
2571 while ((separator = refString.indexOf('\n', separator)) >= 0) {
2572 separator++;
2573 urlCount++;
2574 }
2575
2576 Vector<Vector<String>> referrals = new Vector<>(urlCount);
2577 int iURL;
2578 int i = 0;
2579
2580 separator = refString.indexOf('\n');
2581 iURL = separator + 1;
2582 while ((separator = refString.indexOf('\n', iURL)) >= 0) {
2583 Vector<String> referral = new Vector<>(1);
2584 referral.addElement(refString.substring(iURL, separator));
2585 referrals.addElement(referral);
2586 iURL = separator + 1;
2587 }
2588 Vector<String> referral = new Vector<>(1);
2589 referral.addElement(refString.substring(iURL));
2590 referrals.addElement(referral);
2591
2592 return referrals;
2593 }
2594
2595
2596
2597
2598
2599 private void setBinaryAttributes(String attrIds) {
2600 if (attrIds == null) {
2601 binaryAttrs = null;
2602 } else {
2603 binaryAttrs = new Hashtable<>(11, 0.75f);
2604 StringTokenizer tokens =
2605 new StringTokenizer(attrIds.toLowerCase(Locale.ENGLISH), " ");
2606
2607 while (tokens.hasMoreTokens()) {
2608 binaryAttrs.put(tokens.nextToken(), Boolean.TRUE);
2609 }
2610 }
2611 }
2612
2613
2614
2615 @SuppressWarnings("deprecation")
2616 protected void finalize() {
2617 try {
2618 close();
2619 } catch (NamingException e) {
2620
2621 }
2622 }
2623
2624 synchronized public void close() throws NamingException {
2625 if (debug) {
2626 System.err.println("LdapCtx: close() called " + this);
2627 (new Throwable()).printStackTrace();
2628 }
2629
2630
2631 if (eventSupport != null) {
2632 eventSupport.cleanup();
2633 removeUnsolicited();
2634 }
2635
2636
2637 if (enumCount > 0) {
2638 if (debug)
2639 System.err.println("LdapCtx: close deferred");
2640 closeRequested = true;
2641 return;
2642 }
2643 closeConnection(SOFT_CLOSE);
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654 }
2655
2656 @SuppressWarnings("unchecked")
2657 public void reconnect(Control[] connCtls) throws NamingException {
2658
2659 envprops = (envprops == null
2660 ? new Hashtable<String, Object>(5, 0.75f)
2661 : (Hashtable<String, Object>)envprops.clone());
2662
2663 if (connCtls == null) {
2664 envprops.remove(BIND_CONTROLS);
2665 bindCtls = null;
2666 } else {
2667 envprops.put(BIND_CONTROLS, bindCtls = cloneControls(connCtls));
2668 }
2669
2670 sharable = false;
2671 reconnect = true;
2672 ensureOpen();
2673 }
2674
2675 private void ensureOpen() throws NamingException {
2676 ensureOpen(false);
2677 }
2678
2679 private void ensureOpen(boolean startTLS) throws NamingException {
2680
2681 try {
2682 if (clnt == null) {
2683 if (debug) {
2684 System.err.println("LdapCtx: Reconnecting " + this);
2685 }
2686
2687
2688 schemaTrees = new Hashtable<>(11, 0.75f);
2689 connect(startTLS);
2690
2691 } else if (!sharable || startTLS) {
2692
2693 synchronized (clnt) {
2694 if (!clnt.isLdapv3
2695 || clnt.referenceCount > 1
2696 || clnt.usingSaslStreams()) {
2697 closeConnection(SOFT_CLOSE);
2698 }
2699 }
2700
2701 schemaTrees = new Hashtable<>(11, 0.75f);
2702 connect(startTLS);
2703 }
2704
2705 } finally {
2706 sharable = true;
2707
2708 }
2709 }
2710
2711 private void connect(boolean startTLS) throws NamingException {
2712 if (debug) { System.err.println("LdapCtx: Connecting " + this); }
2713
2714 String user = null;
2715 Object passwd = null;
2716 String secProtocol = null;
2717 String socketFactory = null;
2718 String authMechanism = null;
2719 String ver = null;
2720 int ldapVersion;
2721 boolean usePool = false;
2722
2723 if (envprops != null) {
2724 user = (String)envprops.get(Context.SECURITY_PRINCIPAL);
2725 passwd = envprops.get(Context.SECURITY_CREDENTIALS);
2726 ver = (String)envprops.get(VERSION);
2727 secProtocol =
2728 useSsl ? "ssl" : (String)envprops.get(Context.SECURITY_PROTOCOL);
2729 socketFactory = (String)envprops.get(SOCKET_FACTORY);
2730 authMechanism =
2731 (String)envprops.get(Context.SECURITY_AUTHENTICATION);
2732
2733 usePool = "true".equalsIgnoreCase((String)envprops.get(ENABLE_POOL));
2734 }
2735
2736 if (socketFactory == null) {
2737 socketFactory =
2738 "ssl".equals(secProtocol) ? DEFAULT_SSL_FACTORY : null;
2739 }
2740
2741 if (authMechanism == null) {
2742 authMechanism = (user == null) ? "none" : "simple";
2743 }
2744
2745 try {
2746 boolean initial = (clnt == null);
2747
2748 if (initial || reconnect) {
2749 ldapVersion = (ver != null) ? Integer.parseInt(ver) :
2750 DEFAULT_LDAP_VERSION;
2751
2752 clnt = LdapClient.getInstance(
2753 usePool,
2754
2755
2756 hostname,
2757 port_number,
2758 socketFactory,
2759 connectTimeout,
2760 readTimeout,
2761 trace,
2762
2763
2764 ldapVersion,
2765 authMechanism,
2766 bindCtls,
2767 secProtocol,
2768
2769
2770 user,
2771 passwd,
2772
2773
2774 envprops);
2775
2776 reconnect = false;
2777
2778
2779
2780
2781
2782 if (clnt.authenticateCalled()) {
2783 return;
2784 }
2785
2786 } else if (sharable && startTLS) {
2787 return;
2788
2789 } else {
2790
2791
2792 ldapVersion = LdapClient.LDAP_VERSION3;
2793 }
2794
2795 LdapResult answer = clnt.authenticate(initial,
2796 user, passwd, ldapVersion, authMechanism, bindCtls, envprops);
2797
2798 respCtls = answer.resControls;
2799
2800 if (answer.status != LdapClient.LDAP_SUCCESS) {
2801 if (initial) {
2802 closeConnection(HARD_CLOSE);
2803 }
2804 processReturnCode(answer);
2805 }
2806
2807 } catch (LdapReferralException e) {
2808 if (handleReferrals == LdapClient.LDAP_REF_THROW)
2809 throw e;
2810
2811 String referral;
2812 LdapURL url;
2813 NamingException saved_ex = null;
2814
2815
2816
2817 while (true) {
2818
2819 if ((referral = e.getNextReferral()) == null) {
2820
2821
2822 if (saved_ex != null) {
2823 throw (NamingException)(saved_ex.fillInStackTrace());
2824 } else {
2825
2826 throw new NamingException(
2827 "Internal error processing referral during connection");
2828 }
2829 }
2830
2831
2832 url = new LdapURL(referral);
2833 hostname = url.getHost();
2834 if ((hostname != null) && (hostname.charAt(0) == '[')) {
2835 hostname = hostname.substring(1, hostname.length() - 1);
2836 }
2837 port_number = url.getPort();
2838
2839
2840 try {
2841 connect(startTLS);
2842 break;
2843
2844 } catch (NamingException ne) {
2845 saved_ex = ne;
2846 continue;
2847 }
2848 }
2849 }
2850 }
2851
2852 private void closeConnection(boolean hardclose) {
2853 removeUnsolicited();
2854
2855 if (clnt != null) {
2856 if (debug) {
2857 System.err.println("LdapCtx: calling clnt.close() " + this);
2858 }
2859 clnt.close(reqCtls, hardclose);
2860 clnt = null;
2861 }
2862 }
2863
2864
2865 private int enumCount = 0;
2866 private boolean closeRequested = false;
2867
2868 synchronized void incEnumCount() {
2869 ++enumCount;
2870 if (debug) System.err.println("LdapCtx: " + this + " enum inc: " + enumCount);
2871 }
2872
2873 synchronized void decEnumCount() {
2874 --enumCount;
2875 if (debug) System.err.println("LdapCtx: " + this + " enum dec: " + enumCount);
2876
2877 if (enumCount == 0 && closeRequested) {
2878 try {
2879 close();
2880 } catch (NamingException e) {
2881
2882 }
2883 }
2884 }
2885
2886
2887
2888
2889 protected void processReturnCode(LdapResult answer) throws NamingException {
2890 processReturnCode(answer, null, this, null, envprops, null);
2891 }
2892
2893 void processReturnCode(LdapResult answer, Name remainName)
2894 throws NamingException {
2895 processReturnCode(answer,
2896 (new CompositeName()).add(currentDN),
2897 this,
2898 remainName,
2899 envprops,
2900 fullyQualifiedName(remainName));
2901 }
2902
2903 protected void processReturnCode(LdapResult res, Name resolvedName,
2904 Object resolvedObj, Name remainName, Hashtable<?,?> envprops, String fullDN)
2905 throws NamingException {
2906
2907 String msg = LdapClient.getErrorMessage(res.status, res.errorMessage);
2908 NamingException e;
2909 LdapReferralException r = null;
2910
2911 switch (res.status) {
2912
2913 case LdapClient.LDAP_SUCCESS:
2914
2915
2916 if (res.referrals != null) {
2917
2918 msg = "Unprocessed Continuation Reference(s)";
2919
2920 if (handleReferrals == LdapClient.LDAP_REF_IGNORE) {
2921 e = new PartialResultException(msg);
2922 break;
2923 }
2924
2925
2926 int contRefCount = res.referrals.size();
2927 LdapReferralException head = null;
2928 LdapReferralException ptr = null;
2929
2930 msg = "Continuation Reference";
2931
2932
2933 for (int i = 0; i < contRefCount; i++) {
2934
2935 r = new LdapReferralException(resolvedName, resolvedObj,
2936 remainName, msg, envprops, fullDN, handleReferrals,
2937 reqCtls);
2938 r.setReferralInfo(res.referrals.elementAt(i), true);
2939
2940 if (hopCount > 1) {
2941 r.setHopCount(hopCount);
2942 }
2943
2944 if (head == null) {
2945 head = ptr = r;
2946 } else {
2947 ptr.nextReferralEx = r;
2948 ptr = r;
2949 }
2950 }
2951 res.referrals = null;
2952
2953 if (res.refEx == null) {
2954 res.refEx = head;
2955
2956 } else {
2957 ptr = res.refEx;
2958
2959 while (ptr.nextReferralEx != null) {
2960 ptr = ptr.nextReferralEx;
2961 }
2962 ptr.nextReferralEx = head;
2963 }
2964
2965
2966 if (hopCount > referralHopLimit) {
2967 NamingException lee =
2968 new LimitExceededException("Referral limit exceeded");
2969 lee.setRootCause(r);
2970 throw lee;
2971 }
2972 }
2973 return;
2974
2975 case LdapClient.LDAP_REFERRAL:
2976
2977 if (handleReferrals == LdapClient.LDAP_REF_IGNORE) {
2978 e = new PartialResultException(msg);
2979 break;
2980 }
2981
2982 r = new LdapReferralException(resolvedName, resolvedObj, remainName,
2983 msg, envprops, fullDN, handleReferrals, reqCtls);
2984
2985 Vector<String> refs;
2986 if (res.referrals == null) {
2987 refs = null;
2988 } else if (handleReferrals == LdapClient.LDAP_REF_FOLLOW_SCHEME) {
2989 refs = new Vector<>();
2990 for (String s : res.referrals.elementAt(0)) {
2991 if (s.startsWith("ldap:")) {
2992 refs.add(s);
2993 }
2994 }
2995 if (refs.isEmpty()) {
2996 refs = null;
2997 }
2998 } else {
2999 refs = res.referrals.elementAt(0);
3000 }
3001 r.setReferralInfo(refs, false);
3002
3003 if (hopCount > 1) {
3004 r.setHopCount(hopCount);
3005 }
3006
3007
3008 if (hopCount > referralHopLimit) {
3009 NamingException lee =
3010 new LimitExceededException("Referral limit exceeded");
3011 lee.setRootCause(r);
3012 e = lee;
3013
3014 } else {
3015 e = r;
3016 }
3017 break;
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031 case LdapClient.LDAP_PARTIAL_RESULTS:
3032
3033 if (handleReferrals == LdapClient.LDAP_REF_IGNORE) {
3034 e = new PartialResultException(msg);
3035 break;
3036 }
3037
3038
3039 if ((res.errorMessage != null) && (!res.errorMessage.equals(""))) {
3040 res.referrals = extractURLs(res.errorMessage);
3041 } else {
3042 e = new PartialResultException(msg);
3043 break;
3044 }
3045
3046
3047 r = new LdapReferralException(resolvedName,
3048 resolvedObj,
3049 remainName,
3050 msg,
3051 envprops,
3052 fullDN,
3053 handleReferrals,
3054 reqCtls);
3055
3056 if (hopCount > 1) {
3057 r.setHopCount(hopCount);
3058 }
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069 if (((res.entries == null) || (res.entries.isEmpty())) &&
3070 ((res.referrals != null) && (res.referrals.size() == 1))) {
3071
3072 r.setReferralInfo(res.referrals, false);
3073
3074
3075 if (hopCount > referralHopLimit) {
3076 NamingException lee =
3077 new LimitExceededException("Referral limit exceeded");
3078 lee.setRootCause(r);
3079 e = lee;
3080
3081 } else {
3082 e = r;
3083 }
3084
3085 } else {
3086 r.setReferralInfo(res.referrals, true);
3087 res.refEx = r;
3088 return;
3089 }
3090 break;
3091
3092 case LdapClient.LDAP_INVALID_DN_SYNTAX:
3093 case LdapClient.LDAP_NAMING_VIOLATION:
3094
3095 if (remainName != null) {
3096 e = new
3097 InvalidNameException(remainName.toString() + ": " + msg);
3098 } else {
3099 e = new InvalidNameException(msg);
3100 }
3101 break;
3102
3103 default:
3104 e = mapErrorCode(res.status, res.errorMessage);
3105 break;
3106 }
3107 e.setResolvedName(resolvedName);
3108 e.setResolvedObj(resolvedObj);
3109 e.setRemainingName(remainName);
3110 throw e;
3111 }
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122 public static NamingException mapErrorCode(int errorCode,
3123 String errorMessage) {
3124
3125 if (errorCode == LdapClient.LDAP_SUCCESS)
3126 return null;
3127
3128 NamingException e = null;
3129 String message = LdapClient.getErrorMessage(errorCode, errorMessage);
3130
3131 switch (errorCode) {
3132
3133 case LdapClient.LDAP_ALIAS_DEREFERENCING_PROBLEM:
3134 e = new NamingException(message);
3135 break;
3136
3137 case LdapClient.LDAP_ALIAS_PROBLEM:
3138 e = new NamingException(message);
3139 break;
3140
3141 case LdapClient.LDAP_ATTRIBUTE_OR_VALUE_EXISTS:
3142 e = new AttributeInUseException(message);
3143 break;
3144
3145 case LdapClient.LDAP_AUTH_METHOD_NOT_SUPPORTED:
3146 case LdapClient.LDAP_CONFIDENTIALITY_REQUIRED:
3147 case LdapClient.LDAP_STRONG_AUTH_REQUIRED:
3148 case LdapClient.LDAP_INAPPROPRIATE_AUTHENTICATION:
3149 e = new AuthenticationNotSupportedException(message);
3150 break;
3151
3152 case LdapClient.LDAP_ENTRY_ALREADY_EXISTS:
3153 e = new NameAlreadyBoundException(message);
3154 break;
3155
3156 case LdapClient.LDAP_INVALID_CREDENTIALS:
3157 case LdapClient.LDAP_SASL_BIND_IN_PROGRESS:
3158 e = new AuthenticationException(message);
3159 break;
3160
3161 case LdapClient.LDAP_INAPPROPRIATE_MATCHING:
3162 e = new InvalidSearchFilterException(message);
3163 break;
3164
3165 case LdapClient.LDAP_INSUFFICIENT_ACCESS_RIGHTS:
3166 e = new NoPermissionException(message);
3167 break;
3168
3169 case LdapClient.LDAP_INVALID_ATTRIBUTE_SYNTAX:
3170 case LdapClient.LDAP_CONSTRAINT_VIOLATION:
3171 e = new InvalidAttributeValueException(message);
3172 break;
3173
3174 case LdapClient.LDAP_LOOP_DETECT:
3175 e = new NamingException(message);
3176 break;
3177
3178 case LdapClient.LDAP_NO_SUCH_ATTRIBUTE:
3179 e = new NoSuchAttributeException(message);
3180 break;
3181
3182 case LdapClient.LDAP_NO_SUCH_OBJECT:
3183 e = new NameNotFoundException(message);
3184 break;
3185
3186 case LdapClient.LDAP_OBJECT_CLASS_MODS_PROHIBITED:
3187 case LdapClient.LDAP_OBJECT_CLASS_VIOLATION:
3188 case LdapClient.LDAP_NOT_ALLOWED_ON_RDN:
3189 e = new SchemaViolationException(message);
3190 break;
3191
3192 case LdapClient.LDAP_NOT_ALLOWED_ON_NON_LEAF:
3193 e = new ContextNotEmptyException(message);
3194 break;
3195
3196 case LdapClient.LDAP_OPERATIONS_ERROR:
3197
3198 e = new NamingException(message);
3199 break;
3200
3201 case LdapClient.LDAP_OTHER:
3202 e = new NamingException(message);
3203 break;
3204
3205 case LdapClient.LDAP_PROTOCOL_ERROR:
3206 e = new CommunicationException(message);
3207 break;
3208
3209 case LdapClient.LDAP_SIZE_LIMIT_EXCEEDED:
3210 e = new SizeLimitExceededException(message);
3211 break;
3212
3213 case LdapClient.LDAP_TIME_LIMIT_EXCEEDED:
3214 e = new TimeLimitExceededException(message);
3215 break;
3216
3217 case LdapClient.LDAP_UNAVAILABLE_CRITICAL_EXTENSION:
3218 e = new OperationNotSupportedException(message);
3219 break;
3220
3221 case LdapClient.LDAP_UNAVAILABLE:
3222 case LdapClient.LDAP_BUSY:
3223 e = new ServiceUnavailableException(message);
3224 break;
3225
3226 case LdapClient.LDAP_UNDEFINED_ATTRIBUTE_TYPE:
3227 e = new InvalidAttributeIdentifierException(message);
3228 break;
3229
3230 case LdapClient.LDAP_UNWILLING_TO_PERFORM:
3231 e = new OperationNotSupportedException(message);
3232 break;
3233
3234 case LdapClient.LDAP_COMPARE_FALSE:
3235 case LdapClient.LDAP_COMPARE_TRUE:
3236 case LdapClient.LDAP_IS_LEAF:
3237
3238
3239 e = new NamingException(message);
3240 break;
3241
3242 case LdapClient.LDAP_ADMIN_LIMIT_EXCEEDED:
3243 e = new LimitExceededException(message);
3244 break;
3245
3246 case LdapClient.LDAP_REFERRAL:
3247 e = new NamingException(message);
3248 break;
3249
3250 case LdapClient.LDAP_PARTIAL_RESULTS:
3251 e = new NamingException(message);
3252 break;
3253
3254 case LdapClient.LDAP_INVALID_DN_SYNTAX:
3255 case LdapClient.LDAP_NAMING_VIOLATION:
3256 e = new InvalidNameException(message);
3257 break;
3258
3259 default:
3260 e = new NamingException(message);
3261 break;
3262 }
3263
3264 return e;
3265 }
3266
3267
3268
3269 public ExtendedResponse extendedOperation(ExtendedRequest request)
3270 throws NamingException {
3271
3272 boolean startTLS = (request.getID().equals(STARTTLS_REQ_OID));
3273 ensureOpen(startTLS);
3274
3275 try {
3276
3277 LdapResult answer =
3278 clnt.extendedOp(request.getID(), request.getEncodedValue(),
3279 reqCtls, startTLS);
3280 respCtls = answer.resControls;
3281
3282 if (answer.status != LdapClient.LDAP_SUCCESS) {
3283 processReturnCode(answer, new CompositeName());
3284 }
3285
3286
3287 int len = (answer.extensionValue == null) ?
3288 0 :
3289 answer.extensionValue.length;
3290
3291 ExtendedResponse er =
3292 request.createExtendedResponse(answer.extensionId,
3293 answer.extensionValue, 0, len);
3294
3295 if (er instanceof StartTlsResponseImpl) {
3296
3297 String domainName = (String)
3298 (envprops != null ? envprops.get(DOMAIN_NAME) : null);
3299 ((StartTlsResponseImpl)er).setConnection(clnt.conn, domainName);
3300 }
3301 return er;
3302
3303 } catch (LdapReferralException e) {
3304
3305 if (handleReferrals == LdapClient.LDAP_REF_THROW)
3306 throw e;
3307
3308
3309 while (true) {
3310
3311 LdapReferralContext refCtx =
3312 (LdapReferralContext)e.getReferralContext(envprops, bindCtls);
3313
3314
3315 try {
3316
3317 return refCtx.extendedOperation(request);
3318
3319 } catch (LdapReferralException re) {
3320 e = re;
3321 continue;
3322
3323 } finally {
3324
3325 refCtx.close();
3326 }
3327 }
3328
3329 } catch (IOException e) {
3330 NamingException e2 = new CommunicationException(e.getMessage());
3331 e2.setRootCause(e);
3332 throw e2;
3333 }
3334 }
3335
3336 public void setRequestControls(Control[] reqCtls) throws NamingException {
3337 if (handleReferrals == LdapClient.LDAP_REF_IGNORE) {
3338 this.reqCtls = addControl(reqCtls, manageReferralControl);
3339 } else {
3340 this.reqCtls = cloneControls(reqCtls);
3341 }
3342 }
3343
3344 public Control[] getRequestControls() throws NamingException {
3345 return cloneControls(reqCtls);
3346 }
3347
3348 public Control[] getConnectControls() throws NamingException {
3349 return cloneControls(bindCtls);
3350 }
3351
3352 public Control[] getResponseControls() throws NamingException {
3353 return (respCtls != null)? convertControls(respCtls) : null;
3354 }
3355
3356
3357
3358
3359
3360 Control[] convertControls(Vector<Control> ctls) throws NamingException {
3361 int count = ctls.size();
3362
3363 if (count == 0) {
3364 return null;
3365 }
3366
3367 Control[] controls = new Control[count];
3368
3369 for (int i = 0; i < count; i++) {
3370
3371 controls[i] = myResponseControlFactory.getControlInstance(
3372 ctls.elementAt(i));
3373
3374
3375 if (controls[i] == null) {
3376 controls[i] = ControlFactory.getControlInstance(
3377 ctls.elementAt(i), this, envprops);
3378 }
3379 }
3380 return controls;
3381 }
3382
3383 private static Control[] addControl(Control[] prevCtls, Control addition) {
3384 if (prevCtls == null) {
3385 return new Control[]{addition};
3386 }
3387
3388
3389 int found = findControl(prevCtls, addition);
3390 if (found != -1) {
3391 return prevCtls;
3392 }
3393
3394 Control[] newCtls = new Control[prevCtls.length+1];
3395 System.arraycopy(prevCtls, 0, newCtls, 0, prevCtls.length);
3396 newCtls[prevCtls.length] = addition;
3397 return newCtls;
3398 }
3399
3400 private static int findControl(Control[] ctls, Control target) {
3401 for (int i = 0; i < ctls.length; i++) {
3402 if (ctls[i] == target) {
3403 return i;
3404 }
3405 }
3406 return -1;
3407 }
3408
3409 private static Control[] removeControl(Control[] prevCtls, Control target) {
3410 if (prevCtls == null) {
3411 return null;
3412 }
3413
3414
3415 int found = findControl(prevCtls, target);
3416 if (found == -1) {
3417 return prevCtls;
3418 }
3419
3420
3421 Control[] newCtls = new Control[prevCtls.length-1];
3422 System.arraycopy(prevCtls, 0, newCtls, 0, found);
3423 System.arraycopy(prevCtls, found+1, newCtls, found,
3424 prevCtls.length-found-1);
3425 return newCtls;
3426 }
3427
3428 private static Control[] cloneControls(Control[] ctls) {
3429 if (ctls == null) {
3430 return null;
3431 }
3432 Control[] copiedCtls = new Control[ctls.length];
3433 System.arraycopy(ctls, 0, copiedCtls, 0, ctls.length);
3434 return copiedCtls;
3435 }
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445 public void addNamingListener(Name nm, int scope, NamingListener l)
3446 throws NamingException {
3447 addNamingListener(getTargetName(nm), scope, l);
3448 }
3449
3450 public void addNamingListener(String nm, int scope, NamingListener l)
3451 throws NamingException {
3452 if (eventSupport == null)
3453 eventSupport = new EventSupport(this);
3454 eventSupport.addNamingListener(getTargetName(new CompositeName(nm)),
3455 scope, l);
3456
3457
3458 if (l instanceof UnsolicitedNotificationListener && !unsolicited) {
3459 addUnsolicited();
3460 }
3461 }
3462
3463 public void removeNamingListener(NamingListener l) throws NamingException {
3464 if (eventSupport == null)
3465 return;
3466
3467 eventSupport.removeNamingListener(l);
3468
3469
3470 if (l instanceof UnsolicitedNotificationListener &&
3471 !eventSupport.hasUnsolicited()) {
3472 removeUnsolicited();
3473 }
3474 }
3475
3476 public void addNamingListener(String nm, String filter, SearchControls ctls,
3477 NamingListener l) throws NamingException {
3478 if (eventSupport == null)
3479 eventSupport = new EventSupport(this);
3480 eventSupport.addNamingListener(getTargetName(new CompositeName(nm)),
3481 filter, cloneSearchControls(ctls), l);
3482
3483
3484 if (l instanceof UnsolicitedNotificationListener && !unsolicited) {
3485 addUnsolicited();
3486 }
3487 }
3488
3489 public void addNamingListener(Name nm, String filter, SearchControls ctls,
3490 NamingListener l) throws NamingException {
3491 addNamingListener(getTargetName(nm), filter, ctls, l);
3492 }
3493
3494 public void addNamingListener(Name nm, String filter, Object[] filterArgs,
3495 SearchControls ctls, NamingListener l) throws NamingException {
3496 addNamingListener(getTargetName(nm), filter, filterArgs, ctls, l);
3497 }
3498
3499 public void addNamingListener(String nm, String filterExpr, Object[] filterArgs,
3500 SearchControls ctls, NamingListener l) throws NamingException {
3501 String strfilter = SearchFilter.format(filterExpr, filterArgs);
3502 addNamingListener(getTargetName(new CompositeName(nm)), strfilter, ctls, l);
3503 }
3504
3505 public boolean targetMustExist() {
3506 return true;
3507 }
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517 private static String getTargetName(Name nm) throws NamingException {
3518 if (nm instanceof CompositeName) {
3519 if (nm.size() > 1) {
3520 throw new InvalidNameException(
3521 "Target cannot span multiple namespaces: " + nm);
3522 } else if (nm.isEmpty()) {
3523 return "";
3524 } else {
3525 return nm.get(0);
3526 }
3527 } else {
3528
3529 return nm.toString();
3530 }
3531 }
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546 private void addUnsolicited() throws NamingException {
3547 if (debug) {
3548 System.out.println("LdapCtx.addUnsolicited: " + this);
3549 }
3550
3551
3552 ensureOpen();
3553 synchronized (eventSupport) {
3554 clnt.addUnsolicited(this);
3555 unsolicited = true;
3556 }
3557 }
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573 private void removeUnsolicited() {
3574 if (debug) {
3575 System.out.println("LdapCtx.removeUnsolicited: " + unsolicited);
3576 }
3577 if (eventSupport == null) {
3578 return;
3579 }
3580
3581
3582 synchronized(eventSupport) {
3583 if (unsolicited && clnt != null) {
3584 clnt.removeUnsolicited(this);
3585 }
3586 unsolicited = false;
3587 }
3588 }
3589
3590
3591
3592
3593
3594 void fireUnsolicited(Object obj) {
3595 if (debug) {
3596 System.out.println("LdapCtx.fireUnsolicited: " + obj);
3597 }
3598
3599 synchronized(eventSupport) {
3600 if (unsolicited) {
3601 eventSupport.fireUnsolicited(obj);
3602
3603 if (obj instanceof NamingException) {
3604 unsolicited = false;
3605
3606
3607
3608 }
3609 }
3610 }
3611 }
3612 }