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