示例#1
0
文件: session.c 项目: roderico/linm
/* {{{ proto libssh2_session_startup
 * session: LIBSSH2_SESSION struct allocated and owned by the calling program
 * Returns: 0 on success, or non-zero on failure
 * Any memory allocated by libssh2 will use alloc/realloc/free
 * callbacks in session
 * socket *must* be populated with an opened and connected socket.
 */
LIBSSH2_API int
libssh2_session_startup(LIBSSH2_SESSION * session, int sock)
{
    int rc;

    if (session->startup_state == libssh2_NB_state_idle) {
        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
                       "session_startup for socket %d", sock);
        /* FIXME: on some platforms (like win32) sockets are unsigned */
        if (sock < 0) {
            /* Did we forget something? */
            libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE,
                          "Bad socket provided", 0);
            return LIBSSH2_ERROR_SOCKET_NONE;
        }
        session->socket_fd = sock;

        session->socket_block =
            !_libssh2_get_socket_nonblocking(session->socket_fd);
        if (session->socket_block) {
            /*
             * Since we can't be sure that we are in blocking or there
             * was an error detecting the state, so set to blocking to
             * be sure
             */
            _libssh2_nonblock(session->socket_fd, 0);
        }

        session->startup_state = libssh2_NB_state_created;
    }

    /* TODO: Liveness check */

    if (session->startup_state == libssh2_NB_state_created) {
        rc = libssh2_banner_send(session);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block sending banner to remote host", 0);
            return LIBSSH2_ERROR_EAGAIN;
        } else if (rc) {
            /* Unable to send banner? */
            libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND,
                          "Error sending banner to remote host", 0);
            return LIBSSH2_ERROR_BANNER_SEND;
        }

        session->startup_state = libssh2_NB_state_sent;
    }

    if (session->startup_state == libssh2_NB_state_sent) {
        rc = libssh2_banner_receive(session);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block waiting for banner", 0);
            return LIBSSH2_ERROR_EAGAIN;
        } else if (rc) {
            /* Unable to receive banner from remote */
            libssh2_error(session, LIBSSH2_ERROR_BANNER_NONE,
                          "Timeout waiting for banner", 0);
            return LIBSSH2_ERROR_BANNER_NONE;
        }

        session->startup_state = libssh2_NB_state_sent1;
    }

    if (session->startup_state == libssh2_NB_state_sent1) {
        rc = libssh2_kex_exchange(session, 0, &session->startup_key_state);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block exchanging encryption keys", 0);
            return LIBSSH2_ERROR_EAGAIN;
        } else if (rc) {
            libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE,
                          "Unable to exchange encryption keys", 0);
            return LIBSSH2_ERROR_KEX_FAILURE;
        }

        session->startup_state = libssh2_NB_state_sent2;
    }

    if (session->startup_state == libssh2_NB_state_sent2) {
        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
                       "Requesting userauth service");

        /* Request the userauth service */
        session->startup_service[0] = SSH_MSG_SERVICE_REQUEST;
        libssh2_htonu32(session->startup_service + 1,
                        sizeof("ssh-userauth") - 1);
        memcpy(session->startup_service + 5, "ssh-userauth",
               sizeof("ssh-userauth") - 1);

        session->startup_state = libssh2_NB_state_sent3;
    }

    if (session->startup_state == libssh2_NB_state_sent3) {
        rc = libssh2_packet_write(session, session->startup_service,
                                  sizeof("ssh-userauth") + 5 - 1);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block asking for ssh-userauth service", 0);
            return LIBSSH2_ERROR_EAGAIN;
        } else if (rc) {
            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
                          "Unable to ask for ssh-userauth service", 0);
            return LIBSSH2_ERROR_SOCKET_SEND;
        }

        session->startup_state = libssh2_NB_state_sent4;
    }

    if (session->startup_state == libssh2_NB_state_sent4) {
        rc = libssh2_packet_require_ex(session, SSH_MSG_SERVICE_ACCEPT,
                                       &session->startup_data,
                                       &session->startup_data_len, 0, NULL, 0,
                                       &session->startup_req_state);
        if (rc == PACKET_EAGAIN) {
            return LIBSSH2_ERROR_EAGAIN;
        } else if (rc) {
            return LIBSSH2_ERROR_SOCKET_DISCONNECT;
        }
        session->startup_service_length =
            libssh2_ntohu32(session->startup_data + 1);

        if ((session->startup_service_length != (sizeof("ssh-userauth") - 1))
            || strncmp("ssh-userauth", (char *) session->startup_data + 5,
                       session->startup_service_length)) {
            LIBSSH2_FREE(session, session->startup_data);
            session->startup_data = NULL;
            libssh2_error(session, LIBSSH2_ERROR_PROTO,
                          "Invalid response received from server", 0);
            return LIBSSH2_ERROR_PROTO;
        }
        LIBSSH2_FREE(session, session->startup_data);
        session->startup_data = NULL;

        session->startup_state = libssh2_NB_state_idle;

        return 0;
    }

    /* just for safety return some error */
    return LIBSSH2_ERROR_INVAL;
}
示例#2
0
/* {{{ libssh2_publickey_add_ex
 * Add a new public key entry
 */
LIBSSH2_API int libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
															const unsigned char *blob, unsigned long blob_len, char overwrite,
															unsigned long num_attrs, libssh2_publickey_attribute attrs[])
{
	LIBSSH2_CHANNEL *channel = pkey->channel;
	LIBSSH2_SESSION *session = channel->session;
	unsigned char *packet = NULL, *s;
	unsigned long i, packet_len = 19 + name_len + blob_len;
	unsigned char *comment = NULL;
	unsigned long comment_len = 0;
	/*	packet_len(4) +
		add_len(4) +
		"add"(3) +
		name_len(4) +
		{name}
		blob_len(4) +
		{blob} */

#ifdef LIBSSH2_DEBUG_PUBLICKEY
	_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Adding %s pubickey", name);
#endif

	if (pkey->version == 1) {
		for(i = 0; i < num_attrs; i++) {
			/* Search for a comment attribute */
			if (attrs[i].name_len == (sizeof("comment") - 1) &&
				strncmp(attrs[i].name, "comment", sizeof("comment") - 1) == 0) {
				comment = attrs[i].value;
				comment_len = attrs[i].value_len;
				break;
			}
		}
		packet_len += 4 + comment_len;
	} else {
		packet_len += 5; /* overwrite(1) + attribute_count(4) */
		for(i = 0; i < num_attrs; i++) {
			packet_len += 9 + attrs[i].name_len + attrs[i].value_len;
			/* name_len(4) + value_len(4) + mandatory(1) */
		}
	}

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

	s = packet;
	libssh2_htonu32(s, packet_len - 4);						s += 4;
	libssh2_htonu32(s, sizeof("add") - 1);					s += 4;
	memcpy(s, "add", sizeof("add") - 1);					s += sizeof("add") - 1;
	if (pkey->version == 1) {
		libssh2_htonu32(s, comment_len);					s += 4;
		if (comment) {
			memcpy(s, comment, comment_len);				s += comment_len;
		}

		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;
	} else {
		/* Version == 2 */

		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;
		*(s++) = overwrite ? 0xFF : 0;
		libssh2_htonu32(s, num_attrs);						s += 4;
		for(i = 0; i < num_attrs; i++) {
			libssh2_htonu32(s, attrs[i].name_len);			s += 4;
			memcpy(s, attrs[i].name, attrs[i].name_len);	s += attrs[i].name_len;
			libssh2_htonu32(s, attrs[i].value_len);			s += 4;
			memcpy(s, attrs[i].value, attrs[i].value_len);	s += attrs[i].value_len;
			*(s++) = attrs[i].mandatory ? 0xFF : 0;
		}
	}

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

	return libssh2_publickey_response_success(pkey);
}
示例#3
0
/* {{{ libssh2_publickey_list_fetch
 * Fetch a list of supported public key from a server
 */
LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned long *num_keys, libssh2_publickey_list **pkey_list)
{
	LIBSSH2_CHANNEL *channel = pkey->channel;
	LIBSSH2_SESSION *session = channel->session;
	libssh2_publickey_list *list = NULL;
	unsigned char *s, buffer[12], *data = NULL;
	unsigned long buffer_len = 12, keys = 0, max_keys = 0, data_len, i, response;
	/*	packet_len(4) + 
		list_len(4) +
		"list"(4) */

	s = buffer;
	libssh2_htonu32(s, buffer_len - 4);							s += 4;
	libssh2_htonu32(s, sizeof("list") - 1);						s += 4;
	memcpy(s, "list", sizeof("list") - 1);						s += sizeof("list") - 1;

#ifdef LIBSSH2_DEBUG_PUBLICKEY
	_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"list\" packet");
#endif
    if ((s - buffer) != libssh2_channel_write(channel, buffer, (s - buffer))) {
        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey list packet", 0);
		return -1;
    }

	while (1) {
		if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
			libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
			goto err_exit;
		}

		s = data;
		if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
			libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
			goto err_exit;
		}

		switch (response) {
			case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
			/* Error, or processing complete */
			{
				unsigned long status, descr_len, lang_len;
				unsigned char *descr, *lang;
				
				status = libssh2_ntohu32(s);					s += 4;
				descr_len = libssh2_ntohu32(s);					s += 4;
				descr = s;										s += descr_len;
				lang_len = libssh2_ntohu32(s);					s += 4;
				lang = s;										s += lang_len;

				if (s > data + data_len) {
					libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
					goto err_exit;
				}

				if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
					LIBSSH2_FREE(session, data);
					*pkey_list = list;
					*num_keys = keys;
					return 0;
				}

				libssh2_publickey_status_error(pkey, session, status, descr, descr_len);
				goto err_exit;
			}
			case LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY:
				/* What we want */
				if (keys >= max_keys) {
					/* Grow the key list if necessary */
					max_keys += 8;
					list = LIBSSH2_REALLOC(session, list, (max_keys + 1) * sizeof(libssh2_publickey_list));
					if (!list) {
						libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey list", 0);
						goto err_exit;
					}
				}
				if (pkey->version == 1) {
					unsigned long comment_len;

					comment_len = libssh2_ntohu32(s);								s += 4;
					if (comment_len) {
						list[keys].num_attrs = 1;
						list[keys].attrs = LIBSSH2_ALLOC(session, sizeof(libssh2_publickey_attribute));
						if (!list[keys].attrs) {
							libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey attributes", 0);
							goto err_exit;
						}
						list[keys].attrs[0].name = "comment";
						list[keys].attrs[0].name_len = sizeof("comment") - 1;
						list[keys].attrs[0].value = s;
						list[keys].attrs[0].value_len = comment_len;
						list[keys].attrs[0].mandatory = 0;

						s += comment_len;
					} else {
						list[keys].num_attrs = 0;
						list[keys].attrs = NULL;
					}
					list[keys].name_len = libssh2_ntohu32(s);						s += 4;
					list[keys].name = s;											s += list[keys].name_len;
					list[keys].blob_len = libssh2_ntohu32(s);						s += 4;
					list[keys].blob = s;											s += list[keys].blob_len;
				} else {
					/* Version == 2 */
					list[keys].name_len = libssh2_ntohu32(s);						s += 4;
					list[keys].name = s;											s += list[keys].name_len;
					list[keys].blob_len = libssh2_ntohu32(s);						s += 4;
					list[keys].blob = s;											s += list[keys].blob_len;
					list[keys].num_attrs = libssh2_ntohu32(s);						s += 4;
					if (list[keys].num_attrs) {
						list[keys].attrs = LIBSSH2_ALLOC(session, list[keys].num_attrs * sizeof(libssh2_publickey_attribute));
						if (!list[keys].attrs) {
							libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey attributes", 0);
							goto err_exit;
						}
						for(i = 0; i < list[keys].num_attrs; i++) {
							list[keys].attrs[i].name_len = libssh2_ntohu32(s);			s += 4;
							list[keys].attrs[i].name = s;								s += list[keys].attrs[i].name_len;
							list[keys].attrs[i].value_len = libssh2_ntohu32(s);			s += 4;
							list[keys].attrs[i].value = s;								s += list[keys].attrs[i].value_len;
							list[keys].attrs[i].mandatory = 0;	/* actually an ignored value */
						}
					} else {
						list[keys].attrs = NULL;
					}
				}
				list[keys].packet = data; /* To be FREEd in libssh2_publickey_list_free() */
				keys++;

				list[keys].packet = NULL; /* Terminate the list */
				data = NULL;
				break;
			default:
				/* Unknown/Unexpected */
				libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
				LIBSSH2_FREE(session, data);
		}
	}

	/* Only reached via explicit goto */
 err_exit:
	if (data) {
		LIBSSH2_FREE(session, data);
	}
	if (list) {
		libssh2_publickey_list_free(pkey, list);
	}
	return -1;
}
示例#4
0
文件: openssl.c 项目: yeonsh/libssh2
int
_libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
                                unsigned char **method,
                                size_t *method_len,
                                unsigned char **pubkeydata,
                                size_t *pubkeydata_len,
                                const char *privatekeydata,
                                size_t privatekeydata_len,
                                const char *passphrase)
{
    int       st;
    BIO*      bp;
    EVP_PKEY* pk;

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

    bp = BIO_new_mem_buf((char *)privatekeydata, privatekeydata_len);
    if (!bp) {
        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) {
        return _libssh2_error(session,
                              LIBSSH2_ERROR_FILE,
                              "Unable to extract public key "
                              "from private key file: "
                              "Wrong passphrase or invalid/unrecognized "
                              "private key file format");
    }

    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 = _libssh2_error(session,
                            LIBSSH2_ERROR_FILE,
                            "Unable to extract public key "
                            "from private key file: "
                            "Unsupported private key file format");
        break;
    }

    EVP_PKEY_free(pk);
    return st;
}
示例#5
0
/* {{{ libssh2_publickey_init
 * Startup the publickey subsystem
 */
LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session)
{
	LIBSSH2_PUBLICKEY *pkey = NULL;
	LIBSSH2_CHANNEL *channel = NULL;
	unsigned char buffer[19];
	/*	packet_len(4) + 
		version_len(4) + 
		"version"(7) + 
		version_num(4) */
	unsigned char *s, *data = NULL;
	unsigned long data_len;
	int response;

#ifdef LIBSSH2_DEBUG_PUBLICKEY
	_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Initializing publickey subsystem");
#endif

	channel = libssh2_channel_open_session(session);
	if (!channel) {
		libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to startup channel", 0);
		goto err_exit;
	}
	if (libssh2_channel_subsystem(channel, "publickey")) {
		libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to request publickey subsystem", 0);
		goto err_exit;
	}

	libssh2_channel_set_blocking(channel, 1);
	libssh2_channel_handle_extended_data(channel, LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);

	pkey = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PUBLICKEY));
	if (!pkey) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a new publickey structure", 0);
		goto err_exit;
	}
	pkey->channel = channel;
	pkey->version = 0;

	s = buffer;
	libssh2_htonu32(s, 4 + (sizeof("version") - 1) + 4);	s += 4;
	libssh2_htonu32(s, sizeof("version") - 1);				s += 4;
	memcpy(s, "version", sizeof("version") - 1);			s += sizeof("version") - 1;
	libssh2_htonu32(s, LIBSSH2_PUBLICKEY_VERSION);			s += 4;

#ifdef LIBSSH2_DEBUG_PUBLICKEY
	_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey version packet advertising version %d support", (int)LIBSSH2_PUBLICKEY_VERSION);
#endif
    if ((s - buffer) != libssh2_channel_write(channel, buffer, (s - buffer))) {
        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey version packet", 0);
		goto err_exit;
    }

	while (1) {
		if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
			libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
			goto err_exit;
		}

		s = data;
		if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
			libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
			goto err_exit;
		}

		switch (response) {
			case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
			/* Error */
			{
				unsigned long status, descr_len, lang_len;
				unsigned char *descr, *lang;
				
				status = libssh2_ntohu32(s);					s += 4;
				descr_len = libssh2_ntohu32(s);					s += 4;
				descr = s;										s += descr_len;
				lang_len = libssh2_ntohu32(s);					s += 4;
				lang = s;										s += lang_len;

				if (s > data + data_len) {
					libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
					goto err_exit;
				}

				libssh2_publickey_status_error(NULL, session, status, descr, descr_len);
				goto err_exit;
			}
			case LIBSSH2_PUBLICKEY_RESPONSE_VERSION:
				/* What we want */
				pkey->version = libssh2_ntohu32(s);
				if (pkey->version > LIBSSH2_PUBLICKEY_VERSION) {
#ifdef LIBSSH2_DEBUG_PUBLICKEY
					_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Truncating remote publickey version from %lu", pkey->version);
#endif
					pkey->version = LIBSSH2_PUBLICKEY_VERSION;
				}
#ifdef LIBSSH2_DEBUG_PUBLICKEY
				_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Enabling publickey subsystem version %lu", pkey->version);
#endif
				LIBSSH2_FREE(session, data);
				return pkey;
			default:
				/* Unknown/Unexpected */
				libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
				LIBSSH2_FREE(session, data);
				data = NULL;
		}
	}

	/* Never reached except by direct goto */
 err_exit:
	if (channel) {
		libssh2_channel_close(channel);
	}
	if (pkey) {
		LIBSSH2_FREE(session, pkey);
	}
	if (data) {
		LIBSSH2_FREE(session, data);
	}
	return NULL;
}
示例#6
0
文件: session.c 项目: roderico/linm
/* {{{ libssh2_session_disconnect_ex
 */
LIBSSH2_API int
libssh2_session_disconnect_ex(LIBSSH2_SESSION * session, int reason,
                              const char *description, const char *lang)
{
    unsigned char *s;
    unsigned long descr_len = 0, lang_len = 0;
    int rc;

    if (session->disconnect_state == libssh2_NB_state_idle) {
        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
                       "Disconnecting: reason=%d, desc=%s, lang=%s", reason,
                       description, lang);
        if (description) {
            descr_len = strlen(description);
        }
        if (lang) {
            lang_len = strlen(lang);
        }
        /* 13 = packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */
        session->disconnect_data_len = descr_len + lang_len + 13;

        s = session->disconnect_data =
            LIBSSH2_ALLOC(session, session->disconnect_data_len);
        if (!session->disconnect_data) {
            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                          "Unable to allocate memory for disconnect packet",
                          0);
            session->disconnect_state = libssh2_NB_state_idle;
            return -1;
        }

        *(s++) = SSH_MSG_DISCONNECT;
        libssh2_htonu32(s, reason);
        s += 4;

        libssh2_htonu32(s, descr_len);
        s += 4;
        if (description) {
            memcpy(s, description, descr_len);
            s += descr_len;
        }

        libssh2_htonu32(s, lang_len);
        s += 4;
        if (lang) {
            memcpy(s, lang, lang_len);
            s += lang_len;
        }

        session->disconnect_state = libssh2_NB_state_created;
    }

    rc = libssh2_packet_write(session, session->disconnect_data,
                              session->disconnect_data_len);
    if (rc == PACKET_EAGAIN) {
        return PACKET_EAGAIN;
    }

    LIBSSH2_FREE(session, session->disconnect_data);
    session->disconnect_data = NULL;
    session->disconnect_state = libssh2_NB_state_idle;

    return 0;
}
示例#7
0
文件: openssl.c 项目: stinb/libssh2
int
_libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
                                unsigned char **method,
                                size_t *method_len,
                                unsigned char **pubkeydata,
                                size_t *pubkeydata_len,
                                const char *privatekeydata,
                                size_t privatekeydata_len,
                                const char *passphrase)
{
    int       st;
    BIO*      bp;
    EVP_PKEY* pk;
    int       pktype;

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

    bp = BIO_new_mem_buf((char *)privatekeydata, privatekeydata_len);
    if(!bp) {
        return -1;
    }

    BIO_reset(bp);
    pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void *)passphrase);
    BIO_free(bp);

    if(pk == NULL) {
        return _libssh2_error(session,
                              LIBSSH2_ERROR_FILE,
                              "Unable to extract public key "
                              "from private key file: "
                              "Wrong passphrase or invalid/unrecognized "
                              "private key file format");
    }

#ifdef HAVE_OPAQUE_STRUCTS
    pktype = EVP_PKEY_id(pk);
#else
    pktype = pk->type;
#endif

    switch(pktype) {
    case EVP_PKEY_RSA :
        st = gen_publickey_from_rsa_evp(session, method, method_len,
                                        pubkeydata, pubkeydata_len, pk);
        break;
#if LIBSSH2_DSA
    case EVP_PKEY_DSA :
        st = gen_publickey_from_dsa_evp(session, method, method_len,
                                        pubkeydata, pubkeydata_len, pk);
        break;
#endif /* LIBSSH_DSA */
    default :
        st = _libssh2_error(session,
                            LIBSSH2_ERROR_FILE,
                            "Unable to extract public key "
                            "from private key file: "
                            "Unsupported private key file format");
        break;
    }

    EVP_PKEY_free(pk);
    return st;
}
示例#8
0
/* {{{ libssh2_packet_new
 * Create a new packet and attach it to the brigade
 */
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 received for channel %lu/%lu stream #%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) {
                        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 = libssh2_packet_queue_listener(session, data, datalen,
                                                   &session->
                                                   packAdd_Qlstn_state);
                if (rc == PACKET_EAGAIN) {
                    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 = libssh2_packet_x11_open(session, data, datalen,
                                             &session->packAdd_x11open_state);
                if (rc == PACKET_EAGAIN) {
                    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;
        }
        /*
         * 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->packAdd_key_state);
        if (rc == PACKET_EAGAIN) {
            return PACKET_EAGAIN;
        }
    }

    session->packAdd_state = libssh2_NB_state_idle;
    return 0;
}
示例#9
0
/* {{{ libssh2_packet_queue_listener
 * Queue a connection request for a listener
 */
static inline int
libssh2_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_packet_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_packet_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;
    }
}
示例#10
0
/*
 * libssh2_scp_send_ex
 *
 * Send a file using SCP
 *
 */
LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode,
                    size_t size, long mtime, long atime)
{
    int cmd_len;
    unsigned const char *base;
    int rc;

    if (session->scpSend_state == libssh2_NB_state_idle) {
        session->scpSend_command_len =
            libssh2_shell_quotedsize(path) + sizeof("scp -t ") +
            ((mtime || atime)?1:0);

        session->scpSend_command =
            LIBSSH2_ALLOC(session, session->scpSend_command_len);
        if (!session->scpSend_command) {
            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                          "Unable to allocate a command buffer for scp session",
                          0);
            return NULL;
        }

        sprintf((char *)session->scpSend_command, "scp -%st ",
                (mtime || atime)?"p":"");

        cmd_len = strlen((char *)session->scpSend_command);

        (void)libssh2_shell_quotearg(path,
                                     &session->scpSend_command[cmd_len],
                                     session->scpSend_command_len - cmd_len);

        session->scpSend_command[session->scpSend_command_len - 1] = '\0';

        _libssh2_debug(session, LIBSSH2_DBG_SCP,
                       "Opening channel for SCP send");
        /* Allocate a channel */

        session->scpSend_state = libssh2_NB_state_created;
    }

    if (session->scpSend_state == libssh2_NB_state_created) {
        session->scpSend_channel =
            libssh2_channel_open_ex(session, "session", sizeof("session") - 1,
                                    LIBSSH2_CHANNEL_WINDOW_DEFAULT,
                                    LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0);
        if (!session->scpSend_channel) {
            if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
                /* previous call set libssh2_session_last_error(), pass it
                   through */
                LIBSSH2_FREE(session, session->scpSend_command);
                session->scpSend_command = NULL;
                session->scpSend_state = libssh2_NB_state_idle;
            }
            else {
                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                              "Would block starting up channel", 0);
            }
            return NULL;
        }

        session->scpSend_state = libssh2_NB_state_sent;
    }

    if (session->scpSend_state == libssh2_NB_state_sent) {
        /* Request SCP for the desired file */
        rc = libssh2_channel_process_startup(session->scpSend_channel, "exec",
                                             sizeof("exec") - 1,
                                             (char *) session->scpSend_command,
                                             session->scpSend_command_len);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block requesting SCP startup", 0);
            return NULL;
        }
        else if (rc) {
            /* previous call set libssh2_session_last_error(), pass it
               through */
            LIBSSH2_FREE(session, session->scpSend_command);
            session->scpSend_command = NULL;
            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                          "Unknown error while getting error string", 0);
            goto scp_send_error;
        }
        LIBSSH2_FREE(session, session->scpSend_command);
        session->scpSend_command = NULL;

        session->scpSend_state = libssh2_NB_state_sent1;
    }

    if (session->scpSend_state == libssh2_NB_state_sent1) {
        /* Wait for ACK */
        rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
                                     (char *) session->scpSend_response, 1);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block waiting for response from remote", 0);
            return NULL;
        } else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                          "Invalid ACK response from remote", 0);
            goto scp_send_error;
        }

        if (mtime || atime) {
            /* Send mtime and atime to be used for file */
            session->scpSend_response_len =
                snprintf((char *) session->scpSend_response,
                         LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", mtime,
                         atime);
            _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s",
                           session->scpSend_response);
        }

        session->scpSend_state = libssh2_NB_state_sent2;
    }

    /* Send mtime and atime to be used for file */
    if (mtime || atime) {
        if (session->scpSend_state == libssh2_NB_state_sent2) {
            rc = libssh2_channel_write_ex(session->scpSend_channel, 0,
                                          (char *) session->scpSend_response,
                                          session->scpSend_response_len);
            if (rc == PACKET_EAGAIN) {
                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                              "Would block sending time data for SCP file", 0);
                return NULL;
            } else if (rc != (int)session->scpSend_response_len) {
                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
                              "Unable to send time data for SCP file", 0);
                goto scp_send_error;
            }

            session->scpSend_state = libssh2_NB_state_sent3;
        }

        if (session->scpSend_state == libssh2_NB_state_sent3) {
            /* Wait for ACK */
            rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
                                         (char *) session->scpSend_response,
                                         1);
            if (rc == PACKET_EAGAIN) {
                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                              "Would block waiting for response", 0);
                return NULL;
            } else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
                libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                              "Invalid ACK response from remote", 0);
                goto scp_send_error;
            }

            session->scpSend_state = libssh2_NB_state_sent4;
        }
    } else {
        if (session->scpSend_state == libssh2_NB_state_sent2) {
            session->scpSend_state = libssh2_NB_state_sent4;
        }
    }

    if (session->scpSend_state == libssh2_NB_state_sent4) {
        /* Send mode, size, and basename */
        base = (unsigned char *) strrchr(path, '/');
        if (base) {
            base++;
        } else {
            base = (unsigned char *) path;
        }

        session->scpSend_response_len =
            snprintf((char *) session->scpSend_response,
                     LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %lu %s\n", mode,
                     (unsigned long) size, base);
        _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s",
                       session->scpSend_response);

        session->scpSend_state = libssh2_NB_state_sent5;
    }

    if (session->scpSend_state == libssh2_NB_state_sent5) {
        rc = libssh2_channel_write_ex(session->scpSend_channel, 0,
                                      (char *) session->scpSend_response,
                                      session->scpSend_response_len);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block send core file data for SCP file", 0);
            return NULL;
        } else if (rc != (int)session->scpSend_response_len) {
            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
                          "Unable to send core file data for SCP file", 0);
            goto scp_send_error;
        }

        session->scpSend_state = libssh2_NB_state_sent6;
    }

    if (session->scpSend_state == libssh2_NB_state_sent6) {
        /* Wait for ACK */
        rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
                                     (char *) session->scpSend_response, 1);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block waiting for response", 0);
            return NULL;
        } else if (rc <= 0) {
            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                          "Invalid ACK response from remote", 0);
            goto scp_send_error;
        } else if (session->scpSend_response[0] != 0) {
            /*
             * Set this as the default error for here, if
             * we are successful it will be replaced
             */
            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                          "Invalid ACK response from remote", 0);

            session->scpSend_err_len =
                _libssh2_channel_packet_data_len(session->scpSend_channel, 0);
            session->scpSend_err_msg =
                LIBSSH2_ALLOC(session, session->scpSend_err_len + 1);
            if (!session->scpSend_err_msg) {
                goto scp_send_error;
            }
            memset(session->scpSend_err_msg, 0, session->scpSend_err_len + 1);

            /* Read the remote error message */
            rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
                                         session->scpSend_err_msg,
                                         session->scpSend_err_len);
            if (rc <= 0) {
                /*
                 * Since we have alread started reading this packet, it is
                 * already in the systems so it can't return PACKET_EAGAIN
                 */
                LIBSSH2_FREE(session, session->scpSend_err_msg);
                session->scpSend_err_msg = NULL;
                goto scp_send_error;
            }

            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                          session->scpSend_err_msg, 1);
            session->scpSend_err_msg = NULL;
            goto scp_send_error;
        }
    }

    session->scpSend_state = libssh2_NB_state_idle;

    return session->scpSend_channel;

  scp_send_error:
    while (libssh2_channel_free(session->scpSend_channel) == PACKET_EAGAIN);
    session->scpSend_channel = NULL;
    session->scpSend_state = libssh2_NB_state_idle;
    return NULL;
}
示例#11
0
/* {{{ libssh2_packet_x11_open
 * Accept a forwarded X11 connection
 */
