[sane-devel] [PATCH 3/3] saned: reorganize flags, remove run_mode SANED_RUN_DEBUG
luizluca at gmail.com
luizluca at gmail.com
Sat Jul 22 08:43:18 UTC 2017
From: Luiz Angelo Daros de Luca <luizluca at gmail.com>
Flags like -a, -d and -s have many overlap effects. This patch restricts
the effect of flags to a simple action.
New -u (user) flag replaces -a optional argument for running saned as a different user.
The code that retrieve the user info and drop privileges migrated to runas_user().
As a side effect, PID file can be created even if getting user info fails.
New -l (listen) flag sets run_mode to standalone. It can be cancelled with -i.
New -i (inetd, default) flag sets run_mode to inetd. It is useful only to cancel -l.
New -D (daemonize) flag daemonizes saned after bind. Requires -l and it can be cancelled
by -f.
New -f (foreground) flag for running saned in foreground (useful for procd).
It can be cancelled using new -D flag.
New -o (once) make saned exit after the first client disconnects.
Flag -s (syslog) now only forces output to syslog and does not accept arguments. It can be
cancelled using -e. Previous behavior can be reproduced with '-a -d level -o -f -s'.
New -e (stderr) flag for redirecting output to stderr, instead of syslog. It can be
cancelled using -s.
Flag -d (debug) now only sets the debug level and argument is required. Previous behavior
can be reproduced with '-a -d level -o -f'.
The run_mode SANED_RUN_DEBUG and SANED_RUN_ALONE shared most of its code
path. With the new flags dealing with their difference, SANED_RUN_DEBUG is gone.
Flag '-a' still works as before but it can be replaced by '-l -D -u user'.
Current uses of -d (debug) or -s (syslog) will break.
Signed-off-by: Luiz Angelo Daros de Luca <luizluca at gmail.com>
---
doc/saned.man | 78 ++++++++------
frontend/saned.c | 306 +++++++++++++++++++++++++++++++------------------------
2 files changed, 220 insertions(+), 164 deletions(-)
diff --git a/doc/saned.man b/doc/saned.man
index 8542d254..0bddc58d 100644
--- a/doc/saned.man
+++ b/doc/saned.man
@@ -6,15 +6,21 @@ saned \- SANE network daemon
.B saned
.B [ \-a
.I [ username ]
+.B ]
+.B [ \-u
+.I username
+.B ]
.B [ \-b
.I address
.B ]
-.B | \-d
-.I [ n ]
-.B | \-s
-.I [ n ]
-.B | \-h
+.B [ \-l | \-i ]
+.B [ \-D | \-f ]
+.B [ \-o ]
+.B [ \-d
+.I n
.B ]
+.B [ \-s | \-e ]
+.B [ \-h ]
.SH DESCRIPTION
.B saned
is the SANE (Scanner Access Now Easy) daemon that allows remote clients
@@ -22,51 +28,63 @@ to access image acquisition devices available on the local host.
.SH OPTIONS
.PP
The
-.B \-a
+.B \-l
flag requests that
.B saned
run in standalone daemon mode. In this mode,
.B saned
-will detach from the console and run in the background, listening for incoming
-client connections;
+will listening for incoming client connections;
.B inetd
is not required for
.B saned
-operations in this mode. If the optional
-.B username
-is given after
-.B \-a
-,
+operations in this mode. The
+.B \-b
+flag can control which address
.B saned
-will drop root privileges and run as this user (and group).
+will bind. The
+.B \-u
+.I username
+flag requests that
+.B saned
+drop root privileges and run as this user (and group) after bind.
+The
+.B \-B
+flag will request
+.B saned
+to detach from the console and run in the background, while
+.B \-f
+flag will keep it attached to the console and running foreground.
+The flag
+.B \-a
+is equals to
+.B \-l \-B \-u
+.I username
+.
+.PP
+The
+.B \-e
+flag will request that
+.B saned
+output to stderr while the
+.B \-s
+flag forces the output to syslog.
.PP
The
.B \-d
-and
-.B \-s
-flags request that
+flag sets the debug level of
.B saned
-run in debug mode (as opposed to
-.BR inetd (8)
-daemon mode). In this mode,
-.B saned
-explicitly waits for a connection request. When compiled with
-debugging enabled, these flags may be followed by a number to request
+. When compiled with debugging enabled, these flags may be followed by a number to request
debug info. The larger the number, the more verbose the debug output.
E.g.,
.B \-d128
will request printing of all debug info. Debug level 0 means no debug output
-at all. The default value is 2. If flag
-.B \-d
-is used, the debug messages will be printed to stderr while
-.B \-s
-requests using syslog.
+at all. The default value is 2.
.PP
The
-.B \-b
+.B \-o
flag requests that
.B saned
-bind to a specific address.
+exits after the first client disconnects. Useful for debugging.
.PP
If
.B saned
diff --git a/frontend/saned.c b/frontend/saned.c
index 6b97e914..93afd612 100644
--- a/frontend/saned.c
+++ b/frontend/saned.c
@@ -251,6 +251,8 @@ static Wire wire;
static int num_handles;
static int debug;
static int run_mode;
+static int run_foreground;
+static int run_once;
static Handle *handle;
static char *bind_addr;
static union
@@ -298,9 +300,10 @@ 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 SANED_EXEC_FOREGROUND 0
+#define SANED_EXEC_BACKGROUND 1
#define DBG_ERR 1
#define DBG_WARN 2
@@ -2964,6 +2967,114 @@ do_bindings (int *nfds, struct pollfd **fds)
static void
+runas_user (char *user)
+{
+ uid_t runas_uid = 0;
+ gid_t runas_gid = 0;
+ struct passwd *pwent;
+ gid_t *grplist = NULL;
+ struct group *grp;
+ int ngroups = 0;
+ int ret;
+
+ pwent = getpwnam(user);
+
+ 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;
+
+ /* 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");
+
+ exit (1);
+ }
+
+ ngroups = 1;
+ grplist[0] = runas_gid;
+
+ setgrent();
+ while ((grp = getgrent()) != NULL)
+ {
+ int i = 0;
+
+ /* 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;
+
+ /* 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++;
+ }
+ }
+ 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;
@@ -2973,84 +3084,12 @@ run_standalone (char *user)
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;
do_bindings (&nfds, &fds);
- if (run_mode != SANED_RUN_DEBUG)
+ if (run_foreground == SANE_FALSE)
{
- if (user)
- {
- pwent = getpwnam(user);
-
- 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;
-
- /* 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");
-
- exit (1);
- }
-
- ngroups = 1;
- grplist[0] = runas_gid;
-
- setgrent();
- while ((grp = getgrent()) != NULL)
- {
- int i = 0;
-
- /* 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;
-
- /* 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++;
- }
- }
- endgrent();
- }
-
DBG (DBG_MSG, "run_standalone: daemonizing now\n");
fd = open ("/dev/null", O_RDWR);
@@ -3093,42 +3132,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 +3197,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,14 +3211,6 @@ run_standalone (char *user)
close (fdp->fd);
free (fds);
-
- if (run_mode == SANED_RUN_DEBUG)
- {
- if (fd > 0)
- handle_connection (fd);
-
- bail_out(0);
- }
}
@@ -3299,12 +3301,17 @@ 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 stderr\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] equals to `-l -D -u user'\n"
+ " -l, --listen run in standalone mode (listen for connection)\n"
+ " -i, --inetd run in inetd mode (default)\n"
+ " -u, --user=user run as `user'\n"
+ " -D, --daemonize run in background\n"
+ " -f, --foreground run in foreground (default)\n"
+ " -o, --once exit after first client disconnects\n"
+ " -d, --debug=level set debug level `level' (default is 2)\n"
+ " -s, --syslog output to syslog (default)\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 +3324,15 @@ 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'},
+ {"inetd", no_argument, 0, 'i'},
+ {"user", required_argument, 0, 'u'},
+ {"daemonize", no_argument, 0, 'D'},
+ {"foreground",no_argument, 0, 'f'},
+ {"once", no_argument, 0, 'o'},
+ {"debug", required_argument, 0, 'd'},
+ {"syslog", no_argument, 0, 's'},
+ {"stderr", no_argument, 0, 'e'},
{"bind", required_argument, 0, 'b'},
{0, 0, 0, 0 }
};
@@ -3342,20 +3356,44 @@ 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::liu:Dfod:seb:", 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 'i':
+ run_mode = SANED_RUN_INETD;
+ break;
+ case 'u':
user = optarg;
break;
+ case 'D':
+ run_foreground = SANE_FALSE;
+ break;
+ case 'f':
+ run_foreground = SANE_TRUE;
+ break;
+ case 'o':
+ run_once = SANE_TRUE;
+ break;
case 'd':
- log_to_syslog = SANE_FALSE;
+ debug = atoi(optarg);
+ break;
case 's':
- run_mode = SANED_RUN_DEBUG;
- if(optarg)
- debug = atoi(optarg);
+ log_to_syslog = SANE_TRUE;
+ break;
+ case 'e':
+ log_to_syslog = SANE_FALSE;
break;
case 'b':
bind_addr = optarg;
@@ -3405,7 +3443,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);
}
--
2.11.0
More information about the sane-devel
mailing list