Exemple #1
0
/* {{{ libssh2_session_last_error
 * Returns error code and populates an error string into errmsg
 * If want_buf is non-zero then the string placed into errmsg must be freed by the calling program
 * Otherwise it is assumed to be owned by libssh2
 */
LIBSSH2_API int
libssh2_session_last_error(LIBSSH2_SESSION * session, char **errmsg,
                           int *errmsg_len, int want_buf)
{
    /* No error to report */
    if (!session->err_code) {
        if (errmsg) {
            if (want_buf) {
                *errmsg = LIBSSH2_ALLOC(session, 1);
                if (*errmsg) {
                    **errmsg = 0;
                }
            } else {
                *errmsg = (char *) "";
            }
        }
        if (errmsg_len) {
            *errmsg_len = 0;
        }
        return 0;
    }

    if (errmsg) {
        char *serrmsg = session->err_msg ? session->err_msg : (char *) "";
        int ownbuf = session->err_msg ? session->err_should_free : 0;

        if (want_buf) {
            if (ownbuf) {
                /* Just give the calling program the buffer */
                *errmsg = serrmsg;
                session->err_should_free = 0;
            } else {
                /* Make a copy so the calling program can own it */
                *errmsg = LIBSSH2_ALLOC(session, session->err_msglen + 1);
                if (*errmsg) {
                    memcpy(*errmsg, session->err_msg, session->err_msglen);
                    (*errmsg)[session->err_msglen] = 0;
                }
            }
        } else {
            *errmsg = serrmsg;
        }
    }

    if (errmsg_len) {
        *errmsg_len = session->err_msglen;
    }

    return session->err_code;
}
Exemple #2
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 #3
0
/* {{{ libssh2_banner_set
 * Set the local banner
 */
LIBSSH2_API int
libssh2_banner_set(LIBSSH2_SESSION * session, const char *banner)
{
    int banner_len = banner ? strlen(banner) : 0;

    if (session->local.banner) {
        LIBSSH2_FREE(session, session->local.banner);
        session->local.banner = NULL;
    }

    if (!banner_len) {
        return 0;
    }

    session->local.banner = LIBSSH2_ALLOC(session, banner_len + 3);
    if (!session->local.banner) {
        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                      "Unable to allocate memory for local banner", 0);
        return -1;
    }

    memcpy(session->local.banner, banner, banner_len);
    session->local.banner[banner_len] = '\0';
    _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting local Banner: %s",
                   session->local.banner);
    session->local.banner[banner_len++] = '\r';
    session->local.banner[banner_len++] = '\n';
    session->local.banner[banner_len++] = '\0';

    return 0;
}
Exemple #4
0
/*
 * hostkey_method_ssh_dss_signv
 *
 * Construct a signature from an array of vectors
 */
static int
hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session,
                             unsigned char **signature,
                             unsigned long *signature_len,
                             unsigned long veccount,
                             const struct iovec datavec[],
                             void **abstract)
{
    libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
    unsigned char hash[SHA_DIGEST_LENGTH];
    libssh2_sha1_ctx ctx;
    unsigned int i;

    *signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
    if (!*signature) {
        return -1;
    }

    *signature_len = 2 * SHA_DIGEST_LENGTH;
    memset(*signature, 0, 2 * SHA_DIGEST_LENGTH);

    libssh2_sha1_init(&ctx);
    for(i = 0; i < veccount; i++) {
        libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
    }
    libssh2_sha1_final(ctx, hash);

    if (_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH, *signature)) {
        LIBSSH2_FREE(session, *signature);
        return -1;
    }

    return 0;
}
Exemple #5
0
int
_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
                       libssh2_rsa_ctx * rsactx,
                       const unsigned char *hash,
                       unsigned long hash_len,
                       unsigned char **signature, unsigned long *signature_len)
{
    int ret;
    unsigned char *sig;
    unsigned int sig_len;

    sig_len = RSA_size(rsactx);
    sig = LIBSSH2_ALLOC(session, sig_len);

    if (!sig) {
        return -1;
    }

    ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx);

    if (!ret) {
        LIBSSH2_FREE(session, sig);
        return -1;
    }

    *signature = sig;
    *signature_len = sig_len;

    return 0;
}
Exemple #6
0
static voidpf
libssh2_comp_method_zlib_alloc(voidpf opaque, uInt items, uInt size)
{
    LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque;

    return (voidpf) LIBSSH2_ALLOC(session, items * size);
}
Exemple #7
0
/* {{{ libssh2_comp_method_zlib_init
 * All your bandwidth are belong to us (so save some)
 */
static int
libssh2_comp_method_zlib_init(LIBSSH2_SESSION * session, int compress,
                              void **abstract)
{
    z_stream *strm;
    int status;

    strm = LIBSSH2_ALLOC(session, sizeof(z_stream));
    if (!strm) {
        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                      "Unable to allocate memory for zlib compression/decompression",
                      0);
        return -1;
    }
    memset(strm, 0, sizeof(z_stream));

    strm->opaque = (voidpf) session;
    strm->zalloc = (alloc_func) libssh2_comp_method_zlib_alloc;
    strm->zfree = (free_func) libssh2_comp_method_zlib_free;
    if (compress) {
        /* deflate */
        status = deflateInit(strm, Z_DEFAULT_COMPRESSION);
    } else {
        /* inflate */
        status = inflateInit(strm);
    }

    if (status != Z_OK) {
        LIBSSH2_FREE(session, strm);
        return -1;
    }
    *abstract = strm;

    return 0;
}
Exemple #8
0
/* {{{ libssh2_publickey_packet_receive
 * Read a packet from the subsystem
 */