static inline int
libssh2_packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
                        unsigned long datalen,
                        packet_x11_open_state_t * x11open_state)
{
    int failure_code = 2;       /* SSH_OPEN_CONNECT_FAILED */
    unsigned char *s = data + (sizeof("x11") - 1) + 5;
    /* 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;
    int rc;

    (void) datalen;

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

        _libssh2_debug(session, LIBSSH2_DBG_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_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 = 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_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);
            p = x11open_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;

            x11open_state->state = libssh2_NB_state_created;
        }

        if (x11open_state->state == libssh2_NB_state_created) {
            rc = libssh2_packet_write(session, x11open_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);
                x11open_state->state = libssh2_NB_state_idle;
                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, (char *) x11open_state->shost,
                             x11open_state->sport);

            x11open_state->state = libssh2_NB_state_idle;
            return 0;
        }
    } else {
        failure_code = 4;       /* SSH_OPEN_RESOURCE_SHORTAGE */
    }

  x11_exit:
    p = x11open_state->packet;
    *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
    libssh2_htonu32(p, x11open_state->sender_channel);
    p += 4;
    libssh2_htonu32(p, failure_code);
    p += 4;
    libssh2_htonu32(p, sizeof(X11FwdUnAvil) - 1);
    p += 4;
    memcpy(s, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1);
    p += sizeof(X11FwdUnAvil) - 1;
    libssh2_htonu32(p, 0);

    rc = libssh2_packet_write(session, x11open_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);
        x11open_state->state = libssh2_NB_state_idle;
        return -1;
    }
    x11open_state->state = libssh2_NB_state_idle;
    return 0;
}
示例#12
0
/* {{{ libssh2_kexinit
 * Send SSH_MSG_KEXINIT packet
 */
static int libssh2_kexinit(LIBSSH2_SESSION *session)
{
	size_t data_len = 62; /* packet_type(1) + cookie(16) + first_packet_follows(1) + reserved(4) + length longs(40) */
	size_t kex_len,			hostkey_len = 0;
	size_t crypt_cs_len,	crypt_sc_len;
	size_t comp_cs_len,		comp_sc_len;
	size_t mac_cs_len,		mac_sc_len;
	size_t lang_cs_len,		lang_sc_len;
	unsigned char *data, *s;

	kex_len			= LIBSSH2_METHOD_PREFS_LEN(session->kex_prefs,			libssh2_kex_methods);
	hostkey_len		= LIBSSH2_METHOD_PREFS_LEN(session->hostkey_prefs,		libssh2_hostkey_methods());
	crypt_cs_len	= LIBSSH2_METHOD_PREFS_LEN(session->local.crypt_prefs,	libssh2_crypt_methods());
	crypt_sc_len	= LIBSSH2_METHOD_PREFS_LEN(session->remote.crypt_prefs,	libssh2_crypt_methods());
	mac_cs_len		= LIBSSH2_METHOD_PREFS_LEN(session->local.mac_prefs,	libssh2_mac_methods());
	mac_sc_len		= LIBSSH2_METHOD_PREFS_LEN(session->remote.mac_prefs,	libssh2_mac_methods());
	comp_cs_len		= LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs,	libssh2_comp_methods());
	comp_sc_len		= LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs,	libssh2_comp_methods());
	lang_cs_len		= LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs,	NULL);
	lang_sc_len		= LIBSSH2_METHOD_PREFS_LEN(session->remote.lang_prefs,	NULL);

	data_len += kex_len			+ hostkey_len + \
				crypt_cs_len	+ crypt_sc_len + \
				comp_cs_len		+ comp_sc_len + \
				mac_cs_len		+ mac_sc_len + \
				lang_cs_len		+ lang_sc_len;

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

	*(s++) = SSH_MSG_KEXINIT;

	libssh2_random(s, 16);
	s += 16;

	/* Ennumerating through these lists twice is probably (certainly?) inefficient from a CPU standpoint, but it saves multiple malloc/realloc calls */
	LIBSSH2_METHOD_PREFS_STR(s, kex_len,		session->kex_prefs,				libssh2_kex_methods);
	LIBSSH2_METHOD_PREFS_STR(s, hostkey_len,	session->hostkey_prefs,			libssh2_hostkey_methods());
	LIBSSH2_METHOD_PREFS_STR(s, crypt_cs_len,	session->local.crypt_prefs,		libssh2_crypt_methods());
	LIBSSH2_METHOD_PREFS_STR(s, crypt_sc_len,	session->remote.crypt_prefs,	libssh2_crypt_methods());
	LIBSSH2_METHOD_PREFS_STR(s, mac_cs_len,		session->local.mac_prefs,		libssh2_mac_methods());
	LIBSSH2_METHOD_PREFS_STR(s, mac_sc_len,		session->remote.mac_prefs,		libssh2_mac_methods());
	LIBSSH2_METHOD_PREFS_STR(s, comp_cs_len,	session->local.comp_prefs,		libssh2_comp_methods());
	LIBSSH2_METHOD_PREFS_STR(s, comp_sc_len,	session->remote.comp_prefs,		libssh2_comp_methods());
	LIBSSH2_METHOD_PREFS_STR(s, lang_cs_len,	session->local.lang_prefs,		NULL);
	LIBSSH2_METHOD_PREFS_STR(s, lang_sc_len,	session->remote.lang_prefs,		NULL);

	/* No optimistic KEX packet follows */
	/* Deal with optimistic packets
	 * session->flags |= KEXINIT_OPTIMISTIC
	 * session->flags |= KEXINIT_METHODSMATCH
	 */
	*(s++) = 0;

	/* Reserved == 0 */
	*(s++) = 0;
	*(s++) = 0;
	*(s++) = 0;
	*(s++) = 0;

#ifdef LIBSSH2_DEBUG_KEX
{
	/* Funnily enough, they'll all "appear" to be '\0' terminated */
	char *p = data + 21; /* type(1) + cookie(16) + len(4) */

	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent KEX: %s", p);				p += kex_len + 4;
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent HOSTKEY: %s", p);			p += hostkey_len + 4;
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent CRYPT_CS: %s", p);			p += crypt_cs_len + 4;
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent CRYPT_SC: %s", p);			p += crypt_sc_len + 4;
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent MAC_CS: %s", p);				p += mac_cs_len + 4;
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent MAC_SC: %s", p);				p += mac_sc_len + 4;
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent COMP_CS: %s", p);			p += comp_cs_len + 4;
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent COMP_SC: %s", p);			p += comp_sc_len + 4;
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent LANG_CS: %s", p);			p += lang_cs_len + 4;
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent LANG_SC: %s", p);			p += lang_sc_len + 4;
}
#endif /* LIBSSH2_DEBUG_KEX */
	if (libssh2_packet_write(session, data, data_len)) {
		LIBSSH2_FREE(session, data);
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send KEXINIT packet to remote host", 0);
		return -1;
	}

	if (session->local.kexinit) {
		LIBSSH2_FREE(session, session->local.kexinit);
	}

	session->local.kexinit = data;
	session->local.kexinit_len = data_len;

	return 0;
}
示例#13
0
/* {{{ libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange
 * Diffie Hellman Key Exchange, Group Agnostic
 */
static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session, _libssh2_bn *g, _libssh2_bn *p, int group_order,
																		unsigned char packet_type_init, unsigned char packet_type_reply,
																		unsigned char *midhash, unsigned long midhash_len)
{
	unsigned char *e_packet = NULL, *s_packet = NULL, *tmp, h_sig_comp[SHA_DIGEST_LENGTH], c;
	unsigned long e_packet_len, s_packet_len, tmp_len;
	int ret = 0;
	_libssh2_bn_ctx *ctx = _libssh2_bn_ctx_new();
	_libssh2_bn *x = _libssh2_bn_init(); /* Random from client */
	_libssh2_bn *e = _libssh2_bn_init(); /* g^x mod p */
	_libssh2_bn *f = _libssh2_bn_init(); /* g^(Random from server) mod p */
	_libssh2_bn *k = _libssh2_bn_init(); /* The shared secret: f^x mod p */
	unsigned char *s, *f_value, *k_value = NULL, *h_sig;
	unsigned long f_value_len, k_value_len, h_sig_len;
	libssh2_sha1_ctx exchange_hash;

	/* Generate x and e */
	_libssh2_bn_rand(x, group_order, 0, -1);
	_libssh2_bn_mod_exp(e, g, x, p, ctx);

	/* Send KEX init */
	e_packet_len = _libssh2_bn_bytes(e) + 6; /* packet_type(1) + String Length(4) + leading 0(1) */
	if (_libssh2_bn_bits(e) % 8) {
		/* Leading 00 not needed */
		e_packet_len--;
	}
	e_packet = LIBSSH2_ALLOC(session, e_packet_len);
	if (!e_packet) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Out of memory error", 0);
		ret = -1;
		goto clean_exit;
	}
	e_packet[0] = packet_type_init;
	libssh2_htonu32(e_packet + 1, e_packet_len - 5);
	if (_libssh2_bn_bits(e) % 8) {
		_libssh2_bn_to_bin(e, e_packet + 5);
	} else {
		e_packet[5] = 0;
		_libssh2_bn_to_bin(e, e_packet + 6);
	}

#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending KEX packet %d", (int)packet_type_init);
#endif
	if (libssh2_packet_write(session, e_packet, e_packet_len)) {
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send KEX init message", 0);
		ret = -11;
		goto clean_exit;
	}

	if (session->burn_optimistic_kexinit) {
		/* The first KEX packet to come along will be the guess initially sent by the server
		 * That guess turned out to be wrong so we need to silently ignore it */
		int burn_type;
#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Waiting for badly guessed KEX packet (to be ignored)");
#endif
		burn_type = libssh2_packet_burn(session);
		if (burn_type <= 0) {
			/* Failed to receive a packet */
			ret = -1;
			goto clean_exit;
		}
		session->burn_optimistic_kexinit = 0;

#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Burnt packet of type: %02x", (unsigned int)burn_type);
#endif
	}

	/* Wait for KEX reply */
	if (libssh2_packet_require(session, packet_type_reply, &s_packet, &s_packet_len)) {
		libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, "Timed out waiting for KEX reply", 0);
		ret = -1;
		goto clean_exit;
	}

	/* Parse KEXDH_REPLY */
	s = s_packet + 1;

	session->server_hostkey_len = libssh2_ntohu32(s);			s += 4;
	session->server_hostkey = LIBSSH2_ALLOC(session, session->server_hostkey_len);
	if (!session->server_hostkey) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for a copy of the host key", 0);
		ret = -1;
		goto clean_exit;
	}
	memcpy(session->server_hostkey, s, session->server_hostkey_len);
	s += session->server_hostkey_len;

