diff --git a/configure.in b/configure.in index ee1f894..809d36c 100644 --- a/configure.in +++ b/configure.in @@ -860,12 +860,12 @@ AC_CHECK_FUNCS(mktime nanosleep unsetenv) AC_CHECK_FUNCS(gethostname select socket) AC_CHECK_FUNCS(uname syslog __clone pipe2 fcntl ioctl) AC_CHECK_FUNCS(prctl setlinebuf waitpid atexit kill) -AC_CHECK_FUNCS(chown getcwd scandir mkstemp getpwnam) +AC_CHECK_FUNCS(chown getcwd scandir mkstemp) AC_CHECK_FUNCS(brk sbrk memalign valloc) AC_CHECK_FUNCS(signal sighold sigrelse tcgetattr) AC_CHECK_FUNCS(regex regcmp regexec regcomp) AC_CHECK_FUNCS(strtod strtol strtoll strtoull) -AC_CHECK_FUNCS(sysinfo) +AC_CHECK_FUNCS(sysinfo getpwnam getpwnam_r) AC_CHECK_FUNCS(backtrace) dnl only define readdir64 on non-linux platforms that support it diff --git a/src/include/pcp/impl.h b/src/include/pcp/impl.h index 7326ad8..c9a81cb 100644 --- a/src/include/pcp/impl.h +++ b/src/include/pcp/impl.h @@ -1152,6 +1152,7 @@ extern int __pmProcessTerminate(pid_t, int); extern pid_t __pmProcessCreate(char **, int *, int *); extern int __pmProcessDataSize(unsigned long *); extern int __pmProcessRunTimes(double *, double *); +extern int __pmSetProcessIdentity(const char *); /* * platform independent memory mapped file handling diff --git a/src/include/pcp/platform_header.h.in b/src/include/pcp/platform_header.h.in index b7b52c3..591ad0f 100644 --- a/src/include/pcp/platform_header.h.in +++ b/src/include/pcp/platform_header.h.in @@ -219,6 +219,7 @@ extern "C" { #undef HAVE_SCANDIR #undef HAVE_MKSTEMP #undef HAVE_GETPWNAM +#undef HAVE_GETPWNAM_R #undef HAVE_BRK #undef HAVE_SBRK diff --git a/src/libpcp/src/util.c b/src/libpcp/src/util.c index e4d6de6..365c3c9 100644 --- a/src/libpcp/src/util.c +++ b/src/libpcp/src/util.c @@ -45,6 +45,9 @@ #if defined(HAVE_IEEEFP_H) #include #endif +#if defined(HAVE_PWD_H) +#include +#endif static FILE **filelog; static int nfilelog; @@ -1523,6 +1526,47 @@ __pmProcessCreate(char **argv, int *infd, int *outfd) } int +__pmSetProcessIdentity(const char *username) +{ + gid_t gid; + uid_t uid; + struct passwd *pw; + +#if defined(HAVE_GETPWNAM_R) /* thread-safe variant first */ + struct passwd pwd; + char buf[16*1024]; + int sts; + + sts = getpwnam_r(username, &pwd, buf, sizeof(buf), &pw); + if (pw == NULL) { + __pmNotifyErr(LOG_WARNING, + "cannot find the %s user to switch to\n", username); + return (sts == 0) ? -ESRCH : -oserror(); + } + uid = pwd.pw_uid; + gid = pwd.pw_uid; +#elif defined(HAVE_GETPWNAM) + if ((pw = getpwnam(username)) == 0) { + __pmNotifyErr(LOG_WARNING, + "cannot find the %s user to switch to\n", username); + return -oserror(); + } + uid = pw->pw_uid; + gid = pw->pw_uid; +#else +!bozo! +#endif + + if (setgid(gid) < 0 || setuid(uid) < 0) { + __pmNotifyErr(LOG_WARNING, + "cannot switch to uid/gid of %s user (%d/%d)\n", username, uid, gid); + return -oserror(); + } + + return 0; +} + +int __pmSetSignalHandler(int sig, __pmSignalHandler func) { signal(sig, func); diff --git a/src/libpcp/src/win32.c b/src/libpcp/src/win32.c index 9390433..80fbbf6 100644 --- a/src/libpcp/src/win32.c +++ b/src/libpcp/src/win32.c @@ -127,6 +127,13 @@ sigterm_callback(int sig) } int +__pmSetProcessIdentity(const char *username) +{ + (void)username; + return 0; /* Not Yet Implemented */ +} + +int __pmSetProgname(const char *program) { int sts1, sts2; diff --git a/src/perl/PMDA/PMDA.xs b/src/perl/PMDA/PMDA.xs index 51a1442..66b33c7 100644 --- a/src/perl/PMDA/PMDA.xs +++ b/src/perl/PMDA/PMDA.xs @@ -816,7 +816,7 @@ set_user(self,username) pmdaInterface *self char * username CODE: - RETVAL = local_user(username); + RETVAL = __pmSetProcessIdentity(username); OUTPUT: RETVAL diff --git a/src/perl/PMDA/local.c b/src/perl/PMDA/local.c index a0476e8..edc5270 100644 --- a/src/perl/PMDA/local.c +++ b/src/perl/PMDA/local.c @@ -51,30 +51,6 @@ local_strdup_prefix(const char *prefix, const char *string) } int -local_user(const char *username) -{ -#ifdef HAVE_GETPWNAM - /* lose root privileges if we have them */ - struct passwd *pw; - - if ((pw = getpwnam(username)) == 0) { - __pmNotifyErr(LOG_WARNING, - "cannot find the user %s to switch to\n", username); - return -1; - } - if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) { - __pmNotifyErr(LOG_WARNING, - "cannot switch to uid/gid of user %s\n", username); - return -1; - } - return 0; -#else - __pmNotifyErr(LOG_WARNING, "cannot switch to user %s\n", username); - return -1; -#endif -} - -int local_timer(double timeout, scalar_t *callback, int cookie) { int size = sizeof(*timers) * (ntimers + 1); diff --git a/src/pmcd/pmcd.options b/src/pmcd/pmcd.options index eb40a2c..f4179b8 100644 --- a/src/pmcd/pmcd.options +++ b/src/pmcd/pmcd.options @@ -13,9 +13,12 @@ # -D N # -f -# Restricting incoming PDU size to prevent DOS attacks +# maximum incoming PDU size (default 64KB) # -L 16384 +# assume identity of some user other than "pcp" +# -U root + # enable event tracing bit fields # 1 trace connections # 2 trace PDUs diff --git a/src/pmcd/pmdaproc.sh b/src/pmcd/pmdaproc.sh index 349b65e..82f88a6 100644 --- a/src/pmcd/pmdaproc.sh +++ b/src/pmcd/pmdaproc.sh @@ -148,6 +148,8 @@ socket_opt=$default_socket_opt socket_inet_def='' # IPC Protocol for daemon (binary only now) ipc_prot=binary +# Need to force a restart of pmcd? +forced_restart=false # Delay after install before checking (sec) check_delay=3 # Additional command line args to go in $PCP_PMCDCONF_PATH @@ -425,7 +427,7 @@ $1=="'$myname'" && $2=="'$mydomain'" { next } # signal pmcd if it is running, else start it # - if pminfo -v pmcd.version >/dev/null 2>&1 + if ! $forced_restart && pminfo -v pmcd.version >/dev/null 2>&1 then pmsignal -a -s HUP pmcd >/dev/null 2>&1 # allow signal processing to be done before checking status diff --git a/src/pmcd/src/pmcd.c b/src/pmcd/src/pmcd.c index 0c6b57c..6be619b 100644 --- a/src/pmcd/src/pmcd.c +++ b/src/pmcd/src/pmcd.c @@ -35,19 +35,20 @@ static int run_daemon = 1; /* run as a daemon, see -f */ int _creds_timeout = 3; /* Timeout for agents credential PDU */ static char *fatalfile = "/dev/tty";/* fatal messages at startup go here */ static char *pmnsfile = PM_NS_DEFAULT; -static int dupok = 0; /* set to 1 for -N pmnsfile */ +static char *username = "pcp"; +static int dupok; /* set to 1 for -N pmnsfile */ /* * Interfaces we're willing to listen for clients on, from -i */ -static int nintf = 0; -static char **intflist = NULL; +static int nintf; +static char **intflist; /* * Ports we're willing to listen for clients on, from -p or $PMCD_PORT */ -static int nport = 0; -static int *portlist = NULL; +static int nport; +static int *portlist; /* * For maintaining info about a request port that clients may connect to pmcd on @@ -62,9 +63,9 @@ typedef struct { /* * A list of the ports that pmcd is listening for client connections on */ -static unsigned nReqPorts = 0; /* number of ports */ -static unsigned szReqPorts = 0; /* capacity of ports array */ -static ReqPortInfo *reqPorts = NULL; /* ports array */ +static unsigned nReqPorts; /* number of ports */ +static unsigned szReqPorts; /* capacity of ports array */ +static ReqPortInfo *reqPorts; /* ports array */ int maxReqPortFd = -1; /* highest request port file descriptor */ #ifdef HAVE_SA_SIGINFO @@ -202,7 +203,7 @@ ParseOptions(int argc, char *argv[]) putenv("POSIXLY_CORRECT="); #endif - while ((c = getopt(argc, argv, "D:fi:l:L:N:n:p:q:t:T:x:?")) != EOF) + while ((c = getopt(argc, argv, "D:fi:l:L:N:n:p:q:t:T:U:x:?")) != EOF) switch (c) { case 'D': /* debug flag */ @@ -237,7 +238,7 @@ ParseOptions(int argc, char *argv[]) case 'L': /* Maximum size for PDUs from clients */ val = (int)strtol (optarg, NULL, 0); if ( val <= 0 ) { - fputs ("pmcd: -L require a posivite value\n", stderr); + fputs ("pmcd: -L requires a positive value\n", stderr); errflag++; } else { __pmSetPDUCeiling (val); @@ -312,6 +313,10 @@ ParseOptions(int argc, char *argv[]) _pmcd_trace_mask = val; break; + case 'U': + username = optarg; + break; + case 'x': fatalfile = optarg; break; @@ -339,6 +344,7 @@ ParseOptions(int argc, char *argv[]) " -q timeout PMDA initial negotiation timeout (seconds) [default 3]\n" " -T traceflag Event trace control\n" " -t timeout PMDA response timeout (seconds) [default 5]\n" +" -U username in daemon mode, run as named user [default pcp]\n" " -x file fatal messages at startup sent to file [default /dev/tty]\n", pmProgname); if (usage) @@ -1137,8 +1143,12 @@ main(int argc, char *argv[]) DontStart(); } - if (run_daemon && CreatePIDfile() < 0) - DontStart(); + if (run_daemon) { + if (CreatePIDfile() < 0) + DontStart(); + if (__pmSetProcessIdentity(username) < 0) + DontStart(); + } PrintAgentInfo(stderr); __pmAccDumpHosts(stderr); diff --git a/src/pmdas/elasticsearch/Install b/src/pmdas/elasticsearch/Install index 45b0ea2..3a906c3 100755 --- a/src/pmdas/elasticsearch/Install +++ b/src/pmdas/elasticsearch/Install @@ -21,6 +21,7 @@ iam=elasticsearch perl_opt=true daemon_opt=false +forced_restart=true for module in JSON LWP::UserAgent do diff --git a/src/pmdas/mysql/Install b/src/pmdas/mysql/Install index 71930b8..6067af8 100755 --- a/src/pmdas/mysql/Install +++ b/src/pmdas/mysql/Install @@ -25,6 +25,7 @@ iam=mysql perl_opt=true daemon_opt=false +forced_restart=true perl -e "use DBI" 2>/dev/null if test $? -ne 0; then diff --git a/src/pmdas/mysql/pmdamysql.pl b/src/pmdas/mysql/pmdamysql.pl index 71e7dfb..fa9e6dd 100644 --- a/src/pmdas/mysql/pmdamysql.pl +++ b/src/pmdas/mysql/pmdamysql.pl @@ -1755,6 +1755,7 @@ $pmda->add_indom($process_indom, \@process_instances, $pmda->set_fetch_callback(\&mysql_fetch_callback); $pmda->set_fetch(\&mysql_connection_setup); $pmda->set_refresh(\&mysql_refresh); +$pmda->set_user('mysql'); $pmda->run; =pod diff --git a/src/pmdas/oracle/Install b/src/pmdas/oracle/Install index 32c6032..a64aac0 100755 --- a/src/pmdas/oracle/Install +++ b/src/pmdas/oracle/Install @@ -23,6 +23,7 @@ user=$iam domain=32 perl_opt=true daemon_opt=false +forced_restart=true perl -e "use DBI" 2>/dev/null if test $? -ne 0; then diff --git a/src/pmdas/postgresql/Install b/src/pmdas/postgresql/Install index e2e4e74..3cf31be 100755 --- a/src/pmdas/postgresql/Install +++ b/src/pmdas/postgresql/Install @@ -21,6 +21,7 @@ iam=postgresql perl_opt=true daemon_opt=false +forced_restart=true perl -e "use DBI" 2>/dev/null if test $? -ne 0; then diff --git a/src/pmie/src/pmie.c b/src/pmie/src/pmie.c index 2d4790f..400255a 100644 --- a/src/pmie/src/pmie.c +++ b/src/pmie/src/pmie.c @@ -58,6 +58,7 @@ char *clientid; static FILE *logfp; static char logfile[MAXPATHLEN+1]; static char perffile[PMIE_PATHSIZE]; /* /var/tmp/ file name */ +static char *username = "pcp"; static char menu[] = "pmie debugger commands\n\n" @@ -91,6 +92,7 @@ static char usage[] = " -S starttime start of the time window\n" " -T endtime end of the time window\n" " -t interval sample interval [default 10 seconds]\n" + " -U username in daemon mode, run as named user [default pcp]\n" " -V verbose mode, annotated expression values printed\n" " -v verbose mode, expression values printed\n" " -W verbose mode, satisfying expression values printed\n" @@ -452,6 +454,29 @@ sigbadproc(int sig) /*********************************************************************** + * manipulate the environment for this process - different user, group + ************************************************************************/ + +static void +daemonInit(void) +{ + /* Note: we can no longer unilaterally close stdin here, as it + * can really confuse remap_stdout_stderr() during log rotation! + */ + if (agent) + close(fileno(stdin)); + +#ifndef IS_MINGW + if (setsid() == -1) { /* not process group leader, lose controlling tty */ + __pmNotifyErr(LOG_WARNING, "StartDaemon: setsid"); + } +#endif + + __pmSetProcessIdentity(username); +} + + +/*********************************************************************** * command line processing - extract command line arguments & initialize ***********************************************************************/ @@ -479,7 +504,7 @@ getargs(int argc, char *argv[]) memset(&tv2, 0, sizeof(tv2)); dstructInit(); - while ((c=getopt(argc, argv, "a:A:bc:CdD:efHh:j:l:n:O:S:t:T:vVWXxzZ:?")) != EOF) { + while ((c=getopt(argc, argv, "a:A:bc:CdD:efHh:j:l:n:O:S:t:T:U:vVWXxzZ:?")) != EOF) { switch (c) { case 'a': /* archives */ @@ -615,6 +640,11 @@ getargs(int argc, char *argv[]) stopFlag = optarg; break; + case 'U': /* run as named user */ + username = optarg; + isdaemon = 1; + break; + case 'v': /* print values */ verbose = 1; break; @@ -790,16 +820,8 @@ getargs(int argc, char *argv[]) * Kevin Wang */ - if (isdaemon) { /* daemon mode */ - /* Note: we can no longer unilaterally close stdin here, as it - * can really confuse remap_stdout_stderr() during log rotation! - */ - if (agent) - close(fileno(stdin)); -#ifndef IS_MINGW - setsid(); /* not process group leader, lose controlling tty */ -#endif - } + if (isdaemon) /* daemon mode */ + daemonInit(); if (stomping) stompInit(); /* connect to our message server */ diff --git a/src/pmlogger/pmlogger.c b/src/pmlogger/pmlogger.c index b5f2c8b..6a90748 100644 --- a/src/pmlogger/pmlogger.c +++ b/src/pmlogger/pmlogger.c @@ -39,7 +39,7 @@ int rflag; /* report sizes */ struct timeval delta = { 60, 0 }; /* default logging interval */ int unbuffered; /* is -u specified? */ int qa_case; /* QA error injection state */ -char *note = NULL; /* note for port map file */ +char *note; /* note for port map file */ static int pmcdfd; /* comms to pmcd */ static fd_set fds; /* file descriptors mask for select */ @@ -481,8 +481,10 @@ main(int argc, char **argv) int sts; int sep = __pmPathSeparator(); int errflag = 0; + int isdaemon = 0; char local[MAXHOSTNAMELEN]; char *pmnsfile = PM_NS_DEFAULT; + char *username = "pcp"; char *logfile = "pmlogger.log"; /* default log (not archive) file name */ char *endnum; @@ -503,7 +505,7 @@ main(int argc, char **argv) * corresponding changes are made to pmnewlog when pmlogger * options are passed through from the control file */ - while ((c = getopt(argc, argv, "c:D:h:l:Lm:n:Prs:T:t:uv:V:x:?")) != EOF) { + while ((c = getopt(argc, argv, "c:D:h:l:Lm:n:Prs:T:t:uU:v:V:x:?")) != EOF) { switch (c) { case 'c': /* config file */ @@ -552,6 +554,7 @@ main(int argc, char **argv) case 'm': /* note for port map file */ note = optarg; + isdaemon = (strcmp(note, "pmlogger_check") == 0); break; case 'n': /* alternative name space file */ @@ -560,6 +563,7 @@ main(int argc, char **argv) case 'P': /* this is the primary pmlogger */ primary = 1; + isdaemon = 1; break; case 'r': /* report sizes of pmResult records */ @@ -591,6 +595,11 @@ main(int argc, char **argv) } break; + case 'U': /* run as named user */ + username = optarg; + isdaemon = 1; + break; + case 'u': /* flush output buffers after each fetch */ unbuffered = 1; break; @@ -652,6 +661,7 @@ Options:\n\ -t interval default logging interval [default 60.0 seconds]\n\ -T endtime terminate at given time\n\ -u output is unbuffered\n\ + -U username in daemon mode, run as named user [default pcp]\n\ -v volsize switch log volumes after volsize has been accumulated\n\ -V version version for archive (default and only version is 2)\n\ -x fd control file descriptor for application launching pmlogger\n\ @@ -672,6 +682,10 @@ Options:\n\ note = xnote; } + /* if we are running as a daemon, change user early */ + if (isdaemon) + __pmSetProcessIdentity(username); + __pmOpenLog("pmlogger", logfile, stderr, &sts); /* base name for archive is here ... */ diff --git a/src/pmproxy/pmproxy.c b/src/pmproxy/pmproxy.c index 5d75474..ae39824 100644 --- a/src/pmproxy/pmproxy.c +++ b/src/pmproxy/pmproxy.c @@ -19,13 +19,11 @@ #include #endif -int proxy_hi_openfds = -1; /* Highest known file descriptor for pmproxy */ - static int timeToDie; /* For SIGINT handling */ static char *logfile = "pmproxy.log"; /* log file name */ static int run_daemon = 1; /* run as a daemon, see -f */ static char *fatalfile = "/dev/tty";/* fatal messages at startup go here */ -static char *username; +static char *username = "pcp"; /* * For maintaining info about a request port that clients may connect to @@ -172,7 +170,7 @@ ParseOptions(int argc, char *argv[]) case 'L': /* Maximum size for PDUs from clients */ val = (int)strtol (optarg, NULL, 0); if ( val <= 0 ) { - fputs ("pmproxy: -L require a posivite value\n", stderr); + fputs ("pmproxy: -L requires a positive value\n", stderr); errflag++; } else { __pmSetPDUCeiling (val); diff --git a/src/pmproxy/pmproxy.options b/src/pmproxy/pmproxy.options index 298c767..bd83e0c 100644 --- a/src/pmproxy/pmproxy.options +++ b/src/pmproxy/pmproxy.options @@ -11,11 +11,11 @@ # make log go someplace else # -l /some/place/else -# restricting incomming PDU size to prevent DOS attacks +# maximum incoming PDU size (default 64KB) # -L 16384 -# assume identity of some user other than root --U nobody +# assume identity of some user other than "pcp" +# -U nobody # emergency messages before logfile created # -x /tmp/desperate.log