I'm trying to add "virtual" mailboxes to a system. Real users with different uids own domains. Each domain has a passwd-file passdb. I don't want to use this passwd-file for the userdb, because I want to fix the home, mail and uid/gid settings. Can I use the static userdb in a less static manner, e.g.
userdb static { args = uid=%{owner of /vmail/%d} gid=%{gid of /vmail/%d} home=/vmail/%d/users/%u mail=mbox:/vmail/%d/users/%u/mail:INBOX=/vmail/%d/users/%u/INBOX }
Or is it just a bad idea to let relatively untrusted domain owners manage their own passwd-file at all...?
Cheers,
John.
On Fri, 2007-04-20 at 14:00 +0100, John Robinson wrote:
I'm trying to add "virtual" mailboxes to a system. Real users with different uids own domains. Each domain has a passwd-file passdb. I don't want to use this passwd-file for the userdb, because I want to fix the home, mail and uid/gid settings. Can I use the static userdb in a less static manner, e.g.
userdb static { args = uid=%{owner of /vmail/%d} gid=%{gid of /vmail/%d} home=/vmail/%d/users/%u mail=mbox:/vmail/%d/users/%u/mail:INBOX=/vmail/%d/users/%u/INBOX }
Hmm. You could always use a checkpassword script which does everything, but the above does look like it could be useful. I'm just not sure what would be the best way to implement it so that it would be useful for other kinds of configurations too..
One possibility would be to set "uid_file=/vmail/%d gid_file=/vmail/%d". I guess that would be good. Added to TODO, but I'm not sure when I get around to implementing it.
On 11/05/2007 15:57, Timo Sirainen wrote:
On Fri, 2007-04-20 at 14:00 +0100, John Robinson wrote:
I'm trying to add "virtual" mailboxes to a system. Real users with different uids own domains. Each domain has a passwd-file passdb. I don't want to use this passwd-file for the userdb, because I want to fix the home, mail and uid/gid settings. Can I use the static userdb in a less static manner, e.g.
userdb static { args = uid=%{owner of /vmail/%d} gid=%{gid of /vmail/%d} home=/vmail/%d/users/%u mail=mbox:/vmail/%d/users/%u/mail:INBOX=/vmail/%d/users/%u/INBOX }
Hmm. You could always use a checkpassword script which does everything, but the above does look like it could be useful. I'm just not sure what would be the best way to implement it so that it would be useful for other kinds of configurations too..
One possibility would be to set "uid_file=/vmail/%d gid_file=/vmail/%d". I guess that would be good. Added to TODO, but I'm not sure when I get around to implementing it.
Something like the attached? It applies cleanly to 1.0.0, I've tested it lightly and it appears to work. My testing was to use passdb pam with userdb static { args = uid_file=/home/%u gid_file=/home/%u home=/home/%u }. It's perhaps not perfect: it doesn't complain if you set both uid and uid_file, ditto gid and gid_file, and it doesn't do any sanity checks on the result of the expansion[1]. Cheers, John. [1] Use uid_file=/vmail/%d and login with domain ../etc/passwd and you end up looking at /etc/passwd. I don't know whether this matters: it's only doing a stat(), hopefully dovecot won't let you check mail as root, and anyway presumably the user has already had their password checked by now, and someone logging in as foo@../etc/passwd or whatever would have failed a password check. diff -urN --exclude='*~' dovecot-1.0.0.orig/src/auth/userdb-static.c dovecot-1.0.0-semistatic/src/auth/userdb-static.c --- dovecot-1.0.0.orig/src/auth/userdb-static.c 2007-03-21 20:01:56.000000000 +0000 +++ dovecot-1.0.0-semistatic/src/auth/userdb-static.c 2007-05-15 02:46:32.000000000 +0100 @@ -10,6 +10,8 @@ #include "userdb.h" #include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> struct static_context { userdb_callback_t *callback, *old_callback; @@ -33,8 +35,10 @@ const struct var_expand_table *table; struct auth_stream_reply *reply; string_t *str; - const char *const *args, *value; + const char *const *args, *key, *value; unsigned int i, count; + bool ok = TRUE; + struct stat fileinfo; t_push(); str = t_str_new(256); @@ -46,17 +50,39 @@ args = array_get(&module->template, &count); i_assert((count % 2) == 0); for (i = 0; i < count; i += 2) { + key = args[i]; if (args[i+1] == NULL) value = NULL; else { str_truncate(str, 0); var_expand(str, args[i+1], table); value = str_c(str); + if (strcasecmp(key, "uid_file") == 0) { + if (stat(value, &fileinfo) != 0) { + ok = FALSE; + auth_request_log_info(auth_request, "static-userdb", + "Can't stat uid_file %s: %s", + value, strerror(errno)); + } else { + key = "uid"; + value = dec2str(fileinfo.st_uid); + } + } else if (strcasecmp(key, "gid_file") == 0) { + if (stat(value, &fileinfo) != 0) { + ok = FALSE; + auth_request_log_info(auth_request, "static-userdb", + "Can't stat gid_file %s: %s", + value, strerror(errno)); + } else { + key = "gid"; + value = dec2str(fileinfo.st_gid); + } + } } - auth_stream_reply_add(reply, args[i], value); + auth_stream_reply_add(reply, key, value); } - callback(USERDB_RESULT_OK, reply, auth_request); + callback((ok ? USERDB_RESULT_OK : USERDB_RESULT_INTERNAL_FAILURE), reply, auth_request); t_pop(); } @@ -131,11 +157,14 @@ const char *const *tmp, *key, *value; uid_t uid; gid_t gid; + bool uid_file; + bool gid_file; module = p_new(auth_userdb->auth->pool, struct static_userdb_module, 1); uid = (uid_t)-1; gid = (gid_t)-1; + uid_file = gid_file = FALSE; tmp = t_strsplit_spaces(args, " "); ARRAY_CREATE(&module->template, auth_userdb->auth->pool, @@ -165,6 +194,10 @@ value); } value = dec2str(gid); + } else if (strcasecmp(key, "uid_file") == 0) { + uid_file = TRUE; + } else if (strcasecmp(key, "gid_file") == 0) { + gid_file = TRUE; } else if (strcmp(key, "allow_all_users") == 0) { module->allow_all_users = value == NULL || strcasecmp(value, "yes") == 0; @@ -180,9 +213,9 @@ } t_pop(); - if (uid == (uid_t)-1) + if ((uid == (uid_t)-1) && !uid_file) i_fatal("static userdb: uid missing"); - if (gid == (gid_t)-1) + if ((gid == (gid_t)-1) && !gid_file) i_fatal("static userdb: gid missing"); return &module->module; }
On 15.5.2007, at 5.16, John Robinson wrote:
One possibility would be to set "uid_file=/vmail/%d gid_file=/ vmail/%d". I guess that would be good. Added to TODO, but I'm not sure when I
get around to implementing it.Something like the attached?
Otherwise it's OK, but I'd want it to work with all userdbs. Looks
like the code doesn't currently support doing that in any easy way.
With passdbs it'd have been easy to use auth_request_set_field(). I
guess I'll add a similar auth_request_add_userdb_field() for CVS HEAD.
[1] Use uid_file=/vmail/%d and login with domain ../etc/passwd and
you end up looking at /etc/passwd. I don't know whether this
matters: it's only doing a stat(), hopefully dovecot won't let you
check mail as root, and anyway presumably the user has already had
their password checked by now, and someone logging in as foo@../etc/ passwd or whatever would have failed a password check.
Right.
Hmm. Although this makes me think about deliver.. If using PAM/
checkpassword and userdb static, Dovecot can't verify that the user
exists. Now if the username or domain contains ../ in it, the %n and %
d variables in mail location will contain ../ also, which could mean
that deliver can write to locations where it's not ever supposed to
be writing anything.
I think the main problem is that username validations and
translations are done only for authentications, not for deliver's
userdb lookups. I guess I'll have to change this. After that '/' will
be in invalid character list by default.
Instead of %s strerror() you can use %m which does the same.
On Tue, 2007-05-15 at 12:24 +0300, Timo Sirainen wrote:
On 15.5.2007, at 5.16, John Robinson wrote:
One possibility would be to set "uid_file=/vmail/%d gid_file=/ vmail/%d". I guess that would be good. Added to TODO, but I'm not sure when I
get around to implementing it.Something like the attached?
Otherwise it's OK, but I'd want it to work with all userdbs. Looks
like the code doesn't currently support doing that in any easy way.
With passdbs it'd have been easy to use auth_request_set_field(). I
guess I'll add a similar auth_request_add_userdb_field() for CVS HEAD.
Added uidgid_file to v1.1 tree: http://hg.dovecot.org/dovecot/rev/f7cdede45a88
participants (2)
-
John Robinson
-
Timo Sirainen