static int libssh2_publickey_packet_receive(LIBSSH2_PUBLICKEY *pkey, unsigned char **data, unsigned long *data_len)
{
	LIBSSH2_CHANNEL *channel = pkey->channel;
	LIBSSH2_SESSION *session = channel->session;
	unsigned char buffer[4];
	unsigned long packet_len;
	unsigned char *packet;

	if (libssh2_channel_read(channel, buffer, 4) != 4) {
		libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid response from publickey subsystem", 0);
		return -1;
	}

	packet_len = libssh2_ntohu32(buffer);
	packet = LIBSSH2_ALLOC(session, packet_len);
	if (!packet) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate publickey response buffer", 0);
		return -1;
	}

	if (libssh2_channel_read(channel, packet, packet_len) != packet_len) {
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for publickey subsystem response packet", 0);
		LIBSSH2_FREE(session, packet);
		return -1;
	}

	*data = packet;
	*data_len = packet_len;

	return 0;
}
Exemple #9
0
static unsigned char *
gen_publickey_from_rsa(LIBSSH2_SESSION *session, RSA *rsa,
                       size_t *key_len)
{
    int            e_bytes, n_bytes;
    unsigned long  len;
    unsigned char* key;
    unsigned char* p;

    e_bytes = BN_num_bytes(rsa->e) + 1;
    n_bytes = BN_num_bytes(rsa->n) + 1;

    /* Key form is "ssh-rsa" + e + n. */
    len = 4 + 7 + 4 + e_bytes + 4 + n_bytes;

    key = LIBSSH2_ALLOC(session, len);
    if (key == NULL) {
        return NULL;
    }

    /* Process key encoding. */
    p = key;

    _libssh2_htonu32(p, 7);  /* Key type. */
    p += 4;
    memcpy(p, "ssh-rsa", 7);
    p += 7;

    p = write_bn(p, rsa->e, e_bytes);
    p = write_bn(p, rsa->n, n_bytes);

    *key_len = (size_t)(p - key);
    return key;
}
Exemple #10
0
static int
agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
{
    unsigned char buf[4];
    int rc;

    /* Send the length of the request */
    if (transctx->state == agent_NB_state_request_created) {
        _libssh2_htonu32(buf, transctx->request_len);
        rc = send(agent->fd, buf, sizeof buf, 0);
        if (rc < 0) {
            if (errno == EAGAIN)
                return LIBSSH2_ERROR_EAGAIN;
            return -1;
        }
        transctx->state = agent_NB_state_request_length_sent;
    }

    /* Send the request body */
    if (transctx->state == agent_NB_state_request_length_sent) {
        rc = send(agent->fd, transctx->request,
                  transctx->request_len, 0);
        if (rc < 0) {
            if (errno == EAGAIN)
                return LIBSSH2_ERROR_EAGAIN;
            return -1;
        }
        transctx->state = agent_NB_state_request_sent;
    }

    /* Receive the length of a response */
    if (transctx->state == agent_NB_state_request_sent) {
        rc = recv(agent->fd, buf, sizeof buf, 0);
        if (rc < 0) {
            if (errno == EAGAIN)
                return LIBSSH2_ERROR_EAGAIN;
            return -1;
        }
        transctx->response_len = _libssh2_ntohu32(buf);
        transctx->response = LIBSSH2_ALLOC(agent->session,
                                           transctx->response_len);
        if (!transctx->response) {
            return LIBSSH2_ERROR_ALLOC;
        }
        transctx->state = agent_NB_state_response_length_received;
    }

    /* Receive the response body */
    if (transctx->state == agent_NB_state_response_length_received) {
        rc = recv(agent->fd, transctx->response, transctx->response_len, 0);
        if (rc < 0) {
            if (errno == EAGAIN)
                return LIBSSH2_ERROR_EAGAIN;
            return -1;
        }
        transctx->state = agent_NB_state_response_received;
    }

    return 0;
}
Exemple #11
0
int
_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
                       libssh2_rsa_ctx * rsactx,
                       const unsigned char *hash,
                       size_t hash_len,
                       unsigned char **signature, size_t *signature_len)
{
    gcry_sexp_t sig_sexp;
    gcry_sexp_t data;
    int rc;
    const char *tmp;
    size_t size;

    if(hash_len != SHA_DIGEST_LENGTH) {
        return -1;
    }

    if(gcry_sexp_build(&data, NULL,
                        "(data (flags pkcs1) (hash sha1 %b))",
                        hash_len, hash)) {
        return -1;
    }

    rc = gcry_pk_sign(&sig_sexp, data, rsactx);

    gcry_sexp_release(data);

    if(rc != 0) {
        return -1;
    }

    data = gcry_sexp_find_token(sig_sexp, "s", 0);
    if(!data) {
        return -1;
    }

    tmp = gcry_sexp_nth_data(data, 1, &size);
    if(!tmp) {
        return -1;
    }

    if(tmp[0] == '\0') {
        tmp++;
        size--;
    }

    *signature = LIBSSH2_ALLOC(session, size);
    if(!*signature) {
        return -1;
    }
    memcpy(*signature, tmp, size);
    *signature_len = size;

    return rc;
}
Exemple #12
0
static unsigned char *
gen_publickey_from_dsa(LIBSSH2_SESSION* session, DSA *dsa,
                       size_t *key_len)
{
    int            p_bytes, q_bytes, g_bytes, k_bytes;
    unsigned long  len;
    unsigned char *key;
    unsigned char *p;

    const BIGNUM * p_bn;
    const BIGNUM * q;
    const BIGNUM * g;
    const BIGNUM * pub_key;
#ifdef HAVE_OPAQUE_STRUCTS
    DSA_get0_pqg(dsa, &p_bn, &q, &g);
#else
    p_bn = dsa->p;
    q = dsa->q;
    g = dsa->g;
#endif

#ifdef HAVE_OPAQUE_STRUCTS
    DSA_get0_key(dsa, &pub_key, NULL);
#else
    pub_key = dsa->pub_key;
#endif
    p_bytes = BN_num_bytes(p_bn) + 1;
    q_bytes = BN_num_bytes(q) + 1;
    g_bytes = BN_num_bytes(g) + 1;
    k_bytes = BN_num_bytes(pub_key) + 1;

    /* Key form is "ssh-dss" + p + q + g + pub_key. */
    len = 4 + 7 + 4 + p_bytes + 4 + q_bytes + 4 + g_bytes + 4 + k_bytes;

    key = LIBSSH2_ALLOC(session, len);
    if(key == NULL) {
        return NULL;
    }

    /* Process key encoding. */
    p = key;

    _libssh2_htonu32(p, 7);  /* Key type. */
    p += 4;
    memcpy(p, "ssh-dss", 7);
    p += 7;

    p = write_bn(p, p_bn, p_bytes);
    p = write_bn(p, q, q_bytes);
    p = write_bn(p, g, g_bytes);
    p = write_bn(p, pub_key, k_bytes);

    *key_len = (size_t)(p - key);
    return key;
}
Exemple #13
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 #14
0
/* {{{ proto libssh2_userauth_list
 * List authentication methods
 * Will yield successful login if "none" happens to be allowable for this user
 * Not a common configuration for any SSH server though
 * username should be NULL, or a null terminated string
 */
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, unsigned int username_len)
{
	unsigned char reply_codes[3] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
	unsigned long data_len = username_len + 31; /* packet_type(1) + username_len(4) + service_len(4) + service(14)"ssh-connection" +
												   method_len(4) + method(4)"none" */
	unsigned long methods_len;
	unsigned char *data, *s;

	s = data = LIBSSH2_ALLOC(session, data_len);
	if (!data) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for userauth_list", 0);
		return NULL;
	}

	*(s++) = SSH_MSG_USERAUTH_REQUEST;
	libssh2_htonu32(s, username_len);				s += 4;
	if (username) {
		memcpy(s, username, username_len);			s += username_len;
	}

	libssh2_htonu32(s, 14);							s += 4;
	memcpy(s, "ssh-connection", 14);				s += 14;

	libssh2_htonu32(s, 4);							s += 4;
	memcpy(s, "none", 4);							s += 4;

	if (libssh2_packet_write(session, data, data_len)) {
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-none request", 0);
		LIBSSH2_FREE(session, data);
		return NULL;
	}
	LIBSSH2_FREE(session, data);

	if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
		return NULL;
	}

	if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
		/* Wow, who'dve thought... */
		LIBSSH2_FREE(session, data);
		session->state |= LIBSSH2_STATE_AUTHENTICATED;
		return NULL;
	}

	methods_len = libssh2_ntohu32(data + 1);
	memcpy(data, data + 5, methods_len);
	data[methods_len] = '\0';
#ifdef LIBSSH2_DEBUG_USERAUTH
	_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Permitted auth methods: %s", data);
#endif
	return (char *)data;
}
Exemple #15
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)
        return NULL;

    knh->session = session;

    _libssh2_list_init(&knh->head);

    return knh;
}
Exemple #16
0
int
_libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION *session,
                              libssh2_rsa_ctx *rsa,
                              const unsigned char *hash,
                              size_t hash_len,
                              unsigned char **signature,
                              size_t *signature_len)
{
    BCRYPT_PKCS1_PADDING_INFO paddingInfo;
    unsigned char *data, *sig;
    unsigned long cbData, datalen, siglen;
    int ret;

    datalen = (unsigned long)hash_len;
    data = malloc(datalen);
    if (!data) {
        return -1;
    }

    paddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM;

    memcpy(data, hash, datalen);

    ret = BCryptSignHash(rsa->hKey, &paddingInfo,
                         data, datalen, NULL, 0,
                         &cbData, BCRYPT_PAD_PKCS1);
    if (BCRYPT_SUCCESS(ret)) {
        siglen = cbData;
        sig = LIBSSH2_ALLOC(session, siglen);
        if (sig) {
            ret = BCryptSignHash(rsa->hKey, &paddingInfo,
                                 data, datalen, sig, siglen,
                                 &cbData, BCRYPT_PAD_PKCS1);
            if (BCRYPT_SUCCESS(ret)) {
                *signature_len = siglen;
                *signature = sig;
            } else {
                LIBSSH2_FREE(session, sig);
            }
        } else
            ret = STATUS_NO_MEMORY;
    }

    free(data);

    return BCRYPT_SUCCESS(ret) ? 0 : -1;
}
Exemple #17
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 #18
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 #19
0
/* {{{ libssh2_publickey_remove_ex
 * Remove an existing publickey so that authentication can no longer be performed using it
 */
LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
                                                            const unsigned char *blob, unsigned long blob_len)
{
	LIBSSH2_CHANNEL *channel = pkey->channel;
	LIBSSH2_SESSION *session = channel->session;
	unsigned char *s, *packet = NULL;
	unsigned long packet_len = 22 + name_len + blob_len;
	/*	packet_len(4) + 
		remove_len(4) +
		"remove"(6) +
		name_len(4) +
		{name}
		blob_len(4) +
		{blob} */

	packet = LIBSSH2_ALLOC(session, packet_len);
	if (!packet) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey \"remove\" packet", 0);
		return -1;
	}

	s = packet;
	libssh2_htonu32(s, packet_len - 4);							s += 4;
	libssh2_htonu32(s, sizeof("remove") - 1);					s += 4;
	memcpy(s, "remove", sizeof("remove") - 1);					s += sizeof("remove") - 1;
	libssh2_htonu32(s, name_len);								s += 4;
	memcpy(s, name, name_len);									s += name_len;
	libssh2_htonu32(s, blob_len);								s += 4;
	memcpy(s, blob, blob_len);									s += blob_len;

