Larger changes to the daemon:

1998-12-09  Martin Baulig  <martin@home-of-linux.org>

	Larger changes to the daemon:

	- Dropped all the unix domain socket stuff - we don't need it for
	connections on the local host, here we behave just like any normal
	application.
	- Added poptimization: use the --help parameter to get usage info
	- Made it a real daemon, fork into background and write to syslog.
	- It's now possible to invoke the daemon from inetd, you'll get
	GNU_SECURE authentication in this case.
	- Don't make this executable suid/sgid - if invoked as root it
	sets uid/gid to SERVER_UID/SERVER_GID as defined in server_config.h
	- Added missing features, so you can now really use this thing.
This commit is contained in:
Martin Baulig
1998-12-09 21:28:45 +00:00
committed by Martin Baulig
parent 3daeda7307
commit b1f8913794
5 changed files with 637 additions and 693 deletions

View File

@@ -1,3 +1,18 @@
1998-12-09 Martin Baulig <martin@home-of-linux.org>
Larger changes to the daemon:
- Dropped all the unix domain socket stuff - we don't need it for
connections on the local host, here we behave just like any normal
application.
- Added poptimization: use the --help parameter to get usage info
- Made it a real daemon, fork into background and write to syslog.
- It's now possible to invoke the daemon from inetd, you'll get
GNU_SECURE authentication in this case.
- Don't make this executable suid/sgid - if invoked as root it
sets uid/gid to SERVER_UID/SERVER_GID as defined in server_config.h
- Added missing features, so you can now really use this thing.
1998-11-11 Martin Baulig <martin@home-of-linux.org> 1998-11-11 Martin Baulig <martin@home-of-linux.org>
* gnuserv.c (main): Set `server->features' directly rather than * gnuserv.c (main): Set `server->features' directly rather than

View File

