/* 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);
}
Exemple #2
0
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;
}
Exemple #3
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;
}