#ifdef LIBSSH2_DEBUG_PUBLICKEY
	_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"remove\" packet: type=%s blob_len=%ld", name, blob_len);
#endif
    if ((s - packet) != libssh2_channel_write(channel, packet, (s - packet))) {
        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey remove packet", 0);
		LIBSSH2_FREE(session, packet);
		return -1;
    }
	LIBSSH2_FREE(session, packet);
	packet = NULL;

	return libssh2_publickey_response_success(pkey);
}
Exemple #20
0
static unsigned char *
gen_publickey_from_rsa(LIBSSH2_SESSION *session, RSA *rsa,
                       size_t *key_len)
{
    int            e_bytes, n_bytes;
    unsigned long  len;
    unsigned char *key;
    unsigned char *p;
    const BIGNUM * e;
    const BIGNUM * n;
#ifdef HAVE_OPAQUE_STRUCTS
    RSA_get0_key(rsa, &n, &e, NULL);
#else
    e = rsa->e;
    n = rsa->n;
#endif
    e_bytes = BN_num_bytes(e) + 1;
    n_bytes = BN_num_bytes(n) + 1;

    /* Key form is "ssh-rsa" + e + n. */
    len = 4 + 7 + 4 + e_bytes + 4 + n_bytes;

    key = LIBSSH2_ALLOC(session, len);
    if(key == NULL) {
        return NULL;
    }

    /* Process key encoding. */
    p = key;

    _libssh2_htonu32(p, 7);  /* Key type. */
    p += 4;
    memcpy(p, "ssh-rsa", 7);
    p += 7;

    p = write_bn(p, e, e_bytes);
    p = write_bn(p, n, n_bytes);

    *key_len = (size_t)(p - key);
    return key;
}
Exemple #21
0
static void libssh2_publickey_status_error(LIBSSH2_PUBLICKEY *pkey, LIBSSH2_SESSION *session, int status, unsigned char *message, int message_len)
{
	char *status_text;
	int status_text_len;
	char *m, *s;
	int m_len;

	/* GENERAL_FAILURE got remapped between version 1 and 2 */
	if (status == 6 && pkey && pkey->version == 1) {
		status = 7;
	}

	if (status < 0 || status > LIBSSH2_PUBLICKEY_STATUS_CODE_MAX) {
		status_text = "unknown";
		status_text_len = sizeof("unknown") - 1;
	} else {
		status_text = libssh2_publickey_status_codes[status].name;
		status_text_len = libssh2_publickey_status_codes[status].name_len;
	}

	m_len = (sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1) + status_text_len + 
			(sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1) + message_len +
			(sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END) - 1);
	m = LIBSSH2_ALLOC(session, m_len + 1);
	if (!m) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for status message", 0);
		return;
	}
	s = m;
	memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_START, sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1);
															s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1;
	memcpy(s, status_text, status_text_len);				s += status_text_len;
	memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_MID, sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1);
															s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1;
	memcpy(s, message, message_len);						s += message_len;
	memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_END, sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END) - 1);
															s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END);
	libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, m, 1);
}
Exemple #22
0
static unsigned char *
gen_publickey_from_dsa(LIBSSH2_SESSION* session, DSA *dsa,
                       size_t *key_len)
{
    int            p_bytes, q_bytes, g_bytes, k_bytes;
    unsigned long  len;
    unsigned char* key;
    unsigned char* p;

    p_bytes = BN_num_bytes(dsa->p) + 1;
    q_bytes = BN_num_bytes(dsa->q) + 1;
    g_bytes = BN_num_bytes(dsa->g) + 1;
    k_bytes = BN_num_bytes(dsa->pub_key) + 1;

    /* Key form is "ssh-dss" + p + q + g + pub_key. */
    len = 4 + 7 + 4 + p_bytes + 4 + q_bytes + 4 + g_bytes + 4 + k_bytes;

    key = LIBSSH2_ALLOC(session, len);
    if (key == NULL) {
        return NULL;
    }

    /* Process key encoding. */
    p = key;

    _libssh2_htonu32(p, 7);  /* Key type. */
    p += 4;
    memcpy(p, "ssh-dss", 7);
    p += 7;

    p = write_bn(p, dsa->p, p_bytes);
    p = write_bn(p, dsa->q, q_bytes);
    p = write_bn(p, dsa->g, g_bytes);
    p = write_bn(p, dsa->pub_key, k_bytes);

    *key_len = (size_t)(p - key);
    return key;
}
Exemple #23
0
static int
_libssh2_init(LIBSSH2_SESSION * session,
              const LIBSSH2_CRYPT_METHOD * method,
              unsigned char *iv, int *free_iv,
              unsigned char *secret, int *free_secret,
              int encrypt, void **abstract)
{
    struct crypt_ctx *ctx = LIBSSH2_ALLOC(session,
                                          sizeof(struct crypt_ctx));
    if (!ctx) {
        return -1;
    }
    ctx->encrypt = encrypt;
    ctx->algo = method->algo;
    if (_libssh2_cipher_init(&ctx->h, ctx->algo, iv, secret, encrypt)) {
        LIBSSH2_FREE(session, ctx);
        return -1;
    }
    *abstract = ctx;
    *free_iv = 1;
    *free_secret = 1;
    return 0;
}
Exemple #24
0
/* {{{ libssh2_packet_read
 * Collect a packet into the input brigade
 * block only controls whether or not to wait for a packet to start,
 * Once a packet starts, libssh2 will block until it is complete
 * Returns packet type added to input brigade (0 if nothing added), or -1 on failure
 */
int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
{
	int packet_type = -1;

	if (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
		return 0;
	}

#ifndef WIN32
	fcntl(session->socket_fd, F_SETFL, O_NONBLOCK);
#else
	{
		u_long non_block = TRUE;
		ioctlsocket(session->socket_fd, FIONBIO, &non_block);
	}
#endif

#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Checking for packet: will%s block", should_block ? "" : " not");
#endif
	if (session->state & LIBSSH2_STATE_NEWKEYS) {
		/* Temporary Buffer
		 * The largest blocksize (currently) is 32, the largest MAC (currently) is 20
		 */
		unsigned char block[2 * 32], *payload, *s, tmp[6];
		long read_len;
		unsigned long blocksize = session->remote.crypt->blocksize;
		unsigned long packet_len, payload_len;
		int padding_len;
		int macstate;
		int free_payload = 1;
		/* Safely ignored in CUSTOM cipher mode */
		EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)session->remote.crypt_abstract;

		/* Note: If we add any cipher with a blocksize less than 6 we'll need to get more creative with this
		 * For now, all blocksize sizes are 8+
		 */
		if (should_block) {
			read_len = libssh2_blocking_read(session, block, blocksize);
		} else {
			read_len = recv(session->socket_fd, block, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
			if (read_len <= 0) {
				return 0;
			}
			read_len += libssh2_blocking_read(session, block + read_len, blocksize - read_len);
		}
		if (read_len < blocksize) {
			return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
		}

		if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
			EVP_Cipher(ctx, block + blocksize, block, blocksize);
			memcpy(block, block + blocksize, blocksize);
		} else {
			if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
				libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
				return -1;
			}
		}

		packet_len = libssh2_ntohu32(block);
		padding_len = block[4];
