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