changeset 4782:2c1cc5bbc260 HEAD

Added auth_request_set_credentials() to modify credentials in passdb and implemented it for SQL passdb. Added passdb_need_set_credentials boolean to mechanisms to indicate that it's required (OTP will need it). Patch by Andrey Panin.
author Timo Sirainen <tss@iki.fi>
date Wed, 08 Nov 2006 22:22:08 +0200
parents e55f5f2dbb2c
children db7983ff23b8
files src/auth/auth-request.c src/auth/auth-request.h src/auth/auth-worker-client.c src/auth/auth.c src/auth/db-sql.c src/auth/db-sql.h src/auth/mech-anonymous.c src/auth/mech-apop.c src/auth/mech-cram-md5.c src/auth/mech-digest-md5.c src/auth/mech-gssapi.c src/auth/mech-login.c src/auth/mech-ntlm.c src/auth/mech-plain.c src/auth/mech-rpa.c src/auth/mech.h src/auth/passdb-blocking.c src/auth/passdb-blocking.h src/auth/passdb-bsdauth.c src/auth/passdb-checkpassword.c src/auth/passdb-ldap.c src/auth/passdb-pam.c src/auth/passdb-passwd-file.c src/auth/passdb-passwd.c src/auth/passdb-shadow.c src/auth/passdb-sia.c src/auth/passdb-sql.c src/auth/passdb-vpopmail.c src/auth/passdb.h
diffstat 29 files changed, 223 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/auth/auth-request.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/auth-request.c	Wed Nov 08 22:22:08 2006 +0200
@@ -536,6 +536,34 @@
 	}
 }
 
+void auth_request_set_credentials(struct auth_request *request,
+				  enum passdb_credentials credentials,
+				  const char *data,
+				  set_credentials_callback_t *callback)
+{
+	struct passdb_module *passdb = request->passdb->passdb;
+	const char *cache_key, *new_credentials;
+
+	cache_key = passdb_cache == NULL ? NULL : passdb->cache_key;
+	if (cache_key != NULL)
+		auth_cache_remove(passdb_cache, request, cache_key);
+
+	request->private_callback.set_credentials = callback;
+
+	new_credentials = t_strconcat("{",
+		passdb_credentials_to_str(credentials), "}", data, NULL);
+
+	if (passdb->blocking)
+		passdb_blocking_set_credentials(request, new_credentials);
+	else if (passdb->iface.set_credentials != NULL) {
+		passdb->iface.set_credentials(request, new_credentials,
+					      callback);
+	} else {
+		/* this passdb doesn't support credentials update */
+		callback(PASSDB_RESULT_INTERNAL_FAILURE, request);
+	}
+}
+
 void auth_request_userdb_callback(struct auth_stream_reply *reply,
 				  struct auth_request *request)
 {
--- a/src/auth/auth-request.h	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/auth-request.h	Wed Nov 08 22:22:08 2006 +0200
@@ -59,6 +59,7 @@
 	union {
 		verify_plain_callback_t *verify_plain;
 		lookup_credentials_callback_t *lookup_credentials;
+		set_credentials_callback_t *set_credentials;
                 userdb_callback_t *userdb;
 	} private_callback;
         enum passdb_credentials credentials;
@@ -149,6 +150,10 @@
 void auth_request_lookup_credentials_callback(enum passdb_result result,
 					      const char *credentials,
 					      struct auth_request *request);
+void auth_request_set_credentials(struct auth_request *request,
+				  enum passdb_credentials credentials,
+				  const char *data,
+				  set_credentials_callback_t *callback);
 void auth_request_userdb_callback(struct auth_stream_reply *reply,
 				  struct auth_request *request);
 
--- a/src/auth/auth-worker-client.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/auth-worker-client.c	Wed Nov 08 22:22:08 2006 +0200
@@ -234,6 +234,70 @@
 }
 
 static void
