summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Sulfrian <alexander@sulfrian.net>2015-11-30 02:11:56 +0100
committerAlexander Sulfrian <alexander@sulfrian.net>2015-11-30 02:16:41 +0100
commitcb8c9b87cd6f8ce1f3dc3b923bab9d4a135d6601 (patch)
tree20c712cbeb637862769309936dcc274882d28b43
parent464f2172837ecc789f437aeff6806b0f2e6b9bc9 (diff)
downloadldap-plugin-cb8c9b87cd6f8ce1f3dc3b923bab9d4a135d6601.tar.gz
ldap-plugin-cb8c9b87cd6f8ce1f3dc3b923bab9d4a135d6601.tar.bz2
ldap-plugin-cb8c9b87cd6f8ce1f3dc3b923bab9d4a135d6601.zip
Add password fallback
Add pre_bind function for service password fallback.
-rw-r--r--service_passwords.c244
1 files changed, 244 insertions, 0 deletions
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 <slapi-plugin.h>
+/* 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;
}