#include #include #include #include /* This is missing in slapi-plugin.h: */ extern int slapi_pw_find(struct berval **vals, struct berval *v); static Slapi_ComponentId *plugin_id = NULL; /* Get an entry specified by a DN and with the specified attributes. */ static int get_entry(const char *dn, char **attrs, Slapi_Entry **entry) { Slapi_Entry **entries = NULL; Slapi_PBlock *pb = NULL; int rc = 0; if (entry) { *entry = NULL; } pb = slapi_pblock_new(); slapi_search_internal_set_pb( pb, dn, LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0 /* attrsonly */, NULL /* controls */, NULL /* uniqueid */, plugin_id, 0 /* actions */); slapi_search_internal_pb(pb); slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc); if (LDAP_SUCCESS == rc) { slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); if (NULL != entries && NULL != entries[0]) { if (entry) { Slapi_Entry *tmp = NULL; tmp = entries[0]; *entry = slapi_entry_dup(tmp); } } else { /* No entry there */ rc = LDAP_NO_SUCH_OBJECT; } } slapi_free_search_results_internal(pb); slapi_pblock_destroy(pb); pb = NULL; return rc; } /* Check if the parent entry contains a uid attribute. */ static int dn_contains_uid(const char *dn) { char *attrs[] = { "uid", NULL }; Slapi_Entry *entry = NULL; Slapi_Attr *attr = NULL; Slapi_ValueSet *uid_values = NULL; int rc = 0; rc |= get_entry(dn, attrs, &entry); if (rc != 0 || entry == NULL) { /* parent_dn not found */ rc = 1; goto fail1; } rc |= slapi_entry_attr_find(entry, "uid", &attr); if (rc != 0 || attr == NULL) { /* no uid attribute */ rc = 1; goto fail1; } rc |= slapi_attr_get_valueset(attr, &uid_values); if (rc != 0 || slapi_valueset_count(uid_values) == 0) { /* empty uid value */ rc = 1; goto fail1; } fail1: slapi_entry_free(entry); return rc; } static int auth(char *dn, struct berval *credentials) { char *attrs[] = { "userPassword", NULL }; Slapi_Entry *entry = NULL; Slapi_Attr *attr = NULL; struct berval **userPasswords = NULL; int rc = 0; /* get entry */ rc |= get_entry(dn, attrs, &entry); if (rc != 0 || entry == NULL) { rc = -1; goto fail1; } /* get userpassword attr */ rc |= slapi_entry_attr_find(entry, "userPassword", &attr); if (rc != 0 || attr == NULL) { rc = 1; goto fail1; } /* get attribute values */ rc |= slapi_attr_get_values(attr, &userPasswords); if (rc != 0 || userPasswords == NULL) { rc = 1; goto fail1; } /* check password */ rc |= slapi_pw_find(userPasswords, credentials); fail1: slapi_entry_free(entry); return rc; } static int auth_with_password_fallback(char *dn, struct berval *credentials) { char *parent_dn; int rc = 0; char fn[] = "auth_with_password_fallback in service_passwords plug-in"; slapi_log_error( SLAPI_LOG_PLUGIN, fn, "Try password fallback with dn: %s.\n", dn); rc = auth(dn, credentials); if (rc == 0) { /* auth success */ return 0; } else if (rc == 1) { /* auth fail, but entry exists (no fallback) */ return 1; } /* fallback to parent dn */ parent_dn = slapi_dn_parent(dn); rc = auth(parent_dn, credentials); if (rc == 0) { /* auth success */ return 0; } return 1; } static int pre_bind(Slapi_PBlock *pb) { char *dn; int method; struct berval *credentials; int is_replication; int is_internal; int connId; int opId; long msgId; char *parent_dn; int rc = 0; char fn[] = "pre_bind in service_passwords plug-in"; /* Obtain the bind information from the parameter block. */ rc |= slapi_pblock_get(pb, SLAPI_BIND_TARGET, &dn); rc |= slapi_pblock_get(pb, SLAPI_BIND_METHOD, &method); rc |= slapi_pblock_get(pb, SLAPI_BIND_CREDENTIALS, &credentials); rc |= slapi_pblock_get(pb, SLAPI_OPERATION_MSGID, &msgId); rc |= slapi_pblock_get(pb, SLAPI_CONN_ID, &connId); rc |= slapi_pblock_get(pb, SLAPI_OPERATION_ID, &opId); rc |= slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replication); rc |= slapi_pblock_get(pb, SLAPI_IS_INTERNAL_OPERATION, &is_internal); if (rc != 0) { slapi_log_error( SLAPI_LOG_PLUGIN, fn, "Could not get parameters for bind operation (error %d).\n", rc); /* Cancel bind */ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL); return LDAP_OPERATIONS_ERROR; } if (is_replication || is_internal) { return 0; } if (method != LDAP_AUTH_SIMPLE) { slapi_log_error( SLAPI_LOG_PLUGIN, fn, "The service_passwords plug-in does not handle this bind " "(method %d).\n", method); return 0; } parent_dn = slapi_dn_parent(dn); if (dn_contains_uid(parent_dn) != 0) { /* parent_dn is not an user, so we ignore this bind request. */ return 0; } if (auth_with_password_fallback(dn, credentials) == 0) { /* auth success: set connection info */ rc |= slapi_pblock_set(pb, SLAPI_CONN_DN, slapi_ch_strdup(dn)); if (rc != 0) { slapi_log_error( SLAPI_LOG_PLUGIN, fn, "Failed to set connection info.\n"); rc = LDAP_OPERATIONS_ERROR; slapi_send_ldap_result(pb, rc, NULL, NULL, 0, NULL); return rc; } /* auth done */ slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL); return 1; } /* auth fail */ rc = LDAP_INVALID_CREDENTIALS; slapi_send_ldap_result(pb, rc, NULL, NULL, 0, NULL); return rc; } Slapi_PluginDesc bindpdesc = { .spd_id = "service_passwords", .spd_vendor = "spline", .spd_version = "1.0", .spd_description = "preoperation plugin " "to authenticate a bind against different passwords" }; int service_passwords_init(Slapi_PBlock *pb) { int rc = 0; rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_CURRENT_VERSION); rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *) &bindpdesc); rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_BIND_FN, (void *) pre_bind); rc |= slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &plugin_id); return rc; }