+set_credentials_callback(enum passdb_result result,
+			  struct auth_request *request)
+{
+	struct auth_worker_client *client = request->context;
+
+	string_t *str;
+
+	str = t_str_new(64);
+	str_printfa(str, "%u\t", request->id);
+
+	if (result != PASSDB_RESULT_OK)
+		str_printfa(str, "FAIL\t%d\t", result);
+	else
+		str_printfa(str, "OK\t%s\t", request->user);
+	str_append_c(str, '\n');
+	o_stream_send(client->output, str_data(str), str_len(str));
+
+	auth_request_unref(&request);
+	auth_worker_client_check_throttle(client);
+	auth_worker_client_unref(&client);
+}
+
+static void
+auth_worker_handle_setcred(struct auth_worker_client *client,
+			   unsigned int id, const char *args)
+{
+	struct auth_request *auth_request;
+	unsigned int passdb_id;
+	const char *data;
+
+	passdb_id = atoi(t_strcut(args, '\t'));
+	args = strchr(args, '\t');
+	if (args == NULL) {
+		i_error("BUG: Auth worker server sent us invalid SETCRED");
+		return;
+	}
+	args++;
+
+	data = t_strcut(args, '\t');
+	args = strchr(args, '\t');
+	if (args != NULL) args++;
+
+	auth_request = worker_auth_request_new(client, id, args);
+
+	if (auth_request->user == NULL || auth_request->service == NULL) {
+		i_error("BUG: SETCRED had missing parameters");
+		auth_request_unref(&auth_request);
+		return;
+	}
+
+	while (auth_request->passdb->id != passdb_id) {
+		auth_request->passdb = auth_request->passdb->next;
+		if (auth_request->passdb == NULL) {
+			i_error("BUG: SETCRED had invalid passdb ID");
+			auth_request_unref(&auth_request);
+			return;
+		}
+	}
+
+	auth_request->passdb->passdb->iface.
+		set_credentials(auth_request, data, set_credentials_callback);
+}
+
+static void
 lookup_user_callback(struct auth_stream_reply *reply,
 		     struct auth_request *auth_request)
 {
@@ -303,6 +367,8 @@
 		auth_worker_handle_passv(client, id, line + 6);
 	else if (strncmp(line, "PASSL\t", 6) == 0)
 		auth_worker_handle_passl(client, id, line + 6);
+	else if (strncmp(line, "SETCRED\t", 8) == 0)
+		auth_worker_handle_setcred(client, id, line + 8);
 	else if (strncmp(line, "USER\t", 5) == 0)
 		auth_worker_handle_user(client, id, line + 5);
 
--- a/src/auth/auth.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/auth.c	Wed Nov 08 22:22:08 2006 +0200
@@ -143,6 +143,17 @@
 	return FALSE;
 }
 
+static int auth_passdb_list_have_set_credentials(struct auth *auth)
+{
+	struct auth_passdb *passdb;
+
+	for (passdb = auth->passdbs; passdb != NULL; passdb = passdb->next) {
+		if (passdb->passdb->iface.set_credentials != NULL)
+			return TRUE;
+	}
+	return FALSE;
+}
+
 static void auth_mech_list_verify_passdb(struct auth *auth)
 {
 	struct mech_module_list *list;
@@ -154,6 +165,9 @@
 		if (list->module.passdb_need_credentials &&
                     !auth_passdb_list_have_credentials(auth))
 			break;
+ 		if (list->module.passdb_need_set_credentials &&
+ 		    !auth_passdb_list_have_set_credentials(auth))
+ 			break;
 	}
 
 	if (list != NULL) {
--- a/src/auth/db-sql.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/db-sql.c	Wed Nov 08 22:22:08 2006 +0200
@@ -18,6 +18,7 @@
 	DEF(SET_STR, connect),
 	DEF(SET_STR, password_query),
 	DEF(SET_STR, user_query),
+ 	DEF(SET_STR, update_query),
 	DEF(SET_STR, default_pass_scheme),
 
 	{ 0, NULL, 0 }
@@ -28,6 +29,7 @@
 	MEMBER(connect) NULL,
 	MEMBER(password_query) "SELECT password FROM users WHERE userid = '%u'",
 	MEMBER(user_query) "SELECT home, uid, gid FROM users WHERE userid = '%u'",
+	MEMBER(update_query) "UPDATE users SET password = '%w' WHERE userid = '%u'",
 	MEMBER(default_pass_scheme) "PLAIN-MD5"
 };
 
--- a/src/auth/db-sql.h	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/db-sql.h	Wed Nov 08 22:22:08 2006 +0200
@@ -8,6 +8,7 @@
 	const char *connect;
 	const char *password_query;
 	const char *user_query;
+	const char *update_query;
 	const char *default_pass_scheme;
 };
 
--- a/src/auth/mech-anonymous.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/mech-anonymous.c	Wed Nov 08 22:22:08 2006 +0200
@@ -41,6 +41,7 @@
 
 	MEMBER(passdb_need_plain) FALSE,
 	MEMBER(passdb_need_credentials) FALSE,
+	MEMBER(passdb_need_set_credentials) FALSE,
 
 	mech_anonymous_auth_new,
 	mech_generic_auth_initial,
--- a/src/auth/mech-apop.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/mech-apop.c	Wed Nov 08 22:22:08 2006 +0200
@@ -156,6 +156,7 @@
 
 	MEMBER(passdb_need_plain) FALSE,
 	MEMBER(passdb_need_credentials) TRUE,
+	MEMBER(passdb_need_set_credentials) FALSE,
 
 	mech_apop_auth_new,
 	mech_apop_auth_initial,
--- a/src/auth/mech-cram-md5.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/mech-cram-md5.c	Wed Nov 08 22:22:08 2006 +0200
@@ -188,6 +188,7 @@
 
 	MEMBER(passdb_need_plain) FALSE,
 	MEMBER(passdb_need_credentials) TRUE,
+	MEMBER(passdb_need_set_credentials) FALSE,
 
 	mech_cram_md5_auth_new,
 	mech_cram_md5_auth_initial,
--- a/src/auth/mech-digest-md5.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/mech-digest-md5.c	Wed Nov 08 22:22:08 2006 +0200
@@ -619,6 +619,7 @@
 
 	MEMBER(passdb_need_plain) FALSE,
 	MEMBER(passdb_need_credentials) TRUE,
+	MEMBER(passdb_need_set_credentials) FALSE,
 
 	mech_digest_md5_auth_new,
 	mech_digest_md5_auth_initial,
--- a/src/auth/mech-gssapi.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/mech-gssapi.c	Wed Nov 08 22:22:08 2006 +0200
@@ -402,6 +402,7 @@
 
 	MEMBER(passdb_need_plain) FALSE, 
 	MEMBER(passdb_need_credentials) FALSE, 
+	MEMBER(passdb_need_set_credentials) FALSE,
 
 	mech_gssapi_auth_new,
 	mech_gssapi_auth_initial,
--- a/src/auth/mech-login.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/mech-login.c	Wed Nov 08 22:22:08 2006 +0200
@@ -84,6 +84,7 @@
 
 	MEMBER(passdb_need_plain) TRUE,
 	MEMBER(passdb_need_credentials) FALSE,
+	MEMBER(passdb_need_set_credentials) FALSE,
 
 	mech_login_auth_new,
 	mech_login_auth_initial,
--- a/src/auth/mech-ntlm.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/mech-ntlm.c	Wed Nov 08 22:22:08 2006 +0200
@@ -262,6 +262,7 @@
 
 	MEMBER(passdb_need_plain) FALSE,
 	MEMBER(passdb_need_credentials) TRUE,
+	MEMBER(passdb_need_set_credentials) FALSE,
 
 	mech_ntlm_auth_new,
 	mech_generic_auth_initial,
--- a/src/auth/mech-plain.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/mech-plain.c	Wed Nov 08 22:22:08 2006 +0200
@@ -91,6 +91,7 @@
 
 	MEMBER(passdb_need_plain) TRUE,
 	MEMBER(passdb_need_credentials) FALSE,
+	MEMBER(passdb_need_set_credentials) FALSE,
 
 	mech_plain_auth_new,
 	mech_generic_auth_initial,
--- a/src/auth/mech-rpa.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/mech-rpa.c	Wed Nov 08 22:22:08 2006 +0200
@@ -601,6 +601,7 @@
 
 	MEMBER(passdb_need_plain) FALSE,
 	MEMBER(passdb_need_credentials) TRUE,
