1 /*
2  * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.jndi.ldap;
27 
28 import java.security.AccessControlContext;
29 import java.security.AccessController;
30 import java.security.PrivilegedActionException;
31 import java.security.PrivilegedExceptionAction;
32 import java.util.Vector;
33 import javax.naming.*;
34 import javax.naming.directory.*;
35 import javax.naming.spi.*;
36 import javax.naming.ldap.*;
37 import javax.naming.ldap.LdapName;
38 
39 import com.sun.jndi.toolkit.ctx.Continuation;
40 
41 final class LdapSearchEnumeration
42         extends AbstractLdapNamingEnumeration<SearchResult> {
43 
44     private Name startName;             // prefix of names of search results
45     private LdapCtx.SearchArgs searchArgs = null;
46 
47     private final AccessControlContext acc = AccessController.getContext();
48 
LdapSearchEnumeration(LdapCtx homeCtx, LdapResult search_results, String starter, LdapCtx.SearchArgs args, Continuation cont)49     LdapSearchEnumeration(LdapCtx homeCtx, LdapResult search_results,
50         String starter, LdapCtx.SearchArgs args, Continuation cont)
51         throws NamingException {
52 
53         super(homeCtx, search_results,
54               args.name, /* listArg */
55               cont);
56 
57         // fully qualified name of starting context of search
58         startName = new LdapName(starter);
59         searchArgs = args;
60     }
61 
62     @Override
createItem(String dn, Attributes attrs, Vector<Control> respCtls)63     protected SearchResult createItem(String dn, Attributes attrs,
64                                       Vector<Control> respCtls)
65             throws NamingException {
66 
67         Object obj = null;
68 
69         String relStart;         // name relative to starting search context
70         String relHome;          // name relative to homeCtx.currentDN
71         boolean relative = true; // whether relative to currentDN
72 
73         // need to strip off all but lowest component of dn
74         // so that is relative to current context (currentDN)
75 
76         try {
77             Name parsed = new LdapName(dn);
78             // System.err.println("dn string: " + dn);
79             // System.err.println("dn name: " + parsed);
80 
81             if (startName != null && parsed.startsWith(startName)) {
82                 relStart = parsed.getSuffix(startName.size()).toString();
83                 relHome = parsed.getSuffix(homeCtx.currentParsedDN.size()).toString();
84             } else {
85                 relative = false;
86                 relHome = relStart =
87                     LdapURL.toUrlString(homeCtx.hostname, homeCtx.port_number,
88                     dn, homeCtx.hasLdapsScheme);
89             }
90         } catch (NamingException e) {
91             // could not parse name
92             relative = false;
93             relHome = relStart =
94                 LdapURL.toUrlString(homeCtx.hostname, homeCtx.port_number,
95                 dn, homeCtx.hasLdapsScheme);
96         }
97 
98         // Name relative to search context
99         CompositeName cn = new CompositeName();
100         if (!relStart.isEmpty()) {
101             cn.add(relStart);
102         }
103 
104         // Name relative to homeCtx
105         CompositeName rcn = new CompositeName();
106         if (!relHome.isEmpty()) {
107             rcn.add(relHome);
108         }
109         //System.err.println("relStart: " + cn);
110         //System.err.println("relHome: " + rcn);
111 
112         // Fix attributes to be able to get schema
113         homeCtx.setParents(attrs, rcn);
114 
115         // only generate object when requested
116         if (searchArgs.cons.getReturningObjFlag()) {
117 
118             if (attrs.get(Obj.JAVA_ATTRIBUTES[Obj.CLASSNAME]) != null) {
119                 // Entry contains Java-object attributes (ser/ref object)
120                 // serialized object or object reference
121                 try {
122                     obj = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
123                         @Override
124                         public Object run() throws NamingException {
125                             return Obj.decodeObject(attrs);
126                         }
127                     }, acc);
128                 } catch (PrivilegedActionException e) {
129                     throw (NamingException)e.getException();
130                 }
131             }
132             if (obj == null) {
133                 obj = new LdapCtx(homeCtx, dn);
134             }
135 
136             // Call getObjectInstance before removing unrequested attributes
137             try {
138                 // rcn is either relative to homeCtx or a fully qualified DN
139                 obj = DirectoryManager.getObjectInstance(
140                     obj, rcn, (relative ? homeCtx : null),
141                     homeCtx.envprops, attrs);
142             } catch (NamingException e) {
143                 throw e;
144             } catch (Exception e) {
145                 NamingException ne =
146                     new NamingException(
147                             "problem generating object using object factory");
148                 ne.setRootCause(e);
149                 throw ne;
150             }
151 
152             // remove Java attributes from result, if necessary
153             // Even if CLASSNAME attr not there, there might be some
154             // residual attributes
155 
156             String[] reqAttrs;
157             if ((reqAttrs = searchArgs.reqAttrs) != null) {
158                 // create an attribute set for those requested
159                 Attributes rattrs = new BasicAttributes(true); // ignore case
160                 for (int i = 0; i < reqAttrs.length; i++) {
161                     rattrs.put(reqAttrs[i], null);
162                 }
163                 for (int i = 0; i < Obj.JAVA_ATTRIBUTES.length; i++) {
164                     // Remove Java-object attributes if not requested
165                     if (rattrs.get(Obj.JAVA_ATTRIBUTES[i]) == null) {
166                         attrs.remove(Obj.JAVA_ATTRIBUTES[i]);
167                     }
168                 }
169             }
170 
171         }
172 
173         /*
174          * name in search result is either the stringified composite name
175          * relative to the search context that can be passed directly to
176          * methods of the search context, or the fully qualified DN
177          * which can be used with the initial context.
178          */
179         SearchResult sr;
180         if (respCtls != null) {
181             sr = new SearchResultWithControls(
182                 (relative ? cn.toString() : relStart), obj, attrs,
183                 relative, homeCtx.convertControls(respCtls));
184         } else {
185             sr = new SearchResult(
186                 (relative ? cn.toString() : relStart),
187                 obj, attrs, relative);
188         }
189         sr.setNameInNamespace(dn);
190         return sr;
191     }
192 
193     @Override
appendUnprocessedReferrals(LdapReferralException ex)194     public void appendUnprocessedReferrals(LdapReferralException ex) {
195 
196         // a referral has been followed so do not create relative names
197         startName = null;
198         super.appendUnprocessedReferrals(ex);
199     }
200 
201     @Override
getReferredResults( LdapReferralContext refCtx)202     protected AbstractLdapNamingEnumeration<? extends NameClassPair> getReferredResults(
203             LdapReferralContext refCtx) throws NamingException {
204         // repeat the original operation at the new context
205         return (AbstractLdapNamingEnumeration<? extends NameClassPair>)refCtx.search(
206                 searchArgs.name, searchArgs.filter, searchArgs.cons);
207     }
208 
209     @Override
update(AbstractLdapNamingEnumeration<? extends NameClassPair> ne)210     protected void update(AbstractLdapNamingEnumeration<? extends NameClassPair> ne) {
211         super.update(ne);
212 
213         // Update search-specific variables
214         LdapSearchEnumeration se = (LdapSearchEnumeration)ne;
215         startName = se.startName;
216     }
217 
setStartName(Name nm)218     void setStartName(Name nm) {
219         startName = nm;
220     }
221 }
222