/* This function is called by the transport library when the CA has been connected, or the connection has failed. The `error' indicates the reason. This starts a thread to process the client initiated enrollment. */ static void pkix_tcp_connect_callback(SshTcpError error, SshStream stream, void *context) { SshFSMThread thread = (SshFSMThread)context; SshPkiThreadData tdata = ssh_fsm_get_tdata(thread); SSH_DEBUG(SSH_D_HIGHOK, ("thread %p connected error %d", thread, error)); if (error == SSH_TCP_OK) { tdata->wrapper = ssh_packet_wrap(stream, pkix_tcp_receive_data, pkix_tcp_receive_eof, NULL_FNPTR, context); if (tdata->polling_id == 0) SSH_FSM_SET_NEXT(pkix_send_initial); else SSH_FSM_SET_NEXT(pkix_send_subsequent); } else { SshPkiGlobalData gdata = ssh_fsm_get_gdata(thread); SshPkiSession session = gdata->session; session->status = SSH_PKI_FAILED; SSH_FSM_SET_NEXT(pkix_done); } SSH_FSM_CONTINUE_AFTER_CALLBACK(thread); }
int main(int argc, char **argv) { SshStream stdio_stream; SshSigner signer; char config_filename[512]; char *temp_name; #ifdef SLEEP_AFTER_STARTUP sleep(30); #endif /* SLEEP_AFTER_STARTUP */ /* Get program name (without path). */ if ((temp_name = strrchr(argv[0], '/')) != NULL) progname = ssh_xstrdup(temp_name + 1); else progname = ssh_xstrdup(argv[0]); /* XXX there should be a way to give command-line parameters to this program, but, they should only be used if the uid is the same as euid. */ ssh_event_loop_initialize(); signer = ssh_xcalloc(1, sizeof(*signer)); #ifdef SIGNER_QUIET signer->quiet = TRUE; #else /* SIGNER_QUIET */ signer->quiet = FALSE; #endif /* SIGNER_QUIET */ ssh_debug_register_callbacks(signer_ssh_fatal, signer_ssh_warning, signer_ssh_debug, (void *)signer); #ifdef SIGNER_DEBUG ssh_debug_set_global_level(5); #endif /* SIGNER_DEBUG */ /* Act as server. */ signer->config = ssh_server_create_config(); SSH_TRACE(2, ("public key file: %s", signer->config->public_host_key_file)); SSH_TRACE(2, ("private key file: %s", signer->config->host_key_file)); SSH_TRACE(2, ("randomseed file: %s", signer->config->random_seed_file)); /* Initialize user context with euid. This is used to dig up the hostkey and such. */ signer->effective_user_data = ssh_user_initialize_with_uid(geteuid(), FALSE); signer->random_state = ssh_randseed_open(signer->effective_user_data, signer->config); /* XXX what about alternative config files? This should be possible to configure somehow. An option for configure is probably a good idea. */ snprintf(config_filename, sizeof(config_filename), "%s/%s", SSH_SERVER_DIR, SSH_SERVER_CONFIG_FILE); if (!ssh_config_read_file(signer->effective_user_data, signer->config, NULL, config_filename, NULL)) ssh_warning("%s: Failed to read config file %s", argv[0], config_filename); stdio_stream = ssh_stream_fd_wrap2(fileno(stdin), fileno(stdout), TRUE); signer->wrapper = ssh_packet_wrap(stdio_stream, signer_received_packet, signer_received_eof, signer_can_send, signer); ssh_event_loop_run(); return 0; }
void ssh_client_auth_hostbased(SshAuthClientOperation op, const char *user, unsigned int packet_type, SshBuffer *packet_in, const unsigned char *session_id, size_t session_id_len, void **state_placeholder, SshAuthClientCompletionProc completion, void *completion_context, void *method_context) { SshClientHostbasedAuth state; SshClient client; SshStream stdio_stream; char hostkeyfile[512]; /* char *keytype; SshPublicKey pubkey;*/ char **signer_argv; char config_filename[512]; size_t hostname_len; SSH_DEBUG(6, ("auth_hostbased op = %d user = %s", op, user)); client = (SshClient)method_context; state = *state_placeholder; switch (op) { /* This operation is always non-interactive, as hostkeys shouldn't have passphrases. Check for it, though. XXX */ case SSH_AUTH_CLIENT_OP_START_NONINTERACTIVE: /* XXX There is a bug in sshauthc.c (or elsewhere). Authentication methods, that are not allowed, should not be tried. Now it calls SSH_AUTH_CLIENT_OP_START_NONINTERACTIVE for every authentication method before checking.*/ (*completion)(SSH_AUTH_CLIENT_FAIL, user, NULL, completion_context); break; case SSH_AUTH_CLIENT_OP_START: /* This is the first operation for doing hostbased authentication. We should not have any previous saved state when we come here. */ SSH_ASSERT(*state_placeholder == NULL); /* Initialize a context. */ state = ssh_xcalloc(1, sizeof(*state)); state->session_id = session_id; state->session_id_len = session_id_len; state->user = ssh_xstrdup(user); /* We have to dig up the server configuration to get the place for the client host's publickey. This is a very kludgeish solution. XXX*/ state->server_conf = ssh_server_create_config(); /* Dig up hosts publickey. */ snprintf(config_filename, sizeof(config_filename), "%s/%s", SSH_SERVER_DIR, SSH_SERVER_CONFIG_FILE); if (!ssh_config_read_file(client->user_data, state->server_conf, NULL, config_filename, NULL)) SSH_TRACE(2, ("Failed to read config file %s", \ config_filename)); if(state->server_conf->public_host_key_file[0] != '/') { snprintf(hostkeyfile, sizeof(hostkeyfile), "%s/%s", SSH_SERVER_DIR, state->server_conf->public_host_key_file); } else { snprintf(hostkeyfile, sizeof(hostkeyfile), "%s", state->server_conf->public_host_key_file); } /* This pubkey*-stuff is for the client _host's_ public hostkey. */ SSH_DEBUG(4, ("Reading pubkey-blob from %s...", hostkeyfile)); if (ssh2_key_blob_read(client->user_data, hostkeyfile, NULL, &state->pubkeyblob, &state->pubkeyblob_len, NULL) != SSH_KEY_MAGIC_PUBLIC) { goto error; } SSH_DEBUG(4, ("done.")); if ((state->pubkey_algorithm = ssh_pubkeyblob_type(state->pubkeyblob, state->pubkeyblob_len)) == NULL) { goto error; } state->local_user_name = ssh_user_name(client->user_data); state->local_host_name = ssh_xmalloc(MAXHOSTNAMELEN + 1); ssh_tcp_get_host_name(state->local_host_name, MAXHOSTNAMELEN + 1); hostname_len = strlen(state->local_host_name); /* Sanity check */ SSH_ASSERT(hostname_len + 2 < MAXHOSTNAMELEN); /* We want FQDN. */ state->local_host_name[hostname_len] = '.'; state->local_host_name[hostname_len + 1] = '\0'; state->completion = completion; state->completion_context = completion_context; state->state_placeholder = state_placeholder; /* Assign the state to the placeholder that survives across calls. (this is actually not needed, as hostbased authentication procedure is very simple. Just one packet from client to server, and server's response in one packet.) */ *state_placeholder = state; /* Open a pipestream connection to ssh-signer. */ switch (ssh_pipe_create_and_fork(&stdio_stream, NULL)) { case SSH_PIPE_ERROR: /* Something went wrong. */ ssh_warning("Couldn't create pipe to connect to %s.", client->config->signer_path); goto error; break; case SSH_PIPE_CHILD_OK: /* Exec ssh-signer */ SSH_TRACE(0, ("Child: Execing ssh-signer...(path: %s)", \ client->config->signer_path)); signer_argv = ssh_xcalloc(2, sizeof(char *)); signer_argv[0] = client->config->signer_path; signer_argv[1] = NULL; execvp(client->config->signer_path, signer_argv); fprintf(stderr, "Couldn't exec '%s' (System error message: %s)", client->config->signer_path, strerror(errno)); ssh_fatal("Executing ssh-signer failed."); break; case SSH_PIPE_PARENT_OK: state->wrapper = ssh_packet_wrap(stdio_stream, auth_hostbased_received_packet, auth_hostbased_received_eof, auth_hostbased_can_send, state); /* We don't check wrapper's validity, as ssh_packet_wrap should always succeed.*/ break; } /* Here we continue as parent. */ /* sign packet with ssh-signer (a suid-program). */ if (ssh_packet_wrapper_can_send(state->wrapper)) { ssh_client_auth_hostbased_send_to_signer(state); } /* If ssh_packet_wrapper_can_send returns FALSE, auth_hostbased_can_send will call the ...send_to_signer function above. */ /* Rest is done in callbacks. */ break; case SSH_AUTH_CLIENT_OP_CONTINUE: SSH_TRACE(2, ("Invalid message. We didn't return " \ "SSH_AUTH_CLIENT_SEND_AND_CONTINUE at any stage!")); /* Send failure message.*/ (*completion)(SSH_AUTH_CLIENT_FAIL, user, NULL, completion_context); return; case SSH_AUTH_CLIENT_OP_ABORT: /* Abort the authentication operation immediately. */ /* XXX Destroy 'state'-object. */ *state_placeholder = NULL; break; default: /* something weird is going on.. */ ssh_fatal("ssh_client_auth_hostbased: unknown op %d", (int)op); } return; error: /* XXX Destroy state. */ /* Send failure message.*/ (*completion)(SSH_AUTH_CLIENT_FAIL, user, NULL, completion_context); return; }