Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions php_ssh2.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ extern php_stream_wrapper php_ssh2_sftp_wrapper;
extern int le_ssh2_session;
extern int le_ssh2_sftp;

static inline zend_bool php_ssh2_session_is_open(zend_resource *session_rsrc)
{
return session_rsrc && session_rsrc->ptr != NULL;
}

#if PHP_VERSION_ID < 70300
#define SSH2_URL_STR(a) (a)
#define SSH2_URL_LEN(a) strlen(a)
Expand Down
47 changes: 43 additions & 4 deletions ssh2.c
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,10 @@ PHP_FUNCTION(ssh2_forward_accept)
RETURN_FALSE;
}

if (!php_ssh2_session_is_open(data->session_rsrc)) {
RETURN_FALSE;
}

channel = libssh2_channel_forward_accept(data->listener);

if (!channel) {
Expand All @@ -916,6 +920,7 @@ PHP_FUNCTION(ssh2_forward_accept)
channel_data->channel = channel;
channel_data->streamid = 0;
channel_data->is_blocking = 0;
channel_data->timeout = 0;
channel_data->session_rsrc = data->session_rsrc;
channel_data->refcount = NULL;

Expand Down Expand Up @@ -1010,12 +1015,28 @@ PHP_FUNCTION(ssh2_poll)
res_type = Z_RES_P(tmpzval)->type;
res = zend_fetch_resource_ex(tmpzval, "Poll Resource", res_type);
if (res_type == le_ssh2_listener) {
php_ssh2_listener_data *listener_data = (php_ssh2_listener_data*)res;

if (!php_ssh2_session_is_open(listener_data->session_rsrc)) {
php_error_docref(NULL, E_WARNING, "Cannot poll a listener after its session is closed");
numfds--;
continue;
}

pollfds[i].type = LIBSSH2_POLLFD_LISTENER;
pollfds[i].fd.listener = ((php_ssh2_listener_data*)res)->listener;
pollfds[i].fd.listener = listener_data->listener;
} else if ((res_type == le_stream || res_type == le_pstream) &&
((php_stream*)res)->ops == &php_ssh2_channel_stream_ops) {
php_ssh2_channel_data *channel_data = (php_ssh2_channel_data*)((php_stream*)res)->abstract;

if (!php_ssh2_session_is_open(channel_data->session_rsrc)) {
php_error_docref(NULL, E_WARNING, "Cannot poll a channel after its session is closed");
numfds--;
continue;
}

pollfds[i].type = LIBSSH2_POLLFD_CHANNEL;
pollfds[i].fd.channel = ((php_ssh2_channel_data*)(((php_stream*)res)->abstract))->channel;
pollfds[i].fd.channel = channel_data->channel;
/* TODO: Add the ability to select against other stream types */
} else {
php_error_docref(NULL, E_WARNING, "Invalid resource type in subarray: %s", zend_rsrc_list_get_rsrc_type(Z_RES_P(tmpzval)));
Expand Down Expand Up @@ -1114,6 +1135,10 @@ PHP_FUNCTION(ssh2_publickey_add)
RETURN_FALSE;
}

if (!php_ssh2_session_is_open(data->session_rsrc)) {
RETURN_FALSE;
}

if (zattrs) {
HashPosition pos;
zval *attr_val;
Expand Down Expand Up @@ -1209,6 +1234,10 @@ PHP_FUNCTION(ssh2_publickey_remove)
RETURN_FALSE;
}

if (!php_ssh2_session_is_open(data->session_rsrc)) {
RETURN_FALSE;
}

if (libssh2_publickey_remove_ex(data->pkey, (unsigned char *) algo, algo_len, (unsigned char *) blob, blob_len)) {
php_error_docref(NULL, E_WARNING, "Unable to remove %s key", algo);
RETURN_FALSE;
Expand Down Expand Up @@ -1236,6 +1265,10 @@ PHP_FUNCTION(ssh2_publickey_list)
RETURN_FALSE;
}

if (!php_ssh2_session_is_open(data->session_rsrc)) {
RETURN_FALSE;
}

if (libssh2_publickey_list_fetch(data->pkey, &num_keys, &keys)) {
php_error_docref(NULL, E_WARNING, "Unable to list keys on remote server");
RETURN_FALSE;
Expand Down Expand Up @@ -1389,7 +1422,10 @@ static void php_ssh2_listener_dtor(zend_resource *rsrc)
php_ssh2_listener_data *data = (php_ssh2_listener_data*)rsrc->ptr;
LIBSSH2_LISTENER *listener = data->listener;

libssh2_channel_forward_cancel(listener);
if (php_ssh2_session_is_open(data->session_rsrc)) {
libssh2_channel_forward_cancel(listener);
}

zend_list_delete(data->session_rsrc);
efree(data);
}
Expand All @@ -1399,7 +1435,10 @@ static void php_ssh2_pkey_subsys_dtor(zend_resource *rsrc)
php_ssh2_pkey_subsys_data *data = (php_ssh2_pkey_subsys_data*)rsrc->ptr;
LIBSSH2_PUBLICKEY *pkey = data->pkey;

libssh2_publickey_shutdown(pkey);
if (php_ssh2_session_is_open(data->session_rsrc)) {
libssh2_publickey_shutdown(pkey);
}

zend_list_delete(data->session_rsrc);
efree(data);
}
Expand Down
118 changes: 81 additions & 37 deletions ssh2_fopen_wrappers.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,20 @@ static ssize_t php_ssh2_channel_stream_write(php_stream *stream, const char *buf
{
php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract;
ssize_t writestate;
LIBSSH2_SESSION *session;

libssh2_channel_set_blocking(abstract->channel, abstract->is_blocking);
session = (LIBSSH2_SESSION *)zend_fetch_resource(abstract->session_rsrc, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
#ifdef PHP_SSH2_SESSION_TIMEOUT
LIBSSH2_SESSION *session;
#endif

if (!php_ssh2_session_is_open(abstract->session_rsrc)) {
return -1;
}

libssh2_channel_set_blocking(abstract->channel, abstract->is_blocking);

#ifdef PHP_SSH2_SESSION_TIMEOUT
session = (LIBSSH2_SESSION *)zend_fetch_resource(abstract->session_rsrc, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);

if (abstract->is_blocking) {
libssh2_session_set_timeout(session, abstract->timeout);
}
Expand All @@ -70,16 +76,8 @@ static ssize_t php_ssh2_channel_stream_write(php_stream *stream, const char *buf
#endif

if (writestate == LIBSSH2_ERROR_EAGAIN) {
#if PHP_VERSION_ID < 70400
writestate = 0;
#endif
} else if (writestate < 0) {
char *error_msg = NULL;
if (libssh2_session_last_error(session, &error_msg, NULL, 0) == writestate) {
php_error_docref(NULL, E_WARNING, "Failure '%s' (%ld)", error_msg, writestate);
}

stream->eof = 1;
#if PHP_VERSION_ID < 70400
writestate = 0;
#endif
Expand All @@ -96,13 +94,21 @@ static ssize_t php_ssh2_channel_stream_read(php_stream *stream, char *buf, size_
{
php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract;
ssize_t readstate;

#ifdef PHP_SSH2_SESSION_TIMEOUT
LIBSSH2_SESSION *session;
#endif

if (!php_ssh2_session_is_open(abstract->session_rsrc)) {
stream->eof = 1;
return -1;
}

stream->eof = libssh2_channel_eof(abstract->channel);
libssh2_channel_set_blocking(abstract->channel, abstract->is_blocking);
session = (LIBSSH2_SESSION *)zend_fetch_resource(abstract->session_rsrc, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);

#ifdef PHP_SSH2_SESSION_TIMEOUT
session = (LIBSSH2_SESSION *)zend_fetch_resource(abstract->session_rsrc, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);

if (abstract->is_blocking) {
libssh2_session_set_timeout(session, abstract->timeout);
}
Expand All @@ -117,17 +123,15 @@ static ssize_t php_ssh2_channel_stream_read(php_stream *stream, char *buf, size_
#endif

if (readstate == LIBSSH2_ERROR_EAGAIN) {
#if PHP_VERSION_ID < 70400
stream->eof = 0;
readstate = 0;
#endif
} else if (readstate < 0) {
char *error_msg = NULL;
if (libssh2_session_last_error(session, &error_msg, NULL, 0) == readstate) {
php_error_docref(NULL, E_WARNING, "Failure '%s' (%ld)", error_msg, readstate);
}

stream->eof = 1;
stream->eof = 0;
#if PHP_VERSION_ID < 70400
readstate = 0;
#endif
} else {
stream->eof = (readstate == 0 && libssh2_channel_eof(abstract->channel));
}
return readstate;
}
Expand All @@ -141,8 +145,10 @@ static int php_ssh2_channel_stream_close(php_stream *stream, int close_handle)
if (abstract->refcount) {
efree(abstract->refcount);
}
libssh2_channel_eof(abstract->channel);
libssh2_channel_free(abstract->channel);
if (php_ssh2_session_is_open(abstract->session_rsrc)) {
libssh2_channel_free(abstract->channel);
}

zend_list_delete(abstract->session_rsrc);
}
efree(abstract);
Expand All @@ -154,6 +160,10 @@ static int php_ssh2_channel_stream_flush(php_stream *stream)
{
php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract;

if (!php_ssh2_session_is_open(abstract->session_rsrc)) {
return -1;
}

return libssh2_channel_flush_ex(abstract->channel, abstract->streamid);
}

Expand All @@ -163,6 +173,10 @@ static int php_ssh2_channel_stream_cast(php_stream *stream, int castas, void **r
LIBSSH2_SESSION *session;
php_ssh2_session_data **session_data;

if (!php_ssh2_session_is_open(abstract->session_rsrc)) {
return FAILURE;
}

session = (LIBSSH2_SESSION *)zend_fetch_resource(abstract->session_rsrc, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
session_data = (php_ssh2_session_data **)libssh2_session_abstract(session);

Expand Down Expand Up @@ -192,8 +206,10 @@ static int php_ssh2_channel_stream_set_option(php_stream *stream, int option, in
break;

case PHP_STREAM_OPTION_META_DATA_API:
add_assoc_long((zval*)ptrparam, "exit_status", libssh2_channel_get_exit_status(abstract->channel));
break;
if (php_ssh2_session_is_open(abstract->session_rsrc)) {
add_assoc_long((zval*)ptrparam, "exit_status", libssh2_channel_get_exit_status(abstract->channel));
}
return PHP_STREAM_OPTION_RETURN_OK;

case PHP_STREAM_OPTION_READ_TIMEOUT:
ret = abstract->timeout;
Expand All @@ -207,6 +223,10 @@ static int php_ssh2_channel_stream_set_option(php_stream *stream, int option, in
break;

case PHP_STREAM_OPTION_CHECK_LIVENESS:
if (!php_ssh2_session_is_open(abstract->session_rsrc)) {
return stream->eof = 1;
}

return stream->eof = libssh2_channel_eof(abstract->channel);
break;
}
Expand Down Expand Up @@ -303,6 +323,11 @@ php_url *php_ssh2_fopen_wrapper_parse_path(const char *path, char *type, php_str
/* suppress potential warning by passing NULL as resource_type_name */
sftp_data = (php_ssh2_sftp_data *)zend_fetch_resource(Z_RES_P(zresource), NULL, le_ssh2_sftp);
if (sftp_data) {
if (!php_ssh2_session_is_open(sftp_data->session_rsrc)) {
php_url_free(resource);
return NULL;
}

/* Want the sftp layer */
Z_ADDREF_P(zresource);
*psftp_rsrc = Z_RES_P(zresource);
Expand Down Expand Up @@ -347,6 +372,11 @@ php_url *php_ssh2_fopen_wrapper_parse_path(const char *path, char *type, php_str
php_ssh2_sftp_data *sftp_data;
sftp_data = (php_ssh2_sftp_data *)zend_fetch_resource(Z_RES_P(tmpzval), PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
if (sftp_data) {
if (!php_ssh2_session_is_open(sftp_data->session_rsrc)) {
php_url_free(resource);
return NULL;
}

Z_ADDREF_P(tmpzval);
*psftp_rsrc = Z_RES_P(tmpzval);
*psftp = sftp_data->sftp;
Expand Down Expand Up @@ -454,20 +484,23 @@ php_url *php_ssh2_fopen_wrapper_parse_path(const char *path, char *type, php_str
return NULL;
}

if (pubkey_file && privkey_file &&
(php_check_open_basedir(pubkey_file) || php_check_open_basedir(privkey_file))) {
php_url_free(resource);
return NULL;
}

session = php_ssh2_session_connect(SSH2_URL_STR(resource->host), resource->port, methods, callbacks);
if (!session) {
/* Unable to connect! */
php_url_free(resource);
return NULL;
}

ZVAL_RES(&zsession, zend_register_resource(session, le_ssh2_session));

/* Authenticate */
if (pubkey_file && privkey_file) {
if (php_check_open_basedir(pubkey_file) || php_check_open_basedir(privkey_file)) {
php_url_free(resource);
return NULL;
}

/* Attempt pubkey authentication */
if (!libssh2_userauth_publickey_fromfile(session, username, pubkey_file, privkey_file, password)) {
goto session_authed;
Expand All @@ -483,14 +516,10 @@ php_url *php_ssh2_fopen_wrapper_parse_path(const char *path, char *type, php_str

/* Auth failure */
php_url_free(resource);
if (Z_RES(zsession)) {
zend_list_delete(Z_RES(zsession));
}
zend_list_delete(Z_RES(zsession));
return NULL;

session_authed:
ZVAL_RES(&zsession, zend_register_resource(session, le_ssh2_session));

if (psftp && psftp_rsrc) {
LIBSSH2_SFTP *sftp;

Expand All @@ -505,7 +534,6 @@ php_url *php_ssh2_fopen_wrapper_parse_path(const char *path, char *type, php_str
sftp_data->session = session;
sftp_data->sftp = sftp;
sftp_data->session_rsrc = Z_RES(zsession);
Z_ADDREF(zsession);
*psftp_rsrc = zend_register_resource(sftp_data, le_ssh2_sftp);
*psftp = sftp;
}
Expand Down Expand Up @@ -785,6 +813,10 @@ PHP_FUNCTION(ssh2_shell_resize)

data = (php_ssh2_channel_data*)parent->abstract;

if (!php_ssh2_session_is_open(data->session_rsrc)) {
RETURN_FALSE;
}

libssh2_channel_request_pty_size_ex(data->channel, width, height, width_px, height_px);

RETURN_TRUE;
Expand Down Expand Up @@ -1465,6 +1497,10 @@ PHP_FUNCTION(ssh2_fetch_stream)

data = (php_ssh2_channel_data*)parent->abstract;

if (!php_ssh2_session_is_open(data->session_rsrc)) {
RETURN_FALSE;
}

if (!data->refcount) {
data->refcount = emalloc(sizeof(unsigned char));
*(data->refcount) = 1;
Expand All @@ -1485,7 +1521,7 @@ PHP_FUNCTION(ssh2_fetch_stream)
if (!stream) {
php_error_docref(NULL, E_WARNING, "Error opening substream");
efree(stream_data);
(data->refcount)--;
(*(data->refcount))--;
RETURN_FALSE;
}

Expand Down Expand Up @@ -1521,6 +1557,10 @@ PHP_FUNCTION(ssh2_send_signal)
RETURN_FALSE;
}

if (!php_ssh2_session_is_open(data->session_rsrc)) {
RETURN_FALSE;
}

ssh2_ret = libssh2_channel_signal_ex(data->channel, signal->val, signal->len);
if (ssh2_ret < 0) {
php_error_docref(NULL, E_WARNING, "Couldn't send signal %s to channel (Return code %d)", signal->val, ssh2_ret);
Expand Down Expand Up @@ -1558,6 +1598,10 @@ PHP_FUNCTION(ssh2_send_eof)
RETURN_FALSE;
}

if (!php_ssh2_session_is_open(data->session_rsrc)) {
RETURN_FALSE;
}

ssh2_ret = libssh2_channel_send_eof(data->channel);
if (ssh2_ret < 0) {
php_error_docref(NULL, E_WARNING, "Couldn't send EOF to channel (Return code %d)", ssh2_ret);
Expand Down
Loading