Mercurial > dovecot > original-hg > dovecot-1.2
changeset 3504:ee0e39cf4ca5 HEAD
Added support for variables in passwd-file path.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Fri, 22 Jul 2005 15:42:57 +0300 |
parents | c727a35c9602 |
children | 0e05687892dc |
files | src/auth/db-passwd-file.c src/auth/db-passwd-file.h src/auth/passdb-passwd-file.c src/auth/userdb-passwd-file.c |
diffstat | 4 files changed, 179 insertions(+), 44 deletions(-) [+] |
line wrap: on
line diff
--- a/src/auth/db-passwd-file.c Fri Jul 22 14:47:07 2005 +0300 +++ b/src/auth/db-passwd-file.c Fri Jul 22 15:42:57 2005 +0300 @@ -11,6 +11,7 @@ #include "istream.h" #include "hash.h" #include "str.h" +#include "var-expand.h" #include <stdlib.h> #include <unistd.h> @@ -120,7 +121,21 @@ hash_insert(pw->users, pu->user_realm, pu); } -static void passwd_file_open(struct passwd_file *pw) +static struct passwd_file * +passwd_file_new(struct db_passwd_file *db, const char *expanded_path) +{ + struct passwd_file *pw; + + pw = i_new(struct passwd_file, 1); + pw->db = db; + pw->path = i_strdup(expanded_path); + pw->fd = -1; + + hash_insert(db->files, pw->path, pw); + return pw; +} + +static int passwd_file_open(struct passwd_file *pw) { struct istream *input; const char *const *args; @@ -129,11 +144,16 @@ int fd; fd = open(pw->path, O_RDONLY); - if (fd == -1) - i_fatal("passwd-file %s: Can't open file: %m", pw->path); + if (fd == -1) { + i_error("passwd-file %s: Can't open file: %m", pw->path); + return FALSE; + } - if (fstat(fd, &st) != 0) - i_fatal("passwd-file %s: fstat() failed: %m", pw->path); + if (fstat(fd, &st) != 0) { + i_error("passwd-file %s: fstat() failed: %m", pw->path); + (void)close(fd); + return FALSE; + } pw->fd = fd; pw->stamp = st.st_mtime; @@ -153,11 +173,12 @@ /* at least two fields */ const char *no_args = NULL; passwd_file_add(pw, args[0], args[1], - pw->userdb ? args+2 : &no_args); + pw->db->userdb ? args+2 : &no_args); } t_pop(); } i_stream_unref(input); + return TRUE; } static void passwd_file_close(struct passwd_file *pw) @@ -178,51 +199,157 @@ } } -static void passwd_file_sync(struct passwd_file *pw) +static void passwd_file_free(struct passwd_file *pw) +{ + hash_remove(pw->db->files, pw->path); + + passwd_file_close(pw); + i_free(pw->path); + i_free(pw); +} + +static int passwd_file_sync(struct passwd_file *pw) { struct stat st; - if (stat(pw->path, &st) < 0) - i_fatal("passwd-file %s: stat() failed: %m", pw->path); + if (stat(pw->path, &st) < 0) { + /* with variables don't give hard errors, or errors about + nonexisting files */ + if (errno != ENOENT) + i_error("passwd-file %s: stat() failed: %m", pw->path); + + passwd_file_free(pw); + return FALSE; + } if (st.st_mtime != pw->stamp) { passwd_file_close(pw); - passwd_file_open(pw); + return passwd_file_open(pw); + } + return TRUE; +} + +struct db_passwd_file *db_passwd_file_parse(const char *path, int userdb) +{ + struct db_passwd_file *db; + const char *p; + int percents = FALSE; + + db = i_new(struct db_passwd_file, 1); + db->refcount = 1; + db->userdb = userdb; + db->files = hash_create(default_pool, default_pool, 100, + str_hash, (hash_cmp_callback_t *)strcmp); + + for (p = path; *p != '\0'; p++) { + if (*p == '%' && p[1] != '\0') { + p++; + switch (var_get_key(p)) { + case 'd': + db->domain_var = TRUE; + db->vars = TRUE; + break; + case '%': + percents = TRUE; + break; + default: + db->vars = TRUE; + break; + } + } + } + + if (percents && !db->vars) { + /* just extra escaped % chars. remove them. */ + struct var_expand_table empty_table[1]; + string_t *dest; + + empty_table[0].key = '\0'; + dest = t_str_new(256); + var_expand(dest, path, empty_table); + path = str_c(dest); + } + + db->path = i_strdup(path); + + if (!db->vars) { + /* no variables, open the file immediately */ + db->default_file = passwd_file_new(db, path); + if (!passwd_file_open(db->default_file)) + exit(FATAL_DEFAULT); + } + return db; +} + +void db_passwd_file_unref(struct db_passwd_file *db) +{ + struct hash_iterate_context *iter; + void *key, *value; + + if (--db->refcount == 0) { + iter = hash_iterate_init(db->files); + while (hash_iterate(iter, &key, &value)) + passwd_file_free(value); + hash_iterate_deinit(iter); + + hash_destroy(db->files); + i_free(db->path); + i_free(db); } } -struct passwd_file *db_passwd_file_parse(const char *path, int userdb) +static const char *path_fix(const char *path) { - struct passwd_file *pw; - - pw = i_new(struct passwd_file, 1); - pw->refcount = 1; - pw->path = i_strdup(path); - pw->userdb = userdb; + const char *p; - passwd_file_open(pw); - return pw; -} + p = strchr(path, '/'); + if (p == NULL) + return path; -void db_passwd_file_unref(struct passwd_file *pw) -{ - if (--pw->refcount == 0) { - passwd_file_close(pw); - i_free(pw->path); - i_free(pw); - } + /* most likely this is an invalid request. just cut off the '/' and + everything after it. */ + return t_strdup_until(path, p); } struct passwd_user * -db_passwd_file_lookup(struct passwd_file *pw, struct auth_request *request) +db_passwd_file_lookup(struct db_passwd_file *db, struct auth_request *request) { + struct passwd_file *pw; struct passwd_user *pu; - passwd_file_sync(pw); + if (!db->vars) + pw = db->default_file; + else { + const struct var_expand_table *table; + string_t *dest; + + t_push(); + + table = auth_request_get_var_expand_table(request, path_fix); + dest = t_str_new(256); + var_expand(dest, db->path, table); - pu = hash_lookup(pw->users, request->user); + pw = hash_lookup(db->files, str_c(dest)); + if (pw == NULL) { + /* doesn't exist yet. create lookup for it. */ + pw = passwd_file_new(db, str_c(dest)); + } + + t_pop(); + } + + if (!passwd_file_sync(pw)) { + auth_request_log_info(request, "passwd-file", + "no passwd file"); + return NULL; + } + + t_push(); + pu = hash_lookup(pw->users, !db->domain_var ? request->user : + t_strcut(request->user, '@')); if (pu == NULL) auth_request_log_info(request, "passwd-file", "unknown user"); + t_pop(); return pu; }
--- a/src/auth/db-passwd-file.h Fri Jul 22 14:47:07 2005 +0300 +++ b/src/auth/db-passwd-file.h Fri Jul 22 15:42:57 2005 +0300 @@ -15,24 +15,35 @@ }; struct passwd_file { - int refcount; + struct db_passwd_file *db; pool_t pool; char *path; time_t stamp; int fd; - int userdb; struct hash_table *users; }; -extern struct passwd_file *userdb_pwf; -extern struct passwd_file *passdb_pwf; +struct db_passwd_file { + int refcount; + + char *path; + struct hash_table *files; + struct passwd_file *default_file; + + unsigned int domain_var:1; + unsigned int vars:1; + unsigned int userdb:1; +}; + +extern struct db_passwd_file *userdb_pwf; +extern struct db_passwd_file *passdb_pwf; struct passwd_user * -db_passwd_file_lookup(struct passwd_file *pw, struct auth_request *request); +db_passwd_file_lookup(struct db_passwd_file *db, struct auth_request *request); -struct passwd_file *db_passwd_file_parse(const char *path, int userdb); -void db_passwd_file_unref(struct passwd_file *pw); +struct db_passwd_file *db_passwd_file_parse(const char *path, int userdb); +void db_passwd_file_unref(struct db_passwd_file *db); #endif
--- a/src/auth/passdb-passwd-file.c Fri Jul 22 14:47:07 2005 +0300 +++ b/src/auth/passdb-passwd-file.c Fri Jul 22 15:42:57 2005 +0300 @@ -8,7 +8,7 @@ #include "password-scheme.h" #include "db-passwd-file.h" -struct passwd_file *passdb_pwf = NULL; +struct db_passwd_file *passdb_pwf = NULL; static void passwd_file_verify_plain(struct auth_request *request, const char *password, @@ -24,10 +24,6 @@ return; } - /* we use case-sensitive lookups. otherwise we'd have to update - request->user to pu->user */ - i_assert(strcmp(request->user, pu->user_realm) == 0); - crypted_pass = pu->password; scheme = password_get_scheme(&crypted_pass); if (scheme == NULL) scheme = "CRYPT";
--- a/src/auth/userdb-passwd-file.c Fri Jul 22 14:47:07 2005 +0300 +++ b/src/auth/userdb-passwd-file.c Fri Jul 22 15:42:57 2005 +0300 @@ -8,7 +8,7 @@ #include "userdb.h" #include "db-passwd-file.h" -struct passwd_file *userdb_pwf = NULL; +struct db_passwd_file *userdb_pwf = NULL; static void passwd_file_lookup(struct auth_request *auth_request, userdb_callback_t *callback) @@ -42,7 +42,8 @@ /* resync */ userdb_pwf->userdb = TRUE; - userdb_pwf->stamp = 0; + if (userdb_pwf->default_file != NULL) + userdb_pwf->default_file->stamp = 0; } else { userdb_pwf = db_passwd_file_parse(args, TRUE); }