version 1.129, 2023/12/18 14:45:49 |
version 1.130, 2024/05/17 00:30:24 |
|
|
#ifdef GSSAPI |
#ifdef GSSAPI |
#include "ssh-gss.h" |
#include "ssh-gss.h" |
#endif |
#endif |
#include "monitor_wrap.h" |
|
#include "atomicio.h" |
#include "atomicio.h" |
#include "monitor_fdpass.h" |
#include "monitor_fdpass.h" |
#include "misc.h" |
#include "misc.h" |
|
|
#include "channels.h" |
#include "channels.h" |
#include "session.h" |
#include "session.h" |
#include "servconf.h" |
#include "servconf.h" |
|
#include "monitor_wrap.h" |
|
|
#include "ssherr.h" |
#include "ssherr.h" |
|
|
|
|
debug3_f("entering"); |
debug3_f("entering"); |
|
|
if (atomicio(read, sock, buf, sizeof(buf)) != sizeof(buf)) { |
if (atomicio(read, sock, buf, sizeof(buf)) != sizeof(buf)) { |
if (errno == EPIPE) |
if (errno == EPIPE) { |
|
debug3_f("monitor fd closed"); |
cleanup_exit(255); |
cleanup_exit(255); |
|
} |
fatal_f("read: %s", strerror(errno)); |
fatal_f("read: %s", strerror(errno)); |
} |
} |
msg_len = PEEK_U32(buf); |
msg_len = PEEK_U32(buf); |
|
|
return (0); |
return (0); |
} |
} |
|
|
|
void |
|
mm_decode_activate_server_options(struct ssh *ssh, struct sshbuf *m) |
|
{ |
|
const u_char *p; |
|
size_t len; |
|
u_int i; |
|
ServerOptions *newopts; |
|
int r; |
|
|
|
if ((r = sshbuf_get_string_direct(m, &p, &len)) != 0) |
|
fatal_fr(r, "parse opts"); |
|
if (len != sizeof(*newopts)) |
|
fatal_f("option block size mismatch"); |
|
newopts = xcalloc(sizeof(*newopts), 1); |
|
memcpy(newopts, p, sizeof(*newopts)); |
|
|
|
#define M_CP_STROPT(x) do { \ |
|
if (newopts->x != NULL && \ |
|
(r = sshbuf_get_cstring(m, &newopts->x, NULL)) != 0) \ |
|
fatal_fr(r, "parse %s", #x); \ |
|
} while (0) |
|
#define M_CP_STRARRAYOPT(x, nx) do { \ |
|
newopts->x = newopts->nx == 0 ? \ |
|
NULL : xcalloc(newopts->nx, sizeof(*newopts->x)); \ |
|
for (i = 0; i < newopts->nx; i++) { \ |
|
if ((r = sshbuf_get_cstring(m, \ |
|
&newopts->x[i], NULL)) != 0) \ |
|
fatal_fr(r, "parse %s", #x); \ |
|
} \ |
|
} while (0) |
|
/* See comment in servconf.h */ |
|
COPY_MATCH_STRING_OPTS(); |
|
#undef M_CP_STROPT |
|
#undef M_CP_STRARRAYOPT |
|
|
|
copy_set_server_options(&options, newopts, 1); |
|
log_change_level(options.log_level); |
|
log_verbose_reset(); |
|
for (i = 0; i < options.num_log_verbose; i++) |
|
log_verbose_add(options.log_verbose[i]); |
|
free(newopts); |
|
} |
|
|
#define GETPW(b, id) \ |
#define GETPW(b, id) \ |
do { \ |
do { \ |
if ((r = sshbuf_get_string_direct(b, &p, &len)) != 0) \ |
if ((r = sshbuf_get_string_direct(b, &p, &len)) != 0) \ |
|
|
struct sshbuf *m; |
struct sshbuf *m; |
struct passwd *pw; |
struct passwd *pw; |
size_t len; |
size_t len; |
u_int i; |
|
ServerOptions *newopts; |
|
int r; |
int r; |
u_char ok; |
u_char ok; |
const u_char *p; |
const u_char *p; |
|
|
|
|
out: |
out: |
/* copy options block as a Match directive may have changed some */ |
/* copy options block as a Match directive may have changed some */ |
if ((r = sshbuf_get_string_direct(m, &p, &len)) != 0) |
mm_decode_activate_server_options(ssh, m); |
fatal_fr(r, "parse opts"); |
server_process_permitopen(ssh); |
if (len != sizeof(*newopts)) |
server_process_channel_timeouts(ssh); |
fatal_f("option block size mismatch"); |
|
newopts = xcalloc(sizeof(*newopts), 1); |
|
memcpy(newopts, p, sizeof(*newopts)); |
|
|
|
#define M_CP_STROPT(x) do { \ |
|
if (newopts->x != NULL && \ |
|
(r = sshbuf_get_cstring(m, &newopts->x, NULL)) != 0) \ |
|
fatal_fr(r, "parse %s", #x); \ |
|
} while (0) |
|
#define M_CP_STRARRAYOPT(x, nx) do { \ |
|
newopts->x = newopts->nx == 0 ? \ |
|
NULL : xcalloc(newopts->nx, sizeof(*newopts->x)); \ |
|
for (i = 0; i < newopts->nx; i++) { \ |
|
if ((r = sshbuf_get_cstring(m, \ |
|
&newopts->x[i], NULL)) != 0) \ |
|
fatal_fr(r, "parse %s", #x); \ |
|
} \ |
|
} while (0) |
|
/* See comment in servconf.h */ |
|
COPY_MATCH_STRING_OPTS(); |
|
#undef M_CP_STROPT |
|
#undef M_CP_STRARRAYOPT |
|
|
|
copy_set_server_options(&options, newopts, 1); |
|
log_change_level(options.log_level); |
|
log_verbose_reset(); |
|
for (i = 0; i < options.num_log_verbose; i++) |
|
log_verbose_add(options.log_verbose[i]); |
|
process_permitopen(ssh, &options); |
|
process_channel_timeouts(ssh, &options); |
|
kex_set_server_sig_algs(ssh, options.pubkey_accepted_algos); |
kex_set_server_sig_algs(ssh, options.pubkey_accepted_algos); |
free(newopts); |
|
sshbuf_free(m); |
sshbuf_free(m); |
|
|
return (pw); |
return (pw); |
|
|
return (authenticated); |
return (authenticated); |
} |
} |
#endif /* GSSAPI */ |
#endif /* GSSAPI */ |
|
|
|
/* |
|
* Inform channels layer of permitopen options for a single forwarding |
|
* direction (local/remote). |
|
*/ |
|
static void |
|
server_process_permitopen_list(struct ssh *ssh, int listen, |
|
char **opens, u_int num_opens) |
|
{ |
|
u_int i; |
|
int port; |
|
char *host, *arg, *oarg; |
|
int where = listen ? FORWARD_REMOTE : FORWARD_LOCAL; |
|
const char *what = listen ? "permitlisten" : "permitopen"; |
|
|
|
channel_clear_permission(ssh, FORWARD_ADM, where); |
|
if (num_opens == 0) |
|
return; /* permit any */ |
|
|
|
/* handle keywords: "any" / "none" */ |
|
if (num_opens == 1 && strcmp(opens[0], "any") == 0) |
|
return; |
|
if (num_opens == 1 && strcmp(opens[0], "none") == 0) { |
|
channel_disable_admin(ssh, where); |
|
return; |
|
} |
|
/* Otherwise treat it as a list of permitted host:port */ |
|
for (i = 0; i < num_opens; i++) { |
|
oarg = arg = xstrdup(opens[i]); |
|
host = hpdelim(&arg); |
|
if (host == NULL) |
|
fatal_f("missing host in %s", what); |
|
host = cleanhostname(host); |
|
if (arg == NULL || ((port = permitopen_port(arg)) < 0)) |
|
fatal_f("bad port number in %s", what); |
|
/* Send it to channels layer */ |
|
channel_add_permission(ssh, FORWARD_ADM, |
|
where, host, port); |
|
free(oarg); |
|
} |
|
} |
|
|
|
/* |
|
* Inform channels layer of permitopen options from configuration. |
|
*/ |
|
void |
|
server_process_permitopen(struct ssh *ssh) |
|
{ |
|
server_process_permitopen_list(ssh, 0, |
|
options.permitted_opens, options.num_permitted_opens); |
|
server_process_permitopen_list(ssh, 1, |
|
options.permitted_listens, options.num_permitted_listens); |
|
} |
|
|
|
void |
|
server_process_channel_timeouts(struct ssh *ssh) |
|
{ |
|
u_int i, secs; |
|
char *type; |
|
|
|
debug3_f("setting %u timeouts", options.num_channel_timeouts); |
|
channel_clear_timeouts(ssh); |
|
for (i = 0; i < options.num_channel_timeouts; i++) { |
|
if (parse_pattern_interval(options.channel_timeouts[i], |
|
&type, &secs) != 0) { |
|
fatal_f("internal error: bad timeout %s", |
|
options.channel_timeouts[i]); |
|
} |
|
channel_add_timeout(ssh, type, secs); |
|
free(type); |
|
} |
|
} |
|
|
|
struct connection_info * |
|
server_get_connection_info(struct ssh *ssh, int populate, int use_dns) |
|
{ |
|
static struct connection_info ci; |
|
|
|
if (ssh == NULL || !populate) |
|
return &ci; |
|
ci.host = use_dns ? ssh_remote_hostname(ssh) : ssh_remote_ipaddr(ssh); |
|
ci.address = ssh_remote_ipaddr(ssh); |
|
ci.laddress = ssh_local_ipaddr(ssh); |
|
ci.lport = ssh_local_port(ssh); |
|
ci.rdomain = ssh_packet_rdomain_in(ssh); |
|
return &ci; |
|
} |
|
|