@@ -14,8 +14,7 @@
LINK = $(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -o $@ LINK = $(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -o $@
CFLAGS = -Wall -W @CFLAGS@ \ CFLAGS = -Wall -W @CFLAGS@ -D_BSD
-D_BSD -DGLIBTOP_DAEMON_SLAVE
if NEED_LIBGTOP if NEED_LIBGTOP
suid_sysdeps = $(top_builddir)/sysdeps/@sysdeps_dir@/libgtop_sysdeps_suid.la suid_sysdeps = $(top_builddir)/sysdeps/@sysdeps_dir@/libgtop_sysdeps_suid.la

View File

@@ -33,6 +33,9 @@
#include <glibtop/parameter.h> #include <glibtop/parameter.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <syslog.h>
__BEGIN_DECLS __BEGIN_DECLS
@@ -57,6 +60,12 @@ extern void handle_slave_command __P((glibtop_command *, glibtop_response *, con
extern void do_output __P((int, glibtop_response *, off_t, size_t, const void *)); extern void do_output __P((int, glibtop_response *, off_t, size_t, const void *));
extern int do_read __P((int, void *, size_t)); extern int do_read __P((int, void *, size_t));
extern void syslog_message __P((int, char *, ...));
extern void syslog_io_message __P((int, char *, ...));
extern int enable_debug;
extern int verbose_output;
__END_DECLS __END_DECLS
#endif #endif

View File

@@ -41,9 +41,9 @@
#include <glibtop/gnuserv.h> #include <glibtop/gnuserv.h>
#include <fcntl.h> #include <popt-gnome.h>
#include <sys/wait.h>
#include <sys/socket.h> #include "daemon.h"
#ifdef AIX #ifdef AIX
#include <sys/select.h> #include <sys/select.h>
@@ -53,19 +53,51 @@ extern void handle_parent_connection __P ((int));
extern void handle_slave_connection __P ((int, int)); extern void handle_slave_connection __P ((int, int));
extern void handle_ipc_connection __P ((int)); extern void handle_ipc_connection __P ((int));
#if !defined(UNIX_DOMAIN_SOCKETS) && !defined(INTERNET_DOMAIN_SOCKETS) #if !defined(INTERNET_DOMAIN_SOCKETS)
#error "Unix Domain sockets or Internet Domain sockets are required" #error "Internet Domain sockets are required"
#endif #endif
#ifdef INTERNET_DOMAIN_SOCKETS
#ifdef AUTH_MAGIC_COOKIE #ifdef AUTH_MAGIC_COOKIE
#include <X11/X.h> #include <X11/X.h>
#include <X11/Xauth.h> #include <X11/Xauth.h>
static Xauth *server_xauth = NULL; static Xauth *server_xauth = NULL;
#endif /* INTERNET_DOMAIN_SOCKETS */ #endif /* AUTH_MAGIC_COOKIE */
int enable_debug = 0;
int verbose_output = 0;
static int no_daemon = 0;
static int invoked_from_inetd = 0;
static int changed_uid = 0;
void
syslog_message (int priority, char *format, ...)
{
va_list ap;
char buffer [BUFSIZ];
va_start (ap, format);
vsnprintf (buffer, BUFSIZ-1, format, ap);
va_end (ap);
syslog (priority, buffer);
}
void
syslog_io_message (int priority, char *format, ...)
{
va_list ap;
char buffer [BUFSIZ];
char buffer2 [BUFSIZ];
va_start (ap, format);
vsnprintf (buffer, BUFSIZ-1, format, ap);
va_end (ap);
snprintf (buffer2, BUFSIZ-1, "%s: %s", buffer, strerror (errno));
syslog (priority, buffer2);
}
/* /*
* timed_read - Read with timeout. * timed_read - Read with timeout.
@@ -94,14 +126,14 @@ timed_read (int fd, char *buf, int max, int timeout, int one_line)
*buf++ = c; *buf++ = c;
++nbytes; ++nbytes;
} else { } else {
glibtop_warn_io ("read error on socket"); syslog_io_message (LOG_WARNING, "read error on socket");
return -1; return -1;
} }
} else if (r == 0) { } else if (r == 0) {
glibtop_warn ("read timed out"); syslog_io_message (LOG_WARNING, "read timed out");
return -1; return -1;
} else { } else {
glibtop_warn_io ("error in select"); syslog_io_message (LOG_WARNING, "error in select");
return -1; return -1;
} }
} while ((nbytes < max) && !(one_line && (c == '\n'))); } while ((nbytes < max) && !(one_line && (c == '\n')));
@@ -127,23 +159,22 @@ permitted (u_long host_addr, int fd)
char buf[1024]; char buf[1024];
int auth_data_len; int auth_data_len;
if (fd > 0) {
/* we are checking permission on a real connection */
/* Read auth protocol name */ /* Read auth protocol name */
if (timed_read (fd, auth_protocol, AUTH_NAMESZ, AUTH_TIMEOUT, 1) <= 0) if (timed_read (fd, auth_protocol, AUTH_NAMESZ, AUTH_TIMEOUT, 1) <= 0)
return FALSE; return FALSE;
#ifdef LIBGTOP_ENABLE_DEBUG if (enable_debug)
fprintf (stderr, "Client sent authenticatin protocol '%s'\n", syslog_message (LOG_DEBUG,
"Client sent authenticatin protocol '%s'.",
auth_protocol); auth_protocol);
#endif
if (strcmp (auth_protocol, DEFAUTH_NAME) && if (strcmp (auth_protocol, DEFAUTH_NAME) &&
strcmp (auth_protocol, MCOOKIE_NAME)) { strcmp (auth_protocol, MCOOKIE_NAME)) {
glibtop_warn ("Invalid authentication protocol " syslog_message (LOG_WARNING,
"'%s' from client", auth_protocol); "Invalid authentication protocol "
"'%s' from client",
auth_protocol);
return FALSE; return FALSE;
} }
@@ -161,12 +192,13 @@ permitted (u_long host_addr, int fd)
return FALSE; return FALSE;
#ifdef AUTH_MAGIC_COOKIE #ifdef AUTH_MAGIC_COOKIE
if (server_xauth && server_xauth->data && if (!invoked_from_inetd && server_xauth && server_xauth->data &&
!memcmp (buf, server_xauth->data, auth_data_len)) { !memcmp (buf, server_xauth->data, auth_data_len)) {
return TRUE; return TRUE;
} }
#else #else
glibtop_warn ("Client tried Xauth, but server is " syslog_message (LOG_WARNING,
"Client tried Xauth, but server is "
"not compiled with Xauth"); "not compiled with Xauth");
#endif #endif
@@ -175,27 +207,30 @@ permitted (u_long host_addr, int fd)
* GNU_SECURE protocol.... * GNU_SECURE protocol....
*/ */
glibtop_warn ("Xauth authentication failed, " if (verbose_output)
if (changed_uid || invoked_from_inetd)
syslog_message (LOG_WARNING,
"Xauth authentication not allowed, "
"trying GNU_SECURE ...");
else
syslog_message (LOG_WARNING,
"Xauth authentication failed, "
"trying GNU_SECURE auth..."); "trying GNU_SECURE auth...");
} }
/* Other auth protocols go here, and should execute only if /* Other auth protocols go here, and should execute only if
* the * auth_protocol name matches. */ * the * auth_protocol name matches. */
}
/* Now, try the old GNU_SECURE stuff... */ /* Now, try the old GNU_SECURE stuff... */
#ifdef LIBGTOP_ENABLE_DEBUG if (enable_debug)
fprintf (stderr, "Doing GNU_SECURE auth ...\n"); syslog_message (LOG_DEBUG, "Doing GNU_SECURE auth ...");
#endif
/* Now check the chain for that hash key */ /* Now check the chain for that hash key */
for (i = 0; i < HOST_TABLE_ENTRIES; i++) { for (i = 0; i < HOST_TABLE_ENTRIES; i++) {
#ifdef LIBGTOP_ENABLE_DEBUG if (enable_debug)
fprintf (stderr, "Trying %lx - %lx\n", syslog_message (LOG_DEBUG, "Trying %lx - %lx",
host_addr, permitted_hosts [i]); host_addr, permitted_hosts [i]);
#endif
if (host_addr == permitted_hosts [i]) if (host_addr == permitted_hosts [i])
return (TRUE); return (TRUE);
} }
@@ -226,8 +261,10 @@ setup_table (void)
gethostname (hostname, HOSTNAMSZ); gethostname (hostname, HOSTNAMSZ);
if ((host_addr = glibtop_internet_addr (hostname)) == -1) if ((host_addr = glibtop_internet_addr (hostname)) == -1) {
glibtop_error ("Can't resolve '%s'", hostname); syslog_io_message (LOG_ERR, "Can't resolve '%s'", hostname);
exit (1);
}
#ifdef AUTH_MAGIC_COOKIE #ifdef AUTH_MAGIC_COOKIE
@@ -245,23 +282,23 @@ setup_table (void)
/* Resolv host names from permitted_host_names []. */ /* Resolv host names from permitted_host_names []. */
for (i = 0; i < HOST_TABLE_ENTRIES; i++) { for (i = 0; i < HOST_TABLE_ENTRIES; i++) {
#ifdef LIBGTOP_ENABLE_DEBUG if (enable_debug)
fprintf (stderr, "Resolving %s ...\n", syslog_message (LOG_DEBUG, "Resolving %s ...",
permitted_host_names [i]); permitted_host_names [i]);
#endif
permitted_hosts [i] = permitted_hosts [i] =
glibtop_internet_addr (permitted_host_names [i]); glibtop_internet_addr (permitted_host_names [i]);
if ((long) permitted_hosts [i] == -1) if ((long) permitted_hosts [i] == -1) {
glibtop_error ("Can't resolve '%s'", syslog_io_message (LOG_ERR, "Can't resolve '%s'",
permitted_host_names [i]); permitted_host_names [i]);
exit (1);
}
} }
#ifdef LIBGTOP_ENABLE_DEBUG if (enable_debug)
for (i = 0; i < HOST_TABLE_ENTRIES; i++) for (i = 0; i < HOST_TABLE_ENTRIES; i++)
fprintf (stderr, "Host %s - %lx\n", syslog_message (LOG_DEBUG, "Host %s - %lx",
permitted_host_names [i], permitted_host_names [i],
permitted_hosts [i]); permitted_hosts [i]);
#endif
hosts += HOST_TABLE_ENTRIES; hosts += HOST_TABLE_ENTRIES;
@@ -292,19 +329,27 @@ internet_init (void)
/* We use a fixed port given in the config file. */ /* We use a fixed port given in the config file. */
server.sin_port = htons (SERVER_PORT); server.sin_port = htons (SERVER_PORT);
fprintf (stderr, "Using port %u.\n", server.sin_port); if (verbose_output)
syslog_message (LOG_INFO, "Using port %u.", SERVER_PORT);
/* Create the listen socket. */ /* Create the listen socket. */
if ((ls = socket (AF_INET, SOCK_STREAM, 0)) == -1) if ((ls = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
glibtop_error_io ("unable to create socket"); syslog_io_message (LOG_ERR, "unable to create socket");
exit (1);
}
/* Bind the listen address to the socket. */ /* Bind the listen address to the socket. */
if (bind (ls, (struct sockaddr *) &server, sizeof (struct sockaddr_in)) == -1) if (bind (ls, (struct sockaddr *) &server,
glibtop_error_io ("bind"); sizeof (struct sockaddr_in)) == -1) {
syslog_io_message (LOG_ERR, "bind");
exit (1);
}
/* Initiate the listen on the socket so remote users * can connect. */ /* Initiate the listen on the socket so remote users * can connect. */
if (listen (ls, 20) == -1) if (listen (ls, 20) == -1) {
glibtop_error_io ("listen"); syslog_io_message (LOG_ERR, "listen");
exit (1);
}
return (ls); return (ls);
} /* internet_init */ } /* internet_init */
@@ -325,298 +370,203 @@ handle_internet_request (int ls)
memset ((char *) &peer, 0, sizeof (struct sockaddr_in)); memset ((char *) &peer, 0, sizeof (struct sockaddr_in));
if ((s = accept (ls, (struct sockaddr *) &peer, (void *) &addrlen)) == -1) if ((s = accept (ls, (struct sockaddr *) &peer, (void *) &addrlen)) == -1) {
glibtop_error_io ("accept"); syslog_io_message (LOG_ERR, "accept");
exit (1);
}
#ifdef LIBGTOP_ENABLE_DEBUG if (verbose_output)
fprintf (stderr, "Connection was made from %s.\n", syslog_message (LOG_INFO, "Connection was made from %s port %u.",
inet_ntoa (peer.sin_addr)); inet_ntoa (peer.sin_addr), ntohs (peer.sin_port));
#endif
/* Check that access is allowed - if not return crud to the client */ /* Check that access is allowed - if not return crud to the client */
if (!permitted (peer.sin_addr.s_addr, s)) { if (!permitted (peer.sin_addr.s_addr, s)) {
close (s); close (s);
glibtop_warn ("Refused connection from %s.", syslog_message (LOG_CRIT, "Refused connection from %s.",
inet_ntoa (peer.sin_addr)); inet_ntoa (peer.sin_addr));
return; return;
} /* if */ } /* if */
#ifdef LIBGTOP_ENABLE_DEBUG if (verbose_output)
fprintf (stderr, "Accepted connection from %s (%u) on socket %d.\n", syslog_message (LOG_INFO, "Accepted connection from %s port %u.",
inet_ntoa (peer.sin_addr), ntohs (peer.sin_port), s); inet_ntoa (peer.sin_addr), ntohs (peer.sin_port));
#endif
pid = fork (); pid = fork ();
if (pid == -1) if (pid == -1) {
glibtop_error_io ("fork failed"); syslog_io_message (LOG_ERR, "fork failed");
exit (1);
}
if (pid) if (pid) {
if (verbose_output)
syslog_message (LOG_INFO, "Child pid is %d.", pid);
return; return;
}
handle_parent_connection (s); handle_parent_connection (s);
close (s); close (s);
#ifdef LIBGTOP_ENABLE_DEBUG if (verbose_output)
fprintf (stderr, "Closed connection to %s (%d).\n", syslog_message (LOG_INFO, "Closed connection to %s port %u.",
inet_ntoa (peer.sin_addr), ntohs (peer.sin_port)); inet_ntoa (peer.sin_addr), ntohs (peer.sin_port));
#endif
_exit (0); _exit (0);
} /* handle_internet_request */ } /* handle_internet_request */
#endif /* INTERNET_DOMAIN_SOCKETS */
#ifdef UNIX_DOMAIN_SOCKETS
/*
* unix_init -- initialize server, returning an unix-domain socket that can
* be listened on.
*/
static int
unix_init (void)
{
int ls; /* socket descriptor */
struct sockaddr_un server; /* unix socket address */
int bindlen;
if ((ls = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
glibtop_error_io ("unable to create socket");
/* Set up address structure for the listen socket. */
#ifdef HIDE_UNIX_SOCKET
sprintf (server.sun_path, "/tmp/lgtddir%d", (int) geteuid ());
if (mkdir (server.sun_path, 0700) < 0) {
/* assume it already exists, and try to set perms */
if (chmod (server.sun_path, 0700) < 0)
glibtop_error_io ("Can't set permissions on %s",
server.sun_path);
}
strcat (server.sun_path, "/lgtd");
unlink (server.sun_path); /* remove old file if it exists */
#else /* HIDE_UNIX_SOCKET */
sprintf (server.sun_path, "/tmp/lgtd%d", (int) geteuid ());
unlink (server.sun_path); /* remove old file if it exists */
#endif /* HIDE_UNIX_SOCKET */
server.sun_family = AF_UNIX;
#ifdef HAVE_SOCKADDR_SUN_LEN
/* See W. R. Stevens "Advanced Programming in the Unix Environment"
* p. 502 */
bindlen = (sizeof (server.sun_len) + sizeof (server.sun_family)
+ strlen (server.sun_path) + 1);
server.sun_len = bindlen;
#else
bindlen = strlen (server.sun_path) + sizeof (server.sun_family);
#endif
if (bind (ls, (struct sockaddr *) &server, bindlen) < 0)
glibtop_error_io ("bind");
chmod (server.sun_path, 0700); /* only this user can send commands */
if (listen (ls, 20) < 0)
glibtop_error_io ("listen");
/* #### there are also better ways of dealing with this when sigvec()
* is present. */
#if defined (HAVE_SIGPROCMASK)
{
sigset_t _mask;
sigemptyset (&_mask);
sigaddset (&_mask, SIGPIPE);
sigprocmask (SIG_BLOCK, &_mask, NULL);
}
#else
signal (SIGPIPE, SIG_IGN); /* in case user kills client */
#endif
return (ls);
} /* unix_init */
/*
* handle_unix_request -- accept a request from a client and send the information
* to stdout (the gnu process).
*/
static void
handle_unix_request (int ls)
{
int s;
size_t len = sizeof (struct sockaddr_un);
struct sockaddr_un server; /* for unix socket address */
pid_t pid;
server.sun_family = AF_UNIX;
if ((s = accept (ls, (struct sockaddr *) &server, (void *) &len)) < 0)
glibtop_error_io ("accept");
#ifdef LIBGTOP_ENABLE_DEBUG
fprintf (stderr, "Accepted connection on socket %d.\n", s);
#endif
#ifdef GLIBTOP_DAEMON_SLAVE
pid = fork ();
if (pid == -1)
glibtop_error_io ("fork failed");
if (pid)
return;
handle_slave_connection (s, s);
#endif
close (s);
#ifdef LIBGTOP_ENABLE_DEBUG
fprintf (stderr, "Closed connection on socket %d.\n", s);
#endif
glibtop_close_r (glibtop_global_server);
exit (0);
} /* handle_unix_request */
#endif /* UNIX_DOMAIN_SOCKETS */
static void static void
handle_signal (int sig) handle_signal (int sig)
{ {
fprintf (stderr, "Catched signal %d.\n", sig); if (sig == SIGCHLD)
return;
syslog_message (LOG_ERR, "Catched signal %d.\n", sig);
exit (1);
} }
const struct poptOption popt_options [] = {
POPT_AUTOHELP
{ "debug", 'd', POPT_ARG_NONE, &enable_debug, 0,
N_("Enable debugging"), N_("DEBUG") },
{ "verbose", 'v', POPT_ARG_NONE, &verbose_output, 0,
N_("Enable verbose output"), N_("VERBOSE") },
{ "no-daemon", 'f', POPT_ARG_NONE, &no_daemon, 0,
N_("Don't fork into background"), N_("NO-DAEMON") },
{ "inetd", 'i', POPT_ARG_NONE, &invoked_from_inetd, 0,
N_("Invoked from inetd"), N_("INETD") },
{ NULL, '\0', 0, NULL, 0 }
};
int int
main (int argc, char *argv []) main (int argc, char *argv [])
{ {
const unsigned method = GLIBTOP_METHOD_PIPE;
const unsigned long features = GLIBTOP_SYSDEPS_ALL;
glibtop *server = glibtop_global_server; glibtop *server = glibtop_global_server;
poptContext context;
int nextopt;
int ils = -1; /* internet domain listen socket */ int ils = -1; /* internet domain listen socket */
int uls = -1; /* unix domain listen socket */
pid_t pid; /* On non-glibc systems, this is not set up for us. */
if (!program_invocation_name) {
char *arg;
program_invocation_name = argv[0];
arg = strrchr (argv[0], '/');
program_invocation_short_name =
arg ? (arg + 1) : program_invocation_name;
}
context = poptGetContext ("libgtop-daemon", argc, argv,
popt_options, 0);
poptReadDefaultConfig (context, TRUE);
while ((nextopt = poptGetNextOpt (context)) > 0)
/* do nothing */ ;
if(nextopt != -1) {
printf (_("Error on option %s: %s.\n"
"Run '%s --help' to see a full list of "
"available command line options.\n"),
poptBadOption (context, 0),
poptStrerror (nextopt),
argv[0]);
exit(1);
}
if (enable_debug)
verbose_output = 1;
if (no_daemon) {
openlog ("libgtop-daemon", LOG_PERROR | LOG_PID, LOG_LOCAL0);
} else {
openlog ("libgtop-daemon", LOG_PID, LOG_LOCAL0);
}
if (!no_daemon && !invoked_from_inetd) {
pid_t pid = fork ();
if (pid == -1) {
syslog_io_message (LOG_ERR, "fork failed");
exit (1);
} else if (pid)
exit (0);
close (0);
setsid ();
}
glibtop_init_r (&glibtop_global_server, 0, GLIBTOP_INIT_NO_INIT); glibtop_init_r (&glibtop_global_server, 0, GLIBTOP_INIT_NO_INIT);
/* Fork a child.
*
* The parent will listen for incoming internet connections
* and the child will listen for connections from the local
* host using unix domain name sockets.
*/
signal (SIGCHLD, handle_signal); signal (SIGCHLD, handle_signal);
#ifdef GLIBTOP_DAEMON_SLAVE
pid = fork ();
#else
pid = getpid ();
#endif
if (pid == -1)
glibtop_error_io ("fork failed");
else if (pid == 0) {
/* We are the child. */
const unsigned method = GLIBTOP_METHOD_DIRECT;
/* Temporarily drop our priviledges. */
#ifdef LIBGTOP_ENABLE_DEBUG
fprintf (stderr, "Child ID: (%d, %d) - (%d, %d)\n",
(int) getuid (), (int) geteuid (),
(int) getgid (), (int) getegid ());
#endif
if (setreuid (geteuid (), getuid ()))
glibtop_error_io ("setreuid (euid <-> uid)");
if (setregid (getegid (), getgid ()))
glibtop_error_io ("setregid (egid <-> gid)");
#ifdef LIBGTOP_ENABLE_DEBUG
fprintf (stderr, "Child ID: (%d, %d) - (%d, %d)\n",
(int) getuid (), (int) geteuid (),
(int) getgid (), (int) getegid ());
#endif
#ifdef UNIX_DOMAIN_SOCKETS
/* get a unix domain socket to listen on. */
uls = unix_init ();
#endif
glibtop_set_parameter_l (server, GLIBTOP_PARAM_METHOD,
&method, sizeof (method));
server->features = glibtop_server_features;
glibtop_init_r (&server, 0, 0);
} else {
/* We are the parent. */
#ifdef GLIBTOP_DAEMON_SLAVE
const unsigned method = GLIBTOP_METHOD_UNIX;
#else
const unsigned method = GLIBTOP_METHOD_PIPE;
#endif
const unsigned long features = GLIBTOP_SYSDEPS_ALL;
/* If we are root, completely switch to SERVER_UID and /* If we are root, completely switch to SERVER_UID and
* SERVER_GID. Otherwise we completely drop any priviledges. * SERVER_GID. Otherwise we completely drop any priviledges.
*/ */
#ifdef LIBGTOP_ENABLE_DEBUG if (enable_debug)
fprintf (stderr, "Parent ID: (%d, %d) - (%d, %d)\n", syslog_message (LOG_DEBUG, "Parent ID: (%d, %d) - (%d, %d)",
getuid (), geteuid (), getgid (), getegid ()); getuid (), geteuid (), getgid (), getegid ());
#endif
if (setreuid (geteuid (), getuid ()))
glibtop_error_io ("setreuid (euid <-> uid)");
if (setregid (getegid (), getgid ()))
glibtop_error_io ("setregid (egid <-> gid)");
#ifdef LIBGTOP_ENABLE_DEBUG
fprintf (stderr, "Parent ID: (%d, %d) - (%d, %d)\n",
getuid (), geteuid (), getgid (), getegid ());
#endif
if ((geteuid () == 0) || (getuid () == 0)) {
if (setreuid (0, 0))
glibtop_error_io ("setreuid (root)");
}
#ifdef LIBGTOP_ENABLE_DEBUG
fprintf (stderr, "Parent ID: (%d, %d) - (%d, %d)\n",
getuid (), geteuid (), getgid (), getegid ());
#endif
if (geteuid () == 0) { if (geteuid () == 0) {
if (setregid (SERVER_GID, SERVER_GID)) changed_uid = 1;
glibtop_error_io ("setregid (SERVER_GID)"); if (setregid (SERVER_GID, SERVER_GID)) {
if (setreuid (SERVER_UID, SERVER_UID)) syslog_io_message (LOG_ERR, "setregid (SERVER_GID)");
glibtop_error_io ("setreuid (SERVER_UID)"); exit (1);
}
if (setreuid (SERVER_UID, SERVER_UID)) {
syslog_io_message (LOG_ERR, "setreuid (SERVER_UID)");
exit (1);
}
} else { } else {
if (setreuid (geteuid (), geteuid ())) if (setreuid (geteuid (), geteuid ())) {
glibtop_error_io ("setreuid (euid)"); syslog_io_message (LOG_ERR, "setreuid (euid)");
exit (1);
}
} }
#ifdef LIBGTOP_ENABLE_DEBUG if (enable_debug)
fprintf (stderr, "Parent ID: (%d, %d) - (%d, %d)\n", syslog_message (LOG_DEBUG, "Parent ID: (%d, %d) - (%d, %d)",
getuid (), geteuid (), getgid (), getegid ()); getuid (), geteuid (), getgid (), getegid ());
#endif
/* Give our child a little time to start up. */ if (invoked_from_inetd) {
sleep (2); size_t addrlen = sizeof (struct sockaddr_in);
struct sockaddr_in peer;
memset ((char *) &peer, 0, sizeof (struct sockaddr_in));
if (getpeername (0, (struct sockaddr *) &peer, (void *) &addrlen)) {
syslog_io_message (LOG_ERR, "getpeername");
exit (1);
}
if (verbose_output)
syslog_message (LOG_INFO, "Connection was made from %s port %u.",
inet_ntoa (peer.sin_addr), ntohs (peer.sin_port));
/* Check that access is allowed - if not return crud to the client */
if (!permitted (peer.sin_addr.s_addr, 0)) {
close (0);
syslog_message (LOG_CRIT, "Refused connection from %s.",
inet_ntoa (peer.sin_addr));
exit (1);
}
handle_parent_connection (0);
exit (0);
}
#ifdef INTERNET_DOMAIN_SOCKETS
/* get a internet domain socket to listen on. */ /* get a internet domain socket to listen on. */
ils = internet_init (); ils = internet_init ();
#endif
if (ils <= 0) {
syslog_message (LOG_ERR, "Unable to get internet domain socket.");
exit (1);
}
glibtop_set_parameter_l (server, GLIBTOP_PARAM_METHOD, glibtop_set_parameter_l (server, GLIBTOP_PARAM_METHOD,
&method, sizeof (method)); &method, sizeof (method));
@@ -625,22 +575,23 @@ main (int argc, char *argv [])
glibtop_init_r (&server, 0, 0); glibtop_init_r (&server, 0, 0);
}
while (1) { while (1) {
fd_set rmask; fd_set rmask;
int ret; int status, ret;
while ((ret = wait3 (NULL, WNOHANG, NULL)) != 0) { while ((ret = wait3 (&status, WNOHANG, NULL)) != 0) {
if ((ret == -1) && (errno == ECHILD)) if ((ret == -1) && (errno == ECHILD))
break; break;
if ((ret == -1) && ((errno == EAGAIN))) if ((ret == -1) && ((errno == EAGAIN)))
continue; continue;
if (ret > 0) if (ret == 0) {
fprintf (stderr, "Child %d exited.\n", ret); syslog_io_message (LOG_WARNING, "wait3");
else continue;
glibtop_warn_io ("wait3: %d", ret); }
if (verbose_output)
syslog_message (LOG_INFO, "Child %d exited.", ret);
} }
FD_ZERO (&rmask); FD_ZERO (&rmask);
@@ -648,41 +599,22 @@ main (int argc, char *argv [])
/* Only the child accepts connections from standard /* Only the child accepts connections from standard
* input made by its parent. */ * input made by its parent. */
if (pid == 0)
FD_SET (fileno (stdin), &rmask);
if (uls >= 0)
FD_SET (uls, &rmask);
if (ils >= 0)
FD_SET (ils, &rmask); FD_SET (ils, &rmask);
#ifdef LIBGTOP_ENABLE_DEBUG if (enable_debug)
fprintf (stderr, "Server ready and waiting for connections.\n"); syslog_message (LOG_DEBUG,
#endif "Server ready and waiting for connections.");
if (select (max2 (fileno (stdin), max2 (uls, ils)) + 1, &rmask, if (select (ils+1, &rmask, (fd_set *) NULL, (fd_set *) NULL,
(fd_set *) NULL, (fd_set *) NULL,
(struct timeval *) NULL) < 0) { (struct timeval *) NULL) < 0) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
glibtop_error_io ("select"); syslog_io_message (LOG_ERR, "select");
exit (1);
} }
#ifdef UNIX_DOMAIN_SOCKETS if (FD_ISSET (ils, &rmask))
if (uls > 0 && FD_ISSET (uls, &rmask))
handle_unix_request (uls);
#endif
#ifdef INTERNET_DOMAIN_SOCKETS
if (ils > 0 && FD_ISSET (ils, &rmask))
handle_internet_request (ils); handle_internet_request (ils);
#endif
#ifdef GLIBTOP_DAEMON_SLAVE
if ((pid == 0) && FD_ISSET (fileno (stdin), &rmask))
handle_slave_connection (fileno (stdin),
fileno (stdout));
#endif
} }
return 0; return 0;

View File

@@ -46,23 +46,26 @@ handle_parent_connection (int s)
glibtop_send_version (glibtop_global_server, s); glibtop_send_version (glibtop_global_server, s);
fprintf (stderr, "Parent features = %lu\n", glibtop_server_features); if (verbose_output)
syslog_message (LOG_INFO, "Parent features = %lu",
glibtop_server_features);
#ifdef DEBUG if (enable_debug)
fprintf (stderr, "SIZEOF: %u - %u - %u - %u - %u - %u\n", syslog_message (LOG_DEBUG, "SIZEOF: %u - %u - %u - %u - %u - %u",
sizeof (glibtop_command), sizeof (glibtop_response), sizeof (glibtop_command), sizeof (glibtop_response),
sizeof (glibtop_mountentry), sizeof (glibtop_union), sizeof (glibtop_mountentry), sizeof (glibtop_union),
sizeof (glibtop_sysdeps), sizeof (glibtop_response_union)); sizeof (glibtop_sysdeps),
#endif sizeof (glibtop_response_union));
while (do_read (s, cmnd, sizeof (glibtop_command))) { while (do_read (s, cmnd, sizeof (glibtop_command))) {
#ifdef PARENT_DEBUG if (enable_debug)
fprintf (stderr, "Parent (%d) received command %d from client.\n", syslog_message (LOG_DEBUG,
"Parent (%d) received command %d from client.",
getpid (), (int) cmnd->command); getpid (), (int) cmnd->command);
#endif
if (cmnd->data_size >= BUFSIZ) { if (cmnd->data_size >= BUFSIZ) {
glibtop_warn ("Client sent %d bytes, but buffer is %d", syslog_message (LOG_WARNING,
"Client sent %d bytes, but buffer is %d",
cmnd->data_size, BUFSIZ); cmnd->data_size, BUFSIZ);
return; return;
} }
@@ -72,10 +75,9 @@ handle_parent_connection (int s)
memset (parameter, 0, sizeof (parameter)); memset (parameter, 0, sizeof (parameter));
if (cmnd->data_size) { if (cmnd->data_size) {
#ifdef PARENT_DEBUG if (enable_debug)
fprintf (stderr, "Client has %d bytes of data.\n", syslog_message (LOG_DEBUG, "Client has %d bytes of data.",
(int) cmnd->data_size); (int) cmnd->data_size);
#endif
do_read (s, parameter, cmnd->data_size); do_read (s, parameter, cmnd->data_size);
@@ -86,19 +88,6 @@ handle_parent_connection (int s)
switch (cmnd->command) { switch (cmnd->command) {
case GLIBTOP_CMND_QUIT: case GLIBTOP_CMND_QUIT:
do_output (s, resp, 0, 0, NULL); do_output (s, resp, 0, 0, NULL);
#ifdef GLIBTOP_DAEMON_SLAVE
fprintf (stderr, "Sending QUIT command (%d).\n",
server->socket);
glibtop_call_l (server, GLIBTOP_CMND_QUIT,
0, NULL, 0, NULL);
fprintf (stderr, "Done sending QUIT command (%d).\n",
server->socket);
close (server->socket);
#endif
return; return;
case GLIBTOP_CMND_SYSDEPS: case GLIBTOP_CMND_SYSDEPS:
memcpy (&resp->u.sysdeps, &server->sysdeps, memcpy (&resp->u.sysdeps, &server->sysdeps,
@@ -238,7 +227,7 @@ handle_parent_connection (int s)
0, NULL); 0, NULL);
break; break;
default: default:
glibtop_warn ("Parent received unknown command %u", syslog_message (LOG_ERR, "Parent received unknown command %u.",
cmnd->command); cmnd->command);
break; break;
} }