COMMAND

    rlogin

SYSTEMS AFFECTED

    Linux

PROBLEM

    Jacob A.  Langford has  discovered a  bug in  the rhost  module of
    Linux-PAM-0.57.  This bug leads  to a vulnerability in the  remote
    login authentication, with the effect that ordinary user  accounts
    may not be password protected.

    There is only  one case when  the bug causes  a vulnerability. The
    problem case  is when  the user's  .rhost file  has the  name of a
    machine with *more than one IP address* as the *final* entry.

    To be explicit, here  are two example .rhost  files:  One of  them
    leaves an account wide open, the other does not.

        CAUSES PROBLEMS                  DOES NOT CAUSE PROBLEMS
        ----------------                 -----------------------

        karman.tam.uiuc.edu              vn.nas.nasa.gov
        vn.nas.nasa.gov                  karman.tam.uiuc.edu

    Note that  vn.nas.nasa.gov has  two IP  addresses.   Thus, as  the
    final entry of  a .rhost file,  it leaves the  user's account wide
    open, i.e.   any other user  of the same  name can log  in to that
    account from any machine without a password.

    The problem  is in  the rhost  module of  PAM.   The module  calls
    gethostbyname() in two locations, once for the connecting machine,
    then once  for each  named entry  in the  .rhosts file.   The call
    returns  a  structure  with  a  pointer  to a list of IP addresses
    stored  as  unsigned  longs.   Since  there  may  be  multiple  IP
    addresses, the PAM  code uses a  while loop over  the addresses of
    the connecting machine, then another while loop over the addresses
    of  the  machines  named  in  .rhosts.   These  while  loops   are
    terminated by  a null  pointer in  the address  list.   Apparently
    gethostbyname does not allocate new memory for the unsigned  longs
    each time  it is  called.   Thus the  calls to gethostbyname() for
    the .rhosts  entries clobber  the subsequent  IP addresses  of the
    connecting machine.   If the  final .rhost  entry is  a name  with
    multiple IP addresses, the the null terminator gets replaced  with
    the second IP address of the final entry in the .rhost file.   The
    second iteration of the while  loop on the connecting machine  now
    sets the IP number of the  connecting machine to the IP number  of
    the final  entry in  the .rhosts  file.   A match  follows and the
    account is open.

    Linux-PAM-0.58preG  (and  probably  Linux-PAM-0.59preA)  are still
    vulnerable.

SOLUTION

    Until the PAM module is updated, users should check that the  last
    entry of their .rhost file only has one IP address.  They can  use
    the command nslookup, for example.

    A fix:

    --- Linux-PAM-0.58.orig/modules/pam_rhosts/pam_rhosts_auth.c    Mon Aug  4 04:14:14 1997
    +++ Linux-PAM-0.58/modules/pam_rhosts/pam_rhosts_auth.c Wed Oct  1 11:43:14 1997
    @@ -524,25 +524,32 @@
     {
         struct hostent *hp;
         int answer = 1;                             /* default to failure */
    -    u_long addr;
    -    char **ap;
    +    u_long *addrs;
    +    int n, i;

         opts->last_error = (char *) 0;
         hp               = gethostbyname(rhost);         /* identify host */

         if (hp != NULL) {
    -       ap = hp->h_addr_list;
    -       while (*ap) {                     /* loop though address list */
    -           memcpy (&addr, *ap, sizeof(addr));
    -
    -           /* check user on remote host */
    -           if (pam_iruserok(pamh, opts, addr, superuser, ruser, luser, rhost)
    -               == 0) {
    -               answer = 0;                                /* success */
    -               break;
    -           }
    -           ++ap;
    -       }
    +
    +        /* loop though address list */
    +        for (n = 0; hp->h_addr_list[n]; n++);
    +        D(("rhosts: %d addresses", n))
    +
    +        if (n) {
    +            addrs = malloc (n * sizeof(*addrs));
    +            for (i = 0; i < n; i++)
    +                memcpy (addrs+i, hp->h_addr_list[i], sizeof(*addrs));
    +
    +            for (i = 0; i < n && answer; i++) {
    +                D(("rhosts: address %d is %04x", i, addrs[i]))
    +                answer = pam_iruserok(pamh, opts, addrs[i], superuser,
    +                                      ruser, luser, rhost);
    +                         /* answer == 0 means success */
    +            }
    +
    +            free (addrs);
    +        }
         }

         return answer;