]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Fixed var_expand() to take a table of variables rather than a few predefined
authorTimo Sirainen <tss@iki.fi>
Mon, 24 May 2004 22:33:50 +0000 (01:33 +0300)
committerTimo Sirainen <tss@iki.fi>
Mon, 24 May 2004 22:33:50 +0000 (01:33 +0300)
ones. Added support for modifiers.

--HG--
branch : HEAD

23 files changed:
dovecot-example.conf
src/auth/auth-master-connection.c
src/auth/mech.c
src/auth/mech.h
src/auth/passdb-ldap.c
src/auth/passdb-mysql.c
src/auth/passdb-pgsql.c
src/auth/userdb-ldap.c
src/auth/userdb-mysql.c
src/auth/userdb-passwd-file.c
src/auth/userdb-passwd.c
src/auth/userdb-pgsql.c
src/auth/userdb-static.c
src/auth/userdb-vpopmail.c
src/auth/userdb.h
src/lib-index/mail-index-sync-update.c
src/lib/strfuncs.c
src/lib/strfuncs.h
src/lib/var-expand.c
src/lib/var-expand.h
src/master/common.h
src/master/login-process.h
src/master/mail-process.c

index 4dcd0dbd2525f16965309dd5c2d2f7f332a8680e..6687267f8140117c55d360b5d99632e2da38dfb1 100644 (file)
 #   %n - user part in user@domain, same as %u if there's no domain
 #   %d - domain part in user@domain, empty if user there's no domain
 #   %h - home directory
+#   %p - protocol (IMAP or POP3)
+#
+# You can apply a modifiers for each variable (eg. %Lp = pop3):
+#   %L - lowercase
+#   %U - uppercase
+#   %E - escape '"', "'" and '\' characters by inserting '\' before them.
 #
 # You can also limit a width of string by giving the number of max. characters
 # after the '%' character. For example %1u gives the first character of