#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Processing packet %lu bytes long (with %lu bytes padding)", packet_len, padding_len);
#endif
		memcpy(tmp, block, 5); /* Use this for MAC later */

		payload_len = packet_len - 1; /* padding_len(1) */
		/* Sanity Check */
		if ((payload_len > LIBSSH2_PACKET_MAXPAYLOAD) ||
			((packet_len + 4) % blocksize)) {
			/* If something goes horribly wrong during the decryption phase, just bailout and die gracefully */
			session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
			libssh2_error(session, LIBSSH2_ERROR_PROTO, "Fatal protocol error, invalid payload size", 0);
			return -1;
		}

		s = payload = LIBSSH2_ALLOC(session, payload_len);
		memcpy(s, block + 5, blocksize - 5);
		s += blocksize - 5;

		while ((s - payload) < payload_len) {
			read_len = libssh2_blocking_read(session, block, blocksize);
			if (read_len < blocksize) {
				LIBSSH2_FREE(session, payload);
				return -1;
			}
			if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
				EVP_Cipher(ctx, block + blocksize, block, blocksize);
				memcpy(s, block + blocksize, blocksize);
			} else {
				if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
					libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
					LIBSSH2_FREE(session, payload);
					return -1;
				}
				memcpy(s, block, blocksize);
			}

			s += blocksize;
		}

		read_len = libssh2_blocking_read(session, block, session->remote.mac->mac_len);
		if (read_len < session->remote.mac->mac_len) {
			LIBSSH2_FREE(session, payload);
			return -1;
		}

		/* Calculate MAC hash */
 		session->remote.mac->hash(session, block + session->remote.mac->mac_len, session->remote.seqno, tmp, 5, payload, payload_len, &session->remote.mac_abstract);

		macstate =  (strncmp(block, block + session->remote.mac->mac_len, session->remote.mac->mac_len) == 0) ? LIBSSH2_MAC_CONFIRMED : LIBSSH2_MAC_INVALID;

		session->remote.seqno++;

		/* Ignore padding */
		payload_len -= padding_len;

		if (session->remote.comp &&
			strcmp(session->remote.comp->name, "none")) {
			/* Decompress */
			unsigned char *data;
			unsigned long data_len;

			if (session->remote.comp->comp(session, 0, &data, &data_len, LIBSSH2_PACKET_MAXDECOMP, &free_payload, payload, payload_len, &session->remote.comp_abstract)) {
				LIBSSH2_FREE(session, payload);
				return -1;
			}
#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Payload decompressed: %lu bytes(compressed) to %lu bytes(uncompressed)", data_len, payload_len);
#endif
			if (free_payload) {
				LIBSSH2_FREE(session, payload);
				payload = data;
				payload_len = data_len;
			} else {
				if (data == payload) {
					/* It's not to be freed, because the compression layer reused payload,
					 * So let's do the same!
					 */
					payload_len = data_len;
				} else {
					/* No comp_method actually lets this happen, but let's prepare for the future */

					LIBSSH2_FREE(session, payload);

					/* We need a freeable struct otherwise the brigade won't know what to do with it */
					payload = LIBSSH2_ALLOC(session, data_len);
					if (!payload) {
						libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for copy of uncompressed data", 0);
						return -1;
					}
					memcpy(payload, data, data_len);
					payload_len = data_len;
				}
			}
		}

		packet_type = payload[0];
		libssh2_packet_add(session, payload, payload_len, macstate);

	} else { /* No cipher active */
		unsigned char *payload;
		unsigned char buf[24];
		unsigned long buf_len, payload_len;
		unsigned long packet_length;
		unsigned long padding_length;

		if (should_block) {
			buf_len = libssh2_blocking_read(session, buf, 5);
		} else {
			buf_len = recv(session->socket_fd, buf, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
			if (buf_len <= 0) {
				return 0;
			}
			buf_len += libssh2_blocking_read(session, buf, 5 - buf_len);
		}
		if (buf_len < 5) {
			/* Something bad happened */
			return -1;
		}
		packet_length = libssh2_ntohu32(buf);
		padding_length = buf[4];
#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Processing plaintext packet %lu bytes long (with %lu bytes padding)", packet_length, padding_length);
#endif

		payload_len = packet_length - padding_length - 1; /* padding_length(1) */
		payload = LIBSSH2_ALLOC(session, payload_len);
		if (!payload) {
			libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for copy of plaintext data", 0);
			return -1;
		}

		if (libssh2_blocking_read(session, payload, payload_len) < payload_len) {
			return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
		}
		while (padding_length) {
			int l;
			/* Flush padding */
			l = libssh2_blocking_read(session, buf, padding_length);
			if (l > 0)
				padding_length -= l;
			else
				break;
		}

		packet_type = payload[0];

		/* MACs don't exist in non-encrypted mode */
		libssh2_packet_add(session, payload, payload_len, LIBSSH2_MAC_CONFIRMED);
		session->remote.seqno++;
	}
	return packet_type;
}
Exemple #25
0
/* {{{ libssh2_packet_queue_listener
 * Queue a connection request for a listener
 */
inline int libssh2_packet_queue_listener(LIBSSH2_SESSION *session, unsigned char *data, unsigned long datalen)
{
	/* Look for a matching listener */
	unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5;
	unsigned long packet_len = 17 + (sizeof("Forward not requested") - 1);
	unsigned char *p, packet[17 + (sizeof("Forward not requested") - 1)];
					/* packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
	LIBSSH2_LISTENER *l = session->listeners;
	char failure_code = 1; /* SSH_OPEN_ADMINISTRATIVELY_PROHIBITED */
	unsigned long sender_channel, initial_window_size, packet_size;
	unsigned char *host, *shost;
	unsigned long port, sport, host_len, shost_len;

	sender_channel = libssh2_ntohu32(s);		s += 4;

	initial_window_size = libssh2_ntohu32(s);	s += 4;
	packet_size = libssh2_ntohu32(s);			s += 4;

	host_len = libssh2_ntohu32(s);				s += 4;
	host = s;									s += host_len;
	port = libssh2_ntohu32(s);					s += 4;

	shost_len = libssh2_ntohu32(s);				s += 4;
	shost = s;									s += shost_len;
	sport = libssh2_ntohu32(s);					s += 4;

#ifdef LIBSSH2_DEBUG_CONNECTION
	_libssh2_debug(session, LIBSSH2_DBG_CONN, "Remote received connection from %s:%ld to %s:%ld", shost, sport, host, port);
#endif
	while (l) {
		if ((l->port == port) &&
			(strlen(l->host) == host_len) &&
			(memcmp(l->host, host, host_len) == 0)) {
			/* This is our listener */
			LIBSSH2_CHANNEL *channel, *last_queued = l->queue;

			if (l->queue_maxsize &&
				(l->queue_maxsize <= l->queue_size)) {
				/* Queue is full */
				failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
#ifdef LIBSSH2_DEBUG_CONNECTION
	_libssh2_debug(session, LIBSSH2_DBG_CONN, "Listener queue full, ignoring");
#endif
				break;
			}

			channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
			if (!channel) {
				libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for new connection", 0);
				failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
				break;
			}
			memset(channel, 0, sizeof(LIBSSH2_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", 0);
				LIBSSH2_FREE(session, channel);
				failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
				break;
			}
			memcpy(channel->channel_type, "forwarded-tcpip", channel->channel_type_len + 1);

			channel->remote.id = 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 = initial_window_size;
			channel->local.window_size = initial_window_size;
			channel->local.packet_size = packet_size;

#ifdef LIBSSH2_DEBUG_CONNECTION
	_libssh2_debug(session, LIBSSH2_DBG_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);
#endif

			p = packet;
			*(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
			libssh2_htonu32(p, channel->remote.id);						p += 4;
			libssh2_htonu32(p, channel->local.id);						p += 4;
			libssh2_htonu32(p, channel->remote.window_size_initial);	p += 4;
			libssh2_htonu32(p, channel->remote.packet_size);			p += 4;

			if (libssh2_packet_write(session, packet, 17)) {
				libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open confirmation", 0);
				return -1;
			}

			/* Link the channel into the end of the queue list */

			if (!last_queued) {
				l->queue = channel;
				return 0;
			}

			while (last_queued->next) last_queued = last_queued->next;

			last_queued->next = channel;
			channel->prev = last_queued;

			l->queue_size++;

			return 0;
		}

		l = l->next;
	}

	/* We're not listening to you */
	{

		p = packet;
		*(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
		libssh2_htonu32(p, sender_channel);		p += 4;
		libssh2_htonu32(p, failure_code);		p += 4;
		libssh2_htonu32(p, sizeof("Forward not requested") - 1);	p += 4;
		memcpy(s, "Forward not requested", sizeof("Forward not requested") - 1);	p += sizeof("Forward not requested") - 1;
		libssh2_htonu32(p, 0);

		if (libssh2_packet_write(session, packet, packet_len)) {
			libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send open failure", 0);
			return -1;
		}
		return 0;
	}
}
Exemple #26
0
/* {{{ libssh2_packet_new
 * Create a new packet and attach it to the brigade
 */
static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, size_t datalen, int macstate)
{
	LIBSSH2_PACKET *packet;
	unsigned long data_head = 0;

#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Packet type %d received, length=%d", (int)data[0], (int)datalen);
#endif
	if (macstate == LIBSSH2_MAC_INVALID) {
		if (session->macerror) {
			if (LIBSSH2_MACERROR(session, data, datalen) == 0) {
				/* Calling app has given the OK, Process it anyway */
				macstate = LIBSSH2_MAC_CONFIRMED;
			} else {
				libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC, "Invalid Message Authentication Code received", 0);
				if (session->ssh_msg_disconnect) {
					LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR, "Invalid MAC received", sizeof("Invalid MAC received") - 1, "", 0);
				}
				return -1;
			}
		} else {
			libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC, "Invalid Message Authentication Code received", 0);
			if (session->ssh_msg_disconnect) {
				LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR, "Invalid MAC received", sizeof("Invalid MAC received") - 1, "", 0);
			}
			return -1;
		}
	}

	/* A couple exceptions to the packet adding rule: */
	switch (data[0]) {
		case SSH_MSG_DISCONNECT:
		{
			char *message, *language;
			int reason, message_len, language_len;

			reason = libssh2_ntohu32(data + 1);
			message_len = libssh2_ntohu32(data + 5);
			message = data + 9; /* packet_type(1) + reason(4) + message_len(4) */
			language_len = libssh2_ntohu32(data + 9 + message_len);
			/* This is where we hack on the data a little,
			 * Use the MSB of language_len to to a terminating NULL (In all liklihood it is already)
			 * Shift the language tag back a byte (In all likelihood it's zero length anyway
			 * Store a NULL in the last byte of the packet to terminate the language string
			 * With the lengths passed this isn't *REALLY* necessary, but it's "kind"
			 */
			message[message_len] = '\0';
			language = data + 9 + message_len + 3;
			if (language_len) {
				memcpy(language, language + 1, language_len);
			}
			language[language_len] = '\0';

			if (session->ssh_msg_disconnect) {
				LIBSSH2_DISCONNECT(session, reason, message, message_len, language, language_len);
			}
#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Disconnect(%d): %s(%s)", reason, message, language);
#endif
			LIBSSH2_FREE(session, data);
			session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
			return -1;
		}
			break;
		case SSH_MSG_IGNORE:
			/* As with disconnect, back it up one and add a trailing NULL */
			memcpy(data + 4, data + 5, datalen - 5);
			data[datalen] = '\0';
			if (session->ssh_msg_ignore) {
				LIBSSH2_IGNORE(session, data + 4, datalen - 5);
			}
			LIBSSH2_FREE(session, data);
			return 0;
			break;
		case SSH_MSG_DEBUG:
		{
			int always_display = data[0];
			char *message, *language;
			int message_len, language_len;

			message_len = libssh2_ntohu32(data + 2);
			message = data + 6; /* packet_type(1) + display(1) + message_len(4) */
			language_len = libssh2_ntohu32(data + 6 + message_len);
			/* This is where we hack on the data a little,
			 * Use the MSB of language_len to to a terminating NULL (In all liklihood it is already)
			 * Shift the language tag back a byte (In all likelihood it's zero length anyway
			 * Store a NULL in the last byte of the packet to terminate the language string
			 * With the lengths passed this isn't *REALLY* necessary, but it's "kind"
			 */
			message[message_len] = '\0';
			language = data + 6 + message_len + 3;
			if (language_len) {
				memcpy(language, language + 1, language_len);
			}
			language[language_len] = '\0';

			if (session->ssh_msg_debug) {
				LIBSSH2_DEBUG(session, always_display, message, message_len, language, language_len);
			}
#ifdef LIBSSH2_DEBUG_TRANSPORT
	/* _libssh2_debug will actually truncate this for us so that it's not an inordinate about of data */
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Debug Packet: %s", message);
#endif
			LIBSSH2_FREE(session, data);
			return 0;
		}
			break;
		case SSH_MSG_CHANNEL_EXTENDED_DATA:
			data_head += 4; /* streamid(4) */
		case SSH_MSG_CHANNEL_DATA:
			data_head += 9; /* packet_type(1) + channelno(4) + datalen(4) */
			{
				LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));

				if (!channel) {
					libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN, "Packet received for unknown channel, ignoring", 0);
					LIBSSH2_FREE(session, data);
					return 0;
				}
