зеркало из https://github.com/mozilla/pjs.git
466 строки
11 KiB
C
466 строки
11 KiB
C
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
*
|
|
* 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.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
/*
|
|
* Copyright (c) 1990 Regents of the University of Michigan.
|
|
* All rights reserved.
|
|
*/
|
|
/*
|
|
* getvalues.c
|
|
*/
|
|
|
|
#if 0
|
|
#ifndef lint
|
|
static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
|
|
#endif
|
|
#endif
|
|
|
|
#include "ldap-int.h"
|
|
|
|
|
|
static void **
|
|
internal_ldap_get_values( LDAP *ld, LDAPMessage *entry, const char *target,
|
|
int lencall )
|
|
{
|
|
struct berelement ber;
|
|
char *attr;
|
|
int rc;
|
|
void **vals;
|
|
|
|
LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_values\n", 0, 0, 0 );
|
|
|
|
if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
|
|
return( NULL ); /* punt */
|
|
}
|
|
if ( target == NULL ||
|
|
!NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
|
|
LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
|
|
return( NULL );
|
|
}
|
|
|
|
ber = *entry->lm_ber;
|
|
|
|
/* skip sequence, dn, sequence of, and snag the first attr */
|
|
if ( ber_scanf( &ber, "{x{{a", &attr ) == LBER_ERROR ) {
|
|
LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
|
|
return( NULL );
|
|
}
|
|
|
|
rc = strcasecmp( (char *)target, attr );
|
|
NSLDAPI_FREE( attr );
|
|
if ( rc != 0 ) {
|
|
while ( 1 ) {
|
|
if ( ber_scanf( &ber, "x}{a", &attr ) == LBER_ERROR ) {
|
|
LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR,
|
|
NULL, NULL );
|
|
return( NULL );
|
|
}
|
|
|
|
rc = strcasecmp( (char *)target, attr );
|
|
if ( rc == 0 ) {
|
|
NSLDAPI_FREE( attr );
|
|
break;
|
|
}
|
|
NSLDAPI_FREE( attr );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* if we get this far, we've found the attribute and are sitting
|
|
* just before the set of values.
|
|
*/
|
|
|
|
if ( lencall ) {
|
|
rc = ber_scanf( &ber, "[V]", &vals );
|
|
} else {
|
|
rc = ber_scanf( &ber, "[v]", &vals );
|
|
}
|
|
|
|
if ( rc == LBER_ERROR ) {
|
|
rc = LDAP_DECODING_ERROR;
|
|
} else {
|
|
rc = LDAP_SUCCESS;
|
|
}
|
|
|
|
LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
|
|
|
|
return(( rc == LDAP_SUCCESS ) ? vals : NULL );
|
|
}
|
|
|
|
|
|
/* For language-sensitive attribute matching, we are looking for a
|
|
language tag that looks like one of the following:
|
|
|
|
cn
|
|
cn;lang-en
|
|
cn;lang-en-us
|
|
cn;lang-ja
|
|
cn;lang-ja-JP-kanji
|
|
|
|
The base language specification consists of two letters following
|
|
"lang-". After that, there may be additional language-specific
|
|
narrowings preceded by a "-". In our processing we go from the
|
|
specific to the general, preferring a complete subtype match, but
|
|
accepting a partial one. For example:
|
|
|
|
For a request for "cn;lang-en-us", we would return cn;lang-en-us
|
|
if present, otherwise cn;lang-en if present, otherwise cn.
|
|
|
|
Besides the language subtype, there may be other subtypes:
|
|
|
|
cn;lang-ja;binary (Unlikely!)
|
|
cn;lang-ja;phonetic
|
|
|
|
If not in the target, they are ignored. If they are in the target,
|
|
they must be in the attribute to match.
|
|
*/
|
|
#define LANG_SUBTYPE_INDEX_NONE -1
|
|
#define LANG_SUBTYPE_INDEX_DUPLICATE -2
|
|
|
|
typedef struct {
|
|
int start;
|
|
int length;
|
|
} _SubStringIndex;
|
|
|
|
static int
|
|
parse_subtypes( const char *target, int *baseLenp, char **langp,
|
|
_SubStringIndex **subs, int *nsubtypes )
|
|
{
|
|
int nSubtypes = 0;
|
|
int ind = 0;
|
|
char *nextToken;
|
|
_SubStringIndex *result = NULL;
|
|
int langIndex;
|
|
int targetLen;
|
|
int subtypeStart;
|
|
|
|
langIndex = LANG_SUBTYPE_INDEX_NONE;
|
|
*subs = NULL;
|
|
*langp = NULL;
|
|
*baseLenp = 0;
|
|
*nsubtypes = 0;
|
|
targetLen = strlen( target );
|
|
|
|
/* Parse past base attribute */
|
|
nextToken = strchr( target, ';' );
|
|
if ( NULL != nextToken ) {
|
|
subtypeStart = nextToken - target + 1;
|
|
*baseLenp = subtypeStart - 1;
|
|
}
|
|
else {
|
|
subtypeStart = targetLen;
|
|
*baseLenp = subtypeStart;
|
|
}
|
|
ind = subtypeStart;
|
|
|
|
/* How many subtypes? */
|
|
nextToken = (char *)target + subtypeStart;
|
|
while ( nextToken && *nextToken ) {
|
|
char *thisToken = nextToken;
|
|
nextToken = strchr( thisToken, ';' );
|
|
if ( NULL != nextToken )
|
|
nextToken++;
|
|
if ( 0 == strncasecmp( thisToken, "lang-", 5 ) ) {
|
|
/* If there was a previous lang tag, this is illegal! */
|
|
if ( langIndex != LANG_SUBTYPE_INDEX_NONE ) {
|
|
langIndex = LANG_SUBTYPE_INDEX_DUPLICATE;
|
|
return langIndex;
|
|
}
|
|
else {
|
|
langIndex = nSubtypes;
|
|
}
|
|
} else {
|
|
nSubtypes++;
|
|
}
|
|
}
|
|
/* No language subtype? */
|
|
if ( langIndex < 0 )
|
|
return langIndex;
|
|
|
|
/* Allocate array of non-language subtypes */
|
|
if ( nSubtypes > 0 ) {
|
|
result = (_SubStringIndex *)NSLDAPI_MALLOC( sizeof(*result)
|
|
* nSubtypes );
|
|
memset( result, 0, sizeof(*result) * nSubtypes );
|
|
}
|
|
ind = 0;
|
|
nSubtypes = 0;
|
|
ind = subtypeStart;
|
|
nextToken = (char *)target + subtypeStart;
|
|
while ( nextToken && *nextToken ) {
|
|
char *thisToken = nextToken;
|
|
int len;
|
|
nextToken = strchr( thisToken, ';' );
|
|
if ( NULL != nextToken ) {
|
|
len = nextToken - thisToken;
|
|
nextToken++;
|
|
}
|
|
else {
|
|
nextToken = (char *)target + targetLen;
|
|
len = nextToken - thisToken;
|
|
}
|
|
if ( 0 == strncasecmp( thisToken, "lang-", 5 ) ) {
|
|
int i;
|
|
*langp = (char *)NSLDAPI_MALLOC( len + 1 );
|
|
for( i = 0; i < len; i++ )
|
|
(*langp)[i] = toupper( target[ind+i] );
|
|
(*langp)[len] = 0;
|
|
}
|
|
else {
|
|
result[nSubtypes].start = thisToken - target;
|
|
result[nSubtypes].length = len;
|
|
nSubtypes++;
|
|
}
|
|
}
|
|
*subs = result;
|
|
*nsubtypes = nSubtypes;
|
|
return langIndex;
|
|
}
|
|
|
|
|
|
static int
|
|
check_lang_match( const char *target, const char *baseTarget,
|
|
_SubStringIndex *targetTypes,
|
|
int ntargetTypes, char *targetLang, char *attr )
|
|
{
|
|
int langIndex;
|
|
_SubStringIndex *subtypes;
|
|
int baseLen;
|
|
char *lang;
|
|
int nsubtypes;
|
|
int mismatch = 0;
|
|
int match = -1;
|
|
int i;
|
|
|
|
/* Get all subtypes in the attribute name */
|
|
langIndex = parse_subtypes( attr, &baseLen, &lang, &subtypes, &nsubtypes );
|
|
|
|
/* Check if there any required non-language subtypes which are
|
|
not in this attribute */
|
|
for( i = 0; i < ntargetTypes; i++ ) {
|
|
char *t = (char *)target+targetTypes[i].start;
|
|
int tlen = targetTypes[i].length;
|
|
int j;
|
|
for( j = 0; j < nsubtypes; j++ ) {
|
|
char *a = attr + subtypes[j].start;
|
|
int alen = subtypes[j].length;
|
|
if ( (tlen == alen) && !strncasecmp( t, a, tlen ) )
|
|
break;
|
|
}
|
|
if ( j >= nsubtypes ) {
|
|
mismatch = 1;
|
|
break;
|
|
}
|
|
}
|
|
if ( mismatch ) {
|
|
if ( NULL != subtypes )
|
|
NSLDAPI_FREE( subtypes );
|
|
if ( NULL != lang )
|
|
NSLDAPI_FREE( lang );
|
|
return -1;
|
|
}
|
|
|
|
/* If there was no language subtype... */
|
|
if ( langIndex < 0 ) {
|
|
if ( NULL != subtypes )
|
|
NSLDAPI_FREE( subtypes );
|
|
if ( NULL != lang )
|
|
NSLDAPI_FREE( lang );
|
|
if ( LANG_SUBTYPE_INDEX_NONE == langIndex )
|
|
return 0;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
/* Okay, now check the language subtag */
|
|
i = 0;
|
|
while( targetLang[i] && lang[i] &&
|
|
(toupper(targetLang[i]) == toupper(lang[i])) )
|
|
i++;
|
|
|
|
/* The total length can't be longer than the requested subtype */
|
|
if ( !lang[i] || (lang[i] == ';') ) {
|
|
/* If the found subtype is shorter than the requested one, the next
|
|
character in the requested one should be "-" */
|
|
if ( !targetLang[i] || (targetLang[i] == '-') )
|
|
match = i;
|
|
}
|
|
return match;
|
|
}
|
|
|
|
static int check_base_match( const char *target, char *attr )
|
|
{
|
|
int i = 0;
|
|
int rc;
|
|
while( target[i] && attr[i] && (toupper(target[i]) == toupper(attr[i])) )
|
|
i++;
|
|
rc = ( !target[i] && (!attr[i] || (';' == attr[i])) );
|
|
return rc;
|
|
}
|
|
|
|
static void **
|
|
internal_ldap_get_lang_values( LDAP *ld, LDAPMessage *entry,
|
|
const char *target, char **type, int lencall )
|
|
{
|
|
struct berelement ber;
|
|
char *attr = NULL;
|
|
int rc;
|
|
void **vals = NULL;
|
|
int langIndex;
|
|
_SubStringIndex *subtypes;
|
|
int nsubtypes;
|
|
char *baseTarget = NULL;
|
|
int bestMatch = 0;
|
|
char *lang = NULL;
|
|
int len;
|
|
int firstAttr = 1;
|
|
char *bestType = NULL;
|
|
|
|
LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_values\n", 0, 0, 0 );
|
|
|
|
if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
|
|
return( NULL );
|
|
}
|
|
if ( (target == NULL) ||
|
|
!NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
|
|
LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
|
|
return( NULL );
|
|
}
|
|
|
|
/* A language check was requested, so see if there really is a
|
|
language subtype in the attribute spec */
|
|
langIndex = parse_subtypes( target, &len, &lang,
|
|
&subtypes, &nsubtypes );
|
|
if ( langIndex < 0 ) {
|
|
if ( NULL != subtypes ) {
|
|
NSLDAPI_FREE( subtypes );
|
|
subtypes = NULL;
|
|
}
|
|
vals = internal_ldap_get_values( ld, entry, target, lencall );
|
|
if ( NULL != type )
|
|
*type = nsldapi_strdup( target );
|
|
return vals;
|
|
} else {
|
|
/* Get just the base attribute name */
|
|
baseTarget = (char *)NSLDAPI_MALLOC( len + 1 );
|
|
memcpy( baseTarget, target, len );
|
|
baseTarget[len] = 0;
|
|
}
|
|
|
|
ber = *entry->lm_ber;
|
|
|
|
/* Process all attributes in the entry */
|
|
while ( 1 ) {
|
|
int foundMatch = 0;
|
|
if ( NULL != attr )
|
|
NSLDAPI_FREE( attr );
|
|
if ( firstAttr ) {
|
|
firstAttr = 0;
|
|
/* skip sequence, dn, sequence of, and snag the first attr */
|
|
if ( ber_scanf( &ber, "{x{{a", &attr ) == LBER_ERROR ) {
|
|
break;
|
|
}
|
|
} else {
|
|
if ( ber_scanf( &ber, "{a", &attr ) == LBER_ERROR ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( check_base_match( (const char *)baseTarget, attr ) ) {
|
|
int thisMatch = check_lang_match( target, baseTarget,
|
|
subtypes, nsubtypes, lang, attr );
|
|
if ( thisMatch > bestMatch ) {
|
|
if ( vals )
|
|
NSLDAPI_FREE( vals );
|
|
foundMatch = 1;
|
|
bestMatch = thisMatch;
|
|
if ( NULL != bestType )
|
|
NSLDAPI_FREE( bestType );
|
|
bestType = attr;
|
|
attr = NULL;
|
|
}
|
|
}
|
|
if ( foundMatch ) {
|
|
if ( lencall ) {
|
|
rc = ber_scanf( &ber, "[V]}", &vals );
|
|
} else {
|
|
rc = ber_scanf( &ber, "[v]}", &vals );
|
|
}
|
|
} else {
|
|
ber_scanf( &ber, "x}" );
|
|
}
|
|
}
|
|
|
|
NSLDAPI_FREE( lang );
|
|
NSLDAPI_FREE( baseTarget );
|
|
NSLDAPI_FREE( subtypes );
|
|
|
|
if ( NULL != type )
|
|
*type = bestType;
|
|
else if ( NULL != bestType )
|
|
NSLDAPI_FREE( bestType );
|
|
|
|
if ( NULL == vals ) {
|
|
rc = LDAP_DECODING_ERROR;
|
|
} else {
|
|
rc = LDAP_SUCCESS;
|
|
}
|
|
|
|
LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
|
|
|
|
return( vals );
|
|
}
|
|
|
|
|
|
char **
|
|
LDAP_CALL
|
|
ldap_get_values( LDAP *ld, LDAPMessage *entry, const char *target )
|
|
{
|
|
return( (char **) internal_ldap_get_values( ld, entry, target, 0 ) );
|
|
}
|
|
|
|
struct berval **
|
|
LDAP_CALL
|
|
ldap_get_values_len( LDAP *ld, LDAPMessage *entry, const char *target )
|
|
{
|
|
return( (struct berval **) internal_ldap_get_values( ld, entry, target,
|
|
1 ) );
|
|
}
|
|
|
|
char **
|
|
LDAP_CALL
|
|
ldap_get_lang_values( LDAP *ld, LDAPMessage *entry, const char *target,
|
|
char **type )
|
|
{
|
|
return( (char **) internal_ldap_get_lang_values( ld, entry,
|
|
target, type, 0 ) );
|
|
}
|
|
|
|
struct berval **
|
|
LDAP_CALL
|
|
ldap_get_lang_values_len( LDAP *ld, LDAPMessage *entry, const char *target,
|
|
char **type )
|
|
{
|
|
return( (struct berval **) internal_ldap_get_lang_values( ld, entry,
|
|
target, type, 1 ) );
|
|
}
|
|
|