diff options
author | djm@openbsd.org <djm@openbsd.org> | 2018-10-02 12:40:07 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2018-10-02 22:41:01 +1000 |
commit | cd98925c6405e972dc9f211afc7e75e838abe81c (patch) | |
tree | 295a45cea9fce0ad18a8463d604e1fdce8246768 /session.c | |
parent | dba50258333f2604a87848762af07ba2cc40407a (diff) |
upstream: Add server support for signalling sessions via the SSH
channel/ session protocol. Signalling is only supported to sesssions that are
not subsystems and were not started with a forced command.
Long requested in bz#1424
Based on a patch from markus@ and reworked by dtucker@;
ok markus@ dtucker@
OpenBSD-Commit-ID: 4bea826f575862eaac569c4bedd1056a268be1c3
Diffstat (limited to 'session.c')
-rw-r--r-- | session.c | 76 |
1 files changed, 75 insertions, 1 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: session.c,v 1.305 2018/07/25 13:56:23 deraadt Exp $ */ | 1 | /* $OpenBSD: session.c,v 1.306 2018/10/02 12:40:07 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
4 | * All rights reserved | 4 | * All rights reserved |
@@ -705,7 +705,9 @@ do_exec(struct ssh *ssh, Session *s, const char *command) | |||
705 | command = auth_opts->force_command; | 705 | command = auth_opts->force_command; |
706 | forced = "(key-option)"; | 706 | forced = "(key-option)"; |
707 | } | 707 | } |
708 | s->forced = 0; | ||
708 | if (forced != NULL) { | 709 | if (forced != NULL) { |
710 | s->forced = 1; | ||
709 | if (IS_INTERNAL_SFTP(command)) { | 711 | if (IS_INTERNAL_SFTP(command)) { |
710 | s->is_subsystem = s->is_subsystem ? | 712 | s->is_subsystem = s->is_subsystem ? |
711 | SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR; | 713 | SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR; |
@@ -2101,6 +2103,76 @@ session_env_req(struct ssh *ssh, Session *s) | |||
2101 | return (0); | 2103 | return (0); |
2102 | } | 2104 | } |
2103 | 2105 | ||
2106 | /* | ||
2107 | * Conversion of signals from ssh channel request names. | ||
2108 | * Subset of signals from RFC 4254 section 6.10C, with SIGINFO as | ||
2109 | * local extension. | ||
2110 | */ | ||
2111 | static int | ||
2112 | name2sig(char *name) | ||
2113 | { | ||
2114 | #define SSH_SIG(x) if (strcmp(name, #x) == 0) return SIG ## x | ||
2115 | SSH_SIG(HUP); | ||
2116 | SSH_SIG(INT); | ||
2117 | SSH_SIG(KILL); | ||
2118 | SSH_SIG(QUIT); | ||
2119 | SSH_SIG(TERM); | ||
2120 | SSH_SIG(USR1); | ||
2121 | SSH_SIG(USR2); | ||
2122 | #undef SSH_SIG | ||
2123 | if (strcmp(name, "INFO@openssh.com") == 0) | ||
2124 | return SIGINFO; | ||
2125 | return -1; | ||
2126 | } | ||
2127 | |||
2128 | static int | ||
2129 | session_signal_req(struct ssh *ssh, Session *s) | ||
2130 | { | ||
2131 | char *signame = NULL; | ||
2132 | int r, sig, success = 0; | ||
2133 | |||
2134 | if ((r = sshpkt_get_cstring(ssh, &signame, NULL)) != 0 || | ||
2135 | (r = sshpkt_get_end(ssh)) != 0) { | ||
2136 | error("%s: parse packet: %s", __func__, ssh_err(r)); | ||
2137 | goto out; | ||
2138 | } | ||
2139 | if ((sig = name2sig(signame)) == -1) { | ||
2140 | error("%s: unsupported signal \"%s\"", __func__, signame); | ||
2141 | goto out; | ||
2142 | } | ||
2143 | if (s->pid <= 0) { | ||
2144 | error("%s: no pid for session %d", __func__, s->self); | ||
2145 | goto out; | ||
2146 | } | ||
2147 | if (s->forced || s->is_subsystem) { | ||
2148 | error("%s: refusing to send signal %s to %s session", __func__, | ||
2149 | signame, s->forced ? "forced-command" : "subsystem"); | ||
2150 | goto out; | ||
2151 | } | ||
2152 | if (!use_privsep || mm_is_monitor()) { | ||
2153 | error("%s: session signalling requires privilege separation", | ||
2154 | __func__); | ||
2155 | goto out; | ||
2156 | } | ||
2157 | |||
2158 | debug("%s: signal %s, killpg(%ld, %d)", __func__, signame, | ||
2159 | (long)s->pid, sig); | ||
2160 | temporarily_use_uid(s->pw); | ||
2161 | r = killpg(s->pid, sig); | ||
2162 | restore_uid(); | ||
2163 | if (r != 0) { | ||
2164 | error("%s: killpg(%ld, %d): %s", __func__, (long)s->pid, | ||
2165 | sig, strerror(errno)); | ||
2166 | goto out; | ||
2167 | } | ||
2168 | |||
2169 | /* success */ | ||
2170 | success = 1; | ||
2171 | out: | ||
2172 | free(signame); | ||
2173 | return success; | ||
2174 | } | ||
2175 | |||
2104 | static int | 2176 | static int |
2105 | session_auth_agent_req(struct ssh *ssh, Session *s) | 2177 | session_auth_agent_req(struct ssh *ssh, Session *s) |
2106 | { | 2178 | { |
@@ -2157,6 +2229,8 @@ session_input_channel_req(struct ssh *ssh, Channel *c, const char *rtype) | |||
2157 | success = session_window_change_req(ssh, s); | 2229 | success = session_window_change_req(ssh, s); |
2158 | } else if (strcmp(rtype, "break") == 0) { | 2230 | } else if (strcmp(rtype, "break") == 0) { |
2159 | success = session_break_req(ssh, s); | 2231 | success = session_break_req(ssh, s); |
2232 | } else if (strcmp(rtype, "signal") == 0) { | ||
2233 | success = session_signal_req(ssh, s); | ||
2160 | } | 2234 | } |
2161 | 2235 | ||
2162 | return success; | 2236 | return success; |