[sane-devel] Suggested change for saned

Petter Reinholdtsen pere@hungry.com
Sat, 1 Dec 2001 12:14:47 +0100


I came across a two year old bug report in the Debian bug database,
and decided to have a look.  The bug report reads:

  I tried to use a scanner with the net-device. I have written the
  FQDN of several hosts in the file saned.conf. But I got no
  connection. The problem was the FQDN. The hostname without the
  domain works well. I think this is a strange behavior and makes it
  impossible to let hosts of different domains connect to saned.
    - <URL:http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=51171>

I'm not sure (I'm missing a test environment), but I believe this
patch should solve the problem.  Instead of comparing the DNS name
strings, the names are converted to IP addresses before these are
compared.  Could someone test if the patch works?  It compiles, but I
haven't tested it.

(All the bugs associated with sane in Debians bug tracking system is
available from these URLs:

  <URL:http://bugs.debian.org/cgi-bin/pkgreport.cgi?src=sane-backends>
  <URL:http://bugs.debian.org/cgi-bin/pkgreport.cgi?src=sane-frontends>

JFYI)

Index: frontend/saned.c
===================================================================
RCS file: /cvsroot/external/sane/sane-backends/frontend/saned.c,v
retrieving revision 1.11
diff -u -w -r1.11 saned.c
--- saned.c	2001/10/12 19:56:08	1.11
+++ saned.c	2001/11/22 10:03:39
@@ -56,6 +56,8 @@
 #include <sys/time.h>
 #include <sys/types.h>
 
+#include <arpa/inet.h> /* inet_ntoa() */
+
 #include "../include/sane/sane.h"
 #include "../include/sane/sanei.h"
 #include "../include/sane/sanei_net.h"
@@ -329,6 +331,10 @@
   struct sockaddr_in sin;
   int i, j, access_ok = 0;
   struct hostent *he;
+  char r_addr[16]; /* 16 = make sure there is room for IPv6 addr */
+  char l_addr[16];
+  int  r_length;
+  int  l_length;
   char rhost[1024];
   int len;
   FILE *fp;
@@ -346,6 +352,14 @@
       DBG (1, "getpeername failed: %s\n", strerror (errno));
       return SANE_STATUS_INVAL;
     }
+  /* always allow access from local host: */
+
+  if (IN_LOOPBACK (ntohl (sin.sin_addr.s_addr)))
+    {
+      DBG (1, "host is local (IN_LOOPBACK): access accepted\n");
+      return SANE_STATUS_GOOD;
+    }
+
   he = gethostbyaddr ((const char *) &sin.sin_addr,
 		      sizeof (sin.sin_addr), sin.sin_family);
   if (!he)
@@ -356,27 +370,46 @@
 
   remote_hostname = strdup (he->h_name);
 
-  /* always allow access from local host: */
-
-  if (IN_LOOPBACK (ntohl (sin.sin_addr.s_addr)))
+  /* Store host address and length.  This only uses the first IP address.
+     If the host have more then one IP address, the others are silently
+     ignored. */
+  r_length = he->h_length;
+  if (r_length > sizeof(r_addr))
     {
-      DBG (1, "host is local (IN_LOOPBACK): access accepted\n");
-      return SANE_STATUS_GOOD;
+      DBG (1, "remote address length too long: %d > %d\n", r_length,
+           sizeof(r_addr));
+      return SANE_STATUS_INVAL;
     }
+  memcpy(&r_addr[0], he->h_addr_list[0], r_length);
 
-  if (strcasecmp (hostname, he->h_name) == 0)
+  he = gethostbyname(hostname);
+  if (!he)
     {
-      DBG (1, "host is local (name == local hostname): access accepted\n");
-      return SANE_STATUS_GOOD;
+      DBG (1, "gethostbyname failed: %s\n", strerror (errno));
+      return SANE_STATUS_INVAL;
+    }
+  l_length = he->h_length;
+  if (l_length > sizeof(l_addr))
+    {
+      DBG (1, "remote address length too long: %d > %d\n", l_length,
+           sizeof(l_addr));
+      return SANE_STATUS_INVAL;
     }
+  memcpy(&l_addr[0], he->h_addr_list[0], l_length);
 
-  /* check alias list: */
-  for (i = 0; he->h_aliases[i]; ++i)
-    if (strcasecmp (hostname, he->h_aliases[i]) == 0)
+  if (r_length == l_length)
+    {
+      if (memcmp(l_addr, r_addr, r_length) == 0)
       {
-	DBG (1, "host is local (alias == local hostname): access accepted\n");
+          DBG (1, "host is local (name == local hostname): access accepted\n");
 	return SANE_STATUS_GOOD;
       }
+    }
+  else
+    { /* Ignoring localhost address */
+      DBG (2, "remote and local addresses have different length %d != %d\n",
+           r_length, l_length);
+    }
 
   /* must be a remote host: check contents of PATH_NET_CONFIG or
      /etc/hosts.equiv if former doesn't exist: */
@@ -408,17 +441,21 @@
 
 	  DBG (3, "config file host name entry: %s\n", rhost);
 
-	  if (strcasecmp (rhost, he->h_name) == 0 || strcmp (rhost, "+") == 0)
-	    access_ok = 1;
-	  DBG (3, "peer name: %s\n", he->h_name);
-	  for (i = 0; he->h_aliases[i]; ++i)
-	    {
-	      DBG (3, "peer name alias: %s\n", he->h_aliases[i]);
-	      if (strcasecmp (rhost, he->h_aliases[i]) == 0)
+          if (strcmp (rhost, "+") == 0)
 		{
 		  access_ok = 1;
-		  break;
 		}
+          else
+            {
+              /* FIXME: inet_ntoa() assumes IPv4 */
+              struct in_addr naddr;
+              memcpy(&naddr.s_addr, &r_addr[0], sizeof(naddr.s_addr));
+              DBG (3, "peer addr: %s\n", inet_ntoa(naddr));
+
+              he = gethostbyname(rhost);
+              if ( r_length == he->h_length
+                   && memcmp(&r_addr[0], he->h_addr_list[0], r_length) )
+                access_ok = 1;
 	    }
 	}
       fclose (fp);