X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=authbind.git;a=blobdiff_plain;f=helper.c;h=a58e7aae666f30899a9673f2efbaf7b070b8bdd2;hp=e086e9e23808f9fa6c84d6d5ff822230e3ebf78e;hb=177b6e8b804eaf719774eecc6e24a85190a6d89d;hpb=8ddfdffdd892f3ab3fb42c10ff5abd6653f7c166;ds=sidebyside diff --git a/helper.c b/helper.c index e086e9e..a58e7aa 100644 --- a/helper.c +++ b/helper.c @@ -1,31 +1,22 @@ /* - * setuid. Invoked with socket on stdin. - * Usage: helper - * both are hex strings, padded to the right length. - * they are pairs of hex digits for each byte (network byte order) + * helper.c - setuid helper program for authbind * - * If /etc/authbind cannot be chdir'd into, is an error. - * - * First, check /etc/authbind/byport/ with access(2,X_OK). - * If OK, then authorised. - * If ENOENT then keep looking. - * Otherwise, not authorised, errno=whatever - * - * Then check /etc/authbind/byboth/: likewise. - * - * Then try to read /etc/authbind/byuid/ (with superuser privs!) - * If ENOENT, then not authorised, errno=EPERM - * If cannot open, then not authorised, errno=whatever - * If it contains a line of the form - * /:, - * then authorised, otherwise not authorised, errno=ENOENT - * If read error then is an error - * - * In each case, - * is dotted quad - * is decimal in host order - * is prefix length (so 0.0.0.0/32 matches any) - * is decimal unsigned + * authbind is Copyright (C) 1998 Ian Jackson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * */ #include @@ -39,7 +30,9 @@ #include #include -#define CONFIGDIR "/etc/authbind" +#ifndef CONFIGDIR +# define CONFIGDIR "/etc/authbind" +#endif static void exiterrno(int e) { exit(e>0 && e<128 ? e : ENOSYS); @@ -53,71 +46,222 @@ static void perrorfail(const char *m) { } static void badusage(void) { - fputs("libauthbind's helper: bad usage\n",stderr); + 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) 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= alen ? 0x0ffffffffUL<<(32-alen) : 0; + if ((haddr4&thmask) != thaddr) continue; + + } else { + + char *comma = strchr(fnbuf,','); + if (!comma) continue; + *comma++ = '\0'; + + char *slash = strchr(fnbuf,'/'); + char *hyphen = strchr(fnbuf,'-'); + + if (slash && hyphen) + continue; + + if (slash) { + int alen; + *slash++ = '\0'; + nchar = -1; + sscanf(slash," %u %n",&alen,&nchar); + if (nchar != strlen(slash)) + continue; + unsigned char thaddr[addrlen_any]; + if (inet_pton(af,fnbuf,thaddr) != 1) + continue; + int pfxlen_remain = alen; + int i; + for (i=0; i> pfxlen_thisbyte); + unsigned thaddr_thisbyte = thaddr[i]; + unsigned addr_thisbyte = ((unsigned char*)addr_any)[i]; + if ((addr_thisbyte & mask_thisbyte) != thaddr_thisbyte) + goto badline; + } + if (pfxlen_remain) badline: continue; + /* hooray */ + } else { + 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; + } + + if (nchar = -1, + sscanf(comma," %u-%u %n", + &pmin,&pmax,&nchar), + nchar == strlen(comma)) { + /* good */ + } else if (nchar = -1, + sscanf(comma," %u %n", + &pmin,&nchar), + nchar == strlen(comma)) { + pmax = pmin; + } else { + 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");