[Dovecot] Help implementing username_format in auth PAM driver

lee at trager.us lee at trager.us
Thu Apr 24 06:50:49 UTC 2014


While configuring my server with dovecot I noticed that the PAM
authentication driver does not support the username_format option as
does the password file driver. This didn't seem too hard to implement
so I through together a patch.

As you can see in the attached patch I only modify the username sent
to PAM. Despit doing this I run into the domain lost
issue(http://wiki2.dovecot.org/DomainLost). This prevents me from
using the domain name in my mail_location config string. What I don't
understand is why does changing the username string sent to PAM for
authentication trigger this issue? Shouldn't dovecot continue to use
the client supplied username as I am *not* changing it anywhere in my
config?

Thanks,

Lee
-------------- next part --------------
diff --git a/src/auth/passdb-pam.c b/src/auth/passdb-pam.c
index cf0b3c9..5f42a5a 100644
--- a/src/auth/passdb-pam.c
+++ b/src/auth/passdb-pam.c
@@ -37,6 +37,7 @@
 typedef pam_const void *pam_item_t;
 
 #define PASSDB_PAM_DEFAULT_MAX_REQUESTS 100
+#define PASSDB_PAM_DEFAULT_USERNAME_FORMAT "%u"
 
 struct pam_passdb_module {
 	struct passdb_module module;
@@ -47,6 +48,7 @@ struct pam_passdb_module {
 	unsigned int pam_setcred:1;
 	unsigned int pam_session:1;
 	unsigned int failure_show_msg:1;
+	const char *username_format;
 };
 
 struct pam_conv_context {
@@ -55,6 +57,17 @@ struct pam_conv_context {
 	const char *failure_msg;
 };
 
+inline const char*
+pam_username_lookup(struct auth_request *request)
+{
+	struct passdb_module *_module = request->passdb->passdb;
+	struct pam_passdb_module *module = (struct pam_passdb_module *)_module;
+	string_t *username = t_str_new(256);
+	var_expand(username, module->username_format,
+		   auth_request_get_var_expand_table(request, auth_request_str_escape));
+	return str_c(username);
+}
+
 static int
 pam_userpass_conv(int num_msg, pam_const struct pam_message **msg,
 		  struct pam_response **resp_r, void *appdata_ptr)
@@ -82,7 +95,7 @@ pam_userpass_conv(int num_msg, pam_const struct pam_message **msg,
 		case PAM_PROMPT_ECHO_ON:
 			/* Assume we're asking for user. We might not ever
 			   get here because PAM already knows the user. */
-			string = strdup(ctx->request->user);
+			string = strdup(pam_username_lookup(ctx->request));
 			if (string == NULL)
 				i_fatal_status(FATAL_OUTOFMEM, "Out of memory");
 			break;
@@ -240,7 +253,7 @@ static void set_pam_items(struct auth_request *request, pam_handle_t *pamh)
 	host = net_ip2addr(&request->remote_ip);
 	if (host != NULL)
 		(void)pam_set_item(pamh, PAM_RHOST, host);
-	(void)pam_set_item(pamh, PAM_RUSER, request->user);
+	(void)pam_set_item(pamh, PAM_RUSER, pam_username_lookup(request));
 	/* TTY is needed by eg. pam_access module */
 	(void)pam_set_item(pamh, PAM_TTY, "dovecot");
 }
@@ -262,7 +275,7 @@ pam_verify_plain_call(struct auth_request *request, const char *service,
 	ctx.request = request;
 	ctx.pass = password;
 
-	status = pam_start(service, request->user, &conv, &pamh);
+	status = pam_start(service, pam_username_lookup(request), &conv, &pamh);
 	if (status != PAM_SUCCESS) {
 		auth_request_log_error(request, "pam", "pam_start() failed: %s",
 				       pam_strerror(pamh, status));
@@ -331,6 +344,7 @@ pam_preinit(pool_t pool, const char *args)
 {
 	struct pam_passdb_module *module;
 	const char *const *t_args;
+	const char *format = PASSDB_PAM_DEFAULT_USERNAME_FORMAT;
 	int i;
 
 	module = p_new(pool, struct pam_passdb_module, 1);
@@ -367,9 +381,14 @@ pam_preinit(pool_t pool, const char *args)
 			}
 		} else if (t_args[i+1] == NULL) {
 			module->service_name = p_strdup(pool, t_args[i]);
+		} else if (strncmp(t_args[i], "username_format=", 16) == 0) {
+		        format = auth_cache_parse_key(pool, t_args[i] + 16);
 		} else {
 			i_fatal("pam: Unknown setting: %s", t_args[i]);
 		}
 	}
+
+	module->username_format = format;
+
 	return &module->module;
 }


More information about the dovecot mailing list