db-ldap.c revision d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76
c636315472e4f87313af7be30b7fbcad4b8ca8a4Stephen Gallagher/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher#if defined(BUILTIN_LDAP) || defined(PLUGIN_BUILD)
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce# define LDAP_SASL_QUIET 0 /* Doesn't exist in Solaris LDAP */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher/* Older versions may require calling ldap_result() twice */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher/* Solaris LDAP library doesn't have LDAP_OPT_SUCCESS */
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher const char *name, *value, *template, *val_1_arr[2];
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher const char *const *static_attrs;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#define DEF_STR(name) DEF_STRUCT_STR(name, ldap_settings)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#define DEF_INT(name) DEF_STRUCT_INT(name, ldap_settings)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, ldap_settings)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct ldap_settings default_ldap_settings = {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(user_attrs) "homeDirectory=home,uidNumber=uid,gidNumber=gid",
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher MEMBER(user_filter) "(&(objectClass=posixAccount)(uid=%u))",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(pass_attrs) "uid=user,userPassword=password",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MEMBER(pass_filter) "(&(objectClass=posixAccount)(uid=%u))",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct ldap_connection *ldap_connections = NULL;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int db_ldap_bind(struct ldap_connection *conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void db_ldap_conn_close(struct ldap_connection *conn);
c7919a4fe41133cc466aa3d9431bfceee5784e7bJan Cholasta i_fatal("LDAP: Unknown deref option '%s'", str);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Unknown scope option '%s'", str);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int tls_require_cert2str(const char *str)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Unknown tls_require_cert value '%s'", str);
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagherstatic int ldap_get_errno(struct ldap_connection *conn)
b97595ae059c69b1960a6e7e56d74660388a683bJan Zeleny ret = ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, (void *) &err);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("LDAP: Can't get error number: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherconst char *ldap_get_error(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return ldap_err2string(ldap_get_errno(conn));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void ldap_conn_reconnect(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int ldap_handle_error(struct ldap_connection *conn)
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce /* invalid input */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* connection problems */
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zelenystatic int db_ldap_request_bind(struct ldap_connection *conn,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(request->type == LDAP_REQUEST_TYPE_BIND);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(conn->conn_state == LDAP_CONN_STATE_BOUND_AUTH ||
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->conn_state == LDAP_CONN_STATE_BOUND_DEFAULT);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher request->msgid = ldap_bind(conn->ld, brequest->dn,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_request_log_error(request->auth_request, "ldap",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "ldap_bind(%s) failed: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* broken request, remove it */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->conn_state = LDAP_CONN_STATE_BINDING;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int db_ldap_request_search(struct ldap_connection *conn,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(conn->conn_state == LDAP_CONN_STATE_BOUND_DEFAULT);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ldap_search(conn->ld, srequest->base, conn->set.ldap_scope,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher srequest->filter, srequest->attributes, 0);
2e6087c6cc903d5164b9a1d5e3d791fd046001d9Jakub Hrozek auth_request_log_error(request->auth_request, "ldap",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "ldap_search() failed (filter %s): %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* broken request, remove it */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool db_ldap_request_queue_next(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_request *const *requestp, *request;
bfbf5cb0f00c60c0f000f56c282377b13b9a89abSumit Bose unsigned int queue_size = aqueue_count(conn->request_queue);
2e6087c6cc903d5164b9a1d5e3d791fd046001d9Jakub Hrozek /* no non-pending requests */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (queue_size > DB_LDAP_MAX_PENDING_REQUESTS) {
2e6087c6cc903d5164b9a1d5e3d791fd046001d9Jakub Hrozek /* wait until server has replied to some requests */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher requestp = array_idx(&conn->request_array,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher request->type == LDAP_REQUEST_TYPE_BIND) {
823a5b3f4375f12b6edae4dd5169ee01771baebeJan Zeleny /* we can't do binds until all existing requests are finished */
5f90993426fa2bdc3b3d994c9e85e0805bb92bbcSimo Sorce /* wait until we're in bound state */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (request->type == LDAP_REQUEST_TYPE_BIND)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* bind to default dn first */
8c3a4809b3420657289b42f028a1c9019b112991Stephen Gallagher /* we can do anything in this state */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = db_ldap_request_search(conn, request);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else if (ret < 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* disconnected */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* broken request, remove from queue */
65e8f538ad35ba7d86cd9e60a3d86aec34537027Stephen Gallaghervoid db_ldap_request(struct ldap_connection *conn,
cc84fd46f356c4a36a721ab135a33ec77c93e34dJakub Hrozek aqueue_count(conn->request_queue) >= DB_LDAP_MAX_QUEUE_SIZE) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* Queue is full already, fail this request */
65e8f538ad35ba7d86cd9e60a3d86aec34537027Stephen Gallagher struct ldap_request *const *first_requestp;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher first_requestp = array_idx(&conn->request_array,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_request_log_error(request->auth_request, "ldap",
1a853121ca2ba8ede6df429ee76942131ffb0f65Jan Zeleny "Request queue is full (oldest added %d secs ago)",
ad07ed37b6b51ef134d4524edaf2259e19ac984fJan Zeleny (int)(time(NULL) - (*first_requestp)->create_time));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int db_ldap_connect_finish(struct ldap_connection *conn, int ret)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("LDAP: Can't connect to server: %s",
347f7c4d1e8e83fc7ffcaf9524a67e8b3ad5d7c5Jan Cholasta conn->set.dn == NULL ? "(none)" : conn->set.dn,
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek conn->conn_state = LDAP_CONN_STATE_BOUND_DEFAULT;
374bf54785365273b20690bd3792c25a44738041Pavel Březinastatic void db_ldap_default_bind_finished(struct ldap_connection *conn,
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher ret = ldap_result2error(conn->ld, res, FALSE);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (db_ldap_connect_finish(conn, ret) < 0) {
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher /* lost connection, close it */
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagherstatic void db_ldap_abort_requests(struct ldap_connection *conn,
1f1e6cbc59868f06dee3ab4b3df660fcb77ce1c8Jakub Hrozek while (aqueue_count(conn->request_queue) > 0 && max_count > 0) {
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher diff = ioloop_time - request->create_time;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher /* timed out, abort */
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher auth_request_log_error(request->auth_request, "ldap",
29be7d76c949b82350c7603cfd362a1fcb47eb1bJan Zeleny auth_request_log_info(request->auth_request, "ldap",
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagherdb_ldap_handle_result(struct ldap_connection *conn, LDAPMessage *res)
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher struct ldap_request *const *requests, *request = NULL;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher unsigned int i, count;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher count = aqueue_count(conn->request_queue);
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose requests = count == 0 ? NULL : array_idx(&conn->request_array, 0);
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher for (i = 0; i < count; i++) {
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher request = requests[aqueue_idx(conn->request_queue, i)];
b6dfbf81c61d4431aaa81687ec53e892f8b71edbSumit Bose i_error("LDAP: Reply with unknown msgid %d", msgid);
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose i_assert(conn->conn_state == LDAP_CONN_STATE_BINDING);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_result2error(conn->ld, res, 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ret != LDAP_SUCCESS && request->type == LDAP_REQUEST_TYPE_SEARCH) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* handle search failures here */
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher auth_request_log_error(request->auth_request, "ldap",
e369fc08906383e6d5c39832f31bb6600a33f887Simo Sorce "ldap_search(%s) failed: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* see if there are timed out requests */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void ldap_input(struct ldap_connection *conn)
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina ret = ldap_result(conn->ld, LDAP_RES_ANY, 1, &timeout, &res);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* try again, there may be another in buffer */
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek /* send more requests */
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek } else if (ldap_get_errno(conn) != LDAP_SERVER_DOWN) {
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek i_error("LDAP: ldap_result() failed: %s", ldap_get_error(conn));
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek } else if (aqueue_count(conn->request_queue) > 0 ||
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta i_error("LDAP: Connection lost to LDAP server, reconnecting");
bd03e67c9d2fc4ad0275e7a573385ee5b7b9307aJan Cholasta /* server probably disconnected an idle connection. don't
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta reconnect until the next request comes. */
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bosesasl_interact(LDAP *ld ATTR_UNUSED, unsigned flags ATTR_UNUSED,
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose struct db_ldap_sasl_bind_context *context = defaults;
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose const char *str;
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose for (in = interact; in->id != SASL_CB_LIST_END; in++) {
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozekstatic int db_ldap_bind(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(conn->conn_state != LDAP_CONN_STATE_BINDING);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher msgid = ldap_bind(conn->ld, conn->set.dn, conn->set.dnpass,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(ldap_get_errno(conn) != LDAP_SUCCESS);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (db_ldap_connect_finish(conn, ldap_get_errno(conn)) < 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* lost connection, close it */
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher conn->conn_state = LDAP_CONN_STATE_BINDING;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void db_ldap_get_fd(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* get the connection's fd */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_get_option(conn->ld, LDAP_OPT_DESC, (void *)&conn->fd);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Can't get connection fd: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* Solaris LDAP library seems to be broken */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Buggy LDAP library returned wrong fd: %d",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdb_ldap_set_opt(struct ldap_connection *conn, int opt, const void *value,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *optname, const char *value_str)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_set_option(conn == NULL ? NULL : conn->ld, opt, value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Can't set option %s to %s: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher optname, value_str, ldap_err2string(ret));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdb_ldap_set_opt_str(struct ldap_connection *conn, int opt, const char *value,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_set_opt(conn, opt, value, optname, value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void db_ldap_set_tls_options(struct ldap_connection *conn)
c737e1444fb186e349e59bfa9dac4995b720b4b1Jan Zeleny db_ldap_set_opt_str(NULL, LDAP_OPT_X_TLS_CACERTFILE,
f1828234a850dd28465425248a83a993f262918fPavel Březina db_ldap_set_opt_str(NULL, LDAP_OPT_X_TLS_CACERTDIR,
f1828234a850dd28465425248a83a993f262918fPavel Březina conn->set.tls_ca_cert_dir, "tls_ca_cert_dir");
f1828234a850dd28465425248a83a993f262918fPavel Březina db_ldap_set_opt_str(NULL, LDAP_OPT_X_TLS_CERTFILE,
f1828234a850dd28465425248a83a993f262918fPavel Březina db_ldap_set_opt_str(NULL, LDAP_OPT_X_TLS_KEYFILE,
f1828234a850dd28465425248a83a993f262918fPavel Březina db_ldap_set_opt_str(NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
f8c829e72968b574e1c9bda96f4d5f206622358fPavel Březina conn->set.tls_cipher_suite, "tls_cipher_suite");
f8c829e72968b574e1c9bda96f4d5f206622358fPavel Březina int value = tls_require_cert2str(conn->set.tls_require_cert);
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek db_ldap_set_opt(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &value,
f8c829e72968b574e1c9bda96f4d5f206622358fPavel Březina "tls_require_cert", conn->set.tls_require_cert);
558998ce664055a75595371118f818084d8f2b23Jan Cholasta "your LDAP library doesn't seem to support them");
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholastastatic void db_ldap_set_options(struct ldap_connection *conn)
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta db_ldap_set_opt(conn, LDAP_OPT_DEREF, &conn->set.ldap_deref,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_set_opt(NULL, LDAP_OPT_DEBUG_LEVEL, &value,
21f28bdbab10881b9fb0b890dfa15af429326606Sumit Bose i_fatal("LDAP: sasl_bind=yes requires ldap_version=3");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: tls=yes requires ldap_version=3");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_ldap_set_opt(conn, LDAP_OPT_PROTOCOL_VERSION, &ldap_version,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "protocol_version", dec2str(ldap_version));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherint db_ldap_connect(struct ldap_connection *conn)
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (conn->conn_state != LDAP_CONN_STATE_DISCONNECTED)
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (ldap_initialize(&conn->ld, conn->set.uris) != LDAP_SUCCESS)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Your LDAP library doesn't support "
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "'uris' setting, use 'hosts' instead.");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->ld = ldap_init(conn->set.hosts, LDAP_PORT);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: ldap_init() failed with hosts: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_start_tls_s(conn->ld, NULL, NULL);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher strncmp(conn->set.uris, "ldaps:", 6) == 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "and ldaps URI");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("LDAP: ldap_start_tls_s() failed: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("LDAP: Your LDAP library doesn't support TLS");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher context.authzid = conn->set.sasl_authz_id;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* There doesn't seem to be a way to do SASL binding
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher asynchronously.. */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = ldap_sasl_interactive_bind_s(conn->ld, NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (db_ldap_connect_finish(conn, ret) < 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: sasl_bind=yes but no SASL support compiled in");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->conn_state = LDAP_CONN_STATE_BOUND_DEFAULT;
9d7d4458d94d0aac0a7edf999368eb18f89cb76aJakub Hrozek conn->io = io_add(conn->fd, IO_READ, ldap_input, conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void db_ldap_disconnect_timeout(struct ldap_connection *conn)
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher DB_LDAP_REQUEST_DISCONNECT_TIMEOUT_SECS, FALSE,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "Aborting (timeout), we're not connected to LDAP server");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (aqueue_count(conn->request_queue) == 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* no requests left, remove this timeout handler */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void db_ldap_conn_close(struct ldap_connection *conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct ldap_request *const *requests, *request;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher unsigned int i;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->conn_state = LDAP_CONN_STATE_DISCONNECTED;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher requests = array_idx(&conn->request_array, 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (i = 0; i < conn->pending_count; i++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher request = requests[aqueue_idx(conn->request_queue, i)];
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* the fd may have already been closed before ldap_unbind(),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher so we'll have to use io_remove_closed(). */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (aqueue_count(conn->request_queue) == 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->to = timeout_add(DB_LDAP_REQUEST_DISCONNECT_TIMEOUT_SECS *
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher 1000/2, db_ldap_disconnect_timeout, conn);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallaghervoid db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher char ***attr_names_r, struct hash_table *attr_map,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher unsigned int i, j, size;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (size = 0; attr[size] != NULL; size++) ;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *attr_names_r = p_new(conn->pool, char *, size + 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (i = j = 0; i < size; i++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* allow spaces here so "foo=1, bar=2" works */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher name = value = p_strdup(conn->pool, attr_data);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher else if (p != attr_data) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher name = p_strdup_until(conn->pool, attr_data, p);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* =<static key>=<static value> */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (skip_attr == NULL || strcmp(skip_attr, value) != 0)) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher p_strdup(conn->pool, str_c(static_data)));
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagherdb_ldap_value_get_var_expand_table(struct auth_request *auth_request)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const struct var_expand_table *auth_table;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_table = auth_request_get_var_expand_table(auth_request, NULL);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher for (count = 0; auth_table[count].key != '\0'; count++) ;
fe60346714a73ac3987f786731389320633dd245Pavel Březina table = t_new(struct var_expand_table, count + 1);
fe60346714a73ac3987f786731389320633dd245Pavel Březina memcpy(table + 1, auth_table, sizeof(*table) * count);
fe60346714a73ac3987f786731389320633dd245Pavel Březina ((c) == '*' || (c) == '(' || (c) == ')' || (c) == '\\')
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek const struct auth_request *auth_request ATTR_UNUSED)
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek const char *p;
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek if (*p == '\0')
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher str_append_n(ret, str, (size_t) (p - str));
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher for (; *p != '\0'; p++) {
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagherdb_ldap_result_iterate_init(struct ldap_connection *conn, LDAPMessage *entry,
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose ctx = t_new(struct db_ldap_result_iterate_context, 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher static_data = hash_table_lookup(attr_map, "");
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher table = auth_request_get_var_expand_table(auth_request, NULL);
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek ctx->static_attrs = t_strsplit(str_c(str), ",");
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek ctx->attr = ldap_first_attribute(conn->ld, entry, &ctx->ber);
f232789430a080384188d5da89b19d874cf17513Jakub Hrozekdb_ldap_result_iterate_finish(struct db_ldap_result_iterate_context *ctx)
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek auth_request_log_debug(ctx->auth_request, "ldap",
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek auth_request_log_debug(ctx->auth_request, "ldap",
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek "no fields returned by the server");
f8c829e72968b574e1c9bda96f4d5f206622358fPavel Březinadb_ldap_result_change_attr(struct db_ldap_result_iterate_context *ctx)
6e8238868a4d17030bb4f01494961d0354a953bfJakub Hrozek ctx->name = hash_table_lookup(ctx->attr_map, ctx->attr);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_printfa(ctx->debug, " %s(%s)=", ctx->attr,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->name != NULL ? ctx->name : "?unknown?");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (ctx->template = strchr(ctx->name, '=')) != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* we want to use variables */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->name = t_strdup_until(ctx->name, ctx->template);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->var_table = db_ldap_value_get_var_expand_table(
f128b7b865062da662127712935dcc58bd022384Stephen Gallagher ctx->vals = ldap_get_values(ctx->conn->ld, ctx->entry,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdb_ldap_result_return_value(struct db_ldap_result_iterate_context *ctx)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher var_expand(ctx->var, ctx->template, ctx->var_table);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ctx->auth_request->auth->set->debug_passwords ||
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_append(ctx->debug, PASSWORD_HIDDEN_STR);
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozekstatic bool db_ldap_result_int_next(struct db_ldap_result_iterate_context *ctx)
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek const char *p;
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek /* a new attribute */
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek /* continuing existing attribute */
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ctx->attr = ldap_next_attribute(ctx->conn->ld, ctx->entry,
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (ctx->static_attrs != NULL && *ctx->static_attrs != NULL) {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ctx->name = t_strdup_until(*ctx->static_attrs, p);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* make _next_all() return correct values */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherbool db_ldap_result_iterate_next(struct db_ldap_result_iterate_context *ctx,
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher const char **name_r, const char **value_r)
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagherbool db_ldap_result_iterate_next_all(struct db_ldap_result_iterate_context *ctx,
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny const char *const **values_r)
619bd403265ce0880989ba6f8324b010949851bcSumit Bose /* we can use only one value with templates */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *values_r = (const char *const *)ctx->vals;
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagherstatic const char *parse_setting(const char *key, const char *value,
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher return parse_setting_from_defs(conn->pool, setting_defs,
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagherstatic struct ldap_connection *ldap_conn_find(const char *config_path)
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher for (conn = ldap_connections; conn != NULL; conn = conn->next) {
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher if (strcmp(conn->config_path, config_path) == 0)
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagherstruct ldap_connection *db_ldap_init(const char *config_path)
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher /* see if it already exists */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Configuration file path not given");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher pool = pool_alloconly_create("ldap_connection", 1024);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn = p_new(pool, struct ldap_connection, 1);
88aeed9a31b734a92630d5e881c960c5f77ba0ceJakub Hrozek conn->conn_state = LDAP_CONN_STATE_DISCONNECTED;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher conn->config_path = p_strdup(pool, config_path);
e92ecf948387d1687a5e772ac86e606b1b6af957Stephen Gallagher if (!settings_read(config_path, NULL, parse_setting,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->set.uris == NULL && conn->set.hosts == NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Dovecot compiled without support for LDAP uris "
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "(ldap_initialize not found)");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (str != NULL && strcmp(str, conn->set.ldaprc_path) != 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("LDAP: Multiple different ldaprc_path "
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "settings not allowed (%s and %s)",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher env_put(t_strconcat("LDAPRC=", conn->set.ldaprc_path, NULL));
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher conn->set.ldap_deref = deref2str(conn->set.deref);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set.ldap_scope = scope2str(conn->set.scope);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_array_init(&conn->request_array, DB_LDAP_MAX_QUEUE_SIZE);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->request_queue = aqueue_init(&conn->request_array.arr);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallaghervoid db_ldap_unref(struct ldap_connection **_conn)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (p = &ldap_connections; *p != NULL; p = &(*p)->next) {
e526b608657f229f7486b3aa8c53b0f2c53b42b1Jan Zeleny db_ldap_abort_requests(conn, -1U, 0, FALSE, "Shutting down");
1a853121ca2ba8ede6df429ee76942131ffb0f65Jan Zeleny/* Building a plugin */
1a853121ca2ba8ede6df429ee76942131ffb0f65Jan Zelenyextern struct passdb_module_interface passdb_ldap;