Add support for logging server warning/error messages.
We can use sudo_warn_set_conversation() to set a conversation function that either writes to a log file or calls syslog().
This commit is contained in:
@@ -16,7 +16,7 @@
|
|||||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
.\"
|
.\"
|
||||||
.TH "SUDO_LOGSRVD.CONF" "@mansectform@" "May 1, 2021" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
|
.TH "SUDO_LOGSRVD.CONF" "@mansectform@" "June 13, 2021" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
|
||||||
.nh
|
.nh
|
||||||
.if n .ad l
|
.if n .ad l
|
||||||
.SH "NAME"
|
.SH "NAME"
|
||||||
@@ -128,6 +128,23 @@ Multiple
|
|||||||
lines may be specified to listen on more than one port or interface.
|
lines may be specified to listen on more than one port or interface.
|
||||||
.RE
|
.RE
|
||||||
.TP 10n
|
.TP 10n
|
||||||
|
server_log = string
|
||||||
|
Where to log server warning and error messages.
|
||||||
|
Supported values are
|
||||||
|
\fInone\fR,
|
||||||
|
\fIstderr\fR,
|
||||||
|
\fIsyslog\fR,
|
||||||
|
or a path name beginning with the
|
||||||
|
\(oq/\(cq
|
||||||
|
character.
|
||||||
|
Note that a value of
|
||||||
|
\fIstderr\fR
|
||||||
|
is only effective when used in conjunction with the
|
||||||
|
\fB\-n\fR
|
||||||
|
option.
|
||||||
|
The default value is
|
||||||
|
\fIsyslog\fR.
|
||||||
|
.TP 10n
|
||||||
pid_file = path
|
pid_file = path
|
||||||
The path to the file containing the process ID of the running
|
The path to the file containing the process ID of the running
|
||||||
\fBsudo_logsrvd\fR.
|
\fBsudo_logsrvd\fR.
|
||||||
@@ -704,6 +721,12 @@ When a message is split, additional parts will include the string
|
|||||||
after the user name and before the continued command line arguments.
|
after the user name and before the continued command line arguments.
|
||||||
JSON-format log entries are never split and are not affected by
|
JSON-format log entries are never split and are not affected by
|
||||||
\fImaxlen\fR.
|
\fImaxlen\fR.
|
||||||
|
.TP 6n
|
||||||
|
server_facility = string
|
||||||
|
Syslog facility if syslog is being used for server warning messages.
|
||||||
|
See above for a list of supported facilities.
|
||||||
|
Defaults to
|
||||||
|
\fRdaemon\fR
|
||||||
.SS "logfile"
|
.SS "logfile"
|
||||||
The
|
The
|
||||||
\fIlogfile\fR
|
\fIlogfile\fR
|
||||||
@@ -761,6 +784,9 @@ Sudo log server configuration file
|
|||||||
# The file containing the ID of the running sudo_logsrvd process.
|
# The file containing the ID of the running sudo_logsrvd process.
|
||||||
#pid_file = @rundir@/sudo_logsrvd.pid
|
#pid_file = @rundir@/sudo_logsrvd.pid
|
||||||
|
|
||||||
|
# Where to log server warnings: none, stderr, syslog, or a path name.
|
||||||
|
#server_log = syslog
|
||||||
|
|
||||||
# If true, enable the SO_KEEPALIVE socket option on client connections.
|
# If true, enable the SO_KEEPALIVE socket option on client connections.
|
||||||
#tcp_keepalive = true
|
#tcp_keepalive = true
|
||||||
|
|
||||||
@@ -955,6 +981,10 @@ Sudo log server configuration file
|
|||||||
# client.
|
# client.
|
||||||
#alert_priority = alert
|
#alert_priority = alert
|
||||||
|
|
||||||
|
# The syslog facility to use for server warning messages.
|
||||||
|
# Defaults to daemon.
|
||||||
|
#server_facility = daemon
|
||||||
|
|
||||||
[logfile]
|
[logfile]
|
||||||
# The path to the file-based event log.
|
# The path to the file-based event log.
|
||||||
# This path must be fully-qualified and start with a '/' character.
|
# This path must be fully-qualified and start with a '/' character.
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
.\"
|
.\"
|
||||||
.Dd May 1, 2021
|
.Dd June 13, 2021
|
||||||
.Dt SUDO_LOGSRVD.CONF @mansectform@
|
.Dt SUDO_LOGSRVD.CONF @mansectform@
|
||||||
.Os Sudo @PACKAGE_VERSION@
|
.Os Sudo @PACKAGE_VERSION@
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -114,6 +114,22 @@ plaintext and TLS connections.
|
|||||||
Multiple
|
Multiple
|
||||||
.Em listen_address
|
.Em listen_address
|
||||||
lines may be specified to listen on more than one port or interface.
|
lines may be specified to listen on more than one port or interface.
|
||||||
|
.It server_log = string
|
||||||
|
Where to log server warning and error messages.
|
||||||
|
Supported values are
|
||||||
|
.Em none ,
|
||||||
|
.Em stderr ,
|
||||||
|
.Em syslog ,
|
||||||
|
or a path name beginning with the
|
||||||
|
.Ql /
|
||||||
|
character.
|
||||||
|
Note that a value of
|
||||||
|
.Em stderr
|
||||||
|
is only effective when used in conjunction with the
|
||||||
|
.Fl n
|
||||||
|
option.
|
||||||
|
The default value is
|
||||||
|
.Em syslog .
|
||||||
.It pid_file = path
|
.It pid_file = path
|
||||||
The path to the file containing the process ID of the running
|
The path to the file containing the process ID of the running
|
||||||
.Nm sudo_logsrvd .
|
.Nm sudo_logsrvd .
|
||||||
@@ -634,6 +650,11 @@ When a message is split, additional parts will include the string
|
|||||||
after the user name and before the continued command line arguments.
|
after the user name and before the continued command line arguments.
|
||||||
JSON-format log entries are never split and are not affected by
|
JSON-format log entries are never split and are not affected by
|
||||||
.Em maxlen .
|
.Em maxlen .
|
||||||
|
.It server_facility = string
|
||||||
|
Syslog facility if syslog is being used for server warning messages.
|
||||||
|
See above for a list of supported facilities.
|
||||||
|
Defaults to
|
||||||
|
.Li daemon
|
||||||
.El
|
.El
|
||||||
.Ss logfile
|
.Ss logfile
|
||||||
The
|
The
|
||||||
@@ -692,6 +713,9 @@ Sudo log server configuration file
|
|||||||
# The file containing the ID of the running sudo_logsrvd process.
|
# The file containing the ID of the running sudo_logsrvd process.
|
||||||
#pid_file = @rundir@/sudo_logsrvd.pid
|
#pid_file = @rundir@/sudo_logsrvd.pid
|
||||||
|
|
||||||
|
# Where to log server warnings: none, stderr, syslog, or a path name.
|
||||||
|
#server_log = syslog
|
||||||
|
|
||||||
# If true, enable the SO_KEEPALIVE socket option on client connections.
|
# If true, enable the SO_KEEPALIVE socket option on client connections.
|
||||||
#tcp_keepalive = true
|
#tcp_keepalive = true
|
||||||
|
|
||||||
@@ -886,6 +910,10 @@ Sudo log server configuration file
|
|||||||
# client.
|
# client.
|
||||||
#alert_priority = alert
|
#alert_priority = alert
|
||||||
|
|
||||||
|
# The syslog facility to use for server warning messages.
|
||||||
|
# Defaults to daemon.
|
||||||
|
#server_facility = daemon
|
||||||
|
|
||||||
[logfile]
|
[logfile]
|
||||||
# The path to the file-based event log.
|
# The path to the file-based event log.
|
||||||
# This path must be fully-qualified and start with a '/' character.
|
# This path must be fully-qualified and start with a '/' character.
|
||||||
|
@@ -24,6 +24,9 @@
|
|||||||
# The file containing the ID of the running sudo_logsrvd process.
|
# The file containing the ID of the running sudo_logsrvd process.
|
||||||
#pid_file = /var/run/sudo/sudo_logsrvd.pid
|
#pid_file = /var/run/sudo/sudo_logsrvd.pid
|
||||||
|
|
||||||
|
# Where to log server warnings: none, stderr, syslog, or a path name.
|
||||||
|
#server_log = syslog
|
||||||
|
|
||||||
# If true, enable the SO_KEEPALIVE socket option on client connections.
|
# If true, enable the SO_KEEPALIVE socket option on client connections.
|
||||||
#tcp_keepalive = true
|
#tcp_keepalive = true
|
||||||
|
|
||||||
@@ -219,6 +222,10 @@
|
|||||||
# client.
|
# client.
|
||||||
#alert_priority = alert
|
#alert_priority = alert
|
||||||
|
|
||||||
|
# The syslog facility to use for server warning messages.
|
||||||
|
# Defaults to daemon.
|
||||||
|
#server_facility = daemon
|
||||||
|
|
||||||
[logfile]
|
[logfile]
|
||||||
# The path to the file-based event log.
|
# The path to the file-based event log.
|
||||||
# This path must be fully-qualified and start with a '/' character.
|
# This path must be fully-qualified and start with a '/' character.
|
||||||
|
@@ -87,6 +87,7 @@ static struct connection_list connections = TAILQ_HEAD_INITIALIZER(connections);
|
|||||||
static struct listener_list listeners = TAILQ_HEAD_INITIALIZER(listeners);
|
static struct listener_list listeners = TAILQ_HEAD_INITIALIZER(listeners);
|
||||||
static const char server_id[] = "Sudo Audit Server " PACKAGE_VERSION;
|
static const char server_id[] = "Sudo Audit Server " PACKAGE_VERSION;
|
||||||
static const char *conf_file = _PATH_SUDO_LOGSRVD_CONF;
|
static const char *conf_file = _PATH_SUDO_LOGSRVD_CONF;
|
||||||
|
static bool is_early = true;
|
||||||
|
|
||||||
/* Event loop callbacks. */
|
/* Event loop callbacks. */
|
||||||
static void client_msg_cb(int fd, int what, void *v);
|
static void client_msg_cb(int fd, int what, void *v);
|
||||||
@@ -1819,6 +1820,9 @@ daemonize(bool nofork)
|
|||||||
int fd;
|
int fd;
|
||||||
debug_decl(daemonize, SUDO_DEBUG_UTIL);
|
debug_decl(daemonize, SUDO_DEBUG_UTIL);
|
||||||
|
|
||||||
|
if (chdir("/") == -1)
|
||||||
|
sudo_warn("chdir(\"/\")");
|
||||||
|
|
||||||
if (!nofork) {
|
if (!nofork) {
|
||||||
switch (sudo_debug_fork()) {
|
switch (sudo_debug_fork()) {
|
||||||
case -1:
|
case -1:
|
||||||
@@ -1835,21 +1839,38 @@ daemonize(bool nofork)
|
|||||||
if (setsid() == -1)
|
if (setsid() == -1)
|
||||||
sudo_fatal("setsid");
|
sudo_fatal("setsid");
|
||||||
write_pidfile();
|
write_pidfile();
|
||||||
}
|
|
||||||
|
|
||||||
if (chdir("/") == -1)
|
if ((fd = open(_PATH_DEVNULL, O_RDWR)) != -1) {
|
||||||
sudo_warn("chdir(\"/\")");
|
(void) dup2(fd, STDIN_FILENO);
|
||||||
if ((fd = open(_PATH_DEVNULL, O_RDWR)) != -1) {
|
(void) dup2(fd, STDOUT_FILENO);
|
||||||
(void) dup2(fd, STDIN_FILENO);
|
(void) dup2(fd, STDERR_FILENO);
|
||||||
(void) dup2(fd, STDOUT_FILENO);
|
if (fd > STDERR_FILENO)
|
||||||
(void) dup2(fd, STDERR_FILENO);
|
(void) close(fd);
|
||||||
if (fd > STDERR_FILENO)
|
}
|
||||||
(void) close(fd);
|
} else {
|
||||||
|
if ((fd = open(_PATH_DEVNULL, O_RDWR)) != -1) {
|
||||||
|
/* Preserve stdout/stderr in nofork mode (if open). */
|
||||||
|
(void) dup2(fd, STDIN_FILENO);
|
||||||
|
if (fcntl(STDOUT_FILENO, F_GETFL) == -1)
|
||||||
|
(void) dup2(fd, STDOUT_FILENO);
|
||||||
|
if (fcntl(STDERR_FILENO, F_GETFL) == -1)
|
||||||
|
(void) dup2(fd, STDERR_FILENO);
|
||||||
|
if (fd > STDERR_FILENO)
|
||||||
|
(void) close(fd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
is_early = false;
|
||||||
|
|
||||||
debug_return;
|
debug_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The early flag is used to decide whether sudo_warn() goes to stderr too. */
|
||||||
|
bool
|
||||||
|
logsrvd_is_early(void)
|
||||||
|
{
|
||||||
|
return is_early;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usage(bool fatal)
|
usage(bool fatal)
|
||||||
{
|
{
|
||||||
|
@@ -197,6 +197,7 @@ bool fmt_log_id_message(const char *id, struct connection_closure *closure);
|
|||||||
bool schedule_error_message(const char *errstr, struct connection_closure *closure);
|
bool schedule_error_message(const char *errstr, struct connection_closure *closure);
|
||||||
struct connection_buffer *get_free_buf(size_t, struct connection_closure *closure);
|
struct connection_buffer *get_free_buf(size_t, struct connection_closure *closure);
|
||||||
struct connection_closure *connection_closure_alloc(int fd, bool tls, bool relay_only, struct sudo_event_base *base);
|
struct connection_closure *connection_closure_alloc(int fd, bool tls, bool relay_only, struct sudo_event_base *base);
|
||||||
|
bool logsrvd_is_early(void);
|
||||||
|
|
||||||
/* logsrvd_conf.c */
|
/* logsrvd_conf.c */
|
||||||
bool logsrvd_conf_read(const char *path);
|
bool logsrvd_conf_read(const char *path);
|
||||||
|
@@ -78,6 +78,13 @@
|
|||||||
((_c)->relay._f != -1 ? (_c)->relay._f : (_c)->server._f)
|
((_c)->relay._f != -1 ? (_c)->relay._f : (_c)->server._f)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum server_log_type {
|
||||||
|
SERVER_LOG_NONE,
|
||||||
|
SERVER_LOG_STDERR,
|
||||||
|
SERVER_LOG_SYSLOG,
|
||||||
|
SERVER_LOG_FILE
|
||||||
|
};
|
||||||
|
|
||||||
struct logsrvd_config;
|
struct logsrvd_config;
|
||||||
typedef bool (*logsrvd_conf_cb_t)(struct logsrvd_config *, const char *, size_t);
|
typedef bool (*logsrvd_conf_cb_t)(struct logsrvd_config *, const char *, size_t);
|
||||||
|
|
||||||
@@ -102,6 +109,9 @@ static struct logsrvd_config {
|
|||||||
struct address_list_container addresses;
|
struct address_list_container addresses;
|
||||||
struct timespec timeout;
|
struct timespec timeout;
|
||||||
bool tcp_keepalive;
|
bool tcp_keepalive;
|
||||||
|
enum server_log_type log_type;
|
||||||
|
FILE *log_stream;
|
||||||
|
char *log_file;
|
||||||
char *pid_file;
|
char *pid_file;
|
||||||
#if defined(HAVE_OPENSSL)
|
#if defined(HAVE_OPENSSL)
|
||||||
char *tls_key_path;
|
char *tls_key_path;
|
||||||
@@ -152,6 +162,7 @@ static struct logsrvd_config {
|
|||||||
} eventlog;
|
} eventlog;
|
||||||
struct logsrvd_config_syslog {
|
struct logsrvd_config_syslog {
|
||||||
unsigned int maxlen;
|
unsigned int maxlen;
|
||||||
|
int server_facility;
|
||||||
int facility;
|
int facility;
|
||||||
int acceptpri;
|
int acceptpri;
|
||||||
int rejectpri;
|
int rejectpri;
|
||||||
@@ -560,6 +571,37 @@ cb_server_pid_file(struct logsrvd_config *config, const char *str, size_t offset
|
|||||||
debug_return_bool(true);
|
debug_return_bool(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
cb_server_log(struct logsrvd_config *config, const char *str, size_t offset)
|
||||||
|
{
|
||||||
|
char *copy = NULL;
|
||||||
|
enum server_log_type log_type = SERVER_LOG_NONE;
|
||||||
|
debug_decl(cb_server_log, SUDO_DEBUG_UTIL);
|
||||||
|
|
||||||
|
/* An empty value means to disable the server log. */
|
||||||
|
if (*str != '\0') {
|
||||||
|
if (*str != '/') {
|
||||||
|
log_type = SERVER_LOG_FILE;
|
||||||
|
if ((copy = strdup(str)) == NULL) {
|
||||||
|
sudo_warn(NULL);
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
} else if (strcmp(str, "stderr") == 0) {
|
||||||
|
log_type = SERVER_LOG_STDERR;
|
||||||
|
} else if (strcmp(str, "syslog") == 0) {
|
||||||
|
log_type = SERVER_LOG_SYSLOG;
|
||||||
|
} else {
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(config->server.log_file);
|
||||||
|
config->server.log_file = copy;
|
||||||
|
config->server.log_type = log_type;
|
||||||
|
|
||||||
|
debug_return_bool(true);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(HAVE_OPENSSL)
|
#if defined(HAVE_OPENSSL)
|
||||||
static bool
|
static bool
|
||||||
cb_tls_key(struct logsrvd_config *config, const char *path, size_t offset)
|
cb_tls_key(struct logsrvd_config *config, const char *path, size_t offset)
|
||||||
@@ -806,6 +848,23 @@ cb_syslog_maxlen(struct logsrvd_config *config, const char *str, size_t offset)
|
|||||||
debug_return_bool(true);
|
debug_return_bool(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
cb_syslog_server_facility(struct logsrvd_config *config, const char *str, size_t offset)
|
||||||
|
{
|
||||||
|
int logfac;
|
||||||
|
debug_decl(cb_syslog_server_facility, SUDO_DEBUG_UTIL);
|
||||||
|
|
||||||
|
if (!sudo_str2logfac(str, &logfac)) {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
|
"invalid syslog priority %s", str);
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
config->syslog.server_facility = logfac;
|
||||||
|
|
||||||
|
debug_return_bool(true);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
cb_syslog_facility(struct logsrvd_config *config, const char *str, size_t offset)
|
cb_syslog_facility(struct logsrvd_config *config, const char *str, size_t offset)
|
||||||
{
|
{
|
||||||
@@ -940,6 +999,7 @@ static struct logsrvd_config_entry server_conf_entries[] = {
|
|||||||
{ "timeout", cb_server_timeout },
|
{ "timeout", cb_server_timeout },
|
||||||
{ "tcp_keepalive", cb_server_keepalive },
|
{ "tcp_keepalive", cb_server_keepalive },
|
||||||
{ "pid_file", cb_server_pid_file },
|
{ "pid_file", cb_server_pid_file },
|
||||||
|
{ "server_log", cb_server_log },
|
||||||
#if defined(HAVE_OPENSSL)
|
#if defined(HAVE_OPENSSL)
|
||||||
{ "tls_key", cb_tls_key, offsetof(struct logsrvd_config, server.tls_key_path) },
|
{ "tls_key", cb_tls_key, offsetof(struct logsrvd_config, server.tls_key_path) },
|
||||||
{ "tls_cacert", cb_tls_cacert, offsetof(struct logsrvd_config, server.tls_cacert_path) },
|
{ "tls_cacert", cb_tls_cacert, offsetof(struct logsrvd_config, server.tls_cacert_path) },
|
||||||
@@ -993,6 +1053,7 @@ static struct logsrvd_config_entry eventlog_conf_entries[] = {
|
|||||||
|
|
||||||
static struct logsrvd_config_entry syslog_conf_entries[] = {
|
static struct logsrvd_config_entry syslog_conf_entries[] = {
|
||||||
{ "maxlen", cb_syslog_maxlen },
|
{ "maxlen", cb_syslog_maxlen },
|
||||||
|
{ "server_facility", cb_syslog_server_facility },
|
||||||
{ "facility", cb_syslog_facility },
|
{ "facility", cb_syslog_facility },
|
||||||
{ "reject_priority", cb_syslog_rejectpri },
|
{ "reject_priority", cb_syslog_rejectpri },
|
||||||
{ "accept_priority", cb_syslog_acceptpri },
|
{ "accept_priority", cb_syslog_acceptpri },
|
||||||
@@ -1098,28 +1159,25 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static FILE *
|
static FILE *
|
||||||
logsrvd_open_eventlog(struct logsrvd_config *config)
|
logsrvd_open_log_file(const char *path, int flags)
|
||||||
{
|
{
|
||||||
mode_t oldmask;
|
mode_t oldmask;
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
const char *omode;
|
const char *omode;
|
||||||
int fd, flags;
|
int fd;
|
||||||
debug_decl(logsrvd_open_eventlog, SUDO_DEBUG_UTIL);
|
debug_decl(logsrvd_open_log_file, SUDO_DEBUG_UTIL);
|
||||||
|
|
||||||
/* Cannot append to a JSON file. */
|
if (ISSET(flags, O_APPEND)) {
|
||||||
if (config->eventlog.log_format == EVLOG_JSON) {
|
|
||||||
flags = O_RDWR|O_CREAT;
|
|
||||||
omode = "w";
|
|
||||||
} else {
|
|
||||||
flags = O_WRONLY|O_APPEND|O_CREAT;
|
|
||||||
omode = "a";
|
omode = "a";
|
||||||
|
} else {
|
||||||
|
omode = "w";
|
||||||
}
|
}
|
||||||
oldmask = umask(S_IRWXG|S_IRWXO);
|
oldmask = umask(S_IRWXG|S_IRWXO);
|
||||||
fd = open(config->logfile.path, flags, S_IRUSR|S_IWUSR);
|
fd = open(path, flags, S_IRUSR|S_IWUSR);
|
||||||
(void)umask(oldmask);
|
(void)umask(oldmask);
|
||||||
if (fd == -1 || (fp = fdopen(fd, omode)) == NULL) {
|
if (fd == -1 || (fp = fdopen(fd, omode)) == NULL) {
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
"unable to open log file %s", config->logfile.path);
|
"unable to open log file %s", path);
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
@@ -1127,6 +1185,21 @@ logsrvd_open_eventlog(struct logsrvd_config *config)
|
|||||||
debug_return_ptr(fp);
|
debug_return_ptr(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FILE *
|
||||||
|
logsrvd_open_eventlog(struct logsrvd_config *config)
|
||||||
|
{
|
||||||
|
int flags;
|
||||||
|
debug_decl(logsrvd_open_eventlog, SUDO_DEBUG_UTIL);
|
||||||
|
|
||||||
|
/* Cannot append to a JSON file. */
|
||||||
|
if (config->eventlog.log_format == EVLOG_JSON) {
|
||||||
|
flags = O_RDWR|O_CREAT;
|
||||||
|
} else {
|
||||||
|
flags = O_WRONLY|O_APPEND|O_CREAT;
|
||||||
|
}
|
||||||
|
debug_return_ptr(logsrvd_open_log_file(config->logfile.path, flags));
|
||||||
|
}
|
||||||
|
|
||||||
static FILE *
|
static FILE *
|
||||||
logsrvd_stub_open_log(int type, const char *logfile)
|
logsrvd_stub_open_log(int type, const char *logfile)
|
||||||
{
|
{
|
||||||
@@ -1160,6 +1233,175 @@ logsrvd_conf_eventlog_setconf(struct logsrvd_config *config)
|
|||||||
debug_return;
|
debug_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Conversation function for use by sudo_warn/sudo_fatal.
|
||||||
|
* Logs to stdout/stderr.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
logsrvd_conv_stderr(int num_msgs, const struct sudo_conv_message msgs[],
|
||||||
|
struct sudo_conv_reply replies[], struct sudo_conv_callback *callback)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
debug_decl(logsrvd_conv_stderr, SUDO_DEBUG_UTIL);
|
||||||
|
|
||||||
|
for (i = 0; i < num_msgs; i++) {
|
||||||
|
if (fputs(msgs[i].msg, stderr) == EOF)
|
||||||
|
debug_return_int(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_return_int(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Conversation function for use by sudo_warn/sudo_fatal.
|
||||||
|
* Acts as a no-op log sink.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
logsrvd_conv_none(int num_msgs, const struct sudo_conv_message msgs[],
|
||||||
|
struct sudo_conv_reply replies[], struct sudo_conv_callback *callback)
|
||||||
|
{
|
||||||
|
/* Also write to stderr if still in the foreground. */
|
||||||
|
if (logsrvd_is_early()) {
|
||||||
|
(void)logsrvd_conv_stderr(num_msgs, msgs, replies, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Conversation function for use by sudo_warn/sudo_fatal.
|
||||||
|
* Logs to syslog.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
logsrvd_conv_syslog(int num_msgs, const struct sudo_conv_message msgs[],
|
||||||
|
struct sudo_conv_reply replies[], struct sudo_conv_callback *callback)
|
||||||
|
{
|
||||||
|
char *buf = NULL, *cp = NULL;
|
||||||
|
const char *progname;
|
||||||
|
size_t proglen, bufsize = 0;
|
||||||
|
int i;
|
||||||
|
debug_decl(logsrvd_conv_syslog, SUDO_DEBUG_UTIL);
|
||||||
|
|
||||||
|
/* Also write to stderr if still in the foreground. */
|
||||||
|
if (logsrvd_is_early()) {
|
||||||
|
(void)logsrvd_conv_stderr(num_msgs, msgs, replies, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Concat messages into a flag string that we can syslog.
|
||||||
|
*/
|
||||||
|
progname = getprogname();
|
||||||
|
proglen = strlen(progname);
|
||||||
|
for (i = 0; i < num_msgs; i++) {
|
||||||
|
const char *msg = msgs[i].msg;
|
||||||
|
size_t len = strlen(msg);
|
||||||
|
size_t used = (size_t)(cp - buf);
|
||||||
|
|
||||||
|
/* Strip leading "sudo_logsrvd: " prefix. */
|
||||||
|
if (strncmp(msg, progname, proglen) == 0) {
|
||||||
|
msg += proglen;
|
||||||
|
len -= proglen;
|
||||||
|
if (len == 0) {
|
||||||
|
/* Skip over ": " string that follows program name. */
|
||||||
|
if (i + 1 < num_msgs && strcmp(msgs[i + 1].msg, ": ") == 0) {
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (msg[0] == ':' && msg[1] == ' ') {
|
||||||
|
/* Handle "progname: " */
|
||||||
|
msg += 2;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Strip off trailing newlines. */
|
||||||
|
while (len > 1 && msgs[i].msg[len - 1] == '\n')
|
||||||
|
len--;
|
||||||
|
if (len == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (len >= bufsize - used) {
|
||||||
|
bufsize += 1024;
|
||||||
|
char *tmp = realloc(buf, bufsize);
|
||||||
|
if (tmp == NULL) {
|
||||||
|
free(buf);
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
|
"unable to allocate memory");
|
||||||
|
debug_return_int(-1);
|
||||||
|
}
|
||||||
|
buf = tmp;
|
||||||
|
cp = tmp + used;
|
||||||
|
}
|
||||||
|
memcpy(cp, msgs[i].msg, len);
|
||||||
|
cp[len] = '\0';
|
||||||
|
cp += len;
|
||||||
|
}
|
||||||
|
if (buf != NULL) {
|
||||||
|
openlog(progname, 0, logsrvd_config->syslog.server_facility);
|
||||||
|
syslog(LOG_ERR, "%s", buf);
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
/* Restore old syslog settings. */
|
||||||
|
if (logsrvd_config->eventlog.log_type == EVLOG_SYSLOG)
|
||||||
|
openlog("sudo", 0, logsrvd_config->syslog.facility);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_return_int(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Conversation function for use by sudo_warn/sudo_fatal.
|
||||||
|
* Logs to an already-open log file.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
logsrvd_conv_logfile(int num_msgs, const struct sudo_conv_message msgs[],
|
||||||
|
struct sudo_conv_reply replies[], struct sudo_conv_callback *callback)
|
||||||
|
{
|
||||||
|
const char *progname;
|
||||||
|
size_t proglen;
|
||||||
|
int i;
|
||||||
|
debug_decl(logsrvd_conv_logfile, SUDO_DEBUG_UTIL);
|
||||||
|
|
||||||
|
/* Also write to stderr if still in the foreground. */
|
||||||
|
if (logsrvd_is_early()) {
|
||||||
|
(void)logsrvd_conv_stderr(num_msgs, msgs, replies, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logsrvd_config->server.log_stream == NULL) {
|
||||||
|
errno = EBADF;
|
||||||
|
debug_return_int(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
progname = getprogname();
|
||||||
|
proglen = strlen(progname);
|
||||||
|
for (i = 0; i < num_msgs; i++) {
|
||||||
|
const char *msg = msgs[i].msg;
|
||||||
|
size_t len = strlen(msg);
|
||||||
|
|
||||||
|
/* Strip leading "sudo_logsrvd: " prefix. */
|
||||||
|
if (strncmp(msg, progname, proglen) == 0) {
|
||||||
|
msg += proglen;
|
||||||
|
len -= proglen;
|
||||||
|
if (len == 0) {
|
||||||
|
/* Skip over ": " string that follows program name. */
|
||||||
|
if (i + 1 < num_msgs && strcmp(msgs[i + 1].msg, ": ") == 0) {
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (msg[0] == ':' && msg[1] == ' ') {
|
||||||
|
/* Handle "progname: " */
|
||||||
|
msg += 2;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fwrite(msgs[i].msg, len, 1, logsrvd_config->server.log_stream) != 1)
|
||||||
|
debug_return_int(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_return_int(0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Free the specified struct logsrvd_config and its contents. */
|
/* Free the specified struct logsrvd_config and its contents. */
|
||||||
static void
|
static void
|
||||||
logsrvd_conf_free(struct logsrvd_config *config)
|
logsrvd_conf_free(struct logsrvd_config *config)
|
||||||
@@ -1172,6 +1414,9 @@ logsrvd_conf_free(struct logsrvd_config *config)
|
|||||||
/* struct logsrvd_config_server */
|
/* struct logsrvd_config_server */
|
||||||
address_list_delref(&config->server.addresses.addrs);
|
address_list_delref(&config->server.addresses.addrs);
|
||||||
free(config->server.pid_file);
|
free(config->server.pid_file);
|
||||||
|
free(config->server.log_file);
|
||||||
|
if (config->server.log_stream != NULL)
|
||||||
|
fclose(config->server.log_stream);
|
||||||
#if defined(HAVE_OPENSSL)
|
#if defined(HAVE_OPENSSL)
|
||||||
free(config->server.tls_key_path);
|
free(config->server.tls_key_path);
|
||||||
free(config->server.tls_cert_path);
|
free(config->server.tls_cert_path);
|
||||||
@@ -1245,6 +1490,7 @@ logsrvd_conf_alloc(void)
|
|||||||
config->server.addresses.refcnt = 1;
|
config->server.addresses.refcnt = 1;
|
||||||
config->server.timeout.tv_sec = DEFAULT_SOCKET_TIMEOUT_SEC;
|
config->server.timeout.tv_sec = DEFAULT_SOCKET_TIMEOUT_SEC;
|
||||||
config->server.tcp_keepalive = true;
|
config->server.tcp_keepalive = true;
|
||||||
|
config->server.log_type = SERVER_LOG_SYSLOG;
|
||||||
config->server.pid_file = strdup(_PATH_SUDO_LOGSRVD_PID);
|
config->server.pid_file = strdup(_PATH_SUDO_LOGSRVD_PID);
|
||||||
if (config->server.pid_file == NULL) {
|
if (config->server.pid_file == NULL) {
|
||||||
sudo_warn(NULL);
|
sudo_warn(NULL);
|
||||||
@@ -1298,6 +1544,7 @@ logsrvd_conf_alloc(void)
|
|||||||
|
|
||||||
/* Syslog defaults */
|
/* Syslog defaults */
|
||||||
config->syslog.maxlen = 960;
|
config->syslog.maxlen = 960;
|
||||||
|
config->syslog.server_facility = LOG_DAEMON;
|
||||||
if (!cb_syslog_facility(config, LOGFAC, 0)) {
|
if (!cb_syslog_facility(config, LOGFAC, 0)) {
|
||||||
sudo_warnx(U_("unknown syslog facility %s"), LOGFAC);
|
sudo_warnx(U_("unknown syslog facility %s"), LOGFAC);
|
||||||
goto bad;
|
goto bad;
|
||||||
@@ -1411,6 +1658,31 @@ logsrvd_conf_apply(struct logsrvd_config *config)
|
|||||||
if (TAILQ_EMPTY(&config->relay.relays.addrs))
|
if (TAILQ_EMPTY(&config->relay.relays.addrs))
|
||||||
config->relay.store_first = false;
|
config->relay.store_first = false;
|
||||||
|
|
||||||
|
/* Open server log if specified. */
|
||||||
|
switch (config->server.log_type) {
|
||||||
|
case SERVER_LOG_SYSLOG:
|
||||||
|
sudo_warn_set_conversation(logsrvd_conv_syslog);
|
||||||
|
break;
|
||||||
|
case SERVER_LOG_FILE:
|
||||||
|
config->server.log_stream =
|
||||||
|
logsrvd_open_log_file(config->server.log_file, O_WRONLY|O_APPEND|O_CREAT);
|
||||||
|
if (config->server.log_stream == NULL)
|
||||||
|
debug_return_bool(false);
|
||||||
|
sudo_warn_set_conversation(logsrvd_conv_logfile);
|
||||||
|
break;
|
||||||
|
case SERVER_LOG_NONE:
|
||||||
|
sudo_warn_set_conversation(logsrvd_conv_none);
|
||||||
|
break;
|
||||||
|
case SERVER_LOG_STDERR:
|
||||||
|
/* Default is stderr. */
|
||||||
|
sudo_warn_set_conversation(NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
|
"cannot open unknown log type %d", config->eventlog.log_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Open event log if specified. */
|
/* Open event log if specified. */
|
||||||
switch (config->eventlog.log_type) {
|
switch (config->eventlog.log_type) {
|
||||||
case EVLOG_SYSLOG:
|
case EVLOG_SYSLOG:
|
||||||
|
Reference in New Issue
Block a user