[Dovecot] Different classes of user
Hello list! Only recently joined, please excuse me if this is a stupid question.
I'd like to have 2 classes of user: those with shell accounts, and those without. They'll all have "real" accounts, for which the password can be checked with PAM. I've set up SSL too. What I want to arrange is for users with shell accounts not to be succeed in logging in to Dovecot without using TLS/SSL. I'll have to allow unencrypted logins (for non-shell users), but I want to reject/refuse such a login from someone with a shell account.
I've already made my exim do this, with the following logic in my authenticator there: if (pam auth ok) and ((tls) or (user's shell not listed in /etc/shells))
I haven't worked out how to make Dovecot do this, yet. So far I just tried using * as the PAM service name, in the hope that not only would pop3 or imap get passed through, but pop3s and imaps might, and I had a line in my /etc/pam.d/imap and pop like this: auth required pam_succeed_if.so debug shell notin /bin/bash:/bin/sh which worked, but unfortunately also got used for imapS logins. Then I realised this was likely to be the wrong thing anyway, because it would presumably only cover IMAPS on port 993, and not IMAP+TLS on the usual port 143.
So I've had a go but got it wrong. What should I do to get it right?
Cheers,
John.
Just bumping my own question. On 10/02/2007 03:01, I wrote: [...]
What I want to arrange is for users with shell accounts not to be succeed in logging in to Dovecot without using TLS/SSL. I'll have to allow unencrypted logins (for non-shell users), but I want to reject/refuse such a login from someone with a shell account. [...] I've had a go but got it wrong. What should I do to get it right?
Anyone? Please?
Cheers,
John.
John Robinson wrote:
Just bumping my own question. On 10/02/2007 03:01, I wrote: [...]
What I want to arrange is for users with shell accounts not to be succeed in logging in to Dovecot without using TLS/SSL. I'll have to allow unencrypted logins (for non-shell users), but I want to reject/refuse such a login from someone with a shell account. [...] I've had a go but got it wrong. What should I do to get it right?
Anyone? Please?
Cheers,
John.
You could run two different Dovecot configurations simultaneously, one for SSL (not listening on the non-SSL ports) authenticating against shell or non-shell (having multiple passdb/authdbs probably) and one for non-SSL that authenticates only non-shell users. (This doesn't handle the TLS, alas, but most clients use SSL anyway, I think).
Hope this helps, Chris
-- --+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+- Christopher Wakelin, c.d.wakelin@reading.ac.uk IT Services Centre, The University of Reading, Tel: +44 (0)118 378 8439 Whiteknights, Reading, RG6 2AF, UK Fax: +44 (0)118 975 3094
On 14/02/2007 17:58, Chris Wakelin wrote:
You could run two different Dovecot configurations simultaneously, one for SSL (not listening on the non-SSL ports) authenticating against shell or non-shell (having multiple passdb/authdbs probably) and one for non-SSL that authenticates only non-shell users. (This doesn't handle the TLS, alas, but most clients use SSL anyway, I think).
Yeah, but, yuk, and anyway I really would like to handle TLS over port 143.
The most generic way I can quickly see of adding this feature would be to allow individual authentication processes, or different passdbs, a flag for whether they are to be used with or without SSL/TLS (default: either). Then people can have two authentication processes (or whatever), one handling SSL/TLS-enabled logins, and one handling others. In my case I could then use PAM for both but with different service names.
I'm sure I can't be the only person in the world who'd like to be able to handle with/without TLS differently. In fact, this might be of interest to almost anyone with both system and virtual users. Timo?
Cheers,
John.
On Wed, 2007-02-14 at 18:27 +0000, John Robinson wrote:
The most generic way I can quickly see of adding this feature would be to allow individual authentication processes, or different passdbs, a flag for whether they are to be used with or without SSL/TLS (default: either). Then people can have two authentication processes (or whatever), one handling SSL/TLS-enabled logins, and one handling others. In my case I could then use PAM for both but with different service names.
I'm sure I can't be the only person in the world who'd like to be able to handle with/without TLS differently. In fact, this might be of interest to almost anyone with both system and virtual users. Timo?
There was a patch to add '%c' variable to dovecot-auth which would say "TLS" or "SSL" or "". Or something like that. However that couldn't be passed to PAM.
Yea, maybe the disable_plaintext_auth setting could be added inside passdbs. But not before v1.0, so you'll need to figure out another way to do this.
On 14/02/2007 18:39, Timo Sirainen wrote:
On Wed, 2007-02-14 at 18:27 +0000, John Robinson wrote: [...]
I'm sure I can't be the only person in the world who'd like to be able to handle with/without TLS differently. In fact, this might be of interest to almost anyone with both system and virtual users. Timo?
There was a patch to add '%c' variable to dovecot-auth which would say "TLS" or "SSL" or "". Or something like that. However that couldn't be passed to PAM.
Yea, maybe the disable_plaintext_auth setting could be added inside passdbs. But not before v1.0, so you'll need to figure out another way to do this.
Right, I'm going to have to fudge it myself.
I propose to amend the syntax of the PAM service name in dovecot.conf, and allow a placeholder character at the end of it (probably ?). At runtime, if it's there, I'll either remove it or change it to an 's', varying the service name supplied by dovecot to PAM depending on whether the current connection uses TLS/SSL.
I'm not much of a C programmer, in fact I'm rusty at programming at all, but I'll have a go. In passdb-pam.c:pam_verify_plain(), what can I do to find out whether the current connection is using TLS/SSL? Hopefully this will end up being a 5-line patch and I won't introduce any horrific security hole.
Cheers,
John.
On Wed, 2007-02-14 at 19:17 +0000, John Robinson wrote:
I propose to amend the syntax of the PAM service name in dovecot.conf, and allow a placeholder character at the end of it (probably ?). At runtime, if it's there, I'll either remove it or change it to an 's', varying the service name supplied by dovecot to PAM depending on whether the current connection uses TLS/SSL.
I think I'll add the %c variable and than allow the PAM service name to contain %variables. So you can then use eg. "dovecot%c" as the service name and it expands to "dovecot" / "dovecotsecure" or something.
I'm not much of a C programmer, in fact I'm rusty at programming at all, but I'll have a go. In passdb-pam.c:pam_verify_plain(), what can I do to find out whether the current connection is using TLS/SSL? Hopefully this will end up being a 5-line patch and I won't introduce any horrific security hole.
Hmm. Actually it looks like dovecot-auth doesn't store that information anywhere. I think what you need is:
In auth_request_import() check if key contains "secured". If it does, it's SSL/TLS. Add such bitfield to struct auth_request. Then use it in the PAM code.
On 14/02/2007 19:52, Timo Sirainen wrote:
I propose to amend the syntax of the PAM service name in dovecot.conf, [...] I think I'll add the %c variable and than allow the PAM service name to contain %variables. So you can then use eg. "dovecot%c" as the service name and it expands to "dovecot" / "dovecotsecure" or something. [...] In auth_request_import() check if key contains "secured". If it does, it's SSL/TLS. Add such bitfield to struct auth_request. Then use it in
On Wed, 2007-02-14 at 19:17 +0000, John Robinson wrote: the PAM code.
Something like the attached? I've done both the %c patch myself (it expands to "secured") and sent the service name for expansion. It appears to work for me (I successfully used "dovecot%3c" with PAM files dovecot and dovecotsec), but I'd be very grateful if you'd look it over and see if there are any horrible errors in it - and if it's not too bad, feel free to include it in the distribution. Cheers, John. diff -ur --exclude='*.orig' --exclude='*.rej' --exclude='*~' dovecot-1.0.rc22.orig/src/auth/auth-request.c dovecot-1.0.rc22/src/auth/auth-request.c --- dovecot-1.0.rc22.orig/src/auth/auth-request.c 2007-01-24 16:35:00.000000000 +0000 +++ dovecot-1.0.rc22/src/auth/auth-request.c 2007-02-18 12:50:19.000000000 +0000 @@ -155,6 +155,8 @@ net_addr2ip(value, &request->local_ip); else if (strcmp(key, "rip") == 0) net_addr2ip(value, &request->remote_ip); + else if (strcmp(key, "secured") == 0) + request->tls_secured = 1; else return FALSE; @@ -1017,6 +1019,7 @@ { 'p', NULL }, { 'w', NULL }, { '!', NULL }, + { 'c', NULL }, { '\0', NULL } }; struct var_expand_table *tab; @@ -1051,6 +1054,7 @@ tab[9].value = auth_request->passdb == NULL ? "" : dec2str(auth_request->passdb->id); } + tab[10].value = auth_request->tls_secured ? "secured" : ""; return tab; } diff -ur --exclude='*.orig' --exclude='*.rej' --exclude='*~' dovecot-1.0.rc22.orig/src/auth/auth-request.h dovecot-1.0.rc22/src/auth/auth-request.h --- dovecot-1.0.rc22.orig/src/auth/auth-request.h 2007-01-16 13:21:58.000000000 +0000 +++ dovecot-1.0.rc22/src/auth/auth-request.h 2007-02-18 12:50:59.000000000 +0000 @@ -81,6 +81,7 @@ unsigned int proxy:1; unsigned int cert_username:1; unsigned int userdb_lookup:1; + unsigned int tls_secured:1; /* ... mechanism specific data ... */ }; diff -ur --exclude='*.orig' --exclude='*.rej' --exclude='*~' dovecot-1.0.rc22.orig/src/auth/passdb-pam.c dovecot-1.0.rc22/src/auth/passdb-pam.c --- dovecot-1.0.rc22.orig/src/auth/passdb-pam.c 2006-12-03 16:57:23.000000000 +0000 +++ dovecot-1.0.rc22/src/auth/passdb-pam.c 2007-02-18 12:47:35.000000000 +0000 @@ -393,9 +393,20 @@ const char *service; int fd[2]; pid_t pid; + const struct var_expand_table *table; + string_t *expanded_service; - service = module->service_name != NULL ? - module->service_name : request->service; + if (module->service_name == NULL) { + service = request->service; + } else { + t_push(); + expanded_service = t_str_new(256); + table = auth_request_get_var_expand_table(request, + auth_request_str_escape); + var_expand(expanded_service, module->service_name, table); + service = p_strdup(request->pool, str_c(expanded_service)); + t_pop(); + } if (pipe(fd) < 0) { auth_request_log_error(request, "pam", "pipe() failed: %m"); callback(PASSDB_RESULT_INTERNAL_FAILURE, request);
On Sun, 2007-02-18 at 12:57 +0000, John Robinson wrote:
- else if (strcmp(key, "secured") == 0)
request->tls_secured = 1;
Note that "secured" doesn't necessarily mean SSL/TLS. It's also set if you're logging in from the same computer (local ip == remote ip).
- if (module->service_name == NULL) {
service = request->service;
- } else {
t_push();
expanded_service = t_str_new(256);
table = auth_request_get_var_expand_table(request,
var_expand(expanded_service, module->service_name, table);
service = p_strdup(request->pool, str_c(expanded_service));
t_pop();
- }
I'd remove t_push/t_pop and use service = str_c(expanded_service) directly. p_strdup()ing from request pool uses more memory a bit longer.
Otherwise looks ok. But I think I'll add this to CVS HEAD and not v1.0. I'm at least trying to keep a feature freeze. :)
On 18/02/2007 13:07, Timo Sirainen wrote:
On Sun, 2007-02-18 at 12:57 +0000, John Robinson wrote:
- else if (strcmp(key, "secured") == 0)
request->tls_secured = 1;
Note that "secured" doesn't necessarily mean SSL/TLS. It's also set if you're logging in from the same computer (local ip == remote ip).
I guess it ought just to be called "secured" then, not "tls_secured", but I was only doing what you said :-)
[...]
I'd remove t_push/t_pop and use service = str_c(expanded_service) directly. p_strdup()ing from request pool uses more memory a bit longer.
Well, I copied'n'pasted from auth-request.c:auth_request_fix_username() which has an example of expanding a string, rather than really knowing what all those things did, hoping that they did it safely and securely.
Otherwise looks ok. But I think I'll add this to CVS HEAD and not v1.0. I'm at least trying to keep a feature freeze. :)
Oh go on, it's not likely to hurt any existing installations...
Cheers,
John.
On Sun, 2007-02-18 at 15:12 +0000, John Robinson wrote:
Otherwise looks ok. But I think I'll add this to CVS HEAD and not v1.0. I'm at least trying to keep a feature freeze. :)
Oh go on, it's not likely to hurt any existing installations...
I added %c to v1.0, but the service name only to CVS HEAD: http://dovecot.org/list/dovecot-cvs/2007-March/008036.html
On 10/03/2007 14:15, Timo Sirainen wrote:
On Sun, 2007-02-18 at 15:12 +0000, John Robinson wrote:
Otherwise looks ok. But I think I'll add this to CVS HEAD and not v1.0. I'm at least trying to keep a feature freeze. :) Oh go on, it's not likely to hurt any existing installations...
I added %c to v1.0, but the service name only to CVS HEAD: http://dovecot.org/list/dovecot-cvs/2007-March/008036.html
Here's that service name patch reworked for 1.0.0 (for which many thanks!). Timo, if you haven't already, you may want to change the internal default in CVS HEAD to "%Ls" instead of "%s" (as I have done in the attached), to handle the other PAMs which don't downcase the service name (an issue you fixed for 1.0). Cheers, John. diff -urN dovecot-1.0.0/src/auth/passdb-pam.c dovecot-1.0.0-pamservice/src/auth/passdb-pam.c --- dovecot-1.0.0/src/auth/passdb-pam.c 2007-04-03 04:35:42.000000000 +0100 +++ dovecot-1.0.0-pamservice/src/auth/passdb-pam.c 2007-04-17 11:01:09.000000000 +0100 @@ -15,6 +15,8 @@ #include "buffer.h" #include "ioloop.h" #include "hash.h" +#include "str.h" +#include "var-expand.h" #include "network.h" #include "passdb.h" #include "safe-memset.h" @@ -424,12 +426,16 @@ struct pam_passdb_module *module = (struct pam_passdb_module *)_module; struct pam_auth_request *pam_auth_request; enum passdb_result result; + string_t *expanded_service; const char *service; int fd[2]; pid_t pid; - service = module->service_name != NULL ? - module->service_name : t_str_lcase(request->service); + expanded_service = t_str_new(64); + var_expand(expanded_service, module->service_name, + auth_request_get_var_expand_table(request, NULL)); + service = str_c(expanded_service); + auth_request_log_debug(request, "pam", "lookup service=%s", service); if (worker) { @@ -505,7 +511,8 @@ } else if (strcmp(t_args[i], "blocking=yes") == 0) { module->module.blocking = TRUE; } else if (strcmp(t_args[i], "*") == 0) { - module->service_name = NULL; + /* for backwards compatibility */ + module->service_name = "%Ls"; } else if (t_args[i+1] == NULL) { if (*t_args[i] != '\0') { module->service_name =
participants (3)
-
Chris Wakelin
-
John Robinson
-
Timo Sirainen