X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=authbind.git;a=blobdiff_plain;f=helper.c;h=0841cd2f89f2083acff44e5669b5e5ca9c8a7089;hp=96892abf476fb4e6dc1925f3d4f518fd1d7c9812;hb=7027a83b4c98ddaf94c4621e0ee55020e17779e3;hpb=ced277da933eb4aeb199ee534cfe9a15804061cc diff --git a/helper.c b/helper.c index 96892ab..0841cd2 100644 --- a/helper.c +++ b/helper.c @@ -34,8 +34,6 @@ # define CONFIGDIR "/etc/authbind" #endif -static const char *rcsid="$Id$"; - static void exiterrno(int e) { exit(e>0 && e<128 ? e : ENOSYS); } @@ -48,72 +46,184 @@ static void perrorfail(const char *m) { } static void badusage(void) { - fprintf(stderr,"libauthbind's helper: bad usage\n %s\n",rcsid); + fprintf(stderr,"libauthbind's helper: bad usage\n"); exit(ENOSYS); } -static struct sockaddr_in saddr; +static struct sockaddr_in saddr4; +static struct sockaddr_in6 saddr6; + +static struct sockaddr *saddr_any; +static const void *addr_any; +static size_t saddrlen_any, addrlen_any; static void authorised(void) { - if (bind(0,&saddr,sizeof(saddr))) exiterrno(errno); + if (bind(0,saddr_any,saddrlen_any)) exiterrno(errno); else _exit(0); } +static void checkexecflagfile(const char *file) { + if (!access(file,X_OK)) authorised(); + if (errno != ENOENT) exiterrno(errno); +} + +static void hex2bytes(const char *string, unsigned char *out, int len) { + int i; + for (i=0; i= IPPORT_RESERVED/2) _exit(EPERM); + hport= htons(port); + if (hport >= IPPORT_RESERVED/2) tophalfchar= "!"; if (chdir(CONFIGDIR)) perrorfail("chdir " CONFIGDIR); fnbuf[sizeof(fnbuf)-1]= 0; - memset(&saddr,0,sizeof(saddr)); - saddr.sin_family= AF_INET; - saddr.sin_port= port; - saddr.sin_addr.s_addr= addr; - hport= htons(port); - snprintf(fnbuf,sizeof(fnbuf)-1,"byport/%u",hport); - if (!access(fnbuf,X_OK)) authorised(); - if (errno != ENOENT) exiterrno(errno); + switch (af) { + case AF_INET: + saddr4.sin_family= af; + saddr4.sin_port= port; + saddr4.sin_addr.s_addr= addr4; + break; + case AF_INET6: + saddr6.sin6_family= af; + saddr6.sin6_port= port; + break; + default: + abort(); + } - np= inet_ntoa(saddr.sin_addr); assert(np); - snprintf(fnbuf,sizeof(fnbuf)-1,"byaddr/%s:%u",np,hport); + snprintf(fnbuf,sizeof(fnbuf)-1,"byport/%s%u",tophalfchar,hport); if (!access(fnbuf,X_OK)) authorised(); if (errno != ENOENT) exiterrno(errno); + char npbuf[INET_ADDRSTRLEN + INET6_ADDRSTRLEN]; + np= inet_ntop(af,addr_any,npbuf,sizeof(npbuf)); + assert(np); + + if (af == AF_INET) { + snprintf(fnbuf,sizeof(fnbuf)-1,"byaddr/%s%s:%u",tophalfchar,np,hport); + checkexecflagfile(fnbuf); + } + + snprintf(fnbuf,sizeof(fnbuf)-1,"byaddr/%s%s,%u",tophalfchar,np,hport); + checkexecflagfile(fnbuf); + + if (af == AF_INET6) { + char sbuf[addrlen_any*3+1], *sp = sbuf; + const unsigned char *ip = addr_any; + int i; + for (i=0; i<8; i++) { + unsigned val = 0; + val |= *ip++; val <<= 8; + val |= *ip++; + if (i) *sp++ = ':'; + sp += sprintf(sp,"%x",val); + } + snprintf(fnbuf,sizeof(fnbuf)-1,"byaddr/%s%s,%u",tophalfchar,sbuf,hport); + checkexecflagfile(fnbuf); + } + uid= getuid(); if (uid==(uid_t)-1) perrorfail("getuid"); - snprintf(fnbuf,sizeof(fnbuf)-1,"byuid/%lu",(unsigned long)uid); + snprintf(fnbuf,sizeof(fnbuf)-1,"byuid/%s%lu",tophalfchar,(unsigned long)uid); file= fopen(fnbuf,"r"); if (!file) exiterrno(errno==ENOENT ? EPERM : errno); - haddr= ntohl(addr); - while (fgets(fnbuf,sizeof(fnbuf)-1,file)) { - nchar= -1; - sscanf(fnbuf," %u.%u.%u.%u/%u:%u,%u %n", - &a1,&a2,&a3,&a4,&alen,&pmin,&pmax,&nchar); - if (nchar != strlen(fnbuf) || - alen>32 || pmin&~0x0ffff || pmax&~0x0ffff || - a1&~0x0ff || a2&~0xff || a3&~0x0ff || a4&~0x0ff) - continue; - + unsigned int a1,a2,a3,a4, alen,pmin,pmax; + int nchar; + + if (af == AF_INET && + (nchar = -1, + sscanf(fnbuf," %u.%u.%u.%u/%u: %u,%u %n", + &a1,&a2,&a3,&a4,&alen,&pmin,&pmax,&nchar), + nchar == strlen(fnbuf))) { + + if (alen>32 || pmin&~0x0ffff || pmax&~0x0ffff || + a1&~0x0ff || a2&~0xff || a3&~0x0ff || a4&~0x0ff) + continue; + + unsigned long thaddr, thmask; + thaddr= (a1<<24)|(a2<<16)|(a3<<8)|(a4); + thmask= 0x0ffffffffUL<<(32-alen); + if ((haddr4&thmask) != thaddr) continue; + + } else { + + char *comma = strchr(fnbuf,','); + if (!comma) continue; + *comma++ = '\0'; + + char *hyphen = strchr(fnbuf,'-'); + const char *min, *max; + if (hyphen) { + *hyphen++ = '\0'; + min = fnbuf; + max = hyphen; + } else { + min = fnbuf; + max = fnbuf; + } + unsigned char minaddr[addrlen_any]; + unsigned char maxaddr[addrlen_any]; + if (inet_pton(af,min,minaddr) != 1 || + inet_pton(af,max,maxaddr) != 1) + continue; + if (memcmp(addr_any,minaddr,addrlen_any) < 0 || + memcmp(addr_any,maxaddr,addrlen_any) > 0) + continue; + + nchar = -1; + sscanf(comma," %u-%u %n", + &pmin,&pmax,&nchar); + if (nchar != strlen(comma)) + continue; + + } if (hportpmax) continue; - thaddr= (a1<<24)|(a2<<16)|(a3<<8)|(a4); - thmask= 0x0ffffffffUL<<(32-alen); - if ((haddr&thmask) != thaddr) continue; authorised(); } if (ferror(file)) perrorfail("read per-uid file");