#if LIBSSH2_MD5
{
	libssh2_md5_ctx fingerprint_ctx;

	libssh2_md5_init(&fingerprint_ctx);
	libssh2_md5_update(fingerprint_ctx, session->server_hostkey, session->server_hostkey_len);
	libssh2_md5_final(fingerprint_ctx, session->server_hostkey_md5);
}
#ifdef LIBSSH2_DEBUG_KEX
{
	char fingerprint[50], *fprint = fingerprint;
	int i;
	for(i = 0; i < 16; i++, fprint += 3) {
		snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]);
	}
	*(--fprint) = '\0';
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server's MD5 Fingerprint: %s", fingerprint);
}
#endif /* LIBSSH2_DEBUG_KEX */
#endif /* ! LIBSSH2_MD5 */

{
	libssh2_sha1_ctx fingerprint_ctx;

	libssh2_sha1_init(&fingerprint_ctx);
	libssh2_sha1_update (fingerprint_ctx, session->server_hostkey, session->server_hostkey_len);
	libssh2_sha1_final(fingerprint_ctx, session->server_hostkey_sha1);
}
#ifdef LIBSSH2_DEBUG_KEX
{
	char fingerprint[64], *fprint = fingerprint;
	int i;
	for(i = 0; i < 20; i++, fprint += 3) {
		snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]);
	}
	*(--fprint) = '\0';
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server's SHA1 Fingerprint: %s", fingerprint);
}
#endif /* LIBSSH2_DEBUG_KEX */

	if (session->hostkey->init(session, session->server_hostkey, session->server_hostkey_len, &session->server_hostkey_abstract)) {
		libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, "Unable to initialize hostkey importer", 0);
		ret = -1;
		goto clean_exit;
	}

	f_value_len = libssh2_ntohu32(s);							s += 4;
	f_value = s;												s += f_value_len;
	_libssh2_bn_from_bin(f, f_value_len, f_value);

	h_sig_len = libssh2_ntohu32(s);								s += 4;
	h_sig = s;

	/* Compute the shared secret */
	_libssh2_bn_mod_exp(k, f, x, p, ctx);
	k_value_len = _libssh2_bn_bytes(k) + 5;
	if (_libssh2_bn_bits(k) % 8) {
		/* don't need leading 00 */
		k_value_len--;
	}
	k_value = LIBSSH2_ALLOC(session, k_value_len);
	if (!k_value) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate buffer for K", 0);
		ret = -1;
		goto clean_exit;
	}
	libssh2_htonu32(k_value, k_value_len - 4);
	if (_libssh2_bn_bits(k) % 8) {
		_libssh2_bn_to_bin(k, k_value + 4);
	} else {
		k_value[4] = 0;
		_libssh2_bn_to_bin(k, k_value + 5);
	}

	libssh2_sha1_init(&exchange_hash);
	if (session->local.banner) {
		libssh2_htonu32(h_sig_comp,
				strlen((char *)session->local.banner) - 2);
		libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
		libssh2_sha1_update(exchange_hash, (char *)session->local.banner,
			    strlen((char *)session->local.banner) - 2);
	} else {
		libssh2_htonu32(h_sig_comp, sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
		libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
		libssh2_sha1_update(exchange_hash, LIBSSH2_SSH_DEFAULT_BANNER,
			    sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
	}

	libssh2_htonu32(h_sig_comp, strlen((char *)session->remote.banner));
	libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
	libssh2_sha1_update(exchange_hash, session->remote.banner,
		    strlen((char *)session->remote.banner));

	libssh2_htonu32(h_sig_comp, session->local.kexinit_len);
	libssh2_sha1_update(exchange_hash,		h_sig_comp,							4);
	libssh2_sha1_update(exchange_hash,		session->local.kexinit,				session->local.kexinit_len);

	libssh2_htonu32(h_sig_comp, session->remote.kexinit_len);
	libssh2_sha1_update(exchange_hash,		h_sig_comp,							4);
	libssh2_sha1_update(exchange_hash,		session->remote.kexinit,			session->remote.kexinit_len);

	libssh2_htonu32(h_sig_comp, session->server_hostkey_len);
	libssh2_sha1_update(exchange_hash,		h_sig_comp,							4);
	libssh2_sha1_update(exchange_hash,		session->server_hostkey,			session->server_hostkey_len);

	if (packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) {
		/* diffie-hellman-group-exchange hashes additional fields */
#ifdef LIBSSH2_DH_GEX_NEW
		libssh2_htonu32(h_sig_comp,		LIBSSH2_DH_GEX_MINGROUP);
		libssh2_htonu32(h_sig_comp + 4,	LIBSSH2_DH_GEX_OPTGROUP);
		libssh2_htonu32(h_sig_comp + 8, LIBSSH2_DH_GEX_MAXGROUP);
		libssh2_sha1_update(exchange_hash,	h_sig_comp,							12);
#else
		libssh2_htonu32(h_sig_comp,		LIBSSH2_DH_GEX_OPTGROUP);
		libssh2_sha1_update(exchange_hash,	h_sig_comp,							4);
#endif
	}

	if (midhash) {
		libssh2_sha1_update(exchange_hash, midhash,							midhash_len);
	}

	libssh2_sha1_update(exchange_hash,		e_packet + 1,						e_packet_len - 1);

	libssh2_htonu32(h_sig_comp, f_value_len);
	libssh2_sha1_update(exchange_hash,		h_sig_comp,							4);
	libssh2_sha1_update(exchange_hash,		f_value,							f_value_len);

	libssh2_sha1_update(exchange_hash,		k_value,							k_value_len);

	libssh2_sha1_final(exchange_hash, h_sig_comp);

	if (session->hostkey->sig_verify(session, h_sig, h_sig_len, h_sig_comp, 20, &session->server_hostkey_abstract)) {
		libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, "Unable to verify hostkey signature", 0);
		ret = -1;
		goto clean_exit;
	}

#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending NEWKEYS message");
#endif
	c = SSH_MSG_NEWKEYS;
	if (libssh2_packet_write(session, &c, 1)) {
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send NEWKEYS message", 0);
		ret = -1;
		goto clean_exit;
	}

	if (libssh2_packet_require(session, SSH_MSG_NEWKEYS, &tmp, &tmp_len)) {
		libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, "Timed out waiting for NEWKEYS", 0);
		ret = -1;
		goto clean_exit;
	}
	/* The first key exchange has been performed, switch to active crypt/comp/mac mode */
	session->state |= LIBSSH2_STATE_NEWKEYS;
#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Received NEWKEYS message");
#endif

	/* This will actually end up being just packet_type(1) for this packet type anyway */
	LIBSSH2_FREE(session, tmp);

	if (!session->session_id) {
		session->session_id = LIBSSH2_ALLOC(session, SHA_DIGEST_LENGTH);
		if (!session->session_id) {
			ret = -1;
			goto clean_exit;
		}
		memcpy(session->session_id, h_sig_comp, SHA_DIGEST_LENGTH);
		session->session_id_len = SHA_DIGEST_LENGTH;
#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "session_id calculated");
#endif
	}

	/* Cleanup any existing cipher */
	if (session->local.crypt->dtor) {
		session->local.crypt->dtor(session, &session->local.crypt_abstract);
	}

	/* Calculate IV/Secret/Key for each direction */
	if (session->local.crypt->init) {
		unsigned char *iv = NULL, *secret = NULL;
		int free_iv = 0, free_secret = 0;

		LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, session->local.crypt->iv_len, "A");
		LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, session->local.crypt->secret_len, "C");
		if (session->local.crypt->init(session, session->local.crypt, iv, &free_iv, secret, &free_secret, 1, &session->local.crypt_abstract)) {
		  LIBSSH2_FREE(session, iv);
		  LIBSSH2_FREE(session, secret);
		  ret = -1;
		  goto clean_exit;
		}

		if (free_iv) {
			memset(iv, 0, session->local.crypt->iv_len);
			LIBSSH2_FREE(session, iv);
		}

		if (free_secret) {
			memset(secret, 0, session->local.crypt->secret_len);
			LIBSSH2_FREE(session, secret);
		}
	}
#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Client to Server IV and Key calculated");
#endif

	if (session->remote.crypt->dtor) {
		/* Cleanup any existing cipher */
		session->remote.crypt->dtor(session, &session->remote.crypt_abstract);
	}

	if (session->remote.crypt->init) {
		unsigned char *iv = NULL, *secret = NULL;
		int free_iv = 0, free_secret = 0;

		LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, session->remote.crypt->iv_len, "B");
		LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, session->remote.crypt->secret_len, "D");
		if (session->remote.crypt->init(session, session->remote.crypt, iv, &free_iv, secret, &free_secret, 0, &session->remote.crypt_abstract)) {
		  LIBSSH2_FREE(session, iv);
		  LIBSSH2_FREE(session, secret);
		  ret = -1;
		  goto clean_exit;
		}

		if (free_iv) {
			memset(iv, 0, session->remote.crypt->iv_len);
			LIBSSH2_FREE(session, iv);
		}

		if (free_secret) {
			memset(secret, 0, session->remote.crypt->secret_len);
			LIBSSH2_FREE(session, secret);
		}
	}
#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server to Client IV and Key calculated");
#endif

	if (session->local.mac->dtor) {
		session->local.mac->dtor(session, &session->local.mac_abstract);
	}

	if (session->local.mac->init) {
		unsigned char *key = NULL;
		int free_key = 0;

		LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->local.mac->key_len, "E");
		session->local.mac->init(session, key, &free_key, &session->local.mac_abstract);

		if (free_key) {
			memset(key, 0, session->local.mac->key_len);
			LIBSSH2_FREE(session, key);
		}
	}
#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Client to Server HMAC Key calculated");
#endif

	if (session->remote.mac->dtor) {
		session->remote.mac->dtor(session, &session->remote.mac_abstract);
	}

	if (session->remote.mac->init) {
		unsigned char *key = NULL;
		int free_key = 0;

		LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->remote.mac->key_len, "F");
		session->remote.mac->init(session, key, &free_key, &session->remote.mac_abstract);

		if (free_key) {
			memset(key, 0, session->remote.mac->key_len);
			LIBSSH2_FREE(session, key);
		}
	}
#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server to Client HMAC Key calculated");
#endif

 clean_exit:
	_libssh2_bn_free(x);
	_libssh2_bn_free(e);
	_libssh2_bn_free(f);
	_libssh2_bn_free(k);
	_libssh2_bn_ctx_free(ctx);

	if (e_packet) {
		LIBSSH2_FREE(session, e_packet);
	}

	if (s_packet) {
		LIBSSH2_FREE(session, s_packet);
	}

	if (k_value) {
		LIBSSH2_FREE(session, k_value);
	}

	if (session->server_hostkey) {
		LIBSSH2_FREE(session, session->server_hostkey);
		session->server_hostkey = NULL;
	}

	return ret;
}
示例#14
0
/* {{{ libssh2_kex_agree_methods
 * Decide which specific method to use of the methods offered by each party
 */
static int libssh2_kex_agree_methods(LIBSSH2_SESSION *session, unsigned char *data, unsigned data_len)
{
	unsigned char *kex, *hostkey, *crypt_cs, *crypt_sc, *comp_cs, *comp_sc, *mac_cs, *mac_sc, *lang_cs, *lang_sc;
	size_t kex_len, hostkey_len, crypt_cs_len, crypt_sc_len, comp_cs_len, comp_sc_len, mac_cs_len, mac_sc_len, lang_cs_len, lang_sc_len;
	unsigned char *s = data;

	/* Skip packet_type, we know it already */
	s++;

	/* Skip cookie, don't worry, it's preserved in the kexinit field */
	s += 16;

	/* Locate each string */
	kex_len			= libssh2_ntohu32(s);		kex			= s + 4;		s += 4 + kex_len;
	hostkey_len		= libssh2_ntohu32(s);		hostkey		= s + 4;		s += 4 + hostkey_len;
	crypt_cs_len	= libssh2_ntohu32(s);		crypt_cs	= s + 4;		s += 4 + crypt_cs_len;
	crypt_sc_len	= libssh2_ntohu32(s);		crypt_sc	= s + 4;		s += 4 + crypt_sc_len;
	mac_cs_len		= libssh2_ntohu32(s);		mac_cs		= s + 4;		s += 4 + mac_cs_len;
	mac_sc_len		= libssh2_ntohu32(s);		mac_sc		= s + 4;		s += 4 + mac_sc_len;
	comp_cs_len		= libssh2_ntohu32(s);		comp_cs		= s + 4;		s += 4 + comp_cs_len;
	comp_sc_len		= libssh2_ntohu32(s);		comp_sc		= s + 4;		s += 4 + comp_sc_len;
	lang_cs_len		= libssh2_ntohu32(s);		lang_cs		= s + 4;		s += 4 + lang_cs_len;
	lang_sc_len		= libssh2_ntohu32(s);		lang_sc		= s + 4;		s += 4 + lang_sc_len;

	/* If the server sent an optimistic packet, assume that it guessed wrong.
	 * If the guess is determined to be right (by libssh2_kex_agree_kex_hostkey)
	 * This flag will be reset to zero so that it's not ignored */
	session->burn_optimistic_kexinit = *(s++);
	/* Next uint32 in packet is all zeros (reserved) */

	if (libssh2_kex_agree_kex_hostkey(session, kex, kex_len, hostkey, hostkey_len)) {
		return -1;
	}

	if (libssh2_kex_agree_crypt(session, &session->local,  crypt_cs, crypt_cs_len) ||
		libssh2_kex_agree_crypt(session, &session->remote, crypt_sc, crypt_sc_len)) {
		return -1;
	}

	if (libssh2_kex_agree_mac(session, &session->local,  mac_cs, mac_cs_len) ||
		libssh2_kex_agree_mac(session, &session->remote, mac_sc, mac_sc_len)) {
		return -1;
	}

	if (libssh2_kex_agree_comp(session, &session->local,  comp_cs, comp_cs_len) ||
		libssh2_kex_agree_comp(session, &session->remote, comp_sc, comp_sc_len)) {
		return -1;
	}

	if (libssh2_kex_agree_lang(session, &session->local,  lang_cs, lang_cs_len) ||
		libssh2_kex_agree_lang(session, &session->remote, lang_sc, lang_sc_len)) {
		return -1;
	}

#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on KEX method: %s", session->kex->name);
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on HOSTKEY method: %s", session->hostkey->name);
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_CS method: %s", session->local.crypt->name);
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_SC method: %s", session->remote.crypt->name);
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_CS method: %s", session->local.mac->name);
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_SC method: %s", session->remote.mac->name);
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_CS method: %s", session->local.comp->name);
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_SC method: %s", session->remote.comp->name);
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_CS method:"); /* None yet */
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_SC method:"); /* None yet */
#endif

	/* Initialize compression layer */
	if (session->local.comp && session->local.comp->init &&
		session->local.comp->init(session, 1, &session->local.comp_abstract)) {
		return -1;
	}

	if (session->remote.comp && session->remote.comp->init &&
		session->remote.comp->init(session, 0, &session->remote.comp_abstract)) {
		return -1;
	}

	return 0;
}
示例#15
0
文件: session.c 项目: roderico/linm
/* {{{ proto libssh2_session_free
 * Frees the memory allocated to the session
 * Also closes and frees any channels attached to this session
 */
