Alex Chernyakhovsky and I found some edge cases in the .k5login handling code when the file exists but is for some reason not readable. It appears the code is entirely designed to assume that if the file exists, it is readable. There are some specific cases where this is likely to happen, including when running under SELinux or on AFS.
Specifically, k5login_ok (in lib/krb5/os/kuserok.c) checks whether the file exists by checking access(filename, F_OK). However, the file can exist but not be readable, in which case the fopen() later will fail. It's not clear what the intended behavior here is, and the code seems to be treating a failure of fopen() more like a system error (compare e.g. the previous get_k5login_filename call returning ENOMEM) than explicitly considering the case of a .k5login that exists but isn't readable. Although the code presumably generally runs as root, there are a fair number of cases in which this can happen; we've run into the default SELinux configuration preventing ssh from reading files in users' home directories (see Red Hat Bugzilla #501107), and in AFS, since you don't have the user's tokens yet at this point, the obvious approach of making a .k5login in your non-world-readable AFS home directory will fail. There are also some cases where the file can exist but access() still returns nonzero; one in particular is EACCES. It's not clear to me if, say, POSIX allows that for F_OK, but AFS can actually return EACCESS in certain cases, specifically when the file hasn't been brought into cache by a user authenticated to read the file. In this case by a two-wrongs-make-a-right mechanism, you do in fact get to log in most of the time because the "if access(filename, F_OK) != 0" check can't distinguish ENOENT and any other nonzero return like EACCESS, and so the code behaves as if the file doesn't exist. Finally, it's not really clear that the correct response to the .k5login not being owned by the user or by root should cause a "REJECT" return, i.e., the same as if the .k5login existed and actively did not include the user. In the case of a malicious user creating the file, this seems to enable a denial-of-service as opposed to just returning "PASS", the return code given when the .k5login doesn't exist at all, in which case the user could at least log in with his/her own principal. On the other hand, in the non-malicious case (e.g. some AFS setups), this is definitely less helpful than "PASS". We're thinking that the best solution may be a fourth return code from k5login_ok, "UNUSABLE", in addition to ACCEPT/PASS/REJECT, to indicate that a .k5login exists but is unreadable or otherwise unusable to make security policy decisions. By default UNUSABLE would work like REJECT but instead callers of krb5_kuserok could use it to log a much clearer error asking you to investigate the permissions around the .k5login, but perhaps an option in krb5.conf could allow UNUSABLE to work like PASS. Another solution would be simply to explicitly consider the case of a .k5login being unreadable as the .k5login essentially not existing, and return PASS instead. -- Geoffrey Thomas [email protected] ________________________________________________ Kerberos mailing list [email protected] https://mailman.mit.edu/mailman/listinfo/kerberos
