1 #pragma ident "%Z%%M% %I% %E% SMI" 2 3 /* 4 * The contents of this file are subject to the Netscape Public 5 * License Version 1.1 (the "License"); you may not use this file 6 * except in compliance with the License. You may obtain a copy of 7 * the License at http://www.mozilla.org/NPL/ 8 * 9 * Software distributed under the License is distributed on an "AS 10 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 11 * implied. See the License for the specific language governing 12 * rights and limitations under the License. 13 * 14 * The Original Code is Mozilla Communicator client code, released 15 * March 31, 1998. 16 * 17 * The Initial Developer of the Original Code is Netscape 18 * Communications Corporation. Portions created by Netscape are 19 * Copyright (C) 1998-1999 Netscape Communications Corporation. All 20 * Rights Reserved. 21 * 22 * Contributor(s): 23 */ 24 /* 25 * Copyright (c) 1990 Regents of the University of Michigan. 26 * All rights reserved. 27 */ 28 /* 29 * getvalues.c 30 */ 31 32 #if 0 33 #ifndef lint 34 static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; 35 #endif 36 #endif 37 38 #include "ldap-int.h" 39 40 41 static void ** 42 internal_ldap_get_values( LDAP *ld, LDAPMessage *entry, const char *target, 43 int lencall ) 44 { 45 struct berelement ber; 46 char *attr; 47 int rc; 48 void **vals; 49 50 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_values\n", 0, 0, 0 ); 51 52 if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { 53 return( NULL ); /* punt */ 54 } 55 if ( target == NULL || 56 !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) { 57 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL ); 58 return( NULL ); 59 } 60 61 ber = *entry->lm_ber; 62 63 /* skip sequence, dn, sequence of, and snag the first attr */ 64 if ( ber_scanf( &ber, "{x{{a", &attr ) == LBER_ERROR ) { 65 LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL ); 66 return( NULL ); 67 } 68 69 rc = strcasecmp( (char *)target, attr ); 70 NSLDAPI_FREE( attr ); 71 if ( rc != 0 ) { 72 while ( 1 ) { 73 if ( ber_scanf( &ber, "x}{a", &attr ) == LBER_ERROR ) { 74 LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, 75 NULL, NULL ); 76 return( NULL ); 77 } 78 79 rc = strcasecmp( (char *)target, attr ); 80 if ( rc == 0 ) { 81 NSLDAPI_FREE( attr ); 82 break; 83 } 84 NSLDAPI_FREE( attr ); 85 } 86 } 87 88 /* 89 * if we get this far, we've found the attribute and are sitting 90 * just before the set of values. 91 */ 92 93 if ( lencall ) { 94 rc = ber_scanf( &ber, "[V]", &vals ); 95 } else { 96 rc = ber_scanf( &ber, "[v]", &vals ); 97 } 98 99 if ( rc == LBER_ERROR ) { 100 rc = LDAP_DECODING_ERROR; 101 } else { 102 rc = LDAP_SUCCESS; 103 } 104 105 LDAP_SET_LDERRNO( ld, rc, NULL, NULL ); 106 107 return(( rc == LDAP_SUCCESS ) ? vals : NULL ); 108 } 109 110 111 /* For language-sensitive attribute matching, we are looking for a 112 language tag that looks like one of the following: 113 114 cn 115 cn;lang-en 116 cn;lang-en-us 117 cn;lang-ja 118 cn;lang-ja-JP-kanji 119 120 The base language specification consists of two letters following 121 "lang-". After that, there may be additional language-specific 122 narrowings preceded by a "-". In our processing we go from the 123 specific to the general, preferring a complete subtype match, but 124 accepting a partial one. For example: 125 126 For a request for "cn;lang-en-us", we would return cn;lang-en-us 127 if present, otherwise cn;lang-en if present, otherwise cn. 128 129 Besides the language subtype, there may be other subtypes: 130 131 cn;lang-ja;binary (Unlikely!) 132 cn;lang-ja;phonetic 133 134 If not in the target, they are ignored. If they are in the target, 135 they must be in the attribute to match. 136 */ 137 #define LANG_SUBTYPE_INDEX_NONE -1 138 #define LANG_SUBTYPE_INDEX_DUPLICATE -2 139 140 typedef struct { 141 int start; 142 int length; 143 } _SubStringIndex; 144 145 static int 146 parse_subtypes( const char *target, int *baseLenp, char **langp, 147 _SubStringIndex **subs, int *nsubtypes ) 148 { 149 int nSubtypes = 0; 150 int ind = 0; 151 char *nextToken; 152 _SubStringIndex *result = NULL; 153 int langIndex; 154 int targetLen; 155 int subtypeStart; 156 157 langIndex = LANG_SUBTYPE_INDEX_NONE; 158 *subs = NULL; 159 *langp = NULL; 160 *baseLenp = 0; 161 *nsubtypes = 0; 162 targetLen = strlen( target ); 163 164 /* Parse past base attribute */ 165 nextToken = strchr( target, ';' ); 166 if ( NULL != nextToken ) { 167 subtypeStart = nextToken - target + 1; 168 *baseLenp = subtypeStart - 1; 169 } 170 else { 171 subtypeStart = targetLen; 172 *baseLenp = subtypeStart; 173 } 174 ind = subtypeStart; 175 176 /* How many subtypes? */ 177 nextToken = (char *)target + subtypeStart; 178 while ( nextToken && *nextToken ) { 179 char *thisToken = nextToken; 180 nextToken = strchr( thisToken, ';' ); 181 if ( NULL != nextToken ) 182 nextToken++; 183 if ( 0 == strncasecmp( thisToken, "lang-", 5 ) ) { 184 /* If there was a previous lang tag, this is illegal! */ 185 if ( langIndex != LANG_SUBTYPE_INDEX_NONE ) { 186 langIndex = LANG_SUBTYPE_INDEX_DUPLICATE; 187 return langIndex; 188 } 189 else { 190 langIndex = nSubtypes; 191 } 192 } else { 193 nSubtypes++; 194 } 195 } 196 /* No language subtype? */ 197 if ( langIndex < 0 ) 198 return langIndex; 199 200 /* Allocate array of non-language subtypes */ 201 if ( nSubtypes > 0 ) { 202 result = (_SubStringIndex *)NSLDAPI_MALLOC( sizeof(*result) 203 * nSubtypes ); 204 if (result == NULL) { 205 return LANG_SUBTYPE_INDEX_NONE; /* Error */ 206 } 207 memset( result, 0, sizeof(*result) * nSubtypes ); 208 } 209 ind = 0; 210 nSubtypes = 0; 211 ind = subtypeStart; 212 nextToken = (char *)target + subtypeStart; 213 while ( nextToken && *nextToken ) { 214 char *thisToken = nextToken; 215 int len; 216 nextToken = strchr( thisToken, ';' ); 217 if ( NULL != nextToken ) { 218 len = nextToken - thisToken; 219 nextToken++; 220 } 221 else { 222 nextToken = (char *)target + targetLen; 223 len = nextToken - thisToken; 224 } 225 if ( 0 == strncasecmp( thisToken, "lang-", 5 ) ) { 226 int i; 227 *langp = (char *)NSLDAPI_MALLOC( len + 1 ); 228 if (*langp == NULL) { 229 if (result != NULL) 230 NSLDAPI_FREE(result); 231 return LANG_SUBTYPE_INDEX_NONE; /* Error */ 232 } 233 for( i = 0; i < len; i++ ) 234 (*langp)[i] = toupper( target[ind+i] ); 235 (*langp)[len] = 0; 236 } 237 else { 238 result[nSubtypes].start = thisToken - target; 239 result[nSubtypes].length = len; 240 nSubtypes++; 241 } 242 } 243 *subs = result; 244 *nsubtypes = nSubtypes; 245 return langIndex; 246 } 247 248 249 static int 250 check_lang_match( const char *target, const char *baseTarget, 251 _SubStringIndex *targetTypes, 252 int ntargetTypes, char *targetLang, char *attr ) 253 { 254 int langIndex; 255 _SubStringIndex *subtypes; 256 int baseLen; 257 char *lang; 258 int nsubtypes; 259 int mismatch = 0; 260 int match = -1; 261 int i; 262 263 /* Get all subtypes in the attribute name */ 264 langIndex = parse_subtypes( attr, &baseLen, &lang, &subtypes, &nsubtypes ); 265 266 /* Check if there any required non-language subtypes which are 267 not in this attribute */ 268 for( i = 0; i < ntargetTypes; i++ ) { 269 char *t = (char *)target+targetTypes[i].start; 270 int tlen = targetTypes[i].length; 271 int j; 272 for( j = 0; j < nsubtypes; j++ ) { 273 char *a = attr + subtypes[j].start; 274 int alen = subtypes[j].length; 275 if ( (tlen == alen) && !strncasecmp( t, a, tlen ) ) 276 break; 277 } 278 if ( j >= nsubtypes ) { 279 mismatch = 1; 280 break; 281 } 282 } 283 if ( mismatch ) { 284 if ( NULL != subtypes ) 285 NSLDAPI_FREE( subtypes ); 286 if ( NULL != lang ) 287 NSLDAPI_FREE( lang ); 288 return -1; 289 } 290 291 /* If there was no language subtype... */ 292 if ( langIndex < 0 ) { 293 if ( NULL != subtypes ) 294 NSLDAPI_FREE( subtypes ); 295 if ( NULL != lang ) 296 NSLDAPI_FREE( lang ); 297 if ( LANG_SUBTYPE_INDEX_NONE == langIndex ) 298 return 0; 299 else 300 return -1; 301 } 302 303 /* Okay, now check the language subtag */ 304 i = 0; 305 while( targetLang[i] && lang[i] && 306 (toupper(targetLang[i]) == toupper(lang[i])) ) 307 i++; 308 309 /* The total length can't be longer than the requested subtype */ 310 if ( !lang[i] || (lang[i] == ';') ) { 311 /* If the found subtype is shorter than the requested one, the next 312 character in the requested one should be "-" */ 313 if ( !targetLang[i] || (targetLang[i] == '-') ) 314 match = i; 315 } 316 return match; 317 } 318 319 static int check_base_match( const char *target, char *attr ) 320 { 321 int i = 0; 322 int rc; 323 while( target[i] && attr[i] && (toupper(target[i]) == toupper(attr[i])) ) 324 i++; 325 rc = ( !target[i] && (!attr[i] || (';' == attr[i])) ); 326 return rc; 327 } 328 329 static void ** 330 internal_ldap_get_lang_values( LDAP *ld, LDAPMessage *entry, 331 const char *target, char **type, int lencall ) 332 { 333 struct berelement ber; 334 char *attr = NULL; 335 int rc; 336 void **vals = NULL; 337 int langIndex; 338 _SubStringIndex *subtypes; 339 int nsubtypes; 340 char *baseTarget = NULL; 341 int bestMatch = 0; 342 char *lang = NULL; 343 int len; 344 int firstAttr = 1; 345 char *bestType = NULL; 346 347 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_values\n", 0, 0, 0 ); 348 349 if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { 350 return( NULL ); 351 } 352 if ( (target == NULL) || 353 !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) { 354 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL ); 355 return( NULL ); 356 } 357 358 /* A language check was requested, so see if there really is a 359 language subtype in the attribute spec */ 360 langIndex = parse_subtypes( target, &len, &lang, 361 &subtypes, &nsubtypes ); 362 if ( langIndex < 0 ) { 363 if ( NULL != subtypes ) { 364 NSLDAPI_FREE( subtypes ); 365 subtypes = NULL; 366 } 367 vals = internal_ldap_get_values( ld, entry, target, lencall ); 368 if ( NULL != type ) 369 *type = nsldapi_strdup( target ); 370 return vals; 371 } else { 372 /* Get just the base attribute name */ 373 baseTarget = (char *)NSLDAPI_MALLOC( len + 1 ); 374 if (baseTarget == NULL) { 375 return( NULL ); 376 } 377 memcpy( baseTarget, target, len ); 378 baseTarget[len] = 0; 379 } 380 381 ber = *entry->lm_ber; 382 383 /* Process all attributes in the entry */ 384 while ( 1 ) { 385 int foundMatch = 0; 386 if ( NULL != attr ) 387 NSLDAPI_FREE( attr ); 388 if ( firstAttr ) { 389 firstAttr = 0; 390 /* skip sequence, dn, sequence of, and snag the first attr */ 391 if ( ber_scanf( &ber, "{x{{a", &attr ) == LBER_ERROR ) { 392 break; 393 } 394 } else { 395 if ( ber_scanf( &ber, "{a", &attr ) == LBER_ERROR ) { 396 break; 397 } 398 } 399 400 if ( check_base_match( (const char *)baseTarget, attr ) ) { 401 int thisMatch = check_lang_match( target, baseTarget, 402 subtypes, nsubtypes, lang, attr ); 403 if ( thisMatch > bestMatch ) { 404 if ( vals ) 405 NSLDAPI_FREE( vals ); 406 foundMatch = 1; 407 bestMatch = thisMatch; 408 if ( NULL != bestType ) 409 NSLDAPI_FREE( bestType ); 410 bestType = attr; 411 attr = NULL; 412 } 413 } 414 if ( foundMatch ) { 415 if ( lencall ) { 416 rc = ber_scanf( &ber, "[V]}", &vals ); 417 } else { 418 rc = ber_scanf( &ber, "[v]}", &vals ); 419 } 420 } else { 421 ber_scanf( &ber, "x}" ); 422 } 423 } 424 425 NSLDAPI_FREE( lang ); 426 NSLDAPI_FREE( baseTarget ); 427 NSLDAPI_FREE( subtypes ); 428 429 if ( NULL != type ) 430 *type = bestType; 431 else if ( NULL != bestType ) 432 NSLDAPI_FREE( bestType ); 433 434 if ( NULL == vals ) { 435 rc = LDAP_DECODING_ERROR; 436 } else { 437 rc = LDAP_SUCCESS; 438 } 439 440 LDAP_SET_LDERRNO( ld, rc, NULL, NULL ); 441 442 return( vals ); 443 } 444 445 446 char ** 447 LDAP_CALL 448 ldap_get_values( LDAP *ld, LDAPMessage *entry, const char *target ) 449 { 450 return( (char **) internal_ldap_get_values( ld, entry, target, 0 ) ); 451 } 452 453 struct berval ** 454 LDAP_CALL 455 ldap_get_values_len( LDAP *ld, LDAPMessage *entry, const char *target ) 456 { 457 return( (struct berval **) internal_ldap_get_values( ld, entry, target, 458 1 ) ); 459 } 460 461 char ** 462 LDAP_CALL 463 ldap_get_lang_values( LDAP *ld, LDAPMessage *entry, const char *target, 464 char **type ) 465 { 466 return( (char **) internal_ldap_get_lang_values( ld, entry, 467 target, type, 0 ) ); 468 } 469 470 struct berval ** 471 LDAP_CALL 472 ldap_get_lang_values_len( LDAP *ld, LDAPMessage *entry, const char *target, 473 char **type ) 474 { 475 return( (struct berval **) internal_ldap_get_lang_values( ld, entry, 476 target, type, 1 ) ); 477 } 478 479