001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.tools;
028 import org.opends.messages.Message;
029
030 import java.io.File;
031 import java.io.FileInputStream;
032 import java.io.IOException;
033 import java.io.PrintStream;
034
035 import org.opends.server.protocols.asn1.ASN1OctetString;
036 import org.opends.server.protocols.ldap.LDAPControl;
037 import org.opends.server.protocols.ldap.LDAPResultCode;
038 import org.opends.server.types.DN;
039
040 import static org.opends.messages.ToolMessages.*;
041 import static org.opends.server.util.ServerConstants.*;
042 import static org.opends.server.util.StaticUtils.*;
043
044
045
046 /**
047 * This class provides utility functions for all the client side tools.
048 */
049 public class LDAPToolUtils
050 {
051
052
053 /**
054 * Parse the specified command line argument to create the
055 * appropriate LDAPControl. The argument string should be in the format
056 * controloid[:criticality[:value|::b64value|:<fileurl]]
057 *
058 * @param argString The argument string containing the encoded control
059 * information.
060 * @param err A print stream to which error messages should be
061 * written if a problem occurs.
062 *
063 * @return The control decoded from the provided string, or <CODE>null</CODE>
064 * if an error occurs while parsing the argument value.
065 */
066 public static LDAPControl getControl(String argString, PrintStream err)
067 {
068 LDAPControl control = null;
069 String controlOID = null;
070 boolean controlCriticality = false;
071 ASN1OctetString controlValue = null;
072
073 int idx = argString.indexOf(":");
074
075 if(idx < 0)
076 {
077 controlOID = argString;
078 }
079 else
080 {
081 controlOID = argString.substring(0, idx);
082 }
083
084 String lowerOID = toLowerCase(controlOID);
085 if (lowerOID.equals("accountusable") || lowerOID.equals("accountusability"))
086 {
087 controlOID = OID_ACCOUNT_USABLE_CONTROL;
088 }
089 else if (lowerOID.equals("authzid") ||
090 lowerOID.equals("authorizationidentity"))
091 {
092 controlOID = OID_AUTHZID_REQUEST;
093 }
094 else if (lowerOID.equals("noop") || lowerOID.equals("no-op"))
095 {
096 controlOID = OID_LDAP_NOOP_OPENLDAP_ASSIGNED;
097 }
098 else if (lowerOID.equals("subentries"))
099 {
100 controlOID = OID_LDAP_SUBENTRIES;
101 }
102 else if (lowerOID.equals("managedsait"))
103 {
104 controlOID = OID_MANAGE_DSAIT_CONTROL;
105 }
106 else if (lowerOID.equals("pwpolicy") || lowerOID.equals("passwordpolicy"))
107 {
108 controlOID = OID_PASSWORD_POLICY_CONTROL;
109 }
110 else if (lowerOID.equals("subtreedelete") || lowerOID.equals("treedelete"))
111 {
112 controlOID = OID_SUBTREE_DELETE_CONTROL;
113 }
114 else if (lowerOID.equals("realattrsonly") ||
115 lowerOID.equals("realattributesonly"))
116 {
117 controlOID = OID_REAL_ATTRS_ONLY;
118 }
119 else if (lowerOID.equals("virtualattrsonly") ||
120 lowerOID.equals("virtualattributesonly"))
121 {
122 controlOID = OID_VIRTUAL_ATTRS_ONLY;
123 }
124 else if(lowerOID.equals("effectiverights") ||
125 lowerOID.equals("geteffectiverights"))
126 {
127 controlOID = OID_GET_EFFECTIVE_RIGHTS;
128 }
129
130 if (idx < 0)
131 {
132 return new LDAPControl(controlOID);
133 }
134
135 String remainder = argString.substring(idx+1, argString.length());
136
137 idx = remainder.indexOf(":");
138 if(idx == -1)
139 {
140 if(remainder.equalsIgnoreCase("true"))
141 {
142 controlCriticality = true;
143 } else if(remainder.equalsIgnoreCase("false"))
144 {
145 controlCriticality = false;
146 } else
147 {
148 err.println("Invalid format for criticality value:" + remainder);
149 return null;
150 }
151 control = new LDAPControl(controlOID, controlCriticality);
152 return control;
153
154 }
155
156 String critical = remainder.substring(0, idx);
157 if(critical.equalsIgnoreCase("true"))
158 {
159 controlCriticality = true;
160 } else if(critical.equalsIgnoreCase("false"))
161 {
162 controlCriticality = false;
163 } else
164 {
165 err.println("Invalid format for criticality value:" + critical);
166 return null;
167 }
168
169 String valString = remainder.substring(idx+1, remainder.length());
170 if(valString.charAt(0) == ':')
171 {
172 controlValue =
173 new ASN1OctetString(valString.substring(1, valString.length()));
174 } else if(valString.charAt(0) == '<')
175 {
176 // Read data from the file.
177 String filePath = valString.substring(1, valString.length());
178 try
179 {
180 byte[] val = readBytesFromFile(filePath, err);
181 controlValue = new ASN1OctetString(val);
182 }
183 catch (Exception e)
184 {
185 return null;
186 }
187 } else
188 {
189 controlValue = new ASN1OctetString(valString);
190 }
191
192 control = new LDAPControl(controlOID, controlCriticality, controlValue);
193 return control;
194
195 }
196
197 /**
198 * Read the data from the specified file and return it in a byte array.
199 *
200 * @param filePath The path to the file that should be read.
201 * @param err A print stream to which error messages should be
202 * written if a problem occurs.
203 *
204 * @return A byte array containing the contents of the requested file.
205 *
206 * @throws IOException If a problem occurs while trying to read the
207 * specified file.
208 */
209 public static byte[] readBytesFromFile(String filePath, PrintStream err)
210 throws IOException
211 {
212 byte[] val = null;
213 FileInputStream fis = null;
214 try
215 {
216 File file = new File(filePath);
217 fis = new FileInputStream (file);
218 long length = file.length();
219 val = new byte[(int)length];
220 // Read in the bytes
221 int offset = 0;
222 int numRead = 0;
223 while (offset < val.length &&
224 (numRead=fis.read(val, offset, val.length-offset)) >= 0) {
225 offset += numRead;
226 }
227
228 // Ensure all the bytes have been read in
229 if (offset < val.length)
230 {
231 err.println("Could not completely read file "+filePath);
232 return null;
233 }
234
235 return val;
236 } finally
237 {
238 if (fis != null)
239 {
240 fis.close();
241 }
242 }
243 }
244
245 /**
246 * Prints a multi-line error message with the provided information to the
247 * given print stream.
248 *
249 * @param err The print stream to use to write the error message.
250 * @param explanation The general explanation to provide to the user, or
251 * {@code null} if there is none.
252 * @param resultCode The result code returned from the server, or -1 if
253 * there is none.
254 * @param errorMessage The additional information / error message returned
255 * from the server, or {@code null} if there was none.
256 * @param matchedDN The matched DN returned from the server, or
257 * {@code null} if there was none.
258 */
259 public static void printErrorMessage(PrintStream err, Message explanation,
260 int resultCode, Message errorMessage,
261 DN matchedDN)
262 {
263 if ((explanation != null) && (explanation.length() > 0))
264 {
265 err.println(explanation);
266 }
267
268 if (resultCode >= 0)
269 {
270 err.println(ERR_TOOL_RESULT_CODE.get(resultCode,
271 LDAPResultCode.toString(resultCode)));
272 }
273
274 if ((errorMessage != null) && (errorMessage.length() > 0))
275 {
276 err.println(ERR_TOOL_ERROR_MESSAGE.get(errorMessage));
277 }
278
279 if (matchedDN != null)
280 {
281 err.println(ERR_TOOL_MATCHED_DN.get(matchedDN.toString()));
282 }
283 }
284 }
285