LDAPEXT Working Group M. Smith INTERNET-DRAFT Netscape Communications Corp. Intended Category: Standards Track Expires: 20 April 2000 20 October 1999 C LDAP API LDERRNO Extension 1. Status of this Memo This document is an Internet-Draft and is in full conformance with all provisions of Section 10 of RFC2026. Internet-Drafts are working docu- ments of the Internet Engineering Task Force (IETF), its areas, and its working groups. Note that other groups may also distribute working documents as Internet-Drafts. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress." The list of current Internet-Drafts can be accessed at http://www.ietf.org/ietf/1id-abstracts.txt. The list of Internet-Draft Shadow Directories can be accessed at http://www.ietf.org/shadow.html. This draft document will be submitted to the RFC Editor as a Standards Track document. Distribution of this memo is unlimited. Technical dis- cussion of this document will take place on the IETF LDAP Extension Working Group mailing list . Please send editorial comments directly to the author . Copyright (C) The Internet Society (1998-1999). All Rights Reserved. Please see the Copyright section near the end of this document for more information. Expires: 20 April 2000 [Page 1] INTERNET-DRAFT C LDAP API LDERRNO Extension 20 October 1999 2. Introduction This document defines an extension to the C LDAP API to support report- ing of specific errors for functions in the API that do not provide a way to access detailed information about failures. Three new functions are defined: ldap_get_lderrno(), ldap_set_lderrno(), and ldap_dup_string(). The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", and "MAY" in this document are to be interpreted as described in RFC 2119 [KEYWORDS]. 3. Table of Contents 1. Status of this Memo............................................1 2. Introduction...................................................2 3. Table of Contents..............................................2 4. Background and Intended Usage..................................2 5. Advertising the LDERRNO C LDAP API Extension...................4 6. Retrieving Error Information...................................4 7. Setting Error Information......................................5 8. Example Code...................................................7 9. Security Considerations........................................9 10. Copyright......................................................9 11. Bibliography...................................................10 12. Author's Address...............................................10 13. Appendix A - Summary of Additions to the C LDAP API............10 14. Appendix B - Open Issues.......................................11 14.1. System Errors?..............................................11 14.2. Failure of ldap_err2string?.................................11 14.3. Why this instead of [ERRREP]?...............................11 4. Background and Intended Usage In this specification, the phrase "error information" refers to a set of LDAP error information that includes an integer LDAP error code, a matched DN string, and a text error message string. The C LDAP API [CAPI] defines a C language application programming interface (API) to the Lightweight Directory Access Protocol [LDAP]. This document defines an extension to that API to support reporting of specific errors for functions in the C LDAP API that do not return detailed error information. The mechanism described also provides a more convenient method for applications to retrieve error information from an LDAP session handle. Expires: 20 April 2000 [Page 2] INTERNET-DRAFT C LDAP API LDERRNO Extension 20 October 1999 Some of the C LDAP API functions do not return or provide a method to retrieve detailed error information (such as by accessing an error code from the LDAP session handle). Excluding functions that only dispose of memory, these functions are: ber_alloc_t() ber_bvdup() ber_first_element() ber_flatten() ber_init() ber_next_element() ber_peek_tag() ber_printf() ber_scanf() ber_skip_tag() ldap_count_values() ldap_count_values_len() ldap_dn2ufn() ldap_err2string() -- can we just say that this can never return NULL? ldap_explode_dn() ldap_explode_rdn() ldap_init() ldap_msgid() ldap_msgtype() The reason these functions do not return a specific error code is so that compatibility with existing implementations of the C LDAP API could be maintained. In some environments, such as where memory resources are extremely tight and the application may be able to implement a recovery algorithm and retry a function call in the face of failure, it is essen- tial that access to specific, detailed error information be provided. This document defines three new functions: ldap_get_lderrno(), ldap_set_lderrno(), and ldap_dup_string(). The ldap_get_lderrno() func- tion MAY be used by callers of the C LDAP API to retrieve error informa- tion. The ldap_set_lderrno() function MAY be used by callers of the C LDAP API to set error information, which can be useful when functions that wish to use the provided error reporting mechanisms are layered on top of the C LDAP API. The ldap_dup_string() function SHOULD be used to allocate strings that are passed to ldap_set_lderrno(). C LDAP API implementations that support this extension MUST implement global error information that is separate from that associated with LDAP session handles. In addition, implementations that support the LDAP_API_FEATURE_SESSION_THREAD_SAFE extension described in [CONCURR] MUST implement thread-specific storage for the global error information and for the information associated with LDAP session handles. Expires: 20 April 2000 [Page 3] INTERNET-DRAFT C LDAP API LDERRNO Extension 20 October 1999 5. Advertising the LDERRNO C LDAP API Extension To conform with the requirements defined in the C LDAP API specification [CAPI], implementations that support this extension SHOULD advertise the existence of this extension as follows: Define the macro LDAP_API_FEATURE_LDERRNO as a value that corresponds to the "level" or revision of this specification. When this document is published as an RFC, the value to use for LDAP_API_FEATURE_LDERRNO is the RFC number itself. While this document is an Internet Draft, the value to use is 1000 plus the revision number of this draft, i.e., 1000 for the -00 revision of this draft, 1001 for the -01 ver- sion, and so on. Return the text string LDERRNO in the ldapai_extensions array of the LDAPAPIInfo structure following a successful call to ldap_get_option() with an option parameter value of LDAP_OPT_API_INFO. Return information about the extension when the ldapaif_name field in the LDAPAPIFeatureInfo structure is set to the text string LDERRNO and a call to ldap_get_option() with an option parameter value of LDAP_OPT_API_FEATURE_INFO is made. 6. Retrieving Error Information The ldap_get_lderrno() function MAY be used by callers of the C LDAP API to retrieve error information. It is RECOMMENDED that this function be used instead of the ldap_get_option() call with the LDAP_OPT_ERROR_NUMBER, LDAP_OPT_ERROR_STRING, or LDAP_OPT_MATCHED_DN options. /* function used to retrieve error information: */ int ldap_get_lderrno( LDAP *ld, char **matcheddnp, char **errmsgp ); When reporting error information for functions that accept an LDAP ses- sion handle, the values returned by ldap_get_lderrno() MUST be identical to those reported by ldap_get_option(). To retrieve global error infor- mation for functions that do not accept an LDAP session handle, callers MUST pass NULL for the `ld' parameter. Expires: 20 April 2000 [Page 4] INTERNET-DRAFT C LDAP API LDERRNO Extension 20 October 1999 The parameters to the ldap_get_lderrno() function are: ld An LDAP session handle, as obtained from a call to ldap_init(). If NULL is passed for `ld', global error information is returned. If the API implementation supports the LDAP_API_FEATURE_SESSION_THREAD_SAFE extension as described in [CONCURR], thread-specific error information is returned. matcheddnp A result parameter that will be filled in with a DN indicat- ing how much of the name in the request was recognized. If no matched DN information is available, this MUST be set to NULL. If there is no need to retrieve the matched DN infor- mation, callers of ldap_get_lderrno() SHOULD pass NULL for `matcheddnp'. Note that the string returned is a thread- specific value if the API implementation supports the LDAP_API_FEATURE_SESSION_THREAD_SAFE extension as described in [CONCURR]. The string data MUST NOT be disposed of by the caller as the memory occupied is maintained by the API implementation. errmsgp A result parameter that will be filled in with a text string that provides additional error detail, e.g., from the error- Message field of an LDAPResult message. If no text error message is available, this MUST be set to NULL. If there is no need to retrieve the text error message, callers of ldap_get_lderrno() SHOULD pass NULL for `errmsgp'. Note that the string returned is a thread-specific value if the API implementation supports the LDAP_API_FEATURE_SESSION_THREAD_SAFE extension as described in [CONCURR]. The string data MUST NOT be disposed of by the caller as the memory occupied is maintained by the API implementation. The ldap_get_lderrno() function returns a C LDAP API integer error code. The value returned is a thread-specific value if the API implementation supports the LDAP_API_FEATURE_SESSION_THREAD_SAFE extension as described in [CONCURR]. 7. Setting Error Information The ldap_set_lderrno() function MAY be used by callers of the C LDAP API to set error information. It is RECOMMENDED that this function be used instead of the ldap_set_option() call with the LDAP_OPT_ERROR_NUMBER, LDAP_OPT_ERROR_STRING, or LDAP_OPT_MATCHED_DN options. Expires: 20 April 2000 [Page 5] INTERNET-DRAFT C LDAP API LDERRNO Extension 20 October 1999 The ldap_dup_string() function SHOULD be used to allocate strings that are passed to ldap_set_lderrno(). /* function used to set error information: */ int ldap_set_lderrno( LDAP *ld, int lderror, char *matcheddn, char *errmsg ); /* function used to duplicate text strings: */ int ldap_dup_string( char **dstp, const char *src ); The parameters to the ldap_set_lderrno() function are: ld An LDAP session handle, as obtained from a call to ldap_init(). If NULL is passed for `ld', global error information is set. If the API implementation supports the LDAP_API_FEATURE_SESSION_THREAD_SAFE extension as described in [CONCURR], thread-specific error information is set. lderror A C LDAP API integer error code. matcheddn A text string that indicates what portion of a DN was matched in carrying out an operation. The memory that `matcheddn' occupies MUST be allocated by the C LDAP API implementation and not by the calling application. Accept- able values include those returned through the use of the `a' format modifier with ber_scanf() and values generated by the ldap_dup_string() function. errmsg A text string that provides extra textual information about an error. The memory that `errmsg' occupies MUST be allo- cated by the C LDAP API implementation and not by the cal- ling application. Acceptable values include those returned through the use of the `a' format modifier with ber_scanf() and values generated by the ldap_dup_string() function. The ldap_set_lderrno() function returns an LDAP error code that indi- cates whether it was able to set the error information. LDAP_SUCCESS is returned if all goes well, and another LDAP error code that is defined in [CAPI] is returned if some other problem occurs. The parameters to the ldap_dup_string() function are: dstp This result parameter will be set to memory that contains a Expires: 20 April 2000 [Page 6] INTERNET-DRAFT C LDAP API LDERRNO Extension 20 October 1999 copy of the `src' string. If `src' is NULL or the ldap_dup_string() call fails, this MUST be set to NULL. src A pointer to a string to duplicate. NULL values for `src' are allowed. ldap_dup_string() returns an LDAP error code that indicates whether it was able to allocate memory and duplicate the contents of `src'. LDAP_SUCCESS is returned if all goes well, and another LDAP error code that is defined in [CAPI] is returned if some other problem occurs. Passing NULL for the `src' parameter MUST result in `*dstp' being set to NULL and ldap_dup_string() MUST return LDAP_SUCCESS. 8. Example Code The following is an example showing how an application may obtain the error information resulting from failed C LDAP API calls. #include #include void print_ldap_error( const char *s, int lderr, const char *matcheddn, const char *errmsg ) { if ( matcheddn == NULL ) { matcheddn = ""; } if ( errmsg == NULL ) { errmsg = ""; } fprintf( stderr, "%s: err=%d (%s)\n\tmatcheddn=%s, text=%s\n", s, lderr, ldap_err2string( lderr ), matcheddn, errmsg ); } int bind_and_unbind( const char *binddn ) { LDAP *ld; char *ufn, *matcheddn, *errmsg; int msgid, rc, lderr, binderr; LDAPMessage *res; rc = 0; /* get an LDAP session handle */ Expires: 20 April 2000 [Page 7] INTERNET-DRAFT C LDAP API LDERRNO Extension 20 October 1999 ld = ldap_init( "localhost", LDAP_PORT ); if ( ld == NULL ) { lderr = ldap_get_lderrno( NULL, &matcheddn, &errmsg ); print_ldap_error( "ldap_init failed", lderr, matcheddn, errmsg ); return -1; } /* print "user friendly form" of binddn */ ufn = ldap_dn2ufn( binddn ); if ( ufn == NULL ) { lderr = ldap_get_lderrno( NULL, &matcheddn, &errmsg ); print_ldap_error( "ldap_dn2ufn failed", lderr, matcheddn, errmsg ); } printf( "About to do an unauthenticated bind as %s\n", ufn == NULL ? binddn : ufn ); ldap_memfree( ufn ); /* perform an unauthenticated bind with binddn as the DN */ msgid = ldap_simple_bind( ld, binddn, NULL ); if ( msgid == -1 ) { lderr = ldap_get_lderrno( ld, &matcheddn, &errmsg ); print_ldap_error( "ldap_simple_bind failed", lderr, matcheddn, errmsg ); rc = -1; goto unbind; } if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &res ) <= 0 ) { lderr = ldap_get_lderrno( ld, &matcheddn, &errmsg ); print_ldap_error( "ldap_result failed", lderr, matcheddn, errmsg ); rc = -1; goto unbind; } if (( lderr = ldap_parse_result( ld, res, &binderr, &matcheddn, &errmsg, NULL, NULL, 1 ) != LDAP_SUCCESS )) { print_ldap_error( "ldap_parse_result failed\n", lderr, NULL, NULL ); rc = -1; } else { print_ldap_error( "bind result", binderr, matcheddn, errmsg ); ldap_memfree( matcheddn ); ldap_memfree( errmsg ); if ( binderr != LDAP_SUCCESS ) { rc = -1; } } Expires: 20 April 2000 [Page 8] INTERNET-DRAFT C LDAP API LDERRNO Extension 20 October 1999 ldap_msgfree( res ); /* ... */ unbind: /* unbind and dispose of session handle */ if ( ldap_unbind( ld ) != 0 ) { lderr = ldap_get_lderrno( NULL, &matcheddn, &errmsg ); print_ldap_error( "ldap_unbind failed", lderr, matcheddn, errmsg ); rc = -1; } return rc; } 9. Security Considerations This C LDAP API extension does not impose any additional security con- siderations beyond those discussed in the C LDAP API specification [CAPI]. 10. Copyright Copyright (C) The Internet Society (1999). All Rights Reserved. This document and translations of it may be copied and furnished to oth- ers, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and dis- tributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Stan- dards process must be followed, or as required to translate it into languages other than English. The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns. This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT Expires: 20 April 2000 [Page 9] INTERNET-DRAFT C LDAP API LDERRNO Extension 20 October 1999 LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FIT- NESS FOR A PARTICULAR PURPOSE. 11. Bibliography [CAPI] M. Smith, T. Howes, A. Herron, M. Wahl, A. Anantha, "The C LDAP Application Program Interface", INTERNET-DRAFT, , 8 October 1999. [KEYWORDS] S. Bradner, "Key words for use in RFCs to Indicate Require- ment Levels", RFC 2119, March 1997. [LDAP] M. Wahl, T. Howes, S. Kille, "Lightweight Directory Access Protocol (v3)", RFC 2251, December 1997. [CONCURR] K. Zeilenga, "LDAP C API Concurrency Extensions", INTERNET- DRAFT, , 28 September 1999. [ERRREP] K. Zeilenga, "LDAP C API Error Reporting Extension", INTERNET-DRAFT, 28 September 1999. 12. Author's Address Mark Smith Netscape Communications Corp. 501 E. Middlefield Rd., Mailstop MV068 Mountain View, CA 94043 USA +1 650 937-3477 mcs@netscape.com 13. Appendix A - Summary of Additions to the C LDAP API This extension introduces no additional macros. This extension introduces no structures or typedefs. This extension introduces the following functions: ldap_get_lderrno() ldap_set_lderrno() Expires: 20 April 2000 [Page 10] INTERNET-DRAFT C LDAP API LDERRNO Extension 20 October 1999 ldap_dup_string() 14. Appendix B - Open Issues 14.1. System Errors? What about reporting of "system" errors such as for ldap_init() failures? Do we need to introduce additional error codes such as LDAP_HOST_UNREACHABLE and LDAP_HOST_UNKNOWN? 14.2. Failure of ldap_err2string? It is almost ridiculous to require that callers of the C LDAP API check to see if calls to ldap_err2string() fail. Can we stipulate that ldap_err2string() will never fail; that is, that it MUST return a valid string pointer and MUST NOT return NULL? 14.3. Why this instead of [ERRREP]? Why is this a better solution than the lderrno approach described in [ERRREP]? One argument is that most implementations will need to define lderrno as a macro that calls a function, so why not just be explicit and define functions like ldap_get_lderrno() and ldap_set_lderrno()? Also, this specification includes support for manipulating the matched DN and a text error message as well. One potential disadvantage of the approach defined in this specification is that there is no separation between failures within the API implementation and errors returned by an LDAP server, but arguably requiring that separation restricts API imple- mentors too much. Expires: 20 April 2000 [Page 11]