ones. Added support for modifiers.
--HG--
branch : HEAD
# %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
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 */
#include "buffer.h"
#include "hash.h"
#include "mech.h"
+#include "var-expand.h"
#include "auth-client-connection.h"
#include <stdlib.h>
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;
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);
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);
}
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;
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;
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);
}
}
}
-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;
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);
}
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;
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;
#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;
}
}
}
-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;
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);
}
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;
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);
#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;
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;
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;
/* 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;
}
#ifndef __USERDB_H
#define __USERDB_H
+#include "mech.h"
+
struct user_data {
const char *virtual_user;
const char *home;
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;
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);
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);
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)
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);
#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
#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
#include "../auth/auth-master-interface.h"
-enum {
+enum process_type {
PROCESS_TYPE_UNKNOWN,
PROCESS_TYPE_AUTH,
PROCESS_TYPE_LOGIN,
struct login_group {
struct login_group *next;
- int process_type;
+ enum process_type process_type;
struct settings *set;
unsigned int processes;
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;
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;
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) {
/* 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)
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;
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));