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