summaryrefslogtreecommitdiff
path: root/frontend/saned.c
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/saned.c')
-rw-r--r--frontend/saned.c530
1 files changed, 316 insertions, 214 deletions
diff --git a/frontend/saned.c b/frontend/saned.c
index 3bb99bb..ac5e700 100644
--- a/frontend/saned.c
+++ b/frontend/saned.c
@@ -87,7 +87,7 @@
#if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
# include <sys/poll.h>
#else
-/*
+/*
* This replacement poll() using select() is only designed to cover
* our needs in run_standalone(). It should probably be extended...
*/
@@ -203,13 +203,13 @@ static AvahiEntryGroup *avahi_group = NULL;
(((const uint32_t *) (a))[0] == 0 \
&& ((const uint32_t *) (a))[1] == 0 \
&& ((const uint32_t *) (a))[2] == 0 \
- && ((const uint32_t *) (a))[3] == htonl (1))
+ && ((const uint32_t *) (a))[3] == htonl (1))
# endif
# ifndef IN6_IS_ADDR_V4MAPPED
# define IN6_IS_ADDR_V4MAPPED(a) \
((((const uint32_t *) (a))[0] == 0) \
&& (((const uint32_t *) (a))[1] == 0) \
- && (((const uint32_t *) (a))[2] == htonl (0xffff)))
+ && (((const uint32_t *) (a))[2] == htonl (0xffff)))
# endif
#endif /* ENABLE_IPV6 */
@@ -251,6 +251,9 @@ static Wire wire;
static int num_handles;
static int debug;
static int run_mode;
+static int run_foreground;
+static int run_once;
+static int data_connect_timeout = 4000;
static Handle *handle;
static char *bind_addr;
static union
@@ -298,9 +301,7 @@ static SANE_Bool log_to_syslog = SANE_TRUE;
static int process_request (Wire * w);
#define SANED_RUN_INETD 0
-#define SANED_RUN_DEBUG 1
-#define SANED_RUN_ALONE 2
-
+#define SANED_RUN_ALONE 1
#define DBG_ERR 1
#define DBG_WARN 2
@@ -402,7 +403,7 @@ auth_callback (SANE_String_Const res,
break;
default:
- DBG (DBG_WARN,
+ DBG (DBG_WARN,
"auth_callback: called for unexpected request %d (resource=%s)\n",
current_request, res);
break;
@@ -430,7 +431,7 @@ auth_callback (SANE_String_Const res,
{
DBG (DBG_WARN,
"auth_callback: bad procedure number %d "
- "(expected: %d, resource=%s)\n", procnum, SANE_NET_AUTHORIZE,
+ "(expected: %d, resource=%s)\n", procnum, SANE_NET_AUTHORIZE,
res);
return;
}
@@ -565,7 +566,7 @@ check_v4_in_range (struct sockaddr_in *sin, char *base_ip, char *netmask)
int cidr;
int i, err;
char *end;
- uint32_t mask;
+ uint32_t mask;
struct sockaddr_in *base;
struct addrinfo hints;
struct addrinfo *res;
@@ -573,7 +574,7 @@ check_v4_in_range (struct sockaddr_in *sin, char *base_ip, char *netmask)
cidr = -1;
cidr = strtol (netmask, &end, 10);
-
+
/* Sanity check on the cidr value */
if ((cidr < 0) || (cidr > 32) || (end == netmask))
{
@@ -584,13 +585,13 @@ check_v4_in_range (struct sockaddr_in *sin, char *base_ip, char *netmask)
mask = 0;
cidr -= 8;
- /* Build a bitmask out of the CIDR value */
+ /* Build a bitmask out of the CIDR value */
for (i = 3; cidr >= 0; i--)
{
mask |= (0xff << (8 * i));
cidr -= 8;
}
-
+
if (cidr < 0)
mask |= (cidrtomask[cidr + 8] << (8 * i));
@@ -600,7 +601,7 @@ check_v4_in_range (struct sockaddr_in *sin, char *base_ip, char *netmask)
memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = PF_INET;
-
+
err = getaddrinfo (base_ip, NULL, &hints, &res);
if (err)
{
@@ -616,9 +617,9 @@ check_v4_in_range (struct sockaddr_in *sin, char *base_ip, char *netmask)
*/
if ((base->sin_addr.s_addr & mask) == (sin->sin_addr.s_addr & mask))
ret = SANE_TRUE;
-
+
freeaddrinfo (res);
-
+
return ret;
}
@@ -649,17 +650,17 @@ check_v6_in_range (struct sockaddr_in6 *sin6, char *base_ip, char *netmask)
memset (mask, 0, (16 * sizeof (unsigned int)));
cidr -= 8;
-
+
/* Build a bitmask out of the CIDR value */
for (i = 0; cidr >= 0; i++)
{
mask[i] = 0xff;
cidr -= 8;
}
-
+
if (cidr < 0)
mask[i] = cidrtomask[cidr + 8];
-
+
/* get a sockaddr_in6 representing the base IP address */
memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_flags = AI_NUMERICHOST;
@@ -686,9 +687,9 @@ check_v6_in_range (struct sockaddr_in6 *sin6, char *base_ip, char *netmask)
break;
}
}
-
+
freeaddrinfo (res);
-
+
return ret;
}
# endif /* ENABLE_IPV6 */
@@ -699,12 +700,12 @@ check_v4_in_range (struct in_addr *inaddr, struct in_addr *base, char *netmask)
int cidr;
int i;
char *end;
- uint32_t mask;
+ uint32_t mask;
SANE_Bool ret = SANE_FALSE;
cidr = -1;
cidr = strtol (netmask, &end, 10);
-
+
/* sanity check on the cidr value */
if ((cidr < 0) || (cidr > 32) || (end == netmask))
{
@@ -714,14 +715,14 @@ check_v4_in_range (struct in_addr *inaddr, struct in_addr *base, char *netmask)
mask = 0;
cidr -= 8;
-
+
/* Build a bitmask out of the CIDR value */
for (i = 3; cidr >= 0; i--)
{
mask |= (0xff << (8 * i));
cidr -= 8;
}
-
+
if (cidr < 0)
mask |= (cidrtomask[cidr + 8] << (8 * i));
@@ -733,7 +734,7 @@ check_v4_in_range (struct in_addr *inaddr, struct in_addr *base, char *netmask)
*/
if ((base->s_addr & mask) == (inaddr->s_addr & mask))
ret = SANE_TRUE;
-
+
return ret;
}
#endif /* SANED_USES_AF_INDEP */
@@ -801,7 +802,7 @@ check_host (int fd)
memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = PF_INET;
-
+
err = getaddrinfo (remote_ipv4, NULL, &hints, &res);
if (err)
{
@@ -901,13 +902,13 @@ check_host (int fd)
{
DBG (DBG_DBG, "check_host: local hostname(s) (from DNS): %s\n",
resp->ai_canonname);
-
+
err = getnameinfo (resp->ai_addr, resp->ai_addrlen, text_addr,
sizeof (text_addr), NULL, 0, NI_NUMERICHOST);
if (err)
strncpy (text_addr, "[error]", 8);
-#ifdef ENABLE_IPV6
+#ifdef ENABLE_IPV6
if ((strcasecmp (text_addr, remote_ip) == 0) ||
((IPv4map == SANE_TRUE) && (strcmp (text_addr, remote_ipv4) == 0)))
#else
@@ -915,18 +916,18 @@ check_host (int fd)
#endif /* ENABLE_IPV6 */
{
DBG (DBG_MSG, "check_host: remote host has same addr as local: access granted\n");
-
+
freeaddrinfo (res);
res = NULL;
return SANE_STATUS_GOOD;
}
}
-
+
freeaddrinfo (res);
res = NULL;
-
- DBG (DBG_DBG,
+
+ DBG (DBG_DBG,
"check_host: remote host doesn't have same addr as local\n");
}
@@ -947,8 +948,8 @@ check_host (int fd)
config_file_names[j], strerror (errno));
continue;
}
-
- while (!access_ok && sanei_config_read (config_line_buf,
+
+ while (!access_ok && sanei_config_read (config_line_buf,
sizeof (config_line_buf), fp))
{
config_line = config_line_buf; /* from now on, use a pointer */
@@ -993,7 +994,7 @@ check_host (int fd)
if (strcmp (config_line, "+") == 0)
{
access_ok = 1;
- DBG (DBG_DBG,
+ DBG (DBG_DBG,
"check_host: access granted from any host (`+')\n");
}
/* compare remote_ip (remote IP address) to the config_line */
@@ -1033,7 +1034,7 @@ check_host (int fd)
memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = PF_INET;
-
+
err = getaddrinfo (remote_ipv4, NULL, &hints, &res);
if (err)
DBG (DBG_DBG, "check_host: getaddrinfo() failed: %s\n", gai_strerror (err));
@@ -1044,7 +1045,7 @@ check_host (int fd)
if ((SS_FAMILY(remote_address.ss) == AF_INET) ||
(IPv4map == SANE_TRUE))
{
-
+
if (check_v4_in_range (sin, config_line, netmask))
{
DBG (DBG_DBG, "check_host: access granted from IP address %s (in subnet %s/%s)\n",
@@ -1056,7 +1057,7 @@ check_host (int fd)
/* restore the old sin pointer */
sin = &remote_address.sin;
}
-
+
if (res != NULL)
{
freeaddrinfo (res);
@@ -1086,11 +1087,11 @@ check_host (int fd)
#else
hints.ai_family = PF_INET;
#endif /* ENABLE_IPV6 */
-
+
err = getaddrinfo (config_line, NULL, &hints, &res);
if (err)
{
- DBG (DBG_DBG,
+ DBG (DBG_DBG,
"check_host: getaddrinfo for `%s' failed: %s\n",
config_line, gai_strerror (err));
DBG (DBG_MSG, "check_host: entry isn't an IP address "
@@ -1105,19 +1106,19 @@ check_host (int fd)
sizeof (text_addr), NULL, 0, NI_NUMERICHOST);
if (err)
strncpy (text_addr, "[error]", 8);
-
- DBG (DBG_MSG,
- "check_host: DNS lookup returns IP address: %s\n",
- text_addr);
-
-#ifdef ENABLE_IPV6
+
+ DBG (DBG_MSG,
+ "check_host: DNS lookup returns IP address: %s\n",
+ text_addr);
+
+#ifdef ENABLE_IPV6
if ((strcasecmp (text_addr, remote_ip) == 0) ||
((IPv4map == SANE_TRUE) && (strcmp (text_addr, remote_ipv4) == 0)))
#else
if (strcmp (text_addr, remote_ip) == 0)
#endif /* ENABLE_IPV6 */
access_ok = 1;
-
+
if (access_ok)
break;
}
@@ -1128,10 +1129,10 @@ check_host (int fd)
}
fclose (fp);
}
-
+
if (access_ok)
return SANE_STATUS_GOOD;
-
+
return SANE_STATUS_ACCESS_DENIED;
}
@@ -1150,7 +1151,7 @@ check_host (int fd)
char hostname[MAXHOSTNAMELEN];
char *r_hostname;
static struct in_addr config_line_address;
-
+
int len;
FILE *fp;
@@ -1164,7 +1165,7 @@ check_host (int fd)
}
r_hostname = inet_ntoa (sin.sin_addr);
remote_ip = strdup (r_hostname);
- DBG (DBG_WARN, "check_host: access by remote host: %s\n",
+ DBG (DBG_WARN, "check_host: access by remote host: %s\n",
remote_ip);
/* Save remote address for check of control and data connections */
memcpy (&remote_address, &sin.sin_addr, sizeof (remote_address));
@@ -1203,7 +1204,7 @@ check_host (int fd)
{
DBG (DBG_DBG, "check_host: local hostname (from DNS): %s\n",
he->h_name);
-
+
if ((he->h_length == 4) || (he->h_addrtype == AF_INET))
{
if (!inet_ntop (he->h_addrtype, he->h_addr_list[0], text_addr,
@@ -1211,9 +1212,9 @@ check_host (int fd)
strcpy (text_addr, "[error]");
DBG (DBG_DBG, "check_host: local host address (from DNS): %s\n",
text_addr);
- if (memcmp (he->h_addr_list[0], &remote_address.s_addr, 4) == 0)
+ if (memcmp (he->h_addr_list[0], &remote_address.s_addr, 4) == 0)
{
- DBG (DBG_MSG,
+ DBG (DBG_MSG,
"check_host: remote host has same addr as local: "
"access accepted\n");
return SANE_STATUS_GOOD;
@@ -1246,8 +1247,8 @@ check_host (int fd)
config_file_names[j], strerror (errno));
continue;
}
-
- while (!access_ok && sanei_config_read (config_line_buf,
+
+ while (!access_ok && sanei_config_read (config_line_buf,
sizeof (config_line_buf), fp))
{
config_line = config_line_buf; /* from now on, use a pointer */
@@ -1275,14 +1276,14 @@ check_host (int fd)
if (strcmp (config_line, "+") == 0)
{
access_ok = 1;
- DBG (DBG_DBG,
+ DBG (DBG_DBG,
"check_host: access accepted from any host (`+')\n");
}
else
{
if (inet_pton (AF_INET, config_line, &config_line_address) > 0)
{
- if (memcmp (&remote_address.s_addr,
+ if (memcmp (&remote_address.s_addr,
&config_line_address.s_addr, 4) == 0)
access_ok = 1;
else if (netmask != NULL)
@@ -1297,13 +1298,13 @@ check_host (int fd)
}
else
{
- DBG (DBG_DBG,
+ DBG (DBG_DBG,
"check_host: inet_pton for `%s' failed\n",
config_line);
he = gethostbyname (config_line);
if (!he)
{
- DBG (DBG_DBG,
+ DBG (DBG_DBG,
"check_host: gethostbyname for `%s' failed: %s\n",
config_line, hstrerror (h_errno));
DBG (DBG_MSG, "check_host: entry isn't an IP address "
@@ -1313,10 +1314,10 @@ check_host (int fd)
if (!inet_ntop (he->h_addrtype, he->h_addr_list[0],
text_addr, sizeof (text_addr)))
strcpy (text_addr, "[error]");
- DBG (DBG_MSG,
+ DBG (DBG_MSG,
"check_host: DNS lookup returns IP address: %s\n",
text_addr);
- if (memcmp (&remote_address.s_addr,
+ if (memcmp (&remote_address.s_addr,
he->h_addr_list[0], 4) == 0)
access_ok = 1;
}
@@ -1356,7 +1357,7 @@ init (Wire * w)
DBG (DBG_ERR, "init: bad status after sanei_w_set_dir: %d\n", w->status);
return -1;
}
-
+
sanei_w_word (w, &word); /* decode procedure number */
if (w->status || word != SANE_NET_INIT)
{
@@ -1658,7 +1659,7 @@ do_scan (Wire * w, int h, int data_fd)
long int nwritten;
SANE_Int length;
size_t nbytes;
-
+
DBG (3, "do_scan: start\n");
FD_ZERO (&rd_mask);
@@ -1699,8 +1700,8 @@ do_scan (Wire * w, int h, int data_fd)
FD_CLR (be_fd, &rd_mask);
be_fd = -1;
/* only set status_dirty if EOF hasn't been already detected */
- if (status == SANE_STATUS_GOOD)
- status_dirty = 1;
+ if (status == SANE_STATUS_GOOD)
+ status_dirty = 1;
status = SANE_STATUS_EOF;
DBG (DBG_INFO, "do_scan: select_fd was closed --> EOF\n");
continue;
@@ -1723,17 +1724,18 @@ do_scan (Wire * w, int h, int data_fd)
nbytes = bytes_in_buf;
if (writer + nbytes > sizeof (buf))
nbytes = sizeof (buf) - writer;
- DBG (DBG_INFO,
+ DBG (DBG_INFO,
"do_scan: trying to write %d bytes to client\n",
nbytes);
nwritten = write (data_fd, buf + writer, nbytes);
- DBG (DBG_INFO,
+ DBG (DBG_INFO,
"do_scan: wrote %ld bytes to client\n", nwritten);
if (nwritten < 0)
{
DBG (DBG_ERR, "do_scan: write failed (%s)\n",
strerror (errno));
status = SANE_STATUS_CANCELLED;
+ handle[h].docancel = 1;
break;
}
bytes_in_buf -= nwritten;
@@ -1791,7 +1793,7 @@ do_scan (Wire * w, int h, int data_fd)
reader = store_reclen (buf, sizeof (buf), reader, 0xffffffff);
buf[reader] = status;
bytes_in_buf += 5;
- DBG (DBG_MSG, "do_scan: statuscode `%s' was added to buffer\n",
+ DBG (DBG_MSG, "do_scan: statuscode `%s' was added to buffer\n",
sane_strstatus(status));
}
@@ -1799,13 +1801,19 @@ do_scan (Wire * w, int h, int data_fd)
{
DBG (DBG_MSG,
"do_scan: processing RPC request on fd %d\n", w->io.fd);
- process_request (w);
+ if(process_request (w) < 0)
+ handle[h].docancel = 1;
+
if (handle[h].docancel)
break;
}
}
while (status == SANE_STATUS_GOOD || bytes_in_buf > 0 || status_dirty);
DBG (DBG_MSG, "do_scan: done, status=%s\n", sane_strstatus (status));
+
+ if(handle[h].docancel)
+ sane_cancel (handle[h].handle);
+
handle[h].docancel = 0;
handle[h].scanning = 0;
}
@@ -1854,7 +1862,7 @@ process_request (Wire * w)
sanei_w_string (w, &name);
if (w->status)
{
- DBG (DBG_ERR,
+ DBG (DBG_ERR,
"process_request: (open) error while decoding args (%s)\n",
strerror (w->status));
return 1;
@@ -1871,7 +1879,7 @@ process_request (Wire * w)
can_authorize = 1;
resource = strdup (name);
-
+
if (strlen(resource) == 0) {
const SANE_Device **device_list;
@@ -1879,8 +1887,8 @@ process_request (Wire * w)
DBG(DBG_DBG, "process_request: (open) strlen(resource) == 0\n");
free (resource);
- if ((i = sane_get_devices (&device_list, SANE_TRUE)) !=
- SANE_STATUS_GOOD)
+ if ((i = sane_get_devices (&device_list, SANE_TRUE)) !=
+ SANE_STATUS_GOOD)
{
DBG(DBG_ERR, "process_request: (open) sane_get_devices failed\n");
memset (&reply, 0, sizeof (reply));
@@ -1889,7 +1897,7 @@ process_request (Wire * w)
break;
}
- if ((device_list == NULL) || (device_list[0] == NULL))
+ if ((device_list == NULL) || (device_list[0] == NULL))
{
DBG(DBG_ERR, "process_request: (open) device_list[0] == 0\n");
memset (&reply, 0, sizeof (reply));
@@ -1907,7 +1915,7 @@ process_request (Wire * w)
if (sanei_authorize (resource, "saned", auth_callback) !=
SANE_STATUS_GOOD)
{
- DBG (DBG_ERR, "process_request: access to resource `%s' denied\n",
+ DBG (DBG_ERR, "process_request: access to resource `%s' denied\n",
resource);
free (resource);
memset (&reply, 0, sizeof (reply)); /* avoid leaking bits */
@@ -1915,12 +1923,12 @@ process_request (Wire * w)
}
else
{
- DBG (DBG_MSG, "process_request: access to resource `%s' granted\n",
+ DBG (DBG_MSG, "process_request: access to resource `%s' granted\n",
resource);
free (resource);
memset (&reply, 0, sizeof (reply)); /* avoid leaking bits */
reply.status = sane_open (name, &be_handle);
- DBG (DBG_MSG, "process_request: sane_open returned: %s\n",
+ DBG (DBG_MSG, "process_request: sane_open returned: %s\n",
sane_strstatus (reply.status));
}
@@ -2062,7 +2070,7 @@ process_request (Wire * w)
case SANE_NET_START:
{
SANE_Start_Reply reply;
- int fd = -1, data_fd;
+ int fd = -1, data_fd = -1;
h = decode_handle (w, "start");
if (h < 0)
@@ -2087,9 +2095,36 @@ process_request (Wire * w)
char text_addr[64];
int len;
int error;
+ struct pollfd fds[1];
+ int ret;
- DBG (DBG_MSG, "process_request: waiting for data connection\n");
- data_fd = accept (fd, 0, 0);
+ fds->fd = fd;
+ fds->events = POLLIN;
+
+ DBG (DBG_MSG, "process_request: waiting 4s for data connection\n");
+ if(data_connect_timeout)
+ {
+ while (1)
+ {
+ ret = poll (fds, 1, data_connect_timeout);
+ if (ret < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ else
+ {
+ DBG (DBG_ERR, "run_standalone: poll failed: %s\n",
+ strerror (errno));
+ }
+ break;
+ }
+ break;
+ }
+ }
+ else
+ ret = 0;
+ if(ret >= 0)
+ data_fd = accept (fd, 0, 0);
close (fd);
/* Get address of remote host */
@@ -2112,7 +2147,7 @@ process_request (Wire * w)
DBG (DBG_MSG, "process_request: access to data port from %s\n",
text_addr);
-
+
if (strcmp (text_addr, remote_ip) != 0)
{
DBG (DBG_ERR, "process_request: however, only %s is authorized\n",
@@ -2129,14 +2164,41 @@ process_request (Wire * w)
{
struct sockaddr_in sin;
int len;
+ int ret;
+ struct pollfd fds[1];
+
+ fds->fd = fd;
+ fds->events = POLLIN;
DBG (DBG_MSG, "process_request: waiting for data connection\n");
- data_fd = accept (fd, 0, 0);
+ if(data_connect_timeout)
+ {
+ while (1)
+ {
+ ret = poll (fds, 1, data_connect_timeout);
+ if (ret < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ else
+ {
+ DBG (DBG_ERR, "run_standalone: poll failed: %s\n", strerror (errno));
+ }
+ break;
+ }
+ break;
+ }
+ }
+ else
+ ret = 0;
+ if(ret >= 0)
+ data_fd = accept (fd, 0, 0);
+
close (fd);
/* Get address of remote host */
len = sizeof (sin);
- if (getpeername (data_fd, (struct sockaddr *) &sin,
+ if (getpeername (data_fd, (struct sockaddr *) &sin,
(socklen_t *) &len) < 0)
{
DBG (DBG_ERR, "process_request: getpeername failed: %s\n",
@@ -2147,13 +2209,13 @@ process_request (Wire * w)
if (memcmp (&remote_address, &sin.sin_addr,
sizeof (remote_address)) != 0)
{
- DBG (DBG_ERR,
+ DBG (DBG_ERR,
"process_request: access to data port from %s\n",
inet_ntoa (sin.sin_addr));
- DBG (DBG_ERR,
+ DBG (DBG_ERR,
"process_request: however, only %s is authorized\n",
inet_ntoa (remote_address));
- DBG (DBG_ERR,
+ DBG (DBG_ERR,
"process_request: configuration problem or attack?\n");
close (data_fd);
data_fd = -1;
@@ -2320,7 +2382,7 @@ handle_connection (int fd)
reset_watchdog ();
if (process_request (&wire) < 0)
break;
- }
+ }
}
static void
@@ -2735,6 +2797,26 @@ read_config (void)
DBG (DBG_INFO, "read_config: data port range: %d - %d\n", data_port_lo, data_port_hi);
}
}
+ else if(strstr(config_line, "data_connect_timeout") != NULL)
+ {
+ optval = sanei_config_skip_whitespace (++optval);
+ if ((optval != NULL) && (*optval != '\0'))
+ {
+ val = strtol (optval, &endval, 10);
+ if (optval == endval)
+ {
+ DBG (DBG_ERR, "read_config: invalid value for data_connect_timeout\n");
+ continue;
+ }
+ else if ((val < 0) || (val > 65535))
+ {
+ DBG (DBG_ERR, "read_config: data_connect_timeout is invalid\n");
+ continue;
+ }
+ data_connect_timeout = val;
+ DBG (DBG_INFO, "read_config: data connect timeout: %d\n", data_connect_timeout);
+ }
+ }
}
fclose (fp);
DBG (DBG_INFO, "read_config: done reading config\n");
@@ -2964,93 +3046,129 @@ do_bindings (int *nfds, struct pollfd **fds)
static void
-run_standalone (char *user)
+runas_user (char *user)
{
- struct pollfd *fds = NULL;
- struct pollfd *fdp = NULL;
- int nfds;
- int fd = -1;
- int i;
- int ret;
-
uid_t runas_uid = 0;
gid_t runas_gid = 0;
struct passwd *pwent;
gid_t *grplist = NULL;
struct group *grp;
int ngroups = 0;
- FILE *pidfile;
+ int ret;
- do_bindings (&nfds, &fds);
+ pwent = getpwnam(user);
- if (run_mode != SANED_RUN_DEBUG)
+ if (pwent == NULL)
{
- if (user)
- {
- pwent = getpwnam(user);
+ DBG (DBG_ERR, "FATAL ERROR: user %s not found on system\n", user);
+ bail_out (1);
+ }
- if (pwent == NULL)
- {
- DBG (DBG_ERR, "FATAL ERROR: user %s not found on system\n", user);
- bail_out (1);
- }
+ runas_uid = pwent->pw_uid;
+ runas_gid = pwent->pw_gid;
- runas_uid = pwent->pw_uid;
- runas_gid = pwent->pw_gid;
+ /* Get group list for runas_uid */
+ grplist = (gid_t *)malloc(sizeof(gid_t));
- /* Get group list for runas_uid */
- grplist = (gid_t *)malloc(sizeof(gid_t));
+ if (grplist == NULL)
+ {
+ DBG (DBG_ERR, "FATAL ERROR: cannot allocate memory for group list\n");
- if (grplist == NULL)
- {
- DBG (DBG_ERR, "FATAL ERROR: cannot allocate memory for group list\n");
+ exit (1);
+ }
- exit (1);
- }
+ ngroups = 1;
+ grplist[0] = runas_gid;
- ngroups = 1;
- grplist[0] = runas_gid;
+ setgrent();
+ while ((grp = getgrent()) != NULL)
+ {
+ int i = 0;
- setgrent();
- while ((grp = getgrent()) != NULL)
- {
- int i = 0;
+ /* Already added current group */
+ if (grp->gr_gid == runas_gid)
+ continue;
- /* Already added current group */
- if (grp->gr_gid == runas_gid)
- continue;
+ while (grp->gr_mem[i])
+ {
+ if (strcmp(grp->gr_mem[i], user) == 0)
+ {
+ int need_to_add = 1, j;
- while (grp->gr_mem[i])
+ /* Make sure its not already in list */
+ for (j = 0; j < ngroups; j++)
{
- if (strcmp(grp->gr_mem[i], user) == 0)
- {
- int need_to_add = 1, j;
-
- /* Make sure its not already in list */
- for (j = 0; j < ngroups; j++)
- {
- if (grp->gr_gid == grplist[i])
- need_to_add = 0;
- }
- if (need_to_add)
- {
- grplist = (gid_t *)realloc(grplist,
- sizeof(gid_t)*ngroups+1);
- if (grplist == NULL)
- {
- DBG (DBG_ERR, "FATAL ERROR: cannot reallocate memory for group list\n");
-
- exit (1);
- }
- grplist[ngroups++] = grp->gr_gid;
- }
- }
- i++;
- }
+ if (grp->gr_gid == grplist[i])
+ need_to_add = 0;
+ }
+ if (need_to_add)
+ {
+ grplist = (gid_t *)realloc(grplist,
+ sizeof(gid_t)*ngroups+1);
+ if (grplist == NULL)
+ {
+ DBG (DBG_ERR, "FATAL ERROR: cannot reallocate memory for group list\n");
+
+ exit (1);
+ }
+ grplist[ngroups++] = grp->gr_gid;
+ }
}
- endgrent();
+ i++;
+ }
+ }
+ endgrent();
+
+ /* Drop privileges if requested */
+ if (runas_uid > 0)
+ {
+ ret = setgroups(ngroups, grplist);
+ if (ret < 0)
+ {
+ DBG (DBG_ERR, "FATAL ERROR: could not set group list: %s\n", strerror(errno));
+
+ exit (1);
+ }
+
+ free(grplist);
+
+ ret = setegid (runas_gid);
+ if (ret < 0)
+ {
+ DBG (DBG_ERR, "FATAL ERROR: setegid to gid %d failed: %s\n", runas_gid, strerror (errno));
+
+ exit (1);
+ }
+
+ ret = seteuid (runas_uid);
+ if (ret < 0)
+ {
+ DBG (DBG_ERR, "FATAL ERROR: seteuid to uid %d failed: %s\n", runas_uid, strerror (errno));
+
+ exit (1);
}
+ DBG (DBG_WARN, "Dropped privileges to uid %d gid %d\n", runas_uid, runas_gid);
+ }
+}
+
+
+static void
+run_standalone (char *user)
+{
+ struct pollfd *fds = NULL;
+ struct pollfd *fdp = NULL;
+ int nfds;
+ int fd = -1;
+ int i;
+ int ret;
+
+ FILE *pidfile;
+
+ do_bindings (&nfds, &fds);
+
+ if (run_foreground == SANE_FALSE)
+ {
DBG (DBG_MSG, "run_standalone: daemonizing now\n");
fd = open ("/dev/null", O_RDWR);
@@ -3093,42 +3211,13 @@ run_standalone (char *user)
setsid ();
- /* Drop privileges if requested */
- if (runas_uid > 0)
- {
- ret = setgroups(ngroups, grplist);
- if (ret < 0)
- {
- DBG (DBG_ERR, "FATAL ERROR: could not set group list: %s\n", strerror(errno));
-
- exit (1);
- }
-
- free(grplist);
-
- ret = setegid (runas_gid);
- if (ret < 0)
- {
- DBG (DBG_ERR, "FATAL ERROR: setegid to gid %d failed: %s\n", runas_gid, strerror (errno));
-
- exit (1);
- }
-
- ret = seteuid (runas_uid);
- if (ret < 0)
- {
- DBG (DBG_ERR, "FATAL ERROR: seteuid to uid %d failed: %s\n", runas_uid, strerror (errno));
-
- exit (1);
- }
-
- DBG (DBG_WARN, "Dropped privileges to uid %d gid %d\n", runas_uid, runas_gid);
- }
-
signal(SIGINT, sig_int_term_handler);
signal(SIGTERM, sig_int_term_handler);
}
+ if (user)
+ runas_user(user);
+
#ifdef WITH_AVAHI
DBG (DBG_INFO, "run_standalone: spawning Avahi process\n");
saned_avahi (fds, nfds);
@@ -3187,13 +3276,13 @@ run_standalone (char *user)
continue;
}
- if (run_mode == SANED_RUN_DEBUG)
- break; /* We have the only connection we're going to handle */
- else
- handle_client (fd);
+ handle_client (fd);
+
+ if (run_once == SANE_TRUE)
+ break; /* We have handled the only connection we're going to handle */
}
- if (run_mode == SANED_RUN_DEBUG)
+ if (run_once == SANE_TRUE)
break;
}
@@ -3201,21 +3290,13 @@ run_standalone (char *user)
close (fdp->fd);
free (fds);
-
- if (run_mode == SANED_RUN_DEBUG)
- {
- if (fd > 0)
- handle_connection (fd);
-
- bail_out(0);
- }
}
static void
run_inetd (char __sane_unused__ *sock)
{
-
+
int fd = -1;
#ifdef HAVE_SYSTEMD
@@ -3223,7 +3304,7 @@ run_inetd (char __sane_unused__ *sock)
n = sd_listen_fds(0);
- if (n > 1)
+ if (n > 1)
{
DBG (DBG_ERR, "run_inetd: Too many file descriptors (sockets) received from systemd!\n");
return;
@@ -3236,7 +3317,7 @@ run_inetd (char __sane_unused__ *sock)
}
#endif
- if (fd == -1)
+ if (fd == -1)
{
int dave_null;
@@ -3299,12 +3380,14 @@ static void usage(char *me, int err)
fprintf (stderr,
"Usage: %s [OPTIONS]\n\n"
" Options:\n\n"
- " -a, --alone[=user] run standalone and fork in background as `user'\n"
- " -d, --debug[=level] run foreground with output to stdout\n"
- " and debug level `level' (default is 2)\n"
- " -s, --syslog[=level] run foreground with output to syslog\n"
- " and debug level `level' (default is 2)\n"
- " -b, --bind=addr bind address `addr'\n"
+ " -a, --alone[=user] equal to `-l -D -u user'\n"
+ " -l, --listen run in standalone mode (listen for connection)\n"
+ " -u, --user=user run as `user'\n"
+ " -D, --daemonize run in background\n"
+ " -o, --once exit after first client disconnects\n"
+ " -d, --debug=level set debug level `level' (default is 2)\n"
+ " -e, --stderr output to stderr\n"
+ " -b, --bind=addr bind address `addr' (default all interfaces)\n"
" -h, --help show this help message and exit\n", me);
exit(err);
@@ -3317,8 +3400,12 @@ static struct option long_options[] =
/* These options set a flag. */
{"help", no_argument, 0, 'h'},
{"alone", optional_argument, 0, 'a'},
- {"debug", optional_argument, 0, 'd'},
- {"syslog", optional_argument, 0, 's'},
+ {"listen", no_argument, 0, 'l'},
+ {"user", required_argument, 0, 'u'},
+ {"daemonize", no_argument, 0, 'D'},
+ {"once", no_argument, 0, 'o'},
+ {"debug", required_argument, 0, 'd'},
+ {"stderr", no_argument, 0, 'e'},
{"bind", required_argument, 0, 'b'},
{0, 0, 0, 0 }
};
@@ -3342,20 +3429,35 @@ main (int argc, char *argv[])
numchildren = 0;
run_mode = SANED_RUN_INETD;
+ run_foreground = SANE_TRUE;
+ run_once = SANE_FALSE;
- while((c = getopt_long(argc, argv,"ha::d::s::b:", long_options, &long_index )) != -1)
+ while((c = getopt_long(argc, argv,"ha::lu:Dod:eb:", long_options, &long_index )) != -1)
{
switch(c) {
case 'a':
run_mode = SANED_RUN_ALONE;
+ run_foreground = SANE_FALSE;
+ if (optarg)
+ user = optarg;
+ break;
+ case 'l':
+ run_mode = SANED_RUN_ALONE;
+ break;
+ case 'u':
user = optarg;
break;
+ case 'D':
+ run_foreground = SANE_FALSE;
+ break;
+ case 'o':
+ run_once = SANE_TRUE;
+ break;
case 'd':
+ debug = atoi(optarg);
+ break;
+ case 'e':
log_to_syslog = SANE_FALSE;
- case 's':
- run_mode = SANED_RUN_DEBUG;
- if(optarg)
- debug = atoi(optarg);
break;
case 'b':
bind_addr = optarg;
@@ -3405,7 +3507,7 @@ main (int argc, char *argv[])
DBG (DBG_WARN, "saned from %s ready\n", PACKAGE_STRING);
}
- if ((run_mode == SANED_RUN_ALONE) || (run_mode == SANED_RUN_DEBUG))
+ if (run_mode == SANED_RUN_ALONE)
{
run_standalone(user);
}