1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
|
/*
20140120
Jan Mojzis
Public domain.
*/
#include "buf.h"
#include "ssh.h"
#include "e.h"
#include "bug.h"
#include "str.h"
#include "log.h"
#include "packetparser.h"
#include "packet.h"
int packet_channel_request(struct buf *b1, struct buf *b2,
const char *customcmd) {
long long pos = 0;
crypto_uint8 ch, wantreply;
crypto_uint32 id, a, b, x, y;
char *cmd;
crypto_uint32 cmdlen;
char *p1, *p2;
const char *ps;
crypto_uint32 plen1, plen2;
pos = packetparser_uint8(b1->buf, b1->len, pos,
&ch); /* byte SSH_MSG_CHANNEL_REQUEST */
if (ch != SSH_MSG_CHANNEL_REQUEST) bug_proto();
pos = packetparser_uint32(b1->buf, b1->len, pos,
&id); /* uint32 recipient channel */
if (id != channel_getid()) bug_proto();
pos = packetparser_uint32(
b1->buf, b1->len, pos,
&cmdlen); /* string request type in US-ASCII characters only */
cmd = (char *) b1->buf + pos;
pos = packetparser_skip(b1->buf, b1->len, pos, cmdlen);
pos = packetparser_uint8(b1->buf, b1->len, pos,
&wantreply); /* boolean want reply */
cmd[cmdlen] = 0;
if (str_equaln(cmd, cmdlen, "exec")) {
/* byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "exec"
boolean want reply
string command
*/
pos = packetparser_uint32(b1->buf, b1->len, pos, &plen1);
p1 = (char *) b1->buf + pos;
pos = packetparser_skip(b1->buf, b1->len, pos, plen1);
pos = packetparser_end(b1->buf, b1->len, pos);
buf_putnum8(b1, 0);
p1[plen1] = 0;
if (customcmd) {
log_d4("packet=SSH_MSG_CHANNEL_REQUEST, exec ", p1,
", rejected: custom program is selected using param. -e ",
customcmd);
goto reject;
}
if (!channel_exec(p1)) bug();
log_d3("packet=SSH_MSG_CHANNEL_REQUEST, exec ", p1, ", accepted");
goto accept;
}
if (str_equaln(cmd, cmdlen, "subsystem")) {
/* byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "subsystem"
boolean want reply
string subsystem name
*/
pos = packetparser_uint32(b1->buf, b1->len, pos, &plen1);
p1 = (char *) b1->buf + pos;
pos = packetparser_skip(b1->buf, b1->len, pos, plen1);
pos = packetparser_end(b1->buf, b1->len, pos);
buf_putnum8(b1, 0);
p1[plen1] = 0;
if (customcmd) {
log_d4("packet=SSH_MSG_CHANNEL_REQUEST, subsystem ", p1,
", rejected: custom program is selected using param. -e ",
customcmd);
goto reject;
}
ps = channel_subsystem_get(p1);
if (!ps) {
log_d3("packet=SSH_MSG_CHANNEL_REQUEST, subsystem ", p1,
", rejected");
goto reject;
}
if (!channel_exec(ps)) bug();
log_d5("packet=SSH_MSG_CHANNEL_REQUEST, subsystem ", p1, "=", ps,
", accepted");
goto accept;
}
if (str_equaln(cmd, cmdlen, "shell")) {
/* byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "shell"
boolean want reply
*/
pos = packetparser_end(b1->buf, b1->len, pos);
if (customcmd) {
if (!channel_exec(customcmd)) bug();
log_d3("packet=SSH_MSG_CHANNEL_REQUEST, shell, accepted, executing "
"custom shell '",
customcmd, "'");
}
else {
if (!channel_exec(0)) bug();
log_d1("packet=SSH_MSG_CHANNEL_REQUEST, shell, accepted");
}
goto accept;
}
if (str_equaln(cmd, cmdlen, "env")) {
/* byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "env"
boolean want reply
string variable name
string variable value
*/
/**/
pos = packetparser_uint32(b1->buf, b1->len, pos,
&plen1); /* string variable name */
p1 = (char *) b1->buf + pos;
pos = packetparser_skip(b1->buf, b1->len, pos, plen1);
pos = packetparser_uint32(b1->buf, b1->len, pos,
&plen2); /* string variable value */
p2 = (char *) b1->buf + pos;
pos = packetparser_skip(b1->buf, b1->len, pos, plen2);
pos = packetparser_end(b1->buf, b1->len, pos);
buf_putnum8(b1, 0);
p1[plen1] = 0;
p2[plen2] = 0;
if (channel_env(p1, p2)) {
log_d5("packet=SSH_MSG_CHANNEL_REQUEST, env ", p1, "=", p2,
", accepted");
goto accept;
}
else {
log_d5("packet=SSH_MSG_CHANNEL_REQUEST, env ", p1, "=", p2,
", rejected");
goto reject;
}
}
if (str_equaln(cmd, cmdlen, "pty-req")) {
/*
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "pty-req"
boolean want_reply
string TERM environment variable value (e.g., vt100)
uint32 terminal width, characters (e.g., 80)
uint32 terminal height, rows (e.g., 24)
uint32 terminal width, pixels (e.g., 640)
uint32 terminal height, pixels (e.g., 480)
string encoded terminal modes
*/
pos = packetparser_uint32(b1->buf, b1->len, pos, &plen1);
p1 = (char *) b1->buf + pos;
pos = packetparser_skip(b1->buf, b1->len, pos, plen1);
pos = packetparser_uint32(b1->buf, b1->len, pos, &a);
pos = packetparser_uint32(b1->buf, b1->len, pos, &b);
pos = packetparser_uint32(b1->buf, b1->len, pos, &x);
pos = packetparser_uint32(b1->buf, b1->len, pos, &y);
pos = packetparser_uint32(b1->buf, b1->len, pos, &plen2);
p2 = (char *) b1->buf + pos;
pos = packetparser_skip(b1->buf, b1->len, pos, plen2);
pos = packetparser_end(b1->buf, b1->len, pos);
buf_putnum8(b1, 0);
/* XXX TODO encoded terminal modes (p2, plen2) */
p1[plen1] = 0;
p2[plen2] = 0;
if (!channel_openterminal(p1, a, b, x, y)) {
log_w1("unable to open terminal");
log_d3("packet=SSH_MSG_CHANNEL_REQUEST, pty-req ", p1,
", rejected");
goto reject;
}
log_d3("packet=SSH_MSG_CHANNEL_REQUEST, pty-req ", p1, ", accepted");
goto accept;
}
if (str_equaln(cmd, cmdlen, "window-change")) {
/*
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "window-change"
boolean FALSE
uint32 terminal width, columns
uint32 terminal height, rows
uint32 terminal width, pixels
uint32 terminal height, pixels
*/
pos = packetparser_uint32(b1->buf, b1->len, pos, &a);
pos = packetparser_uint32(b1->buf, b1->len, pos, &b);
pos = packetparser_uint32(b1->buf, b1->len, pos, &x);
pos = packetparser_uint32(b1->buf, b1->len, pos, &y);
pos = packetparser_end(b1->buf, b1->len, pos);
channel_ptyresize(a, b, x, y);
log_d1("packet=SSH_MSG_CHANNEL_REQUEST, window-change, accepted");
goto accept;
}
log_d3("packet=SSH_MSG_CHANNEL_REQUEST, ", cmd, ", rejected or ignored");
reject:
/* reject channel request */
if (!wantreply) goto done;
buf_purge(b2);
buf_putnum8(b2, SSH_MSG_CHANNEL_FAILURE); /* byte SSH_MSG_CHANNEL_SUCCESS */
buf_putnum32(b2, id); /* uint32 recipient channel */
packet_put(b2);
buf_purge(b1);
buf_purge(b2);
return 1;
accept:
if (!wantreply) goto done;
buf_purge(b2);
buf_putnum8(b2, SSH_MSG_CHANNEL_SUCCESS); /* byte SSH_MSG_CHANNEL_SUCCESS */
buf_putnum32(b2, id); /* uint32 recipient channel */
packet_put(b2);
buf_purge(b1);
buf_purge(b2);
return 1;
done:
buf_purge(b1);
buf_purge(b2);
return 1;
}
|