diff options
-rw-r--r-- | channels.c | 374 | ||||
-rw-r--r-- | channels.h | 6 | ||||
-rw-r--r-- | readconf.c | 42 | ||||
-rw-r--r-- | ssh.1 | 21 | ||||
-rw-r--r-- | ssh.c | 5 | ||||
-rw-r--r-- | ssh_config.5 | 16 |
6 files changed, 346 insertions, 118 deletions
diff --git a/channels.c b/channels.c index 89b7d3486..8ef37c453 100644 --- a/channels.c +++ b/channels.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.c,v 1.371 2017/09/19 12:10:30 millert Exp $ */ | 1 | /* $OpenBSD: channels.c,v 1.372 2017/09/21 19:16:53 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -209,6 +209,8 @@ static const char *channel_rfwd_bind_host(const char *listen_host); | |||
209 | /* non-blocking connect helpers */ | 209 | /* non-blocking connect helpers */ |
210 | static int connect_next(struct channel_connect *); | 210 | static int connect_next(struct channel_connect *); |
211 | static void channel_connect_ctx_free(struct channel_connect *); | 211 | static void channel_connect_ctx_free(struct channel_connect *); |
212 | static Channel *rdynamic_connect_prepare(struct ssh *, char *, char *); | ||
213 | static int rdynamic_connect_finish(struct ssh *, Channel *); | ||
212 | 214 | ||
213 | /* Setup helper */ | 215 | /* Setup helper */ |
214 | static void channel_handler_init(struct ssh_channels *sc); | 216 | static void channel_handler_init(struct ssh_channels *sc); |
@@ -282,6 +284,8 @@ channel_lookup(struct ssh *ssh, int id) | |||
282 | case SSH_CHANNEL_LARVAL: | 284 | case SSH_CHANNEL_LARVAL: |
283 | case SSH_CHANNEL_CONNECTING: | 285 | case SSH_CHANNEL_CONNECTING: |
284 | case SSH_CHANNEL_DYNAMIC: | 286 | case SSH_CHANNEL_DYNAMIC: |
287 | case SSH_CHANNEL_RDYNAMIC_OPEN: | ||
288 | case SSH_CHANNEL_RDYNAMIC_FINISH: | ||
285 | case SSH_CHANNEL_OPENING: | 289 | case SSH_CHANNEL_OPENING: |
286 | case SSH_CHANNEL_OPEN: | 290 | case SSH_CHANNEL_OPEN: |
287 | case SSH_CHANNEL_ABANDONED: | 291 | case SSH_CHANNEL_ABANDONED: |
@@ -671,6 +675,7 @@ channel_still_open(struct ssh *ssh) | |||
671 | case SSH_CHANNEL_CLOSED: | 675 | case SSH_CHANNEL_CLOSED: |
672 | case SSH_CHANNEL_AUTH_SOCKET: | 676 | case SSH_CHANNEL_AUTH_SOCKET: |
673 | case SSH_CHANNEL_DYNAMIC: | 677 | case SSH_CHANNEL_DYNAMIC: |
678 | case SSH_CHANNEL_RDYNAMIC_OPEN: | ||
674 | case SSH_CHANNEL_CONNECTING: | 679 | case SSH_CHANNEL_CONNECTING: |
675 | case SSH_CHANNEL_ZOMBIE: | 680 | case SSH_CHANNEL_ZOMBIE: |
676 | case SSH_CHANNEL_ABANDONED: | 681 | case SSH_CHANNEL_ABANDONED: |
@@ -681,6 +686,7 @@ channel_still_open(struct ssh *ssh) | |||
681 | continue; | 686 | continue; |
682 | case SSH_CHANNEL_OPENING: | 687 | case SSH_CHANNEL_OPENING: |
683 | case SSH_CHANNEL_OPEN: | 688 | case SSH_CHANNEL_OPEN: |
689 | case SSH_CHANNEL_RDYNAMIC_FINISH: | ||
684 | case SSH_CHANNEL_X11_OPEN: | 690 | case SSH_CHANNEL_X11_OPEN: |
685 | case SSH_CHANNEL_MUX_CLIENT: | 691 | case SSH_CHANNEL_MUX_CLIENT: |
686 | case SSH_CHANNEL_MUX_PROXY: | 692 | case SSH_CHANNEL_MUX_PROXY: |
@@ -707,6 +713,8 @@ channel_find_open(struct ssh *ssh) | |||
707 | switch (c->type) { | 713 | switch (c->type) { |
708 | case SSH_CHANNEL_CLOSED: | 714 | case SSH_CHANNEL_CLOSED: |
709 | case SSH_CHANNEL_DYNAMIC: | 715 | case SSH_CHANNEL_DYNAMIC: |
716 | case SSH_CHANNEL_RDYNAMIC_OPEN: | ||
717 | case SSH_CHANNEL_RDYNAMIC_FINISH: | ||
710 | case SSH_CHANNEL_X11_LISTENER: | 718 | case SSH_CHANNEL_X11_LISTENER: |
711 | case SSH_CHANNEL_PORT_LISTENER: | 719 | case SSH_CHANNEL_PORT_LISTENER: |
712 | case SSH_CHANNEL_RPORT_LISTENER: | 720 | case SSH_CHANNEL_RPORT_LISTENER: |
@@ -772,6 +780,8 @@ channel_open_message(struct ssh *ssh) | |||
772 | case SSH_CHANNEL_OPENING: | 780 | case SSH_CHANNEL_OPENING: |
773 | case SSH_CHANNEL_CONNECTING: | 781 | case SSH_CHANNEL_CONNECTING: |
774 | case SSH_CHANNEL_DYNAMIC: | 782 | case SSH_CHANNEL_DYNAMIC: |
783 | case SSH_CHANNEL_RDYNAMIC_OPEN: | ||
784 | case SSH_CHANNEL_RDYNAMIC_FINISH: | ||
775 | case SSH_CHANNEL_OPEN: | 785 | case SSH_CHANNEL_OPEN: |
776 | case SSH_CHANNEL_X11_OPEN: | 786 | case SSH_CHANNEL_X11_OPEN: |
777 | case SSH_CHANNEL_MUX_PROXY: | 787 | case SSH_CHANNEL_MUX_PROXY: |
@@ -1124,8 +1134,7 @@ channel_pre_mux_client(struct ssh *ssh, | |||
1124 | 1134 | ||
1125 | /* try to decode a socks4 header */ | 1135 | /* try to decode a socks4 header */ |
1126 | static int | 1136 | static int |
1127 | channel_decode_socks4(struct ssh *ssh, Channel *c, | 1137 | channel_decode_socks4(Channel *c, struct sshbuf *input, struct sshbuf *output) |
1128 | fd_set *readset, fd_set *writeset) | ||
1129 | { | 1138 | { |
1130 | const u_char *p; | 1139 | const u_char *p; |
1131 | char *host; | 1140 | char *host; |
@@ -1141,11 +1150,11 @@ channel_decode_socks4(struct ssh *ssh, Channel *c, | |||
1141 | 1150 | ||
1142 | debug2("channel %d: decode socks4", c->self); | 1151 | debug2("channel %d: decode socks4", c->self); |
1143 | 1152 | ||
1144 | have = sshbuf_len(c->input); | 1153 | have = sshbuf_len(input); |
1145 | len = sizeof(s4_req); | 1154 | len = sizeof(s4_req); |
1146 | if (have < len) | 1155 | if (have < len) |
1147 | return 0; | 1156 | return 0; |
1148 | p = sshbuf_ptr(c->input); | 1157 | p = sshbuf_ptr(input); |
1149 | 1158 | ||
1150 | need = 1; | 1159 | need = 1; |
1151 | /* SOCKS4A uses an invalid IP address 0.0.0.x */ | 1160 | /* SOCKS4A uses an invalid IP address 0.0.0.x */ |
@@ -1170,15 +1179,15 @@ channel_decode_socks4(struct ssh *ssh, Channel *c, | |||
1170 | } | 1179 | } |
1171 | if (found < need) | 1180 | if (found < need) |
1172 | return 0; | 1181 | return 0; |
1173 | if ((r = sshbuf_get(c->input, &s4_req.version, 1)) != 0 || | 1182 | if ((r = sshbuf_get(input, &s4_req.version, 1)) != 0 || |
1174 | (r = sshbuf_get(c->input, &s4_req.command, 1)) != 0 || | 1183 | (r = sshbuf_get(input, &s4_req.command, 1)) != 0 || |
1175 | (r = sshbuf_get(c->input, &s4_req.dest_port, 2)) != 0 || | 1184 | (r = sshbuf_get(input, &s4_req.dest_port, 2)) != 0 || |
1176 | (r = sshbuf_get(c->input, &s4_req.dest_addr, 4)) != 0) { | 1185 | (r = sshbuf_get(input, &s4_req.dest_addr, 4)) != 0) { |
1177 | debug("channels %d: decode socks4: %s", c->self, ssh_err(r)); | 1186 | debug("channels %d: decode socks4: %s", c->self, ssh_err(r)); |
1178 | return -1; | 1187 | return -1; |
1179 | } | 1188 | } |
1180 | have = sshbuf_len(c->input); | 1189 | have = sshbuf_len(input); |
1181 | p = sshbuf_ptr(c->input); | 1190 | p = sshbuf_ptr(input); |
1182 | if (memchr(p, '\0', have) == NULL) { | 1191 | if (memchr(p, '\0', have) == NULL) { |
1183 | error("channel %d: decode socks4: user not nul terminated", | 1192 | error("channel %d: decode socks4: user not nul terminated", |
1184 | c->self); | 1193 | c->self); |
@@ -1188,7 +1197,7 @@ channel_decode_socks4(struct ssh *ssh, Channel *c, | |||
1188 | debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); | 1197 | debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); |
1189 | len++; /* trailing '\0' */ | 1198 | len++; /* trailing '\0' */ |
1190 | strlcpy(username, p, sizeof(username)); | 1199 | strlcpy(username, p, sizeof(username)); |
1191 | if ((r = sshbuf_consume(c->input, len)) != 0) { | 1200 | if ((r = sshbuf_consume(input, len)) != 0) { |
1192 | fatal("%s: channel %d: consume: %s", __func__, | 1201 | fatal("%s: channel %d: consume: %s", __func__, |
1193 | c->self, ssh_err(r)); | 1202 | c->self, ssh_err(r)); |
1194 | } | 1203 | } |
@@ -1198,8 +1207,8 @@ channel_decode_socks4(struct ssh *ssh, Channel *c, | |||
1198 | host = inet_ntoa(s4_req.dest_addr); | 1207 | host = inet_ntoa(s4_req.dest_addr); |
1199 | c->path = xstrdup(host); | 1208 | c->path = xstrdup(host); |
1200 | } else { /* SOCKS4A: two strings */ | 1209 | } else { /* SOCKS4A: two strings */ |
1201 | have = sshbuf_len(c->input); | 1210 | have = sshbuf_len(input); |
1202 | p = sshbuf_ptr(c->input); | 1211 | p = sshbuf_ptr(input); |
1203 | if (memchr(p, '\0', have) == NULL) { | 1212 | if (memchr(p, '\0', have) == NULL) { |
1204 | error("channel %d: decode socks4a: host not nul " | 1213 | error("channel %d: decode socks4a: host not nul " |
1205 | "terminated", c->self); | 1214 | "terminated", c->self); |
@@ -1215,7 +1224,7 @@ channel_decode_socks4(struct ssh *ssh, Channel *c, | |||
1215 | return -1; | 1224 | return -1; |
1216 | } | 1225 | } |
1217 | c->path = xstrdup(p); | 1226 | c->path = xstrdup(p); |
1218 | if ((r = sshbuf_consume(c->input, len)) != 0) { | 1227 | if ((r = sshbuf_consume(input, len)) != 0) { |
1219 | fatal("%s: channel %d: consume: %s", __func__, | 1228 | fatal("%s: channel %d: consume: %s", __func__, |
1220 | c->self, ssh_err(r)); | 1229 | c->self, ssh_err(r)); |
1221 | } | 1230 | } |
@@ -1234,7 +1243,7 @@ channel_decode_socks4(struct ssh *ssh, Channel *c, | |||
1234 | s4_rsp.command = 90; /* cd: req granted */ | 1243 | s4_rsp.command = 90; /* cd: req granted */ |
1235 | s4_rsp.dest_port = 0; /* ignored */ | 1244 | s4_rsp.dest_port = 0; /* ignored */ |
1236 | s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */ | 1245 | s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */ |
1237 | if ((r = sshbuf_put(c->output, &s4_rsp, sizeof(s4_rsp))) != 0) { | 1246 | if ((r = sshbuf_put(output, &s4_rsp, sizeof(s4_rsp))) != 0) { |
1238 | fatal("%s: channel %d: append reply: %s", __func__, | 1247 | fatal("%s: channel %d: append reply: %s", __func__, |
1239 | c->self, ssh_err(r)); | 1248 | c->self, ssh_err(r)); |
1240 | } | 1249 | } |
@@ -1251,8 +1260,7 @@ channel_decode_socks4(struct ssh *ssh, Channel *c, | |||
1251 | #define SSH_SOCKS5_SUCCESS 0x00 | 1260 | #define SSH_SOCKS5_SUCCESS 0x00 |
1252 | 1261 | ||
1253 | static int | 1262 | static int |
1254 | channel_decode_socks5(struct ssh *ssh, Channel *c, | 1263 | channel_decode_socks5(Channel *c, struct sshbuf *input, struct sshbuf *output) |
1255 | fd_set *readset, fd_set *writeset) | ||
1256 | { | 1264 | { |
1257 | /* XXX use get/put_u8 instead of trusting struct padding */ | 1265 | /* XXX use get/put_u8 instead of trusting struct padding */ |
1258 | struct { | 1266 | struct { |
@@ -1268,10 +1276,10 @@ channel_decode_socks5(struct ssh *ssh, Channel *c, | |||
1268 | int r; | 1276 | int r; |
1269 | 1277 | ||
1270 | debug2("channel %d: decode socks5", c->self); | 1278 | debug2("channel %d: decode socks5", c->self); |
1271 | p = sshbuf_ptr(c->input); | 1279 | p = sshbuf_ptr(input); |
1272 | if (p[0] != 0x05) | 1280 | if (p[0] != 0x05) |
1273 | return -1; | 1281 | return -1; |
1274 | have = sshbuf_len(c->input); | 1282 | have = sshbuf_len(input); |
1275 | if (!(c->flags & SSH_SOCKS5_AUTHDONE)) { | 1283 | if (!(c->flags & SSH_SOCKS5_AUTHDONE)) { |
1276 | /* format: ver | nmethods | methods */ | 1284 | /* format: ver | nmethods | methods */ |
1277 | if (have < 2) | 1285 | if (have < 2) |
@@ -1291,17 +1299,16 @@ channel_decode_socks5(struct ssh *ssh, Channel *c, | |||
1291 | c->self); | 1299 | c->self); |
1292 | return -1; | 1300 | return -1; |
1293 | } | 1301 | } |
1294 | if ((r = sshbuf_consume(c->input, nmethods + 2)) != 0) { | 1302 | if ((r = sshbuf_consume(input, nmethods + 2)) != 0) { |
1295 | fatal("%s: channel %d: consume: %s", __func__, | 1303 | fatal("%s: channel %d: consume: %s", __func__, |
1296 | c->self, ssh_err(r)); | 1304 | c->self, ssh_err(r)); |
1297 | } | 1305 | } |
1298 | /* version, method */ | 1306 | /* version, method */ |
1299 | if ((r = sshbuf_put_u8(c->output, 0x05)) != 0 || | 1307 | if ((r = sshbuf_put_u8(output, 0x05)) != 0 || |
1300 | (r = sshbuf_put_u8(c->output, SSH_SOCKS5_NOAUTH)) != 0) { | 1308 | (r = sshbuf_put_u8(output, SSH_SOCKS5_NOAUTH)) != 0) { |
1301 | fatal("%s: channel %d: append reply: %s", __func__, | 1309 | fatal("%s: channel %d: append reply: %s", __func__, |
1302 | c->self, ssh_err(r)); | 1310 | c->self, ssh_err(r)); |
1303 | } | 1311 | } |
1304 | FD_SET(c->sock, writeset); | ||
1305 | c->flags |= SSH_SOCKS5_AUTHDONE; | 1312 | c->flags |= SSH_SOCKS5_AUTHDONE; |
1306 | debug2("channel %d: socks5 auth done", c->self); | 1313 | debug2("channel %d: socks5 auth done", c->self); |
1307 | return 0; /* need more */ | 1314 | return 0; /* need more */ |
@@ -1338,19 +1345,19 @@ channel_decode_socks5(struct ssh *ssh, Channel *c, | |||
1338 | need++; | 1345 | need++; |
1339 | if (have < need) | 1346 | if (have < need) |
1340 | return 0; | 1347 | return 0; |
1341 | if ((r = sshbuf_consume(c->input, sizeof(s5_req))) != 0) { | 1348 | if ((r = sshbuf_consume(input, sizeof(s5_req))) != 0) { |
1342 | fatal("%s: channel %d: consume: %s", __func__, | 1349 | fatal("%s: channel %d: consume: %s", __func__, |
1343 | c->self, ssh_err(r)); | 1350 | c->self, ssh_err(r)); |
1344 | } | 1351 | } |
1345 | if (s5_req.atyp == SSH_SOCKS5_DOMAIN) { | 1352 | if (s5_req.atyp == SSH_SOCKS5_DOMAIN) { |
1346 | /* host string length */ | 1353 | /* host string length */ |
1347 | if ((r = sshbuf_consume(c->input, 1)) != 0) { | 1354 | if ((r = sshbuf_consume(input, 1)) != 0) { |
1348 | fatal("%s: channel %d: consume: %s", __func__, | 1355 | fatal("%s: channel %d: consume: %s", __func__, |
1349 | c->self, ssh_err(r)); | 1356 | c->self, ssh_err(r)); |
1350 | } | 1357 | } |
1351 | } | 1358 | } |
1352 | if ((r = sshbuf_get(c->input, &dest_addr, addrlen)) != 0 || | 1359 | if ((r = sshbuf_get(input, &dest_addr, addrlen)) != 0 || |
1353 | (r = sshbuf_get(c->input, &dest_port, 2)) != 0) { | 1360 | (r = sshbuf_get(input, &dest_port, 2)) != 0) { |
1354 | debug("channel %d: parse addr/port: %s", c->self, ssh_err(r)); | 1361 | debug("channel %d: parse addr/port: %s", c->self, ssh_err(r)); |
1355 | return -1; | 1362 | return -1; |
1356 | } | 1363 | } |
@@ -1380,9 +1387,9 @@ channel_decode_socks5(struct ssh *ssh, Channel *c, | |||
1380 | s5_rsp.atyp = SSH_SOCKS5_IPV4; | 1387 | s5_rsp.atyp = SSH_SOCKS5_IPV4; |
1381 | dest_port = 0; /* ignored */ | 1388 | dest_port = 0; /* ignored */ |
1382 | 1389 | ||
1383 | if ((r = sshbuf_put(c->output, &s5_rsp, sizeof(s5_rsp))) != 0 || | 1390 | if ((r = sshbuf_put(output, &s5_rsp, sizeof(s5_rsp))) != 0 || |
1384 | (r = sshbuf_put_u32(c->output, ntohl(INADDR_ANY))) != 0 || | 1391 | (r = sshbuf_put_u32(output, ntohl(INADDR_ANY))) != 0 || |
1385 | (r = sshbuf_put(c->output, &dest_port, sizeof(dest_port))) != 0) | 1392 | (r = sshbuf_put(output, &dest_port, sizeof(dest_port))) != 0) |
1386 | fatal("%s: channel %d: append reply: %s", __func__, | 1393 | fatal("%s: channel %d: append reply: %s", __func__, |
1387 | c->self, ssh_err(r)); | 1394 | c->self, ssh_err(r)); |
1388 | return 1; | 1395 | return 1; |
@@ -1434,10 +1441,10 @@ channel_pre_dynamic(struct ssh *ssh, Channel *c, | |||
1434 | /* XXX sshbuf_peek_u8? */ | 1441 | /* XXX sshbuf_peek_u8? */ |
1435 | switch (p[0]) { | 1442 | switch (p[0]) { |
1436 | case 0x04: | 1443 | case 0x04: |
1437 | ret = channel_decode_socks4(ssh, c, readset, writeset); | 1444 | ret = channel_decode_socks4(c, c->input, c->output); |
1438 | break; | 1445 | break; |
1439 | case 0x05: | 1446 | case 0x05: |
1440 | ret = channel_decode_socks5(ssh, c, readset, writeset); | 1447 | ret = channel_decode_socks5(c, c->input, c->output); |
1441 | break; | 1448 | break; |
1442 | default: | 1449 | default: |
1443 | ret = -1; | 1450 | ret = -1; |
@@ -1449,6 +1456,8 @@ channel_pre_dynamic(struct ssh *ssh, Channel *c, | |||
1449 | debug2("channel %d: pre_dynamic: need more", c->self); | 1456 | debug2("channel %d: pre_dynamic: need more", c->self); |
1450 | /* need more */ | 1457 | /* need more */ |
1451 | FD_SET(c->sock, readset); | 1458 | FD_SET(c->sock, readset); |
1459 | if (sshbuf_len(c->output)) | ||
1460 | FD_SET(c->sock, writeset); | ||
1452 | } else { | 1461 | } else { |
1453 | /* switch to the next state */ | 1462 | /* switch to the next state */ |
1454 | c->type = SSH_CHANNEL_OPENING; | 1463 | c->type = SSH_CHANNEL_OPENING; |
@@ -1456,6 +1465,81 @@ channel_pre_dynamic(struct ssh *ssh, Channel *c, | |||
1456 | } | 1465 | } |
1457 | } | 1466 | } |
1458 | 1467 | ||
1468 | /* simulate read-error */ | ||
1469 | static void | ||
1470 | rdynamic_close(struct ssh *ssh, Channel *c) | ||
1471 | { | ||
1472 | c->type = SSH_CHANNEL_OPEN; | ||
1473 | chan_read_failed(ssh, c); | ||
1474 | sshbuf_reset(c->input); | ||
1475 | chan_ibuf_empty(ssh, c); | ||
1476 | sshbuf_reset(c->output); | ||
1477 | chan_write_failed(ssh, c); | ||
1478 | } | ||
1479 | |||
1480 | /* reverse dynamic port forwarding */ | ||
1481 | static void | ||
1482 | channel_before_prepare_select_rdynamic(struct ssh *ssh, Channel *c) | ||
1483 | { | ||
1484 | const u_char *p; | ||
1485 | u_int have, len; | ||
1486 | int r, ret; | ||
1487 | |||
1488 | have = sshbuf_len(c->output); | ||
1489 | debug2("channel %d: pre_rdynamic: have %d", c->self, have); | ||
1490 | /* sshbuf_dump(c->output, stderr); */ | ||
1491 | /* EOF received */ | ||
1492 | if (c->flags & CHAN_EOF_RCVD) { | ||
1493 | if ((r = sshbuf_consume(c->output, have)) != 0) { | ||
1494 | fatal("%s: channel %d: consume: %s", | ||
1495 | __func__, c->self, ssh_err(r)); | ||
1496 | } | ||
1497 | rdynamic_close(ssh, c); | ||
1498 | return; | ||
1499 | } | ||
1500 | /* check if the fixed size part of the packet is in buffer. */ | ||
1501 | if (have < 3) | ||
1502 | return; | ||
1503 | /* try to guess the protocol */ | ||
1504 | p = sshbuf_ptr(c->output); | ||
1505 | switch (p[0]) { | ||
1506 | case 0x04: | ||
1507 | /* switch input/output for reverse forwarding */ | ||
1508 | ret = channel_decode_socks4(c, c->output, c->input); | ||
1509 | break; | ||
1510 | case 0x05: | ||
1511 | ret = channel_decode_socks5(c, c->output, c->input); | ||
1512 | break; | ||
1513 | default: | ||
1514 | ret = -1; | ||
1515 | break; | ||
1516 | } | ||
1517 | if (ret < 0) { | ||
1518 | rdynamic_close(ssh, c); | ||
1519 | } else if (ret == 0) { | ||
1520 | debug2("channel %d: pre_rdynamic: need more", c->self); | ||
1521 | /* send socks request to peer */ | ||
1522 | len = sshbuf_len(c->input); | ||
1523 | if (len > 0 && len < c->remote_window) { | ||
1524 | if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_DATA)) != 0 || | ||
1525 | (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || | ||
1526 | (r = sshpkt_put_stringb(ssh, c->input)) != 0 || | ||
1527 | (r = sshpkt_send(ssh)) != 0) { | ||
1528 | fatal("%s: channel %i: rdynamic: %s", __func__, | ||
1529 | c->self, ssh_err(r)); | ||
1530 | } | ||
1531 | if ((r = sshbuf_consume(c->input, len)) != 0) { | ||
1532 | fatal("%s: channel %d: consume: %s", | ||
1533 | __func__, c->self, ssh_err(r)); | ||
1534 | } | ||
1535 | c->remote_window -= len; | ||
1536 | } | ||
1537 | } else if (rdynamic_connect_finish(ssh, c) < 0) { | ||
1538 | /* the connect failed */ | ||
1539 | rdynamic_close(ssh, c); | ||
1540 | } | ||
1541 | } | ||
1542 | |||
1459 | /* This is our fake X11 server socket. */ | 1543 | /* This is our fake X11 server socket. */ |
1460 | static void | 1544 | static void |
1461 | channel_post_x11_listener(struct ssh *ssh, Channel *c, | 1545 | channel_post_x11_listener(struct ssh *ssh, Channel *c, |
@@ -1699,14 +1783,15 @@ static void | |||
1699 | channel_post_connecting(struct ssh *ssh, Channel *c, | 1783 | channel_post_connecting(struct ssh *ssh, Channel *c, |
1700 | fd_set *readset, fd_set *writeset) | 1784 | fd_set *readset, fd_set *writeset) |
1701 | { | 1785 | { |
1702 | int err = 0, sock, r; | 1786 | int err = 0, sock, isopen, r; |
1703 | socklen_t sz = sizeof(err); | 1787 | socklen_t sz = sizeof(err); |
1704 | 1788 | ||
1705 | if (!FD_ISSET(c->sock, writeset)) | 1789 | if (!FD_ISSET(c->sock, writeset)) |
1706 | return; | 1790 | return; |
1707 | if (!c->have_remote_id) | 1791 | if (!c->have_remote_id) |
1708 | fatal(":%s: channel %d: no remote id", __func__, c->self); | 1792 | fatal(":%s: channel %d: no remote id", __func__, c->self); |
1709 | 1793 | /* for rdynamic the OPEN_CONFIRMATION has been sent already */ | |
1794 | isopen = (c->type == SSH_CHANNEL_RDYNAMIC_FINISH); | ||
1710 | if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) { | 1795 | if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) { |
1711 | err = errno; | 1796 | err = errno; |
1712 | error("getsockopt SO_ERROR failed"); | 1797 | error("getsockopt SO_ERROR failed"); |
@@ -1716,14 +1801,21 @@ channel_post_connecting(struct ssh *ssh, Channel *c, | |||
1716 | c->self, c->connect_ctx.host, c->connect_ctx.port); | 1801 | c->self, c->connect_ctx.host, c->connect_ctx.port); |
1717 | channel_connect_ctx_free(&c->connect_ctx); | 1802 | channel_connect_ctx_free(&c->connect_ctx); |
1718 | c->type = SSH_CHANNEL_OPEN; | 1803 | c->type = SSH_CHANNEL_OPEN; |
1719 | if ((r = sshpkt_start(ssh, | 1804 | if (isopen) { |
1720 | SSH2_MSG_CHANNEL_OPEN_CONFIRMATION)) != 0 || | 1805 | /* no message necessary */ |
1721 | (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || | 1806 | } else { |
1722 | (r = sshpkt_put_u32(ssh, c->self)) != 0 || | 1807 | if ((r = sshpkt_start(ssh, |
1723 | (r = sshpkt_put_u32(ssh, c->local_window)) != 0 || | 1808 | SSH2_MSG_CHANNEL_OPEN_CONFIRMATION)) != 0 || |
1724 | (r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0) { | 1809 | (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
1725 | fatal("%s: channel %i: confirm: %s", __func__, | 1810 | (r = sshpkt_put_u32(ssh, c->self)) != 0 || |
1726 | c->self, ssh_err(r)); | 1811 | (r = sshpkt_put_u32(ssh, c->local_window)) != 0 || |
1812 | (r = sshpkt_put_u32(ssh, c->local_maxpacket)) | ||
1813 | != 0) | ||
1814 | fatal("%s: channel %i: confirm: %s", __func__, | ||
1815 | c->self, ssh_err(r)); | ||
1816 | if ((r = sshpkt_send(ssh)) != 0) | ||
1817 | fatal("%s: channel %i: %s", __func__, c->self, | ||
1818 | ssh_err(r)); | ||
1727 | } | 1819 | } |
1728 | } else { | 1820 | } else { |
1729 | debug("channel %d: connection failed: %s", | 1821 | debug("channel %d: connection failed: %s", |
@@ -1739,22 +1831,27 @@ channel_post_connecting(struct ssh *ssh, Channel *c, | |||
1739 | error("connect_to %.100s port %d: failed.", | 1831 | error("connect_to %.100s port %d: failed.", |
1740 | c->connect_ctx.host, c->connect_ctx.port); | 1832 | c->connect_ctx.host, c->connect_ctx.port); |
1741 | channel_connect_ctx_free(&c->connect_ctx); | 1833 | channel_connect_ctx_free(&c->connect_ctx); |
1742 | if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN_FAILURE)) != 0 || | 1834 | if (isopen) { |
1743 | (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || | 1835 | rdynamic_close(ssh, c); |
1744 | (r = sshpkt_put_u32(ssh, SSH2_OPEN_CONNECT_FAILED)) != 0) { | 1836 | } else { |
1745 | fatal("%s: channel %i: failure: %s", __func__, | 1837 | if ((r = sshpkt_start(ssh, |
1746 | c->self, ssh_err(r)); | 1838 | SSH2_MSG_CHANNEL_OPEN_FAILURE)) != 0 || |
1747 | } | 1839 | (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
1748 | if ((datafellows & SSH_BUG_OPENFAILURE) == 0 && | 1840 | (r = sshpkt_put_u32(ssh, SSH2_OPEN_CONNECT_FAILED)) |
1749 | ((r = sshpkt_put_cstring(ssh, strerror(err))) != 0 || | 1841 | != 0) |
1750 | (r = sshpkt_put_cstring(ssh, "")) != 0)) { | 1842 | fatal("%s: channel %i: failure: %s", __func__, |
1751 | fatal("%s: channel %i: failure: %s", __func__, | 1843 | c->self, ssh_err(r)); |
1752 | c->self, ssh_err(r)); | 1844 | if ((datafellows & SSH_BUG_OPENFAILURE) == 0 && |
1845 | ((r = sshpkt_put_cstring(ssh, strerror(err))) != 0 || | ||
1846 | (r = sshpkt_put_cstring(ssh, "")) != 0)) | ||
1847 | fatal("%s: channel %i: failure: %s", __func__, | ||
1848 | c->self, ssh_err(r)); | ||
1849 | if ((r = sshpkt_send(ssh)) != 0) | ||
1850 | fatal("%s: channel %i: %s", __func__, c->self, | ||
1851 | ssh_err(r)); | ||
1852 | chan_mark_dead(ssh, c); | ||
1753 | } | 1853 | } |
1754 | chan_mark_dead(ssh, c); | ||
1755 | } | 1854 | } |
1756 | if ((r = sshpkt_send(ssh)) != 0) | ||
1757 | fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r)); | ||
1758 | } | 1855 | } |
1759 | 1856 | ||
1760 | static int | 1857 | static int |
@@ -2187,6 +2284,7 @@ channel_handler_init(struct ssh_channels *sc) | |||
2187 | pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; | 2284 | pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; |
2188 | pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; | 2285 | pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; |
2189 | pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; | 2286 | pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; |
2287 | pre[SSH_CHANNEL_RDYNAMIC_FINISH] = &channel_pre_connecting; | ||
2190 | pre[SSH_CHANNEL_MUX_LISTENER] = &channel_pre_listener; | 2288 | pre[SSH_CHANNEL_MUX_LISTENER] = &channel_pre_listener; |
2191 | pre[SSH_CHANNEL_MUX_CLIENT] = &channel_pre_mux_client; | 2289 | pre[SSH_CHANNEL_MUX_CLIENT] = &channel_pre_mux_client; |
2192 | 2290 | ||
@@ -2199,6 +2297,7 @@ channel_handler_init(struct ssh_channels *sc) | |||
2199 | post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; | 2297 | post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; |
2200 | post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; | 2298 | post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; |
2201 | post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; | 2299 | post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; |
2300 | post[SSH_CHANNEL_RDYNAMIC_FINISH] = &channel_post_connecting; | ||
2202 | post[SSH_CHANNEL_MUX_LISTENER] = &channel_post_mux_listener; | 2301 | post[SSH_CHANNEL_MUX_LISTENER] = &channel_post_mux_listener; |
2203 | post[SSH_CHANNEL_MUX_CLIENT] = &channel_post_mux_client; | 2302 | post[SSH_CHANNEL_MUX_CLIENT] = &channel_post_mux_client; |
2204 | 2303 | ||
@@ -2280,6 +2379,27 @@ channel_handler(struct ssh *ssh, int table, | |||
2280 | } | 2379 | } |
2281 | 2380 | ||
2282 | /* | 2381 | /* |
2382 | * Create sockets before allocating the select bitmasks. | ||
2383 | * This is necessary for things that need to happen after reading | ||
2384 | * the network-input but before channel_prepare_select(). | ||
2385 | */ | ||
2386 | static void | ||
2387 | channel_before_prepare_select(struct ssh *ssh) | ||
2388 | { | ||
2389 | struct ssh_channels *sc = ssh->chanctxt; | ||
2390 | Channel *c; | ||
2391 | u_int i, oalloc; | ||
2392 | |||
2393 | for (i = 0, oalloc = sc->channels_alloc; i < oalloc; i++) { | ||
2394 | c = sc->channels[i]; | ||
2395 | if (c == NULL) | ||
2396 | continue; | ||
2397 | if (c->type == SSH_CHANNEL_RDYNAMIC_OPEN) | ||
2398 | channel_before_prepare_select_rdynamic(ssh, c); | ||
2399 | } | ||
2400 | } | ||
2401 | |||
2402 | /* | ||
2283 | * Allocate/update select bitmasks and add any bits relevant to channels in | 2403 | * Allocate/update select bitmasks and add any bits relevant to channels in |
2284 | * select bitmasks. | 2404 | * select bitmasks. |
2285 | */ | 2405 | */ |
@@ -2289,6 +2409,8 @@ channel_prepare_select(struct ssh *ssh, fd_set **readsetp, fd_set **writesetp, | |||
2289 | { | 2409 | { |
2290 | u_int n, sz, nfdset; | 2410 | u_int n, sz, nfdset; |
2291 | 2411 | ||
2412 | channel_before_prepare_select(ssh); /* might update channel_max_fd */ | ||
2413 | |||
2292 | n = MAXIMUM(*maxfdp, ssh->chanctxt->channel_max_fd); | 2414 | n = MAXIMUM(*maxfdp, ssh->chanctxt->channel_max_fd); |
2293 | 2415 | ||
2294 | nfdset = howmany(n+1, NFDBITS); | 2416 | nfdset = howmany(n+1, NFDBITS); |
@@ -2794,6 +2916,8 @@ channel_input_data(int type, u_int32_t seq, struct ssh *ssh) | |||
2794 | 2916 | ||
2795 | /* Ignore any data for non-open channels (might happen on close) */ | 2917 | /* Ignore any data for non-open channels (might happen on close) */ |
2796 | if (c->type != SSH_CHANNEL_OPEN && | 2918 | if (c->type != SSH_CHANNEL_OPEN && |
2919 | c->type != SSH_CHANNEL_RDYNAMIC_OPEN && | ||
2920 | c->type != SSH_CHANNEL_RDYNAMIC_FINISH && | ||
2797 | c->type != SSH_CHANNEL_X11_OPEN) | 2921 | c->type != SSH_CHANNEL_X11_OPEN) |
2798 | return 0; | 2922 | return 0; |
2799 | 2923 | ||
@@ -3032,7 +3156,7 @@ channel_input_window_adjust(int type, u_int32_t seq, struct ssh *ssh) | |||
3032 | if ((c = channel_lookup(ssh, id)) == NULL) { | 3156 | if ((c = channel_lookup(ssh, id)) == NULL) { |
3033 | logit("Received window adjust for non-open channel %d.", id); | 3157 | logit("Received window adjust for non-open channel %d.", id); |
3034 | return 0; | 3158 | return 0; |
3035 | } | 3159 | } |
3036 | 3160 | ||
3037 | if (channel_proxy_upstream(c, type, seq, ssh)) | 3161 | if (channel_proxy_upstream(c, type, seq, ssh)) |
3038 | return 0; | 3162 | return 0; |
@@ -3939,21 +4063,18 @@ channel_connect_ctx_free(struct channel_connect *cctx) | |||
3939 | } | 4063 | } |
3940 | 4064 | ||
3941 | /* | 4065 | /* |
3942 | * Return CONNECTING channel to remote host:port or local socket path, | 4066 | * Return connecting socket to remote host:port or local socket path, |
3943 | * passing back the failure reason if appropriate. | 4067 | * passing back the failure reason if appropriate. |
3944 | */ | 4068 | */ |
3945 | static Channel * | 4069 | static int |
3946 | connect_to_reason(struct ssh *ssh, const char *name, int port, | 4070 | connect_to_helper(struct ssh *ssh, const char *name, int port, int socktype, |
3947 | char *ctype, char *rname, int *reason, const char **errmsg) | 4071 | char *ctype, char *rname, struct channel_connect *cctx, |
4072 | int *reason, const char **errmsg) | ||
3948 | { | 4073 | { |
3949 | struct addrinfo hints; | 4074 | struct addrinfo hints; |
3950 | int gaierr; | 4075 | int gaierr; |
3951 | int sock = -1; | 4076 | int sock = -1; |
3952 | char strport[NI_MAXSERV]; | 4077 | char strport[NI_MAXSERV]; |
3953 | struct channel_connect cctx; | ||
3954 | Channel *c; | ||
3955 | |||
3956 | memset(&cctx, 0, sizeof(cctx)); | ||
3957 | 4078 | ||
3958 | if (port == PORT_STREAMLOCAL) { | 4079 | if (port == PORT_STREAMLOCAL) { |
3959 | struct sockaddr_un *sunaddr; | 4080 | struct sockaddr_un *sunaddr; |
@@ -3961,7 +4082,7 @@ connect_to_reason(struct ssh *ssh, const char *name, int port, | |||
3961 | 4082 | ||
3962 | if (strlen(name) > sizeof(sunaddr->sun_path)) { | 4083 | if (strlen(name) > sizeof(sunaddr->sun_path)) { |
3963 | error("%.100s: %.100s", name, strerror(ENAMETOOLONG)); | 4084 | error("%.100s: %.100s", name, strerror(ENAMETOOLONG)); |
3964 | return (NULL); | 4085 | return -1; |
3965 | } | 4086 | } |
3966 | 4087 | ||
3967 | /* | 4088 | /* |
@@ -3974,18 +4095,18 @@ connect_to_reason(struct ssh *ssh, const char *name, int port, | |||
3974 | ai->ai_addr = (struct sockaddr *)(ai + 1); | 4095 | ai->ai_addr = (struct sockaddr *)(ai + 1); |
3975 | ai->ai_addrlen = sizeof(*sunaddr); | 4096 | ai->ai_addrlen = sizeof(*sunaddr); |
3976 | ai->ai_family = AF_UNIX; | 4097 | ai->ai_family = AF_UNIX; |
3977 | ai->ai_socktype = SOCK_STREAM; | 4098 | ai->ai_socktype = socktype; |
3978 | ai->ai_protocol = PF_UNSPEC; | 4099 | ai->ai_protocol = PF_UNSPEC; |
3979 | sunaddr = (struct sockaddr_un *)ai->ai_addr; | 4100 | sunaddr = (struct sockaddr_un *)ai->ai_addr; |
3980 | sunaddr->sun_family = AF_UNIX; | 4101 | sunaddr->sun_family = AF_UNIX; |
3981 | strlcpy(sunaddr->sun_path, name, sizeof(sunaddr->sun_path)); | 4102 | strlcpy(sunaddr->sun_path, name, sizeof(sunaddr->sun_path)); |
3982 | cctx.aitop = ai; | 4103 | cctx->aitop = ai; |
3983 | } else { | 4104 | } else { |
3984 | memset(&hints, 0, sizeof(hints)); | 4105 | memset(&hints, 0, sizeof(hints)); |
3985 | hints.ai_family = ssh->chanctxt->IPv4or6; | 4106 | hints.ai_family = ssh->chanctxt->IPv4or6; |
3986 | hints.ai_socktype = SOCK_STREAM; | 4107 | hints.ai_socktype = socktype; |
3987 | snprintf(strport, sizeof strport, "%d", port); | 4108 | snprintf(strport, sizeof strport, "%d", port); |
3988 | if ((gaierr = getaddrinfo(name, strport, &hints, &cctx.aitop)) | 4109 | if ((gaierr = getaddrinfo(name, strport, &hints, &cctx->aitop)) |
3989 | != 0) { | 4110 | != 0) { |
3990 | if (errmsg != NULL) | 4111 | if (errmsg != NULL) |
3991 | *errmsg = ssh_gai_strerror(gaierr); | 4112 | *errmsg = ssh_gai_strerror(gaierr); |
@@ -3993,32 +4114,46 @@ connect_to_reason(struct ssh *ssh, const char *name, int port, | |||
3993 | *reason = SSH2_OPEN_CONNECT_FAILED; | 4114 | *reason = SSH2_OPEN_CONNECT_FAILED; |
3994 | error("connect_to %.100s: unknown host (%s)", name, | 4115 | error("connect_to %.100s: unknown host (%s)", name, |
3995 | ssh_gai_strerror(gaierr)); | 4116 | ssh_gai_strerror(gaierr)); |
3996 | return NULL; | 4117 | return -1; |
3997 | } | 4118 | } |
3998 | } | 4119 | } |
3999 | 4120 | ||
4000 | cctx.host = xstrdup(name); | 4121 | cctx->host = xstrdup(name); |
4001 | cctx.port = port; | 4122 | cctx->port = port; |
4002 | cctx.ai = cctx.aitop; | 4123 | cctx->ai = cctx->aitop; |
4003 | 4124 | ||
4004 | if ((sock = connect_next(&cctx)) == -1) { | 4125 | if ((sock = connect_next(cctx)) == -1) { |
4005 | error("connect to %.100s port %d failed: %s", | 4126 | error("connect to %.100s port %d failed: %s", |
4006 | name, port, strerror(errno)); | 4127 | name, port, strerror(errno)); |
4007 | channel_connect_ctx_free(&cctx); | 4128 | return -1; |
4008 | return NULL; | ||
4009 | } | 4129 | } |
4010 | c = channel_new(ssh, ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1, | 4130 | |
4011 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1); | 4131 | return sock; |
4012 | c->connect_ctx = cctx; | ||
4013 | return c; | ||
4014 | } | 4132 | } |
4015 | 4133 | ||
4016 | /* Return CONNECTING channel to remote host:port or local socket path */ | 4134 | /* Return CONNECTING channel to remote host:port or local socket path */ |
4017 | static Channel * | 4135 | static Channel * |
4018 | connect_to(struct ssh *ssh, const char *name, int port, | 4136 | connect_to(struct ssh *ssh, const char *host, int port, |
4019 | char *ctype, char *rname) | 4137 | char *ctype, char *rname) |
4020 | { | 4138 | { |
4021 | return connect_to_reason(ssh, name, port, ctype, rname, NULL, NULL); | 4139 | struct channel_connect cctx; |
4140 | Channel *c; | ||
4141 | int sock; | ||
4142 | |||
4143 | memset(&cctx, 0, sizeof(cctx)); | ||
4144 | sock = connect_to_helper(ssh, host, port, SOCK_STREAM, ctype, rname, | ||
4145 | &cctx, NULL, NULL); | ||
4146 | if (sock == -1) { | ||
4147 | channel_connect_ctx_free(&cctx); | ||
4148 | return NULL; | ||
4149 | } | ||
4150 | c = channel_new(ssh, ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1, | ||
4151 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1); | ||
4152 | c->host_port = port; | ||
4153 | c->path = xstrdup(host); | ||
4154 | c->connect_ctx = cctx; | ||
4155 | |||
4156 | return c; | ||
4022 | } | 4157 | } |
4023 | 4158 | ||
4024 | /* | 4159 | /* |
@@ -4038,6 +4173,9 @@ channel_connect_by_listen_address(struct ssh *ssh, const char *listen_host, | |||
4038 | if (open_listen_match_tcpip(fp, listen_host, listen_port, 1)) { | 4173 | if (open_listen_match_tcpip(fp, listen_host, listen_port, 1)) { |
4039 | if (fp->downstream) | 4174 | if (fp->downstream) |
4040 | return fp->downstream; | 4175 | return fp->downstream; |
4176 | if (fp->port_to_connect == 0) | ||
4177 | return rdynamic_connect_prepare(ssh, | ||
4178 | ctype, rname); | ||
4041 | return connect_to(ssh, | 4179 | return connect_to(ssh, |
4042 | fp->host_to_connect, fp->port_to_connect, | 4180 | fp->host_to_connect, fp->port_to_connect, |
4043 | ctype, rname); | 4181 | ctype, rname); |
@@ -4075,7 +4213,10 @@ channel_connect_to_port(struct ssh *ssh, const char *host, u_short port, | |||
4075 | char *ctype, char *rname, int *reason, const char **errmsg) | 4213 | char *ctype, char *rname, int *reason, const char **errmsg) |
4076 | { | 4214 | { |
4077 | struct ssh_channels *sc = ssh->chanctxt; | 4215 | struct ssh_channels *sc = ssh->chanctxt; |
4216 | struct channel_connect cctx; | ||
4217 | Channel *c; | ||
4078 | u_int i, permit, permit_adm = 1; | 4218 | u_int i, permit, permit_adm = 1; |
4219 | int sock; | ||
4079 | ForwardPermission *fp; | 4220 | ForwardPermission *fp; |
4080 | 4221 | ||
4081 | permit = sc->all_opens_permitted; | 4222 | permit = sc->all_opens_permitted; |
@@ -4107,7 +4248,22 @@ channel_connect_to_port(struct ssh *ssh, const char *host, u_short port, | |||
4107 | *reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED; | 4248 | *reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED; |
4108 | return NULL; | 4249 | return NULL; |
4109 | } | 4250 | } |
4110 | return connect_to_reason(ssh, host, port, ctype, rname, reason, errmsg); | 4251 | |
4252 | memset(&cctx, 0, sizeof(cctx)); | ||
4253 | sock = connect_to_helper(ssh, host, port, SOCK_STREAM, ctype, rname, | ||
4254 | &cctx, reason, errmsg); | ||
4255 | if (sock == -1) { | ||
4256 | channel_connect_ctx_free(&cctx); | ||
4257 | return NULL; | ||
4258 | } | ||
4259 | |||
4260 | c = channel_new(ssh, ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1, | ||
4261 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1); | ||
4262 | c->host_port = port; | ||
4263 | c->path = xstrdup(host); | ||
4264 | c->connect_ctx = cctx; | ||
4265 | |||
4266 | return c; | ||
4111 | } | 4267 | } |
4112 | 4268 | ||
4113 | /* Check if connecting to that path is permitted and connect. */ | 4269 | /* Check if connecting to that path is permitted and connect. */ |
@@ -4174,6 +4330,54 @@ channel_send_window_changes(struct ssh *ssh) | |||
4174 | } | 4330 | } |
4175 | } | 4331 | } |
4176 | 4332 | ||
4333 | /* Return RDYNAMIC_OPEN channel: channel allows SOCKS, but is not connected */ | ||
4334 | static Channel * | ||
4335 | rdynamic_connect_prepare(struct ssh *ssh, char *ctype, char *rname) | ||
4336 | { | ||
4337 | Channel *c; | ||
4338 | int r; | ||
4339 | |||
4340 | c = channel_new(ssh, ctype, SSH_CHANNEL_RDYNAMIC_OPEN, -1, -1, -1, | ||
4341 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1); | ||
4342 | c->host_port = 0; | ||
4343 | c->path = NULL; | ||
4344 | |||
4345 | /* | ||
4346 | * We need to open the channel before we have a FD, | ||
4347 | * so that we can get SOCKS header from peer. | ||
4348 | */ | ||
4349 | if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION)) != 0 || | ||
4350 | (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || | ||
4351 | (r = sshpkt_put_u32(ssh, c->self)) != 0 || | ||
4352 | (r = sshpkt_put_u32(ssh, c->local_window)) != 0 || | ||
4353 | (r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0) { | ||
4354 | fatal("%s: channel %i: confirm: %s", __func__, | ||
4355 | c->self, ssh_err(r)); | ||
4356 | } | ||
4357 | return c; | ||
4358 | } | ||
4359 | |||
4360 | /* Return CONNECTING socket to remote host:port or local socket path */ | ||
4361 | static int | ||
4362 | rdynamic_connect_finish(struct ssh *ssh, Channel *c) | ||
4363 | { | ||
4364 | struct channel_connect cctx; | ||
4365 | int sock; | ||
4366 | |||
4367 | memset(&cctx, 0, sizeof(cctx)); | ||
4368 | sock = connect_to_helper(ssh, c->path, c->host_port, SOCK_STREAM, NULL, | ||
4369 | NULL, &cctx, NULL, NULL); | ||
4370 | if (sock == -1) | ||
4371 | channel_connect_ctx_free(&cctx); | ||
4372 | else { | ||
4373 | /* similar to SSH_CHANNEL_CONNECTING but we've already sent the open */ | ||
4374 | c->type = SSH_CHANNEL_RDYNAMIC_FINISH; | ||
4375 | c->connect_ctx = cctx; | ||
4376 | channel_register_fds(ssh, c, sock, sock, -1, 0, 1, 0); | ||
4377 | } | ||
4378 | return sock; | ||
4379 | } | ||
4380 | |||
4177 | /* -- X11 forwarding */ | 4381 | /* -- X11 forwarding */ |
4178 | 4382 | ||
4179 | /* | 4383 | /* |
diff --git a/channels.h b/channels.h index d1cf5dc6a..126b04345 100644 --- a/channels.h +++ b/channels.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.h,v 1.129 2017/09/12 06:35:32 djm Exp $ */ | 1 | /* $OpenBSD: channels.h,v 1.130 2017/09/21 19:16:53 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -57,7 +57,9 @@ | |||
57 | #define SSH_CHANNEL_UNIX_LISTENER 18 /* Listening on a domain socket. */ | 57 | #define SSH_CHANNEL_UNIX_LISTENER 18 /* Listening on a domain socket. */ |
58 | #define SSH_CHANNEL_RUNIX_LISTENER 19 /* Listening to a R-style domain socket. */ | 58 | #define SSH_CHANNEL_RUNIX_LISTENER 19 /* Listening to a R-style domain socket. */ |
59 | #define SSH_CHANNEL_MUX_PROXY 20 /* proxy channel for mux-slave */ | 59 | #define SSH_CHANNEL_MUX_PROXY 20 /* proxy channel for mux-slave */ |
60 | #define SSH_CHANNEL_MAX_TYPE 21 | 60 | #define SSH_CHANNEL_RDYNAMIC_OPEN 21 /* reverse SOCKS, parsing request */ |
61 | #define SSH_CHANNEL_RDYNAMIC_FINISH 22 /* reverse SOCKS, finishing connect */ | ||
62 | #define SSH_CHANNEL_MAX_TYPE 23 | ||
61 | 63 | ||
62 | #define CHANNEL_CANCEL_PORT_STATIC -1 | 64 | #define CHANNEL_CANCEL_PORT_STATIC -1 |
63 | 65 | ||
diff --git a/readconf.c b/readconf.c index 4f38b27cf..f63894f9c 100644 --- a/readconf.c +++ b/readconf.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.c,v 1.278 2017/09/03 23:33:13 djm Exp $ */ | 1 | /* $OpenBSD: readconf.c,v 1.279 2017/09/21 19:16:53 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -836,6 +836,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, | |||
836 | char **cpptr, fwdarg[256]; | 836 | char **cpptr, fwdarg[256]; |
837 | u_int i, *uintptr, max_entries = 0; | 837 | u_int i, *uintptr, max_entries = 0; |
838 | int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0; | 838 | int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0; |
839 | int remotefwd, dynamicfwd; | ||
839 | LogLevel *log_level_ptr; | 840 | LogLevel *log_level_ptr; |
840 | SyslogFacility *log_facility_ptr; | 841 | SyslogFacility *log_facility_ptr; |
841 | long long val64; | 842 | long long val64; |
@@ -1255,31 +1256,36 @@ parse_keytypes: | |||
1255 | fatal("%.200s line %d: Missing port argument.", | 1256 | fatal("%.200s line %d: Missing port argument.", |
1256 | filename, linenum); | 1257 | filename, linenum); |
1257 | 1258 | ||
1258 | if (opcode == oLocalForward || | 1259 | remotefwd = (opcode == oRemoteForward); |
1259 | opcode == oRemoteForward) { | 1260 | dynamicfwd = (opcode == oDynamicForward); |
1260 | arg2 = strdelim(&s); | ||
1261 | if (arg2 == NULL || *arg2 == '\0') | ||
1262 | fatal("%.200s line %d: Missing target argument.", | ||
1263 | filename, linenum); | ||
1264 | 1261 | ||
1265 | /* construct a string for parse_forward */ | 1262 | if (!dynamicfwd) { |
1266 | snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2); | 1263 | arg2 = strdelim(&s); |
1267 | } else if (opcode == oDynamicForward) { | 1264 | if (arg2 == NULL || *arg2 == '\0') { |
1268 | strlcpy(fwdarg, arg, sizeof(fwdarg)); | 1265 | if (remotefwd) |
1266 | dynamicfwd = 1; | ||
1267 | else | ||
1268 | fatal("%.200s line %d: Missing target " | ||
1269 | "argument.", filename, linenum); | ||
1270 | } else { | ||
1271 | /* construct a string for parse_forward */ | ||
1272 | snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, | ||
1273 | arg2); | ||
1274 | } | ||
1269 | } | 1275 | } |
1276 | if (dynamicfwd) | ||
1277 | strlcpy(fwdarg, arg, sizeof(fwdarg)); | ||
1270 | 1278 | ||
1271 | if (parse_forward(&fwd, fwdarg, | 1279 | if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0) |
1272 | opcode == oDynamicForward ? 1 : 0, | ||
1273 | opcode == oRemoteForward ? 1 : 0) == 0) | ||
1274 | fatal("%.200s line %d: Bad forwarding specification.", | 1280 | fatal("%.200s line %d: Bad forwarding specification.", |
1275 | filename, linenum); | 1281 | filename, linenum); |
1276 | 1282 | ||
1277 | if (*activep) { | 1283 | if (*activep) { |
1278 | if (opcode == oLocalForward || | 1284 | if (remotefwd) { |
1279 | opcode == oDynamicForward) | ||
1280 | add_local_forward(options, &fwd); | ||
1281 | else if (opcode == oRemoteForward) | ||
1282 | add_remote_forward(options, &fwd); | 1285 | add_remote_forward(options, &fwd); |
1286 | } else { | ||
1287 | add_local_forward(options, &fwd); | ||
1288 | } | ||
1283 | } | 1289 | } |
1284 | break; | 1290 | break; |
1285 | 1291 | ||
@@ -33,8 +33,8 @@ | |||
33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | .\" | 35 | .\" |
36 | .\" $OpenBSD: ssh.1,v 1.383 2017/06/09 06:43:01 djm Exp $ | 36 | .\" $OpenBSD: ssh.1,v 1.384 2017/09/21 19:16:53 markus Exp $ |
37 | .Dd $Mdocdate: June 9 2017 $ | 37 | .Dd $Mdocdate: September 21 2017 $ |
38 | .Dt SSH 1 | 38 | .Dt SSH 1 |
39 | .Os | 39 | .Os |
40 | .Sh NAME | 40 | .Sh NAME |
@@ -592,21 +592,30 @@ Causes most warning and diagnostic messages to be suppressed. | |||
592 | .Ar remote_socket : local_socket | 592 | .Ar remote_socket : local_socket |
593 | .Sm on | 593 | .Sm on |
594 | .Xc | 594 | .Xc |
595 | .It Fl R Xo | ||
596 | .Sm off | ||
597 | .Oo Ar bind_address : Oc | ||
598 | .Ar port | ||
599 | .Sm on | ||
600 | .Xc | ||
595 | Specifies that connections to the given TCP port or Unix socket on the remote | 601 | Specifies that connections to the given TCP port or Unix socket on the remote |
596 | (server) host are to be forwarded to the given host and port, or Unix socket, | 602 | (server) host are to be forwarded to the local side. |
597 | on the local side. | 603 | .Pp |
598 | This works by allocating a socket to listen to either a TCP | 604 | This works by allocating a socket to listen to either a TCP |
599 | .Ar port | 605 | .Ar port |
600 | or to a Unix socket on the remote side. | 606 | or to a Unix socket on the remote side. |
601 | Whenever a connection is made to this port or Unix socket, the | 607 | Whenever a connection is made to this port or Unix socket, the |
602 | connection is forwarded over the secure channel, and a connection | 608 | connection is forwarded over the secure channel, and a connection |
603 | is made to either | 609 | is made from the local machine to either an explicit destination specified by |
604 | .Ar host | 610 | .Ar host |
605 | port | 611 | port |
606 | .Ar hostport , | 612 | .Ar hostport , |
607 | or | 613 | or |
608 | .Ar local_socket , | 614 | .Ar local_socket , |
609 | from the local machine. | 615 | or, if no explicit destination was specified, |
616 | .Nm | ||
617 | will act as a SOCKS 4/5 proxy and forward connections to the destinations | ||
618 | requested by the remote SOCKS client. | ||
610 | .Pp | 619 | .Pp |
611 | Port forwardings can also be specified in the configuration file. | 620 | Port forwardings can also be specified in the configuration file. |
612 | Privileged ports can be forwarded only when | 621 | Privileged ports can be forwarded only when |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh.c,v 1.463 2017/09/12 06:32:07 djm Exp $ */ | 1 | /* $OpenBSD: ssh.c,v 1.464 2017/09/21 19:16:53 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -868,7 +868,8 @@ main(int ac, char **av) | |||
868 | break; | 868 | break; |
869 | 869 | ||
870 | case 'R': | 870 | case 'R': |
871 | if (parse_forward(&fwd, optarg, 0, 1)) { | 871 | if (parse_forward(&fwd, optarg, 0, 1) || |
872 | parse_forward(&fwd, optarg, 1, 1)) { | ||
872 | add_remote_forward(&options, &fwd); | 873 | add_remote_forward(&options, &fwd); |
873 | } else { | 874 | } else { |
874 | fprintf(stderr, | 875 | fprintf(stderr, |
diff --git a/ssh_config.5 b/ssh_config.5 index ca5a41103..eab8dd01c 100644 --- a/ssh_config.5 +++ b/ssh_config.5 | |||
@@ -33,8 +33,8 @@ | |||
33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | .\" | 35 | .\" |
36 | .\" $OpenBSD: ssh_config.5,v 1.255 2017/09/04 06:34:43 jmc Exp $ | 36 | .\" $OpenBSD: ssh_config.5,v 1.256 2017/09/21 19:16:53 markus Exp $ |
37 | .Dd $Mdocdate: September 4 2017 $ | 37 | .Dd $Mdocdate: September 21 2017 $ |
38 | .Dt SSH_CONFIG 5 | 38 | .Dt SSH_CONFIG 5 |
39 | .Os | 39 | .Os |
40 | .Sh NAME | 40 | .Sh NAME |
@@ -1298,13 +1298,19 @@ accept the tokens described in the | |||
1298 | section. | 1298 | section. |
1299 | .It Cm RemoteForward | 1299 | .It Cm RemoteForward |
1300 | Specifies that a TCP port on the remote machine be forwarded over | 1300 | Specifies that a TCP port on the remote machine be forwarded over |
1301 | the secure channel to the specified host and port from the local machine. | 1301 | the secure channel. |
1302 | The remote port may either be fowarded to a specified host and port | ||
1303 | from the local machine, or may act as a SOCKS 4/5 proxy that allows a remote | ||
1304 | client to connect to arbitrary destinations from the local machine. | ||
1302 | The first argument must be | 1305 | The first argument must be |
1303 | .Sm off | 1306 | .Sm off |
1304 | .Oo Ar bind_address : Oc Ar port | 1307 | .Oo Ar bind_address : Oc Ar port |
1305 | .Sm on | 1308 | .Sm on |
1306 | and the second argument must be | 1309 | If forwarding to a specific destination then the second argument must be |
1307 | .Ar host : Ns Ar hostport . | 1310 | .Ar host : Ns Ar hostport , |
1311 | otherwise if no destination argument is specified then the remote forwarding | ||
1312 | will be established as a SOCKS proxy. | ||
1313 | .Pp | ||
1308 | IPv6 addresses can be specified by enclosing addresses in square brackets. | 1314 | IPv6 addresses can be specified by enclosing addresses in square brackets. |
1309 | Multiple forwardings may be specified, and additional | 1315 | Multiple forwardings may be specified, and additional |
1310 | forwardings can be given on the command line. | 1316 | forwardings can be given on the command line. |