diff --git a/docker/bin/setup b/docker/bin/setup index 04b11547..2cdbfa22 100755 --- a/docker/bin/setup +++ b/docker/bin/setup @@ -18,6 +18,8 @@ EOF cat >> /etc/postgresql/14/main/pg_hba.conf <<-EOF host ldap_db user1 127.0.0.1/32 trust +host ldap_db1 ldap_readonly 127.0.0.1/32 password +host ldap_db2 ldap_rw 127.0.0.1/32 md5 host auth_query_db auth_query_user_scram_sha_256 127.0.0.1/32 trust host auth_query_db auth_query_user_md5 127.0.0.1/32 trust local all postgres trust @@ -71,7 +73,6 @@ psql -h localhost -p 5432 -U postgres -c "set password_encryption TO 'md5'; crea exit 1 } - # Create users psql -h localhost -p 5432 -U postgres -c "set password_encryption = 'scram-sha-256'; create user auth_query_user_scram_sha_256 with password 'passwd'" -d postgres >> $SETUP_LOG 2>&1 || { echo "ERROR: users creation failed, examine the log" @@ -122,3 +123,44 @@ do exit 1 } done + +# Create databases for ldap_storage_credentials +for database_name in ldap_db1 ldap_db2; do + sudo -u postgres createdb $database_name >> "$SETUP_LOG" 2>&1 || { + echo "ERROR: 'createdb $database_name' failed, examine the log" + cat "$SETUP_LOG" + cat "$PG_LOG" + exit 1 + } +done + +# Create users for ldap_storage_credentials +psql -h localhost -p 5432 -U postgres -c "create user ldap_readonly with password 'ldap_pass_readonly'" -d ldap_db1 >> $SETUP_LOG 2>&1 || { + echo "ERROR: users creation failed, examine the log" + cat "$SETUP_LOG" + cat "$PG_LOG" + exit 1 +} + +psql -h localhost -p 5432 -U postgres -c "set password_encryption TO 'md5'; create user ldap_rw with password 'ldap_pass_rw'" -d ldap_db2 >> $SETUP_LOG 2>&1 || { + echo "ERROR: users creation failed, examine the log" + cat "$SETUP_LOG" + cat "$PG_LOG" + exit 1 +} + +# Grant access for ldap_storage_credentials + +psql -h localhost -p 5432 -U postgres -c "GRANT ALL ON DATABASE ldap_db1 TO ldap_readonly" -d postgres >> $SETUP_LOG 2>&1 || { + echo "ERROR: users creation failed, examine the log" + cat "$SETUP_LOG" + cat "$PG_LOG" + exit 1 +} + +psql -h localhost -p 5432 -U postgres -c "GRANT ALL ON DATABASE ldap_db2 TO ldap_rw" -d postgres >> $SETUP_LOG 2>&1 || { + echo "ERROR: users creation failed, examine the log" + cat "$SETUP_LOG" + cat "$PG_LOG" + exit 1 +} diff --git a/docker/ldap/odyssey.conf b/docker/ldap/odyssey.conf index 80040e74..aae7eb64 100644 --- a/docker/ldap/odyssey.conf +++ b/docker/ldap/odyssey.conf @@ -18,6 +18,66 @@ ldap_endpoint "ldap1" { ldapport 389 } +ldap_endpoint "ldap_storage_creds" { + ldapscheme "ldap" + ldapbasedn "dc=example,dc=org" + ldapbinddn "cn=admin,dc=example,dc=org" + ldapbindpasswd "admin" + ldapsearchfilter "(memberOf=cn=localhost,ou=groups,dc=example,dc=org)" + ldapsearchattribute "gecos" + ldapserver "192.168.233.16" + ldapport 389 +} + +database default { + user default { + authentication "clear_text" + + storage "postgres_server" + pool "session" + pool_size 10 + + ldap_pool_size 10 + ldap_pool_timeout 0 + + pool_timeout 0 + + pool_ttl 60 + + pool_discard no + + pool_cancel yes + + pool_rollback yes + + client_fwd_error yes + + application_name_add_host yes + + reserve_session_server_connection no + + server_lifetime 3600 + log_debug no + ldap_endpoint_name "ldap_storage_creds" + + ldap_storage_credentials_attr "memberof" + + ldap_storage_credentials "group_ro" { + ldap_storage_username "ldap_readonly" + ldap_storage_password "ldap_pass_readonly" + } + + ldap_storage_credentials "group_rw" { + ldap_storage_username "ldap_rw" + ldap_storage_password "ldap_pass_rw" + } + + quantiles "0.99,0.95,0.5" + client_max 107 + } + +} + database "ldap_db" { user "user1" { authentication "clear_text" diff --git a/docker/ldap/test_ldap.sh b/docker/ldap/test_ldap.sh index 4054e436..91792ed7 100755 --- a/docker/ldap/test_ldap.sh +++ b/docker/ldap/test_ldap.sh @@ -6,6 +6,9 @@ sleep 1 ldapadd -x -H ldap://192.168.233.16 -D "cn=admin,dc=example,dc=org" -wadmin -f /ldap/usr3.ldif # wait for ldap server to do smt sleep 1 +ldapadd -x -H ldap://192.168.233.16 -D "cn=admin,dc=example,dc=org" -wadmin -f /ldap/usr4.ldif +# wait for ldap server to do smt +sleep 1 /usr/bin/odyssey /ldap/odyssey.conf @@ -37,4 +40,25 @@ PGPASSWORD=notdefault psql -h localhost -p 6432 -U user3 -c "select 1" ldap_db > exit 1 } +PGPASSWORD=default psql -h localhost -p 6432 -U user4 -c "select current_user" ldap_db1 2>/dev/null | grep ldap_readonly | wc -l | grep -q '1' || { + echo "error: failed to successfully auth with correct password and correct db" + ody-stop + cat /var/log/odyssey.log + exit 1 +} + +PGPASSWORD=default psql -h localhost -p 6432 -U user4 -c "select current_user" ldap_db2 2>/dev/null | grep ldap_rw | wc -l | grep -q '1' || { + echo "error: failed to successfully auth with correct password and correct db" + ody-stop + cat /var/log/odyssey.log + exit 1 +} + +PGPASSWORD=notdefault psql -h localhost -p 6432 -U user4 -c "select 1" ldap_db1 >/dev/null 2>&1 && { + echo "error: successfully auth with incorrect password" + ody-stop + cat /var/log/odyssey.log + exit 1 +} + ody-stop diff --git a/docker/ldap/usr4.ldif b/docker/ldap/usr4.ldif new file mode 100644 index 00000000..35a8fa3c --- /dev/null +++ b/docker/ldap/usr4.ldif @@ -0,0 +1,19 @@ +dn: uid=user4,dc=example,dc=org +objectClass: top +objectClass: account +objectClass: posixAccount +objectClass: shadowAccount +cn: user4 +uid: user4 +memberof: cn=localhost,ou=groups,dc=example,dc=org +memberof: cn=localhost_ldap_db1_group_ro,ou=groups,dc=example,dc=org +memberof: cn=localhost_ldap_db2_group_rw,ou=groups,dc=example,dc=org +uidNumber: 16860 +gidNumber: 101 +homeDirectory: /home/user4 +loginShell: /bin/bash +gecos: user4 +userPassword: default +shadowLastChange: 0 +shadowMax: 0 +shadowWarning: 0 diff --git a/documentation/configuration.md b/documentation/configuration.md index f066d971..337c516c 100644 --- a/documentation/configuration.md +++ b/documentation/configuration.md @@ -513,7 +513,102 @@ storage "postgres_server" #storage_user "test" #storage_password "test" ``` +### ldap_storage_credentials +This subsection must located at subsection `user` and used to route clients to a remote PostgreSQL server with special credentials +(`storage_user` and `storage_password`), depending in the client account attributes stored on the LDAP server +(based on OpenLDAP, Active Directory or others). This routing method allows to grant access +with different privileges to different databases located on the same host. + +This routing method maybe used only if variables of ldap_endpoint_name and ldap_storage_credentials_attr +are set. For example: + +``` +storage "test_server" { + type "remote" + port 5432 + host "postgres_server" +} +ldap_endpoint "ldap1" { + ldapscheme "ldap" + ldapbasedn "dc=example,dc=org" + ldapbinddn "cn=admin,dc=example,dc=org" + ldapbindpasswd "admin" + ldapsearchfilter "(memberOf=cn=localhost,ou=groups,dc=example,dc=org)" + ldapsearchattribute "gecos" + ldapserver "192.168.233.16" + ldapport 389 +} +database default { + user default { + authentication "clear_text" + storage "test_server" + + ldap_endpoint_name "ldap1" + ldap_storage_credentials_attr "memberof" + ldap_storage_credentials "group_ro" { + ldap_storage_username "ldap_ro" + ldap_storage_password "password1" + } + ldap_storage_credentials "group_rw" { + ldap_storage_username "ldap_rw" + ldap_storage_password "password2 + } + + #other required regular parameters are hidden from this example + } +} +``` +To successfully route client to PostgreSQL server with correct credentials, client account attributes +stored on LDAP server must contain three required values separated by `_` character: +hostname of PostgreSQL server (`host` value from `storage` section), name of target `database`, +and name of `ldap_storage_credentials` in format `%host_%database_%ldap_storage_credentials` +For example, look at `memberof` attributes in [usr4.ldiff](https://github.com/yandex/odyssey/tree/master/docker/ldap): +``` +dn: uid=user4,dc=example,dc=org +objectClass: top +objectClass: account +objectClass: posixAccount +objectClass: shadowAccount +cn: user4 +uid: user4 +memberof: cn=localhost,ou=groups,dc=example,dc=org +memberof: cn=localhost_ldap_db1_group_ro,ou=groups,dc=example,dc=org +memberof: cn=localhost_ldap_db2_group_rw,ou=groups,dc=example,dc=org +uidNumber: 16860 +gidNumber: 101 +homeDirectory: /home/user4 +loginShell: /bin/bash +gecos: user4 +userPassword: default +shadowLastChange: 0 +shadowMax: 0 +shadowWarning: 0 +``` + +#### ldap_storage_credentials_attr *string* + +Sets the value of the account attribute name from the LDAP server, the values +of which will be used to determine the route and parameters for connecting the client to the PostgreSQL server. + +#### ldap_endpoint_name *string* + +Specifies the name of ldap_endpoint to be used to connect to the LDAP server. + +#### ldap_endpoint + +The ldap_endpoint section is used to configure the parameters for connecting to the LDAP server. For example: + +``` +ldap_endpoint "ldap1" { + ldapscheme "ldap" + ldapbasedn "dc=example,dc=org" + ldapbinddn "cn=admin,dc=example,dc=org" + ldapbindpasswd "admin" + ldapsearchattribute "gecos" + ldapserver "192.168.233.16" + ldapport 389 +} #### password\_passthrough *bool* diff --git a/sources/auth.c b/sources/auth.c index 8bcacd48..ec504229 100644 --- a/sources/auth.c +++ b/sources/auth.c @@ -740,7 +740,12 @@ static inline int od_auth_backend_cleartext(od_server_t *server, route->rule->db_name, route->rule->user_name); return -1; } - +#ifdef LDAP_FOUND + if (client->rule->ldap_storage_credentials_attr) { + password = client->ldap_storage_password; + password_len = client->ldap_storage_password_len; + } +#endif /* PasswordMessage */ machine_msg_t *msg; msg = kiwi_fe_write_password(NULL, password, password_len + 1); @@ -802,7 +807,14 @@ static inline int od_auth_backend_md5(od_server_t *server, char salt[4], route->rule->db_name, route->rule->user_name); return -1; } - +#ifdef LDAP_FOUND + if (client->rule->ldap_storage_credentials_attr) { + user = client->ldap_storage_username; + user_len = client->ldap_storage_username_len; + password = client->ldap_storage_password; + password_len = client->ldap_storage_password_len; + } +#endif /* prepare md5 password using server supplied salt */ kiwi_password_t client_password; kiwi_password_init(&client_password); @@ -935,7 +947,11 @@ static inline int od_auth_backend_sasl_continue(od_server_t *server, return -1; } - +#ifdef LDAP_FOUND + if (client->rule->ldap_storage_credentials_attr) { + password = client->ldap_storage_password; + } +#endif od_debug(&instance->logger, "auth", NULL, server, "continue SASL authentication"); diff --git a/sources/client.h b/sources/client.h index e54b7187..4f6df39d 100644 --- a/sources/client.h +++ b/sources/client.h @@ -63,6 +63,15 @@ struct od_client { od_global_t *global; od_list_t link_pool; od_list_t link; + + /* storage_user & storage_password provided by ldapsearch result */ +#ifdef LDAP_FOUND + char *ldap_storage_username; + int ldap_storage_username_len; + char *ldap_storage_password; + int ldap_storage_password_len; + char *ldap_auth_dn; +#endif }; static const size_t OD_CLIENT_DEFAULT_HASHMAP_SZ = 420; @@ -92,6 +101,13 @@ static inline void od_client_init(od_client_t *client) client->time_setup = 0; client->notify_io = NULL; client->ctl.op = OD_CLIENT_OP_NONE; +#ifdef LDAP_FOUND + client->ldap_storage_username = NULL; + client->ldap_storage_username_len = 0; + client->ldap_storage_password = NULL; + client->ldap_storage_password_len = 0; + client->ldap_auth_dn = NULL; +#endif kiwi_be_startup_init(&client->startup); kiwi_vars_init(&client->vars); diff --git a/sources/config_reader.c b/sources/config_reader.c index e1475c3b..aacd2071 100644 --- a/sources/config_reader.c +++ b/sources/config_reader.c @@ -128,6 +128,10 @@ typedef enum { OD_LLDAP_SCOPE, OD_LLDAP_SEARCH_FILTER, OD_LLDAP_ENDPOINT_NAME, + OD_LLDAP_STORAGE_CREDENTIALS_ATTR, + OD_LLDAP_STORAGE_CREDENTIALS, + OD_LLDAP_STORAGE_USERNAME, + OD_LLDAP_STORAGE_PASSWORD, OD_LWATCHDOG, OD_LWATCHDOG_LAG_QUERY, OD_LWATCHDOG_LAG_INTERVAL, @@ -279,6 +283,11 @@ static od_keyword_t od_config_keywords[] = { od_keyword("ldapsearchfilter", OD_LLDAP_SEARCH_FILTER), od_keyword("ldapscope", OD_LLDAP_SCOPE), od_keyword("ldap_endpoint_name", OD_LLDAP_ENDPOINT_NAME), + od_keyword("ldap_storage_credentials_attr", + OD_LLDAP_STORAGE_CREDENTIALS_ATTR), + od_keyword("ldap_storage_credentials", OD_LLDAP_STORAGE_CREDENTIALS), + od_keyword("ldap_storage_username", OD_LLDAP_STORAGE_USERNAME), + od_keyword("ldap_storage_password", OD_LLDAP_STORAGE_PASSWORD), /* watchdog */ @@ -841,6 +850,124 @@ static inline int od_config_reader_pgoptions(od_config_reader_t *reader, } } +#ifdef LDAP_FOUND + +static inline od_retcode_t +od_config_reader_ldap_storage_credentials(od_config_reader_t *reader, + od_rule_t *rule) +{ + od_ldap_storage_credentials_t *lsc_current; + lsc_current = od_ldap_storage_credentials_alloc(); + if (!lsc_current) { + goto error; + } + + /* name */ + if (!od_config_reader_string(reader, &lsc_current->name)) { + goto error; + } + + if (strlen(lsc_current->name) == 0) { + od_config_reader_error( + reader, NULL, + "empty ldap storage credentials definition"); + goto error; + } + + if (od_ldap_storage_credentials_find(&rule->ldap_storage_creds_list, + lsc_current->name) != NULL) { + od_config_reader_error( + reader, NULL, + "duplicate ldap storage credentials definition: %s", + lsc_current->name); + goto error; + } + + od_rule_ldap_storage_credentials_add(rule, lsc_current); + + /* { */ + if (!od_config_reader_symbol(reader, '{')) { + goto error; + } + + for (;;) { + od_token_t token; + int rc; + rc = od_parser_next(&reader->parser, &token); + switch (rc) { + case OD_PARSER_SYMBOL: + /* } */ + if (token.value.num == '}') { + if (lsc_current->lsc_username == NULL) { + od_config_reader_error( + reader, NULL, + "lsc_username in ldap_storage_credentials '%s' is not defined", + lsc_current->name); + goto error; + } + if (lsc_current->lsc_password == NULL) { + od_config_reader_error( + reader, NULL, + "lsc_password in ldap_storage_credentials '%s' is not defined", + lsc_current->name); + goto error; + } + return OK_RESPONSE; + } + /* fall through */ + case OD_PARSER_KEYWORD: + break; + default: + od_config_reader_error(reader, &token, + "unexpected symbol or token"); + goto error; + } + od_keyword_t *keyword; + keyword = od_keyword_match(od_config_keywords, &token); + if (keyword == NULL) { + od_config_reader_error(reader, &token, + "unknown parameter"); + return NOT_OK_RESPONSE; + } + + switch (keyword->id) { + case OD_LLDAP_STORAGE_USERNAME: { + if (!od_config_reader_string( + reader, &lsc_current->lsc_username)) + goto error; + if (strlen(lsc_current->lsc_username) == 0) { + od_config_reader_error( + reader, &token, + "lsc_username in ldap_storage_credentials '%s' cannot be empty", + lsc_current->name); + goto error; + } + + } break; + case OD_LLDAP_STORAGE_PASSWORD: { + if (!od_config_reader_string( + reader, &lsc_current->lsc_password)) + goto error; + if (strlen(lsc_current->lsc_password) == 0) { + od_config_reader_error( + reader, &token, + "lsc_password in ldap_storage_credentials '%s' cannot be empty", + lsc_current->name); + goto error; + } + } break; + } + } + + return OK_RESPONSE; +error: + if (lsc_current) { + od_ldap_storage_credentials_free(lsc_current); + } + return NOT_OK_RESPONSE; +} +#endif + static int od_config_reader_rule_settings(od_config_reader_t *reader, od_rule_t *rule, od_extention_t *extentions, @@ -1189,6 +1316,56 @@ static int od_config_reader_rule_settings(od_config_reader_t *reader, reader, NULL, "ldap is not supported, check if ldap library is available on the system"); return NOT_OK_RESPONSE; +#endif + } + case OD_LLDAP_STORAGE_CREDENTIALS_ATTR: { +#ifdef LDAP_FOUND + if (!od_config_reader_string( + reader, + &rule->ldap_storage_credentials_attr)) { + return NOT_OK_RESPONSE; + } + if (rule->ldap_endpoint_name == NULL) { + od_config_reader_error( + reader, NULL, + "ldap_endpoint_name is not defined for rule with ldap_storage_credentials_attr '%s'", + rule->ldap_storage_credentials_attr); + return NOT_OK_RESPONSE; + } + if (strlen(rule->ldap_storage_credentials_attr) == 0) { + od_config_reader_error( + reader, NULL, + "ldap_storage_credentials_attr cannot be empty for rule with ldap_endpoint_name '%s'", + rule->ldap_endpoint_name); + return NOT_OK_RESPONSE; + } + continue; +#else + od_config_reader_error( + reader, NULL, + "ldap is not supported, check if ldap library is available on the system"); + return NOT_OK_RESPONSE; +#endif + } + case OD_LLDAP_STORAGE_CREDENTIALS: { +#ifdef LDAP_FOUND + if (od_config_reader_ldap_storage_credentials( + reader, rule) != OK_RESPONSE) { + return NOT_OK_RESPONSE; + } + if (rule->ldap_storage_credentials_attr == NULL) { + od_config_reader_error( + reader, NULL, + "ldap_storage_credentials_attr is not defined for rule with ldap_endpoint_name '%s'", + rule->ldap_endpoint_name); + return NOT_OK_RESPONSE; + } + continue; +#else + od_config_reader_error( + reader, NULL, + "ldap is not supported, check if ldap library is available on the system"); + return NOT_OK_RESPONSE; #endif } case OD_LWATCHDOG_LAG_QUERY: diff --git a/sources/console.c b/sources/console.c index 2f70eeee..65e4234f 100644 --- a/sources/console.c +++ b/sources/console.c @@ -1253,6 +1253,12 @@ static inline int od_console_show_clients_callback(od_client_t *client, else if (client->state == OD_CLIENT_QUEUE) state = "queue"; rc = kiwi_be_write_data_row_add(stream, offset, state, strlen(state)); + if (rc == NOT_OK_RESPONSE) + return NOT_OK_RESPONSE; + /* storage_user */ + rc = kiwi_be_write_data_row_add(stream, offset, + client->rule->storage_user, + client->rule->storage_user_len); if (rc == NOT_OK_RESPONSE) return NOT_OK_RESPONSE; /* addr */ @@ -1348,10 +1354,10 @@ static inline int od_console_show_clients(od_client_t *client, machine_msg_t *msg; msg = kiwi_be_write_row_descriptionf( - stream, "sssssdsdssddssds", "type", "user", "database", "state", - "addr", "port", "local_addr", "local_port", "connect_time", - "request_time", "wait", "wait_us", "ptr", "link", "remote_pid", - "tls"); + stream, "ssssssdsdssddssds", "type", "user", "database", + "state", "storage_user", "addr", "port", "local_addr", + "local_port", "connect_time", "request_time", "wait", "wait_us", + "ptr", "link", "remote_pid", "tls"); if (msg == NULL) return NOT_OK_RESPONSE; diff --git a/sources/frontend.c b/sources/frontend.c index cb5affa6..18807e52 100644 --- a/sources/frontend.c +++ b/sources/frontend.c @@ -2058,6 +2058,17 @@ void od_frontend(void *arg) od_frontend_error(client, KIWI_SYSTEM_ERROR, "client routing failed"); break; + case OD_ROUTER_INSUFFICIENT_ACCESS: + // disabling blind ldapsearch via odyssey error messages + // to collect user account attributes + od_error( + &instance->logger, "startup", client, NULL, + "route for '%s.%s' is not found by ldapsearch for '%s' client, closing", + client->startup.database.value, + client->startup.user.value, peer); + od_frontend_error(client, KIWI_SYNTAX_ERROR, + "incorrect password"); + break; case OD_ROUTER_ERROR_NOT_FOUND: od_error( &instance->logger, "startup", client, NULL, diff --git a/sources/ldap.c b/sources/ldap.c index 7581afcb..4064e193 100644 --- a/sources/ldap.c +++ b/sources/ldap.c @@ -8,8 +8,6 @@ #include #include -#define USE_POOL - od_retcode_t od_ldap_server_free(od_ldap_server_t *serv) { od_list_unlink(&serv->link); @@ -18,9 +16,6 @@ od_retcode_t od_ldap_server_free(od_ldap_server_t *serv) ldap_unbind(serv->conn); } - if (serv->auth_user) { - free(serv->auth_user); - } free(serv); return OK_RESPONSE; } @@ -34,6 +29,12 @@ static inline od_retcode_t od_ldap_error_report_client(od_client_t *cl, int rc) return OK_RESPONSE; case LDAP_INVALID_CREDENTIALS: return NOT_OK_RESPONSE; + case LDAP_INSUFFICIENT_ACCESS: { + // disabling blind ldapsearch via odyssey error messages + // to collect user account attributes + od_frontend_error(cl, KIWI_SYNTAX_ERROR, "incorrect password"); + return NOT_OK_RESPONSE; + } case LDAP_UNAVAILABLE: case LDAP_UNWILLING_TO_PERFORM: case LDAP_BUSY: { @@ -104,9 +105,61 @@ od_retcode_t od_ldap_endpoint_prepare(od_ldap_endpoint_t *le) return OK_RESPONSE; } -static inline od_retcode_t od_ldap_server_prepare(od_logger_t *logger, - od_ldap_server_t *serv, - od_client_t *client) +od_retcode_t +od_ldap_change_storage_credentials(od_logger_t *logger, + od_ldap_storage_credentials_t *lsc, + od_client_t *client) +{ + client->ldap_storage_username = lsc->lsc_username; + client->ldap_storage_username_len = strlen(lsc->lsc_username); + client->ldap_storage_password = lsc->lsc_password; + client->ldap_storage_password_len = strlen(lsc->lsc_password); + od_debug(logger, "auth_ldap", client, NULL, + "storage_user changed to %s", lsc->lsc_username); + return OK_RESPONSE; +} + +od_retcode_t od_ldap_search_storage_credentials(od_logger_t *logger, + struct berval **values, + od_rule_t *rule, + od_client_t *client) +{ + int i; + for (i = 0; i < ldap_count_values_len(values); i++) { + char host_db[128]; + od_snprintf(host_db, sizeof(host_db), "%s_%s", + rule->storage->host, + client->startup.database.value); + if (strstr((char *)values[i]->bv_val, host_db)) { + od_list_t *j; + od_list_foreach(&rule->ldap_storage_creds_list, j) + { + od_ldap_storage_credentials_t *lsc = NULL; + lsc = od_container_of( + j, od_ldap_storage_credentials_t, link); + char host_db_user[128]; + od_snprintf(host_db_user, sizeof(host_db_user), + "%s_%s", host_db, lsc->name); + + if (strstr((char *)values[i]->bv_val, + host_db_user)) { + od_debug(logger, "auth_ldap", client, + NULL, "matched group %s", + (char *)values[i]->bv_val); + od_ldap_change_storage_credentials( + logger, lsc, client); + return OK_RESPONSE; + } + } + } + } + od_debug(logger, "auth_ldap", client, NULL, + "error: route does not match any user attribute"); + return NOT_OK_RESPONSE; +} + +od_retcode_t od_ldap_server_prepare(od_logger_t *logger, od_ldap_server_t *serv, + od_rule_t *rule, od_client_t *client) { od_retcode_t rc; char *auth_user = NULL; @@ -120,20 +173,8 @@ static inline od_retcode_t od_ldap_server_prepare(od_logger_t *logger, char *dn; int count; - rc = ldap_simple_bind_s(serv->conn, - serv->endpoint->ldapbinddn ? - serv->endpoint->ldapbinddn : - "", - serv->endpoint->ldapbindpasswd ? - serv->endpoint->ldapbindpasswd : - ""); - - od_debug(logger, "auth_ldap", NULL, NULL, - "basednn simple bind result: %d", rc); - - if (rc != LDAP_SUCCESS) { - return NOT_OK_RESPONSE; - } + if (rule->ldap_storage_credentials_attr) + attributes[0] = rule->ldap_storage_credentials_attr; if (serv->endpoint->ldapsearchattribute) { od_asprintf(&filter, "(%s=%s)", @@ -166,7 +207,9 @@ static inline od_retcode_t od_ldap_server_prepare(od_logger_t *logger, "basedn search entries count: %d", count); if (count != 1) { if (count == 0) { - // TODO: report err 2 client + free(filter); + ldap_msgfree(search_message); + return LDAP_INSUFFICIENT_ACCESS; } else { } @@ -182,6 +225,31 @@ static inline od_retcode_t od_ldap_server_prepare(od_logger_t *logger, return NOT_OK_RESPONSE; } + if (rule->ldap_storage_credentials_attr) { + struct berval **values = NULL; + values = ldap_get_values_len(serv->conn, entry, + attributes[0]); + if (ldap_count_values_len(values) > 0) { + rc = od_ldap_search_storage_credentials( + logger, values, rule, client); + if (rc != OK_RESPONSE) { + free(filter); + ldap_memfree(dn); + ldap_value_free_len(values); + ldap_msgfree(search_message); + return LDAP_INSUFFICIENT_ACCESS; + } + } else { + od_debug(logger, "auth_ldap", client, NULL, + "error: empty search results"); + free(filter); + ldap_memfree(dn); + ldap_value_free_len(values); + ldap_msgfree(search_message); + return LDAP_INSUFFICIENT_ACCESS; + } + ldap_value_free_len(values); + } auth_user = strdup(dn); free(filter); @@ -199,7 +267,7 @@ static inline od_retcode_t od_ldap_server_prepare(od_logger_t *logger, ""); } - serv->auth_user = auth_user; + client->ldap_auth_dn = auth_user; return OK_RESPONSE; } @@ -209,40 +277,45 @@ od_ldap_server_t *od_ldap_server_allocate() od_ldap_server_t *serv = malloc(sizeof(od_ldap_server_t)); serv->conn = NULL; serv->endpoint = NULL; - serv->auth_user = NULL; return serv; } -static inline od_retcode_t od_ldap_server_init(od_logger_t *logger, - od_ldap_server_t *server, - od_route_t *route, - od_client_t *client) +od_retcode_t od_ldap_server_init(od_logger_t *logger, od_ldap_server_t *server, + od_rule_t *rule) { + od_retcode_t rc; od_id_generate(&server->id, "ls"); od_list_init(&server->link); server->global = NULL; - server->route = route; - od_ldap_endpoint_t *le = route->rule->ldap_endpoint; + od_ldap_endpoint_t *le = rule->ldap_endpoint; server->endpoint = le; if (od_init_ldap_conn(&server->conn, le->ldapurl) != OK_RESPONSE) { return NOT_OK_RESPONSE; } - if (od_ldap_server_prepare(logger, server, client) != OK_RESPONSE) { - return NOT_OK_RESPONSE; - } - return OK_RESPONSE; + rc = ldap_simple_bind_s(server->conn, + server->endpoint->ldapbinddn ? + server->endpoint->ldapbinddn : + "", + server->endpoint->ldapbindpasswd ? + server->endpoint->ldapbindpasswd : + ""); + + od_debug(logger, "auth_ldap", NULL, NULL, + "basednn simple bind result: %d", rc); + + return rc; } static inline int od_ldap_server_auth(od_ldap_server_t *serv, od_client_t *cl, kiwi_password_t *tok) { int rc; - rc = ldap_simple_bind_s(serv->conn, serv->auth_user, tok->password); + rc = ldap_simple_bind_s(serv->conn, cl->ldap_auth_dn, tok->password); od_route_t *route = cl->route; if (route->rule->client_fwd_error) { @@ -252,41 +325,51 @@ static inline int od_ldap_server_auth(od_ldap_server_t *serv, od_client_t *cl, return rc; } -static inline od_ldap_server_t *od_ldap_server_attach(od_route_t *route, - od_client_t *client, - bool wait_for_idle) +od_ldap_server_t *od_ldap_server_pull(od_logger_t *logger, od_rule_t *rule, + bool auth_pool) { - assert(route != NULL); - od_instance_t *instance = client->global->instance; - od_logger_t *logger = &instance->logger; - - od_ldap_server_t *server = NULL; - od_route_lock(route); - -#ifdef USE_POOL od_retcode_t rc; + od_ldap_endpoint_t *le = rule->ldap_endpoint; + od_ldap_server_t *ldap_server = NULL; + + od_server_pool_t *ldap_server_pool; + if (auth_pool) { + ldap_server_pool = le->ldap_auth_pool; + } else { + ldap_server_pool = le->ldap_search_pool; + } + + od_debug(logger, "auth_ldap", NULL, NULL, + "total connections in selected pool: %d", + od_server_pool_total(ldap_server_pool)); + od_ldap_endpoint_lock(le); /* get client server from route server pool */ for (;;) { - server = od_ldap_server_pool_next(&route->ldap_pool, - OD_SERVER_IDLE); - if (server) { + ldap_server = od_ldap_server_pool_next(ldap_server_pool, + OD_SERVER_IDLE); + if (ldap_server) { + od_debug(logger, "auth_ldap", NULL, NULL, + "pulling ldap_server from ldap_pool"); + od_ldap_server_pool_set(ldap_server_pool, ldap_server, + OD_SERVER_ACTIVE); + od_ldap_endpoint_unlock(le); break; } - if (wait_for_idle) { + if (false) { /* special case, when we are interested only in an idle connection * and do not want to start a new one */ // NOT IMPL - od_route_unlock(route); + od_ldap_endpoint_unlock(le); return NULL; } else { /* Maybe start new connection, if pool_size is zero */ /* Maybe start new connection, if we still have capacity for it */ int connections_in_pool = - od_server_pool_total(&route->ldap_pool); - int pool_size = route->rule->ldap_pool_size; + od_server_pool_total(ldap_server_pool); + int pool_size = rule->ldap_pool_size; if (pool_size == 0 || connections_in_pool < pool_size) { // TODO: better limit logic here @@ -294,7 +377,7 @@ static inline od_ldap_server_t *od_ldap_server_attach(od_route_t *route, od_debug( logger, "auth_ldap", NULL, NULL, "spun new connection to ldap server %s", - route->rule->ldap_endpoint_name); + rule->ldap_endpoint_name); break; } } @@ -305,63 +388,106 @@ static inline od_ldap_server_t *od_ldap_server_attach(od_route_t *route, * The condition triggered when a server connection * put into idle state by DETACH events. */ - od_route_unlock(route); + od_ldap_endpoint_unlock(le); - uint32_t timeout = route->rule->ldap_pool_timeout; + uint32_t timeout = rule->ldap_pool_timeout; if (timeout == 0) timeout = UINT32_MAX; - rc = od_route_wait(route, timeout); + rc = od_ldap_endpoint_wait(le, timeout); if (rc == -1) { + od_ldap_endpoint_unlock(le); return NULL; } - od_route_lock(route); + od_ldap_endpoint_lock(le); } -#endif - - if (server == NULL) { - od_route_unlock(route); + if (ldap_server == NULL) { /* create new server object */ - server = od_ldap_server_allocate(); + ldap_server = od_ldap_server_allocate(); - int ldap_rc = - od_ldap_server_init(logger, server, route, client); - - od_route_lock(route); - od_ldap_server_pool_set(&route->ldap_pool, server, - OD_SERVER_UNDEF); - od_route_unlock(route); + int ldap_rc = od_ldap_server_init(logger, ldap_server, rule); if (ldap_rc != LDAP_SUCCESS) { - if (route->rule->client_fwd_error) { - od_ldap_error_report_client(client, ldap_rc); - } - od_ldap_server_free(server); + od_ldap_server_free(ldap_server); + od_ldap_endpoint_unlock(le); return NULL; } - od_route_lock(route); + od_ldap_server_pool_set(ldap_server_pool, ldap_server, + OD_SERVER_ACTIVE); + od_ldap_endpoint_unlock(le); } - od_ldap_server_pool_set(&route->ldap_pool, server, OD_SERVER_ACTIVE); + return ldap_server; +} - od_route_unlock(route); +static inline od_retcode_t od_ldap_server_attach(od_client_t *client) +{ + od_instance_t *instance = client->global->instance; + od_logger_t *logger = &instance->logger; - return server; + od_retcode_t rc; + + /* get client server from route server pool */ + od_ldap_server_t *server = + od_ldap_server_pull(logger, client->rule, false); + + if (server == NULL) { + od_debug(&instance->logger, "auth_ldap", client, NULL, + "failed to get ldap connection"); + if (client->rule->client_fwd_error) { + od_ldap_error_report_client(client, NOT_OK_RESPONSE); + } + return NOT_OK_RESPONSE; + } + + od_ldap_endpoint_lock(client->rule->ldap_endpoint); + + rc = od_ldap_server_prepare(logger, server, client->rule, client); + if (rc == NOT_OK_RESPONSE) { + od_debug(&instance->logger, "auth_ldap", client, NULL, + "closing bad ldap connection, need relogin"); + od_ldap_server_pool_set( + client->rule->ldap_endpoint->ldap_search_pool, server, + OD_SERVER_UNDEF); + od_ldap_server_free(server); + } else { + od_ldap_server_pool_set( + client->rule->ldap_endpoint->ldap_search_pool, server, + OD_SERVER_IDLE); + } + + od_ldap_endpoint_unlock(client->rule->ldap_endpoint); + if (rc != OK_RESPONSE) { + if (client->rule->client_fwd_error) { + od_ldap_error_report_client(client, rc); + } + return NOT_OK_RESPONSE; + } + return OK_RESPONSE; } od_retcode_t od_auth_ldap(od_client_t *cl, kiwi_password_t *tok) { - od_route_t *route = cl->route; od_instance_t *instance = cl->global->instance; + od_retcode_t rc; - od_debug(&instance->logger, "auth_ldap", cl, NULL, - "%d connections are currently issued to ldap", - od_server_pool_active(&route->ldap_pool)); + if (cl->rule->ldap_storage_credentials_attr && + cl->rule->ldap_endpoint_name) { + rc = OK_RESPONSE; + } else { + rc = od_ldap_server_attach(cl); + } + + if (rc != OK_RESPONSE) { + return rc; + } + + od_ldap_server_t *serv = + od_ldap_server_pull(&instance->logger, cl->rule, true); - od_ldap_server_t *serv = od_ldap_server_attach(route, cl, false); if (serv == NULL) { od_debug(&instance->logger, "auth_ldap", cl, NULL, "failed to get ldap connection"); @@ -370,41 +496,36 @@ od_retcode_t od_auth_ldap(od_client_t *cl, kiwi_password_t *tok) int ldap_rc = od_ldap_server_auth(serv, cl, tok); + od_ldap_endpoint_lock(cl->rule->ldap_endpoint); + switch (ldap_rc) { case LDAP_SUCCESS: { -#ifndef USE_POOL - od_ldap_conn_close(route, serv); -#else - od_route_lock(route); - od_ldap_server_pool_set(&route->ldap_pool, serv, - OD_SERVER_IDLE); - od_route_unlock(route); -#endif - return OK_RESPONSE; + od_ldap_server_pool_set(cl->rule->ldap_endpoint->ldap_auth_pool, + serv, OD_SERVER_IDLE); + rc = OK_RESPONSE; + break; } case LDAP_INVALID_SYNTAX: - case LDAP_INVALID_CREDENTIALS: -#ifndef USE_POOL - od_ldap_conn_close(route, serv); -#else - od_route_lock(route); - od_ldap_server_pool_set(&route->ldap_pool, serv, - OD_SERVER_IDLE); - od_route_unlock(route); -#endif - return NOT_OK_RESPONSE; - default: -#ifndef USE_POOL - od_ldap_conn_close(route, serv); -#else - od_route_lock(route); - /*Need to rebind */ - od_ldap_server_pool_set(&route->ldap_pool, serv, - OD_SERVER_UNDEF); - od_route_unlock(route); -#endif - return NOT_OK_RESPONSE; + /* fallthrough */ + case LDAP_INVALID_CREDENTIALS: { + od_ldap_server_pool_set(cl->rule->ldap_endpoint->ldap_auth_pool, + serv, OD_SERVER_IDLE); + rc = NOT_OK_RESPONSE; + break; } + default: { + /*Need to rebind */ + od_ldap_server_pool_set(cl->rule->ldap_endpoint->ldap_auth_pool, + serv, OD_SERVER_UNDEF); + od_ldap_server_free(serv); + rc = NOT_OK_RESPONSE; + break; + } + } + + od_ldap_endpoint_unlock(cl->rule->ldap_endpoint); + + return rc; } od_retcode_t od_ldap_conn_close(od_attribute_unused() od_route_t *route, @@ -445,6 +566,21 @@ od_ldap_endpoint_t *od_ldap_endpoint_alloc() // preparsed connect url le->ldapurl = NULL; + od_server_pool_t *ldap_auth_pool = malloc(sizeof(*ldap_auth_pool)); + od_server_pool_init(ldap_auth_pool); + le->ldap_auth_pool = ldap_auth_pool; + + od_server_pool_t *ldap_search_pool = malloc(sizeof(*ldap_search_pool)); + od_server_pool_init(ldap_search_pool); + le->ldap_search_pool = ldap_search_pool; + + le->wait_bus = machine_channel_create(); + if (le->wait_bus == NULL) { + od_ldap_endpoint_free(le); + return NULL; + } + + pthread_mutex_init(&le->lock, NULL); return le; } @@ -488,12 +624,62 @@ od_retcode_t od_ldap_endpoint_free(od_ldap_endpoint_t *le) } od_list_unlink(&le->link); + if (le->ldap_search_pool) { + od_ldap_server_pool_free(le->ldap_search_pool); + } + + if (le->ldap_auth_pool) { + od_ldap_server_pool_free(le->ldap_search_pool); + } + + pthread_mutex_destroy(&le->lock); + if (le->wait_bus) + machine_channel_free(le->wait_bus); free(le); return OK_RESPONSE; } +od_ldap_storage_credentials_t *od_ldap_storage_credentials_alloc() +{ + od_ldap_storage_credentials_t *lsc = + malloc(sizeof(od_ldap_storage_credentials_t)); + if (lsc == NULL) { + return NULL; + } + od_list_init(&lsc->link); + + lsc->name = NULL; + + lsc->lsc_username = NULL; + lsc->lsc_password = NULL; + + return lsc; +} + +od_retcode_t +od_ldap_storage_credentials_free(od_ldap_storage_credentials_t *lsc) +{ + if (lsc->name) { + free(lsc->name); + } + + if (lsc->lsc_username) { + free(lsc->lsc_username); + } + + if (lsc->lsc_password) { + free(lsc->lsc_password); + } + + od_list_unlink(&lsc->link); + + free(lsc); + + return OK_RESPONSE; +} + od_retcode_t od_ldap_endpoint_add(od_ldap_endpoint_t *ldaps, od_ldap_endpoint_t *target) { @@ -549,3 +735,21 @@ od_retcode_t od_ldap_endpoint_remove(od_ldap_endpoint_t *ldaps, /* target ldap server was not found */ return NOT_OK_RESPONSE; } + +od_ldap_storage_credentials_t * +od_ldap_storage_credentials_find(od_list_t *ldap_storage_creds_list, char *name) +{ + od_list_t *i; + + od_list_foreach(ldap_storage_creds_list, i) + { + od_ldap_storage_credentials_t *lsc = + od_container_of(i, od_ldap_storage_credentials_t, link); + if (strcmp(lsc->name, name) == 0) { + return lsc; + } + } + + /* target storage user was not found */ + return NULL; +} diff --git a/sources/ldap_endpoint.h b/sources/ldap_endpoint.h index ca0a1025..06cddff0 100644 --- a/sources/ldap_endpoint.h +++ b/sources/ldap_endpoint.h @@ -3,6 +3,7 @@ #define OD_ODYSSEY_LDAP_ENDPOINT_H typedef struct { + pthread_mutex_t lock; char *name; char *ldapserver; @@ -23,6 +24,11 @@ typedef struct { // preparsed connect url char *ldapurl; + void *ldap_search_pool; + void *ldap_auth_pool; + + machine_channel_t *wait_bus; + od_list_t link; } od_ldap_endpoint_t; @@ -42,5 +48,54 @@ extern od_retcode_t od_ldap_endpoint_remove(od_ldap_endpoint_t *ldaps, extern od_ldap_endpoint_t *od_ldap_endpoint_alloc(); extern od_retcode_t od_ldap_endpoint_init(od_ldap_endpoint_t *); extern od_retcode_t od_ldap_endpoint_free(od_ldap_endpoint_t *le); +/* ldap_storage_credentials */ +typedef struct { + char *name; + char *lsc_username; + char *lsc_password; + + od_list_t link; +} od_ldap_storage_credentials_t; + +static inline void od_ldap_endpoint_lock(od_ldap_endpoint_t *le) +{ + pthread_mutex_lock(&le->lock); +} + +static inline void od_ldap_endpoint_unlock(od_ldap_endpoint_t *le) +{ + pthread_mutex_unlock(&le->lock); +} + +static inline int od_ldap_endpoint_wait(od_ldap_endpoint_t *le, + uint32_t time_ms) +{ + machine_msg_t *msg; + msg = machine_channel_read(le->wait_bus, time_ms); + if (msg) { + machine_msg_free(msg); + return 0; + } + return -1; +} + +static inline int od_ldap_endpoint_signal(od_ldap_endpoint_t *le) +{ + machine_msg_t *msg; + msg = machine_msg_create(0); + if (msg == NULL) { + return -1; + } + machine_channel_write(le->wait_bus, msg); + return 0; +} + +extern od_ldap_storage_credentials_t * +od_ldap_storage_credentials_find(od_list_t *storage_users, char *target); + +// ------------------------------------------------------- +extern od_ldap_storage_credentials_t *od_ldap_storage_credentials_alloc(); +extern od_retcode_t +od_ldap_storage_credentials_free(od_ldap_storage_credentials_t *lsc); #endif /* OD_ODYSSEY_LDAP_ENDPOINT_H */ diff --git a/sources/od_ldap.h b/sources/od_ldap.h index 34e244e7..69b50bbf 100644 --- a/sources/od_ldap.h +++ b/sources/od_ldap.h @@ -14,8 +14,6 @@ typedef struct { od_global_t *global; void *route; - char *auth_user; - od_list_t link; } od_ldap_server_t; @@ -23,5 +21,13 @@ extern od_retcode_t od_auth_ldap(od_client_t *cl, kiwi_password_t *tok); extern od_retcode_t od_ldap_server_free(od_ldap_server_t *serv); extern od_ldap_server_t *od_ldap_server_allocate(); - +extern od_retcode_t od_ldap_server_init(od_logger_t *logger, + od_ldap_server_t *serv, + od_rule_t *rule); +extern od_retcode_t od_ldap_server_prepare(od_logger_t *logger, + od_ldap_server_t *serv, + od_rule_t *rule, + od_client_t *client); +extern od_ldap_server_t *od_ldap_server_pull(od_logger_t *logger, + od_rule_t *rule, bool auth_pool); #endif /* ODYSSEY_LDAP_H */ diff --git a/sources/route.h b/sources/route.h index 1786d9e1..fe029026 100644 --- a/sources/route.h +++ b/sources/route.h @@ -20,10 +20,6 @@ struct od_route { od_server_pool_t server_pool; od_client_pool_t client_pool; -#ifdef LDAP_FOUND - od_server_pool_t ldap_pool; -#endif - kiwi_params_lock_t params; int64_t tcp_connections; int last_heartbeat; @@ -45,10 +41,6 @@ static inline void od_route_init(od_route_t *route, bool extra_route_logging) od_route_id_init(&route->id); od_server_pool_init(&route->server_pool); -#ifdef LDAP_FOUND - od_server_pool_init(&route->ldap_pool); -#endif - od_client_pool_init(&route->client_pool); /* stat init */ @@ -73,9 +65,7 @@ static inline void od_route_free(od_route_t *route) { od_route_id_free(&route->id); od_pg_server_pool_free(&route->server_pool); -#ifdef LDAP_FOUND - od_ldap_server_pool_free(&route->ldap_pool); -#endif + kiwi_params_lock_free(&route->params); if (route->wait_bus) machine_channel_free(route->wait_bus); diff --git a/sources/router.c b/sources/router.c index eb452844..4ddc2eeb 100644 --- a/sources/router.c +++ b/sources/router.c @@ -354,7 +354,62 @@ od_router_status_t od_router_route(od_router_t *router, od_client_t *client) return OD_ROUTER_ERROR_REPLICATION; } } - +#ifdef LDAP_FOUND + if (rule->ldap_storage_credentials_attr) { + od_ldap_server_t *ldap_server = NULL; + ldap_server = + od_ldap_server_pull(&instance->logger, rule, false); + if (ldap_server == NULL) { + od_debug(&instance->logger, "routing", client, NULL, + "failed to get ldap connection"); + od_router_unlock(router); + return OD_ROUTER_ERROR_NOT_FOUND; + } + int ldap_rc = od_ldap_server_prepare(&instance->logger, + ldap_server, rule, client); + switch (ldap_rc) { + case OK_RESPONSE: { + od_ldap_endpoint_lock(rule->ldap_endpoint); + od_ldap_server_pool_set( + rule->ldap_endpoint->ldap_search_pool, + ldap_server, OD_SERVER_IDLE); + od_ldap_endpoint_unlock(rule->ldap_endpoint); + id.user = client->ldap_storage_username; + id.user_len = client->ldap_storage_username_len + 1; + rule->storage_user = client->ldap_storage_username; + rule->storage_user_len = + client->ldap_storage_username_len; + rule->storage_password = client->ldap_storage_password; + rule->storage_password_len = + client->ldap_storage_password_len; + od_debug(&instance->logger, "routing", client, NULL, + "route->id.user changed to %s", id.user); + break; + } + case LDAP_INSUFFICIENT_ACCESS: { + od_ldap_endpoint_lock(rule->ldap_endpoint); + od_ldap_server_pool_set( + rule->ldap_endpoint->ldap_search_pool, + ldap_server, OD_SERVER_IDLE); + od_ldap_endpoint_unlock(rule->ldap_endpoint); + od_router_unlock(router); + return OD_ROUTER_INSUFFICIENT_ACCESS; + } + default: { + od_debug(&instance->logger, "routing", client, NULL, + "closing bad ldap connection, need relogin"); + od_ldap_endpoint_lock(rule->ldap_endpoint); + od_ldap_server_pool_set( + rule->ldap_endpoint->ldap_search_pool, + ldap_server, OD_SERVER_UNDEF); + od_ldap_endpoint_unlock(rule->ldap_endpoint); + od_ldap_server_free(ldap_server); + od_router_unlock(router); + return OD_ROUTER_ERROR_NOT_FOUND; + } + } + } +#endif /* match or create dynamic route */ od_route_t *route; route = od_route_pool_match(&router->route_pool, &id, rule); diff --git a/sources/rules.c b/sources/rules.c index 526bba7f..0057c2f8 100644 --- a/sources/rules.c +++ b/sources/rules.c @@ -40,6 +40,14 @@ od_ldap_endpoint_t *od_rules_ldap_endpoint_add(od_rules_t *rules, od_list_append(&rules->ldap_endpoints, &ldap->link); return ldap; } + +od_ldap_storage_credentials_t * +od_rule_ldap_storage_credentials_add(od_rule_t *rule, + od_ldap_storage_credentials_t *lsc) +{ + od_list_append(&rule->ldap_storage_creds_list, &lsc->link); + return lsc; +} #endif od_rule_storage_t *od_rules_storage_add(od_rules_t *rules, @@ -148,6 +156,8 @@ od_rule_t *od_rules_add(od_rules_t *rules) #ifdef LDAP_FOUND rule->ldap_endpoint_name = NULL; rule->ldap_endpoint = NULL; + rule->ldap_storage_credentials_attr = NULL; + od_list_init(&rule->ldap_storage_creds_list); #endif kiwi_vars_init(&rule->vars); @@ -200,6 +210,23 @@ void od_rules_rule_free(od_rule_t *rule) } #ifdef PAM_FOUND od_pam_auth_data_free(rule->auth_pam_data); +#endif +#ifdef LDAP_FOUND + if (rule->ldap_endpoint_name) + free(rule->ldap_endpoint_name); + if (rule->ldap_storage_credentials_attr) + free(rule->ldap_storage_credentials_attr); + if (rule->ldap_endpoint) + od_ldap_endpoint_free(rule->ldap_endpoint); + if (&rule->ldap_storage_creds_list) { + od_list_foreach_safe(&rule->ldap_storage_creds_list, i, n) + { + od_ldap_storage_credentials_t *lsc; + lsc = od_container_of(i, od_ldap_storage_credentials_t, + link); + od_ldap_storage_credentials_free(lsc); + } + } #endif if (rule->auth_module) { free(rule->auth_module); @@ -1138,6 +1165,35 @@ void od_rules_print(od_rules_t *rules, od_logger_t *logger) " ldap_endpoint_name %s", rule->ldap_endpoint_name); } + if (rule->ldap_storage_credentials_attr != NULL) { + od_log(logger, "rules", NULL, NULL, + " ldap_storage_credentials_attr %s", + rule->ldap_storage_credentials_attr); + } + if (&rule->ldap_storage_creds_list) { + od_list_t *f; + od_list_foreach(&rule->ldap_storage_creds_list, f) + { + od_ldap_storage_credentials_t *lsc; + lsc = od_container_of( + f, od_ldap_storage_credentials_t, link); + if (lsc->name) { + od_log(logger, "rule", NULL, NULL, + " lsc_name %s", + lsc->name); + } + if (lsc->lsc_username) { + od_log(logger, "rule", NULL, NULL, + " lsc_username %s", + lsc->lsc_username); + } + if (lsc->lsc_password) { + od_log(logger, "rule", NULL, NULL, + " lsc_password %s", + lsc->lsc_password); + } + } + } #endif od_log(logger, "rules", NULL, NULL, " storage %s", diff --git a/sources/rules.h b/sources/rules.h index 4994dde6..e67a88f9 100644 --- a/sources/rules.h +++ b/sources/rules.h @@ -90,6 +90,8 @@ struct od_rule { od_ldap_endpoint_t *ldap_endpoint; int ldap_pool_timeout; int ldap_pool_size; + od_list_t ldap_storage_creds_list; + char *ldap_storage_credentials_attr; #endif char *auth_module; @@ -175,6 +177,9 @@ od_retcode_t od_rules_storages_watchdogs_run(od_logger_t *logger, /* ldap endpoint */ od_ldap_endpoint_t *od_rules_ldap_endpoint_add(od_rules_t *rules, od_ldap_endpoint_t *ldap); +od_ldap_storage_credentials_t * +od_rule_ldap_storage_credentials_add(od_rule_t *rule, + od_ldap_storage_credentials_t *lsc); #endif /* auth */ diff --git a/sources/status.h b/sources/status.h index 6f3785f6..6c63e29f 100644 --- a/sources/status.h +++ b/sources/status.h @@ -105,6 +105,7 @@ typedef enum { OD_ROUTER_ERROR_LIMIT_ROUTE, OD_ROUTER_ERROR_TIMEDOUT, OD_ROUTER_ERROR_REPLICATION, + OD_ROUTER_INSUFFICIENT_ACCESS, } od_router_status_t; static inline char *od_router_status_to_str(od_router_status_t status)