LIBSSH2_API int
libssh2_session_free(LIBSSH2_SESSION * session)
{
    int rc;

    if (session->free_state == libssh2_NB_state_idle) {
        _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Freeing session resource",
                       session->remote.banner);

        session->state = libssh2_NB_state_created;
    }

    if (session->free_state == libssh2_NB_state_created) {
        while (session->channels.head) {
            LIBSSH2_CHANNEL *tmp = session->channels.head;

            rc = libssh2_channel_free(session->channels.head);
            if (rc == PACKET_EAGAIN) {
                return PACKET_EAGAIN;
            }
            if (tmp == session->channels.head) {
                /* channel_free couldn't do it's job, perform a messy cleanup */
                tmp = session->channels.head;

                /* unlink */
                session->channels.head = tmp->next;

                /* free */
                LIBSSH2_FREE(session, tmp);

                /* reverse linking isn't important here, we're killing the structure */
            }
        }

        session->state = libssh2_NB_state_sent;
    }

    if (session->state == libssh2_NB_state_sent) {
        while (session->listeners) {
            rc = libssh2_channel_forward_cancel(session->listeners);
            if (rc == PACKET_EAGAIN) {
                return PACKET_EAGAIN;
            }
        }

        session->state = libssh2_NB_state_sent1;
    }

    if (session->state & LIBSSH2_STATE_NEWKEYS) {
        /* hostkey */
        if (session->hostkey && session->hostkey->dtor) {
            session->hostkey->dtor(session, &session->server_hostkey_abstract);
        }

        /* Client to Server */
        /* crypt */
        if (session->local.crypt && session->local.crypt->dtor) {
            session->local.crypt->dtor(session,
                                       &session->local.crypt_abstract);
        }
        /* comp */
        if (session->local.comp && session->local.comp->dtor) {
            session->local.comp->dtor(session, 1,
                                      &session->local.comp_abstract);
        }
        /* mac */
        if (session->local.mac && session->local.mac->dtor) {
            session->local.mac->dtor(session, &session->local.mac_abstract);
        }

        /* Server to Client */
        /* crypt */
        if (session->remote.crypt && session->remote.crypt->dtor) {
            session->remote.crypt->dtor(session,
                                        &session->remote.crypt_abstract);
        }
        /* comp */
        if (session->remote.comp && session->remote.comp->dtor) {
            session->remote.comp->dtor(session, 0,
                                       &session->remote.comp_abstract);
        }
        /* mac */
        if (session->remote.mac && session->remote.mac->dtor) {
            session->remote.mac->dtor(session, &session->remote.mac_abstract);
        }

        /* session_id */
        if (session->session_id) {
            LIBSSH2_FREE(session, session->session_id);
        }
    }

    /* Free banner(s) */
    if (session->remote.banner) {
        LIBSSH2_FREE(session, session->remote.banner);
    }
    if (session->local.banner) {
        LIBSSH2_FREE(session, session->local.banner);
    }

    /* Free preference(s) */
    if (session->kex_prefs) {
        LIBSSH2_FREE(session, session->kex_prefs);
    }
    if (session->hostkey_prefs) {
        LIBSSH2_FREE(session, session->hostkey_prefs);
    }

    if (session->local.crypt_prefs) {
        LIBSSH2_FREE(session, session->local.crypt_prefs);
    }
    if (session->local.mac_prefs) {
        LIBSSH2_FREE(session, session->local.mac_prefs);
    }
    if (session->local.comp_prefs) {
        LIBSSH2_FREE(session, session->local.comp_prefs);
    }
    if (session->local.lang_prefs) {
        LIBSSH2_FREE(session, session->local.lang_prefs);
    }

    if (session->remote.crypt_prefs) {
        LIBSSH2_FREE(session, session->remote.crypt_prefs);
    }
    if (session->remote.mac_prefs) {
        LIBSSH2_FREE(session, session->remote.mac_prefs);
    }
    if (session->remote.comp_prefs) {
        LIBSSH2_FREE(session, session->remote.comp_prefs);
    }
    if (session->remote.lang_prefs) {
        LIBSSH2_FREE(session, session->remote.lang_prefs);
    }

    /*
     * Make sure all memory used in the state variables are free
     */
    if (session->startup_data) {
        LIBSSH2_FREE(session, session->startup_data);
    }
    if (session->disconnect_data) {
        LIBSSH2_FREE(session, session->disconnect_data);
    }
    if (session->userauth_list_data) {
        LIBSSH2_FREE(session, session->userauth_list_data);
    }
    if (session->userauth_pswd_data) {
        LIBSSH2_FREE(session, session->userauth_pswd_data);
    }
    if (session->userauth_pswd_newpw) {
        LIBSSH2_FREE(session, session->userauth_pswd_newpw);
    }
    if (session->userauth_host_packet) {
        LIBSSH2_FREE(session, session->userauth_host_packet);
    }
    if (session->userauth_host_method) {
        LIBSSH2_FREE(session, session->userauth_host_method);
    }
    if (session->userauth_host_data) {
        LIBSSH2_FREE(session, session->userauth_host_data);
    }
    if (session->userauth_pblc_data) {
        LIBSSH2_FREE(session, session->userauth_pblc_data);
    }
    if (session->userauth_pblc_packet) {
        LIBSSH2_FREE(session, session->userauth_pblc_packet);
    }
    if (session->userauth_pblc_method) {
        LIBSSH2_FREE(session, session->userauth_pblc_method);
    }
    if (session->userauth_kybd_data) {
        LIBSSH2_FREE(session, session->userauth_kybd_data);
    }
    if (session->userauth_kybd_packet) {
        LIBSSH2_FREE(session, session->userauth_kybd_packet);
    }
    if (session->userauth_kybd_auth_instruction) {
        LIBSSH2_FREE(session, session->userauth_kybd_auth_instruction);
    }
    if (session->open_packet) {
        LIBSSH2_FREE(session, session->open_packet);
    }
    if (session->open_data) {
        LIBSSH2_FREE(session, session->open_data);
    }
    if (session->direct_message) {
        LIBSSH2_FREE(session, session->direct_message);
    }
    if (session->fwdLstn_packet) {
        LIBSSH2_FREE(session, session->fwdLstn_packet);
    }
    if (session->pkeyInit_data) {
        LIBSSH2_FREE(session, session->pkeyInit_data);
    }
    if (session->scpRecv_command) {
        LIBSSH2_FREE(session, session->scpRecv_command);
    }
    if (session->scpSend_command) {
        LIBSSH2_FREE(session, session->scpSend_command);
    }
    if (session->scpRecv_err_msg) {
        LIBSSH2_FREE(session, session->scpRecv_err_msg);
    }
    if (session->scpSend_err_msg) {
        LIBSSH2_FREE(session, session->scpSend_err_msg);
    }

    /* Free the error message, if we ar supposed to */
    if (session->err_msg && session->err_should_free) {
        LIBSSH2_FREE(session, session->err_msg);
    }

    /* Cleanup any remaining packets */
    while (session->packets.head) {
        LIBSSH2_PACKET *tmp = session->packets.head;

        /* unlink */
        session->packets.head = tmp->next;

        /* free */
        LIBSSH2_FREE(session, tmp->data);
        LIBSSH2_FREE(session, tmp);
    }

    LIBSSH2_FREE(session, session);

    return 0;
}
示例#16
0
文件: scp.c 项目: kilitary/scanner
/*
 * scp_recv
 *
 * Open a channel and request a remote file via SCP
 *
 */
