X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=libauthbind.c;h=42630e41a00686b66e3a41a6596deea8a16a1087;hb=827a62c6b263944cbb0406952012c2844762a83b;hp=99a7f3f7eaa9ef3c461f376eda07d1a804e535a6;hpb=59d14c88d280ffc962ee93e535ae87567316c544;p=authbind.git diff --git a/libauthbind.c b/libauthbind.c index 99a7f3f..42630e4 100644 --- a/libauthbind.c +++ b/libauthbind.c @@ -31,8 +31,6 @@ #include #include -static const char *rcsid="$Id$"; - #include "authbind.h" typedef void anyfn_type(void); @@ -146,15 +144,31 @@ static const int evilsignals[]= { SIGFPE, SIGILL, SIGSEGV, SIGBUS, 0 }; int bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { pid_t child, rchild; - char portarg[5], addrarg[9]; - int r, status; + char portarg[5], addrarg[33]; + const char *afarg; + int i, r, status, restore_sigchild; const int *evilsignal; sigset_t block, saved; + struct sigaction old_sigchild; + unsigned int portval; + + switch (addr->sa_family) { + case AF_INET: + portval = ((struct sockaddr_in*)addr)->sin_port; + if (addrlen != sizeof(struct sockaddr_in)) goto bail; + break; + case AF_INET6: + portval = ((struct sockaddr_in6*)addr)->sin6_port; + if (addrlen != sizeof(struct sockaddr_in6)) goto bail; + break; + default: + goto bail; + } - if (addr->sa_family != AF_INET || addrlen != sizeof(struct sockaddr_in) || - !geteuid() || ((struct sockaddr_in*)addr)->sin_port == 0 || - ntohs(((struct sockaddr_in*)addr)->sin_port) >= IPPORT_RESERVED/2) + if (!geteuid() || portval == 0 || ntohs(portval) >= IPPORT_RESERVED) { + bail: return old_bind(fd,addr,addrlen); + } sigfillset(&block); for (evilsignal=evilsignals; @@ -162,23 +176,47 @@ int bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { evilsignal++) sigdelset(&block,*evilsignal); if (sigprocmask(SIG_BLOCK,&block,&saved)) return -1; - - sprintf(addrarg,"%08lx", - ((unsigned long)(((struct sockaddr_in*)addr)->sin_addr.s_addr))&0x0ffffffffUL); + + switch (addr->sa_family) { + case AF_INET: + afarg = 0; + sprintf(addrarg,"%08lx", + ((unsigned long)(((struct sockaddr_in*)addr)->sin_addr.s_addr)) + &0x0ffffffffUL); + break; + case AF_INET6: + afarg = "6"; + for (i=0; i<16; i++) + sprintf(addrarg+i*2,"%02x", + ((struct sockaddr_in6*)addr)->sin6_addr.s6_addr[i]); + break; + default: + abort(); + } sprintf(portarg,"%04x", - ((unsigned int)(((struct sockaddr_in*)addr)->sin_port))&0x0ffff); + portval&0x0ffff); + + restore_sigchild= 0; + if (sigaction(SIGCHLD,NULL,&old_sigchild)) return -1; + if (old_sigchild.sa_handler == SIG_IGN) { + struct sigaction new_sigchild; + + new_sigchild.sa_handler= SIG_DFL; + sigemptyset(&new_sigchild.sa_mask); + new_sigchild.sa_flags= 0; + if (sigaction(SIGCHLD,&new_sigchild,&old_sigchild)) return -1; + restore_sigchild= 1; + } child= fork(); if (child==-1) goto x_err; if (!child) { if (dup2(fd,0)) exiterrno(errno); removepreload(); - execl(HELPER,HELPER,addrarg,portarg,(char*)0); + execl(HELPER,HELPER,addrarg,portarg,afarg,(char*)0); status= errno > 0 && errno < 127 ? errno : 127; STDERRSTR_CONST("libauthbind: possible installation problem - " - "could not invoke " HELPER " ("); - STDERRSTR_STRING(rcsid); - STDERRSTR_CONST(")\n"); + "could not invoke " HELPER "\n"); exiterrno(status); } @@ -203,5 +241,13 @@ x_err: r= -1; x: if (sigprocmask(SIG_SETMASK,&saved,0)) abort(); + if (restore_sigchild) { + if (sigaction(SIGCHLD,&old_sigchild,NULL)) return -1; + if (old_sigchild.sa_handler == SIG_IGN) { + int discard; + while (waitpid(-1, &discard, WNOHANG) > 0) + ; + } + } return r; }