passdb-ldap.c revision 35136dd2baf8dc30e4e754294ed81ff48e8c1e64
a11689fe3fbb3bca11b9cb4ae5faf27db96401ccTimo Sirainen/* Copyright (C) 2003 Timo Sirainen */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic const char *default_attr_map[] = {
d595049948579def2d82718dbce0a6b49a281402Timo Sirainen lookup_credentials_callback_t *lookup_credentials;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainenldap_query_save_attr(struct ldap_query_save_context *ctx, const char *attr)
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen unsigned int i;
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen name = hash_lookup(ctx->conn->pass_attr_map, attr);
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen /* in case we're trying to use prefetch userdb,
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen see if we need to add global uid/gid */
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen ctx->add_userdb_uid = ctx->add_userdb_gid = TRUE;
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen vals = ldap_get_values(ctx->conn->ld, ctx->entry, attr);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen auth_request_set_field(ctx->auth_request, name, vals[i],
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenldap_query_save_result(struct ldap_connection *conn, LDAPMessage *entry,
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen attr = ldap_first_attribute(conn->ld, entry, &ber);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen attr = ldap_next_attribute(conn->ld, entry, ber);
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen if (ctx.add_userdb_uid && conn->set.uid != (uid_t)-1) {
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen auth_request_set_field(auth_request, "userdb_uid",
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen if (ctx.add_userdb_gid && conn->set.gid != (gid_t)-1) {
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen auth_request_set_field(auth_request, "userdb_gid",
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainenhandle_request_get_entry(struct ldap_connection *conn,
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen struct passdb_ldap_request *request, LDAPMessage *res)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen passdb_result = PASSDB_RESULT_INTERNAL_FAILURE;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* LDAP query returned something */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen "ldap_search(%s) failed: %s",
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* get the reply */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* success */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* no entries returned */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen "unknown user");
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen request->callback.verify_plain(passdb_result, auth_request);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainenstatic void handle_request(struct ldap_connection *conn,
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen struct ldap_request *request, LDAPMessage *res)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen struct auth_request *auth_request = request->context;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen entry = handle_request_get_entry(conn, auth_request, ldap_request, res);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* got first LDAP entry */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen passdb_result = PASSDB_RESULT_INTERNAL_FAILURE;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen ldap_query_save_result(conn, entry, auth_request);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen "No password in reply");
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen } else if (ldap_next_entry(conn->ld, entry) != NULL) {
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen "Multiple password replies");
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* passdb_password may change on the way,
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen so we'll need to strdup. */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen password = t_strdup(auth_request->passdb_password);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* auth_request_set_field() sets scheme */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen passdb_handle_credentials(passdb_result, password, scheme,
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* verify plain */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen ldap_request->callback.verify_plain(passdb_result,
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen ret = auth_request_password_verify(auth_request,
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen ldap_request->callback.verify_plain(ret > 0 ? PASSDB_RESULT_OK :
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainenstatic void authbind_start(struct ldap_connection *conn,
1b33e848e84e6f74aa0e3339c32fa96bc15102a2Timo Sirainen struct passdb_ldap_request *passdb_ldap_request =
1b33e848e84e6f74aa0e3339c32fa96bc15102a2Timo Sirainen struct auth_request *auth_request = ldap_request->context;
1b33e848e84e6f74aa0e3339c32fa96bc15102a2Timo Sirainen /* switch back to the default dn before doing the next search
1b33e848e84e6f74aa0e3339c32fa96bc15102a2Timo Sirainen /* the DN is kept in base variable, a bit ugly.. */
1b33e848e84e6f74aa0e3339c32fa96bc15102a2Timo Sirainen msgid = ldap_bind(conn->ld, ldap_request->base,
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen hash_insert(conn->requests, POINTER_CAST(msgid), ldap_request);
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen auth_request_log_debug(auth_request, "ldap", "bind: dn=%s",
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen db_ldap_add_delayed_request(conn, ldap_request);
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen /* Bind started */
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainenhandle_request_authbind(struct ldap_connection *conn,
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen struct ldap_request *ldap_request, LDAPMessage *res)
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen struct passdb_ldap_request *passdb_ldap_request =
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen struct auth_request *auth_request = ldap_request->context;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen passdb_result = PASSDB_RESULT_INTERNAL_FAILURE;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen "invalid credentials");
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen passdb_result = PASSDB_RESULT_PASSWORD_MISMATCH;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen "ldap_bind() failed: %s",
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen /* reconnected, retry binding */
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainenhandle_request_authbind_search(struct ldap_connection *conn,
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen struct passdb_ldap_request *passdb_ldap_request =
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen struct auth_request *auth_request = ldap_request->context;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen entry = handle_request_get_entry(conn, auth_request,
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen ldap_query_save_result(conn, entry, auth_request);
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen /* switch the handler to the authenticated bind handler */
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen p_strdup(auth_request->pool, ldap_get_dn(conn->ld, entry));
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen ldap_request->callback = handle_request_authbind;
e9e5e84ffb2ce2e606a24ce6d930580367562ff0Timo Sirainenstatic void ldap_lookup_pass(struct auth_request *auth_request,
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen struct passdb_module *_module = auth_request->passdb->passdb;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const char **attr_names = (const char **)conn->pass_attr_names;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen vars = auth_request_get_var_expand_table(auth_request, ldap_escape);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen ldap_request->base = p_strdup(auth_request->pool, str_c(str));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ldap_request->filter = p_strdup(auth_request->pool, str_c(str));
e9e5e84ffb2ce2e606a24ce6d930580367562ff0Timo Sirainen ldap_request->attributes = conn->pass_attr_names;
e9e5e84ffb2ce2e606a24ce6d930580367562ff0Timo Sirainen auth_request_log_debug(auth_request, "ldap", "pass search: "
e9e5e84ffb2ce2e606a24ce6d930580367562ff0Timo Sirainen "base=%s scope=%s filter=%s fields=%s",
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen db_ldap_search(conn, ldap_request, conn->set.ldap_scope);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainenldap_verify_plain_auth_bind_userdn(struct auth_request *auth_request,
d595049948579def2d82718dbce0a6b49a281402Timo Sirainen struct passdb_module *_module = auth_request->passdb->passdb;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen vars = auth_request_get_var_expand_table(auth_request, ldap_escape);
d595049948579def2d82718dbce0a6b49a281402Timo Sirainen var_expand(dn, conn->set.auth_bind_userdn, vars);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen ldap_request->callback = handle_request_authbind;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ldap_request->base = p_strdup(auth_request->pool, str_c(dn));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenldap_verify_plain_authbind(struct auth_request *auth_request,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct passdb_module *_module = auth_request->passdb->passdb;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen vars = auth_request_get_var_expand_table(auth_request, ldap_escape);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ldap_request->base = p_strdup(auth_request->pool, str_c(str));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ldap_request->filter = p_strdup(auth_request->pool, str_c(str));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* we don't need the attributes to perform authentication, but they
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen may contain some extra parameters. if a password is returned,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen it's just ignored. */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ldap_request->attributes = conn->pass_attr_names;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ldap_request->callback = handle_request_authbind_search;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen "bind search: base=%s filter=%s",
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen db_ldap_search(conn, ldap_request, LDAP_SCOPE_SUBTREE);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenldap_verify_plain(struct auth_request *request,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct passdb_module *_module = request->passdb->passdb;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* reconnect if needed. this is also done by db_ldap_search(), but
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen with auth binds we'll have to do it ourself */
d595049948579def2d82718dbce0a6b49a281402Timo Sirainen callback(PASSDB_RESULT_INTERNAL_FAILURE, request);
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen ldap_request = p_new(request->pool, struct passdb_ldap_request, 1);
d595049948579def2d82718dbce0a6b49a281402Timo Sirainen ldap_request->callback.verify_plain = callback;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ldap_verify_plain_auth_bind_userdn(request, &ldap_request->request);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ldap_verify_plain_authbind(request, &ldap_request->request);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ldap_lookup_pass(request, &ldap_request->request);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic void ldap_lookup_credentials(struct auth_request *request,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ldap_request = p_new(request->pool, struct passdb_ldap_request, 1);
1b33e848e84e6f74aa0e3339c32fa96bc15102a2Timo Sirainen ldap_request->callback.lookup_credentials = callback;
1b33e848e84e6f74aa0e3339c32fa96bc15102a2Timo Sirainen ldap_lookup_pass(request, &ldap_request->request);
1b33e848e84e6f74aa0e3339c32fa96bc15102a2Timo Sirainenpassdb_ldap_preinit(struct auth_passdb *auth_passdb, const char *args)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen module = p_new(auth_passdb->auth->pool, struct ldap_passdb_module, 1);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen hash_create(default_pool, conn->pool, 0, str_hash,
1b33e848e84e6f74aa0e3339c32fa96bc15102a2Timo Sirainen db_ldap_set_attrs(conn, conn->set.pass_attrs, &conn->pass_attr_names,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen module->module.default_pass_scheme = conn->set.default_pass_scheme;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic void passdb_ldap_init(struct passdb_module *_module,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* Credential lookups can't be done with authentication binds */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic void passdb_ldap_deinit(struct passdb_module *_module)