+	MEMBER(passdb_need_set_credentials) FALSE,
 
 	mech_rpa_auth_new,
 	mech_generic_auth_initial,
--- a/src/auth/mech.h	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/mech.h	Wed Nov 08 22:22:08 2006 +0200
@@ -26,6 +26,7 @@
         enum mech_security_flags flags;
 	unsigned int passdb_need_plain:1;
 	unsigned int passdb_need_credentials:1;
+	unsigned int passdb_need_set_credentials:1;
 
 	struct auth_request *(*auth_new)(void);
 	void (*auth_initial)(struct auth_request *request,
--- a/src/auth/passdb-blocking.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/passdb-blocking.c	Wed Nov 08 22:22:08 2006 +0200
@@ -163,3 +163,24 @@
 
 	auth_worker_call(request, str_c(str), lookup_credentials_callback);
 }
+
+static void
+set_credentials_callback(struct auth_request *request, const char *reply)
+{
+	enum passdb_result result = check_failure(request, &reply);
+
+	request->private_callback.set_credentials(result, request);
+}
+
+void passdb_blocking_set_credentials(struct auth_request *request,
+				     const char *new_credentials)
+{
+	string_t *str;
+
+	str = t_str_new(64);
+	str_printfa(str, "SETCRED\t%u\t%s\t",
+		    request->passdb->id, new_credentials);
+	auth_request_export(request, str);
+
+	auth_worker_call(request, str_c(str), set_credentials_callback);
+}
--- a/src/auth/passdb-blocking.h	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/passdb-blocking.h	Wed Nov 08 22:22:08 2006 +0200
@@ -3,5 +3,7 @@
 
 void passdb_blocking_verify_plain(struct auth_request *request);
 void passdb_blocking_lookup_credentials(struct auth_request *request);
+void passdb_blocking_set_credentials(struct auth_request *request,
+				     const char *new_credentials);
 
 #endif
--- a/src/auth/passdb-bsdauth.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/passdb-bsdauth.c	Wed Nov 08 22:22:08 2006 +0200
@@ -72,6 +72,7 @@
 	bsdauth_deinit,
 
 	bsdauth_verify_plain,
+	NULL,
 	NULL
 };
 
--- a/src/auth/passdb-checkpassword.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/passdb-checkpassword.c	Wed Nov 08 22:22:08 2006 +0200
@@ -458,6 +458,7 @@
 	checkpassword_deinit,
 
 	checkpassword_verify_plain,
+	NULL,
 	NULL
 };
 
--- a/src/auth/passdb-ldap.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/passdb-ldap.c	Wed Nov 08 22:22:08 2006 +0200
@@ -532,7 +532,8 @@
 	passdb_ldap_deinit,
 
 	ldap_verify_plain,
-	ldap_lookup_credentials
+	ldap_lookup_credentials,
+	NULL
 };
 
 #endif
--- a/src/auth/passdb-pam.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/passdb-pam.c	Wed Nov 08 22:22:08 2006 +0200
@@ -490,6 +490,7 @@
 	pam_deinit,
 
 	pam_verify_plain,
+	NULL,
 	NULL
 };
 
--- a/src/auth/passdb-passwd-file.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/passdb-passwd-file.c	Wed Nov 08 22:22:08 2006 +0200
@@ -162,7 +162,8 @@
 	passwd_file_deinit,
 
 	passwd_file_verify_plain,
-	passwd_file_lookup_credentials
+	passwd_file_lookup_credentials,
+	NULL
 };
 
 #endif
--- a/src/auth/passdb-passwd.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/passdb-passwd.c	Wed Nov 08 22:22:08 2006 +0200
@@ -76,6 +76,7 @@
 	passwd_deinit,
 
 	passwd_verify_plain,
+	NULL,
 	NULL
 };
 
--- a/src/auth/passdb-shadow.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/passdb-shadow.c	Wed Nov 08 22:22:08 2006 +0200
@@ -76,6 +76,7 @@
 	shadow_deinit,
 
 	shadow_verify_plain,
+	NULL,
 	NULL
 };
 
--- a/src/auth/passdb-sia.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/passdb-sia.c	Wed Nov 08 22:22:08 2006 +0200
@@ -54,7 +54,8 @@
         NULL,
 
         local_sia_verify_plain,
