Mercurial > dovecot > original-hg > dovecot-1.2
changeset 3183:16ea551957ed HEAD
Replaced userdb/passdb settings with blocks so it's possible to give
multiple ones. Plaintext password mechanisms now support handling multiple
passdbs, but others don't yet. Also fixed a few memory leaks.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 07 Mar 2005 20:55:13 +0200 |
parents | 818c75139ac7 |
children | c59506c04088 |
files | dovecot-example.conf src/auth/auth-master-connection.c src/auth/auth-request.c src/auth/auth-request.h src/auth/auth-worker-client.c src/auth/auth.c src/auth/auth.h src/auth/main.c src/auth/passdb-blocking.c src/auth/passdb.c src/auth/passdb.h src/auth/userdb-blocking.c src/auth/userdb-blocking.h src/auth/userdb.c src/auth/userdb.h src/master/auth-process.c src/master/master-settings.c src/master/master-settings.h |
diffstat | 18 files changed, 537 insertions(+), 188 deletions(-) [+] |
line wrap: on
line diff
--- a/dovecot-example.conf Mon Mar 07 11:42:54 2005 +0200 +++ b/dovecot-example.conf Mon Mar 07 20:55:13 2005 +0200 @@ -484,12 +484,6 @@ ## Authentication processes ## -# You can have multiple authentication processes. With plaintext authentication -# the password is checked against each process, the first one which succeeds is -# used. This is useful if you want to allow both system users (/etc/passwd) -# and virtual users to login without duplicating the system users into virtual -# database. - # Executable location #auth_executable = /usr/libexec/dovecot/dovecot-auth @@ -545,29 +539,111 @@ # plain digest-md5 cram-md5 apop anonymous mechanisms = plain - # Password database specifies only the passwords for users. + # + # Password database is used to verify user's password (and nothing more). + # You can have multiple passdbs and userdbs. This is useful if you want to + # allow both system users (/etc/passwd) and virtual users to login without + # duplicating the system users into virtual database. + # # http://wiki.dovecot.org/Authentication - # passwd: /etc/passwd or similiar, using getpwnam() - # shadow: /etc/shadow or similiar, using getspnam() - # pam [<service> | *]: PAM authentication - # checkpassword <path>: checkpassword executable authentication - # passwd-file <path>: passwd-like file with specified location - # vpopmail: vpopmail authentication - # ldap <config path>: LDAP, see doc/dovecot-ldap.conf - # sql <config path>: SQL database, see doc/dovecot-sql.conf - passdb = pam + # + + # PAM authentication. Preferred nowadays by most systems. + # Note that PAM can only be used to verify if user's password is correct, + # so it can't be used as userdb. If you don't want to use a separate user + # database (passwd usually), you can use static userdb. + passdb pam { + # Service name or * as parameter. * means the authenticating service name + # is used, eg. pop3 or imap. + #args = dovecot + } + + # /etc/passwd or similar, using getpwnam() + # In many systems nowadays this uses Name Service Switch, which is + # configured in /etc/nsswitch.conf. + #passdb passwd { + #} + + # /etc/shadow or similiar, using getspnam(). Deprecated by PAM nowadays. + #passdb shadow { + #} + # passwd-like file with specified location + #passdb passwd-file { + # Path for passwd-file + #args = + #} + + # checkpassword executable authentication + #passdb checkpassword { + # Path for checkpassword binary + #args = + #} + + # SQL database + #passdb sql { + # Path for SQL configuration file, see doc/dovecot-sql.conf for example + #args = + #} + + # LDAP database + #passdb ldap { + # Path for LDAP configuration file, see doc/dovecot-ldap.conf for example + #args = + #} + + # vpopmail authentication + #passdb vpopmail { + #} + + # # User database specifies where mails are located and what user/group IDs # own them. For single-UID configuration use "static". + # # http://wiki.dovecot.org/Authentication # http://wiki.dovecot.org/VirtualUsers - # passwd: /etc/passwd or similiar, using getpwnam() - # passwd-file <path>: passwd-like file with specified location - # static uid=<uid> gid=<gid> home=<dir template>: static settings - # vpopmail: vpopmail library - # ldap <config path>: LDAP, see doc/dovecot-ldap.conf - # sql <config path>: SQL database, see doc/dovecot-sql.conf - userdb = passwd + # + + # /etc/passwd or similar, using getpwnam() + # In many systems nowadays this uses Name Service Switch, which is + # configured in /etc/nsswitch.conf. + userdb passwd { + } + + # passwd-like file with specified location + #userdb passwd-file { + # Path for passwd-file + #args = + #} + + # static settings generated from template + #userdb static { + # Template for settings. Can return anything a userdb could normally + # return, eg.: uid, gid, home, mail, nice + # + # A few examples: + # + # args = uid=500 gid=500 home=/var/mail/%u + # args = uid=500 gid=500 home=/home/%u mail=mbox:%h/mail nice=10 + # + #args = + #} + + # SQL database + #userdb sql { + # Path for SQL configuration file, see doc/dovecot-sql.conf for example + #args = + #} + + # LDAP database + #userdb ldap { + # Path for LDAP configuration file, see doc/dovecot-ldap.conf for example + #args = + #} + + # vpopmail + #userdb vpopmail { + #} # User to use for the process. This user needs access to only user and # password databases, nothing else. Only shadow and pam authentication @@ -579,6 +655,7 @@ # Directory where to chroot the process. Most authentication backends don't # work if this is set, and there's no point chrooting if auth_user is root. + # Note that valid_chroot_dirs isn't needed to use this setting. #chroot = # Number of authentication processes to create @@ -588,31 +665,6 @@ #ssl_require_client_cert = no } -# PAM doesn't provide a way to get uid, gid or home directory. If you don't -# want to use a separate user database (passwd usually), you can use static -# userdb. - -#auth onlypam { -# mechanisms = plain -# userdb = static uid=500 gid=500 home=/var/mail/%u -# passdb = pam -# user = dovecot-auth -#} - -#auth ldap { -# mechanisms = plain -# userdb = ldap /etc/dovecot-ldap.conf -# passdb = ldap /etc/dovecot-ldap.conf -# user = dovecot-auth -#} - -#auth virtualfile { -# mechanisms = plain digest-md5 -# userdb = passwd-file /etc/passwd.imap -# passdb = passwd-file /etc/passwd.imap -# user = dovecot-auth -#} - # It's possible to export the authentication interface to other programs, # for example SMTP server which supports talking to Dovecot. Client socket # handles the actual authentication - you give it a username and password @@ -624,8 +676,10 @@ # settings given inside the auth section #auth default_with_listener { # mechanisms = plain -# passdb = passwd -# userdb = pam +# passdb passwd { +# } +# userdb pam { +# } # socket listen { # master { # path = /var/run/dovecot/auth-master
--- a/src/auth/auth-master-connection.c Mon Mar 07 11:42:54 2005 +0200 +++ b/src/auth/auth-master-connection.c Mon Mar 07 20:55:13 2005 +0200 @@ -228,7 +228,10 @@ i_error("close(): %m"); conn->fd = -1; - o_stream_close(conn->output); + i_stream_unref(conn->input); + conn->input = NULL; + + o_stream_unref(conn->output); conn->output = NULL; if (conn->io != NULL) {
--- a/src/auth/auth-request.c Mon Mar 07 11:42:54 2005 +0200 +++ b/src/auth/auth-request.c Mon Mar 07 20:55:13 2005 +0200 @@ -24,6 +24,8 @@ request = mech->auth_new(); request->state = AUTH_REQUEST_STATE_NEW; + request->passdb = auth->passdbs; + request->userdb = auth->userdbs; request->refcount = 1; request->created = ioloop_time; @@ -107,7 +109,7 @@ static void auth_request_save_cache(struct auth_request *request, enum passdb_result result) { - struct passdb_module *passdb = request->auth->passdb; + struct passdb_module *passdb = request->passdb->passdb; string_t *str; if (passdb_cache == NULL) @@ -163,7 +165,7 @@ auth_request_save_cache(request, result); cache_key = passdb_cache == NULL ? NULL : - request->auth->passdb->cache_key; + request->passdb->passdb->cache_key; if (result == PASSDB_RESULT_INTERNAL_FAILURE && cache_key != NULL) { /* lookup failed. if we're looking here only because the request was expired in cache, fallback to using cached @@ -190,6 +192,20 @@ strlen(request->passdb_password)); } + if (result != PASSDB_RESULT_OK && + result != PASSDB_RESULT_INTERNAL_FAILURE && + request->passdb->next != NULL) { + /* try next passdb. */ + if (request->extra_fields != NULL) + str_truncate(request->extra_fields, 0); + + request->state = AUTH_REQUEST_STATE_MECH_CONTINUE; + request->passdb = request->passdb->next; + auth_request_verify_plain(request, request->mech_password, + request->private_callback.verify_plain); + return; + } + safe_memset(request->mech_password, 0, strlen(request->mech_password)); request->private_callback.verify_plain(result, request); @@ -199,13 +215,14 @@ const char *password, verify_plain_callback_t *callback) { - struct passdb_module *passdb = request->auth->passdb; + struct passdb_module *passdb = request->passdb->passdb; enum passdb_result result; const char *cache_key; i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE); - request->mech_password = p_strdup(request->pool, password); + if (request->mech_password == NULL) + request->mech_password = p_strdup(request->pool, password); request->private_callback.verify_plain = callback; cache_key = passdb_cache == NULL ? NULL : passdb->cache_key; @@ -244,7 +261,7 @@ } cache_key = passdb_cache == NULL ? NULL : - request->auth->passdb->cache_key; + request->passdb->passdb->cache_key; if (result == PASSDB_RESULT_INTERNAL_FAILURE && cache_key != NULL) { /* lookup failed. if we're looking here only because the request was expired in cache, fallback to using cached @@ -269,7 +286,7 @@ enum passdb_credentials credentials, lookup_credentials_callback_t *callback) { - struct passdb_module *passdb = request->auth->passdb; + struct passdb_module *passdb = request->passdb->passdb; const char *cache_key, *result, *scheme; i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE); @@ -299,15 +316,40 @@ } } +void auth_request_userdb_callback(const char *result, + struct auth_request *request) +{ + if (result == NULL && request->userdb->next != NULL) { + /* try next userdb. */ + if (request->extra_fields != NULL) + str_truncate(request->extra_fields, 0); + + request->userdb = request->userdb->next; + auth_request_lookup_user(request, + request->private_callback.userdb); + return; + } + + if (result == NULL && request->client_pid != 0) { + /* this was actual login attempt */ + auth_request_log_error(request, "userdb", + "user not found from userdb"); + } + + request->private_callback.userdb(result, request); +} + void auth_request_lookup_user(struct auth_request *request, userdb_callback_t *callback) { - struct userdb_module *userdb = request->auth->userdb; + struct userdb_module *userdb = request->userdb->userdb; + + request->private_callback.userdb = callback; if (userdb->blocking) - userdb_blocking_lookup(request, callback); + userdb_blocking_lookup(request); else - userdb->lookup(request, callback); + userdb->lookup(request, auth_request_userdb_callback); } int auth_request_set_username(struct auth_request *request,
--- a/src/auth/auth-request.h Mon Mar 07 11:42:54 2005 +0200 +++ b/src/auth/auth-request.h Mon Mar 07 20:55:13 2005 +0200 @@ -28,6 +28,8 @@ struct mech_module *mech; struct auth *auth; + struct auth_passdb *passdb; + struct auth_userdb *userdb; unsigned int connect_uid; unsigned int client_pid; @@ -109,5 +111,7 @@ void auth_request_lookup_credentials_callback(enum passdb_result result, const char *credentials, struct auth_request *request); +void auth_request_userdb_callback(const char *result, + struct auth_request *request); #endif
--- a/src/auth/auth-worker-client.c Mon Mar 07 11:42:54 2005 +0200 +++ b/src/auth/auth-worker-client.c Mon Mar 07 20:55:13 2005 +0200 @@ -54,6 +54,8 @@ auth_request->refcount = 1; auth_request->created = ioloop_time; auth_request->auth = client->auth; + auth_request->passdb = client->auth->passdbs; + auth_request->userdb = client->auth->userdbs; client->refcount++; auth_request->context = client; @@ -115,6 +117,15 @@ /* verify plaintext password */ struct auth_request *auth_request; const char *password; + unsigned int num; + + num = atoi(t_strcut(args, '\t')); + args = strchr(args, '\t'); + if (args == NULL) { + i_error("BUG: Auth worker server sent us invalid PASSV"); + return; + } + args++; password = t_strcut(args, '\t'); args = strchr(args, '\t'); @@ -124,8 +135,16 @@ auth_request->mech_password = p_strdup(auth_request->pool, password); - client->auth->passdb->verify_plain(auth_request, password, - verify_plain_callback); + for (; num > 0; num++) { + auth_request->passdb = auth_request->passdb->next; + if (auth_request->passdb == NULL) { + i_error("BUG: PASSV had invalid passdb num"); + return; + } + } + + auth_request->passdb->passdb->verify_plain(auth_request, password, + verify_plain_callback); } static void @@ -162,16 +181,35 @@ struct auth_request *auth_request; const char *credentials_str; enum passdb_credentials credentials; + unsigned int num; + + num = atoi(t_strcut(args, '\t')); + args = strchr(args, '\t'); + if (args == NULL) { + i_error("BUG: Auth worker server sent us invalid PASSL"); + return; + } + args++; credentials_str = t_strcut(args, '\t'); args = strchr(args, '\t'); if (args != NULL) args++; - credentials = atoi(credentials_str); + credentials = atoi(credentials_str); auth_request = worker_auth_request_new(client, id, args); - client->auth->passdb->lookup_credentials(auth_request, credentials, - lookup_credentials_callback); + + for (; num > 0; num++) { + auth_request->passdb = auth_request->passdb->next; + if (auth_request->passdb == NULL) { + i_error("BUG: PASSL had invalid passdb num"); + return; + } + } + + auth_request->passdb->passdb-> + lookup_credentials(auth_request, credentials, + lookup_credentials_callback); } static void @@ -196,9 +234,24 @@ { /* lookup user */ struct auth_request *auth_request; + unsigned int num; + + num = atoi(t_strcut(args, '\t')); + args = strchr(args, '\t'); + if (args != NULL) args++; auth_request = worker_auth_request_new(client, id, args); - client->auth->userdb->lookup(auth_request, lookup_user_callback); + + for (; num > 0; num++) { + auth_request->userdb = auth_request->userdb->next; + if (auth_request->userdb == NULL) { + i_error("BUG: USER had invalid userdb num"); + return; + } + } + + auth_request->userdb->userdb-> + lookup(auth_request, lookup_user_callback); } static int
--- a/src/auth/auth.c Mon Mar 07 11:42:54 2005 +0200 +++ b/src/auth/auth.c Mon Mar 07 20:55:13 2005 +0200 @@ -7,6 +7,7 @@ #include "mech.h" #include "userdb.h" #include "passdb.h" +#include "passdb-cache.h" #include "auth.h" #include "auth-request-handler.h" @@ -15,23 +16,46 @@ struct auth *auth_preinit(void) { - struct auth *auth; - const char *env; + struct auth *auth; + const char *driver, *args; + pool_t pool; + unsigned int i; - auth = i_new(struct auth, 1); + pool = pool_alloconly_create("auth", 1024); + auth = p_new(pool, struct auth, 1); + auth->pool = pool; auth->verbose = getenv("VERBOSE") != NULL; auth->verbose_debug = getenv("VERBOSE_DEBUG") != NULL; - env = getenv("PASSDB"); - if (env == NULL) - i_fatal("PASSDB environment is unset"); - passdb_preinit(auth, env); + t_push(); + for (i = 1; ; i++) { + driver = getenv(t_strdup_printf("PASSDB_%u_DRIVER", i)); + if (driver == NULL) + break; + + args = getenv(t_strdup_printf("PASSDB_%u_ARGS", i)); + passdb_preinit(auth, driver, args); + + } + t_pop(); - env = getenv("USERDB"); - if (env == NULL) - i_fatal("USERDB environment is unset"); - userdb_preinit(auth, env); + t_push(); + for (i = 1; ; i++) { + driver = getenv(t_strdup_printf("USERDB_%u_DRIVER", i)); + if (driver == NULL) + break; + + args = getenv(t_strdup_printf("USERDB_%u_ARGS", i)); + userdb_preinit(auth, driver, args); + + } + t_pop(); + + if (auth->passdbs == NULL) + i_fatal("No password databases set"); + if (auth->userdbs == NULL) + i_fatal("No user databases set"); return auth; } @@ -51,7 +75,7 @@ { struct mech_module_list *list; - list = i_new(struct mech_module_list, 1); + list = p_new(auth->pool, struct mech_module_list, 1); list->module = *mech; str_printfa(auth->mech_handshake, "MECH\t%s", mech->mech_name); @@ -75,35 +99,62 @@ auth->mech_modules = list; } +static int auth_passdb_list_have_plain(struct auth *auth) +{ + struct auth_passdb *passdb; + + for (passdb = auth->passdbs; passdb != NULL; passdb = passdb->next) { + if (passdb->passdb->verify_plain != NULL) + return TRUE; + } + return FALSE; +} + +static int auth_passdb_list_have_credentials(struct auth *auth) +{ + struct auth_passdb *passdb; + + for (passdb = auth->passdbs; passdb != NULL; passdb = passdb->next) { + if (passdb->passdb->lookup_credentials != NULL) + return TRUE; + } + return FALSE; +} + static void auth_mech_list_verify_passdb(struct auth *auth) { struct mech_module_list *list; for (list = auth->mech_modules; list != NULL; list = list->next) { if (list->module.passdb_need_plain && - auth->passdb->verify_plain == NULL) + !auth_passdb_list_have_plain(auth)) break; if (list->module.passdb_need_credentials && - auth->passdb->lookup_credentials == NULL) + !auth_passdb_list_have_credentials(auth)) break; } if (list != NULL) { - i_fatal("Passdb %s doesn't support %s method", - auth->passdb->name, list->module.mech_name); + i_fatal("%s mechanism can't be supported with given passdbs", + list->module.mech_name); } } void auth_init(struct auth *auth) { + struct auth_passdb *passdb; + struct auth_userdb *userdb; struct mech_module *mech; const char *const *mechanisms; const char *env; - passdb_init(auth); - userdb_init(auth); + for (passdb = auth->passdbs; passdb != NULL; passdb = passdb->next) + passdb_init(passdb); + for (userdb = auth->userdbs; userdb != NULL; userdb = userdb->next) + userdb_init(userdb); + passdb_cache_init(); - auth->mech_handshake = str_new(default_pool, 512); + auth->mech_handshake = str_new(auth->pool, 512); auth->anonymous_username = getenv("ANONYMOUS_USERNAME"); if (auth->anonymous_username != NULL && @@ -170,8 +221,14 @@ void auth_deinit(struct auth *auth) { - userdb_deinit(auth); - passdb_deinit(auth); + struct auth_passdb *passdb; + struct auth_userdb *userdb; - str_free(auth->mech_handshake); + passdb_cache_deinit(); + for (passdb = auth->passdbs; passdb != NULL; passdb = passdb->next) + passdb_deinit(passdb); + for (userdb = auth->userdbs; userdb != NULL; userdb = userdb->next) + userdb_deinit(userdb); + + pool_unref(auth->pool); }
--- a/src/auth/auth.h Mon Mar 07 11:42:54 2005 +0200 +++ b/src/auth/auth.h Mon Mar 07 20:55:13 2005 +0200 @@ -1,19 +1,38 @@ #ifndef __AUTH_H #define __AUTH_H +struct auth_passdb { + struct auth *auth; + struct auth_passdb *next; + + unsigned int num; + const char *args; + struct passdb_module *passdb; +#ifdef HAVE_MODULES + struct auth_module *module; +#endif +}; + +struct auth_userdb { + struct auth *auth; + struct auth_userdb *next; + + unsigned int num; + const char *args; + struct userdb_module *userdb; +#ifdef HAVE_MODULES + struct auth_module *module; +#endif +}; + struct auth { + pool_t pool; + struct mech_module_list *mech_modules; buffer_t *mech_handshake; - struct passdb_module *passdb; - struct userdb_module *userdb; - -#ifdef HAVE_MODULES - struct auth_module *passdb_module; - struct auth_module *userdb_module; -#endif - - char *passdb_args, *userdb_args; + struct auth_passdb *passdbs; + struct auth_userdb *userdbs; const char *const *auth_realms; const char *default_realm;
--- a/src/auth/main.c Mon Mar 07 11:42:54 2005 +0200 +++ b/src/auth/main.c Mon Mar 07 20:55:13 2005 +0200 @@ -271,6 +271,7 @@ for (i = 0; i < size; i++) auth_master_connection_destroy(master[i]); } + buffer_free(masters_buf); auth_request_handler_deinit(); auth_deinit(auth);
--- a/src/auth/passdb-blocking.c Mon Mar 07 11:42:54 2005 +0200 +++ b/src/auth/passdb-blocking.c Mon Mar 07 20:55:13 2005 +0200 @@ -12,19 +12,35 @@ static enum passdb_result check_failure(struct auth_request *request, const char **reply) { + enum passdb_result ret; + const char *p; + /* OK / FAIL */ if (strncmp(*reply, "OK\t", 3) == 0) { *reply += 3; return PASSDB_RESULT_OK; } - /* FAIL \t result */ - if (strncmp(*reply, "FAIL\t", 5) != 0) { + /* FAIL \t result \t password */ + if (strncmp(*reply, "FAIL\t", 5) == 0) { + *reply += 5; + ret = atoi(t_strcut(*reply, '\t')); + + p = strchr(*reply, '\t'); + if (p == NULL) + *reply += strlen(*reply); + else + *reply = p + 1; + if (ret != PASSDB_RESULT_OK) + return ret; + + auth_request_log_error(request, "blocking", + "Received invalid FAIL result from worker: %d", ret); + return PASSDB_RESULT_INTERNAL_FAILURE; + } else { auth_request_log_error(request, "blocking", "Received unknown reply from worker: %s", *reply); return PASSDB_RESULT_INTERNAL_FAILURE; - } else { - return atoi(*reply + 5); } } @@ -90,7 +106,7 @@ i_assert(request->extra_fields == NULL); str = t_str_new(64); - str_append(str, "PASSV\t"); + str_printfa(str, "PASSV\t%u\t", request->passdb->num); str_append(str, request->mech_password); str_append_c(str, '\t'); auth_request_export(request, str); @@ -123,7 +139,8 @@ i_assert(request->extra_fields == NULL); str = t_str_new(64); - str_printfa(str, "PASSL\t%d\t", request->credentials); + str_printfa(str, "PASSL\t%u\t%d\t", + request->passdb->num, request->credentials); auth_request_export(request, str); auth_worker_call(request, str_c(str), lookup_credentials_callback);
--- a/src/auth/passdb.c Mon Mar 07 11:42:54 2005 +0200 +++ b/src/auth/passdb.c Mon Mar 07 20:55:13 2005 +0200 @@ -5,7 +5,6 @@ #include "password-scheme.h" #include "auth-worker-server.h" #include "passdb.h" -#include "passdb-cache.h" #include <stdlib.h> @@ -117,67 +116,65 @@ callback(PASSDB_RESULT_OK, password, auth_request); } -void passdb_preinit(struct auth *auth, const char *data) +void passdb_preinit(struct auth *auth, const char *driver, const char *args) { struct passdb_module **p; - const char *name, *args; - - args = strchr(data, ' '); - name = t_strcut(data, ' '); + struct auth_passdb *auth_passdb, **dest; if (args == NULL) args = ""; - while (*args == ' ' || *args == '\t') - args++; - auth->passdb_args = i_strdup(args); + auth_passdb = p_new(auth->pool, struct auth_passdb, 1); + auth_passdb->auth = auth; + auth_passdb->args = p_strdup(auth->pool, args); + + for (dest = &auth->passdbs; *dest != NULL; dest = &(*dest)->next) + auth_passdb->num++; + *dest = auth_passdb; for (p = passdbs; *p != NULL; p++) { - if (strcmp((*p)->name, name) == 0) { - auth->passdb = *p; + if (strcmp((*p)->name, driver) == 0) { + auth_passdb->passdb = *p; break; } } #ifdef HAVE_MODULES - auth->passdb_module = auth->passdb != NULL ? NULL : - auth_module_open(name); - if (auth->passdb_module != NULL) { - auth->passdb = auth_module_sym(auth->passdb_module, - t_strconcat("passdb_", name, - NULL)); + if (auth_passdb->passdb == NULL) + auth_passdb->module = auth_module_open(driver); + if (auth_passdb->module != NULL) { + auth_passdb->passdb = + auth_module_sym(auth_passdb->module, + t_strconcat("passdb_", driver, NULL)); } #endif - if (auth->passdb == NULL) - i_fatal("Unknown passdb type '%s'", name); + if (auth_passdb->passdb == NULL) + i_fatal("Unknown passdb driver '%s'", driver); - if (auth->passdb->preinit != NULL) - auth->passdb->preinit(auth->passdb_args); + if (auth_passdb->passdb->preinit != NULL) + auth_passdb->passdb->preinit(auth_passdb->args); } -void passdb_init(struct auth *auth) +void passdb_init(struct auth_passdb *passdb) { - passdb_cache_init(); - if (auth->passdb->init != NULL) - auth->passdb->init(auth->passdb_args); + if (passdb->passdb->init != NULL) + passdb->passdb->init(passdb->args); - i_assert(auth->passdb->default_pass_scheme != NULL || - auth->passdb->cache_key == NULL); + i_assert(passdb->passdb->default_pass_scheme != NULL || + passdb->passdb->cache_key == NULL); - if (auth->passdb->blocking && !worker) { + if (passdb->passdb->blocking && !worker) { /* blocking passdb - we need an auth server */ auth_worker_server_init(); } } -void passdb_deinit(struct auth *auth) +void passdb_deinit(struct auth_passdb *passdb) { - if (auth->passdb->deinit != NULL) - auth->passdb->deinit(); + if (passdb->passdb->deinit != NULL) + passdb->passdb->deinit(); #ifdef HAVE_MODULES - if (auth->passdb_module != NULL) - auth_module_close(auth->passdb_module); + if (passdb->module != NULL) + auth_module_close(passdb->module); #endif - passdb_cache_deinit(); - i_free(auth->passdb_args); }
--- a/src/auth/passdb.h Mon Mar 07 11:42:54 2005 +0200 +++ b/src/auth/passdb.h Mon Mar 07 20:55:13 2005 +0200 @@ -67,9 +67,9 @@ lookup_credentials_callback_t *callback, struct auth_request *auth_request); -void passdb_preinit(struct auth *auth, const char *data); -void passdb_init(struct auth *auth); -void passdb_deinit(struct auth *auth); +void passdb_preinit(struct auth *auth, const char *driver, const char *args); +void passdb_init(struct auth_passdb *passdb); +void passdb_deinit(struct auth_passdb *passdb); #include "auth-request.h"
--- a/src/auth/userdb-blocking.c Mon Mar 07 11:42:54 2005 +0200 +++ b/src/auth/userdb-blocking.c Mon Mar 07 20:55:13 2005 +0200 @@ -13,15 +13,12 @@ request->private_callback.userdb(reply, request); } -void userdb_blocking_lookup(struct auth_request *request, - userdb_callback_t *callback) +void userdb_blocking_lookup(struct auth_request *request) { string_t *str; - request->private_callback.userdb = callback; - str = t_str_new(64); - str_append(str, "USER\t"); + str_printfa(str, "USER\t%u\t", request->userdb->num); auth_request_export(request, str); auth_worker_call(request, str_c(str), user_callback);
--- a/src/auth/userdb-blocking.h Mon Mar 07 11:42:54 2005 +0200 +++ b/src/auth/userdb-blocking.h Mon Mar 07 20:55:13 2005 +0200 @@ -1,7 +1,6 @@ #ifndef __USERDB_BLOCKING_H #define __USERDB_BLOCKING_H -void userdb_blocking_lookup(struct auth_request *request, - userdb_callback_t *callback); +void userdb_blocking_lookup(struct auth_request *request); #endif
--- a/src/auth/userdb.c Mon Mar 07 11:42:54 2005 +0200 +++ b/src/auth/userdb.c Mon Mar 07 20:55:13 2005 +0200 @@ -77,56 +77,57 @@ return gr->gr_gid; } -void userdb_preinit(struct auth *auth, const char *data) +void userdb_preinit(struct auth *auth, const char *driver, const char *args) { struct userdb_module **p; - const char *name, *args; - - args = strchr(data, ' '); - name = t_strcut(data, ' '); + struct auth_userdb *auth_userdb, **dest; if (args == NULL) args = ""; - while (*args == ' ' || *args == '\t') - args++; - auth->userdb_args = i_strdup(args); + auth_userdb = p_new(auth->pool, struct auth_userdb, 1); + auth_userdb->auth = auth; + auth_userdb->args = p_strdup(auth->pool, args); + + for (dest = &auth->userdbs; *dest != NULL; dest = &(*dest)->next) + auth_userdb->num++; + *dest = auth_userdb; for (p = userdbs; *p != NULL; p++) { - if (strcmp((*p)->name, name) == 0) { - auth->userdb = *p; + if (strcmp((*p)->name, driver) == 0) { + auth_userdb->userdb = *p; break; } } + #ifdef HAVE_MODULES - auth->userdb_module = auth->userdb != NULL ? NULL : - auth_module_open(name); - if (auth->userdb_module != NULL) { - auth->userdb = auth_module_sym(auth->userdb_module, - t_strconcat("userdb_", name, - NULL)); + if (auth_userdb->userdb == NULL) + auth_userdb->module = auth_module_open(driver); + if (auth_userdb->module != NULL) { + auth_userdb->userdb = + auth_module_sym(auth_userdb->module, + t_strconcat("userdb_", driver, NULL)); } #endif - if (auth->userdb == NULL) - i_fatal("Unknown userdb type '%s'", name); + if (auth_userdb->userdb == NULL) + i_fatal("Unknown userdb driver '%s'", driver); - if (auth->userdb->preinit != NULL) - auth->userdb->preinit(args); + if (auth_userdb->userdb->preinit != NULL) + auth_userdb->userdb->preinit(auth_userdb->args); } -void userdb_init(struct auth *auth) +void userdb_init(struct auth_userdb *userdb) { - if (auth->userdb->init != NULL) - auth->userdb->init(auth->userdb_args); + if (userdb->userdb->init != NULL) + userdb->userdb->init(userdb->args); } -void userdb_deinit(struct auth *auth) +void userdb_deinit(struct auth_userdb *userdb) { - if (auth->userdb->deinit != NULL) - auth->userdb->deinit(); + if (userdb->userdb->deinit != NULL) + userdb->userdb->deinit(); #ifdef HAVE_MODULES - if (auth->userdb_module != NULL) - auth_module_close(auth->userdb_module); + if (userdb->module != NULL) + auth_module_close(userdb->module); #endif - i_free(auth->userdb_args); }
--- a/src/auth/userdb.h Mon Mar 07 11:42:54 2005 +0200 +++ b/src/auth/userdb.h Mon Mar 07 20:55:13 2005 +0200 @@ -24,9 +24,9 @@ uid_t userdb_parse_uid(struct auth_request *request, const char *str); gid_t userdb_parse_gid(struct auth_request *request, const char *str); -void userdb_preinit(struct auth *auth, const char *data); -void userdb_init(struct auth *auth); -void userdb_deinit(struct auth *auth); +void userdb_preinit(struct auth *auth, const char *driver, const char *args); +void userdb_init(struct auth_userdb *passdb); +void userdb_deinit(struct auth_userdb *passdb); #include "auth-request.h"
--- a/src/master/auth-process.c Mon Mar 07 11:42:54 2005 +0200 +++ b/src/master/auth-process.c Mon Mar 07 20:55:13 2005 +0200 @@ -397,6 +397,8 @@ static void auth_set_environment(struct auth_settings *set) { struct auth_socket_settings *as; + struct auth_passdb_settings *ap; + struct auth_userdb_settings *au; const char *str; int i; @@ -410,8 +412,6 @@ env_put(t_strconcat("MECHANISMS=", set->mechanisms, NULL)); env_put(t_strconcat("REALMS=", set->realms, NULL)); env_put(t_strconcat("DEFAULT_REALM=", set->default_realm, NULL)); - env_put(t_strconcat("USERDB=", set->userdb, NULL)); - env_put(t_strconcat("PASSDB=", set->passdb, NULL)); env_put(t_strconcat("USERNAME_CHARS=", set->username_chars, NULL)); env_put(t_strconcat("USERNAME_TRANSLATION=", set->username_translation, NULL)); @@ -420,6 +420,15 @@ env_put(t_strdup_printf("CACHE_SIZE=%u", set->cache_size)); env_put(t_strdup_printf("CACHE_TTL=%u", set->cache_ttl)); + for (ap = set->passdbs, i = 1; ap != NULL; ap = ap->next, i++) { + env_put(t_strdup_printf("PASSDB_%u_DRIVER=%s", i, ap->driver)); + env_put(t_strdup_printf("PASSDB_%u_ARGS=%s", i, ap->args)); + } + for (au = set->userdbs, i = 1; au != NULL; au = au->next, i++) { + env_put(t_strdup_printf("USERDB_%u_DRIVER=%s", i, au->driver)); + env_put(t_strdup_printf("USERDB_%u_ARGS=%s", i, au->args)); + } + for (as = set->sockets, i = 1; as != NULL; as = as->next, i++) { if (strcmp(as->type, "listen") != 0) continue;
--- a/src/master/master-settings.c Mon Mar 07 11:42:54 2005 +0200 +++ b/src/master/master-settings.c Mon Mar 07 20:55:13 2005 +0200 @@ -17,6 +17,8 @@ SETTINGS_TYPE_SERVER, SETTINGS_TYPE_AUTH, SETTINGS_TYPE_AUTH_SOCKET, + SETTINGS_TYPE_AUTH_PASSDB, + SETTINGS_TYPE_AUTH_USERDB, SETTINGS_TYPE_NAMESPACE, SETTINGS_TYPE_SOCKET }; @@ -29,6 +31,8 @@ struct auth_settings *auth; struct socket_settings *socket; struct auth_socket_settings *auth_socket; + struct auth_passdb_settings *auth_passdb; + struct auth_userdb_settings *auth_userdb; struct namespace_settings *namespace; int level; @@ -139,8 +143,6 @@ DEF(SET_STR, mechanisms), DEF(SET_STR, realms), DEF(SET_STR, default_realm), - DEF(SET_STR, userdb), - DEF(SET_STR, passdb), DEF(SET_INT, cache_size), DEF(SET_INT, cache_ttl), DEF(SET_STR, executable), @@ -186,6 +188,28 @@ #undef DEF #define DEF(type, name) \ + { type, #name, offsetof(struct auth_passdb_settings, name) } + +static struct setting_def auth_passdb_setting_defs[] = { + DEF(SET_STR, driver), + DEF(SET_STR, args), + + { 0, NULL, 0 } +}; + +#undef DEF +#define DEF(type, name) \ + { type, #name, offsetof(struct auth_userdb_settings, name) } + +static struct setting_def auth_userdb_setting_defs[] = { + DEF(SET_STR, driver), + DEF(SET_STR, args), + + { 0, NULL, 0 } +}; + +#undef DEF +#define DEF(type, name) \ { type, #name, offsetof(struct namespace_settings, name) } static struct setting_def namespace_setting_defs[] = { @@ -315,8 +339,6 @@ MEMBER(mechanisms) "plain", MEMBER(realms) NULL, MEMBER(default_realm) NULL, - MEMBER(userdb) "passwd", - MEMBER(passdb) "pam", MEMBER(cache_size) 0, MEMBER(cache_ttl) 3600, MEMBER(executable) PKG_LIBEXECDIR"/dovecot-auth", @@ -337,6 +359,8 @@ /* .. */ MEMBER(uid) 0, MEMBER(gid) 0, + MEMBER(passdbs) NULL, + MEMBER(userdbs) NULL, MEMBER(sockets) NULL }; @@ -646,6 +670,42 @@ return auth_settings_new(server, name); } +static struct auth_passdb_settings * +auth_passdb_settings_new(struct auth_settings *auth, const char *type) +{ + struct auth_passdb_settings *as, **as_p; + + as = p_new(settings_pool, struct auth_passdb_settings, 1); + + as->parent = auth; + as->driver = str_lcase(p_strdup(settings_pool, type)); + + as_p = &auth->passdbs; + while (*as_p != NULL) + as_p = &(*as_p)->next; + *as_p = as; + + return as; +} + +static struct auth_userdb_settings * +auth_userdb_settings_new(struct auth_settings *auth, const char *type) +{ + struct auth_userdb_settings *as, **as_p; + + as = p_new(settings_pool, struct auth_userdb_settings, 1); + + as->parent = auth; + as->driver = str_lcase(p_strdup(settings_pool, type)); + + as_p = &auth->userdbs; + while (*as_p != NULL) + as_p = &(*as_p)->next; + *as_p = as; + + return as; +} + static struct auth_socket_settings * auth_socket_settings_new(struct auth_settings *auth, const char *type) { @@ -775,6 +835,14 @@ return parse_setting_from_defs(settings_pool, auth_socket_setting_defs, ctx->auth_socket, key, value); + case SETTINGS_TYPE_AUTH_PASSDB: + return parse_setting_from_defs(settings_pool, + auth_passdb_setting_defs, + ctx->auth_passdb, key, value); + case SETTINGS_TYPE_AUTH_USERDB: + return parse_setting_from_defs(settings_pool, + auth_userdb_setting_defs, + ctx->auth_userdb, key, value); case SETTINGS_TYPE_NAMESPACE: return parse_setting_from_defs(settings_pool, namespace_setting_defs, @@ -906,6 +974,18 @@ return ctx->auth_socket != NULL; } + if (ctx->type == SETTINGS_TYPE_AUTH && strcmp(type, "passdb") == 0) { + ctx->type = SETTINGS_TYPE_AUTH_PASSDB; + ctx->auth_passdb = auth_passdb_settings_new(ctx->auth, name); + return TRUE; + } + + if (ctx->type == SETTINGS_TYPE_AUTH && strcmp(type, "userdb") == 0) { + ctx->type = SETTINGS_TYPE_AUTH_USERDB; + ctx->auth_userdb = auth_userdb_settings_new(ctx->auth, name); + return TRUE; + } + if (ctx->type == SETTINGS_TYPE_AUTH_SOCKET) { ctx->type = SETTINGS_TYPE_SOCKET;
--- a/src/master/master-settings.h Mon Mar 07 11:42:54 2005 +0200 +++ b/src/master/master-settings.h Mon Mar 07 20:55:13 2005 +0200 @@ -125,6 +125,22 @@ struct socket_settings client; }; +struct auth_passdb_settings { + struct auth_settings *parent; + struct auth_passdb_settings *next; + + const char *driver; + const char *args; +}; + +struct auth_userdb_settings { + struct auth_settings *parent; + struct auth_userdb_settings *next; + + const char *driver; + const char *args; +}; + struct auth_settings { struct server_settings *parent; struct auth_settings *next; @@ -133,8 +149,6 @@ const char *mechanisms; const char *realms; const char *default_realm; - const char *userdb; - const char *passdb; unsigned int cache_size; unsigned int cache_ttl; const char *executable; @@ -154,6 +168,8 @@ /* .. */ uid_t uid; gid_t gid; + struct auth_passdb_settings *passdbs; + struct auth_userdb_settings *userdbs; struct auth_socket_settings *sockets; };