1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci Copyright (C) 1997 Andreas Beck 3141cc406Sopenharmony_ci Copyright (C) 2001 - 2004 Henning Meier-Geinitz 4141cc406Sopenharmony_ci Copyright (C) 2003, 2008 Julien BLACHE <jb@jblache.org> 5141cc406Sopenharmony_ci AF-independent + IPv6 code, standalone mode 6141cc406Sopenharmony_ci 7141cc406Sopenharmony_ci This file is part of the SANE package. 8141cc406Sopenharmony_ci 9141cc406Sopenharmony_ci SANE is free software; you can redistribute it and/or modify it under 10141cc406Sopenharmony_ci the terms of the GNU General Public License as published by the Free 11141cc406Sopenharmony_ci Software Foundation; either version 2 of the License, or (at your 12141cc406Sopenharmony_ci option) any later version. 13141cc406Sopenharmony_ci 14141cc406Sopenharmony_ci SANE is distributed in the hope that it will be useful, but WITHOUT 15141cc406Sopenharmony_ci ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16141cc406Sopenharmony_ci FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17141cc406Sopenharmony_ci for more details. 18141cc406Sopenharmony_ci 19141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 20141cc406Sopenharmony_ci along with sane; see the file COPYING. 21141cc406Sopenharmony_ci If not, see <https://www.gnu.org/licenses/>. 22141cc406Sopenharmony_ci 23141cc406Sopenharmony_ci The SANE network daemon. This is the counterpart to the NET 24141cc406Sopenharmony_ci backend. 25141cc406Sopenharmony_ci*/ 26141cc406Sopenharmony_ci 27141cc406Sopenharmony_ci#ifdef _AIX 28141cc406Sopenharmony_ci# include "../include/lalloca.h" /* MUST come first for AIX! */ 29141cc406Sopenharmony_ci#endif 30141cc406Sopenharmony_ci 31141cc406Sopenharmony_ci#include "../include/sane/config.h" 32141cc406Sopenharmony_ci#include "../include/lalloca.h" 33141cc406Sopenharmony_ci#include <sys/types.h> 34141cc406Sopenharmony_ci 35141cc406Sopenharmony_ci#if defined(HAVE_GETADDRINFO) && defined (HAVE_GETNAMEINFO) 36141cc406Sopenharmony_ci# define SANED_USES_AF_INDEP 37141cc406Sopenharmony_ci# ifdef HAS_SS_FAMILY 38141cc406Sopenharmony_ci# define SS_FAMILY(ss) ss.ss_family 39141cc406Sopenharmony_ci# elif defined(HAS___SS_FAMILY) 40141cc406Sopenharmony_ci# define SS_FAMILY(ss) ss.__ss_family 41141cc406Sopenharmony_ci# else /* fallback to the old, IPv4-only code */ 42141cc406Sopenharmony_ci# undef SANED_USES_AF_INDEP 43141cc406Sopenharmony_ci# undef ENABLE_IPV6 44141cc406Sopenharmony_ci# endif 45141cc406Sopenharmony_ci#else 46141cc406Sopenharmony_ci# undef ENABLE_IPV6 47141cc406Sopenharmony_ci#endif /* HAVE_GETADDRINFO && HAVE_GETNAMEINFO */ 48141cc406Sopenharmony_ci 49141cc406Sopenharmony_ci#include <assert.h> 50141cc406Sopenharmony_ci#include <errno.h> 51141cc406Sopenharmony_ci#include <fcntl.h> 52141cc406Sopenharmony_ci#include <netdb.h> 53141cc406Sopenharmony_ci#include <signal.h> 54141cc406Sopenharmony_ci#include <stdio.h> 55141cc406Sopenharmony_ci#include <stdlib.h> 56141cc406Sopenharmony_ci#include <string.h> 57141cc406Sopenharmony_ci#include <syslog.h> 58141cc406Sopenharmony_ci#include <time.h> 59141cc406Sopenharmony_ci#include <unistd.h> 60141cc406Sopenharmony_ci#include <limits.h> 61141cc406Sopenharmony_ci#ifdef HAVE_LIBC_H 62141cc406Sopenharmony_ci# include <libc.h> /* NeXTStep/OpenStep */ 63141cc406Sopenharmony_ci#endif 64141cc406Sopenharmony_ci 65141cc406Sopenharmony_ci#ifdef HAVE_SYS_SELECT_H 66141cc406Sopenharmony_ci# include <sys/select.h> 67141cc406Sopenharmony_ci#endif 68141cc406Sopenharmony_ci 69141cc406Sopenharmony_ci#include <netinet/in.h> 70141cc406Sopenharmony_ci 71141cc406Sopenharmony_ci#include <stdarg.h> 72141cc406Sopenharmony_ci 73141cc406Sopenharmony_ci#include <sys/param.h> 74141cc406Sopenharmony_ci#include <sys/socket.h> 75141cc406Sopenharmony_ci 76141cc406Sopenharmony_ci#include <sys/time.h> 77141cc406Sopenharmony_ci#include <sys/types.h> 78141cc406Sopenharmony_ci#include <arpa/inet.h> 79141cc406Sopenharmony_ci 80141cc406Sopenharmony_ci#include <sys/wait.h> 81141cc406Sopenharmony_ci 82141cc406Sopenharmony_ci#include <pwd.h> 83141cc406Sopenharmony_ci#include <grp.h> 84141cc406Sopenharmony_ci 85141cc406Sopenharmony_ci#include "lgetopt.h" 86141cc406Sopenharmony_ci 87141cc406Sopenharmony_ci#if defined(HAVE_POLL_H) && defined(HAVE_POLL) 88141cc406Sopenharmony_ci# include <poll.h> 89141cc406Sopenharmony_ci#else 90141cc406Sopenharmony_ci/* 91141cc406Sopenharmony_ci * This replacement poll() using select() is only designed to cover 92141cc406Sopenharmony_ci * our needs in run_standalone(). It should probably be extended... 93141cc406Sopenharmony_ci */ 94141cc406Sopenharmony_cistruct pollfd 95141cc406Sopenharmony_ci{ 96141cc406Sopenharmony_ci int fd; 97141cc406Sopenharmony_ci short events; 98141cc406Sopenharmony_ci short revents; 99141cc406Sopenharmony_ci}; 100141cc406Sopenharmony_ci 101141cc406Sopenharmony_ci#define POLLIN 0x0001 102141cc406Sopenharmony_ci#define POLLERR 0x0002 103141cc406Sopenharmony_ci 104141cc406Sopenharmony_ciint 105141cc406Sopenharmony_cipoll (struct pollfd *ufds, unsigned int nfds, int timeout); 106141cc406Sopenharmony_ci 107141cc406Sopenharmony_ciint 108141cc406Sopenharmony_cipoll (struct pollfd *ufds, unsigned int nfds, int timeout) 109141cc406Sopenharmony_ci{ 110141cc406Sopenharmony_ci struct pollfd *fdp; 111141cc406Sopenharmony_ci 112141cc406Sopenharmony_ci fd_set rfds; 113141cc406Sopenharmony_ci fd_set efds; 114141cc406Sopenharmony_ci struct timeval tv; 115141cc406Sopenharmony_ci int maxfd = 0; 116141cc406Sopenharmony_ci unsigned int i; 117141cc406Sopenharmony_ci int ret; 118141cc406Sopenharmony_ci 119141cc406Sopenharmony_ci tv.tv_sec = timeout / 1000; 120141cc406Sopenharmony_ci tv.tv_usec = (timeout - tv.tv_sec * 1000) * 1000; 121141cc406Sopenharmony_ci 122141cc406Sopenharmony_ci FD_ZERO (&rfds); 123141cc406Sopenharmony_ci FD_ZERO (&efds); 124141cc406Sopenharmony_ci 125141cc406Sopenharmony_ci for (i = 0, fdp = ufds; i < nfds; i++, fdp++) 126141cc406Sopenharmony_ci { 127141cc406Sopenharmony_ci fdp->revents = 0; 128141cc406Sopenharmony_ci 129141cc406Sopenharmony_ci if (fdp->events & POLLIN) 130141cc406Sopenharmony_ci FD_SET (fdp->fd, &rfds); 131141cc406Sopenharmony_ci 132141cc406Sopenharmony_ci FD_SET (fdp->fd, &efds); 133141cc406Sopenharmony_ci 134141cc406Sopenharmony_ci maxfd = (fdp->fd > maxfd) ? fdp->fd : maxfd; 135141cc406Sopenharmony_ci } 136141cc406Sopenharmony_ci 137141cc406Sopenharmony_ci maxfd++; 138141cc406Sopenharmony_ci 139141cc406Sopenharmony_ci ret = select (maxfd, &rfds, NULL, &efds, &tv); 140141cc406Sopenharmony_ci 141141cc406Sopenharmony_ci if (ret < 0) 142141cc406Sopenharmony_ci return ret; 143141cc406Sopenharmony_ci 144141cc406Sopenharmony_ci for (i = 0, fdp = ufds; i < nfds; i++, fdp++) 145141cc406Sopenharmony_ci { 146141cc406Sopenharmony_ci if (fdp->events & POLLIN) 147141cc406Sopenharmony_ci if (FD_ISSET (fdp->fd, &rfds)) 148141cc406Sopenharmony_ci fdp->revents |= POLLIN; 149141cc406Sopenharmony_ci 150141cc406Sopenharmony_ci if (FD_ISSET (fdp->fd, &efds)) 151141cc406Sopenharmony_ci fdp->revents |= POLLERR; 152141cc406Sopenharmony_ci } 153141cc406Sopenharmony_ci 154141cc406Sopenharmony_ci return ret; 155141cc406Sopenharmony_ci} 156141cc406Sopenharmony_ci#endif /* HAVE_SYS_POLL_H && HAVE_POLL */ 157141cc406Sopenharmony_ci 158141cc406Sopenharmony_ci#if WITH_AVAHI 159141cc406Sopenharmony_ci# include <avahi-client/client.h> 160141cc406Sopenharmony_ci# include <avahi-client/publish.h> 161141cc406Sopenharmony_ci 162141cc406Sopenharmony_ci# include <avahi-common/alternative.h> 163141cc406Sopenharmony_ci# include <avahi-common/simple-watch.h> 164141cc406Sopenharmony_ci# include <avahi-common/malloc.h> 165141cc406Sopenharmony_ci# include <avahi-common/error.h> 166141cc406Sopenharmony_ci 167141cc406Sopenharmony_ci# define SANED_SERVICE_DNS "_sane-port._tcp" 168141cc406Sopenharmony_ci# define SANED_NAME "saned" 169141cc406Sopenharmony_ci 170141cc406Sopenharmony_cipid_t avahi_pid = -1; 171141cc406Sopenharmony_ci 172141cc406Sopenharmony_cichar *avahi_svc_name; 173141cc406Sopenharmony_ci 174141cc406Sopenharmony_cistatic AvahiClient *avahi_client = NULL; 175141cc406Sopenharmony_cistatic AvahiSimplePoll *avahi_poll = NULL; 176141cc406Sopenharmony_cistatic AvahiEntryGroup *avahi_group = NULL; 177141cc406Sopenharmony_ci#endif /* WITH_AVAHI */ 178141cc406Sopenharmony_ci 179141cc406Sopenharmony_ci#ifdef HAVE_SYSTEMD 180141cc406Sopenharmony_ci#include <systemd/sd-daemon.h> 181141cc406Sopenharmony_ci#endif 182141cc406Sopenharmony_ci 183141cc406Sopenharmony_ci 184141cc406Sopenharmony_ci#include "../include/sane/sane.h" 185141cc406Sopenharmony_ci#include "../include/sane/sanei.h" 186141cc406Sopenharmony_ci#include "../include/sane/sanei_net.h" 187141cc406Sopenharmony_ci#include "../include/sane/sanei_codec_bin.h" 188141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 189141cc406Sopenharmony_ci 190141cc406Sopenharmony_ci#include "../include/sane/sanei_auth.h" 191141cc406Sopenharmony_ci 192141cc406Sopenharmony_ci#ifndef EXIT_SUCCESS 193141cc406Sopenharmony_ci# define EXIT_SUCCESS 0 194141cc406Sopenharmony_ci#endif 195141cc406Sopenharmony_ci 196141cc406Sopenharmony_ci#ifndef IN_LOOPBACK 197141cc406Sopenharmony_ci# define IN_LOOPBACK(addr) (addr == 0x7f000001L) 198141cc406Sopenharmony_ci#endif 199141cc406Sopenharmony_ci 200141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 201141cc406Sopenharmony_ci# ifndef IN6_IS_ADDR_LOOPBACK 202141cc406Sopenharmony_ci# define IN6_IS_ADDR_LOOPBACK(a) \ 203141cc406Sopenharmony_ci (((const uint32_t *) (a))[0] == 0 \ 204141cc406Sopenharmony_ci && ((const uint32_t *) (a))[1] == 0 \ 205141cc406Sopenharmony_ci && ((const uint32_t *) (a))[2] == 0 \ 206141cc406Sopenharmony_ci && ((const uint32_t *) (a))[3] == htonl (1)) 207141cc406Sopenharmony_ci# endif 208141cc406Sopenharmony_ci# ifndef IN6_IS_ADDR_V4MAPPED 209141cc406Sopenharmony_ci# define IN6_IS_ADDR_V4MAPPED(a) \ 210141cc406Sopenharmony_ci((((const uint32_t *) (a))[0] == 0) \ 211141cc406Sopenharmony_ci && (((const uint32_t *) (a))[1] == 0) \ 212141cc406Sopenharmony_ci && (((const uint32_t *) (a))[2] == htonl (0xffff))) 213141cc406Sopenharmony_ci# endif 214141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 215141cc406Sopenharmony_ci 216141cc406Sopenharmony_ci#ifndef MAXHOSTNAMELEN 217141cc406Sopenharmony_ci# define MAXHOSTNAMELEN 120 218141cc406Sopenharmony_ci#endif 219141cc406Sopenharmony_ci 220141cc406Sopenharmony_ci#ifndef PATH_MAX 221141cc406Sopenharmony_ci# define PATH_MAX 1024 222141cc406Sopenharmony_ci#endif 223141cc406Sopenharmony_ci 224141cc406Sopenharmony_cistruct saned_child { 225141cc406Sopenharmony_ci pid_t pid; 226141cc406Sopenharmony_ci struct saned_child *next; 227141cc406Sopenharmony_ci}; 228141cc406Sopenharmony_cistruct saned_child *children; 229141cc406Sopenharmony_ciint numchildren; 230141cc406Sopenharmony_ci 231141cc406Sopenharmony_ci#define SANED_CONFIG_FILE "saned.conf" 232141cc406Sopenharmony_ci#define SANED_PID_FILE "/var/run/saned.pid" 233141cc406Sopenharmony_ci 234141cc406Sopenharmony_ci#define SANED_SERVICE_NAME "sane-port" 235141cc406Sopenharmony_ci#define SANED_SERVICE_PORT 6566 236141cc406Sopenharmony_ci#define SANED_SERVICE_PORT_S "6566" 237141cc406Sopenharmony_ci 238141cc406Sopenharmony_citypedef struct 239141cc406Sopenharmony_ci{ 240141cc406Sopenharmony_ci u_int inuse:1; /* is this handle in use? */ 241141cc406Sopenharmony_ci u_int scanning:1; /* are we scanning? */ 242141cc406Sopenharmony_ci u_int docancel:1; /* cancel the current scan */ 243141cc406Sopenharmony_ci SANE_Handle handle; /* backends handle */ 244141cc406Sopenharmony_ci} 245141cc406Sopenharmony_ciHandle; 246141cc406Sopenharmony_ci 247141cc406Sopenharmony_cistatic SANE_Net_Procedure_Number current_request; 248141cc406Sopenharmony_cistatic const char *prog_name; 249141cc406Sopenharmony_cistatic int can_authorize; 250141cc406Sopenharmony_cistatic Wire wire; 251141cc406Sopenharmony_cistatic int num_handles; 252141cc406Sopenharmony_cistatic int debug; 253141cc406Sopenharmony_cistatic int run_mode; 254141cc406Sopenharmony_cistatic int run_foreground; 255141cc406Sopenharmony_cistatic int run_once; 256141cc406Sopenharmony_cistatic int data_connect_timeout = 4000; 257141cc406Sopenharmony_cistatic Handle *handle; 258141cc406Sopenharmony_cistatic char *bind_addr; 259141cc406Sopenharmony_cistatic short bind_port = -1; 260141cc406Sopenharmony_cistatic union 261141cc406Sopenharmony_ci{ 262141cc406Sopenharmony_ci int w; 263141cc406Sopenharmony_ci u_char ch; 264141cc406Sopenharmony_ci} 265141cc406Sopenharmony_cibyte_order; 266141cc406Sopenharmony_ci 267141cc406Sopenharmony_ci/* The default-user name. This is not used to imply any rights. All 268141cc406Sopenharmony_ci it does is save a remote user some work by reducing the amount of 269141cc406Sopenharmony_ci text s/he has to type when authentication is requested. */ 270141cc406Sopenharmony_cistatic const char *default_username = "saned-user"; 271141cc406Sopenharmony_cistatic char *remote_ip; 272141cc406Sopenharmony_ci 273141cc406Sopenharmony_ci/* data port range */ 274141cc406Sopenharmony_cistatic in_port_t data_port_lo; 275141cc406Sopenharmony_cistatic in_port_t data_port_hi; 276141cc406Sopenharmony_ci 277141cc406Sopenharmony_ci#ifdef SANED_USES_AF_INDEP 278141cc406Sopenharmony_cistatic union { 279141cc406Sopenharmony_ci struct sockaddr_storage ss; 280141cc406Sopenharmony_ci struct sockaddr sa; 281141cc406Sopenharmony_ci struct sockaddr_in sin; 282141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 283141cc406Sopenharmony_ci struct sockaddr_in6 sin6; 284141cc406Sopenharmony_ci#endif 285141cc406Sopenharmony_ci} remote_address; 286141cc406Sopenharmony_cistatic int remote_address_len; 287141cc406Sopenharmony_ci#else 288141cc406Sopenharmony_cistatic struct in_addr remote_address; 289141cc406Sopenharmony_ci#endif /* SANED_USES_AF_INDEP */ 290141cc406Sopenharmony_ci 291141cc406Sopenharmony_ci#ifndef _PATH_HEQUIV 292141cc406Sopenharmony_ci# define _PATH_HEQUIV "/etc/hosts.equiv" 293141cc406Sopenharmony_ci#endif 294141cc406Sopenharmony_ci 295141cc406Sopenharmony_cistatic const char *config_file_names[] = { 296141cc406Sopenharmony_ci _PATH_HEQUIV, SANED_CONFIG_FILE 297141cc406Sopenharmony_ci}; 298141cc406Sopenharmony_ci 299141cc406Sopenharmony_cistatic SANE_Bool log_to_syslog = SANE_TRUE; 300141cc406Sopenharmony_ci 301141cc406Sopenharmony_ci/* forward declarations: */ 302141cc406Sopenharmony_cistatic int process_request (Wire * w); 303141cc406Sopenharmony_ci 304141cc406Sopenharmony_ci#define SANED_RUN_INETD 0 305141cc406Sopenharmony_ci#define SANED_RUN_ALONE 1 306141cc406Sopenharmony_ci 307141cc406Sopenharmony_ci#define DBG_ERR 1 308141cc406Sopenharmony_ci#define DBG_WARN 2 309141cc406Sopenharmony_ci#define DBG_MSG 3 310141cc406Sopenharmony_ci#define DBG_INFO 4 311141cc406Sopenharmony_ci#define DBG_DBG 5 312141cc406Sopenharmony_ci 313141cc406Sopenharmony_ci#define DBG saned_debug_call 314141cc406Sopenharmony_ci 315141cc406Sopenharmony_cistatic void 316141cc406Sopenharmony_cisaned_debug_call (int level, const char *fmt, ...) 317141cc406Sopenharmony_ci{ 318141cc406Sopenharmony_ci#ifndef NDEBUG 319141cc406Sopenharmony_ci va_list ap; 320141cc406Sopenharmony_ci va_start (ap, fmt); 321141cc406Sopenharmony_ci if (debug >= level) 322141cc406Sopenharmony_ci { 323141cc406Sopenharmony_ci if (log_to_syslog) 324141cc406Sopenharmony_ci { 325141cc406Sopenharmony_ci /* print to syslog */ 326141cc406Sopenharmony_ci vsyslog (LOG_DEBUG, fmt, ap); 327141cc406Sopenharmony_ci } 328141cc406Sopenharmony_ci else 329141cc406Sopenharmony_ci { 330141cc406Sopenharmony_ci /* print to stderr */ 331141cc406Sopenharmony_ci fprintf (stderr, "[saned] "); 332141cc406Sopenharmony_ci vfprintf (stderr, fmt, ap); 333141cc406Sopenharmony_ci } 334141cc406Sopenharmony_ci } 335141cc406Sopenharmony_ci va_end (ap); 336141cc406Sopenharmony_ci#endif 337141cc406Sopenharmony_ci} 338141cc406Sopenharmony_ci 339141cc406Sopenharmony_ci 340141cc406Sopenharmony_cistatic void 341141cc406Sopenharmony_cireset_watchdog (void) 342141cc406Sopenharmony_ci{ 343141cc406Sopenharmony_ci if (!debug) 344141cc406Sopenharmony_ci alarm (3600); 345141cc406Sopenharmony_ci} 346141cc406Sopenharmony_ci 347141cc406Sopenharmony_cistatic void 348141cc406Sopenharmony_ciauth_callback (SANE_String_Const res, 349141cc406Sopenharmony_ci SANE_Char *username, 350141cc406Sopenharmony_ci SANE_Char *password) 351141cc406Sopenharmony_ci{ 352141cc406Sopenharmony_ci SANE_Net_Procedure_Number procnum; 353141cc406Sopenharmony_ci SANE_Authorization_Req req; 354141cc406Sopenharmony_ci SANE_Word word, ack = 0; 355141cc406Sopenharmony_ci 356141cc406Sopenharmony_ci memset (username, 0, SANE_MAX_USERNAME_LEN); 357141cc406Sopenharmony_ci memset (password, 0, SANE_MAX_PASSWORD_LEN); 358141cc406Sopenharmony_ci 359141cc406Sopenharmony_ci if (!can_authorize) 360141cc406Sopenharmony_ci { 361141cc406Sopenharmony_ci DBG (DBG_WARN, 362141cc406Sopenharmony_ci "auth_callback: called during non-authorizable RPC (resource=%s)\n", 363141cc406Sopenharmony_ci res); 364141cc406Sopenharmony_ci return; 365141cc406Sopenharmony_ci } 366141cc406Sopenharmony_ci 367141cc406Sopenharmony_ci if (wire.status) 368141cc406Sopenharmony_ci { 369141cc406Sopenharmony_ci DBG(DBG_ERR, "auth_callback: bad status %d\n", wire.status); 370141cc406Sopenharmony_ci return; 371141cc406Sopenharmony_ci } 372141cc406Sopenharmony_ci 373141cc406Sopenharmony_ci switch (current_request) 374141cc406Sopenharmony_ci { 375141cc406Sopenharmony_ci case SANE_NET_OPEN: 376141cc406Sopenharmony_ci { 377141cc406Sopenharmony_ci SANE_Open_Reply reply; 378141cc406Sopenharmony_ci 379141cc406Sopenharmony_ci memset (&reply, 0, sizeof (reply)); 380141cc406Sopenharmony_ci reply.resource_to_authorize = (char *) res; 381141cc406Sopenharmony_ci sanei_w_reply (&wire, (WireCodecFunc) sanei_w_open_reply, &reply); 382141cc406Sopenharmony_ci } 383141cc406Sopenharmony_ci break; 384141cc406Sopenharmony_ci 385141cc406Sopenharmony_ci case SANE_NET_CONTROL_OPTION: 386141cc406Sopenharmony_ci { 387141cc406Sopenharmony_ci SANE_Control_Option_Reply reply; 388141cc406Sopenharmony_ci 389141cc406Sopenharmony_ci memset (&reply, 0, sizeof (reply)); 390141cc406Sopenharmony_ci reply.resource_to_authorize = (char *) res; 391141cc406Sopenharmony_ci sanei_w_reply (&wire, 392141cc406Sopenharmony_ci (WireCodecFunc) sanei_w_control_option_reply, &reply); 393141cc406Sopenharmony_ci } 394141cc406Sopenharmony_ci break; 395141cc406Sopenharmony_ci 396141cc406Sopenharmony_ci case SANE_NET_START: 397141cc406Sopenharmony_ci { 398141cc406Sopenharmony_ci SANE_Start_Reply reply; 399141cc406Sopenharmony_ci 400141cc406Sopenharmony_ci memset (&reply, 0, sizeof (reply)); 401141cc406Sopenharmony_ci reply.resource_to_authorize = (char *) res; 402141cc406Sopenharmony_ci sanei_w_reply (&wire, (WireCodecFunc) sanei_w_start_reply, &reply); 403141cc406Sopenharmony_ci } 404141cc406Sopenharmony_ci break; 405141cc406Sopenharmony_ci 406141cc406Sopenharmony_ci default: 407141cc406Sopenharmony_ci DBG (DBG_WARN, 408141cc406Sopenharmony_ci "auth_callback: called for unexpected request %d (resource=%s)\n", 409141cc406Sopenharmony_ci current_request, res); 410141cc406Sopenharmony_ci break; 411141cc406Sopenharmony_ci } 412141cc406Sopenharmony_ci 413141cc406Sopenharmony_ci if (wire.status) 414141cc406Sopenharmony_ci { 415141cc406Sopenharmony_ci DBG(DBG_ERR, "auth_callback: bad status %d\n", wire.status); 416141cc406Sopenharmony_ci return; 417141cc406Sopenharmony_ci } 418141cc406Sopenharmony_ci 419141cc406Sopenharmony_ci reset_watchdog (); 420141cc406Sopenharmony_ci 421141cc406Sopenharmony_ci sanei_w_set_dir (&wire, WIRE_DECODE); 422141cc406Sopenharmony_ci sanei_w_word (&wire, &word); 423141cc406Sopenharmony_ci 424141cc406Sopenharmony_ci if (wire.status) 425141cc406Sopenharmony_ci { 426141cc406Sopenharmony_ci DBG(DBG_ERR, "auth_callback: bad status %d\n", wire.status); 427141cc406Sopenharmony_ci return; 428141cc406Sopenharmony_ci } 429141cc406Sopenharmony_ci 430141cc406Sopenharmony_ci procnum = word; 431141cc406Sopenharmony_ci if (procnum != SANE_NET_AUTHORIZE) 432141cc406Sopenharmony_ci { 433141cc406Sopenharmony_ci DBG (DBG_WARN, 434141cc406Sopenharmony_ci "auth_callback: bad procedure number %d " 435141cc406Sopenharmony_ci "(expected: %d, resource=%s)\n", procnum, SANE_NET_AUTHORIZE, 436141cc406Sopenharmony_ci res); 437141cc406Sopenharmony_ci return; 438141cc406Sopenharmony_ci } 439141cc406Sopenharmony_ci 440141cc406Sopenharmony_ci sanei_w_authorization_req (&wire, &req); 441141cc406Sopenharmony_ci if (wire.status) 442141cc406Sopenharmony_ci { 443141cc406Sopenharmony_ci DBG(DBG_ERR, "auth_callback: bad status %d\n", wire.status); 444141cc406Sopenharmony_ci return; 445141cc406Sopenharmony_ci } 446141cc406Sopenharmony_ci 447141cc406Sopenharmony_ci if (req.username) 448141cc406Sopenharmony_ci strcpy (username, req.username); 449141cc406Sopenharmony_ci if (req.password) 450141cc406Sopenharmony_ci strcpy (password, req.password); 451141cc406Sopenharmony_ci if (!req.resource || strcmp (req.resource, res) != 0) 452141cc406Sopenharmony_ci { 453141cc406Sopenharmony_ci DBG (DBG_MSG, 454141cc406Sopenharmony_ci "auth_callback: got auth for resource %s (expected resource=%s)\n", 455141cc406Sopenharmony_ci res, req.resource); 456141cc406Sopenharmony_ci } 457141cc406Sopenharmony_ci sanei_w_free (&wire, (WireCodecFunc) sanei_w_authorization_req, &req); 458141cc406Sopenharmony_ci sanei_w_reply (&wire, (WireCodecFunc) sanei_w_word, &ack); 459141cc406Sopenharmony_ci} 460141cc406Sopenharmony_ci 461141cc406Sopenharmony_cistatic void 462141cc406Sopenharmony_ciquit (int signum) 463141cc406Sopenharmony_ci{ 464141cc406Sopenharmony_ci static int running = 0; 465141cc406Sopenharmony_ci int i; 466141cc406Sopenharmony_ci 467141cc406Sopenharmony_ci if (signum) 468141cc406Sopenharmony_ci DBG (DBG_ERR, "quit: received signal %d\n", signum); 469141cc406Sopenharmony_ci 470141cc406Sopenharmony_ci if (running) 471141cc406Sopenharmony_ci { 472141cc406Sopenharmony_ci DBG (DBG_ERR, "quit: already active, returning\n"); 473141cc406Sopenharmony_ci return; 474141cc406Sopenharmony_ci } 475141cc406Sopenharmony_ci running = 1; 476141cc406Sopenharmony_ci 477141cc406Sopenharmony_ci for (i = 0; i < num_handles; ++i) 478141cc406Sopenharmony_ci if (handle[i].inuse) 479141cc406Sopenharmony_ci sane_close (handle[i].handle); 480141cc406Sopenharmony_ci 481141cc406Sopenharmony_ci sane_exit (); 482141cc406Sopenharmony_ci sanei_w_exit (&wire); 483141cc406Sopenharmony_ci if (handle) 484141cc406Sopenharmony_ci free (handle); 485141cc406Sopenharmony_ci DBG (DBG_WARN, "quit: exiting\n"); 486141cc406Sopenharmony_ci if (log_to_syslog) 487141cc406Sopenharmony_ci closelog (); 488141cc406Sopenharmony_ci exit (EXIT_SUCCESS); /* This is a nowait-daemon. */ 489141cc406Sopenharmony_ci} 490141cc406Sopenharmony_ci 491141cc406Sopenharmony_cistatic SANE_Word 492141cc406Sopenharmony_ciget_free_handle (void) 493141cc406Sopenharmony_ci{ 494141cc406Sopenharmony_ci# define ALLOC_INCREMENT 16 495141cc406Sopenharmony_ci static int h, last_handle_checked = -1; 496141cc406Sopenharmony_ci 497141cc406Sopenharmony_ci if (num_handles > 0) 498141cc406Sopenharmony_ci { 499141cc406Sopenharmony_ci h = last_handle_checked + 1; 500141cc406Sopenharmony_ci do 501141cc406Sopenharmony_ci { 502141cc406Sopenharmony_ci if (h >= num_handles) 503141cc406Sopenharmony_ci h = 0; 504141cc406Sopenharmony_ci if (!handle[h].inuse) 505141cc406Sopenharmony_ci { 506141cc406Sopenharmony_ci last_handle_checked = h; 507141cc406Sopenharmony_ci memset (handle + h, 0, sizeof (handle[0])); 508141cc406Sopenharmony_ci handle[h].inuse = 1; 509141cc406Sopenharmony_ci return h; 510141cc406Sopenharmony_ci } 511141cc406Sopenharmony_ci ++h; 512141cc406Sopenharmony_ci } 513141cc406Sopenharmony_ci while (h != last_handle_checked); 514141cc406Sopenharmony_ci } 515141cc406Sopenharmony_ci 516141cc406Sopenharmony_ci /* we're out of handles---alloc some more: */ 517141cc406Sopenharmony_ci last_handle_checked = num_handles - 1; 518141cc406Sopenharmony_ci num_handles += ALLOC_INCREMENT; 519141cc406Sopenharmony_ci if (handle) 520141cc406Sopenharmony_ci handle = realloc (handle, num_handles * sizeof (handle[0])); 521141cc406Sopenharmony_ci else 522141cc406Sopenharmony_ci handle = malloc (num_handles * sizeof (handle[0])); 523141cc406Sopenharmony_ci if (!handle) 524141cc406Sopenharmony_ci return -1; 525141cc406Sopenharmony_ci memset (handle + last_handle_checked + 1, 0, 526141cc406Sopenharmony_ci ALLOC_INCREMENT * sizeof (handle[0])); 527141cc406Sopenharmony_ci return get_free_handle (); 528141cc406Sopenharmony_ci# undef ALLOC_INCREMENT 529141cc406Sopenharmony_ci} 530141cc406Sopenharmony_ci 531141cc406Sopenharmony_cistatic void 532141cc406Sopenharmony_ciclose_handle (int h) 533141cc406Sopenharmony_ci{ 534141cc406Sopenharmony_ci if (h >= 0 && handle[h].inuse) 535141cc406Sopenharmony_ci { 536141cc406Sopenharmony_ci sane_close (handle[h].handle); 537141cc406Sopenharmony_ci handle[h].inuse = 0; 538141cc406Sopenharmony_ci } 539141cc406Sopenharmony_ci} 540141cc406Sopenharmony_ci 541141cc406Sopenharmony_cistatic SANE_Word 542141cc406Sopenharmony_cidecode_handle (Wire * w, const char *op) 543141cc406Sopenharmony_ci{ 544141cc406Sopenharmony_ci SANE_Word h; 545141cc406Sopenharmony_ci 546141cc406Sopenharmony_ci sanei_w_word (w, &h); 547141cc406Sopenharmony_ci if (w->status || (unsigned) h >= (unsigned) num_handles || !handle[h].inuse) 548141cc406Sopenharmony_ci { 549141cc406Sopenharmony_ci DBG (DBG_ERR, 550141cc406Sopenharmony_ci "decode_handle: %s: error while decoding handle argument " 551141cc406Sopenharmony_ci "(h=%d, %s)\n", op, h, strerror (w->status)); 552141cc406Sopenharmony_ci return -1; 553141cc406Sopenharmony_ci } 554141cc406Sopenharmony_ci return h; 555141cc406Sopenharmony_ci} 556141cc406Sopenharmony_ci 557141cc406Sopenharmony_ci 558141cc406Sopenharmony_ci 559141cc406Sopenharmony_ci/* Convert a number of bits to an 8-bit bitmask */ 560141cc406Sopenharmony_cistatic unsigned int cidrtomask[9] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 561141cc406Sopenharmony_ci 0xF8, 0xFC, 0xFE, 0xFF }; 562141cc406Sopenharmony_ci 563141cc406Sopenharmony_ci#ifdef SANED_USES_AF_INDEP 564141cc406Sopenharmony_cistatic SANE_Bool 565141cc406Sopenharmony_cicheck_v4_in_range (struct sockaddr_in *sin, char *base_ip, char *netmask) 566141cc406Sopenharmony_ci{ 567141cc406Sopenharmony_ci int cidr; 568141cc406Sopenharmony_ci int i, err; 569141cc406Sopenharmony_ci char *end; 570141cc406Sopenharmony_ci uint32_t mask; 571141cc406Sopenharmony_ci struct sockaddr_in *base; 572141cc406Sopenharmony_ci struct addrinfo hints; 573141cc406Sopenharmony_ci struct addrinfo *res; 574141cc406Sopenharmony_ci SANE_Bool ret = SANE_FALSE; 575141cc406Sopenharmony_ci 576141cc406Sopenharmony_ci cidr = -1; 577141cc406Sopenharmony_ci cidr = strtol (netmask, &end, 10); 578141cc406Sopenharmony_ci 579141cc406Sopenharmony_ci /* Sanity check on the cidr value */ 580141cc406Sopenharmony_ci if ((cidr < 0) || (cidr > 32) || (end == netmask)) 581141cc406Sopenharmony_ci { 582141cc406Sopenharmony_ci DBG (DBG_ERR, "check_v4_in_range: invalid CIDR value (%s) !\n", netmask); 583141cc406Sopenharmony_ci return SANE_FALSE; 584141cc406Sopenharmony_ci } 585141cc406Sopenharmony_ci 586141cc406Sopenharmony_ci mask = 0; 587141cc406Sopenharmony_ci cidr -= 8; 588141cc406Sopenharmony_ci 589141cc406Sopenharmony_ci /* Build a bitmask out of the CIDR value */ 590141cc406Sopenharmony_ci for (i = 3; cidr >= 0; i--) 591141cc406Sopenharmony_ci { 592141cc406Sopenharmony_ci mask |= (0xff << (8 * i)); 593141cc406Sopenharmony_ci cidr -= 8; 594141cc406Sopenharmony_ci } 595141cc406Sopenharmony_ci 596141cc406Sopenharmony_ci if (cidr < 0) 597141cc406Sopenharmony_ci mask |= (cidrtomask[cidr + 8] << (8 * i)); 598141cc406Sopenharmony_ci 599141cc406Sopenharmony_ci mask = htonl (mask); 600141cc406Sopenharmony_ci 601141cc406Sopenharmony_ci /* get a sockaddr_in representing the base IP address */ 602141cc406Sopenharmony_ci memset (&hints, 0, sizeof (struct addrinfo)); 603141cc406Sopenharmony_ci hints.ai_flags = AI_NUMERICHOST; 604141cc406Sopenharmony_ci hints.ai_family = PF_INET; 605141cc406Sopenharmony_ci 606141cc406Sopenharmony_ci err = getaddrinfo (base_ip, NULL, &hints, &res); 607141cc406Sopenharmony_ci if (err) 608141cc406Sopenharmony_ci { 609141cc406Sopenharmony_ci DBG (DBG_DBG, "check_v4_in_range: getaddrinfo() failed: %s\n", gai_strerror (err)); 610141cc406Sopenharmony_ci return SANE_FALSE; 611141cc406Sopenharmony_ci } 612141cc406Sopenharmony_ci 613141cc406Sopenharmony_ci base = (struct sockaddr_in *) res->ai_addr; 614141cc406Sopenharmony_ci 615141cc406Sopenharmony_ci /* 616141cc406Sopenharmony_ci * Check that the address belongs to the specified subnet, using the bitmask. 617141cc406Sopenharmony_ci * The address is represented by a 32bit integer. 618141cc406Sopenharmony_ci */ 619141cc406Sopenharmony_ci if ((base->sin_addr.s_addr & mask) == (sin->sin_addr.s_addr & mask)) 620141cc406Sopenharmony_ci ret = SANE_TRUE; 621141cc406Sopenharmony_ci 622141cc406Sopenharmony_ci freeaddrinfo (res); 623141cc406Sopenharmony_ci 624141cc406Sopenharmony_ci return ret; 625141cc406Sopenharmony_ci} 626141cc406Sopenharmony_ci 627141cc406Sopenharmony_ci 628141cc406Sopenharmony_ci# ifdef ENABLE_IPV6 629141cc406Sopenharmony_ci 630141cc406Sopenharmony_cistatic SANE_Bool 631141cc406Sopenharmony_cicheck_v6_in_range (struct sockaddr_in6 *sin6, char *base_ip, char *netmask) 632141cc406Sopenharmony_ci{ 633141cc406Sopenharmony_ci int cidr; 634141cc406Sopenharmony_ci int i, err; 635141cc406Sopenharmony_ci unsigned int mask[16]; 636141cc406Sopenharmony_ci char *end; 637141cc406Sopenharmony_ci struct sockaddr_in6 *base; 638141cc406Sopenharmony_ci struct addrinfo hints; 639141cc406Sopenharmony_ci struct addrinfo *res; 640141cc406Sopenharmony_ci SANE_Bool ret = SANE_TRUE; 641141cc406Sopenharmony_ci 642141cc406Sopenharmony_ci cidr = -1; 643141cc406Sopenharmony_ci cidr = strtol (netmask, &end, 10); 644141cc406Sopenharmony_ci 645141cc406Sopenharmony_ci /* Sanity check on the cidr value */ 646141cc406Sopenharmony_ci if ((cidr < 0) || (cidr > 128) || (end == netmask)) 647141cc406Sopenharmony_ci { 648141cc406Sopenharmony_ci DBG (DBG_ERR, "check_v6_in_range: invalid CIDR value (%s) !\n", netmask); 649141cc406Sopenharmony_ci return SANE_FALSE; 650141cc406Sopenharmony_ci } 651141cc406Sopenharmony_ci 652141cc406Sopenharmony_ci memset (mask, 0, (16 * sizeof (unsigned int))); 653141cc406Sopenharmony_ci cidr -= 8; 654141cc406Sopenharmony_ci 655141cc406Sopenharmony_ci /* Build a bitmask out of the CIDR value */ 656141cc406Sopenharmony_ci for (i = 0; cidr >= 0; i++) 657141cc406Sopenharmony_ci { 658141cc406Sopenharmony_ci mask[i] = 0xff; 659141cc406Sopenharmony_ci cidr -= 8; 660141cc406Sopenharmony_ci } 661141cc406Sopenharmony_ci 662141cc406Sopenharmony_ci if (cidr < 0) 663141cc406Sopenharmony_ci mask[i] = cidrtomask[cidr + 8]; 664141cc406Sopenharmony_ci 665141cc406Sopenharmony_ci /* get a sockaddr_in6 representing the base IP address */ 666141cc406Sopenharmony_ci memset (&hints, 0, sizeof (struct addrinfo)); 667141cc406Sopenharmony_ci hints.ai_flags = AI_NUMERICHOST; 668141cc406Sopenharmony_ci hints.ai_family = PF_INET6; 669141cc406Sopenharmony_ci 670141cc406Sopenharmony_ci err = getaddrinfo (base_ip, NULL, &hints, &res); 671141cc406Sopenharmony_ci if (err) 672141cc406Sopenharmony_ci { 673141cc406Sopenharmony_ci DBG (DBG_DBG, "check_v6_in_range: getaddrinfo() failed: %s\n", gai_strerror (err)); 674141cc406Sopenharmony_ci return SANE_FALSE; 675141cc406Sopenharmony_ci } 676141cc406Sopenharmony_ci 677141cc406Sopenharmony_ci base = (struct sockaddr_in6 *) res->ai_addr; 678141cc406Sopenharmony_ci 679141cc406Sopenharmony_ci /* 680141cc406Sopenharmony_ci * Check that the address belongs to the specified subnet. 681141cc406Sopenharmony_ci * The address is reprensented by an array of 16 8bit integers. 682141cc406Sopenharmony_ci */ 683141cc406Sopenharmony_ci for (i = 0; i < 16; i++) 684141cc406Sopenharmony_ci { 685141cc406Sopenharmony_ci if ((base->sin6_addr.s6_addr[i] & mask[i]) != (sin6->sin6_addr.s6_addr[i] & mask[i])) 686141cc406Sopenharmony_ci { 687141cc406Sopenharmony_ci ret = SANE_FALSE; 688141cc406Sopenharmony_ci break; 689141cc406Sopenharmony_ci } 690141cc406Sopenharmony_ci } 691141cc406Sopenharmony_ci 692141cc406Sopenharmony_ci freeaddrinfo (res); 693141cc406Sopenharmony_ci 694141cc406Sopenharmony_ci return ret; 695141cc406Sopenharmony_ci} 696141cc406Sopenharmony_ci# endif /* ENABLE_IPV6 */ 697141cc406Sopenharmony_ci#else /* !SANED_USES_AF_INDEP */ 698141cc406Sopenharmony_cistatic SANE_Bool 699141cc406Sopenharmony_cicheck_v4_in_range (struct in_addr *inaddr, struct in_addr *base, char *netmask) 700141cc406Sopenharmony_ci{ 701141cc406Sopenharmony_ci int cidr; 702141cc406Sopenharmony_ci int i; 703141cc406Sopenharmony_ci char *end; 704141cc406Sopenharmony_ci uint32_t mask; 705141cc406Sopenharmony_ci SANE_Bool ret = SANE_FALSE; 706141cc406Sopenharmony_ci 707141cc406Sopenharmony_ci cidr = -1; 708141cc406Sopenharmony_ci cidr = strtol (netmask, &end, 10); 709141cc406Sopenharmony_ci 710141cc406Sopenharmony_ci /* sanity check on the cidr value */ 711141cc406Sopenharmony_ci if ((cidr < 0) || (cidr > 32) || (end == netmask)) 712141cc406Sopenharmony_ci { 713141cc406Sopenharmony_ci DBG (DBG_ERR, "check_v4_in_range: invalid CIDR value (%s) !\n", netmask); 714141cc406Sopenharmony_ci return SANE_FALSE; 715141cc406Sopenharmony_ci } 716141cc406Sopenharmony_ci 717141cc406Sopenharmony_ci mask = 0; 718141cc406Sopenharmony_ci cidr -= 8; 719141cc406Sopenharmony_ci 720141cc406Sopenharmony_ci /* Build a bitmask out of the CIDR value */ 721141cc406Sopenharmony_ci for (i = 3; cidr >= 0; i--) 722141cc406Sopenharmony_ci { 723141cc406Sopenharmony_ci mask |= (0xff << (8 * i)); 724141cc406Sopenharmony_ci cidr -= 8; 725141cc406Sopenharmony_ci } 726141cc406Sopenharmony_ci 727141cc406Sopenharmony_ci if (cidr < 0) 728141cc406Sopenharmony_ci mask |= (cidrtomask[cidr + 8] << (8 * i)); 729141cc406Sopenharmony_ci 730141cc406Sopenharmony_ci mask = htonl (mask); 731141cc406Sopenharmony_ci 732141cc406Sopenharmony_ci /* 733141cc406Sopenharmony_ci * Check that the address belongs to the specified subnet, using the bitmask. 734141cc406Sopenharmony_ci * The address is represented by a 32bit integer. 735141cc406Sopenharmony_ci */ 736141cc406Sopenharmony_ci if ((base->s_addr & mask) == (inaddr->s_addr & mask)) 737141cc406Sopenharmony_ci ret = SANE_TRUE; 738141cc406Sopenharmony_ci 739141cc406Sopenharmony_ci return ret; 740141cc406Sopenharmony_ci} 741141cc406Sopenharmony_ci#endif /* SANED_USES_AF_INDEP */ 742141cc406Sopenharmony_ci 743141cc406Sopenharmony_ci 744141cc406Sopenharmony_ci 745141cc406Sopenharmony_ci/* Access control */ 746141cc406Sopenharmony_ci#ifdef SANED_USES_AF_INDEP 747141cc406Sopenharmony_cistatic SANE_Status 748141cc406Sopenharmony_cicheck_host (int fd) 749141cc406Sopenharmony_ci{ 750141cc406Sopenharmony_ci struct sockaddr_in *sin = NULL; 751141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 752141cc406Sopenharmony_ci struct sockaddr_in6 *sin6; 753141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 754141cc406Sopenharmony_ci struct addrinfo hints; 755141cc406Sopenharmony_ci struct addrinfo *res; 756141cc406Sopenharmony_ci struct addrinfo *resp; 757141cc406Sopenharmony_ci int j, access_ok = 0; 758141cc406Sopenharmony_ci int err; 759141cc406Sopenharmony_ci char text_addr[64]; 760141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 761141cc406Sopenharmony_ci SANE_Bool IPv4map = SANE_FALSE; 762141cc406Sopenharmony_ci char *remote_ipv4 = NULL; /* in case we have an IPv4-mapped address (eg ::ffff:127.0.0.1) */ 763141cc406Sopenharmony_ci char *tmp; 764141cc406Sopenharmony_ci struct addrinfo *remote_ipv4_addr = NULL; 765141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 766141cc406Sopenharmony_ci char config_line_buf[1024]; 767141cc406Sopenharmony_ci char *config_line; 768141cc406Sopenharmony_ci char *netmask; 769141cc406Sopenharmony_ci char hostname[MAXHOSTNAMELEN]; 770141cc406Sopenharmony_ci 771141cc406Sopenharmony_ci int len; 772141cc406Sopenharmony_ci FILE *fp; 773141cc406Sopenharmony_ci 774141cc406Sopenharmony_ci /* Get address of remote host */ 775141cc406Sopenharmony_ci remote_address_len = sizeof (remote_address.ss); 776141cc406Sopenharmony_ci if (getpeername (fd, &remote_address.sa, (socklen_t *) &remote_address_len) < 0) 777141cc406Sopenharmony_ci { 778141cc406Sopenharmony_ci DBG (DBG_ERR, "check_host: getpeername failed: %s\n", strerror (errno)); 779141cc406Sopenharmony_ci remote_ip = strdup ("[error]"); 780141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 781141cc406Sopenharmony_ci } 782141cc406Sopenharmony_ci 783141cc406Sopenharmony_ci err = getnameinfo (&remote_address.sa, remote_address_len, 784141cc406Sopenharmony_ci hostname, sizeof (hostname), NULL, 0, NI_NUMERICHOST); 785141cc406Sopenharmony_ci if (err) 786141cc406Sopenharmony_ci { 787141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: getnameinfo failed: %s\n", gai_strerror(err)); 788141cc406Sopenharmony_ci remote_ip = strdup ("[error]"); 789141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 790141cc406Sopenharmony_ci } 791141cc406Sopenharmony_ci else 792141cc406Sopenharmony_ci remote_ip = strdup (hostname); 793141cc406Sopenharmony_ci 794141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 795141cc406Sopenharmony_ci sin6 = &remote_address.sin6; 796141cc406Sopenharmony_ci 797141cc406Sopenharmony_ci if (IN6_IS_ADDR_V4MAPPED ((struct in6_addr *)sin6->sin6_addr.s6_addr)) 798141cc406Sopenharmony_ci { 799141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: detected an IPv4-mapped address\n"); 800141cc406Sopenharmony_ci remote_ipv4 = remote_ip + 7; 801141cc406Sopenharmony_ci IPv4map = SANE_TRUE; 802141cc406Sopenharmony_ci 803141cc406Sopenharmony_ci memset (&hints, 0, sizeof (struct addrinfo)); 804141cc406Sopenharmony_ci hints.ai_flags = AI_NUMERICHOST; 805141cc406Sopenharmony_ci hints.ai_family = PF_INET; 806141cc406Sopenharmony_ci 807141cc406Sopenharmony_ci err = getaddrinfo (remote_ipv4, NULL, &hints, &res); 808141cc406Sopenharmony_ci if (err) 809141cc406Sopenharmony_ci { 810141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: getaddrinfo() failed: %s\n", gai_strerror (err)); 811141cc406Sopenharmony_ci IPv4map = SANE_FALSE; /* we failed, remote_ipv4_addr points to nothing */ 812141cc406Sopenharmony_ci } 813141cc406Sopenharmony_ci else 814141cc406Sopenharmony_ci { 815141cc406Sopenharmony_ci remote_ipv4_addr = res; 816141cc406Sopenharmony_ci sin = (struct sockaddr_in *)res->ai_addr; 817141cc406Sopenharmony_ci } 818141cc406Sopenharmony_ci } 819141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 820141cc406Sopenharmony_ci 821141cc406Sopenharmony_ci DBG (DBG_WARN, "check_host: access by remote host: %s\n", remote_ip); 822141cc406Sopenharmony_ci 823141cc406Sopenharmony_ci /* Always allow access from local host. Do it here to avoid DNS lookups 824141cc406Sopenharmony_ci and reading saned.conf. */ 825141cc406Sopenharmony_ci 826141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 827141cc406Sopenharmony_ci if (IPv4map == SANE_TRUE) 828141cc406Sopenharmony_ci { 829141cc406Sopenharmony_ci if (IN_LOOPBACK (ntohl (sin->sin_addr.s_addr))) 830141cc406Sopenharmony_ci { 831141cc406Sopenharmony_ci DBG (DBG_MSG, 832141cc406Sopenharmony_ci "check_host: remote host is IN_LOOPBACK: access granted\n"); 833141cc406Sopenharmony_ci freeaddrinfo (remote_ipv4_addr); 834141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 835141cc406Sopenharmony_ci } 836141cc406Sopenharmony_ci freeaddrinfo (remote_ipv4_addr); 837141cc406Sopenharmony_ci } 838141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 839141cc406Sopenharmony_ci 840141cc406Sopenharmony_ci sin = &remote_address.sin; 841141cc406Sopenharmony_ci 842141cc406Sopenharmony_ci switch (SS_FAMILY(remote_address.ss)) 843141cc406Sopenharmony_ci { 844141cc406Sopenharmony_ci case AF_INET: 845141cc406Sopenharmony_ci if (IN_LOOPBACK (ntohl (sin->sin_addr.s_addr))) 846141cc406Sopenharmony_ci { 847141cc406Sopenharmony_ci DBG (DBG_MSG, 848141cc406Sopenharmony_ci "check_host: remote host is IN_LOOPBACK: access granted\n"); 849141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 850141cc406Sopenharmony_ci } 851141cc406Sopenharmony_ci break; 852141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 853141cc406Sopenharmony_ci case AF_INET6: 854141cc406Sopenharmony_ci if (IN6_IS_ADDR_LOOPBACK ((struct in6_addr *)sin6->sin6_addr.s6_addr)) 855141cc406Sopenharmony_ci { 856141cc406Sopenharmony_ci DBG (DBG_MSG, 857141cc406Sopenharmony_ci "check_host: remote host is IN6_LOOPBACK: access granted\n"); 858141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 859141cc406Sopenharmony_ci } 860141cc406Sopenharmony_ci break; 861141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 862141cc406Sopenharmony_ci default: 863141cc406Sopenharmony_ci break; 864141cc406Sopenharmony_ci } 865141cc406Sopenharmony_ci 866141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: remote host is not IN_LOOPBACK" 867141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 868141cc406Sopenharmony_ci " nor IN6_LOOPBACK" 869141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 870141cc406Sopenharmony_ci "\n"); 871141cc406Sopenharmony_ci 872141cc406Sopenharmony_ci 873141cc406Sopenharmony_ci /* Get name of local host */ 874141cc406Sopenharmony_ci if (gethostname (hostname, sizeof (hostname)) < 0) 875141cc406Sopenharmony_ci { 876141cc406Sopenharmony_ci DBG (DBG_ERR, "check_host: gethostname failed: %s\n", strerror (errno)); 877141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 878141cc406Sopenharmony_ci } 879141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: local hostname: %s\n", hostname); 880141cc406Sopenharmony_ci 881141cc406Sopenharmony_ci /* Get local addresses */ 882141cc406Sopenharmony_ci memset (&hints, 0, sizeof (hints)); 883141cc406Sopenharmony_ci hints.ai_flags = AI_CANONNAME; 884141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 885141cc406Sopenharmony_ci hints.ai_family = PF_UNSPEC; 886141cc406Sopenharmony_ci#else 887141cc406Sopenharmony_ci hints.ai_family = PF_INET; 888141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 889141cc406Sopenharmony_ci 890141cc406Sopenharmony_ci err = getaddrinfo (hostname, NULL, &hints, &res); 891141cc406Sopenharmony_ci if (err) 892141cc406Sopenharmony_ci { 893141cc406Sopenharmony_ci DBG (DBG_ERR, "check_host: getaddrinfo for local hostname failed: %s\n", 894141cc406Sopenharmony_ci gai_strerror (err)); 895141cc406Sopenharmony_ci 896141cc406Sopenharmony_ci /* Proceed even if the local hostname does not resolve */ 897141cc406Sopenharmony_ci if (err != EAI_NONAME) 898141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 899141cc406Sopenharmony_ci } 900141cc406Sopenharmony_ci else 901141cc406Sopenharmony_ci { 902141cc406Sopenharmony_ci for (resp = res; resp != NULL; resp = resp->ai_next) 903141cc406Sopenharmony_ci { 904141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: local hostname(s) (from DNS): %s\n", 905141cc406Sopenharmony_ci resp->ai_canonname); 906141cc406Sopenharmony_ci 907141cc406Sopenharmony_ci err = getnameinfo (resp->ai_addr, resp->ai_addrlen, text_addr, 908141cc406Sopenharmony_ci sizeof (text_addr), NULL, 0, NI_NUMERICHOST); 909141cc406Sopenharmony_ci if (err) 910141cc406Sopenharmony_ci strncpy (text_addr, "[error]", 8); 911141cc406Sopenharmony_ci 912141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 913141cc406Sopenharmony_ci if ((strcasecmp (text_addr, remote_ip) == 0) || 914141cc406Sopenharmony_ci ((IPv4map == SANE_TRUE) && (strcmp (text_addr, remote_ipv4) == 0))) 915141cc406Sopenharmony_ci#else 916141cc406Sopenharmony_ci if (strcmp (text_addr, remote_ip) == 0) 917141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 918141cc406Sopenharmony_ci { 919141cc406Sopenharmony_ci DBG (DBG_MSG, "check_host: remote host has same addr as local: access granted\n"); 920141cc406Sopenharmony_ci 921141cc406Sopenharmony_ci freeaddrinfo (res); 922141cc406Sopenharmony_ci res = NULL; 923141cc406Sopenharmony_ci 924141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 925141cc406Sopenharmony_ci } 926141cc406Sopenharmony_ci } 927141cc406Sopenharmony_ci 928141cc406Sopenharmony_ci freeaddrinfo (res); 929141cc406Sopenharmony_ci res = NULL; 930141cc406Sopenharmony_ci 931141cc406Sopenharmony_ci DBG (DBG_DBG, 932141cc406Sopenharmony_ci "check_host: remote host doesn't have same addr as local\n"); 933141cc406Sopenharmony_ci } 934141cc406Sopenharmony_ci 935141cc406Sopenharmony_ci /* must be a remote host: check contents of PATH_NET_CONFIG or 936141cc406Sopenharmony_ci /etc/hosts.equiv if former doesn't exist: */ 937141cc406Sopenharmony_ci for (j = 0; j < NELEMS (config_file_names); ++j) 938141cc406Sopenharmony_ci { 939141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: opening config file: %s\n", 940141cc406Sopenharmony_ci config_file_names[j]); 941141cc406Sopenharmony_ci if (config_file_names[j][0] == '/') 942141cc406Sopenharmony_ci fp = fopen (config_file_names[j], "r"); 943141cc406Sopenharmony_ci else 944141cc406Sopenharmony_ci fp = sanei_config_open (config_file_names[j]); 945141cc406Sopenharmony_ci if (!fp) 946141cc406Sopenharmony_ci { 947141cc406Sopenharmony_ci DBG (DBG_MSG, 948141cc406Sopenharmony_ci "check_host: can't open config file: %s (%s)\n", 949141cc406Sopenharmony_ci config_file_names[j], strerror (errno)); 950141cc406Sopenharmony_ci continue; 951141cc406Sopenharmony_ci } 952141cc406Sopenharmony_ci 953141cc406Sopenharmony_ci while (!access_ok && sanei_config_read (config_line_buf, 954141cc406Sopenharmony_ci sizeof (config_line_buf), fp)) 955141cc406Sopenharmony_ci { 956141cc406Sopenharmony_ci config_line = config_line_buf; /* from now on, use a pointer */ 957141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: config file line: `%s'\n", config_line); 958141cc406Sopenharmony_ci if (config_line[0] == '#') 959141cc406Sopenharmony_ci continue; /* ignore comments */ 960141cc406Sopenharmony_ci 961141cc406Sopenharmony_ci if (strchr (config_line, '=')) 962141cc406Sopenharmony_ci continue; /* ignore lines with an = sign */ 963141cc406Sopenharmony_ci 964141cc406Sopenharmony_ci len = strlen (config_line); 965141cc406Sopenharmony_ci if (!len) 966141cc406Sopenharmony_ci continue; /* ignore empty lines */ 967141cc406Sopenharmony_ci 968141cc406Sopenharmony_ci /* look for a subnet specification */ 969141cc406Sopenharmony_ci netmask = strchr (config_line, '/'); 970141cc406Sopenharmony_ci if (netmask != NULL) 971141cc406Sopenharmony_ci { 972141cc406Sopenharmony_ci *netmask = '\0'; 973141cc406Sopenharmony_ci netmask++; 974141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: subnet with base IP = %s, CIDR netmask = %s\n", 975141cc406Sopenharmony_ci config_line, netmask); 976141cc406Sopenharmony_ci } 977141cc406Sopenharmony_ci 978141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 979141cc406Sopenharmony_ci /* IPv6 addresses are enclosed in [] */ 980141cc406Sopenharmony_ci if (*config_line == '[') 981141cc406Sopenharmony_ci { 982141cc406Sopenharmony_ci config_line++; 983141cc406Sopenharmony_ci tmp = strchr (config_line, ']'); 984141cc406Sopenharmony_ci if (tmp == NULL) 985141cc406Sopenharmony_ci { 986141cc406Sopenharmony_ci DBG (DBG_ERR, 987141cc406Sopenharmony_ci "check_host: malformed IPv6 address in config file, skipping: [%s\n", 988141cc406Sopenharmony_ci config_line); 989141cc406Sopenharmony_ci continue; 990141cc406Sopenharmony_ci } 991141cc406Sopenharmony_ci *tmp = '\0'; 992141cc406Sopenharmony_ci } 993141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 994141cc406Sopenharmony_ci 995141cc406Sopenharmony_ci if (strcmp (config_line, "+") == 0) 996141cc406Sopenharmony_ci { 997141cc406Sopenharmony_ci access_ok = 1; 998141cc406Sopenharmony_ci DBG (DBG_DBG, 999141cc406Sopenharmony_ci "check_host: access granted from any host (`+')\n"); 1000141cc406Sopenharmony_ci } 1001141cc406Sopenharmony_ci /* compare remote_ip (remote IP address) to the config_line */ 1002141cc406Sopenharmony_ci else if (strcasecmp (config_line, remote_ip) == 0) 1003141cc406Sopenharmony_ci { 1004141cc406Sopenharmony_ci access_ok = 1; 1005141cc406Sopenharmony_ci DBG (DBG_DBG, 1006141cc406Sopenharmony_ci "check_host: access granted from IP address %s\n", remote_ip); 1007141cc406Sopenharmony_ci } 1008141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1009141cc406Sopenharmony_ci else if ((IPv4map == SANE_TRUE) && (strcmp (config_line, remote_ipv4) == 0)) 1010141cc406Sopenharmony_ci { 1011141cc406Sopenharmony_ci access_ok = 1; 1012141cc406Sopenharmony_ci DBG (DBG_DBG, 1013141cc406Sopenharmony_ci "check_host: access granted from IP address %s (IPv4-mapped)\n", remote_ip); 1014141cc406Sopenharmony_ci } 1015141cc406Sopenharmony_ci /* handle IP ranges, take care of the IPv4map stuff */ 1016141cc406Sopenharmony_ci else if (netmask != NULL) 1017141cc406Sopenharmony_ci { 1018141cc406Sopenharmony_ci if (strchr (config_line, ':') != NULL) /* is a v6 address */ 1019141cc406Sopenharmony_ci { 1020141cc406Sopenharmony_ci if (SS_FAMILY(remote_address.ss) == AF_INET6) 1021141cc406Sopenharmony_ci { 1022141cc406Sopenharmony_ci if (check_v6_in_range (sin6, config_line, netmask)) 1023141cc406Sopenharmony_ci { 1024141cc406Sopenharmony_ci access_ok = 1; 1025141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: access granted from IP address %s (in subnet [%s]/%s)\n", 1026141cc406Sopenharmony_ci remote_ip, config_line, netmask); 1027141cc406Sopenharmony_ci } 1028141cc406Sopenharmony_ci } 1029141cc406Sopenharmony_ci } 1030141cc406Sopenharmony_ci else /* is a v4 address */ 1031141cc406Sopenharmony_ci { 1032141cc406Sopenharmony_ci if (IPv4map == SANE_TRUE) 1033141cc406Sopenharmony_ci { 1034141cc406Sopenharmony_ci /* get a sockaddr_in representing the v4-mapped IP address */ 1035141cc406Sopenharmony_ci memset (&hints, 0, sizeof (struct addrinfo)); 1036141cc406Sopenharmony_ci hints.ai_flags = AI_NUMERICHOST; 1037141cc406Sopenharmony_ci hints.ai_family = PF_INET; 1038141cc406Sopenharmony_ci 1039141cc406Sopenharmony_ci err = getaddrinfo (remote_ipv4, NULL, &hints, &res); 1040141cc406Sopenharmony_ci if (err) 1041141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: getaddrinfo() failed: %s\n", gai_strerror (err)); 1042141cc406Sopenharmony_ci else 1043141cc406Sopenharmony_ci sin = (struct sockaddr_in *)res->ai_addr; 1044141cc406Sopenharmony_ci } 1045141cc406Sopenharmony_ci 1046141cc406Sopenharmony_ci if ((SS_FAMILY(remote_address.ss) == AF_INET) || 1047141cc406Sopenharmony_ci (IPv4map == SANE_TRUE)) 1048141cc406Sopenharmony_ci { 1049141cc406Sopenharmony_ci 1050141cc406Sopenharmony_ci if (check_v4_in_range (sin, config_line, netmask)) 1051141cc406Sopenharmony_ci { 1052141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: access granted from IP address %s (in subnet %s/%s)\n", 1053141cc406Sopenharmony_ci ((IPv4map == SANE_TRUE) ? remote_ipv4 : remote_ip), config_line, netmask); 1054141cc406Sopenharmony_ci access_ok = 1; 1055141cc406Sopenharmony_ci } 1056141cc406Sopenharmony_ci else 1057141cc406Sopenharmony_ci { 1058141cc406Sopenharmony_ci /* restore the old sin pointer */ 1059141cc406Sopenharmony_ci sin = &remote_address.sin; 1060141cc406Sopenharmony_ci } 1061141cc406Sopenharmony_ci 1062141cc406Sopenharmony_ci if (res != NULL) 1063141cc406Sopenharmony_ci { 1064141cc406Sopenharmony_ci freeaddrinfo (res); 1065141cc406Sopenharmony_ci res = NULL; 1066141cc406Sopenharmony_ci } 1067141cc406Sopenharmony_ci } 1068141cc406Sopenharmony_ci } 1069141cc406Sopenharmony_ci } 1070141cc406Sopenharmony_ci#else /* !ENABLE_IPV6 */ 1071141cc406Sopenharmony_ci /* handle IP ranges */ 1072141cc406Sopenharmony_ci else if (netmask != NULL) 1073141cc406Sopenharmony_ci { 1074141cc406Sopenharmony_ci if (check_v4_in_range (sin, config_line, netmask)) 1075141cc406Sopenharmony_ci { 1076141cc406Sopenharmony_ci access_ok = 1; 1077141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: access granted from IP address %s (in subnet %s/%s)\n", 1078141cc406Sopenharmony_ci remote_ip, config_line, netmask); 1079141cc406Sopenharmony_ci } 1080141cc406Sopenharmony_ci } 1081141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1082141cc406Sopenharmony_ci else 1083141cc406Sopenharmony_ci { 1084141cc406Sopenharmony_ci memset (&hints, 0, sizeof (hints)); 1085141cc406Sopenharmony_ci hints.ai_flags = AI_CANONNAME; 1086141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1087141cc406Sopenharmony_ci hints.ai_family = PF_UNSPEC; 1088141cc406Sopenharmony_ci#else 1089141cc406Sopenharmony_ci hints.ai_family = PF_INET; 1090141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1091141cc406Sopenharmony_ci 1092141cc406Sopenharmony_ci err = getaddrinfo (config_line, NULL, &hints, &res); 1093141cc406Sopenharmony_ci if (err) 1094141cc406Sopenharmony_ci { 1095141cc406Sopenharmony_ci DBG (DBG_DBG, 1096141cc406Sopenharmony_ci "check_host: getaddrinfo for `%s' failed: %s\n", 1097141cc406Sopenharmony_ci config_line, gai_strerror (err)); 1098141cc406Sopenharmony_ci DBG (DBG_MSG, "check_host: entry isn't an IP address " 1099141cc406Sopenharmony_ci "and can't be found in DNS\n"); 1100141cc406Sopenharmony_ci continue; 1101141cc406Sopenharmony_ci } 1102141cc406Sopenharmony_ci else 1103141cc406Sopenharmony_ci { 1104141cc406Sopenharmony_ci for (resp = res; resp != NULL; resp = resp->ai_next) 1105141cc406Sopenharmony_ci { 1106141cc406Sopenharmony_ci err = getnameinfo (resp->ai_addr, resp->ai_addrlen, text_addr, 1107141cc406Sopenharmony_ci sizeof (text_addr), NULL, 0, NI_NUMERICHOST); 1108141cc406Sopenharmony_ci if (err) 1109141cc406Sopenharmony_ci strncpy (text_addr, "[error]", 8); 1110141cc406Sopenharmony_ci 1111141cc406Sopenharmony_ci DBG (DBG_MSG, 1112141cc406Sopenharmony_ci "check_host: DNS lookup returns IP address: %s\n", 1113141cc406Sopenharmony_ci text_addr); 1114141cc406Sopenharmony_ci 1115141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1116141cc406Sopenharmony_ci if ((strcasecmp (text_addr, remote_ip) == 0) || 1117141cc406Sopenharmony_ci ((IPv4map == SANE_TRUE) && (strcmp (text_addr, remote_ipv4) == 0))) 1118141cc406Sopenharmony_ci#else 1119141cc406Sopenharmony_ci if (strcmp (text_addr, remote_ip) == 0) 1120141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1121141cc406Sopenharmony_ci access_ok = 1; 1122141cc406Sopenharmony_ci 1123141cc406Sopenharmony_ci if (access_ok) 1124141cc406Sopenharmony_ci break; 1125141cc406Sopenharmony_ci } 1126141cc406Sopenharmony_ci freeaddrinfo (res); 1127141cc406Sopenharmony_ci res = NULL; 1128141cc406Sopenharmony_ci } 1129141cc406Sopenharmony_ci } 1130141cc406Sopenharmony_ci } 1131141cc406Sopenharmony_ci fclose (fp); 1132141cc406Sopenharmony_ci } 1133141cc406Sopenharmony_ci 1134141cc406Sopenharmony_ci if (access_ok) 1135141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1136141cc406Sopenharmony_ci 1137141cc406Sopenharmony_ci return SANE_STATUS_ACCESS_DENIED; 1138141cc406Sopenharmony_ci} 1139141cc406Sopenharmony_ci 1140141cc406Sopenharmony_ci#else /* !SANED_USES_AF_INDEP */ 1141141cc406Sopenharmony_ci 1142141cc406Sopenharmony_cistatic SANE_Status 1143141cc406Sopenharmony_cicheck_host (int fd) 1144141cc406Sopenharmony_ci{ 1145141cc406Sopenharmony_ci struct sockaddr_in sin; 1146141cc406Sopenharmony_ci int j, access_ok = 0; 1147141cc406Sopenharmony_ci struct hostent *he; 1148141cc406Sopenharmony_ci char text_addr[64]; 1149141cc406Sopenharmony_ci char config_line_buf[1024]; 1150141cc406Sopenharmony_ci char *config_line; 1151141cc406Sopenharmony_ci char *netmask; 1152141cc406Sopenharmony_ci char hostname[MAXHOSTNAMELEN]; 1153141cc406Sopenharmony_ci char *r_hostname; 1154141cc406Sopenharmony_ci static struct in_addr config_line_address; 1155141cc406Sopenharmony_ci 1156141cc406Sopenharmony_ci int len; 1157141cc406Sopenharmony_ci FILE *fp; 1158141cc406Sopenharmony_ci 1159141cc406Sopenharmony_ci /* Get address of remote host */ 1160141cc406Sopenharmony_ci len = sizeof (sin); 1161141cc406Sopenharmony_ci if (getpeername (fd, (struct sockaddr *) &sin, (socklen_t *) &len) < 0) 1162141cc406Sopenharmony_ci { 1163141cc406Sopenharmony_ci DBG (DBG_ERR, "check_host: getpeername failed: %s\n", strerror (errno)); 1164141cc406Sopenharmony_ci remote_ip = strdup ("[error]"); 1165141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1166141cc406Sopenharmony_ci } 1167141cc406Sopenharmony_ci r_hostname = inet_ntoa (sin.sin_addr); 1168141cc406Sopenharmony_ci remote_ip = strdup (r_hostname); 1169141cc406Sopenharmony_ci DBG (DBG_WARN, "check_host: access by remote host: %s\n", 1170141cc406Sopenharmony_ci remote_ip); 1171141cc406Sopenharmony_ci /* Save remote address for check of control and data connections */ 1172141cc406Sopenharmony_ci memcpy (&remote_address, &sin.sin_addr, sizeof (remote_address)); 1173141cc406Sopenharmony_ci 1174141cc406Sopenharmony_ci /* Always allow access from local host. Do it here to avoid DNS lookups 1175141cc406Sopenharmony_ci and reading saned.conf. */ 1176141cc406Sopenharmony_ci if (IN_LOOPBACK (ntohl (sin.sin_addr.s_addr))) 1177141cc406Sopenharmony_ci { 1178141cc406Sopenharmony_ci DBG (DBG_MSG, 1179141cc406Sopenharmony_ci "check_host: remote host is IN_LOOPBACK: access accepted\n"); 1180141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1181141cc406Sopenharmony_ci } 1182141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: remote host is not IN_LOOPBACK\n"); 1183141cc406Sopenharmony_ci 1184141cc406Sopenharmony_ci /* Get name of local host */ 1185141cc406Sopenharmony_ci if (gethostname (hostname, sizeof (hostname)) < 0) 1186141cc406Sopenharmony_ci { 1187141cc406Sopenharmony_ci DBG (DBG_ERR, "check_host: gethostname failed: %s\n", strerror (errno)); 1188141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1189141cc406Sopenharmony_ci } 1190141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: local hostname: %s\n", hostname); 1191141cc406Sopenharmony_ci 1192141cc406Sopenharmony_ci /* Get local address */ 1193141cc406Sopenharmony_ci he = gethostbyname (hostname); 1194141cc406Sopenharmony_ci 1195141cc406Sopenharmony_ci if (!he) 1196141cc406Sopenharmony_ci { 1197141cc406Sopenharmony_ci DBG (DBG_ERR, "check_host: gethostbyname for local hostname failed: %s\n", 1198141cc406Sopenharmony_ci hstrerror (h_errno)); 1199141cc406Sopenharmony_ci 1200141cc406Sopenharmony_ci /* Proceed even if the local hostname doesn't resolve */ 1201141cc406Sopenharmony_ci if (h_errno != HOST_NOT_FOUND) 1202141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1203141cc406Sopenharmony_ci } 1204141cc406Sopenharmony_ci else 1205141cc406Sopenharmony_ci { 1206141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: local hostname (from DNS): %s\n", 1207141cc406Sopenharmony_ci he->h_name); 1208141cc406Sopenharmony_ci 1209141cc406Sopenharmony_ci if ((he->h_length == 4) || (he->h_addrtype == AF_INET)) 1210141cc406Sopenharmony_ci { 1211141cc406Sopenharmony_ci if (!inet_ntop (he->h_addrtype, he->h_addr_list[0], text_addr, 1212141cc406Sopenharmony_ci sizeof (text_addr))) 1213141cc406Sopenharmony_ci strcpy (text_addr, "[error]"); 1214141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: local host address (from DNS): %s\n", 1215141cc406Sopenharmony_ci text_addr); 1216141cc406Sopenharmony_ci if (memcmp (he->h_addr_list[0], &remote_address.s_addr, 4) == 0) 1217141cc406Sopenharmony_ci { 1218141cc406Sopenharmony_ci DBG (DBG_MSG, 1219141cc406Sopenharmony_ci "check_host: remote host has same addr as local: " 1220141cc406Sopenharmony_ci "access accepted\n"); 1221141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1222141cc406Sopenharmony_ci } 1223141cc406Sopenharmony_ci } 1224141cc406Sopenharmony_ci else 1225141cc406Sopenharmony_ci { 1226141cc406Sopenharmony_ci DBG (DBG_ERR, "check_host: can't get local address " 1227141cc406Sopenharmony_ci "(only IPv4 is supported)\n"); 1228141cc406Sopenharmony_ci } 1229141cc406Sopenharmony_ci 1230141cc406Sopenharmony_ci DBG (DBG_DBG, 1231141cc406Sopenharmony_ci "check_host: remote host doesn't have same addr as local\n"); 1232141cc406Sopenharmony_ci } 1233141cc406Sopenharmony_ci 1234141cc406Sopenharmony_ci /* must be a remote host: check contents of PATH_NET_CONFIG or 1235141cc406Sopenharmony_ci /etc/hosts.equiv if former doesn't exist: */ 1236141cc406Sopenharmony_ci for (j = 0; j < NELEMS (config_file_names); ++j) 1237141cc406Sopenharmony_ci { 1238141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: opening config file: %s\n", 1239141cc406Sopenharmony_ci config_file_names[j]); 1240141cc406Sopenharmony_ci if (config_file_names[j][0] == '/') 1241141cc406Sopenharmony_ci fp = fopen (config_file_names[j], "r"); 1242141cc406Sopenharmony_ci else 1243141cc406Sopenharmony_ci fp = sanei_config_open (config_file_names[j]); 1244141cc406Sopenharmony_ci if (!fp) 1245141cc406Sopenharmony_ci { 1246141cc406Sopenharmony_ci DBG (DBG_MSG, 1247141cc406Sopenharmony_ci "check_host: can't open config file: %s (%s)\n", 1248141cc406Sopenharmony_ci config_file_names[j], strerror (errno)); 1249141cc406Sopenharmony_ci continue; 1250141cc406Sopenharmony_ci } 1251141cc406Sopenharmony_ci 1252141cc406Sopenharmony_ci while (!access_ok && sanei_config_read (config_line_buf, 1253141cc406Sopenharmony_ci sizeof (config_line_buf), fp)) 1254141cc406Sopenharmony_ci { 1255141cc406Sopenharmony_ci config_line = config_line_buf; /* from now on, use a pointer */ 1256141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: config file line: `%s'\n", config_line); 1257141cc406Sopenharmony_ci if (config_line[0] == '#') 1258141cc406Sopenharmony_ci continue; /* ignore comments */ 1259141cc406Sopenharmony_ci 1260141cc406Sopenharmony_ci if (strchr (config_line, '=')) 1261141cc406Sopenharmony_ci continue; /* ignore lines with an = sign */ 1262141cc406Sopenharmony_ci 1263141cc406Sopenharmony_ci len = strlen (config_line); 1264141cc406Sopenharmony_ci if (!len) 1265141cc406Sopenharmony_ci continue; /* ignore empty lines */ 1266141cc406Sopenharmony_ci 1267141cc406Sopenharmony_ci /* look for a subnet specification */ 1268141cc406Sopenharmony_ci netmask = strchr (config_line, '/'); 1269141cc406Sopenharmony_ci if (netmask != NULL) 1270141cc406Sopenharmony_ci { 1271141cc406Sopenharmony_ci *netmask = '\0'; 1272141cc406Sopenharmony_ci netmask++; 1273141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: subnet with base IP = %s, CIDR netmask = %s\n", 1274141cc406Sopenharmony_ci config_line, netmask); 1275141cc406Sopenharmony_ci } 1276141cc406Sopenharmony_ci 1277141cc406Sopenharmony_ci if (strcmp (config_line, "+") == 0) 1278141cc406Sopenharmony_ci { 1279141cc406Sopenharmony_ci access_ok = 1; 1280141cc406Sopenharmony_ci DBG (DBG_DBG, 1281141cc406Sopenharmony_ci "check_host: access accepted from any host (`+')\n"); 1282141cc406Sopenharmony_ci } 1283141cc406Sopenharmony_ci else 1284141cc406Sopenharmony_ci { 1285141cc406Sopenharmony_ci if (inet_pton (AF_INET, config_line, &config_line_address) > 0) 1286141cc406Sopenharmony_ci { 1287141cc406Sopenharmony_ci if (memcmp (&remote_address.s_addr, 1288141cc406Sopenharmony_ci &config_line_address.s_addr, 4) == 0) 1289141cc406Sopenharmony_ci access_ok = 1; 1290141cc406Sopenharmony_ci else if (netmask != NULL) 1291141cc406Sopenharmony_ci { 1292141cc406Sopenharmony_ci if (check_v4_in_range (&remote_address, &config_line_address, netmask)) 1293141cc406Sopenharmony_ci { 1294141cc406Sopenharmony_ci access_ok = 1; 1295141cc406Sopenharmony_ci DBG (DBG_DBG, "check_host: access granted from IP address %s (in subnet %s/%s)\n", 1296141cc406Sopenharmony_ci remote_ip, config_line, netmask); 1297141cc406Sopenharmony_ci } 1298141cc406Sopenharmony_ci } 1299141cc406Sopenharmony_ci } 1300141cc406Sopenharmony_ci else 1301141cc406Sopenharmony_ci { 1302141cc406Sopenharmony_ci DBG (DBG_DBG, 1303141cc406Sopenharmony_ci "check_host: inet_pton for `%s' failed\n", 1304141cc406Sopenharmony_ci config_line); 1305141cc406Sopenharmony_ci he = gethostbyname (config_line); 1306141cc406Sopenharmony_ci if (!he) 1307141cc406Sopenharmony_ci { 1308141cc406Sopenharmony_ci DBG (DBG_DBG, 1309141cc406Sopenharmony_ci "check_host: gethostbyname for `%s' failed: %s\n", 1310141cc406Sopenharmony_ci config_line, hstrerror (h_errno)); 1311141cc406Sopenharmony_ci DBG (DBG_MSG, "check_host: entry isn't an IP address " 1312141cc406Sopenharmony_ci "and can't be found in DNS\n"); 1313141cc406Sopenharmony_ci continue; 1314141cc406Sopenharmony_ci } 1315141cc406Sopenharmony_ci if (!inet_ntop (he->h_addrtype, he->h_addr_list[0], 1316141cc406Sopenharmony_ci text_addr, sizeof (text_addr))) 1317141cc406Sopenharmony_ci strcpy (text_addr, "[error]"); 1318141cc406Sopenharmony_ci DBG (DBG_MSG, 1319141cc406Sopenharmony_ci "check_host: DNS lookup returns IP address: %s\n", 1320141cc406Sopenharmony_ci text_addr); 1321141cc406Sopenharmony_ci if (memcmp (&remote_address.s_addr, 1322141cc406Sopenharmony_ci he->h_addr_list[0], 4) == 0) 1323141cc406Sopenharmony_ci access_ok = 1; 1324141cc406Sopenharmony_ci } 1325141cc406Sopenharmony_ci } 1326141cc406Sopenharmony_ci } 1327141cc406Sopenharmony_ci fclose (fp); 1328141cc406Sopenharmony_ci if (access_ok) 1329141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1330141cc406Sopenharmony_ci } 1331141cc406Sopenharmony_ci return SANE_STATUS_ACCESS_DENIED; 1332141cc406Sopenharmony_ci} 1333141cc406Sopenharmony_ci 1334141cc406Sopenharmony_ci#endif /* SANED_USES_AF_INDEP */ 1335141cc406Sopenharmony_ci 1336141cc406Sopenharmony_cistatic int 1337141cc406Sopenharmony_ciinit (Wire * w) 1338141cc406Sopenharmony_ci{ 1339141cc406Sopenharmony_ci SANE_Word word, be_version_code; 1340141cc406Sopenharmony_ci SANE_Init_Reply reply; 1341141cc406Sopenharmony_ci SANE_Status status; 1342141cc406Sopenharmony_ci SANE_Init_Req req; 1343141cc406Sopenharmony_ci 1344141cc406Sopenharmony_ci reset_watchdog (); 1345141cc406Sopenharmony_ci 1346141cc406Sopenharmony_ci status = check_host (w->io.fd); 1347141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1348141cc406Sopenharmony_ci { 1349141cc406Sopenharmony_ci DBG (DBG_WARN, "init: access by host %s denied\n", remote_ip); 1350141cc406Sopenharmony_ci return -1; 1351141cc406Sopenharmony_ci } 1352141cc406Sopenharmony_ci else 1353141cc406Sopenharmony_ci DBG (DBG_MSG, "init: access granted\n"); 1354141cc406Sopenharmony_ci 1355141cc406Sopenharmony_ci sanei_w_set_dir (w, WIRE_DECODE); 1356141cc406Sopenharmony_ci if (w->status) 1357141cc406Sopenharmony_ci { 1358141cc406Sopenharmony_ci DBG (DBG_ERR, "init: bad status after sanei_w_set_dir: %d\n", w->status); 1359141cc406Sopenharmony_ci return -1; 1360141cc406Sopenharmony_ci } 1361141cc406Sopenharmony_ci 1362141cc406Sopenharmony_ci sanei_w_word (w, &word); /* decode procedure number */ 1363141cc406Sopenharmony_ci if (w->status || word != SANE_NET_INIT) 1364141cc406Sopenharmony_ci { 1365141cc406Sopenharmony_ci DBG (DBG_ERR, "init: bad status=%d or procnum=%d\n", 1366141cc406Sopenharmony_ci w->status, word); 1367141cc406Sopenharmony_ci return -1; 1368141cc406Sopenharmony_ci } 1369141cc406Sopenharmony_ci 1370141cc406Sopenharmony_ci sanei_w_init_req (w, &req); 1371141cc406Sopenharmony_ci if (w->status) 1372141cc406Sopenharmony_ci { 1373141cc406Sopenharmony_ci DBG (DBG_ERR, "init: bad status after sanei_w_init_req: %d\n", w->status); 1374141cc406Sopenharmony_ci return -1; 1375141cc406Sopenharmony_ci } 1376141cc406Sopenharmony_ci 1377141cc406Sopenharmony_ci w->version = SANEI_NET_PROTOCOL_VERSION; 1378141cc406Sopenharmony_ci if (req.username) 1379141cc406Sopenharmony_ci default_username = strdup (req.username); 1380141cc406Sopenharmony_ci 1381141cc406Sopenharmony_ci sanei_w_free (w, (WireCodecFunc) sanei_w_init_req, &req); 1382141cc406Sopenharmony_ci if (w->status) 1383141cc406Sopenharmony_ci { 1384141cc406Sopenharmony_ci DBG (DBG_ERR, "init: bad status after sanei_w_free: %d\n", w->status); 1385141cc406Sopenharmony_ci return -1; 1386141cc406Sopenharmony_ci } 1387141cc406Sopenharmony_ci 1388141cc406Sopenharmony_ci reply.version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, 1389141cc406Sopenharmony_ci SANEI_NET_PROTOCOL_VERSION); 1390141cc406Sopenharmony_ci 1391141cc406Sopenharmony_ci DBG (DBG_WARN, "init: access granted to %s@%s\n", 1392141cc406Sopenharmony_ci default_username, remote_ip); 1393141cc406Sopenharmony_ci 1394141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) 1395141cc406Sopenharmony_ci { 1396141cc406Sopenharmony_ci status = sane_init (&be_version_code, auth_callback); 1397141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1398141cc406Sopenharmony_ci DBG (DBG_ERR, "init: failed to initialize backend (%s)\n", 1399141cc406Sopenharmony_ci sane_strstatus (status)); 1400141cc406Sopenharmony_ci 1401141cc406Sopenharmony_ci if (SANE_VERSION_MAJOR (be_version_code) != V_MAJOR) 1402141cc406Sopenharmony_ci { 1403141cc406Sopenharmony_ci DBG (DBG_ERR, 1404141cc406Sopenharmony_ci "init: unexpected backend major version %d (expected %d)\n", 1405141cc406Sopenharmony_ci SANE_VERSION_MAJOR (be_version_code), V_MAJOR); 1406141cc406Sopenharmony_ci status = SANE_STATUS_INVAL; 1407141cc406Sopenharmony_ci } 1408141cc406Sopenharmony_ci } 1409141cc406Sopenharmony_ci reply.status = status; 1410141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1411141cc406Sopenharmony_ci reply.version_code = 0; 1412141cc406Sopenharmony_ci sanei_w_reply (w, (WireCodecFunc) sanei_w_init_reply, &reply); 1413141cc406Sopenharmony_ci 1414141cc406Sopenharmony_ci if (w->status || status != SANE_STATUS_GOOD) 1415141cc406Sopenharmony_ci return -1; 1416141cc406Sopenharmony_ci 1417141cc406Sopenharmony_ci return 0; 1418141cc406Sopenharmony_ci} 1419141cc406Sopenharmony_ci 1420141cc406Sopenharmony_ci#ifdef SANED_USES_AF_INDEP 1421141cc406Sopenharmony_cistatic int 1422141cc406Sopenharmony_cistart_scan (Wire * w, int h, SANE_Start_Reply * reply) 1423141cc406Sopenharmony_ci{ 1424141cc406Sopenharmony_ci union { 1425141cc406Sopenharmony_ci struct sockaddr_storage ss; 1426141cc406Sopenharmony_ci struct sockaddr sa; 1427141cc406Sopenharmony_ci struct sockaddr_in sin; 1428141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1429141cc406Sopenharmony_ci struct sockaddr_in6 sin6; 1430141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1431141cc406Sopenharmony_ci } data_addr; 1432141cc406Sopenharmony_ci struct sockaddr_in *sin; 1433141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1434141cc406Sopenharmony_ci struct sockaddr_in6 *sin6; 1435141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1436141cc406Sopenharmony_ci SANE_Handle be_handle; 1437141cc406Sopenharmony_ci int fd, len; 1438141cc406Sopenharmony_ci in_port_t data_port; 1439141cc406Sopenharmony_ci int ret = -1; 1440141cc406Sopenharmony_ci 1441141cc406Sopenharmony_ci be_handle = handle[h].handle; 1442141cc406Sopenharmony_ci 1443141cc406Sopenharmony_ci len = sizeof (data_addr.ss); 1444141cc406Sopenharmony_ci if (getsockname (w->io.fd, &data_addr.sa, (socklen_t *) &len) < 0) 1445141cc406Sopenharmony_ci { 1446141cc406Sopenharmony_ci DBG (DBG_ERR, "start_scan: failed to obtain socket address (%s)\n", 1447141cc406Sopenharmony_ci strerror (errno)); 1448141cc406Sopenharmony_ci reply->status = SANE_STATUS_IO_ERROR; 1449141cc406Sopenharmony_ci return -1; 1450141cc406Sopenharmony_ci } 1451141cc406Sopenharmony_ci 1452141cc406Sopenharmony_ci fd = socket (SS_FAMILY(data_addr.ss), SOCK_STREAM, 0); 1453141cc406Sopenharmony_ci if (fd < 0) 1454141cc406Sopenharmony_ci { 1455141cc406Sopenharmony_ci DBG (DBG_ERR, "start_scan: failed to obtain data socket (%s)\n", 1456141cc406Sopenharmony_ci strerror (errno)); 1457141cc406Sopenharmony_ci reply->status = SANE_STATUS_IO_ERROR; 1458141cc406Sopenharmony_ci return -1; 1459141cc406Sopenharmony_ci } 1460141cc406Sopenharmony_ci 1461141cc406Sopenharmony_ci switch (SS_FAMILY(data_addr.ss)) 1462141cc406Sopenharmony_ci { 1463141cc406Sopenharmony_ci case AF_INET: 1464141cc406Sopenharmony_ci sin = &data_addr.sin; 1465141cc406Sopenharmony_ci break; 1466141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1467141cc406Sopenharmony_ci case AF_INET6: 1468141cc406Sopenharmony_ci sin6 = &data_addr.sin6; 1469141cc406Sopenharmony_ci break; 1470141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1471141cc406Sopenharmony_ci default: 1472141cc406Sopenharmony_ci break; 1473141cc406Sopenharmony_ci } 1474141cc406Sopenharmony_ci 1475141cc406Sopenharmony_ci /* Try to bind a port between data_port_lo and data_port_hi for the data connection */ 1476141cc406Sopenharmony_ci for (data_port = data_port_lo; data_port <= data_port_hi; data_port++) 1477141cc406Sopenharmony_ci { 1478141cc406Sopenharmony_ci switch (SS_FAMILY(data_addr.ss)) 1479141cc406Sopenharmony_ci { 1480141cc406Sopenharmony_ci case AF_INET: 1481141cc406Sopenharmony_ci sin->sin_port = htons(data_port); 1482141cc406Sopenharmony_ci break; 1483141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1484141cc406Sopenharmony_ci case AF_INET6: 1485141cc406Sopenharmony_ci sin6->sin6_port = htons(data_port); 1486141cc406Sopenharmony_ci break; 1487141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1488141cc406Sopenharmony_ci default: 1489141cc406Sopenharmony_ci break; 1490141cc406Sopenharmony_ci } 1491141cc406Sopenharmony_ci 1492141cc406Sopenharmony_ci DBG (DBG_INFO, "start_scan: trying to bind data port %d\n", data_port); 1493141cc406Sopenharmony_ci 1494141cc406Sopenharmony_ci ret = bind (fd, &data_addr.sa, len); 1495141cc406Sopenharmony_ci if (ret == 0) 1496141cc406Sopenharmony_ci break; 1497141cc406Sopenharmony_ci } 1498141cc406Sopenharmony_ci 1499141cc406Sopenharmony_ci if (ret < 0) 1500141cc406Sopenharmony_ci { 1501141cc406Sopenharmony_ci DBG (DBG_ERR, "start_scan: failed to bind address (%s)\n", 1502141cc406Sopenharmony_ci strerror (errno)); 1503141cc406Sopenharmony_ci reply->status = SANE_STATUS_IO_ERROR; 1504141cc406Sopenharmony_ci return -1; 1505141cc406Sopenharmony_ci } 1506141cc406Sopenharmony_ci 1507141cc406Sopenharmony_ci if (listen (fd, 1) < 0) 1508141cc406Sopenharmony_ci { 1509141cc406Sopenharmony_ci DBG (DBG_ERR, "start_scan: failed to make socket listen (%s)\n", 1510141cc406Sopenharmony_ci strerror (errno)); 1511141cc406Sopenharmony_ci reply->status = SANE_STATUS_IO_ERROR; 1512141cc406Sopenharmony_ci return -1; 1513141cc406Sopenharmony_ci } 1514141cc406Sopenharmony_ci 1515141cc406Sopenharmony_ci if (getsockname (fd, &data_addr.sa, (socklen_t *) &len) < 0) 1516141cc406Sopenharmony_ci { 1517141cc406Sopenharmony_ci DBG (DBG_ERR, "start_scan: failed to obtain socket address (%s)\n", 1518141cc406Sopenharmony_ci strerror (errno)); 1519141cc406Sopenharmony_ci reply->status = SANE_STATUS_IO_ERROR; 1520141cc406Sopenharmony_ci return -1; 1521141cc406Sopenharmony_ci } 1522141cc406Sopenharmony_ci 1523141cc406Sopenharmony_ci switch (SS_FAMILY(data_addr.ss)) 1524141cc406Sopenharmony_ci { 1525141cc406Sopenharmony_ci case AF_INET: 1526141cc406Sopenharmony_ci sin = &data_addr.sin; 1527141cc406Sopenharmony_ci reply->port = ntohs (sin->sin_port); 1528141cc406Sopenharmony_ci break; 1529141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 1530141cc406Sopenharmony_ci case AF_INET6: 1531141cc406Sopenharmony_ci sin6 = &data_addr.sin6; 1532141cc406Sopenharmony_ci reply->port = ntohs (sin6->sin6_port); 1533141cc406Sopenharmony_ci break; 1534141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 1535141cc406Sopenharmony_ci default: 1536141cc406Sopenharmony_ci break; 1537141cc406Sopenharmony_ci } 1538141cc406Sopenharmony_ci 1539141cc406Sopenharmony_ci DBG (DBG_MSG, "start_scan: using port %d for data\n", reply->port); 1540141cc406Sopenharmony_ci 1541141cc406Sopenharmony_ci reply->status = sane_start (be_handle); 1542141cc406Sopenharmony_ci if (reply->status == SANE_STATUS_GOOD) 1543141cc406Sopenharmony_ci { 1544141cc406Sopenharmony_ci handle[h].scanning = 1; 1545141cc406Sopenharmony_ci handle[h].docancel = 0; 1546141cc406Sopenharmony_ci } 1547141cc406Sopenharmony_ci 1548141cc406Sopenharmony_ci return fd; 1549141cc406Sopenharmony_ci} 1550141cc406Sopenharmony_ci 1551141cc406Sopenharmony_ci#else /* !SANED_USES_AF_INDEP */ 1552141cc406Sopenharmony_ci 1553141cc406Sopenharmony_cistatic int 1554141cc406Sopenharmony_cistart_scan (Wire * w, int h, SANE_Start_Reply * reply) 1555141cc406Sopenharmony_ci{ 1556141cc406Sopenharmony_ci struct sockaddr_in sin; 1557141cc406Sopenharmony_ci SANE_Handle be_handle; 1558141cc406Sopenharmony_ci int fd, len; 1559141cc406Sopenharmony_ci in_port_t data_port; 1560141cc406Sopenharmony_ci int ret; 1561141cc406Sopenharmony_ci 1562141cc406Sopenharmony_ci be_handle = handle[h].handle; 1563141cc406Sopenharmony_ci 1564141cc406Sopenharmony_ci len = sizeof (sin); 1565141cc406Sopenharmony_ci if (getsockname (w->io.fd, (struct sockaddr *) &sin, (socklen_t *) &len) < 0) 1566141cc406Sopenharmony_ci { 1567141cc406Sopenharmony_ci DBG (DBG_ERR, "start_scan: failed to obtain socket address (%s)\n", 1568141cc406Sopenharmony_ci strerror (errno)); 1569141cc406Sopenharmony_ci reply->status = SANE_STATUS_IO_ERROR; 1570141cc406Sopenharmony_ci return -1; 1571141cc406Sopenharmony_ci } 1572141cc406Sopenharmony_ci 1573141cc406Sopenharmony_ci fd = socket (AF_INET, SOCK_STREAM, 0); 1574141cc406Sopenharmony_ci if (fd < 0) 1575141cc406Sopenharmony_ci { 1576141cc406Sopenharmony_ci DBG (DBG_ERR, "start_scan: failed to obtain data socket (%s)\n", 1577141cc406Sopenharmony_ci strerror (errno)); 1578141cc406Sopenharmony_ci reply->status = SANE_STATUS_IO_ERROR; 1579141cc406Sopenharmony_ci return -1; 1580141cc406Sopenharmony_ci } 1581141cc406Sopenharmony_ci 1582141cc406Sopenharmony_ci /* Try to bind a port between data_port_lo and data_port_hi for the data connection */ 1583141cc406Sopenharmony_ci for (data_port = data_port_lo; data_port <= data_port_hi; data_port++) 1584141cc406Sopenharmony_ci { 1585141cc406Sopenharmony_ci sin.sin_port = htons(data_port); 1586141cc406Sopenharmony_ci 1587141cc406Sopenharmony_ci DBG(DBG_INFO, "start_scan: trying to bind data port %d\n", data_port); 1588141cc406Sopenharmony_ci 1589141cc406Sopenharmony_ci ret = bind (fd, (struct sockaddr *) &sin, len); 1590141cc406Sopenharmony_ci if (ret == 0) 1591141cc406Sopenharmony_ci break; 1592141cc406Sopenharmony_ci } 1593141cc406Sopenharmony_ci 1594141cc406Sopenharmony_ci if (ret < 0) 1595141cc406Sopenharmony_ci { 1596141cc406Sopenharmony_ci DBG (DBG_ERR, "start_scan: failed to bind address (%s)\n", 1597141cc406Sopenharmony_ci strerror (errno)); 1598141cc406Sopenharmony_ci reply->status = SANE_STATUS_IO_ERROR; 1599141cc406Sopenharmony_ci return -1; 1600141cc406Sopenharmony_ci } 1601141cc406Sopenharmony_ci 1602141cc406Sopenharmony_ci if (listen (fd, 1) < 0) 1603141cc406Sopenharmony_ci { 1604141cc406Sopenharmony_ci DBG (DBG_ERR, "start_scan: failed to make socket listen (%s)\n", 1605141cc406Sopenharmony_ci strerror (errno)); 1606141cc406Sopenharmony_ci reply->status = SANE_STATUS_IO_ERROR; 1607141cc406Sopenharmony_ci return -1; 1608141cc406Sopenharmony_ci } 1609141cc406Sopenharmony_ci 1610141cc406Sopenharmony_ci if (getsockname (fd, (struct sockaddr *) &sin, (socklen_t *) &len) < 0) 1611141cc406Sopenharmony_ci { 1612141cc406Sopenharmony_ci DBG (DBG_ERR, "start_scan: failed to obtain socket address (%s)\n", 1613141cc406Sopenharmony_ci strerror (errno)); 1614141cc406Sopenharmony_ci reply->status = SANE_STATUS_IO_ERROR; 1615141cc406Sopenharmony_ci return -1; 1616141cc406Sopenharmony_ci } 1617141cc406Sopenharmony_ci 1618141cc406Sopenharmony_ci reply->port = ntohs (sin.sin_port); 1619141cc406Sopenharmony_ci 1620141cc406Sopenharmony_ci DBG (DBG_MSG, "start_scan: using port %d for data\n", reply->port); 1621141cc406Sopenharmony_ci 1622141cc406Sopenharmony_ci reply->status = sane_start (be_handle); 1623141cc406Sopenharmony_ci if (reply->status == SANE_STATUS_GOOD) 1624141cc406Sopenharmony_ci { 1625141cc406Sopenharmony_ci handle[h].scanning = 1; 1626141cc406Sopenharmony_ci handle[h].docancel = 0; 1627141cc406Sopenharmony_ci } 1628141cc406Sopenharmony_ci 1629141cc406Sopenharmony_ci return fd; 1630141cc406Sopenharmony_ci} 1631141cc406Sopenharmony_ci#endif /* SANED_USES_AF_INDEP */ 1632141cc406Sopenharmony_ci 1633141cc406Sopenharmony_cistatic int 1634141cc406Sopenharmony_cistore_reclen (SANE_Byte * buf, size_t buf_size, int i, size_t reclen) 1635141cc406Sopenharmony_ci{ 1636141cc406Sopenharmony_ci buf[i++] = (reclen >> 24) & 0xff; 1637141cc406Sopenharmony_ci if (i >= (int) buf_size) 1638141cc406Sopenharmony_ci i = 0; 1639141cc406Sopenharmony_ci buf[i++] = (reclen >> 16) & 0xff; 1640141cc406Sopenharmony_ci if (i >= (int) buf_size) 1641141cc406Sopenharmony_ci i = 0; 1642141cc406Sopenharmony_ci buf[i++] = (reclen >> 8) & 0xff; 1643141cc406Sopenharmony_ci if (i >= (int) buf_size) 1644141cc406Sopenharmony_ci i = 0; 1645141cc406Sopenharmony_ci buf[i++] = (reclen >> 0) & 0xff; 1646141cc406Sopenharmony_ci if (i >= (int) buf_size) 1647141cc406Sopenharmony_ci i = 0; 1648141cc406Sopenharmony_ci return i; 1649141cc406Sopenharmony_ci} 1650141cc406Sopenharmony_ci 1651141cc406Sopenharmony_cistatic void 1652141cc406Sopenharmony_cido_scan (Wire * w, int h, int data_fd) 1653141cc406Sopenharmony_ci{ 1654141cc406Sopenharmony_ci int num_fds, be_fd = -1, reader, writer, bytes_in_buf, status_dirty = 0; 1655141cc406Sopenharmony_ci SANE_Handle be_handle = handle[h].handle; 1656141cc406Sopenharmony_ci struct timeval tv, *timeout = 0; 1657141cc406Sopenharmony_ci fd_set rd_set, rd_mask, wr_set, wr_mask; 1658141cc406Sopenharmony_ci SANE_Byte buf[8192]; 1659141cc406Sopenharmony_ci SANE_Status status; 1660141cc406Sopenharmony_ci long int nwritten; 1661141cc406Sopenharmony_ci SANE_Int length; 1662141cc406Sopenharmony_ci size_t nbytes; 1663141cc406Sopenharmony_ci 1664141cc406Sopenharmony_ci DBG (3, "do_scan: start\n"); 1665141cc406Sopenharmony_ci 1666141cc406Sopenharmony_ci FD_ZERO (&rd_mask); 1667141cc406Sopenharmony_ci FD_SET (w->io.fd, &rd_mask); 1668141cc406Sopenharmony_ci num_fds = w->io.fd + 1; 1669141cc406Sopenharmony_ci 1670141cc406Sopenharmony_ci FD_ZERO (&wr_mask); 1671141cc406Sopenharmony_ci FD_SET (data_fd, &wr_mask); 1672141cc406Sopenharmony_ci if (data_fd >= num_fds) 1673141cc406Sopenharmony_ci num_fds = data_fd + 1; 1674141cc406Sopenharmony_ci 1675141cc406Sopenharmony_ci sane_set_io_mode (be_handle, SANE_TRUE); 1676141cc406Sopenharmony_ci if (sane_get_select_fd (be_handle, &be_fd) == SANE_STATUS_GOOD) 1677141cc406Sopenharmony_ci { 1678141cc406Sopenharmony_ci FD_SET (be_fd, &rd_mask); 1679141cc406Sopenharmony_ci if (be_fd >= num_fds) 1680141cc406Sopenharmony_ci num_fds = be_fd + 1; 1681141cc406Sopenharmony_ci } 1682141cc406Sopenharmony_ci else 1683141cc406Sopenharmony_ci { 1684141cc406Sopenharmony_ci memset (&tv, 0, sizeof (tv)); 1685141cc406Sopenharmony_ci timeout = &tv; 1686141cc406Sopenharmony_ci } 1687141cc406Sopenharmony_ci 1688141cc406Sopenharmony_ci status = SANE_STATUS_GOOD; 1689141cc406Sopenharmony_ci reader = writer = bytes_in_buf = 0; 1690141cc406Sopenharmony_ci do 1691141cc406Sopenharmony_ci { 1692141cc406Sopenharmony_ci rd_set = rd_mask; 1693141cc406Sopenharmony_ci wr_set = wr_mask; 1694141cc406Sopenharmony_ci if (select (num_fds, &rd_set, &wr_set, 0, timeout) < 0) 1695141cc406Sopenharmony_ci { 1696141cc406Sopenharmony_ci if (be_fd >= 0 && errno == EBADF) 1697141cc406Sopenharmony_ci { 1698141cc406Sopenharmony_ci /* This normally happens when a backend closes a select 1699141cc406Sopenharmony_ci filedescriptor when reaching the end of file. So 1700141cc406Sopenharmony_ci pass back this status to the client: */ 1701141cc406Sopenharmony_ci FD_CLR (be_fd, &rd_mask); 1702141cc406Sopenharmony_ci be_fd = -1; 1703141cc406Sopenharmony_ci /* only set status_dirty if EOF hasn't been already detected */ 1704141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) 1705141cc406Sopenharmony_ci status_dirty = 1; 1706141cc406Sopenharmony_ci status = SANE_STATUS_EOF; 1707141cc406Sopenharmony_ci DBG (DBG_INFO, "do_scan: select_fd was closed --> EOF\n"); 1708141cc406Sopenharmony_ci continue; 1709141cc406Sopenharmony_ci } 1710141cc406Sopenharmony_ci else 1711141cc406Sopenharmony_ci { 1712141cc406Sopenharmony_ci status = SANE_STATUS_IO_ERROR; 1713141cc406Sopenharmony_ci DBG (DBG_ERR, "do_scan: select failed (%s)\n", strerror (errno)); 1714141cc406Sopenharmony_ci break; 1715141cc406Sopenharmony_ci } 1716141cc406Sopenharmony_ci } 1717141cc406Sopenharmony_ci 1718141cc406Sopenharmony_ci if (bytes_in_buf) 1719141cc406Sopenharmony_ci { 1720141cc406Sopenharmony_ci if (FD_ISSET (data_fd, &wr_set)) 1721141cc406Sopenharmony_ci { 1722141cc406Sopenharmony_ci if (bytes_in_buf > 0) 1723141cc406Sopenharmony_ci { 1724141cc406Sopenharmony_ci /* write more input data */ 1725141cc406Sopenharmony_ci nbytes = bytes_in_buf; 1726141cc406Sopenharmony_ci if (writer + nbytes > sizeof (buf)) 1727141cc406Sopenharmony_ci nbytes = sizeof (buf) - writer; 1728141cc406Sopenharmony_ci DBG (DBG_INFO, 1729141cc406Sopenharmony_ci "do_scan: trying to write %d bytes to client\n", 1730141cc406Sopenharmony_ci nbytes); 1731141cc406Sopenharmony_ci nwritten = write (data_fd, buf + writer, nbytes); 1732141cc406Sopenharmony_ci DBG (DBG_INFO, 1733141cc406Sopenharmony_ci "do_scan: wrote %ld bytes to client\n", nwritten); 1734141cc406Sopenharmony_ci if (nwritten < 0) 1735141cc406Sopenharmony_ci { 1736141cc406Sopenharmony_ci DBG (DBG_ERR, "do_scan: write failed (%s)\n", 1737141cc406Sopenharmony_ci strerror (errno)); 1738141cc406Sopenharmony_ci status = SANE_STATUS_CANCELLED; 1739141cc406Sopenharmony_ci handle[h].docancel = 1; 1740141cc406Sopenharmony_ci break; 1741141cc406Sopenharmony_ci } 1742141cc406Sopenharmony_ci bytes_in_buf -= nwritten; 1743141cc406Sopenharmony_ci writer += nwritten; 1744141cc406Sopenharmony_ci if (writer == sizeof (buf)) 1745141cc406Sopenharmony_ci writer = 0; 1746141cc406Sopenharmony_ci } 1747141cc406Sopenharmony_ci } 1748141cc406Sopenharmony_ci } 1749141cc406Sopenharmony_ci else if (status == SANE_STATUS_GOOD 1750141cc406Sopenharmony_ci && (timeout || FD_ISSET (be_fd, &rd_set))) 1751141cc406Sopenharmony_ci { 1752141cc406Sopenharmony_ci int i; 1753141cc406Sopenharmony_ci 1754141cc406Sopenharmony_ci /* get more input data */ 1755141cc406Sopenharmony_ci 1756141cc406Sopenharmony_ci /* reserve 4 bytes to store the length of the data record: */ 1757141cc406Sopenharmony_ci i = reader; 1758141cc406Sopenharmony_ci reader += 4; 1759141cc406Sopenharmony_ci if (reader >= (int) sizeof (buf)) 1760141cc406Sopenharmony_ci reader -= sizeof(buf); 1761141cc406Sopenharmony_ci 1762141cc406Sopenharmony_ci assert (bytes_in_buf == 0); 1763141cc406Sopenharmony_ci nbytes = sizeof (buf) - 4; 1764141cc406Sopenharmony_ci if (reader + nbytes > sizeof (buf)) 1765141cc406Sopenharmony_ci nbytes = sizeof (buf) - reader; 1766141cc406Sopenharmony_ci 1767141cc406Sopenharmony_ci DBG (DBG_INFO, 1768141cc406Sopenharmony_ci "do_scan: trying to read %d bytes from scanner\n", nbytes); 1769141cc406Sopenharmony_ci status = sane_read (be_handle, buf + reader, nbytes, &length); 1770141cc406Sopenharmony_ci DBG (DBG_INFO, 1771141cc406Sopenharmony_ci "do_scan: read %d bytes from scanner\n", length); 1772141cc406Sopenharmony_ci 1773141cc406Sopenharmony_ci reset_watchdog (); 1774141cc406Sopenharmony_ci 1775141cc406Sopenharmony_ci reader += length; 1776141cc406Sopenharmony_ci if (reader >= (int) sizeof (buf)) 1777141cc406Sopenharmony_ci reader = 0; 1778141cc406Sopenharmony_ci bytes_in_buf += length + 4; 1779141cc406Sopenharmony_ci 1780141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1781141cc406Sopenharmony_ci { 1782141cc406Sopenharmony_ci reader = i; /* restore reader index */ 1783141cc406Sopenharmony_ci status_dirty = 1; 1784141cc406Sopenharmony_ci DBG (DBG_MSG, 1785141cc406Sopenharmony_ci "do_scan: status = `%s'\n", sane_strstatus(status)); 1786141cc406Sopenharmony_ci } 1787141cc406Sopenharmony_ci else 1788141cc406Sopenharmony_ci store_reclen (buf, sizeof (buf), i, length); 1789141cc406Sopenharmony_ci } 1790141cc406Sopenharmony_ci 1791141cc406Sopenharmony_ci if (status_dirty && sizeof (buf) - bytes_in_buf >= 5) 1792141cc406Sopenharmony_ci { 1793141cc406Sopenharmony_ci status_dirty = 0; 1794141cc406Sopenharmony_ci reader = store_reclen (buf, sizeof (buf), reader, 0xffffffff); 1795141cc406Sopenharmony_ci buf[reader] = status; 1796141cc406Sopenharmony_ci bytes_in_buf += 5; 1797141cc406Sopenharmony_ci DBG (DBG_MSG, "do_scan: statuscode `%s' was added to buffer\n", 1798141cc406Sopenharmony_ci sane_strstatus(status)); 1799141cc406Sopenharmony_ci } 1800141cc406Sopenharmony_ci 1801141cc406Sopenharmony_ci if (FD_ISSET (w->io.fd, &rd_set)) 1802141cc406Sopenharmony_ci { 1803141cc406Sopenharmony_ci DBG (DBG_MSG, 1804141cc406Sopenharmony_ci "do_scan: processing RPC request on fd %d\n", w->io.fd); 1805141cc406Sopenharmony_ci if(process_request (w) < 0) 1806141cc406Sopenharmony_ci handle[h].docancel = 1; 1807141cc406Sopenharmony_ci 1808141cc406Sopenharmony_ci if (handle[h].docancel) 1809141cc406Sopenharmony_ci break; 1810141cc406Sopenharmony_ci } 1811141cc406Sopenharmony_ci } 1812141cc406Sopenharmony_ci while (status == SANE_STATUS_GOOD || bytes_in_buf > 0 || status_dirty); 1813141cc406Sopenharmony_ci DBG (DBG_MSG, "do_scan: done, status=%s\n", sane_strstatus (status)); 1814141cc406Sopenharmony_ci 1815141cc406Sopenharmony_ci if(handle[h].docancel) 1816141cc406Sopenharmony_ci sane_cancel (handle[h].handle); 1817141cc406Sopenharmony_ci 1818141cc406Sopenharmony_ci handle[h].docancel = 0; 1819141cc406Sopenharmony_ci handle[h].scanning = 0; 1820141cc406Sopenharmony_ci} 1821141cc406Sopenharmony_ci 1822141cc406Sopenharmony_cistatic int 1823141cc406Sopenharmony_ciprocess_request (Wire * w) 1824141cc406Sopenharmony_ci{ 1825141cc406Sopenharmony_ci SANE_Handle be_handle; 1826141cc406Sopenharmony_ci SANE_Word h, word; 1827141cc406Sopenharmony_ci int i; 1828141cc406Sopenharmony_ci 1829141cc406Sopenharmony_ci DBG (DBG_DBG, "process_request: waiting for request\n"); 1830141cc406Sopenharmony_ci sanei_w_set_dir (w, WIRE_DECODE); 1831141cc406Sopenharmony_ci sanei_w_word (w, &word); /* decode procedure number */ 1832141cc406Sopenharmony_ci 1833141cc406Sopenharmony_ci if (w->status) 1834141cc406Sopenharmony_ci { 1835141cc406Sopenharmony_ci DBG (DBG_ERR, 1836141cc406Sopenharmony_ci "process_request: bad status %d\n", w->status); 1837141cc406Sopenharmony_ci return -1; 1838141cc406Sopenharmony_ci } 1839141cc406Sopenharmony_ci 1840141cc406Sopenharmony_ci current_request = word; 1841141cc406Sopenharmony_ci 1842141cc406Sopenharmony_ci DBG (DBG_MSG, "process_request: got request %d\n", current_request); 1843141cc406Sopenharmony_ci 1844141cc406Sopenharmony_ci switch (current_request) 1845141cc406Sopenharmony_ci { 1846141cc406Sopenharmony_ci case SANE_NET_GET_DEVICES: 1847141cc406Sopenharmony_ci { 1848141cc406Sopenharmony_ci SANE_Get_Devices_Reply reply; 1849141cc406Sopenharmony_ci 1850141cc406Sopenharmony_ci reply.status = 1851141cc406Sopenharmony_ci sane_get_devices ((const SANE_Device ***) &reply.device_list, 1852141cc406Sopenharmony_ci SANE_TRUE); 1853141cc406Sopenharmony_ci sanei_w_reply (w, (WireCodecFunc) sanei_w_get_devices_reply, &reply); 1854141cc406Sopenharmony_ci } 1855141cc406Sopenharmony_ci break; 1856141cc406Sopenharmony_ci 1857141cc406Sopenharmony_ci case SANE_NET_OPEN: 1858141cc406Sopenharmony_ci { 1859141cc406Sopenharmony_ci SANE_Open_Reply reply; 1860141cc406Sopenharmony_ci SANE_Handle be_handle; 1861141cc406Sopenharmony_ci SANE_String name, resource; 1862141cc406Sopenharmony_ci 1863141cc406Sopenharmony_ci sanei_w_string (w, &name); 1864141cc406Sopenharmony_ci if (w->status) 1865141cc406Sopenharmony_ci { 1866141cc406Sopenharmony_ci DBG (DBG_ERR, 1867141cc406Sopenharmony_ci "process_request: (open) error while decoding args (%s)\n", 1868141cc406Sopenharmony_ci strerror (w->status)); 1869141cc406Sopenharmony_ci return 1; 1870141cc406Sopenharmony_ci } 1871141cc406Sopenharmony_ci 1872141cc406Sopenharmony_ci if (!name) 1873141cc406Sopenharmony_ci { 1874141cc406Sopenharmony_ci DBG (DBG_ERR, "process_request: (open) device_name == NULL\n"); 1875141cc406Sopenharmony_ci reply.status = SANE_STATUS_INVAL; 1876141cc406Sopenharmony_ci sanei_w_reply (w, (WireCodecFunc) sanei_w_open_reply, &reply); 1877141cc406Sopenharmony_ci return 1; 1878141cc406Sopenharmony_ci } 1879141cc406Sopenharmony_ci 1880141cc406Sopenharmony_ci can_authorize = 1; 1881141cc406Sopenharmony_ci 1882141cc406Sopenharmony_ci resource = strdup (name); 1883141cc406Sopenharmony_ci 1884141cc406Sopenharmony_ci if (strlen(resource) == 0) { 1885141cc406Sopenharmony_ci 1886141cc406Sopenharmony_ci const SANE_Device **device_list; 1887141cc406Sopenharmony_ci 1888141cc406Sopenharmony_ci DBG(DBG_DBG, "process_request: (open) strlen(resource) == 0\n"); 1889141cc406Sopenharmony_ci free (resource); 1890141cc406Sopenharmony_ci 1891141cc406Sopenharmony_ci if ((i = sane_get_devices (&device_list, SANE_TRUE)) != 1892141cc406Sopenharmony_ci SANE_STATUS_GOOD) 1893141cc406Sopenharmony_ci { 1894141cc406Sopenharmony_ci DBG(DBG_ERR, "process_request: (open) sane_get_devices failed\n"); 1895141cc406Sopenharmony_ci memset (&reply, 0, sizeof (reply)); 1896141cc406Sopenharmony_ci reply.status = i; 1897141cc406Sopenharmony_ci sanei_w_reply (w, (WireCodecFunc) sanei_w_open_reply, &reply); 1898141cc406Sopenharmony_ci break; 1899141cc406Sopenharmony_ci } 1900141cc406Sopenharmony_ci 1901141cc406Sopenharmony_ci if ((device_list == NULL) || (device_list[0] == NULL)) 1902141cc406Sopenharmony_ci { 1903141cc406Sopenharmony_ci DBG(DBG_ERR, "process_request: (open) device_list[0] == 0\n"); 1904141cc406Sopenharmony_ci memset (&reply, 0, sizeof (reply)); 1905141cc406Sopenharmony_ci reply.status = SANE_STATUS_INVAL; 1906141cc406Sopenharmony_ci sanei_w_reply (w, (WireCodecFunc) sanei_w_open_reply, &reply); 1907141cc406Sopenharmony_ci break; 1908141cc406Sopenharmony_ci } 1909141cc406Sopenharmony_ci 1910141cc406Sopenharmony_ci resource = strdup (device_list[0]->name); 1911141cc406Sopenharmony_ci } 1912141cc406Sopenharmony_ci 1913141cc406Sopenharmony_ci if (strchr (resource, ':')) 1914141cc406Sopenharmony_ci *(strchr (resource, ':')) = 0; 1915141cc406Sopenharmony_ci 1916141cc406Sopenharmony_ci if (sanei_authorize (resource, "saned", auth_callback) != 1917141cc406Sopenharmony_ci SANE_STATUS_GOOD) 1918141cc406Sopenharmony_ci { 1919141cc406Sopenharmony_ci DBG (DBG_ERR, "process_request: access to resource `%s' denied\n", 1920141cc406Sopenharmony_ci resource); 1921141cc406Sopenharmony_ci free (resource); 1922141cc406Sopenharmony_ci memset (&reply, 0, sizeof (reply)); /* avoid leaking bits */ 1923141cc406Sopenharmony_ci reply.status = SANE_STATUS_ACCESS_DENIED; 1924141cc406Sopenharmony_ci } 1925141cc406Sopenharmony_ci else 1926141cc406Sopenharmony_ci { 1927141cc406Sopenharmony_ci DBG (DBG_MSG, "process_request: access to resource `%s' granted\n", 1928141cc406Sopenharmony_ci resource); 1929141cc406Sopenharmony_ci free (resource); 1930141cc406Sopenharmony_ci memset (&reply, 0, sizeof (reply)); /* avoid leaking bits */ 1931141cc406Sopenharmony_ci reply.status = sane_open (name, &be_handle); 1932141cc406Sopenharmony_ci DBG (DBG_MSG, "process_request: sane_open returned: %s\n", 1933141cc406Sopenharmony_ci sane_strstatus (reply.status)); 1934141cc406Sopenharmony_ci } 1935141cc406Sopenharmony_ci 1936141cc406Sopenharmony_ci if (reply.status == SANE_STATUS_GOOD) 1937141cc406Sopenharmony_ci { 1938141cc406Sopenharmony_ci h = get_free_handle (); 1939141cc406Sopenharmony_ci if (h < 0) 1940141cc406Sopenharmony_ci reply.status = SANE_STATUS_NO_MEM; 1941141cc406Sopenharmony_ci else 1942141cc406Sopenharmony_ci { 1943141cc406Sopenharmony_ci handle[h].handle = be_handle; 1944141cc406Sopenharmony_ci reply.handle = h; 1945141cc406Sopenharmony_ci } 1946141cc406Sopenharmony_ci } 1947141cc406Sopenharmony_ci 1948141cc406Sopenharmony_ci can_authorize = 0; 1949141cc406Sopenharmony_ci 1950141cc406Sopenharmony_ci sanei_w_reply (w, (WireCodecFunc) sanei_w_open_reply, &reply); 1951141cc406Sopenharmony_ci sanei_w_free (w, (WireCodecFunc) sanei_w_string, &name); 1952141cc406Sopenharmony_ci } 1953141cc406Sopenharmony_ci break; 1954141cc406Sopenharmony_ci 1955141cc406Sopenharmony_ci case SANE_NET_CLOSE: 1956141cc406Sopenharmony_ci { 1957141cc406Sopenharmony_ci SANE_Word ack = 0; 1958141cc406Sopenharmony_ci 1959141cc406Sopenharmony_ci h = decode_handle (w, "close"); 1960141cc406Sopenharmony_ci close_handle (h); 1961141cc406Sopenharmony_ci sanei_w_reply (w, (WireCodecFunc) sanei_w_word, &ack); 1962141cc406Sopenharmony_ci } 1963141cc406Sopenharmony_ci break; 1964141cc406Sopenharmony_ci 1965141cc406Sopenharmony_ci case SANE_NET_GET_OPTION_DESCRIPTORS: 1966141cc406Sopenharmony_ci { 1967141cc406Sopenharmony_ci SANE_Option_Descriptor_Array opt; 1968141cc406Sopenharmony_ci 1969141cc406Sopenharmony_ci h = decode_handle (w, "get_option_descriptors"); 1970141cc406Sopenharmony_ci if (h < 0) 1971141cc406Sopenharmony_ci return 1; 1972141cc406Sopenharmony_ci be_handle = handle[h].handle; 1973141cc406Sopenharmony_ci sane_control_option (be_handle, 0, SANE_ACTION_GET_VALUE, 1974141cc406Sopenharmony_ci &opt.num_options, 0); 1975141cc406Sopenharmony_ci 1976141cc406Sopenharmony_ci opt.desc = malloc (opt.num_options * sizeof (opt.desc[0])); 1977141cc406Sopenharmony_ci for (i = 0; i < opt.num_options; ++i) 1978141cc406Sopenharmony_ci opt.desc[i] = (SANE_Option_Descriptor *) 1979141cc406Sopenharmony_ci sane_get_option_descriptor (be_handle, i); 1980141cc406Sopenharmony_ci 1981141cc406Sopenharmony_ci sanei_w_reply (w,(WireCodecFunc) sanei_w_option_descriptor_array, 1982141cc406Sopenharmony_ci &opt); 1983141cc406Sopenharmony_ci 1984141cc406Sopenharmony_ci free (opt.desc); 1985141cc406Sopenharmony_ci } 1986141cc406Sopenharmony_ci break; 1987141cc406Sopenharmony_ci 1988141cc406Sopenharmony_ci case SANE_NET_CONTROL_OPTION: 1989141cc406Sopenharmony_ci { 1990141cc406Sopenharmony_ci SANE_Control_Option_Req req; 1991141cc406Sopenharmony_ci SANE_Control_Option_Reply reply; 1992141cc406Sopenharmony_ci 1993141cc406Sopenharmony_ci sanei_w_control_option_req (w, &req); 1994141cc406Sopenharmony_ci if (w->status || (unsigned) req.handle >= (unsigned) num_handles 1995141cc406Sopenharmony_ci || !handle[req.handle].inuse) 1996141cc406Sopenharmony_ci { 1997141cc406Sopenharmony_ci DBG (DBG_ERR, 1998141cc406Sopenharmony_ci "process_request: (control_option) " 1999141cc406Sopenharmony_ci "error while decoding args h=%d (%s)\n" 2000141cc406Sopenharmony_ci , req.handle, strerror (w->status)); 2001141cc406Sopenharmony_ci return 1; 2002141cc406Sopenharmony_ci } 2003141cc406Sopenharmony_ci 2004141cc406Sopenharmony_ci /* Addresses CVE-2017-6318 (#315576, Debian BTS #853804) */ 2005141cc406Sopenharmony_ci /* This is done here (rather than in sanei/sanei_wire.c where 2006141cc406Sopenharmony_ci * it should be done) to minimize scope of impact and amount 2007141cc406Sopenharmony_ci * of code change. 2008141cc406Sopenharmony_ci */ 2009141cc406Sopenharmony_ci if (w->direction == WIRE_DECODE 2010141cc406Sopenharmony_ci && req.value_type == SANE_TYPE_STRING 2011141cc406Sopenharmony_ci && req.action == SANE_ACTION_GET_VALUE) 2012141cc406Sopenharmony_ci { 2013141cc406Sopenharmony_ci if (req.value) 2014141cc406Sopenharmony_ci { 2015141cc406Sopenharmony_ci /* FIXME: If req.value contains embedded NUL 2016141cc406Sopenharmony_ci * characters, this is wrong but we do not have 2017141cc406Sopenharmony_ci * access to the amount of memory allocated in 2018141cc406Sopenharmony_ci * sanei/sanei_wire.c at this point. 2019141cc406Sopenharmony_ci */ 2020141cc406Sopenharmony_ci w->allocated_memory -= (1 + strlen (req.value)); 2021141cc406Sopenharmony_ci free (req.value); 2022141cc406Sopenharmony_ci } 2023141cc406Sopenharmony_ci req.value = malloc (req.value_size); 2024141cc406Sopenharmony_ci if (!req.value) 2025141cc406Sopenharmony_ci { 2026141cc406Sopenharmony_ci w->status = ENOMEM; 2027141cc406Sopenharmony_ci DBG (DBG_ERR, 2028141cc406Sopenharmony_ci "process_request: (control_option) " 2029141cc406Sopenharmony_ci "h=%d (%s)\n", req.handle, strerror (w->status)); 2030141cc406Sopenharmony_ci return 1; 2031141cc406Sopenharmony_ci } 2032141cc406Sopenharmony_ci memset (req.value, 0, req.value_size); 2033141cc406Sopenharmony_ci w->allocated_memory += req.value_size; 2034141cc406Sopenharmony_ci } 2035141cc406Sopenharmony_ci 2036141cc406Sopenharmony_ci can_authorize = 1; 2037141cc406Sopenharmony_ci 2038141cc406Sopenharmony_ci memset (&reply, 0, sizeof (reply)); /* avoid leaking bits */ 2039141cc406Sopenharmony_ci be_handle = handle[req.handle].handle; 2040141cc406Sopenharmony_ci reply.status = sane_control_option (be_handle, req.option, 2041141cc406Sopenharmony_ci req.action, req.value, 2042141cc406Sopenharmony_ci &reply.info); 2043141cc406Sopenharmony_ci reply.value_type = req.value_type; 2044141cc406Sopenharmony_ci reply.value_size = req.value_size; 2045141cc406Sopenharmony_ci reply.value = req.value; 2046141cc406Sopenharmony_ci 2047141cc406Sopenharmony_ci can_authorize = 0; 2048141cc406Sopenharmony_ci 2049141cc406Sopenharmony_ci sanei_w_reply (w, (WireCodecFunc) sanei_w_control_option_reply, 2050141cc406Sopenharmony_ci &reply); 2051141cc406Sopenharmony_ci sanei_w_free (w, (WireCodecFunc) sanei_w_control_option_req, &req); 2052141cc406Sopenharmony_ci } 2053141cc406Sopenharmony_ci break; 2054141cc406Sopenharmony_ci 2055141cc406Sopenharmony_ci case SANE_NET_GET_PARAMETERS: 2056141cc406Sopenharmony_ci { 2057141cc406Sopenharmony_ci SANE_Get_Parameters_Reply reply; 2058141cc406Sopenharmony_ci 2059141cc406Sopenharmony_ci h = decode_handle (w, "get_parameters"); 2060141cc406Sopenharmony_ci if (h < 0) 2061141cc406Sopenharmony_ci return 1; 2062141cc406Sopenharmony_ci be_handle = handle[h].handle; 2063141cc406Sopenharmony_ci 2064141cc406Sopenharmony_ci reply.status = sane_get_parameters (be_handle, &reply.params); 2065141cc406Sopenharmony_ci 2066141cc406Sopenharmony_ci sanei_w_reply (w, (WireCodecFunc) sanei_w_get_parameters_reply, 2067141cc406Sopenharmony_ci &reply); 2068141cc406Sopenharmony_ci } 2069141cc406Sopenharmony_ci break; 2070141cc406Sopenharmony_ci 2071141cc406Sopenharmony_ci case SANE_NET_START: 2072141cc406Sopenharmony_ci { 2073141cc406Sopenharmony_ci SANE_Start_Reply reply; 2074141cc406Sopenharmony_ci int fd = -1, data_fd = -1; 2075141cc406Sopenharmony_ci 2076141cc406Sopenharmony_ci h = decode_handle (w, "start"); 2077141cc406Sopenharmony_ci if (h < 0) 2078141cc406Sopenharmony_ci return 1; 2079141cc406Sopenharmony_ci 2080141cc406Sopenharmony_ci memset (&reply, 0, sizeof (reply)); /* avoid leaking bits */ 2081141cc406Sopenharmony_ci reply.byte_order = SANE_NET_LITTLE_ENDIAN; 2082141cc406Sopenharmony_ci if (byte_order.w != 1) 2083141cc406Sopenharmony_ci reply.byte_order = SANE_NET_BIG_ENDIAN; 2084141cc406Sopenharmony_ci 2085141cc406Sopenharmony_ci if (handle[h].scanning) 2086141cc406Sopenharmony_ci reply.status = SANE_STATUS_DEVICE_BUSY; 2087141cc406Sopenharmony_ci else 2088141cc406Sopenharmony_ci fd = start_scan (w, h, &reply); 2089141cc406Sopenharmony_ci 2090141cc406Sopenharmony_ci sanei_w_reply (w, (WireCodecFunc) sanei_w_start_reply, &reply); 2091141cc406Sopenharmony_ci 2092141cc406Sopenharmony_ci#ifdef SANED_USES_AF_INDEP 2093141cc406Sopenharmony_ci if (reply.status == SANE_STATUS_GOOD) 2094141cc406Sopenharmony_ci { 2095141cc406Sopenharmony_ci struct sockaddr_storage ss; 2096141cc406Sopenharmony_ci char text_addr[64]; 2097141cc406Sopenharmony_ci int len; 2098141cc406Sopenharmony_ci int error; 2099141cc406Sopenharmony_ci struct pollfd fds[1]; 2100141cc406Sopenharmony_ci int ret; 2101141cc406Sopenharmony_ci 2102141cc406Sopenharmony_ci fds->fd = fd; 2103141cc406Sopenharmony_ci fds->events = POLLIN; 2104141cc406Sopenharmony_ci 2105141cc406Sopenharmony_ci DBG (DBG_MSG, "process_request: waiting 4s for data connection\n"); 2106141cc406Sopenharmony_ci if(data_connect_timeout) 2107141cc406Sopenharmony_ci { 2108141cc406Sopenharmony_ci while (1) 2109141cc406Sopenharmony_ci { 2110141cc406Sopenharmony_ci ret = poll (fds, 1, data_connect_timeout); 2111141cc406Sopenharmony_ci if (ret < 0) 2112141cc406Sopenharmony_ci { 2113141cc406Sopenharmony_ci if (errno == EINTR) 2114141cc406Sopenharmony_ci continue; 2115141cc406Sopenharmony_ci else 2116141cc406Sopenharmony_ci { 2117141cc406Sopenharmony_ci DBG (DBG_ERR, "run_standalone: poll failed: %s\n", 2118141cc406Sopenharmony_ci strerror (errno)); 2119141cc406Sopenharmony_ci } 2120141cc406Sopenharmony_ci break; 2121141cc406Sopenharmony_ci } 2122141cc406Sopenharmony_ci break; 2123141cc406Sopenharmony_ci } 2124141cc406Sopenharmony_ci } 2125141cc406Sopenharmony_ci else 2126141cc406Sopenharmony_ci ret = 0; 2127141cc406Sopenharmony_ci if(ret >= 0) 2128141cc406Sopenharmony_ci data_fd = accept (fd, 0, 0); 2129141cc406Sopenharmony_ci close (fd); 2130141cc406Sopenharmony_ci 2131141cc406Sopenharmony_ci /* Get address of remote host */ 2132141cc406Sopenharmony_ci len = sizeof (ss); 2133141cc406Sopenharmony_ci if (getpeername (data_fd, (struct sockaddr *) &ss, (socklen_t *) &len) < 0) 2134141cc406Sopenharmony_ci { 2135141cc406Sopenharmony_ci DBG (DBG_ERR, "process_request: getpeername failed: %s\n", 2136141cc406Sopenharmony_ci strerror (errno)); 2137141cc406Sopenharmony_ci return 1; 2138141cc406Sopenharmony_ci } 2139141cc406Sopenharmony_ci 2140141cc406Sopenharmony_ci error = getnameinfo ((struct sockaddr *) &ss, len, text_addr, 2141141cc406Sopenharmony_ci sizeof (text_addr), NULL, 0, NI_NUMERICHOST); 2142141cc406Sopenharmony_ci if (error) 2143141cc406Sopenharmony_ci { 2144141cc406Sopenharmony_ci DBG (DBG_ERR, "process_request: getnameinfo failed: %s\n", 2145141cc406Sopenharmony_ci gai_strerror (error)); 2146141cc406Sopenharmony_ci return 1; 2147141cc406Sopenharmony_ci } 2148141cc406Sopenharmony_ci 2149141cc406Sopenharmony_ci DBG (DBG_MSG, "process_request: access to data port from %s\n", 2150141cc406Sopenharmony_ci text_addr); 2151141cc406Sopenharmony_ci 2152141cc406Sopenharmony_ci if (strcmp (text_addr, remote_ip) != 0) 2153141cc406Sopenharmony_ci { 2154141cc406Sopenharmony_ci DBG (DBG_ERR, "process_request: however, only %s is authorized\n", 2155141cc406Sopenharmony_ci text_addr); 2156141cc406Sopenharmony_ci DBG (DBG_ERR, "process_request: configuration problem or attack?\n"); 2157141cc406Sopenharmony_ci close (data_fd); 2158141cc406Sopenharmony_ci data_fd = -1; 2159141cc406Sopenharmony_ci return -1; 2160141cc406Sopenharmony_ci } 2161141cc406Sopenharmony_ci 2162141cc406Sopenharmony_ci#else /* !SANED_USES_AF_INDEP */ 2163141cc406Sopenharmony_ci 2164141cc406Sopenharmony_ci if (reply.status == SANE_STATUS_GOOD) 2165141cc406Sopenharmony_ci { 2166141cc406Sopenharmony_ci struct sockaddr_in sin; 2167141cc406Sopenharmony_ci int len; 2168141cc406Sopenharmony_ci int ret; 2169141cc406Sopenharmony_ci struct pollfd fds[1]; 2170141cc406Sopenharmony_ci 2171141cc406Sopenharmony_ci fds->fd = fd; 2172141cc406Sopenharmony_ci fds->events = POLLIN; 2173141cc406Sopenharmony_ci 2174141cc406Sopenharmony_ci DBG (DBG_MSG, "process_request: waiting for data connection\n"); 2175141cc406Sopenharmony_ci if(data_connect_timeout) 2176141cc406Sopenharmony_ci { 2177141cc406Sopenharmony_ci while (1) 2178141cc406Sopenharmony_ci { 2179141cc406Sopenharmony_ci ret = poll (fds, 1, data_connect_timeout); 2180141cc406Sopenharmony_ci if (ret < 0) 2181141cc406Sopenharmony_ci { 2182141cc406Sopenharmony_ci if (errno == EINTR) 2183141cc406Sopenharmony_ci continue; 2184141cc406Sopenharmony_ci else 2185141cc406Sopenharmony_ci { 2186141cc406Sopenharmony_ci DBG (DBG_ERR, "run_standalone: poll failed: %s\n", strerror (errno)); 2187141cc406Sopenharmony_ci } 2188141cc406Sopenharmony_ci break; 2189141cc406Sopenharmony_ci } 2190141cc406Sopenharmony_ci break; 2191141cc406Sopenharmony_ci } 2192141cc406Sopenharmony_ci } 2193141cc406Sopenharmony_ci else 2194141cc406Sopenharmony_ci ret = 0; 2195141cc406Sopenharmony_ci if(ret >= 0) 2196141cc406Sopenharmony_ci data_fd = accept (fd, 0, 0); 2197141cc406Sopenharmony_ci 2198141cc406Sopenharmony_ci close (fd); 2199141cc406Sopenharmony_ci 2200141cc406Sopenharmony_ci /* Get address of remote host */ 2201141cc406Sopenharmony_ci len = sizeof (sin); 2202141cc406Sopenharmony_ci if (getpeername (data_fd, (struct sockaddr *) &sin, 2203141cc406Sopenharmony_ci (socklen_t *) &len) < 0) 2204141cc406Sopenharmony_ci { 2205141cc406Sopenharmony_ci DBG (DBG_ERR, "process_request: getpeername failed: %s\n", 2206141cc406Sopenharmony_ci strerror (errno)); 2207141cc406Sopenharmony_ci return 1; 2208141cc406Sopenharmony_ci } 2209141cc406Sopenharmony_ci 2210141cc406Sopenharmony_ci if (memcmp (&remote_address, &sin.sin_addr, 2211141cc406Sopenharmony_ci sizeof (remote_address)) != 0) 2212141cc406Sopenharmony_ci { 2213141cc406Sopenharmony_ci DBG (DBG_ERR, 2214141cc406Sopenharmony_ci "process_request: access to data port from %s\n", 2215141cc406Sopenharmony_ci inet_ntoa (sin.sin_addr)); 2216141cc406Sopenharmony_ci DBG (DBG_ERR, 2217141cc406Sopenharmony_ci "process_request: however, only %s is authorized\n", 2218141cc406Sopenharmony_ci inet_ntoa (remote_address)); 2219141cc406Sopenharmony_ci DBG (DBG_ERR, 2220141cc406Sopenharmony_ci "process_request: configuration problem or attack?\n"); 2221141cc406Sopenharmony_ci close (data_fd); 2222141cc406Sopenharmony_ci data_fd = -1; 2223141cc406Sopenharmony_ci return -1; 2224141cc406Sopenharmony_ci } 2225141cc406Sopenharmony_ci else 2226141cc406Sopenharmony_ci DBG (DBG_MSG, "process_request: access to data port from %s\n", 2227141cc406Sopenharmony_ci inet_ntoa (sin.sin_addr)); 2228141cc406Sopenharmony_ci#endif /* SANED_USES_AF_INDEP */ 2229141cc406Sopenharmony_ci 2230141cc406Sopenharmony_ci if (data_fd < 0) 2231141cc406Sopenharmony_ci { 2232141cc406Sopenharmony_ci sane_cancel (handle[h].handle); 2233141cc406Sopenharmony_ci handle[h].scanning = 0; 2234141cc406Sopenharmony_ci handle[h].docancel = 0; 2235141cc406Sopenharmony_ci DBG (DBG_ERR, "process_request: accept failed! (%s)\n", 2236141cc406Sopenharmony_ci strerror (errno)); 2237141cc406Sopenharmony_ci return 1; 2238141cc406Sopenharmony_ci } 2239141cc406Sopenharmony_ci fcntl (data_fd, F_SETFL, 1); /* set non-blocking */ 2240141cc406Sopenharmony_ci shutdown (data_fd, 0); 2241141cc406Sopenharmony_ci do_scan (w, h, data_fd); 2242141cc406Sopenharmony_ci close (data_fd); 2243141cc406Sopenharmony_ci } 2244141cc406Sopenharmony_ci } 2245141cc406Sopenharmony_ci break; 2246141cc406Sopenharmony_ci 2247141cc406Sopenharmony_ci case SANE_NET_CANCEL: 2248141cc406Sopenharmony_ci { 2249141cc406Sopenharmony_ci SANE_Word ack = 0; 2250141cc406Sopenharmony_ci 2251141cc406Sopenharmony_ci h = decode_handle (w, "cancel"); 2252141cc406Sopenharmony_ci if (h >= 0) 2253141cc406Sopenharmony_ci { 2254141cc406Sopenharmony_ci sane_cancel (handle[h].handle); 2255141cc406Sopenharmony_ci handle[h].docancel = 1; 2256141cc406Sopenharmony_ci } 2257141cc406Sopenharmony_ci sanei_w_reply (w, (WireCodecFunc) sanei_w_word, &ack); 2258141cc406Sopenharmony_ci } 2259141cc406Sopenharmony_ci break; 2260141cc406Sopenharmony_ci 2261141cc406Sopenharmony_ci case SANE_NET_EXIT: 2262141cc406Sopenharmony_ci return -1; 2263141cc406Sopenharmony_ci break; 2264141cc406Sopenharmony_ci 2265141cc406Sopenharmony_ci case SANE_NET_INIT: 2266141cc406Sopenharmony_ci case SANE_NET_AUTHORIZE: 2267141cc406Sopenharmony_ci default: 2268141cc406Sopenharmony_ci DBG (DBG_ERR, 2269141cc406Sopenharmony_ci "process_request: received unexpected procedure number %d\n", 2270141cc406Sopenharmony_ci current_request); 2271141cc406Sopenharmony_ci return -1; 2272141cc406Sopenharmony_ci } 2273141cc406Sopenharmony_ci 2274141cc406Sopenharmony_ci return 0; 2275141cc406Sopenharmony_ci} 2276141cc406Sopenharmony_ci 2277141cc406Sopenharmony_ci 2278141cc406Sopenharmony_cistatic int 2279141cc406Sopenharmony_ciwait_child (pid_t pid, int *status, int options) 2280141cc406Sopenharmony_ci{ 2281141cc406Sopenharmony_ci struct saned_child *c; 2282141cc406Sopenharmony_ci struct saned_child *p = NULL; 2283141cc406Sopenharmony_ci int ret; 2284141cc406Sopenharmony_ci 2285141cc406Sopenharmony_ci ret = waitpid(pid, status, options); 2286141cc406Sopenharmony_ci 2287141cc406Sopenharmony_ci if (ret <= 0) 2288141cc406Sopenharmony_ci return ret; 2289141cc406Sopenharmony_ci 2290141cc406Sopenharmony_ci#if WITH_AVAHI 2291141cc406Sopenharmony_ci if ((avahi_pid > 0) && (ret == avahi_pid)) 2292141cc406Sopenharmony_ci { 2293141cc406Sopenharmony_ci avahi_pid = -1; 2294141cc406Sopenharmony_ci numchildren--; 2295141cc406Sopenharmony_ci return ret; 2296141cc406Sopenharmony_ci } 2297141cc406Sopenharmony_ci#endif /* WITH_AVAHI */ 2298141cc406Sopenharmony_ci 2299141cc406Sopenharmony_ci for (c = children; (c != NULL) && (c->next != NULL); p = c, c = c->next) 2300141cc406Sopenharmony_ci { 2301141cc406Sopenharmony_ci if (c->pid == ret) 2302141cc406Sopenharmony_ci { 2303141cc406Sopenharmony_ci if (c == children) 2304141cc406Sopenharmony_ci children = c->next; 2305141cc406Sopenharmony_ci else if (p != NULL) 2306141cc406Sopenharmony_ci p->next = c->next; 2307141cc406Sopenharmony_ci 2308141cc406Sopenharmony_ci free(c); 2309141cc406Sopenharmony_ci 2310141cc406Sopenharmony_ci numchildren--; 2311141cc406Sopenharmony_ci 2312141cc406Sopenharmony_ci break; 2313141cc406Sopenharmony_ci } 2314141cc406Sopenharmony_ci } 2315141cc406Sopenharmony_ci 2316141cc406Sopenharmony_ci return ret; 2317141cc406Sopenharmony_ci} 2318141cc406Sopenharmony_ci 2319141cc406Sopenharmony_cistatic int 2320141cc406Sopenharmony_ciadd_child (pid_t pid) 2321141cc406Sopenharmony_ci{ 2322141cc406Sopenharmony_ci struct saned_child *c; 2323141cc406Sopenharmony_ci 2324141cc406Sopenharmony_ci c = (struct saned_child *) malloc (sizeof(struct saned_child)); 2325141cc406Sopenharmony_ci 2326141cc406Sopenharmony_ci if (c == NULL) 2327141cc406Sopenharmony_ci { 2328141cc406Sopenharmony_ci DBG (DBG_ERR, "add_child: out of memory\n"); 2329141cc406Sopenharmony_ci return -1; 2330141cc406Sopenharmony_ci } 2331141cc406Sopenharmony_ci 2332141cc406Sopenharmony_ci c->pid = pid; 2333141cc406Sopenharmony_ci c->next = children; 2334141cc406Sopenharmony_ci 2335141cc406Sopenharmony_ci children = c; 2336141cc406Sopenharmony_ci 2337141cc406Sopenharmony_ci return 0; 2338141cc406Sopenharmony_ci} 2339141cc406Sopenharmony_ci 2340141cc406Sopenharmony_ci 2341141cc406Sopenharmony_cistatic void 2342141cc406Sopenharmony_cihandle_connection (int fd) 2343141cc406Sopenharmony_ci{ 2344141cc406Sopenharmony_ci#ifdef TCP_NODELAY 2345141cc406Sopenharmony_ci int on = 1; 2346141cc406Sopenharmony_ci int level = -1; 2347141cc406Sopenharmony_ci#endif 2348141cc406Sopenharmony_ci 2349141cc406Sopenharmony_ci DBG (DBG_DBG, "handle_connection: processing client connection\n"); 2350141cc406Sopenharmony_ci 2351141cc406Sopenharmony_ci wire.io.fd = fd; 2352141cc406Sopenharmony_ci 2353141cc406Sopenharmony_ci signal (SIGALRM, quit); 2354141cc406Sopenharmony_ci signal (SIGPIPE, quit); 2355141cc406Sopenharmony_ci 2356141cc406Sopenharmony_ci#ifdef TCP_NODELAY 2357141cc406Sopenharmony_ci# ifdef SOL_TCP 2358141cc406Sopenharmony_ci level = SOL_TCP; 2359141cc406Sopenharmony_ci# else /* !SOL_TCP */ 2360141cc406Sopenharmony_ci /* Look up the protocol level in the protocols database. */ 2361141cc406Sopenharmony_ci { 2362141cc406Sopenharmony_ci struct protoent *p; 2363141cc406Sopenharmony_ci p = getprotobyname ("tcp"); 2364141cc406Sopenharmony_ci if (p == 0) 2365141cc406Sopenharmony_ci { 2366141cc406Sopenharmony_ci DBG (DBG_WARN, "handle_connection: cannot look up `tcp' protocol number"); 2367141cc406Sopenharmony_ci } 2368141cc406Sopenharmony_ci else 2369141cc406Sopenharmony_ci level = p->p_proto; 2370141cc406Sopenharmony_ci } 2371141cc406Sopenharmony_ci# endif /* SOL_TCP */ 2372141cc406Sopenharmony_ci if (level == -1 2373141cc406Sopenharmony_ci || setsockopt (wire.io.fd, level, TCP_NODELAY, &on, sizeof (on))) 2374141cc406Sopenharmony_ci DBG (DBG_WARN, "handle_connection: failed to put socket in TCP_NODELAY mode (%s)", 2375141cc406Sopenharmony_ci strerror (errno)); 2376141cc406Sopenharmony_ci#endif /* !TCP_NODELAY */ 2377141cc406Sopenharmony_ci 2378141cc406Sopenharmony_ci if (init (&wire) < 0) 2379141cc406Sopenharmony_ci return; 2380141cc406Sopenharmony_ci 2381141cc406Sopenharmony_ci while (1) 2382141cc406Sopenharmony_ci { 2383141cc406Sopenharmony_ci reset_watchdog (); 2384141cc406Sopenharmony_ci if (process_request (&wire) < 0) 2385141cc406Sopenharmony_ci break; 2386141cc406Sopenharmony_ci } 2387141cc406Sopenharmony_ci} 2388141cc406Sopenharmony_ci 2389141cc406Sopenharmony_cistatic void 2390141cc406Sopenharmony_cihandle_client (int fd) 2391141cc406Sopenharmony_ci{ 2392141cc406Sopenharmony_ci pid_t pid; 2393141cc406Sopenharmony_ci int i; 2394141cc406Sopenharmony_ci 2395141cc406Sopenharmony_ci DBG (DBG_DBG, "handle_client: spawning child process\n"); 2396141cc406Sopenharmony_ci 2397141cc406Sopenharmony_ci pid = fork (); 2398141cc406Sopenharmony_ci if (pid == 0) 2399141cc406Sopenharmony_ci { 2400141cc406Sopenharmony_ci /* child */ 2401141cc406Sopenharmony_ci if (log_to_syslog) 2402141cc406Sopenharmony_ci closelog(); 2403141cc406Sopenharmony_ci 2404141cc406Sopenharmony_ci for (i = 3; i < fd; i++) 2405141cc406Sopenharmony_ci close(i); 2406141cc406Sopenharmony_ci 2407141cc406Sopenharmony_ci if (log_to_syslog) 2408141cc406Sopenharmony_ci openlog ("saned", LOG_PID | LOG_CONS, LOG_DAEMON); 2409141cc406Sopenharmony_ci 2410141cc406Sopenharmony_ci handle_connection (fd); 2411141cc406Sopenharmony_ci quit (0); 2412141cc406Sopenharmony_ci } 2413141cc406Sopenharmony_ci else if (pid > 0) 2414141cc406Sopenharmony_ci { 2415141cc406Sopenharmony_ci /* parent */ 2416141cc406Sopenharmony_ci add_child (pid); 2417141cc406Sopenharmony_ci close(fd); 2418141cc406Sopenharmony_ci } 2419141cc406Sopenharmony_ci else 2420141cc406Sopenharmony_ci { 2421141cc406Sopenharmony_ci /* FAILED */ 2422141cc406Sopenharmony_ci DBG (DBG_ERR, "handle_client: fork() failed: %s\n", strerror (errno)); 2423141cc406Sopenharmony_ci close(fd); 2424141cc406Sopenharmony_ci } 2425141cc406Sopenharmony_ci} 2426141cc406Sopenharmony_ci 2427141cc406Sopenharmony_cistatic void 2428141cc406Sopenharmony_cibail_out (int error) 2429141cc406Sopenharmony_ci{ 2430141cc406Sopenharmony_ci DBG (DBG_ERR, "%sbailing out, waiting for children...\n", (error) ? "FATAL ERROR; " : ""); 2431141cc406Sopenharmony_ci 2432141cc406Sopenharmony_ci#if WITH_AVAHI 2433141cc406Sopenharmony_ci if (avahi_pid > 0) 2434141cc406Sopenharmony_ci kill (avahi_pid, SIGTERM); 2435141cc406Sopenharmony_ci#endif /* WITH_AVAHI */ 2436141cc406Sopenharmony_ci 2437141cc406Sopenharmony_ci while (numchildren > 0) 2438141cc406Sopenharmony_ci wait_child (-1, NULL, 0); 2439141cc406Sopenharmony_ci 2440141cc406Sopenharmony_ci DBG (DBG_ERR, "bail_out: all children exited\n"); 2441141cc406Sopenharmony_ci 2442141cc406Sopenharmony_ci exit ((error) ? 1 : 0); 2443141cc406Sopenharmony_ci} 2444141cc406Sopenharmony_ci 2445141cc406Sopenharmony_civoid 2446141cc406Sopenharmony_cisig_int_term_handler (int signum); 2447141cc406Sopenharmony_ci 2448141cc406Sopenharmony_civoid 2449141cc406Sopenharmony_cisig_int_term_handler (int signum) 2450141cc406Sopenharmony_ci{ 2451141cc406Sopenharmony_ci /* unused */ 2452141cc406Sopenharmony_ci (void) signum; 2453141cc406Sopenharmony_ci 2454141cc406Sopenharmony_ci signal (SIGINT, NULL); 2455141cc406Sopenharmony_ci signal (SIGTERM, NULL); 2456141cc406Sopenharmony_ci 2457141cc406Sopenharmony_ci bail_out (0); 2458141cc406Sopenharmony_ci} 2459141cc406Sopenharmony_ci 2460141cc406Sopenharmony_ci 2461141cc406Sopenharmony_ci#if WITH_AVAHI 2462141cc406Sopenharmony_cistatic void 2463141cc406Sopenharmony_cisaned_avahi (struct pollfd *fds, int nfds); 2464141cc406Sopenharmony_ci 2465141cc406Sopenharmony_cistatic void 2466141cc406Sopenharmony_cisaned_create_avahi_services (AvahiClient *c); 2467141cc406Sopenharmony_ci 2468141cc406Sopenharmony_cistatic void 2469141cc406Sopenharmony_cisaned_avahi_callback (AvahiClient *c, AvahiClientState state, void *userdata); 2470141cc406Sopenharmony_ci 2471141cc406Sopenharmony_cistatic void 2472141cc406Sopenharmony_cisaned_avahi_group_callback (AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata); 2473141cc406Sopenharmony_ci 2474141cc406Sopenharmony_ci 2475141cc406Sopenharmony_cistatic void 2476141cc406Sopenharmony_cisaned_avahi (struct pollfd *fds, int nfds) 2477141cc406Sopenharmony_ci{ 2478141cc406Sopenharmony_ci struct pollfd *fdp = NULL; 2479141cc406Sopenharmony_ci int error; 2480141cc406Sopenharmony_ci 2481141cc406Sopenharmony_ci avahi_pid = fork (); 2482141cc406Sopenharmony_ci 2483141cc406Sopenharmony_ci if (avahi_pid > 0) 2484141cc406Sopenharmony_ci { 2485141cc406Sopenharmony_ci numchildren++; 2486141cc406Sopenharmony_ci return; 2487141cc406Sopenharmony_ci } 2488141cc406Sopenharmony_ci else if (avahi_pid < 0) 2489141cc406Sopenharmony_ci { 2490141cc406Sopenharmony_ci DBG (DBG_ERR, "saned_avahi: could not spawn Avahi process: %s\n", strerror (errno)); 2491141cc406Sopenharmony_ci return; 2492141cc406Sopenharmony_ci } 2493141cc406Sopenharmony_ci 2494141cc406Sopenharmony_ci signal (SIGINT, NULL); 2495141cc406Sopenharmony_ci signal (SIGTERM, NULL); 2496141cc406Sopenharmony_ci 2497141cc406Sopenharmony_ci /* Close network fds */ 2498141cc406Sopenharmony_ci for (fdp = fds; nfds > 0; nfds--, fdp++) 2499141cc406Sopenharmony_ci close (fdp->fd); 2500141cc406Sopenharmony_ci 2501141cc406Sopenharmony_ci free(fds); 2502141cc406Sopenharmony_ci 2503141cc406Sopenharmony_ci avahi_svc_name = avahi_strdup(SANED_NAME); 2504141cc406Sopenharmony_ci 2505141cc406Sopenharmony_ci avahi_poll = avahi_simple_poll_new (); 2506141cc406Sopenharmony_ci if (avahi_poll == NULL) 2507141cc406Sopenharmony_ci { 2508141cc406Sopenharmony_ci DBG (DBG_ERR, "saned_avahi: failed to create simple poll object\n"); 2509141cc406Sopenharmony_ci goto fail; 2510141cc406Sopenharmony_ci } 2511141cc406Sopenharmony_ci 2512141cc406Sopenharmony_ci avahi_client = avahi_client_new (avahi_simple_poll_get (avahi_poll), AVAHI_CLIENT_NO_FAIL, saned_avahi_callback, NULL, &error); 2513141cc406Sopenharmony_ci if (avahi_client == NULL) 2514141cc406Sopenharmony_ci { 2515141cc406Sopenharmony_ci DBG (DBG_ERR, "saned_avahi: failed to create client: %s\n", avahi_strerror (error)); 2516141cc406Sopenharmony_ci goto fail; 2517141cc406Sopenharmony_ci } 2518141cc406Sopenharmony_ci 2519141cc406Sopenharmony_ci avahi_simple_poll_loop (avahi_poll); 2520141cc406Sopenharmony_ci 2521141cc406Sopenharmony_ci DBG (DBG_INFO, "saned_avahi: poll loop exited\n"); 2522141cc406Sopenharmony_ci 2523141cc406Sopenharmony_ci exit(EXIT_SUCCESS); 2524141cc406Sopenharmony_ci 2525141cc406Sopenharmony_ci /* NOT REACHED */ 2526141cc406Sopenharmony_ci return; 2527141cc406Sopenharmony_ci 2528141cc406Sopenharmony_ci fail: 2529141cc406Sopenharmony_ci if (avahi_client) 2530141cc406Sopenharmony_ci avahi_client_free (avahi_client); 2531141cc406Sopenharmony_ci 2532141cc406Sopenharmony_ci if (avahi_poll) 2533141cc406Sopenharmony_ci avahi_simple_poll_free (avahi_poll); 2534141cc406Sopenharmony_ci 2535141cc406Sopenharmony_ci avahi_free (avahi_svc_name); 2536141cc406Sopenharmony_ci 2537141cc406Sopenharmony_ci exit(EXIT_FAILURE); 2538141cc406Sopenharmony_ci} 2539141cc406Sopenharmony_ci 2540141cc406Sopenharmony_cistatic void 2541141cc406Sopenharmony_cisaned_avahi_group_callback (AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) 2542141cc406Sopenharmony_ci{ 2543141cc406Sopenharmony_ci char *n; 2544141cc406Sopenharmony_ci 2545141cc406Sopenharmony_ci /* unused */ 2546141cc406Sopenharmony_ci (void) userdata; 2547141cc406Sopenharmony_ci 2548141cc406Sopenharmony_ci if ((!g) || (g != avahi_group)) 2549141cc406Sopenharmony_ci return; 2550141cc406Sopenharmony_ci 2551141cc406Sopenharmony_ci switch (state) 2552141cc406Sopenharmony_ci { 2553141cc406Sopenharmony_ci case AVAHI_ENTRY_GROUP_ESTABLISHED: 2554141cc406Sopenharmony_ci /* The entry group has been established successfully */ 2555141cc406Sopenharmony_ci DBG (DBG_INFO, "saned_avahi_group_callback: service '%s' successfully established\n", avahi_svc_name); 2556141cc406Sopenharmony_ci break; 2557141cc406Sopenharmony_ci 2558141cc406Sopenharmony_ci case AVAHI_ENTRY_GROUP_COLLISION: 2559141cc406Sopenharmony_ci /* A service name collision with a remote service 2560141cc406Sopenharmony_ci * happened. Let's pick a new name */ 2561141cc406Sopenharmony_ci n = avahi_alternative_service_name (avahi_svc_name); 2562141cc406Sopenharmony_ci avahi_free (avahi_svc_name); 2563141cc406Sopenharmony_ci avahi_svc_name = n; 2564141cc406Sopenharmony_ci 2565141cc406Sopenharmony_ci DBG (DBG_WARN, "saned_avahi_group_callback: service name collision, renaming service to '%s'\n", avahi_svc_name); 2566141cc406Sopenharmony_ci 2567141cc406Sopenharmony_ci /* And recreate the services */ 2568141cc406Sopenharmony_ci saned_create_avahi_services (avahi_entry_group_get_client (g)); 2569141cc406Sopenharmony_ci break; 2570141cc406Sopenharmony_ci 2571141cc406Sopenharmony_ci case AVAHI_ENTRY_GROUP_FAILURE : 2572141cc406Sopenharmony_ci DBG (DBG_ERR, "saned_avahi_group_callback: entry group failure: %s\n", avahi_strerror (avahi_client_errno (avahi_entry_group_get_client (g)))); 2573141cc406Sopenharmony_ci 2574141cc406Sopenharmony_ci /* Some kind of failure happened while we were registering our services */ 2575141cc406Sopenharmony_ci avahi_simple_poll_quit (avahi_poll); 2576141cc406Sopenharmony_ci break; 2577141cc406Sopenharmony_ci 2578141cc406Sopenharmony_ci case AVAHI_ENTRY_GROUP_UNCOMMITED: 2579141cc406Sopenharmony_ci case AVAHI_ENTRY_GROUP_REGISTERING: 2580141cc406Sopenharmony_ci break; 2581141cc406Sopenharmony_ci } 2582141cc406Sopenharmony_ci} 2583141cc406Sopenharmony_ci 2584141cc406Sopenharmony_cistatic void 2585141cc406Sopenharmony_cisaned_create_avahi_services (AvahiClient *c) 2586141cc406Sopenharmony_ci{ 2587141cc406Sopenharmony_ci char *n; 2588141cc406Sopenharmony_ci char txt[32]; 2589141cc406Sopenharmony_ci AvahiProtocol proto; 2590141cc406Sopenharmony_ci int ret; 2591141cc406Sopenharmony_ci 2592141cc406Sopenharmony_ci if (!c) 2593141cc406Sopenharmony_ci return; 2594141cc406Sopenharmony_ci 2595141cc406Sopenharmony_ci if (!avahi_group) 2596141cc406Sopenharmony_ci { 2597141cc406Sopenharmony_ci avahi_group = avahi_entry_group_new (c, saned_avahi_group_callback, NULL); 2598141cc406Sopenharmony_ci if (avahi_group == NULL) 2599141cc406Sopenharmony_ci { 2600141cc406Sopenharmony_ci DBG (DBG_ERR, "saned_create_avahi_services: avahi_entry_group_new() failed: %s\n", avahi_strerror (avahi_client_errno (c))); 2601141cc406Sopenharmony_ci goto fail; 2602141cc406Sopenharmony_ci } 2603141cc406Sopenharmony_ci } 2604141cc406Sopenharmony_ci 2605141cc406Sopenharmony_ci if (avahi_entry_group_is_empty (avahi_group)) 2606141cc406Sopenharmony_ci { 2607141cc406Sopenharmony_ci DBG (DBG_INFO, "saned_create_avahi_services: adding service '%s'\n", avahi_svc_name); 2608141cc406Sopenharmony_ci 2609141cc406Sopenharmony_ci snprintf(txt, sizeof (txt), "protovers=%x", SANE_VERSION_CODE (V_MAJOR, V_MINOR, SANEI_NET_PROTOCOL_VERSION)); 2610141cc406Sopenharmony_ci 2611141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 2612141cc406Sopenharmony_ci proto = AVAHI_PROTO_UNSPEC; 2613141cc406Sopenharmony_ci#else 2614141cc406Sopenharmony_ci proto = AVAHI_PROTO_INET; 2615141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 2616141cc406Sopenharmony_ci 2617141cc406Sopenharmony_ci ret = avahi_entry_group_add_service (avahi_group, AVAHI_IF_UNSPEC, proto, 0, avahi_svc_name, SANED_SERVICE_DNS, NULL, NULL, SANED_SERVICE_PORT, txt, NULL); 2618141cc406Sopenharmony_ci if (ret < 0) 2619141cc406Sopenharmony_ci { 2620141cc406Sopenharmony_ci if (ret == AVAHI_ERR_COLLISION) 2621141cc406Sopenharmony_ci { 2622141cc406Sopenharmony_ci n = avahi_alternative_service_name (avahi_svc_name); 2623141cc406Sopenharmony_ci avahi_free (avahi_svc_name); 2624141cc406Sopenharmony_ci avahi_svc_name = n; 2625141cc406Sopenharmony_ci 2626141cc406Sopenharmony_ci DBG (DBG_WARN, "saned_create_avahi_services: service name collision, renaming service to '%s'\n", avahi_svc_name); 2627141cc406Sopenharmony_ci 2628141cc406Sopenharmony_ci avahi_entry_group_reset (avahi_group); 2629141cc406Sopenharmony_ci 2630141cc406Sopenharmony_ci saned_create_avahi_services (c); 2631141cc406Sopenharmony_ci 2632141cc406Sopenharmony_ci return; 2633141cc406Sopenharmony_ci } 2634141cc406Sopenharmony_ci 2635141cc406Sopenharmony_ci DBG (DBG_ERR, "saned_create_avahi_services: failed to add %s service: %s\n", SANED_SERVICE_DNS, avahi_strerror (ret)); 2636141cc406Sopenharmony_ci goto fail; 2637141cc406Sopenharmony_ci } 2638141cc406Sopenharmony_ci 2639141cc406Sopenharmony_ci /* Tell the server to register the service */ 2640141cc406Sopenharmony_ci ret = avahi_entry_group_commit (avahi_group); 2641141cc406Sopenharmony_ci if (ret < 0) 2642141cc406Sopenharmony_ci { 2643141cc406Sopenharmony_ci DBG (DBG_ERR, "saned_create_avahi_services: failed to commit entry group: %s\n", avahi_strerror (ret)); 2644141cc406Sopenharmony_ci goto fail; 2645141cc406Sopenharmony_ci } 2646141cc406Sopenharmony_ci } 2647141cc406Sopenharmony_ci 2648141cc406Sopenharmony_ci return; 2649141cc406Sopenharmony_ci 2650141cc406Sopenharmony_ci fail: 2651141cc406Sopenharmony_ci avahi_simple_poll_quit (avahi_poll); 2652141cc406Sopenharmony_ci} 2653141cc406Sopenharmony_ci 2654141cc406Sopenharmony_cistatic void 2655141cc406Sopenharmony_cisaned_avahi_callback (AvahiClient *c, AvahiClientState state, void *userdata) 2656141cc406Sopenharmony_ci{ 2657141cc406Sopenharmony_ci int error; 2658141cc406Sopenharmony_ci 2659141cc406Sopenharmony_ci /* unused */ 2660141cc406Sopenharmony_ci (void) userdata; 2661141cc406Sopenharmony_ci 2662141cc406Sopenharmony_ci if (!c) 2663141cc406Sopenharmony_ci return; 2664141cc406Sopenharmony_ci 2665141cc406Sopenharmony_ci switch (state) 2666141cc406Sopenharmony_ci { 2667141cc406Sopenharmony_ci case AVAHI_CLIENT_CONNECTING: 2668141cc406Sopenharmony_ci DBG (DBG_INFO, "saned_avahi_callback: AVAHI_CLIENT_CONNECTING\n"); 2669141cc406Sopenharmony_ci break; 2670141cc406Sopenharmony_ci 2671141cc406Sopenharmony_ci case AVAHI_CLIENT_S_RUNNING: 2672141cc406Sopenharmony_ci DBG (DBG_INFO, "saned_avahi_callback: AVAHI_CLIENT_S_RUNNING\n"); 2673141cc406Sopenharmony_ci saned_create_avahi_services (c); 2674141cc406Sopenharmony_ci break; 2675141cc406Sopenharmony_ci 2676141cc406Sopenharmony_ci case AVAHI_CLIENT_S_COLLISION: 2677141cc406Sopenharmony_ci DBG (DBG_INFO, "saned_avahi_callback: AVAHI_CLIENT_S_COLLISION\n"); 2678141cc406Sopenharmony_ci if (avahi_group) 2679141cc406Sopenharmony_ci avahi_entry_group_reset (avahi_group); 2680141cc406Sopenharmony_ci break; 2681141cc406Sopenharmony_ci 2682141cc406Sopenharmony_ci case AVAHI_CLIENT_S_REGISTERING: 2683141cc406Sopenharmony_ci DBG (DBG_INFO, "saned_avahi_callback: AVAHI_CLIENT_S_REGISTERING\n"); 2684141cc406Sopenharmony_ci if (avahi_group) 2685141cc406Sopenharmony_ci avahi_entry_group_reset (avahi_group); 2686141cc406Sopenharmony_ci break; 2687141cc406Sopenharmony_ci 2688141cc406Sopenharmony_ci case AVAHI_CLIENT_FAILURE: 2689141cc406Sopenharmony_ci DBG (DBG_INFO, "saned_avahi_callback: AVAHI_CLIENT_FAILURE\n"); 2690141cc406Sopenharmony_ci 2691141cc406Sopenharmony_ci error = avahi_client_errno (c); 2692141cc406Sopenharmony_ci if (error == AVAHI_ERR_DISCONNECTED) 2693141cc406Sopenharmony_ci { 2694141cc406Sopenharmony_ci DBG (DBG_INFO, "saned_avahi_callback: AVAHI_ERR_DISCONNECTED\n"); 2695141cc406Sopenharmony_ci 2696141cc406Sopenharmony_ci /* Server disappeared - try to reconnect */ 2697141cc406Sopenharmony_ci avahi_client_free (avahi_client); 2698141cc406Sopenharmony_ci avahi_client = NULL; 2699141cc406Sopenharmony_ci avahi_group = NULL; 2700141cc406Sopenharmony_ci 2701141cc406Sopenharmony_ci avahi_client = avahi_client_new (avahi_simple_poll_get (avahi_poll), AVAHI_CLIENT_NO_FAIL, saned_avahi_callback, NULL, &error); 2702141cc406Sopenharmony_ci if (avahi_client == NULL) 2703141cc406Sopenharmony_ci { 2704141cc406Sopenharmony_ci DBG (DBG_ERR, "saned_avahi_callback: failed to create client: %s\n", avahi_strerror (error)); 2705141cc406Sopenharmony_ci avahi_simple_poll_quit (avahi_poll); 2706141cc406Sopenharmony_ci } 2707141cc406Sopenharmony_ci } 2708141cc406Sopenharmony_ci else 2709141cc406Sopenharmony_ci { 2710141cc406Sopenharmony_ci /* Another error happened - game over */ 2711141cc406Sopenharmony_ci DBG (DBG_ERR, "saned_avahi_callback: client failure: %s\n", avahi_strerror (error)); 2712141cc406Sopenharmony_ci avahi_simple_poll_quit (avahi_poll); 2713141cc406Sopenharmony_ci } 2714141cc406Sopenharmony_ci break; 2715141cc406Sopenharmony_ci } 2716141cc406Sopenharmony_ci} 2717141cc406Sopenharmony_ci#endif /* WITH_AVAHI */ 2718141cc406Sopenharmony_ci 2719141cc406Sopenharmony_ci 2720141cc406Sopenharmony_cistatic void 2721141cc406Sopenharmony_ciread_config (void) 2722141cc406Sopenharmony_ci{ 2723141cc406Sopenharmony_ci char config_line[PATH_MAX]; 2724141cc406Sopenharmony_ci const char *optval; 2725141cc406Sopenharmony_ci char *endval; 2726141cc406Sopenharmony_ci long val; 2727141cc406Sopenharmony_ci FILE *fp; 2728141cc406Sopenharmony_ci int len; 2729141cc406Sopenharmony_ci 2730141cc406Sopenharmony_ci DBG (DBG_INFO, "read_config: searching for config file\n"); 2731141cc406Sopenharmony_ci fp = sanei_config_open (SANED_CONFIG_FILE); 2732141cc406Sopenharmony_ci if (fp) 2733141cc406Sopenharmony_ci { 2734141cc406Sopenharmony_ci while (sanei_config_read (config_line, sizeof (config_line), fp)) 2735141cc406Sopenharmony_ci { 2736141cc406Sopenharmony_ci if (config_line[0] == '#') 2737141cc406Sopenharmony_ci continue; /* ignore line comments */ 2738141cc406Sopenharmony_ci 2739141cc406Sopenharmony_ci optval = strchr (config_line, '='); 2740141cc406Sopenharmony_ci if (optval == NULL) 2741141cc406Sopenharmony_ci continue; /* only interested in options, skip hosts */ 2742141cc406Sopenharmony_ci 2743141cc406Sopenharmony_ci len = strlen (config_line); 2744141cc406Sopenharmony_ci if (!len) 2745141cc406Sopenharmony_ci continue; /* ignore empty lines */ 2746141cc406Sopenharmony_ci 2747141cc406Sopenharmony_ci /* 2748141cc406Sopenharmony_ci * Check for saned options. 2749141cc406Sopenharmony_ci * Anything that isn't an option is a client. 2750141cc406Sopenharmony_ci */ 2751141cc406Sopenharmony_ci if (strstr(config_line, "data_portrange") != NULL) 2752141cc406Sopenharmony_ci { 2753141cc406Sopenharmony_ci optval = sanei_config_skip_whitespace (++optval); 2754141cc406Sopenharmony_ci if ((optval != NULL) && (*optval != '\0')) 2755141cc406Sopenharmony_ci { 2756141cc406Sopenharmony_ci val = strtol (optval, &endval, 10); 2757141cc406Sopenharmony_ci if (optval == endval) 2758141cc406Sopenharmony_ci { 2759141cc406Sopenharmony_ci DBG (DBG_ERR, "read_config: invalid value for data_portrange\n"); 2760141cc406Sopenharmony_ci continue; 2761141cc406Sopenharmony_ci } 2762141cc406Sopenharmony_ci else if ((val < 0) || (val > 65535)) 2763141cc406Sopenharmony_ci { 2764141cc406Sopenharmony_ci DBG (DBG_ERR, "read_config: data_portrange start port is invalid\n"); 2765141cc406Sopenharmony_ci continue; 2766141cc406Sopenharmony_ci } 2767141cc406Sopenharmony_ci 2768141cc406Sopenharmony_ci optval = strchr (endval, '-'); 2769141cc406Sopenharmony_ci if (optval == NULL) 2770141cc406Sopenharmony_ci { 2771141cc406Sopenharmony_ci DBG (DBG_ERR, "read_config: no end port value for data_portrange\n"); 2772141cc406Sopenharmony_ci continue; 2773141cc406Sopenharmony_ci } 2774141cc406Sopenharmony_ci 2775141cc406Sopenharmony_ci optval = sanei_config_skip_whitespace (++optval); 2776141cc406Sopenharmony_ci 2777141cc406Sopenharmony_ci data_port_lo = val; 2778141cc406Sopenharmony_ci 2779141cc406Sopenharmony_ci val = strtol (optval, &endval, 10); 2780141cc406Sopenharmony_ci if (optval == endval) 2781141cc406Sopenharmony_ci { 2782141cc406Sopenharmony_ci DBG (DBG_ERR, "read_config: invalid value for data_portrange\n"); 2783141cc406Sopenharmony_ci data_port_lo = 0; 2784141cc406Sopenharmony_ci continue; 2785141cc406Sopenharmony_ci } 2786141cc406Sopenharmony_ci else if ((val < 0) || (val > 65535)) 2787141cc406Sopenharmony_ci { 2788141cc406Sopenharmony_ci DBG (DBG_ERR, "read_config: data_portrange end port is invalid\n"); 2789141cc406Sopenharmony_ci data_port_lo = 0; 2790141cc406Sopenharmony_ci continue; 2791141cc406Sopenharmony_ci } 2792141cc406Sopenharmony_ci else if (val < data_port_lo) 2793141cc406Sopenharmony_ci { 2794141cc406Sopenharmony_ci DBG (DBG_ERR, "read_config: data_portrange end port is less than start port\n"); 2795141cc406Sopenharmony_ci data_port_lo = 0; 2796141cc406Sopenharmony_ci continue; 2797141cc406Sopenharmony_ci } 2798141cc406Sopenharmony_ci 2799141cc406Sopenharmony_ci data_port_hi = val; 2800141cc406Sopenharmony_ci 2801141cc406Sopenharmony_ci DBG (DBG_INFO, "read_config: data port range: %d - %d\n", data_port_lo, data_port_hi); 2802141cc406Sopenharmony_ci } 2803141cc406Sopenharmony_ci } 2804141cc406Sopenharmony_ci else if(strstr(config_line, "data_connect_timeout") != NULL) 2805141cc406Sopenharmony_ci { 2806141cc406Sopenharmony_ci optval = sanei_config_skip_whitespace (++optval); 2807141cc406Sopenharmony_ci if ((optval != NULL) && (*optval != '\0')) 2808141cc406Sopenharmony_ci { 2809141cc406Sopenharmony_ci val = strtol (optval, &endval, 10); 2810141cc406Sopenharmony_ci if (optval == endval) 2811141cc406Sopenharmony_ci { 2812141cc406Sopenharmony_ci DBG (DBG_ERR, "read_config: invalid value for data_connect_timeout\n"); 2813141cc406Sopenharmony_ci continue; 2814141cc406Sopenharmony_ci } 2815141cc406Sopenharmony_ci else if ((val < 0) || (val > 65535)) 2816141cc406Sopenharmony_ci { 2817141cc406Sopenharmony_ci DBG (DBG_ERR, "read_config: data_connect_timeout is invalid\n"); 2818141cc406Sopenharmony_ci continue; 2819141cc406Sopenharmony_ci } 2820141cc406Sopenharmony_ci data_connect_timeout = val; 2821141cc406Sopenharmony_ci DBG (DBG_INFO, "read_config: data connect timeout: %d\n", data_connect_timeout); 2822141cc406Sopenharmony_ci } 2823141cc406Sopenharmony_ci } 2824141cc406Sopenharmony_ci } 2825141cc406Sopenharmony_ci fclose (fp); 2826141cc406Sopenharmony_ci DBG (DBG_INFO, "read_config: done reading config\n"); 2827141cc406Sopenharmony_ci } 2828141cc406Sopenharmony_ci else 2829141cc406Sopenharmony_ci DBG (DBG_ERR, "read_config: could not open config file (%s): %s\n", 2830141cc406Sopenharmony_ci SANED_CONFIG_FILE, strerror (errno)); 2831141cc406Sopenharmony_ci} 2832141cc406Sopenharmony_ci 2833141cc406Sopenharmony_ci 2834141cc406Sopenharmony_ci#ifdef SANED_USES_AF_INDEP 2835141cc406Sopenharmony_cistatic void 2836141cc406Sopenharmony_cido_bindings_family (int family, int *nfds, struct pollfd **fds, struct addrinfo *res) 2837141cc406Sopenharmony_ci{ 2838141cc406Sopenharmony_ci struct addrinfo *resp; 2839141cc406Sopenharmony_ci struct pollfd *fdp; 2840141cc406Sopenharmony_ci short sane_port; 2841141cc406Sopenharmony_ci int fd = -1; 2842141cc406Sopenharmony_ci int on = 1; 2843141cc406Sopenharmony_ci int i; 2844141cc406Sopenharmony_ci 2845141cc406Sopenharmony_ci sane_port = bind_port; 2846141cc406Sopenharmony_ci fdp = *fds; 2847141cc406Sopenharmony_ci 2848141cc406Sopenharmony_ci for (resp = res, i = 0; resp != NULL; resp = resp->ai_next, i++) 2849141cc406Sopenharmony_ci { 2850141cc406Sopenharmony_ci /* We're not interested */ 2851141cc406Sopenharmony_ci if (resp->ai_family != family) 2852141cc406Sopenharmony_ci continue; 2853141cc406Sopenharmony_ci 2854141cc406Sopenharmony_ci if (resp->ai_family == AF_INET) 2855141cc406Sopenharmony_ci { 2856141cc406Sopenharmony_ci if (sane_port != -1) 2857141cc406Sopenharmony_ci ((struct sockaddr_in *) resp->ai_addr)->sin_port = htons(sane_port); 2858141cc406Sopenharmony_ci else 2859141cc406Sopenharmony_ci sane_port = ntohs(((struct sockaddr_in *) resp->ai_addr)->sin_port); 2860141cc406Sopenharmony_ci } 2861141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 2862141cc406Sopenharmony_ci else if (resp->ai_family == AF_INET6) 2863141cc406Sopenharmony_ci { 2864141cc406Sopenharmony_ci if (sane_port != -1) 2865141cc406Sopenharmony_ci ((struct sockaddr_in6 *) resp->ai_addr)->sin6_port = htons(sane_port); 2866141cc406Sopenharmony_ci else 2867141cc406Sopenharmony_ci sane_port = ntohs (((struct sockaddr_in6 *) resp->ai_addr)->sin6_port); 2868141cc406Sopenharmony_ci } 2869141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 2870141cc406Sopenharmony_ci else 2871141cc406Sopenharmony_ci continue; 2872141cc406Sopenharmony_ci 2873141cc406Sopenharmony_ci DBG (DBG_DBG, "do_bindings: [%d] socket () using IPv%d\n", i, (family == AF_INET) ? 4 : 6); 2874141cc406Sopenharmony_ci if ((fd = socket (resp->ai_family, SOCK_STREAM, 0)) < 0) 2875141cc406Sopenharmony_ci { 2876141cc406Sopenharmony_ci DBG (DBG_ERR, "do_bindings: [%d] socket failed: %s\n", i, strerror (errno)); 2877141cc406Sopenharmony_ci 2878141cc406Sopenharmony_ci continue; 2879141cc406Sopenharmony_ci } 2880141cc406Sopenharmony_ci 2881141cc406Sopenharmony_ci DBG (DBG_DBG, "do_bindings: [%d] setsockopt ()\n", i); 2882141cc406Sopenharmony_ci if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on))) 2883141cc406Sopenharmony_ci DBG (DBG_ERR, "do_bindings: [%d] failed to put socket in SO_REUSEADDR mode (%s)\n", i, strerror (errno)); 2884141cc406Sopenharmony_ci 2885141cc406Sopenharmony_ci 2886141cc406Sopenharmony_ci DBG (DBG_DBG, "do_bindings: [%d] bind () to port %d\n", i, sane_port); 2887141cc406Sopenharmony_ci if (bind (fd, resp->ai_addr, resp->ai_addrlen) < 0) 2888141cc406Sopenharmony_ci { 2889141cc406Sopenharmony_ci /* 2890141cc406Sopenharmony_ci * Binding a socket may fail with EADDRINUSE if we already bound 2891141cc406Sopenharmony_ci * to an IPv6 addr returned by getaddrinfo (usually the first ones) 2892141cc406Sopenharmony_ci * and we're trying to bind to an IPv4 addr now. 2893141cc406Sopenharmony_ci * It can also fail because we're trying to bind an IPv6 socket and IPv6 2894141cc406Sopenharmony_ci * is not functional on this machine. 2895141cc406Sopenharmony_ci * In any case, a bind() call returning an error is not necessarily fatal. 2896141cc406Sopenharmony_ci */ 2897141cc406Sopenharmony_ci DBG (DBG_WARN, "do_bindings: [%d] bind failed: %s\n", i, strerror (errno)); 2898141cc406Sopenharmony_ci 2899141cc406Sopenharmony_ci close (fd); 2900141cc406Sopenharmony_ci 2901141cc406Sopenharmony_ci continue; 2902141cc406Sopenharmony_ci } 2903141cc406Sopenharmony_ci 2904141cc406Sopenharmony_ci DBG (DBG_DBG, "do_bindings: [%d] listen ()\n", i); 2905141cc406Sopenharmony_ci if (listen (fd, 1) < 0) 2906141cc406Sopenharmony_ci { 2907141cc406Sopenharmony_ci DBG (DBG_ERR, "do_bindings: [%d] listen failed: %s\n", i, strerror (errno)); 2908141cc406Sopenharmony_ci 2909141cc406Sopenharmony_ci close (fd); 2910141cc406Sopenharmony_ci 2911141cc406Sopenharmony_ci continue; 2912141cc406Sopenharmony_ci } 2913141cc406Sopenharmony_ci 2914141cc406Sopenharmony_ci if (sane_port == 0) 2915141cc406Sopenharmony_ci { 2916141cc406Sopenharmony_ci /* sane was asked to bind to an ephemeral port, log it */ 2917141cc406Sopenharmony_ci socklen_t len = sizeof (*resp->ai_addr); 2918141cc406Sopenharmony_ci if (getsockname(fd, resp->ai_addr, &len) != -1) 2919141cc406Sopenharmony_ci { 2920141cc406Sopenharmony_ci if (resp->ai_family == AF_INET) 2921141cc406Sopenharmony_ci { 2922141cc406Sopenharmony_ci DBG (DBG_INFO, "do_bindings: [%d] selected ephemeral port: %d\n", i, ntohs(((struct sockaddr_in *) resp->ai_addr)->sin_port)); 2923141cc406Sopenharmony_ci } 2924141cc406Sopenharmony_ci 2925141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 2926141cc406Sopenharmony_ci if (resp->ai_family == AF_INET6) 2927141cc406Sopenharmony_ci { 2928141cc406Sopenharmony_ci DBG (DBG_INFO, "do_bindings: [%d] selected ephemeral port: %d\n", i, ntohs(((struct sockaddr_in6 *) resp->ai_addr)->sin6_port)); 2929141cc406Sopenharmony_ci } 2930141cc406Sopenharmony_ci 2931141cc406Sopenharmony_ci#endif /* ENABLE_IPV6 */ 2932141cc406Sopenharmony_ci 2933141cc406Sopenharmony_ci } 2934141cc406Sopenharmony_ci } 2935141cc406Sopenharmony_ci 2936141cc406Sopenharmony_ci fdp->fd = fd; 2937141cc406Sopenharmony_ci fdp->events = POLLIN; 2938141cc406Sopenharmony_ci 2939141cc406Sopenharmony_ci (*nfds)++; 2940141cc406Sopenharmony_ci fdp++; 2941141cc406Sopenharmony_ci } 2942141cc406Sopenharmony_ci 2943141cc406Sopenharmony_ci *fds = fdp; 2944141cc406Sopenharmony_ci} 2945141cc406Sopenharmony_ci 2946141cc406Sopenharmony_cistatic void 2947141cc406Sopenharmony_cido_bindings (int *nfds, struct pollfd **fds) 2948141cc406Sopenharmony_ci{ 2949141cc406Sopenharmony_ci struct addrinfo *res; 2950141cc406Sopenharmony_ci struct addrinfo *resp; 2951141cc406Sopenharmony_ci struct addrinfo hints; 2952141cc406Sopenharmony_ci struct pollfd *fdp; 2953141cc406Sopenharmony_ci int err; 2954141cc406Sopenharmony_ci 2955141cc406Sopenharmony_ci DBG (DBG_DBG, "do_bindings: trying to get port for service \"%s\" (getaddrinfo)\n", SANED_SERVICE_NAME); 2956141cc406Sopenharmony_ci 2957141cc406Sopenharmony_ci memset (&hints, 0, sizeof (struct addrinfo)); 2958141cc406Sopenharmony_ci 2959141cc406Sopenharmony_ci hints.ai_family = PF_UNSPEC; 2960141cc406Sopenharmony_ci hints.ai_flags = AI_PASSIVE; 2961141cc406Sopenharmony_ci hints.ai_socktype = SOCK_STREAM; 2962141cc406Sopenharmony_ci 2963141cc406Sopenharmony_ci err = getaddrinfo (bind_addr, SANED_SERVICE_NAME, &hints, &res); 2964141cc406Sopenharmony_ci if (err) 2965141cc406Sopenharmony_ci { 2966141cc406Sopenharmony_ci DBG (DBG_WARN, "do_bindings: \" %s \" service unknown on your host; you should add\n", SANED_SERVICE_NAME); 2967141cc406Sopenharmony_ci DBG (DBG_WARN, "do_bindings: %s %d/tcp saned # SANE network scanner daemon\n", SANED_SERVICE_NAME, SANED_SERVICE_PORT); 2968141cc406Sopenharmony_ci DBG (DBG_WARN, "do_bindings: to your /etc/services file (or equivalent). Proceeding anyway.\n"); 2969141cc406Sopenharmony_ci err = getaddrinfo (bind_addr, SANED_SERVICE_PORT_S, &hints, &res); 2970141cc406Sopenharmony_ci if (err) 2971141cc406Sopenharmony_ci { 2972141cc406Sopenharmony_ci DBG (DBG_ERR, "do_bindings: getaddrinfo() failed even with numeric port: %s\n", gai_strerror (err)); 2973141cc406Sopenharmony_ci bail_out (1); 2974141cc406Sopenharmony_ci } 2975141cc406Sopenharmony_ci } 2976141cc406Sopenharmony_ci 2977141cc406Sopenharmony_ci for (resp = res, *nfds = 0; resp != NULL; resp = resp->ai_next, (*nfds)++) 2978141cc406Sopenharmony_ci ; 2979141cc406Sopenharmony_ci 2980141cc406Sopenharmony_ci *fds = malloc (*nfds * sizeof (struct pollfd)); 2981141cc406Sopenharmony_ci 2982141cc406Sopenharmony_ci if (fds == NULL) 2983141cc406Sopenharmony_ci { 2984141cc406Sopenharmony_ci DBG (DBG_ERR, "do_bindings: not enough memory for fds\n"); 2985141cc406Sopenharmony_ci freeaddrinfo (res); 2986141cc406Sopenharmony_ci bail_out (1); 2987141cc406Sopenharmony_ci } 2988141cc406Sopenharmony_ci 2989141cc406Sopenharmony_ci fdp = *fds; 2990141cc406Sopenharmony_ci *nfds = 0; 2991141cc406Sopenharmony_ci 2992141cc406Sopenharmony_ci /* bind IPv6 first, IPv4 second */ 2993141cc406Sopenharmony_ci#ifdef ENABLE_IPV6 2994141cc406Sopenharmony_ci do_bindings_family (AF_INET6, nfds, &fdp, res); 2995141cc406Sopenharmony_ci#endif 2996141cc406Sopenharmony_ci do_bindings_family (AF_INET, nfds, &fdp, res); 2997141cc406Sopenharmony_ci 2998141cc406Sopenharmony_ci resp = NULL; 2999141cc406Sopenharmony_ci freeaddrinfo (res); 3000141cc406Sopenharmony_ci 3001141cc406Sopenharmony_ci if (*nfds <= 0) 3002141cc406Sopenharmony_ci { 3003141cc406Sopenharmony_ci DBG (DBG_ERR, "do_bindings: couldn't bind an address. Exiting.\n"); 3004141cc406Sopenharmony_ci bail_out (1); 3005141cc406Sopenharmony_ci } 3006141cc406Sopenharmony_ci} 3007141cc406Sopenharmony_ci 3008141cc406Sopenharmony_ci#else /* !SANED_USES_AF_INDEP */ 3009141cc406Sopenharmony_ci 3010141cc406Sopenharmony_cistatic void 3011141cc406Sopenharmony_cido_bindings (int *nfds, struct pollfd **fds) 3012141cc406Sopenharmony_ci{ 3013141cc406Sopenharmony_ci struct sockaddr_in sin; 3014141cc406Sopenharmony_ci struct servent *serv; 3015141cc406Sopenharmony_ci short port; 3016141cc406Sopenharmony_ci int fd = -1; 3017141cc406Sopenharmony_ci int on = 1; 3018141cc406Sopenharmony_ci 3019141cc406Sopenharmony_ci DBG (DBG_DBG, "do_bindings: trying to get port for service \"%s\" (getservbyname)\n", SANED_SERVICE_NAME); 3020141cc406Sopenharmony_ci serv = getservbyname (SANED_SERVICE_NAME, "tcp"); 3021141cc406Sopenharmony_ci 3022141cc406Sopenharmony_ci if (serv) 3023141cc406Sopenharmony_ci { 3024141cc406Sopenharmony_ci port = serv->s_port; 3025141cc406Sopenharmony_ci DBG (DBG_MSG, "do_bindings: port is %d\n", ntohs (port)); 3026141cc406Sopenharmony_ci } 3027141cc406Sopenharmony_ci else 3028141cc406Sopenharmony_ci { 3029141cc406Sopenharmony_ci port = htons (SANED_SERVICE_PORT); 3030141cc406Sopenharmony_ci DBG (DBG_WARN, "do_bindings: \"%s\" service unknown on your host; you should add\n", SANED_SERVICE_NAME); 3031141cc406Sopenharmony_ci DBG (DBG_WARN, "do_bindings: %s %d/tcp saned # SANE network scanner daemon\n", SANED_SERVICE_NAME, SANED_SERVICE_PORT); 3032141cc406Sopenharmony_ci DBG (DBG_WARN, "do_bindings: to your /etc/services file (or equivalent). Proceeding anyway.\n"); 3033141cc406Sopenharmony_ci } 3034141cc406Sopenharmony_ci 3035141cc406Sopenharmony_ci *nfds = 1; 3036141cc406Sopenharmony_ci *fds = malloc (*nfds * sizeof (struct pollfd)); 3037141cc406Sopenharmony_ci 3038141cc406Sopenharmony_ci if (fds == NULL) 3039141cc406Sopenharmony_ci { 3040141cc406Sopenharmony_ci DBG (DBG_ERR, "do_bindings: not enough memory for fds\n"); 3041141cc406Sopenharmony_ci bail_out (1); 3042141cc406Sopenharmony_ci } 3043141cc406Sopenharmony_ci 3044141cc406Sopenharmony_ci memset (&sin, 0, sizeof (sin)); 3045141cc406Sopenharmony_ci 3046141cc406Sopenharmony_ci sin.sin_family = AF_INET; 3047141cc406Sopenharmony_ci if(bind_addr) 3048141cc406Sopenharmony_ci sin.sin_addr.s_addr = inet_addr(bind_addr); 3049141cc406Sopenharmony_ci else 3050141cc406Sopenharmony_ci sin.sin_addr.s_addr = INADDR_ANY; 3051141cc406Sopenharmony_ci sin.sin_port = port; 3052141cc406Sopenharmony_ci 3053141cc406Sopenharmony_ci DBG (DBG_DBG, "do_bindings: socket ()\n"); 3054141cc406Sopenharmony_ci fd = socket (AF_INET, SOCK_STREAM, 0); 3055141cc406Sopenharmony_ci 3056141cc406Sopenharmony_ci DBG (DBG_DBG, "do_bindings: setsockopt ()\n"); 3057141cc406Sopenharmony_ci if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on))) 3058141cc406Sopenharmony_ci DBG (DBG_ERR, "do_bindings: failed to put socket in SO_REUSEADDR mode (%s)", strerror (errno)); 3059141cc406Sopenharmony_ci 3060141cc406Sopenharmony_ci DBG (DBG_DBG, "do_bindings: bind ()\n"); 3061141cc406Sopenharmony_ci if (bind (fd, (struct sockaddr *) &sin, sizeof (sin)) < 0) 3062141cc406Sopenharmony_ci { 3063141cc406Sopenharmony_ci DBG (DBG_ERR, "do_bindings: bind failed: %s", strerror (errno)); 3064141cc406Sopenharmony_ci bail_out (1); 3065141cc406Sopenharmony_ci } 3066141cc406Sopenharmony_ci 3067141cc406Sopenharmony_ci DBG (DBG_DBG, "do_bindings: listen ()\n"); 3068141cc406Sopenharmony_ci if (listen (fd, 1) < 0) 3069141cc406Sopenharmony_ci { 3070141cc406Sopenharmony_ci DBG (DBG_ERR, "do_bindings: listen failed: %s", strerror (errno)); 3071141cc406Sopenharmony_ci bail_out (1); 3072141cc406Sopenharmony_ci } 3073141cc406Sopenharmony_ci 3074141cc406Sopenharmony_ci (*fds)->fd = fd; 3075141cc406Sopenharmony_ci (*fds)->events = POLLIN; 3076141cc406Sopenharmony_ci} 3077141cc406Sopenharmony_ci 3078141cc406Sopenharmony_ci#endif /* SANED_USES_AF_INDEP */ 3079141cc406Sopenharmony_ci 3080141cc406Sopenharmony_ci 3081141cc406Sopenharmony_cistatic void 3082141cc406Sopenharmony_cirunas_user (char *user) 3083141cc406Sopenharmony_ci{ 3084141cc406Sopenharmony_ci uid_t runas_uid = 0; 3085141cc406Sopenharmony_ci gid_t runas_gid = 0; 3086141cc406Sopenharmony_ci struct passwd *pwent; 3087141cc406Sopenharmony_ci gid_t *grplist = NULL; 3088141cc406Sopenharmony_ci struct group *grp; 3089141cc406Sopenharmony_ci int ngroups = 0; 3090141cc406Sopenharmony_ci int ret; 3091141cc406Sopenharmony_ci 3092141cc406Sopenharmony_ci pwent = getpwnam(user); 3093141cc406Sopenharmony_ci 3094141cc406Sopenharmony_ci if (pwent == NULL) 3095141cc406Sopenharmony_ci { 3096141cc406Sopenharmony_ci DBG (DBG_ERR, "FATAL ERROR: user %s not found on system\n", user); 3097141cc406Sopenharmony_ci bail_out (1); 3098141cc406Sopenharmony_ci } 3099141cc406Sopenharmony_ci 3100141cc406Sopenharmony_ci runas_uid = pwent->pw_uid; 3101141cc406Sopenharmony_ci runas_gid = pwent->pw_gid; 3102141cc406Sopenharmony_ci 3103141cc406Sopenharmony_ci /* Get group list for runas_uid */ 3104141cc406Sopenharmony_ci grplist = (gid_t *)malloc(sizeof(gid_t)); 3105141cc406Sopenharmony_ci 3106141cc406Sopenharmony_ci if (grplist == NULL) 3107141cc406Sopenharmony_ci { 3108141cc406Sopenharmony_ci DBG (DBG_ERR, "FATAL ERROR: cannot allocate memory for group list\n"); 3109141cc406Sopenharmony_ci 3110141cc406Sopenharmony_ci exit (1); 3111141cc406Sopenharmony_ci } 3112141cc406Sopenharmony_ci 3113141cc406Sopenharmony_ci ngroups = 1; 3114141cc406Sopenharmony_ci grplist[0] = runas_gid; 3115141cc406Sopenharmony_ci 3116141cc406Sopenharmony_ci setgrent(); 3117141cc406Sopenharmony_ci while ((grp = getgrent()) != NULL) 3118141cc406Sopenharmony_ci { 3119141cc406Sopenharmony_ci int i = 0; 3120141cc406Sopenharmony_ci 3121141cc406Sopenharmony_ci /* Already added current group */ 3122141cc406Sopenharmony_ci if (grp->gr_gid == runas_gid) 3123141cc406Sopenharmony_ci continue; 3124141cc406Sopenharmony_ci 3125141cc406Sopenharmony_ci while (grp->gr_mem[i]) 3126141cc406Sopenharmony_ci { 3127141cc406Sopenharmony_ci if (strcmp(grp->gr_mem[i], user) == 0) 3128141cc406Sopenharmony_ci { 3129141cc406Sopenharmony_ci int need_to_add = 1, j; 3130141cc406Sopenharmony_ci 3131141cc406Sopenharmony_ci /* Make sure its not already in list */ 3132141cc406Sopenharmony_ci for (j = 0; j < ngroups; j++) 3133141cc406Sopenharmony_ci { 3134141cc406Sopenharmony_ci if (grp->gr_gid == grplist[i]) 3135141cc406Sopenharmony_ci need_to_add = 0; 3136141cc406Sopenharmony_ci } 3137141cc406Sopenharmony_ci if (need_to_add) 3138141cc406Sopenharmony_ci { 3139141cc406Sopenharmony_ci grplist = (gid_t *)realloc(grplist, 3140141cc406Sopenharmony_ci sizeof(gid_t)*ngroups+1); 3141141cc406Sopenharmony_ci if (grplist == NULL) 3142141cc406Sopenharmony_ci { 3143141cc406Sopenharmony_ci DBG (DBG_ERR, "FATAL ERROR: cannot reallocate memory for group list\n"); 3144141cc406Sopenharmony_ci 3145141cc406Sopenharmony_ci exit (1); 3146141cc406Sopenharmony_ci } 3147141cc406Sopenharmony_ci grplist[ngroups++] = grp->gr_gid; 3148141cc406Sopenharmony_ci } 3149141cc406Sopenharmony_ci } 3150141cc406Sopenharmony_ci i++; 3151141cc406Sopenharmony_ci } 3152141cc406Sopenharmony_ci } 3153141cc406Sopenharmony_ci endgrent(); 3154141cc406Sopenharmony_ci 3155141cc406Sopenharmony_ci /* Drop privileges if requested */ 3156141cc406Sopenharmony_ci if (runas_uid > 0) 3157141cc406Sopenharmony_ci { 3158141cc406Sopenharmony_ci ret = setgroups(ngroups, grplist); 3159141cc406Sopenharmony_ci if (ret < 0) 3160141cc406Sopenharmony_ci { 3161141cc406Sopenharmony_ci DBG (DBG_ERR, "FATAL ERROR: could not set group list: %s\n", strerror(errno)); 3162141cc406Sopenharmony_ci 3163141cc406Sopenharmony_ci exit (1); 3164141cc406Sopenharmony_ci } 3165141cc406Sopenharmony_ci 3166141cc406Sopenharmony_ci free(grplist); 3167141cc406Sopenharmony_ci 3168141cc406Sopenharmony_ci ret = setegid (runas_gid); 3169141cc406Sopenharmony_ci if (ret < 0) 3170141cc406Sopenharmony_ci { 3171141cc406Sopenharmony_ci DBG (DBG_ERR, "FATAL ERROR: setegid to gid %d failed: %s\n", runas_gid, strerror (errno)); 3172141cc406Sopenharmony_ci 3173141cc406Sopenharmony_ci exit (1); 3174141cc406Sopenharmony_ci } 3175141cc406Sopenharmony_ci 3176141cc406Sopenharmony_ci ret = seteuid (runas_uid); 3177141cc406Sopenharmony_ci if (ret < 0) 3178141cc406Sopenharmony_ci { 3179141cc406Sopenharmony_ci DBG (DBG_ERR, "FATAL ERROR: seteuid to uid %d failed: %s\n", runas_uid, strerror (errno)); 3180141cc406Sopenharmony_ci 3181141cc406Sopenharmony_ci exit (1); 3182141cc406Sopenharmony_ci } 3183141cc406Sopenharmony_ci 3184141cc406Sopenharmony_ci DBG (DBG_WARN, "Dropped privileges to uid %d gid %d\n", runas_uid, runas_gid); 3185141cc406Sopenharmony_ci } 3186141cc406Sopenharmony_ci} 3187141cc406Sopenharmony_ci 3188141cc406Sopenharmony_ci 3189141cc406Sopenharmony_cistatic void 3190141cc406Sopenharmony_cirun_standalone (char *user) 3191141cc406Sopenharmony_ci{ 3192141cc406Sopenharmony_ci struct pollfd *fds = NULL; 3193141cc406Sopenharmony_ci struct pollfd *fdp = NULL; 3194141cc406Sopenharmony_ci int nfds; 3195141cc406Sopenharmony_ci int fd = -1; 3196141cc406Sopenharmony_ci int i; 3197141cc406Sopenharmony_ci int ret; 3198141cc406Sopenharmony_ci 3199141cc406Sopenharmony_ci FILE *pidfile; 3200141cc406Sopenharmony_ci 3201141cc406Sopenharmony_ci do_bindings (&nfds, &fds); 3202141cc406Sopenharmony_ci 3203141cc406Sopenharmony_ci if (run_foreground == SANE_FALSE) 3204141cc406Sopenharmony_ci { 3205141cc406Sopenharmony_ci DBG (DBG_MSG, "run_standalone: daemonizing now\n"); 3206141cc406Sopenharmony_ci 3207141cc406Sopenharmony_ci fd = open ("/dev/null", O_RDWR); 3208141cc406Sopenharmony_ci if (fd < 0) 3209141cc406Sopenharmony_ci { 3210141cc406Sopenharmony_ci DBG (DBG_ERR, "FATAL ERROR: cannot open /dev/null: %s\n", strerror (errno)); 3211141cc406Sopenharmony_ci exit (1); 3212141cc406Sopenharmony_ci } 3213141cc406Sopenharmony_ci 3214141cc406Sopenharmony_ci ret = fork (); 3215141cc406Sopenharmony_ci if (ret > 0) 3216141cc406Sopenharmony_ci { 3217141cc406Sopenharmony_ci _exit (0); 3218141cc406Sopenharmony_ci } 3219141cc406Sopenharmony_ci else if (ret < 0) 3220141cc406Sopenharmony_ci { 3221141cc406Sopenharmony_ci DBG (DBG_ERR, "FATAL ERROR: fork failed: %s\n", strerror (errno)); 3222141cc406Sopenharmony_ci exit (1); 3223141cc406Sopenharmony_ci } 3224141cc406Sopenharmony_ci 3225141cc406Sopenharmony_ci DBG (DBG_WARN, "Now daemonized\n"); 3226141cc406Sopenharmony_ci 3227141cc406Sopenharmony_ci /* Write out PID file */ 3228141cc406Sopenharmony_ci pidfile = fopen (SANED_PID_FILE, "w"); 3229141cc406Sopenharmony_ci if (pidfile) 3230141cc406Sopenharmony_ci { 3231141cc406Sopenharmony_ci fprintf (pidfile, "%d", getpid()); 3232141cc406Sopenharmony_ci fclose (pidfile); 3233141cc406Sopenharmony_ci } 3234141cc406Sopenharmony_ci else 3235141cc406Sopenharmony_ci DBG (DBG_ERR, "Could not write PID file: %s\n", strerror (errno)); 3236141cc406Sopenharmony_ci 3237141cc406Sopenharmony_ci chdir ("/"); 3238141cc406Sopenharmony_ci 3239141cc406Sopenharmony_ci dup2 (fd, STDIN_FILENO); 3240141cc406Sopenharmony_ci dup2 (fd, STDOUT_FILENO); 3241141cc406Sopenharmony_ci dup2 (fd, STDERR_FILENO); 3242141cc406Sopenharmony_ci 3243141cc406Sopenharmony_ci close (fd); 3244141cc406Sopenharmony_ci 3245141cc406Sopenharmony_ci setsid (); 3246141cc406Sopenharmony_ci 3247141cc406Sopenharmony_ci signal(SIGINT, sig_int_term_handler); 3248141cc406Sopenharmony_ci signal(SIGTERM, sig_int_term_handler); 3249141cc406Sopenharmony_ci } 3250141cc406Sopenharmony_ci 3251141cc406Sopenharmony_ci if (user) 3252141cc406Sopenharmony_ci runas_user(user); 3253141cc406Sopenharmony_ci 3254141cc406Sopenharmony_ci#if WITH_AVAHI 3255141cc406Sopenharmony_ci DBG (DBG_INFO, "run_standalone: spawning Avahi process\n"); 3256141cc406Sopenharmony_ci saned_avahi (fds, nfds); 3257141cc406Sopenharmony_ci 3258141cc406Sopenharmony_ci /* NOT REACHED (Avahi process) */ 3259141cc406Sopenharmony_ci#endif /* WITH_AVAHI */ 3260141cc406Sopenharmony_ci 3261141cc406Sopenharmony_ci DBG (DBG_MSG, "run_standalone: waiting for control connection\n"); 3262141cc406Sopenharmony_ci 3263141cc406Sopenharmony_ci while (1) 3264141cc406Sopenharmony_ci { 3265141cc406Sopenharmony_ci ret = poll (fds, nfds, 500); 3266141cc406Sopenharmony_ci if (ret < 0) 3267141cc406Sopenharmony_ci { 3268141cc406Sopenharmony_ci if (errno == EINTR) 3269141cc406Sopenharmony_ci continue; 3270141cc406Sopenharmony_ci else 3271141cc406Sopenharmony_ci { 3272141cc406Sopenharmony_ci DBG (DBG_ERR, "run_standalone: poll failed: %s\n", strerror (errno)); 3273141cc406Sopenharmony_ci free (fds); 3274141cc406Sopenharmony_ci bail_out (1); 3275141cc406Sopenharmony_ci } 3276141cc406Sopenharmony_ci } 3277141cc406Sopenharmony_ci 3278141cc406Sopenharmony_ci /* Wait for children */ 3279141cc406Sopenharmony_ci while (wait_child (-1, NULL, WNOHANG) > 0) 3280141cc406Sopenharmony_ci ; 3281141cc406Sopenharmony_ci 3282141cc406Sopenharmony_ci if (ret == 0) 3283141cc406Sopenharmony_ci continue; 3284141cc406Sopenharmony_ci 3285141cc406Sopenharmony_ci for (i = 0, fdp = fds; i < nfds; i++, fdp++) 3286141cc406Sopenharmony_ci { 3287141cc406Sopenharmony_ci /* Error on an fd */ 3288141cc406Sopenharmony_ci if (fdp->revents & (POLLERR | POLLHUP | POLLNVAL)) 3289141cc406Sopenharmony_ci { 3290141cc406Sopenharmony_ci for (i = 0, fdp = fds; i < nfds; i++, fdp++) 3291141cc406Sopenharmony_ci close (fdp->fd); 3292141cc406Sopenharmony_ci 3293141cc406Sopenharmony_ci free (fds); 3294141cc406Sopenharmony_ci 3295141cc406Sopenharmony_ci DBG (DBG_WARN, "run_standalone: invalid fd in set, attempting to re-bind\n"); 3296141cc406Sopenharmony_ci 3297141cc406Sopenharmony_ci /* Reopen sockets */ 3298141cc406Sopenharmony_ci do_bindings (&nfds, &fds); 3299141cc406Sopenharmony_ci 3300141cc406Sopenharmony_ci break; 3301141cc406Sopenharmony_ci } 3302141cc406Sopenharmony_ci else if (! (fdp->revents & POLLIN)) 3303141cc406Sopenharmony_ci continue; 3304141cc406Sopenharmony_ci 3305141cc406Sopenharmony_ci fd = accept (fdp->fd, 0, 0); 3306141cc406Sopenharmony_ci if (fd < 0) 3307141cc406Sopenharmony_ci { 3308141cc406Sopenharmony_ci DBG (DBG_ERR, "run_standalone: accept failed: %s", strerror (errno)); 3309141cc406Sopenharmony_ci continue; 3310141cc406Sopenharmony_ci } 3311141cc406Sopenharmony_ci 3312141cc406Sopenharmony_ci handle_client (fd); 3313141cc406Sopenharmony_ci 3314141cc406Sopenharmony_ci if (run_once == SANE_TRUE) 3315141cc406Sopenharmony_ci break; /* We have handled the only connection we're going to handle */ 3316141cc406Sopenharmony_ci } 3317141cc406Sopenharmony_ci 3318141cc406Sopenharmony_ci if (run_once == SANE_TRUE) 3319141cc406Sopenharmony_ci break; 3320141cc406Sopenharmony_ci } 3321141cc406Sopenharmony_ci 3322141cc406Sopenharmony_ci for (i = 0, fdp = fds; i < nfds; i++, fdp++) 3323141cc406Sopenharmony_ci close (fdp->fd); 3324141cc406Sopenharmony_ci 3325141cc406Sopenharmony_ci free (fds); 3326141cc406Sopenharmony_ci} 3327141cc406Sopenharmony_ci 3328141cc406Sopenharmony_ci 3329141cc406Sopenharmony_cistatic void 3330141cc406Sopenharmony_cirun_inetd (char __sane_unused__ *sock) 3331141cc406Sopenharmony_ci{ 3332141cc406Sopenharmony_ci 3333141cc406Sopenharmony_ci int fd = -1; 3334141cc406Sopenharmony_ci 3335141cc406Sopenharmony_ci#ifdef HAVE_SYSTEMD 3336141cc406Sopenharmony_ci int n; 3337141cc406Sopenharmony_ci 3338141cc406Sopenharmony_ci n = sd_listen_fds(0); 3339141cc406Sopenharmony_ci 3340141cc406Sopenharmony_ci if (n > 1) 3341141cc406Sopenharmony_ci { 3342141cc406Sopenharmony_ci DBG (DBG_ERR, "run_inetd: Too many file descriptors (sockets) received from systemd!\n"); 3343141cc406Sopenharmony_ci return; 3344141cc406Sopenharmony_ci } 3345141cc406Sopenharmony_ci 3346141cc406Sopenharmony_ci if (n == 1) 3347141cc406Sopenharmony_ci { 3348141cc406Sopenharmony_ci fd = SD_LISTEN_FDS_START + 0; 3349141cc406Sopenharmony_ci DBG (DBG_INFO, "run_inetd: Using systemd socket %d!\n", fd); 3350141cc406Sopenharmony_ci } 3351141cc406Sopenharmony_ci#endif 3352141cc406Sopenharmony_ci 3353141cc406Sopenharmony_ci if (fd == -1) 3354141cc406Sopenharmony_ci { 3355141cc406Sopenharmony_ci int dave_null; 3356141cc406Sopenharmony_ci 3357141cc406Sopenharmony_ci /* Some backends really can't keep their dirty fingers off 3358141cc406Sopenharmony_ci * stdin/stdout/stderr; we work around them here so they don't 3359141cc406Sopenharmony_ci * mess up the network dialog and crash the remote net backend 3360141cc406Sopenharmony_ci * by messing with the inetd socket. 3361141cc406Sopenharmony_ci * For systemd this not an issue as systemd uses fd >= 3 for the 3362141cc406Sopenharmony_ci * socket and can even redirect stdout and stderr to syslog. 3363141cc406Sopenharmony_ci * We can even use this to get the debug logging 3364141cc406Sopenharmony_ci */ 3365141cc406Sopenharmony_ci do 3366141cc406Sopenharmony_ci { 3367141cc406Sopenharmony_ci /* get new fd for the inetd socket */ 3368141cc406Sopenharmony_ci fd = dup (1); 3369141cc406Sopenharmony_ci 3370141cc406Sopenharmony_ci if (fd == -1) 3371141cc406Sopenharmony_ci { 3372141cc406Sopenharmony_ci DBG (DBG_ERR, "run_inetd: duplicating fd failed: %s", strerror (errno)); 3373141cc406Sopenharmony_ci return; 3374141cc406Sopenharmony_ci } 3375141cc406Sopenharmony_ci } 3376141cc406Sopenharmony_ci while (fd < 3); 3377141cc406Sopenharmony_ci 3378141cc406Sopenharmony_ci /* Our good'ole friend Dave Null to the rescue */ 3379141cc406Sopenharmony_ci dave_null = open ("/dev/null", O_RDWR); 3380141cc406Sopenharmony_ci if (dave_null < 0) 3381141cc406Sopenharmony_ci { 3382141cc406Sopenharmony_ci DBG (DBG_ERR, "run_inetd: could not open /dev/null: %s", strerror (errno)); 3383141cc406Sopenharmony_ci return; 3384141cc406Sopenharmony_ci } 3385141cc406Sopenharmony_ci 3386141cc406Sopenharmony_ci close (STDIN_FILENO); 3387141cc406Sopenharmony_ci close (STDOUT_FILENO); 3388141cc406Sopenharmony_ci close (STDERR_FILENO); 3389141cc406Sopenharmony_ci 3390141cc406Sopenharmony_ci dup2 (dave_null, STDIN_FILENO); 3391141cc406Sopenharmony_ci dup2 (dave_null, STDOUT_FILENO); 3392141cc406Sopenharmony_ci dup2 (dave_null, STDERR_FILENO); 3393141cc406Sopenharmony_ci 3394141cc406Sopenharmony_ci close (dave_null); 3395141cc406Sopenharmony_ci } 3396141cc406Sopenharmony_ci#ifdef HAVE_OS2_H 3397141cc406Sopenharmony_ci /* under OS/2, the socket handle is passed as argument on the command 3398141cc406Sopenharmony_ci line; the socket handle is relative to IBM TCP/IP, so a call 3399141cc406Sopenharmony_ci to impsockethandle() is required to add it to the EMX runtime */ 3400141cc406Sopenharmony_ci if (sock) 3401141cc406Sopenharmony_ci { 3402141cc406Sopenharmony_ci fd = _impsockhandle (atoi (sock), 0); 3403141cc406Sopenharmony_ci if (fd == -1) 3404141cc406Sopenharmony_ci perror ("impsockhandle"); 3405141cc406Sopenharmony_ci } 3406141cc406Sopenharmony_ci#endif /* HAVE_OS2_H */ 3407141cc406Sopenharmony_ci 3408141cc406Sopenharmony_ci handle_connection(fd); 3409141cc406Sopenharmony_ci} 3410141cc406Sopenharmony_ci 3411141cc406Sopenharmony_cistatic void usage(char *me, int err) 3412141cc406Sopenharmony_ci{ 3413141cc406Sopenharmony_ci fprintf (stderr, 3414141cc406Sopenharmony_ci "Usage: %s [OPTIONS]\n\n" 3415141cc406Sopenharmony_ci " Options:\n\n" 3416141cc406Sopenharmony_ci " -a, --alone[=user] equal to `-l -D -u user'\n" 3417141cc406Sopenharmony_ci " -l, --listen run in standalone mode (listen for connection)\n" 3418141cc406Sopenharmony_ci " -u, --user=user run as `user'\n" 3419141cc406Sopenharmony_ci " -D, --daemonize run in background\n" 3420141cc406Sopenharmony_ci " -o, --once exit after first client disconnects\n" 3421141cc406Sopenharmony_ci " -d, --debug=level set debug level `level' (default is 2)\n" 3422141cc406Sopenharmony_ci " -e, --stderr output to stderr\n" 3423141cc406Sopenharmony_ci " -b, --bind=addr bind address `addr' (default all interfaces)\n" 3424141cc406Sopenharmony_ci " -p, --port=port bind port `port` (default sane-port or 6566)\n" 3425141cc406Sopenharmony_ci " -h, --help show this help message and exit\n", me); 3426141cc406Sopenharmony_ci 3427141cc406Sopenharmony_ci exit(err); 3428141cc406Sopenharmony_ci} 3429141cc406Sopenharmony_ci 3430141cc406Sopenharmony_cistatic int debug; 3431141cc406Sopenharmony_ci 3432141cc406Sopenharmony_cistatic struct option long_options[] = 3433141cc406Sopenharmony_ci{ 3434141cc406Sopenharmony_ci/* These options set a flag. */ 3435141cc406Sopenharmony_ci {"help", no_argument, 0, 'h'}, 3436141cc406Sopenharmony_ci {"alone", optional_argument, 0, 'a'}, 3437141cc406Sopenharmony_ci {"listen", no_argument, 0, 'l'}, 3438141cc406Sopenharmony_ci {"user", required_argument, 0, 'u'}, 3439141cc406Sopenharmony_ci {"daemonize", no_argument, 0, 'D'}, 3440141cc406Sopenharmony_ci {"once", no_argument, 0, 'o'}, 3441141cc406Sopenharmony_ci {"debug", required_argument, 0, 'd'}, 3442141cc406Sopenharmony_ci {"stderr", no_argument, 0, 'e'}, 3443141cc406Sopenharmony_ci {"bind", required_argument, 0, 'b'}, 3444141cc406Sopenharmony_ci {"port", required_argument, 0, 'p'}, 3445141cc406Sopenharmony_ci {0, 0, 0, 0 } 3446141cc406Sopenharmony_ci}; 3447141cc406Sopenharmony_ci 3448141cc406Sopenharmony_ciint 3449141cc406Sopenharmony_cimain (int argc, char *argv[]) 3450141cc406Sopenharmony_ci{ 3451141cc406Sopenharmony_ci char options[64] = ""; 3452141cc406Sopenharmony_ci char *user = NULL; 3453141cc406Sopenharmony_ci char *sock = NULL; 3454141cc406Sopenharmony_ci int c; 3455141cc406Sopenharmony_ci int long_index = 0; 3456141cc406Sopenharmony_ci 3457141cc406Sopenharmony_ci debug = DBG_WARN; 3458141cc406Sopenharmony_ci 3459141cc406Sopenharmony_ci prog_name = strrchr (argv[0], '/'); 3460141cc406Sopenharmony_ci if (prog_name) 3461141cc406Sopenharmony_ci ++prog_name; 3462141cc406Sopenharmony_ci else 3463141cc406Sopenharmony_ci prog_name = argv[0]; 3464141cc406Sopenharmony_ci 3465141cc406Sopenharmony_ci numchildren = 0; 3466141cc406Sopenharmony_ci run_mode = SANED_RUN_INETD; 3467141cc406Sopenharmony_ci run_foreground = SANE_TRUE; 3468141cc406Sopenharmony_ci run_once = SANE_FALSE; 3469141cc406Sopenharmony_ci 3470141cc406Sopenharmony_ci while((c = getopt_long(argc, argv,"ha::lu:Dod:eb:p:", long_options, &long_index )) != -1) 3471141cc406Sopenharmony_ci { 3472141cc406Sopenharmony_ci switch(c) { 3473141cc406Sopenharmony_ci case 'a': 3474141cc406Sopenharmony_ci run_mode = SANED_RUN_ALONE; 3475141cc406Sopenharmony_ci run_foreground = SANE_FALSE; 3476141cc406Sopenharmony_ci if (optarg) 3477141cc406Sopenharmony_ci user = optarg; 3478141cc406Sopenharmony_ci break; 3479141cc406Sopenharmony_ci case 'l': 3480141cc406Sopenharmony_ci run_mode = SANED_RUN_ALONE; 3481141cc406Sopenharmony_ci break; 3482141cc406Sopenharmony_ci case 'u': 3483141cc406Sopenharmony_ci user = optarg; 3484141cc406Sopenharmony_ci break; 3485141cc406Sopenharmony_ci case 'D': 3486141cc406Sopenharmony_ci run_foreground = SANE_FALSE; 3487141cc406Sopenharmony_ci break; 3488141cc406Sopenharmony_ci case 'o': 3489141cc406Sopenharmony_ci run_once = SANE_TRUE; 3490141cc406Sopenharmony_ci break; 3491141cc406Sopenharmony_ci case 'd': 3492141cc406Sopenharmony_ci debug = atoi(optarg); 3493141cc406Sopenharmony_ci break; 3494141cc406Sopenharmony_ci case 'e': 3495141cc406Sopenharmony_ci log_to_syslog = SANE_FALSE; 3496141cc406Sopenharmony_ci break; 3497141cc406Sopenharmony_ci case 'b': 3498141cc406Sopenharmony_ci bind_addr = optarg; 3499141cc406Sopenharmony_ci break; 3500141cc406Sopenharmony_ci case 'p': 3501141cc406Sopenharmony_ci bind_port = atoi(optarg); 3502141cc406Sopenharmony_ci break; 3503141cc406Sopenharmony_ci case 'h': 3504141cc406Sopenharmony_ci usage(argv[0], EXIT_SUCCESS); 3505141cc406Sopenharmony_ci break; 3506141cc406Sopenharmony_ci default: 3507141cc406Sopenharmony_ci usage(argv[0], EXIT_FAILURE); 3508141cc406Sopenharmony_ci break; 3509141cc406Sopenharmony_ci } 3510141cc406Sopenharmony_ci } 3511141cc406Sopenharmony_ci 3512141cc406Sopenharmony_ci if (log_to_syslog) 3513141cc406Sopenharmony_ci openlog ("saned", LOG_PID | LOG_CONS, LOG_DAEMON); 3514141cc406Sopenharmony_ci 3515141cc406Sopenharmony_ci read_config (); 3516141cc406Sopenharmony_ci 3517141cc406Sopenharmony_ci byte_order.w = 0; 3518141cc406Sopenharmony_ci byte_order.ch = 1; 3519141cc406Sopenharmony_ci 3520141cc406Sopenharmony_ci sanei_w_init (&wire, sanei_codec_bin_init); 3521141cc406Sopenharmony_ci wire.io.read = read; 3522141cc406Sopenharmony_ci wire.io.write = write; 3523141cc406Sopenharmony_ci 3524141cc406Sopenharmony_ci#ifdef SANED_USES_AF_INDEP 3525141cc406Sopenharmony_ci strcat(options, "AF-indep"); 3526141cc406Sopenharmony_ci# ifdef ENABLE_IPV6 3527141cc406Sopenharmony_ci strcat(options, "+IPv6"); 3528141cc406Sopenharmony_ci#endif 3529141cc406Sopenharmony_ci#else 3530141cc406Sopenharmony_ci strcat(options, "IPv4 only"); 3531141cc406Sopenharmony_ci#endif 3532141cc406Sopenharmony_ci#ifdef HAVE_SYSTEMD 3533141cc406Sopenharmony_ci if (sd_listen_fds(0) > 0) 3534141cc406Sopenharmony_ci { 3535141cc406Sopenharmony_ci strcat(options, "+systemd"); 3536141cc406Sopenharmony_ci } 3537141cc406Sopenharmony_ci#endif 3538141cc406Sopenharmony_ci 3539141cc406Sopenharmony_ci if (strlen(options) > 0) 3540141cc406Sopenharmony_ci { 3541141cc406Sopenharmony_ci DBG (DBG_WARN, "saned (%s) from %s starting up\n", options, PACKAGE_STRING); 3542141cc406Sopenharmony_ci } 3543141cc406Sopenharmony_ci else 3544141cc406Sopenharmony_ci { 3545141cc406Sopenharmony_ci DBG (DBG_WARN, "saned from %s ready\n", PACKAGE_STRING); 3546141cc406Sopenharmony_ci } 3547141cc406Sopenharmony_ci 3548141cc406Sopenharmony_ci if (run_mode == SANED_RUN_ALONE) 3549141cc406Sopenharmony_ci { 3550141cc406Sopenharmony_ci run_standalone(user); 3551141cc406Sopenharmony_ci } 3552141cc406Sopenharmony_ci else 3553141cc406Sopenharmony_ci { 3554141cc406Sopenharmony_ci#ifdef HAVE_OS2_H 3555141cc406Sopenharmony_ci if (argc == 2) 3556141cc406Sopenharmony_ci sock = argv[1]; 3557141cc406Sopenharmony_ci#endif 3558141cc406Sopenharmony_ci run_inetd(sock); 3559141cc406Sopenharmony_ci } 3560141cc406Sopenharmony_ci 3561141cc406Sopenharmony_ci DBG (DBG_WARN, "saned exiting\n"); 3562141cc406Sopenharmony_ci 3563141cc406Sopenharmony_ci return 0; 3564141cc406Sopenharmony_ci} 3565