From: Timo Sirainen Date: Mon, 24 May 2004 22:33:50 +0000 (+0300) Subject: Fixed var_expand() to take a table of variables rather than a few predefined X-Git-Tag: 1.1.alpha1~4049 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3b94ff5951db4d4eddb7a80ed4e3f61207202635;p=thirdparty%2Fdovecot%2Fcore.git Fixed var_expand() to take a table of variables rather than a few predefined ones. Added support for modifiers. --HG-- branch : HEAD --- diff --git a/dovecot-example.conf b/dovecot-example.conf index 4dcd0dbd25..6687267f81 100644 --- a/dovecot-example.conf +++ b/dovecot-example.conf @@ -166,6 +166,12 @@ # %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 diff --git a/src/auth/auth-master-connection.c b/src/auth/auth-master-connection.c index 93359cc9fa..018c7d0973 100644 --- a/src/auth/auth-master-connection.c +++ b/src/auth/auth-master-connection.c @@ -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 */ diff --git a/src/auth/mech.c b/src/auth/mech.c index 44aad31c5b..93fdb2359b 100644 --- a/src/auth/mech.c +++ b/src/auth/mech.c @@ -5,6 +5,7 @@ #include "buffer.h" #include "hash.h" #include "mech.h" +#include "var-expand.h" #include "auth-client-connection.h" #include @@ -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; diff --git a/src/auth/mech.h b/src/auth/mech.h index fb8e101f23..3a1ed5a0f8 100644 --- a/src/auth/mech.h +++ b/src/auth/mech.h @@ -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); diff --git a/src/auth/passdb-ldap.c b/src/auth/passdb-ldap.c index fafc0a466c..5ad50281a3 100644 --- a/src/auth/passdb-ldap.c +++ b/src/auth/passdb-ldap.c @@ -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); } diff --git a/src/auth/passdb-mysql.c b/src/auth/passdb-mysql.c index afb4cdc3e7..9e38523e48 100644 --- a/src/auth/passdb-mysql.c +++ b/src/auth/passdb-mysql.c @@ -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; diff --git a/src/auth/passdb-pgsql.c b/src/auth/passdb-pgsql.c index 5073b539b7..c0459a306c 100644 --- a/src/auth/passdb-pgsql.c +++ b/src/auth/passdb-pgsql.c @@ -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; diff --git a/src/auth/userdb-ldap.c b/src/auth/userdb-ldap.c index 7086d41e80..1bba1688d8 100644 --- a/src/auth/userdb-ldap.c +++ b/src/auth/userdb-ldap.c @@ -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); } diff --git a/src/auth/userdb-mysql.c b/src/auth/userdb-mysql.c index 5847b6f905..daf73a93df 100644 --- a/src/auth/userdb-mysql.c +++ b/src/auth/userdb-mysql.c @@ -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); } diff --git a/src/auth/userdb-passwd-file.c b/src/auth/userdb-passwd-file.c index 9fd1456a37..f3359c424d 100644 --- a/src/auth/userdb-passwd-file.c +++ b/src/auth/userdb-passwd-file.c @@ -11,13 +11,13 @@ 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; diff --git a/src/auth/userdb-passwd.c b/src/auth/userdb-passwd.c index 901d9b8d59..7d9c9c3341 100644 --- a/src/auth/userdb-passwd.c +++ b/src/auth/userdb-passwd.c @@ -10,16 +10,16 @@ #include -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; } diff --git a/src/auth/userdb-pgsql.c b/src/auth/userdb-pgsql.c index 2134335799..710145e955 100644 --- a/src/auth/userdb-pgsql.c +++ b/src/auth/userdb-pgsql.c @@ -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); } diff --git a/src/auth/userdb-static.c b/src/auth/userdb-static.c index 423694b9c9..d0cef280f8 100644 --- a/src/auth/userdb-static.c +++ b/src/auth/userdb-static.c @@ -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); diff --git a/src/auth/userdb-vpopmail.c b/src/auth/userdb-vpopmail.c index f06bd6bdc6..7b62c94890 100644 --- a/src/auth/userdb-vpopmail.c +++ b/src/auth/userdb-vpopmail.c @@ -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; } diff --git a/src/auth/userdb.h b/src/auth/userdb.h index 47ba245319..e23f73659a 100644 --- a/src/auth/userdb.h +++ b/src/auth/userdb.h @@ -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; diff --git a/src/lib-index/mail-index-sync-update.c b/src/lib-index/mail-index-sync-update.c index abbce79bd2..ccd683f171 100644 --- a/src/lib-index/mail-index-sync-update.c +++ b/src/lib-index/mail-index-sync-update.c @@ -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); diff --git a/src/lib/strfuncs.c b/src/lib/strfuncs.c index f95c5732d1..20eaeabfaf 100644 --- a/src/lib/strfuncs.c +++ b/src/lib/strfuncs.c @@ -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) diff --git a/src/lib/strfuncs.h b/src/lib/strfuncs.h index ea9bb1056b..024b031ac2 100644 --- a/src/lib/strfuncs.h +++ b/src/lib/strfuncs.h @@ -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); diff --git a/src/lib/var-expand.c b/src/lib/var-expand.c index 194565d0cf..996bc31382 100644 --- a/src/lib/var-expand.c +++ b/src/lib/var-expand.c @@ -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 diff --git a/src/lib/var-expand.h b/src/lib/var-expand.h index 86ce1600eb..f57f4ec6f0 100644 --- a/src/lib/var-expand.h +++ b/src/lib/var-expand.h @@ -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 diff --git a/src/master/common.h b/src/master/common.h index 44612a691e..31336a55af 100644 --- a/src/master/common.h +++ b/src/master/common.h @@ -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, diff --git a/src/master/login-process.h b/src/master/login-process.h index b8eede788b..7445c5e46f 100644 --- a/src/master/login-process.h +++ b/src/master/login-process.h @@ -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; diff --git a/src/master/mail-process.c b/src/master/mail-process.c index 4adbd965aa..c500581a4d 100644 --- a/src/master/mail-process.c +++ b/src/master/mail-process.c @@ -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));