From cb8c9b87cd6f8ce1f3dc3b923bab9d4a135d6601 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Mon, 30 Nov 2015 02:11:56 +0100 Subject: Add password fallback Add pre_bind function for service password fallback. --- service_passwords.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) diff --git a/service_passwords.c b/service_passwords.c index e5ddba4..03c0c96 100644 --- a/service_passwords.c +++ b/service_passwords.c @@ -4,8 +4,251 @@ #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(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 parent_dn_contains_uid(char *dn) +{ + char *parent_dn; + char *attrs[] = { "uid", NULL }; + Slapi_Entry *entry = NULL; + Slapi_Attr *attr = NULL; + Slapi_ValueSet *uid_values = NULL; + + int rc = 0; + + parent_dn = slapi_dn_parent(dn); + + rc |= get_entry(parent_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; + + 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; + } + + if (parent_dn_contains_uid(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", @@ -20,6 +263,7 @@ int service_passwords_init(Slapi_PBlock *pb) 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; } -- cgit v1.2.3-1-g7c22