db-ldap.c revision 6ef7e31619edfaa17ed044b45861d106a86191ef
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen/* Copyright (C) 2003 Timo Sirainen */
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen#if defined(PASSDB_LDAP) || defined(USERDB_LDAP)
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen/* Older versions may require calling ldap_result() twice */
48559742084e98049335c21c53dfd1ff95f11cd8Timo Sirainen/* Solaris LDAP library doesn't have LDAP_OPT_SUCCESS */
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen { type, #name, offsetof(struct ldap_settings, name) }
5a8b0ce25f7838652b4a0cb9dab0ad19ec0fab25Timo Sirainen MEMBER(user_attrs) "uid,homeDirectory,,,uidNumber,gidNumber",
5a8b0ce25f7838652b4a0cb9dab0ad19ec0fab25Timo Sirainen MEMBER(user_filter) "(&(objectClass=posixAccount)(uid=%u))",
5a8b0ce25f7838652b4a0cb9dab0ad19ec0fab25Timo Sirainen MEMBER(pass_filter) "(&(objectClass=posixAccount)(uid=%u))",
c4457e497e01b57565d24da624968699b166e02aTimo Sirainenstatic struct ldap_connection *ldap_connections = NULL;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic void ldap_conn_close(struct ldap_connection *conn, bool flush_requests);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_fatal("LDAP: Unknown deref option '%s'", str);
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen i_fatal("LDAP: Unknown scope option '%s'", str);
ebfcfd258acc89633c47d9c3b0b40a1a3f75cdcbTimo Sirainenconst char *ldap_get_error(struct ldap_connection *conn)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ret = ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, (void *) &err);
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainenvoid db_ldap_search(struct ldap_connection *conn, struct ldap_request *request,
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen msgid = ldap_search(conn->ld, request->base, scope,
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_error("LDAP: ldap_search() failed (filter %s): %s",
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen hash_insert(conn->requests, POINTER_CAST(msgid), request);
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainenstatic void ldap_conn_retry_requests(struct ldap_connection *conn)
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainen conn->requests = hash_create(default_pool, conn->pool, 0, NULL, NULL);
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen db_ldap_search(conn, request, conn->set.ldap_scope);
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainenstatic void ldap_conn_reconnect(struct ldap_connection *conn)
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainen /* failed to reconnect. fail all requests. */
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen ret = ldap_result(conn->ld, LDAP_RES_ANY, 1, &timeout, &res);
a8fc29f19ea6e2d472ba779b2dd5ca4e1f3dac79Timo Sirainen /* try again, there may be another in buffer */
ebfcfd258acc89633c47d9c3b0b40a1a3f75cdcbTimo Sirainen request = hash_lookup(conn->requests, POINTER_CAST(msgid));
ebfcfd258acc89633c47d9c3b0b40a1a3f75cdcbTimo Sirainen hash_remove(conn->requests, POINTER_CAST(msgid));
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenbool db_ldap_connect(struct ldap_connection *conn)
e65cc79f80577e83c706f0678c78e2c0bd91434fTimo Sirainen if (ldap_initialize(&conn->ld, conn->set.uris) != LDAP_SUCCESS)
48559742084e98049335c21c53dfd1ff95f11cd8Timo Sirainen i_fatal("LDAP: Your LDAP library doesn't support "
48559742084e98049335c21c53dfd1ff95f11cd8Timo Sirainen "'uris' setting, use 'hosts' instead.");
e65cc79f80577e83c706f0678c78e2c0bd91434fTimo Sirainen conn->ld = ldap_init(conn->set.hosts, LDAP_PORT);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen i_fatal("LDAP: ldap_init() failed with hosts: %s",
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ret = ldap_set_option(conn->ld, LDAP_OPT_DEREF,
b567e0172c73dcf7642462e86962060358dd5f28Timo Sirainen ret = ldap_set_option(conn->ld, LDAP_OPT_PROTOCOL_VERSION,
b567e0172c73dcf7642462e86962060358dd5f28Timo Sirainen i_fatal("LDAP: Can't set protocol version %u: %s",
b567e0172c73dcf7642462e86962060358dd5f28Timo Sirainen conn->set.ldap_version, ldap_err2string(ret));
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen /* FIXME: we shouldn't use blocking bind */
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen ret = ldap_simple_bind_s(conn->ld, conn->set.dn, conn->set.dnpass);
ebfcfd258acc89633c47d9c3b0b40a1a3f75cdcbTimo Sirainen i_error("LDAP: Can't connect to server: %s", conn->set.hosts);
ebfcfd258acc89633c47d9c3b0b40a1a3f75cdcbTimo Sirainen i_error("LDAP: ldap_simple_bind_s() failed (dn %s): %s",
ebfcfd258acc89633c47d9c3b0b40a1a3f75cdcbTimo Sirainen conn->set.dn == NULL ? "(none)" : conn->set.dn,
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen /* register LDAP input to ioloop */
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen ret = ldap_get_option(conn->ld, LDAP_OPT_DESC, (void *) &fd);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->io = io_add(fd, IO_READ, ldap_input, conn);
ed5e91e58dfc372c2135c55427bf6f25a7725042Timo Sirainen /* in case there are requests waiting, retry them */
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic void ldap_conn_close(struct ldap_connection *conn, bool flush_requests)
9f431ccfb6932746db56245c8a3d3415717ef545Timo Sirainenvoid db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist,
0d7d27765267594a5870892268ab345148306d49Timo Sirainen char ***attr_names_r, struct hash_table *attr_map,
9f431ccfb6932746db56245c8a3d3415717ef545Timo Sirainen const char *const default_attr_map[])
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen const char *const *attr;
9f431ccfb6932746db56245c8a3d3415717ef545Timo Sirainen unsigned int i, size;
0e90e1b11b699166a4a4c5e01d132a28c3e26affTimo Sirainen /* @UNSAFE */
0d7d27765267594a5870892268ab345148306d49Timo Sirainen *attr_names_r = p_new(conn->pool, char *, size + 1);
9f431ccfb6932746db56245c8a3d3415717ef545Timo Sirainen for (i = 0; i < size; i++) {
9f431ccfb6932746db56245c8a3d3415717ef545Timo Sirainen name = p_strdup_until(conn->pool, attr[i], p);
1c38a95332f1945c9806d7d83175a0d948f51291Timo Sirainen ((c) == '*' || (c) == '(' || (c) == ')' || (c) == '\\')
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen const char *p;
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen if (*p == '\0')
d1f0acc7fc722e13e8296228703adfe8a884d59eTimo Sirainen for (; *p != '\0'; p++) {
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenstatic const char *parse_setting(const char *key, const char *value,
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen return parse_setting_from_defs(conn->pool, setting_defs,
c4457e497e01b57565d24da624968699b166e02aTimo Sirainenstatic struct ldap_connection *ldap_conn_find(const char *config_path)
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen for (conn = ldap_connections; conn != NULL; conn = conn->next) {
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen if (strcmp(conn->config_path, config_path) == 0)
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenstruct ldap_connection *db_ldap_init(const char *config_path)
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen /* see if it already exists */
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen pool = pool_alloconly_create("ldap_connection", 1024);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn = p_new(pool, struct ldap_connection, 1);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->requests = hash_create(default_pool, pool, 0, NULL, NULL);
c4457e497e01b57565d24da624968699b166e02aTimo Sirainen conn->config_path = p_strdup(pool, config_path);
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen if (!settings_read(config_path, NULL, parse_setting, NULL, conn))
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen conn->set.ldap_deref = deref2str(conn->set.deref);
e714eed72515794c46c6712a611e5ab924d903daTimo Sirainen conn->set.ldap_scope = scope2str(conn->set.scope);
e714eed72515794c46c6712a611e5ab924d903daTimo Sirainen userdb_parse_uid(NULL, conn->set.user_global_uid);
e714eed72515794c46c6712a611e5ab924d903daTimo Sirainen userdb_parse_gid(NULL, conn->set.user_global_gid);
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainenvoid db_ldap_unref(struct ldap_connection *conn)
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen for (p = &ldap_connections; *p != NULL; p = &(*p)->next) {