#ifdef LIBSSH2_DEBUG_CONNECTION
{
	unsigned long stream_id = 0;

	if (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) {
		stream_id = libssh2_ntohu32(data + 5);
	}

	_libssh2_debug(session, LIBSSH2_DBG_CONN, "%d bytes received for channel %lu/%lu stream #%lu", (int)(datalen - data_head), channel->local.id, channel->remote.id, stream_id);
}
#endif
				if ((channel->remote.extended_data_ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) && (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)) {
					/* Pretend we didn't receive this */
					LIBSSH2_FREE(session, data);

#ifdef LIBSSH2_DEBUG_CONNECTION
	_libssh2_debug(session, LIBSSH2_DBG_CONN, "Ignoring extended data and refunding %d bytes", (int)(datalen - 13));
#endif
					/* Adjust the window based on the block we just freed */
					libssh2_channel_receive_window_adjust(channel, datalen - 13, 0);

					return 0;
				}

				/* REMEMBER! remote means remote as source of data, NOT remote window! */
				if (channel->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", 0);
					datalen = channel->remote.packet_size + data_head;
				}
				if (channel->remote.window_size <= 0) {
					/* 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", 0);
					LIBSSH2_FREE(session, data);
					return 0;
				}
				/* Reset EOF status */
				channel->remote.eof = 0;

				if ((datalen - data_head) > channel->remote.window_size) {
					libssh2_error(session, LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, "Remote sent more data than current window allows, truncating", 0);
					datalen = channel->remote.window_size + data_head;
				} else {
					/* Now that we've received it, shrink our window */
					channel->remote.window_size -= datalen - data_head;
				}
			}
			break;
		case SSH_MSG_CHANNEL_EOF:
			{
				LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));

				if (!channel) {
					/* We may have freed already, just quietly ignore this... */
					LIBSSH2_FREE(session, data);
					return 0;
				}

#ifdef LIBSSH2_DEBUG_CONNECTION
	_libssh2_debug(session, LIBSSH2_DBG_CONN, "EOF received for channel %lu/%lu", channel->local.id, channel->remote.id);
#endif
				channel->remote.eof = 1;

				LIBSSH2_FREE(session, data);
				return 0;
			}
			break;
	    case SSH_MSG_CHANNEL_REQUEST:
		    {
				if (libssh2_ntohu32(data+5) == sizeof("exit-status") - 1
					&& !memcmp("exit-status", data + 9, sizeof("exit-status") - 1)) {

					/* we've got "exit-status" packet. Set the session value */
					LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data+1));

					if (channel) {
						channel->exit_status = libssh2_ntohu32(data + 9 + sizeof("exit-status"));
#ifdef LIBSSH2_DEBUG_CONNECTION
						_libssh2_debug(session, LIBSSH2_DBG_CONN, "Exit status %lu received for channel %lu/%lu", channel->exit_status, channel->local.id, channel->remote.id);
#endif
					}

					LIBSSH2_FREE(session, data);
					return 0;
				}
			}
			break;
		case SSH_MSG_CHANNEL_CLOSE:
			{
				LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));

				if (!channel) {
					/* We may have freed already, just quietly ignore this... */
					LIBSSH2_FREE(session, data);
					return 0;
				}
#ifdef LIBSSH2_DEBUG_CONNECTION
	_libssh2_debug(session, LIBSSH2_DBG_CONN, "Close received for channel %lu/%lu", channel->local.id, channel->remote.id);
