chiark / gitweb /
~~-ify changelog
[authbind.git] / helper.c
index cc4efe2..a58e7aa 100644 (file)
--- a/helper.c
+++ b/helper.c
@@ -62,6 +62,11 @@ static void authorised(void) {
   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<len; i++) {
@@ -138,14 +143,27 @@ int main(int argc, const char *const *argv) {
   assert(np);
 
   if (af == AF_INET) {
-    snprintf(fnbuf,sizeof(fnbuf)-1,"byaddr/%s%s:%u",np,tophalfchar,hport);
-    if (!access(fnbuf,X_OK)) authorised();
-    if (errno != ENOENT) exiterrno(errno);
+    snprintf(fnbuf,sizeof(fnbuf)-1,"byaddr/%s%s:%u",tophalfchar,np,hport);
+    checkexecflagfile(fnbuf);
   }
 
-  snprintf(fnbuf,sizeof(fnbuf)-1,"byaddr/%s%s,%u",np,tophalfchar,hport);
-  if (!access(fnbuf,X_OK)) authorised();
-  if (errno != ENOENT) exiterrno(errno);
+  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/%s%lu",tophalfchar,(unsigned long)uid);
@@ -155,10 +173,11 @@ int main(int argc, const char *const *argv) {
 
   while (fgets(fnbuf,sizeof(fnbuf)-1,file)) {
     unsigned int a1,a2,a3,a4, alen,pmin,pmax;
-    int nchar= -1;
+    int nchar;
 
     if (af == AF_INET &&
-       (sscanf(fnbuf," %u.%u.%u.%u/%u: %u,%u %n",
+       (nchar = -1,
+        sscanf(fnbuf," %u.%u.%u.%u/%u: %u,%u %n",
                &a1,&a2,&a3,&a4,&alen,&pmin,&pmax,&nchar),
         nchar == strlen(fnbuf))) {
 
@@ -168,38 +187,77 @@ int main(int argc, const char *const *argv) {
 
       unsigned long thaddr, thmask;
       thaddr= (a1<<24)|(a2<<16)|(a3<<8)|(a4);
-      thmask= 0x0ffffffffUL<<(32-alen);
+      thmask= alen ? 0x0ffffffffUL<<(32-alen) : 0;
       if ((haddr4&thmask) != thaddr) continue;
 
     } else {
 
       char *comma = strchr(fnbuf,',');
-      if (comma) continue;
+      if (!comma) continue;
       *comma++ = '\0';
 
+      char *slash = strchr(fnbuf,'/');
       char *hyphen = strchr(fnbuf,'-');
-      const char *min, *max;
-      if (hyphen) {
-       *hyphen++ = '\0';
-       min = fnbuf;
-       max = hyphen;
+
+      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<addrlen_any; i++) {
+         int pfxlen_thisbyte = pfxlen_remain < 8 ? pfxlen_remain : 8;
+         pfxlen_remain -= pfxlen_thisbyte;
+         unsigned mask_thisbyte = 0xff ^ (0xff >> 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 {
-       min = fnbuf;
-       max = 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;
       }
-      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;
 
-      sscanf(comma," %u-%u %n",
-            &pmin,&pmax,&nchar);
-      if (nchar != strlen(comma))
+      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 (hport<pmin || hport>pmax) continue;