📄 ldap.c
字号:
errorInfo->errorCode = LdapGetLastError();
if( errorInfo->errorCode == LDAP_SUCCESS )
{
/* In true Microsoft fashion LdapGetLastError() can return
LDAP_SUCCESS with the error string set to "Success.", so if we
get this we use the status value returned by the original LDAP
function call instead */
errorInfo->errorCode = ldapStatus;
}
errorMessage = ldap_err2string( errorInfo->errorCode );
#if 0
/* The exact conditions under which ldap_err2string() does something
useful are somewhat undefined, it may be necessary to use the
following which works with general Windows error codes rather than
special-case LDAP function result codes */
errorInfo->errorCode = GetLastError();
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorInfo->errorCode,
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
ldapInfo->errorMessage, MAX_ERRMSG_SIZE - 1, NULL );
#endif /* 0 */
#elif defined( NETSCAPE_CLIENT )
errorInfo->errorCode = ldap_get_lderrno( ldapInfo->ld, NULL,
&errorMessage );
#else
/* As usual there are various incompatible ways of getting the necessary
information, we use whatever's available */
#ifdef LDAP_OPT_ERROR_NUMBER
ldap_get_option( ldapInfo->ld, LDAP_OPT_ERROR_NUMBER,
&errorInfo->errorCode );
#else
ldap_get_option( ldapInfo->ld, LDAP_OPT_RESULT_CODE,
&errorInfo->errorCode );
#endif /* Various ways of getting the error information */
ldap_get_option( ldapInfo->ld, LDAP_OPT_ERROR_STRING,
&errorMessage );
#endif /* Different LDAP client types */
if( errorMessage != NULL )
setErrorString( errorInfo, errorMessage, strlen( errorMessage ) );
else
clearErrorString( errorInfo );
}
/* Map an LDAP error to the corresponding cryptlib error. The various LDAP
imlpementations differ slightly in their error codes, so we have to
adjust them as appropriate */
static int mapLdapError( const int ldapError, const int defaultError )
{
switch( ldapError )
{
case LDAP_INAPPROPRIATE_AUTH:
case LDAP_INVALID_CREDENTIALS:
case LDAP_AUTH_UNKNOWN:
#if defined( __WINDOWS__ )
case LDAP_INSUFFICIENT_RIGHTS:
case LDAP_AUTH_METHOD_NOT_SUPPORTED:
#elif defined( NETSCAPE_CLIENT )
case LDAP_INSUFFICIENT_ACCESS:
#else
case LDAP_INSUFFICIENT_ACCESS:
case LDAP_AUTH_METHOD_NOT_SUPPORTED:
#endif /* Different client types */
return( CRYPT_ERROR_PERMISSION );
#if defined( __WINDOWS__ )
case LDAP_ATTRIBUTE_OR_VALUE_EXISTS:
case LDAP_ALREADY_EXISTS:
#elif defined( NETSCAPE_CLIENT )
case LDAP_TYPE_OR_VALUE_EXISTS:
#else
case LDAP_TYPE_OR_VALUE_EXISTS:
case LDAP_ALREADY_EXISTS:
#endif /* Different client types */
return( CRYPT_ERROR_DUPLICATE );
#if defined( __WINDOWS__ )
case LDAP_CONFIDENTIALITY_REQUIRED:
#elif defined( NETSCAPE_CLIENT )
/* Nothing */
#else
case LDAP_CONFIDENTIALITY_REQUIRED:
case LDAP_STRONG_AUTH_REQUIRED:
return( CRYPT_ERROR_NOSECURE );
#endif /* Different client types */
case LDAP_INVALID_DN_SYNTAX:
return( CRYPT_ARGERROR_STR1 );
case LDAP_TIMELIMIT_EXCEEDED:
case LDAP_TIMEOUT:
return( CRYPT_ERROR_TIMEOUT );
#ifndef NETSCAPE_CLIENT
case LDAP_NO_RESULTS_RETURNED:
#endif /* NETSCAPE_CLIENT */
case LDAP_NO_SUCH_ATTRIBUTE:
case LDAP_NO_SUCH_OBJECT:
return( CRYPT_ERROR_NOTFOUND );
#ifndef NETSCAPE_CLIENT
case LDAP_NOT_SUPPORTED:
case LDAP_UNAVAILABLE:
return( CRYPT_ERROR_NOTAVAIL );
#endif /* NETSCAPE_CLIENT */
case LDAP_SIZELIMIT_EXCEEDED:
case LDAP_RESULTS_TOO_LARGE:
return( CRYPT_ERROR_OVERFLOW );
case LDAP_NO_MEMORY:
return( CRYPT_ERROR_MEMORY );
}
return( defaultError );
}
/* Copy attribute information into an LDAPMod structure so it can be written to
the directory */
static LDAPMod *copyAttribute( const char *attributeName,
const void *attributeValue,
const int attributeLength )
{
LDAPMod *ldapModPtr;
/* Allocate room for the LDAPMod structure and the data pointers.
mod_values and mod_bvalues members have the same representation so we
can allocate them with the same malloc */
if( ( ldapModPtr = ( LDAPMod * ) clAlloc( "copyAttribute", \
sizeof( LDAPMod ) ) ) == NULL )
return( NULL );
if( ( ldapModPtr->mod_values = clAlloc( "copyAttribute", \
2 * sizeof( void * ) ) ) == NULL )
{
clFree( "copyAttribute", ldapModPtr );
return( NULL );
}
/* Set up the pointers to the attribute information. This differs
slightly depending on whether we're adding text or binary data */
if( !attributeLength )
{
ldapModPtr->mod_op = LDAP_MOD_ADD;
ldapModPtr->mod_type = ( char * ) attributeName;
ldapModPtr->mod_values[ 0 ] = ( char * ) attributeValue;
ldapModPtr->mod_values[ 1 ] = NULL;
}
else
{
if( ( ldapModPtr->mod_bvalues[ 0 ] = \
clAlloc( "copyAttribute", sizeof( struct berval ) ) ) == NULL )
{
clFree( "copyAttribute", ldapModPtr->mod_values );
clFree( "copyAttribute", ldapModPtr );
return( NULL );
}
ldapModPtr->mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
ldapModPtr->mod_type = ( char * ) attributeName;
ldapModPtr->mod_bvalues[ 0 ]->bv_len = attributeLength;
ldapModPtr->mod_bvalues[ 0 ]->bv_val = ( char * ) attributeValue;
ldapModPtr->mod_bvalues[ 1 ] = NULL;
}
return( ldapModPtr );
}
/* Encode DN information in the RFC 1779 reversed format. We don't have to
explicitly check for overflows (which will lead to truncation of the
resulting encoded DN) because the certificate management code limits the
size of each component to a small fraction of the total buffer size.
Besides which, it's LDAP, anyone using this crap as a certificate store
is asking for it anyway */
static void catComponent( char *dest, const int destLen, char *src )
{
int i;
/* Find the end of the existing destination string */
for( i = 0; i < destLen && dest[ i ] != '\0'; i++ );
if( i >= destLen )
retIntError_Void();
/* Append the source string, escaping special chars */
while( i < destLen - 1 && *src != '\0' )
{
const char ch = *src++;
if( ch == ',' )
{
dest[ i++ ] = '\\';
if( i >= destLen )
break;
}
dest[ i++ ] = ch;
}
dest[ i ] = '\0';
}
static int encodeDN( char *dn, const int maxDnLen, char *C, char *SP,
char *L, char *O, char *OU, char *CN )
{
strlcpy_s( dn, maxDnLen, "CN=" );
catComponent( dn, maxDnLen, CN );
if( *OU )
{
strlcat_s( dn, maxDnLen, ",OU=" );
catComponent( dn, maxDnLen, OU );
}
if( *O )
{
strlcat_s( dn, maxDnLen, ",O=" );
catComponent( dn, maxDnLen, O );
}
if( *L )
{
strlcat_s( dn, maxDnLen, ",L=" );
catComponent( dn, maxDnLen, L );
}
if( *SP )
{
strlcat_s( dn, maxDnLen, ",ST=" ); /* Not to be confused with ST=street */
catComponent( dn, maxDnLen, SP );
}
strlcat_s( dn, maxDnLen, ",C=" );
catComponent( dn, maxDnLen, C );
return( CRYPT_OK );
}
/* Decompose an LDAP URL of the general form ldap://server:port/user into its
various components */
static int parseURL( char *ldapServer, char **ldapUser, int *ldapPort )
{
char *strPtr;
/* Clear return value */
*ldapUser = NULL;
*ldapPort = LDAP_PORT;
/* Handle a leading URL specifier if this is present */
if( !strCompare( ldapServer, "ldaps://", 8 ) )
/* We can't do LDAP over SSL without a lot of extra work */
return( CRYPT_ERROR_BADDATA );
if( !strCompare( ldapServer, "ldap://", 7 ) )
memmove( ldapServer, ldapServer + 7, strlen( ldapServer ) - 6 );
/* Decompose what's left into a FQDN, port, and user name */
if( ( strPtr = strchr( ldapServer, '/' ) ) != NULL )
{
*strPtr++ = '\0';
*ldapUser = strPtr;
}
if( ( strPtr = strchr( ldapServer, ':' ) ) != NULL )
{
*strPtr++ = '\0';
*ldapPort = atoi( strPtr );
if( *ldapPort < 26 || *ldapPort > 65534L )
return( CRYPT_ERROR_BADDATA );
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Directory Open/Close Routines *
* *
****************************************************************************/
/* Close a previously-opened LDAP connection. We have to have this before
the init function since it may be called by it if the open process fails.
This is necessary because the complex LDAP open may require a fairly
extensive cleanup afterwards */
STDC_NONNULL_ARG( ( 1 ) ) \
static int shutdownFunction( INOUT KEYSET_INFO *keysetInfoPtr )
{
LDAP_INFO *ldapInfo = keysetInfoPtr->keysetLDAP;
assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
REQUIRES( keysetInfoPtr->type == KEYSET_LDAP );
ldap_unbind( ldapInfo->ld );
ldapInfo->ld = NULL;
return( CRYPT_OK );
}
/* Open a connection to an LDAP directory */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int initFunction( INOUT KEYSET_INFO *keysetInfoPtr,
IN_BUFFER( nameLength ) const char *name,
IN_LENGTH_SHORT const int nameLength,
IN_ENUM( CRYPT_KEYOPT ) const CRYPT_KEYOPT_TYPE options )
{
LDAP_INFO *ldapInfo = keysetInfoPtr->keysetLDAP;
char ldapServer[ MAX_URL_SIZE + 8 ], *ldapUser;
int maxEntries = 2, timeout, ldapPort, ldapStatus = LDAP_OTHER, status;
assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
assert( isReadPtr( name, nameLength ) );
REQUIRES( keysetInfoPtr->type == KEYSET_LDAP );
REQUIRES( nameLength >= MIN_URL_SIZE && nameLength < MAX_URL_SIZE );
REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );
/* Check the URL. The Netscape and OpenLDAP APIs provide the function
ldap_is_ldap_url() for this, but this requires a complete LDAP URL
rather than just a server name and port */
if( nameLength > MAX_URL_SIZE - 1 )
return( CRYPT_ARGERROR_STR1 );
memcpy( ldapServer, name, nameLength );
ldapServer[ nameLength ] = '\0';
status = parseURL( ldapServer, &ldapUser, &ldapPort );
if( cryptStatusError( status ) )
return( CRYPT_ARGERROR_STR1 );
/* Open the connection to the server */
if( ( ldapInfo->ld = ldap_init( ldapServer, ldapPort ) ) == NULL )
return( CRYPT_ERROR_OPEN );
if( ( ldapStatus = ldap_simple_bind_s( ldapInfo->ld, ldapUser,
NULL ) ) != LDAP_SUCCESS )
{
getErrorInfo( keysetInfoPtr, ldapStatus );
ldap_unbind( ldapInfo->ld );
ldapInfo->ld = NULL;
return( mapLdapError( ldapStatus, CRYPT_ERROR_OPEN ) );
}
/* Set the search timeout and limit the maximum number of returned
entries to 2 (setting the search timeout is mostly redundant since we
use search_st anyway, however there may be other operations which also
require some sort of timeout which can't be explicitly specified */
krnlSendMessage( keysetInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE,
&timeout, CRYPT_OPTION_NET_READTIMEOUT );
if( timeout < 15 )
/* Network I/O may be set to be nonblocking, so we make sure we try
for at least 15s before timing out */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -