diff options
| author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2017-07-15 11:29:05 +0200 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2017-07-15 11:29:05 +0200 | 
| commit | 324a8a71bb7d9e4f8bc49b6bc47efaf9fb58282e (patch) | |
| tree | bd2d48a139bfbe869f4f49359b63097931a45e7b /frontend | |
| parent | 2ca8a81bd0d99fe4d75c229d0e988d8ef710285f (diff) | |
| parent | 1edb02101a9306fc711cd422ed507d18165b1691 (diff) | |
Merge branch 'release/experimental/1.0.27-1_experimental1'experimental/1.0.27-1_experimental1
Diffstat (limited to 'frontend')
| -rw-r--r-- | frontend/Makefile.am | 12 | ||||
| -rw-r--r-- | frontend/Makefile.in | 86 | ||||
| -rw-r--r-- | frontend/saned.c | 169 | ||||
| -rw-r--r-- | frontend/scanimage.c | 100 | ||||
| -rw-r--r-- | frontend/sicc.c | 67 | ||||
| -rw-r--r-- | frontend/sicc.h | 19 | ||||
| -rw-r--r-- | frontend/stiff.c | 99 | 
7 files changed, 381 insertions, 171 deletions
| diff --git a/frontend/Makefile.am b/frontend/Makefile.am index 23061b3..525953f 100644 --- a/frontend/Makefile.am +++ b/frontend/Makefile.am @@ -14,21 +14,21 @@ else  EXTRA_PROGRAMS += saned  endif -AM_CPPFLAGS = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include +AM_CPPFLAGS += -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include -scanimage_SOURCES = scanimage.c stiff.c stiff.h +scanimage_SOURCES = scanimage.c sicc.c sicc.h stiff.c stiff.h  scanimage_LDADD = ../backend/libsane.la ../sanei/libsanei.la ../lib/liblib.la \ -             ../lib/libfelib.la @PNG_LIBS@ @JPEG_LIBS@ +                  $(PNG_LIBS) $(JPEG_LIBS)  saned_SOURCES = saned.c  saned_LDADD = ../backend/libsane.la ../sanei/libsanei.la ../lib/liblib.la \ -             ../lib/libfelib.la @SYSLOG_LIBS@ @SYSTEMD_LIBS@ +              $(SYSLOG_LIBS) $(SYSTEMD_LIBS) $(AVAHI_LIBS)  test_SOURCES = test.c -test_LDADD = ../lib/liblib.la ../lib/libfelib.la ../backend/libsane.la +test_LDADD = ../lib/liblib.la ../backend/libsane.la  tstbackend_SOURCES = tstbackend.c -tstbackend_LDADD = ../lib/liblib.la ../lib/libfelib.la ../backend/libsane.la +tstbackend_LDADD = ../lib/liblib.la ../backend/libsane.la  clean-local:  	rm -f test tstbackend diff --git a/frontend/Makefile.in b/frontend/Makefile.in index 2e36e0e..9ea467f 100644 --- a/frontend/Makefile.in +++ b/frontend/Makefile.in @@ -86,11 +86,16 @@ subdir = frontend  DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \  	$(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp  ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/ltoptions.m4 \ +am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ +	$(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ +	$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ +	$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/ltoptions.m4 \  	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ -	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/acinclude.m4 \ -	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/byteorder.m4 \ -	$(top_srcdir)/m4/stdint.m4 $(top_srcdir)/configure.in +	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ +	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ +	$(top_srcdir)/acinclude.m4 $(top_srcdir)/m4/libtool.m4 \ +	$(top_srcdir)/m4/byteorder.m4 $(top_srcdir)/m4/stdint.m4 \ +	$(top_srcdir)/configure.ac  am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \  	$(ACLOCAL_M4)  mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs @@ -102,24 +107,25 @@ am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)"  PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS)  am_saned_OBJECTS = saned.$(OBJEXT)  saned_OBJECTS = $(am_saned_OBJECTS) +am__DEPENDENCIES_1 =  saned_DEPENDENCIES = ../backend/libsane.la ../sanei/libsanei.la \ -	../lib/liblib.la ../lib/libfelib.la +	../lib/liblib.la $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ +	$(am__DEPENDENCIES_1)  AM_V_lt = $(am__v_lt_@AM_V@)  am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)  am__v_lt_0 = --silent  am__v_lt_1 =  -am_scanimage_OBJECTS = scanimage.$(OBJEXT) stiff.$(OBJEXT) +am_scanimage_OBJECTS = scanimage.$(OBJEXT) sicc.$(OBJEXT) \ +	stiff.$(OBJEXT)  scanimage_OBJECTS = $(am_scanimage_OBJECTS)  scanimage_DEPENDENCIES = ../backend/libsane.la ../sanei/libsanei.la \ -	../lib/liblib.la ../lib/libfelib.la +	../lib/liblib.la $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)  am_test_OBJECTS = test.$(OBJEXT)  test_OBJECTS = $(am_test_OBJECTS) -test_DEPENDENCIES = ../lib/liblib.la ../lib/libfelib.la \ -	../backend/libsane.la +test_DEPENDENCIES = ../lib/liblib.la ../backend/libsane.la  am_tstbackend_OBJECTS = tstbackend.$(OBJEXT)  tstbackend_OBJECTS = $(am_tstbackend_OBJECTS) -tstbackend_DEPENDENCIES = ../lib/liblib.la ../lib/libfelib.la \ -	../backend/libsane.la +tstbackend_DEPENDENCIES = ../lib/liblib.la ../backend/libsane.la  AM_V_P = $(am__v_P_@AM_V@)  am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)  am__v_P_0 = false @@ -186,7 +192,11 @@ DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)  ACLOCAL = @ACLOCAL@  ALLOCA = @ALLOCA@  AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ -I. -I$(srcdir) -I$(top_builddir)/include \ +	-I$(top_srcdir)/include  AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AM_LDFLAGS = @AM_LDFLAGS@  AR = @AR@  AS = @AS@  AUTOCONF = @AUTOCONF@ @@ -207,7 +217,7 @@ CPPFLAGS = @CPPFLAGS@  CYGPATH_W = @CYGPATH_W@  DEFS = @DEFS@  DEPDIR = @DEPDIR@ -DISTCLEAN_FILES = @DISTCLEAN_FILES@ +DLH = @DLH@  DLLTOOL = @DLLTOOL@  DL_LIBS = @DL_LIBS@  DSYMUTIL = @DSYMUTIL@ @@ -220,34 +230,42 @@ ECHO_T = @ECHO_T@  EGREP = @EGREP@  EXEEXT = @EXEEXT@  FGREP = @FGREP@ +FIG2DEV = @FIG2DEV@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@  GPHOTO2_CPPFLAGS = @GPHOTO2_CPPFLAGS@  GPHOTO2_LDFLAGS = @GPHOTO2_LDFLAGS@  GPHOTO2_LIBS = @GPHOTO2_LIBS@  GREP = @GREP@ +GS = @GS@  HAVE_GPHOTO2 = @HAVE_GPHOTO2@  IEEE1284_LIBS = @IEEE1284_LIBS@ -INCLUDES = @INCLUDES@  INSTALL = @INSTALL@  INSTALL_DATA = @INSTALL_DATA@  INSTALL_LOCKPATH = @INSTALL_LOCKPATH@  INSTALL_PROGRAM = @INSTALL_PROGRAM@  INSTALL_SCRIPT = @INSTALL_SCRIPT@  INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@  JPEG_LIBS = @JPEG_LIBS@  LATEX = @LATEX@  LD = @LD@  LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@  LIBOBJS = @LIBOBJS@  LIBS = @LIBS@  LIBTOOL = @LIBTOOL@ -LIBUSB_1_0_CFLAGS = @LIBUSB_1_0_CFLAGS@ -LIBUSB_1_0_LIBS = @LIBUSB_1_0_LIBS@  LIBV4L_CFLAGS = @LIBV4L_CFLAGS@  LIBV4L_LIBS = @LIBV4L_LIBS@ -LINKER_RPATH = @LINKER_RPATH@  LIPO = @LIPO@  LN_S = @LN_S@  LOCKPATH_GROUP = @LOCKPATH_GROUP@ +LTALLOCA = @LTALLOCA@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@  LTLIBOBJS = @LTLIBOBJS@  MAINT = @MAINT@  MAKEINDEX = @MAKEINDEX@ @@ -256,10 +274,10 @@ MANIFEST_TOOL = @MANIFEST_TOOL@  MATH_LIB = @MATH_LIB@  MKDIR_P = @MKDIR_P@  MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@  MSGMERGE = @MSGMERGE@  NM = @NM@  NMEDIT = @NMEDIT@ -NUMBER_VERSION = @NUMBER_VERSION@  OBJDUMP = @OBJDUMP@  OBJEXT = @OBJEXT@  OTOOL = @OTOOL@ @@ -272,10 +290,13 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@  PACKAGE_URL = @PACKAGE_URL@  PACKAGE_VERSION = @PACKAGE_VERSION@  PATH_SEPARATOR = @PATH_SEPARATOR@ +PDFLATEX = @PDFLATEX@  PKG_CONFIG = @PKG_CONFIG@  PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@  PKG_CONFIG_PATH = @PKG_CONFIG_PATH@  PNG_LIBS = @PNG_LIBS@ +POSUB = @POSUB@ +PPMTOGIF = @PPMTOGIF@  PRELOADABLE_BACKENDS = @PRELOADABLE_BACKENDS@  PRELOADABLE_BACKENDS_ENABLED = @PRELOADABLE_BACKENDS_ENABLED@  PTHREAD_LIBS = @PTHREAD_LIBS@ @@ -297,12 +318,16 @@ SYSLOG_LIBS = @SYSLOG_LIBS@  SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@  SYSTEMD_LIBS = @SYSTEMD_LIBS@  TIFF_LIBS = @TIFF_LIBS@ +USB_CFLAGS = @USB_CFLAGS@  USB_LIBS = @USB_LIBS@ +USE_NLS = @USE_NLS@  VERSION = @VERSION@  V_MAJOR = @V_MAJOR@  V_MINOR = @V_MINOR@  V_REV = @V_REV@  XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@  abs_builddir = @abs_builddir@  abs_srcdir = @abs_srcdir@  abs_top_builddir = @abs_top_builddir@ @@ -358,19 +383,18 @@ target_alias = @target_alias@  top_build_prefix = @top_build_prefix@  top_builddir = @top_builddir@  top_srcdir = @top_srcdir@ -AM_CPPFLAGS = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include -scanimage_SOURCES = scanimage.c stiff.c stiff.h +scanimage_SOURCES = scanimage.c sicc.c sicc.h stiff.c stiff.h  scanimage_LDADD = ../backend/libsane.la ../sanei/libsanei.la ../lib/liblib.la \ -             ../lib/libfelib.la @PNG_LIBS@ @JPEG_LIBS@ +                  $(PNG_LIBS) $(JPEG_LIBS)  saned_SOURCES = saned.c  saned_LDADD = ../backend/libsane.la ../sanei/libsanei.la ../lib/liblib.la \ -             ../lib/libfelib.la @SYSLOG_LIBS@ @SYSTEMD_LIBS@ +              $(SYSLOG_LIBS) $(SYSTEMD_LIBS) $(AVAHI_LIBS)  test_SOURCES = test.c -test_LDADD = ../lib/liblib.la ../lib/libfelib.la ../backend/libsane.la +test_LDADD = ../lib/liblib.la ../backend/libsane.la  tstbackend_SOURCES = tstbackend.c -tstbackend_LDADD = ../lib/liblib.la ../lib/libfelib.la ../backend/libsane.la +tstbackend_LDADD = ../lib/liblib.la ../backend/libsane.la  all: all-am  .SUFFIXES: @@ -528,27 +552,31 @@ distclean-compile:  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/saned.Po@am__quote@  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scanimage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sicc.Po@am__quote@  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stiff.Po@am__quote@  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tstbackend.Po@am__quote@  .c.o: -@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po  @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@  @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@  @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<  .c.obj: -@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po  @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@  @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@  @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`  .c.lo: -@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo  @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@  @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@  @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< diff --git a/frontend/saned.c b/frontend/saned.c index 108512d..3bb99bb 100644 --- a/frontend/saned.c +++ b/frontend/saned.c @@ -82,6 +82,8 @@  #include <pwd.h>  #include <grp.h> +#include "lgetopt.h" +  #if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)  # include <sys/poll.h>  #else @@ -196,16 +198,19 @@ static AvahiEntryGroup *avahi_group = NULL;  #endif  #ifdef ENABLE_IPV6 -# define SANE_IN6_IS_ADDR_LOOPBACK(a) \ +# ifndef IN6_IS_ADDR_LOOPBACK +# define IN6_IS_ADDR_LOOPBACK(a) \          (((const uint32_t *) (a))[0] == 0                                   \           && ((const uint32_t *) (a))[1] == 0                                \           && ((const uint32_t *) (a))[2] == 0                                \           && ((const uint32_t *) (a))[3] == htonl (1))  - -#define SANE_IN6_IS_ADDR_V4MAPPED(a) \ +# endif +# ifndef IN6_IS_ADDR_V4MAPPED +# define IN6_IS_ADDR_V4MAPPED(a) \  ((((const uint32_t *) (a))[0] == 0)                                 \   && (((const uint32_t *) (a))[1] == 0)                              \   && (((const uint32_t *) (a))[2] == htonl (0xffff)))  +# endif  #endif /* ENABLE_IPV6 */  #ifndef MAXHOSTNAMELEN @@ -247,6 +252,7 @@ static int num_handles;  static int debug;  static int run_mode;  static Handle *handle; +static char *bind_addr;  static union  {    int w; @@ -786,7 +792,7 @@ check_host (int fd)  #ifdef ENABLE_IPV6    sin6 = &remote_address.sin6; -  if (SANE_IN6_IS_ADDR_V4MAPPED (sin6->sin6_addr.s6_addr)) +  if (IN6_IS_ADDR_V4MAPPED ((struct in6_addr *)sin6->sin6_addr.s6_addr))      {        DBG (DBG_DBG, "check_host: detected an IPv4-mapped address\n");        remote_ipv4 = remote_ip + 7; @@ -843,7 +849,7 @@ check_host (int fd)  	break;  #ifdef ENABLE_IPV6        case AF_INET6: -	if (SANE_IN6_IS_ADDR_LOOPBACK (sin6->sin6_addr.s6_addr)) +	if (IN6_IS_ADDR_LOOPBACK ((struct in6_addr *)sin6->sin6_addr.s6_addr))  	  {  	    DBG (DBG_MSG,  		 "check_host: remote host is IN6_LOOPBACK: access granted\n"); @@ -1428,7 +1434,7 @@ start_scan (Wire * w, int h, SANE_Start_Reply * reply)    SANE_Handle be_handle;    int fd, len;    in_port_t data_port; -  int ret; +  int ret = -1;    be_handle = handle[h].handle; @@ -1986,6 +1992,38 @@ process_request (Wire * w)  	    return 1;  	  } +        /* Addresses CVE-2017-6318 (#315576, Debian BTS #853804) */ +        /* This is done here (rather than in sanei/sanei_wire.c where +         * it should be done) to minimize scope of impact and amount +         * of code change. +         */ +        if (w->direction == WIRE_DECODE +            && req.value_type == SANE_TYPE_STRING +            && req.action     == SANE_ACTION_GET_VALUE) +          { +            if (req.value) +              { +                /* FIXME: If req.value contains embedded NUL +                 *        characters, this is wrong but we do not have +                 *        access to the amount of memory allocated in +                 *        sanei/sanei_wire.c at this point. +                 */ +                w->allocated_memory -= (1 + strlen (req.value)); +                free (req.value); +              } +            req.value = malloc (req.value_size); +            if (!req.value) +              { +                w->status = ENOMEM; +                DBG (DBG_ERR, +                     "process_request: (control_option) " +                     "h=%d (%s)\n", req.handle, strerror (w->status)); +                return 1; +              } +            memset (req.value, 0, req.value_size); +            w->allocated_memory += req.value_size; +          } +  	can_authorize = 1;  	memset (&reply, 0, sizeof (reply));	/* avoid leaking bits */ @@ -2807,13 +2845,13 @@ do_bindings (int *nfds, struct pollfd **fds)    hints.ai_flags = AI_PASSIVE;    hints.ai_socktype = SOCK_STREAM; -  err = getaddrinfo (NULL, SANED_SERVICE_NAME, &hints, &res); +  err = getaddrinfo (bind_addr, SANED_SERVICE_NAME, &hints, &res);    if (err)      {        DBG (DBG_WARN, "do_bindings: \" %s \" service unknown on your host; you should add\n", SANED_SERVICE_NAME);        DBG (DBG_WARN, "do_bindings:      %s %d/tcp saned # SANE network scanner daemon\n", SANED_SERVICE_NAME, SANED_SERVICE_PORT);        DBG (DBG_WARN, "do_bindings: to your /etc/services file (or equivalent). Proceeding anyway.\n"); -      err = getaddrinfo (NULL, SANED_SERVICE_PORT_S, &hints, &res); +      err = getaddrinfo (bind_addr, SANED_SERVICE_PORT_S, &hints, &res);        if (err)  	{  	  DBG (DBG_ERR, "do_bindings: getaddrinfo() failed even with numeric port: %s\n", gai_strerror (err)); @@ -2891,7 +2929,10 @@ do_bindings (int *nfds, struct pollfd **fds)    memset (&sin, 0, sizeof (sin));    sin.sin_family = AF_INET; -  sin.sin_addr.s_addr = INADDR_ANY; +  if(bind_addr) +    sin.sin_addr.s_addr = inet_addr(bind_addr); +  else +    sin.sin_addr.s_addr = INADDR_ANY;    sin.sin_port = port;    DBG (DBG_DBG, "do_bindings: socket ()\n"); @@ -2923,7 +2964,7 @@ do_bindings (int *nfds, struct pollfd **fds)  static void -run_standalone (int argc, char **argv) +run_standalone (char *user)  {    struct pollfd *fds = NULL;    struct pollfd *fdp = NULL; @@ -2944,13 +2985,13 @@ run_standalone (int argc, char **argv)    if (run_mode != SANED_RUN_DEBUG)      { -      if (argc > 2) +      if (user)  	{ -	  pwent = getpwnam(argv[2]); +	  pwent = getpwnam(user);  	  if (pwent == NULL)  	    { -	      DBG (DBG_ERR, "FATAL ERROR: user %s not found on system\n", argv[2]); +	      DBG (DBG_ERR, "FATAL ERROR: user %s not found on system\n", user);  	      bail_out (1);  	    } @@ -2981,7 +3022,7 @@ run_standalone (int argc, char **argv)                while (grp->gr_mem[i])  		{ -                  if (strcmp(grp->gr_mem[i], argv[2]) == 0) +                  if (strcmp(grp->gr_mem[i], user) == 0)                      {                        int need_to_add = 1, j; @@ -3172,7 +3213,7 @@ run_standalone (int argc, char **argv)  static void -run_inetd (int argc, char **argv) +run_inetd (char __sane_unused__ *sock)  {    int fd = -1; @@ -3238,18 +3279,13 @@ run_inetd (int argc, char **argv)        close (dave_null);      } -#ifndef HAVE_OS2_H -  /* Unused in this function */ -  argc = argc; -  argv = argv; - -#else +#ifdef HAVE_OS2_H    /* under OS/2, the socket handle is passed as argument on the command       line; the socket handle is relative to IBM TCP/IP, so a call       to impsockethandle() is required to add it to the EMX runtime */ -  if (argc == 2) +  if (sock)      { -      fd = _impsockhandle (atoi (argv[1]), 0); +      fd = _impsockhandle (atoi (sock), 0);        if (fd == -1)  	perror ("impsockhandle");      } @@ -3258,11 +3294,44 @@ run_inetd (int argc, char **argv)    handle_connection(fd);  } +static void usage(char *me, int err) +{ +  fprintf (stderr, +       "Usage: %s [OPTIONS]\n\n" +       " Options:\n\n" +       "  -a, --alone[=user]	run standalone and fork in background as `user'\n" +       "  -d, --debug[=level]	run foreground with output to stdout\n" +       "			and debug level `level' (default is 2)\n" +       "  -s, --syslog[=level]	run foreground with output to syslog\n" +       "			and debug level `level' (default is 2)\n" +       "  -b, --bind=addr	bind address `addr'\n" +       "  -h, --help		show this help message and exit\n", me); + +  exit(err); +} + +static int debug; + +static struct option long_options[] = +{ +/* These options set a flag. */ +  {"help",	no_argument,		0, 'h'}, +  {"alone",	optional_argument,	0, 'a'}, +  {"debug",	optional_argument,	0, 'd'}, +  {"syslog",	optional_argument,	0, 's'}, +  {"bind",	required_argument,	0, 'b'}, +  {0,		0,			0,  0 } +};  int  main (int argc, char *argv[])  {    char options[64] = ""; +  char *user = NULL; +  char *sock = NULL; +  int c; +  int long_index = 0; +    debug = DBG_WARN;    prog_name = strrchr (argv[0], '/'); @@ -3274,34 +3343,30 @@ main (int argc, char *argv[])    numchildren = 0;    run_mode = SANED_RUN_INETD; -  if (argc >= 2) +  while((c = getopt_long(argc, argv,"ha::d::s::b:", long_options, &long_index )) != -1)      { -      if (strncmp (argv[1], "-a", 2) == 0) +      switch(c) { +      case 'a':  	run_mode = SANED_RUN_ALONE; -      else if (strncmp (argv[1], "-d", 2) == 0) -	{ -	  run_mode = SANED_RUN_DEBUG; -	  log_to_syslog = SANE_FALSE; -	} -      else if (strncmp (argv[1], "-s", 2) == 0) +	user = optarg; +	break; +      case 'd': +	log_to_syslog = SANE_FALSE; +      case 's':  	run_mode = SANED_RUN_DEBUG; -      else -        { -          printf ("Usage: saned [ -a [ username ] | -d [ n ] | -s [ n ] ] | -h\n"); -          if ((strncmp (argv[1], "-h", 2) == 0) || -               (strncmp (argv[1], "--help", 6) == 0)) -            exit (EXIT_SUCCESS); -          else -            exit (EXIT_FAILURE); -        } -    } - -  if (run_mode == SANED_RUN_DEBUG) -    { -      if (argv[1][2]) -	debug = atoi (argv[1] + 2); - -      DBG (DBG_WARN, "main: starting debug mode (level %d)\n", debug); +	if(optarg) +	  debug = atoi(optarg); +	break; +      case 'b': +	bind_addr = optarg; +	break; +      case 'h': +	usage(argv[0], EXIT_SUCCESS); +	break; +      default: +	usage(argv[0], EXIT_FAILURE); +	break; +      }      }    if (log_to_syslog) @@ -3342,11 +3407,15 @@ main (int argc, char *argv[])    if ((run_mode == SANED_RUN_ALONE) || (run_mode == SANED_RUN_DEBUG))      { -      run_standalone(argc, argv); +      run_standalone(user);      }    else      { -      run_inetd(argc, argv); +#ifdef HAVE_OS2_H +      if (argc == 2) +	sock = argv[1]; +#endif +      run_inetd(sock);      }    DBG (DBG_WARN, "saned exiting\n"); diff --git a/frontend/scanimage.c b/frontend/scanimage.c index 7f7c1f0..fe02750 100644 --- a/frontend/scanimage.c +++ b/frontend/scanimage.c @@ -56,6 +56,7 @@  #include "../include/sane/sanei.h"  #include "../include/sane/saneopts.h" +#include "sicc.h"  #include "stiff.h"  #include "../include/md5.h" @@ -322,7 +323,7 @@ auth_callback (SANE_String_Const resource,      }  } -static RETSIGTYPE +static void  sighandler (int signum)  {    static SANE_Bool first_time = SANE_TRUE; @@ -1165,9 +1166,14 @@ write_pnm_header (SANE_Frame format, int width, int height, int depth, FILE *ofp  #ifdef HAVE_LIBPNG  static void -write_png_header (SANE_Frame format, int width, int height, int depth, FILE *ofp, png_structp* png_ptr, png_infop* info_ptr) +write_png_header (SANE_Frame format, int width, int height, int depth, int dpi, const char * icc_profile, FILE *ofp, png_structp* png_ptr, png_infop* info_ptr)  {    int color_type; +  /* PNG does not have imperial reference units, so we must convert to metric. */ +  /* There are nominally 39.3700787401575 inches in a meter. */ +  const double pixels_per_meter = dpi * 39.3700787401575; +  size_t icc_size = 0; +  void *icc_buffer;    *png_ptr = png_create_write_struct         (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); @@ -1200,13 +1206,47 @@ write_png_header (SANE_Frame format, int width, int height, int depth, FILE *ofp      depth, color_type, PNG_INTERLACE_NONE,      PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); +  png_set_pHYs(*png_ptr, *info_ptr, +    pixels_per_meter, pixels_per_meter, +    PNG_RESOLUTION_METER); + +  if (icc_profile) +    { +      icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size); +      if (icc_size > 0) +        { +	  /* libpng will abort if the profile and image colour spaces do not match*/ +	  /* The data colour space field is at bytes 16 to 20 in an ICC profile */ +	  /* see: ICC.1:2010 § 7.2.6 */ +	  int is_gray_profile = strncmp((char *) icc_buffer + 16, "GRAY", 4) == 0; +	  int is_rgb_profile = strncmp((char *) icc_buffer + 16, "RGB ", 4) == 0; +	  if ((is_gray_profile && color_type == PNG_COLOR_TYPE_GRAY) || +	      (is_rgb_profile && color_type == PNG_COLOR_TYPE_RGB)) +	    { +	      png_set_iCCP(*png_ptr, *info_ptr, basename(icc_profile), PNG_COMPRESSION_TYPE_BASE, icc_buffer, icc_size); +	    } +	  else +	    { +	      if (is_gray_profile) +	        { +		  fprintf(stderr, "Ignoring 'GRAY' space ICC profile because the image is RGB.\n"); +	        } +	      if (is_rgb_profile) +	        { +		  fprintf(stderr, "Ignoring 'RGB ' space ICC profile because the image is Grayscale.\n"); +		} +	    } +	  free(icc_buffer); +	} +    } +    png_write_info(*png_ptr, *info_ptr);  }  #endif  #ifdef HAVE_LIBJPEG  static void -write_jpeg_header (SANE_Frame format, int width, int height, FILE *ofp, struct jpeg_compress_struct *cinfo, struct jpeg_error_mgr *jerr) +write_jpeg_header (SANE_Frame format, int width, int height, int dpi, FILE *ofp, struct jpeg_compress_struct *cinfo, struct jpeg_error_mgr *jerr)  {    cinfo->err = jpeg_std_error(jerr);    jpeg_create_compress(cinfo); @@ -1231,6 +1271,11 @@ write_jpeg_header (SANE_Frame format, int width, int height, FILE *ofp, struct j      }    jpeg_set_defaults(cinfo); +  /* jpeg_set_defaults overrides density, be careful. */ +  cinfo->density_unit = 1;   /* Inches */ +  cinfo->X_density = cinfo->Y_density = dpi; +  cinfo->write_JFIF_header = TRUE; +    jpeg_set_quality(cinfo, 75, TRUE);    jpeg_start_compress(cinfo, TRUE);  } @@ -1379,13 +1424,15 @@ scan_it (FILE *ofp)  #ifdef HAVE_LIBPNG  		  case OUTPUT_PNG:  		    write_png_header (parm.format, parm.pixels_per_line, -				      parm.lines, parm.depth, ofp, &png_ptr, &info_ptr); +				      parm.lines, parm.depth, resolution_value, +				      icc_profile, ofp, &png_ptr, &info_ptr);  		    break;  #endif  #ifdef HAVE_LIBJPEG  		  case OUTPUT_JPEG:  		    write_jpeg_header (parm.format, parm.pixels_per_line, -				      parm.lines, ofp, &cinfo, &jerr); +				       parm.lines, resolution_value, +				       ofp, &cinfo, &jerr);  		    break;  #endif  		  } @@ -1529,6 +1576,21 @@ scan_it (FILE *ofp)  			  for(j = 0; j < parm.bytes_per_line; j++)  			    pngbuf[j] = ~pngbuf[j];  			} +#ifndef WORDS_BIGENDIAN +                      /* SANE is endian-native, PNG is big-endian, */ +                      /* see: https://www.w3.org/TR/2003/REC-PNG-20031110/#7Integers-and-byte-order */ +                      if (parm.depth == 16) +                        { +                          int j; +                          for (j = 0; j < parm.bytes_per_line; j += 2) +                            { +                              SANE_Byte LSB; +                              LSB = pngbuf[j]; +                              pngbuf[j] = pngbuf[j + 1]; +                              pngbuf[j + 1] = LSB; +                            } +                        } +#endif  		      png_write_row(png_ptr, pngbuf);  		      i += parm.bytes_per_line - pngrow;  		      left -= parm.bytes_per_line - pngrow; @@ -1635,13 +1697,15 @@ scan_it (FILE *ofp)  #ifdef HAVE_LIBPNG        case OUTPUT_PNG:  	write_png_header (parm.format, parm.pixels_per_line, -                          image.height, parm.depth, ofp, &png_ptr, &info_ptr); +			  image.height, parm.depth, resolution_value, +			  icc_profile, ofp, &png_ptr, &info_ptr);        break;  #endif  #ifdef HAVE_LIBJPEG        case OUTPUT_JPEG:  	write_jpeg_header (parm.format, parm.pixels_per_line, -	parm.lines, ofp, &cinfo, &jerr); +			   parm.lines, resolution_value, +			   ofp, &cinfo, &jerr);        break;  #endif        } @@ -2474,9 +2538,16 @@ List of available devices:", prog_name);          ofp = stdout;        if (batch) -	fprintf (stderr, -		 "Scanning %d pages, incrementing by %d, numbering from %d\n", -		 batch_count, batch_increment, batch_start_at); +	{ +	  fputs("Scanning ", stderr); +	  if (batch_count == BATCH_COUNT_UNLIMITED) +	    fputs("infinity", stderr); +	  else +	    fprintf(stderr, "%d", batch_count); +	  fprintf (stderr, +		   " page%s, incrementing by %d, numbering from %d\n", +		   batch_count == 1 ? "" : "s", batch_increment, batch_start_at); +	}        else if(isatty(fileno(ofp))){  	fprintf (stderr,"%s: output is not a file, exiting\n", prog_name); @@ -2509,8 +2580,6 @@ List of available devices:", prog_name);  		  if (readbuf2 == NULL)  		    { -		      fprintf (stderr, "Batch terminated, %d pages scanned\n", -			       (n - batch_increment));  		      if (ofp)  			{  			  fclose (ofp); @@ -2612,6 +2681,13 @@ List of available devices:", prog_name);  	      && (batch_count == BATCH_COUNT_UNLIMITED || --batch_count))  	     && SANE_STATUS_GOOD == status); +      if (batch) +	{ +	  int num_pgs = (n - batch_start_at) / batch_increment; +	  fprintf (stderr, "Batch terminated, %d page%s scanned\n", +		   num_pgs, num_pgs == 1 ? "" : "s"); +	} +        if (batch  	  && SANE_STATUS_NO_DOCS == status  	  && (batch_count == BATCH_COUNT_UNLIMITED) diff --git a/frontend/sicc.c b/frontend/sicc.c new file mode 100644 index 0000000..c93e5c3 --- /dev/null +++ b/frontend/sicc.c @@ -0,0 +1,67 @@ +/* Load an ICC profile for embedding in an output file +   Copyright (C) 2017 Aaron Muir Hamilton <aaron@correspondwith.me> + +   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 of the +   License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */ + +#include "../include/sane/config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <sys/stat.h> + +void * +sanei_load_icc_profile (const char *path, size_t *size) +{ +  FILE *fd = NULL; +  size_t stated_size = 0; +  void *profile = NULL; +  struct stat s; + +  fd = fopen(path, "r"); + +  if (!fd) +  { +    fprintf(stderr, "Could not open ICC profile %s\n", path); +  } +  else +  { +    fstat(fileno(fd), &s); +    stated_size = 16777216 * fgetc(fd) + 65536 * fgetc(fd) + 256 * fgetc(fd) + fgetc(fd); +    rewind(fd); + +    if (stated_size > (size_t) s.st_size) +    { +      fprintf(stderr, "Ignoring ICC profile because file %s is shorter than the profile\n", path); +    } +    else +    { +      profile = malloc(stated_size); + +      if (fread(profile, stated_size, 1, fd) != 1) +      { +        fprintf(stderr, "Error reading ICC profile %s\n", path); +        free(profile); +      } +      else +      { +        fclose(fd); +        *size = stated_size; +        return profile; +      } +    } +    fclose(fd); +  } +  return NULL; +} diff --git a/frontend/sicc.h b/frontend/sicc.h new file mode 100644 index 0000000..5c225da --- /dev/null +++ b/frontend/sicc.h @@ -0,0 +1,19 @@ +/* Load an ICC profile for embedding in an output file +   Copyright (C) 2017 Aaron Muir Hamilton <aaron@correspondwith.me> + +   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 of the +   License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */ + +void * +sanei_load_icc_profile (const char *path, size_t *size); diff --git a/frontend/stiff.c b/frontend/stiff.c index 01d845b..c9153e5 100644 --- a/frontend/stiff.c +++ b/frontend/stiff.c @@ -1,6 +1,7 @@  /* Create SANE/tiff headers TIFF interfacing routines for SANE     Copyright (C) 2000 Peter Kirchgessner     Copyright (C) 2002 Oliver Rauch: added tiff ICC profile +   Copyright (C) 2017 Aaron Muir Hamilton <aaron@correspondwith.me>     This program is free software; you can redistribute it and/or     modify it under the terms of the GNU General Public License as @@ -20,6 +21,7 @@     2000-11-19, PK: Color TIFF-header: write 3 values for bits per sample     2001-12-16, PK: Write fill order tag for b/w-images     2002-08-27, OR: Added tiff tag for ICC profile +   2017-04-16, AMH: Separate ICC profile loading into a separate file  */  #ifdef _AIX  # include "../include/lalloca.h"	/* MUST come first for AIX! */ @@ -31,6 +33,7 @@  #include "../include/sane/config.h"  #include "../include/sane/sane.h" +#include "sicc.h"  #include "stiff.h"  typedef struct { @@ -269,22 +272,12 @@ write_tiff_grey_header (FILE *fptr, int width, int height, int depth,      int strip_bytecount;      int ntags;      int motorola, bps, maxsamplevalue; -    FILE *icc_file = 0; -    int icc_len = -1; +    void *icc_buffer = NULL; +    size_t icc_size = 0;      if (icc_profile)      { -      icc_file = fopen(icc_profile, "r"); - -      if (!icc_file) -      { -        fprintf(stderr, "Could not open ICC profile %s\n", icc_profile); -      } -      else -      { -        icc_len = 16777216 * fgetc(icc_file) + 65536 * fgetc(icc_file) + 256 * fgetc(icc_file) + fgetc(icc_file); -        rewind(icc_file); -      } +      icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size);      }      ifd = create_ifd (); @@ -302,10 +295,10 @@ write_tiff_grey_header (FILE *fptr, int width, int height, int depth,          data_size += 2*4 + 2*4;      } -    if (icc_len > 0) /* if icc profile exists add memory for tag */ +    if (icc_size > 0) /* if icc profile exists add memory for tag */      {          ntags += 1; -        data_size += icc_len; +        data_size += icc_size;      }      ifd_size = 2 + ntags*12 + 4; @@ -355,10 +348,10 @@ write_tiff_grey_header (FILE *fptr, int width, int height, int depth,          add_ifd_entry (ifd, 296, IFDE_TYP_SHORT, 1, 2);      } -    if (icc_len > 0) /* add ICC-profile TAG */ +    if (icc_size > 0) /* add ICC-profile TAG */      { -      add_ifd_entry(ifd, 34675, 7, icc_len, data_offset); -      data_offset += icc_len; +      add_ifd_entry(ifd, 34675, 7, (int) icc_size, data_offset); +      data_offset += icc_size;      }      /* I prefer motorola format. Its human readable. But for 16 bit, */ @@ -383,33 +376,16 @@ write_tiff_grey_header (FILE *fptr, int width, int height, int depth,          write_i4 (fptr, 1, motorola);      } -    /* Write ICC profile */ -    if (icc_len > 0) +    if (icc_size > 0)      { -      int i; -      for (i=0; i<icc_len; i++) -      { -        if (!feof(icc_file)) -        { -          fputc(fgetc(icc_file), fptr); -        } -        else -        { -          fprintf(stderr, "ICC profile %s is too short\n", icc_profile); -          break; -        } -      } +      fwrite(icc_buffer, icc_size, 1, fptr);      } -    if (icc_file) -    { -      fclose(icc_file); -    } +    free(icc_buffer);      free_ifd (ifd);  } -  static void  write_tiff_color_header (FILE *fptr, int width, int height, int depth,                           int resolution, const char *icc_profile) @@ -419,22 +395,12 @@ write_tiff_color_header (FILE *fptr, int width, int height, int depth,      int strip_bytecount;      int ntags;      int motorola, bps, maxsamplevalue; -    FILE *icc_file = 0; -    int icc_len = -1; +    void *icc_buffer = NULL; +    size_t icc_size = 0;      if (icc_profile)      { -      icc_file = fopen(icc_profile, "r"); - -      if (!icc_file) -      { -        fprintf(stderr, "Could not open ICC profile %s\n", icc_profile); -      } -      else -      { -        icc_len = 16777216 * fgetc(icc_file) + 65536 * fgetc(icc_file) + 256 * fgetc(icc_file) + fgetc(icc_file); -        rewind(icc_file); -      } +      icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size);      } @@ -454,10 +420,10 @@ write_tiff_color_header (FILE *fptr, int width, int height, int depth,          data_size += 2*4 + 2*4;      } -    if (icc_len > 0) /* if icc profile exists add memory for tag */ +    if (icc_size > 0) /* if icc profile exists add memory for tag */      {          ntags += 1; -        data_size += icc_len; +        data_size += icc_size;      } @@ -513,10 +479,10 @@ write_tiff_color_header (FILE *fptr, int width, int height, int depth,          add_ifd_entry (ifd, 296, IFDE_TYP_SHORT, 1, 2);      } -    if (icc_len > 0) /* add ICC-profile TAG */ +    if (icc_size > 0) /* add ICC-profile TAG */      { -      add_ifd_entry(ifd, 34675, 7, icc_len, data_offset); -      data_offset += icc_len; +      add_ifd_entry(ifd, 34675, 7, (int) icc_size, data_offset); +      data_offset += icc_size;      } @@ -558,27 +524,12 @@ write_tiff_color_header (FILE *fptr, int width, int height, int depth,      }      /* Write ICC profile */ -    if (icc_len > 0) +    if (icc_size > 0)      { -      int i; -      for (i=0; i<icc_len; i++) -      { -        if (!feof(icc_file)) -        { -          fputc(fgetc(icc_file), fptr); -        } -        else -        { -          fprintf(stderr, "ICC profile %s is too short\n", icc_profile); -          break; -        } -      } +      fwrite(icc_buffer, icc_size, 1, fptr);      } -    if (icc_file) -    { -      fclose(icc_file); -    } +    free(icc_buffer);      free_ifd (ifd);  } | 