#endif

				channel->remote.close = 1;
				/* TODO: Add a callback for this */

				LIBSSH2_FREE(session, data);
				return 0;
			}
			break;
		case SSH_MSG_CHANNEL_OPEN:
			if ((datalen >= (sizeof("forwarded-tcpip") + 4)) &&
				((sizeof("forwarded-tcpip")-1) == libssh2_ntohu32(data + 1)) &&
				(memcmp(data + 5, "forwarded-tcpip", sizeof("forwarded-tcpip") - 1) == 0)) {
				int retval = libssh2_packet_queue_listener(session, data, datalen);

				LIBSSH2_FREE(session, data);
				return retval;
			}
			if ((datalen >= (sizeof("x11") + 4)) &&
				((sizeof("x11")-1) == libssh2_ntohu32(data + 1)) &&
				(memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {
				int retval = libssh2_packet_x11_open(session, data, datalen);

				LIBSSH2_FREE(session, data);
				return retval;
			}
			break;
		case SSH_MSG_CHANNEL_WINDOW_ADJUST:
			{
				LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));
				unsigned long bytestoadd = libssh2_ntohu32(data + 5);

				if (channel && bytestoadd) {
					channel->local.window_size += bytestoadd;
				}
#ifdef LIBSSH2_DEBUG_CONNECTION
	_libssh2_debug(session, LIBSSH2_DBG_CONN, "Window adjust received for channel %lu/%lu, adding %lu bytes, new window_size=%lu", channel->local.id, channel->remote.id, bytestoadd, channel->local.window_size);
#endif

				LIBSSH2_FREE(session, data);
				return 0;
			}
			break;
	}

	packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
	memset(packet, 0, sizeof(LIBSSH2_PACKET));

	packet->data = data;
	packet->data_len = datalen;
	packet->data_head = data_head;
	packet->mac = macstate;
	packet->brigade = &session->packets;
	packet->next = NULL;

	if (session->packets.tail) {
		packet->prev = session->packets.tail;
		packet->prev->next = packet;
		session->packets.tail = packet;
	} else {
		session->packets.head = packet;
		session->packets.tail = packet;
		packet->prev = NULL;
	}

	if (data[0] == SSH_MSG_KEXINIT && !(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) {
		/* Remote wants new keys
		 * Well, it's already in the brigade,
		 * let's just call back into ourselves
		 */
#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Renegotiating Keys");
#endif
		libssh2_kex_exchange(session, 1);
		/* 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 */
	}

	return 0;
}
Exemple #27
0
/* {{{ libssh2_packet_x11_open
 * Accept a forwarded X11 connection
 */
inline int libssh2_packet_x11_open(LIBSSH2_SESSION *session, unsigned char *data, unsigned long datalen)
{
	int failure_code = 2; /* SSH_OPEN_CONNECT_FAILED */
	unsigned char *s = data + (sizeof("x11") - 1) + 5;
	unsigned long packet_len = 17 + (sizeof("X11 Forward Unavailable") - 1);
	unsigned char *p, packet[17 + (sizeof("X11 Forward Unavailable") - 1)];
					/* packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
	LIBSSH2_CHANNEL *channel;
	unsigned long sender_channel, initial_window_size, packet_size;
	unsigned char *shost;
	unsigned long sport, shost_len;

	sender_channel = libssh2_ntohu32(s);			s += 4;
	initial_window_size = libssh2_ntohu32(s);		s += 4;
	packet_size = libssh2_ntohu32(s);				s += 4;
	shost_len = libssh2_ntohu32(s);					s += 4;
	shost = s;										s += shost_len;
	sport = libssh2_ntohu32(s);						s += 4;

#ifdef LIBSSH2_DEBUG_CONNECTION
	_libssh2_debug(session, LIBSSH2_DBG_CONN, "X11 Connection Received from %s:%ld on channel %lu", shost, sport, sender_channel);
#endif
	if (session->x11) {
		channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
		if (!channel) {
			libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for new connection", 0);
			failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
			goto x11_exit;
		}
		memset(channel, 0, sizeof(LIBSSH2_CHANNEL));

		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, "Unable to allocate a channel for new connection", 0);
			LIBSSH2_FREE(session, channel);
			failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
			goto x11_exit;
		}
		memcpy(channel->channel_type, "x11", channel->channel_type_len + 1);

		channel->remote.id = 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 = initial_window_size;
		channel->local.window_size = initial_window_size;
		channel->local.packet_size = packet_size;

#ifdef LIBSSH2_DEBUG_CONNECTION
	_libssh2_debug(session, LIBSSH2_DBG_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);
#endif
		p = packet;
		*(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
		libssh2_htonu32(p, channel->remote.id);						p += 4;
		libssh2_htonu32(p, channel->local.id);						p += 4;
		libssh2_htonu32(p, channel->remote.window_size_initial);	p += 4;
		libssh2_htonu32(p, channel->remote.packet_size);			p += 4;

		if (libssh2_packet_write(session, packet, 17)) {
			libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open confirmation", 0);
			return -1;
		}

		/* Link the channel into the session */
		if (session->channels.tail) {
			session->channels.tail->next = channel;
			channel->prev = session->channels.tail;
		} else {
			session->channels.head = channel;
			channel->prev = NULL;
		}
		channel->next = NULL;
		session->channels.tail = channel;

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

		return 0;
	} else {
		failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
	}

 x11_exit:
	p = packet;
	*(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
	libssh2_htonu32(p, sender_channel);				p += 4;
	libssh2_htonu32(p, failure_code);				p += 4;
	libssh2_htonu32(p, sizeof("X11 Forward Unavailable") - 1);		p += 4;
	memcpy(s, "X11 Forward Unavailable", sizeof("X11 Forward Unavailable") - 1); p += sizeof("X11 Forward Unavailable") - 1;
	libssh2_htonu32(p, 0);

	if (libssh2_packet_write(session, packet, packet_len)) {
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send open failure", 0);
		return -1;
	}
	return 0;
}
Exemple #28
0
/* {{{ libssh2_packet_write
 * Send a packet, encrypting it and adding a MAC code if necessary
 * Returns 0 on success, non-zero on failure
 */
