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