summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Sulfrian <alexander@sulfrian.net>2016-11-18 19:53:10 +0100
committerAlexander Sulfrian <alexander@sulfrian.net>2016-11-19 21:40:52 +0100
commitc9dd6bc3b4273395878d559ecec72cd02c154d54 (patch)
tree906b6506589c53746ff5671a2f13e47fbe7fdc2b
parent9005628254a247597bf7ee2b25df18585f02d953 (diff)
downloadldap-plugin-c9dd6bc3b4273395878d559ecec72cd02c154d54.tar.gz
ldap-plugin-c9dd6bc3b4273395878d559ecec72cd02c154d54.tar.bz2
ldap-plugin-c9dd6bc3b4273395878d559ecec72cd02c154d54.zip
Use connection private data storage for gold status
After a bind operation the service_name and the gold_service status is saved in a connection data extension, so that it can be used by the other methods and f.e. the pre_entry method do not need to build the service dn again.
-rw-r--r--service_passwords.c351
1 files changed, 269 insertions, 82 deletions
diff --git a/service_passwords.c b/service_passwords.c
index a5a3b3d..1f27600 100644
--- a/service_passwords.c
+++ b/service_passwords.c
@@ -7,9 +7,42 @@
/* This is missing in slapi-plugin.h: */
extern int slapi_pw_find(struct berval **vals, struct berval *v);
-static Slapi_ComponentId *plugin_id = NULL;
+/**
+ * Private plugin data
+ */
+
+typedef struct {
+ /** object type for the extension */
+ int obj_type;
+
+ /** extension handle for the extension */
+ int handle;
+} extension_data;
+
+typedef struct {
+ /** extension of the connection data */
+ extension_data conn_ext;
+
+ /** base DN for the service accounts */
+ char *service_base_dn;
+
+ /** id to represent the plugin for internal operations */
+ Slapi_ComponentId *plugin_id;
+} plugin_data;
+
+/** Per-connection private data of this plugin. Set in pre_bind. */
+typedef struct {
+ /** Service name in the bind DN. */
+ char *service_name;
-static char *service_base_dn = NULL;
+ /**
+ * If the connection was bound against a gold service (or a
+ * virtual entry of a gold service).
+ */
+ int gold_service;
+} private_connection_data;
+
+static plugin_data private;
/** Get an entry specified by a DN and with the specified attributes.
*
@@ -46,7 +79,7 @@ static int get_entry(const char *dn, char **attrs, Slapi_Entry **entry)
0 /* attrsonly */,
NULL /* controls */,
NULL /* uniqueid */,
- plugin_id,
+ private.plugin_id,
0 /* actions */);
slapi_search_internal_pb(pb);
@@ -463,7 +496,8 @@ static char *get_service_dn(const char *service)
rdn = slapi_rdn_new();
slapi_rdn_add(rdn, "cn", service);
- new_dn = slapi_dn_plus_rdn(service_base_dn, slapi_rdn_get_rdn(rdn));
+ new_dn = slapi_dn_plus_rdn(private.service_base_dn,
+ slapi_rdn_get_rdn(rdn));
slapi_rdn_free(&rdn);
return new_dn;
@@ -515,8 +549,7 @@ static int pre_bind(Slapi_PBlock *pb)
if (rc != 0) {
slapi_log_error(
SLAPI_LOG_PLUGIN, fn,
- "Could not get parameters for bind operation (error %d).\n",
- rc);
+ "Could not get parameters (error %d).\n", rc);
/* Cancel bind */
slapi_send_ldap_result(
@@ -566,7 +599,6 @@ static int pre_bind(Slapi_PBlock *pb)
if (auth_with_password_fallback(dn, credentials) == 0) {
/* auth success: set connection info */
rc |= slapi_pblock_set(pb, SLAPI_CONN_DN, dn);
-
if (rc != 0) {
slapi_log_error(
SLAPI_LOG_PLUGIN, fn,
@@ -586,6 +618,137 @@ static int pre_bind(Slapi_PBlock *pb)
return SLAPI_BIND_FAIL;
}
+/** \c POST_BIND plugin to save the extra connection data after bind.
+ *
+ * This method is called after a bind operation and try to detect if the
+ * \c BIND_DN contains a service name. The \c BIND_DN either be a service dn or
+ * a virtual service entry of a user. If it is a virtual entry of the user, than
+ * the service prefix is used to build the service dn.
+ *
+ * If the service dn is found, the method checks whether that entry is a gold
+ * service or not. The service name and the gold service status is saved in the
+ * private connection extension data, so that it can be used by the other
+ * methods of this plugin.
+ *
+ * @param[in,out] pb Parameter block of the operation.
+ * @return
+ * * <tt>0</tt> on success
+ * * <tt>!= 0</tt> in case of error
+ */
+static int post_bind(Slapi_PBlock *pb)
+{
+ Slapi_Connection *conn;
+ char *bind_dn;
+
+ private_connection_data *conn_ext = NULL;
+ int gold_service = 0;
+ char *service = NULL;
+ char *service_dn = NULL;
+ char *parent_dn = NULL;
+
+ int rc = 0;
+ char fn[] = "post_bind in service_passwords plug-in";
+
+ rc |= slapi_pblock_get(pb, SLAPI_CONNECTION, &conn);
+ rc |= slapi_pblock_get(pb, SLAPI_CONN_DN, &bind_dn);
+
+ if (rc != 0) {
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Could not get parameters (error %d).\n", rc);
+ return rc;
+ }
+
+ if (is_service(bind_dn, &service, &gold_service) != 0) {
+ parent_dn = slapi_dn_parent(bind_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);
+
+ if (rc != 0) {
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Invalid service '%s' in bind dn '%s'.\n",
+ service, bind_dn);
+ goto fail1;
+ }
+ }
+
+ /* set the connection private data */
+ conn_ext = (private_connection_data*)slapi_get_object_extension(
+ private.conn_ext.obj_type, conn, private.conn_ext.handle);
+ if (conn_ext == NULL) {
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Failed to get connection private data.\n");
+
+ rc = LDAP_OPERATIONS_ERROR;
+ goto fail1;
+ }
+
+ conn_ext->gold_service = gold_service;
+ conn_ext->service_name = service;
+ return 0;
+
+fail1:
+ slapi_ch_free_string(&service);
+ return rc;
+}
+
+
+/** \c POST_UNBIND plugin to reset the connection data after unbind.
+ *
+ * @param[in,out] pb Parameter block of the operation.
+ * @return
+ * * <tt>0</tt> on success
+ * * <tt>!= 0</tt> in case of error
+ */
+static int post_unbind(Slapi_PBlock *pb)
+{
+ Slapi_Connection *conn;
+
+ private_connection_data *conn_ext = NULL;
+
+ int rc = 0;
+ char fn[] = "post_unbind in service_passwords plug-in";
+
+ rc |= slapi_pblock_get(pb, SLAPI_CONNECTION, &conn);
+
+ if (rc != 0) {
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Could not get parameters (error %d).\n", rc);
+ return rc;
+ }
+
+ conn_ext = (private_connection_data*)slapi_get_object_extension(
+ private.conn_ext.obj_type, conn, private.conn_ext.handle);
+ if (conn_ext == NULL) {
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Failed to get connection private data.\n");
+ return -1;
+ }
+
+ conn_ext->gold_service = 0;
+
+ if (conn_ext->service_name != NULL) {
+ slapi_ch_free_string(&conn_ext->service_name);
+ conn_ext->service_name = NULL;
+ }
+
+ return rc;
+}
+
/** \c PRE_ENTRY plugin to rewrite returned search results to keep the service
* name until bind.
*
@@ -607,16 +770,15 @@ static int pre_bind(Slapi_PBlock *pb)
*/
static int pre_entry(Slapi_PBlock *pb)
{
+ Slapi_Connection *conn;
char *bind_dn;
Slapi_Entry *entry;
Slapi_Operation *op;
int is_replication;
int is_internal;
- int gold_service = 0;
+ private_connection_data *conn_ext = NULL;
int gold_account = 0;
- char *service = NULL;
- char *service_dn = NULL;
char *parent_dn = NULL;
const char *result_dn = NULL;
Slapi_Entry *new_entry;
@@ -624,6 +786,7 @@ static int pre_entry(Slapi_PBlock *pb)
int rc = 0;
char fn[] = "pre_entry in service_passwords plug-in";
+ rc |= slapi_pblock_get(pb, SLAPI_CONNECTION, &conn);
rc |= slapi_pblock_get(pb, SLAPI_CONN_DN, &bind_dn);
rc |= slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_ENTRY, &entry);
rc |= slapi_pblock_get(pb, SLAPI_OPERATION, &op);
@@ -654,28 +817,13 @@ static int pre_entry(Slapi_PBlock *pb)
return 0;
}
- if (is_service(bind_dn, &service, &gold_service) != 0) {
- parent_dn = slapi_dn_parent(bind_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);
-
- if (rc != 0) {
- slapi_log_error(
- SLAPI_LOG_PLUGIN, fn,
- "Invalid service '%s' in bind dn '%s'.\n",
- service, bind_dn);
- goto fail1;
- }
+ conn_ext = (private_connection_data*)slapi_get_object_extension(
+ private.conn_ext.obj_type, conn, private.conn_ext.handle);
+ if (conn_ext == NULL) {
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Failed to get connection private data.\n");
+ return -1;
}
result_dn = slapi_entry_get_dn(entry);
@@ -686,19 +834,17 @@ static int pre_entry(Slapi_PBlock *pb)
slapi_ch_free_string(&parent_dn);
if (rc == 0) {
- rc = -1;
- goto fail1;
+ return -1;
}
/* modify the dn of the returned entry */
if (is_user(result_dn, &gold_account) == 0) {
- if (gold_service != 0 && gold_account == 0) {
+ if (conn_ext->gold_service != 0 && gold_account == 0) {
/* ignore non-gold account for gold services */
- rc = -1;
- goto fail1;
+ return -1;
}
else {
- new_entry = prepend_service_prefix(entry, service);
+ new_entry = prepend_service_prefix(entry, conn_ext->service_name);
/* 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
@@ -707,9 +853,6 @@ static int pre_entry(Slapi_PBlock *pb)
}
}
-fail1:
- slapi_ch_free_string(&service);
-
return rc;
}
@@ -734,22 +877,22 @@ fail1:
*/
static int pre_search(Slapi_PBlock *pb)
{
+ Slapi_Connection *conn;
char *bind_dn;
char *base;
Slapi_Filter *search_filter = NULL;
int is_replication;
int is_internal;
+ private_connection_data *conn_ext = NULL;
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_CONNECTION, &conn);
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);
@@ -776,34 +919,21 @@ static int pre_search(Slapi_PBlock *pb)
return 0;
}
- if (is_service(bind_dn, NULL, &gold_service) != 0) {
- parent_dn = slapi_dn_parent(bind_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);
+ conn_ext = (private_connection_data*)slapi_get_object_extension(
+ private.conn_ext.obj_type, conn, private.conn_ext.handle);
+ if (conn_ext == NULL) {
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Failed to get connection private data.\n");
+ return -1;
+ }
- slapi_send_ldap_result(
- pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
- return LDAP_OPERATIONS_ERROR;
- }
+ if (conn_ext->service_name == NULL) {
+ /* ignore searches without a service in the bind_dn */
+ return 0;
}
- if (gold_service) {
+ if (conn_ext->gold_service) {
/* modify search filter, to only get the gold accounts */
gold_filter = slapi_str2filter("(|(objectClass=splineGoldAccounts)(!(objectClass=splineAccount)))");
@@ -818,7 +948,7 @@ static int pre_search(Slapi_PBlock *pb)
}
joined_filter = slapi_filter_join(LDAP_FILTER_AND, gold_filter, search_filter);
-
+
if (joined_filter == NULL) {
slapi_log_error(
SLAPI_LOG_PLUGIN, fn,
@@ -869,33 +999,60 @@ static int check_arguments(Slapi_PBlock *pb)
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) {
+ return -1;
+ }
+
+ private.service_base_dn = slapi_ch_strdup(argv[0]);
+ return 0;
+}
+
+void *create_connection_data(__attribute__((unused)) void *object,
+ __attribute__((unused)) void *parent)
+{
+ private_connection_data* ext;
+ char fn[] = "create_connection_data in service_passwords plug-in";
+
+ ext = (private_connection_data*)slapi_ch_malloc(sizeof(private_connection_data));
+ if (ext == NULL) {
slapi_log_error(
SLAPI_LOG_PLUGIN, fn,
- "Could not get parameters (error %d, arvc=%d).\n",
- rc, argc);
+ "Could not allocate memory.\n");
+ return NULL;
+ }
- return rc;
+ ext->service_name = NULL;
+ ext->gold_service = 0;
+ return ext;
+}
+
+void free_connection_data(void *extension,
+ __attribute__((unused)) void *object,
+ __attribute__((unused)) void *parent)
+{
+ private_connection_data* ext;
+
+ if (extension == NULL) {
+ return;
}
- 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);
+ ext = (private_connection_data*)extension;
- return rc;
+ if (ext->service_name != NULL) {
+ slapi_ch_free_string(&ext->service_name);
+ }
+
+ slapi_ch_free((void **)&ext);
}
Slapi_PluginDesc bindpdesc = {
.spd_id = "service_passwords",
.spd_vendor = "spline",
- .spd_version = "0.2",
+ .spd_version = "0.3",
.spd_description = "preoperation plugin "
"to authenticate a bind against different passwords"
};
@@ -903,14 +1060,44 @@ Slapi_PluginDesc bindpdesc = {
int service_passwords_init(Slapi_PBlock *pb)
{
int rc = 0;
+ char fn[] = "service_passwords_init in service_passwords plug-in";
rc |= check_arguments(pb);
+ if (rc != 0) {
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Could not get arguments (error %d).\n",
+ rc);
+ return rc;
+ }
+
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);
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_POST_BIND_FN, (void *) post_bind);
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_POST_UNBIND_FN, (void *) post_unbind);
+ rc |= slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &private.plugin_id);
+ if (rc != 0) {
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Could not set plugin parameters (error %d).\n",
+ rc);
+ return rc;
+ }
+
+ rc |= slapi_register_object_extension(
+ bindpdesc.spd_id, SLAPI_EXT_CONNECTION,
+ create_connection_data, free_connection_data,
+ &private.conn_ext.obj_type, &private.conn_ext.handle);
+ if (rc != 0) {
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN, fn,
+ "Could not register connection extension (error %d).\n",
+ rc);
+ return rc;
+ }
return rc;
}