/* Initializes subbuffer to parse a string from buffer */ int parse_sub_buffer(struct simple_buffer *buffer, struct simple_buffer *subbuffer) { uint32_t length; const uint8_t *data; if (!parse_string(buffer, &length, &data)) return 0; simple_buffer_init(subbuffer, length, data); return 1; }
static void do_service_request(struct packet_handler *c, struct ssh_connection *connection, struct lsh_string *packet) { CAST(service_handler, closure, c); struct simple_buffer buffer; unsigned msg_number; int name; simple_buffer_init(&buffer, packet->length, packet->data); if (parse_uint8(&buffer, &msg_number) && (msg_number == SSH_MSG_SERVICE_REQUEST) && parse_atom(&buffer, &name) && parse_eod(&buffer)) { if (name) { CAST_SUBTYPE(command, service, ALIST_GET(closure->services, name)); if (service) { /* Don't accept any further service requests */ connection->dispatch[SSH_MSG_SERVICE_REQUEST] = &connection_fail_handler; /* Start service */ #if DATAFELLOWS_WORKAROUNDS if (connection->peer_flags & PEER_SERVICE_ACCEPT_KLUDGE) C_WRITE(connection, format_service_accept_kludge()); else #endif /* DATAFELLOWS_WORKAROUNDS */ C_WRITE(connection, format_service_accept(name)); COMMAND_CALL(service, connection, closure->c, closure->e); return; } } EXCEPTION_RAISE(connection->e, make_protocol_exception(SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, NULL)); } else PROTOCOL_ERROR(connection->e, "Invalid SERVICE_REQUEST message"); }
static void lshd_service_request_handler(struct transport_forward *self, uint32_t length, const uint8_t *packet) { struct simple_buffer buffer; unsigned msg_number; const uint8_t *name; uint32_t name_length; simple_buffer_init(&buffer, length, packet); if (parse_uint8(&buffer, &msg_number) && (msg_number == SSH_MSG_SERVICE_REQUEST) && parse_string(&buffer, &name_length, &name) && parse_eod(&buffer)) { CAST(lshd_context, ctx, self->super.ctx); const struct service_entry *service = service_config_lookup(ctx->service_config, name_length, name); if (service) { int pipe[2]; pid_t child; if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe) < 0) { werror("lshd_service_request_handler: socketpair failed: %e.\n", errno); transport_disconnect(&self->super, SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, "Service could not be started"); return; } child = fork(); if (child < 0) { werror("lshd_service_request_handler: fork failed: %e.\n", errno); close(pipe[0]); close(pipe[1]); transport_disconnect(&self->super, SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, "Service could not be started"); return; } if (child) { /* Parent process */ close(pipe[1]); transport_send_packet(&self->super, TRANSPORT_WRITE_FLAG_PUSH, format_service_accept(name_length, name)); /* Setup forwarding. Replaces event_handler and packet_handler. */ transport_forward_setup(self, pipe[0], pipe[0]); } else { /* Child process */ struct arglist args; const char *program; unsigned i; close(pipe[0]); dup2(pipe[1], STDIN_FILENO); dup2(pipe[1], STDOUT_FILENO); close(pipe[1]); /* FIXME: Pass sufficient information so that $SSH_CLIENT can be set properly. */ arglist_init (&args); program = service->args.argv[0]; arglist_push (&args, program); /* If not absolute, interpret it relative to libexecdir. */ if (program[0] != '/') program = lsh_get_cstring(ssh_format("%lz/%lz", ctx->service_config->libexec_dir, program)); for (i = 1; i < service->args.argc; i++) { const char *arg = service->args.argv[i]; if (arg[0] == '$') { if (!strcmp(arg+1, "(session_id)")) arg = lsh_get_cstring(ssh_format("%lxS", self->super.session_id)); } arglist_push (&args, arg); } debug("exec of service %s, program %z. Argument list:\n", name_length, name, program); for (i = 0; i < args.argc; i++) debug(" %z\n", args.argv[i]); execv(program, (char **) args.argv); werror("lshd_service_request_handler: exec of %z failed: %e.\n", args.argv[0], errno); _exit(EXIT_FAILURE); } } else transport_disconnect(&self->super, SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, "Service not available"); } else transport_protocol_error(&self->super, "Invalid SERVICE_REQUEST"); }
static struct lsh_string * lsh_decode_key(struct lsh_string *contents) { struct simple_buffer buffer; enum lsh_atom type; struct verifier *v; simple_buffer_init(&buffer, STRING_LD(contents)); if (!parse_atom(&buffer, &type)) { werror("Invalid (binary) input data.\n"); return NULL; } switch (type) { case ATOM_SSH_DSS: { werror("Reading key of type ssh-dss...\n"); v = parse_ssh_dss_public(&buffer); if (!v) { werror("Invalid dsa key.\n"); return NULL; } break; } case ATOM_SSH_DSA_SHA256_LOCAL: { werror("Reading key of type ssh-dsa-sha256...\n"); v = parse_ssh_dsa_sha256_public(&buffer); if (!v) { werror("Invalid dsa-sha256 key.\n"); return NULL; } break; } case ATOM_SSH_RSA: { werror("Reading key of type ssh-rsa...\n"); v = parse_ssh_rsa_public(&buffer); if (!v) { werror("Invalid rsa key.\n"); return NULL; } break; } default: werror("Unknown key type."); return NULL; } return PUBLIC_SPKI_KEY(v, 1); }
static int do_rsa_verify(struct verifier *v, int algorithm, UINT32 length, const UINT8 *msg, UINT32 signature_length, const UINT8 *signature_data) { CAST(rsa_verifier, self, v); mpz_t s; int res = 0; trace("do_rsa_verify: Verifying %a signature\n", algorithm); mpz_init(s); switch(algorithm) { #if 0 case ATOM_RSA_PKCS1_SHA1: case ATOM_RSA_PKCS1_SHA1_LOCAL: if (signature_length > self->size) goto fail; bignum_parse_u(s, signature_length, signature_data); break; case ATOM_SPKI: #endif case ATOM_SSH_RSA: { struct simple_buffer buffer; UINT32 length; const UINT8 *digits; int atom; simple_buffer_init(&buffer, signature_length, signature_data); if (!(parse_atom(&buffer, &atom) && (atom == ATOM_SSH_RSA) && parse_string(&buffer, &length, &digits) && (length <= self->size) && parse_eod(&buffer) )) goto fail; bignum_parse_u(s, length, digits); break; } /* It doesn't matter here which flavour of SPKI is used. */ case ATOM_SPKI_SIGN_RSA: case ATOM_SPKI_SIGN_DSS: { struct simple_buffer buffer; struct sexp *e; simple_buffer_init(&buffer, signature_length, signature_data); if (! ( (e = sexp_parse_canonical(&buffer)) && parse_eod(&buffer) && decode_rsa_sig_val(e, s, self->size)) ) goto fail; break; } default: fatal("do_rsa_verify: Internal error!\n"); } res = rsa_pkcs1_verify(self, length, msg, s); fail: mpz_clear(s); return res; }