Add syslog logging

This commit is contained in:
Oliver Sturm 2009-10-23 10:31:22 +02:00 committed by Stefan Bühler
parent b471b98d5c
commit a65ce431b9
3 changed files with 106 additions and 18 deletions

5
README
View File

@ -75,6 +75,8 @@ REQUIRE_PWENT If set, target users are reuired to have passwd-entries. The
ALLOW_CHECKGID If set, enabled the CHECK_GID feature, q.v. Defaults to 1. ALLOW_CHECKGID If set, enabled the CHECK_GID feature, q.v. Defaults to 1.
USE_SYSLOG If set, log errors and (if enabled) debug messages to syslog.
Defaults to 1.
The following configuration parameters shouldn't normally be changed. In case you have a The following configuration parameters shouldn't normally be changed. In case you have a
clash with some other ENV arguments to the target program, they can be changed, however. clash with some other ENV arguments to the target program, they can be changed, however.
@ -99,6 +101,8 @@ ENV_CHECK_GID The same as ENV_UID, but controls the name of the CHECK_GI
ENV_NON_RESIDENT The same as ENV_UID, but controls the name of the NON_RESIDENT ENV_NON_RESIDENT The same as ENV_UID, but controls the name of the NON_RESIDENT
parameter. Defaults to "NON_RESIDENT=". parameter. Defaults to "NON_RESIDENT=".
ENV_DEBUG Controls the name of environment variable used to enable debug
output to syslog (depends on USE_SYSLOG)
--------------------- ---------------------
COMPILE AND INSTALL COMPILE AND INSTALL
@ -161,6 +165,7 @@ NON_RESIDENT If set (to anything), the wrapper will drop privileges and
web-server) to terminate the target process, and thus prevents it web-server) to terminate the target process, and thus prevents it
from effectively managing it. from effectively managing it.
DEBUG If set to anything, debug output to syslog is enabled.
----------------------------------- -----------------------------------
SECURITY CHECKS AND THEIR REASONS SECURITY CHECKS AND THEIR REASONS

View File

