Blame src/known_hosts.c

Packit Service 31306d
/*
Packit Service 31306d
 * keyfiles.c - private and public key handling for authentication.
Packit Service 31306d
 *
Packit Service 31306d
 * This file is part of the SSH Library
Packit Service 31306d
 *
Packit Service 31306d
 * Copyright (c) 2003-2009 by Aris Adamantiadis
Packit Service 31306d
 * Copyright (c) 2009      by Andreas Schneider <asn@cryptomilk.org>
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is free software; you can redistribute it and/or modify
Packit Service 31306d
 * it under the terms of the GNU Lesser General Public License as published by
Packit Service 31306d
 * the Free Software Foundation; either version 2.1 of the License, or (at your
Packit Service 31306d
 * option) any later version.
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is distributed in the hope that it will be useful, but
Packit Service 31306d
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit Service 31306d
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
Packit Service 31306d
 * License for more details.
Packit Service 31306d
 *
Packit Service 31306d
 * You should have received a copy of the GNU Lesser General Public License
Packit Service 31306d
 * along with the SSH Library; see the file COPYING.  If not, write to
Packit Service 31306d
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
Packit Service 31306d
 * MA 02111-1307, USA.
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
#include "config.h"
Packit Service 31306d
Packit Service 31306d
#include <ctype.h>
Packit Service 31306d
#include <errno.h>
Packit Service 31306d
#include <stdio.h>
Packit Service 31306d
Packit Service 31306d
#include "libssh/priv.h"
Packit Service 31306d
#include "libssh/session.h"
Packit Service 31306d
#include "libssh/buffer.h"
Packit Service 31306d
#include "libssh/misc.h"
Packit Service 31306d
#include "libssh/dh.h"
Packit Service 31306d
#include "libssh/pki.h"
Packit Service 31306d
#include "libssh/options.h"
Packit Service 31306d
#include "libssh/knownhosts.h"
Packit Service 31306d
/*todo: remove this include */
Packit Service 31306d
#include "libssh/string.h"
Packit Service 31306d
#include "libssh/token.h"
Packit Service 31306d
Packit Service 31306d
#ifndef _WIN32
Packit Service 31306d
# include <netinet/in.h>
Packit Service 31306d
# include <arpa/inet.h>
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @addtogroup libssh_session
Packit Service 31306d
 *
Packit Service 31306d
 * @{
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief Return one line of known host file.
Packit Service 31306d
 *
Packit Service 31306d
 * This will return a token array containing (host|ip), keytype and key.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] file     A pointer to the known host file. Could be pointing to
Packit Service 31306d
 *                      NULL at start.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  filename The file name of the known host file.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] found_type A pointer to a string to be set with the found key
Packit Service 31306d
 *                        type.
Packit Service 31306d
 *
Packit Service 31306d
 * @returns             The found_type type of key (ie "dsa","ssh-rsa"). Don't
Packit Service 31306d
 *                      free that value. NULL if no match was found or the file
Packit Service 31306d
 *                      was not found.
Packit Service 31306d
 */
Packit Service 31306d
static struct ssh_tokens_st *ssh_get_knownhost_line(FILE **file,
Packit Service 31306d
                                                    const char *filename,
Packit Service 31306d
                                                    const char **found_type)
Packit Service 31306d
{
Packit Service 31306d
    char buffer[4096] = {0};
Packit Service 31306d
    char *ptr;
Packit Service 31306d
    struct ssh_tokens_st *tokens;
Packit Service 31306d
Packit Service 31306d
    if (*file == NULL) {
Packit Service 31306d
        *file = fopen(filename,"r");
Packit Service 31306d
        if (*file == NULL) {
Packit Service 31306d
            return NULL;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    while (fgets(buffer, sizeof(buffer), *file)) {
Packit Service 31306d
        ptr = strchr(buffer, '\n');
Packit Service 31306d
        if (ptr) {
Packit Service 31306d
            *ptr =  '\0';
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        ptr = strchr(buffer,'\r');
Packit Service 31306d
        if (ptr) {
Packit Service 31306d
            *ptr = '\0';
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (buffer[0] == '\0' || buffer[0] == '#') {
Packit Service 31306d
            continue; /* skip empty lines */
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        tokens = ssh_tokenize(buffer, ' ');
Packit Service 31306d
        if (tokens == NULL) {
Packit Service 31306d
            fclose(*file);
Packit Service 31306d
            *file = NULL;
Packit Service 31306d
Packit Service 31306d
            return NULL;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (tokens->tokens[0] == NULL ||
Packit Service 31306d
            tokens->tokens[1] == NULL ||
Packit Service 31306d
            tokens->tokens[2] == NULL)
Packit Service 31306d
        {
Packit Service 31306d
            /* it should have at least 3 tokens */
Packit Service 31306d
            ssh_tokens_free(tokens);
Packit Service 31306d
            continue;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        *found_type = tokens->tokens[1];
Packit Service 31306d
Packit Service 31306d
        return tokens;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    fclose(*file);
Packit Service 31306d
    *file = NULL;
Packit Service 31306d
Packit Service 31306d
    /* we did not find anything, end of file*/
Packit Service 31306d
    return NULL;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief Check the public key in the known host line matches the public key of
Packit Service 31306d
 * the currently connected server.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] session   The SSH session to use.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] tokens    A list of tokens in the known_hosts line.
Packit Service 31306d
 *
Packit Service 31306d
 * @returns             1 if the key matches, 0 if the key doesn't match and -1
Packit Service 31306d
 *                      on error.
Packit Service 31306d
 */
Packit Service 31306d
static int check_public_key(ssh_session session, char **tokens) {
Packit Service 31306d
  ssh_string pubkey_blob = NULL;
Packit Service 31306d
  ssh_buffer pubkey_buffer;
Packit Service 31306d
  char *pubkey_64;
Packit Service 31306d
  int rc;
Packit Service 31306d
Packit Service 31306d
    /* ssh-dss or ssh-rsa */
Packit Service 31306d
    pubkey_64 = tokens[2];
Packit Service 31306d
    pubkey_buffer = base64_to_bin(pubkey_64);
Packit Service 31306d
Packit Service 31306d
  if (pubkey_buffer == NULL) {
Packit Service 31306d
    ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
        "Verifying that server is a known host: base64 error");
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  rc = ssh_dh_get_current_server_publickey_blob(session, &pubkey_blob);
Packit Service 31306d
  if (rc != 0) {
Packit Service 31306d
      ssh_buffer_free(pubkey_buffer);
Packit Service 31306d
      return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (ssh_buffer_get_len(pubkey_buffer) != ssh_string_len(pubkey_blob)) {
Packit Service 31306d
    ssh_string_free(pubkey_blob);
Packit Service 31306d
    ssh_buffer_free(pubkey_buffer);
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  /* now test that they are identical */
Packit Service 31306d
  if (memcmp(ssh_buffer_get(pubkey_buffer), ssh_string_data(pubkey_blob),
Packit Service 31306d
        ssh_buffer_get_len(pubkey_buffer)) != 0) {
Packit Service 31306d
    ssh_string_free(pubkey_blob);
Packit Service 31306d
    ssh_buffer_free(pubkey_buffer);
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  ssh_string_free(pubkey_blob);
Packit Service 31306d
  ssh_buffer_free(pubkey_buffer);
Packit Service 31306d
  return 1;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 * @brief Check if a hostname matches a openssh-style hashed known host.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  host     The host to check.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  hashed   The hashed value.
Packit Service 31306d
 *
Packit Service 31306d
 * @returns             1 if it matches, 0 otherwise.
Packit Service 31306d
 */
Packit Service 31306d
static int match_hashed_host(const char *host, const char *sourcehash)
Packit Service 31306d
{
Packit Service 31306d
  /* Openssh hash structure :
Packit Service 31306d
   * |1|base64 encoded salt|base64 encoded hash
Packit Service 31306d
   * hash is produced that way :
Packit Service 31306d
   * hash := HMAC_SHA1(key=salt,data=host)
Packit Service 31306d
   */
Packit Service 31306d
  unsigned char buffer[256] = {0};
Packit Service 31306d
  ssh_buffer salt;
Packit Service 31306d
  ssh_buffer hash;
Packit Service 31306d
  HMACCTX mac;
Packit Service 31306d
  char *source;
Packit Service 31306d
  char *b64hash;
Packit Service 31306d
  int match;
Packit Service 31306d
  unsigned int size;
Packit Service 31306d
Packit Service 31306d
  if (strncmp(sourcehash, "|1|", 3) != 0) {
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  source = strdup(sourcehash + 3);
Packit Service 31306d
  if (source == NULL) {
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  b64hash = strchr(source, '|');
Packit Service 31306d
  if (b64hash == NULL) {
Packit Service 31306d
    /* Invalid hash */
Packit Service 31306d
    SAFE_FREE(source);
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  *b64hash = '\0';
Packit Service 31306d
  b64hash++;
Packit Service 31306d
Packit Service 31306d
  salt = base64_to_bin(source);
Packit Service 31306d
  if (salt == NULL) {
Packit Service 31306d
    SAFE_FREE(source);
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  hash = base64_to_bin(b64hash);
Packit Service 31306d
  SAFE_FREE(source);
Packit Service 31306d
  if (hash == NULL) {
Packit Service 31306d
    ssh_buffer_free(salt);
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  mac = hmac_init(ssh_buffer_get(salt), ssh_buffer_get_len(salt), SSH_HMAC_SHA1);
Packit Service 31306d
  if (mac == NULL) {
Packit Service 31306d
    ssh_buffer_free(salt);
Packit Service 31306d
    ssh_buffer_free(hash);
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
  size = sizeof(buffer);
Packit Service 31306d
  hmac_update(mac, host, strlen(host));
Packit Service 31306d
  hmac_final(mac, buffer, &size);
Packit Service 31306d
Packit Service 31306d
  if (size == ssh_buffer_get_len(hash) &&
Packit Service 31306d
      memcmp(buffer, ssh_buffer_get(hash), size) == 0) {
Packit Service 31306d
    match = 1;
Packit Service 31306d
  } else {
Packit Service 31306d
    match = 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  ssh_buffer_free(salt);
Packit Service 31306d
  ssh_buffer_free(hash);
Packit Service 31306d
Packit Service 31306d
  SSH_LOG(SSH_LOG_PACKET,
Packit Service 31306d
      "Matching a hashed host: %s match=%d", host, match);
Packit Service 31306d
Packit Service 31306d
  return match;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/* How it's working :
Packit Service 31306d
 * 1- we open the known host file and bitch if it doesn't exist
Packit Service 31306d
 * 2- we need to examine each line of the file, until going on state SSH_SERVER_KNOWN_OK:
Packit Service 31306d
 *  - there's a match. if the key is good, state is SSH_SERVER_KNOWN_OK,
Packit Service 31306d
 *    else it's SSH_SERVER_KNOWN_CHANGED (or SSH_SERVER_FOUND_OTHER)
Packit Service 31306d
 *  - there's no match : no change
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief This function is deprecated
Packit Service 31306d
 *
Packit Service 31306d
 * @deprecated          Please use ssh_session_is_known_server()
Packit Service 31306d
 * @see ssh_session_is_known_server()
Packit Service 31306d
 */
Packit Service 31306d
int ssh_is_server_known(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    FILE *file = NULL;
Packit Service 31306d
    char *host;
Packit Service 31306d
    char *hostport;
Packit Service 31306d
    const char *type;
Packit Service 31306d
    int match;
Packit Service 31306d
    int i = 0;
Packit Service 31306d
    char *files[3];
Packit Service 31306d
Packit Service 31306d
    struct ssh_tokens_st *tokens;
Packit Service 31306d
Packit Service 31306d
    int ret = SSH_SERVER_NOT_KNOWN;
Packit Service 31306d
Packit Service 31306d
    if (session->opts.knownhosts == NULL) {
Packit Service 31306d
        if (ssh_options_apply(session) < 0) {
Packit Service 31306d
            ssh_set_error(session, SSH_REQUEST_DENIED,
Packit Service 31306d
                    "Can't find a known_hosts file");
Packit Service 31306d
Packit Service 31306d
            return SSH_SERVER_FILE_NOT_FOUND;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (session->opts.host == NULL) {
Packit Service 31306d
        ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
                "Can't verify host in known hosts if the hostname isn't known");
Packit Service 31306d
Packit Service 31306d
        return SSH_SERVER_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (session->current_crypto == NULL){
Packit Service 31306d
        ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
                "ssh_is_host_known called without cryptographic context");
Packit Service 31306d
Packit Service 31306d
        return SSH_SERVER_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    host = ssh_lowercase(session->opts.host);
Packit Service 31306d
    hostport = ssh_hostport(host, session->opts.port > 0 ? session->opts.port : 22);
Packit Service 31306d
    if (host == NULL || hostport == NULL) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        SAFE_FREE(host);
Packit Service 31306d
        SAFE_FREE(hostport);
Packit Service 31306d
Packit Service 31306d
        return SSH_SERVER_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Set the list of known hosts files */
Packit Service 31306d
    i = 0;
Packit Service 31306d
    if (session->opts.global_knownhosts != NULL){
Packit Service 31306d
        files[i++] = session->opts.global_knownhosts;
Packit Service 31306d
    }
Packit Service 31306d
    files[i++] = session->opts.knownhosts;
Packit Service 31306d
    files[i] = NULL;
Packit Service 31306d
    i = 0;
Packit Service 31306d
Packit Service 31306d
    do {
Packit Service 31306d
        tokens = ssh_get_knownhost_line(&file,
Packit Service 31306d
                                        files[i],
Packit Service 31306d
                                        &type);
Packit Service 31306d
Packit Service 31306d
        /* End of file, return the current state or use next file */
Packit Service 31306d
        if (tokens == NULL) {
Packit Service 31306d
            ++i;
Packit Service 31306d
            if(files[i] == NULL)
Packit Service 31306d
                break;
Packit Service 31306d
            else
Packit Service 31306d
                continue;
Packit Service 31306d
        }
Packit Service 31306d
        match = match_hashed_host(host, tokens->tokens[0]);
Packit Service 31306d
        if (match == 0){
Packit Service 31306d
            match = match_hostname(hostport, tokens->tokens[0],
Packit Service 31306d
                                   strlen(tokens->tokens[0]));
Packit Service 31306d
        }
Packit Service 31306d
        if (match == 0) {
Packit Service 31306d
            match = match_hostname(host, tokens->tokens[0],
Packit Service 31306d
                                   strlen(tokens->tokens[0]));
Packit Service 31306d
        }
Packit Service 31306d
        if (match == 0) {
Packit Service 31306d
            match = match_hashed_host(hostport, tokens->tokens[0]);
Packit Service 31306d
        }
Packit Service 31306d
        if (match) {
Packit Service 31306d
            ssh_key pubkey = ssh_dh_get_current_server_publickey(session);
Packit Service 31306d
            const char *pubkey_type = ssh_key_type_to_char(ssh_key_type(pubkey));
Packit Service 31306d
Packit Service 31306d
            /* We got a match. Now check the key type */
Packit Service 31306d
            if (strcmp(pubkey_type, type) != 0) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_PACKET,
Packit Service 31306d
                        "ssh_is_server_known: server type [%s] doesn't match the "
Packit Service 31306d
                        "type [%s] in known_hosts file",
Packit Service 31306d
                        pubkey_type,
Packit Service 31306d
                        type);
Packit Service 31306d
                /* Different type. We don't override the known_changed error which is
Packit Service 31306d
                 * more important */
Packit Service 31306d
                if (ret != SSH_SERVER_KNOWN_CHANGED)
Packit Service 31306d
                    ret = SSH_SERVER_FOUND_OTHER;
Packit Service 31306d
                ssh_tokens_free(tokens);
Packit Service 31306d
                continue;
Packit Service 31306d
            }
Packit Service 31306d
            /* so we know the key type is good. We may get a good key or a bad key. */
Packit Service 31306d
            match = check_public_key(session, tokens->tokens);
Packit Service 31306d
            ssh_tokens_free(tokens);
Packit Service 31306d
Packit Service 31306d
            if (match < 0) {
Packit Service 31306d
                ret = SSH_SERVER_ERROR;
Packit Service 31306d
                break;
Packit Service 31306d
            } else if (match == 1) {
Packit Service 31306d
                ret = SSH_SERVER_KNOWN_OK;
Packit Service 31306d
                break;
Packit Service 31306d
            } else if(match == 0) {
Packit Service 31306d
                /* We override the status with the wrong key state */
Packit Service 31306d
                ret = SSH_SERVER_KNOWN_CHANGED;
Packit Service 31306d
            }
Packit Service 31306d
        } else {
Packit Service 31306d
            ssh_tokens_free(tokens);
Packit Service 31306d
        }
Packit Service 31306d
    } while (1);
Packit Service 31306d
Packit Service 31306d
    if ((ret == SSH_SERVER_NOT_KNOWN) &&
Packit Service 31306d
            (session->opts.StrictHostKeyChecking == 0)) {
Packit Service 31306d
        int rv = ssh_session_update_known_hosts(session);
Packit Service 31306d
        if (rv != SSH_OK) {
Packit Service 31306d
            ret = SSH_SERVER_ERROR;
Packit Service 31306d
        } else {
Packit Service 31306d
            ret = SSH_SERVER_KNOWN_OK;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SAFE_FREE(host);
Packit Service 31306d
    SAFE_FREE(hostport);
Packit Service 31306d
    if (file != NULL) {
Packit Service 31306d
        fclose(file);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Return the current state at end of file */
Packit Service 31306d
    return ret;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @deprecated Please use ssh_session_export_known_hosts_entry()
Packit Service 31306d
 * @brief This function is deprecated.
Packit Service 31306d
 */
Packit Service 31306d
char * ssh_dump_knownhost(ssh_session session) {
Packit Service 31306d
    ssh_key server_pubkey = NULL;
Packit Service 31306d
    char *host;
Packit Service 31306d
    char *hostport;
Packit Service 31306d
    size_t len = 4096;
Packit Service 31306d
    char *buffer;
Packit Service 31306d
    char *b64_key;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (session->opts.host == NULL) {
Packit Service 31306d
        ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
                "Can't write host in known hosts if the hostname isn't known");
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    host = ssh_lowercase(session->opts.host);
Packit Service 31306d
    /* If using a nonstandard port, save the host in the [host]:port format */
Packit Service 31306d
    if (session->opts.port > 0 && session->opts.port != 22) {
Packit Service 31306d
        hostport = ssh_hostport(host, session->opts.port);
Packit Service 31306d
        SAFE_FREE(host);
Packit Service 31306d
        if (hostport == NULL) {
Packit Service 31306d
            return NULL;
Packit Service 31306d
        }
Packit Service 31306d
        host = hostport;
Packit Service 31306d
        hostport = NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (session->current_crypto==NULL) {
Packit Service 31306d
        ssh_set_error(session, SSH_FATAL, "No current crypto context");
Packit Service 31306d
        SAFE_FREE(host);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    server_pubkey = ssh_dh_get_current_server_publickey(session);
Packit Service 31306d
    if (server_pubkey == NULL){
Packit Service 31306d
        ssh_set_error(session, SSH_FATAL, "No public key present");
Packit Service 31306d
        SAFE_FREE(host);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    buffer = calloc (1, 4096);
Packit Service 31306d
    if (!buffer) {
Packit Service 31306d
        SAFE_FREE(host);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_pki_export_pubkey_base64(server_pubkey, &b64_key);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        SAFE_FREE(buffer);
Packit Service 31306d
        SAFE_FREE(host);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    snprintf(buffer, len,
Packit Service 31306d
            "%s %s %s\n",
Packit Service 31306d
            host,
Packit Service 31306d
            server_pubkey->type_c,
Packit Service 31306d
            b64_key);
Packit Service 31306d
Packit Service 31306d
    SAFE_FREE(host);
Packit Service 31306d
    SAFE_FREE(b64_key);
Packit Service 31306d
Packit Service 31306d
    return buffer;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @deprecated Please use ssh_session_update_known_hosts()
Packit Service 31306d
 * @brief This function is deprecated
Packit Service 31306d
 */
Packit Service 31306d
int ssh_write_knownhost(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    FILE *file;
Packit Service 31306d
    char *buffer = NULL;
Packit Service 31306d
    char *dir;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (session->opts.knownhosts == NULL) {
Packit Service 31306d
        if (ssh_options_apply(session) < 0) {
Packit Service 31306d
            ssh_set_error(session, SSH_FATAL, "Can't find a known_hosts file");
Packit Service 31306d
            return SSH_ERROR;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    errno = 0;
Packit Service 31306d
    file = fopen(session->opts.knownhosts, "a");
Packit Service 31306d
    if (file == NULL) {
Packit Service 31306d
        if (errno == ENOENT) {
Packit Service 31306d
            dir = ssh_dirname(session->opts.knownhosts);
Packit Service 31306d
            if (dir == NULL) {
Packit Service 31306d
                ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
Packit Service 31306d
                return SSH_ERROR;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            rc = ssh_mkdirs(dir, 0700);
Packit Service 31306d
            if (rc < 0) {
Packit Service 31306d
                ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
                              "Cannot create %s directory: %s",
Packit Service 31306d
                              dir, strerror(errno));
Packit Service 31306d
                SAFE_FREE(dir);
Packit Service 31306d
                return SSH_ERROR;
Packit Service 31306d
            }
Packit Service 31306d
            SAFE_FREE(dir);
Packit Service 31306d
Packit Service 31306d
            errno = 0;
Packit Service 31306d
            file = fopen(session->opts.knownhosts, "a");
Packit Service 31306d
            if (file == NULL) {
Packit Service 31306d
                ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
                              "Couldn't open known_hosts file %s"
Packit Service 31306d
                              " for appending: %s",
Packit Service 31306d
                              session->opts.knownhosts, strerror(errno));
Packit Service 31306d
                return SSH_ERROR;
Packit Service 31306d
            }
Packit Service 31306d
        } else {
Packit Service 31306d
            ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
                          "Couldn't open known_hosts file %s for appending: %s",
Packit Service 31306d
                          session->opts.knownhosts, strerror(errno));
Packit Service 31306d
            return SSH_ERROR;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_session_export_known_hosts_entry(session, &buffer);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        fclose(file);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (fwrite(buffer, strlen(buffer), 1, file) != 1 || ferror(file)) {
Packit Service 31306d
        SAFE_FREE(buffer);
Packit Service 31306d
        fclose(file);
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SAFE_FREE(buffer);
Packit Service 31306d
    fclose(file);
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#define KNOWNHOSTS_MAXTYPES 10
Packit Service 31306d
Packit Service 31306d
/** @} */