summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Sulfrian <alexander@sulfrian.net>2016-11-19 21:46:16 +0100
committerAlexander Sulfrian <alexander@sulfrian.net>2016-11-19 21:46:16 +0100
commit50b77a397e28923d4886357ca7ca4a6066da6112 (patch)
treebe09985a3c2b4499438ca57f6826a2a78c438e93
parent90009c3acb7a0dfa970ca00aea908d8d405afdd3 (diff)
parent9005628254a247597bf7ee2b25df18585f02d953 (diff)
downloadldap-plugin-50b77a397e28923d4886357ca7ca4a6066da6112.tar.gz
ldap-plugin-50b77a397e28923d4886357ca7ca4a6066da6112.tar.bz2
ldap-plugin-50b77a397e28923d4886357ca7ca4a6066da6112.zip
Merge branch 'master' into debian
* master: pre_search: Set filter to speed up the search for gold accounts Fix version Get service_base_dn from the plugin arguments pre_entry: Check for gold service even if a user is authed pre_entry: Only return gold accounts for gold services pre_bind: Check permissions for gold services get_service_dn: Get the service dn from service name is_service: Add possibility to check for gold services is_user: Add possibility to check for gold accounts Use new custom objectClass: splineAccount Fix Makefile
-rw-r--r--Makefile12
-rw-r--r--service_passwords.c236
2 files changed, 225 insertions, 23 deletions
diff --git a/Makefile b/Makefile
index 1dccd71..81cc5a3 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,7 @@
OPENLDAP_SOURCE := ../source/openldap-2.4.40+dfsg
-TARGET = service_passwords
-INCLUDE_FLAGS = -I$(OPENLDAP_SOURCE)/include
-CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -fPIC -Wall -Wextra
-LDFLAGS = -G
+TARGET := service_passwords
+CFLAGS := -I$(OPENLDAP_SOURCE)/include -D_REENTRANT -fPIC -Wall -Wextra $(CFLAGS)
all: $(TARGET).so
@@ -12,10 +10,14 @@ clean:
$(RM) -r html/ latex/
%.so: %.o
- $(LD) $(LDFLAGS) -o $@ $^
+ gcc $(LDFLAGS) -shared -Wl,-soname,$(TARGET) -llber -o $@ $^
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $^
doc:
doxygen Doxyfile
+
+install: $(TARGET).so
+ install -d $(DESTDIR)/usr/lib/ldap/
+ install -m=0644 $(TARGET).so $(DESTDIR)/usr/lib/ldap/
diff --git a/service_passwords.c b/service_passwords.c
index 56c6e58..a5a3b3d 100644
--- a/service_passwords.c
+++ b/service_passwords.c
@@ -9,6 +9,8 @@ extern int slapi_pw_find(struct berval **vals, struct berval *v);
static Slapi_ComponentId *plugin_id = NULL;
+static char *service_base_dn = NULL;
+
/** Get an entry specified by a DN and with the specified attributes.
*
* This functions get a entry specified by a \c DN. It's doing this with an
@@ -75,18 +77,27 @@ static int get_entry(const char *dn, char **attrs, Slapi_Entry **entry)
/** Check if the given DN is a user account.
*
* This functions checks, if the given DN is a DN of a user account. All user
- * accounts have to have the \c inetOrgPerson object class.
+ * accounts have to have the \c splineAccount object class.
*
* @param[in] dn DN of the entry.
+ * @param[out] gold_account If not \c NULL, this method will also check, if
+ * the entry has the \c splineGoldAccount object
+ * class. If the entry is a gold account this will
+ * be set to 1, otherwise 0.
+ *
* @return 0 if the entry is a user account, 1 otherwise
*/
-static int is_user(const char *dn)
+static int is_user(const char *dn, int *gold_account)
{
char *attrs[] = { "objectClass", NULL };
Slapi_Entry *entry = NULL;
int rc = 0;
+ if (gold_account != NULL) {
+ *gold_account = 0;
+ }
+
rc |= get_entry(dn, attrs, &entry);
if (rc != 0 || entry == NULL) {
/* dn not found */
@@ -95,12 +106,20 @@ static int is_user(const char *dn)
}
if (slapi_entry_attr_hasvalue(
- entry, "objectClass", "inetOrgPerson") == 0) {
+ entry, "objectClass", "splineAccount") == 0) {
/* no user account */
rc = 1;
goto fail1;
}
+ /* check if this user has a "gold" account */
+ if (gold_account != NULL) {
+ if (slapi_entry_attr_hasvalue(
+ entry, "objectClass", "splineGoldAccount") != 0) {
+ *gold_account = 1;
+ }
+ }
+
fail1:
slapi_entry_free(entry);
@@ -122,9 +141,11 @@ fail1:
* If this is NULL, the function will only check if the DN
* is a service account and will not allocate memory for the
* service name.
+ * @param[out] gold_service If not \c NULL, this method will also check, if
+ * the service requires a \c splineGoldAccount.
* @return 0 if the entry is a service account, 1 otherwise.
*/
-static int is_service(const char *dn, char **service)
+static int is_service(const char *dn, char **service, int *gold_service)
{
Slapi_Entry *entry = NULL;
char *attrs[] = { "objectClass", "cn", NULL };
@@ -132,6 +153,10 @@ static int is_service(const char *dn, char **service)
struct berval **cn = NULL;
int rc = 0;
+ if (gold_service != NULL) {
+ *gold_service = 0;
+ }
+
rc |= get_entry(dn, attrs, &entry);
if (rc != 0 || entry == NULL) {
/* dn not found */
@@ -146,6 +171,13 @@ static int is_service(const char *dn, char **service)
goto fail1;
}
+ if (gold_service != NULL) {
+ if (slapi_entry_attr_hasvalue(
+ entry, "objectClass", "goldServiceAccount") != 0) {
+ *gold_service = 1;
+ }
+ }
+
rc |= slapi_entry_attr_find(entry, "cn", &attr);
if (rc != 0 || attr == NULL) {
/* no cn attribute */
@@ -415,6 +447,28 @@ static char *get_virtual_service(const char *dn)
return service;
}
+/** The DN of the service specified by name.
+ *
+ * This function builds the \c DN of a service from the service name and
+ * the base dn for the services.
+ *
+ * @param[in] service The name of the service.
+ * @return Pointer to the service dn. The caller is responsible for freeing
+ * it with \c slapi_ch_free_string.
+ */
+static char *get_service_dn(const char *service)
+{
+ char *new_dn = NULL;
+ Slapi_RDN *rdn = NULL;
+
+ rdn = slapi_rdn_new();
+ slapi_rdn_add(rdn, "cn", service);
+ new_dn = slapi_dn_plus_rdn(service_base_dn, slapi_rdn_get_rdn(rdn));
+ slapi_rdn_free(&rdn);
+
+ return new_dn;
+}
+
/** \c PRE_BIND plugin to allow password fallback.
*
* This function is called before a bind operation. If the BIND_DN is a user
@@ -443,6 +497,10 @@ static int pre_bind(Slapi_PBlock *pb)
int is_internal = 0;
char *parent_dn = NULL;
+ char *service = NULL;
+ char *service_dn = NULL;
+ int gold_account = 0;
+ int gold_service = 0;
int rc = 0;
char fn[] = "pre_bind in service_passwords plug-in";
@@ -481,7 +539,7 @@ static int pre_bind(Slapi_PBlock *pb)
}
parent_dn = slapi_dn_parent(dn);
- rc |= is_user(parent_dn);
+ rc |= is_user(parent_dn, &gold_account);
slapi_ch_free_string(&parent_dn);
if (rc != 0) {
@@ -489,6 +547,22 @@ static int pre_bind(Slapi_PBlock *pb)
return SLAPI_BIND_SUCCESS;
}
+ service = get_virtual_service(dn);
+ service_dn = get_service_dn(service);
+ rc |= is_service(service_dn, NULL, &gold_service);
+ slapi_ch_free_string(&service_dn);
+ slapi_ch_free_string(&service);
+
+ if (rc != 0) {
+ /* Invalid service */
+ return SLAPI_BIND_FAIL;
+ }
+
+ if (gold_service != 0 && gold_account == 0) {
+ /* This is a bind for a gold_service, but it's not a gold account. */
+ return SLAPI_BIND_FAIL;
+ }
+
if (auth_with_password_fallback(dn, credentials) == 0) {
/* auth success: set connection info */
rc |= slapi_pblock_set(pb, SLAPI_CONN_DN, dn);
@@ -539,7 +613,10 @@ static int pre_entry(Slapi_PBlock *pb)
int is_replication;
int is_internal;
+ int gold_service = 0;
+ int gold_account = 0;
char *service = NULL;
+ char *service_dn = NULL;
char *parent_dn = NULL;
const char *result_dn = NULL;
Slapi_Entry *new_entry;
@@ -577,9 +654,9 @@ static int pre_entry(Slapi_PBlock *pb)
return 0;
}
- if (is_service(bind_dn, &service) != 0) {
+ if (is_service(bind_dn, &service, &gold_service) != 0) {
parent_dn = slapi_dn_parent(bind_dn);
- rc |= is_user(parent_dn);
+ rc |= is_user(parent_dn, NULL);
slapi_ch_free_string(&parent_dn);
if (rc != 0) {
@@ -587,13 +664,25 @@ static int pre_entry(Slapi_PBlock *pb)
}
service = get_virtual_service(bind_dn);
+
+ service_dn = get_service_dn(service);
+ rc |= is_service(service_dn, NULL, &gold_service);
+ slapi_ch_free_string(&service_dn);
+
+ if (rc != 0) {
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Invalid service '%s' in bind dn '%s'.\n",
+ service, bind_dn);
+ goto fail1;
+ }
}
result_dn = slapi_entry_get_dn(entry);
/* ignore service_password entries */
parent_dn = slapi_dn_parent(result_dn);
- rc |= is_user(parent_dn);
+ rc |= is_user(parent_dn, NULL);
slapi_ch_free_string(&parent_dn);
if (rc == 0) {
@@ -602,13 +691,20 @@ static int pre_entry(Slapi_PBlock *pb)
}
/* modify the dn of the returned entry */
- if (is_user(result_dn) == 0) {
- new_entry = prepend_service_prefix(entry, service);
+ if (is_user(result_dn, &gold_account) == 0) {
+ if (gold_service != 0 && gold_account == 0) {
+ /* ignore non-gold account for gold services */
+ rc = -1;
+ goto fail1;
+ }
+ else {
+ new_entry = prepend_service_prefix(entry, service);
- /* Set the new entry as the new result in the pblock and also set the
- the REP_ENTRY_MUSTBEFREED flag, so that the entry gets free'd when
- ready. */
- slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_ENTRY, new_entry);
+ /* Set the new entry as the new result in the pblock and also set the
+ the REP_ENTRY_MUSTBEFREED flag, so that the entry gets free'd when
+ ready. */
+ slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_ENTRY, new_entry);
+ }
}
fail1:
@@ -640,16 +736,23 @@ static int pre_search(Slapi_PBlock *pb)
{
char *bind_dn;
char *base;
+ Slapi_Filter *search_filter = NULL;
int is_replication;
int is_internal;
char *parent_dn = NULL;
+ char *service = NULL;
+ char *service_dn = NULL;
+ int gold_service = 0;
+ Slapi_Filter *gold_filter = NULL;
+ Slapi_Filter *joined_filter = NULL;
int rc = 0;
char fn[] = "pre_search in service_passwords plug-in";
rc |= slapi_pblock_get(pb, SLAPI_CONN_DN, &bind_dn);
rc |= slapi_pblock_get(pb, SLAPI_TARGET_DN, &base);
+ rc |= slapi_pblock_get(pb, SLAPI_SEARCH_FILTER, &search_filter);
rc |= slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replication);
rc |= slapi_pblock_get(pb, SLAPI_IS_INTERNAL_OPERATION, &is_internal);
@@ -673,19 +776,76 @@ static int pre_search(Slapi_PBlock *pb)
return 0;
}
- if (is_service(bind_dn, NULL) != 0) {
+ if (is_service(bind_dn, NULL, &gold_service) != 0) {
parent_dn = slapi_dn_parent(bind_dn);
- rc |= is_user(parent_dn);
+ rc |= is_user(parent_dn, NULL);
slapi_ch_free_string(&parent_dn);
if (rc != 0) {
return 0;
}
+
+ service = get_virtual_service(bind_dn);
+ service_dn = get_service_dn(service);
+ rc |= is_service(service_dn, NULL, &gold_service);
+ slapi_ch_free_string(&service_dn);
+ slapi_ch_free_string(&service);
+
+ if (rc != 0) {
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Invalid service in bind dn '%s'.\n",
+ bind_dn);
+
+ slapi_send_ldap_result(
+ pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
+ return LDAP_OPERATIONS_ERROR;
+ }
+ }
+
+ if (gold_service) {
+ /* modify search filter, to only get the gold accounts */
+ gold_filter = slapi_str2filter("(|(objectClass=splineGoldAccounts)(!(objectClass=splineAccount)))");
+
+ if (gold_filter == NULL) {
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Could not build search filter\n");
+
+ slapi_send_ldap_result(
+ pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ joined_filter = slapi_filter_join(LDAP_FILTER_AND, gold_filter, search_filter);
+
+ if (joined_filter == NULL) {
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Could not join search filters\n");
+
+ slapi_send_ldap_result(
+ pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ rc |= slapi_pblock_set(pb, SLAPI_SEARCH_FILTER, joined_filter);
+
+ if (rc != 0) {
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Could not set new search filter (error %d).\n",
+ rc);
+
+ slapi_send_ldap_result(
+ pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
+ return LDAP_OPERATIONS_ERROR;
+ }
}
parent_dn = slapi_dn_parent(base);
- if (is_user(parent_dn) == 0) {
+ if (is_user(parent_dn, NULL) == 0) {
rc |= slapi_pblock_set(pb, SLAPI_TARGET_DN, parent_dn);
}
@@ -694,10 +854,48 @@ static int pre_search(Slapi_PBlock *pb)
return rc;
}
+/** Check the supplied argument list.
+ *
+ * The \c base_dn for service accounts is the only argument that is required.
+ *
+ * @param[in] pb Parameter block of the plugin initialization.
+ * @return
+ * * 0 if the argument could be found
+ * * not 0 on any error
+ */
+static int check_arguments(Slapi_PBlock *pb)
+{
+ int rc = 0;
+
+ int argc = 0;
+ char **argv;
+ char *fn = "check_arguments";
+
+ rc |= slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
+ rc |= slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
+
+ if (rc != 0 || argc < 1) {
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Could not get parameters (error %d, arvc=%d).\n",
+ rc, argc);
+
+ return rc;
+ }
+
+ service_base_dn = slapi_ch_strdup(argv[0]);
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Using '%s' as base_dn for service accounts.\n",
+ service_base_dn);
+
+ return rc;
+}
+
Slapi_PluginDesc bindpdesc = {
.spd_id = "service_passwords",
.spd_vendor = "spline",
- .spd_version = "1.0",
+ .spd_version = "0.2",
.spd_description = "preoperation plugin "
"to authenticate a bind against different passwords"
};
@@ -706,11 +904,13 @@ int service_passwords_init(Slapi_PBlock *pb)
{
int rc = 0;
+ rc |= check_arguments(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_set(pb, SLAPI_PLUGIN_PRE_ENTRY_FN, (void *) pre_entry);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_SEARCH_FN, (void *) pre_search);
rc |= slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &plugin_id);
+
return rc;
}