@ -63,6 +63,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define ENV_TARGET "TARGET=" #define ENV_TARGET "TARGET="
#define ENV_CHECK_GID "CHECK_GID=" #define ENV_CHECK_GID "CHECK_GID="
#define ENV_NON_RESIDENT "NON_RESIDENT=" #define ENV_NON_RESIDENT "NON_RESIDENT="
#define ENV_DEBUG "DEBUG"
/* Return values for various errors. */ /* Return values for various errors. */
@ -126,6 +127,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sys/types.h> #include <sys/types.h>
#include <grp.h> #include <grp.h>
#if USE_SYSLOG
# include <syslog.h>
# include <errno.h>
#else /* USE_SYSLOG */
/* this should be after all includes */
# undef SKIP
# undef openlog
# undef setlogmask
# undef syslog
# define SKIP do { } while (0)
# define openlog(...) SKIP
# define setlogmask(...) SKIP
# define syslog(...) SKIP
#endif /* USE_SYSLOG */
/* The global child PID and previous SIGTERM handler. */ /* The global child PID and previous SIGTERM handler. */
int pid; int pid;
void (*oldHandler)(int); void (*oldHandler)(int);
@ -147,9 +168,15 @@ void sigTermHandler(int signal)
/* Down to business. */ /* Down to business. */
int main(int argc, char* argv[], char* envp[]) int main(int argc, char* argv[], char* envp[])
{ {
openlog("execwrap", LOG_PID, LOG_AUTHPRIV);
setlogmask(LOG_UPTO(LOG_NOTICE));
/* Verify parent UID. Only the super user and PARENT_UID are allowed. */ /* Verify parent UID. Only the super user and PARENT_UID are allowed. */
if(getuid() != 0 && getuid() != PARENT_UID) return RC_CALLER_UID; int myuid = getuid();
if(myuid != 0 && myuid != PARENT_UID) {
syslog(LOG_ERR, "exiting with RC_CALLER_UID, UID=%d", myuid);
return RC_CALLER_UID;
}
/* Command line options. */ /* Command line options. */
if(argc > 1) if(argc > 1)
@ -176,6 +203,13 @@ int main(int argc, char* argv[], char* envp[])
return RC_BAD_OPTION; return RC_BAD_OPTION;
} }
/* we need this check before the loop over the environment,
as we cannot rely on it to be the first env var we find */
if (NULL != getenv(ENV_DEBUG)) {
setlogmask(LOG_UPTO(LOG_DEBUG));
syslog(LOG_DEBUG, "activated debug output");
}
/* Grab stuff from environment, and set defaults. */ /* Grab stuff from environment, and set defaults. */
uid_t uid = DEFAULT_UID; uid_t uid = DEFAULT_UID;
gid_t gid = DEFAULT_GID; gid_t gid = DEFAULT_GID;
@ -186,19 +220,26 @@ int main(int argc, char* argv[], char* envp[])
char* s; char* s;
while(NULL != (s = *p++)) while(NULL != (s = *p++))
{ {
/* Target UID. */ /* Target UID. */
if(!strncmp(ENV_UID, s, ENV_UID_LEN)) if(!strncmp(ENV_UID, s, ENV_UID_LEN))
{ {
uid = atoi(s + ENV_UID_LEN); uid = atoi(s + ENV_UID_LEN);
if(uid < TARGET_MIN_UID) return RC_TARGET_UID; if(uid < TARGET_MIN_UID) {
syslog(LOG_ERR, "exiting with RC_TARGET_UID, UID=%d", uid);
return RC_TARGET_UID;
}
syslog(LOG_DEBUG, "target UID is %d", uid);
} }
/* Target GID. */ /* Target GID. */
if(!strncmp(ENV_GID, s, ENV_GID_LEN)) if(!strncmp(ENV_GID, s, ENV_GID_LEN))
{ {
gid = atoi(s + ENV_GID_LEN); gid = atoi(s + ENV_GID_LEN);
if(gid < TARGET_MIN_GID) return RC_TARGET_GID; if(gid < TARGET_MIN_GID) {
syslog(LOG_ERR, "exiting with RC_TARGET_GID, GID=%d", gid);
return RC_TARGET_GID;
}
syslog(LOG_DEBUG, "target GID is %d", gid);
} }
/* Target script. */ /* Target script. */
@ -206,7 +247,11 @@ int main(int argc, char* argv[], char* envp[])
{ {
target = s + ENV_TARGET_LEN; target = s + ENV_TARGET_LEN;
if((target[0] != '/') || strchr(target, '~') || strstr(target, "..") || if((target[0] != '/') || strchr(target, '~') || strstr(target, "..") ||
strncmp(TARGET_PATH_PREFIX, target, TARGET_PATH_PREFIX_LEN)) return RC_TARGET; strncmp(TARGET_PATH_PREFIX, target, TARGET_PATH_PREFIX_LEN)) {
syslog(LOG_ERR, "exiting with RC_TARGET, target=%s", target);
return RC_TARGET;
}
syslog(LOG_DEBUG, "TARGET is %s", target);
} }
/* Check GID instead of UID. */ /* Check GID instead of UID. */
@ -226,14 +271,24 @@ int main(int argc, char* argv[], char* envp[])
} }
/* See if we got all we need. */ /* See if we got all we need. */
if(!target) return RC_MISSING_CONFIG; if(!target) {
syslog(LOG_ERR, "exiting with RC_MISSING_CONFIG, no TARGET");
return RC_MISSING_CONFIG;
}
/* Fetch user information from passwd. */ /* Fetch user information from passwd. */
struct passwd *pwent = getpwuid(uid); struct passwd *pwent = getpwuid(uid);
#if REQUIRE_PWENT #if REQUIRE_PWENT
if(!pwent) return RC_MISSING_PWENT; if(!pwent) {
syslog(LOG_ERR, "exiting with RC_MISSING_PWENT, pwent required by config, but not found");
return RC_MISSING_PWENT;
}
#endif #endif
if (pwent) {
syslog(LOG_DEBUG, "pwent found, pw_name=%s", pwent->pw_name);
}
/* Install the SIGTERM handler. */ /* Install the SIGTERM handler. */
if(!non_resident) if(!non_resident)
{ {
@ -246,23 +301,41 @@ int main(int argc, char* argv[], char* envp[])
{ {
/* We're in the child. Drop privileges and set the group list. */ /* We're in the child. Drop privileges and set the group list. */
if(pwent && initgroups(pwent->pw_name, gid)) return RC_SETGID; if(pwent && initgroups(pwent->pw_name, gid)) {
if(setgid(gid)) return RC_SETGID; syslog(LOG_ERR, "exiting with RC_SETGID, initgroup failed, errno=%d", errno);
if(setuid(uid)) return RC_SETUID; return RC_SETGID;
}
if(setgid(gid)) {
syslog(LOG_ERR, "exiting with RC_SETGID, setgid failed, errno=%d", errno);
return RC_SETGID;
}
if(setuid(uid)) {
syslog(LOG_ERR, "exiting with RC_SETUID, setuid failed, errno=%d", errno);
return RC_SETUID;
}
/* Stat the target script. */ /* Stat the target script. */
char uid_ok = 1; char uid_ok = 1;
struct stat stat_buf; struct stat stat_buf;
if(stat(target, &stat_buf)) return RC_STAT; if(stat(target, &stat_buf)) {
syslog(LOG_ERR, "exiting with RC_STAT, stat failed, errno=%d", errno);
return RC_STAT;
}
int modes = stat_buf.st_mode; int modes = stat_buf.st_mode;
/* Never allow world-write. */ /* Never allow world-write. */
if(modes & S_IWOTH) return RC_WORLD_WRITE; if(modes & S_IWOTH) {
syslog(LOG_ERR, "exiting with RC_WORLD_WRITE, modes=%d", modes);
return RC_WORLD_WRITE;
}
/* Only allow user miss-match if check_gid is set. */ /* Only allow user miss-match if check_gid is set. */
if(uid != stat_buf.st_uid) if(uid != stat_buf.st_uid)
{ {
if(!check_gid) return RC_WRONG_USER; if(!check_gid) {
syslog(LOG_ERR, "exiting with RC_WRONG_USER");
return RC_WRONG_USER;
}
uid_ok = 0; uid_ok = 0;
} }
@ -270,11 +343,18 @@ int main(int argc, char* argv[], char* envp[])
Also, don't allow if neither user or group match. */ Also, don't allow if neither user or group match. */
if(gid != stat_buf.st_gid) if(gid != stat_buf.st_gid)
{ {
if(modes & S_IWGRP) return RC_GROUP_WRITE; if(modes & S_IWGRP) {
if(!uid_ok) return RC_WRONG_GROUP; syslog(LOG_ERR, "exiting with RC_GROUP_WRITE, modes=%d", modes);
return RC_GROUP_WRITE;
}
if(!uid_ok) {
syslog(LOG_ERR, "exiting with RC_WRONG_GROUP");
return RC_WRONG_GROUP;
}
} }
/* All checks passed, let's become the target! */ /* All checks passed, let's become the target! */
syslog(LOG_NOTICE, "executing target=%s, UID=%d, GID=%d", target, uid, gid);
execl(target, target, NULL); execl(target, target, NULL);
return RC_EXEC; return RC_EXEC;

View File

@ -32,3 +32,6 @@ See the README for documentation.
/* Allow use of the CHECK_GID mode? */ /* Allow use of the CHECK_GID mode? */
#define ALLOW_CHECKGID 1 #define ALLOW_CHECKGID 1
/* Use syslog to report errors */
#define USE_SYSLOG 1