krb5_kuserok and unreadable .k5login files

Geoffrey Thomas geofft at MIT.EDU
Sat Nov 6 22:06:43 EDT 2010


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
geofft at mit.edu



More information about the Kerberos mailing list