index 93359cc9fa3be115012f647daa36335de3a0dbec..018c7d09737e58189e65a996c45e400d8ea89e57 100644 (file)
@@ -149,7 +149,7 @@ static void master_handle_request(struct auth_master_connection *conn,
                master_request->tag = request->tag;
 
                conn->refcount++;
-               userdb->lookup(auth_request->user, userdb_callback,
+               userdb->lookup(auth_request, userdb_callback,
                               master_request);
 
                /* the auth request is finished, we don't need it anymore */
index 44aad31c5b605a10c53ecf1d5f77aa43fe99e906..93fdb2359bd58a0531e375b3ff73522e6ce157ba 100644 (file)
@@ -5,6 +5,7 @@
 #include "buffer.h"
 #include "hash.h"
 #include "mech.h"
+#include "var-expand.h"
 #include "auth-client-connection.h"
 
 #include <stdlib.h>
@@ -225,6 +226,48 @@ int auth_request_unref(struct auth_request *request)
        return FALSE;
 }
 
+static const char *escape_none(const char *str)
+{
+       return str;
+}
+
+const struct var_expand_table *
+auth_request_get_var_expand_table(const struct auth_request *auth_request,
+                                 const char *(*escape_func)(const char *))
+{
+       static struct var_expand_table static_tab[] = {
+               { 'u', NULL },
+               { 'n', NULL },
+               { 'd', NULL },
+               { 'p', NULL },
+               { '\0', NULL }
+       };
+       struct var_expand_table *tab;
+
+       if (escape_func == NULL)
+               escape_func = escape_none;
+
+       tab = t_malloc(sizeof(static_tab));
+       memcpy(tab, static_tab, sizeof(static_tab));
+
+       tab[0].value = escape_func(auth_request->user);
+       tab[1].value = escape_func(t_strcut(auth_request->user, '@'));
+       tab[2].value = strchr(auth_request->user, '@');
+       if (tab[2].value != NULL)
+               tab[2].value = escape_func(tab[2].value+1);
+
+       switch (auth_request->protocol) {
+       case AUTH_PROTOCOL_IMAP:
+               tab[3].value = "IMAP";
+               break;
+       case AUTH_PROTOCOL_POP3:
+               tab[3].value = "POP3";
+               break;
+       }
+
+       return tab;
+}
+
 extern struct mech_module mech_plain;
 extern struct mech_module mech_cram_md5;
 extern struct mech_module mech_digest_md5;
index fb8e101f23c209bc7c9e2f0e42797b9176c1ea08..3a1ed5a0f80ed32e0b85c8cc09b325f0d3df1adb 100644 (file)
@@ -75,6 +75,10 @@ mech_cyrus_sasl_new(struct auth_client_connection *conn,
 void auth_request_ref(struct auth_request *request);
 int auth_request_unref(struct auth_request *request);
 
+const struct var_expand_table *
+auth_request_get_var_expand_table(const struct auth_request *auth_request,
+                                 const char *(*escape_func)(const char *));
+
 void mech_init(void);
 void mech_deinit(void);
 
index fafc0a466c0b1e561332758a5ae41b137d474ef8..5ad50281a38d7661557f4c2f9e5a9b2e30290d72 100644 (file)
@@ -141,16 +141,18 @@ static void ldap_lookup_pass(struct auth_request *auth_request,
                             struct ldap_request *ldap_request)
 {
        struct ldap_connection *conn = passdb_ldap_conn->conn;
-       const char *user, *filter;
+       const char *filter;
        string_t *str;
 
-       user = ldap_escape(auth_request->user);
        if (conn->set.pass_filter == NULL) {
                filter = t_strdup_printf("(&(objectClass=posixAccount)(%s=%s))",
-                       passdb_ldap_conn->attr_names[ATTR_VIRTUAL_USER], user);
+                       passdb_ldap_conn->attr_names[ATTR_VIRTUAL_USER],
+                       ldap_escape(auth_request->user));
        } else {
                str = t_str_new(512);
-               var_expand(str, conn->set.pass_filter, user, NULL);
+               var_expand(str, conn->set.pass_filter,
+                          auth_request_get_var_expand_table(auth_request,
+                                                            ldap_escape));
                filter = str_c(str);
        }
 
index afb4cdc3e7b31ee833a19dabd9ed3bee411e05b1..9e38523e484f3ca5e6d8137eaf008469571a46ad 100644 (file)
@@ -108,7 +108,8 @@ static void mysql_lookup_pass(struct auth_request *auth_request,
 
        str = t_str_new(512);
        var_expand(str, conn->set.password_query,
-                  str_escape(auth_request->user), NULL);
+                  auth_request_get_var_expand_table(auth_request,
+                                                    str_escape));
        query = str_c(str);
 
        mysql_request->callback = mysql_handle_request;
index 5073b539b7a32e296ca9a53e05077dcf537e8bc8..c0459a306cc62c05bfd6a28be667158a7433b6f5 100644 (file)
@@ -105,7 +105,8 @@ static void pgsql_lookup_pass(struct auth_request *auth_request,
 
        str = t_str_new(512);
        var_expand(str, conn->set.password_query,
-                  db_pgsql_escape(auth_request->user), NULL);
+                  auth_request_get_var_expand_table(auth_request,
+                                                    db_pgsql_escape));
        query = str_c(str);
 
        pgsql_request->callback = pgsql_handle_request;
index 7086d41e804a95dea5929e0a75e837015fbc2de1..1bba1688d84ce20f6b27bac8b47ada083630c80f 100644 (file)
@@ -149,21 +149,23 @@ static void handle_request(struct ldap_connection *conn,
        t_pop();
 }
 
-static void userdb_ldap_lookup(const char *user, userdb_callback_t *callback,
-                              void *context)
+static void userdb_ldap_lookup(struct auth_request *auth_request,
+                              userdb_callback_t *callback, void *context)
 {
        struct ldap_connection *conn = userdb_ldap_conn->conn;
        struct userdb_ldap_request *request;
        const char *filter;
        string_t *str;
 
-       user = ldap_escape(user);
        if (conn->set.user_filter == NULL) {
                filter = t_strdup_printf("(&(objectClass=posixAccount)(%s=%s))",
-                       userdb_ldap_conn->attr_names[ATTR_VIRTUAL_USER], user);
+                       userdb_ldap_conn->attr_names[ATTR_VIRTUAL_USER],
+                       ldap_escape(auth_request->user));
        } else {
                str = t_str_new(512);
-               var_expand(str, conn->set.user_filter, user, NULL);
+               var_expand(str, conn->set.user_filter,
+                          auth_request_get_var_expand_table(auth_request,
+                                                            ldap_escape));
                filter = str_c(str);
        }
 
index 5847b6f9050757072c4f93d51709adadeab7f91a..daf73a93df6dd050db3831dd8c8dd9324a1ad28e 100644 (file)
@@ -114,8 +114,8 @@ static void mysql_handle_request(struct mysql_connection *conn __attr_unused__,
        }
 }
 
-static void userdb_mysql_lookup(const char *user, userdb_callback_t *callback,
-                               void *context)
+static void userdb_mysql_lookup(struct auth_request *auth_request,
+                               userdb_callback_t *callback, void *context)
 {
        struct mysql_connection *conn = userdb_mysql_conn->conn;
        struct userdb_mysql_request *request;
@@ -123,14 +123,17 @@ static void userdb_mysql_lookup(const char *user, userdb_callback_t *callback,
        string_t *str;
 
        str = t_str_new(512);
-       var_expand(str, conn->set.user_query, str_escape(user), NULL);
+       var_expand(str, conn->set.user_query,
+                  auth_request_get_var_expand_table(auth_request,
+                                                    str_escape));
        query = str_c(str);
 
-       request = i_malloc(sizeof(struct userdb_mysql_request) + strlen(user));
+       request = i_malloc(sizeof(struct userdb_mysql_request) +
+                          strlen(auth_request->user));
        request->request.callback = mysql_handle_request;
        request->request.context = context;
        request->userdb_callback = callback;
-       strcpy(request->username, user);
+       strcpy(request->username, auth_request->user);
 
        db_mysql_query(conn, query, &request->request);
 }
index 9fd1456a37c65f2163310f9b1b8d3de52b7b2db7..f3359c424d07f36e293db58ce8468d74469ee6a5 100644 (file)
 
 struct passwd_file *userdb_pwf = NULL;
 
-static void passwd_file_lookup(const char *user, userdb_callback_t *callback,
-                              void *context)
+static void passwd_file_lookup(struct auth_request *auth_request,
+                              userdb_callback_t *callback, void *context)
 {
        struct user_data data;
        struct passwd_user *pu;
 
-       pu = db_passwd_file_lookup(userdb_pwf, user);
+       pu = db_passwd_file_lookup(userdb_pwf, auth_request->user);
        if (pu == NULL) {
                callback(NULL, context);
                return;
@@ -27,7 +27,7 @@ static void passwd_file_lookup(const char *user, userdb_callback_t *callback,
        data.uid = pu->uid;
        data.gid = pu->gid;
 
-       data.virtual_user = user;
+       data.virtual_user = auth_request->user;
        data.home = pu->home;
        data.mail = pu->mail;
 
index 901d9b8d5936ac59a6481a340fa28575d9a11e23..7d9c9c3341f6a5f8b245720f574c9a4470590c41 100644 (file)
 
 #include <pwd.h>
 
-static void passwd_lookup(const char *user, userdb_callback_t *callback,
-                         void *context)
+static void passwd_lookup(struct auth_request *auth_request,
+                         userdb_callback_t *callback, void *context)
 {
        struct user_data data;
        struct passwd *pw;
 
-       pw = getpwnam(user);
+       pw = getpwnam(auth_request->user);
        if (pw == NULL) {
                if (verbose)
-                       i_info("passwd(%s): unknown user", user);
+                       i_info("passwd(%s): unknown user", auth_request->user);
                callback(NULL, context);
                return;
        }
index 2134335799b74e70216d567917ff29804f56ae67..710145e9555bc7054b554d3213d32e3c4112dea7 100644 (file)
@@ -84,8 +84,8 @@ static void pgsql_handle_request(struct pgsql_connection *conn __attr_unused__,
        }
 }
 
-static void userdb_pgsql_lookup(const char *user, userdb_callback_t *callback,
-                               void *context)
+static void userdb_pgsql_lookup(struct auth_request *auth_request,
+                               userdb_callback_t *callback, void *context)
 {
        struct pgsql_connection *conn = userdb_pgsql_conn->conn;
        struct userdb_pgsql_request *request;
@@ -93,14 +93,17 @@ static void userdb_pgsql_lookup(const char *user, userdb_callback_t *callback,
        string_t *str;
 
        str = t_str_new(512);
-       var_expand(str, conn->set.user_query, db_pgsql_escape(user), NULL);
+       var_expand(str, conn->set.user_query,
+                  auth_request_get_var_expand_table(auth_request,
+                                                    db_pgsql_escape));
        query = str_c(str);
 
-       request = i_malloc(sizeof(struct userdb_pgsql_request) + strlen(user));
+       request = i_malloc(sizeof(struct userdb_pgsql_request) +
+                          strlen(auth_request->user));
        request->request.callback = pgsql_handle_request;
        request->request.context = context;
        request->userdb_callback = callback;
-       strcpy(request->username, user);
+       strcpy(request->username, auth_request->user);
 
        db_pgsql_query(conn, query, &request->request);
 }
index 423694b9c90dc2ed5cffd4976853a7c82d1472d6..d0cef280f88392b07a0e45144be1121c0c3238c1 100644 (file)
@@ -16,8 +16,8 @@ static uid_t static_uid;
 static gid_t static_gid;
 static char *static_home_template;
 
-static void static_lookup(const char *user, userdb_callback_t *callback,
-                         void *context)
+static void static_lookup(struct auth_request *auth_request,
+                         userdb_callback_t *callback, void *context)
 {
        struct user_data data;
        string_t *str;
@@ -26,10 +26,11 @@ static void static_lookup(const char *user, userdb_callback_t *callback,
        data.uid = static_uid;
        data.gid = static_gid;
 
-       data.virtual_user = data.system_user = user;
+       data.virtual_user = data.system_user = auth_request->user;
 
        str = t_str_new(256);
-       var_expand(str, static_home_template, user, NULL);
+       var_expand(str, static_home_template,
+                  auth_request_get_var_expand_table(auth_request, NULL));
        data.home = str_c(str);
 
        callback(&data, context);
index f06bd6bdc6e1127c3f0331b9c8fa09b6aec6529c..7b62c94890840ad6b6c98648b0e339359073de78 100644 (file)
@@ -46,8 +46,8 @@ struct vqpasswd *vpopmail_lookup_vqp(const char *user,
 
 #ifdef USERDB_VPOPMAIL
 
-static void vpopmail_lookup(const char *user, userdb_callback_t *callback,
-                           void *context)
+static void vpopmail_lookup(struct auth_request *auth_request,
+                           userdb_callback_t *callback, void *context)
 {
        char vpop_user[VPOPMAIL_LIMIT], vpop_domain[VPOPMAIL_LIMIT];
        struct vqpasswd *vpw;
@@ -56,7 +56,7 @@ static void vpopmail_lookup(const char *user, userdb_callback_t *callback,
        gid_t gid;
        pool_t pool;
 
-       vpw = vpopmail_lookup_vqp(user, vpop_user, vpop_domain);
+       vpw = vpopmail_lookup_vqp(auth_request->user, vpop_user, vpop_domain);
        if (vpw == NULL) {
                callback(NULL, context);
                return;
@@ -67,7 +67,7 @@ static void vpopmail_lookup(const char *user, userdb_callback_t *callback,
        if (vget_assign(vpop_domain, NULL, 0, &uid, &gid) == NULL) {
                if (verbose) {
                        i_info("vpopmail(%s): vget_assign(%s) failed",
-                              user, vpop_domain);
+                              auth_request->user, vpop_domain);
                }
                callback(NULL, context);
                return;
@@ -77,12 +77,12 @@ static void vpopmail_lookup(const char *user, userdb_callback_t *callback,
                /* user's homedir doesn't exist yet, create it */
                if (verbose) {
                        i_info("vpopmail(%s): pw_dir isn't set, creating",
-                              user);
+                              auth_request->user);
                }
 
                if (make_user_dir(vpop_user, vpop_domain, uid, gid) == NULL) {
                        i_error("vpopmail(%s): make_user_dir(%s, %s) failed",
-                               user, vpop_user, vpop_domain);
+                               auth_request->user, vpop_user, vpop_domain);
                        callback(NULL, context);
                        return;
                }
index 47ba2453192ddd05f70b49c132460ea46b9db1e3..e23f73659a749444a69018856a57c3069832266b 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __USERDB_H
 #define __USERDB_H
 
+#include "mech.h"
+
 struct user_data {
        const char *virtual_user;
        const char *home;
@@ -17,8 +19,8 @@ struct userdb_module {
        void (*init)(const char *args);
        void (*deinit)(void);
 
-       void (*lookup)(const char *user, userdb_callback_t *callback,
-                      void *context);
+       void (*lookup)(struct auth_request *auth_request,
+                      userdb_callback_t *callback, void *context);
 };
 
 extern struct userdb_module *userdb;
index abbce79bd2bf9af76ddef3be436ddc58388c2ef8..ccd683f1713c6d802ef8b7ed6882be19fe6dd8ac 100644 (file)
@@ -81,6 +81,7 @@ void mail_index_sync_expunge(struct mail_index_view *view,
 
        map->records_count -= count;
        hdr->messages_count -= count;
+       view->messages_count -= count;
 
        if (map->buffer != NULL) {
                buffer_set_used_size(map->buffer, map->records_count);
@@ -123,6 +124,7 @@ static int sync_append(const struct mail_index_record *rec, void *context)
        map->records[map->records_count++] = *rec;
        map->hdr_copy.messages_count++;
        map->hdr_copy.next_uid = rec->uid+1;
+       view->messages_count++;
 
        mail_index_header_update_counts(&map->hdr_copy, 0, rec->flags);
        mail_index_header_update_lowwaters(&map->hdr_copy, rec);
index f95c5732d14c2926ecdaee3bafbf0dc6888e719b..20eaeabfaff91b5bf77ad6189b78a8e1480c5a5e 100644 (file)
@@ -433,6 +433,16 @@ char *str_lcase(char *str)
         return str;
 }
 
+const char *t_str_lcase(const char *str)
+{
+       return str_lcase(t_strdup_noconst(str));
+}
+
+const char *t_str_ucase(const char *str)
+{
+       return str_ucase(t_strdup_noconst(str));
+}
+
 int null_strcmp(const char *s1, const char *s2)
 {
        if (s1 == NULL)
index ea9bb1056b43b12ef359d81d38457cdd9bd87253..024b031ac2bbcf7d2615ee847328b42c20884b47 100644 (file)
@@ -50,6 +50,8 @@ int str_ppath(char *dest, size_t dstsize, const char *dir,
 
 char *str_ucase(char *str);
 char *str_lcase(char *str);
+const char *t_str_lcase(const char *str);
+const char *t_str_ucase(const char *str);
 
 int null_strcmp(const char *s1, const char *s2);
 int memcasecmp(const void *p1, const void *p2, size_t size);
index 194565d0cfdd83a5fba699eb4ed2d079cd36bb37..996bc313822f13ed2dd59ad1389bcbce89300015 100644 (file)
@@ -2,53 +2,70 @@
 
 #include "lib.h"
 #include "str.h"
+#include "strescape.h"
 #include "var-expand.h"
 
+struct var_expand_modifier {
+       char key;
+       const char *(*func)(const char *);
+};
+
+static const struct var_expand_modifier modifiers[] = {
+       { 'L', t_str_lcase },
+       { 'U', t_str_ucase },
+       { 'E', str_escape },
+       { '\0', NULL }
+};
+
 void var_expand(string_t *dest, const char *str,
-               const char *user, const char *home)
+               const struct var_expand_table *table)
 {
+        const struct var_expand_modifier *m;
+        const struct var_expand_table *t;
        const char *var;
        unsigned int width;
+       const char *(*modifier)(const char *);
 
        for (; *str != '\0'; str++) {
                if (*str != '%')
                        str_append_c(dest, *str);
                else {
+                       str++;
                        width = 0;
-                       while (str[1] >= '0' && str[1] <= '9') {
-                               width = width*10 + (str[1] - '0');
+                       while (*str >= '0' && *str <= '9') {
+                               width = width*10 + (*str - '0');
                                str++;
                        }
 
-                       switch (str[1]) {
-                       case '%':
-                               var = "%";
-                               break;
-                       case 'u':
-                               var = user;
-                               break;
-                       case 'h':
-                               var = home;
-                               break;
-                       case 'n':
-                               var = t_strcut(user, '@');
-                               break;
-                       case 'd':
-                               var = strchr(user, '@');
-                               if (var != NULL) var++;
-                               break;
-                       default:
-                               str_append_c(dest, '%');
-                               if (str[1] != '\0')
-                                       str_append_c(dest, str[1]);
-                               var = NULL;
+                       modifier = NULL;
+                       for (m = modifiers; m->key != '\0'; m++) {
+                               if (m->key == *str) {
+                                       modifier = m->func;
+                                       str++;
+                                       break;
+                               }
+                       }
+
+                       if (*str == '\0')
                                break;
+
+                       var = NULL;
+                       for (t = table; t->key != '\0'; t++) {
+                               if (t->key == *str) {
+                                       var = t->value != NULL ? t->value : "";
+                                       break;
+                               }
                        }
 
-                       if (str[1] != '\0')
-                               str++;
+                       if (var == NULL) {
+                               /* not found */
+                               if (*str == '%')
+                                       var = "%";
+                       }
 
                        if (var != NULL) {
+                               if (modifier != NULL)
+                                       var = modifier(var);
                                if (width == 0)
                                        str_append(dest, var);
                                else
index 86ce1600eb35c5f14a2efab10096dfccbf66092b..f57f4ec6f0775065d164367f44c03c0d029b4ce4 100644 (file)
@@ -1,13 +1,14 @@
 #ifndef __VAR_EXPAND_H
 #define __VAR_EXPAND_H
 
-/* Expand % variables in str:
+struct var_expand_table {
+       char key;
+       const char *value;
+};
 
-    %u user or user@domain
-    %h home
-    %n user
-    %d domain */
+/* Expand % variables in src and append the string in dest.
+   table must end with key = 0. */
 void var_expand(string_t *dest, const char *str,
-               const char *user, const char *home);
+               const struct var_expand_table *table);
 
 #endif
index 44612a691ef50f86b962b7c42a13f328048bf1e4..31336a55afe3ee40cf4f5783b5dcbdb621c1f6a7 100644 (file)
@@ -9,7 +9,7 @@ struct ip_addr;
 
 #include "../auth/auth-master-interface.h"
 
-enum {
+enum process_type {
        PROCESS_TYPE_UNKNOWN,
        PROCESS_TYPE_AUTH,
        PROCESS_TYPE_LOGIN,
index b8eede788baf28bcd59caa0c1cb2e6b83232122a..7445c5e46f95d8f68797deca775b29fc9df863ee 100644 (file)
@@ -4,7 +4,7 @@
 struct login_group {
        struct login_group *next;
 
-       int process_type;
+       enum process_type process_type;
        struct settings *set;
 
        unsigned int processes;
index 4adbd965aa67e895d1081494b8a38eaaab5188bf..c500581a4da4fe687733e1cfd3998d7dca0360db 100644 (file)
@@ -74,8 +74,35 @@ static int validate_chroot(struct settings *set, const char *dir)
        return FALSE;
 }
 
-static const char *expand_mail_env(const char *env, const char *user,
-                                  const char *home)
+static const struct var_expand_table *
+get_var_expand_table(const char *user, const char *home,
+                    enum process_type process_type)
+{
+       static struct var_expand_table static_tab[] = {
+               { 'u', NULL },
+               { 'n', NULL },
+               { 'd', NULL },
+               { 'p', NULL },
+               { 'h', NULL },
+               { '\0', NULL }
+       };
+       struct var_expand_table *tab;
+
+       tab = t_malloc(sizeof(static_tab));
+       memcpy(tab, static_tab, sizeof(static_tab));
+
+       tab[0].value = user;
+       tab[1].value = t_strcut(user, '@');
+       tab[2].value = strchr(user, '@');
+       if (tab[2].value != NULL) tab[2].value++;
+       tab[3].value = str_ucase(t_strdup_noconst(process_names[process_type]));
+       tab[4].value = home;
+
+       return tab;
+}
+
+static const char *
+expand_mail_env(const char *env, const struct var_expand_table *table)
 {
        string_t *str;
        const char *p;
@@ -95,18 +122,17 @@ static const char *expand_mail_env(const char *env, const char *user,
 
        if (env[0] == '~' && env[1] == '/') {
                /* expand home */
-               str_append(str, home);
-               env++;
+               env = t_strconcat("%h", env+1, NULL);
        }
 
        /* expand %vars */
-        var_expand(str, env, user, home);
+       var_expand(str, env, table);
        return str_c(str);
 }
 
-static void env_put_namespace(struct namespace_settings *ns,
-                             const char *default_location,
-                             const char *user, const char *home)
+static void
+env_put_namespace(struct namespace_settings *ns, const char *default_location,
+                 const struct var_expand_table *table)
 {
        const char *location;
        unsigned int i;
@@ -120,7 +146,7 @@ static void env_put_namespace(struct namespace_settings *ns,
 
                location = ns->location != NULL ? ns->location :
                        default_location;
-               location = expand_mail_env(location, user, home);
+               location = expand_mail_env(location, table);
                env_put(t_strdup_printf("NAMESPACE_%u=%s", i, location));
 
                if (ns->separator != NULL) {
@@ -135,7 +161,7 @@ static void env_put_namespace(struct namespace_settings *ns,
                        /* expand variables, eg. ~%u/ can be useful */
                        str = t_str_new(256);
                        str_printfa(str, "NAMESPACE_%u_PREFIX=", i);
-                       var_expand(str, ns->prefix, user, home);
+                       var_expand(str, ns->prefix, table);
                        env_put(str_c(str));
                }
                if (ns->inbox)
@@ -151,6 +177,7 @@ int create_mail_process(struct login_group *group, int socket,
                        struct auth_master_reply *reply, const char *data)
 {
        struct settings *set = group->set;
+       const struct var_expand_table *var_expand_table;
        const char *argv[4];
        const char *addr, *mail, *user, *chroot_dir, *home_dir, *full_home_dir;
        const char *executable, *p, *prefix;
@@ -317,12 +344,16 @@ int create_mail_process(struct login_group *group, int socket,
           mechanism might allow leaving extra data there. */
        mail = data + reply->mail_idx;
        user = data + reply->virtual_user_idx;
+
+       var_expand_table =
+               get_var_expand_table(user, home_dir, group->process_type);
+
        if (*mail == '\0' && set->default_mail_env != NULL)
-               mail = expand_mail_env(set->default_mail_env, user, home_dir);
+               mail = expand_mail_env(set->default_mail_env, var_expand_table);
 
        if (set->server->namespaces != NULL) {
                env_put_namespace(set->server->namespaces,
-                                 mail, user, home_dir);
+                                 mail, var_expand_table);
        }
 
        env_put(t_strconcat("MAIL=", mail, NULL));