From: Luiz Angelo Daros de Luca <[email protected]> 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 <[email protected]> --- 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 -- sane-devel mailing list: [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/sane-devel Unsubscribe: Send mail with subject "unsubscribe your_password" to [email protected]
