X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=authbind.git;a=blobdiff_plain;f=libauthbind.c;h=a685ce3fe200c957a5f686a90eaf3e19811fb66b;hp=dd5c4841c314ff22f3d14768deb1e4926e9a4302;hb=b00ea62e68f29d5adda57a02c873bd602a9be5ad;hpb=a942b07a4483cfa4a5f0a8307e3b6239f7f44998 diff --git a/libauthbind.c b/libauthbind.c index dd5c484..a685ce3 100644 --- a/libauthbind.c +++ b/libauthbind.c @@ -25,13 +25,12 @@ #include #include #include +#include #include #include #include #include -static const char *rcsid="$Id$"; - #include "authbind.h" typedef void anyfn_type(void); @@ -40,13 +39,11 @@ typedef int bindfn_type(int fd, const struct sockaddr *addr, socklen_t addrlen); #define STDERRSTR_CONST(m) write(2,m,sizeof(m)-1) #define STDERRSTR_STRING(m) write(2,m,strlen(m)) -static int find_any(const char *name, anyfn_type **keep) { +static anyfn_type *find_any(const char *name) { static const char *dlerr; anyfn_type *kv; - if (*keep) return 0; - kv= dlsym(RTLD_NEXT,name); - if (kv) { *keep= kv; return 0; } + kv= dlsym(RTLD_NEXT,name); if (kv) return kv; dlerr= dlerror(); if (!dlerr) dlerr= "dlsym() failed for no reason"; STDERRSTR_CONST("libauthbind: error finding original version of "); STDERRSTR_STRING(name); @@ -54,14 +51,14 @@ static int find_any(const char *name, anyfn_type **keep) { STDERRSTR_STRING(dlerr); STDERRSTR_STRING("\n"); errno= ENOSYS; - return -1; + return 0; } static bindfn_type find_bind, *old_bind= find_bind; int find_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { anyfn_type *anyfn; - if (find_any("bind",&anyfn)) return -1; + anyfn= find_any("bind"); if (!anyfn) return -1; old_bind= (bindfn_type*)anyfn; return old_bind(fd,addr,addrlen); } @@ -143,43 +140,93 @@ int _init(void) { return 0; } +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 status; + char portarg[5], addrarg[33]; + const char *afarg; + int i, r, status; + const int *evilsignal; + sigset_t block, saved; + 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) || - ntohs(((struct sockaddr_in*)addr)->sin_port) >= IPPORT_RESERVED/2 || !geteuid()) + if (!geteuid() || portval == 0 || ntohs(portval) >= IPPORT_RESERVED) { + bail: return old_bind(fd,addr,addrlen); + } - sprintf(addrarg,"%08lx", - ((unsigned long)(((struct sockaddr_in*)addr)->sin_addr.s_addr))&0x0ffffffffUL); + sigfillset(&block); + for (evilsignal=evilsignals; + *evilsignal; + evilsignal++) + sigdelset(&block,*evilsignal); + if (sigprocmask(SIG_BLOCK,&block,&saved)) return -1; + + 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); - child= fork(); if (child==-1) return -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); - status= errno; + 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); } rchild= waitpid(child,&status,0); - if (rchild==-1) return -1; - if (rchild!=child) { errno= ECHILD; return -1; } + if (rchild==-1) goto x_err; + if (rchild!=child) { errno= ECHILD; goto x_err; } if (WIFEXITED(status)) { - if (WEXITSTATUS(status)) { errno= WEXITSTATUS(status); return -1; } - return 0; + if (WEXITSTATUS(status)) { + errno= WEXITSTATUS(status); + if (errno >= 127) errno= ENXIO; + goto x_err; + } + r= 0; + goto x; } else { errno= ENOSYS; - return -1; + goto x_err; } + +x_err: + r= -1; +x: + if (sigprocmask(SIG_SETMASK,&saved,0)) abort(); + return r; }