/* * Copyright (c) 2001 by Sun Microsystems, Inc. * All rights reserved. */ /* * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998-1999 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ /* * Copyright (c) 1994 Regents of the University of Michigan. * All rights reserved. */ /* * getdn.c */ #include "ldap-int.h" char * LDAP_CALL ldap_get_dn( LDAP *ld, LDAPMessage *entry ) { char *dn; struct berelement tmp; LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 ); if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { return( NULL ); /* punt */ } if ( !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) { LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL ); return( NULL ); } tmp = *entry->lm_ber; /* struct copy */ if ( ber_scanf( &tmp, "{a", &dn ) == LBER_ERROR ) { LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL ); return( NULL ); } return( dn ); } char * LDAP_CALL ldap_dn2ufn( const char *dn ) { char *p, *ufn, *r; size_t plen; int state; LDAPDebug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 ); if ( dn == NULL ) { dn = ""; } if ( ldap_is_dns_dn( dn ) || ( p = strchr( dn, '=' )) == NULL ) return( nsldapi_strdup( (char *)dn )); ufn = nsldapi_strdup( ++p ); #define INQUOTE 1 #define OUTQUOTE 2 state = OUTQUOTE; for ( p = ufn, r = ufn; *p; p += plen ) { plen = 1; switch ( *p ) { case '\\': if ( *++p == '\0' ) plen=0; else { *r++ = '\\'; r += (plen = LDAP_UTF8COPY(r,p)); } break; case '"': if ( state == INQUOTE ) state = OUTQUOTE; else state = INQUOTE; *r++ = *p; break; case ';': case ',': if ( state == OUTQUOTE ) *r++ = ','; else *r++ = *p; break; case '=': if ( state == INQUOTE ) *r++ = *p; else { char *rsave = r; LDAP_UTF8DEC(r); *rsave = '\0'; while ( !ldap_utf8isspace( r ) && *r != ';' && *r != ',' && r > ufn ) LDAP_UTF8DEC(r); LDAP_UTF8INC(r); if ( strcasecmp( r, "c" ) && strcasecmp( r, "o" ) && strcasecmp( r, "ou" ) && strcasecmp( r, "st" ) && strcasecmp( r, "l" ) && strcasecmp( r, "dc" ) && strcasecmp( r, "uid" ) && strcasecmp( r, "cn" ) ) { r = rsave; *r++ = '='; } } break; default: r += (plen = LDAP_UTF8COPY(r,p)); break; } } *r = '\0'; return( ufn ); } char ** LDAP_CALL ldap_explode_dns( const char *dn ) { int ncomps, maxcomps; char *s, *cpydn; char **rdns; #ifdef HAVE_STRTOK_R /* defined in portable.h */ char *lasts; #endif if ( dn == NULL ) { dn = ""; } if ( (rdns = (char **)NSLDAPI_MALLOC( 8 * sizeof(char *) )) == NULL ) { return( NULL ); } maxcomps = 8; ncomps = 0; cpydn = nsldapi_strdup( (char *)dn ); for ( s = STRTOK( cpydn, "@.", &lasts ); s != NULL; s = STRTOK( NULL, "@.", &lasts ) ) { if ( ncomps == maxcomps ) { maxcomps *= 2; if ( (rdns = (char **)NSLDAPI_REALLOC( rdns, maxcomps * sizeof(char *) )) == NULL ) { NSLDAPI_FREE( cpydn ); return( NULL ); } } rdns[ncomps++] = nsldapi_strdup( s ); } rdns[ncomps] = NULL; NSLDAPI_FREE( cpydn ); return( rdns ); } #define LDAP_DN 1 #define LDAP_RDN 2 static char ** ldap_explode( const char *dn, const int notypes, const int nametype ) { char *p, *q, *rdnstart, **rdns = NULL; size_t plen = 0; int state, count = 0, endquote, len, goteq; LDAPDebug( LDAP_DEBUG_TRACE, "ldap_explode\n", 0, 0, 0 ); if ( dn == NULL ) { dn = ""; } #if 0 if ( ldap_is_dns_dn( dn ) ) { return( ldap_explode_dns( dn ) ); } #endif while ( ldap_utf8isspace( (char *)dn )) { /* ignore leading spaces */ ++dn; } p = rdnstart = (char *) dn; state = OUTQUOTE; goteq = 0; do { p += plen; plen = 1; switch ( *p ) { case '\\': if ( *++p == '\0' ) p--; else plen = LDAP_UTF8LEN(p); break; case '"': if ( state == INQUOTE ) state = OUTQUOTE; else state = INQUOTE; break; case '+': if ( nametype != LDAP_RDN ) break; /* FALLTHROUGH */ case ';': case ',': case '\0': if ( state == OUTQUOTE ) { /* * semicolon and comma are not valid RDN * separators. */ if ( nametype == LDAP_RDN && ( *p == ';' || *p == ',' || !goteq)) { ldap_charray_free( rdns ); return NULL; } if ( (*p == ',' || *p == ';') && !goteq ) { /* If we get here, we have a case similar * to =,,= * This is not a valid dn */ ldap_charray_free( rdns ); return NULL; } goteq = 0; ++count; if ( rdns == NULL ) { if (( rdns = (char **)NSLDAPI_MALLOC( 8 * sizeof( char *))) == NULL ) return( NULL ); } else if ( count >= 8 ) { if (( rdns = (char **)NSLDAPI_REALLOC( rdns, (count+1) * sizeof( char *))) == NULL ) return( NULL ); } rdns[ count ] = NULL; endquote = 0; if ( notypes ) { for ( q = rdnstart; q < p && *q != '='; ++q ) { ; } if ( q < p ) { /* *q == '=' */ rdnstart = ++q; } if ( *rdnstart == '"' ) { ++rdnstart; } if ( *(p-1) == '"' ) { endquote = 1; --p; } } len = p - rdnstart; if (( rdns[ count-1 ] = (char *)NSLDAPI_CALLOC( 1, len + 1 )) != NULL ) { SAFEMEMCPY( rdns[ count-1 ], rdnstart, len ); if ( !endquote ) { /* trim trailing spaces */ while ( len > 0 && ldap_utf8isspace( &rdns[count-1][len-1] )) { --len; } } rdns[ count-1 ][ len ] = '\0'; } /* * Don't forget to increment 'p' back to where * it should be. If we don't, then we will * never get past an "end quote." */ if ( endquote == 1 ) p++; rdnstart = *p ? p + 1 : p; while ( ldap_utf8isspace( rdnstart )) ++rdnstart; } break; case '=': if ( state == OUTQUOTE ) { goteq = 1; } /* FALLTHROUGH */ default: plen = LDAP_UTF8LEN(p); break; } } while ( *p ); return( rdns ); } char ** LDAP_CALL ldap_explode_dn( const char *dn, const int notypes ) { return( ldap_explode( dn, notypes, LDAP_DN ) ); } char ** LDAP_CALL ldap_explode_rdn( const char *rdn, const int notypes ) { return( ldap_explode( rdn, notypes, LDAP_RDN ) ); } int LDAP_CALL ldap_is_dns_dn( const char *dn ) { return( dn != NULL && dn[ 0 ] != '\0' && strchr( dn, '=' ) == NULL && strchr( dn, ',' ) == NULL ); } #ifdef _SOLARIS_SDK /* * Convert a DNS domain name into an X.500 distinguished name. * For example, "sales.wiz.com" -> "dc=sales,dc=wiz,dc=com" * * If an error is encountered zero is returned, otherwise a string * distinguished name and the number of nameparts is returned. * The caller should free the returned string if it is non-zero. */ char * ldap_dns_to_dn( char *dns_name, int *nameparts ) { size_t dns_len; char *dn = 0; char *cp; /* check for NULL string, empty name and name ending in '.' */ if (dns_name && (dns_len = strlen(dns_name)) && (dns_name[dns_len - 1] != '.')) { if (dn = (char *)malloc(dns_len * 3 + 1)) { *nameparts = 0; cp = dn; while (*dns_name) { *cp++ = 'd'; *cp++ = 'c'; *cp++ = '='; while (*dns_name && (*dns_name != '.')) { *cp++ = *dns_name++; } if (*dns_name == '.') { dns_name++; *cp++ = ','; } (*nameparts)++; } *cp = '\0'; } } return (dn); } #endif