From cc39f7526186582a9c0f18446368a451c78ad6ed Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Fri, 28 Feb 2003 12:34:35 +0000 Subject: [PATCH] Support for dynamic registration of controls, both through native and SLAPI plugins. --- servers/slapd/controls.c | 307 ++++++++++++++++++++++-------- servers/slapd/main.c | 14 ++ servers/slapd/proto-slap.h | 15 +- servers/slapd/root_dse.c | 14 +- servers/slapd/slap.h | 25 +++ servers/slapd/slapi/slapi_utils.c | 157 +++++++++------ 6 files changed, 378 insertions(+), 154 deletions(-) diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index c4b726d79b..ce704e417f 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -19,31 +19,6 @@ #include "../../libraries/liblber/lber-int.h" -#define SLAP_CTRL_FRONTEND 0x80000000U -#define SLAP_CTRL_FRONTEND_SEARCH 0x01000000U /* for NOOP */ - -#define SLAP_CTRL_OPFLAGS 0x0000FFFFU -#define SLAP_CTRL_ABANDON 0x00000001U -#define SLAP_CTRL_ADD 0x00002002U -#define SLAP_CTRL_BIND 0x00000004U -#define SLAP_CTRL_COMPARE 0x00001008U -#define SLAP_CTRL_DELETE 0x00002010U -#define SLAP_CTRL_MODIFY 0x00002020U -#define SLAP_CTRL_RENAME 0x00002040U -#define SLAP_CTRL_SEARCH 0x00001080U -#define SLAP_CTRL_UNBIND 0x00000100U - -#define SLAP_CTRL_INTROGATE (SLAP_CTRL_COMPARE|SLAP_CTRL_SEARCH) -#define SLAP_CTRL_UPDATE \ - (SLAP_CTRL_ADD|SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME) -#define SLAP_CTRL_ACCESS (SLAP_CTRL_INTROGATE|SLAP_CTRL_UPDATE) - -typedef int (SLAP_CTRL_PARSE_FN) LDAP_P(( - Connection *conn, - Operation *op, - LDAPControl *ctrl, - const char **text )); - static SLAP_CTRL_PARSE_FN parseProxyAuthz; static SLAP_CTRL_PARSE_FN parseManageDSAit; static SLAP_CTRL_PARSE_FN parseNoOp; @@ -70,112 +45,286 @@ static char *proxy_authz_extops[] = { NULL }; -/* - * all known request control OIDs should be added to this list - */ -char *slap_known_controls[] = { - LDAP_CONTROL_MANAGEDSAIT, - LDAP_CONTROL_PROXY_AUTHZ, - -#ifdef LDAP_CONTROL_SUBENTRIES - LDAP_CONTROL_SUBENTRIES, -#endif /* LDAP_CONTROL_SUBENTRIES */ - - LDAP_CONTROL_NOOP, - -#ifdef LDAP_CONTROL_DUPENT_REQUEST - LDAP_CONTROL_DUPENT_REQUEST, -#endif /* LDAP_CONTROL_DUPENT_REQUEST */ +struct slap_control { + /* + * Control OID + */ + char *sc_oid; -#ifdef LDAP_CONTROL_PAGEDRESULTS - LDAP_CONTROL_PAGEDRESULTS, -#endif + /* + * Operations supported by control + */ + slap_mask_t sc_mask; -#ifdef LDAP_CONTROL_SORTREQUEST - LDAP_CONTROL_SORTREQUEST, -#endif /* LDAP_CONTROL_SORTREQUEST */ + /* + * Extended operations supported by control + */ + char **sc_extendedops; -#ifdef LDAP_CONTROL_VLVREQUEST - LDAP_CONTROL_VLVREQUEST, -#endif /* LDAP_CONTROL_VLVREQUEST */ + /* + * Control parsing callback + */ + SLAP_CTRL_PARSE_FN *sc_parse; - LDAP_CONTROL_VALUESRETURNFILTER, - NULL + LDAP_SLIST_ENTRY(slap_control) sc_next; }; -static struct slap_control { - char *sc_oid; - slap_mask_t sc_mask; - char **sc_extendedops; - SLAP_CTRL_PARSE_FN *sc_parse; +static LDAP_SLIST_HEAD(ControlsList, slap_control) controls_list + = LDAP_SLIST_HEAD_INITIALIZER(&controls_list); -} supportedControls[] = { +/* + * all known request control OIDs should be added to this list + */ +char **slap_known_controls = NULL; + +static struct slap_control control_defs[] = { { LDAP_CONTROL_VALUESRETURNFILTER, SLAP_CTRL_SEARCH, NULL, - parseValuesReturnFilter }, + parseValuesReturnFilter, NULL }, #ifdef LDAP_CONTROL_PAGEDRESULTS { LDAP_CONTROL_PAGEDRESULTS, SLAP_CTRL_SEARCH, NULL, - parsePagedResults }, + parsePagedResults, NULL }, #endif #ifdef LDAP_CONTROL_X_DOMAIN_SCOPE { LDAP_CONTROL_X_DOMAIN_SCOPE, SLAP_CTRL_FRONTEND|SLAP_CTRL_SEARCH, NULL, - parseDomainScope }, + parseDomainScope, NULL }, #endif #ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY { LDAP_CONTROL_X_PERMISSIVE_MODIFY, SLAP_CTRL_MODIFY, NULL, - parsePermissiveModify }, + parsePermissiveModify, NULL }, #endif #ifdef LDAP_CONTROL_SUBENTRIES { LDAP_CONTROL_SUBENTRIES, SLAP_CTRL_SEARCH, NULL, - parseSubentries }, + parseSubentries, NULL }, #endif { LDAP_CONTROL_NOOP, SLAP_CTRL_ACCESS, NULL, - parseNoOp }, + parseNoOp, NULL }, #ifdef LDAP_CLIENT_UPDATE { LDAP_CONTROL_CLIENT_UPDATE, SLAP_CTRL_SEARCH, NULL, - parseClientUpdate }, + parseClientUpdate, NULL }, #endif #ifdef LDAP_SYNC { LDAP_CONTROL_SYNC, SLAP_CTRL_SEARCH, NULL, - parseLdupSync }, + parseLdupSync, NULL }, #endif { LDAP_CONTROL_MANAGEDSAIT, SLAP_CTRL_ACCESS, NULL, - parseManageDSAit }, + parseManageDSAit, NULL }, { LDAP_CONTROL_PROXY_AUTHZ, SLAP_CTRL_FRONTEND|SLAP_CTRL_ACCESS, proxy_authz_extops, - parseProxyAuthz }, - { NULL, 0, NULL, 0 } + parseProxyAuthz, NULL }, + { NULL, 0, NULL, 0, NULL } }; -char * -get_supported_ctrl(int index) +/* + * Register a supported control. + * + * This can be called by an OpenLDAP plugin or, indirectly, by a + * SLAPI plugin calling slapi_register_supported_control(). + */ +int +register_supported_control(const char *controloid, + slap_mask_t controlmask, + char **controlexops, + SLAP_CTRL_PARSE_FN *controlparsefn) +{ + struct slap_control *sc; + int i; + + if ( controloid == NULL ) { + return LDAP_PARAM_ERROR; + } + + sc = (struct slap_control *)SLAP_MALLOC( sizeof( *sc ) ); + if ( sc == NULL ) { + return LDAP_NO_MEMORY; + } + sc->sc_oid = ch_strdup( controloid ); + sc->sc_mask = controlmask; + if ( controlexops != NULL ) { + sc->sc_extendedops = ldap_charray_dup( controlexops ); + if ( sc->sc_extendedops == NULL ) { + ch_free( sc ); + return LDAP_NO_MEMORY; + } + } else { + sc->sc_extendedops = NULL; + } + sc->sc_parse = controlparsefn; + + /* Update slap_known_controls, too. */ + if ( slap_known_controls == NULL ) { + slap_known_controls = (char **)SLAP_MALLOC( 2 * sizeof(char *) ); + if ( slap_known_controls == NULL ) { + if ( sc->sc_extendedops != NULL ) ldap_charray_free( sc->sc_extendedops ); + ch_free( sc ); + return LDAP_NO_MEMORY; + } + slap_known_controls[0] = ch_strdup( sc->sc_oid ); + slap_known_controls[1] = NULL; + } else { + for ( i = 0; slap_known_controls[i] != NULL; i++ ) + ; + slap_known_controls = (char **)SLAP_REALLOC( slap_known_controls, (i + 2) * sizeof(char *) ); + if ( slap_known_controls == NULL ) { + if ( sc->sc_extendedops != NULL ) ldap_charray_free( sc->sc_extendedops ); + ch_free( sc ); + return LDAP_NO_MEMORY; + } + slap_known_controls[i++] = ch_strdup( sc->sc_oid ); + slap_known_controls[i] = NULL; + } + + LDAP_SLIST_NEXT( sc, sc_next ) = NULL; + LDAP_SLIST_INSERT_HEAD( &controls_list, sc, sc_next ); + + return LDAP_SUCCESS; +} + +/* + * One-time initialization of internal controls. + */ +int +slap_controls_init( void ) +{ + int i, rc; + struct slap_control *sc; + + rc = LDAP_SUCCESS; + + for ( i = 0; control_defs[i].sc_oid != NULL; i++ ) { + rc = register_supported_control( control_defs[i].sc_oid, + control_defs[i].sc_mask, control_defs[i].sc_extendedops, + control_defs[i].sc_parse ); + if ( rc != LDAP_SUCCESS ) + break; + } + + return rc; +} + +/* + * Free memory associated with list of supported controls. + */ +void +controls_destroy( void ) { - return supportedControls[index].sc_oid; + struct slap_control *sc; + + while ( !LDAP_SLIST_EMPTY(&controls_list) ) { + sc = LDAP_SLIST_FIRST(&controls_list); + LDAP_SLIST_REMOVE_HEAD(&controls_list, sc_next); + + ch_free( sc->sc_oid ); + if ( sc->sc_extendedops != NULL ) { + ldap_charray_free( sc->sc_extendedops ); + } + } } -slap_mask_t -get_supported_ctrl_mask(int index) +/* + * Format the supportedControl attribute of the root DSE, + * detailing which controls are supported by the directory + * server. + */ +int +controls_root_dse_info( Entry *e ) { - return supportedControls[index].sc_mask; + AttributeDescription *ad_supportedControl + = slap_schema.si_ad_supportedControl; + struct berval vals[2]; + struct slap_control *sc; + + vals[1].bv_val = NULL; + vals[1].bv_len = 0; + + LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) { + vals[0].bv_val = sc->sc_oid; + vals[0].bv_len = strlen( sc->sc_oid ); +#ifdef SLAP_NVALUES + if ( attr_merge( e, ad_supportedControl, vals, NULL ) ) +#else + if ( attr_merge( e, ad_supportedControl, vals ) ) +#endif /* SLAP_NVALUES */ + return -1; + } + + return 0; } +/* + * Return a list of OIDs and operation masks for supported + * controls. Used by SLAPI. + */ +int +get_supported_controls(char ***ctrloidsp, + slap_mask_t **ctrlmasks) +{ + int i, n; + char **oids; + slap_mask_t *masks; + int rc; + struct slap_control *sc; + + n = 0; + + LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) { + n++; + } + + if ( n == 0 ) { + *ctrloidsp = NULL; + *ctrlmasks = NULL; + return LDAP_SUCCESS; + } + + oids = (char **)SLAP_MALLOC( (n + 1) * sizeof(char *) ); + if ( oids == NULL ) { + return LDAP_NO_MEMORY; + } + masks = (slap_mask_t *)SLAP_MALLOC( (n + 1) * sizeof(slap_mask_t) ); + if ( masks == NULL ) { + ch_free( oids ); + return LDAP_NO_MEMORY; + } + + n = 0; + + LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) { + oids[n] = ch_strdup( sc->sc_oid ); + masks[n] = sc->sc_mask; + n++; + } + oids[n] = NULL; + masks[n] = 0; + + *ctrloidsp = oids; + *ctrlmasks = masks; + + return LDAP_SUCCESS; +} + +/* + * Find a control given its OID. + */ static struct slap_control * find_ctrl( const char *oid ) { - int i; - for( i=0; supportedControls[i].sc_oid; i++ ) { - if( strcmp( oid, supportedControls[i].sc_oid ) == 0 ) { - return &supportedControls[i]; + struct slap_control *sc; + + LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) { + if ( strcmp( oid, sc->sc_oid ) == 0 ) { + return sc; } } + return NULL; } diff --git a/servers/slapd/main.c b/servers/slapd/main.c index d9e19b4f97..f627ad1ad9 100644 --- a/servers/slapd/main.c +++ b/servers/slapd/main.c @@ -397,6 +397,18 @@ int main( int argc, char **argv ) goto destroy; } + if ( slap_controls_init( ) != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG( OPERATION, CRIT, "main: controls initialization error\n", 0, 0, 0 ); +#else + Debug( LDAP_DEBUG_ANY, + "controls initialization error\n", + 0, 0, 0 ); +#endif + + goto destroy; + } + #ifdef HAVE_TLS /* Library defaults to full certificate checking. This is correct when * a client is verifying a server because all servers should have a @@ -608,6 +620,8 @@ stop: #endif slapd_daemon_destroy(); + controls_destroy(); + schema_destroy(); #ifdef HAVE_TLS diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 6a1ff16cae..93605a4708 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -296,10 +296,15 @@ LDAP_SLAPD_F (int) get_ctrls LDAP_P(( Connection *co, Operation *op, int senderrors )); - -LDAP_SLAPD_F (char *) get_supported_ctrl LDAP_P((int index)); - -LDAP_SLAPD_F (slap_mask_t) get_supported_ctrl_mask LDAP_P((int index)); +LDAP_SLAPD_F (int) register_supported_control LDAP_P(( + const char *controloid, + slap_mask_t controlmask, + char **controlexops, + SLAP_CTRL_PARSE_FN *controlparsefn )); +LDAP_SLAPD_F (int) slap_controls_init LDAP_P ((void)); +LDAP_SLAPD_F (void) controls_destroy LDAP_P ((void)); +LDAP_SLAPD_F (int) controls_root_dse_info LDAP_P ((Entry *e)); +LDAP_SLAPD_F (int) get_supported_controls LDAP_P (( char ***ctrloidsp, slap_mask_t **ctrlmasks )); /* * config.c @@ -548,7 +553,7 @@ LDAP_SLAPD_F (int) slap_startup LDAP_P(( Backend *be )); LDAP_SLAPD_F (int) slap_shutdown LDAP_P(( Backend *be )); LDAP_SLAPD_F (int) slap_destroy LDAP_P((void)); -LDAP_SLAPD_V (char *) slap_known_controls[]; +LDAP_SLAPD_V (char **) slap_known_controls; /* * kerberos.c diff --git a/servers/slapd/root_dse.c b/servers/slapd/root_dse.c index e7a80d0150..bb8e5ed8c5 100644 --- a/servers/slapd/root_dse.c +++ b/servers/slapd/root_dse.c @@ -55,8 +55,6 @@ root_dse_info( = slap_schema.si_ad_objectClass; AttributeDescription *ad_namingContexts = slap_schema.si_ad_namingContexts; - AttributeDescription *ad_supportedControl - = slap_schema.si_ad_supportedControl; AttributeDescription *ad_supportedExtension = slap_schema.si_ad_supportedExtension; AttributeDescription *ad_supportedLDAPVersion @@ -158,16 +156,8 @@ root_dse_info( /* altServer unsupported */ /* supportedControl */ - for ( i=0; (vals[0].bv_val = get_supported_ctrl(i)) != NULL; i++ ) { - vals[0].bv_len = strlen( vals[0].bv_val ); -#ifdef SLAP_NVALUES - if( attr_merge( e, ad_supportedControl, vals, NULL ) ) -#else - if( attr_merge( e, ad_supportedControl, vals ) ) -#endif - { - return LDAP_OTHER; - } + if ( controls_root_dse_info( e ) != 0 ) { + return LDAP_OTHER; } /* supportedExtension */ diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index d9871e0ed1..80a5f4aa48 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -2102,6 +2102,31 @@ enum { #define SLAP_SEARCH_MAX_CTRLS 10 #endif +#define SLAP_CTRL_FRONTEND 0x80000000U +#define SLAP_CTRL_FRONTEND_SEARCH 0x01000000U /* for NOOP */ + +#define SLAP_CTRL_OPFLAGS 0x0000FFFFU +#define SLAP_CTRL_ABANDON 0x00000001U +#define SLAP_CTRL_ADD 0x00002002U +#define SLAP_CTRL_BIND 0x00000004U +#define SLAP_CTRL_COMPARE 0x00001008U +#define SLAP_CTRL_DELETE 0x00002010U +#define SLAP_CTRL_MODIFY 0x00002020U +#define SLAP_CTRL_RENAME 0x00002040U +#define SLAP_CTRL_SEARCH 0x00001080U +#define SLAP_CTRL_UNBIND 0x00000100U + +#define SLAP_CTRL_INTROGATE (SLAP_CTRL_COMPARE|SLAP_CTRL_SEARCH) +#define SLAP_CTRL_UPDATE \ + (SLAP_CTRL_ADD|SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME) +#define SLAP_CTRL_ACCESS (SLAP_CTRL_INTROGATE|SLAP_CTRL_UPDATE) + +typedef int (SLAP_CTRL_PARSE_FN) LDAP_P(( + Connection *conn, + Operation *op, + LDAPControl *ctrl, + const char **text )); + LDAP_END_DECL #include "proto-slap.h" diff --git a/servers/slapd/slapi/slapi_utils.c b/servers/slapd/slapi/slapi_utils.c index 3f8956aa6d..21fa0e7bac 100644 --- a/servers/slapd/slapi/slapi_utils.c +++ b/servers/slapd/slapi/slapi_utils.c @@ -1129,15 +1129,101 @@ slapi_control_present( #endif /* LDAP_SLAPI */ } +#ifdef LDAP_SLAPI +static void +slapControlMask2SlapiControlOp(slap_mask_t slap_mask, + unsigned long *slapi_mask) +{ + *slapi_mask = SLAPI_OPERATION_NONE; + + if ( slap_mask & SLAP_CTRL_ABANDON ) + *slapi_mask |= SLAPI_OPERATION_ABANDON; + + if ( slap_mask & SLAP_CTRL_ADD ) + *slapi_mask |= SLAPI_OPERATION_ADD; + + if ( slap_mask & SLAP_CTRL_BIND ) + *slapi_mask |= SLAPI_OPERATION_BIND; + + if ( slap_mask & SLAP_CTRL_COMPARE ) + *slapi_mask |= SLAPI_OPERATION_COMPARE; + + if ( slap_mask & SLAP_CTRL_DELETE ) + *slapi_mask |= SLAPI_OPERATION_DELETE; + + if ( slap_mask & SLAP_CTRL_MODIFY ) + *slapi_mask |= SLAPI_OPERATION_MODIFY; + + if ( slap_mask & SLAP_CTRL_RENAME ) + *slapi_mask |= SLAPI_OPERATION_MODDN; + + if ( slap_mask & SLAP_CTRL_SEARCH ) + *slapi_mask |= SLAPI_OPERATION_SEARCH; + + if ( slap_mask & SLAP_CTRL_UNBIND ) + *slapi_mask |= SLAPI_OPERATION_UNBIND; +} + +static void +slapiControlOp2SlapControlMask(unsigned long slapi_mask, + slap_mask_t *slap_mask) +{ + *slap_mask = 0; + + if ( slapi_mask & SLAPI_OPERATION_BIND ) + *slap_mask |= SLAP_CTRL_BIND; + + if ( slapi_mask & SLAPI_OPERATION_UNBIND ) + *slap_mask |= SLAP_CTRL_UNBIND; + + if ( slapi_mask & SLAPI_OPERATION_SEARCH ) + *slap_mask |= SLAP_CTRL_SEARCH; + + if ( slapi_mask & SLAPI_OPERATION_MODIFY ) + *slap_mask |= SLAP_CTRL_MODIFY; + + if ( slapi_mask & SLAPI_OPERATION_ADD ) + *slap_mask |= SLAP_CTRL_ADD; + + if ( slapi_mask & SLAPI_OPERATION_DELETE ) + *slap_mask |= SLAP_CTRL_DELETE; + + if ( slapi_mask & SLAPI_OPERATION_MODDN ) + *slap_mask |= SLAP_CTRL_RENAME; + + if ( slapi_mask & SLAPI_OPERATION_COMPARE ) + *slap_mask |= SLAP_CTRL_COMPARE; + + if ( slapi_mask & SLAPI_OPERATION_ABANDON ) + *slap_mask |= SLAP_CTRL_ABANDON; + + *slap_mask = SLAP_CTRL_FRONTEND; +} + +static int +parseSlapiControl( + Connection *conn, + Operation *op, + LDAPControl *ctrl, + const char **text) +{ + /* Plugins must deal with controls themselves. */ + + return LDAP_SUCCESS; +} +#endif /* LDAP_SLAPI */ + void slapi_register_supported_control( char *controloid, unsigned long controlops ) { #ifdef LDAP_SLAPI - /* FIXME -- can not add controls to OpenLDAP dynamically */ - slapi_log_error( SLAPI_LOG_FATAL, "SLAPI_CONTROLS", - "OpenLDAP does not support dynamic registration of LDAP controls\n" ); + slap_mask_t controlmask; + + slapiControlOp2SlapControlMask( controlops, &controlmask ); + + register_supported_control( controloid, controlmask, NULL, parseSlapiControl ); #endif /* LDAP_SLAPI */ } @@ -1147,64 +1233,19 @@ slapi_get_supported_controls( unsigned long **ctrlopsp ) { #ifdef LDAP_SLAPI - int i, n; - int rc = 1; - char **oids = NULL; - unsigned long *masks = NULL; - - for (n = 0; get_supported_ctrl( n ) != NULL; n++) { - ; /* count them */ - } - - if ( n == 0 ) { - /* no controls */ - *ctrloidsp = NULL; - *ctrlopsp = NULL; - return LDAP_SUCCESS; - } + int i, rc; - - oids = (char **)slapi_ch_malloc( (n + 1) * sizeof(char *) ); - if ( oids == NULL ) { - rc = LDAP_NO_MEMORY; - goto error_return; - } - - masks = (unsigned long *)slapi_ch_malloc( n * sizeof(int) ); - if ( masks == NULL ) { - rc = LDAP_NO_MEMORY; - goto error_return; + rc = get_supported_controls( ctrloidsp, (slap_mask_t **)ctrlopsp ); + if ( rc != LDAP_SUCCESS ) { + return rc; } - for ( i = 0; i < n; i++ ) { - /* - * FIXME: Netscape's specification says nothing about - * memory; should we copy the OIDs or return pointers - * to internal values? In OpenLDAP the latter is safe - * since we do not allow to register coltrols runtime - */ - oids[ i ] = ch_strdup( get_supported_ctrl( i ) ); - if ( oids[ i ] == NULL ) { - rc = LDAP_NO_MEMORY; - goto error_return; - } - masks[ i ] = (unsigned long)get_supported_ctrl_mask( i ); + for ( i = 0; (*ctrloidsp)[i] != NULL; i++ ) { + /* In place, naughty. */ + slapControlMask2SlapiControlOp( (*ctrlopsp)[i], &((*ctrlopsp)[i]) ); } - *ctrloidsp = oids; - *ctrlopsp = masks; return LDAP_SUCCESS; - -error_return: - if ( rc != LDAP_SUCCESS ) { - for ( i = 0; oids != NULL && oids[ i ] != NULL; i++ ) { - ch_free( oids[ i ] ); - } - ch_free( oids ); - ch_free( masks ); - } - - return rc; #else /* LDAP_SLAPI */ return 1; #endif /* LDAP_SLAPI */ @@ -1241,10 +1282,10 @@ char ** slapi_get_supported_saslmechanisms( void ) { #ifdef LDAP_SLAPI - /* FIXME -- can not get the saslmechanism wihtout a connection. */ + /* FIXME -- can not get the saslmechanism without a connection. */ slapi_log_error( SLAPI_LOG_FATAL, "SLAPI_SASL", - "can not get the saslmechanism " - "wihtout a connection\n" ); + "can not get the SASL mechanism list " + "without a connection\n" ); return NULL; #else /* LDAP_SLAPI */ return NULL; -- 2.39.5