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
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;
 }

Reply via email to