version 1.539, 2020/10/16 13:26:13 |
version 1.540, 2020/10/18 11:32:02 |
|
|
} |
} |
if (cname != NULL && res->ai_canonname != NULL) { |
if (cname != NULL && res->ai_canonname != NULL) { |
if (strlcpy(cname, res->ai_canonname, clen) >= clen) { |
if (strlcpy(cname, res->ai_canonname, clen) >= clen) { |
error("%s: host \"%s\" cname \"%s\" too long (max %lu)", |
error_f("host \"%s\" cname \"%s\" too long (max %lu)", |
__func__, name, res->ai_canonname, (u_long)clen); |
name, res->ai_canonname, (u_long)clen); |
if (clen > 0) |
if (clen > 0) |
*cname = '\0'; |
*cname = '\0'; |
} |
} |
|
|
hints.ai_socktype = SOCK_STREAM; |
hints.ai_socktype = SOCK_STREAM; |
hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV; |
hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV; |
if ((gaierr = getaddrinfo(name, strport, &hints, &res)) != 0) { |
if ((gaierr = getaddrinfo(name, strport, &hints, &res)) != 0) { |
debug2("%s: could not resolve name %.100s as address: %s", |
debug2_f("could not resolve name %.100s as address: %s", |
__func__, name, ssh_gai_strerror(gaierr)); |
name, ssh_gai_strerror(gaierr)); |
return NULL; |
return NULL; |
} |
} |
if (res == NULL) { |
if (res == NULL) { |
debug("%s: getaddrinfo %.100s returned no addresses", |
debug_f("getaddrinfo %.100s returned no addresses", name); |
__func__, name); |
|
return NULL; |
return NULL; |
} |
} |
if (res->ai_next != NULL) { |
if (res->ai_next != NULL) { |
debug("%s: getaddrinfo %.100s returned multiple addresses", |
debug_f("getaddrinfo %.100s returned multiple addresses", name); |
__func__, name); |
|
goto fail; |
goto fail; |
} |
} |
if ((gaierr = getnameinfo(res->ai_addr, res->ai_addrlen, |
if ((gaierr = getnameinfo(res->ai_addr, res->ai_addrlen, |
addr, sizeof(addr), NULL, 0, NI_NUMERICHOST)) != 0) { |
addr, sizeof(addr), NULL, 0, NI_NUMERICHOST)) != 0) { |
debug("%s: Could not format address for name %.100s: %s", |
debug_f("Could not format address for name %.100s: %s", |
__func__, name, ssh_gai_strerror(gaierr)); |
name, ssh_gai_strerror(gaierr)); |
goto fail; |
goto fail; |
} |
} |
if (strlcpy(caddr, addr, clen) >= clen) { |
if (strlcpy(caddr, addr, clen) >= clen) { |
error("%s: host \"%s\" addr \"%s\" too long (max %lu)", |
error_f("host \"%s\" addr \"%s\" too long (max %lu)", |
__func__, name, addr, (u_long)clen); |
name, addr, (u_long)clen); |
if (clen > 0) |
if (clen > 0) |
*caddr = '\0'; |
*caddr = '\0'; |
fail: |
fail: |
|
|
if (!direct && |
if (!direct && |
options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) |
options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) |
return 0; |
return 0; |
debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname); |
debug3_f("check \"%s\" CNAME \"%s\"", *namep, cname); |
for (i = 0; i < options.num_permitted_cnames; i++) { |
for (i = 0; i < options.num_permitted_cnames; i++) { |
rule = options.permitted_cnames + i; |
rule = options.permitted_cnames + i; |
if (match_pattern_list(*namep, rule->source_list, 1) != 1 || |
if (match_pattern_list(*namep, rule->source_list, 1) != 1 || |
|
|
*/ |
*/ |
if ((addrs = resolve_addr(*hostp, port, |
if ((addrs = resolve_addr(*hostp, port, |
newname, sizeof(newname))) != NULL) { |
newname, sizeof(newname))) != NULL) { |
debug2("%s: hostname %.100s is address", __func__, *hostp); |
debug2_f("hostname %.100s is address", *hostp); |
if (strcasecmp(*hostp, newname) != 0) { |
if (strcasecmp(*hostp, newname) != 0) { |
debug2("%s: canonicalised address \"%s\" => \"%s\"", |
debug2_f("canonicalised address \"%s\" => \"%s\"", |
__func__, *hostp, newname); |
*hostp, newname); |
free(*hostp); |
free(*hostp); |
*hostp = xstrdup(newname); |
*hostp = xstrdup(newname); |
} |
} |
|
|
* attempts at canonicalisation. |
* attempts at canonicalisation. |
*/ |
*/ |
if (is_addr_fast(*hostp)) { |
if (is_addr_fast(*hostp)) { |
debug("%s: hostname %.100s is an unrecognised address", |
debug_f("hostname %.100s is an unrecognised address", *hostp); |
__func__, *hostp); |
|
return NULL; |
return NULL; |
} |
} |
|
|
|
|
|
|
/* If domain name is anchored, then resolve it now */ |
/* If domain name is anchored, then resolve it now */ |
if ((*hostp)[strlen(*hostp) - 1] == '.') { |
if ((*hostp)[strlen(*hostp) - 1] == '.') { |
debug3("%s: name is fully qualified", __func__); |
debug3_f("name is fully qualified"); |
fullhost = xstrdup(*hostp); |
fullhost = xstrdup(*hostp); |
if ((addrs = resolve_host(fullhost, port, 0, |
if ((addrs = resolve_host(fullhost, port, 0, |
newname, sizeof(newname))) != NULL) |
newname, sizeof(newname))) != NULL) |
|
|
ndots++; |
ndots++; |
} |
} |
if (ndots > options.canonicalize_max_dots) { |
if (ndots > options.canonicalize_max_dots) { |
debug3("%s: not canonicalizing hostname \"%s\" (max dots %d)", |
debug3_f("not canonicalizing hostname \"%s\" (max dots %d)", |
__func__, *hostp, options.canonicalize_max_dots); |
*hostp, options.canonicalize_max_dots); |
return NULL; |
return NULL; |
} |
} |
/* Attempt each supplied suffix */ |
/* Attempt each supplied suffix */ |
for (i = 0; i < options.num_canonical_domains; i++) { |
for (i = 0; i < options.num_canonical_domains; i++) { |
xasprintf(&fullhost, "%s.%s.", *hostp, |
xasprintf(&fullhost, "%s.%s.", *hostp, |
options.canonical_domains[i]); |
options.canonical_domains[i]); |
debug3("%s: attempting \"%s\" => \"%s\"", __func__, |
debug3_f("attempting \"%s\" => \"%s\"", *hostp, fullhost); |
*hostp, fullhost); |
|
if ((addrs = resolve_host(fullhost, port, 0, |
if ((addrs = resolve_host(fullhost, port, 0, |
newname, sizeof(newname))) == NULL) { |
newname, sizeof(newname))) == NULL) { |
free(fullhost); |
free(fullhost); |
|
|
notfound: |
notfound: |
if (!options.canonicalize_fallback_local) |
if (!options.canonicalize_fallback_local) |
fatal("%s: Could not resolve host \"%s\"", __progname, *hostp); |
fatal("%s: Could not resolve host \"%s\"", __progname, *hostp); |
debug2("%s: host %s not found in any suffix", __func__, *hostp); |
debug2_f("host %s not found in any suffix", *hostp); |
return NULL; |
return NULL; |
} |
} |
|
|
|
|
break; |
break; |
case SSH_ERR_INTERNAL_ERROR: |
case SSH_ERR_INTERNAL_ERROR: |
case SSH_ERR_ALLOC_FAIL: |
case SSH_ERR_ALLOC_FAIL: |
fatal("load %s \"%s\": %s", message, path, ssh_err(r)); |
fatal_r(r, "load %s \"%s\"", message, path); |
case SSH_ERR_SYSTEM_ERROR: |
case SSH_ERR_SYSTEM_ERROR: |
/* Ignore missing files */ |
/* Ignore missing files */ |
if (errno == ENOENT) |
if (errno == ENOENT) |
break; |
break; |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
default: |
default: |
error("load %s \"%s\": %s", message, path, ssh_err(r)); |
error_r(r, "load %s \"%s\"", message, path); |
break; |
break; |
} |
} |
} |
} |
|
|
for (i = 0; i < ac; i++) { |
for (i = 0; i < ac; i++) { |
if ((r = sshbuf_putf(command, "%s%s", |
if ((r = sshbuf_putf(command, "%s%s", |
i ? " " : "", av[i])) != 0) |
i ? " " : "", av[i])) != 0) |
fatal("%s: buffer error: %s", |
fatal_fr(r, "buffer error"); |
__func__, ssh_err(r)); |
|
} |
} |
} |
} |
|
|
|
|
free(cp); |
free(cp); |
if ((r = sshbuf_put(command, options.remote_command, |
if ((r = sshbuf_put(command, options.remote_command, |
strlen(options.remote_command))) != 0) |
strlen(options.remote_command))) != 0) |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
fatal_fr(r, "buffer error"); |
} |
} |
|
|
if (options.control_path != NULL) { |
if (options.control_path != NULL) { |
|
|
/* XXX check errors? */ |
/* XXX check errors? */ |
#define L_PUBKEY(p,o) do { \ |
#define L_PUBKEY(p,o) do { \ |
if ((o) >= sensitive_data.nkeys) \ |
if ((o) >= sensitive_data.nkeys) \ |
fatal("%s pubkey out of array bounds", __func__); \ |
fatal_f("pubkey out of array bounds"); \ |
check_load(sshkey_load_public(p, &(sensitive_data.keys[o]), NULL), \ |
check_load(sshkey_load_public(p, &(sensitive_data.keys[o]), NULL), \ |
p, "pubkey"); \ |
p, "pubkey"); \ |
} while (0) |
} while (0) |
#define L_CERT(p,o) do { \ |
#define L_CERT(p,o) do { \ |
if ((o) >= sensitive_data.nkeys) \ |
if ((o) >= sensitive_data.nkeys) \ |
fatal("%s cert out of array bounds", __func__); \ |
fatal_f("cert out of array bounds"); \ |
check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), p, "cert"); \ |
check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), p, "cert"); \ |
} while (0) |
} while (0) |
|
|
|
|
{ |
{ |
pid_t pid; |
pid_t pid; |
|
|
debug("%s: backgrounding master process", __func__); |
debug_f("backgrounding master process"); |
|
|
/* |
/* |
* master (current process) into the background, and make the |
* master (current process) into the background, and make the |
|
|
*/ |
*/ |
switch ((pid = fork())) { |
switch ((pid = fork())) { |
case -1: |
case -1: |
fatal("%s: fork: %s", __func__, strerror(errno)); |
fatal_f("fork: %s", strerror(errno)); |
case 0: |
case 0: |
/* Child: master process continues mainloop */ |
/* Child: master process continues mainloop */ |
break; |
break; |
default: |
default: |
/* Parent: set up mux client to connect to backgrounded master */ |
/* Parent: set up mux client to connect to backgrounded master */ |
debug2("%s: background process is %ld", __func__, (long)pid); |
debug2_f("background process is %ld", (long)pid); |
stdin_null_flag = ostdin_null_flag; |
stdin_null_flag = ostdin_null_flag; |
options.request_tty = orequest_tty; |
options.request_tty = orequest_tty; |
tty_flag = otty_flag; |
tty_flag = otty_flag; |
|
|
fatal("Failed to connect to new control master"); |
fatal("Failed to connect to new control master"); |
} |
} |
if (stdfd_devnull(1, 1, !(log_is_on_stderr() && debug_flag)) == -1) |
if (stdfd_devnull(1, 1, !(log_is_on_stderr() && debug_flag)) == -1) |
error("%s: stdfd_devnull failed", __func__); |
error_f("stdfd_devnull failed"); |
daemon(1, 1); |
daemon(1, 1); |
setproctitle("%s [mux]", options.control_path); |
setproctitle("%s [mux]", options.control_path); |
} |
} |
|
|
if (daemon(1, 1) == -1) |
if (daemon(1, 1) == -1) |
fatal("daemon() failed: %.200s", strerror(errno)); |
fatal("daemon() failed: %.200s", strerror(errno)); |
if (stdfd_devnull(1, 1, !(log_is_on_stderr() && debug_flag)) == -1) |
if (stdfd_devnull(1, 1, !(log_is_on_stderr() && debug_flag)) == -1) |
error("%s: stdfd_devnull failed", __func__); |
error_f("stdfd_devnull failed"); |
} |
} |
|
|
static void |
static void |
|
|
if (forward_confirms_pending == -1) |
if (forward_confirms_pending == -1) |
return; |
return; |
if (--forward_confirms_pending == 0) { |
if (--forward_confirms_pending == 0) { |
debug("%s: all expected forwarding replies received", __func__); |
debug_f("all expected forwarding replies received"); |
if (fork_after_authentication_flag) |
if (fork_after_authentication_flag) |
fork_postauth(); |
fork_postauth(); |
} else { |
} else { |
debug2("%s: %d expected forwarding replies remaining", |
debug2_f("%d expected forwarding replies remaining", |
__func__, forward_confirms_pending); |
forward_confirms_pending); |
} |
} |
} |
} |
|
|
|
|
if (rfwd->listen_path == NULL && rfwd->listen_port == 0) { |
if (rfwd->listen_path == NULL && rfwd->listen_port == 0) { |
if (type == SSH2_MSG_REQUEST_SUCCESS) { |
if (type == SSH2_MSG_REQUEST_SUCCESS) { |
if ((r = sshpkt_get_u32(ssh, &port)) != 0) |
if ((r = sshpkt_get_u32(ssh, &port)) != 0) |
fatal("%s: %s", __func__, ssh_err(r)); |
fatal_fr(r, "parse packet"); |
if (port > 65535) { |
if (port > 65535) { |
error("Invalid allocated port %u for remote " |
error("Invalid allocated port %u for remote " |
"forward to %s:%d", port, |
"forward to %s:%d", port, |
|
|
cleanup_exit(255); |
cleanup_exit(255); |
} |
} |
|
|
debug("%s: tunnel forward established, id=%d", __func__, id); |
debug_f("tunnel forward established, id=%d", id); |
forwarding_success(); |
forwarding_success(); |
} |
} |
|
|
|
|
if (options.stdio_forward_host == NULL) |
if (options.stdio_forward_host == NULL) |
return; |
return; |
|
|
debug3("%s: %s:%d", __func__, options.stdio_forward_host, |
debug3_f("%s:%d", options.stdio_forward_host, |
options.stdio_forward_port); |
options.stdio_forward_port); |
|
|
if ((in = dup(STDIN_FILENO)) == -1 || |
if ((in = dup(STDIN_FILENO)) == -1 || |
|
|
fatal("channel_connect_stdio_fwd: dup() in/out failed"); |
fatal("channel_connect_stdio_fwd: dup() in/out failed"); |
if ((c = channel_connect_stdio_fwd(ssh, options.stdio_forward_host, |
if ((c = channel_connect_stdio_fwd(ssh, options.stdio_forward_host, |
options.stdio_forward_port, in, out)) == NULL) |
options.stdio_forward_port, in, out)) == NULL) |
fatal("%s: channel_connect_stdio_fwd failed", __func__); |
fatal_f("channel_connect_stdio_fwd failed"); |
channel_register_cleanup(ssh, c->self, client_cleanup_stdio_fwd, 0); |
channel_register_cleanup(ssh, c->self, client_cleanup_stdio_fwd, 0); |
channel_register_open_confirm(ssh, c->self, ssh_stdio_confirm, NULL); |
channel_register_open_confirm(ssh, c->self, ssh_stdio_confirm, NULL); |
} |
} |
|
|
error("Could not request tunnel forwarding."); |
error("Could not request tunnel forwarding."); |
} |
} |
if (forward_confirms_pending > 0) { |
if (forward_confirms_pending > 0) { |
debug("%s: expecting replies for %d forwards", __func__, |
debug_f("expecting replies for %d forwards", |
forward_confirms_pending); |
forward_confirms_pending); |
} |
} |
} |
} |
|
|
if ((r = ssh_get_authentication_socket(NULL)) != 0) { |
if ((r = ssh_get_authentication_socket(NULL)) != 0) { |
options.forward_agent = 0; |
options.forward_agent = 0; |
if (r != SSH_ERR_AGENT_NOT_PRESENT) |
if (r != SSH_ERR_AGENT_NOT_PRESENT) |
debug("ssh_get_authentication_socket: %s", |
debug_r(r, "ssh_get_authentication_socket"); |
ssh_err(r)); |
|
} |
} |
} |
} |
} |
} |
|
|
debug("Requesting authentication agent forwarding."); |
debug("Requesting authentication agent forwarding."); |
channel_request_start(ssh, id, "auth-agent-req@openssh.com", 0); |
channel_request_start(ssh, id, "auth-agent-req@openssh.com", 0); |
if ((r = sshpkt_send(ssh)) != 0) |
if ((r = sshpkt_send(ssh)) != 0) |
fatal("%s: %s", __func__, ssh_err(r)); |
fatal_fr(r, "send packet"); |
} |
} |
|
|
/* Tell the packet module whether this is an interactive session. */ |
/* Tell the packet module whether this is an interactive session. */ |
|
|
window, packetmax, CHAN_EXTENDED_WRITE, |
window, packetmax, CHAN_EXTENDED_WRITE, |
"client-session", /*nonblock*/0); |
"client-session", /*nonblock*/0); |
|
|
debug3("%s: channel_new: %d", __func__, c->self); |
debug3_f("channel_new: %d", c->self); |
|
|
channel_send_open(ssh, c->self); |
channel_send_open(ssh, c->self); |
if (!no_shell_flag) |
if (!no_shell_flag) |
|
|
"no-more-sessions@openssh.com")) != 0 || |
"no-more-sessions@openssh.com")) != 0 || |
(r = sshpkt_put_u8(ssh, 0)) != 0 || |
(r = sshpkt_put_u8(ssh, 0)) != 0 || |
(r = sshpkt_send(ssh)) != 0) |
(r = sshpkt_send(ssh)) != 0) |
fatal("%s: %s", __func__, ssh_err(r)); |
fatal_fr(r, "send packet"); |
} |
} |
|
|
/* Execute a local command */ |
/* Execute a local command */ |
|
|
* as it may want to write to stdout. |
* as it may want to write to stdout. |
*/ |
*/ |
if (!need_controlpersist_detach && stdfd_devnull(0, 1, 0) == -1) |
if (!need_controlpersist_detach && stdfd_devnull(0, 1, 0) == -1) |
error("%s: stdfd_devnull failed", __func__); |
error_f("stdfd_devnull failed"); |
|
|
/* |
/* |
* If requested and we are not interested in replies to remote |
* If requested and we are not interested in replies to remote |
|
|
continue; |
continue; |
} |
} |
if (!sshkey_is_cert(public)) { |
if (!sshkey_is_cert(public)) { |
debug("%s: key %s type %s is not a certificate", |
debug_f("key %s type %s is not a certificate", |
__func__, cp, sshkey_type(public)); |
cp, sshkey_type(public)); |
sshkey_free(public); |
sshkey_free(public); |
free(cp); |
free(cp); |
continue; |
continue; |
|
|
} |
} |
|
|
if (options.num_certificate_files > SSH_MAX_CERTIFICATE_FILES) |
if (options.num_certificate_files > SSH_MAX_CERTIFICATE_FILES) |
fatal("%s: too many certificates", __func__); |
fatal_f("too many certificates"); |
for (i = 0; i < options.num_certificate_files; i++) { |
for (i = 0; i < options.num_certificate_files; i++) { |
cp = tilde_expand_filename(options.certificate_files[i], |
cp = tilde_expand_filename(options.certificate_files[i], |
getuid()); |
getuid()); |
|
|
continue; |
continue; |
} |
} |
if (!sshkey_is_cert(public)) { |
if (!sshkey_is_cert(public)) { |
debug("%s: key %s type %s is not a certificate", |
debug_f("key %s type %s is not a certificate", |
__func__, filename, sshkey_type(public)); |
filename, sshkey_type(public)); |
sshkey_free(public); |
sshkey_free(public); |
free(filename); |
free(filename); |
continue; |
continue; |