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"); }
/* Alternative constructor using a key of type ssh-rsa, when the atom * "ssh-rsa" is already read from the buffer. */ struct verifier * parse_ssh_rsa_public(struct simple_buffer *buffer) { NEW(rsa_verifier, res); init_rsa_verifier(res, &rsa_sha1_algorithm); if (parse_bignum(buffer, res->e, RSA_MAX_SIZE) && (mpz_sgn(res->e) == 1) && parse_bignum(buffer, res->n, RSA_MAX_SIZE) && (mpz_sgn(res->n) == 1) && (mpz_cmp(res->e, res->n) < 0) && parse_eod(buffer) && rsa_check_size(res)) return &res->super; else { KILL(res); return NULL; } }
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 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; }