int buffer_get_bignum2(Buffer *buffer, BIGNUM *value) { unsigned int len; unsigned char *bin; if ((bin = (unsigned char *)buffer_get_string_ret(buffer, &len)) == NULL) { return (-1); } if (len > 0 && (bin[0] & 0x80)) { free(bin); return (-1); } if (len > 8 * 1024) { free(bin); return (-1); } if (BN_bin2bn(bin, len, value) == NULL) { free(bin); return (-1); } free(bin); return (0); }
int buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value) { u_int len; u_char *bin; if ((bin = buffer_get_string_ret(buffer, &len)) == NULL) { error("buffer_get_bignum2_ret: invalid bignum"); return (-1); } if (len > 0 && (bin[0] & 0x80)) { error("buffer_get_bignum2_ret: negative numbers not supported"); free(bin); return (-1); } if (len > 8 * 1024) { error("buffer_get_bignum2_ret: cannot handle BN of size %d", len); free(bin); return (-1); } if (BN_bin2bn(bin, len, value) == NULL) { error("buffer_get_bignum2_ret: BN_bin2bn failed"); free(bin); return (-1); } free(bin); return (0); }
void * buffer_get_bignum2_as_string_ret(Buffer *buffer, u_int *length_ptr) { u_int len; u_char *bin, *p, *ret; if ((p = bin = buffer_get_string_ret(buffer, &len)) == NULL) { error("%s: invalid bignum", __func__); return NULL; } if (len > 0 && (bin[0] & 0x80)) { error("%s: negative numbers not supported", __func__); free(bin); return NULL; } if (len > 8 * 1024) { error("%s: cannot handle BN of size %d", __func__, len); free(bin); return NULL; } /* Skip zero prefix on numbers with the MSB set */ if (len > 1 && bin[0] == 0x00 && (bin[1] & 0x80) != 0) { p++; len--; } ret = xmalloc(len); memcpy(ret, p, len); memset(p, '\0', len); free(bin); return ret; }
void * buffer_get_string(Buffer *buffer, u_int *length_ptr) { void *ret; if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL) fatal("%s: buffer error", __func__); return (ret); }
static int process_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r) { u_int ver; struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; if (state == NULL) fatal("%s: channel %d: c->mux_ctx == NULL", __func__, c->self); if (state->hello_rcvd) { error("%s: HELLO received twice", __func__); return -1; } if (buffer_get_int_ret(&ver, m) != 0) { malf: error("%s: malformed message", __func__); return -1; } if (ver != SSHMUX_VER) { error("Unsupported multiplexing protocol version %d " "(expected %d)", ver, SSHMUX_VER); return -1; } debug2("%s: channel %d slave version %u", __func__, c->self, ver); /* No extensions are presently defined */ while (buffer_len(m) > 0) { char *name = buffer_get_string_ret(m, NULL); char *value = buffer_get_string_ret(m, NULL); if (name == NULL || value == NULL) { if (name != NULL) xfree(name); goto malf; } debug2("Unrecognised slave extension \"%s\"", name); xfree(name); xfree(value); } state->hello_rcvd = 1; return 0; }
void rexec_recv_rng_seed(Buffer *m) { u_char *buf; u_int len; buf = buffer_get_string_ret(m, &len); if (buf != NULL) { debug3("rexec_recv_rng_seed: seeding rng with %u bytes", len); RAND_add(buf, len, len); } }
int buffer_get_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve, EC_POINT *point) { u_char *buf; u_int len; BN_CTX *bnctx; int ret = -1; if ((buf = buffer_get_string_ret(buffer, &len)) == NULL) { error("%s: invalid point", __func__); return -1; } if ((bnctx = BN_CTX_new()) == NULL) fatal("%s: BN_CTX_new failed", __func__); if (len > BUFFER_MAX_ECPOINT_LEN) { error("%s: EC_POINT too long: %u > max %u", __func__, len, BUFFER_MAX_ECPOINT_LEN); goto out; } if (len == 0) { error("%s: EC_POINT buffer is empty", __func__); goto out; } if (buf[0] != POINT_CONVERSION_UNCOMPRESSED) { error("%s: EC_POINT is in an incorrect form: " "0x%02x (want 0x%02x)", __func__, buf[0], POINT_CONVERSION_UNCOMPRESSED); goto out; } if (EC_POINT_oct2point(curve, point, buf, len, bnctx) != 1) { error("buffer_get_bignum2_ret: BN_bin2bn failed"); goto out; } /* EC_POINT_oct2point verifies that the point is on the curve for us */ ret = 0; out: BN_CTX_free(bnctx); bzero(buf, len); xfree(buf); return ret; }
char * buffer_get_cstring_ret(Buffer *buffer, u_int *length_ptr) { u_int length; char *cp, *ret = buffer_get_string_ret(buffer, &length); if (ret == NULL) return NULL; if ((cp = memchr(ret, '\0', length)) != NULL) { /* XXX allow \0 at end-of-string for a while, remove later */ if (cp == ret + length - 1) error("buffer_get_cstring_ret: string contains \\0"); else { bzero(ret, length); free(ret); return NULL; } } if (length_ptr != NULL) *length_ptr = length; return ret; }
static int parse_option_list(u_char *optblob, size_t optblob_len, struct passwd *pw, u_int which, int crit, int *cert_no_port_forwarding_flag, int *cert_no_agent_forwarding_flag, int *cert_no_x11_forwarding_flag, int *cert_no_pty_flag, int *cert_no_user_rc, char **cert_forced_command, int *cert_source_address_done) { char *command, *allowed; const char *remote_ip; u_char *name = NULL, *data_blob = NULL; u_int nlen, dlen, clen; Buffer c, data; int ret = -1, found; buffer_init(&data); /* Make copy to avoid altering original */ buffer_init(&c); buffer_append(&c, optblob, optblob_len); while (buffer_len(&c) > 0) { if ((name = buffer_get_cstring_ret(&c, &nlen)) == NULL || (data_blob = buffer_get_string_ret(&c, &dlen)) == NULL) { error("Certificate options corrupt"); goto out; } buffer_append(&data, data_blob, dlen); debug3("found certificate option \"%.100s\" len %u", name, dlen); if (strlen(name) != nlen) { error("Certificate constraint name contains \\0"); goto out; } found = 0; if ((which & OPTIONS_EXTENSIONS) != 0) { if (strcmp(name, "permit-X11-forwarding") == 0) { *cert_no_x11_forwarding_flag = 0; found = 1; } else if (strcmp(name, "permit-agent-forwarding") == 0) { *cert_no_agent_forwarding_flag = 0; found = 1; } else if (strcmp(name, "permit-port-forwarding") == 0) { *cert_no_port_forwarding_flag = 0; found = 1; } else if (strcmp(name, "permit-pty") == 0) { *cert_no_pty_flag = 0; found = 1; } else if (strcmp(name, "permit-user-rc") == 0) { *cert_no_user_rc = 0; found = 1; } } if (!found && (which & OPTIONS_CRITICAL) != 0) { if (strcmp(name, "force-command") == 0) { if ((command = buffer_get_cstring_ret(&data, &clen)) == NULL) { error("Certificate constraint \"%s\" " "corrupt", name); goto out; } if (strlen(command) != clen) { error("force-command constraint " "contains \\0"); goto out; } if (*cert_forced_command != NULL) { error("Certificate has multiple " "force-command options"); xfree(command); goto out; } *cert_forced_command = command; found = 1; } if (strcmp(name, "source-address") == 0) { if ((allowed = buffer_get_cstring_ret(&data, &clen)) == NULL) { error("Certificate constraint " "\"%s\" corrupt", name); goto out; } if (strlen(allowed) != clen) { error("source-address constraint " "contains \\0"); goto out; } if ((*cert_source_address_done)++) { error("Certificate has multiple " "source-address options"); xfree(allowed); goto out; } remote_ip = get_remote_ipaddr(); switch (addr_match_cidr_list(remote_ip, allowed)) { case 1: /* accepted */ xfree(allowed); break; case 0: /* no match */ logit("Authentication tried for %.100s " "with valid certificate but not " "from a permitted host " "(ip=%.200s).", pw->pw_name, remote_ip); auth_debug_add("Your address '%.200s' " "is not permitted to use this " "certificate for login.", remote_ip); xfree(allowed); goto out; case -1: error("Certificate source-address " "contents invalid"); xfree(allowed); goto out; } found = 1; } } if (!found) { if (crit) { error("Certificate critical option \"%s\" " "is not supported", name); goto out; } else { logit("Certificate extension \"%s\" " "is not supported", name); } } else if (buffer_len(&data) != 0) { error("Certificate option \"%s\" corrupt " "(extra data)", name); goto out; } buffer_clear(&data); xfree(name); xfree(data_blob); name = data_blob = NULL; } /* successfully parsed all options */ ret = 0; out: if (ret != 0 && cert_forced_command != NULL && *cert_forced_command != NULL) { xfree(*cert_forced_command); *cert_forced_command = NULL; } if (name != NULL) xfree(name); if (data_blob != NULL) xfree(data_blob); buffer_free(&data); buffer_free(&c); return ret; }
static int process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r) { Channel *nc; struct mux_session_confirm_ctx *cctx; char *reserved, *cmd, *cp; u_int i, j, len, env_len, escape_char, window, packetmax; int new_fd[3]; /* Reply for SSHMUX_COMMAND_OPEN */ cctx = xcalloc(1, sizeof(*cctx)); cctx->term = NULL; cmd = reserved = NULL; if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || buffer_get_int_ret(&cctx->want_tty, m) != 0 || buffer_get_int_ret(&cctx->want_x_fwd, m) != 0 || buffer_get_int_ret(&cctx->want_agent_fwd, m) != 0 || buffer_get_int_ret(&cctx->want_subsys, m) != 0 || buffer_get_int_ret(&escape_char, m) != 0 || (cctx->term = buffer_get_string_ret(m, &len)) == NULL || (cmd = buffer_get_string_ret(m, &len)) == NULL) { malf: if (cmd != NULL) xfree(cmd); if (reserved != NULL) xfree(reserved); if (cctx->term != NULL) xfree(cctx->term); error("%s: malformed message", __func__); return -1; } xfree(reserved); reserved = NULL; cctx->env = NULL; env_len = 0; while (buffer_len(m) > 0) { #define MUX_MAX_ENV_VARS 4096 if ((cp = buffer_get_string_ret(m, &len)) == NULL) { xfree(cmd); goto malf; } if (!env_permitted(cp)) { xfree(cp); continue; } cctx->env = xrealloc(cctx->env, env_len + 2, sizeof(*cctx->env)); cctx->env[env_len++] = cp; cctx->env[env_len] = NULL; if (env_len > MUX_MAX_ENV_VARS) { error(">%d environment variables received, ignoring " "additional", MUX_MAX_ENV_VARS); break; } } debug2("%s: channel %d: request tty %d, X %d, agent %d, subsys %d, " "term \"%s\", cmd \"%s\", env %u", __func__, c->self, cctx->want_tty, cctx->want_x_fwd, cctx->want_agent_fwd, cctx->want_subsys, cctx->term, cmd, env_len); buffer_init(&cctx->cmd); buffer_append(&cctx->cmd, cmd, strlen(cmd)); xfree(cmd); cmd = NULL; /* Gather fds from client */ for(i = 0; i < 3; i++) { if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) { error("%s: failed to receive fd %d from slave", __func__, i); for (j = 0; j < i; j++) close(new_fd[j]); for (j = 0; j < env_len; j++) xfree(cctx->env[j]); if (env_len > 0) xfree(cctx->env); xfree(cctx->term); buffer_free(&cctx->cmd); xfree(cctx); /* prepare reply */ buffer_put_int(r, MUX_S_FAILURE); buffer_put_int(r, rid); buffer_put_cstring(r, "did not receive file descriptors"); return -1; } } debug3("%s: got fds stdin %d, stdout %d, stderr %d", __func__, new_fd[0], new_fd[1], new_fd[2]); /* XXX support multiple child sessions in future */ if (c->remote_id != -1) { debug2("%s: session already open", __func__); /* prepare reply */ buffer_put_int(r, MUX_S_FAILURE); buffer_put_int(r, rid); buffer_put_cstring(r, "Multiple sessions not supported"); cleanup: close(new_fd[0]); close(new_fd[1]); close(new_fd[2]); xfree(cctx->term); if (env_len != 0) { for (i = 0; i < env_len; i++) xfree(cctx->env[i]); xfree(cctx->env); } buffer_free(&cctx->cmd); return 0; } if (options.control_master == SSHCTL_MASTER_ASK || options.control_master == SSHCTL_MASTER_AUTO_ASK) { if (!ask_permission("Allow shared connection to %s? ", host)) { debug2("%s: session refused by user", __func__); /* prepare reply */ buffer_put_int(r, MUX_S_PERMISSION_DENIED); buffer_put_int(r, rid); buffer_put_cstring(r, "Permission denied"); goto cleanup; } } /* Try to pick up ttymodes from client before it goes raw */ if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) error("%s: tcgetattr: %s", __func__, strerror(errno)); /* enable nonblocking unless tty */ if (!isatty(new_fd[0])) set_nonblock(new_fd[0]); if (!isatty(new_fd[1])) set_nonblock(new_fd[1]); if (!isatty(new_fd[2])) set_nonblock(new_fd[2]); window = CHAN_SES_WINDOW_DEFAULT; packetmax = CHAN_SES_PACKET_DEFAULT; if (cctx->want_tty) { window >>= 1; packetmax >>= 1; }