/* * Returns an arbitrary binary string from the buffer. The string cannot * be longer than 256k. The returned value points to memory allocated * with xmalloc; it is the responsibility of the calling function to free * the data. If length_ptr is non-NULL, the length of the returned data * will be stored there. A null character will be automatically appended * to the returned string, and is not counted in length. */ void * buffer_get_string_ret(Buffer *buffer, u_int *length_ptr) { u_char *value; u_int len; /* Get the length. */ if (buffer_get_int_ret(&len, buffer) != 0) { error("buffer_get_string_ret: cannot extract length"); return (NULL); } if (len > 256 * 1024) { error("buffer_get_string_ret: bad string length %u", len); return (NULL); } /* Allocate space for the string. Add one byte for a null character. */ value = xmalloc(len + 1); /* Get the string. */ if (buffer_get_ret(buffer, value, len) == -1) { error("buffer_get_string_ret: buffer_get failed"); free(value); return (NULL); } /* Append a null character to make processing easier. */ value[len] = '\0'; /* Optionally return the length of the string. */ if (length_ptr) *length_ptr = len; return (value); }
u_int buffer_get_int(Buffer *buffer) { u_int ret = 0; /* XXX: GCC */ if (buffer_get_int_ret(&ret, buffer) == -1) fatal("%s: buffer error", __func__); return (ret); }
u_int buffer_get_int(Buffer *buffer) { u_int ret; if (buffer_get_int_ret(&ret, buffer) == -1) fatal("buffer_get_int: buffer error"); return (ret); }
void * buffer_get_string_ptr_ret(Buffer *buffer, u_int *length_ptr) { void *ptr; u_int len; if (buffer_get_int_ret(&len, buffer) != 0) return NULL; if (len > 256 * 1024) { error("buffer_get_string_ptr: bad string length %u", len); return NULL; } ptr = buffer_ptr(buffer); buffer_consume(buffer, len); if (length_ptr) *length_ptr = len; return (ptr); }
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; }
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; }