Author: rmeggins
Update of /cvs/dirsec/console/src/com/netscape/management/client/util In directory cvs01.phx2.fedoraproject.org:/tmp/cvs-serv8170/src/com/netscape/management/client/util
Modified Files: LDAPUtil.java Log Message: Bug 586571 - DS Console shows escaped DNs
https://bugzilla.redhat.com/show_bug.cgi?id=586571 Resolves: bug 586571 Bug Description: DS Console shows escaped DNs Reviewed by: nkinder (Thanks!) Branch: HEAD Fix Description: Was not working correctly in the property and advanced editor for editing some DNs that contained other DNs as RDN values. I also moved a lot of the DN handling code into the main console package into the LDAPUtil class. This will allow the main console to handle DN escapes as well. Unfortunately, if managing a new DS on a machine which only has the old console framework, these methods will be missing. So, use the new methods if available, otherwise, fallback on the DSUtil implementation. Platforms tested: RHEL5 x86_64 Flag Day: no Doc impact: no
Index: LDAPUtil.java =================================================================== RCS file: /cvs/dirsec/console/src/com/netscape/management/client/util/LDAPUtil.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- LDAPUtil.java 12 Feb 2010 16:53:00 -0000 1.3 +++ LDAPUtil.java 3 May 2010 20:37:56 -0000 1.4 @@ -22,8 +22,11 @@
import java.util.*; import java.text.*; + import netscape.ldap.*; import netscape.ldap.util.DN; +import netscape.ldap.util.RDN; + import com.netscape.management.client.console.*; import com.netscape.management.client.util.UtilConsoleGlobals;
@@ -768,4 +771,253 @@
// DS ldbm database configuration root DN final static String LDBM_PLUGIN_ROOT = "cn=ldbm database, cn=plugins, cn=config"; + + /** + * Check if the string is a valid dn + * + */ + static public boolean isValidDN (String dn){ + if (dn.equals ("")) + return true; + + if (!netscape.ldap.util.DN.isDN(dn)) + return false; + + int eq = dn.indexOf('='); + + return (eq > 0 && eq < dn.length () -1 ); + } + + static public boolean equalDNs(String dn1, String dn2) { + boolean retVal = false; + if (isValidDN(dn1) && isValidDN(dn2)) { + retVal = equalDNs(new DN(dn1), new DN(dn2)); + } + return retVal; + } + + static public boolean equalDNs(DN dn1, DN dn2) { + boolean status = (dn1 == null || dn2 == null); + if (status) { // if at least one of the arguments is null + status = (dn1 == dn2); // true if both are null, false otherwise + return status; // short circuit + } + + Vector thisRDNs = dn1.getRDNs(); + Vector thatRDNs = dn2.getRDNs(); + if (thisRDNs != null && thatRDNs != null && + thisRDNs.size() == thatRDNs.size()) { + int ii; + for (ii = 0; ii < thisRDNs.size(); ++ii) { + RDN thisRDN = (RDN)thisRDNs.elementAt(ii); + RDN thatRDN = (RDN)thatRDNs.elementAt(ii); + if (!thisRDN.equals(thatRDN)) + break; + } + + // all RDNs were equal + if (ii == thisRDNs.size()) + status = true; + } + + return status; + } + + /** + * Returns the RDN value after unescaping any escaped characters. + * Can be a simple escape - a \ followed by any character - + * this will just remove the \ and leave the character in the + * result unescaped. + * Can be a hex escape - a \ followed by two hex digits - the + * \ will be removed and the two hex digits converted to a single + * char in the string. + * Note that this is different than netscape.ldap.LDAPDN#unEscapeRDN(java.lang.String + * in that this function will handle hex escapes. + * If the rdn value is bogus or otherwise cannot be parsed correctly, the original + * rdn value will be returned, with escapes if it had them. + * <P> + * + * @param rdnval the RDN value to unescape + * @return the unescaped RDN value or the original RDN value if there were errors + * @see netscape.ldap.LDAPDN#escapeRDN(java.lang.String) + */ + public static String unEscapeRDNVal(String rdnval) { + StringBuffer copy = new StringBuffer(); + CharacterIterator it = new StringCharacterIterator(rdnval); + for (char ch = it.first(); ch != CharacterIterator.DONE; ch = it.next()) { + if (ch == '\') { + ch = it.next(); + if (ch == CharacterIterator.DONE) { + // bogus - escape at end of string + return rdnval; + } + int val1 = Character.digit(ch, 16); + if ((val1 >= 0) && (val1 < 16)) { + val1 = val1 * 16; + ch = it.next(); + if (ch == CharacterIterator.DONE) { + // bogus - escape followed by only 1 hex digit + return rdnval; + } + int val2 = Character.digit(ch, 16); + if ((val2 < 0) || (val2 > 15)) { + return rdnval; + } + // must be a two digit hex code if we got here + ch = (char)(val1 + val2); + } + } + copy.append(ch); + } + return copy.toString(); + } + + /** + * Returns the RDN after unescaping any escaped characters. + * Can be a simple escape - a \ followed by any character - + * this will just remove the \ and leave the character in the + * result unescaped. + * Can be a hex escape - a \ followed by two hex digits - the + * \ will be removed and the two hex digits converted to a single + * char in the string. + * Note that this is different than netscape.ldap.LDAPDN#unEscapeRDN(java.lang.String + * in that this function will handle hex escapes. + * If the rdn is bogus or otherwise cannot be parsed correctly, the original + * rdn value will be returned, with escapes if it had them. + * <P> + * + * @param rdn the RDN to unescape + * @return the unescaped RDN or the original RDN if there were errors + * @see netscape.ldap.LDAPDN#escapeRDN(java.lang.String) + */ + public static String unEscapeRDN(String rdn) { + RDN name = new RDN(rdn); + String[] vals = name.getValues(); + if ( (vals == null) || (vals.length < 1) ) { + return rdn; + } + String[] types = name.getTypes(); + + StringBuffer rdnbuf = new StringBuffer(); + for (int ii = 0; ii < vals.length; ++ii) { + if (rdnbuf.length() > 0) { + rdnbuf.append("+"); + } + rdnbuf.append(types[ii] + "=" + unEscapeRDNVal(vals[ii])); + } + + return rdnbuf.toString(); + } + + /** + * Returns the DN after unescaping any escaped characters. + * Can be a simple escape - a \ followed by any character - + * this will just remove the \ and leave the character in the + * result unescaped. + * Can be a hex escape - a \ followed by two hex digits - the + * \ will be removed and the two hex digits converted to a single + * char in the string. + * If the dn is bogus or otherwise cannot be parsed correctly, the original + * dn value will be returned, with escapes if it had them. + * <P> + * + * @param dn the DN to unescape + * @return the unescaped DN or the original DN if there were errors + */ + public static String unEscapeDN(String dn) { + if ((dn == null) || (dn.equals(""))) { + return dn; + } + String[] rdns = LDAPDN.explodeDN(dn, false); + if ((rdns == null) || (rdns.length < 1)) { + return dn; + } + StringBuffer retdn = new StringBuffer(); + for (int ii = 0; ii < rdns.length; ++ii) { + if (retdn.length() > 0) { + retdn.append(","); + } + retdn.append(unEscapeRDN(rdns[ii])); + } + + return retdn.toString(); + } + + public static boolean[] DN_ESCAPE_CHARS = null; + static { + // get max val of DN.ESCAPED_CHAR + char maxval = 0; + for (char ii = 0; ii < DN.ESCAPED_CHAR.length; ++ii) { + if (maxval < DN.ESCAPED_CHAR[ii]) { + maxval = DN.ESCAPED_CHAR[ii]; + } + } + // add the '=' + if (maxval < '=') { + maxval = '='; + } + // create an array large enough to hold spaces + // for all values up to maxval + DN_ESCAPE_CHARS = new boolean[maxval+1]; + // set default value to false + for (char ii = 0; ii < (int)maxval; ++ii) { + DN_ESCAPE_CHARS[ii] = false; + } + // set escape char vals to true + for (char ii = 0; ii < DN.ESCAPED_CHAR.length; ++ii) { + DN_ESCAPE_CHARS[DN.ESCAPED_CHAR[ii]] = true; + } + // add the equals sign + DN_ESCAPE_CHARS['='] = true; + } + /** + * Escape the given DN string value for use as an RDN value. Uses + * the \XX hex escapes. + * @param dnval value to escape for use as an RDN value + * @return the escaped string + */ + public static String escapeDNVal(String dnval) { + StringBuffer copy = new StringBuffer(); + CharacterIterator it = new StringCharacterIterator(dnval); + for (char ch = it.first(); ch != CharacterIterator.DONE; ch = it.next()) { + if ((ch > 0) && (ch < DN_ESCAPE_CHARS.length) && DN_ESCAPE_CHARS[ch]) { + copy.append('\'); + copy.append(Integer.toHexString((int)ch).toUpperCase()); + } else { + copy.append(ch); + } + } + return copy.toString(); + } + + /** + * This function was stolen from dsalib_dn.c. It checks the string + * for LDAPv2 style quoting e.g. o="foo, bar", c=US, a format which + * is now deprecated. + * + * @param dn The DN to scan + * @return true if the given string contains LDAPv2 style quoting + */ + static public boolean DNUsesLDAPv2Quoting(String dn) { + char ESC = '\'; + char Q = '"'; + boolean ret = false; + + // check dn for a even number (incl. 0) of ESC followed by Q + if (dn == null) + return ret; + + int p = dn.indexOf(Q); + if (p >= 0) + { + int nESC = 0; + for (--p; (p >= 0) && (dn.charAt(p) == ESC); --p) + ++nESC; + // the quote is unescaped if it is preceded by an even + // number of escape characters, including 0 + ret = ((nESC % 2) == 0); + } + + return ret; + } }
389-commits@lists.fedoraproject.org