1 /* 2 * Copyright (c) 2001 by Sun Microsystems, Inc. 3 * All rights reserved. 4 */ 5 6 /* 7 * The contents of this file are subject to the Netscape Public 8 * License Version 1.1 (the "License"); you may not use this file 9 * except in compliance with the License. You may obtain a copy of 10 * the License at http://www.mozilla.org/NPL/ 11 * 12 * Software distributed under the License is distributed on an "AS 13 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 14 * implied. See the License for the specific language governing 15 * rights and limitations under the License. 16 * 17 * The Original Code is Mozilla Communicator client code, released 18 * March 31, 1998. 19 * 20 * The Initial Developer of the Original Code is Netscape 21 * Communications Corporation. Portions created by Netscape are 22 * Copyright (C) 1998-1999 Netscape Communications Corporation. All 23 * Rights Reserved. 24 * 25 * Contributor(s): 26 */ 27 /* 28 * Copyright (c) 1994 Regents of the University of Michigan. 29 * All rights reserved. 30 */ 31 /* 32 * getdn.c 33 */ 34 35 #include "ldap-int.h" 36 37 char * 38 LDAP_CALL 39 ldap_get_dn( LDAP *ld, LDAPMessage *entry ) 40 { 41 char *dn; 42 struct berelement tmp; 43 44 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 ); 45 46 if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { 47 return( NULL ); /* punt */ 48 } 49 50 if ( !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) { 51 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL ); 52 return( NULL ); 53 } 54 55 tmp = *entry->lm_ber; /* struct copy */ 56 if ( ber_scanf( &tmp, "{a", &dn ) == LBER_ERROR ) { 57 LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL ); 58 return( NULL ); 59 } 60 61 return( dn ); 62 } 63 64 char * 65 LDAP_CALL 66 ldap_dn2ufn( const char *dn ) 67 { 68 char *p, *ufn, *r; 69 size_t plen; 70 int state; 71 72 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 ); 73 74 if ( dn == NULL ) { 75 dn = ""; 76 } 77 78 if ( ldap_is_dns_dn( dn ) || ( p = strchr( dn, '=' )) == NULL ) 79 return( nsldapi_strdup( (char *)dn )); 80 81 ufn = nsldapi_strdup( ++p ); 82 83 #define INQUOTE 1 84 #define OUTQUOTE 2 85 state = OUTQUOTE; 86 for ( p = ufn, r = ufn; *p; p += plen ) { 87 plen = 1; 88 switch ( *p ) { 89 case '\\': 90 if ( *++p == '\0' ) 91 plen=0; 92 else { 93 *r++ = '\\'; 94 r += (plen = LDAP_UTF8COPY(r,p)); 95 } 96 break; 97 case '"': 98 if ( state == INQUOTE ) 99 state = OUTQUOTE; 100 else 101 state = INQUOTE; 102 *r++ = *p; 103 break; 104 case ';': 105 case ',': 106 if ( state == OUTQUOTE ) 107 *r++ = ','; 108 else 109 *r++ = *p; 110 break; 111 case '=': 112 if ( state == INQUOTE ) 113 *r++ = *p; 114 else { 115 char *rsave = r; 116 LDAP_UTF8DEC(r); 117 *rsave = '\0'; 118 while ( !ldap_utf8isspace( r ) && *r != ';' 119 && *r != ',' && r > ufn ) 120 LDAP_UTF8DEC(r); 121 LDAP_UTF8INC(r); 122 123 if ( strcasecmp( r, "c" ) 124 && strcasecmp( r, "o" ) 125 && strcasecmp( r, "ou" ) 126 && strcasecmp( r, "st" ) 127 && strcasecmp( r, "l" ) 128 && strcasecmp( r, "dc" ) 129 && strcasecmp( r, "uid" ) 130 && strcasecmp( r, "cn" ) ) { 131 r = rsave; 132 *r++ = '='; 133 } 134 } 135 break; 136 default: 137 r += (plen = LDAP_UTF8COPY(r,p)); 138 break; 139 } 140 } 141 *r = '\0'; 142 143 return( ufn ); 144 } 145 146 char ** 147 LDAP_CALL 148 ldap_explode_dns( const char *dn ) 149 { 150 int ncomps, maxcomps; 151 char *s, *cpydn; 152 char **rdns; 153 #ifdef HAVE_STRTOK_R /* defined in portable.h */ 154 char *lasts; 155 #endif 156 157 if ( dn == NULL ) { 158 dn = ""; 159 } 160 161 if ( (rdns = (char **)NSLDAPI_MALLOC( 8 * sizeof(char *) )) == NULL ) { 162 return( NULL ); 163 } 164 165 maxcomps = 8; 166 ncomps = 0; 167 cpydn = nsldapi_strdup( (char *)dn ); 168 for ( s = STRTOK( cpydn, "@.", &lasts ); s != NULL; 169 s = STRTOK( NULL, "@.", &lasts ) ) { 170 if ( ncomps == maxcomps ) { 171 maxcomps *= 2; 172 if ( (rdns = (char **)NSLDAPI_REALLOC( rdns, maxcomps * 173 sizeof(char *) )) == NULL ) { 174 NSLDAPI_FREE( cpydn ); 175 return( NULL ); 176 } 177 } 178 rdns[ncomps++] = nsldapi_strdup( s ); 179 } 180 rdns[ncomps] = NULL; 181 NSLDAPI_FREE( cpydn ); 182 183 return( rdns ); 184 } 185 186 #define LDAP_DN 1 187 #define LDAP_RDN 2 188 189 static char ** 190 ldap_explode( const char *dn, const int notypes, const int nametype ) 191 { 192 char *p, *q, *rdnstart, **rdns = NULL; 193 size_t plen = 0; 194 int state, count = 0, endquote, len, goteq; 195 196 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_explode\n", 0, 0, 0 ); 197 198 if ( dn == NULL ) { 199 dn = ""; 200 } 201 202 #if 0 203 if ( ldap_is_dns_dn( dn ) ) { 204 return( ldap_explode_dns( dn ) ); 205 } 206 #endif 207 208 while ( ldap_utf8isspace( (char *)dn )) { /* ignore leading spaces */ 209 ++dn; 210 } 211 212 p = rdnstart = (char *) dn; 213 state = OUTQUOTE; 214 goteq = 0; 215 216 do { 217 p += plen; 218 plen = 1; 219 switch ( *p ) { 220 case '\\': 221 if ( *++p == '\0' ) 222 p--; 223 else 224 plen = LDAP_UTF8LEN(p); 225 break; 226 case '"': 227 if ( state == INQUOTE ) 228 state = OUTQUOTE; 229 else 230 state = INQUOTE; 231 break; 232 case '+': if ( nametype != LDAP_RDN ) break; 233 /* FALLTHROUGH */ 234 case ';': 235 case ',': 236 case '\0': 237 if ( state == OUTQUOTE ) { 238 /* 239 * semicolon and comma are not valid RDN 240 * separators. 241 */ 242 if ( nametype == LDAP_RDN && 243 ( *p == ';' || *p == ',' || !goteq)) { 244 ldap_charray_free( rdns ); 245 return NULL; 246 } 247 if ( (*p == ',' || *p == ';') && !goteq ) { 248 /* If we get here, we have a case similar 249 * to <attr>=<value>,<string>,<attr>=<value> 250 * This is not a valid dn */ 251 ldap_charray_free( rdns ); 252 return NULL; 253 } 254 goteq = 0; 255 ++count; 256 if ( rdns == NULL ) { 257 if (( rdns = (char **)NSLDAPI_MALLOC( 8 258 * sizeof( char *))) == NULL ) 259 return( NULL ); 260 } else if ( count >= 8 ) { 261 if (( rdns = (char **)NSLDAPI_REALLOC( 262 rdns, (count+1) * 263 sizeof( char *))) == NULL ) 264 return( NULL ); 265 } 266 rdns[ count ] = NULL; 267 endquote = 0; 268 if ( notypes ) { 269 for ( q = rdnstart; 270 q < p && *q != '='; ++q ) { 271 ; 272 } 273 if ( q < p ) { /* *q == '=' */ 274 rdnstart = ++q; 275 } 276 if ( *rdnstart == '"' ) { 277 ++rdnstart; 278 } 279 280 if ( *(p-1) == '"' ) { 281 endquote = 1; 282 --p; 283 } 284 } 285 286 len = p - rdnstart; 287 if (( rdns[ count-1 ] = (char *)NSLDAPI_CALLOC( 288 1, len + 1 )) != NULL ) { 289 SAFEMEMCPY( rdns[ count-1 ], rdnstart, 290 len ); 291 if ( !endquote ) { 292 /* trim trailing spaces */ 293 while ( len > 0 && 294 ldap_utf8isspace( 295 &rdns[count-1][len-1] )) { 296 --len; 297 } 298 } 299 rdns[ count-1 ][ len ] = '\0'; 300 } 301 302 /* 303 * Don't forget to increment 'p' back to where 304 * it should be. If we don't, then we will 305 * never get past an "end quote." 306 */ 307 if ( endquote == 1 ) 308 p++; 309 310 rdnstart = *p ? p + 1 : p; 311 while ( ldap_utf8isspace( rdnstart )) 312 ++rdnstart; 313 } 314 break; 315 case '=': 316 if ( state == OUTQUOTE ) { 317 goteq = 1; 318 } 319 /* FALLTHROUGH */ 320 default: 321 plen = LDAP_UTF8LEN(p); 322 break; 323 } 324 } while ( *p ); 325 326 return( rdns ); 327 } 328 329 char ** 330 LDAP_CALL 331 ldap_explode_dn( const char *dn, const int notypes ) 332 { 333 return( ldap_explode( dn, notypes, LDAP_DN ) ); 334 } 335 336 char ** 337 LDAP_CALL 338 ldap_explode_rdn( const char *rdn, const int notypes ) 339 { 340 return( ldap_explode( rdn, notypes, LDAP_RDN ) ); 341 } 342 343 int 344 LDAP_CALL 345 ldap_is_dns_dn( const char *dn ) 346 { 347 return( dn != NULL && dn[ 0 ] != '\0' && strchr( dn, '=' ) == NULL && 348 strchr( dn, ',' ) == NULL ); 349 } 350 351 #ifdef _SOLARIS_SDK 352 353 /* 354 * Convert a DNS domain name into an X.500 distinguished name. 355 * For example, "sales.wiz.com" -> "dc=sales,dc=wiz,dc=com" 356 * 357 * If an error is encountered zero is returned, otherwise a string 358 * distinguished name and the number of nameparts is returned. 359 * The caller should free the returned string if it is non-zero. 360 */ 361 362 char * 363 ldap_dns_to_dn( 364 char *dns_name, 365 int *nameparts 366 ) 367 { 368 size_t dns_len; 369 char *dn = 0; 370 char *cp; 371 372 /* check for NULL string, empty name and name ending in '.' */ 373 if (dns_name && (dns_len = strlen(dns_name)) && 374 (dns_name[dns_len - 1] != '.')) { 375 if (dn = (char *)malloc(dns_len * 3 + 1)) { 376 *nameparts = 0; 377 cp = dn; 378 while (*dns_name) { 379 *cp++ = 'd'; 380 *cp++ = 'c'; 381 *cp++ = '='; 382 383 while (*dns_name && (*dns_name != '.')) { 384 *cp++ = *dns_name++; 385 } 386 if (*dns_name == '.') { 387 dns_name++; 388 *cp++ = ','; 389 } 390 (*nameparts)++; 391 } 392 *cp = '\0'; 393 } 394 } 395 return (dn); 396 } 397 398 #endif 399 400