void add_file(SshAgent agent, const char *filename)
{
  SshPrivateKey key = NULL;
  char *saved_comment, *comment = NULL, *pass;
  int query_cnt;
  unsigned char *certs = NULL;
  size_t certs_len;
  char privname[500], pubname[500];
  unsigned long magic;
  struct stat st;

  if (action == ADD_URL)
    {
      printf("Adding URL identity: %s\n", filename);
      snprintf(privname, sizeof(privname), "%s", filename);
      if (have_attrs)
        ssh_agent_add_with_attrs(agent, NULL, NULL, 0, privname,
                                 path_limit, path_constraint, use_limit,
                                 forbid_compat, key_timeout,
                                 agent_completion, (void *)agent);
      else
        ssh_agent_add(agent, NULL, NULL, 0, privname,
                      agent_completion, (void *)agent);
      return;
    }
  else if (action == DELETE_URL)
    {
      printf("Deleting URL identity: %s\n", filename);
      snprintf(privname, sizeof(privname), "%s", filename);
      ssh_agent_delete(agent, NULL, 0, privname,
                       agent_completion, (void *)agent);
      return;
    }
#ifdef WITH_PGP
  if (pgp_mode == PGP_KEY_NONE)
#endif /* WITH_PGP */
    {
      /* Construct the names of the public and private key files. */
      if (strlen(filename) > 4 &&
          strcmp(filename + strlen(filename) - 4, ".pub") == 0)
        {
          snprintf(pubname, sizeof(pubname), "%s", filename);
          snprintf(privname, sizeof(privname), "%s", filename);
          privname[strlen(privname) - 4] = '\0';
        }
      else
        {
          snprintf(pubname, sizeof(pubname), "%s.pub", filename);
          snprintf(privname, sizeof(privname), "%s", filename);
        }
    
      if (action == ADD)
        printf("Adding identity: %s\n", pubname);
      else if (action == DELETE)
        printf("Deleting identity: %s\n", pubname);
    
      if (stat(pubname, &st) < 0)
        {
          printf("Public key file %s does not exist.\n", pubname);
          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
          return;
        }
    
      if (stat(privname, &st) < 0)
        {
          printf("Private key file %s does not exist.\n", privname);
          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
          return;
        }
    
      /* Read the public key blob. */
      magic = ssh2_key_blob_read(user, 
                                 pubname,
                                 TRUE,
                                 &saved_comment,
                                 &certs, 
                                 &certs_len,
                                 NULL);
      if (magic != SSH_KEY_MAGIC_PUBLIC)
        {
          printf("Bad public key file %s\n", pubname);
          ssh_xfree(certs);
          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
          return;
        }
    
      if (action == ADD)
        {
          /* Loop until we manage to load the file, or a maximum number of
             attempts have been made.  First try with an empty passphrase. */
          pass = ssh_xstrdup("");
          query_cnt = 0;
          while ((key = ssh_privkey_read(user, 
                                         privname,
                                         pass, 
                                         &comment, 
                                         NULL)) == NULL)
            {
              char buf[1024];
              FILE *f;
            
              /* Free the old passphrase. */
              memset(pass, 0, strlen(pass));
              ssh_xfree(pass);
            
              query_cnt++;
              if (query_cnt > 5)
                {
                  fprintf(stderr,
                          "You don't seem to know the correct passphrase.\n");
                  exit(EXIT_STATUS_BADPASS);
                }
            
              /* Ask for a passphrase. */
              if (!use_stdin && getenv("DISPLAY") && !isatty(fileno(stdin)))
                {
                  snprintf(buf, sizeof(buf),
                           "ssh-askpass2 '%sEnter passphrase for %.100s'", 
                           ((query_cnt <= 1) ? 
                            "" : 
                            "You entered wrong passphrase.  "), 
                           saved_comment);
                  f = popen(buf, "r");
                  if (!fgets(buf, sizeof(buf), f))
                    {
                      pclose(f);
                      ssh_xfree(saved_comment);
                      exit(EXIT_STATUS_BADPASS);
                    }
                  pclose(f);
                  if (strchr(buf, '\n'))
                    *strchr(buf, '\n') = 0;
                  pass = ssh_xstrdup(buf);
                }
              else
                {
                  if (query_cnt <= 1)
                    {
                      if ((strcmp(privname, saved_comment) == 0) ||
                          (((strlen(privname) + 4) == strlen(saved_comment)) &&
                           (strncmp(privname, 
                                    saved_comment, 
                                    strlen(privname)) == 0)))
                        {
                          printf("Need passphrase for %s.\n", 
                                 privname);
                        }
                      else
                        {
                          printf("Need passphrase for %s (%s).\n", 
                                 privname, saved_comment);
                        }
                    }
                  else
                    {
                      printf("Bad passphrase.\n");
                    }
                  pass = ssh_read_passphrase("Enter passphrase: ", use_stdin);
                  if (pass == NULL || strcmp(pass, "") == 0)
                    {
                      ssh_xfree(saved_comment);
                      ssh_xfree(pass);
                      exit(EXIT_STATUS_BADPASS);
                    }
                }
            }
          memset(pass, 0, strlen(pass));
          ssh_xfree(pass);
          ssh_xfree(saved_comment);
          /* Construct a comment for the key by combining file name and
             comment in the file. */
          if ((saved_comment = strrchr(privname, '/')) != NULL)
            saved_comment++;
          else
            saved_comment = privname;
          saved_comment = ssh_string_concat_3(saved_comment, ": ", comment);
        }
      else
        {
          /* Construct a comment for the key by combining file name and
             comment in the file. */
          if ((saved_comment = strrchr(privname, '/')) != NULL)
            saved_comment++;
          else
            saved_comment = privname;
          if (comment)
            saved_comment = ssh_string_concat_3(saved_comment, ": ", comment);
          else
            saved_comment = ssh_xstrdup(saved_comment);
        }
    
      if (action == ADD)
        {
          /* Send the key to the authentication agent. */
          if (have_attrs)
            ssh_agent_add_with_attrs(agent, key, certs, certs_len, 
                                     saved_comment, path_limit, 
                                     path_constraint, use_limit,
                                     forbid_compat, key_timeout,
                                     agent_completion, (void *)agent);
          else
            ssh_agent_add(agent, key, certs, certs_len, saved_comment,
                          agent_completion, (void *)agent);
          ssh_private_key_free(key);
        }
      else if (action == DELETE)
        {
          ssh_agent_delete(agent, certs, certs_len, saved_comment,
                           agent_completion, (void *)agent);
        }
      ssh_xfree(saved_comment);
    }
#ifdef WITH_PGP
  else
    {
      unsigned char *blob, *public_blob;
      size_t blob_len, public_blob_len;
      Boolean found = FALSE;
      unsigned long id;
      char *endptr;
      SshPgpSecretKey pgp_key;
      SshPrivateKey key;
      char buf[1024];
      FILE *f;

      comment = NULL;
      switch (pgp_mode)
        {
        case PGP_KEY_NAME:
          found = ssh2_find_pgp_secret_key_with_name(user,
                                                     pgp_keyring,
                                                     filename,
                                                     &blob,
                                                     &blob_len,
                                                     &comment);
          break;
          
        case PGP_KEY_FINGERPRINT:
          found = ssh2_find_pgp_secret_key_with_fingerprint(user,
                                                            pgp_keyring,
                                                            filename,
                                                            &blob,
                                                            &blob_len,
                                                            &comment);
          break;
          
        case PGP_KEY_ID:
          id = strtoul(filename, &endptr, 0);
          if ((*filename != '\0') && (*endptr == '\0'))
            {
              found = ssh2_find_pgp_secret_key_with_id(user,
                                                       pgp_keyring,
                                                       id,
                                                       &blob,
                                                       &blob_len,
                                                       &comment);
            }
          else
            {
              fprintf(stderr, "%s: invalid pgp key id \"%s\".\n", 
                      av0, filename);
              found = FALSE;
            }
          break;
          
        default:
          ssh_fatal("internal error");
        }
      if (! found)
        {
          fprintf(stderr, "%s: pgp key \"%s\" not found.\n", 
                  av0, filename);
          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
          return;
        }
      if (ssh_pgp_secret_key_decode(blob, blob_len, &pgp_key) == 0)
        {
          fprintf(stderr, "%s: unable to decode pgp key \"%s\".\n", 
                  av0, filename);
          memset(blob, 'F', blob_len);
          ssh_xfree(blob);
          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
          return;
        }

      if ((public_blob_len = ssh_encode_pubkeyblob(pgp_key->public_key->key,
                                                   &public_blob)) == 0)
        {
          fprintf(stderr, "%s: unable to encode pgp key \"%s\".\n", 
                  av0, filename);
          ssh_pgp_secret_key_free(pgp_key);
          memset(blob, 'F', blob_len);
          ssh_xfree(blob);
          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
          return;
        }
      if (action == ADD)
        {
          query_cnt = 0;
          while ((pgp_key->key == NULL) &&
                 (pgp_key->decryption_failed == TRUE))
            {
              query_cnt++;
              if (query_cnt > 5)
                {
                  fprintf(stderr,
                          "You don't seem to know the correct passphrase.\n");
                  exit(EXIT_STATUS_BADPASS);
                }
              /* Ask for a passphrase. */
              if (!use_stdin && getenv("DISPLAY") && !isatty(fileno(stdin)))
                {
                  snprintf(buf, sizeof(buf),
                           "ssh-askpass2 '%sEnter passphrase for \"%.100s\"'", 
                           ((query_cnt <= 1) ? 
                            "" : 
                            "You entered wrong passphrase.  "), 
                           comment);
                  f = popen(buf, "r");
                  if (!fgets(buf, sizeof(buf), f))
                    {
                      pclose(f);
                      fprintf(stderr, "No passphrase.\n");
                      exit(EXIT_STATUS_BADPASS);
                    }
                  pclose(f);
                  if (strchr(buf, '\n'))
                    *strchr(buf, '\n') = 0;
                  pass = ssh_xstrdup(buf);
                }
              else
                {
                  if (query_cnt <= 1)
                    printf("Need passphrase for \"%s\".\n", comment);
                  else
                    printf("Bad passphrase.\n");
                  pass = ssh_read_passphrase("Enter passphrase: ", use_stdin);
                  if (pass == NULL || strcmp(pass, "") == 0)
                    {
                      ssh_xfree(pass);
                      fprintf(stderr, "No passphrase.\n");
                      exit(EXIT_STATUS_BADPASS);
                    }
                }
              ssh_pgp_secret_key_free(pgp_key);
              if (ssh_pgp_secret_key_decode_with_passphrase(blob, 
                                                            blob_len, 
                                                            pass,
                                                            &pgp_key) == 0)
                {
                  memset(pass, 0, strlen(pass));
                  ssh_xfree(pass);
                  fprintf(stderr, "%s: unable to decode pgp key \"%s\".\n", 
                          av0, filename);
                  memset(blob, 'F', blob_len);
                  ssh_xfree(blob);
                  ssh_xfree(public_blob);
                  (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
                  return;
                }
              memset(pass, 0, strlen(pass));
              ssh_xfree(pass);
            }
          if (pgp_key->key == NULL)
            {
              fprintf(stderr, "%s: unable to decode pgp key \"%s\".\n", 
                      av0, filename);
              ssh_xfree(public_blob);
              ssh_pgp_secret_key_free(pgp_key);
              (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
              return;
            }
          memset(blob, 'F', blob_len);
          ssh_xfree(blob);
          if (ssh_private_key_copy(pgp_key->key, &key) != SSH_CRYPTO_OK)
            {
              fprintf(stderr, "%s: unable to export pgp key \"%s\".\n", 
                      av0, filename);
              ssh_pgp_secret_key_free(pgp_key);
              (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
              return;
            }
          ssh_pgp_secret_key_free(pgp_key);
          if (have_attrs)
            ssh_agent_add_with_attrs(agent, key, 
                                     public_blob, public_blob_len, 
                                     comment, path_limit, 
                                     path_constraint, use_limit,
                                     forbid_compat, key_timeout,
                                     agent_completion, (void *)agent);
          else
            ssh_agent_add(agent, key, 
                          public_blob, public_blob_len, comment, 
                          agent_completion, (void *)agent);
          ssh_xfree(comment);
          ssh_xfree(public_blob);
          ssh_private_key_free(key);
          return;
        }
      else if (action == DELETE)
        {
          ssh_agent_delete(agent, 
                           public_blob, 
                           public_blob_len, 
                           filename,
                           agent_completion,
                           (void *)agent);
          ssh_pgp_secret_key_free(pgp_key);
          memset(blob, 'F', blob_len);
          ssh_xfree(blob);
          ssh_xfree(public_blob);
          return;
        }
    }
#endif /* WITH_PGP */
}
SshEapToken
ssh_eap_dup_token(SshEapToken src)
{
  SshEapToken dst;

  dst = ssh_calloc(1, sizeof(*dst));

  if (dst == NULL)
    return NULL;

  dst->type = src->type;

  switch (src->type)
    {



















    case SSH_EAP_TOKEN_PRIVATE_KEY:
   if (src->token.prvkey.private_key != NULL)
     {
       if (ssh_private_key_copy(src->token.prvkey.private_key, 
				&dst->token.prvkey.private_key) 
	   != SSH_CRYPTO_OK)
	 {
	   ssh_free(dst);
	   return NULL;
	 }
       if (src->token.prvkey.id_data != NULL)
         {
           dst->token.prvkey.id_data 
             = ssh_memdup(src->token.prvkey.id_data,
                          src->token.prvkey.id_data_size);
           if (dst->token.prvkey.id_data == NULL)
             {
               ssh_private_key_free(dst->token.prvkey.private_key);
               ssh_free(dst);
               return NULL;
             }
           dst->token.prvkey.id_data_size = src->token.prvkey.id_data_size;
         }
     }
   break;

    case SSH_EAP_TOKEN_CERTIFICATE_AUTHORITY:
      {
        int cnt;
        int i;

        /* Count the ca count. */
        for (cnt = 0; src->token.cas && src->token.cas[cnt]; cnt++)
          ;

        if (cnt == 0)
          {
            SSH_DEBUG(SSH_D_ERROR, ("Cannot duplicate token, no"
                                    " CA's to duplicate."));
            ssh_free(dst);
            return NULL;
          }

        dst->token.cas = ssh_calloc(cnt + 1, sizeof(unsigned char *));
        if (dst->token.cas == NULL)
          {
            ssh_free(dst);
            return NULL;
          }

        for (i = 0; i < cnt; i++)
          dst->token.cas[i] = src->token.cas[i];

        break;
      }

#ifdef SSHDIST_EAP_SIM
    case SSH_EAP_TOKEN_SIM_CHALLENGE:
#endif /* SSHDIST_EAP_SIM */
#ifdef SSHDIST_EAP_AKA
    case SSH_EAP_TOKEN_AKA_CHALLENGE:
    case SSH_EAP_TOKEN_AKA_SYNCH_REQ:
#endif /* SSHDIST_EAP_AKA */
    case SSH_EAP_TOKEN_USERNAME:
    case SSH_EAP_TOKEN_SHARED_SECRET:
    case SSH_EAP_TOKEN_SALT:

      if (src->token.buffer.dptr != NULL)
        {
          dst->token.buffer.dptr = ssh_malloc(src->token.buffer.len);
          if (dst->token.buffer.dptr == NULL)
            {
              ssh_free(dst);
              return NULL;
            }
	  
          dst->token.buffer.len = src->token.buffer.len;
          memcpy(dst->token.buffer.dptr, src->token.buffer.dptr,
                 src->token.buffer.len);
        }
      else
        {
          dst->token.buffer.dptr = NULL;
          dst->token.buffer.len = 0;
        }
      break;
    case SSH_EAP_TOKEN_COUNTER32:
      dst->token.counter32 = src->token.counter32;
      break;
      
#ifdef SSHDIST_EAP_AKA_DASH
    case SSH_EAP_TOKEN_AKA_DASH_KDF_INPUT:
      dst->token.success = src->token.success;
      break;
#endif /* SSHDIST_EAP_AKA_DASH */

#ifdef SSHDIST_EAP_AKA
    case SSH_EAP_TOKEN_AKA_AUTH_REJECT:
#endif /* SSHDIST_EAP_AKA */
    case SSH_EAP_TOKEN_NONE:
      break;
    default:
      SSH_NOTREACHED;
    }

  SSH_DEBUG(SSH_D_MY, ("duplicated token at %p", dst));

  return dst;
}
void ikev2_fb_request_certificates_cb(SshIkev2Error error_code,
				      SshPrivateKey private_key_out,
				      int number_of_certificates,
				      SshIkev2CertEncoding *cert_encs,
				      const unsigned char **certs,
				      size_t *cert_lengths,
				      void *context)
{
  SshIkev2FbNegotiation neg = (SshIkev2FbNegotiation) context;
  SshIkeCertificateEncodingType *ikev1_cert_encodings = NULL;
  SshPrivateKey private_key_copy = NULL;
  unsigned char **ikev1_certs = NULL;
  size_t *ikev1_cert_lengths = NULL;
  int i;

  SSH_IKEV2_FB_V2_COMPLETE_CALL(neg);

  if (error_code != SSH_IKEV2_ERROR_OK)
    {
      SSH_DEBUG(SSH_D_FAIL, ("Private key/Certificate lookup failed, "
			     "error '%s'",
			     ssh_ikev2_error_to_string(error_code)));
      goto error;
    }

  if (number_of_certificates == 0)
    {
      SSH_DEBUG(SSH_D_FAIL, ("No certificates found"));
      goto error;
    }

  SSH_ASSERT(private_key_out != NULL);

  if (ssh_private_key_copy(private_key_out, &private_key_copy)
      != SSH_CRYPTO_OK)
    {
      SSH_DEBUG(SSH_D_FAIL, ("Private key copy failed"));
      goto error;
    }

  /* Copy the returned certificates */
  ikev1_cert_encodings = ssh_calloc(number_of_certificates,
				    sizeof(SshIkeCertificateEncodingType));
  ikev1_certs = ssh_calloc(number_of_certificates,
			   sizeof(unsigned char *));
  ikev1_cert_lengths = ssh_calloc(number_of_certificates,
				  sizeof(size_t));

  if (ikev1_cert_encodings == NULL || ikev1_certs == NULL ||
      ikev1_cert_lengths == NULL)
    {
      SSH_DEBUG(SSH_D_FAIL, ("Memory allocation failure"));
      goto error;
    }

  for (i = 0; i < number_of_certificates; i++)
    {
      ikev1_cert_encodings[i] =
	ikev2_fb_v2_cert_encoding_to_v1(cert_encs[i]);
      ikev1_cert_lengths[i] = cert_lengths[i];
      if (!(ikev1_certs[i] = ssh_memdup(certs[i], cert_lengths[i])))
	{
	  SSH_DEBUG(SSH_D_FAIL, ("Certificate copy failed"));
	  goto error;
	}
    }

  /* Save the certificates and private key. */
  neg->number_of_certificates = number_of_certificates;
  neg->cert_encodings = ikev1_cert_encodings;
  neg->certs = ikev1_certs;
  neg->cert_lengths = ikev1_cert_lengths;
  neg->private_key = private_key_copy;

  SSH_DEBUG(SSH_D_LOWOK, ("Found %d certificates", number_of_certificates));

  SSH_FSM_CONTINUE_AFTER_CALLBACK(neg->sub_thread);
  return;

 error:

  if (private_key_copy)
    ssh_private_key_free(private_key_copy);

  if (ikev1_certs)
    for (i = 0; i < number_of_certificates; i++)
      ssh_free(ikev1_certs[i]);

  ssh_free(ikev1_certs);
  ssh_free(ikev1_cert_encodings);
  ssh_free(ikev1_cert_lengths);

  SSH_FSM_CONTINUE_AFTER_CALLBACK(neg->sub_thread);
}