int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len)
{
	unsigned long packet_length = data_len + 1;
	unsigned long block_size = (session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->blocksize : 8;
	/* At this point packet_length doesn't include the packet_len field itself */
	unsigned long padding_length;
	int free_data = 0;
	unsigned char buf[246]; /* 6 byte header plus max padding size(240) */

#ifdef LIBSSH2_DEBUG_TRANSPORT
{
	/* Show a hint of what's being sent */
	char excerpt[32];
	int ex_len = 0, db_ofs = 0;

	for (; ex_len < 24 && db_ofs < data_len; ex_len += 3, db_ofs++) snprintf(excerpt + ex_len, 4, "%02X ", data[db_ofs]);
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending packet type %d, length=%lu, %s", (int)data[0], data_len, excerpt);
}
#endif
	if ((session->state & LIBSSH2_STATE_NEWKEYS) &&
		strcmp(session->local.comp->name, "none")) {

		if (session->local.comp->comp(session, 1, &data, &data_len, LIBSSH2_PACKET_MAXCOMP, &free_data, data, data_len, &session->local.comp_abstract)) {
			return -1;
		}
#ifdef LIBSSH2_DEBUG_TRANSPORT
		_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Compressed payload to %lu bytes", data_len);
#endif
	}

#ifndef WIN32
	fcntl(session->socket_fd, F_SETFL, 0);
#else
	{
		u_long non_block = FALSE;
		ioctlsocket(session->socket_fd, FIONBIO, &non_block);
	}
#endif

	packet_length = data_len + 1; /* padding_length(1) -- MAC doesn't count -- Padding to be added soon */
	padding_length = block_size - ((packet_length + 4) % block_size);
	if (padding_length < 4) {
		padding_length += block_size;
	}
	/* TODO: Maybe add 1 or 2 times block_size to padding_length randomly -- shake things up a bit... */

	packet_length += padding_length;
	libssh2_htonu32(buf, packet_length);
	buf[4] = padding_length;
#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending packet with total length %lu (%lu bytes padding)", packet_length, padding_length);
#endif

	if (session->state & LIBSSH2_STATE_NEWKEYS) {
		/* Encryption is in effect */
		unsigned char *encbuf, *s;
		int ret;

		/* Safely ignored in CUSTOM cipher mode */
		EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)session->local.crypt_abstract;

		/* include packet_length(4) itself and room for the hash at the end */
		encbuf = LIBSSH2_ALLOC(session, 4 + packet_length + session->local.mac->mac_len);
		if (!encbuf) {
			libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate encryption buffer", 0);
			if (free_data) {
				LIBSSH2_FREE(session, data);
			}
			return -1;
		}

		/* Copy packet to encoding buffer */
		memcpy(encbuf, buf, 5);
		memcpy(encbuf + 5, data, data_len);
		RAND_bytes(encbuf + 5 + data_len, padding_length);
		if (free_data) {
			LIBSSH2_FREE(session, data);
		}

		/* Calculate MAC hash */
 		session->local.mac->hash(session, encbuf + 4 + packet_length , session->local.seqno, encbuf, 4 + packet_length, NULL, 0, &session->local.mac_abstract);

		/* Encrypt data */
		for(s = encbuf; (s - encbuf) < (4 + packet_length) ; s += session->local.crypt->blocksize) {
			if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
				EVP_Cipher(ctx, buf, s, session->local.crypt->blocksize);
				memcpy(s, buf, session->local.crypt->blocksize);
			} else {
				session->local.crypt->crypt(session, s, &session->local.crypt_abstract);
			}
		}

		session->local.seqno++;

		/* Send It */
		ret = ((4 + packet_length + session->local.mac->mac_len) == send(session->socket_fd, encbuf, 4 + packet_length + session->local.mac->mac_len, LIBSSH2_SOCKET_SEND_FLAGS(session))) ? 0 : -1;

		/* Cleanup environment */
		LIBSSH2_FREE(session, encbuf);

		return ret;
	} else { /* LIBSSH2_ENDPOINT_CRYPT_NONE */
		/* Simplified write for non-encrypted mode */
		struct iovec data_vector[3];

		/* Using vectors means we don't have to alloc a new buffer -- a byte saved is a byte earned
		 * No MAC during unencrypted phase
		 */
		data_vector[0].iov_base = buf;
		data_vector[0].iov_len = 5;
		data_vector[1].iov_base = (char*)data;
		data_vector[1].iov_len = data_len;
		data_vector[2].iov_base = buf + 5;
		data_vector[2].iov_len = padding_length;

		session->local.seqno++;

		/* Ignore this, it can't actually happen :) */
		if (free_data) {
			LIBSSH2_FREE(session, data);
		}

		return ((packet_length + 4) == writev(session->socket_fd, data_vector, 3)) ? 0 : 1;
	}
}
Exemple #29
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
     */
    unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5;
    /* 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 *listen = session->listeners;
    char failure_code = 1;      /* SSH_OPEN_ADMINISTRATIVELY_PROHIBITED */
    int rc;

    (void) datalen;

    if (listen_state->state == libssh2_NB_state_idle) {
        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);
        s += 4;

        _libssh2_debug(session, LIBSSH2_DBG_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 (listen) {
            if ((listen->port == (int) listen_state->port) &&
                (strlen(listen->host) == listen_state->host_len) &&
                (memcmp
                 (listen->host, listen_state->host,
                  listen_state->host_len) == 0)) {
                /* This is our listener */
                LIBSSH2_CHANNEL *channel, *last_queued = listen->queue;

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

                    channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
                    if (!channel) {
                        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                                      "Unable to allocate a channel for new connection",
                                      0);
                        failure_code = 4;       /* SSH_OPEN_RESOURCE_SHORTAGE */
                        listen_state->state = libssh2_NB_state_sent;
                        break;
                    }
                    memset(channel, 0, sizeof(LIBSSH2_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",
                                      0);
                        LIBSSH2_FREE(session, channel);
                        failure_code = 4;       /* 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_DBG_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_htonu32(p, channel->remote.id);
                    p += 4;
                    _libssh2_htonu32(p, channel->local.id);
                    p += 4;
                    _libssh2_htonu32(p, channel->remote.window_size_initial);
                    p += 4;
                    _libssh2_htonu32(p, channel->remote.packet_size);
                    p += 4;

                    listen_state->state = libssh2_NB_state_created;
                }

                if (listen_state->state == libssh2_NB_state_created) {
                    rc = _libssh2_transport_write(session, listen_state->packet,
                                                  17);
                    if (rc == PACKET_EAGAIN) {
                        return PACKET_EAGAIN;
                    } else if (rc) {
                        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
                                      "Unable to send channel open confirmation",
                                      0);
                        listen_state->state = libssh2_NB_state_idle;
                        return -1;
                    }

                    /* Link the channel into the end of the queue list */

                    if (!last_queued) {
                        listen->queue = channel;
                        listen_state->state = libssh2_NB_state_idle;
                        return 0;
                    }

                    while (last_queued->next) {
                        last_queued = last_queued->next;
                    }

                    last_queued->next = channel;
                    channel->prev = last_queued;

                    listen->queue_size++;

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

            listen = listen->next;
        }

        listen_state->state = libssh2_NB_state_sent;
    }

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

        rc = _libssh2_transport_write(session, listen_state->packet,
                                      packet_len);
        if (rc == PACKET_EAGAIN) {
            return PACKET_EAGAIN;
        } else if (rc) {
            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
                          "Unable to send open failure", 0);
            listen_state->state = libssh2_NB_state_idle;
            return -1;
        }
        listen_state->state = libssh2_NB_state_idle;
        return 0;
    }
}
Exemple #30
0
/*
 * _libssh2_packet_add
 *
 * Create a new packet and attach it to the brigade. Called from the transport
 * layer when it as received a packet.
 */
