Package: tacacs+ Version: 4.0.4.19-7 Severity: wishlist Tags: ipv6 patch Hello, While looking at the source code of tacacs+ I noticed that it uses gethostbyname(). This has two problems: * It's an obsolete call, see gethostbyname() * Depending on the libc6, you may get IPv6 addresses returned which will mean you will try to wedge a IPv6 address into an IPv4 sockaddr and you end up with a horrible mess.
See http://lists.debian.org/debian-ipv6/2010/05/msg00000.html for some discussion about this. The attached patch uses getaddrinfo() and fixes it to IPv4 addresses only. It could probably work with IPv6 too with some more checking. - Craig -- System Information: Debian Release: squeeze/sid APT prefers unstable APT policy: (500, 'unstable') Architecture: amd64 (x86_64) Kernel: Linux 2.6.32-trunk-amd64 (SMP w/2 CPU cores) Locale: LANG=en_AU.UTF-8, LC_CTYPE=en_AU.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Versions of packages tacacs+ depends on: ii adduser 3.112 add and remove users and groups ii libc6 2.10.2-8 Embedded GNU C Library: Shared lib ii libpam0g 1.1.1-3 Pluggable Authentication Modules l ii libtacacs+1 4.0.4.19-7 TACACS+ authentication daemon ii libwrap0 7.6.q-18 Wietse Venema's TCP wrappers libra ii python 2.5.4-9 An interactive high-level object-o tacacs+ recommends no packages. tacacs+ suggests no packages. -- Configuration Files: /etc/tacacs+/tac_plus.conf [Errno 13] Permission denied: u'/etc/tacacs+/tac_plus.conf' -- no debconf information
#! /bin/sh /usr/share/dpatch/dpatch-run ## gethostbyname.dpatch by <csm...@debian.org> ## ## All lines beginning with `## DP:' are a description of the patch. ## DP: uses getaddrinfo instead of gethostbyname @DPATCH@ diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' tacacs+-4.0.4.19~/maxsess.c tacacs+-4.0.4.19/maxsess.c --- tacacs+-4.0.4.19~/maxsess.c 2010-05-20 11:18:17.000000000 +1000 +++ tacacs+-4.0.4.19/maxsess.c 2010-05-20 11:18:50.000000000 +1000 @@ -351,39 +351,22 @@ static int ckfinger(char *user, char *nas, struct identity *idp) { - struct sockaddr_in sin; - struct servent *serv; - int count, s, bufsize; + struct addrinfo hints, *res; + int count, s, bufsize, errcode; char *buf, *p, *pn; int incr = 4096, slop = 32; - u_long inaddr; char *curport = portname(idp->NAS_port); char *name; - /* The finger service, aka port 79 */ - serv = getservbyname("finger", "tcp"); - if (serv) { - sin.sin_port = serv->s_port; - } else { - sin.sin_port = 79; - } - /* Get IP addr for the NAS */ - inaddr = inet_addr(nas); - if (inaddr != -1) { - /* A dotted decimal address */ - memcpy(&sin.sin_addr, &inaddr, sizeof(inaddr)); - sin.sin_family = AF_INET; - } else { - struct hostent *host = gethostbyname(nas); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; /* IPv4 only until all code is checked */ + hints.ai_socktype = SOCK_STREAM; - if (host == NULL) { - report(LOG_ERR, "ckfinger: gethostbyname %s failure: %s", - nas, strerror(errno)); + if ( (errcode = getaddrinfo(nas, "finger", &hints, &res)) != 0) { + report(LOG_ERR, "ckfinger: getaddrinfo %s failure: %s", + nas, gai_strerror(errcode)); return(0); - } - memcpy(&sin.sin_addr, host->h_addr, host->h_length); - sin.sin_family = host->h_addrtype; } s = socket(AF_INET, SOCK_STREAM, 0); @@ -391,11 +374,19 @@ report(LOG_ERR, "ckfinger: socket: %s", strerror(errno)); return(0); } - if (connect(s, (struct sockaddr *) & sin, sizeof(sin)) < 0) { + errcode=-1; + while (res) { + if ( (errcode = connect(s,res->ai_addr,res->ai_addrlen)) == 0) + break; + res = res->ai_next; + } + freeaddrinfo(res); + if (errcode != 0) { report(LOG_ERR, "ckfinger: connect failure %s", strerror(errno)); close(s); return(0); } + /* Read in the finger output into a single flat buffer */ buf = NULL; bufsize = 0;