-        NULL
+	NULL,
+	NULL
 };
 
 #endif
--- a/src/auth/passdb-sql.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/passdb-sql.c	Wed Nov 08 22:22:08 2006 +0200
@@ -7,6 +7,7 @@
 #include "str.h"
 #include "strescape.h"
 #include "var-expand.h"
+#include "safe-memset.h"
 #include "password-scheme.h"
 #include "auth-cache.h"
 #include "db-sql.h"
@@ -26,6 +27,7 @@
 	union {
 		verify_plain_callback_t *verify_plain;
                 lookup_credentials_callback_t *lookup_credentials;
+		set_credentials_callback_t *set_credentials;
 	} callback;
 };
 
@@ -177,6 +179,56 @@
         sql_lookup_pass(sql_request);
 }
 
+static void sql_set_credentials_callback(const char *error, void *context)
+{
+	struct passdb_sql_request *sql_request = context;
+	enum passdb_result result;
+
+	if (error == NULL)
+		result = PASSDB_RESULT_OK;
+	else {
+		result = PASSDB_RESULT_INTERNAL_FAILURE;
+		auth_request_log_error(sql_request->auth_request, "sql",
+				       "Set credentials query failed: %s",
+				       error);
+	}
+	sql_request->callback.set_credentials(result,
+					      sql_request->auth_request);
+	i_free(sql_request);
+}
+
+static int sql_set_credentials(struct auth_request *request,
+			       const char *new_credentials,
+			       set_credentials_callback_t *callback)
+{
+	struct sql_passdb_module *module =
+		(struct sql_passdb_module *) request->passdb->passdb;
+	struct sql_transaction_context *transaction;
+	struct passdb_sql_request *sql_request;
+	string_t *query;
+
+	t_push();
+
+	request->mech_password = p_strdup(request->pool, new_credentials);
+
+	query = t_str_new(512);
+	var_expand(query, module->conn->set.update_query, 
+		   auth_request_get_var_expand_table(request,
+						     passdb_sql_escape));
+
+	sql_request = i_new(struct passdb_sql_request, 1);
+	sql_request->auth_request = request;
+	sql_request->callback.set_credentials = callback;
+
+	transaction = sql_transaction_begin(module->conn->db);
+	sql_update(transaction, str_c(query));
+	sql_transaction_commit(&transaction,
+			       sql_set_credentials_callback, sql_request);
+
+	t_pop();
+	return 0;
+}
+
 static struct passdb_module *
 passdb_sql_preinit(struct auth_passdb *auth_passdb, const char *args)
 {
@@ -223,7 +275,8 @@
 	passdb_sql_deinit,
        
 	sql_verify_plain,
-	sql_lookup_credentials
+	sql_lookup_credentials,
+	sql_set_credentials
 };
 
 #endif
--- a/src/auth/passdb-vpopmail.c	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/passdb-vpopmail.c	Wed Nov 08 22:22:08 2006 +0200
@@ -153,7 +153,8 @@
 	vpopmail_deinit,
 
 	vpopmail_verify_plain,
-	vpopmail_lookup_credentials
+	vpopmail_lookup_credentials,
+	NULL
 };
 
 #endif
--- a/src/auth/passdb.h	Wed Nov 08 22:02:34 2006 +0200
+++ b/src/auth/passdb.h	Wed Nov 08 22:22:08 2006 +0200
@@ -35,6 +35,8 @@
 typedef void lookup_credentials_callback_t(enum passdb_result result,
 					   const char *password,
 					   struct auth_request *request);
+typedef void set_credentials_callback_t(enum passdb_result result,
+					struct auth_request *request);
 
 struct passdb_module_interface {
 	const char *name;
@@ -52,6 +54,11 @@
 	   auth_request->credentials. */
 	void (*lookup_credentials)(struct auth_request *request, 
 				   lookup_credentials_callback_t *callback);
+
+	/* Update credentials */
+	int (*set_credentials)(struct auth_request *request,
+			       const char *new_credentials,
+			       set_credentials_callback_t *callback);
 };
 
 struct passdb_module {