static LIBSSH2_CHANNEL *
scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
{
    int cmd_len;
    int rc;
    int tmp_err_code;
    const char *tmp_err_msg;

    if (session->scpRecv_state == libssh2_NB_state_idle) {
        session->scpRecv_mode = 0;
        session->scpRecv_size = 0;
        session->scpRecv_mtime = 0;
        session->scpRecv_atime = 0;

        session->scpRecv_command_len =
            _libssh2_shell_quotedsize(path) + sizeof("scp -f ") + (sb?1:0);

        session->scpRecv_command =
            LIBSSH2_ALLOC(session, session->scpRecv_command_len);

        if (!session->scpRecv_command) {
            _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                           "Unable to allocate a command buffer for "
                           "SCP session");
            return NULL;
        }

        snprintf((char *)session->scpRecv_command,
                 session->scpRecv_command_len, "scp -%sf ", sb?"p":"");

        cmd_len = strlen((char *)session->scpRecv_command);

        (void) shell_quotearg(path,
                              &session->scpRecv_command[cmd_len],
                              session->scpRecv_command_len - cmd_len);


        _libssh2_debug(session, LIBSSH2_TRACE_SCP,
                       "Opening channel for SCP receive");

        session->scpRecv_state = libssh2_NB_state_created;
    }

    if (session->scpRecv_state == libssh2_NB_state_created) {
        /* Allocate a channel */
        session->scpRecv_channel =
            _libssh2_channel_open(session, "session",
                                  sizeof("session") - 1,
                                  LIBSSH2_CHANNEL_WINDOW_DEFAULT,
                                  LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL,
                                  0);
        if (!session->scpRecv_channel) {
            if (libssh2_session_last_errno(session) !=
                    LIBSSH2_ERROR_EAGAIN) {
                LIBSSH2_FREE(session, session->scpRecv_command);
                session->scpRecv_command = NULL;
                session->scpRecv_state = libssh2_NB_state_idle;
            }
            else {
                _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                               "Would block starting up channel");
            }
            return NULL;
        }

        session->scpRecv_state = libssh2_NB_state_sent;
    }

    if (session->scpRecv_state == libssh2_NB_state_sent) {
        /* Request SCP for the desired file */
        rc = _libssh2_channel_process_startup(session->scpRecv_channel, "exec",
                                              sizeof("exec") - 1,
                                              (char *) session->scpRecv_command,
                                              session->scpRecv_command_len);
        if (rc == LIBSSH2_ERROR_EAGAIN) {
            _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                           "Would block requesting SCP startup");
            return NULL;
        } else if (rc) {
            LIBSSH2_FREE(session, session->scpRecv_command);
            session->scpRecv_command = NULL;
            goto scp_recv_error;
        }
        LIBSSH2_FREE(session, session->scpRecv_command);
        session->scpRecv_command = NULL;

        _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sending initial wakeup");
        /* SCP ACK */
        session->scpRecv_response[0] = '\0';

        session->scpRecv_state = libssh2_NB_state_sent1;
    }

    if (session->scpRecv_state == libssh2_NB_state_sent1) {
        rc = _libssh2_channel_write(session->scpRecv_channel, 0,
                                    session->scpRecv_response, 1);
        if (rc == LIBSSH2_ERROR_EAGAIN) {
            _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                           "Would block sending initial wakeup");
            return NULL;
        } else if (rc != 1) {
            goto scp_recv_error;
        }

        /* Parse SCP response */
        session->scpRecv_response_len = 0;

        session->scpRecv_state = libssh2_NB_state_sent2;
    }

    if ((session->scpRecv_state == libssh2_NB_state_sent2)
            || (session->scpRecv_state == libssh2_NB_state_sent3)) {
        while (sb && (session->scpRecv_response_len <
                      LIBSSH2_SCP_RESPONSE_BUFLEN)) {
            unsigned char *s, *p;

            if (session->scpRecv_state == libssh2_NB_state_sent2) {
                rc = _libssh2_channel_read(session->scpRecv_channel, 0,
                                           (char *) session->
                                           scpRecv_response +
                                           session->scpRecv_response_len, 1);
                if (rc == LIBSSH2_ERROR_EAGAIN) {
                    _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                   "Would block waiting for SCP response");
                    return NULL;
                }
                else if (rc < 0) {
                    /* error, give up */
                    _libssh2_error(session, rc, "Failed reading SCP response");
                    goto scp_recv_error;
                }
                else if(rc == 0)
                    goto scp_recv_empty_channel;

                session->scpRecv_response_len++;

                if (session->scpRecv_response[0] != 'T') {
                    size_t err_len;
                    char *err_msg;

                    /* there can be
                       01 for warnings
                       02 for errors

                       The following string MUST be newline terminated
                    */
                    err_len =
                        _libssh2_channel_packet_data_len(session->
                                                         scpRecv_channel, 0);
                    err_msg = LIBSSH2_ALLOC(session, err_len + 1);
                    if (!err_msg) {
                        _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                                       "Failed to get memory ");
                        goto scp_recv_error;
                    }

                    /* Read the remote error message */
                    (void)_libssh2_channel_read(session->scpRecv_channel, 0,
                                                err_msg, err_len);
                    /* If it failed for any reason, we ignore it anyway. */

                    /* zero terminate the error */
                    err_msg[err_len]=0;

                    _libssh2_debug(session, LIBSSH2_TRACE_SCP,
                                   "got %02x %s", session->scpRecv_response[0],
                                   err_msg);

                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Failed to recv file");

                    LIBSSH2_FREE(session, err_msg);
                    goto scp_recv_error;
                }

                if ((session->scpRecv_response_len > 1) &&
                        ((session->
                          scpRecv_response[session->scpRecv_response_len - 1] <
                          '0')
                         || (session->
                             scpRecv_response[session->scpRecv_response_len - 1] >
                             '9'))
                        && (session->
                            scpRecv_response[session->scpRecv_response_len - 1] !=
                            ' ')
                        && (session->
                            scpRecv_response[session->scpRecv_response_len - 1] !=
                            '\r')
                        && (session->
                            scpRecv_response[session->scpRecv_response_len - 1] !=
                            '\n')) {
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid data in SCP response");
                    goto scp_recv_error;
                }

                if ((session->scpRecv_response_len < 9)
                        || (session->
                            scpRecv_response[session->scpRecv_response_len - 1] !=
                            '\n')) {
                    if (session->scpRecv_response_len ==
                            LIBSSH2_SCP_RESPONSE_BUFLEN) {
                        /* You had your chance */
                        _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                       "Unterminated response from SCP server");
                        goto scp_recv_error;
                    }
                    /* Way too short to be an SCP response, or not done yet,
                       short circuit */
                    continue;
                }

                /* We're guaranteed not to go under response_len == 0 by the
                   logic above */
                while ((session->
                        scpRecv_response[session->scpRecv_response_len - 1] ==
                        '\r')
                        || (session->
                            scpRecv_response[session->scpRecv_response_len -
                                             1] == '\n'))
                    session->scpRecv_response_len--;
                session->scpRecv_response[session->scpRecv_response_len] =
                    '\0';

                if (session->scpRecv_response_len < 8) {
                    /* EOL came too soon */
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, "
                                   "too short" );
                    goto scp_recv_error;
                }

                s = session->scpRecv_response + 1;

                p = (unsigned char *) strchr((char *) s, ' ');
                if (!p || ((p - s) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, "
                                   "malformed mtime");
                    goto scp_recv_error;
                }

                *(p++) = '\0';
                /* Make sure we don't get fooled by leftover values */
                session->scpRecv_mtime = strtol((char *) s, NULL, 10);

                s = (unsigned char *) strchr((char *) p, ' ');
                if (!s || ((s - p) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, malformed mtime.usec");
                    goto scp_recv_error;
                }

                /* Ignore mtime.usec */
                s++;
                p = (unsigned char *) strchr((char *) s, ' ');
                if (!p || ((p - s) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, too short or malformed");
                    goto scp_recv_error;
                }

                *p = '\0';
                /* Make sure we don't get fooled by leftover values */
                session->scpRecv_atime = strtol((char *) s, NULL, 10);

                /* SCP ACK */
                session->scpRecv_response[0] = '\0';

                session->scpRecv_state = libssh2_NB_state_sent3;
            }

            if (session->scpRecv_state == libssh2_NB_state_sent3) {
                rc = _libssh2_channel_write(session->scpRecv_channel, 0,
                                            session->scpRecv_response, 1);
                if (rc == LIBSSH2_ERROR_EAGAIN) {
                    _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                   "Would block waiting to send SCP ACK");
                    return NULL;
                } else if (rc != 1) {
                    goto scp_recv_error;
                }

                _libssh2_debug(session, LIBSSH2_TRACE_SCP,
                               "mtime = %ld, atime = %ld",
                               session->scpRecv_mtime, session->scpRecv_atime);

                /* We *should* check that atime.usec is valid, but why let
                   that stop use? */
                break;
            }
        }

        session->scpRecv_state = libssh2_NB_state_sent4;
    }

    if (session->scpRecv_state == libssh2_NB_state_sent4) {
        session->scpRecv_response_len = 0;

        session->scpRecv_state = libssh2_NB_state_sent5;
    }

    if ((session->scpRecv_state == libssh2_NB_state_sent5)
            || (session->scpRecv_state == libssh2_NB_state_sent6)) {
        while (session->scpRecv_response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) {
            char *s, *p, *e = NULL;

            if (session->scpRecv_state == libssh2_NB_state_sent5) {
                rc = _libssh2_channel_read(session->scpRecv_channel, 0,
                                           (char *) session->
                                           scpRecv_response +
                                           session->scpRecv_response_len, 1);
                if (rc == LIBSSH2_ERROR_EAGAIN) {
                    _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                   "Would block waiting for SCP response");
                    return NULL;
                }
                else if (rc < 0) {
                    /* error, bail out*/
                    _libssh2_error(session, rc, "Failed reading SCP response");
                    goto scp_recv_error;
                }
                else if(rc == 0)
                    goto scp_recv_empty_channel;

                session->scpRecv_response_len++;

                if (session->scpRecv_response[0] != 'C') {
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server");
                    goto scp_recv_error;
                }

                if ((session->scpRecv_response_len > 1) &&
                        (session->
                         scpRecv_response[session->scpRecv_response_len - 1] !=
                         '\r')
                        && (session->
                            scpRecv_response[session->scpRecv_response_len - 1] !=
                            '\n')
                        &&
                        (session->
                         scpRecv_response[session->scpRecv_response_len - 1]
                         < 32)) {
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid data in SCP response");
                    goto scp_recv_error;
                }

                if ((session->scpRecv_response_len < 7)
                        || (session->
                            scpRecv_response[session->scpRecv_response_len - 1] !=
                            '\n')) {
                    if (session->scpRecv_response_len ==
                            LIBSSH2_SCP_RESPONSE_BUFLEN) {
                        /* You had your chance */
                        _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                       "Unterminated response from SCP server");
                        goto scp_recv_error;
                    }
                    /* Way too short to be an SCP response, or not done yet,
                       short circuit */
                    continue;
                }

                /* We're guaranteed not to go under response_len == 0 by the
                   logic above */
                while ((session->
                        scpRecv_response[session->scpRecv_response_len - 1] ==
                        '\r')
                        || (session->
                            scpRecv_response[session->scpRecv_response_len -
                                             1] == '\n')) {
                    session->scpRecv_response_len--;
                }
                session->scpRecv_response[session->scpRecv_response_len] =
                    '\0';

                if (session->scpRecv_response_len < 6) {
                    /* EOL came too soon */
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, too short");
                    goto scp_recv_error;
                }

                s = (char *) session->scpRecv_response + 1;

                p = strchr(s, ' ');
                if (!p || ((p - s) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, malformed mode");
                    goto scp_recv_error;
                }

                *(p++) = '\0';
                /* Make sure we don't get fooled by leftover values */

                session->scpRecv_mode = strtol(s, &e, 8);
                if (e && *e) {
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, invalid mode");
                    goto scp_recv_error;
                }

                s = strchr(p, ' ');
                if (!s || ((s - p) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, too short or malformed");
                    goto scp_recv_error;
                }

                *s = '\0';
                /* Make sure we don't get fooled by leftover values */
                session->scpRecv_size = scpsize_strtol(p, &e, 10);
                if (e && *e) {
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, invalid size");
                    goto scp_recv_error;
                }

                /* SCP ACK */
                session->scpRecv_response[0] = '\0';

                session->scpRecv_state = libssh2_NB_state_sent6;
            }

            if (session->scpRecv_state == libssh2_NB_state_sent6) {
                rc = _libssh2_channel_write(session->scpRecv_channel, 0,
                                            session->scpRecv_response, 1);
                if (rc == LIBSSH2_ERROR_EAGAIN) {
                    _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                   "Would block sending SCP ACK");
                    return NULL;
                } else if (rc != 1) {
                    goto scp_recv_error;
                }
                _libssh2_debug(session, LIBSSH2_TRACE_SCP,
                               "mode = 0%lo size = %ld", session->scpRecv_mode,
                               session->scpRecv_size);

                /* We *should* check that basename is valid, but why let that
                   stop us? */
                break;
            }
        }

        session->scpRecv_state = libssh2_NB_state_sent7;
    }

    if (sb) {
        memset(sb, 0, sizeof(struct stat));

        sb->st_mtime = session->scpRecv_mtime;
        sb->st_atime = session->scpRecv_atime;
        sb->st_size = session->scpRecv_size;
        sb->st_mode = session->scpRecv_mode;
    }

    session->scpRecv_state = libssh2_NB_state_idle;
    return session->scpRecv_channel;

scp_recv_empty_channel:
    /* the code only jumps here as a result of a zero read from channel_read()
       so we check EOF status to avoid getting stuck in a loop */
    if(libssh2_channel_eof(session->scpRecv_channel))
        _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                       "Unexpected channel close");
    else
        return session->scpRecv_channel;
    /* fall-through */
scp_recv_error:
    tmp_err_code = session->err_code;
    tmp_err_msg = session->err_msg;
    while (libssh2_channel_free(session->scpRecv_channel) ==
            LIBSSH2_ERROR_EAGAIN);
    session->err_code = tmp_err_code;
    session->err_msg = tmp_err_msg;
    session->scpRecv_channel = NULL;
    session->scpRecv_state = libssh2_NB_state_idle;
    return NULL;
}
示例#17
0
文件: session.c 项目: roderico/linm
/* {{{ libssh2_banner_receive
 * Wait for a hello from the remote host
 * Allocate a buffer and store the banner in session->remote.banner
 * Returns: 0 on success, PACKET_EAGAIN if read would block, 1 on failure
 */
static int
libssh2_banner_receive(LIBSSH2_SESSION * session)
{
    int ret;
    int banner_len;

    if (session->banner_TxRx_state == libssh2_NB_state_idle) {
        banner_len = 0;

        session->banner_TxRx_state = libssh2_NB_state_created;
    } else {
        banner_len = session->banner_TxRx_total_send;
    }

    while ((banner_len < (int) sizeof(session->banner_TxRx_banner)) &&
           ((banner_len == 0)
            || (session->banner_TxRx_banner[banner_len - 1] != '\n'))) {
        char c = '\0';

        ret =
            recv(session->socket_fd, &c, 1,
                 LIBSSH2_SOCKET_RECV_FLAGS(session));

        if (ret < 0) {
#ifdef WIN32
            switch (WSAGetLastError()) {
            case WSAEWOULDBLOCK:
                errno = EAGAIN;
                break;

            case WSAENOTSOCK:
                errno = EBADF;
                break;

            case WSAENOTCONN:
            case WSAECONNABORTED:
                errno = WSAENOTCONN;
                break;

            case WSAEINTR:
                errno = EINTR;
                break;
            }
#endif /* WIN32 */
            if (errno == EAGAIN) {
                session->banner_TxRx_total_send = banner_len;
                return PACKET_EAGAIN;
            }

            /* Some kinda error */
            session->banner_TxRx_state = libssh2_NB_state_idle;
            session->banner_TxRx_total_send = 0;
            return 1;
        }

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

        if (c == '\0') {
            /* NULLs are not allowed in SSH banners */
            session->banner_TxRx_state = libssh2_NB_state_idle;
            session->banner_TxRx_total_send = 0;
            return 1;
        }

        session->banner_TxRx_banner[banner_len++] = c;
    }

    while (banner_len &&
           ((session->banner_TxRx_banner[banner_len - 1] == '\n') ||
            (session->banner_TxRx_banner[banner_len - 1] == '\r'))) {
        banner_len--;
    }

    /* From this point on, we are done here */
    session->banner_TxRx_state = libssh2_NB_state_idle;
    session->banner_TxRx_total_send = 0;

    if (!banner_len)
        return 1;

    session->remote.banner = LIBSSH2_ALLOC(session, banner_len + 1);
    if (!session->remote.banner) {
        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                      "Error allocating space for remote banner", 0);
        return 1;
    }
    memcpy(session->remote.banner, session->banner_TxRx_banner, banner_len);
    session->remote.banner[banner_len] = '\0';
    _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Received Banner: %s",
                   session->remote.banner);
    return 0;
}
示例#18
0
文件: scp.c 项目: kilitary/scanner
/*
 * scp_send()
 *
 * Send a file using SCP
 *
 */