int
_libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
                    size_t datalen, int macstate)
{
    int rc;

    if (session->packAdd_state == libssh2_NB_state_idle) {
        session->packAdd_data_head = 0;

        /* Zero the whole thing out */
        memset(&session->packAdd_key_state, 0,
               sizeof(session->packAdd_key_state));

        /* Zero the whole thing out */
        memset(&session->packAdd_Qlstn_state, 0,
               sizeof(session->packAdd_Qlstn_state));

        /* Zero the whole thing out */
        memset(&session->packAdd_x11open_state, 0,
               sizeof(session->packAdd_x11open_state));

        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
                       "Packet type %d received, length=%d",
                       (int) data[0], (int) datalen);
        if (macstate == LIBSSH2_MAC_INVALID) {
            if (session->macerror) {
                if (LIBSSH2_MACERROR(session, (char *) data, datalen) == 0) {
                    /* Calling app has given the OK, Process it anyway */
                    macstate = LIBSSH2_MAC_CONFIRMED;
                } else {
                    libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
                                  "Invalid Message Authentication Code received",
                                  0);
                    if (session->ssh_msg_disconnect) {
                        LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR,
                                           "Invalid MAC received",
                                           sizeof("Invalid MAC received") - 1,
                                           "", 0);
                    }
                    LIBSSH2_FREE(session, data);
                    return -1;
                }
            } else {
                libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
                              "Invalid Message Authentication Code received",
                              0);
                if (session->ssh_msg_disconnect) {
                    LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR,
                                       "Invalid MAC received",
                                       sizeof("Invalid MAC received") - 1,
                                       "", 0);
                }
                LIBSSH2_FREE(session, data);
                return -1;
            }
        }

        session->packAdd_state = libssh2_NB_state_allocated;
    }

    /*
     * =============================== NOTE ===============================
     * I know this is very ugly and not a really good use of "goto", but
     * this case statement would be even uglier to do it any other way
     */
    if (session->packAdd_state == libssh2_NB_state_jump1) {
        goto libssh2_packet_add_jump_point1;
    } else if (session->packAdd_state == libssh2_NB_state_jump2) {
        goto libssh2_packet_add_jump_point2;
    } else if (session->packAdd_state == libssh2_NB_state_jump3) {
        goto libssh2_packet_add_jump_point3;
    }

    if (session->packAdd_state == libssh2_NB_state_allocated) {
        /* A couple exceptions to the packet adding rule: */
        switch (data[0]) {
        case SSH_MSG_DISCONNECT:
            {
                char *message, *language;
                int reason, message_len, language_len;

                reason = _libssh2_ntohu32(data + 1);
                message_len = _libssh2_ntohu32(data + 5);
                /* 9 = packet_type(1) + reason(4) + message_len(4) */
                message = (char *) data + 9;
                language_len = _libssh2_ntohu32(data + 9 + message_len);
                /*
                 * This is where we hack on the data a little,
                 * Use the MSB of language_len to to a terminating NULL
                 * (In all liklihood it is already)
                 * Shift the language tag back a byte (In all likelihood
                 * it's zero length anyway)
                 * Store a NULL in the last byte of the packet to terminate
                 * the language string
                 * With the lengths passed this isn't *REALLY* necessary,
                 * but it's "kind"
                 */
                message[message_len] = '\0';
                language = (char *) data + 9 + message_len + 3;
                if (language_len) {
                    memcpy(language, language + 1, language_len);
                }
                language[language_len] = '\0';

                if (session->ssh_msg_disconnect) {
                    LIBSSH2_DISCONNECT(session, reason, message,
                                       message_len, language, language_len);
                }
                _libssh2_debug(session, LIBSSH2_DBG_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 -1;
            }
            break;

        case SSH_MSG_IGNORE:
            /* As with disconnect, back it up one and add a trailing NULL */
            memcpy(data + 4, data + 5, datalen - 5);
            data[datalen] = '\0';
            if (session->ssh_msg_ignore) {
                LIBSSH2_IGNORE(session, (char *) data + 4, datalen - 5);
            }
            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return 0;
            break;

        case SSH_MSG_DEBUG:
            {
                int always_display = data[0];
                char *message, *language;
                int message_len, language_len;

                message_len = _libssh2_ntohu32(data + 2);
                /* 6 = packet_type(1) + display(1) + message_len(4) */
                message = (char *) data + 6;
                language_len = _libssh2_ntohu32(data + 6 + message_len);
                /*
                 * This is where we hack on the data a little,
                 * Use the MSB of language_len to to a terminating NULL
                 * (In all liklihood it is already)
                 * Shift the language tag back a byte (In all likelihood
                 * it's zero length anyway)
                 * Store a NULL in the last byte of the packet to terminate
                 * the language string
                 * With the lengths passed this isn't *REALLY* necessary,
                 * but it's "kind"
                 */
                message[message_len] = '\0';
                language = (char *) data + 6 + message_len + 3;
                if (language_len) {
                    memcpy(language, language + 1, language_len);
                }
                language[language_len] = '\0';

                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_DBG_TRANS,
                               "Debug Packet: %s", message);
                LIBSSH2_FREE(session, data);
                session->packAdd_state = libssh2_NB_state_idle;
                return 0;
            }
            break;

        case SSH_MSG_CHANNEL_EXTENDED_DATA:
            /* streamid(4) */
            session->packAdd_data_head += 4;
        case SSH_MSG_CHANNEL_DATA:
            /* packet_type(1) + channelno(4) + datalen(4) */
            session->packAdd_data_head += 9;

            session->packAdd_channel =
                _libssh2_channel_locate(session, _libssh2_ntohu32(data + 1));

            if (!session->packAdd_channel) {
                libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN,
                              "Packet received for unknown channel, ignoring",
                              0);
                LIBSSH2_FREE(session, data);
                session->packAdd_state = libssh2_NB_state_idle;
                return 0;
            }
#ifdef LIBSSH2DEBUG
            {
                unsigned long stream_id = 0;
                if (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) {
                    stream_id = _libssh2_ntohu32(data + 5);
                }

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

                _libssh2_debug(session, LIBSSH2_DBG_CONN,
                               "Ignoring extended data and refunding %d bytes",
                               (int) (datalen - 13));
                /* 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_channel,
                                                           datalen - 13,
                                                           0);
                if (rc == PACKET_EAGAIN) {
                    session->socket_block_directions =
                        LIBSSH2_SESSION_BLOCK_OUTBOUND;
                    return PACKET_EAGAIN;
                }
                session->packAdd_state = libssh2_NB_state_idle;
                return 0;
            }

            /*
             * REMEMBER! remote means remote as source of data,
             * NOT remote window!
             */
            if (session->packAdd_channel->remote.packet_size <
                (datalen - session->packAdd_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", 0);
                datalen =
                    session->packAdd_channel->remote.packet_size +
                    session->packAdd_data_head;
            }
            if (session->packAdd_channel->remote.window_size <= 0) {
                /*
                 * 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",
                              0);
                LIBSSH2_FREE(session, data);
                session->packAdd_state = libssh2_NB_state_idle;
                return 0;
            }
            /* Reset EOF status */
            session->packAdd_channel->remote.eof = 0;

            if ((datalen - session->packAdd_data_head) >
                session->packAdd_channel->remote.window_size) {
                libssh2_error(session,
                              LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
                              "Remote sent more data than current "
                              "window allows, truncating",
                              0);
                datalen =
                    session->packAdd_channel->remote.window_size +
                    session->packAdd_data_head;
            }
            else {
                /* Now that we've received it, shrink our window */
                session->packAdd_channel->remote.window_size -=
                    datalen - session->packAdd_data_head;
            }

            break;

        case SSH_MSG_CHANNEL_EOF:
            {
                session->packAdd_channel =
                    _libssh2_channel_locate(session, _libssh2_ntohu32(data + 1));

                if (!session->packAdd_channel) {
                    /* 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_DBG_CONN,
                               "EOF received for channel %lu/%lu",
                               session->packAdd_channel->local.id,
                               session->packAdd_channel->remote.id);
                session->packAdd_channel->remote.eof = 1;

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

        case SSH_MSG_CHANNEL_REQUEST:
            {
                if (_libssh2_ntohu32(data + 5) == sizeof("exit-status") - 1
                    && !memcmp("exit-status", data + 9,
                               sizeof("exit-status") - 1)) {

                    /* we've got "exit-status" packet. Set the session value */
                    session->packAdd_channel =
                        _libssh2_channel_locate(session,
                                                _libssh2_ntohu32(data + 1));

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

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

        case SSH_MSG_CHANNEL_CLOSE:
            {
                session->packAdd_channel =
                    _libssh2_channel_locate(session, _libssh2_ntohu32(data + 1));

                if (!session->packAdd_channel) {
                    /* 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_DBG_CONN,
                               "Close received for channel %lu/%lu",
                               session->packAdd_channel->local.id,
                               session->packAdd_channel->remote.id);

                session->packAdd_channel->remote.close = 1;
                session->packAdd_channel->remote.eof = 1;
                /* TODO: Add a callback for this */

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

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

              libssh2_packet_add_jump_point2:
                session->packAdd_state = libssh2_NB_state_jump2;
                rc = packet_queue_listener(session, data, datalen,
                                           &session->packAdd_Qlstn_state);
                if (rc == PACKET_EAGAIN) {
                    session->socket_block_directions =
                        LIBSSH2_SESSION_BLOCK_OUTBOUND;
                    return PACKET_EAGAIN;
                }

                LIBSSH2_FREE(session, data);
                session->packAdd_state = libssh2_NB_state_idle;
                return rc;
            }
            if ((datalen >= (sizeof("x11") + 4)) &&
                ((sizeof("x11") - 1) == _libssh2_ntohu32(data + 1)) &&
                (memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {

              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 == PACKET_EAGAIN) {
                    session->socket_block_directions =
                        LIBSSH2_SESSION_BLOCK_OUTBOUND;
                    return PACKET_EAGAIN;
                }

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

        case SSH_MSG_CHANNEL_WINDOW_ADJUST:
            {
                unsigned long bytestoadd = _libssh2_ntohu32(data + 5);
                session->packAdd_channel =
                    _libssh2_channel_locate(session,
                                            _libssh2_ntohu32(data + 1));

                if (session->packAdd_channel && bytestoadd) {
                    session->packAdd_channel->local.window_size += bytestoadd;
                }
                _libssh2_debug(session, LIBSSH2_DBG_CONN,
                               "Window adjust received for channel %lu/%lu, adding %lu bytes, new window_size=%lu",
                               session->packAdd_channel->local.id,
                               session->packAdd_channel->remote.id,
                               bytestoadd,
                               session->packAdd_channel->local.window_size);

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

        session->packAdd_state = libssh2_NB_state_sent;
    }

    if (session->packAdd_state == libssh2_NB_state_sent) {
        session->packAdd_packet =
            LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
        if (!session->packAdd_packet) {
            _libssh2_debug(session, LIBSSH2_ERROR_ALLOC,
                           "Unable to allocate memory for LIBSSH2_PACKET");
            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return -1;
        }
        memset(session->packAdd_packet, 0, sizeof(LIBSSH2_PACKET));

        session->packAdd_packet->data = data;
        session->packAdd_packet->data_len = datalen;
        session->packAdd_packet->data_head = session->packAdd_data_head;
        session->packAdd_packet->mac = macstate;
        session->packAdd_packet->brigade = &session->packets;
        session->packAdd_packet->next = NULL;

        if (session->packets.tail) {
            session->packAdd_packet->prev = session->packets.tail;
            session->packAdd_packet->prev->next = session->packAdd_packet;
            session->packets.tail = session->packAdd_packet;
        } else {
            session->packets.head = session->packAdd_packet;
            session->packets.tail = session->packAdd_packet;
            session->packAdd_packet->prev = NULL;
        }

        session->packAdd_state = libssh2_NB_state_sent1;
    }

    if ((data[0] == 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_DBG_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;

        /*
         * Also, don't use packAdd_key_state for key re-exchange,
         * as it will be wiped out in the middle of the exchange.
         * How about re-using the startup_key_state?
         */
        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 == PACKET_EAGAIN) {
            return PACKET_EAGAIN;
        }
    }

    session->packAdd_state = libssh2_NB_state_idle;
    return 0;
}