summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <Todd.Miller@sudo.ws>2022-01-28 08:52:42 -0700
committerTodd C. Miller <Todd.Miller@sudo.ws>2022-01-28 08:52:42 -0700
commitd877deed1edd31a24e634ed651c9b32253587b73 (patch)
tree1863ca2deb25f8e8aa00e488968da2c2bfcf729f
parent2c14ad69b00f5bafb63feebdf5931d5392fc219f (diff)
downloadsudo-d877deed1edd31a24e634ed651c9b32253587b73.tar.gz
Add new log_passwords and passprompt_regex settings.
When logging terminal input, if log_passwords is false and any of the regular expressions in the passprompt_regex list are found in the terminal output, terminal input will be replaced with '*' characters until a newline or carriage return is found in the input or an output character is received.
-rw-r--r--docs/sudo_logsrvd.conf.man.in54
-rw-r--r--docs/sudo_logsrvd.conf.mdoc.in52
-rw-r--r--examples/sudo_logsrvd.conf10
-rw-r--r--logsrvd/logsrvd.h4
-rw-r--r--logsrvd/logsrvd_conf.c86
-rw-r--r--logsrvd/logsrvd_local.c20
6 files changed, 205 insertions, 21 deletions
diff --git a/docs/sudo_logsrvd.conf.man.in b/docs/sudo_logsrvd.conf.man.in
index 5e44c15fd..d34aa10a8 100644
--- a/docs/sudo_logsrvd.conf.man.in
+++ b/docs/sudo_logsrvd.conf.man.in
@@ -16,7 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.TH "SUDO_LOGSRVD.CONF" "@mansectform@" "January 19, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
+.TH "SUDO_LOGSRVD.CONF" "@mansectform@" "January 27, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh
.if n .ad l
.SH "NAME"
@@ -268,7 +268,7 @@ The default value is
.TP 10n
tls_verify = bool
If true,
-\fBsudo_logsrvd.conf\fR
+\fBsudo_logsrvd\fR
will validate its own certificate at startup time or when the
configuration is changed.
If false, no verification is performed of the server certificate.
@@ -590,6 +590,35 @@ is set, it will be used instead of the user's primary group-ID.
By default, I/O log files and directories are created with user and
group-ID 0.
.TP 10n
+log_passwords = bool
+Most programs that require a user's password will disable echo before
+reading the password to avoid displaying the plaintext password on
+the screen.
+However, if terminal input is being logged,
+the password will still be present in the I/O log.
+If
+\fIlog_passwords\fR
+is set to
+\fRfalse\fR,
+\fBsudo_logsrvd\fR
+will attempt to prevent passwords from being logged.
+It does this by using the regular expressions in
+\fIpassprompt_regex\fR
+to match a password prompt in the terminal output buffer.
+When a match is found, input characters in the I/O log will be replaced with
+\(oq*\(cq
+until either a line feed or carriage return is found in the terminal input
+or a new terminal output buffer is received.
+If, however, a program displays characters as the user types them
+(such as
+\fBsudo\fR
+when the
+\fIpwfeedback\fR
+option is set), only the
+first character of the password will be replaced in the I/O log.
+The default value is
+\fRtrue\fR.
+.TP 10n
maxseq = number
The maximum sequence number that will be substituted for the
\(lq\fR%{seq}\fR\(rq
@@ -606,6 +635,17 @@ base 36 sequence number
\(lqZZZZZZ\(rq)
will be silently truncated to 2176782336.
The default value is 2176782336.
+.TP 10n
+passprompt_regex = string
+One or more POSIX extended regular expressions used to
+match password prompts in the terminal output when
+\fIlog_passwords\fR
+is disabled.
+Multiple
+\fIpassprompt_regex\fR
+settings may be specified.
+The default value is
+\(lq[Pp]assword[: ]*\(rq.
.SS "eventlog"
The
\fIeventlog\fR
@@ -948,6 +988,10 @@ Sudo log server configuration file
# specified by iolog_mode.
#iolog_mode = 0600
+# If disabled, sudo_logsrvd will attempt to avoid logging plaintext
+# password in the terminal input using passprompt_regex.
+#log_passwords = true
+
# The maximum sequence number that will be substituted for the "%{seq}"
# escape in the I/O log file. While the value substituted for "%{seq}"
# is in base 36, maxseq itself should be expressed in decimal. Values
@@ -955,6 +999,12 @@ Sudo log server configuration file
# number "ZZZZZZ") will be silently truncated to 2176782336.
#maxseq = 2176782336
+# One or more POSIX extended regular expressions used to match
+# password prompts in the terminal output when log_passwords is
+# disabled. Multiple passprompt_regex settings may be specified.
+#passprompt_regex = [Pp]assword[: ]*
+#passprompt_regex = [Pp]assword for [a-z0-9]+: *
+
[eventlog]
# Where to log accept, reject, exit, and alert events.
# Accepted values are syslog, logfile, or none.
diff --git a/docs/sudo_logsrvd.conf.mdoc.in b/docs/sudo_logsrvd.conf.mdoc.in
index 539bc14c7..bcf0bda36 100644
--- a/docs/sudo_logsrvd.conf.mdoc.in
+++ b/docs/sudo_logsrvd.conf.mdoc.in
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd January 19, 2022
+.Dd January 27, 2022
.Dt SUDO_LOGSRVD.CONF @mansectform@
.Os Sudo @PACKAGE_VERSION@
.Sh NAME
@@ -229,7 +229,7 @@ The default value is
.Pa /etc/ssl/sudo/private/logsrvd_key.pem .
.It tls_verify = bool
If true,
-.Nm
+.Nm sudo_logsrvd
will validate its own certificate at startup time or when the
configuration is changed.
If false, no verification is performed of the server certificate.
@@ -522,6 +522,34 @@ If
is set, it will be used instead of the user's primary group-ID.
By default, I/O log files and directories are created with user and
group-ID 0.
+.It log_passwords = bool
+Most programs that require a user's password will disable echo before
+reading the password to avoid displaying the plaintext password on
+the screen.
+However, if terminal input is being logged,
+the password will still be present in the I/O log.
+If
+.Em log_passwords
+is set to
+.Li false ,
+.Nm sudo_logsrvd
+will attempt to prevent passwords from being logged.
+It does this by using the regular expressions in
+.Em passprompt_regex
+to match a password prompt in the terminal output buffer.
+When a match is found, input characters in the I/O log will be replaced with
+.Ql *
+until either a line feed or carriage return is found in the terminal input
+or a new terminal output buffer is received.
+If, however, a program displays characters as the user types them
+(such as
+.Nm sudo
+when the
+.Em pwfeedback
+option is set), only the
+first character of the password will be replaced in the I/O log.
+The default value is
+.Li true .
.It maxseq = number
The maximum sequence number that will be substituted for the
.Dq Li %{seq}
@@ -538,6 +566,16 @@ base 36 sequence number
.Dq ZZZZZZ )
will be silently truncated to 2176782336.
The default value is 2176782336.
+.It passprompt_regex = string
+One or more POSIX extended regular expressions used to
+match password prompts in the terminal output when
+.Em log_passwords
+is disabled.
+Multiple
+.Em passprompt_regex
+settings may be specified.
+The default value is
+.Dq [Pp]assword[: ]* .
.El
.Ss eventlog
The
@@ -876,6 +914,10 @@ Sudo log server configuration file
# specified by iolog_mode.
#iolog_mode = 0600
+# If disabled, sudo_logsrvd will attempt to avoid logging plaintext
+# password in the terminal input using passprompt_regex.
+#log_passwords = true
+
# The maximum sequence number that will be substituted for the "%{seq}"
# escape in the I/O log file. While the value substituted for "%{seq}"
# is in base 36, maxseq itself should be expressed in decimal. Values
@@ -883,6 +925,12 @@ Sudo log server configuration file
# number "ZZZZZZ") will be silently truncated to 2176782336.
#maxseq = 2176782336
+# One or more POSIX extended regular expressions used to match
+# password prompts in the terminal output when log_passwords is
+# disabled. Multiple passprompt_regex settings may be specified.
+#passprompt_regex = [Pp]assword[: ]*
+#passprompt_regex = [Pp]assword for [a-z0-9]+: *
+
[eventlog]
# Where to log accept, reject, exit, and alert events.
# Accepted values are syslog, logfile, or none.
diff --git a/examples/sudo_logsrvd.conf b/examples/sudo_logsrvd.conf
index 32dbd821b..5fd7d3f40 100644
--- a/examples/sudo_logsrvd.conf
+++ b/examples/sudo_logsrvd.conf
@@ -179,6 +179,10 @@
# specified by iolog_mode.
#iolog_mode = 0600
+# If disabled, sudo_logsrvd will attempt to avoid logging plaintext
+# password in the terminal input using passprompt_regex.
+#log_passwords = true
+
# The maximum sequence number that will be substituted for the "%{seq}"
# escape in the I/O log file. While the value substituted for "%{seq}"
# is in base 36, maxseq itself should be expressed in decimal. Values
@@ -186,6 +190,12 @@
# number "ZZZZZZ") will be silently truncated to 2176782336.
#maxseq = 2176782336
+# One or more POSIX extended regular expressions used to match
+# password prompts in the terminal output when log_passwords is
+# disabled. Multiple passprompt_regex settings may be specified.
+#passprompt_regex = [Pp]assword[: ]*
+#passprompt_regex = [Pp]assword for [a-z0-9]+: *
+
[eventlog]
# Where to log accept, reject, exit, and alert events.
# Accepted values are syslog, logfile, or none.
diff --git a/logsrvd/logsrvd.h b/logsrvd/logsrvd.h
index ef8191b65..2565e999a 100644
--- a/logsrvd/logsrvd.h
+++ b/logsrvd/logsrvd.h
@@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: ISC
*
- * Copyright (c) 2019-2021 Todd C. Miller <Todd.Miller@sudo.ws>
+ * Copyright (c) 2019-2022 Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -208,6 +208,8 @@ struct connection_closure *connection_closure_alloc(int fd, bool tls, bool relay
bool logsrvd_conf_read(const char *path);
const char *logsrvd_conf_iolog_dir(void);
const char *logsrvd_conf_iolog_file(void);
+bool logsrvd_conf_iolog_log_passwords(void);
+void *logsrvd_conf_iolog_passprompt_regex(void);
struct server_address_list *logsrvd_conf_server_listen_address(void);
struct server_address_list *logsrvd_conf_relay_address(void);
const char *logsrvd_conf_relay_dir(void);
diff --git a/logsrvd/logsrvd_conf.c b/logsrvd/logsrvd_conf.c
index 836f1a7d8..993c4b4f6 100644
--- a/logsrvd/logsrvd_conf.c
+++ b/logsrvd/logsrvd_conf.c
@@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: ISC
*
- * Copyright (c) 2019-2021 Todd C. Miller <Todd.Miller@sudo.ws>
+ * Copyright (c) 2019-2022 Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -148,12 +148,14 @@ static struct logsrvd_config {
bool compress;
bool flush;
bool gid_set;
+ bool log_passwords;
uid_t uid;
gid_t gid;
mode_t mode;
unsigned int maxseq;
char *iolog_dir;
char *iolog_file;
+ void *passprompt_regex;
} iolog;
struct logsrvd_config_eventlog {
int log_type;
@@ -215,6 +217,18 @@ logsrvd_conf_iolog_file(void)
return logsrvd_config->iolog.iolog_file;
}
+bool
+logsrvd_conf_iolog_log_passwords(void)
+{
+ return logsrvd_config->iolog.log_passwords;
+}
+
+void *
+logsrvd_conf_iolog_passprompt_regex(void)
+{
+ return logsrvd_config->iolog.passprompt_regex;
+}
+
/* server getters */
struct server_address_list *
logsrvd_conf_server_listen_address(void)
@@ -368,6 +382,19 @@ cb_iolog_compress(struct logsrvd_config *config, const char *str, size_t offset)
}
static bool
+cb_iolog_log_passwords(struct logsrvd_config *config, const char *str, size_t offset)
+{
+ int val;
+ debug_decl(cb_iolog_log_passwords, SUDO_DEBUG_UTIL);
+
+ if ((val = sudo_strtobool(str)) == -1)
+ debug_return_bool(false);
+
+ config->iolog.log_passwords = val;
+ debug_return_bool(true);
+}
+
+static bool
cb_iolog_flush(struct logsrvd_config *config, const char *str, size_t offset)
{
int val;
@@ -449,6 +476,20 @@ cb_iolog_maxseq(struct logsrvd_config *config, const char *str, size_t offset)
debug_return_bool(true);
}
+static bool
+cb_iolog_passprompt_regex(struct logsrvd_config *config, const char *str, size_t offset)
+{
+ debug_decl(cb_iolog_passprompt_regex, SUDO_DEBUG_UTIL);
+
+ if (config->iolog.passprompt_regex == NULL) {
+ /* Lazy alloc of the passprompt regex handle. */
+ config->iolog.passprompt_regex = iolog_pwfilt_alloc();
+ if (config->iolog.passprompt_regex == NULL)
+ debug_return_bool(false);
+ }
+ debug_return_bool(iolog_pwfilt_add(config->iolog.passprompt_regex, str));
+}
+
/* Server callbacks */
static bool
append_address(struct server_address_list *addresses, const char *str,
@@ -1069,7 +1110,9 @@ static struct logsrvd_config_entry iolog_conf_entries[] = {
{ "iolog_user", cb_iolog_user },
{ "iolog_group", cb_iolog_group },
{ "iolog_mode", cb_iolog_mode },
+ { "log_passwords", cb_iolog_log_passwords },
{ "maxseq", cb_iolog_maxseq },
+ { "passprompt_regex", cb_iolog_passprompt_regex },
{ NULL }
};
@@ -1242,7 +1285,7 @@ logsrvd_stub_close_log(int type, FILE *fp)
return;
}
-/* Set eventlog configuration settings from on logsrvd config. */
+/* Set eventlog configuration settings from logsrvd config. */
static void
logsrvd_conf_eventlog_setconf(struct logsrvd_config *config)
{
@@ -1262,6 +1305,22 @@ logsrvd_conf_eventlog_setconf(struct logsrvd_config *config)
debug_return;
}
+/* Set I/O log configuration settings from logsrvd config. */
+static void
+logsrvd_conf_iolog_setconf(struct logsrvd_config *config)
+{
+ debug_decl(logsrvd_conf_iolog_setconf, SUDO_DEBUG_UTIL);
+
+ iolog_set_defaults();
+ iolog_set_compress(config->iolog.compress);
+ iolog_set_flush(config->iolog.flush);
+ iolog_set_owner(config->iolog.uid, config->iolog.gid);
+ iolog_set_mode(config->iolog.mode);
+ iolog_set_maxseq(config->iolog.maxseq);
+
+ debug_return;
+}
+
/*
* Conversation function for use by sudo_warn/sudo_fatal.
* Logs to stdout/stderr.
@@ -1483,6 +1542,7 @@ logsrvd_conf_free(struct logsrvd_config *config)
/* struct logsrvd_config_iolog */
free(config->iolog.iolog_dir);
free(config->iolog.iolog_file);
+ iolog_pwfilt_free(config->iolog.passprompt_regex);
/* struct logsrvd_config_logfile */
free(config->logfile.path);
@@ -1573,6 +1633,7 @@ logsrvd_conf_alloc(void)
config->iolog.uid = ROOT_UID;
config->iolog.gid = ROOT_GID;
config->iolog.gid_set = false;
+ config->iolog.log_passwords = true;
/* Event log defaults */
config->eventlog.log_type = EVLOG_SYSLOG;
@@ -1619,6 +1680,12 @@ logsrvd_conf_apply(struct logsrvd_config *config)
#endif
debug_decl(logsrvd_conf_apply, SUDO_DEBUG_UTIL);
+ /* There can be multiple passprompt regular expressions. */
+ if (config->iolog.passprompt_regex == NULL) {
+ if (!cb_iolog_passprompt_regex(config, PASSPROMPT_REGEX, 0))
+ debug_return_bool(false);
+ }
+
/* There can be multiple addresses so we can't set a default earlier. */
if (TAILQ_EMPTY(&config->server.addresses.addrs)) {
/* Enable plaintext listender. */
@@ -1738,15 +1805,12 @@ logsrvd_conf_apply(struct logsrvd_config *config)
break;
}
- /* Set I/O log library settings */
- iolog_set_defaults();
- iolog_set_compress(config->iolog.compress);
- iolog_set_flush(config->iolog.flush);
- iolog_set_owner(config->iolog.uid, config->iolog.gid);
- iolog_set_mode(config->iolog.mode);
- iolog_set_maxseq(config->iolog.maxseq);
-
- /* Set event log config */
+ /*
+ * Update event and I/O log library config and install the new
+ * logsrvd config. We must not fail past this point or the event
+ * and I/O log config will be inconsistent with the logsrvd config.
+ */
+ logsrvd_conf_iolog_setconf(config);
logsrvd_conf_eventlog_setconf(config);
logsrvd_conf_free(logsrvd_config);
diff --git a/logsrvd/logsrvd_local.c b/logsrvd/logsrvd_local.c
index 819c60bb2..a4cbb9fdb 100644
--- a/logsrvd/logsrvd_local.c
+++ b/logsrvd/logsrvd_local.c
@@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: ISC
*
- * Copyright (c) 2019-2021 Todd C. Miller <Todd.Miller@sudo.ws>
+ * Copyright (c) 2019-2022 Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -523,8 +523,9 @@ store_iobuf_local(int iofd, IoBuffer *iobuf, uint8_t *buf, size_t buflen,
struct connection_closure *closure)
{
const struct eventlog *evlog = closure->evlog;
+ struct ProtobufCBinaryData data = iobuf->data;
+ char tbuf[1024], *newbuf = NULL;
const char *errstr;
- char tbuf[1024];
int len;
debug_decl(store_iobuf_local, SUDO_DEBUG_UTIL);
@@ -538,19 +539,27 @@ store_iobuf_local(int iofd, IoBuffer *iobuf, uint8_t *buf, size_t buflen,
/* FIXME - assumes IOFD_* matches IO_EVENT_* */
len = snprintf(tbuf, sizeof(tbuf), "%d %lld.%09d %zu\n",
iofd, (long long)iobuf->delay->tv_sec, (int)iobuf->delay->tv_nsec,
- iobuf->data.len);
+ data.len);
if (len < 0 || len >= ssizeof(tbuf)) {
sudo_warnx(U_("unable to format timing buffer, length %d"), len);
goto bad;
}
+ if (!logsrvd_conf_iolog_log_passwords()) {
+ if (!iolog_pwfilt_run(logsrvd_conf_iolog_passprompt_regex(), iofd,
+ (char *)data.data, data.len, &newbuf))
+ goto bad;
+ if (newbuf != NULL)
+ data.data = (uint8_t *)newbuf;
+ }
+
/* Write to specified I/O log file. */
- if (!iolog_write(&closure->iolog_files[iofd], iobuf->data.data,
- iobuf->data.len, &errstr)) {
+ if (!iolog_write(&closure->iolog_files[iofd], data.data, data.len, &errstr)) {
sudo_warnx(U_("%s/%s: %s"), evlog->iolog_path, iolog_fd_to_name(iofd),
errstr);
goto bad;
}
+ free(newbuf);
/* Write timing data. */
if (!iolog_write(&closure->iolog_files[IOFD_TIMING], tbuf,
@@ -574,6 +583,7 @@ store_iobuf_local(int iofd, IoBuffer *iobuf, uint8_t *buf, size_t buflen,
debug_return_bool(true);
bad:
+ free(newbuf);
if (closure->errstr == NULL)
closure->errstr = _("error writing IoBuffer");
debug_return_bool(false);