static LIBSSH2_CHANNEL *
scp_send(LIBSSH2_SESSION * session, const char *path, int mode,
         libssh2_int64_t size, time_t mtime, time_t atime)
{
    int cmd_len;
    int rc;
    int tmp_err_code;
    const char *tmp_err_msg;

    if (session->scpSend_state == libssh2_NB_state_idle) {
        session->scpSend_command_len =
            _libssh2_shell_quotedsize(path) + sizeof("scp -t ") +
            ((mtime || atime)?1:0);

        session->scpSend_command =
            LIBSSH2_ALLOC(session, session->scpSend_command_len);
        if (!session->scpSend_command) {
            _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                           "Unable to allocate a command buffer for scp session");
            return NULL;
        }

        snprintf((char *)session->scpSend_command, session->scpSend_command_len,
                 "scp -%st ", (mtime || atime)?"p":"");

        cmd_len = strlen((char *)session->scpSend_command);

        (void)shell_quotearg(path,
                             &session->scpSend_command[cmd_len],
                             session->scpSend_command_len - cmd_len);

        session->scpSend_command[session->scpSend_command_len - 1] = '\0';

        _libssh2_debug(session, LIBSSH2_TRACE_SCP,
                       "Opening channel for SCP send");
        /* Allocate a channel */

        session->scpSend_state = libssh2_NB_state_created;
    }

    if (session->scpSend_state == libssh2_NB_state_created) {
        session->scpSend_channel =
            _libssh2_channel_open(session, "session", sizeof("session") - 1,
                                  LIBSSH2_CHANNEL_WINDOW_DEFAULT,
                                  LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0);
        if (!session->scpSend_channel) {
            if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
                /* previous call set libssh2_session_last_error(), pass it
                   through */
                LIBSSH2_FREE(session, session->scpSend_command);
                session->scpSend_command = NULL;
                session->scpSend_state = libssh2_NB_state_idle;
            }
            else {
                _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                               "Would block starting up channel");
            }
            return NULL;
        }

        session->scpSend_state = libssh2_NB_state_sent;
    }

    if (session->scpSend_state == libssh2_NB_state_sent) {
        /* Request SCP for the desired file */
        rc = _libssh2_channel_process_startup(session->scpSend_channel, "exec",
                                              sizeof("exec") - 1,
                                              (char *) session->scpSend_command,
                                              session->scpSend_command_len);
        if (rc == LIBSSH2_ERROR_EAGAIN) {
            _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                           "Would block requesting SCP startup");
            return NULL;
        }
        else if (rc) {
            /* previous call set libssh2_session_last_error(), pass it
               through */
            LIBSSH2_FREE(session, session->scpSend_command);
            session->scpSend_command = NULL;
            _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                           "Unknown error while getting error string");
            goto scp_send_error;
        }
        LIBSSH2_FREE(session, session->scpSend_command);
        session->scpSend_command = NULL;

        session->scpSend_state = libssh2_NB_state_sent1;
    }

    if (session->scpSend_state == libssh2_NB_state_sent1) {
        /* Wait for ACK */
        rc = _libssh2_channel_read(session->scpSend_channel, 0,
                                   (char *) session->scpSend_response, 1);
        if (rc == LIBSSH2_ERROR_EAGAIN) {
            _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                           "Would block waiting for response from remote");
            return NULL;
        }
        else if (rc < 0) {
            _libssh2_error(session, rc, "SCP failure");
            goto scp_send_error;
        }
        else if(!rc)
            /* remain in the same state */
            goto scp_send_empty_channel;
        else if (session->scpSend_response[0] != 0) {
            _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                           "Invalid ACK response from remote");
            goto scp_send_error;
        }
        if (mtime || atime) {
            /* Send mtime and atime to be used for file */
            session->scpSend_response_len =
                snprintf((char *) session->scpSend_response,
                         LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n",
                         (long)mtime, (long)atime);
            _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s",
                           session->scpSend_response);
        }

        session->scpSend_state = libssh2_NB_state_sent2;
    }

    /* Send mtime and atime to be used for file */
    if (mtime || atime) {
        if (session->scpSend_state == libssh2_NB_state_sent2) {
            rc = _libssh2_channel_write(session->scpSend_channel, 0,
                                        session->scpSend_response,
                                        session->scpSend_response_len);
            if (rc == LIBSSH2_ERROR_EAGAIN) {
                _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                               "Would block sending time data for SCP file");
                return NULL;
            } else if (rc != (int)session->scpSend_response_len) {
                _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
                               "Unable to send time data for SCP file");
                goto scp_send_error;
            }

            session->scpSend_state = libssh2_NB_state_sent3;
        }

        if (session->scpSend_state == libssh2_NB_state_sent3) {
            /* Wait for ACK */
            rc = _libssh2_channel_read(session->scpSend_channel, 0,
                                       (char *) session->scpSend_response, 1);
            if (rc == LIBSSH2_ERROR_EAGAIN) {
                _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                               "Would block waiting for response");
                return NULL;
            }
            else if (rc < 0) {
                _libssh2_error(session, rc, "SCP failure");
                goto scp_send_error;
            }
            else if(!rc)
                /* remain in the same state */
                goto scp_send_empty_channel;
            else if (session->scpSend_response[0] != 0) {
                _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                               "Invalid SCP ACK response");
                goto scp_send_error;
            }

            session->scpSend_state = libssh2_NB_state_sent4;
        }
    } else {
        if (session->scpSend_state == libssh2_NB_state_sent2) {
            session->scpSend_state = libssh2_NB_state_sent4;
        }
    }

    if (session->scpSend_state == libssh2_NB_state_sent4) {
        /* Send mode, size, and basename */
        const char *base = strrchr(path, '/');
        if (base)
            base++;
        else
            base = path;

        session->scpSend_response_len =
            snprintf((char *) session->scpSend_response,
                     LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %"
                     LIBSSH2_INT64_T_FORMAT " %s\n", mode,
                     size, base);
        _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s",
                       session->scpSend_response);

        session->scpSend_state = libssh2_NB_state_sent5;
    }

    if (session->scpSend_state == libssh2_NB_state_sent5) {
        rc = _libssh2_channel_write(session->scpSend_channel, 0,
                                    session->scpSend_response,
                                    session->scpSend_response_len);
        if (rc == LIBSSH2_ERROR_EAGAIN) {
            _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                           "Would block send core file data for SCP file");
            return NULL;
        } else if (rc != (int)session->scpSend_response_len) {
            _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
                           "Unable to send core file data for SCP file");
            goto scp_send_error;
        }

        session->scpSend_state = libssh2_NB_state_sent6;
    }

    if (session->scpSend_state == libssh2_NB_state_sent6) {
        /* Wait for ACK */
        rc = _libssh2_channel_read(session->scpSend_channel, 0,
                                   (char *) session->scpSend_response, 1);
        if (rc == LIBSSH2_ERROR_EAGAIN) {
            _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                           "Would block waiting for response");
            return NULL;
        }
        else if (rc < 0) {
            _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                           "Invalid ACK response from remote");
            goto scp_send_error;
        }
        else if (rc == 0)
            goto scp_send_empty_channel;

        else if (session->scpSend_response[0] != 0) {
            size_t err_len;
            char *err_msg;

            err_len =
                _libssh2_channel_packet_data_len(session->scpSend_channel, 0);
            err_msg = LIBSSH2_ALLOC(session, err_len + 1);
            if (!err_msg) {
                _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                               "failed to get memory");
                goto scp_send_error;
            }

            /* Read the remote error message */
            rc = _libssh2_channel_read(session->scpSend_channel, 0,
                                       err_msg, err_len);
            if (rc > 0) {
                err_msg[err_len]=0;
                _libssh2_debug(session, LIBSSH2_TRACE_SCP,
                               "got %02x %s", session->scpSend_response[0],
                               err_msg);
            }
            LIBSSH2_FREE(session, err_msg);
            _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                           "failed to send file");
            goto scp_send_error;
        }
    }

    session->scpSend_state = libssh2_NB_state_idle;
    return session->scpSend_channel;

scp_send_empty_channel:
    /* the code only jumps here as a result of a zero read from channel_read()
       so we check EOF status to avoid getting stuck in a loop */
    if(libssh2_channel_eof(session->scpSend_channel)) {
        _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                       "Unexpected channel close");
    }
    else
        return session->scpSend_channel;
    /* fall-through */
scp_send_error:
    tmp_err_code = session->err_code;
    tmp_err_msg = session->err_msg;
    while (libssh2_channel_free(session->scpSend_channel) ==
            LIBSSH2_ERROR_EAGAIN);
    session->err_code = tmp_err_code;
    session->err_msg = tmp_err_msg;
    session->scpSend_channel = NULL;
    session->scpSend_state = libssh2_NB_state_idle;
    return NULL;
}
示例#19
0
/* {{{ libssh2_scp_recv
 * Open a channel and request a remote file via SCP
 *
 * NOTE:  Will block in a busy loop on error.  This has to be done,
 *        otherwise the blocking error code would erase the true
 *        cause of the error.
 */
LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
{
    int path_len = strlen(path);
    int rc;

    if (session->scpRecv_state == libssh2_NB_state_idle) {
        session->scpRecv_mode = 0;
        session->scpRecv_size = 0;
        session->scpRecv_mtime = 0;
        session->scpRecv_atime = 0;

        session->scpRecv_command_len = path_len + sizeof("scp -f ");

        if (sb) {
            session->scpRecv_command_len++;
        }

        session->scpRecv_command =
            LIBSSH2_ALLOC(session, session->scpRecv_command_len);
        if (!session->scpRecv_command) {
            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                          "Unable to allocate a command buffer for SCP session",
                          0);
            return NULL;
        }
        if (sb) {
            memcpy(session->scpRecv_command, "scp -pf ",
                   sizeof("scp -pf ") - 1);
            memcpy(session->scpRecv_command + sizeof("scp -pf ") - 1, path,
                   path_len);
        } else {
            memcpy(session->scpRecv_command, "scp -f ", sizeof("scp -f ") - 1);
            memcpy(session->scpRecv_command + sizeof("scp -f ") - 1, path,
                   path_len);
        }
        session->scpRecv_command[session->scpRecv_command_len - 1] = '\0';

        _libssh2_debug(session, LIBSSH2_DBG_SCP,
                       "Opening channel for SCP receive");

        session->scpRecv_state = libssh2_NB_state_created;
    }

    if (session->scpRecv_state == libssh2_NB_state_created) {
        /* Allocate a channel */
        do {
            session->scpRecv_channel =
                libssh2_channel_open_ex(session, "session",
                                        sizeof("session") - 1,
                                        LIBSSH2_CHANNEL_WINDOW_DEFAULT,
                                        LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL,
                                        0);
            if (!session->scpRecv_channel) {
                if (libssh2_session_last_errno(session) !=
                    LIBSSH2_ERROR_EAGAIN) {
                    LIBSSH2_FREE(session, session->scpRecv_command);
                    session->scpRecv_command = NULL;
                    session->scpRecv_state = libssh2_NB_state_idle;
                    return NULL;
                } else if (libssh2_session_last_errno(session) ==
                           LIBSSH2_ERROR_EAGAIN) {
                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                  "Would block starting up channel", 0);
                    return NULL;
                }
            }
        } while (!session->scpRecv_channel);

        session->scpRecv_state = libssh2_NB_state_sent;
    }

    if (session->scpRecv_state == libssh2_NB_state_sent) {
        /* Request SCP for the desired file */
        rc = libssh2_channel_process_startup(session->scpRecv_channel, "exec",
                                             sizeof("exec") - 1,
                                             (char *) session->scpRecv_command,
                                             session->scpRecv_command_len);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block requesting SCP startup", 0);
            return NULL;
        } else if (rc) {
            LIBSSH2_FREE(session, session->scpRecv_command);
            session->scpRecv_command = NULL;
            goto scp_recv_error;
        }
        LIBSSH2_FREE(session, session->scpRecv_command);
        session->scpRecv_command = NULL;

        _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sending initial wakeup");
        /* SCP ACK */
        session->scpRecv_response[0] = '\0';

        session->scpRecv_state = libssh2_NB_state_sent1;
    }

    if (session->scpRecv_state == libssh2_NB_state_sent1) {
        rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
                                      (char *) session->scpRecv_response, 1);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block sending initial wakeup", 0);
            return NULL;
        } else if (rc != 1) {
            goto scp_recv_error;
        }

        /* Parse SCP response */
        session->scpRecv_response_len = 0;

        session->scpRecv_state = libssh2_NB_state_sent2;
    }

    if ((session->scpRecv_state == libssh2_NB_state_sent2)
        || (session->scpRecv_state == libssh2_NB_state_sent3)) {
        while (sb
               && (session->scpRecv_response_len <
                   LIBSSH2_SCP_RESPONSE_BUFLEN)) {
            unsigned char *s, *p;

            if (session->scpRecv_state == libssh2_NB_state_sent2) {
                rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
                                             (char *) session->
                                             scpRecv_response +
                                             session->scpRecv_response_len, 1);
                if (rc == PACKET_EAGAIN) {
                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                  "Would block waiting for SCP response", 0);
                    return NULL;
                } else if (rc <= 0) {
                    /* Timeout, give up */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Timed out waiting for SCP response", 0);
                    goto scp_recv_error;
                }
                session->scpRecv_response_len++;

                if (session->scpRecv_response[0] != 'T') {
                    /*
                     * Set this as the default error for here, if
                     * we are successful it will be replaced
                     */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid data in SCP response, missing Time data",
                                  0);

                    session->scpRecv_err_len =
                        libssh2_channel_packet_data_len(session->
                                                        scpRecv_channel, 0);
                    session->scpRecv_err_msg =
                        LIBSSH2_ALLOC(session, session->scpRecv_err_len + 1);
                    if (!session->scpRecv_err_msg) {
                        goto scp_recv_error;
                    }
                    memset(session->scpRecv_err_msg, 0,
                           session->scpRecv_err_len + 1);

                    /* Read the remote error message */
                    rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
                                                 session->scpRecv_err_msg,
                                                 session->scpRecv_err_len);
                    if (rc <= 0) {
                        /*
                         * Since we have alread started reading this packet, it is
                         * already in the systems so it can't return PACKET_EAGAIN
                         */
                        LIBSSH2_FREE(session, session->scpRecv_err_msg);
                        session->scpRecv_err_msg = NULL;
                        libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                      "Unknown error while getting error string",
                                      0);
                        goto scp_recv_error;
                    }

                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  session->scpRecv_err_msg, 1);
                    session->scpRecv_err_msg = NULL;
                    goto scp_recv_error;
                }

                if ((session->scpRecv_response_len > 1) &&
                    ((session->
                      scpRecv_response[session->scpRecv_response_len - 1] <
                      '0')
                     || (session->
                         scpRecv_response[session->scpRecv_response_len - 1] >
                         '9'))
                    && (session->
                        scpRecv_response[session->scpRecv_response_len - 1] !=
                        ' ')
                    && (session->
                        scpRecv_response[session->scpRecv_response_len - 1] !=
                        '\r')
                    && (session->
                        scpRecv_response[session->scpRecv_response_len - 1] !=
                        '\n')) {
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid data in SCP response", 0);
                    goto scp_recv_error;
                }

                if ((session->scpRecv_response_len < 9)
                    || (session->
                        scpRecv_response[session->scpRecv_response_len - 1] !=
                        '\n')) {
                    if (session->scpRecv_response_len ==
                        LIBSSH2_SCP_RESPONSE_BUFLEN) {
                        /* You had your chance */
                        libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                      "Unterminated response from SCP server",
                                      0);
                        goto scp_recv_error;
                    }
                    /* Way too short to be an SCP response,  or not done yet, short circuit */
                    continue;
                }

                /* We're guaranteed not to go under response_len == 0 by the logic above */
                while ((session->
                        scpRecv_response[session->scpRecv_response_len - 1] ==
                        '\r')
                       || (session->
                           scpRecv_response[session->scpRecv_response_len -
                                            1] == '\n'))
                    session->scpRecv_response_len--;
                session->scpRecv_response[session->scpRecv_response_len] =
                    '\0';

                if (session->scpRecv_response_len < 8) {
                    /* EOL came too soon */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, too short",
                                  0);
                    goto scp_recv_error;
                }

                s = session->scpRecv_response + 1;

                p = (unsigned char *) strchr((char *) s, ' ');
                if (!p || ((p - s) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, malformed mtime",
                                  0);
                    goto scp_recv_error;
                }

                *(p++) = '\0';
                /* Make sure we don't get fooled by leftover values */
                errno = 0;
                session->scpRecv_mtime = strtol((char *) s, NULL, 10);
                if (errno) {
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, invalid mtime",
                                  0);
                    goto scp_recv_error;
                }
                s = (unsigned char *) strchr((char *) p, ' ');
                if (!s || ((s - p) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, malformed mtime.usec",
                                  0);
                    goto scp_recv_error;
                }

                /* Ignore mtime.usec */
                s++;
                p = (unsigned char *) strchr((char *) s, ' ');
                if (!p || ((p - s) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, too short or malformed",
                                  0);
                    goto scp_recv_error;
                }

                *(p++) = '\0';
                /* Make sure we don't get fooled by leftover values */
                errno = 0;
                session->scpRecv_atime = strtol((char *) s, NULL, 10);
                if (errno) {
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, invalid atime",
                                  0);
                    goto scp_recv_error;
                }

                /* SCP ACK */
                session->scpRecv_response[0] = '\0';

                session->scpRecv_state = libssh2_NB_state_sent3;
            }

            if (session->scpRecv_state == libssh2_NB_state_sent3) {
                rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
                                              (char *) session->
                                              scpRecv_response, 1);
                if (rc == PACKET_EAGAIN) {
                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                  "Would block waiting to send SCP ACK", 0);
                    return NULL;
                } else if (rc != 1) {
                    goto scp_recv_error;
                }

                _libssh2_debug(session, LIBSSH2_DBG_SCP,
                               "mtime = %ld, atime = %ld",
                               session->scpRecv_mtime, session->scpRecv_atime);

                /* We *should* check that atime.usec is valid, but why let that stop use? */
                break;
            }
        }

        session->scpRecv_state = libssh2_NB_state_sent4;
    }

    if (session->scpRecv_state == libssh2_NB_state_sent4) {
        session->scpRecv_response_len = 0;

        session->scpRecv_state = libssh2_NB_state_sent5;
    }

    if ((session->scpRecv_state == libssh2_NB_state_sent5)
        || (session->scpRecv_state == libssh2_NB_state_sent6)) {
        while (session->scpRecv_response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) {
            char *s, *p, *e = NULL;

            if (session->scpRecv_state == libssh2_NB_state_sent5) {
                rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
                                             (char *) session->
                                             scpRecv_response +
                                             session->scpRecv_response_len, 1);
                if (rc == PACKET_EAGAIN) {
                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                  "Would block waiting for SCP response", 0);
                    return NULL;
                } else if (rc <= 0) {
                    /* Timeout, give up */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Timed out waiting for SCP response", 0);
                    goto scp_recv_error;
                }
                session->scpRecv_response_len++;

                if (session->scpRecv_response[0] != 'C') {
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server", 0);
                    goto scp_recv_error;
                }

                if ((session->scpRecv_response_len > 1) &&
                    (session->
                     scpRecv_response[session->scpRecv_response_len - 1] !=
                     '\r')
                    && (session->
                        scpRecv_response[session->scpRecv_response_len - 1] !=
                        '\n')
                    &&
                    ((session->
                      scpRecv_response[session->scpRecv_response_len - 1] < 32)
                     || (session->
                         scpRecv_response[session->scpRecv_response_len - 1] >
                         126))) {
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid data in SCP response", 0);
                    goto scp_recv_error;
                }

                if ((session->scpRecv_response_len < 7)
                    || (session->
                        scpRecv_response[session->scpRecv_response_len - 1] !=
                        '\n')) {
                    if (session->scpRecv_response_len ==
                        LIBSSH2_SCP_RESPONSE_BUFLEN) {
                        /* You had your chance */
                        libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                      "Unterminated response from SCP server",
                                      0);
                        goto scp_recv_error;
                    }
                    /* Way too short to be an SCP response,  or not done yet, short circuit */
                    continue;
                }

                /* We're guaranteed not to go under response_len == 0 by the logic above */
                while ((session->
                        scpRecv_response[session->scpRecv_response_len - 1] ==
                        '\r')
                       || (session->
                           scpRecv_response[session->scpRecv_response_len -
                                            1] == '\n')) {
                    session->scpRecv_response_len--;
                }
                session->scpRecv_response[session->scpRecv_response_len] =
                    '\0';

                if (session->scpRecv_response_len < 6) {
                    /* EOL came too soon */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, too short",
                                  0);
                    goto scp_recv_error;
                }

                s = (char *) session->scpRecv_response + 1;

                p = strchr(s, ' ');
                if (!p || ((p - s) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, malformed mode",
                                  0);
                    goto scp_recv_error;
                }

                *(p++) = '\0';
                /* Make sure we don't get fooled by leftover values */
                errno = 0;
                session->scpRecv_mode = strtol(s, &e, 8);
                if ((e && *e) || errno) {
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, invalid mode",
                                  0);
                    goto scp_recv_error;
                }

                s = strchr(p, ' ');
                if (!s || ((s - p) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, too short or malformed",
                                  0);
                    goto scp_recv_error;
                }

                *(s++) = '\0';
                /* Make sure we don't get fooled by leftover values */
                errno = 0;
                session->scpRecv_size = scpsize_strtol(p, &e, 10);
                if ((e && *e) || errno) {
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, invalid size",
                                  0);
                    goto scp_recv_error;
                }

                /* SCP ACK */
                session->scpRecv_response[0] = '\0';

                session->scpRecv_state = libssh2_NB_state_sent6;
            }

            if (session->scpRecv_state == libssh2_NB_state_sent6) {
                rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
                                              (char *) session->
                                              scpRecv_response, 1);
                if (rc == PACKET_EAGAIN) {
                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                  "Would block sending SCP ACK", 0);
                    return NULL;
                } else if (rc != 1) {
                    goto scp_recv_error;
                }
                _libssh2_debug(session, LIBSSH2_DBG_SCP,
                               "mode = 0%lo size = %ld", session->scpRecv_mode,
                               session->scpRecv_size);

                /* We *should* check that basename is valid, but why let that stop us? */
                break;
            }
        }

        session->scpRecv_state = libssh2_NB_state_sent7;
    }

    if (sb) {
        memset(sb, 0, sizeof(struct stat));

        sb->st_mtime = session->scpRecv_mtime;
        sb->st_atime = session->scpRecv_atime;
        sb->st_size = session->scpRecv_size;
        sb->st_mode = session->scpRecv_mode;
    }

    session->scpRecv_state = libssh2_NB_state_idle;
    return session->scpRecv_channel;

  scp_recv_error:
    while (libssh2_channel_free(session->scpRecv_channel) == PACKET_EAGAIN);
    session->scpRecv_channel = NULL;
    session->scpRecv_state = libssh2_NB_state_idle;
    return NULL;
}
示例#20
0
文件: openssl.c 项目: stinb/libssh2
static int
gen_publickey_from_ec_evp(LIBSSH2_SESSION *session,
                          unsigned char **method,
                          size_t *method_len,
                          unsigned char **pubkeydata,
                          size_t *pubkeydata_len,
                          EVP_PKEY *pk)
{
    int rc = 0;
    EC_KEY *ec = NULL;
    unsigned char *p;
    unsigned char *method_buf = NULL;
    unsigned char *key;
    size_t  key_len = 0;
    unsigned char *octal_value = NULL;
    size_t octal_len;
    const EC_POINT *public_key;
    const EC_GROUP *group;
    BN_CTX *bn_ctx;
    libssh2_curve_type type;

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

    bn_ctx = BN_CTX_new();
    if(bn_ctx == NULL)
        return -1;

    ec = EVP_PKEY_get1_EC_KEY(pk);
    if(ec == NULL) {
        rc = -1;
        goto clean_exit;
    }

    public_key = EC_KEY_get0_public_key(ec);
    group = EC_KEY_get0_group(ec);
    type = _libssh2_ecdsa_key_get_curve_type(ec);

    method_buf = LIBSSH2_ALLOC(session, 19);
    if(method_buf == NULL) {
        return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
            "out of memory");
    }

    if(type == LIBSSH2_EC_CURVE_NISTP256)
        memcpy(method_buf, "ecdsa-sha2-nistp256", 19);
    else if(type == LIBSSH2_EC_CURVE_NISTP384)
        memcpy(method_buf, "ecdsa-sha2-nistp384", 19);
    else if(type == LIBSSH2_EC_CURVE_NISTP521)
        memcpy(method_buf, "ecdsa-sha2-nistp521", 19);
    else {
        _libssh2_debug(session,
            LIBSSH2_TRACE_ERROR,
            "Unsupported EC private key type");
        rc = -1;
        goto clean_exit;
    }

    /* get length */
    octal_len = EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, bn_ctx);
    if(octal_len > EC_MAX_POINT_LEN) {
        rc = -1;
        goto clean_exit;
    }

    octal_value = malloc(octal_len);
    if(octal_value == NULL) {
        rc = -1;
        goto clean_exit;
    }

    /* convert to octal */
    if(EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED,
       octal_value, octal_len, bn_ctx) != octal_len) {
           rc = -1;
           goto clean_exit;
    }

    /* Key form is: type_len(4) + type(19) + domain_len(4) + domain(8) + pub_key_len(4) + pub_key(~65). */
    key_len = 4 + 19 + 4 + 8 + 4 + octal_len;
    key = LIBSSH2_ALLOC(session, key_len);
    if(key == NULL) {
        rc = -1;
        goto  clean_exit;
    }

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

    /* Key type */
    _libssh2_store_str(&p, (const char *)method_buf, 19);

    /* Name domain */
    _libssh2_store_str(&p, (const char *)method_buf + 11, 8);

    /* Public key */
    _libssh2_store_str(&p, (const char *)octal_value, octal_len);

    *method         = method_buf;
    *method_len     = 19;
    *pubkeydata     = key;
    *pubkeydata_len = key_len;

clean_exit:

    if(ec != NULL)
        EC_KEY_free(ec);

    if(bn_ctx != NULL) {
        BN_CTX_free(bn_ctx);
    }

    if(octal_value != NULL)
        free(octal_value);

    if(rc == 0)
        return 0;

    if(method_buf != NULL)
        LIBSSH2_FREE(session, method_buf);

    return -1;
}