diff options
Diffstat (limited to 'ldap/c-sdk/libraries/libldap/error.c')
-rw-r--r-- | ldap/c-sdk/libraries/libldap/error.c | 490 |
1 files changed, 490 insertions, 0 deletions
diff --git a/ldap/c-sdk/libraries/libldap/error.c b/ldap/c-sdk/libraries/libldap/error.c new file mode 100644 index 000000000..82cbb56cb --- /dev/null +++ b/ldap/c-sdk/libraries/libldap/error.c @@ -0,0 +1,490 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "ldap-int.h" + +struct ldaperror { + int e_code; + char *e_reason; +}; + +static struct ldaperror ldap_errlist[] = { + { LDAP_SUCCESS, "Success" }, + { LDAP_OPERATIONS_ERROR, "Operations error" }, + { LDAP_PROTOCOL_ERROR, "Protocol error" }, + { LDAP_TIMELIMIT_EXCEEDED, "Timelimit exceeded" }, + { LDAP_SIZELIMIT_EXCEEDED, "Sizelimit exceeded" }, + { LDAP_COMPARE_FALSE, "Compare false" }, + { LDAP_COMPARE_TRUE, "Compare true" }, + { LDAP_STRONG_AUTH_NOT_SUPPORTED, "Authentication method not supported" }, + { LDAP_STRONG_AUTH_REQUIRED, "Strong authentication required" }, + { LDAP_PARTIAL_RESULTS, "Partial results and referral received" }, + { LDAP_REFERRAL, "Referral received" }, + { LDAP_ADMINLIMIT_EXCEEDED, "Administrative limit exceeded" }, + { LDAP_UNAVAILABLE_CRITICAL_EXTENSION, "Unavailable critical extension" }, + { LDAP_CONFIDENTIALITY_REQUIRED, "Confidentiality required" }, + { LDAP_SASL_BIND_IN_PROGRESS, "SASL bind in progress" }, + + { LDAP_NO_SUCH_ATTRIBUTE, "No such attribute" }, + { LDAP_UNDEFINED_TYPE, "Undefined attribute type" }, + { LDAP_INAPPROPRIATE_MATCHING, "Inappropriate matching" }, + { LDAP_CONSTRAINT_VIOLATION, "Constraint violation" }, + { LDAP_TYPE_OR_VALUE_EXISTS, "Type or value exists" }, + { LDAP_INVALID_SYNTAX, "Invalid syntax" }, + + { LDAP_NO_SUCH_OBJECT, "No such object" }, + { LDAP_ALIAS_PROBLEM, "Alias problem" }, + { LDAP_INVALID_DN_SYNTAX, "Invalid DN syntax" }, + { LDAP_IS_LEAF, "Object is a leaf" }, + { LDAP_ALIAS_DEREF_PROBLEM, "Alias dereferencing problem" }, + + { LDAP_INAPPROPRIATE_AUTH, "Inappropriate authentication" }, + { LDAP_INVALID_CREDENTIALS, "Invalid credentials" }, + { LDAP_INSUFFICIENT_ACCESS, "Insufficient access" }, + { LDAP_BUSY, "DSA is busy" }, + { LDAP_UNAVAILABLE, "DSA is unavailable" }, + { LDAP_UNWILLING_TO_PERFORM, "DSA is unwilling to perform" }, + { LDAP_LOOP_DETECT, "Loop detected" }, + { LDAP_SORT_CONTROL_MISSING, "Sort Control is missing" }, + { LDAP_INDEX_RANGE_ERROR, "Search results exceed the range specified by the offsets" }, + + { LDAP_NAMING_VIOLATION, "Naming violation" }, + { LDAP_OBJECT_CLASS_VIOLATION, "Object class violation" }, + { LDAP_NOT_ALLOWED_ON_NONLEAF, "Operation not allowed on nonleaf" }, + { LDAP_NOT_ALLOWED_ON_RDN, "Operation not allowed on RDN" }, + { LDAP_ALREADY_EXISTS, "Already exists" }, + { LDAP_NO_OBJECT_CLASS_MODS, "Cannot modify object class" }, + { LDAP_RESULTS_TOO_LARGE, "Results too large" }, + { LDAP_AFFECTS_MULTIPLE_DSAS, "Affects multiple servers" }, + + { LDAP_OTHER, "Unknown error" }, + { LDAP_SERVER_DOWN, "Can't contact LDAP server" }, + { LDAP_LOCAL_ERROR, "Local error" }, + { LDAP_ENCODING_ERROR, "Encoding error" }, + { LDAP_DECODING_ERROR, "Decoding error" }, + { LDAP_TIMEOUT, "Timed out" }, + { LDAP_AUTH_UNKNOWN, "Unknown authentication method" }, + { LDAP_FILTER_ERROR, "Bad search filter" }, + { LDAP_USER_CANCELLED, "User cancelled operation" }, + { LDAP_PARAM_ERROR, "Bad parameter to an ldap routine" }, + { LDAP_NO_MEMORY, "Out of memory" }, + { LDAP_CONNECT_ERROR, "Can't connect to the LDAP server" }, + { LDAP_NOT_SUPPORTED, "Not supported by this version of the LDAP protocol" }, + { LDAP_CONTROL_NOT_FOUND, "Requested LDAP control not found" }, + { LDAP_NO_RESULTS_RETURNED, "No results returned" }, + { LDAP_MORE_RESULTS_TO_RETURN, "More results to return" }, + { LDAP_CLIENT_LOOP, "Client detected loop" }, + { LDAP_REFERRAL_LIMIT_EXCEEDED, "Referral hop limit exceeded" }, + { -1, 0 } +}; + +char * +LDAP_CALL +ldap_err2string( int err ) +{ + int i; + + LDAPDebug( LDAP_DEBUG_TRACE, "ldap_err2string\n", 0, 0, 0 ); + + for ( i = 0; ldap_errlist[i].e_code != -1; i++ ) { + if ( err == ldap_errlist[i].e_code ) + return( ldap_errlist[i].e_reason ); + } + + return( "Unknown error" ); +} + + +static char * +nsldapi_safe_strerror( int e ) +{ + char *s; + + if (( s = strerror( e )) == NULL ) { + s = "unknown error"; + } + + return( s ); +} + + +void +LDAP_CALL +ldap_perror( LDAP *ld, const char *s ) +{ + int i, err; + char *matched = NULL; + char *errmsg = NULL; + char *separator; + char msg[1024]; + + LDAPDebug( LDAP_DEBUG_TRACE, "ldap_perror\n", 0, 0, 0 ); + + if ( s == NULL ) { + s = separator = ""; + } else { + separator = ": "; + } + + if ( ld == NULL ) { + snprintf( msg, sizeof( msg ), + "%s%s%s", s, separator, nsldapi_safe_strerror( errno ) ); + ber_err_print( msg ); + return; + } + + LDAP_MUTEX_LOCK( ld, LDAP_ERR_LOCK ); + err = LDAP_GET_LDERRNO( ld, &matched, &errmsg ); + for ( i = 0; ldap_errlist[i].e_code != -1; i++ ) { + if ( err == ldap_errlist[i].e_code ) { + snprintf( msg, sizeof( msg ), + "%s%s%s", s, separator, ldap_errlist[i].e_reason ); + ber_err_print( msg ); + if ( err == LDAP_CONNECT_ERROR ) { + ber_err_print( " - " ); + ber_err_print( nsldapi_safe_strerror( + LDAP_GET_ERRNO( ld ))); + } + ber_err_print( "\n" ); + if ( matched != NULL && *matched != '\0' ) { + snprintf( msg, sizeof( msg ), + "%s%smatched: %s\n", s, separator, matched ); + ber_err_print( msg ); + } + if ( errmsg != NULL && *errmsg != '\0' ) { + snprintf( msg, sizeof( msg ), + "%s%sadditional info: %s\n", s, separator, errmsg ); + ber_err_print( msg ); + } + LDAP_MUTEX_UNLOCK( ld, LDAP_ERR_LOCK ); + return; + } + } + snprintf( msg, sizeof( msg ), + "%s%sNot an LDAP errno %d\n", s, separator, err ); + ber_err_print( msg ); + LDAP_MUTEX_UNLOCK( ld, LDAP_ERR_LOCK ); +} + +int +LDAP_CALL +ldap_result2error( LDAP *ld, LDAPMessage *r, int freeit ) +{ + int lderr_parse, lderr; + + lderr_parse = ldap_parse_result( ld, r, &lderr, NULL, NULL, NULL, + NULL, freeit ); + + if ( lderr_parse != LDAP_SUCCESS ) { + return( lderr_parse ); + } + + return( lderr ); +} + +int +LDAP_CALL +ldap_get_lderrno( LDAP *ld, char **m, char **s ) +{ + if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { + return( LDAP_PARAM_ERROR ); /* punt */ + } + + if ( ld->ld_get_lderrno_fn == NULL ) { + if ( m != NULL ) { + *m = ld->ld_matched; + } + if ( s != NULL ) { + *s = ld->ld_error; + } + return( ld->ld_errno ); + } else { + return( ld->ld_get_lderrno_fn( m, s, ld->ld_lderrno_arg ) ); + } +} + + +/* + * Note: there is no need for callers of ldap_set_lderrno() to lock the + * ld mutex. If applications intend to share an LDAP session handle + * between threads they *must* perform their own locking around the + * session handle or they must install a "set lderrno" thread callback + * function. + * + */ +int +LDAP_CALL +ldap_set_lderrno( LDAP *ld, int e, char *m, char *s ) +{ + if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { + return( LDAP_PARAM_ERROR ); + } + + if ( ld->ld_set_lderrno_fn != NULL ) { + ld->ld_set_lderrno_fn( e, m, s, ld->ld_lderrno_arg ); + } else { + LDAP_MUTEX_LOCK( ld, LDAP_ERR_LOCK ); + ld->ld_errno = e; + if ( ld->ld_matched ) { + NSLDAPI_FREE( ld->ld_matched ); + } + ld->ld_matched = m; + if ( ld->ld_error ) { + NSLDAPI_FREE( ld->ld_error ); + } + ld->ld_error = s; + LDAP_MUTEX_UNLOCK( ld, LDAP_ERR_LOCK ); + } + + return( LDAP_SUCCESS ); +} + + +/* + * Returns an LDAP error that says whether parse succeeded. The error code + * from the LDAP result itself is returned in the errcodep result parameter. + * If any of the result params. (errcodep, matchednp, errmsgp, referralsp, + * or serverctrlsp) are NULL we don't return that info. + */ +int +LDAP_CALL +ldap_parse_result( LDAP *ld, LDAPMessage *res, int *errcodep, char **matchednp, + char **errmsgp, char ***referralsp, LDAPControl ***serverctrlsp, + int freeit ) +{ + LDAPMessage *lm; + int err, errcode; + char *m, *e; + m = e = NULL; + + LDAPDebug( LDAP_DEBUG_TRACE, "ldap_parse_result\n", 0, 0, 0 ); + + if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || + !NSLDAPI_VALID_LDAPMESSAGE_POINTER( res )) { + return( LDAP_PARAM_ERROR ); + } + + /* skip over entries and references to find next result in this chain */ + for ( lm = res; lm != NULL; lm = lm->lm_chain ) { + if ( lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY && + lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE ) { + break; + } + } + + if ( lm == NULL ) { + err = LDAP_NO_RESULTS_RETURNED; + LDAP_SET_LDERRNO( ld, err, NULL, NULL ); + return( err ); + } + + err = nsldapi_parse_result( ld, lm->lm_msgtype, lm->lm_ber, &errcode, + &m, &e, referralsp, serverctrlsp ); + + if ( err == LDAP_SUCCESS ) { + if ( errcodep != NULL ) { + *errcodep = errcode; + } + if ( matchednp != NULL ) { + *matchednp = nsldapi_strdup( m ); + } + if ( errmsgp != NULL ) { + *errmsgp = nsldapi_strdup( e ); + } + + /* + * if there are more result messages in the chain, arrange to + * return the special LDAP_MORE_RESULTS_TO_RETURN "error" code. + */ + for ( lm = lm->lm_chain; lm != NULL; lm = lm->lm_chain ) { + if ( lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY && + lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE ) { + err = LDAP_MORE_RESULTS_TO_RETURN; + break; + } + } + } else { + /* In this case, m and e were already freed by ber_scanf */ + m = e = NULL; + } + + if ( freeit ) { + ldap_msgfree( res ); + } + + LDAP_SET_LDERRNO( ld, ( err == LDAP_SUCCESS ) ? errcode : err, m, e ); + + /* nsldapi_parse_result set m and e, so we have to delete them if they exist. + Only delete them if they haven't been reused for matchednp or errmsgp. + if ( err == LDAP_SUCCESS ) { + if ( (m != NULL) && (matchednp == NULL) ) { + NSLDAPI_FREE( m ); + } + if ( (e != NULL) && (errmsgp == NULL) ) { + NSLDAPI_FREE( e ); + } + } */ + + return( err ); +} + +/* + * returns an LDAP error code indicating success or failure of parsing + * does NOT set any error information inside "ld" + */ +int +nsldapi_parse_result( LDAP *ld, int msgtype, BerElement *rber, int *errcodep, + char **matchednp, char **errmsgp, char ***referralsp, + LDAPControl ***serverctrlsp ) +{ + BerElement ber; + ber_len_t len; + ber_int_t errcode; + int berrc, err; + char *m, *e; + + /* + * Parse the result message. LDAPv3 result messages look like this: + * + * LDAPResult ::= SEQUENCE { + * resultCode ENUMERATED { ... }, + * matchedDN LDAPDN, + * errorMessage LDAPString, + * referral [3] Referral OPTIONAL + * opSpecificStuff OPTIONAL + * } + * + * all wrapped up in an LDAPMessage sequence which looks like this: + * LDAPMessage ::= SEQUENCE { + * messageID MessageID, + * LDAPResult CHOICE { ... }, // message type + * controls [0] Controls OPTIONAL + * } + * + * LDAPv2 messages don't include referrals or controls. + * LDAPv1 messages don't include matchedDN, referrals, or controls. + * + * ldap_result() pulls out the message id, so by the time a result + * message gets here we are sitting at the start of the LDAPResult. + */ + + err = LDAP_SUCCESS; /* optimistic */ + m = e = NULL; + if ( matchednp != NULL ) { + *matchednp = NULL; + } + if ( errmsgp != NULL ) { + *errmsgp = NULL; + } + if ( referralsp != NULL ) { + *referralsp = NULL; + } + if ( serverctrlsp != NULL ) { + *serverctrlsp = NULL; + } + ber = *rber; /* struct copy */ + + if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION2 ) { + berrc = ber_scanf( &ber, "{ia}", &errcode, &e ); + } else { + if (( berrc = ber_scanf( &ber, "{iaa", &errcode, &m, &e )) + != LBER_ERROR ) { + /* check for optional referrals */ + if ( ber_peek_tag( &ber, &len ) == LDAP_TAG_REFERRAL ) { + if ( referralsp == NULL ) { + /* skip referrals */ + berrc = ber_scanf( &ber, "x" ); + } else { + /* suck out referrals */ + berrc = ber_scanf( &ber, "v", + referralsp ); + } + } else if ( referralsp != NULL ) { + *referralsp = NULL; + } + } + + if ( berrc != LBER_ERROR ) { + /* + * skip past optional operation-specific elements: + * bind results - serverSASLcreds + * extendedop results - OID plus value + */ + if ( msgtype == LDAP_RES_BIND ) { + if ( ber_peek_tag( &ber, &len ) == + LDAP_TAG_SASL_RES_CREDS ) { + berrc = ber_scanf( &ber, "x" ); + } + } else if ( msgtype == LDAP_RES_EXTENDED ) { + if ( ber_peek_tag( &ber, &len ) == + LDAP_TAG_EXOP_RES_OID ) { + berrc = ber_scanf( &ber, "x" ); + } + if ( berrc != LBER_ERROR && + ber_peek_tag( &ber, &len ) == + LDAP_TAG_EXOP_RES_VALUE ) { + berrc = ber_scanf( &ber, "x" ); + } + } + } + + /* pull out controls (if requested and any are present) */ + if ( berrc != LBER_ERROR && serverctrlsp != NULL && + ( berrc = ber_scanf( &ber, "}" )) != LBER_ERROR ) { + err = nsldapi_get_controls( &ber, serverctrlsp ); + } + } + + if ( berrc == LBER_ERROR && err == LDAP_SUCCESS ) { + err = LDAP_DECODING_ERROR; + } + + if ( errcodep != NULL ) { + *errcodep = errcode; + } + if ( matchednp != NULL ) { + *matchednp = m; + } else if ( m != NULL ) { + NSLDAPI_FREE( m ); + } + if ( errmsgp != NULL ) { + *errmsgp = e; + } else if ( e != NULL ) { + NSLDAPI_FREE( e ); + } + + return( err ); +} |