static ssh_channel pkd_channel_openreq_cb(ssh_session s, void *userdata) { ssh_channel c = NULL; ssh_channel *out = (ssh_channel *) userdata; /* assumes pubkey authentication has already succeeded */ pkdout("pkd_channel_openreq_cb\n"); c = ssh_channel_new(s); if (c == NULL) { pkderr("ssh_channel_new: %s\n", ssh_get_error(s)); return NULL; } ssh_callbacks_init(&pkd_channel_cb); pkd_channel_cb.userdata = userdata; if (ssh_set_channel_callbacks(c, &pkd_channel_cb) != SSH_OK) { pkderr("ssh_set_channel_callbacks: %s\n", ssh_get_error(s)); ssh_channel_free(c); c = NULL; } *out = c; return c; }
static void *pkd_main(void *args) { int rc = -1; struct pkd_daemon_args *a = (struct pkd_daemon_args *) args; struct sigaction act = { .sa_handler = pkd_sighandler, }; pkd_state.server_fd = -1; pkd_state.req_exec_received = 0; pkd_state.close_received = 0; pkd_state.eof_received = 0; /* SIGUSR1 is used to interrupt 'pkd_accept_fd'. */ rc = sigaction(SIGUSR1, &act, NULL); if (rc != 0) { pkderr("sigaction: %d\n", rc); goto out; } rc = pkd_init_libssh(); if (rc != 0) { pkderr("pkd_init_libssh: %d\n", rc); goto out; } rc = pkd_init_server_fd(1234); if (rc != 0) { pkderr("pkd_init_server_fd: %d\n", rc); goto out; } ctx.pkd_ready = 1; while (ctx.keep_going != 0) { int fd = pkd_accept_fd(); if (fd < 0) { if (ctx.keep_going != 0) { pkderr("pkd_accept_fd"); rc = -1; } else { rc = 0; } break; } rc = pkd_exec_hello(fd, a); if (rc != 0) { pkderr("pkd_exec_hello: %d\n", rc); break; } } close(pkd_state.server_fd); pkd_state.server_fd = -1; out: ctx.rc = rc; return NULL; }
static int pkd_exec_hello(int fd, struct pkd_daemon_args *args) { int rc = -1; ssh_bind b = NULL; ssh_session s = NULL; ssh_event e = NULL; ssh_channel c = NULL; enum ssh_bind_options_e opts = -1; int level = args->opts.libssh_log_level; enum pkd_hostkey_type_e type = args->type; const char *hostkeypath = args->hostkeypath; pkd_state.eof_received = 0; pkd_state.close_received = 0; pkd_state.req_exec_received = 0; b = ssh_bind_new(); if (b == NULL) { pkderr("ssh_bind_new\n"); goto outclose; } if (type == PKD_RSA) { opts = SSH_BIND_OPTIONS_RSAKEY; } else if (type == PKD_ED25519) { opts = SSH_BIND_OPTIONS_HOSTKEY; #ifdef HAVE_DSA } else if (type == PKD_DSA) { opts = SSH_BIND_OPTIONS_DSAKEY; #endif } else if (type == PKD_ECDSA) { opts = SSH_BIND_OPTIONS_ECDSAKEY; } else { pkderr("unknown kex algorithm: %d\n", type); rc = -1; goto outclose; } rc = ssh_bind_options_set(b, opts, hostkeypath); if (rc != 0) { pkderr("ssh_bind_options_set: %s\n", ssh_get_error(b)); goto outclose; } rc = ssh_bind_options_set(b, SSH_BIND_OPTIONS_LOG_VERBOSITY, &level); if (rc != 0) { pkderr("ssh_bind_options_set log verbosity: %s\n", ssh_get_error(b)); goto outclose; } s = ssh_new(); if (s == NULL) { pkderr("ssh_new\n"); goto outclose; } /* * ssh_bind_accept loads host key as side-effect. If this * succeeds, the given 'fd' will be closed upon 'ssh_free(s)'. */ rc = ssh_bind_accept_fd(b, s, fd); if (rc != SSH_OK) { pkderr("ssh_bind_accept_fd: %s\n", ssh_get_error(b)); goto outclose; } /* accept only publickey-based auth */ ssh_set_auth_methods(s, SSH_AUTH_METHOD_PUBLICKEY); /* initialize callbacks */ ssh_callbacks_init(&pkd_server_cb); pkd_server_cb.userdata = &c; rc = ssh_set_server_callbacks(s, &pkd_server_cb); if (rc != SSH_OK) { pkderr("ssh_set_server_callbacks: %s\n", ssh_get_error(s)); goto out; } /* first do key exchange */ rc = ssh_handle_key_exchange(s); if (rc != SSH_OK) { pkderr("ssh_handle_key_exchange: %s\n", ssh_get_error(s)); goto out; } /* setup and pump event to carry out exec channel */ e = ssh_event_new(); if (e == NULL) { pkderr("ssh_event_new\n"); goto out; } rc = ssh_event_add_session(e, s); if (rc != SSH_OK) { pkderr("ssh_event_add_session\n"); goto out; } /* poll until exec channel established */ while ((ctx.keep_going != 0) && (rc != SSH_ERROR) && (pkd_state.req_exec_received == 0)) { rc = ssh_event_dopoll(e, -1 /* infinite timeout */); } if (rc == SSH_ERROR) { pkderr("ssh_event_dopoll\n"); goto out; } else if (c == NULL) { pkderr("poll loop exited but exec channel not ready\n"); rc = -1; goto out; } rc = ssh_channel_write(c, "hello\n", 6); /* XXX: customizable payloads */ if (rc != 6) { pkderr("ssh_channel_write partial (%d)\n", rc); } rc = ssh_channel_request_send_exit_status(c, 0); if (rc != SSH_OK) { pkderr("ssh_channel_request_send_exit_status: %s\n", ssh_get_error(s)); goto out; } rc = ssh_channel_send_eof(c); if (rc != SSH_OK) { pkderr("ssh_channel_send_eof: %s\n", ssh_get_error(s)); goto out; } rc = ssh_channel_close(c); if (rc != SSH_OK) { pkderr("ssh_channel_close: %s\n", ssh_get_error(s)); goto out; } while ((ctx.keep_going != 0) && (pkd_state.eof_received == 0) && (pkd_state.close_received == 0)) { rc = ssh_event_dopoll(e, 1000 /* milliseconds */); if (rc == SSH_ERROR) { /* log, but don't consider this fatal */ pkdout("ssh_event_dopoll for eof + close: %s\n", ssh_get_error(s)); rc = 0; break; } else { rc = 0; } } while ((ctx.keep_going != 0) && (ssh_is_connected(s))) { rc = ssh_event_dopoll(e, 1000 /* milliseconds */); if (rc == SSH_ERROR) { /* log, but don't consider this fatal */ pkdout("ssh_event_dopoll for session connection: %s\n", ssh_get_error(s)); rc = 0; break; } else { rc = 0; } } goto out; outclose: close(fd); out: if (c != NULL) { ssh_channel_free(c); } if (e != NULL) { ssh_event_remove_session(e, s); ssh_event_free(e); } if (s != NULL) { ssh_disconnect(s); ssh_free(s); } if (b != NULL) { ssh_bind_free(b); } return rc; }