+ if ( dn.bv_len == 0 ) {
+ sasl_seterror( sconn, 0,
+ "No password is associated with the Root DSE" );
+ if ( dn.bv_val != NULL ) {
+ ch_free( dn.bv_val );
+ }
+ return SASL_NOUSER;
+ }
+
+ rc = backend_attribute( NULL, NULL, NULL, NULL, &dn,
+ slap_schema.si_ad_userPassword, &vals);
+ if ( rc != LDAP_SUCCESS ) {
+ ch_free( dn.bv_val );
+ sasl_seterror( sconn, 0, ldap_err2string( rc ) );
+ return SASL_NOVERIFY;
+ }
+
+ rc = SASL_NOVERIFY;
+
+ if ( vals != NULL ) {
+ for ( bv = vals; bv->bv_val != NULL; bv++ ) {
+ if ( !lutil_passwd( bv, &cred, NULL ) ) {
+ rc = SASL_OK;
+ break;
+ }
+ }
+ ber_bvarray_free( vals );
+ }
+
+ if ( rc != SASL_OK ) {
+ sasl_seterror( sconn, 0,
+ ldap_err2string( LDAP_INVALID_CREDENTIALS ) );
+ }
+
+ ch_free( dn.bv_val );
+
+ return rc;
+}
+
+static int
+slap_sasl_canonicalize(
+ sasl_conn_t *sconn,
+ void *context,
+ const char *in,
+ unsigned inlen,
+ unsigned flags,
+ const char *user_realm,
+ char *out,
+ unsigned out_max,
+ unsigned *out_len)
+{
+ Connection *conn = (Connection *)context;
+ struct berval dn;
+ int rc;
+
+ *out_len = 0;
+
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+ "slap_sasl_canonicalize: conn %d %s=\"%s\"\n",
+ conn ? conn->c_connid : -1,
+ (flags == SASL_CU_AUTHID) ? "authcid" : "authzid",
+ in ? in : "<empty>" ));
+#else
+ Debug( LDAP_DEBUG_ARGS, "SASL Canonicalize [conn=%ld]: "
+ "%s=\"%s\"\n",
+ conn ? conn->c_connid : -1,
+ (flags == SASL_CU_AUTHID) ? "authcid" : "authzid",
+ in ? in : "<empty>" );
+#endif
+
+ rc = slap_sasl_getdn( conn, (char *)in, (char *)user_realm, &dn,
+ (flags == SASL_CU_AUTHID) ? FLAG_GETDN_AUTHCID : FLAG_GETDN_AUTHZID );
+ if ( rc != LDAP_SUCCESS ) {
+ sasl_seterror( sconn, 0, ldap_err2string( rc ) );
+ return SASL_NOAUTHZ;
+ }
+
+ if ( out_max < dn.bv_len ) {
+ return SASL_BUFOVER;
+ }
+
+ AC_MEMCPY( out, dn.bv_val, dn.bv_len );
+ out[dn.bv_len] = '\0';
+
+ *out_len = dn.bv_len;
+
+ ch_free( dn.bv_val );
+
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+ "slap_sasl_canonicalize: conn %d %s=\"%s\"\n",
+ conn ? conn->c_connid : -1,
+ (flags == SASL_CU_AUTHID) ? "authcDN" : "authzDN",
+ out ));
+#else
+ Debug( LDAP_DEBUG_ARGS, "SASL Canonicalize [conn=%ld]: "
+ "%s=\"%s\"\n",
+ conn ? conn->c_connid : -1,
+ (flags == SASL_CU_AUTHID) ? "authcDN" : "authzDN",
+ out );
+#endif
+
+ return SASL_OK;
+}
+
+static int
+slap_sasl_authorize(
+ sasl_conn_t *sconn,
+ void *context,
+ const char *requested_user,
+ unsigned rlen,
+ const char *auth_identity,
+ unsigned alen,
+ const char *def_realm,
+ unsigned urlen,
+ struct propctx *propctx)
+{
+ Connection *conn = (Connection *)context;
+ struct berval authcDN, authzDN;
+ int rc;
+
+ authcDN.bv_val = (char *)auth_identity;
+ authcDN.bv_len = alen;
+
+ authzDN.bv_val = (char *)requested_user;
+ authzDN.bv_len = rlen;
+
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+ "slap_sasl_authorize: conn %d authcDN=\"%s\" authzDN=\"%s\"\n",
+ conn ? conn->c_connid : -1, authcDN.bv_val, authzDN.bv_val));
+#else
+ Debug( LDAP_DEBUG_ARGS, "SASL Authorize [conn=%ld]: "
+ "authcDN=\"%s\" authzDN=\"%s\"\n",
+ conn ? conn->c_connid : -1, authcDN.bv_val, authzDN.bv_val );
+#endif
+
+ rc = slap_sasl_authorized( &authcDN, &authzDN );
+ if ( rc != LDAP_SUCCESS ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "sasl", LDAP_LEVEL_INFO,
+ "slap_sasl_authorize: conn %ld authorization disallowed (%d)\n",
+ (long)(conn ? conn->c_connid : -1), rc ));
+#else
+ Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: "
+ " authorization disallowed (%d)\n",
+ (long) (conn ? conn->c_connid : -1), rc, 0 );
+#endif
+
+ sasl_seterror( sconn, 0, "not authorized" );
+ return SASL_NOAUTHZ;
+ }
+
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+ "slap_sasl_authorize: conn %d authorization allowed\n",
+ (long)(conn ? conn->c_connid : -1 ) ));
+#else
+ Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: "
+ " authorization allowed\n",
+ (long) (conn ? conn->c_connid : -1), 0, 0 );
+#endif
+
+ return SASL_OK;
+}
+#else
+static int
+slap_sasl_authorize(
+ void *context,
+ const char *authcid,
+ const char *authzid,
+ const char **user,
+ const char **errstr)
+{
+ struct berval authcDN, authzDN;
+ int rc;
+ Connection *conn = context;
+ char *realm;
+
+ *user = NULL;
+
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+ "slap_sasl_authorize: conn %d authcid=\"%s\" authzid=\"%s\"\n",
+ conn ? conn->c_connid : -1,
+ authcid ? authcid : "<empty>",
+ authzid ? authzid : "<empty>" ));
+#else
+ Debug( LDAP_DEBUG_ARGS, "SASL Authorize [conn=%ld]: "
+ "authcid=\"%s\" authzid=\"%s\"\n",
+ (long) (conn ? conn->c_connid : -1),
+ authcid ? authcid : "<empty>",
+ authzid ? authzid : "<empty>" );
+#endif
+
+ /* Figure out how much data we have for the dn */
+ rc = sasl_getprop( conn->c_sasl_context, SASL_REALM, (void **)&realm );
+ if( rc != SASL_OK && rc != SASL_NOTDONE ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "sasl", LDAP_LEVEL_ERR,
+ "slap_sasl_authorize: getprop(REALM) failed.\n" ));
+#else
+ Debug(LDAP_DEBUG_TRACE,
+ "authorize: getprop(REALM) failed!\n", 0,0,0);
+#endif
+ *errstr = "Could not extract realm";
+ return SASL_NOAUTHZ;
+ }
+
+ /* Convert the identities to DN's. If no authzid was given, client will
+ be bound as the DN matching their username */
+ rc = slap_sasl_getdn( conn, (char *)authcid, realm, &authcDN, FLAG_GETDN_AUTHCID );
+ if( rc != LDAP_SUCCESS ) {
+ *errstr = ldap_err2string( rc );
+ return SASL_NOAUTHZ;
+ }
+ if( ( authzid == NULL ) || !strcmp( authcid,authzid ) ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+ "slap_sasl_authorize: conn %d Using authcDN=%s\n",
+ conn ? conn->c_connid : -1, authcDN.bv_val ));
+#else
+ Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: "
+ "Using authcDN=%s\n", (long) (conn ? conn->c_connid : -1), authcDN.bv_val,0 );
+#endif
+
+ *user = authcDN.bv_val;
+ *errstr = NULL;
+ return SASL_OK;
+ }
+ rc = slap_sasl_getdn( conn, (char *)authzid, realm, &authzDN, FLAG_GETDN_AUTHZID );
+ if( rc != LDAP_SUCCESS ) {
+ ch_free( authcDN.bv_val );
+ *errstr = ldap_err2string( rc );
+ return SASL_NOAUTHZ;
+ }
+
+ rc = slap_sasl_authorized( &authcDN, &authzDN );
+ if( rc ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "sasl", LDAP_LEVEL_INFO,
+ "slap_sasl_authorize: conn %ld authorization disallowed (%d)\n",
+ (long)(conn ? conn->c_connid : -1), rc ));
+#else
+ Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: "
+ " authorization disallowed (%d)\n",
+ (long) (conn ? conn->c_connid : -1), rc, 0 );
+#endif
+
+ *errstr = "not authorized";
+ ch_free( authcDN.bv_val );
+ ch_free( authzDN.bv_val );
+ return SASL_NOAUTHZ;
+ }
+
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+ "slap_sasl_authorize: conn %d authorization allowed\n",
+ (long)(conn ? conn->c_connid : -1 ) ));
+#else
+ Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: "
+ " authorization allowed\n",
+ (long) (conn ? conn->c_connid : -1), 0, 0 );
+#endif
+
+
+ ch_free( authcDN.bv_val );
+ *user = authzDN.bv_val;
+ *errstr = NULL;
+ return SASL_OK;
+}
+#endif /* SASL_VERSION_MAJOR >= 2 */
+
+static int
+slap_sasl_err2ldap( int saslerr )
+{
+ int rc;
+
+ switch (saslerr) {
+ case SASL_CONTINUE:
+ rc = LDAP_SASL_BIND_IN_PROGRESS;
+ break;
+ case SASL_FAIL:
+ rc = LDAP_OTHER;
+ break;
+ case SASL_NOMEM:
+ rc = LDAP_OTHER;
+ break;
+ case SASL_NOMECH:
+ rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
+ break;
+ case SASL_BADAUTH:
+ rc = LDAP_INVALID_CREDENTIALS;
+ break;
+ case SASL_NOAUTHZ:
+ rc = LDAP_INSUFFICIENT_ACCESS;
+ break;
+ case SASL_TOOWEAK:
+ case SASL_ENCRYPT:
+ rc = LDAP_INAPPROPRIATE_AUTH;
+ break;
+ default:
+ rc = LDAP_OTHER;
+ break;
+ }
+
+ return rc;
+}
+#endif
+
+
+int slap_sasl_init( void )
+{
+#ifdef HAVE_CYRUS_SASL
+ int rc;
+ static sasl_callback_t server_callbacks[] = {
+ { SASL_CB_LOG, &slap_sasl_log, NULL },
+ { SASL_CB_LIST_END, NULL, NULL }
+ };
+
+ sasl_set_alloc(
+ ch_malloc,
+ ch_calloc,
+ ch_realloc,
+ ch_free );
+
+ sasl_set_mutex(
+ ldap_pvt_sasl_mutex_new,
+ ldap_pvt_sasl_mutex_lock,
+ ldap_pvt_sasl_mutex_unlock,
+ ldap_pvt_sasl_mutex_dispose );
+
+ /* should provide callbacks for logging */
+ /* server name should be configurable */
+ rc = sasl_server_init( server_callbacks, "slapd" );