Hi, there is a long standing problem with logging in chroots. Especially, when you use %u in ChrootDirectory, it is nearly impossible to have /dev/log in every possible chroot for all users. It seems to be important mainly for sftp-internal session which are simply configurable to be chrooted and where admins would like to log sftp session commands. I have put together a patch which introduces a new configuration option LogViaMonitor. When this option is 'yes', then postauth unprivileged processes log via their monitor process instead of via standard channels (syslog, stderr). I've removed closefrom() from close_child_fds() in order not to close m_log_send_fd socket before sftp_server_main() is called. And I've put it to a part of code where it's clear that there will be exec(). I'd appreciate any comment or suggestion. Petr -- Petr Lautrbach
diff --git a/log.c b/log.c index 32e1d2e..d4caeb5 100644 --- a/log.c +++ b/log.c @@ -241,6 +241,11 @@ debug3(const char *fmt,...) void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) { + log_init_handler(av0, level, facility, on_stderr, 1); +} + +void +log_init_handler(char *av0, LogLevel level, SyslogFacility facility, int on_stderr, int reset_handler) { #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) struct syslog_data sdata = SYSLOG_DATA_INIT; #endif @@ -264,8 +269,10 @@ log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) exit(1); } - log_handler = NULL; - log_handler_ctx = NULL; + if (reset_handler) { + log_handler = NULL; + log_handler_ctx = NULL; + } log_on_stderr = on_stderr; if (on_stderr) diff --git a/log.h b/log.h index ae7df25..30c3310 100644 --- a/log.h +++ b/log.h @@ -49,6 +49,7 @@ typedef enum { typedef void (log_handler_fn)(LogLevel, const char *, void *); void log_init(char *, LogLevel, SyslogFacility, int); +void log_init_handler(char *, LogLevel, SyslogFacility, int, int); void log_change_level(LogLevel); int log_is_on_stderr(void); void log_redirect_stderr_to(const char *); diff --git a/monitor.c b/monitor.c index dbe29f1..9f72979 100644 --- a/monitor.c +++ b/monitor.c @@ -363,6 +363,8 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) close(pmonitor->m_log_sendfd); pmonitor->m_log_sendfd = pmonitor->m_recvfd = -1; + pmonitor->m_state = "preauth"; + authctxt = _authctxt; memset(authctxt, 0, sizeof(*authctxt)); @@ -475,6 +477,8 @@ monitor_child_postauth(struct monitor *pmonitor) signal(SIGXFSZ, SIG_IGN); #endif + pmonitor->m_state = "postauth"; + if (compat20) { mon_dispatch = mon_dispatch_postauth20; @@ -543,7 +547,7 @@ monitor_read_log(struct monitor *pmonitor) if (log_level_name(level) == NULL) fatal("%s: invalid log level %u (corrupted message?)", __func__, level); - do_log2(level, "%s [preauth]", msg); + do_log2(level, "%s [%s]", msg, pmonitor->m_state); buffer_free(&logmsg); free(msg); @@ -2051,13 +2055,14 @@ monitor_init(void) mm_init_compression(mon->m_zlib); } + mon->m_state = ""; return mon; } void monitor_reinit(struct monitor *mon) { - monitor_openfds(mon, 0); + monitor_openfds(mon, options.log_via_monitor); } #ifdef GSSAPI diff --git a/monitor.h b/monitor.h index 5bc41b5..78ed40d 100644 --- a/monitor.h +++ b/monitor.h @@ -77,6 +77,7 @@ struct monitor { struct mm_master *m_zlib; struct Kex **m_pkex; pid_t m_pid; + char *m_state; }; struct monitor *monitor_init(void); diff --git a/servconf.c b/servconf.c index b7f3294..c973ee4 100644 --- a/servconf.c +++ b/servconf.c @@ -99,6 +99,7 @@ initialize_server_options(ServerOptions *options) options->tcp_keep_alive = -1; options->log_facility = SYSLOG_FACILITY_NOT_SET; options->log_level = SYSLOG_LEVEL_NOT_SET; + options->log_via_monitor = -1; options->rhosts_rsa_authentication = -1; options->hostbased_authentication = -1; options->hostbased_uses_name_from_packet_only = -1; @@ -230,6 +231,8 @@ fill_default_server_options(ServerOptions *options) options->log_facility = SYSLOG_FACILITY_AUTH; if (options->log_level == SYSLOG_LEVEL_NOT_SET) options->log_level = SYSLOG_LEVEL_INFO; + if (options->log_via_monitor == -1) + options->log_via_monitor = 0; if (options->rhosts_rsa_authentication == -1) options->rhosts_rsa_authentication = 0; if (options->hostbased_authentication == -1) @@ -334,7 +337,7 @@ typedef enum { sUsePAM, /* Standard Options */ sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime, - sPermitRootLogin, sLogFacility, sLogLevel, + sPermitRootLogin, sLogFacility, sLogLevel, sLogViaMonitor, sRhostsRSAAuthentication, sRSAAuthentication, sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, sKerberosGetAFSToken, @@ -394,6 +397,7 @@ static struct { { "permitrootlogin", sPermitRootLogin, SSHCFG_ALL }, { "syslogfacility", sLogFacility, SSHCFG_GLOBAL }, { "loglevel", sLogLevel, SSHCFG_GLOBAL }, + { "logviamonitor", sLogViaMonitor, SSHCFG_GLOBAL }, { "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL }, { "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_ALL }, { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL }, @@ -1239,6 +1243,10 @@ process_server_config_line(ServerOptions *options, char *line, *log_level_ptr = (LogLevel) value; break; + case sLogViaMonitor: + intptr = &options->log_via_monitor; + goto parse_flag; + case sAllowTcpForwarding: intptr = &options->allow_tcp_forwarding; multistate_ptr = multistate_tcpfwd; @@ -2090,6 +2098,7 @@ dump_config(ServerOptions *o) /* string arguments requiring a lookup */ dump_cfg_string(sLogLevel, log_level_name(o->log_level)); dump_cfg_string(sLogFacility, log_facility_name(o->log_facility)); + dump_cfg_fmtint(sLogViaMonitor, o->log_via_monitor); /* string array arguments */ dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files, diff --git a/servconf.h b/servconf.h index 766db3a..f61365c 100644 --- a/servconf.h +++ b/servconf.h @@ -95,6 +95,7 @@ typedef struct { struct ForwardOptions fwd_opts; /* forwarding options */ SyslogFacility log_facility; /* Facility for system logging. */ LogLevel log_level; /* Level for system logging. */ + int log_via_monitor; /* Monitor childs will log via monitor instead of syslog/stderr */ int rhosts_rsa_authentication; /* If true, permit rhosts RSA * authentication. */ int hostbased_authentication; /* If true, permit ssh2 hostbased auth */ diff --git a/session.c b/session.c index 3e96557..e870f1f 100644 --- a/session.c +++ b/session.c @@ -505,8 +505,8 @@ do_exec_no_pty(Session *s, const char *command) is_child = 1; /* Child. Reinitialize the log since the pid has changed. */ - log_init(__progname, options.log_level, - options.log_facility, log_stderr); + log_init_handler(__progname, options.log_level, + options.log_facility, log_stderr, !options.log_via_monitor); /* * Create a new session and process group since the 4.4BSD @@ -674,8 +674,8 @@ do_exec_pty(Session *s, const char *command) close(ptymaster); /* Child. Reinitialize the log because the pid has changed. */ - log_init(__progname, options.log_level, - options.log_facility, log_stderr); + log_init_handler(__progname, options.log_level, + options.log_facility, log_stderr, !options.log_via_monitor); /* Close the master side of the pseudo tty. */ close(ptyfd); @@ -1645,14 +1645,6 @@ child_close_fds(void) * descriptors left by system functions. They will be closed later. */ endpwent(); - - /* - * Close any extra open file descriptors so that we don't have them - * hanging around in clients. Note that we want to do this after - * initgroups, because at least on Solaris 2.3 it leaves file - * descriptors open. - */ - closefrom(STDERR_FILENO + 1); } /* @@ -1798,8 +1790,6 @@ do_child(Session *s, const char *command) exit(1); } - closefrom(STDERR_FILENO + 1); - if (!options.use_login) do_rc_files(s, shell); @@ -1826,9 +1816,17 @@ do_child(Session *s, const char *command) #ifdef WITH_SELINUX ssh_selinux_change_context("sftpd_t"); #endif - exit(sftp_server_main(i, argv, s->pw)); + exit(sftp_server_main(i, argv, s->pw, 0)); } + /* + * Close any extra open file descriptors so that we don't have them + * hanging around in clients. Note that we want to do this after + * initgroups, because at least on Solaris 2.3 it leaves file + * descriptors open. + */ + closefrom(STDERR_FILENO + 1); + fflush(NULL); if (options.use_login) { diff --git a/sftp-server-main.c b/sftp-server-main.c index 7e644ab..e162b7a 100644 --- a/sftp-server-main.c +++ b/sftp-server-main.c @@ -47,5 +47,5 @@ main(int argc, char **argv) return 1; } - return (sftp_server_main(argc, argv, user_pw)); + return (sftp_server_main(argc, argv, user_pw, 0)); } diff --git a/sftp-server.c b/sftp-server.c index 0177130..8fa7fc7 100644 --- a/sftp-server.c +++ b/sftp-server.c @@ -1440,7 +1440,7 @@ sftp_server_usage(void) } int -sftp_server_main(int argc, char **argv, struct passwd *user_pw) +sftp_server_main(int argc, char **argv, struct passwd *user_pw, int reset_handler) { fd_set *rset, *wset; int i, in, out, max, ch, skipargs = 0, log_stderr = 0; @@ -1453,7 +1453,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) extern char *__progname; __progname = ssh_get_progname(argv[0]); - log_init(__progname, log_level, log_facility, log_stderr); + log_init_handler(__progname, log_level, log_facility, log_stderr, reset_handler); pw = pwcopy(user_pw); @@ -1524,7 +1524,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) } } - log_init(__progname, log_level, log_facility, log_stderr); + log_init_handler(__progname, log_level, log_facility, log_stderr, reset_handler); #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) /* diff --git a/sftp.h b/sftp.h index 2bde8bb..ddf1a39 100644 --- a/sftp.h +++ b/sftp.h @@ -97,5 +97,5 @@ struct passwd; -int sftp_server_main(int, char **, struct passwd *); +int sftp_server_main(int, char **, struct passwd *, int); void sftp_server_cleanup_exit(int) __attribute__((noreturn)); diff --git a/sshd.c b/sshd.c index 481d001..c86ac41 100644 --- a/sshd.c +++ b/sshd.c @@ -751,6 +751,12 @@ privsep_postauth(Authctxt *authctxt) close(pmonitor->m_sendfd); pmonitor->m_sendfd = -1; + close(pmonitor->m_log_recvfd); + pmonitor->m_log_recvfd = -1; + + /* Arrange for logging to be sent to the monitor */ + if (options.log_via_monitor) + set_log_handler(mm_log_handler, pmonitor); /* Demote the private keys to public keys. */ demote_sensitive_data(); diff --git a/sshd_config b/sshd_config index e9045bc..cd95720 100644 --- a/sshd_config +++ b/sshd_config @@ -37,6 +37,7 @@ # obsoletes QuietMode and FascistLogging #SyslogFacility AUTH #LogLevel INFO +#LogViaMonitor no # Authentication: diff --git a/sshd_config.5 b/sshd_config.5 index 6766b57..fc0aa0a 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -795,6 +795,16 @@ The default is INFO. DEBUG and DEBUG1 are equivalent. DEBUG2 and DEBUG3 each specify higher levels of debugging output. Logging with a DEBUG level violates the privacy of users and is not recommended. +.It Cm LogViaMonitor +Specifies whether postauth unprivileged processes should log via a monitor. +The +.Dq no +means standard logging, while +.Dq yes +means that processes will log via its monitor process which is usefull when +there's no standard method available (missing /dev/log in chroots). +The default is +.Dq no . .It Cm MACs Specifies the available MAC (message authentication code) algorithms. The MAC algorithm is used in protocol version 2
_______________________________________________ openssh-unix-dev mailing list openssh-unix-dev@xxxxxxxxxxx https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev