Exemple #1
0
static int
agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
{
    HWND hwnd;
    char mapname[23];
    HANDLE filemap;
    unsigned char *p;
    unsigned char *p2;
    int id;
    COPYDATASTRUCT cds;

    if (!transctx || 4 + transctx->request_len > PAGEANT_MAX_MSGLEN)
        return _libssh2_error(agent->session, LIBSSH2_ERROR_INVAL,
                              "illegal input");

    hwnd = FindWindow("Pageant", "Pageant");
    if (!hwnd)
        return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
                              "found no pageant");

    sprintf(mapname, "PageantRequest%08x", (unsigned)GetCurrentThreadId());
    filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
				0, PAGEANT_MAX_MSGLEN, mapname);

    if (filemap == NULL || filemap == INVALID_HANDLE_VALUE)
        return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
                              "failed setting up pageant filemap");

    p2 = p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
    _libssh2_store_str(&p2, (const char *)transctx->request,
                       transctx->request_len);

    cds.dwData = PAGEANT_COPYDATA_ID;
    cds.cbData = 1 + strlen(mapname);
    cds.lpData = mapname;

    id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds);
    if (id > 0) {
	transctx->response_len = _libssh2_ntohu32(p);
        if (transctx->response_len > PAGEANT_MAX_MSGLEN) {
            UnmapViewOfFile(p);
            CloseHandle(filemap);
            return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
                                  "agent setup fail");
        }
	transctx->response = LIBSSH2_ALLOC(agent->session,
                                           transctx->response_len);
	if (!transctx->response) {
            UnmapViewOfFile(p);
            CloseHandle(filemap);
            return _libssh2_error(agent->session, LIBSSH2_ERROR_ALLOC,
                                  "agent malloc");
        }
        memcpy(transctx->response, p + 4, transctx->response_len);
    }

    UnmapViewOfFile(p);
    CloseHandle(filemap);
    return 0;
}
Exemple #2
0
LIBSSH2_API int
libssh2_knownhost_readfile(LIBSSH2_KNOWNHOSTS *hosts,
                           const char *filename, int type)
{
    FILE *file;
    int num = 0;
    char buf[2048];

    if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH)
        return _libssh2_error(hosts->session,
                              LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
                              "Unsupported type of known-host information "
                              "store");

    file = fopen(filename, "r");
    if(file) {
        while(fgets(buf, sizeof(buf), file)) {
            if(libssh2_knownhost_readline(hosts, buf, strlen(buf), type)) {
                num = _libssh2_error(hosts->session, LIBSSH2_ERROR_KNOWN_HOSTS,
                                     "Failed to parse known hosts file");
                break;
            }
            num++;
        }
        fclose(file);
    }
    else
        return _libssh2_error(hosts->session, LIBSSH2_ERROR_FILE,
                              "Failed to open file");

    return num;
}
Exemple #3
0
static int
agent_connect_unix(LIBSSH2_AGENT *agent)
{
    const char *path;
    struct sockaddr_un s_un;

    path = getenv("SSH_AUTH_SOCK");
    if (!path)
        return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE,
                              "no auth sock variable");

    agent->fd = socket(PF_UNIX, SOCK_STREAM, 0);
    if (agent->fd < 0)
        return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_NONE,
                              "failed creating socket");

    s_un.sun_family = AF_UNIX;
    strncpy (s_un.sun_path, path, sizeof s_un.sun_path);
    if (connect(agent->fd, (struct sockaddr*)(&s_un), sizeof s_un) != 0) {
        close (agent->fd);
        return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_NONE,
                              "failed connecting");
    }

    return LIBSSH2_ERROR_NONE;
}
Exemple #4
0
/* |1|[salt]|[hash] */
static int hashed_hostline(LIBSSH2_KNOWNHOSTS *hosts,
                           const char *host, size_t hostlen,
                           const char *key_type_name, size_t key_type_len,
                           const char *key, size_t keylen, int key_type,
                           const char *comment, size_t commentlen)
{
    const char *p;
    char saltbuf[32];
    char hostbuf[256];

    const char *salt = &host[3]; /* skip the magic marker */
    hostlen -= 3;    /* deduct the marker */

    /* this is where the salt starts, find the end of it */
    for(p = salt; *p && (*p != '|'); p++)
        ;

    if(*p=='|') {
        const char *hash = NULL;
        size_t saltlen = p - salt;
        if(saltlen >= (sizeof(saltbuf)-1)) /* weird length */
            return _libssh2_error(hosts->session,
                                  LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
                                  "Failed to parse known_hosts line "
                                  "(unexpectedly long salt)");

        memcpy(saltbuf, salt, saltlen);
        saltbuf[saltlen] = 0; /* zero terminate */
        salt = saltbuf; /* point to the stack based buffer */

        hash = p+1; /* the host hash is after the separator */

        /* now make the host point to the hash */
        host = hash;
        hostlen -= saltlen+1; /* deduct the salt and separator */

        /* check that the lengths seem sensible */
        if(hostlen >= sizeof(hostbuf)-1)
            return _libssh2_error(hosts->session,
                                  LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
                                  "Failed to parse known_hosts line "
                                  "(unexpected length)");

        memcpy(hostbuf, host, hostlen);
        hostbuf[hostlen]=0;

        return knownhost_add(hosts, hostbuf, salt,
                             key_type_name, key_type_len,
                             key, keylen,
                             comment, commentlen,
                             key_type | LIBSSH2_KNOWNHOST_TYPE_SHA1 |
                             LIBSSH2_KNOWNHOST_KEYENC_BASE64, NULL);
    }
    else
        return 0; /* XXX: This should be an error, shouldn't it? */
}
Exemple #5
0
/* old style plain text: [name]([,][name])*

   for the sake of simplicity, we add them as separate hosts with the same
   key
*/
static int oldstyle_hostline(LIBSSH2_KNOWNHOSTS *hosts,
                             const char *host, size_t hostlen,
                             const char *key_type_name, size_t key_type_len,
                             const char *key, size_t keylen, int key_type,
                             const char *comment, size_t commentlen)
{
    int rc = 0;
    size_t namelen = 0;
    const char *name = host + hostlen;

    if(hostlen < 1)
        return _libssh2_error(hosts->session,
                              LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
                              "Failed to parse known_hosts line "
                              "(no host names)");

    while(name > host) {
        --name;
        ++namelen;

        /* when we get the the start or see a comma coming up, add the host
           name to the collection */
        if((name == host) || (*(name-1) == ',')) {

            char hostbuf[256];

            /* make sure we don't overflow the buffer */
            if(namelen >= sizeof(hostbuf)-1)
                return _libssh2_error(hosts->session,
                                      LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
                                      "Failed to parse known_hosts line "
                                      "(unexpected length)");

            /* copy host name to the temp buffer and zero terminate */
            memcpy(hostbuf, name, namelen);
            hostbuf[namelen]=0;

            rc = knownhost_add(hosts, hostbuf, NULL,
                               key_type_name, key_type_len,
                               key, keylen,
                               comment, commentlen,
                               key_type | LIBSSH2_KNOWNHOST_TYPE_PLAIN |
                               LIBSSH2_KNOWNHOST_KEYENC_BASE64, NULL);
            if(rc)
                return rc;

            if(name > host) {
                namelen = 0;
                --name; /* skip comma */
            }
        }
    }

    return rc;
}
Exemple #6
0
/*
 * hostkey_method_ssh_ed25519_init
 *
 * Initialize the server hostkey working area with e/n pair
 */
static int
hostkey_method_ssh_ed25519_init(LIBSSH2_SESSION * session,
                                const unsigned char *hostkey_data,
                                size_t hostkey_data_len,
                                void **abstract)
{
    const unsigned char *s;
    unsigned long len, key_len;
    EVP_PKEY *public_key = NULL;
    libssh2_ed25519_ctx *ctx = NULL;

    if(*abstract) {
        hostkey_method_ssh_ed25519_dtor(session, abstract);
        *abstract = NULL;
    }

    if(hostkey_data_len < 15) {
        return -1;
    }

    s = hostkey_data;
    len = _libssh2_ntohu32(s);
    s += 4;

    if(len != 11 || strncmp((char *) s, "ssh-ed25519", 11) != 0) {
        return -1;
    }

    s += 11;

    //public key
    key_len = _libssh2_ntohu32(s);
    s += 4;

    public_key = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, (const unsigned char*)s, key_len);
    if(public_key == NULL) {
        return _libssh2_error(session, LIBSSH2_ERROR_PROTO, "could not create ED25519 public key");
    }

    ctx = LIBSSH2_CALLOC(session, sizeof(libssh2_ed25519_ctx));
    if(ctx == NULL) {
        return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "could not alloc public/private key");
    }

    ctx->public_key = public_key;
    *abstract = ctx;

    return 0;
}
Exemple #7
0
/*
 * libssh2_knownhost_del
 *
 * Remove a host from the collection of known hosts.
 *
 */
LIBSSH2_API int
libssh2_knownhost_del(LIBSSH2_KNOWNHOSTS *hosts,
                      struct libssh2_knownhost *entry)
{
    struct known_host *node;

    /* check that this was retrieved the right way or get out */
    if(!entry || (entry->magic != KNOWNHOST_MAGIC))
        return _libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL,
                              "Invalid host information");

    /* get the internal node pointer */
    node = entry->node;

    /* unlink from the list of all hosts */
    _libssh2_list_remove(&node->node);

    /* clear the struct now since the memory in which it is allocated is
       about to be freed! */
    memset(entry, 0, sizeof(struct libssh2_knownhost));

    /* free all resources */
    free_host(hosts->session, node);

    return 0;
}
Exemple #8
0
/*
 * libssh2_knownhost_writefile()
 *
 * Write hosts+key pairs to the given file.
 */
LIBSSH2_API int
libssh2_knownhost_writefile(LIBSSH2_KNOWNHOSTS *hosts,
                            const char *filename, int type)
{
    struct known_host *node;
    FILE *file;
    int rc = LIBSSH2_ERROR_NONE;
    char buffer[2048];

    /* we only support this single file type for now, bail out on all other
       attempts */
    if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH)
        return _libssh2_error(hosts->session,
                              LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
                              "Unsupported type of known-host information "
                              "store");

    file = fopen(filename, "w");
    if(!file)
        return _libssh2_error(hosts->session, LIBSSH2_ERROR_FILE,
                              "Failed to open file");

    for(node = _libssh2_list_first(&hosts->head);
        node;
        node = _libssh2_list_next(&node->node)) {
        size_t wrote = 0;
        size_t nwrote;
        rc = knownhost_writeline(hosts, node, buffer, sizeof(buffer), &wrote,
                                 type);
        if(rc)
            break;

        nwrote = fwrite(buffer, 1, wrote, file);
        if(nwrote != wrote) {
            /* failed to write the whole thing, bail out */
            rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_FILE,
                                "Write failed");
            break;
        }
    }
    fclose(file);

    return rc;
}
Exemple #9
0
int
_libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa,
                                    LIBSSH2_SESSION * session,
                                    const char *filedata, size_t filedata_len,
                                    unsigned const char *passphrase)
{
    return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
                         "Unable to extract private key from memory: "
                         "Method unimplemented in libgcrypt backend");
}
Exemple #10
0
static int
gen_publickey_from_dsa_evp(LIBSSH2_SESSION *session,
                           unsigned char **method,
                           size_t *method_len,
                           unsigned char **pubkeydata,
                           size_t *pubkeydata_len,
                           EVP_PKEY *pk)
{
    DSA*           dsa = NULL;
    unsigned char* key;
    unsigned char* method_buf = NULL;
    size_t  key_len;

    _libssh2_debug(session,
                   LIBSSH2_TRACE_AUTH,
                   "Computing public key from DSA private key envelop");

    dsa = EVP_PKEY_get1_DSA(pk);
    if (dsa == NULL) {
        /* Assume memory allocation error... what else could it be ? */
        goto __alloc_error;
    }

    method_buf = LIBSSH2_ALLOC(session, 7);  /* ssh-dss. */
    if (method_buf == NULL) {
        goto __alloc_error;
    }

    key = gen_publickey_from_dsa(session, dsa, &key_len);
    if (key == NULL) {
        goto __alloc_error;
    }
    DSA_free(dsa);

    memcpy(method_buf, "ssh-dss", 7);
    *method         = method_buf;
    *method_len     = 7;
    *pubkeydata     = key;
    *pubkeydata_len = key_len;
    return 0;

  __alloc_error:
    if (dsa != NULL) {
        DSA_free(dsa);
    }
    if (method_buf != NULL) {
        LIBSSH2_FREE(session, method_buf);
    }

    _libssh2_error(session,
                   LIBSSH2_ERROR_ALLOC,
                   "Unable to allocate memory for private key data");
    return -1;
}
Exemple #11
0
static int
agent_connect_pageant(LIBSSH2_AGENT *agent)
{
    HWND hwnd;
    hwnd = FindWindow("Pageant", "Pageant");
    if (!hwnd)
	return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_NONE,
                              "failed connecting agent");
    agent->fd = 0;         /* Mark as the connection has been established */
    return LIBSSH2_ERROR_NONE;
}
Exemple #12
0
static int
agent_disconnect_unix(LIBSSH2_AGENT *agent)
{
    int ret;
    ret = close(agent->fd);

    if(ret == -1)
        return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
                              "failed closing the agent socket");
    return LIBSSH2_ERROR_NONE;
}
Exemple #13
0
int
_libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
                          unsigned char **method,
                          size_t *method_len,
                          unsigned char **pubkeydata,
                          size_t *pubkeydata_len,
                          const char *privatekey,
                          const char *passphrase)
{
    return _libssh2_error(session, LIBSSH2_ERROR_FILE,
                         "Unable to extract public key from private key file: "
                         "Method unimplemented in libgcrypt backend");
}
Exemple #14
0
/*
 * libssh2_agent_init
 *
 * Init an ssh-agent handle. Returns the pointer to the handle.
 *
 */
LIBSSH2_API LIBSSH2_AGENT *
libssh2_agent_init(LIBSSH2_SESSION *session)
{
    LIBSSH2_AGENT *agent;

    agent = LIBSSH2_ALLOC(session, sizeof *agent);
    if (!agent) {
        _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                       "Unable to allocate space for agent connection");
        return NULL;
    }
    memset(agent, 0, sizeof *agent);
    agent->session = session;
    _libssh2_list_init(&agent->head);

    return agent;
}
Exemple #15
0
/*
 * libssh2_knownhost_writeline()
 *
 * Ask libssh2 to convert a known host to an output line for storage.
 *
 * Note that this function returns LIBSSH2_ERROR_BUFFER_TOO_SMALL if the given
 * output buffer is too small to hold the desired output.
 */
LIBSSH2_API int
libssh2_knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts,
                            struct libssh2_knownhost *known,
                            char *buffer, size_t buflen,
                            size_t *outlen, /* the amount of written data */
                            int type)
{
    struct known_host *node;

    if(known->magic != KNOWNHOST_MAGIC)
        return _libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL,
                              "Invalid host information");

    node = known->node;

    return knownhost_writeline(hosts, node, buffer, buflen, outlen, type);
}
Exemple #16
0
/*
 * libssh2_hostkey_method_ssh_dss_sign
 *
 * Verify signature created by remote
 */
static int
hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION * session,
                                  const unsigned char *sig,
                                  size_t sig_len,
                                  const unsigned char *m,
                                  size_t m_len, void **abstract)
{
    libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);

    /* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */
    sig += 15;
    sig_len -= 15;
    if (sig_len != 40) {
        return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
                              "Invalid DSS signature length");
    }
    return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len);
}
Exemple #17
0
/*
 * libssh2_knownhost_init
 *
 * Init a collection of known hosts. Returns the pointer to a collection.
 *
 */
LIBSSH2_API LIBSSH2_KNOWNHOSTS *
libssh2_knownhost_init(LIBSSH2_SESSION *session)
{
    LIBSSH2_KNOWNHOSTS *knh =
        LIBSSH2_ALLOC(session, sizeof(struct _LIBSSH2_KNOWNHOSTS));

    if(!knh) {
        _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                       "Unable to allocate memory for known-hosts "
                       "collection");
        return NULL;
    }

    knh->session = session;

    _libssh2_list_init(&knh->head);

    return knh;
}
Exemple #18
0
LIBSSH2_API int
libssh2_keepalive_send (LIBSSH2_SESSION *session,
                        int *seconds_to_next)
{
    time_t now;

    if (!session->keepalive_interval) {
        if (seconds_to_next)
            *seconds_to_next = 0;
        return 0;
    }

    now = time (NULL);

    if (session->keepalive_last_sent + session->keepalive_interval <= now) {
/* Format is "SSH_MSG_GLOBAL_REQUEST || 4-byte len || str || want-reply". */
        unsigned char keepalive_data[]
            = "\x50\x00\x00\x00\[email protected]";
        size_t len = sizeof (keepalive_data) - 1;
        int rc;

        keepalive_data[len - 1] = session->keepalive_want_reply;

        rc = _libssh2_transport_write(session, keepalive_data, len);
/* Silently ignore PACKET_EAGAIN here: if the write buffer is
   already full, sending another keepalive is not useful. */
        if (rc && rc != LIBSSH2_ERROR_EAGAIN) {
            _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
                           "Unable to send keepalive message");
            return rc;
        }

        session->keepalive_last_sent = now;
        if (seconds_to_next)
            *seconds_to_next = session->keepalive_interval;
    } else if (seconds_to_next) {
        *seconds_to_next = session->keepalive_last_sent
            + session->keepalive_interval - now;
    }

    return 0;
}
Exemple #19
0
/*
 * libssh2_knownhost_readline()
 *
 * Pass in a line of a file of 'type'.
 *
 * LIBSSH2_KNOWNHOST_FILE_OPENSSH is the only supported type.
 *
 * OpenSSH line format:
 *
 * <host> <key>
 *
 * Where the two parts can be created like:
 *
 * <host> can be either
 * <name> or <hash>
 *
 * <name> consists of
 * [name] optionally followed by [,name] one or more times
 *
 * <hash> consists of
 * |1|<salt>|hash
 *
 * <key> can be one of:
 * [RSA bits] [e] [n as a decimal number]
 * 'ssh-dss' [base64-encoded-key]
 * 'ssh-rsa' [base64-encoded-key]
 *
 */
LIBSSH2_API int
libssh2_knownhost_readline(LIBSSH2_KNOWNHOSTS *hosts,
                           const char *line, size_t len, int type)
{
    const char *cp;
    const char *hostp;
    const char *keyp;
    size_t hostlen;
    size_t keylen;
    int rc;

    if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH)
        return _libssh2_error(hosts->session,
                              LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
                              "Unsupported type of known-host information "
                              "store");

    cp = line;

    /* skip leading whitespaces */
    while(len && ((*cp==' ') || (*cp == '\t'))) {
        cp++;
        len--;
    }

    if(!len || !*cp || (*cp == '#') || (*cp == '\n'))
        /* comment or empty line */
        return LIBSSH2_ERROR_NONE;

    /* the host part starts here */
    hostp = cp;

    /* move over the host to the separator */
    while(len && *cp && (*cp!=' ') && (*cp != '\t')) {
        cp++;
        len--;
    }

    hostlen = cp - hostp;

    /* the key starts after the whitespaces */
    while(len && *cp && ((*cp==' ') || (*cp == '\t'))) {
        cp++;
        len--;
    }

    if(!*cp || !len) /* illegal line */
        return _libssh2_error(hosts->session,
                              LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
                              "Failed to parse known_hosts line");

    keyp = cp; /* the key starts here */
    keylen = len;

    /* check if the line (key) ends with a newline and if so kill it */
    while(len && *cp && (*cp != '\n')) {
        cp++;
        len--;
    }

    /* zero terminate where the newline is */
    if(*cp == '\n')
        keylen--; /* don't include this in the count */

    /* deal with this one host+key line */
    rc = hostline(hosts, hostp, hostlen, keyp, keylen);
    if(rc)
        return rc; /* failed */

    return LIBSSH2_ERROR_NONE; /* success */
}
Exemple #20
0
/*
 * hostline()
 *
 * Parse a single known_host line pre-split into host and key.
 *
 * The key part may include an optional comment which will be parsed here
 * for ssh-rsa and ssh-dsa keys.  Comments in other key types aren't handled.
 *
 * The function assumes new-lines have already been removed from the arguments.
 */
static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
                    const char *host, size_t hostlen,
                    const char *key, size_t keylen)
{
    const char *comment = NULL;
    const char *key_type_name = NULL;
    size_t commentlen = 0;
    size_t key_type_len = 0;
    int key_type;

    /* make some checks that the lengths seem sensible */
    if(keylen < 20)
        return _libssh2_error(hosts->session,
                              LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
                              "Failed to parse known_hosts line "
                              "(key too short)");

    switch(key[0]) {
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':
        key_type = LIBSSH2_KNOWNHOST_KEY_RSA1;

        /* Note that the old-style keys (RSA1) aren't truly base64, but we
         * claim it is for now since we can get away with strcmp()ing the
         * entire anything anyway! We need to check and fix these to make them
         * work properly.
         */
        break;

    default:
        key_type_name = key;
        while (keylen && *key &&
               (*key != ' ') && (*key != '\t')) {
            key++;
            keylen--;
        }
        key_type_len = key - key_type_name;

        if (!strncmp(key_type_name, "ssh-dss", key_type_len))
            key_type = LIBSSH2_KNOWNHOST_KEY_SSHDSS;
        else if (!strncmp(key_type_name, "ssh-rsa", key_type_len))
            key_type = LIBSSH2_KNOWNHOST_KEY_SSHRSA;
        else
            key_type = LIBSSH2_KNOWNHOST_KEY_UNKNOWN;

        /* skip whitespaces */
        while((*key ==' ') || (*key == '\t')) {
            key++;
            keylen--;
        }

        comment = key;
        commentlen = keylen;

        /* move over key */
        while(commentlen && *comment &&
              (*comment != ' ') && (*comment != '\t')) {
            comment++;
            commentlen--;
        }

        /* reduce key by comment length */
        keylen -= commentlen;

        /* Distinguish empty comment (a space) from no comment (no space) */
        if (commentlen == 0)
            comment = NULL;

        /* skip whitespaces */
        while(commentlen && *comment &&
              ((*comment ==' ') || (*comment == '\t'))) {
            comment++;
            commentlen--;
        }
        break;
    }

    /* Figure out host format */
    if((hostlen >2) && memcmp(host, "|1|", 3)) {
        /* old style plain text: [name]([,][name])*

           for the sake of simplicity, we add them as separate hosts with the
           same key
        */
        return oldstyle_hostline(hosts, host, hostlen, key_type_name,
                                 key_type_len, key, keylen, key_type,
                                 comment, commentlen);
    }
    else {
        /* |1|[salt]|[hash] */
        return hashed_hostline(hosts, host, hostlen, key_type_name,
                               key_type_len, key, keylen, key_type,
                               comment, commentlen);
    }
}
Exemple #21
0
/*
 * libssh2_packet_queue_listener
 *
 * Queue a connection request for a listener
 */
static inline int
packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
                      unsigned long datalen,
                      packet_queue_listener_state_t *listen_state)
{
    /*
     * Look for a matching listener
     */
    /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
    unsigned long packet_len = 17 + (sizeof(FwdNotReq) - 1);
    unsigned char *p;
    LIBSSH2_LISTENER *listn = _libssh2_list_first(&session->listeners);
    char failure_code = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
    int rc;

    (void) datalen;

    if (listen_state->state == libssh2_NB_state_idle) {
        unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5;
        listen_state->sender_channel = _libssh2_ntohu32(s);
        s += 4;

        listen_state->initial_window_size = _libssh2_ntohu32(s);
        s += 4;
        listen_state->packet_size = _libssh2_ntohu32(s);
        s += 4;

        listen_state->host_len = _libssh2_ntohu32(s);
        s += 4;
        listen_state->host = s;
        s += listen_state->host_len;
        listen_state->port = _libssh2_ntohu32(s);
        s += 4;

        listen_state->shost_len = _libssh2_ntohu32(s);
        s += 4;
        listen_state->shost = s;
        s += listen_state->shost_len;
        listen_state->sport = _libssh2_ntohu32(s);

        _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                       "Remote received connection from %s:%ld to %s:%ld",
                       listen_state->shost, listen_state->sport,
                       listen_state->host, listen_state->port);

        listen_state->state = libssh2_NB_state_allocated;
    }

    if (listen_state->state != libssh2_NB_state_sent) {
        while (listn) {
            if ((listn->port == (int) listen_state->port) &&
                (strlen(listn->host) == listen_state->host_len) &&
                (memcmp (listn->host, listen_state->host,
                         listen_state->host_len) == 0)) {
                /* This is our listener */
                LIBSSH2_CHANNEL *channel = NULL;
                listen_state->channel = NULL;

                if (listen_state->state == libssh2_NB_state_allocated) {
                    if (listn->queue_maxsize &&
                        (listn->queue_maxsize <= listn->queue_size)) {
                        /* Queue is full */
                        failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
                        _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                                       "Listener queue full, ignoring");
                        listen_state->state = libssh2_NB_state_sent;
                        break;
                    }

                    channel = LIBSSH2_CALLOC(session, sizeof(LIBSSH2_CHANNEL));
                    if (!channel) {
                        _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                                       "Unable to allocate a channel for "
                                       "new connection");
                        failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
                        listen_state->state = libssh2_NB_state_sent;
                        break;
                    }
                    listen_state->channel = channel;

                    channel->session = session;
                    channel->channel_type_len = sizeof("forwarded-tcpip") - 1;
                    channel->channel_type = LIBSSH2_ALLOC(session,
                                                          channel->
                                                          channel_type_len +
                                                          1);
                    if (!channel->channel_type) {
                        _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                                       "Unable to allocate a channel for new"
                                       " connection");
                        LIBSSH2_FREE(session, channel);
                        failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
                        listen_state->state = libssh2_NB_state_sent;
                        break;
                    }
                    memcpy(channel->channel_type, "forwarded-tcpip",
                           channel->channel_type_len + 1);

                    channel->remote.id = listen_state->sender_channel;
                    channel->remote.window_size_initial =
                        LIBSSH2_CHANNEL_WINDOW_DEFAULT;
                    channel->remote.window_size =
                        LIBSSH2_CHANNEL_WINDOW_DEFAULT;
                    channel->remote.packet_size =
                        LIBSSH2_CHANNEL_PACKET_DEFAULT;

                    channel->local.id = _libssh2_channel_nextid(session);
                    channel->local.window_size_initial =
                        listen_state->initial_window_size;
                    channel->local.window_size =
                        listen_state->initial_window_size;
                    channel->local.packet_size = listen_state->packet_size;

                    _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                                   "Connection queued: channel %lu/%lu "
                                   "win %lu/%lu packet %lu/%lu",
                                   channel->local.id, channel->remote.id,
                                   channel->local.window_size,
                                   channel->remote.window_size,
                                   channel->local.packet_size,
                                   channel->remote.packet_size);

                    p = listen_state->packet;
                    *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
                    _libssh2_store_u32(&p, channel->remote.id);
                    _libssh2_store_u32(&p, channel->local.id);
                    _libssh2_store_u32(&p,
                                       channel->remote.window_size_initial);
                    _libssh2_store_u32(&p, channel->remote.packet_size);

                    listen_state->state = libssh2_NB_state_created;
                }

                if (listen_state->state == libssh2_NB_state_created) {
                    rc = _libssh2_transport_send(session, listen_state->packet,
                                                 17, NULL, 0);
                    if (rc == LIBSSH2_ERROR_EAGAIN)
                        return rc;
                    else if (rc) {
                        listen_state->state = libssh2_NB_state_idle;
                        return _libssh2_error(session, rc,
                                              "Unable to send channel "
                                              "open confirmation");
                    }

                    /* Link the channel into the end of the queue list */
                    if (listen_state->channel) {
                        _libssh2_list_add(&listn->queue,
                                          &listen_state->channel->node);
                        listn->queue_size++;
                    }

                    listen_state->state = libssh2_NB_state_idle;
                    return 0;
                }
            }

            listn = _libssh2_list_next(&listn->node);
        }

        listen_state->state = libssh2_NB_state_sent;
    }

    /* We're not listening to you */
    p = listen_state->packet;
    *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
    _libssh2_store_u32(&p, listen_state->sender_channel);
    _libssh2_store_u32(&p, failure_code);
    _libssh2_store_str(&p, FwdNotReq, sizeof(FwdNotReq) - 1);
    _libssh2_htonu32(p, 0);

    rc = _libssh2_transport_send(session, listen_state->packet,
                                 packet_len, NULL, 0);
    if (rc == LIBSSH2_ERROR_EAGAIN) {
        return rc;
    } else if (rc) {
        listen_state->state = libssh2_NB_state_idle;
        return _libssh2_error(session, rc, "Unable to send open failure");

    }
    listen_state->state = libssh2_NB_state_idle;
    return 0;
}
Exemple #22
0
static int
agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
           const unsigned char *data, size_t data_len, void **abstract)
{
    LIBSSH2_AGENT *agent = (LIBSSH2_AGENT *) (*abstract);
    agent_transaction_ctx_t transctx = &agent->transctx;
    struct agent_publickey *identity = agent->identity;
    ssize_t len = 1 + 4 + identity->external.blob_len + 4 + data_len + 4;
    ssize_t method_len;
    unsigned char *s;
    int rc;

    /* Create a request to sign the data */
    if (transctx->state == agent_NB_state_init) {
        s = transctx->request = LIBSSH2_ALLOC(session, len);
        if (!transctx->request)
            return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                                  "out of memory");

        *s++ = SSH2_AGENTC_SIGN_REQUEST;
        /* key blob */
        _libssh2_store_str(&s, (const char *)identity->external.blob,
                           identity->external.blob_len);
        /* data */
        _libssh2_store_str(&s, (const char *)data, data_len);

        /* flags */
        _libssh2_store_u32(&s, 0);

        transctx->request_len = s - transctx->request;
        transctx->state = agent_NB_state_request_created;
    }

    /* Make sure to be re-called as a result of EAGAIN. */
    if (*transctx->request != SSH2_AGENTC_SIGN_REQUEST)
        return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE,
                              "illegal request");

    if (!agent->ops)
        /* if no agent has been connected, bail out */
        return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE,
                              "agent not connected");

    rc = agent->ops->transact(agent, transctx);
    if (rc) {
        goto error;
    }
    LIBSSH2_FREE(session, transctx->request);
    transctx->request = NULL;

    len = transctx->response_len;
    s = transctx->response;
    len--;
    if (len < 0) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    if (*s != SSH2_AGENT_SIGN_RESPONSE) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    s++;

    /* Skip the entire length of the signature */
    len -= 4;
    if (len < 0) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    s += 4;

    /* Skip signing method */
    len -= 4;
    if (len < 0) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    method_len = _libssh2_ntohu32(s);
    s += 4;
    len -= method_len;
    if (len < 0) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    s += method_len;

    /* Read the signature */
    len -= 4;
    if (len < 0) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    *sig_len = _libssh2_ntohu32(s);
    s += 4;
    len -= *sig_len;
    if (len < 0) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }

    *sig = LIBSSH2_ALLOC(session, *sig_len);
    if (!*sig) {
        rc = LIBSSH2_ERROR_ALLOC;
        goto error;
    }
    memcpy(*sig, s, *sig_len);

  error:
    LIBSSH2_FREE(session, transctx->request);
    transctx->request = NULL;

    LIBSSH2_FREE(session, transctx->response);
    transctx->response = NULL;

    return _libssh2_error(session, rc, "agent sign failure");
}
Exemple #23
0
static int
agent_list_identities(LIBSSH2_AGENT *agent)
{
    agent_transaction_ctx_t transctx = &agent->transctx;
    ssize_t len, num_identities;
    unsigned char *s;
    int rc;

    /* Create a request to list identities */
    if (transctx->state == agent_NB_state_init) {
      unsigned char c = SSH2_AGENTC_REQUEST_IDENTITIES;
      transctx->request = &c;
      transctx->request_len = 1;
      transctx->state = agent_NB_state_request_created;
    }

    /* Make sure to be re-called as a result of EAGAIN. */
    if (*transctx->request != SSH2_AGENTC_REQUEST_IDENTITIES)
        return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE,
                              "illegal agent request");

    if (!agent->ops)
        /* if no agent has been connected, bail out */
        return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE,
                              "agent not connected");

    rc = agent->ops->transact(agent, transctx);
    if (rc) {
        goto error;
    }
    transctx->request = NULL;

    len = transctx->response_len;
    s = transctx->response;
    len--;
    if (len < 0) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    if (*s != SSH2_AGENT_IDENTITIES_ANSWER) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    s++;

    /* Read the length of identities */
    len -= 4;
    if (len < 0) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    num_identities = _libssh2_ntohu32(s);
    s += 4;

    while (num_identities--) {
        struct agent_publickey *identity;
        ssize_t comment_len;

        identity = LIBSSH2_ALLOC(agent->session, sizeof *identity);
        if (!identity) {
            rc = LIBSSH2_ERROR_ALLOC;
            goto error;
        }

        /* Read the length of the blob */
        len -= 4;
        if (len < 0) {
            rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
            goto error;
        }
        identity->external.blob_len = _libssh2_ntohu32(s);
        s += 4;

        /* Read the blob */
        len -= identity->external.blob_len;
        if (len < 0) {
            rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
            goto error;
        }
        identity->external.blob = LIBSSH2_ALLOC(agent->session,
                                                identity->external.blob_len);
        if (!identity->external.blob) {
            rc = LIBSSH2_ERROR_ALLOC;
            goto error;
        }
        memcpy(identity->external.blob, s, identity->external.blob_len);
        s += identity->external.blob_len;

        /* Read the length of the comment */
        len -= 4;
        if (len < 0) {
            rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
            goto error;
        }
        comment_len = _libssh2_ntohu32(s);
        s += 4;

        /* Read the comment */
        len -= comment_len;
        if (len < 0) {
            rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
            goto error;
        }
        identity->external.comment = LIBSSH2_ALLOC(agent->session,
                                                   comment_len + 1);
        if (!identity->external.comment) {
            rc = LIBSSH2_ERROR_ALLOC;
            goto error;
        }
        identity->external.comment[comment_len] = '\0';
        memcpy(identity->external.comment, s, comment_len);
        s += comment_len;

        _libssh2_list_add(&agent->head, &identity->node);
    }
 error:
    LIBSSH2_FREE(agent->session, transctx->response);
    transctx->response = NULL;

    return _libssh2_error(agent->session, rc,
                          "agent list id failed");
}
Exemple #24
0
/*
 * knownhost_check
 *
 * Check a host and its associated key against the collection of known hosts.
 *
 * The typemask is the type/format of the given host name and key
 *
 * plain  - ascii "hostname.domain.tld"
 * sha1   - NOT SUPPORTED AS INPUT
 * custom - prehashed base64 encoded. Note that this cannot use any salts.
 *
 * Returns:
 *
 * LIBSSH2_KNOWNHOST_CHECK_FAILURE
 * LIBSSH2_KNOWNHOST_CHECK_NOTFOUND
 * LIBSSH2_KNOWNHOST_CHECK_MATCH
 * LIBSSH2_KNOWNHOST_CHECK_MISMATCH
 */
static int
knownhost_check(LIBSSH2_KNOWNHOSTS *hosts,
                const char *hostp, int port,
                const char *key, size_t keylen,
                int typemask,
                struct libssh2_knownhost **ext)
{
    struct known_host *node;
    struct known_host *badkey = NULL;
    int type = typemask & LIBSSH2_KNOWNHOST_TYPE_MASK;
    char *keyalloc = NULL;
    int rc = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND;
    char hostbuff[270]; /* most host names can't be longer than like 256 */
    const char *host;
    int numcheck; /* number of host combos to check */
    int match = 0;

    if(type == LIBSSH2_KNOWNHOST_TYPE_SHA1)
        /* we can't work with a sha1 as given input */
        return LIBSSH2_KNOWNHOST_CHECK_MISMATCH;

    /* if a port number is given, check for a '[host]:port' first before the
       plain 'host' */
    if(port >= 0) {
        int len = snprintf(hostbuff, sizeof(hostbuff), "[%s]:%d", hostp, port);
        if (len < 0 || len >= (int)sizeof(hostbuff)) {
            _libssh2_error(hosts->session,
                           LIBSSH2_ERROR_BUFFER_TOO_SMALL,
                           "Known-host write buffer too small");
            return LIBSSH2_KNOWNHOST_CHECK_FAILURE;
        }
        host = hostbuff;
        numcheck = 2; /* check both combos, start with this */
    }
    else {
        host = hostp;
        numcheck = 1; /* only check this host version */
    }

    if(!(typemask & LIBSSH2_KNOWNHOST_KEYENC_BASE64)) {
        /* we got a raw key input, convert it to base64 for the checks below */
        size_t nlen = _libssh2_base64_encode(hosts->session, key, keylen,
                                             &keyalloc);
        if(!nlen) {
            _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
                           "Unable to allocate memory for base64-encoded "
                           "key");
            return LIBSSH2_KNOWNHOST_CHECK_FAILURE;
        }

        /* make the key point to this */
        key = keyalloc;
    }

    do {
        node = _libssh2_list_first(&hosts->head);
        while (node) {
            switch(node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) {
            case LIBSSH2_KNOWNHOST_TYPE_PLAIN:
                if(type == LIBSSH2_KNOWNHOST_TYPE_PLAIN)
                    match = !strcmp(host, node->name);
                break;
            case LIBSSH2_KNOWNHOST_TYPE_CUSTOM:
                if(type == LIBSSH2_KNOWNHOST_TYPE_CUSTOM)
                    match = !strcmp(host, node->name);
                break;
            case LIBSSH2_KNOWNHOST_TYPE_SHA1:
                if(type == LIBSSH2_KNOWNHOST_TYPE_PLAIN) {
                    /* when we have the sha1 version stored, we can use a
                       plain input to produce a hash to compare with the
                       stored hash.
                    */
                    libssh2_hmac_ctx ctx;
                    unsigned char hash[SHA_DIGEST_LENGTH];

                    if(SHA_DIGEST_LENGTH != node->name_len) {
                        /* the name hash length must be the sha1 size or
                           we can't match it */
                        break;
                    }
                    libssh2_hmac_sha1_init(&ctx, (unsigned char *)node->salt,
                                           node->salt_len);
                    libssh2_hmac_update(ctx, (unsigned char *)host,
                                        strlen(host));
                    libssh2_hmac_final(ctx, hash);
                    libssh2_hmac_cleanup(&ctx);

                    if(!memcmp(hash, node->name, SHA_DIGEST_LENGTH))
                        /* this is a node we're interested in */
                        match = 1;
                }
                break;
            default: /* unsupported type */
                break;
            }
            if(match) {
                int host_key_type = typemask & LIBSSH2_KNOWNHOST_KEY_MASK;
                int known_key_type =
                    node->typemask & LIBSSH2_KNOWNHOST_KEY_MASK;
                /* match on key type as follows:
                   - never match on an unknown key type
                   - if key_type is set to zero, ignore it an match always
                   - otherwise match when both key types are equal
                */
                if ( (host_key_type != LIBSSH2_KNOWNHOST_KEY_UNKNOWN ) &&
                     ( (host_key_type == 0) ||
                       (host_key_type == known_key_type) ) ) {
                    /* host name and key type match, now compare the keys */
                    if(!strcmp(key, node->key)) {
                        /* they match! */
                        if (ext)
                            *ext = knownhost_to_external(node);
                        badkey = NULL;
                        rc = LIBSSH2_KNOWNHOST_CHECK_MATCH;
                        break;
                    }
                    else {
                        /* remember the first node that had a host match but a
                           failed key match since we continue our search from
                           here */
                        if(!badkey)
                            badkey = node;
                    }
                }
                match = 0; /* don't count this as a match anymore */
            }
            node= _libssh2_list_next(&node->node);
        }
        host = hostp;
    } while(!match && --numcheck);

    if(badkey) {
        /* key mismatch */
        if (ext)
            *ext = knownhost_to_external(badkey);
        rc = LIBSSH2_KNOWNHOST_CHECK_MISMATCH;
    }

    if(keyalloc)
        LIBSSH2_FREE(hosts->session, keyalloc);

    return rc;
}
Exemple #25
0
/*
 * _libssh2_packet_add
 *
 * Create a new packet and attach it to the brigade. Called from the transport
 * layer when it has received a packet.
 *
 * The input pointer 'data' is pointing to allocated data that this function
 * is asked to deal with so on failure OR success, it must be freed fine.
 * The only exception is when the return code is LIBSSH2_ERROR_EAGAIN.
 *
 * This function will always be called with 'datalen' greater than zero.
 */
int
_libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
                    size_t datalen, int macstate)
{
    int rc = 0;
    char *message=NULL;
    char *language=NULL;
    size_t message_len=0;
    size_t language_len=0;
    LIBSSH2_CHANNEL *channelp = NULL;
    size_t data_head = 0;
    unsigned char msg = data[0];

    switch(session->packAdd_state) {
    case libssh2_NB_state_idle:
        _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
                       "Packet type %d received, length=%d",
                       (int) msg, (int) datalen);

        if ((macstate == LIBSSH2_MAC_INVALID) &&
            (!session->macerror ||
             LIBSSH2_MACERROR(session, (char *) data, datalen))) {
            /* Bad MAC input, but no callback set or non-zero return from the
               callback */

            LIBSSH2_FREE(session, data);
            return _libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
                                  "Invalid MAC received");
        }
        session->packAdd_state = libssh2_NB_state_allocated;
        break;
    case libssh2_NB_state_jump1:
        goto libssh2_packet_add_jump_point1;
    case libssh2_NB_state_jump2:
        goto libssh2_packet_add_jump_point2;
    case libssh2_NB_state_jump3:
        goto libssh2_packet_add_jump_point3;
    case libssh2_NB_state_jump4:
        goto libssh2_packet_add_jump_point4;
    case libssh2_NB_state_jump5:
        goto libssh2_packet_add_jump_point5;
    default: /* nothing to do */
        break;
    }

    if (session->packAdd_state == libssh2_NB_state_allocated) {
        /* A couple exceptions to the packet adding rule: */
        switch (msg) {

            /*
              byte      SSH_MSG_DISCONNECT
              uint32    reason code
              string    description in ISO-10646 UTF-8 encoding [RFC3629]
              string    language tag [RFC3066]
            */

        case SSH_MSG_DISCONNECT:
            if(datalen >= 5) {
                size_t reason = _libssh2_ntohu32(data + 1);

                if(datalen >= 9) {
                    message_len = _libssh2_ntohu32(data + 5);

                    if(message_len < datalen-13) {
                        /* 9 = packet_type(1) + reason(4) + message_len(4) */
                        message = (char *) data + 9;

                        language_len = _libssh2_ntohu32(data + 9 + message_len);
                        language = (char *) data + 9 + message_len + 4;

                        if(language_len > (datalen-13-message_len)) {
                            /* bad input, clear info */
                            language = message = NULL;
                            language_len = message_len = 0;
                        }
                    }
                    else
                        /* bad size, clear it */
                        message_len=0;
                }
                if (session->ssh_msg_disconnect) {
                    LIBSSH2_DISCONNECT(session, reason, message,
                                       message_len, language, language_len);
                }
                _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
                               "Disconnect(%d): %s(%s)", reason,
                               message, language);
            }

            LIBSSH2_FREE(session, data);
            session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
            session->packAdd_state = libssh2_NB_state_idle;
            return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
                                  "socket disconnect");
            /*
              byte      SSH_MSG_IGNORE
              string    data
            */

        case SSH_MSG_IGNORE:
            if (datalen >= 2) {
                if (session->ssh_msg_ignore) {
                    LIBSSH2_IGNORE(session, (char *) data + 1, datalen - 1);
                }
            } else if (session->ssh_msg_ignore) {
                LIBSSH2_IGNORE(session, "", 0);
            }
            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return 0;

            /*
              byte      SSH_MSG_DEBUG
              boolean   always_display
              string    message in ISO-10646 UTF-8 encoding [RFC3629]
              string    language tag [RFC3066]
            */

        case SSH_MSG_DEBUG:
            if(datalen >= 2) {
                int always_display= data[1];

                if(datalen >= 6) {
                    message_len = _libssh2_ntohu32(data + 2);

                    if(message_len <= (datalen - 10)) {
                        /* 6 = packet_type(1) + display(1) + message_len(4) */
                        message = (char *) data + 6;
                        language_len = _libssh2_ntohu32(data + 6 + message_len);

                        if(language_len <= (datalen - 10 - message_len))
                            language = (char *) data + 10 + message_len;
                    }
                }

                if (session->ssh_msg_debug) {
                    LIBSSH2_DEBUG(session, always_display, message,
                                  message_len, language, language_len);
                }
            }
            /*
             * _libssh2_debug will actually truncate this for us so
             * that it's not an inordinate about of data
             */
            _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
                           "Debug Packet: %s", message);
            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return 0;

            /*
              byte      SSH_MSG_GLOBAL_REQUEST
              string    request name in US-ASCII only
              boolean   want reply
              ....      request-specific data follows
            */

        case SSH_MSG_GLOBAL_REQUEST:
            if(datalen >= 5) {
                uint32_t len =0;
                unsigned char want_reply=0;
                len = _libssh2_ntohu32(data + 1);
                if(datalen >= (6 + len)) {
                    want_reply = data[5 + len];
                    _libssh2_debug(session,
                                   LIBSSH2_TRACE_CONN,
                                   "Received global request type %.*s (wr %X)",
                                   len, data + 5, want_reply);
                }


                if (want_reply) {
                    static const unsigned char packet =
                        SSH_MSG_REQUEST_FAILURE;
                  libssh2_packet_add_jump_point5:
                    session->packAdd_state = libssh2_NB_state_jump5;
                    rc = _libssh2_transport_send(session, &packet, 1, NULL, 0);
                    if (rc == LIBSSH2_ERROR_EAGAIN)
                        return rc;
                }
            }
            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return 0;

            /*
              byte      SSH_MSG_CHANNEL_EXTENDED_DATA
              uint32    recipient channel
              uint32    data_type_code
              string    data
            */

        case SSH_MSG_CHANNEL_EXTENDED_DATA:
            /* streamid(4) */
            data_head += 4;

            /* fall-through */

            /*
              byte      SSH_MSG_CHANNEL_DATA
              uint32    recipient channel
              string    data
            */

        case SSH_MSG_CHANNEL_DATA:
            /* packet_type(1) + channelno(4) + datalen(4) */
            data_head += 9;

            if(datalen >= data_head)
                channelp =
                    _libssh2_channel_locate(session,
                                            _libssh2_ntohu32(data + 1));

            if (!channelp) {
                _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN,
                               "Packet received for unknown channel");
                LIBSSH2_FREE(session, data);
                session->packAdd_state = libssh2_NB_state_idle;
                return 0;
            }
#ifdef LIBSSH2DEBUG
            {
                uint32_t stream_id = 0;
                if (msg == SSH_MSG_CHANNEL_EXTENDED_DATA)
                    stream_id = _libssh2_ntohu32(data + 5);

                _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                               "%d bytes packet_add() for %lu/%lu/%lu",
                               (int) (datalen - data_head),
                               channelp->local.id,
                               channelp->remote.id,
                               stream_id);
            }
#endif
            if ((channelp->remote.extended_data_ignore_mode ==
                 LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) &&
                (msg == SSH_MSG_CHANNEL_EXTENDED_DATA)) {
                /* Pretend we didn't receive this */
                LIBSSH2_FREE(session, data);

                _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                               "Ignoring extended data and refunding %d bytes",
                               (int) (datalen - 13));
                if (channelp->read_avail + datalen - data_head >=
                    channelp->remote.window_size)
                    datalen = channelp->remote.window_size -
                        channelp->read_avail + data_head;

                channelp->remote.window_size -= datalen - data_head;
                _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                               "shrinking window size by %lu bytes to %lu, read_avail %lu",
                               datalen - data_head,
                               channelp->remote.window_size,
                               channelp->read_avail);

                session->packAdd_channelp = channelp;

                /* Adjust the window based on the block we just freed */
              libssh2_packet_add_jump_point1:
                session->packAdd_state = libssh2_NB_state_jump1;
                rc = _libssh2_channel_receive_window_adjust(session->
                                                            packAdd_channelp,
                                                            datalen - 13,
                                                            1, NULL);
                if (rc == LIBSSH2_ERROR_EAGAIN)
                    return rc;

                session->packAdd_state = libssh2_NB_state_idle;
                return 0;
            }

            /*
             * REMEMBER! remote means remote as source of data,
             * NOT remote window!
             */
            if (channelp->remote.packet_size < (datalen - data_head)) {
                /*
                 * Spec says we MAY ignore bytes sent beyond
                 * packet_size
                 */
                _libssh2_error(session,
                               LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED,
                               "Packet contains more data than we offered"
                               " to receive, truncating");
                datalen = channelp->remote.packet_size + data_head;
            }
            if (channelp->remote.window_size <= channelp->read_avail) {
                /*
                 * Spec says we MAY ignore bytes sent beyond
                 * window_size
                 */
                _libssh2_error(session,
                               LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
                               "The current receive window is full,"
                               " data ignored");
                LIBSSH2_FREE(session, data);
                session->packAdd_state = libssh2_NB_state_idle;
                return 0;
            }
            /* Reset EOF status */
            channelp->remote.eof = 0;

            if (channelp->read_avail + datalen - data_head >
                channelp->remote.window_size) {
                _libssh2_error(session,
                               LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
                               "Remote sent more data than current "
                               "window allows, truncating");
                datalen = channelp->remote.window_size -
                    channelp->read_avail + data_head;
            }

            /* Update the read_avail counter. The window size will be
             * updated once the data is actually read from the queue
             * from an upper layer */
            channelp->read_avail += datalen - data_head;

            _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                           "increasing read_avail by %lu bytes to %lu/%lu",
                           (long)(datalen - data_head),
                           (long)channelp->read_avail,
                           (long)channelp->remote.window_size);

            break;

            /*
              byte      SSH_MSG_CHANNEL_EOF
              uint32    recipient channel
            */

        case SSH_MSG_CHANNEL_EOF:
            if(datalen >= 5)
                channelp =
                    _libssh2_channel_locate(session,
                                            _libssh2_ntohu32(data + 1));
            if (!channelp)
                /* We may have freed already, just quietly ignore this... */
                ;
            else {
                _libssh2_debug(session,
                               LIBSSH2_TRACE_CONN,
                               "EOF received for channel %lu/%lu",
                               channelp->local.id,
                               channelp->remote.id);
                channelp->remote.eof = 1;
            }
            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return 0;

            /*
              byte      SSH_MSG_CHANNEL_REQUEST
              uint32    recipient channel
              string    request type in US-ASCII characters only
              boolean   want reply
              ....      type-specific data follows
            */

        case SSH_MSG_CHANNEL_REQUEST:
            if(datalen >= 9) {
                uint32_t channel = _libssh2_ntohu32(data + 1);
                uint32_t len = _libssh2_ntohu32(data + 5);
                unsigned char want_reply = 1;

                if(len < (datalen - 10))
                    want_reply = data[9 + len];

                _libssh2_debug(session,
                               LIBSSH2_TRACE_CONN,
                               "Channel %d received request type %.*s (wr %X)",
                               channel, len, data + 9, want_reply);

                if (len == sizeof("exit-status") - 1
                    && !memcmp("exit-status", data + 9,
                               sizeof("exit-status") - 1)) {

                    /* we've got "exit-status" packet. Set the session value */
                    if(datalen >= 20)
                        channelp =
                            _libssh2_channel_locate(session, channel);

                    if (channelp) {
                        channelp->exit_status =
                            _libssh2_ntohu32(data + 9 + sizeof("exit-status"));
                        _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                                       "Exit status %lu received for "
                                       "channel %lu/%lu",
                                       channelp->exit_status,
                                       channelp->local.id,
                                       channelp->remote.id);
                    }

                }
                else if (len == sizeof("exit-signal") - 1
                         && !memcmp("exit-signal", data + 9,
                                    sizeof("exit-signal") - 1)) {
                    /* command terminated due to signal */
                    if(datalen >= 20)
                        channelp = _libssh2_channel_locate(session, channel);

                    if (channelp) {
                        /* set signal name (without SIG prefix) */
                        uint32_t namelen =
                            _libssh2_ntohu32(data + 9 + sizeof("exit-signal"));
                        channelp->exit_signal =
                            LIBSSH2_ALLOC(session, namelen + 1);
                        if (!channelp->exit_signal)
                            rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                                                "memory for signal name");
                        else {
                            memcpy(channelp->exit_signal,
                                   data + 13 + sizeof("exit_signal"), namelen);
                            channelp->exit_signal[namelen] = '\0';
                            /* TODO: save error message and language tag */
                            _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                                           "Exit signal %s received for "
                                           "channel %lu/%lu",
                                           channelp->exit_signal,
                                           channelp->local.id,
                                           channelp->remote.id);
                        }
                    }
                }


                if (want_reply) {
                    unsigned char packet[5];
                  libssh2_packet_add_jump_point4:
                    session->packAdd_state = libssh2_NB_state_jump4;
                    packet[0] = SSH_MSG_CHANNEL_FAILURE;
                    memcpy(&packet[1], data+1, 4);
                    rc = _libssh2_transport_send(session, packet, 5, NULL, 0);
                    if (rc == LIBSSH2_ERROR_EAGAIN)
                        return rc;
                }
            }
            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return rc;

            /*
              byte      SSH_MSG_CHANNEL_CLOSE
              uint32    recipient channel
            */

        case SSH_MSG_CHANNEL_CLOSE:
            if(datalen >= 5)
                channelp =
                    _libssh2_channel_locate(session,
                                            _libssh2_ntohu32(data + 1));
            if (!channelp) {
                /* We may have freed already, just quietly ignore this... */
                LIBSSH2_FREE(session, data);
                session->packAdd_state = libssh2_NB_state_idle;
                return 0;
            }
            _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                           "Close received for channel %lu/%lu",
                           channelp->local.id,
                           channelp->remote.id);

            channelp->remote.close = 1;
            channelp->remote.eof = 1;

            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return 0;

            /*
              byte      SSH_MSG_CHANNEL_OPEN
              string    "session"
              uint32    sender channel
              uint32    initial window size
              uint32    maximum packet size
            */

        case SSH_MSG_CHANNEL_OPEN:
            if(datalen < 17)
                ;
            else if ((datalen >= (sizeof("forwarded-tcpip") + 4)) &&
                     ((sizeof("forwarded-tcpip") - 1) ==
                      _libssh2_ntohu32(data + 1))
                     &&
                     (memcmp(data + 5, "forwarded-tcpip",
                             sizeof("forwarded-tcpip") - 1) == 0)) {

                /* init the state struct */
                memset(&session->packAdd_Qlstn_state, 0,
                       sizeof(session->packAdd_Qlstn_state));

              libssh2_packet_add_jump_point2:
                session->packAdd_state = libssh2_NB_state_jump2;
                rc = packet_queue_listener(session, data, datalen,
                                           &session->packAdd_Qlstn_state);
            }
            else if ((datalen >= (sizeof("x11") + 4)) &&
                     ((sizeof("x11") - 1) == _libssh2_ntohu32(data + 1)) &&
                     (memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {

                /* init the state struct */
                memset(&session->packAdd_x11open_state, 0,
                       sizeof(session->packAdd_x11open_state));

              libssh2_packet_add_jump_point3:
                session->packAdd_state = libssh2_NB_state_jump3;
                rc = packet_x11_open(session, data, datalen,
                                     &session->packAdd_x11open_state);
            }
            if (rc == LIBSSH2_ERROR_EAGAIN)
                return rc;

            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return rc;

            /*
              byte      SSH_MSG_CHANNEL_WINDOW_ADJUST
              uint32    recipient channel
              uint32    bytes to add
            */
        case SSH_MSG_CHANNEL_WINDOW_ADJUST:
            if(datalen < 9)
                ;
            else {
                uint32_t bytestoadd = _libssh2_ntohu32(data + 5);
                channelp =
                    _libssh2_channel_locate(session,
                                            _libssh2_ntohu32(data + 1));
                if(channelp) {
                    channelp->local.window_size += bytestoadd;

                    _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                                   "Window adjust for channel %lu/%lu, "
                                   "adding %lu bytes, new window_size=%lu",
                                   channelp->local.id,
                                   channelp->remote.id,
                                   bytestoadd,
                                   channelp->local.window_size);
                }
            }
            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return 0;
        default:
            break;
        }

        session->packAdd_state = libssh2_NB_state_sent;
    }

    if (session->packAdd_state == libssh2_NB_state_sent) {
        LIBSSH2_PACKET *packetp =
            LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
        if (!packetp) {
            _libssh2_debug(session, LIBSSH2_ERROR_ALLOC,
                           "memory for packet");
            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return LIBSSH2_ERROR_ALLOC;
        }
        packetp->data = data;
        packetp->data_len = datalen;
        packetp->data_head = data_head;

        _libssh2_list_add(&session->packets, &packetp->node);

        session->packAdd_state = libssh2_NB_state_sent1;
    }

    if ((msg == SSH_MSG_KEXINIT &&
         !(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) ||
        (session->packAdd_state == libssh2_NB_state_sent2)) {
        if (session->packAdd_state == libssh2_NB_state_sent1) {
            /*
             * Remote wants new keys
             * Well, it's already in the brigade,
             * let's just call back into ourselves
             */
            _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Renegotiating Keys");

            session->packAdd_state = libssh2_NB_state_sent2;
        }

        /*
         * The KEXINIT message has been added to the queue.  The packAdd and
         * readPack states need to be reset because _libssh2_kex_exchange
         * (eventually) calls upon _libssh2_transport_read to read the rest of
         * the key exchange conversation.
         */
        session->readPack_state = libssh2_NB_state_idle;
        session->packet.total_num = 0;
        session->packAdd_state = libssh2_NB_state_idle;
        session->fullpacket_state = libssh2_NB_state_idle;

        memset(&session->startup_key_state, 0, sizeof(key_exchange_state_t));

        /*
         * If there was a key reexchange failure, let's just hope we didn't
         * send NEWKEYS yet, otherwise remote will drop us like a rock
         */
        rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state);
        if (rc == LIBSSH2_ERROR_EAGAIN)
            return rc;
    }

    session->packAdd_state = libssh2_NB_state_idle;
    return 0;
}
Exemple #26
0
/*
 * knownhost_writeline()
 *
 * Ask libssh2 to convert a known host to an output line for storage.
 *
 * Note that this function returns LIBSSH2_ERROR_BUFFER_TOO_SMALL if the given
 * output buffer is too small to hold the desired output. The 'outlen' field
 * will then contain the size libssh2 wanted to store, which then is the
 * smallest sufficient buffer it would require.
 *
 */
static int
knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts,
                    struct known_host *node,
                    char *buf, size_t buflen,
                    size_t *outlen, int type)
{
    size_t required_size;

    const char *key_type_name;
    size_t key_type_len;

    /* we only support this single file type for now, bail out on all other
       attempts */
    if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH)
        return _libssh2_error(hosts->session,
                              LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
                              "Unsupported type of known-host information "
                              "store");

    switch(node->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) {
    case LIBSSH2_KNOWNHOST_KEY_RSA1:
        key_type_name = NULL;
        key_type_len = 0;
        break;
    case LIBSSH2_KNOWNHOST_KEY_SSHRSA:
        key_type_name = "ssh-rsa";
        key_type_len = 7;
        break;
    case LIBSSH2_KNOWNHOST_KEY_SSHDSS:
        key_type_name = "ssh-dss";
        key_type_len = 7;
        break;
    case LIBSSH2_KNOWNHOST_KEY_UNKNOWN:
        key_type_name = node->key_type_name;
        if (key_type_name) {
            key_type_len = node->key_type_len;
            break;
        }
        /* otherwise fallback to default and error */
    default:
        return _libssh2_error(hosts->session,
                              LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
                              "Unsupported type of known-host entry");
    }

    /* When putting together the host line there are three aspects to consider:
       - Hashed (SHA1) or unhashed hostname
       - key name or no key name (RSA1)
       - comment or no comment
      
       This means there are 2^3 different formats:
       ("|1|%s|%s %s %s %s\n", salt, hashed_host, key_name, key, comment)
       ("|1|%s|%s %s %s\n", salt, hashed_host, key_name, key)
       ("|1|%s|%s %s %s\n", salt, hashed_host, key, comment)
       ("|1|%s|%s %s\n", salt, hashed_host, key)
       ("%s %s %s %s\n", host, key_name, key, comment)
       ("%s %s %s\n", host, key_name, key)
       ("%s %s %s\n", host, key, comment)
       ("%s %s\n", host, key)
      
       Even if the buffer is too small, we have to set outlen to the number of
       characters the complete line would have taken.  We also don't write
       anything to the buffer unless we are sure we can write everything to the
       buffer. */

    required_size = strlen(node->key);

    if(key_type_len)
        required_size += key_type_len + 1; /* ' ' = 1 */
    if(node->comment)
        required_size += node->comment_len + 1; /* ' ' = 1 */

    if((node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) ==
       LIBSSH2_KNOWNHOST_TYPE_SHA1) {
        char *namealloc;
        size_t name_base64_len;
        char *saltalloc;
        size_t salt_base64_len;

        name_base64_len = _libssh2_base64_encode(hosts->session, node->name,
                                                 node->name_len, &namealloc);
        if(!name_base64_len)
            return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
                                  "Unable to allocate memory for "
                                  "base64-encoded host name");

        salt_base64_len = _libssh2_base64_encode(hosts->session,
                                                 node->salt, node->salt_len,
                                                 &saltalloc);
        if(!salt_base64_len) {
            LIBSSH2_FREE(hosts->session, namealloc);
            return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
                                  "Unable to allocate memory for "
                                  "base64-encoded salt");
        }

        required_size += salt_base64_len + name_base64_len + 7;
        /* |1| + | + ' ' + \n + \0 = 7 */

        if(required_size <= buflen) {
            if(node->comment && key_type_len)
                snprintf(buf, buflen, "|1|%s|%s %s %s %s\n", saltalloc,
                         namealloc, key_type_name, node->key, node->comment);
            else if (node->comment)
                snprintf(buf, buflen, "|1|%s|%s %s %s\n", saltalloc, namealloc,
                         node->key, node->comment);
            else if (key_type_len)
                snprintf(buf, buflen, "|1|%s|%s %s %s\n", saltalloc, namealloc,
                         key_type_name, node->key);
            else
                snprintf(buf, buflen, "|1|%s|%s %s\n", saltalloc, namealloc,
                         node->key);
        }

        LIBSSH2_FREE(hosts->session, namealloc);
        LIBSSH2_FREE(hosts->session, saltalloc);
    }
    else {
        required_size += node->name_len + 3;
        /* ' ' + '\n' + \0 = 3 */

        if(required_size <= buflen) {
            if(node->comment && key_type_len)
                snprintf(buf, buflen, "%s %s %s %s\n", node->name,
                         key_type_name, node->key, node->comment);
            else if (node->comment)
                snprintf(buf, buflen, "%s %s %s\n", node->name, node->key,
                         node->comment);
            else if (key_type_len)
                snprintf(buf, buflen, "%s %s %s\n", node->name, key_type_name,
                         node->key);
            else
                snprintf(buf, buflen, "%s %s\n", node->name, node->key);
        }
    }

    /* we report the full length of the data with the trailing zero excluded */
    *outlen = required_size-1;

    if(required_size <= buflen)
        return LIBSSH2_ERROR_NONE;
    else
        return _libssh2_error(hosts->session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
                              "Known-host write buffer too small");
}
Exemple #27
0
int
_libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
                          unsigned char **method,
                          size_t *method_len,
                          unsigned char **pubkeydata,
                          size_t *pubkeydata_len,
                          const char *privatekey,
                          const char *passphrase)
{
    int       st;
    BIO*      bp;
    EVP_PKEY* pk;

    _libssh2_debug(session,
                   LIBSSH2_TRACE_AUTH,
                   "Computing public key from private key file: %s",
                   privatekey);

    bp = BIO_new_file(privatekey, "r");
    if (bp == NULL) {
        _libssh2_error(session,
                       LIBSSH2_ERROR_FILE,
                       "Unable to open private key file");
        return -1;
    }
    if (!EVP_get_cipherbyname("des")) {
        /* If this cipher isn't loaded it's a pretty good indication that none
         * are.  I have *NO DOUBT* that there's a better way to deal with this
         * ($#&%#$(%$#( Someone buy me an OpenSSL manual and I'll read up on
         * it.
         */
        OpenSSL_add_all_ciphers();
    }
    BIO_reset(bp);
    pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void*)passphrase);
    BIO_free(bp);

    if (pk == NULL) {
        _libssh2_error(session,
                       LIBSSH2_ERROR_FILE,
                       "Wrong passphrase or invalid/unrecognized "
                       "private key file format");
        return -1;
    }

    switch (pk->type) {
    case EVP_PKEY_RSA :
        st = gen_publickey_from_rsa_evp(
            session, method, method_len, pubkeydata, pubkeydata_len, pk);
        break;

    case EVP_PKEY_DSA :
        st = gen_publickey_from_dsa_evp(
            session, method, method_len, pubkeydata, pubkeydata_len, pk);
        break;

    default :
        st = -1;
        _libssh2_error(session,
                       LIBSSH2_ERROR_FILE,
                       "Unsupported private key file format");
        break;
    }

    EVP_PKEY_free(pk);
    return st;
}
Exemple #28
0
/*
 * knownhost_writeline()
 *
 * Ask libssh2 to convert a known host to an output line for storage.
 *
 * Note that this function returns LIBSSH2_ERROR_BUFFER_TOO_SMALL if the given
 * output buffer is too small to hold the desired output. The 'outlen' field
 * will then contain the size libssh2 wanted to store, which then is the
 * smallest sufficient buffer it would require.
 *
 */
static int
knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts,
                    struct known_host *node,
                    char *buf, size_t buflen,
                    size_t *outlen, int type)
{
    int rc = LIBSSH2_ERROR_NONE;
    int tindex;
    const char *keytypes[4]={
        "", /* not used */
        "", /* this type has no name in the file */
        " ssh-rsa",
        " ssh-dss"
    };
    const char *keytype;
    size_t nlen;
    size_t commentlen = 0;

    /* we only support this single file type for now, bail out on all other
       attempts */
    if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH)
        return _libssh2_error(hosts->session,
                              LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
                              "Unsupported type of known-host information "
                              "store");

    tindex = (node->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) >>
        LIBSSH2_KNOWNHOST_KEY_SHIFT;

    /* set the string used in the file */
    keytype = keytypes[tindex];

    /* calculate extra space needed for comment */
    if(node->comment)
        commentlen = strlen(node->comment) + 1;

    if((node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) ==
       LIBSSH2_KNOWNHOST_TYPE_SHA1) {
        char *namealloc;
        char *saltalloc;
        nlen = _libssh2_base64_encode(hosts->session, node->name,
                                      node->name_len, &namealloc);
        if(!nlen)
            return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
                                  "Unable to allocate memory for "
                                  "base64-encoded host name");

        nlen = _libssh2_base64_encode(hosts->session,
                                      node->salt, node->salt_len,
                                      &saltalloc);
        if(!nlen) {
            LIBSSH2_FREE(hosts->session, namealloc);
            return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
                                  "Unable to allocate memory for "
                                  "base64-encoded salt");
        }

        nlen = strlen(saltalloc) + strlen(namealloc) + strlen(keytype) +
            strlen(node->key) + commentlen + 7;
        /* |1| + | + ' ' + \n + \0 = 7 */

        if(nlen <= buflen)
            if(node->comment)
                snprintf(buf, buflen, "|1|%s|%s%s %s %s\n", saltalloc, namealloc,
                        keytype, node->key, node->comment);
            else
                snprintf(buf, buflen, "|1|%s|%s%s %s\n", saltalloc, namealloc,
                        keytype, node->key);
        else
            rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
                                "Known-host write buffer too small");

        LIBSSH2_FREE(hosts->session, namealloc);
        LIBSSH2_FREE(hosts->session, saltalloc);
    }
    else {
        nlen = strlen(node->name) + strlen(keytype) + strlen(node->key) +
            commentlen + 3;
        /* ' ' + '\n' + \0 = 3 */
        if(nlen <= buflen)
            /* these types have the plain name */
            if(node->comment)
                snprintf(buf, buflen, "%s%s %s %s\n", node->name, keytype, node->key,
                        node->comment);
            else
                snprintf(buf, buflen, "%s%s %s\n", node->name, keytype, node->key);
        else
            rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
                                "Known-host write buffer too small");
    }

    /* we report the full length of the data with the trailing zero excluded */
    *outlen = nlen-1;

    return rc;
}
Exemple #29
0
static int
knownhost_add(LIBSSH2_KNOWNHOSTS *hosts,
              const char *host, const char *salt,
              const char *key_type_name, size_t key_type_len,
              const char *key, size_t keylen,
              const char *comment, size_t commentlen,
              int typemask, struct libssh2_knownhost **store)
{
    struct known_host *entry;
    size_t hostlen = strlen(host);
    int rc;
    char *ptr;
    unsigned int ptrlen;

    /* make sure we have a key type set */
    if(!(typemask & LIBSSH2_KNOWNHOST_KEY_MASK))
        return _libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL,
                              "No key type set");

    if(!(entry = LIBSSH2_CALLOC(hosts->session, sizeof(struct known_host))))
        return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
                              "Unable to allocate memory for known host "
                              "entry");

    entry->typemask = typemask;

    switch(entry->typemask  & LIBSSH2_KNOWNHOST_TYPE_MASK) {
    case LIBSSH2_KNOWNHOST_TYPE_PLAIN:
    case LIBSSH2_KNOWNHOST_TYPE_CUSTOM:
        entry->name = LIBSSH2_ALLOC(hosts->session, hostlen+1);
        if(!entry->name) {
            rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
                                "Unable to allocate memory for host name");
            goto error;
        }
        memcpy(entry->name, host, hostlen+1);
        entry->name_len = hostlen;
        break;
    case LIBSSH2_KNOWNHOST_TYPE_SHA1:
        rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen,
                                   host, hostlen);
        if(rc)
            goto error;
        entry->name = ptr;
        entry->name_len = ptrlen;

        rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen,
                                   salt, strlen(salt));
        if(rc)
            goto error;
        entry->salt = ptr;
        entry->salt_len = ptrlen;
        break;
    default:
        rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
                            "Unknown host name type");
        goto error;
    }

    if(typemask & LIBSSH2_KNOWNHOST_KEYENC_BASE64) {
        /* the provided key is base64 encoded already */
        if(!keylen)
            keylen = strlen(key);
        entry->key = LIBSSH2_ALLOC(hosts->session, keylen+1);
        if(!entry->key) {
            rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
                                "Unable to allocate memory for key");
            goto error;
        }
        memcpy(entry->key, key, keylen+1);
        entry->key[keylen]=0; /* force a terminating zero trailer */
    }
    else {
        /* key is raw, we base64 encode it and store it as such */
        size_t nlen = _libssh2_base64_encode(hosts->session, key, keylen,
                                             &ptr);
        if(!nlen) {
            rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
                                "Unable to allocate memory for "
                                "base64-encoded key");
            goto error;
        }

        entry->key = ptr;
    }

    if (key_type_name && ((typemask & LIBSSH2_KNOWNHOST_KEY_MASK) ==
                          LIBSSH2_KNOWNHOST_KEY_UNKNOWN)) {
        entry->key_type_name = LIBSSH2_ALLOC(hosts->session, key_type_len+1);
        if (!entry->key_type_name) {
            rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
                                "Unable to allocate memory for key type");
            goto error;
        }
        memcpy(entry->key_type_name, key_type_name, key_type_len);
        entry->key_type_name[key_type_len]=0;
        entry->key_type_len = key_type_len;
    }

    if (comment) {
        entry->comment = LIBSSH2_ALLOC(hosts->session, commentlen+1);
        if(!entry->comment) {
            rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
                                "Unable to allocate memory for comment");
            goto error;
        }
        memcpy(entry->comment, comment, commentlen+1);
        entry->comment[commentlen]=0; /* force a terminating zero trailer */
        entry->comment_len = commentlen;
    }
    else {
        entry->comment = NULL;
    }

    /* add this new host to the big list of known hosts */
    _libssh2_list_add(&hosts->head, &entry->node);

    if(store)
        *store = knownhost_to_external(entry);

    return LIBSSH2_ERROR_NONE;
  error:
    free_host(hosts->session, entry);
    return rc;
}
Exemple #30
0
/*
 * packet_x11_open
 *
 * Accept a forwarded X11 connection
 */
static inline int
packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
                unsigned long datalen,
                packet_x11_open_state_t *x11open_state)
{
    int failure_code = SSH_OPEN_CONNECT_FAILED;
    /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
    unsigned long packet_len = 17 + (sizeof(X11FwdUnAvil) - 1);
    unsigned char *p;
    LIBSSH2_CHANNEL *channel = x11open_state->channel;
    int rc;

    (void) datalen;

    if (x11open_state->state == libssh2_NB_state_idle) {
        unsigned char *s = data + (sizeof("x11") - 1) + 5;
        x11open_state->sender_channel = _libssh2_ntohu32(s);
        s += 4;
        x11open_state->initial_window_size = _libssh2_ntohu32(s);
        s += 4;
        x11open_state->packet_size = _libssh2_ntohu32(s);
        s += 4;
        x11open_state->shost_len = _libssh2_ntohu32(s);
        s += 4;
        x11open_state->shost = s;
        s += x11open_state->shost_len;
        x11open_state->sport = _libssh2_ntohu32(s);

        _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                       "X11 Connection Received from %s:%ld on channel %lu",
                       x11open_state->shost, x11open_state->sport,
                       x11open_state->sender_channel);

        x11open_state->state = libssh2_NB_state_allocated;
    }

    if (session->x11) {
        if (x11open_state->state == libssh2_NB_state_allocated) {
            channel = LIBSSH2_CALLOC(session, sizeof(LIBSSH2_CHANNEL));
            if (!channel) {
                _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                               "allocate a channel for new connection");
                failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
                goto x11_exit;
            }

            channel->session = session;
            channel->channel_type_len = sizeof("x11") - 1;
            channel->channel_type = LIBSSH2_ALLOC(session,
                                                  channel->channel_type_len +
                                                  1);
            if (!channel->channel_type) {
                _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                               "allocate a channel for new connection");
                LIBSSH2_FREE(session, channel);
                failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
                goto x11_exit;
            }
            memcpy(channel->channel_type, "x11",
                   channel->channel_type_len + 1);

            channel->remote.id = x11open_state->sender_channel;
            channel->remote.window_size_initial =
                LIBSSH2_CHANNEL_WINDOW_DEFAULT;
            channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
            channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT;

            channel->local.id = _libssh2_channel_nextid(session);
            channel->local.window_size_initial =
                x11open_state->initial_window_size;
            channel->local.window_size = x11open_state->initial_window_size;
            channel->local.packet_size = x11open_state->packet_size;

            _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                           "X11 Connection established: channel %lu/%lu "
                           "win %lu/%lu packet %lu/%lu",
                           channel->local.id, channel->remote.id,
                           channel->local.window_size,
                           channel->remote.window_size,
                           channel->local.packet_size,
                           channel->remote.packet_size);
            p = x11open_state->packet;
            *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
            _libssh2_store_u32(&p, channel->remote.id);
            _libssh2_store_u32(&p, channel->local.id);
            _libssh2_store_u32(&p, channel->remote.window_size_initial);
            _libssh2_store_u32(&p, channel->remote.packet_size);

            x11open_state->state = libssh2_NB_state_created;
        }

        if (x11open_state->state == libssh2_NB_state_created) {
            rc = _libssh2_transport_send(session, x11open_state->packet, 17,
                                         NULL, 0);
            if (rc == LIBSSH2_ERROR_EAGAIN) {
                return rc;
            } else if (rc) {
                x11open_state->state = libssh2_NB_state_idle;
                return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
                                      "Unable to send channel open "
                                      "confirmation");
            }

            /* Link the channel into the session */
            _libssh2_list_add(&session->channels, &channel->node);

            /*
             * Pass control to the callback, they may turn right around and
             * free the channel, or actually use it
             */
            LIBSSH2_X11_OPEN(channel, (char *)x11open_state->shost,
                             x11open_state->sport);

            x11open_state->state = libssh2_NB_state_idle;
            return 0;
        }
    }
    else
        failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
    /* fall-trough */
  x11_exit:
    p = x11open_state->packet;
    *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
    _libssh2_store_u32(&p, x11open_state->sender_channel);
    _libssh2_store_u32(&p, failure_code);
    _libssh2_store_str(&p, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1);
    _libssh2_htonu32(p, 0);

    rc = _libssh2_transport_send(session, x11open_state->packet, packet_len,
                                 NULL, 0);
    if (rc == LIBSSH2_ERROR_EAGAIN) {
        return rc;
    } else if (rc) {
        x11open_state->state = libssh2_NB_state_idle;
        return _libssh2_error(session, rc, "Unable to send open failure");
    }
    x11open_state->state = libssh2_NB_state_idle;
    return 0;
}