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