From 1edb02101a9306fc711cd422ed507d18165b1691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sat, 15 Jul 2017 11:25:39 +0200 Subject: move from support/1.0.27 to feature/1.0.27 --- frontend/Makefile.am | 12 ++-- frontend/Makefile.in | 86 +++++++++++++++++--------- frontend/saned.c | 169 ++++++++++++++++++++++++++++++++++++--------------- frontend/scanimage.c | 100 ++++++++++++++++++++++++++---- frontend/sicc.c | 67 ++++++++++++++++++++ frontend/sicc.h | 19 ++++++ frontend/stiff.c | 99 ++++++++---------------------- 7 files changed, 381 insertions(+), 171 deletions(-) create mode 100644 frontend/sicc.c create mode 100644 frontend/sicc.h (limited to 'frontend') 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 #include +#include "lgetopt.h" + #if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL) # include #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 + + 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 +#include +#include + +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 + + 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 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 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