From cc6761cf1f424f27a03ee92275f26713b82942cd Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Sat, 19 Nov 2016 18:58:04 +0100 Subject: POST_BIND: Remove hook. post_bind is not exected, if the pre_bind method has completed the bind operation. Additionally the post_bind method does not have access to the SLAPI_CONN_DN (bind dn). So we have to find another method to save the extension data. --- service_passwords.c | 88 ----------------------------------------------------- 1 file changed, 88 deletions(-) diff --git a/service_passwords.c b/service_passwords.c index 1f27600..6be182f 100644 --- a/service_passwords.c +++ b/service_passwords.c @@ -618,93 +618,6 @@ 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 - * * 0 on success - * * != 0 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. @@ -1076,7 +989,6 @@ int service_passwords_init(Slapi_PBlock *pb) 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_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) { -- cgit v1.2.3-1-g7c22 From 09a9fac51c1625af84755900835bf6679881704f Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Sat, 19 Nov 2016 19:02:26 +0100 Subject: pre_bind: Handle all binds and save extension data The pre_bind method has to handle the binds for service accounts, too. This way it can save the service name and gold service status after a successful bind. --- service_passwords.c | 154 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 119 insertions(+), 35 deletions(-) diff --git a/service_passwords.c b/service_passwords.c index 6be182f..5aaed65 100644 --- a/service_passwords.c +++ b/service_passwords.c @@ -503,6 +503,68 @@ static char *get_service_dn(const char *service) return new_dn; } + +/** Save the information from a successful bind in the connection data. + * + * This method saves the verified data after a bind into the connection + * structure. The bind dn is set as the connection dn and the service name + * and the gold status is saved into the extension object of the connection + * data. + * + * The method directly stores the pointer to the service name in the + * extension data, so that the caller should not be free it anymore after a + * successful call to this method. Instead the destructor of the extension + * data (or the \c POST_UNBIND hook) will take care of the memory. + * + * @param[in,out] pb Parameter block of the operation. + * @param[in] dn The bind dn. + * @param[in] service_name The service name found in the bind dn. (The pointer + * is saved inside the extensions data, so that the caller + * should not free the memory.) + * @param[in] gold_service Whether the service (found in the bind dn) is a + * gold service. + * @return + * * 0 on success + * * != 0 in case of any error + */ +static int save_connection_info(Slapi_PBlock *pb, char *dn, char *service_name, int gold_service) +{ + Slapi_Connection *conn; + + private_connection_data *conn_ext; + + int rc = 0; + char fn[] = "save_connection_info in service_passwords plug-in"; + + rc |= slapi_pblock_get(pb, SLAPI_CONNECTION, &conn); + rc |= slapi_pblock_set(pb, SLAPI_CONN_DN, dn); + if (rc != 0) { + slapi_log_error( + SLAPI_LOG_PLUGIN, fn, + "Failed to get/set connection info.\n"); + return -1; + } + + /* 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"); + return -1; + } + + conn_ext->gold_service = gold_service; + conn_ext->service_name = service_name; + slapi_log_error( + SLAPI_LOG_PLUGIN, fn, + "Setting connection data: %d %s.\n", + gold_service, service_name); + + return 0; +} + /** \c PRE_BIND plugin to allow password fallback. * * This function is called before a bind operation. If the BIND_DN is a user @@ -571,51 +633,73 @@ static int pre_bind(Slapi_PBlock *pb) return SLAPI_BIND_SUCCESS; } - parent_dn = slapi_dn_parent(dn); - rc |= is_user(parent_dn, &gold_account); - slapi_ch_free_string(&parent_dn); + if (is_service(dn, &service, &gold_service) != 0) { + parent_dn = slapi_dn_parent(dn); + rc |= is_user(parent_dn, NULL); + slapi_ch_free_string(&parent_dn); - if (rc != 0) { - /* parent_dn is not an user, so we ignore this bind request. */ - return SLAPI_BIND_SUCCESS; - } + if (rc != 0) { + /* parent_dn is not an user, so we ignore this bind request. */ + 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); + service = get_virtual_service(dn); - if (rc != 0) { - /* Invalid service */ - return SLAPI_BIND_FAIL; - } + service_dn = get_service_dn(service); + rc |= is_service(service_dn, NULL, &gold_service); + slapi_ch_free_string(&service_dn); - 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); if (rc != 0) { slapi_log_error( SLAPI_LOG_PLUGIN, fn, - "Failed to set connection info.\n"); + "Invalid service '%s' in bind dn '%s'.\n", + service, dn); + rc = SLAPI_BIND_FAIL; + goto fail1; + } - rc = LDAP_OPERATIONS_ERROR; - slapi_send_ldap_result(pb, rc, NULL, NULL, 0, NULL); - return rc; + if (gold_service != 0 && gold_account == 0) { + /* This is a bind for a gold_service, but it's not a gold account. */ + rc = SLAPI_BIND_FAIL; + goto fail1; } - /* auth done */ - slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL); - return 1; + if (auth_with_password_fallback(dn, credentials) == 0) { + /* auth success: set connection info */ + if (save_connection_info(pb, dn, service, gold_service) == 0) { + slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL); + return 1; + } + else { + rc = LDAP_OPERATIONS_ERROR; + slapi_send_ldap_result(pb, rc, NULL, NULL, 0, NULL); + goto fail1; + } + } + } + else { + /* service: simple auth, no fallback */ + if (auth(dn, credentials) == 0) { + if (save_connection_info(pb, dn, service, gold_service) == 0) { + slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL); + return 1; + } + else { + rc = LDAP_OPERATIONS_ERROR; + slapi_send_ldap_result(pb, rc, NULL, NULL, 0, NULL); + goto fail1; + } + } } + /* wrong password */ + rc = SLAPI_BIND_FAIL; + +fail1: + slapi_ch_free_string(&service); + /* auth fail */ - return SLAPI_BIND_FAIL; + return rc; } /** \c POST_UNBIND plugin to reset the connection data after unbind. @@ -965,9 +1049,9 @@ void free_connection_data(void *extension, Slapi_PluginDesc bindpdesc = { .spd_id = "service_passwords", .spd_vendor = "spline", - .spd_version = "0.3", - .spd_description = "preoperation plugin " - "to authenticate a bind against different passwords" + .spd_version = "0.4", + .spd_description = "plugin to authenticate a bind " + "against different passwords" }; int service_passwords_init(Slapi_PBlock *pb) -- cgit v1.2.3-1-g7c22