diff -up pam_ssh_agent_auth-0.9/iterate_ssh_agent_keys.c.psaa-build pam_ssh_agent_auth-0.9/iterate_ssh_agent_keys.c --- pam_ssh_agent_auth-0.9/iterate_ssh_agent_keys.c.psaa-build 2009-08-08 11:51:04.000000000 +0200 +++ pam_ssh_agent_auth-0.9/iterate_ssh_agent_keys.c 2009-10-16 15:20:55.000000000 +0200 @@ -41,7 +41,16 @@ #include "buffer.h" #include "key.h" #include "authfd.h" +#include "ssh.h" #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include "userauth_pubkey_from_id.h" @@ -73,6 +82,96 @@ session_id2_gen() return cookie; } +/* + * Added by Jamie Beverly, ensure socket fd points to a socket owned by the user + * A cursory check is done, but to avoid race conditions, it is necessary + * to drop effective UID when connecting to the socket. + * + * If the cause of error is EACCES, because we verified we would not have that + * problem initially, we can safely assume that somebody is attempting to find a + * race condition; so a more "direct" log message is generated. + */ + +int +ssh_get_authentication_socket_for_uid(uid_t uid) +{ + const char *authsocket; + int sock; + struct sockaddr_un sunaddr; + struct stat sock_st; + + authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); + if (!authsocket) + return -1; + + /* Advisory only; seteuid ensures no race condition; but will only log if we see EACCES */ + if( stat(authsocket,&sock_st) == 0) { + if(uid != 0 && sock_st.st_uid != uid) { + fatal("uid %lu attempted to open an agent socket owned by uid %lu", (unsigned long) uid, (unsigned long) sock_st.st_uid); + return -1; + } + } + + /* + * Ensures that the EACCES tested for below can _only_ happen if somebody + * is attempting to race the stat above to bypass authentication. + */ + if( (sock_st.st_mode & S_IWUSR) != S_IWUSR || (sock_st.st_mode & S_IRUSR) != S_IRUSR) { + error("ssh-agent socket has incorrect permissions for owner"); + return -1; + } + + sunaddr.sun_family = AF_UNIX; + strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + return -1; + + /* close on exec */ + if (fcntl(sock, F_SETFD, 1) == -1) { + close(sock); + return -1; + } + + errno = 0; + seteuid(uid); /* To ensure a race condition is not used to circumvent the stat + above, we will temporarily drop UID to the caller */ + if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { + close(sock); + if(errno == EACCES) + fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); + return -1; + } + + seteuid(0); /* we now continue the regularly scheduled programming */ + + return sock; +} + +AuthenticationConnection * +ssh_get_authentication_connection_for_uid(uid_t uid) +{ + AuthenticationConnection *auth; + int sock; + + sock = ssh_get_authentication_socket_for_uid(uid); + + /* + * Fail if we couldn't obtain a connection. This happens if we + * exited due to a timeout. + */ + if (sock < 0) + return NULL; + + auth = xmalloc(sizeof(*auth)); + auth->fd = sock; + buffer_init(&auth->identities); + auth->howmany = 0; + + return auth; +} + int find_authorized_keys(uid_t uid) { @@ -85,7 +184,7 @@ find_authorized_keys(uid_t uid) OpenSSL_add_all_digests(); session_id2 = session_id2_gen(); - if ((ac = ssh_get_authentication_connection(uid))) { + if ((ac = ssh_get_authentication_connection_for_uid(uid))) { verbose("Contacted ssh-agent of user %s (%u)", getpwuid(uid)->pw_name, uid); for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) { @@ -113,3 +212,4 @@ find_authorized_keys(uid_t uid) EVP_cleanup(); return retval; } + diff -up pam_ssh_agent_auth-0.9/Makefile.in.psaa-build pam_ssh_agent_auth-0.9/Makefile.in --- pam_ssh_agent_auth-0.9/Makefile.in.psaa-build 2009-08-06 07:40:16.000000000 +0200 +++ pam_ssh_agent_auth-0.9/Makefile.in 2009-10-16 15:20:55.000000000 +0200 @@ -28,7 +28,7 @@ PATHS= CC=@CC@ LD=@LD@ CFLAGS=@CFLAGS@ -CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ +CPPFLAGS=-I.. -I$(srcdir) -I/usr/include/nss3 -I/usr/include/nspr4 @CPPFLAGS@ $(PATHS) @DEFS@ LIBS=@LIBS@ AR=@AR@ AWK=@AWK@ @@ -37,7 +37,7 @@ INSTALL=@INSTALL@ PERL=@PERL@ SED=@SED@ ENT=@ENT@ -LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ +LDFLAGS=-L.. -L../openbsd-compat/ @LDFLAGS@ LDFLAGS_SHARED = @LDFLAGS_SHARED@ EXEEXT=@EXEEXT@ @@ -48,7 +48,7 @@ PAM_MODULES=pam_ssh_agent_auth.so SSHOBJS=xmalloc.o atomicio.o authfd.o bufaux.o bufbn.o buffer.o cleanup.o entropy.o fatal.o key.o log.o misc.o secure_filename.o ssh-dss.o ssh-rsa.o uuencode.o compat.o -PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o +PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o secure_filename.o MANPAGES_IN = pam_ssh_agent_auth.pod @@ -67,13 +67,13 @@ $(PAM_MODULES): Makefile.in config.h .c.o: $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -LIBCOMPAT=openbsd-compat/libopenbsd-compat.a +LIBCOMPAT=../openbsd-compat/libopenbsd-compat.a $(LIBCOMPAT): always (cd openbsd-compat && $(MAKE)) always: -pam_ssh_agent_auth.so: $(LIBCOMPAT) $(SSHOBJS) $(PAM_SSH_AGENT_AUTH_OBJS) pam_ssh_agent_auth.o - $(LD) $(LDFLAGS_SHARED) -o $@ $(SSHOBJS) $(PAM_SSH_AGENT_AUTH_OBJS) $(LDFLAGS) -lopenbsd-compat $(LIBS) -lpam pam_ssh_agent_auth.o +pam_ssh_agent_auth.so: $(PAM_SSH_AGENT_AUTH_OBJS) pam_ssh_agent_auth.o + $(LD) $(LDFLAGS_SHARED) -o $@ $(PAM_SSH_AGENT_AUTH_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -lpam -lnss3 pam_ssh_agent_auth.o $(MANPAGES): $(MANPAGES_IN) pod2man --section=8 --release=v0.8 --name=pam_ssh_agent_auth --official --center "PAM" pam_ssh_agent_auth.pod > pam_ssh_agent_auth.8 diff -up pam_ssh_agent_auth-0.9/pam_user_authorized_keys.c.psaa-build pam_ssh_agent_auth-0.9/pam_user_authorized_keys.c --- pam_ssh_agent_auth-0.9/pam_user_authorized_keys.c.psaa-build 2009-07-29 02:46:38.000000000 +0200 +++ pam_ssh_agent_auth-0.9/pam_user_authorized_keys.c 2009-10-16 15:50:36.000000000 +0200 @@ -94,7 +94,7 @@ parse_authorized_key_file(const char *us /* * temporary copy, so that both tilde expansion and percent expansion both get to apply to the path */ - strncat(auth_keys_file_buf, authorized_keys_file_input, 4096); + strncat(auth_keys_file_buf, authorized_keys_file_input, sizeof(auth_keys_file_buf)-1); if(allow_user_owned_authorized_keys_file) authorized_keys_file_allowed_owner_uid = getpwnam(user)->pw_uid;