[-]
[+]
|
Added |
php5-ssh2.changes
|
|
[-]
[+]
|
Changed |
php5-ssh2.spec
^
|
|
[-]
[+]
|
Deleted |
ssh2-0.11.3.tgz/ssh2-0.11.3/config.m4
^
|
@@ -1,81 +0,0 @@
-dnl $Id: config.m4 209383 2006-03-15 02:10:23Z pollita $
-dnl config.m4 for extension ssh2
-
-PHP_ARG_WITH(ssh2, for ssh2 support,
-[ --with-ssh2=[DIR] Include ssh2 support])
-
-if test "$PHP_SSH2" != "no"; then
- SEARCH_PATH="/usr/local /usr"
- SEARCH_FOR="/include/libssh2.h"
- if test -r $PHP_SSH2/$SEARCH_FOR; then # path given as parameter
- SSH2_DIR=$PHP_SSH2
- else
- AC_MSG_CHECKING([for ssh2 files in default path])
- for i in $SEARCH_PATH ; do
- if test -r $i/$SEARCH_FOR; then
- SSH2_DIR=$i
- AC_MSG_RESULT(found in $i)
- fi
- done
- fi
-
- if test -z "$SSH2_DIR"; then
- AC_MSG_RESULT([not found])
- AC_MSG_ERROR([The required libssh2 library was not found. You can obtain that package from http://sourceforge.net/projects/libssh2/])
- fi
-
- PHP_ADD_INCLUDE($SSH2_DIR/include)
-
- LIBNAME=ssh2
- LIBSYMBOL=libssh2_banner_set
-
- PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
- [
- PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $SSH2_DIR/lib, SSH2_SHARED_LIBADD)
- AC_DEFINE(HAVE_SSH2LIB,1,[Have libssh2])
- ],[
- AC_MSG_ERROR([libssh2 version >= 0.4 not found])
- ],[
- -L$SSH2_DIR/lib -lm
- ])
-
- PHP_CHECK_LIBRARY($LIBNAME,libssh2_channel_forward_listen_ex,
- [
- AC_DEFINE(PHP_SSH2_REMOTE_FORWARDING, 1, [Have libssh2 with remote forwarding])
- ],[
- AC_MSG_WARN([libssh2 <= 0.4, remote forwarding not enabled])
- ],[
- -L$SSH2_DIR/lib -lm
- ])
-
- PHP_CHECK_LIBRARY($LIBNAME,libssh2_userauth_hostbased_fromfile_ex,
- [
- AC_DEFINE(PHP_SSH2_HOSTBASED_AUTH, 1, [Have libssh2 with hostbased authentication])
- ],[
- AC_MSG_WARN([libssh2 <= 0.6, hostbased authentication not enabled])
- ],[
- -L$SSH2_DIR/lib -lm
- ])
-
- PHP_CHECK_LIBRARY($LIBNAME,libssh2_poll,
- [
- AC_DEFINE(PHP_SSH2_POLL, 1, [Have libssh2 with poll() support])
- ],[
- AC_MSG_WARN([libssh2 <= 0.7, poll support not enabled])
- ],[
- -L$SSH2_DIR/lib -lm
- ])
-
- PHP_CHECK_LIBRARY($LIBNAME,libssh2_publickey_init,
- [
- AC_DEFINE(PHP_SSH2_PUBLICKEY_SUBSYSTEM, 1, [Have libssh2 with publickey subsystem support])
- ],[
- AC_MSG_WARN([libssh2 <= 0.11, publickey subsystem support not enabled])
- ],[
- -L$SSH2_DIR/lib -lm
- ])
-
- PHP_SUBST(SSH2_SHARED_LIBADD)
-
- PHP_NEW_EXTENSION(ssh2, ssh2.c ssh2_fopen_wrappers.c ssh2_sftp.c, $ext_shared)
-fi
|
[-]
[+]
|
Deleted |
ssh2-0.11.3.tgz/ssh2-0.11.3/php_ssh2.h
^
|
@@ -1,222 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | PHP Version 4 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2006 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 2.02 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available at through the world-wide-web at |
- | http://www.php.net/license/2_02.txt. |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: Sara Golemon <pollita@php.net> |
- +----------------------------------------------------------------------+
-
- $Id: php_ssh2.h 306892 2010-12-30 23:59:55Z pajoye $
-*/
-
-#ifndef PHP_SSH2_H
-#define PHP_SSH2_H
-
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-#include "ext/standard/url.h"
-
-#define PHP_SSH2_VERSION "0.11.3-dev"
-#define PHP_SSH2_DEFAULT_PORT 22
-
-/* Exported Constants */
-#define PHP_SSH2_FINGERPRINT_MD5 0x0000
-#define PHP_SSH2_FINGERPRINT_SHA1 0x0001
-#define PHP_SSH2_FINGERPRINT_HEX 0x0000
-#define PHP_SSH2_FINGERPRINT_RAW 0x0002
-
-#define PHP_SSH2_TERM_UNIT_CHARS 0x0000
-#define PHP_SSH2_TERM_UNIT_PIXELS 0x0001
-
-#define PHP_SSH2_DEFAULT_TERMINAL "vanilla"
-#define PHP_SSH2_DEFAULT_TERM_WIDTH 80
-#define PHP_SSH2_DEFAULT_TERM_HEIGHT 25
-#define PHP_SSH2_DEFAULT_TERM_UNIT PHP_SSH2_TERM_UNIT_CHARS
-
-#define PHP_SSH2_SESSION_RES_NAME "SSH2 Session"
-#define PHP_SSH2_CHANNEL_STREAM_NAME "SSH2 Channel"
-#define PHP_SSH2_LISTENER_RES_NAME "SSH2 Listener"
-#define PHP_SSH2_SFTP_RES_NAME "SSH2 SFTP"
-#define PHP_SSH2_PKEY_SUBSYS_RES_NAME "SSH2 Publickey Subsystem"
-
-#define PHP_SSH2_SFTP_STREAM_NAME "SSH2 SFTP File"
-#define PHP_SSH2_SFTP_DIRSTREAM_NAME "SSH2 SFTP Directory"
-#define PHP_SSH2_SFTP_WRAPPER_NAME "SSH2 SFTP"
-
-#define PHP_SSH2_LISTEN_MAX_QUEUED 16
-
-#define PHP_SSH2_DEFAULT_POLL_TIMEOUT 30
-
-extern zend_module_entry ssh2_module_entry;
-#define phpext_ssh2_ptr &ssh2_module_entry
-
-typedef struct _php_ssh2_session_data {
- /* Userspace callback functions */
- zval *ignore_cb;
- zval *debug_cb;
- zval *macerror_cb;
- zval *disconnect_cb;
-
- int socket;
-
-#ifdef ZTS
- /* Avoid unnecessary TSRMLS_FETCH() calls */
- TSRMLS_D;
-#endif
-} php_ssh2_session_data;
-
-typedef struct _php_ssh2_sftp_data {
- LIBSSH2_SESSION *session;
- LIBSSH2_SFTP *sftp;
-
- int session_rsrcid;
-} php_ssh2_sftp_data;
-
-#ifdef PHP_SSH2_REMOTE_FORWARDING
-typedef struct _php_ssh2_listener_data {
- LIBSSH2_SESSION *session;
- LIBSSH2_LISTENER *listener;
-
- int session_rsrcid;
-} php_ssh2_listener_data;
-#endif
-
-#ifdef PHP_SSH2_PUBLICKEY_SUBSYSTEM
-#include "libssh2_publickey.h"
-
-typedef struct _php_ssh2_pkey_subsys_data {
- LIBSSH2_SESSION *session;
- LIBSSH2_PUBLICKEY *pkey;
-
- int session_rsrcid;
-} php_ssh2_pkey_subsys_data;
-#endif
-
-#ifndef PHP_WIN32
-#define closesocket(s) close(s)
-#endif
-
-#ifdef ZTS
-#define SSH2_TSRMLS_SET(datap) ((php_ssh2_session_data*)(datap))->tsrm_ls = TSRMLS_C
-#define SSH2_TSRMLS_FETCH(datap) TSRMLS_D = ((php_ssh2_session_data*)(datap))->tsrm_ls
-#else
-#define SSH2_TSRMLS_SET(datap)
-#define SSH2_TSRMLS_FETCH(datap)
-#endif
-
-#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION >= 3)
-#define ZEND_IS_CALLABLE_TSRMLS_CC TSRMLS_CC
-#else
-#define ZEND_IS_CALLABLE_TSRMLS_CC
-#endif
-
-/* < 5.3 compatibility */
-#ifndef Z_REFCOUNT_P
-#define Z_REFCOUNT_P(pz) (pz)->refcount
-#define Z_REFCOUNT_PP(ppz) Z_REFCOUNT_P(*(ppz))
-#endif
-
-#ifndef Z_SET_REFCOUNT_P
-#define Z_SET_REFCOUNT_P(pz, rc) (pz)->refcount = rc
-#define Z_SET_REFCOUNT_PP(ppz, rc) Z_SET_REFCOUNT_P(*(ppz), rc)
-#endif
-
-#ifndef Z_ISREF_P
-#define Z_ISREF_P(pz) (pz)->is_ref
-#define Z_ISREF_PP(ppz) Z_ISREF_P(*(ppz))
-#endif
-
-#ifndef Z_SET_ISREF_P
-#define Z_SET_ISREF_P(pz) (pz)->is_ref = 1
-#define Z_SET_ISREF_PP(ppz) Z_SET_ISREF_P(*(ppz))
-#endif
-
-#ifndef Z_UNSET_ISREF_P
-#define Z_UNSET_ISREF_P(pz) (pz)->is_ref = 0
-#define Z_UNSET_ISREF_PP(ppz) Z_UNSET_ISREF_P(*(ppz))
-#endif
-
-
-typedef struct _php_ssh2_channel_data {
- LIBSSH2_CHANNEL *channel;
-
- /* Distinguish which stream we should read/write from/to */
- unsigned int streamid;
- char is_blocking;
-
- /* Resource ID, zend_list_addref() when opening, zend_list_delete() when closing */
- long session_rsrc;
-
- /* Allow one stream to be closed while the other is kept open */
- unsigned char *refcount;
-
-} php_ssh2_channel_data;
-
-/* In ssh2_fopen_wrappers.c */
-PHP_FUNCTION(ssh2_shell);
-PHP_FUNCTION(ssh2_exec);
-PHP_FUNCTION(ssh2_tunnel);
-PHP_FUNCTION(ssh2_scp_recv);
-PHP_FUNCTION(ssh2_scp_send);
-PHP_FUNCTION(ssh2_fetch_stream);
-
-/* In ssh2_sftp.c */
-PHP_FUNCTION(ssh2_sftp);
-
-PHP_FUNCTION(ssh2_sftp_rename);
-PHP_FUNCTION(ssh2_sftp_unlink);
-PHP_FUNCTION(ssh2_sftp_mkdir);
-PHP_FUNCTION(ssh2_sftp_rmdir);
-PHP_FUNCTION(ssh2_sftp_stat);
-PHP_FUNCTION(ssh2_sftp_lstat);
-PHP_FUNCTION(ssh2_sftp_symlink);
-PHP_FUNCTION(ssh2_sftp_readlink);
-PHP_FUNCTION(ssh2_sftp_realpath);
-
-LIBSSH2_SESSION *php_ssh2_session_connect(char *host, int port, zval *methods, zval *callbacks TSRMLS_DC);
-void php_ssh2_sftp_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC);
-php_url *php_ssh2_fopen_wraper_parse_path( char *path, char *type, php_stream_context *context,
- LIBSSH2_SESSION **psession, int *presource_id,
- LIBSSH2_SFTP **psftp, int *psftp_rsrcid
- TSRMLS_DC);
-
-extern php_stream_ops php_ssh2_channel_stream_ops;
-
-extern php_stream_wrapper php_ssh2_stream_wrapper_shell;
-extern php_stream_wrapper php_ssh2_stream_wrapper_exec;
-extern php_stream_wrapper php_ssh2_stream_wrapper_tunnel;
-extern php_stream_wrapper php_ssh2_stream_wrapper_scp;
-extern php_stream_wrapper php_ssh2_sftp_wrapper;
-
-/* Resource list entries */
-extern int le_ssh2_session;
-extern int le_ssh2_sftp;
-
-/* {{{ ZIP_OPENBASEDIR_CHECKPATH(filename) */
-#if PHP_API_VERSION < 20100412
-# define SSH2_OPENBASEDIR_CHECKPATH(filename) \
- (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(filename TSRMLS_CC)
-#else
-#define SSH2_OPENBASEDIR_CHECKPATH(filename) \
- php_check_open_basedir(filename TSRMLS_CC)
-#endif
-/* }}} */
-#endif /* PHP_SSH2_H */
-
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * indent-tabs-mode: t
- * End:
- */
|
[-]
[+]
|
Deleted |
ssh2-0.11.3.tgz/ssh2-0.11.3/ssh2.c
^
|
@@ -1,1343 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | PHP Version 4 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2006 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 2.02 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available at through the world-wide-web at |
- | http://www.php.net/license/2_02.txt. |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: Sara Golemon <pollita@php.net> |
- +----------------------------------------------------------------------+
-
- $Id: ssh2.c 317115 2011-09-21 17:40:23Z bjori $
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "php.h"
-#include "ext/standard/info.h"
-#include "ext/standard/file.h"
-#include "php_ssh2.h"
-#include "main/php_network.h"
-
-#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
-#include <openssl/applink.c>
-#endif
-
-/* Internal Constants */
-#ifndef SHA_DIGEST_LENGTH
-#define SHA_DIGEST_LENGTH 20
-#endif
-
-#ifndef MD5_DIGEST_LENGTH
-#define MD5_DIGEST_LENGTH 16
-#endif
-
-/* True global resources - no need for thread safety here */
-int le_ssh2_session;
-#ifdef PHP_SSH2_REMOTE_FORWARDING
-int le_ssh2_listener;
-#endif
-int le_ssh2_sftp;
-#ifdef PHP_SSH2_PUBLICKEY_SUBSYSTEM
-int le_ssh2_pkey_subsys;
-#endif
-
-ZEND_BEGIN_ARG_INFO(php_ssh2_first_arg_force_ref, 0)
- ZEND_ARG_PASS_INFO(1)
-ZEND_END_ARG_INFO()
-
-/* *************
- * Callbacks *
- ************* */
-
-#ifdef ZTS
-#define PHP_SSH2_TSRMLS_FETCH() TSRMLS_D = *(void****)abstract;
-#else
-#define PHP_SSH2_TSRMLS_FETCH()
-#endif
-
-/* {{{ php_ssh2_alloc_cb
- * Wrap emalloc()
- */
-static LIBSSH2_ALLOC_FUNC(php_ssh2_alloc_cb)
-{
- return emalloc(count);
-}
-/* }}} */
-
-/* {{{ php_ssh2_free_cb
- * Wrap efree()
- */
-static LIBSSH2_FREE_FUNC(php_ssh2_free_cb)
-{
- efree(ptr);
-}
-/* }}} */
-
-/* {{{ php_ssh2_realloc_cb
- * Wrap erealloc()
- */
-static LIBSSH2_REALLOC_FUNC(php_ssh2_realloc_cb)
-{
- return erealloc(ptr, count);
-}
-/* }}} */
-
-/* {{{ php_ssh2_debug_cb
- * Debug packets
- */
-LIBSSH2_DEBUG_FUNC(php_ssh2_debug_cb)
-{
- php_ssh2_session_data *data;
- zval *zdisplay, *zmessage, *zlanguage;
- zval **args[3];
- SSH2_TSRMLS_FETCH(*abstract);
-
- if (!abstract || !*abstract) {
- return;
- }
- data = (php_ssh2_session_data*)*abstract;
- if (!data->debug_cb) {
- return;
- }
-
- MAKE_STD_ZVAL(zmessage);
- ZVAL_STRINGL(zmessage, (char*)message, message_len, 1);
- args[0] = &zmessage;
-
- MAKE_STD_ZVAL(zlanguage);
- ZVAL_STRINGL(zlanguage, (char*)language, language_len, 1);
- args[1] = &zlanguage;
-
- MAKE_STD_ZVAL(zdisplay);
- ZVAL_LONG(zdisplay, always_display);
- args[2] = &zdisplay;
-
- if (FAILURE == call_user_function_ex(NULL, NULL, data->disconnect_cb, NULL, 3, args, 0, NULL TSRMLS_CC)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure calling disconnect callback");
- }
- zval_ptr_dtor(&zdisplay);
- zval_ptr_dtor(&zmessage);
- zval_ptr_dtor(&zlanguage);
-}
-/* }}} */
-
-/* {{{ php_ssh2_ignore_cb
- * Ignore packets
- */
-LIBSSH2_IGNORE_FUNC(php_ssh2_ignore_cb)
-{
- php_ssh2_session_data *data;
- zval *zretval = NULL, *zmessage;
- zval **args[1];
- SSH2_TSRMLS_FETCH(*abstract);
-
- if (!abstract || !*abstract) {
- return;
- }
- data = (php_ssh2_session_data*)*abstract;
- if (!data->ignore_cb) {
- return;
- }
-
- MAKE_STD_ZVAL(zmessage);
- ZVAL_STRINGL(zmessage, (char*)message, message_len, 1);
- args[0] = &zmessage;
-
- if (FAILURE == call_user_function_ex(NULL, NULL, data->ignore_cb, &zretval, 1, args, 0, NULL TSRMLS_CC)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure calling ignore callback");
- }
- zval_ptr_dtor(&zmessage);
- if (zretval) {
- zval_ptr_dtor(&zretval);
- }
-}
-/* }}} */
-
-/* {{{ php_ssh2_macerror_cb
- * Called when a MAC error occurs, offers the chance to ignore
- * WHY ARE YOU IGNORING MAC ERRORS??????
- */
-LIBSSH2_MACERROR_FUNC(php_ssh2_macerror_cb)
-{
- php_ssh2_session_data *data;
- zval *zretval = NULL, *zpacket;
- zval **args[1];
- int retval = -1;
- SSH2_TSRMLS_FETCH(*abstract);
-
- if (!abstract || !*abstract) {
- return -1;
- }
- data = (php_ssh2_session_data*)*abstract;
- if (!data->macerror_cb) {
- return -1;
- }
-
- MAKE_STD_ZVAL(zpacket);
- ZVAL_STRINGL(zpacket, (char*)packet, packet_len, 1);
- args[0] = &zpacket;
-
- if (FAILURE == call_user_function_ex(NULL, NULL, data->macerror_cb, &zretval, 1, args, 0, NULL TSRMLS_CC)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure calling macerror callback");
- } else {
- retval = zval_is_true(zretval) ? 0 : -1;
- }
- zval_ptr_dtor(&zpacket);
- if (zretval) {
- zval_ptr_dtor(&zretval);
- }
-
- return retval;
-}
-/* }}} */
-
-/* {{{ php_ssh2_disconnect_cb
- * Connection closed by foreign host
- */
-LIBSSH2_DISCONNECT_FUNC(php_ssh2_disconnect_cb)
-{
- php_ssh2_session_data *data;
- zval *zreason, *zmessage, *zlanguage;
- zval **args[3];
- SSH2_TSRMLS_FETCH(*abstract);
-
- if (!abstract || !*abstract) {
- return;
- }
- data = (php_ssh2_session_data*)*abstract;
- if (!data->disconnect_cb) {
- return;
- }
-
- MAKE_STD_ZVAL(zreason);
- ZVAL_LONG(zreason, reason);
- args[0] = &zreason;
-
- MAKE_STD_ZVAL(zmessage);
- ZVAL_STRINGL(zmessage, (char*)message, message_len, 1);
- args[1] = &zmessage;
-
- MAKE_STD_ZVAL(zlanguage);
- ZVAL_STRINGL(zlanguage, (char*)language, language_len, 1);
- args[2] = &zlanguage;
-
- if (FAILURE == call_user_function_ex(NULL, NULL, data->disconnect_cb, NULL, 3, args, 0, NULL TSRMLS_CC)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure calling disconnect callback");
- }
- zval_ptr_dtor(&zreason);
- zval_ptr_dtor(&zmessage);
- zval_ptr_dtor(&zlanguage);
-}
-/* }}} */
-
-/* *****************
- * Userspace API *
- ***************** */
-
-/* {{{ php_ssh2_set_callback
- * Try to set a method if it's passed in with the hash table
- */
-static int php_ssh2_set_callback(LIBSSH2_SESSION *session, HashTable *ht, char *callback, int callback_len, int callback_type, php_ssh2_session_data *data TSRMLS_DC)
-{
- zval **handler, *copyval;
- void *internal_handler;
-
- if (zend_hash_find(ht, callback, callback_len + 1, (void**)&handler) == FAILURE) {
- return 0;
- }
-
- if (!handler || !*handler || !zend_is_callable(*handler, 0, NULL ZEND_IS_CALLABLE_TSRMLS_CC)) {
- return -1;
- }
-
- ALLOC_INIT_ZVAL(copyval);
- *copyval = **handler;
- zval_copy_ctor(copyval);
-
- switch (callback_type) {
- case LIBSSH2_CALLBACK_IGNORE:
- internal_handler = php_ssh2_ignore_cb;
- if (data->ignore_cb) {
- zval_ptr_dtor(&data->ignore_cb);
- }
- data->ignore_cb = copyval;
- break;
- case LIBSSH2_CALLBACK_DEBUG:
- internal_handler = php_ssh2_debug_cb;
- if (data->debug_cb) {
- zval_ptr_dtor(&data->debug_cb);
- }
- data->debug_cb = copyval;
- break;
- case LIBSSH2_CALLBACK_MACERROR:
- internal_handler = php_ssh2_macerror_cb;
- if (data->macerror_cb) {
- zval_ptr_dtor(&data->macerror_cb);
- }
- data->macerror_cb = copyval;
- break;
- case LIBSSH2_CALLBACK_DISCONNECT:
- internal_handler = php_ssh2_disconnect_cb;
- if (data->disconnect_cb) {
- zval_ptr_dtor(&data->disconnect_cb);
- }
- data->disconnect_cb = copyval;
- break;
- default:
- zval_ptr_dtor(©val);
- return -1;
- }
-
- libssh2_session_callback_set(session, callback_type, internal_handler);
-
- return 0;
-}
-/* }}} */
-
-/* {{{ php_ssh2_set_method
- * Try to set a method if it's passed in with the hash table
- */
-static int php_ssh2_set_method(LIBSSH2_SESSION *session, HashTable *ht, char *method, int method_len, int method_type)
-{
- zval **value;
-
- if (zend_hash_find(ht, method, method_len + 1, (void**)&value) == FAILURE) {
- return 0;
- }
-
- if (!value || !*value || (Z_TYPE_PP(value) != IS_STRING)) {
- return -1;
- }
-
- return libssh2_session_method_pref(session, method_type, Z_STRVAL_PP(value));
-}
-/* }}} */
-
-/* {{{ php_ssh2_session_connect
- * Connect to an SSH server with requested methods
- */
-LIBSSH2_SESSION *php_ssh2_session_connect(char *host, int port, zval *methods, zval *callbacks TSRMLS_DC)
-{
- LIBSSH2_SESSION *session;
- int socket;
- php_ssh2_session_data *data;
- struct timeval tv;
-
- tv.tv_sec = FG(default_socket_timeout);
- tv.tv_usec = 0;
-
-#if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 0)
- socket = php_network_connect_socket_to_host(host, port, SOCK_STREAM, 0, &tv, NULL, NULL, NULL, 0 TSRMLS_CC);
-#elif PHP_MAJOR_VERSION == 5
- socket = php_network_connect_socket_to_host(host, port, SOCK_STREAM, 0, &tv, NULL, NULL TSRMLS_CC);
-#else
- socket = php_hostconnect(host, port, SOCK_STREAM, &tv TSRMLS_CC);
-#endif
-
- if (socket <= 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to %s on port %d", host, port);
- return NULL;
- }
-
- data = ecalloc(1, sizeof(php_ssh2_session_data));
- SSH2_TSRMLS_SET(data);
- data->socket = socket;
-
- session = libssh2_session_init_ex(php_ssh2_alloc_cb, php_ssh2_free_cb, php_ssh2_realloc_cb, data);
- if (!session) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to initialize SSH2 session");
- efree(data);
- closesocket(socket);
- return NULL;
- }
- libssh2_banner_set(session, LIBSSH2_SSH_DEFAULT_BANNER " PHP");
-
- /* Override method preferences */
- if (methods) {
- zval **container;
-
- if (php_ssh2_set_method(session, HASH_OF(methods), "kex", sizeof("kex") - 1, LIBSSH2_METHOD_KEX)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding KEX method");
- }
- if (php_ssh2_set_method(session, HASH_OF(methods), "hostkey", sizeof("hostkey") - 1, LIBSSH2_METHOD_HOSTKEY)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding HOSTKEY method");
- }
-
- if (zend_hash_find(HASH_OF(methods), "client_to_server", sizeof("client_to_server"), (void**)&container) == SUCCESS &&
- container && *container && Z_TYPE_PP(container) == IS_ARRAY) {
- if (php_ssh2_set_method(session, HASH_OF(*container), "crypt", sizeof("crypt") - 1, LIBSSH2_METHOD_CRYPT_CS)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding client to server CRYPT method");
- }
- if (php_ssh2_set_method(session, HASH_OF(*container), "mac", sizeof("mac") - 1, LIBSSH2_METHOD_MAC_CS)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding client to server MAC method");
- }
- if (php_ssh2_set_method(session, HASH_OF(*container), "comp", sizeof("comp") - 1, LIBSSH2_METHOD_COMP_CS)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding client to server COMP method");
- }
- if (php_ssh2_set_method(session, HASH_OF(*container), "lang", sizeof("lang") - 1, LIBSSH2_METHOD_LANG_CS)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding client to server LANG method");
- }
- }
-
- if (zend_hash_find(HASH_OF(methods), "server_to_client", sizeof("server_to_client"), (void**)&container) == SUCCESS &&
- container && *container && Z_TYPE_PP(container) == IS_ARRAY) {
- if (php_ssh2_set_method(session, HASH_OF(*container), "crypt", sizeof("crypt") - 1, LIBSSH2_METHOD_CRYPT_SC)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding server to client CRYPT method");
- }
- if (php_ssh2_set_method(session, HASH_OF(*container), "mac", sizeof("mac") - 1, LIBSSH2_METHOD_MAC_SC)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding server to client MAC method");
- }
- if (php_ssh2_set_method(session, HASH_OF(*container), "comp", sizeof("comp") - 1, LIBSSH2_METHOD_COMP_SC)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding server to client COMP method");
- }
- if (php_ssh2_set_method(session, HASH_OF(*container), "lang", sizeof("lang") - 1, LIBSSH2_METHOD_LANG_SC)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding server to client LANG method");
- }
- }
- }
-
- /* Register Callbacks */
- if (callbacks) {
- /* ignore debug disconnect macerror */
-
- if (php_ssh2_set_callback(session, HASH_OF(callbacks), "ignore", sizeof("ignore") - 1, LIBSSH2_CALLBACK_IGNORE, data TSRMLS_CC)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting IGNORE callback");
- }
-
- if (php_ssh2_set_callback(session, HASH_OF(callbacks), "debug", sizeof("debug") - 1, LIBSSH2_CALLBACK_DEBUG, data TSRMLS_CC)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting DEBUG callback");
- }
-
- if (php_ssh2_set_callback(session, HASH_OF(callbacks), "macerror", sizeof("macerror") - 1, LIBSSH2_CALLBACK_MACERROR, data TSRMLS_CC)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting MACERROR callback");
- }
-
- if (php_ssh2_set_callback(session, HASH_OF(callbacks), "disconnect", sizeof("disconnect") - 1, LIBSSH2_CALLBACK_DISCONNECT, data TSRMLS_CC)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting DISCONNECT callback");
- }
- }
-
- if (libssh2_session_startup(session, socket)) {
- int last_error = 0;
- char *error_msg = NULL;
-
- last_error = libssh2_session_last_error(session, &error_msg, NULL, 0);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error starting up SSH connection(%d): %s", last_error, error_msg);
- closesocket(socket);
- libssh2_session_free(session);
- efree(data);
- return NULL;
- }
-
- return session;
-}
-/* }}} */
-
-/* {{{ proto resource ssh2_connect(string host[, int port[, array methods[, array callbacks]]])
- * Establish a connection to a remote SSH server and return a resource on success, false on error
- */
-PHP_FUNCTION(ssh2_connect)
-{
- LIBSSH2_SESSION *session;
- zval *methods = NULL, *callbacks = NULL;
- char *host;
- long port = PHP_SSH2_DEFAULT_PORT;
- int host_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|la!a!", &host, &host_len, &port, &methods, &callbacks) == FAILURE) {
- RETURN_FALSE;
- }
-
- session = php_ssh2_session_connect(host, port, methods, callbacks TSRMLS_CC);
- if (!session) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to %s", host);
- RETURN_FALSE;
- }
-
- ZEND_REGISTER_RESOURCE(return_value, session, le_ssh2_session);
-}
-/* }}} */
-
-/* {{{ proto array ssh2_methods_negotiated(resource session)
- * Return list of negotiaed methods
- */
-PHP_FUNCTION(ssh2_methods_negotiated)
-{
- LIBSSH2_SESSION *session;
- zval *zsession, *endpoint;
- char *kex, *hostkey, *crypt_cs, *crypt_sc, *mac_cs, *mac_sc, *comp_cs, *comp_sc, *lang_cs, *lang_sc;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zsession) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
-
-#if defined(LIBSSH2_APINO) && LIBSSH2_APINO < 200412301450
- libssh2_session_methods(session, &kex, &hostkey, &crypt_cs, &crypt_sc, &mac_cs, &mac_sc, &comp_cs, &comp_sc, &lang_cs, &lang_sc);
-#else
- kex = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_KEX);
- hostkey = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_HOSTKEY);
- crypt_cs = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_CRYPT_CS);
- crypt_sc = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_CRYPT_SC);
- mac_cs = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_MAC_CS);
- mac_sc = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_MAC_SC);
- comp_cs = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_COMP_CS);
- comp_sc = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_COMP_SC);
- lang_cs = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_LANG_CS);
- lang_sc = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_LANG_SC);
-#endif
-
- array_init(return_value);
- add_assoc_string(return_value, "kex", kex, 1);
- add_assoc_string(return_value, "hostkey", hostkey, 1);
-
- ALLOC_INIT_ZVAL(endpoint);
- array_init(endpoint);
- add_assoc_string(endpoint, "crypt", crypt_cs, 1);
- add_assoc_string(endpoint, "mac", mac_cs, 1);
- add_assoc_string(endpoint, "comp", comp_cs, 1);
- add_assoc_string(endpoint, "lang", lang_cs, 1);
- add_assoc_zval(return_value, "client_to_server", endpoint);
-
- ALLOC_INIT_ZVAL(endpoint);
- array_init(endpoint);
- add_assoc_string(endpoint, "crypt", crypt_sc, 1);
- add_assoc_string(endpoint, "mac", mac_sc, 1);
- add_assoc_string(endpoint, "comp", comp_sc, 1);
- add_assoc_string(endpoint, "lang", lang_sc, 1);
- add_assoc_zval(return_value, "server_to_client", endpoint);
-}
-/* }}} */
-
-/* {{{ proto string ssh2_fingerprint(resource session[, int flags])
- * Returns a server hostkey hash from an active session
- * Defaults to MD5 fingerprint encoded as ASCII hex values
- */
-PHP_FUNCTION(ssh2_fingerprint)
-{
- LIBSSH2_SESSION *session;
- zval *zsession;
- const char *fingerprint;
- long flags = 0;
- int i, fingerprint_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zsession, &flags) == FAILURE) {
- RETURN_FALSE;
- }
- fingerprint_len = (flags & PHP_SSH2_FINGERPRINT_SHA1) ? SHA_DIGEST_LENGTH : MD5_DIGEST_LENGTH;
-
- ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
-
- fingerprint = (char*)libssh2_hostkey_hash(session, (flags & PHP_SSH2_FINGERPRINT_SHA1) ? LIBSSH2_HOSTKEY_HASH_SHA1 : LIBSSH2_HOSTKEY_HASH_MD5);
- if (!fingerprint) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to retreive fingerprint from specified session");
- RETURN_FALSE;
- }
-
- for(i = 0; i < fingerprint_len; i++) {
- if (fingerprint[i] != '\0') {
- goto fingerprint_good;
- }
- }
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "No fingerprint available using specified hash");
- RETURN_NULL();
- fingerprint_good:
- if (flags & PHP_SSH2_FINGERPRINT_RAW) {
- RETURN_STRINGL(fingerprint, fingerprint_len, 1);
- } else {
- char *hexchars;
-
- hexchars = emalloc((fingerprint_len * 2) + 1);
- for(i = 0; i < fingerprint_len; i++) {
- snprintf(hexchars + (2 * i), 3, "%02X", (unsigned char)fingerprint[i]);
- }
- RETURN_STRINGL(hexchars, 2 * fingerprint_len, 0);
- }
-}
-/* }}} */
-
-/* {{{ proto array ssh2_auth_none(resource session, string username)
- * Attempt "none" authentication, returns a list of allowed methods on failed authentication,
- * false on utter failure, or true on success
- */
-PHP_FUNCTION(ssh2_auth_none)
-{
- LIBSSH2_SESSION *session;
- zval *zsession;
- char *username, *methods, *s, *p;
- int username_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsession, &username, &username_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
-
- s = methods = libssh2_userauth_list(session, username, username_len);
- if (!methods) {
- /* Either bad failure, or unexpected success */
- RETURN_BOOL(libssh2_userauth_authenticated(session));
- }
-
- array_init(return_value);
- while ((p = strchr(s, ','))) {
- if ((p - s) > 0) {
- add_next_index_stringl(return_value, s, p - s, 1);
- }
- s = p + 1;
- }
- if (strlen(s)) {
- add_next_index_string(return_value, s, 1);
- }
-}
-/* }}} */
-
-/* {{{ proto bool ssh2_auth_password(resource session, string username, string password)
- * Authenticate over SSH using a plain password
- */
-PHP_FUNCTION(ssh2_auth_password)
-{
- LIBSSH2_SESSION *session;
- zval *zsession;
- char *username, *password;
- int username_len, password_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &zsession, &username, &username_len, &password, &password_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
-
- /* TODO: Support password change callback */
- if (libssh2_userauth_password_ex(session, username, username_len, password, password_len, NULL)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Authentication failed for %s using password", username);
- RETURN_FALSE;
- }
-
- RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto bool ssh2_auth_pubkey_file(resource session, string username, string pubkeyfile, string privkeyfile[, string passphrase])
- * Authenticate using a public key
- */
-PHP_FUNCTION(ssh2_auth_pubkey_file)
-{
- LIBSSH2_SESSION *session;
- zval *zsession;
- char *username, *pubkey, *privkey, *passphrase = NULL;
- int username_len, pubkey_len, privkey_len, passphrase_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsss|s", &zsession, &username, &username_len,
- &pubkey, &pubkey_len,
- &privkey, &privkey_len,
- &passphrase, &passphrase_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- if (SSH2_OPENBASEDIR_CHECKPATH(pubkey) || SSH2_OPENBASEDIR_CHECKPATH(privkey)) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
-
- /* TODO: Support passphrase callback */
- if (libssh2_userauth_publickey_fromfile_ex(session, username, username_len, pubkey, privkey, passphrase)) {
- char *buf;
- int len;
- libssh2_session_last_error(session, &buf, &len, 0);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Authentication failed for %s using public key: %s", username, buf);
- RETURN_FALSE;
- }
-
- RETURN_TRUE;
-}
-/* }}} */
-
-#ifdef PHP_SSH2_HOSTBASED_AUTH
-/* {{{ proto bool ssh2_auth_hostbased_file(resource session, string username, string local_hostname, string pubkeyfile, string privkeyfile[, string passphrase[, string local_username]])
- * Authenticate using a hostkey
- */
-PHP_FUNCTION(ssh2_auth_hostbased_file)
-{
- LIBSSH2_SESSION *session;
- zval *zsession;
- char *username, *hostname, *pubkey, *privkey, *passphrase = NULL, *local_username = NULL;
- int username_len, hostname_len, pubkey_len, privkey_len, passphrase_len, local_username_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rssss|s!s!", &zsession, &username, &username_len,
- &hostname, &hostname_len,
- &pubkey, &pubkey_len,
- &privkey, &privkey_len,
- &passphrase, &passphrase_len,
- &local_username, &local_username_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- if (SSH2_OPENBASEDIR_CHECKPATH(pubkey) || SSH2_OPENBASEDIR_CHECKPATH(privkey)) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
-
- if (!local_username) {
- local_username = username;
- local_username_len = username_len;
- }
-
- /* TODO: Support passphrase callback */
- if (libssh2_userauth_hostbased_fromfile_ex(session, username, username_len, pubkey, privkey, passphrase, hostname, hostname_len, local_username, local_username_len)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Authentication failed for %s using hostbased public key", username);
- RETURN_FALSE;
- }
-
- RETURN_TRUE;
-}
-/* }}} */
-#endif /* PHP_SSH2_HOSTBASED_AUTH */
-
-#ifdef PHP_SSH2_REMOTE_FORWARDING
-/* {{{ proto resource ssh2_forward_listen(resource session, int port[, string host[, long max_connections]])
- * Bind a port on the remote server and listen for connections
- */
-PHP_FUNCTION(ssh2_forward_listen)
-{
- zval *zsession;
- LIBSSH2_SESSION *session;
- LIBSSH2_LISTENER *listener;
- php_ssh2_listener_data *data;
- long port;
- char *host = NULL;
- int host_len;
- long max_connections = PHP_SSH2_LISTEN_MAX_QUEUED;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|sl", &zsession, &port, &host, &host_len, &max_connections) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
-
- listener = libssh2_channel_forward_listen_ex(session, host, port, NULL, max_connections);
-
- if (!listener) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure listening on remote port");
- RETURN_FALSE;
- }
-
- data = emalloc(sizeof(php_ssh2_listener_data));
- data->session = session;
- data->session_rsrcid = Z_LVAL_P(zsession);
- zend_list_addref(data->session_rsrcid);
- data->listener = listener;
-
- ZEND_REGISTER_RESOURCE(return_value, data, le_ssh2_listener);
-}
-/* }}} */
-
-/* {{{ proto stream ssh2_forward_accept(resource listener[, string &shost[, long &sport]])
- * Accept a connection created by a listener
- */
-PHP_FUNCTION(ssh2_forward_accept)
-{
- zval *zlistener;
- php_ssh2_listener_data *data;
- LIBSSH2_CHANNEL *channel;
- php_ssh2_channel_data *channel_data;
- php_stream *stream;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zlistener) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(data, php_ssh2_listener_data*, &zlistener, -1, PHP_SSH2_LISTENER_RES_NAME, le_ssh2_listener);
-
- channel = libssh2_channel_forward_accept(data->listener);
-
- if (!channel) {
- RETURN_FALSE;
- }
-
- channel_data = emalloc(sizeof(php_ssh2_channel_data));
- channel_data->channel = channel;
- channel_data->streamid = 0;
- channel_data->is_blocking = 0;
- channel_data->session_rsrc = data->session_rsrcid;
- channel_data->refcount = NULL;
-
- stream = php_stream_alloc(&php_ssh2_channel_stream_ops, channel_data, 0, "r+");
- if (!stream) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure allocating stream");
- efree(channel_data);
- libssh2_channel_free(channel);
- RETURN_FALSE;
- }
- zend_list_addref(channel_data->session_rsrc);
-
- php_stream_to_zval(stream, return_value);
-}
-/* }}} */
-#endif /* PHP_SSH2_REMOTE_FORWARDING */
-
-#ifdef PHP_SSH2_POLL
-/* {{{ proto int ssh2_poll(array &polldes[, int timeout])
- * Poll the channels/listeners/streams for events
- * Returns number of descriptors which returned non-zero revents
- * Input array should be of the form:
- * array(
- * 0 => array(
- * [resource] => $channel,$listener, or $stream
- * [events] => SSH2_POLL* flags bitwise ORed together
- * ),
- * 1 => ...
- * )
- * Each subarray will be populated with an revents element on return
- */
-PHP_FUNCTION(ssh2_poll)
-{
- zval *zdesc, **subarray;
- long timeout = PHP_SSH2_DEFAULT_POLL_TIMEOUT;
- LIBSSH2_POLLFD *pollfds;
- int numfds, i = 0, fds_ready;
- int le_stream = php_file_le_stream();
- int le_pstream = php_file_le_pstream();
- zval ***pollmap;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &zdesc, &timeout) == FAILURE) {
- RETURN_NULL();
- }
-
- numfds = zend_hash_num_elements(Z_ARRVAL_P(zdesc));
- pollfds = safe_emalloc(sizeof(LIBSSH2_POLLFD), numfds, 0);
- pollmap = safe_emalloc(sizeof(zval**), numfds, 0);
-
- for(zend_hash_internal_pointer_reset(Z_ARRVAL_P(zdesc));
- zend_hash_get_current_data(Z_ARRVAL_P(zdesc), (void**)&subarray) == SUCCESS;
- zend_hash_move_forward(Z_ARRVAL_P(zdesc))) {
- zval **tmpzval;
- int res_type = 0;
- void *res;
-
- if (Z_TYPE_PP(subarray) != IS_ARRAY) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid element in poll array, not a sub array");
- numfds--;
- continue;
- }
- if (zend_hash_find(Z_ARRVAL_PP(subarray), "events", sizeof("events"), (void**)&tmpzval) == FAILURE ||
- Z_TYPE_PP(tmpzval) != IS_LONG) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid data in subarray, no events element, or not a bitmask");
- numfds--;
- continue;
- }
- pollfds[i].events = Z_LVAL_PP(tmpzval);
- if (zend_hash_find(Z_ARRVAL_PP(subarray), "resource", sizeof("resource"), (void**)&tmpzval) == FAILURE ||
- Z_TYPE_PP(tmpzval) != IS_RESOURCE) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid data in subarray, no resource element, or not of type resource");
- numfds--;
- continue;
- }
- zend_list_find(Z_LVAL_PP(tmpzval), &res_type);
- res = zend_fetch_resource(tmpzval TSRMLS_CC, -1, "Poll Resource", NULL, 1, res_type);
- if (res_type == le_ssh2_listener) {
- pollfds[i].type = LIBSSH2_POLLFD_LISTENER;
- pollfds[i].fd.listener = ((php_ssh2_listener_data*)res)->listener;
- } else if ((res_type == le_stream || res_type == le_pstream) &&
- ((php_stream*)res)->ops == &php_ssh2_channel_stream_ops) {
- pollfds[i].type = LIBSSH2_POLLFD_CHANNEL;
- pollfds[i].fd.channel = ((php_ssh2_channel_data*)(((php_stream*)res)->abstract))->channel;
- /* TODO: Add the ability to select against other stream types */
- } else {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid resource type in subarray: %s", zend_rsrc_list_get_rsrc_type(Z_LVAL_PP(tmpzval) TSRMLS_CC));
- numfds--;
- continue;
- }
- pollmap[i] = subarray;
- i++;
- }
-
- fds_ready = libssh2_poll(pollfds, numfds, timeout * 1000);
-
- for(i = 0; i < numfds; i++) {
- zval *subarray = *pollmap[i];
-
- if (!Z_ISREF_P(subarray) && Z_REFCOUNT_P(subarray) > 1) {
- /* Make a new copy of the subarray zval* */
- MAKE_STD_ZVAL(subarray);
- *subarray = **pollmap[i];
-
- /* Point the pData to the new zval* and duplicate its resources */
- *pollmap[i] = subarray;
- zval_copy_ctor(subarray);
-
- /* Fixup its refcount */
- Z_UNSET_ISREF_P(subarray);
- Z_SET_REFCOUNT_P(subarray, 1);
- }
- zend_hash_del(Z_ARRVAL_P(subarray), "revents", sizeof("revents"));
- add_assoc_long(subarray, "revents", pollfds[i].revents);
-
- }
- efree(pollmap);
- efree(pollfds);
-
- RETURN_LONG(fds_ready);
-}
-/* }}} */
-#endif /* PHP_SSH2_POLL */
-
-#ifdef PHP_SSH2_PUBLICKEY_SUBSYSTEM
-/* ***********************
- * Publickey Subsystem *
- *********************** */
-
-/* {{{ proto resource ssh2_publickey_init(resource connection)
-Initialize the publickey subsystem */
-PHP_FUNCTION(ssh2_publickey_init)
-{
- zval *zsession;
- LIBSSH2_SESSION *session;
- LIBSSH2_PUBLICKEY *pkey;
- php_ssh2_pkey_subsys_data *data;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zsession) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
-
- pkey = libssh2_publickey_init(session);
-
- if (!pkey) {
- int last_error = 0;
- char *error_msg = NULL;
-
- last_error = libssh2_session_last_error(session, &error_msg, NULL, 0);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to initialize publickey subsystem(%d) %s", last_error, error_msg);
- RETURN_FALSE;
- }
-
- data = emalloc(sizeof(php_ssh2_pkey_subsys_data));
- data->session = session;
- data->session_rsrcid = Z_LVAL_P(zsession);
- zend_list_addref(data->session_rsrcid);
- data->pkey = pkey;
-
- ZEND_REGISTER_RESOURCE(return_value, data, le_ssh2_pkey_subsys);
-}
-/* }}} */
-
-/* {{{ proto bool ssh2_publickey_add(resource pkey, string algoname, string blob[, bool overwrite=FALSE [,array attributes=NULL]])
-Add an additional publickey */
-PHP_FUNCTION(ssh2_publickey_add)
-{
- zval *zpkey_data, *zattrs = NULL;
- php_ssh2_pkey_subsys_data *data;
- char *algo, *blob;
- int algo_len, blob_len;
- unsigned long num_attrs = 0;
- libssh2_publickey_attribute *attrs = NULL;
- zend_bool overwrite = 0;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss|ba", &zpkey_data, &algo, &algo_len, &blob, &blob_len, &overwrite, &zattrs) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(data, php_ssh2_pkey_subsys_data*, &zpkey_data, -1, PHP_SSH2_PKEY_SUBSYS_RES_NAME, le_ssh2_pkey_subsys);
-
- if (zattrs) {
- HashPosition pos;
- zval **attr_val;
- unsigned long current_attr = 0;
-
- num_attrs = zend_hash_num_elements(Z_ARRVAL_P(zattrs));
- attrs = safe_emalloc(num_attrs, sizeof(libssh2_publickey_attribute), 0);
-
- for(zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(zattrs), &pos);
- zend_hash_get_current_data_ex(Z_ARRVAL_P(zattrs), (void**)&attr_val, &pos) == SUCCESS;
- zend_hash_move_forward_ex(Z_ARRVAL_P(zattrs), &pos)) {
- char *key;
- int key_len, type;
- long idx;
- zval copyval = **attr_val;
-
- type = zend_hash_get_current_key_ex(Z_ARRVAL_P(zattrs), &key, &key_len, &idx, 0, &pos);
- if (type == HASH_KEY_NON_EXISTANT) {
- /* All but impossible */
- break;
- }
- if (type == HASH_KEY_IS_LONG) {
- /* Malformed, ignore */
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Malformed attirbute array, contains numeric index");
- num_attrs--;
- continue;
- }
-
- if (key_len == 0 || (key_len == 1 && *key == '*')) {
- /* Empty key, ignore */
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty attribute key");
- num_attrs--;
- continue;
- }
-
- zval_copy_ctor(©val);
- Z_UNSET_ISREF_P(©val);
- Z_SET_REFCOUNT_P(©val, 1);
- convert_to_string(©val);
-
- if (*key == '*') {
- attrs[current_attr].mandatory = 1;
- attrs[current_attr].name = key + 1;
- attrs[current_attr].name_len = key_len - 2;
- } else {
- attrs[current_attr].mandatory = 0;
- attrs[current_attr].name = key;
- attrs[current_attr].name_len = key_len - 1;
- }
- attrs[current_attr].value_len = Z_STRLEN(copyval);
- attrs[current_attr].value = Z_STRVAL(copyval);
-
- /* copyval deliberately not dtor'd, we're stealing the string */
- current_attr++;
- }
- }
-
- if (libssh2_publickey_add_ex(data->pkey, algo, algo_len, blob, blob_len, overwrite, num_attrs, attrs)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add %s key", algo);
- RETVAL_FALSE;
- } else {
- RETVAL_TRUE;
- }
-
- if (attrs) {
- unsigned long i;
-
- for(i = 0; i < num_attrs; i++) {
- /* name doesn't need freeing */
- efree(attrs[i].value);
- }
- efree(attrs);
- }
-}
-/* }}} */
-
-/* {{{ proto bool ssh2_publickey_remove(resource pkey, string algoname, string blob)
-Remove a publickey entry */
-PHP_FUNCTION(ssh2_publickey_remove)
-{
- zval *zpkey_data;
- php_ssh2_pkey_subsys_data *data;
- char *algo, *blob;
- int algo_len, blob_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &zpkey_data, &algo, &algo_len, &blob, &blob_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(data, php_ssh2_pkey_subsys_data*, &zpkey_data, -1, PHP_SSH2_PKEY_SUBSYS_RES_NAME, le_ssh2_pkey_subsys);
-
- if (libssh2_publickey_remove_ex(data->pkey, algo, algo_len, blob, blob_len)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to remove %s key", algo);
- RETURN_FALSE;
- }
-
- RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto array ssh2_publickey_list(resource pkey)
-List currently installed publickey entries */
-PHP_FUNCTION(ssh2_publickey_list)
-{
- zval *zpkey_data;
- php_ssh2_pkey_subsys_data *data;
- unsigned long num_keys, i;
- libssh2_publickey_list *keys;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zpkey_data) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(data, php_ssh2_pkey_subsys_data*, &zpkey_data, -1, PHP_SSH2_PKEY_SUBSYS_RES_NAME, le_ssh2_pkey_subsys);
-
- if (libssh2_publickey_list_fetch(data->pkey, &num_keys, &keys)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to list keys on remote server");
- RETURN_FALSE;
- }
-
- array_init(return_value);
- for(i = 0; i < num_keys; i++) {
- zval *key, *attrs;
- unsigned long j;
-
- MAKE_STD_ZVAL(key);
- array_init(key);
-
- add_assoc_stringl(key, "name", keys[i].name, keys[i].name_len, 1);
- add_assoc_stringl(key, "blob", keys[i].blob, keys[i].blob_len, 1);
-
- MAKE_STD_ZVAL(attrs);
- array_init(attrs);
- for(j = 0; j < keys[i].num_attrs; j++) {
- zval *attr;
-
- MAKE_STD_ZVAL(attr);
- ZVAL_STRINGL(attr, keys[i].attrs[j].value, keys[i].attrs[j].value_len, 1);
- zend_hash_add(Z_ARRVAL_P(attrs), keys[i].attrs[j].name, keys[i].attrs[j].name_len + 1, (void**)&attr, sizeof(zval*), NULL);
- }
- add_assoc_zval(key, "attrs", attrs);
-
- add_next_index_zval(return_value, key);
- }
-
- libssh2_publickey_list_free(data->pkey, keys);
-}
-/* }}} */
-#endif /* PHP_SSH2_PUBLICKEY_SUBSYSTEM */
-
-/* ***********************
- * Module Housekeeping *
- *********************** */
-
-static void php_ssh2_session_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
-{
- LIBSSH2_SESSION *session = (LIBSSH2_SESSION*)rsrc->ptr;
- php_ssh2_session_data **data = (php_ssh2_session_data**)libssh2_session_abstract(session);
-
- libssh2_session_disconnect(session, "PECL/ssh2 (http://pecl.php.net/packages/ssh2)");
-
- if (*data) {
- if ((*data)->ignore_cb) {
- zval_ptr_dtor(&(*data)->ignore_cb);
- }
- if ((*data)->debug_cb) {
- zval_ptr_dtor(&(*data)->debug_cb);
- }
- if ((*data)->macerror_cb) {
- zval_ptr_dtor(&(*data)->macerror_cb);
- }
- if ((*data)->disconnect_cb) {
- zval_ptr_dtor(&(*data)->disconnect_cb);
- }
-
- closesocket((*data)->socket);
-
- efree(*data);
- *data = NULL;
- }
-
- libssh2_session_free(session);
-}
-
-#ifdef PHP_SSH2_REMOTE_FORWARDING
-static void php_ssh2_listener_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
-{
- php_ssh2_listener_data *data = (php_ssh2_listener_data*)rsrc->ptr;
- LIBSSH2_LISTENER *listener = data->listener;
-
- libssh2_channel_forward_cancel(listener);
- zend_list_delete(data->session_rsrcid);
- efree(data);
-}
-#endif /* PHP_SSH2_REMOTE_FORWARDING */
-
-#ifdef PHP_SSH2_PUBLICKEY_SUBSYSTEM
-static void php_ssh2_pkey_subsys_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
-{
- php_ssh2_pkey_subsys_data *data = (php_ssh2_pkey_subsys_data*)rsrc->ptr;
- LIBSSH2_PUBLICKEY *pkey = data->pkey;
-
- libssh2_publickey_shutdown(pkey);
- zend_list_delete(data->session_rsrcid);
- efree(data);
-}
-#endif /* PHP_SSH2_PUBLICKEY_SUBSYSTEM */
-
-/* {{{ PHP_MINIT_FUNCTION
- */
-PHP_MINIT_FUNCTION(ssh2)
-{
- le_ssh2_session = zend_register_list_destructors_ex(php_ssh2_session_dtor, NULL, PHP_SSH2_SESSION_RES_NAME, module_number);
-#ifdef PHP_SSH2_REMOTE_FORWARDING
- le_ssh2_listener = zend_register_list_destructors_ex(php_ssh2_listener_dtor, NULL, PHP_SSH2_LISTENER_RES_NAME, module_number);
-#endif /* PHP_SSH2_REMOTE_FORWARDING */
- le_ssh2_sftp = zend_register_list_destructors_ex(php_ssh2_sftp_dtor, NULL, PHP_SSH2_SFTP_RES_NAME, module_number);
-#ifdef PHP_SSH2_PUBLICKEY_SUBSYSTEM
- le_ssh2_pkey_subsys = zend_register_list_destructors_ex(php_ssh2_pkey_subsys_dtor, NULL, PHP_SSH2_PKEY_SUBSYS_RES_NAME, module_number);
-#endif /* PHP_SSH2_PUBLICKEY_SUBSYSTEM */
-
- REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_MD5", PHP_SSH2_FINGERPRINT_MD5, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_SHA1", PHP_SSH2_FINGERPRINT_SHA1, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_HEX", PHP_SSH2_FINGERPRINT_HEX, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_RAW", PHP_SSH2_FINGERPRINT_RAW, CONST_CS | CONST_PERSISTENT);
-
- REGISTER_LONG_CONSTANT("SSH2_TERM_UNIT_CHARS", PHP_SSH2_TERM_UNIT_CHARS, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SSH2_TERM_UNIT_PIXELS", PHP_SSH2_TERM_UNIT_PIXELS, CONST_CS | CONST_PERSISTENT);
-
- REGISTER_STRING_CONSTANT("SSH2_DEFAULT_TERMINAL", PHP_SSH2_DEFAULT_TERMINAL, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SSH2_DEFAULT_TERM_WIDTH", PHP_SSH2_DEFAULT_TERM_WIDTH, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SSH2_DEFAULT_TERM_HEIGHT", PHP_SSH2_DEFAULT_TERM_HEIGHT, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SSH2_DEFAULT_TERM_UNIT", PHP_SSH2_DEFAULT_TERM_UNIT, CONST_CS | CONST_PERSISTENT);
-
- REGISTER_LONG_CONSTANT("SSH2_STREAM_STDIO", 0, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SSH2_STREAM_STDERR", SSH_EXTENDED_DATA_STDERR, CONST_CS | CONST_PERSISTENT);
-
-#ifdef PHP_SSH2_POLL
- /* events/revents */
- REGISTER_LONG_CONSTANT("SSH2_POLLIN", LIBSSH2_POLLFD_POLLIN, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SSH2_POLLEXT", LIBSSH2_POLLFD_POLLEXT, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SSH2_POLLOUT", LIBSSH2_POLLFD_POLLOUT, CONST_CS | CONST_PERSISTENT);
-
- /* revents only */
- REGISTER_LONG_CONSTANT("SSH2_POLLERR", LIBSSH2_POLLFD_POLLERR, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SSH2_POLLHUP", LIBSSH2_POLLFD_POLLHUP, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SSH2_POLLNVAL", LIBSSH2_POLLFD_POLLNVAL, CONST_CS | CONST_PERSISTENT);
-#if (defined(LIBSSH2_APINO) && (LIBSSH2_APINO > 200503221619)) || (defined(LIBSSH2_VERSION_NUM) && LIBSSH2_VERSION_NUM >= 0x001000)
- REGISTER_LONG_CONSTANT("SSH2_POLL_SESSION_CLOSED", LIBSSH2_POLLFD_SESSION_CLOSED, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SSH2_POLL_CHANNEL_CLOSED", LIBSSH2_POLLFD_CHANNEL_CLOSED, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SSH2_POLL_LISTENER_CLOSED", LIBSSH2_POLLFD_LISTENER_CLOSED, CONST_CS | CONST_PERSISTENT);
-#endif /* >= LIBSSH2-0.10 */
-#endif /* POLL */
-
- return (php_register_url_stream_wrapper("ssh2.shell", &php_ssh2_stream_wrapper_shell TSRMLS_CC) == SUCCESS &&
- php_register_url_stream_wrapper("ssh2.exec", &php_ssh2_stream_wrapper_exec TSRMLS_CC) == SUCCESS &&
- php_register_url_stream_wrapper("ssh2.tunnel", &php_ssh2_stream_wrapper_tunnel TSRMLS_CC) == SUCCESS &&
- php_register_url_stream_wrapper("ssh2.scp", &php_ssh2_stream_wrapper_scp TSRMLS_CC) == SUCCESS &&
- php_register_url_stream_wrapper("ssh2.sftp", &php_ssh2_sftp_wrapper TSRMLS_CC) == SUCCESS) ? SUCCESS : FAILURE;
-}
-/* }}} */
-
-/* {{{ PHP_MSHUTDOWN_FUNCTION
- */
-PHP_MSHUTDOWN_FUNCTION(ssh2)
-{
- return (php_unregister_url_stream_wrapper("ssh2.shell" TSRMLS_CC) == SUCCESS &&
- php_unregister_url_stream_wrapper("ssh2.exec" TSRMLS_CC) == SUCCESS &&
- php_unregister_url_stream_wrapper("ssh2.tunnel" TSRMLS_CC) == SUCCESS &&
- php_unregister_url_stream_wrapper("ssh2.scp" TSRMLS_CC) == SUCCESS &&
- php_unregister_url_stream_wrapper("ssh2.sftp" TSRMLS_CC) == SUCCESS) ? SUCCESS : FAILURE;
-}
-/* }}} */
-
-/* {{{ PHP_MINFO_FUNCTION
- */
-PHP_MINFO_FUNCTION(ssh2)
-{
- php_info_print_table_start();
- php_info_print_table_header(2, "SSH2 support", "enabled");
- php_info_print_table_row(2, "extension version", PHP_SSH2_VERSION);
- php_info_print_table_row(2, "libssh2 version", LIBSSH2_VERSION);
- php_info_print_table_row(2, "banner", LIBSSH2_SSH_BANNER);
-#ifdef PHP_SSH2_REMOTE_FORWARDING
- php_info_print_table_row(2, "remote forwarding", "enabled");
-#endif
-#ifdef PHP_SSH2_HOSTBASED_AUTH
- php_info_print_table_row(2, "hostbased auth", "enabled");
-#endif
-#ifdef PHP_SSH2_POLL
- php_info_print_table_row(2, "polling support", "enabled");
-#endif
-#ifdef PHP_SSH2_PUBLICKEY_SUBSYSTEM
- php_info_print_table_row(2, "publickey subsystem", "enabled");
-#endif
- php_info_print_table_end();
-}
-/* }}} */
-
-/* {{{ ssh2_functions[]
- */
-zend_function_entry ssh2_functions[] = {
- PHP_FE(ssh2_connect, NULL)
- PHP_FE(ssh2_methods_negotiated, NULL)
- PHP_FE(ssh2_fingerprint, NULL)
-
- PHP_FE(ssh2_auth_none, NULL)
- PHP_FE(ssh2_auth_password, NULL)
- PHP_FE(ssh2_auth_pubkey_file, NULL)
-#ifdef PHP_SSH2_HOSTBASED_AUTH
- PHP_FE(ssh2_auth_hostbased_file, NULL)
-#endif /* PHP_SSH2_HOSTBASED_AUTH */
-
-#ifdef PHP_SSH2_REMOTE_FORWARDING
- PHP_FE(ssh2_forward_listen, NULL)
- PHP_FE(ssh2_forward_accept, NULL)
-#endif /* PHP_SSH2_REMOTE_FORWARDING */
-
- /* Stream Stuff */
- PHP_FE(ssh2_shell, NULL)
- PHP_FE(ssh2_exec, NULL)
- PHP_FE(ssh2_tunnel, NULL)
- PHP_FE(ssh2_scp_recv, NULL)
- PHP_FE(ssh2_scp_send, NULL)
- PHP_FE(ssh2_fetch_stream, NULL)
-#ifdef PHP_SSH2_POLL
- PHP_FE(ssh2_poll, php_ssh2_first_arg_force_ref)
-#endif
-
- /* SFTP Stuff */
- PHP_FE(ssh2_sftp, NULL)
-
- /* SFTP Wrapper Ops */
- PHP_FE(ssh2_sftp_rename, NULL)
- PHP_FE(ssh2_sftp_unlink, NULL)
- PHP_FE(ssh2_sftp_mkdir, NULL)
- PHP_FE(ssh2_sftp_rmdir, NULL)
- PHP_FE(ssh2_sftp_stat, NULL)
- PHP_FE(ssh2_sftp_lstat, NULL)
- PHP_FE(ssh2_sftp_symlink, NULL)
- PHP_FE(ssh2_sftp_readlink, NULL)
- PHP_FE(ssh2_sftp_realpath, NULL)
-
- /* Publickey subsystem */
-#ifdef PHP_SSH2_PUBLICKEY_SUBSYSTEM
- PHP_FE(ssh2_publickey_init, NULL)
- PHP_FE(ssh2_publickey_add, NULL)
- PHP_FE(ssh2_publickey_remove, NULL)
- PHP_FE(ssh2_publickey_list, NULL)
-#endif
-
- {NULL, NULL, NULL}
-};
-/* }}} */
-
-/* {{{ ssh2_module_entry
- */
-zend_module_entry ssh2_module_entry = {
-#if ZEND_MODULE_API_NO >= 20010901
- STANDARD_MODULE_HEADER,
-#endif
- "ssh2",
- ssh2_functions,
- PHP_MINIT(ssh2),
- PHP_MSHUTDOWN(ssh2),
- NULL, /* RINIT */
- NULL, /* RSHUTDOWN */
- PHP_MINFO(ssh2),
-#if ZEND_MODULE_API_NO >= 20010901
- PHP_SSH2_VERSION,
-#endif
- STANDARD_MODULE_PROPERTIES
-};
-/* }}} */
-
-#ifdef COMPILE_DL_SSH2
-ZEND_GET_MODULE(ssh2)
-#endif
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: noet sw=4 ts=4 fdm=marker
- * vim<600: noet sw=4 ts=4
- */
|
[-]
[+]
|
Deleted |
ssh2-0.11.3.tgz/ssh2-0.11.3/ssh2_fopen_wrappers.c
^
|
@@ -1,1273 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | PHP Version 4 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2006 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 2.02 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available at through the world-wide-web at |
- | http://www.php.net/license/2_02.txt. |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: Sara Golemon <pollita@php.net> |
- +----------------------------------------------------------------------+
-
- $Id: ssh2_fopen_wrappers.c 306892 2010-12-30 23:59:55Z pajoye $
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "php.h"
-#include "php_ssh2.h"
-
-/* **********************
- * channel_stream_ops *
- ********************** */
-
-static size_t php_ssh2_channel_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
-{
- php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract;
-
- libssh2_channel_set_blocking(abstract->channel, abstract->is_blocking);
- return libssh2_channel_write_ex(abstract->channel, abstract->streamid, buf, count);
-}
-
-static size_t php_ssh2_channel_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
-{
- php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract;
- ssize_t readstate;
-
- stream->eof = libssh2_channel_eof(abstract->channel);
- libssh2_channel_set_blocking(abstract->channel, abstract->is_blocking);
-
- readstate = libssh2_channel_read_ex(abstract->channel, abstract->streamid, buf, count);
- return (readstate < 0 ? 0 : readstate);
-}
-
-static int php_ssh2_channel_stream_close(php_stream *stream, int close_handle TSRMLS_DC)
-{
- php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract;
-
- if (!abstract->refcount || (--(*(abstract->refcount)) == 0)) {
- /* Last one out, turn off the lights */
- if (abstract->refcount) {
- efree(abstract->refcount);
- }
- libssh2_channel_eof(abstract->channel);
- libssh2_channel_free(abstract->channel);
- zend_list_delete(abstract->session_rsrc);
- }
- efree(abstract);
-
- return 0;
-}
-
-static int php_ssh2_channel_stream_flush(php_stream *stream TSRMLS_DC)
-{
- php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract;
-
- return libssh2_channel_flush_ex(abstract->channel, abstract->streamid);
-}
-
-static int php_ssh2_channel_stream_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
-{
- php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract;
- int ret;
-
- switch (option) {
- case PHP_STREAM_OPTION_BLOCKING:
- ret = abstract->is_blocking;
- abstract->is_blocking = value;
- return ret;
- break;
-#if PHP_MAJOR_VERSION >= 5
- case PHP_STREAM_OPTION_CHECK_LIVENESS:
- return stream->eof = libssh2_channel_eof(abstract->channel);
- break;
-#endif
- }
-
- return -1;
-}
-
-php_stream_ops php_ssh2_channel_stream_ops = {
- php_ssh2_channel_stream_write,
- php_ssh2_channel_stream_read,
- php_ssh2_channel_stream_close,
- php_ssh2_channel_stream_flush,
- PHP_SSH2_CHANNEL_STREAM_NAME,
- NULL, /* seek */
- NULL, /* cast */
- NULL, /* stat */
- php_ssh2_channel_stream_set_option,
-};
-
-/* *********************
- * Magic Path Helper *
- ********************* */
-
-/* {{{ php_ssh2_fopen_wraper_parse_path
- * Parse an ssh2.*:// path
- */
-php_url *php_ssh2_fopen_wraper_parse_path( char *path, char *type, php_stream_context *context,
- LIBSSH2_SESSION **psession, int *presource_id,
- LIBSSH2_SFTP **psftp, int *psftp_rsrcid
- TSRMLS_DC)
-{
- php_ssh2_sftp_data *sftp_data = NULL;
- LIBSSH2_SESSION *session;
- php_url *resource;
- zval *methods = NULL, *callbacks = NULL, zsession, **tmpzval;
- long resource_id;
- char *s, *username = NULL, *password = NULL, *pubkey_file = NULL, *privkey_file = NULL;
- int username_len = 0, password_len = 0;
-
- resource = php_url_parse(path);
- if (!resource) {
- return NULL;
- }
-
- if (strncmp(resource->scheme, "ssh2.", sizeof("ssh2.") - 1)) {
- /* Not an ssh wrapper */
- php_url_free(resource);
- return NULL;
- }
-
- if (strcmp(resource->scheme + sizeof("ssh2.") - 1, type)) {
- /* Wrong ssh2. wrapper type */
- php_url_free(resource);
- return NULL;
- }
-
- if (!resource->host) {
- return NULL;
- }
-
- /* Look for a resource ID to reuse a session */
- s = resource->host;
- if (strncmp(resource->host, "Resource id #", sizeof("Resource id #") - 1) == 0) {
- s = resource->host + sizeof("Resource id #") - 1;
- }
- if (is_numeric_string(s, strlen(s), &resource_id, NULL, 0) == IS_LONG) {
- php_ssh2_sftp_data *sftp_data;
-
- if (psftp) {
- sftp_data = (php_ssh2_sftp_data*)zend_fetch_resource(NULL TSRMLS_CC, resource_id, PHP_SSH2_SFTP_RES_NAME, NULL, 1, le_ssh2_sftp);
- if (sftp_data) {
- /* Want the sftp layer */
- zend_list_addref(resource_id);
- *psftp_rsrcid = resource_id;
- *psftp = sftp_data->sftp;
- *presource_id = sftp_data->session_rsrcid;
- *psession = sftp_data->session;
- return resource;
- }
- }
- session = (LIBSSH2_SESSION *)zend_fetch_resource(NULL TSRMLS_CC, resource_id, PHP_SSH2_SESSION_RES_NAME, NULL, 1, le_ssh2_session);
- if (session) {
- if (psftp) {
- /* We need an sftp layer too */
- LIBSSH2_SFTP *sftp = libssh2_sftp_init(session);
-
- if (!sftp) {
- php_url_free(resource);
- return NULL;
- }
- sftp_data = emalloc(sizeof(php_ssh2_sftp_data));
- sftp_data->sftp = sftp;
- sftp_data->session = session;
- sftp_data->session_rsrcid = resource_id;
- zend_list_addref(resource_id);
- *psftp_rsrcid = ZEND_REGISTER_RESOURCE(NULL, sftp_data, le_ssh2_sftp);
- *psftp = sftp;
- *presource_id = resource_id;
- *psession = session;
- return resource;
- }
- zend_list_addref(resource_id);
- *presource_id = resource_id;
- *psession = session;
- return resource;
- }
- }
-
- /* Fallback on finding it in the context */
- if (resource->host[0] == 0 && context && psftp &&
- php_stream_context_get_option(context, "ssh2", "sftp", &tmpzval) == SUCCESS &&
- Z_TYPE_PP(tmpzval) == IS_RESOURCE) {
- php_ssh2_sftp_data *sftp_data;
- sftp_data = (php_ssh2_sftp_data *)zend_fetch_resource(tmpzval TSRMLS_CC, -1, PHP_SSH2_SFTP_RES_NAME, NULL, 1, le_ssh2_sftp);
- if (sftp_data) {
- zend_list_addref(Z_LVAL_PP(tmpzval));
- *psftp_rsrcid = Z_LVAL_PP(tmpzval);
- *psftp = sftp_data->sftp;
- *presource_id = sftp_data->session_rsrcid;
- *psession = sftp_data->session;
- return resource;
- }
- }
- if (resource->host[0] == 0 && context &&
- php_stream_context_get_option(context, "ssh2", "session", &tmpzval) == SUCCESS &&
- Z_TYPE_PP(tmpzval) == IS_RESOURCE) {
- session = (LIBSSH2_SESSION *)zend_fetch_resource(tmpzval TSRMLS_CC, -1, PHP_SSH2_SESSION_RES_NAME, NULL, 1, le_ssh2_session);
- if (session) {
- if (psftp) {
- /* We need an SFTP layer too! */
- LIBSSH2_SFTP *sftp = libssh2_sftp_init(session);
- php_ssh2_sftp_data *sftp_data;
-
- if (!sftp) {
- php_url_free(resource);
- return NULL;
- }
- sftp_data = emalloc(sizeof(php_ssh2_sftp_data));
- sftp_data->sftp = sftp;
- sftp_data->session = session;
- sftp_data->session_rsrcid = Z_LVAL_PP(tmpzval);
- zend_list_addref(Z_LVAL_PP(tmpzval));
- *psftp_rsrcid = ZEND_REGISTER_RESOURCE(NULL, sftp_data, le_ssh2_sftp);
- *psftp = sftp;
- *presource_id = Z_LVAL_PP(tmpzval);
- *psession = session;
- return resource;
- }
- zend_list_addref(Z_LVAL_PP(tmpzval));
- *psession = session;
- *presource_id = Z_LVAL_PP(tmpzval);
- return resource;
- }
- }
-
- /* Make our own connection then */
- if (!resource->port) {
- resource->port = 22;
- }
-
- if (context &&
- php_stream_context_get_option(context, "ssh2", "methods", &tmpzval) == SUCCESS &&
- Z_TYPE_PP(tmpzval) == IS_ARRAY) {
- methods = *tmpzval;
- }
-
- if (context &&
- php_stream_context_get_option(context, "ssh2", "callbacks", &tmpzval) == SUCCESS &&
- Z_TYPE_PP(tmpzval) == IS_ARRAY) {
- callbacks = *tmpzval;
- }
-
- if (context &&
- php_stream_context_get_option(context, "ssh2", "username", &tmpzval) == SUCCESS &&
- Z_TYPE_PP(tmpzval) == IS_STRING) {
- username = Z_STRVAL_PP(tmpzval);
- username_len = Z_STRLEN_PP(tmpzval);
- }
-
- if (context &&
- php_stream_context_get_option(context, "ssh2", "password", &tmpzval) == SUCCESS &&
- Z_TYPE_PP(tmpzval) == IS_STRING) {
- password = Z_STRVAL_PP(tmpzval);
- password_len = Z_STRLEN_PP(tmpzval);
- }
-
- if (context &&
- php_stream_context_get_option(context, "ssh2", "pubkey_file", &tmpzval) == SUCCESS &&
- Z_TYPE_PP(tmpzval) == IS_STRING) {
- pubkey_file = Z_STRVAL_PP(tmpzval);
- }
-
- if (context &&
- php_stream_context_get_option(context, "ssh2", "privkey_file", &tmpzval) == SUCCESS &&
- Z_TYPE_PP(tmpzval) == IS_STRING) {
- privkey_file = Z_STRVAL_PP(tmpzval);
- }
-
- if (resource->user) {
- int len = strlen(resource->user);
-
- if (len) {
- username = resource->user;
- username_len = len;
- }
- }
-
- if (resource->pass) {
- int len = strlen(resource->pass);
-
- if (len) {
- password = resource->pass;
- password_len = len;
- }
- }
-
- if (!username) {
- /* username is a minimum */
- php_url_free(resource);
- return NULL;
- }
-
- session = php_ssh2_session_connect(resource->host, resource->port, methods, callbacks TSRMLS_CC);
- if (!session) {
- /* Unable to connect! */
- php_url_free(resource);
- return NULL;
- }
-
- /* Authenticate */
- if (pubkey_file && privkey_file) {
- if (SSH2_OPENBASEDIR_CHECKPATH(pubkey_file) || SSH2_OPENBASEDIR_CHECKPATH(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;
- }
- }
-
- if (password) {
- /* Attempt password authentication */
- if (libssh2_userauth_password_ex(session, username, username_len, password, password_len, NULL) == 0) {
- goto session_authed;
- }
- }
-
- /* Auth failure */
- php_url_free(resource);
- zend_list_delete(Z_LVAL(zsession));
- return NULL;
-
-session_authed:
- ZEND_REGISTER_RESOURCE(&zsession, session, le_ssh2_session);
-
- if (psftp) {
- LIBSSH2_SFTP *sftp;
- zval zsftp;
-
- sftp = libssh2_sftp_init(session);
- if (!sftp) {
- php_url_free(resource);
- zend_list_delete(Z_LVAL(zsession));
- return NULL;
- }
-
- sftp_data = emalloc(sizeof(php_ssh2_sftp_data));
- sftp_data->session = session;
- sftp_data->sftp = sftp;
- sftp_data->session_rsrcid = Z_LVAL(zsession);
-
- ZEND_REGISTER_RESOURCE(&zsftp, sftp_data, le_ssh2_sftp);
- *psftp_rsrcid = Z_LVAL(zsftp);
- *psftp = sftp;
- }
-
- *presource_id = Z_LVAL(zsession);
- *psession = session;
-
- return resource;
-}
-/* }}} */
-
-/* *****************
- * Shell Wrapper *
- ***************** */
-
-/* {{{ php_ssh2_shell_open
- * Make a stream from a session
- */
-static php_stream *php_ssh2_shell_open(LIBSSH2_SESSION *session, int resource_id, char *term, int term_len, zval *environment, long width, long height, long type TSRMLS_DC)
-{
- LIBSSH2_CHANNEL *channel;
- php_ssh2_channel_data *channel_data;
- php_stream *stream;
-
- channel = libssh2_channel_open_session(session);
- if (!channel) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to request a channel from remote host");
- return NULL;
- }
-
- if (environment) {
- char *key;
- int key_type, key_len;
- long idx;
-
- for(zend_hash_internal_pointer_reset(HASH_OF(environment));
- (key_type = zend_hash_get_current_key_ex(HASH_OF(environment), &key, &key_len, &idx, 0, NULL)) != HASH_KEY_NON_EXISTANT;
- zend_hash_move_forward(HASH_OF(environment))) {
- if (key_type == HASH_KEY_IS_STRING) {
- zval **value;
-
- if (zend_hash_get_current_data(HASH_OF(environment), (void**)&value) == SUCCESS) {
- zval copyval = **value;
-
- zval_copy_ctor(©val);
- convert_to_string(©val);
- if (libssh2_channel_setenv_ex(channel, key, key_len, Z_STRVAL(copyval), Z_STRLEN(copyval))) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting %s=%s on remote end", key, Z_STRVAL(copyval));
- }
- zval_dtor(©val);
- }
- } else {
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Skipping numeric index in environment array");
- }
- }
- }
-
- if (type == PHP_SSH2_TERM_UNIT_CHARS) {
- if (libssh2_channel_request_pty_ex(channel, term, term_len, NULL, 0, width, height, 0, 0)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %s pty at %ldx%ld characters", term, width, height);
- libssh2_channel_free(channel);
- return NULL;
- }
- } else {
- if (libssh2_channel_request_pty_ex(channel, term, term_len, NULL, 0, 0, 0, width, height)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %s pty at %ldx%ld pixels", term, width, height);
- libssh2_channel_free(channel);
- return NULL;
- }
- }
-
- if (libssh2_channel_shell(channel)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to request shell from remote host");
- libssh2_channel_free(channel);
- return NULL;
- }
-
- /* Turn it into a stream */
- channel_data = emalloc(sizeof(php_ssh2_channel_data));
- channel_data->channel = channel;
- channel_data->streamid = 0;
- channel_data->is_blocking = 0;
- channel_data->session_rsrc = resource_id;
- channel_data->refcount = NULL;
-
- stream = php_stream_alloc(&php_ssh2_channel_stream_ops, channel_data, 0, "r+");
-
- return stream;
-}
-/* }}} */
-
-/* {{{ php_ssh2_fopen_wrapper_shell
- * ssh2.shell:// fopen wrapper
- */
-static php_stream *php_ssh2_fopen_wrapper_shell(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
-{
- LIBSSH2_SESSION *session = NULL;
- php_stream *stream;
- zval **tmpzval, *environment = NULL;
- char *terminal = PHP_SSH2_DEFAULT_TERMINAL;
- long width = PHP_SSH2_DEFAULT_TERM_WIDTH;
- long height = PHP_SSH2_DEFAULT_TERM_HEIGHT;
- long type = PHP_SSH2_DEFAULT_TERM_UNIT;
- int resource_id = 0, terminal_len = sizeof(PHP_SSH2_DEFAULT_TERMINAL) - 1;
- php_url *resource;
- char *s, *e;
-
- resource = php_ssh2_fopen_wraper_parse_path(path, "shell", context, &session, &resource_id, NULL, NULL TSRMLS_CC);
- if (!resource || !session) {
- return NULL;
- }
-
- if (context &&
- php_stream_context_get_option(context, "ssh2", "env", &tmpzval) == SUCCESS &&
- tmpzval && *tmpzval && Z_TYPE_PP(tmpzval) == IS_ARRAY) {
- environment = *tmpzval;
- }
-
- if (context &&
- php_stream_context_get_option(context, "ssh2", "term", &tmpzval) == SUCCESS &&
- tmpzval && *tmpzval && Z_TYPE_PP(tmpzval) == IS_STRING) {
- terminal = Z_STRVAL_PP(tmpzval);
- terminal_len = Z_STRLEN_PP(tmpzval);
- }
-
- if (context &&
- php_stream_context_get_option(context, "ssh2", "term_width", &tmpzval) == SUCCESS &&
- tmpzval && *tmpzval) {
- zval *copyval;
- ALLOC_INIT_ZVAL(copyval);
- *copyval = **tmpzval;
- convert_to_long(copyval);
- width = Z_LVAL_P(copyval);
- zval_ptr_dtor(©val);
- }
-
- if (context &&
- php_stream_context_get_option(context, "ssh2", "term_height", &tmpzval) == SUCCESS &&
- tmpzval && *tmpzval) {
- zval *copyval;
- ALLOC_INIT_ZVAL(copyval);
- *copyval = **tmpzval;
- convert_to_long(copyval);
- height = Z_LVAL_P(copyval);
- zval_ptr_dtor(©val);
- }
-
- if (context &&
- php_stream_context_get_option(context, "ssh2", "term_units", &tmpzval) == SUCCESS &&
- tmpzval && *tmpzval) {
- zval *copyval;
- ALLOC_INIT_ZVAL(copyval);
- *copyval = **tmpzval;
- convert_to_long(copyval);
- type = Z_LVAL_P(copyval);
- zval_ptr_dtor(©val);
- }
-
- s = resource->path ? resource->path : NULL;
- e = s ? s + strlen(s) : NULL;
-
- if (s && s[0] == '/') {
- /* Terminal type encoded into URL overrides context terminal type */
- char *p;
-
- s++;
- p = strchr(s, '/');
- if (p) {
- if (p - s) {
- terminal = s;
- terminal_len = p - terminal;
- s += terminal_len + 1;
- } else {
- /* "null" terminal given, skip it */
- s++;
- }
- } else {
- int len;
-
- if ((len = strlen(path + 1))) {
- terminal = s;
- terminal_len = len;
- s += len;
- }
- }
- }
-
- /* TODO: Accept resolution and environment vars as URL style parameters
- * ssh2.shell://hostorresource/terminal/99x99c?envvar=envval&envvar=envval....
- */
- stream = php_ssh2_shell_open(session, resource_id, terminal, terminal_len, environment, width, height, type TSRMLS_CC);
- if (!stream) {
- zend_list_delete(resource_id);
- }
- php_url_free(resource);
-
- return stream;
-}
-/* }}} */
-
-static php_stream_wrapper_ops php_ssh2_shell_stream_wops = {
- php_ssh2_fopen_wrapper_shell,
- NULL, /* stream_close */
- NULL, /* stat */
- NULL, /* stat_url */
- NULL, /* opendir */
- "ssh2.shell"
-};
-
-php_stream_wrapper php_ssh2_stream_wrapper_shell = {
- &php_ssh2_shell_stream_wops,
- NULL,
- 0
-};
-
-/* {{{ proto stream ssh2_shell(resource session[, string term_type[, array env[, int width, int height[, int width_height_type]]]])
- * Open a shell at the remote end and allocate a channel for it
- */
-PHP_FUNCTION(ssh2_shell)
-{
- LIBSSH2_SESSION *session;
- php_stream *stream;
- zval *zsession;
- zval *environment = NULL;
- char *term = PHP_SSH2_DEFAULT_TERMINAL;
- int term_len = sizeof(PHP_SSH2_DEFAULT_TERMINAL) - 1;
- long width = PHP_SSH2_DEFAULT_TERM_WIDTH;
- long height = PHP_SSH2_DEFAULT_TERM_HEIGHT;
- long type = PHP_SSH2_DEFAULT_TERM_UNIT;
- int argc = ZEND_NUM_ARGS();
-
- if (argc == 5) {
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "width specified without height paramter");
- RETURN_FALSE;
- }
-
- if (zend_parse_parameters(argc TSRMLS_CC, "r|sa!lll", &zsession, &term, &term_len, &environment, &width, &height, &type) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
-
- stream = php_ssh2_shell_open(session, Z_LVAL_P(zsession), term, term_len, environment, width, height, type TSRMLS_CC);
- if (!stream) {
- RETURN_FALSE;
- }
-
- /* Ensure that channels are freed BEFORE the sessions they belong to */
- zend_list_addref(Z_LVAL_P(zsession));
-
- php_stream_to_zval(stream, return_value);
-}
-/* }}} */
-
-/* ****************
- * Exec Wrapper *
- **************** */
-
-/* {{{ php_ssh2_exec_command
- * Make a stream from a session
- */
-static php_stream *php_ssh2_exec_command(LIBSSH2_SESSION *session, int resource_id, char *command, char *term, int term_len, zval *environment, long width, long height, long type TSRMLS_DC)
-{
- LIBSSH2_CHANNEL *channel;
- php_ssh2_channel_data *channel_data;
- php_stream *stream;
-
- channel = libssh2_channel_open_session(session);
- if (!channel) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to request a channel from remote host");
- return NULL;
- }
-
- if (environment) {
- char *key;
- int key_type, key_len;
- long idx;
-
- for(zend_hash_internal_pointer_reset(HASH_OF(environment));
- (key_type = zend_hash_get_current_key_ex(HASH_OF(environment), &key, &key_len, &idx, 0, NULL)) != HASH_KEY_NON_EXISTANT;
- zend_hash_move_forward(HASH_OF(environment))) {
- if (key_type == HASH_KEY_IS_STRING) {
- zval **value;
-
- if (zend_hash_get_current_data(HASH_OF(environment), (void**)&value) == SUCCESS) {
- zval copyval = **value;
-
- zval_copy_ctor(©val);
- convert_to_string(©val);
- if (libssh2_channel_setenv_ex(channel, key, key_len, Z_STRVAL(copyval), Z_STRLEN(copyval))) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting %s=%s on remote end", key, Z_STRVAL(copyval));
- }
- zval_dtor(©val);
- }
- } else {
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Skipping numeric index in environment array");
- }
- }
- }
-
- if (term) {
- if (type == PHP_SSH2_TERM_UNIT_CHARS) {
- if (libssh2_channel_request_pty_ex(channel, term, term_len, NULL, 0, width, height, 0, 0)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %s pty at %ldx%ld characters", term, width, height);
- libssh2_channel_free(channel);
- return NULL;
- }
- } else {
- if (libssh2_channel_request_pty_ex(channel, term, term_len, NULL, 0, 0, 0, width, height)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %s pty at %ldx%ld pixels", term, width, height);
- libssh2_channel_free(channel);
- return NULL;
- }
- }
- }
-
- if (libssh2_channel_exec(channel, command)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to request command execution on remote host");
- libssh2_channel_free(channel);
- return NULL;
- }
-
- /* Turn it into a stream */
- channel_data = emalloc(sizeof(php_ssh2_channel_data));
- channel_data->channel = channel;
- channel_data->streamid = 0;
- channel_data->is_blocking = 0;
- channel_data->session_rsrc = resource_id;
- channel_data->refcount = NULL;
-
- stream = php_stream_alloc(&php_ssh2_channel_stream_ops, channel_data, 0, "r+");
-
- return stream;
-}
-/* }}} */
-
-/* {{{ php_ssh2_fopen_wrapper_exec
- * ssh2.exec:// fopen wrapper
- */
-static php_stream *php_ssh2_fopen_wrapper_exec(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
-{
- LIBSSH2_SESSION *session = NULL;
- php_stream *stream;
- zval **tmpzval, *environment = NULL;
- int resource_id = 0;
- php_url *resource;
- char *terminal = NULL;
- int terminal_len = 0;
- long width = PHP_SSH2_DEFAULT_TERM_WIDTH;
- long height = PHP_SSH2_DEFAULT_TERM_HEIGHT;
- long type = PHP_SSH2_DEFAULT_TERM_UNIT;
-
- resource = php_ssh2_fopen_wraper_parse_path(path, "exec", context, &session, &resource_id, NULL, NULL TSRMLS_CC);
- if (!resource || !session) {
- return NULL;
- }
- if (!resource->path) {
- php_url_free(resource);
- zend_list_delete(resource_id);
- return NULL;
- }
-
- if (context &&
- php_stream_context_get_option(context, "ssh2", "env", &tmpzval) == SUCCESS &&
- tmpzval && *tmpzval && Z_TYPE_PP(tmpzval) == IS_ARRAY) {
- environment = *tmpzval;
- }
-
- if (context &&
- php_stream_context_get_option(context, "ssh2", "term", &tmpzval) == SUCCESS &&
- tmpzval && *tmpzval && Z_TYPE_PP(tmpzval) == IS_STRING) {
- terminal = Z_STRVAL_PP(tmpzval);
- terminal_len = Z_STRLEN_PP(tmpzval);
- }
-
- if (context &&
- php_stream_context_get_option(context, "ssh2", "term_width", &tmpzval) == SUCCESS &&
- tmpzval && *tmpzval) {
- zval *copyval;
- ALLOC_INIT_ZVAL(copyval);
- *copyval = **tmpzval;
- convert_to_long(copyval);
- width = Z_LVAL_P(copyval);
- zval_ptr_dtor(©val);
- }
-
- if (context &&
- php_stream_context_get_option(context, "ssh2", "term_height", &tmpzval) == SUCCESS &&
- tmpzval && *tmpzval) {
- zval *copyval;
- ALLOC_INIT_ZVAL(copyval);
- *copyval = **tmpzval;
- convert_to_long(copyval);
- height = Z_LVAL_P(copyval);
- zval_ptr_dtor(©val);
- }
-
- if (context &&
- php_stream_context_get_option(context, "ssh2", "term_units", &tmpzval) == SUCCESS &&
- tmpzval && *tmpzval) {
- zval *copyval;
- ALLOC_INIT_ZVAL(copyval);
- *copyval = **tmpzval;
- convert_to_long(copyval);
- type = Z_LVAL_P(copyval);
- zval_ptr_dtor(©val);
- }
-
- stream = php_ssh2_exec_command(session, resource_id, resource->path + 1, terminal, terminal_len, environment, width, height, type TSRMLS_CC);
- if (!stream) {
- zend_list_delete(resource_id);
- }
- php_url_free(resource);
-
- return stream;
-}
-/* }}} */
-
-static php_stream_wrapper_ops php_ssh2_exec_stream_wops = {
- php_ssh2_fopen_wrapper_exec,
- NULL, /* stream_close */
- NULL, /* stat */
- NULL, /* stat_url */
- NULL, /* opendir */
- "ssh2.exec"
-};
-
-php_stream_wrapper php_ssh2_stream_wrapper_exec = {
- &php_ssh2_exec_stream_wops,
- NULL,
- 0
-};
-
-/* {{{ proto stream ssh2_exec(resource session, string command[, string pty[, array env[, int width[, int heightp[, int width_height_type]]]]])
- * Execute a command at the remote end and allocate a channel for it
- *
- * This function has a dirty little secret.... pty and env can be in either order.... shhhh... don't tell anyone
- */
-PHP_FUNCTION(ssh2_exec)
-{
- LIBSSH2_SESSION *session;
- php_stream *stream;
- zval *zsession;
- zval *environment = NULL;
- zval *zpty = NULL;
- char *command;
- int command_len;
- long width = PHP_SSH2_DEFAULT_TERM_WIDTH;
- long height = PHP_SSH2_DEFAULT_TERM_HEIGHT;
- long type = PHP_SSH2_DEFAULT_TERM_UNIT;
- char *term = NULL;
- int term_len = 0;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|z!z!lll", &zsession, &command, &command_len, &zpty, &environment, &width, &height, &type) == FAILURE) {
- RETURN_FALSE;
- }
-
- if (zpty && Z_TYPE_P(zpty) == IS_ARRAY) {
- /* Swap pty and environment -- old call style */
- zval *tmp = zpty;
- zpty = environment;
- environment = tmp;
- }
-
- if (environment && Z_TYPE_P(environment) != IS_ARRAY) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "ssh2_exec() expects arg 4 to be of type array");
- RETURN_FALSE;
- }
-
- if (zpty) {
- convert_to_string(zpty);
- term = Z_STRVAL_P(zpty);
- term_len = Z_STRLEN_P(zpty);
- }
-
- ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
-
- stream = php_ssh2_exec_command(session, Z_LVAL_P(zsession), command, term, term_len, environment, width, height, type TSRMLS_CC);
- if (!stream) {
- RETURN_FALSE;
- }
-
- /* Ensure that channels are freed BEFORE the sessions they belong to */
- zend_list_addref(Z_LVAL_P(zsession));
-
- php_stream_to_zval(stream, return_value);
-}
-/* }}} */
-
-/* ***************
- * SCP Wrapper *
- *************** */
-
-/* {{{ php_ssh2_scp_xfer
- * Make a stream from a session
- */
-static php_stream *php_ssh2_scp_xfer(LIBSSH2_SESSION *session, int resource_id, char *filename TSRMLS_DC)
-{
- LIBSSH2_CHANNEL *channel;
- php_ssh2_channel_data *channel_data;
- php_stream *stream;
-
- channel = libssh2_scp_recv(session, filename, NULL);
- if (!channel) {
- char *error = "";
- libssh2_session_last_error(session, &error, NULL, 0);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to request a channel from remote host: %s", error);
- return NULL;
- }
-
- /* Turn it into a stream */
- channel_data = emalloc(sizeof(php_ssh2_channel_data));
- channel_data->channel = channel;
- channel_data->streamid = 0;
- channel_data->is_blocking = 0;
- channel_data->session_rsrc = resource_id;
- channel_data->refcount = NULL;
-
- stream = php_stream_alloc(&php_ssh2_channel_stream_ops, channel_data, 0, "r");
-
- return stream;
-}
-/* }}} */
-
-/* {{{ php_ssh2_fopen_wrapper_scp
- * ssh2.scp:// fopen wrapper (Read mode only, if you want to know why write mode isn't supported as a stream, take a look at the SCP protocol)
- */
-static php_stream *php_ssh2_fopen_wrapper_scp(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
-{
- LIBSSH2_SESSION *session = NULL;
- php_stream *stream;
- int resource_id = 0;
- php_url *resource;
-
- if (strchr(mode, '+') || strchr(mode, 'a') || strchr(mode, 'w')) {
- return NULL;
- }
-
- resource = php_ssh2_fopen_wraper_parse_path(path, "scp", context, &session, &resource_id, NULL, NULL TSRMLS_CC);
- if (!resource || !session) {
- return NULL;
- }
- if (!resource->path) {
- php_url_free(resource);
- zend_list_delete(resource_id);
- return NULL;
- }
-
- stream = php_ssh2_scp_xfer(session, resource_id, resource->path TSRMLS_CC);
- if (!stream) {
- zend_list_delete(resource_id);
- }
- php_url_free(resource);
-
- return stream;
-}
-/* }}} */
-
-static php_stream_wrapper_ops php_ssh2_scp_stream_wops = {
- php_ssh2_fopen_wrapper_scp,
- NULL, /* stream_close */
- NULL, /* stat */
- NULL, /* stat_url */
- NULL, /* opendir */
- "ssh2.scp"
-};
-
-php_stream_wrapper php_ssh2_stream_wrapper_scp = {
- &php_ssh2_scp_stream_wops,
- NULL,
- 0
-};
-
-/* {{{ proto bool ssh2_scp_recv(resource session, string remote_file, string local_file)
- * Request a file via SCP
- */
-PHP_FUNCTION(ssh2_scp_recv)
-{
- LIBSSH2_SESSION *session;
- LIBSSH2_CHANNEL *remote_file;
- struct stat sb;
- php_stream *local_file;
- zval *zsession;
- char *remote_filename, *local_filename;
- int remote_filename_len, local_filename_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &zsession, &remote_filename, &remote_filename_len,
- &local_filename, &local_filename_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
-
- remote_file = libssh2_scp_recv(session, remote_filename, &sb);
- if (!remote_file) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to receive remote file");
- RETURN_FALSE;
- }
- libssh2_channel_set_blocking(remote_file, 1);
-
- local_file = php_stream_open_wrapper(local_filename, "wb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL);
- if (!local_file) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to write to local file");
- libssh2_channel_free(remote_file);
- RETURN_FALSE;
- }
-
- while (sb.st_size) {
- char buffer[8192];
- int bytes_read;
-
- bytes_read = libssh2_channel_read(remote_file, buffer, sb.st_size > 8192 ? 8192 : sb.st_size);
- if (bytes_read < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error reading from remote file");
- libssh2_channel_free(remote_file);
- php_stream_close(local_file);
- RETURN_FALSE;
- }
- php_stream_write(local_file, buffer, bytes_read);
- sb.st_size -= bytes_read;
- }
-
- libssh2_channel_free(remote_file);
- php_stream_close(local_file);
-
- RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto stream ssh2_scp_send(resource session, string local_file, string remote_file[, int create_mode = 0644])
- * Send a file via SCP
- */
-PHP_FUNCTION(ssh2_scp_send)
-{
- LIBSSH2_SESSION *session;
- LIBSSH2_CHANNEL *remote_file;
- php_stream *local_file;
- zval *zsession;
- char *local_filename, *remote_filename;
- int local_filename_len, remote_filename_len;
- long create_mode = 0644;
- php_stream_statbuf ssb;
- int argc = ZEND_NUM_ARGS();
-
- if (zend_parse_parameters(argc TSRMLS_CC, "rss|l", &zsession, &local_filename, &local_filename_len,
- &remote_filename, &remote_filename_len, &create_mode) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
-
- local_file = php_stream_open_wrapper(local_filename, "rb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL);
- if (!local_file) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to read source file");
- RETURN_FALSE;
- }
-
- if (php_stream_stat(local_file, &ssb)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed statting local file");
- php_stream_close(local_file);
- RETURN_FALSE;
- }
-
- if (argc < 4) {
- create_mode = ssb.sb.st_mode & 0777;
- }
-
- remote_file = libssh2_scp_send_ex(session, remote_filename, create_mode, ssb.sb.st_size, ssb.sb.st_atime, ssb.sb.st_mtime);
- if (!remote_file) {
- int last_error = 0;
- char *error_msg = NULL;
-
- last_error = libssh2_session_last_error(session, &error_msg, NULL, 0);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure creating remote file: %s", error_msg);
- php_stream_close(local_file);
- RETURN_FALSE;
- }
- libssh2_channel_set_blocking(remote_file, 1);
-
- while (ssb.sb.st_size) {
- char buffer[8192];
- size_t toread = MIN(8192, ssb.sb.st_size);
- size_t bytesread = php_stream_read(local_file, buffer, toread);
-
- if (bytesread <= 0 || bytesread > toread) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed copying file 2");
- php_stream_close(local_file);
- libssh2_channel_free(remote_file);
- RETURN_FALSE;
- }
-
- if (bytesread != libssh2_channel_write(remote_file, buffer, bytesread)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed copying file");
- php_stream_close(local_file);
- libssh2_channel_free(remote_file);
- RETURN_FALSE;
- }
- ssb.sb.st_size -= bytesread;
- }
-
- php_stream_close(local_file);
- libssh2_channel_free(remote_file);
- RETURN_TRUE;
-}
-/* }}} */
-
-/* ***************************
- * Direct TCP/IP Transport *
- *************************** */
-
-/* {{{ php_ssh2_direct_tcpip
- * Make a stream from a session
- */
-static php_stream *php_ssh2_direct_tcpip(LIBSSH2_SESSION *session, int resource_id, char *host, int port TSRMLS_DC)
-{
- LIBSSH2_CHANNEL *channel;
- php_ssh2_channel_data *channel_data;
- php_stream *stream;
-
- channel = libssh2_channel_direct_tcpip(session, host, port);
- if (!channel) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to request a channel from remote host");
- return NULL;
- }
-
- /* Turn it into a stream */
- channel_data = emalloc(sizeof(php_ssh2_channel_data));
- channel_data->channel = channel;
- channel_data->streamid = 0;
- channel_data->is_blocking = 0;
- channel_data->session_rsrc = resource_id;
- channel_data->refcount = NULL;
-
- stream = php_stream_alloc(&php_ssh2_channel_stream_ops, channel_data, 0, "r+");
-
- return stream;
-}
-/* }}} */
-
-/* {{{ php_ssh2_fopen_wrapper_tunnel
- * ssh2.tunnel:// fopen wrapper
- */
-static php_stream *php_ssh2_fopen_wrapper_tunnel(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
-{
- LIBSSH2_SESSION *session = NULL;
- php_stream *stream = NULL;
- php_url *resource;
- char *host = NULL;
- int port = 0;
- int resource_id = 0;
-
- resource = php_ssh2_fopen_wraper_parse_path(path, "tunnel", context, &session, &resource_id, NULL, NULL TSRMLS_CC);
- if (!resource || !session) {
- return NULL;
- }
-
- if (resource->path && resource->path[0] == '/') {
- char *colon;
-
- host = resource->path + 1;
- if (*host == '[') {
- /* IPv6 Encapsulated Format */
- host++;
- colon = strstr(host, "]:");
- if (colon) {
- *colon = 0;
- colon += 2;
- }
- } else {
- colon = strchr(host, ':');
- if (colon) {
- *(colon++) = 0;
- }
- }
- if (colon) {
- port = atoi(colon);
- }
- }
-
- if ((port <= 0) || (port > 65535) || !host || (strlen(host) == 0)) {
- /* Invalid connection criteria */
- php_url_free(resource);
- zend_list_delete(resource_id);
- return NULL;
- }
-
- stream = php_ssh2_direct_tcpip(session, resource_id, host, port TSRMLS_CC);
- if (!stream) {
- zend_list_delete(resource_id);
- }
- php_url_free(resource);
-
- return stream;
-}
-/* }}} */
-
-static php_stream_wrapper_ops php_ssh2_tunnel_stream_wops = {
- php_ssh2_fopen_wrapper_tunnel,
- NULL, /* stream_close */
- NULL, /* stat */
- NULL, /* stat_url */
- NULL, /* opendir */
- "ssh2.tunnel"
-};
-
-php_stream_wrapper php_ssh2_stream_wrapper_tunnel = {
- &php_ssh2_tunnel_stream_wops,
- NULL,
- 0
-};
-
-/* {{{ proto stream ssh2_tunnel(resource session, string host, int port)
- * Tunnel to remote TCP/IP host/port
- */
-PHP_FUNCTION(ssh2_tunnel)
-{
- LIBSSH2_SESSION *session;
- php_stream *stream;
- zval *zsession;
- char *host;
- int host_len;
- long port;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsl", &zsession, &host, &host_len, &port) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
-
- stream = php_ssh2_direct_tcpip(session, Z_LVAL_P(zsession), host, port TSRMLS_CC);
- if (!stream) {
- RETURN_FALSE;
- }
-
- /* Ensure that channels are freed BEFORE the sessions they belong to */
- zend_list_addref(Z_LVAL_P(zsession));
-
- php_stream_to_zval(stream, return_value);
-}
-/* }}} */
-
-/* ******************
- * Generic Helper *
- ****************** */
-
-/* {{{ proto stream ssh2_fetch_stream(stream channel, int streamid)
- * Fetch an extended data stream
- */
-PHP_FUNCTION(ssh2_fetch_stream)
-{
- php_ssh2_channel_data *data, *stream_data;
- php_stream *parent, *stream;
- zval *zparent;
- long streamid;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zparent, &streamid) == FAILURE) {
- RETURN_FALSE;
- }
-
- if (streamid < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stream ID requested");
- RETURN_FALSE;
- }
-
- php_stream_from_zval(parent, &zparent);
-
- if (parent->ops != &php_ssh2_channel_stream_ops) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Provided stream is not of type " PHP_SSH2_CHANNEL_STREAM_NAME);
- RETURN_FALSE;
- }
-
- data = (php_ssh2_channel_data*)parent->abstract;
-
- if (!data->refcount) {
- data->refcount = emalloc(sizeof(unsigned char));
- *(data->refcount) = 1;
- }
-
- if (*(data->refcount) == 255) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many streams associated to a single channel");
- RETURN_FALSE;
- }
-
- (*(data->refcount))++;
-
- stream_data = emalloc(sizeof(php_ssh2_channel_data));
- memcpy(stream_data, data, sizeof(php_ssh2_channel_data));
- stream_data->streamid = streamid;
-
- stream = php_stream_alloc(&php_ssh2_channel_stream_ops, stream_data, 0, "r+");
- if (!stream) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error opening substream");
- efree(stream_data);
- *(data->refcount)--;
- RETURN_FALSE;
- }
-
- php_stream_to_zval(stream, return_value);
-}
-/* }}} */
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: noet sw=4 ts=4 fdm=marker
- * vim<600: noet sw=4 ts=4
- */
|
[-]
[+]
|
Deleted |
ssh2-0.11.3.tgz/ssh2-0.11.3/ssh2_sftp.c
^
|
@@ -1,856 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | PHP Version 4 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2006 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 2.02 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available at through the world-wide-web at |
- | http://www.php.net/license/2_02.txt. |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: Sara Golemon <pollita@php.net> |
- +----------------------------------------------------------------------+
-
- $Id: ssh2_sftp.c 317118 2011-09-21 19:05:21Z bjori $
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "php.h"
-#include "php_ssh2.h"
-#include "ext/standard/php_string.h"
-
-/* *************************
- * Resource Housekeeping *
- ************************* */
-
-void php_ssh2_sftp_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
-{
- php_ssh2_sftp_data *data = (php_ssh2_sftp_data*)rsrc->ptr;
-
- if (!data) {
- return;
- }
-
- libssh2_sftp_shutdown(data->sftp);
-
- zend_list_delete(data->session_rsrcid);
-
- efree(data);
-}
-
-/* *****************
- * SFTP File Ops *
- ***************** */
-
-inline unsigned long php_ssh2_parse_fopen_modes(char *openmode) {
- unsigned long flags = 0;
-
- if (strchr(openmode, 'a')) {
- flags |= LIBSSH2_FXF_APPEND;
- }
-
- if (strchr(openmode, 'w')) {
- flags |= LIBSSH2_FXF_WRITE | LIBSSH2_FXF_TRUNC | LIBSSH2_FXF_CREAT;
- }
-
- if (strchr(openmode, 'r')) {
- flags |= LIBSSH2_FXF_READ;
- }
-
- if (strchr(openmode, '+')) {
- flags |= LIBSSH2_FXF_READ | LIBSSH2_FXF_WRITE;
- }
-
- if (strchr(openmode, 'x')) {
- flags |= LIBSSH2_FXF_WRITE | LIBSSH2_FXF_TRUNC | LIBSSH2_FXF_EXCL | LIBSSH2_FXF_CREAT;
- }
-
- return flags;
-}
-
-inline int php_ssh2_sftp_attr2ssb(php_stream_statbuf *ssb, LIBSSH2_SFTP_ATTRIBUTES *attrs)
-{
- memset(ssb, 0, sizeof(php_stream_statbuf));
- if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) {
- ssb->sb.st_size = attrs->filesize;
- }
-
- if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) {
- ssb->sb.st_uid = attrs->uid;
- ssb->sb.st_gid = attrs->gid;
- }
- if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
- ssb->sb.st_mode = attrs->permissions;
- }
- if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
- ssb->sb.st_atime = attrs->atime;
- ssb->sb.st_mtime = attrs->mtime;
- }
-
- return 0;
-}
-
-typedef struct _php_ssh2_sftp_handle_data {
- LIBSSH2_SFTP_HANDLE *handle;
-
- long sftp_rsrcid;
-} php_ssh2_sftp_handle_data;
-
-/* {{{ php_ssh2_sftp_stream_write
- */
-static size_t php_ssh2_sftp_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
-{
- php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
- ssize_t bytes_written;
-
- bytes_written = libssh2_sftp_write(data->handle, buf, count);
-
- return (size_t)(bytes_written<0 ? 0 : bytes_written);
-}
-/* }}} */
-
-/* {{{ php_ssh2_sftp_stream_read
- */
-static size_t php_ssh2_sftp_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
-{
- php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
- ssize_t bytes_read;
-
- bytes_read = libssh2_sftp_read(data->handle, buf, count);
-
- stream->eof = (bytes_read <= 0 && bytes_read != LIBSSH2_ERROR_EAGAIN);
-
- return (size_t)(bytes_read<0 ? 0 : bytes_read);
-}
-/* }}} */
-
-/* {{{ php_ssh2_sftp_stream_close
- */
-static int php_ssh2_sftp_stream_close(php_stream *stream, int close_handle TSRMLS_DC)
-{
- php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
-
- libssh2_sftp_close(data->handle);
- zend_list_delete(data->sftp_rsrcid);
- efree(data);
-
- return 0;
-}
-/* }}} */
-
-/* {{{ php_ssh2_sftp_stream_seek
- */
-static int php_ssh2_sftp_stream_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC)
-{
- php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
-
- switch (whence) {
- case SEEK_END:
- {
- LIBSSH2_SFTP_ATTRIBUTES attrs;
-
- if (libssh2_sftp_fstat(data->handle, &attrs)) {
- return -1;
- }
- if ((attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) == 0) {
- return -1;
- }
- offset += attrs.filesize;
- }
- case SEEK_CUR:
- {
- off_t current_offset = libssh2_sftp_tell(data->handle);
-
- if (current_offset < 0) {
- return -1;
- }
-
- offset += current_offset;
- }
- }
-
- libssh2_sftp_seek(data->handle, offset);
-
- if (newoffset) {
- *newoffset = offset;
- }
-
- return 0;
-}
-/* }}} */
-
-/* {{{ php_ssh2_sftp_stream_fstat
- */
-static int php_ssh2_sftp_stream_fstat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
-{
- php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
- LIBSSH2_SFTP_ATTRIBUTES attrs;
-
- if (libssh2_sftp_fstat(data->handle, &attrs)) {
- return -1;
- }
-
- return php_ssh2_sftp_attr2ssb(ssb, &attrs);
-}
-/* }}} */
-
-static php_stream_ops php_ssh2_sftp_stream_ops = {
- php_ssh2_sftp_stream_write,
- php_ssh2_sftp_stream_read,
- php_ssh2_sftp_stream_close,
- NULL, /* flush */
- PHP_SSH2_SFTP_STREAM_NAME,
- php_ssh2_sftp_stream_seek,
- NULL, /* cast */
- php_ssh2_sftp_stream_fstat,
- NULL, /* set_option */
-};
-
-/* {{{ php_ssh2_sftp_stream_opener
- */
-static php_stream *php_ssh2_sftp_stream_opener( php_stream_wrapper *wrapper, char *filename, char *mode,
- int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
-{
- php_ssh2_sftp_handle_data *data;
- LIBSSH2_SESSION *session = NULL;
- LIBSSH2_SFTP *sftp = NULL;
- LIBSSH2_SFTP_HANDLE *handle;
- php_stream *stream;
- int resource_id = 0, sftp_rsrcid = 0;
- php_url *resource;
- unsigned long flags;
- long perms = 0644;
-
- resource = php_ssh2_fopen_wraper_parse_path(filename, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
- if (!resource || !session || !sftp) {
- return NULL;
- }
-
- flags = php_ssh2_parse_fopen_modes(mode);
-
- handle = libssh2_sftp_open(sftp, resource->path, flags, perms);
- if (!handle) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open %s on remote host", filename);
- php_url_free(resource);
- zend_list_delete(sftp_rsrcid);
- return NULL;
- }
-
- data = emalloc(sizeof(php_ssh2_sftp_handle_data));
- data->handle = handle;
- data->sftp_rsrcid = sftp_rsrcid;
-
- stream = php_stream_alloc(&php_ssh2_sftp_stream_ops, data, 0, mode);
- if (!stream) {
- libssh2_sftp_close(handle);
- zend_list_delete(sftp_rsrcid);
- efree(data);
- }
- php_url_free(resource);
-
- return stream;
-}
-/* }}} */
-
-/* **********************
- * SFTP Directory Ops *
- ********************** */
-
-/* {{{ php_ssh2_sftp_dirstream_read
- */
-static size_t php_ssh2_sftp_dirstream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
-{
- php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
- php_stream_dirent *ent = (php_stream_dirent*)buf;
- size_t bytesread = libssh2_sftp_readdir(data->handle, ent->d_name, sizeof(ent->d_name) - 1, NULL);
- char *basename = NULL;
- size_t basename_len = 0;
-
- if (bytesread <= 0) {
- return 0;
- }
- ent->d_name[bytesread] = 0;
-
-#ifdef ZEND_ENGINE_2
- php_basename(ent->d_name, bytesread, NULL, 0, &basename, &basename_len TSRMLS_CC);
-#else
-/* CURSE YOU BC BREAKS! */
- basename = php_basename(ent->d_name, bytesread, NULL, 0);
- if (basename) {
- basename_len = strlen(basename);
- }
-#endif
- if (!basename) {
- return 0;
- }
-
- if (!basename_len) {
- efree(basename);
- return 0;
- }
- bytesread = MIN(sizeof(ent->d_name) - 1, basename_len);
- memcpy(ent->d_name, basename, bytesread);
- ent->d_name[bytesread] = 0;
- efree(basename);
-
- return sizeof(php_stream_dirent);
-}
-/* }}} */
-
-/* {{{ php_ssh2_sftp_dirstream_close
- */
-static int php_ssh2_sftp_dirstream_close(php_stream *stream, int close_handle TSRMLS_DC)
-{
- php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
-
- libssh2_sftp_close(data->handle);
- zend_list_delete(data->sftp_rsrcid);
- efree(data);
-
- return 0;
-}
-/* }}} */
-
-static php_stream_ops php_ssh2_sftp_dirstream_ops = {
- NULL, /* write */
- php_ssh2_sftp_dirstream_read,
- php_ssh2_sftp_dirstream_close,
- NULL, /* flush */
- PHP_SSH2_SFTP_DIRSTREAM_NAME,
- NULL, /* seek */
- NULL, /* cast */
- NULL, /* fstat */
- NULL, /* set_option */
-};
-
-/* {{{ php_ssh2_sftp_dirstream_opener
- */
-static php_stream *php_ssh2_sftp_dirstream_opener( php_stream_wrapper *wrapper, char *filename, char *mode,
- int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
-{
- php_ssh2_sftp_handle_data *data;
- LIBSSH2_SESSION *session = NULL;
- LIBSSH2_SFTP *sftp = NULL;
- LIBSSH2_SFTP_HANDLE *handle;
- php_stream *stream;
- int resource_id = 0, sftp_rsrcid = 0;
- php_url *resource;
-
- resource = php_ssh2_fopen_wraper_parse_path(filename, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
- if (!resource || !session || !sftp) {
- return NULL;
- }
-
- handle = libssh2_sftp_opendir(sftp, resource->path);
- if (!handle) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open %s on remote host", filename);
- php_url_free(resource);
- zend_list_delete(sftp_rsrcid);
- return NULL;
- }
-
- data = emalloc(sizeof(php_ssh2_sftp_handle_data));
- data->handle = handle;
- data->sftp_rsrcid = sftp_rsrcid;
-
- stream = php_stream_alloc(&php_ssh2_sftp_dirstream_ops, data, 0, mode);
- if (!stream) {
- libssh2_sftp_close(handle);
- zend_list_delete(sftp_rsrcid);
- efree(data);
- }
- php_url_free(resource);
-
- return stream;
-}
-/* }}} */
-
-/* ****************
- * SFTP Wrapper *
- **************** */
-
-#ifdef ZEND_ENGINE_2
-/* {{{ php_ssh2_sftp_urlstat
- */
-static int php_ssh2_sftp_urlstat(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC)
-{
- LIBSSH2_SFTP_ATTRIBUTES attrs;
- LIBSSH2_SESSION *session = NULL;
- LIBSSH2_SFTP *sftp = NULL;
- int resource_id = 0, sftp_rsrcid = 0;
- php_url *resource;
-
- resource = php_ssh2_fopen_wraper_parse_path(url, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
- if (!resource || !session || !sftp || !resource->path) {
- return -1;
- }
-
- if (libssh2_sftp_stat_ex(sftp, resource->path, strlen(resource->path),
- (flags & PHP_STREAM_URL_STAT_LINK) ? LIBSSH2_SFTP_LSTAT : LIBSSH2_SFTP_STAT, &attrs)) {
- php_url_free(resource);
- zend_list_delete(sftp_rsrcid);
- return -1;
- }
-
- php_url_free(resource);
-
- /* parse_path addrefs the resource, but we're not holding on to it so we have to delref it before we leave */
- zend_list_delete(sftp_rsrcid);
-
- return php_ssh2_sftp_attr2ssb(ssb, &attrs);
-}
-/* }}} */
-
-/* {{{ php_ssh2_sftp_unlink
- */
-static int php_ssh2_sftp_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC)
-{
- LIBSSH2_SESSION *session = NULL;
- LIBSSH2_SFTP *sftp = NULL;
- int resource_id = 0, sftp_rsrcid = 0;
- php_url *resource;
- int result;
-
- resource = php_ssh2_fopen_wraper_parse_path(url, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
- if (!resource || !session || !sftp || !resource->path) {
- if (resource) {
- php_url_free(resource);
- }
- return 0;
- }
-
- result = libssh2_sftp_unlink(sftp, resource->path);
- php_url_free(resource);
-
- zend_list_delete(sftp_rsrcid);
-
- /* libssh2 uses 0 for success and the streams API uses 0 for failure, so invert */
- return (result == 0) ? -1 : 0;
-}
-/* }}} */
-
-/* {{{ php_ssh2_sftp_rename
- */
-static int php_ssh2_sftp_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC)
-{
- LIBSSH2_SESSION *session = NULL;
- LIBSSH2_SFTP *sftp = NULL;
- int resource_id = 0, sftp_rsrcid = 0;
- php_url *resource, *resource_to;
- int result;
-
- if (strncmp(url_from, "ssh2.sftp://", sizeof("ssh2.sftp://") - 1) ||
- strncmp(url_to, "ssh2.sftp://", sizeof("ssh2.sftp://") - 1)) {
- return 0;
- }
-
- resource_to = php_url_parse(url_to);
- if (!resource_to || !resource_to->path) {
- if (resource_to) {
- php_url_free(resource_to);
- }
- return 0;
- }
-
- resource = php_ssh2_fopen_wraper_parse_path(url_from, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
- if (!resource || !session || !sftp || !resource->path) {
- if (resource) {
- php_url_free(resource);
- }
- php_url_free(resource_to);
- return 0;
- }
-
- result = libssh2_sftp_rename(sftp, resource->path, resource_to->path);
- php_url_free(resource);
- php_url_free(resource_to);
-
- zend_list_delete(sftp_rsrcid);
-
- /* libssh2 uses 0 for success and the streams API uses 0 for failure, so invert */
- return (result == 0) ? -1 : 0;
-}
-/* }}} */
-
-/* {{{ php_ssh2_sftp_mkdir
- */
-static int php_ssh2_sftp_mkdir(php_stream_wrapper *wrapper, char *url, int mode, int options, php_stream_context *context TSRMLS_DC)
-{
- LIBSSH2_SESSION *session = NULL;
- LIBSSH2_SFTP *sftp = NULL;
- int resource_id = 0, sftp_rsrcid = 0;
- php_url *resource;
- int result;
-
- resource = php_ssh2_fopen_wraper_parse_path(url, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
- if (!resource || !session || !sftp || !resource->path) {
- if (resource) {
- php_url_free(resource);
- }
- return 0;
- }
-
- if (options & PHP_STREAM_MKDIR_RECURSIVE) {
- /* Just attempt to make every directory, some will fail, but we only care about the last success/failure */
- char *p = resource->path;
- while ((p = strchr(p + 1, '/'))) {
- libssh2_sftp_mkdir_ex(sftp, resource->path, p - resource->path, mode);
- }
- }
-
- result = libssh2_sftp_mkdir(sftp, resource->path, mode);
- php_url_free(resource);
-
- zend_list_delete(sftp_rsrcid);
-
- /* libssh2 uses 0 for success and the streams API uses 0 for failure, so invert */
- return (result == 0) ? -1 : 0;
-}
-/* }}} */
-
-/* {{{ php_ssh2_sftp_rmdir
- */
-static int php_ssh2_sftp_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC)
-{
- LIBSSH2_SESSION *session = NULL;
- LIBSSH2_SFTP *sftp = NULL;
- int resource_id = 0, sftp_rsrcid = 0;
- php_url *resource;
- int result;
-
- resource = php_ssh2_fopen_wraper_parse_path(url, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
- if (!resource || !session || !sftp || !resource->path) {
- if (resource) {
- php_url_free(resource);
- }
- return 0;
- }
-
- result = libssh2_sftp_rmdir(sftp, resource->path);
- php_url_free(resource);
-
- zend_list_delete(sftp_rsrcid);
-
- /* libssh2 uses 0 for success and the streams API uses 0 for failure, so invert */
- return (result == 0) ? -1 : 0;
-}
-/* }}} */
-#endif
-
-static php_stream_wrapper_ops php_ssh2_sftp_wrapper_ops = {
- php_ssh2_sftp_stream_opener,
- NULL, /* close */
- NULL, /* stat */
-#ifdef ZEND_ENGINE_2
- php_ssh2_sftp_urlstat,
-#else
- NULL, /* url_stat isn't actually functional prior to PHP5 */
-#endif
- php_ssh2_sftp_dirstream_opener,
- PHP_SSH2_SFTP_WRAPPER_NAME,
-#ifdef ZEND_ENGINE_2
- php_ssh2_sftp_unlink,
- php_ssh2_sftp_rename,
- php_ssh2_sftp_mkdir,
- php_ssh2_sftp_rmdir,
-#endif
-};
-
-php_stream_wrapper php_ssh2_sftp_wrapper = {
- &php_ssh2_sftp_wrapper_ops,
- NULL,
- 1,
- 0,
- NULL,
-};
-
-/* *****************
- * Userspace API *
- ***************** */
-
-
-/* {{{ proto resource ssh2_sftp(resource session)
- * Request the SFTP subsystem from an already connected SSH2 server
- */
-PHP_FUNCTION(ssh2_sftp)
-{
- LIBSSH2_SESSION *session;
- LIBSSH2_SFTP *sftp;
- php_ssh2_sftp_data *data;
- zval *zsession;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zsession) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
-
- sftp = libssh2_sftp_init(session);
- if (!sftp) {
- char *sess_err = "Unknown";
-
- libssh2_session_last_error(session, &sess_err, NULL, 0);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to startup SFTP subsystem: %s", sess_err);
- RETURN_FALSE;
- }
-
- data = emalloc(sizeof(php_ssh2_sftp_data));
- data->session = session;
- data->sftp = sftp;
- data->session_rsrcid = Z_LVAL_P(zsession);
- zend_list_addref(Z_LVAL_P(zsession));
-
- ZEND_REGISTER_RESOURCE(return_value, data, le_ssh2_sftp);
-}
-/* }}} */
-
-/* Much of the stuff below can be done via wrapper ops as of PHP5, but is included here for PHP 4.3 users */
-
-/* {{{ proto bool ssh2_sftp_rename(resource sftp, string from, string to)
- */
-PHP_FUNCTION(ssh2_sftp_rename)
-{
- php_ssh2_sftp_data *data;
- zval *zsftp;
- char *src, *dst;
- int src_len, dst_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &zsftp, &src, &src_len, &dst, &dst_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
-
- RETURN_BOOL(!libssh2_sftp_rename_ex(data->sftp, src, src_len, dst, dst_len,
- LIBSSH2_SFTP_RENAME_OVERWRITE | LIBSSH2_SFTP_RENAME_ATOMIC | LIBSSH2_SFTP_RENAME_NATIVE));
-}
-/* }}} */
-
-/* {{{ proto bool ssh2_sftp_unlink(resource sftp, string filename)
- */
-PHP_FUNCTION(ssh2_sftp_unlink)
-{
- php_ssh2_sftp_data *data;
- zval *zsftp;
- char *filename;
- int filename_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsftp, &filename, &filename_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
-
- RETURN_BOOL(!libssh2_sftp_unlink_ex(data->sftp, filename, filename_len));
-}
-/* }}} */
-
-/* {{{ proto bool ssh2_sftp_mkdir(resource sftp, string filename[, int mode[, int recursive]])
- */
-PHP_FUNCTION(ssh2_sftp_mkdir)
-{
- php_ssh2_sftp_data *data;
- zval *zsftp;
- char *filename;
- int filename_len;
- long mode = 0777;
- zend_bool recursive = 0;
- char *p;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|lb", &zsftp, &filename, &filename_len, &mode, &recursive) == FAILURE) {
- RETURN_FALSE;
- }
-
- if (filename_len < 1) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
-
- if (recursive) {
- /* Just attempt to make every directory, some will fail, but we only care about the last success/failure */
- p = filename;
- while ((p = strchr(p + 1, '/'))) {
- if ((p - filename) + 1 == filename_len) {
- break;
- }
- libssh2_sftp_mkdir_ex(data->sftp, filename, p - filename, mode);
- }
- }
-
-
- RETURN_BOOL(!libssh2_sftp_mkdir_ex(data->sftp, filename, filename_len, mode));
-}
-/* }}} */
-
-/* {{{ proto bool ssh2_sftp_rmdir(resource sftp, string filename)
- */
-PHP_FUNCTION(ssh2_sftp_rmdir)
-{
- php_ssh2_sftp_data *data;
- zval *zsftp;
- char *filename;
- int filename_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsftp, &filename, &filename_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
-
- RETURN_BOOL(!libssh2_sftp_rmdir_ex(data->sftp, filename, filename_len));
-}
-/* }}} */
-
-/* {{{ php_ssh2_sftp_stat_func
- * In PHP4.3 this is the only way to request stat into, in PHP >= 5 you can use the fopen wrapper approach
- * Both methods will return identical structures
- * (well, the other one will include other values set to 0 but they don't count)
- */
-static void php_ssh2_sftp_stat_func(INTERNAL_FUNCTION_PARAMETERS, int stat_type)
-{
- php_ssh2_sftp_data *data;
- LIBSSH2_SFTP_ATTRIBUTES attrs;
- zval *zsftp;
- char *path;
- int path_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsftp, &path, &path_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
-
- if (libssh2_sftp_stat_ex(data->sftp, path, path_len, stat_type, &attrs)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to stat remote file");
- RETURN_FALSE;
- }
-
- array_init(return_value);
-
- if (attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) {
- add_index_long(return_value, 7, attrs.filesize);
- add_assoc_long(return_value, "size", attrs.filesize);
- }
- if (attrs.flags & LIBSSH2_SFTP_ATTR_UIDGID) {
- add_index_long(return_value, 4, attrs.uid);
- add_assoc_long(return_value, "uid", attrs.uid);
-
- add_index_long(return_value, 5, attrs.gid);
- add_assoc_long(return_value, "gid", attrs.gid);
- }
- if (attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
- add_index_long(return_value, 2, attrs.permissions);
- add_assoc_long(return_value, "mode", attrs.permissions);
- }
- if (attrs.flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
- add_index_long(return_value, 8, attrs.atime);
- add_assoc_long(return_value, "atime", attrs.atime);
-
- add_index_long(return_value, 9, attrs.mtime);
- add_assoc_long(return_value, "mtime", attrs.mtime);
- }
-}
-/* }}} */
-
-/* {{{ proto array ssh2_sftp_stat(resource sftp, string path)
- */
-PHP_FUNCTION(ssh2_sftp_stat)
-{
- php_ssh2_sftp_stat_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, LIBSSH2_SFTP_STAT);
-}
-/* }}} */
-
-/* {{{ proto array ssh2_sftp_lstat(resource sftp, string path)
- */
-PHP_FUNCTION(ssh2_sftp_lstat)
-{
- php_ssh2_sftp_stat_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, LIBSSH2_SFTP_LSTAT);
-}
-/* }}} */
-
-/* {{{ proto bool ssh2_sftp_symlink(resource sftp, string target, string link)
- */
-PHP_FUNCTION(ssh2_sftp_symlink)
-{
- php_ssh2_sftp_data *data;
- zval *zsftp;
- char *targ, *link;
- int targ_len, link_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &zsftp, &targ, &targ_len, &link, &link_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
-
- RETURN_BOOL(!libssh2_sftp_symlink_ex(data->sftp, targ, targ_len, link, link_len, LIBSSH2_SFTP_SYMLINK));
-}
-/* }}} */
-
-/* {{{ proto string ssh2_sftp_readlink(resource sftp, string link)
- */
-PHP_FUNCTION(ssh2_sftp_readlink)
-{
- php_ssh2_sftp_data *data;
- zval *zsftp;
- char *link;
- int targ_len = 0, link_len;
- char targ[8192];
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsftp, &link, &link_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
-
- if ((targ_len = libssh2_sftp_symlink_ex(data->sftp, link, link_len, targ, 8192, LIBSSH2_SFTP_READLINK)) < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to read link '%s'", link);
- RETURN_FALSE;
- }
-
- RETURN_STRINGL(targ, targ_len, 1);
-}
-/* }}} */
-
-/* {{{ proto string ssh2_sftp_realpath(resource sftp, string filename)
- */
-PHP_FUNCTION(ssh2_sftp_realpath)
-{
- php_ssh2_sftp_data *data;
- zval *zsftp;
- char *link;
- int targ_len = 0, link_len;
- char targ[8192];
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsftp, &link, &link_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
-
- if ((targ_len = libssh2_sftp_symlink_ex(data->sftp, link, link_len, targ, 8192, LIBSSH2_SFTP_REALPATH)) < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to resolve realpath for '%s'", link);
- RETURN_FALSE;
- }
-
- RETURN_STRINGL(targ, targ_len, 1);
-}
-/* }}} */
-
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * indent-tabs-mode: t
- * End:
- */
-
|
[-]
[+]
|
Changed |
ssh2-0.12.tgz/package.xml
^
|
@@ -1,142 +1,171 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<package packagerversion="1.9.4" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
- <name>ssh2</name>
- <channel>pecl.php.net</channel>
- <summary>Bindings for the libssh2 library</summary>
- <description>Provides bindings to the functions of libssh2 which implements the SSH2 protocol.
- libssh2 is available from http:/libssh2.org/</description>
- <lead>
- <name>Pierre Joye</name>
- <user>pajoye</user>
- <email>pierre@php.net</email>
- <active>yes</active>
- </lead>
- <lead>
- <name>Mike Sullivan</name>
- <user>mikesul</user>
- <email>mikesul@php.net</email>
- <active>yes</active>
- </lead>
- <lead>
- <name>Sara Golemon</name>
- <user>pollita</user>
- <email>pollita@php.net</email>
- <active>no</active>
- </lead>
- <date>2011-09-27</date>
- <time>20:05:05</time>
- <version>
- <release>0.11.3</release>
- <api>0.11.0</api>
- </version>
- <stability>
- <release>beta</release>
- <api>beta</api>
- </stability>
- <license uri="http://www.php.net/license">PHP License</license>
- <notes>
-- Fixed bug#24349 (ssh2_sftp_mkdir fails with trailing slash)
-- Fixed bug#22729 (using ssh2.sftp stream on 64bit vs. 32bit)
-- Fixed bug#22671 (trailing spaces trimmed from filenames)
-- Fixed bug#17142 (Missing EOF detection in ssh2.sftp:// streams)
-- Fixed bug#16944 (Segmentation fault SIGSEGV with protected variable with ssh2)
- </notes>
- <contents>
- <dir name="/">
- <file md5sum="caca90a751e033c1d8225a6497507b64" name="config.m4" role="src" />
- <file md5sum="d9800f20e0598cbd97f736df5ed4e2ba" name="ssh2.c" role="src" />
- <file md5sum="723e46cb3e17c21ac39f6fdf6b9ae241" name="php_ssh2.h" role="src" />
- <file md5sum="44849685a0c28737e5162010e47149f4" name="ssh2_fopen_wrappers.c" role="src" />
- <file md5sum="18f51ab86b10a5761da04ec3711bbef6" name="ssh2_sftp.c" role="src" />
- </dir>
- </contents>
- <dependencies>
- <required>
- <php>
- <min>4.0.0</min>
- <max>6.0.0</max>
- </php>
- <pearinstaller>
- <min>1.4.0</min>
- </pearinstaller>
- </required>
- </dependencies>
- <providesextension>ssh2</providesextension>
- <extsrcrelease>
- <configureoption default="autodetect" name="with-ssh2" prompt="libssh2 prefix?" />
- </extsrcrelease>
- <changelog>
- <release>
- <date>2009-11-28</date>
- <version>
- <release>0.11.1</release>
- <api>0.11.0</api>
- </version>
- <stability>
+<?xml version="1.0"?>
+<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.4.7" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
+ <name>ssh2</name>
+ <channel>pecl.php.net</channel>
+ <summary>Bindings for the libssh2 library</summary>
+ <description>
+ Provides bindings to the functions of libssh2 which implements the SSH2 protocol.
+ libssh2 is available from http:/libssh2.org/
+ </description>
+ <lead>
+ <name>Casper Langemeijer</name>
+ <user>langemeijer</user>
+ <email>langemeijer@php.net</email>
+ <active>yes</active>
+ </lead>
+ <lead>
+ <name>Pierre Joye</name>
+ <user>pajoye</user>
+ <email>pierre@php.net</email>
+ <active>yes</active>
+ </lead>
+ <lead>
+ <name>Mike Sullivan</name>
+ <user>mikesul</user>
+ <email>mikesul@php.net</email>
+ <active>no</active>
+ </lead>
+ <lead>
+ <name>Sara Golemon</name>
+ <user>pollita</user>
+ <email>pollita@php.net</email>
+ <active>no</active>
+ </lead>
+ <date>2012-10-15</date>
+ <version>
+ <release>0.12</release>
+ <api>0.12</api>
+ </version>
+ <stability>
<release>beta</release>
<api>beta</api>
- </stability>
- <license uri="http://www.php.net/license">PHP License</license>
- <notes>
-- Fixed the extension version info
-. no other changes since 0.11.1
- </notes>
- </release>
- <release>
- <date>2009-11-28</date>
- <version>
- <release>0.11.1</release>
- <api>0.11.0</api>
- </version>
- <stability>
- <release>beta</release>
- <api>beta</api>
- </stability>
- <license uri="http://www.php.net/license">PHP License</license>
- <notes>
-- Fixed bug #9500, SSH2 sockets not being closed properly because of close vs closesocket difference
-- Fixed Windows support
-- Support for latest libssh2 release
-- Fix build with PHP 5.3
-- Fixed incorrect return values for rename/unlink/mkdir/rmdir with sftp functions/streams
-- Fixed various memory leaks and segfaults
- </notes>
- </release>
- <release>
- <date>2009-11-28</date>
- <version>
- <release>0.11.1-dev</release>
- <api>0.11.0</api>
- </version>
- <stability>
- <release>beta</release>
- <api>beta</api>
- </stability>
- <license uri="http://www.php.net/license">PHP License</license>
- <notes>
-- Support for latest libssh2 release
-- Fix build with PHP 5.3
-- Fixed incorrect return values for rename/unlink/mkdir/rmdir with sftp functions/streams
-- Fixed various memory leaks and segfaults
- </notes>
- </release>
- <release>
- <date>2008-12-08</date>
- <version>
- <release>0.11.0</release>
- <api>0.11.0</api>
- </version>
- <stability>
- <release>beta</release>
- <api>beta</api>
- </stability>
- <license uri="http://www.php.net/license">PHP License</license>
- <notes>
-- Support for latest libssh2 release
-- Fix build with PHP 5.3
-- Fixed incorrect return values for rename/unlink/mkdir/rmdir with sftp functions/streams
-- Fixed various memory leaks and segfaults
- </notes>
- </release>
- </changelog>
+ </stability>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>
+ - Bumped libssh2 version requirement to 1.2 (aug 2009)
+ - Added ssh2_auth_agent() - SSH agent authentication support (with libssh >= 1.2.3)
+ - Added ssh2_sftp_chmod() (fixed bug #59880)
+ - Added support for stream_set_timeout() to channel streams (fixed bug #56377) (with libssh >= 1.2.9)
+ - Added keyboard-interactive to ssh2_auth_password() (fixed bugs #61760 and #54916)
+ - Add license file as requested in bug #59980
+ - Allow for tilde (~) in public and private keyfile paths
+ - Be more verbose about any errors within ssh2_scp_send
+ - Fixed bug #56425 - Problem with ssh2_scp_send
+ - Fixed bug #59794 - ssh2.sftp protocol wrapper works incorrectly for paths which contain a '#'
+ - Fixed bug #63192 - Check if connection is authenticated.
+ - Fixed bug #58576 - Handle error values from reads and writes to a channel.
+ </notes>
+ <contents>
+ <dir name="/">
+ <file role="src" name="config.m4"/>
+ <file role="src" name="ssh2.c"/>
+ <file role="src" name="php_ssh2.h"/>
+ <file role="src" name="ssh2_fopen_wrappers.c"/>
+ <file role="src" name="ssh2_sftp.c"/>
+ <file role="src" name="LICENSE"/>
+ </dir>
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>4.0.0</min>
+ <max>6.0.0</max>
+ </php>
+ <pearinstaller>
+ <min>1.4.0</min>
+ </pearinstaller>
+ </required>
+ </dependencies>
+ <providesextension>ssh2</providesextension>
+ <extsrcrelease>
+ <configureoption name="with-ssh2" default="autodetect" prompt="libssh2 prefix?"/>
+ </extsrcrelease>
+ <changelog>
+ <release>
+ <date>2011-09-22</date>
+ <version>
+ <release>0.11.3</release>
+ <api>0.11.0</api>
+ </version>
+ <notes>
+ - Fixed bug#24349 (ssh2_sftp_mkdir fails with trailing slash)
+ - Fixed bug#22729 (using ssh2.sftp stream on 64bit vs. 32bit)
+ - Fixed bug#22671 (trailing spaces trimmed from filenames)
+ - Fixed bug#17142 (Missing EOF detection in ssh2.sftp:// streams)
+ - Fixed bug#16944 (Segmentation fault SIGSEGV with protected variable with ssh2)
+ </notes>
+ </release>
+ <release>
+ <date>2009-11-28</date>
+ <version>
+ <release>0.11.1</release>
+ <api>0.11.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>
+ - Fixed the extension version info
+ . no other changes since 0.11.1
+ </notes>
+ </release>
+ <release>
+ <date>2009-11-28</date>
+ <version>
+ <release>0.11.1</release>
+ <api>0.11.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>
+ - Fixed bug #9500, SSH2 sockets not being closed properly because of close vs closesocket difference
+ - Fixed Windows support
+ - Support for latest libssh2 release
+ - Fix build with PHP 5.3
+ - Fixed incorrect return values for rename/unlink/mkdir/rmdir with sftp functions/streams
+ - Fixed various memory leaks and segfaults
+ </notes>
+ </release>
+ <release>
+ <date>2009-11-28</date>
+ <version>
+ <release>0.11.1-dev</release>
+ <api>0.11.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>
+ - Support for latest libssh2 release
+ - Fix build with PHP 5.3
+ - Fixed incorrect return values for rename/unlink/mkdir/rmdir with sftp functions/streams
+ - Fixed various memory leaks and segfaults
+ </notes>
+ </release>
+ <release>
+ <date>2008-12-08</date>
+ <version>
+ <release>0.11.0</release>
+ <api>0.11.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>
+ - Support for latest libssh2 release
+ - Fix build with PHP 5.3
+ - Fixed incorrect return values for rename/unlink/mkdir/rmdir with sftp functions/streams
+ - Fixed various memory leaks and segfaults
+ </notes>
+ </release>
+ </changelog>
</package>
|
[-]
[+]
|
Added |
ssh2-0.12.tgz/ssh2-0.12/LICENSE
^
|
@@ -0,0 +1,68 @@
+--------------------------------------------------------------------
+ The PHP License, version 3.01
+Copyright (c) 1999 - 2012 The PHP Group. All rights reserved.
+--------------------------------------------------------------------
+
+Redistribution and use in source and binary forms, with or without
+modification, is permitted provided that the following conditions
+are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ 3. The name "PHP" must not be used to endorse or promote products
+ derived from this software without prior written permission. For
+ written permission, please contact group@php.net.
+
+ 4. Products derived from this software may not be called "PHP", nor
+ may "PHP" appear in their name, without prior written permission
+ from group@php.net. You may indicate that your software works in
+ conjunction with PHP by saying "Foo for PHP" instead of calling
+ it "PHP Foo" or "phpfoo"
+
+ 5. The PHP Group may publish revised and/or new versions of the
+ license from time to time. Each version will be given a
+ distinguishing version number.
+ Once covered code has been published under a particular version
+ of the license, you may always continue to use it under the terms
+ of that version. You may also choose to use such covered code
+ under the terms of any subsequent version of the license
+ published by the PHP Group. No one other than the PHP Group has
+ the right to modify the terms applicable to covered code created
+ under this License.
+
+ 6. Redistributions of any form whatsoever must retain the following
+ acknowledgment:
+ "This product includes PHP software, freely available from
+ <http://www.php.net/software/>".
+
+THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
+ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
+DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------
+
+This software consists of voluntary contributions made by many
+individuals on behalf of the PHP Group.
+
+The PHP Group can be contacted via Email at group@php.net.
+
+For more information on the PHP Group and the PHP project,
+please see <http://www.php.net>.
+
+PHP includes the Zend Engine, freely available at
+<http://www.zend.com>.
\ No newline at end of file
|
[-]
[+]
|
Added |
ssh2-0.12.tgz/ssh2-0.12/config.m4
^
|
@@ -0,0 +1,60 @@
+dnl $Id: config.m4 327906 2012-10-06 13:52:51Z langemeijer $
+dnl config.m4 for extension ssh2
+
+PHP_ARG_WITH(ssh2, for ssh2 support,
+[ --with-ssh2=[DIR] Include ssh2 support])
+
+if test "$PHP_SSH2" != "no"; then
+ SEARCH_PATH="/usr/local /usr"
+ SEARCH_FOR="/include/libssh2.h"
+ if test -r $PHP_SSH2/$SEARCH_FOR; then # path given as parameter
+ SSH2_DIR=$PHP_SSH2
+ else
+ AC_MSG_CHECKING([for ssh2 files in default path])
+ for i in $SEARCH_PATH ; do
+ if test -r $i/$SEARCH_FOR; then
+ SSH2_DIR=$i
+ AC_MSG_RESULT(found in $i)
+ fi
+ done
+ fi
+
+ if test -z "$SSH2_DIR"; then
+ AC_MSG_RESULT([not found])
+ AC_MSG_ERROR([The required libssh2 library was not found. You can obtain that package from http://sourceforge.net/projects/libssh2/])
+ fi
+
+ PHP_ADD_INCLUDE($SSH2_DIR/include)
+
+ PHP_CHECK_LIBRARY(ssh2,libssh2_session_hostkey,
+ [
+ PHP_ADD_LIBRARY_WITH_PATH(ssh2, $SSH2_DIR/lib, SSH2_SHARED_LIBADD)
+ AC_DEFINE(HAVE_SSH2LIB,1,[Have libssh2])
+ ],[
+ AC_MSG_ERROR([libssh2 version >= 1.2 not found])
+ ],[
+ -L$SSH2_DIR/lib -lm
+ ])
+
+ PHP_CHECK_LIBRARY(ssh2,libssh2_agent_init,
+ [
+ AC_DEFINE(PHP_SSH2_AGENT_AUTH, 1, [Have libssh2 with ssh-agent support])
+ ],[
+ AC_MSG_WARN([libssh2 <= 1.2.3, ssh-agent subsystem support not enabled])
+ ],[ ],[
+ -L$SSH2_DIR/lib -lm -L$SSH2_DIR/lib -lm
+ ])
+
+ PHP_CHECK_LIBRARY(ssh2,libssh2_session_set_timeout,
+ [
+ AC_DEFINE(PHP_SSH2_SESSION_TIMEOUT, 1, [Have libssh2 with session timeout support])
+ ],[
+ AC_MSG_WARN([libssh2 < 1.2.9, session timeout support not enabled])
+ ],[
+ -L$SSH2_DIR/lib -lm
+ ])
+
+ PHP_SUBST(SSH2_SHARED_LIBADD)
+
+ PHP_NEW_EXTENSION(ssh2, ssh2.c ssh2_fopen_wrappers.c ssh2_sftp.c, $ext_shared)
+fi
|
[-]
[+]
|
Added |
ssh2-0.12.tgz/ssh2-0.12/php_ssh2.h
^
|
@@ -0,0 +1,233 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 4 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Sara Golemon <pollita@php.net> |
+ +----------------------------------------------------------------------+
+
+ $Id: php_ssh2.h 328041 2012-10-15 18:04:32Z langemeijer $
+*/
+
+#ifndef PHP_SSH2_H
+#define PHP_SSH2_H
+
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+#include "ext/standard/url.h"
+
+#define PHP_SSH2_VERSION "0.12"
+#define PHP_SSH2_DEFAULT_PORT 22
+
+/* Exported Constants */
+#define PHP_SSH2_FINGERPRINT_MD5 0x0000
+#define PHP_SSH2_FINGERPRINT_SHA1 0x0001
+#define PHP_SSH2_FINGERPRINT_HEX 0x0000
+#define PHP_SSH2_FINGERPRINT_RAW 0x0002
+
+#define PHP_SSH2_TERM_UNIT_CHARS 0x0000
+#define PHP_SSH2_TERM_UNIT_PIXELS 0x0001
+
+#define PHP_SSH2_DEFAULT_TERMINAL "vanilla"
+#define PHP_SSH2_DEFAULT_TERM_WIDTH 80
+#define PHP_SSH2_DEFAULT_TERM_HEIGHT 25
+#define PHP_SSH2_DEFAULT_TERM_UNIT PHP_SSH2_TERM_UNIT_CHARS
+
+#define PHP_SSH2_SESSION_RES_NAME "SSH2 Session"
+#define PHP_SSH2_CHANNEL_STREAM_NAME "SSH2 Channel"
+#define PHP_SSH2_LISTENER_RES_NAME "SSH2 Listener"
+#define PHP_SSH2_SFTP_RES_NAME "SSH2 SFTP"
+#define PHP_SSH2_PKEY_SUBSYS_RES_NAME "SSH2 Publickey Subsystem"
+
+#define PHP_SSH2_SFTP_STREAM_NAME "SSH2 SFTP File"
+#define PHP_SSH2_SFTP_DIRSTREAM_NAME "SSH2 SFTP Directory"
+#define PHP_SSH2_SFTP_WRAPPER_NAME "SSH2 SFTP"
+
+#define PHP_SSH2_LISTEN_MAX_QUEUED 16
+
+#define PHP_SSH2_DEFAULT_POLL_TIMEOUT 30
+
+extern zend_module_entry ssh2_module_entry;
+#define phpext_ssh2_ptr &ssh2_module_entry
+
+typedef struct _php_ssh2_session_data {
+ /* Userspace callback functions */
+ zval *ignore_cb;
+ zval *debug_cb;
+ zval *macerror_cb;
+ zval *disconnect_cb;
+
+ int socket;
+
+#ifdef ZTS
+ /* Avoid unnecessary TSRMLS_FETCH() calls */
+ TSRMLS_D;
+#endif
+} php_ssh2_session_data;
+
+typedef struct _php_ssh2_sftp_data {
+ LIBSSH2_SESSION *session;
+ LIBSSH2_SFTP *sftp;
+
+ int session_rsrcid;
+} php_ssh2_sftp_data;
+
+typedef struct _php_ssh2_listener_data {
+ LIBSSH2_SESSION *session;
+ LIBSSH2_LISTENER *listener;
+
+ int session_rsrcid;
+} php_ssh2_listener_data;
+
+#include "libssh2_publickey.h"
+
+typedef struct _php_ssh2_pkey_subsys_data {
+ LIBSSH2_SESSION *session;
+ LIBSSH2_PUBLICKEY *pkey;
+
+ int session_rsrcid;
+} php_ssh2_pkey_subsys_data;
+
+#ifndef PHP_WIN32
+#define closesocket(s) close(s)
+#endif
+
+#ifdef ZTS
+#define SSH2_TSRMLS_SET(datap) ((php_ssh2_session_data*)(datap))->tsrm_ls = TSRMLS_C
+#define SSH2_TSRMLS_FETCH(datap) TSRMLS_D = ((php_ssh2_session_data*)(datap))->tsrm_ls
+#else
+#define SSH2_TSRMLS_SET(datap)
+#define SSH2_TSRMLS_FETCH(datap)
+#endif
+
+#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION >= 3)
+#define ZEND_IS_CALLABLE_TSRMLS_CC TSRMLS_CC
+#else
+#define ZEND_IS_CALLABLE_TSRMLS_CC
+#endif
+
+/* < 5.3 compatibility */
+#ifndef Z_REFCOUNT_P
+#define Z_REFCOUNT_P(pz) (pz)->refcount
+#define Z_REFCOUNT_PP(ppz) Z_REFCOUNT_P(*(ppz))
+#endif
+
+#ifndef Z_SET_REFCOUNT_P
+#define Z_SET_REFCOUNT_P(pz, rc) (pz)->refcount = rc
+#define Z_SET_REFCOUNT_PP(ppz, rc) Z_SET_REFCOUNT_P(*(ppz), rc)
+#endif
+
+#ifndef Z_ISREF_P
+#define Z_ISREF_P(pz) (pz)->is_ref
+#define Z_ISREF_PP(ppz) Z_ISREF_P(*(ppz))
+#endif
+
+#ifndef Z_SET_ISREF_P
+#define Z_SET_ISREF_P(pz) (pz)->is_ref = 1
+#define Z_SET_ISREF_PP(ppz) Z_SET_ISREF_P(*(ppz))
+#endif
+
+#ifndef Z_UNSET_ISREF_P
+#define Z_UNSET_ISREF_P(pz) (pz)->is_ref = 0
+#define Z_UNSET_ISREF_PP(ppz) Z_UNSET_ISREF_P(*(ppz))
+#endif
+
+#define SSH2_FETCH_NONAUTHENTICATED_SESSION(session, zsession) \
+ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session); \
+if (libssh2_userauth_authenticated(session)) { \
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection already authenticated"); \
+ RETURN_FALSE; \
+}
+
+#define SSH2_FETCH_AUTHENTICATED_SESSION(session, zsession) \
+ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session); \
+if (!libssh2_userauth_authenticated(session)) { \
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not authenticated"); \
+ RETURN_FALSE; \
+}
+
+typedef struct _php_ssh2_channel_data {
+ LIBSSH2_CHANNEL *channel;
+
+ /* Distinguish which stream we should read/write from/to */
+ unsigned int streamid;
+ char is_blocking;
+ long timeout;
+
+ /* Resource ID, zend_list_addref() when opening, zend_list_delete() when closing */
+ long session_rsrc;
+
+ /* Allow one stream to be closed while the other is kept open */
+ unsigned char *refcount;
+
+} php_ssh2_channel_data;
+
+/* In ssh2_fopen_wrappers.c */
+PHP_FUNCTION(ssh2_shell);
+PHP_FUNCTION(ssh2_exec);
+PHP_FUNCTION(ssh2_tunnel);
+PHP_FUNCTION(ssh2_scp_recv);
+PHP_FUNCTION(ssh2_scp_send);
+PHP_FUNCTION(ssh2_fetch_stream);
+
+/* In ssh2_sftp.c */
+PHP_FUNCTION(ssh2_sftp);
+
+PHP_FUNCTION(ssh2_sftp_rename);
+PHP_FUNCTION(ssh2_sftp_unlink);
+PHP_FUNCTION(ssh2_sftp_mkdir);
+PHP_FUNCTION(ssh2_sftp_rmdir);
+PHP_FUNCTION(ssh2_sftp_chmod);
+PHP_FUNCTION(ssh2_sftp_stat);
+PHP_FUNCTION(ssh2_sftp_lstat);
+PHP_FUNCTION(ssh2_sftp_symlink);
+PHP_FUNCTION(ssh2_sftp_readlink);
+PHP_FUNCTION(ssh2_sftp_realpath);
+
+LIBSSH2_SESSION *php_ssh2_session_connect(char *host, int port, zval *methods, zval *callbacks TSRMLS_DC);
+void php_ssh2_sftp_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC);
+php_url *php_ssh2_fopen_wraper_parse_path( char *path, char *type, php_stream_context *context,
+ LIBSSH2_SESSION **psession, int *presource_id,
+ LIBSSH2_SFTP **psftp, int *psftp_rsrcid
+ TSRMLS_DC);
+
+extern php_stream_ops php_ssh2_channel_stream_ops;
+
+extern php_stream_wrapper php_ssh2_stream_wrapper_shell;
+extern php_stream_wrapper php_ssh2_stream_wrapper_exec;
+extern php_stream_wrapper php_ssh2_stream_wrapper_tunnel;
+extern php_stream_wrapper php_ssh2_stream_wrapper_scp;
+extern php_stream_wrapper php_ssh2_sftp_wrapper;
+
+/* Resource list entries */
+extern int le_ssh2_session;
+extern int le_ssh2_sftp;
+
+/* {{{ ZIP_OPENBASEDIR_CHECKPATH(filename) */
+#if PHP_API_VERSION < 20100412
+# define SSH2_OPENBASEDIR_CHECKPATH(filename) \
+ (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(filename TSRMLS_CC)
+#else
+#define SSH2_OPENBASEDIR_CHECKPATH(filename) \
+ php_check_open_basedir(filename TSRMLS_CC)
+#endif
+/* }}} */
+#endif /* PHP_SSH2_H */
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Added |
ssh2-0.12.tgz/ssh2-0.12/ssh2.c
^
|
@@ -0,0 +1,1431 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 4 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Sara Golemon <pollita@php.net> |
+ +----------------------------------------------------------------------+
+
+ $Id: ssh2.c 327906 2012-10-06 13:52:51Z langemeijer $
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "ext/standard/info.h"
+#include "ext/standard/file.h"
+#include "php_ssh2.h"
+#include "main/php_network.h"
+
+#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+#include <openssl/applink.c>
+#endif
+
+/* Internal Constants */
+#ifndef SHA_DIGEST_LENGTH
+#define SHA_DIGEST_LENGTH 20
+#endif
+
+#ifndef MD5_DIGEST_LENGTH
+#define MD5_DIGEST_LENGTH 16
+#endif
+
+/* True global resources - no need for thread safety here */
+int le_ssh2_session;
+int le_ssh2_listener;
+int le_ssh2_sftp;
+int le_ssh2_pkey_subsys;
+
+ZEND_BEGIN_ARG_INFO(php_ssh2_first_arg_force_ref, 0)
+ ZEND_ARG_PASS_INFO(1)
+ZEND_END_ARG_INFO()
+
+/* *************
+ * Callbacks *
+ ************* */
+
+#ifdef ZTS
+#define PHP_SSH2_TSRMLS_FETCH() TSRMLS_D = *(void****)abstract;
+#else
+#define PHP_SSH2_TSRMLS_FETCH()
+#endif
+
+/* {{{ php_ssh2_alloc_cb
+ * Wrap emalloc()
+ */
+static LIBSSH2_ALLOC_FUNC(php_ssh2_alloc_cb)
+{
+ return emalloc(count);
+}
+/* }}} */
+
+/* {{{ php_ssh2_free_cb
+ * Wrap efree()
+ */
+static LIBSSH2_FREE_FUNC(php_ssh2_free_cb)
+{
+ efree(ptr);
+}
+/* }}} */
+
+/* {{{ php_ssh2_realloc_cb
+ * Wrap erealloc()
+ */
+static LIBSSH2_REALLOC_FUNC(php_ssh2_realloc_cb)
+{
+ return erealloc(ptr, count);
+}
+/* }}} */
+
+/* {{{ php_ssh2_debug_cb
+ * Debug packets
+ */
+LIBSSH2_DEBUG_FUNC(php_ssh2_debug_cb)
+{
+ php_ssh2_session_data *data;
+ zval *zdisplay, *zmessage, *zlanguage;
+ zval **args[3];
+ SSH2_TSRMLS_FETCH(*abstract);
+
+ if (!abstract || !*abstract) {
+ return;
+ }
+ data = (php_ssh2_session_data*)*abstract;
+ if (!data->debug_cb) {
+ return;
+ }
+
+ MAKE_STD_ZVAL(zmessage);
+ ZVAL_STRINGL(zmessage, (char*)message, message_len, 1);
+ args[0] = &zmessage;
+
+ MAKE_STD_ZVAL(zlanguage);
+ ZVAL_STRINGL(zlanguage, (char*)language, language_len, 1);
+ args[1] = &zlanguage;
+
+ MAKE_STD_ZVAL(zdisplay);
+ ZVAL_LONG(zdisplay, always_display);
+ args[2] = &zdisplay;
+
+ if (FAILURE == call_user_function_ex(NULL, NULL, data->disconnect_cb, NULL, 3, args, 0, NULL TSRMLS_CC)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure calling disconnect callback");
+ }
+ zval_ptr_dtor(&zdisplay);
+ zval_ptr_dtor(&zmessage);
+ zval_ptr_dtor(&zlanguage);
+}
+/* }}} */
+
+/* {{{ php_ssh2_ignore_cb
+ * Ignore packets
+ */
+LIBSSH2_IGNORE_FUNC(php_ssh2_ignore_cb)
+{
+ php_ssh2_session_data *data;
+ zval *zretval = NULL, *zmessage;
+ zval **args[1];
+ SSH2_TSRMLS_FETCH(*abstract);
+
+ if (!abstract || !*abstract) {
+ return;
+ }
+ data = (php_ssh2_session_data*)*abstract;
+ if (!data->ignore_cb) {
+ return;
+ }
+
+ MAKE_STD_ZVAL(zmessage);
+ ZVAL_STRINGL(zmessage, (char*)message, message_len, 1);
+ args[0] = &zmessage;
+
+ if (FAILURE == call_user_function_ex(NULL, NULL, data->ignore_cb, &zretval, 1, args, 0, NULL TSRMLS_CC)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure calling ignore callback");
+ }
+ zval_ptr_dtor(&zmessage);
+ if (zretval) {
+ zval_ptr_dtor(&zretval);
+ }
+}
+/* }}} */
+
+/* {{{ php_ssh2_macerror_cb
+ * Called when a MAC error occurs, offers the chance to ignore
+ * WHY ARE YOU IGNORING MAC ERRORS??????
+ */
+LIBSSH2_MACERROR_FUNC(php_ssh2_macerror_cb)
+{
+ php_ssh2_session_data *data;
+ zval *zretval = NULL, *zpacket;
+ zval **args[1];
+ int retval = -1;
+ SSH2_TSRMLS_FETCH(*abstract);
+
+ if (!abstract || !*abstract) {
+ return -1;
+ }
+ data = (php_ssh2_session_data*)*abstract;
+ if (!data->macerror_cb) {
+ return -1;
+ }
+
+ MAKE_STD_ZVAL(zpacket);
+ ZVAL_STRINGL(zpacket, (char*)packet, packet_len, 1);
+ args[0] = &zpacket;
+
+ if (FAILURE == call_user_function_ex(NULL, NULL, data->macerror_cb, &zretval, 1, args, 0, NULL TSRMLS_CC)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure calling macerror callback");
+ } else {
+ retval = zval_is_true(zretval) ? 0 : -1;
+ }
+ zval_ptr_dtor(&zpacket);
+ if (zretval) {
+ zval_ptr_dtor(&zretval);
+ }
+
+ return retval;
+}
+/* }}} */
+
+/* {{{ php_ssh2_disconnect_cb
+ * Connection closed by foreign host
+ */
+LIBSSH2_DISCONNECT_FUNC(php_ssh2_disconnect_cb)
+{
+ php_ssh2_session_data *data;
+ zval *zreason, *zmessage, *zlanguage;
+ zval **args[3];
+ SSH2_TSRMLS_FETCH(*abstract);
+
+ if (!abstract || !*abstract) {
+ return;
+ }
+ data = (php_ssh2_session_data*)*abstract;
+ if (!data->disconnect_cb) {
+ return;
+ }
+
+ MAKE_STD_ZVAL(zreason);
+ ZVAL_LONG(zreason, reason);
+ args[0] = &zreason;
+
+ MAKE_STD_ZVAL(zmessage);
+ ZVAL_STRINGL(zmessage, (char*)message, message_len, 1);
+ args[1] = &zmessage;
+
+ MAKE_STD_ZVAL(zlanguage);
+ ZVAL_STRINGL(zlanguage, (char*)language, language_len, 1);
+ args[2] = &zlanguage;
+
+ if (FAILURE == call_user_function_ex(NULL, NULL, data->disconnect_cb, NULL, 3, args, 0, NULL TSRMLS_CC)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure calling disconnect callback");
+ }
+ zval_ptr_dtor(&zreason);
+ zval_ptr_dtor(&zmessage);
+ zval_ptr_dtor(&zlanguage);
+}
+/* }}} */
+
+
+
+/* *****************
+ * Userspace API *
+ ***************** */
+
+/* {{{ php_ssh2_set_callback
+ * Try to set a method if it's passed in with the hash table
+ */
+static int php_ssh2_set_callback(LIBSSH2_SESSION *session, HashTable *ht, char *callback, int callback_len, int callback_type, php_ssh2_session_data *data TSRMLS_DC)
+{
+ zval **handler, *copyval;
+ void *internal_handler;
+
+ if (zend_hash_find(ht, callback, callback_len + 1, (void**)&handler) == FAILURE) {
+ return 0;
+ }
+
+ if (!handler || !*handler || !zend_is_callable(*handler, 0, NULL ZEND_IS_CALLABLE_TSRMLS_CC)) {
+ return -1;
+ }
+
+ ALLOC_INIT_ZVAL(copyval);
+ *copyval = **handler;
+ zval_copy_ctor(copyval);
+
+ switch (callback_type) {
+ case LIBSSH2_CALLBACK_IGNORE:
+ internal_handler = php_ssh2_ignore_cb;
+ if (data->ignore_cb) {
+ zval_ptr_dtor(&data->ignore_cb);
+ }
+ data->ignore_cb = copyval;
+ break;
+ case LIBSSH2_CALLBACK_DEBUG:
+ internal_handler = php_ssh2_debug_cb;
+ if (data->debug_cb) {
+ zval_ptr_dtor(&data->debug_cb);
+ }
+ data->debug_cb = copyval;
+ break;
+ case LIBSSH2_CALLBACK_MACERROR:
+ internal_handler = php_ssh2_macerror_cb;
+ if (data->macerror_cb) {
+ zval_ptr_dtor(&data->macerror_cb);
+ }
+ data->macerror_cb = copyval;
+ break;
+ case LIBSSH2_CALLBACK_DISCONNECT:
+ internal_handler = php_ssh2_disconnect_cb;
+ if (data->disconnect_cb) {
+ zval_ptr_dtor(&data->disconnect_cb);
+ }
+ data->disconnect_cb = copyval;
+ break;
+ default:
+ zval_ptr_dtor(©val);
+ return -1;
+ }
+
+ libssh2_session_callback_set(session, callback_type, internal_handler);
+
+ return 0;
+}
+/* }}} */
+
+/* {{{ php_ssh2_set_method
+ * Try to set a method if it's passed in with the hash table
+ */
+static int php_ssh2_set_method(LIBSSH2_SESSION *session, HashTable *ht, char *method, int method_len, int method_type)
+{
+ zval **value;
+
+ if (zend_hash_find(ht, method, method_len + 1, (void**)&value) == FAILURE) {
+ return 0;
+ }
+
+ if (!value || !*value || (Z_TYPE_PP(value) != IS_STRING)) {
+ return -1;
+ }
+
+ return libssh2_session_method_pref(session, method_type, Z_STRVAL_PP(value));
+}
+/* }}} */
+
+/* {{{ php_ssh2_session_connect
+ * Connect to an SSH server with requested methods
+ */
+LIBSSH2_SESSION *php_ssh2_session_connect(char *host, int port, zval *methods, zval *callbacks TSRMLS_DC)
+{
+ LIBSSH2_SESSION *session;
+ int socket;
+ php_ssh2_session_data *data;
+ struct timeval tv;
+
+ tv.tv_sec = FG(default_socket_timeout);
+ tv.tv_usec = 0;
+
+#if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 0)
+ socket = php_network_connect_socket_to_host(host, port, SOCK_STREAM, 0, &tv, NULL, NULL, NULL, 0 TSRMLS_CC);
+#elif PHP_MAJOR_VERSION == 5
+ socket = php_network_connect_socket_to_host(host, port, SOCK_STREAM, 0, &tv, NULL, NULL TSRMLS_CC);
+#else
+ socket = php_hostconnect(host, port, SOCK_STREAM, &tv TSRMLS_CC);
+#endif
+
+ if (socket <= 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to %s on port %d", host, port);
+ return NULL;
+ }
+
+ data = ecalloc(1, sizeof(php_ssh2_session_data));
+ SSH2_TSRMLS_SET(data);
+ data->socket = socket;
+
+ session = libssh2_session_init_ex(php_ssh2_alloc_cb, php_ssh2_free_cb, php_ssh2_realloc_cb, data);
+ if (!session) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to initialize SSH2 session");
+ efree(data);
+ closesocket(socket);
+ return NULL;
+ }
+ libssh2_banner_set(session, LIBSSH2_SSH_DEFAULT_BANNER " PHP");
+
+ /* Override method preferences */
+ if (methods) {
+ zval **container;
+
+ if (php_ssh2_set_method(session, HASH_OF(methods), "kex", sizeof("kex") - 1, LIBSSH2_METHOD_KEX)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding KEX method");
+ }
+ if (php_ssh2_set_method(session, HASH_OF(methods), "hostkey", sizeof("hostkey") - 1, LIBSSH2_METHOD_HOSTKEY)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding HOSTKEY method");
+ }
+
+ if (zend_hash_find(HASH_OF(methods), "client_to_server", sizeof("client_to_server"), (void**)&container) == SUCCESS &&
+ container && *container && Z_TYPE_PP(container) == IS_ARRAY) {
+ if (php_ssh2_set_method(session, HASH_OF(*container), "crypt", sizeof("crypt") - 1, LIBSSH2_METHOD_CRYPT_CS)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding client to server CRYPT method");
+ }
+ if (php_ssh2_set_method(session, HASH_OF(*container), "mac", sizeof("mac") - 1, LIBSSH2_METHOD_MAC_CS)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding client to server MAC method");
+ }
+ if (php_ssh2_set_method(session, HASH_OF(*container), "comp", sizeof("comp") - 1, LIBSSH2_METHOD_COMP_CS)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding client to server COMP method");
+ }
+ if (php_ssh2_set_method(session, HASH_OF(*container), "lang", sizeof("lang") - 1, LIBSSH2_METHOD_LANG_CS)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding client to server LANG method");
+ }
+ }
+
+ if (zend_hash_find(HASH_OF(methods), "server_to_client", sizeof("server_to_client"), (void**)&container) == SUCCESS &&
+ container && *container && Z_TYPE_PP(container) == IS_ARRAY) {
+ if (php_ssh2_set_method(session, HASH_OF(*container), "crypt", sizeof("crypt") - 1, LIBSSH2_METHOD_CRYPT_SC)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding server to client CRYPT method");
+ }
+ if (php_ssh2_set_method(session, HASH_OF(*container), "mac", sizeof("mac") - 1, LIBSSH2_METHOD_MAC_SC)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding server to client MAC method");
+ }
+ if (php_ssh2_set_method(session, HASH_OF(*container), "comp", sizeof("comp") - 1, LIBSSH2_METHOD_COMP_SC)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding server to client COMP method");
+ }
+ if (php_ssh2_set_method(session, HASH_OF(*container), "lang", sizeof("lang") - 1, LIBSSH2_METHOD_LANG_SC)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding server to client LANG method");
+ }
+ }
+ }
+
+ /* Register Callbacks */
+ if (callbacks) {
+ /* ignore debug disconnect macerror */
+
+ if (php_ssh2_set_callback(session, HASH_OF(callbacks), "ignore", sizeof("ignore") - 1, LIBSSH2_CALLBACK_IGNORE, data TSRMLS_CC)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting IGNORE callback");
+ }
+
+ if (php_ssh2_set_callback(session, HASH_OF(callbacks), "debug", sizeof("debug") - 1, LIBSSH2_CALLBACK_DEBUG, data TSRMLS_CC)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting DEBUG callback");
+ }
+
+ if (php_ssh2_set_callback(session, HASH_OF(callbacks), "macerror", sizeof("macerror") - 1, LIBSSH2_CALLBACK_MACERROR, data TSRMLS_CC)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting MACERROR callback");
+ }
+
+ if (php_ssh2_set_callback(session, HASH_OF(callbacks), "disconnect", sizeof("disconnect") - 1, LIBSSH2_CALLBACK_DISCONNECT, data TSRMLS_CC)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting DISCONNECT callback");
+ }
+ }
+
+ if (libssh2_session_startup(session, socket)) {
+ int last_error = 0;
+ char *error_msg = NULL;
+
+ last_error = libssh2_session_last_error(session, &error_msg, NULL, 0);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error starting up SSH connection(%d): %s", last_error, error_msg);
+ closesocket(socket);
+ libssh2_session_free(session);
+ efree(data);
+ return NULL;
+ }
+
+ return session;
+}
+/* }}} */
+
+/* {{{ proto resource ssh2_connect(string host[, int port[, array methods[, array callbacks]]])
+ * Establish a connection to a remote SSH server and return a resource on success, false on error
+ */
+PHP_FUNCTION(ssh2_connect)
+{
+ LIBSSH2_SESSION *session;
+ zval *methods = NULL, *callbacks = NULL;
+ char *host;
+ long port = PHP_SSH2_DEFAULT_PORT;
+ int host_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|la!a!", &host, &host_len, &port, &methods, &callbacks) == FAILURE) {
+ return;
+ }
+
+ session = php_ssh2_session_connect(host, port, methods, callbacks TSRMLS_CC);
+ if (!session) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to %s", host);
+ RETURN_FALSE;
+ }
+
+ ZEND_REGISTER_RESOURCE(return_value, session, le_ssh2_session);
+}
+/* }}} */
+
+/* {{{ proto array ssh2_methods_negotiated(resource session)
+ * Return list of negotiaed methods
+ */
+PHP_FUNCTION(ssh2_methods_negotiated)
+{
+ LIBSSH2_SESSION *session;
+ zval *zsession, *endpoint;
+ char *kex, *hostkey, *crypt_cs, *crypt_sc, *mac_cs, *mac_sc, *comp_cs, *comp_sc, *lang_cs, *lang_sc;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zsession) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
+
+ kex = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_KEX);
+ hostkey = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_HOSTKEY);
+ crypt_cs = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_CRYPT_CS);
+ crypt_sc = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_CRYPT_SC);
+ mac_cs = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_MAC_CS);
+ mac_sc = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_MAC_SC);
+ comp_cs = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_COMP_CS);
+ comp_sc = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_COMP_SC);
+ lang_cs = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_LANG_CS);
+ lang_sc = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_LANG_SC);
+
+ array_init(return_value);
+ add_assoc_string(return_value, "kex", kex, 1);
+ add_assoc_string(return_value, "hostkey", hostkey, 1);
+
+ ALLOC_INIT_ZVAL(endpoint);
+ array_init(endpoint);
+ add_assoc_string(endpoint, "crypt", crypt_cs, 1);
+ add_assoc_string(endpoint, "mac", mac_cs, 1);
+ add_assoc_string(endpoint, "comp", comp_cs, 1);
+ add_assoc_string(endpoint, "lang", lang_cs, 1);
+ add_assoc_zval(return_value, "client_to_server", endpoint);
+
+ ALLOC_INIT_ZVAL(endpoint);
+ array_init(endpoint);
+ add_assoc_string(endpoint, "crypt", crypt_sc, 1);
+ add_assoc_string(endpoint, "mac", mac_sc, 1);
+ add_assoc_string(endpoint, "comp", comp_sc, 1);
+ add_assoc_string(endpoint, "lang", lang_sc, 1);
+ add_assoc_zval(return_value, "server_to_client", endpoint);
+}
+/* }}} */
+
+/* {{{ proto string ssh2_fingerprint(resource session[, int flags])
+ * Returns a server hostkey hash from an active session
+ * Defaults to MD5 fingerprint encoded as ASCII hex values
+ */
+PHP_FUNCTION(ssh2_fingerprint)
+{
+ LIBSSH2_SESSION *session;
+ zval *zsession;
+ const char *fingerprint;
+ long flags = 0;
+ int i, fingerprint_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zsession, &flags) == FAILURE) {
+ return;
+ }
+ fingerprint_len = (flags & PHP_SSH2_FINGERPRINT_SHA1) ? SHA_DIGEST_LENGTH : MD5_DIGEST_LENGTH;
+
+ ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
+
+ fingerprint = (char*)libssh2_hostkey_hash(session, (flags & PHP_SSH2_FINGERPRINT_SHA1) ? LIBSSH2_HOSTKEY_HASH_SHA1 : LIBSSH2_HOSTKEY_HASH_MD5);
+ if (!fingerprint) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to retreive fingerprint from specified session");
+ RETURN_FALSE;
+ }
+
+ for(i = 0; i < fingerprint_len; i++) {
+ if (fingerprint[i] != '\0') {
+ goto fingerprint_good;
+ }
+ }
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No fingerprint available using specified hash");
+ RETURN_NULL();
+ fingerprint_good:
+ if (flags & PHP_SSH2_FINGERPRINT_RAW) {
+ RETURN_STRINGL(fingerprint, fingerprint_len, 1);
+ } else {
+ char *hexchars;
+
+ hexchars = emalloc((fingerprint_len * 2) + 1);
+ for(i = 0; i < fingerprint_len; i++) {
+ snprintf(hexchars + (2 * i), 3, "%02X", (unsigned char)fingerprint[i]);
+ }
+ RETURN_STRINGL(hexchars, 2 * fingerprint_len, 0);
+ }
+}
+/* }}} */
+
+/* {{{ proto array ssh2_auth_none(resource session, string username)
+ * Attempt "none" authentication, returns a list of allowed methods on failed authentication,
+ * false on utter failure, or true on success
+ */
+PHP_FUNCTION(ssh2_auth_none)
+{
+ LIBSSH2_SESSION *session;
+ zval *zsession;
+ char *username, *methods, *s, *p;
+ int username_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsession, &username, &username_len) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
+
+ s = methods = libssh2_userauth_list(session, username, username_len);
+ if (!methods) {
+ /* Either bad failure, or unexpected success */
+ RETURN_BOOL(libssh2_userauth_authenticated(session));
+ }
+
+ array_init(return_value);
+ while ((p = strchr(s, ','))) {
+ if ((p - s) > 0) {
+ add_next_index_stringl(return_value, s, p - s, 1);
+ }
+ s = p + 1;
+ }
+ if (strlen(s)) {
+ add_next_index_string(return_value, s, 1);
+ }
+}
+/* }}} */
+
+char *password_for_kbd_callback;
+
+static void kbd_callback(const char *name, int name_len,
+ const char *instruction, int instruction_len,
+ int num_prompts,
+ const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
+ LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
+ void **abstract)
+{
+ (void)name;
+ (void)name_len;
+ (void)instruction;
+ (void)instruction_len;
+ if (num_prompts == 1) {
+ responses[0].text = estrdup(password_for_kbd_callback);
+ responses[0].length = strlen(password_for_kbd_callback);
+ }
+ (void)prompts;
+ (void)abstract;
+}
+
+/* {{{ proto bool ssh2_auth_password(resource session, string username, string password)
+ * Authenticate over SSH using a plain password
+ */
+PHP_FUNCTION(ssh2_auth_password)
+{
+ LIBSSH2_SESSION *session;
+ zval *zsession;
+ char *username, *password;
+ int username_len, password_len;
+ char *userauthlist;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &zsession, &username, &username_len, &password, &password_len) == FAILURE) {
+ return;
+ }
+
+ SSH2_FETCH_NONAUTHENTICATED_SESSION(session, zsession);
+
+ userauthlist = libssh2_userauth_list(session, username, username_len);
+ password_for_kbd_callback = password;
+ if (strstr(userauthlist, "keyboard-interactive") != NULL) {
+ if (libssh2_userauth_keyboard_interactive(session, username, &kbd_callback) == 0) {
+ RETURN_TRUE;
+ }
+ }
+
+ /* TODO: Support password change callback */
+ if (libssh2_userauth_password_ex(session, username, username_len, password, password_len, NULL)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Authentication failed for %s using password", username);
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool ssh2_auth_pubkey_file(resource session, string username, string pubkeyfile, string privkeyfile[, string passphrase])
+ * Authenticate using a public key
+ */
+PHP_FUNCTION(ssh2_auth_pubkey_file)
+{
+ LIBSSH2_SESSION *session;
+ zval *zsession;
+ char *username, *pubkey, *privkey, *passphrase = NULL;
+ int username_len, pubkey_len, privkey_len, passphrase_len;
+ char *newpath;
+ struct passwd *pws;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsss|s", &zsession, &username, &username_len,
+ &pubkey, &pubkey_len,
+ &privkey, &privkey_len,
+ &passphrase, &passphrase_len) == FAILURE) {
+ return;
+ }
+
+ if (SSH2_OPENBASEDIR_CHECKPATH(pubkey) || SSH2_OPENBASEDIR_CHECKPATH(privkey)) {
+ RETURN_FALSE;
+ }
+
+ SSH2_FETCH_NONAUTHENTICATED_SESSION(session, zsession);
+
+ // Explode '~/paths' stopgap fix because libssh2 does not accept tilde for homedir
+ // This should be ifdef'ed when a fix is available to support older libssh2 versions
+ pws = getpwuid(geteuid());
+ if (pubkey_len >= 2 && *pubkey == '~' && *(pubkey+1) == '/') {
+ newpath = emalloc(strlen(pws->pw_dir) + strlen(pubkey));
+ strcpy(newpath, pws->pw_dir);
+ strcat(newpath, pubkey+1);
+ efree(pubkey);
+ pubkey = newpath;
+ }
+ if (privkey_len >= 2 && *privkey == '~' && *(privkey+1) == '/') {
+ newpath = emalloc(strlen(pws->pw_dir) + strlen(privkey));
+ strcpy(newpath, pws->pw_dir);
+ strcat(newpath, privkey+1);
+ efree(privkey);
+ privkey = newpath;
+ }
+
+ /* TODO: Support passphrase callback */
+ if (libssh2_userauth_publickey_fromfile_ex(session, username, username_len, pubkey, privkey, passphrase)) {
+ char *buf;
+ int len;
+ libssh2_session_last_error(session, &buf, &len, 0);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Authentication failed for %s using public key: %s", username, buf);
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool ssh2_auth_hostbased_file(resource session, string username, string local_hostname, string pubkeyfile, string privkeyfile[, string passphrase[, string local_username]])
+ * Authenticate using a hostkey
+ */
+PHP_FUNCTION(ssh2_auth_hostbased_file)
+{
+ LIBSSH2_SESSION *session;
+ zval *zsession;
+ char *username, *hostname, *pubkey, *privkey, *passphrase = NULL, *local_username = NULL;
+ int username_len, hostname_len, pubkey_len, privkey_len, passphrase_len, local_username_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rssss|s!s!", &zsession, &username, &username_len,
+ &hostname, &hostname_len,
+ &pubkey, &pubkey_len,
+ &privkey, &privkey_len,
+ &passphrase, &passphrase_len,
+ &local_username, &local_username_len) == FAILURE) {
+ return;
+ }
+
+ if (SSH2_OPENBASEDIR_CHECKPATH(pubkey) || SSH2_OPENBASEDIR_CHECKPATH(privkey)) {
+ RETURN_FALSE;
+ }
+
+ SSH2_FETCH_NONAUTHENTICATED_SESSION(session, zsession);
+
+ if (!local_username) {
+ local_username = username;
+ local_username_len = username_len;
+ }
+
+ /* TODO: Support passphrase callback */
+ if (libssh2_userauth_hostbased_fromfile_ex(session, username, username_len, pubkey, privkey, passphrase, hostname, hostname_len, local_username, local_username_len)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Authentication failed for %s using hostbased public key", username);
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto resource ssh2_forward_listen(resource session, int port[, string host[, long max_connections]])
+ * Bind a port on the remote server and listen for connections
+ */
+PHP_FUNCTION(ssh2_forward_listen)
+{
+ zval *zsession;
+ LIBSSH2_SESSION *session;
+ LIBSSH2_LISTENER *listener;
+ php_ssh2_listener_data *data;
+ long port;
+ char *host = NULL;
+ int host_len;
+ long max_connections = PHP_SSH2_LISTEN_MAX_QUEUED;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|sl", &zsession, &port, &host, &host_len, &max_connections) == FAILURE) {
+ return;
+ }
+
+ SSH2_FETCH_AUTHENTICATED_SESSION(session, zsession);
+
+ listener = libssh2_channel_forward_listen_ex(session, host, port, NULL, max_connections);
+
+ if (!listener) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure listening on remote port");
+ RETURN_FALSE;
+ }
+
+ data = emalloc(sizeof(php_ssh2_listener_data));
+ data->session = session;
+ data->session_rsrcid = Z_LVAL_P(zsession);
+ zend_list_addref(data->session_rsrcid);
+ data->listener = listener;
+
+ ZEND_REGISTER_RESOURCE(return_value, data, le_ssh2_listener);
+}
+/* }}} */
+
+/* {{{ proto stream ssh2_forward_accept(resource listener[, string &shost[, long &sport]])
+ * Accept a connection created by a listener
+ */
+PHP_FUNCTION(ssh2_forward_accept)
+{
+ zval *zlistener;
+ php_ssh2_listener_data *data;
+ LIBSSH2_CHANNEL *channel;
+ php_ssh2_channel_data *channel_data;
+ php_stream *stream;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zlistener) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(data, php_ssh2_listener_data*, &zlistener, -1, PHP_SSH2_LISTENER_RES_NAME, le_ssh2_listener);
+
+ channel = libssh2_channel_forward_accept(data->listener);
+
+ if (!channel) {
+ RETURN_FALSE;
+ }
+
+ channel_data = emalloc(sizeof(php_ssh2_channel_data));
+ channel_data->channel = channel;
+ channel_data->streamid = 0;
+ channel_data->is_blocking = 0;
+ channel_data->session_rsrc = data->session_rsrcid;
+ channel_data->refcount = NULL;
+
+ stream = php_stream_alloc(&php_ssh2_channel_stream_ops, channel_data, 0, "r+");
+ if (!stream) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure allocating stream");
+ efree(channel_data);
+ libssh2_channel_free(channel);
+ RETURN_FALSE;
+ }
+ zend_list_addref(channel_data->session_rsrc);
+
+ php_stream_to_zval(stream, return_value);
+}
+/* }}} */
+
+/* {{{ proto int ssh2_poll(array &polldes[, int timeout])
+ * Poll the channels/listeners/streams for events
+ * Returns number of descriptors which returned non-zero revents
+ * Input array should be of the form:
+ * array(
+ * 0 => array(
+ * [resource] => $channel,$listener, or $stream
+ * [events] => SSH2_POLL* flags bitwise ORed together
+ * ),
+ * 1 => ...
+ * )
+ * Each subarray will be populated with an revents element on return
+ */
+PHP_FUNCTION(ssh2_poll)
+{
+ zval *zdesc, **subarray;
+ long timeout = PHP_SSH2_DEFAULT_POLL_TIMEOUT;
+ LIBSSH2_POLLFD *pollfds;
+ int numfds, i = 0, fds_ready;
+ int le_stream = php_file_le_stream();
+ int le_pstream = php_file_le_pstream();
+ zval ***pollmap;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &zdesc, &timeout) == FAILURE) {
+ return;
+ }
+
+ numfds = zend_hash_num_elements(Z_ARRVAL_P(zdesc));
+ pollfds = safe_emalloc(sizeof(LIBSSH2_POLLFD), numfds, 0);
+ pollmap = safe_emalloc(sizeof(zval**), numfds, 0);
+
+ for(zend_hash_internal_pointer_reset(Z_ARRVAL_P(zdesc));
+ zend_hash_get_current_data(Z_ARRVAL_P(zdesc), (void**)&subarray) == SUCCESS;
+ zend_hash_move_forward(Z_ARRVAL_P(zdesc))) {
+ zval **tmpzval;
+ int res_type = 0;
+ void *res;
+
+ if (Z_TYPE_PP(subarray) != IS_ARRAY) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid element in poll array, not a sub array");
+ numfds--;
+ continue;
+ }
+ if (zend_hash_find(Z_ARRVAL_PP(subarray), "events", sizeof("events"), (void**)&tmpzval) == FAILURE ||
+ Z_TYPE_PP(tmpzval) != IS_LONG) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid data in subarray, no events element, or not a bitmask");
+ numfds--;
+ continue;
+ }
+ pollfds[i].events = Z_LVAL_PP(tmpzval);
+ if (zend_hash_find(Z_ARRVAL_PP(subarray), "resource", sizeof("resource"), (void**)&tmpzval) == FAILURE ||
+ Z_TYPE_PP(tmpzval) != IS_RESOURCE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid data in subarray, no resource element, or not of type resource");
+ numfds--;
+ continue;
+ }
+ zend_list_find(Z_LVAL_PP(tmpzval), &res_type);
+ res = zend_fetch_resource(tmpzval TSRMLS_CC, -1, "Poll Resource", NULL, 1, res_type);
+ if (res_type == le_ssh2_listener) {
+ pollfds[i].type = LIBSSH2_POLLFD_LISTENER;
+ pollfds[i].fd.listener = ((php_ssh2_listener_data*)res)->listener;
+ } else if ((res_type == le_stream || res_type == le_pstream) &&
+ ((php_stream*)res)->ops == &php_ssh2_channel_stream_ops) {
+ pollfds[i].type = LIBSSH2_POLLFD_CHANNEL;
+ pollfds[i].fd.channel = ((php_ssh2_channel_data*)(((php_stream*)res)->abstract))->channel;
+ /* TODO: Add the ability to select against other stream types */
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid resource type in subarray: %s", zend_rsrc_list_get_rsrc_type(Z_LVAL_PP(tmpzval) TSRMLS_CC));
+ numfds--;
+ continue;
+ }
+ pollmap[i] = subarray;
+ i++;
+ }
+
+ fds_ready = libssh2_poll(pollfds, numfds, timeout * 1000);
+
+ for(i = 0; i < numfds; i++) {
+ zval *subarray = *pollmap[i];
+
+ if (!Z_ISREF_P(subarray) && Z_REFCOUNT_P(subarray) > 1) {
+ /* Make a new copy of the subarray zval* */
+ MAKE_STD_ZVAL(subarray);
+ *subarray = **pollmap[i];
+
+ /* Point the pData to the new zval* and duplicate its resources */
+ *pollmap[i] = subarray;
+ zval_copy_ctor(subarray);
+
+ /* Fixup its refcount */
+ Z_UNSET_ISREF_P(subarray);
+ Z_SET_REFCOUNT_P(subarray, 1);
+ }
+ zend_hash_del(Z_ARRVAL_P(subarray), "revents", sizeof("revents"));
+ add_assoc_long(subarray, "revents", pollfds[i].revents);
+
+ }
+ efree(pollmap);
+ efree(pollfds);
+
+ RETURN_LONG(fds_ready);
+}
+/* }}} */
+
+/* ***********************
+ * Publickey Subsystem *
+ *********************** */
+
+/* {{{ proto resource ssh2_publickey_init(resource connection)
+Initialize the publickey subsystem */
+PHP_FUNCTION(ssh2_publickey_init)
+{
+ zval *zsession;
+ LIBSSH2_SESSION *session;
+ LIBSSH2_PUBLICKEY *pkey;
+ php_ssh2_pkey_subsys_data *data;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zsession) == FAILURE) {
+ return;
+ }
+
+ SSH2_FETCH_AUTHENTICATED_SESSION(session, zsession);
+
+ pkey = libssh2_publickey_init(session);
+
+ if (!pkey) {
+ int last_error = 0;
+ char *error_msg = NULL;
+
+ last_error = libssh2_session_last_error(session, &error_msg, NULL, 0);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to initialize publickey subsystem(%d) %s", last_error, error_msg);
+ RETURN_FALSE;
+ }
+
+ data = emalloc(sizeof(php_ssh2_pkey_subsys_data));
+ data->session = session;
+ data->session_rsrcid = Z_LVAL_P(zsession);
+ zend_list_addref(data->session_rsrcid);
+ data->pkey = pkey;
+
+ ZEND_REGISTER_RESOURCE(return_value, data, le_ssh2_pkey_subsys);
+}
+/* }}} */
+
+/* {{{ proto bool ssh2_publickey_add(resource pkey, string algoname, string blob[, bool overwrite=FALSE [,array attributes=NULL]])
+Add an additional publickey */
+PHP_FUNCTION(ssh2_publickey_add)
+{
+ zval *zpkey_data, *zattrs = NULL;
+ php_ssh2_pkey_subsys_data *data;
+ char *algo, *blob;
+ int algo_len, blob_len;
+ unsigned long num_attrs = 0;
+ libssh2_publickey_attribute *attrs = NULL;
+ zend_bool overwrite = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss|ba", &zpkey_data, &algo, &algo_len, &blob, &blob_len, &overwrite, &zattrs) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(data, php_ssh2_pkey_subsys_data*, &zpkey_data, -1, PHP_SSH2_PKEY_SUBSYS_RES_NAME, le_ssh2_pkey_subsys);
+
+ if (zattrs) {
+ HashPosition pos;
+ zval **attr_val;
+ unsigned long current_attr = 0;
+
+ num_attrs = zend_hash_num_elements(Z_ARRVAL_P(zattrs));
+ attrs = safe_emalloc(num_attrs, sizeof(libssh2_publickey_attribute), 0);
+
+ for(zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(zattrs), &pos);
+ zend_hash_get_current_data_ex(Z_ARRVAL_P(zattrs), (void**)&attr_val, &pos) == SUCCESS;
+ zend_hash_move_forward_ex(Z_ARRVAL_P(zattrs), &pos)) {
+ char *key;
+ int key_len, type;
+ long idx;
+ zval copyval = **attr_val;
+
+ type = zend_hash_get_current_key_ex(Z_ARRVAL_P(zattrs), &key, &key_len, &idx, 0, &pos);
+ if (type == HASH_KEY_NON_EXISTANT) {
+ /* All but impossible */
+ break;
+ }
+ if (type == HASH_KEY_IS_LONG) {
+ /* Malformed, ignore */
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Malformed attirbute array, contains numeric index");
+ num_attrs--;
+ continue;
+ }
+
+ if (key_len == 0 || (key_len == 1 && *key == '*')) {
+ /* Empty key, ignore */
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty attribute key");
+ num_attrs--;
+ continue;
+ }
+
+ zval_copy_ctor(©val);
+ Z_UNSET_ISREF_P(©val);
+ Z_SET_REFCOUNT_P(©val, 1);
+ convert_to_string(©val);
+
+ if (*key == '*') {
+ attrs[current_attr].mandatory = 1;
+ attrs[current_attr].name = key + 1;
+ attrs[current_attr].name_len = key_len - 2;
+ } else {
+ attrs[current_attr].mandatory = 0;
+ attrs[current_attr].name = key;
+ attrs[current_attr].name_len = key_len - 1;
+ }
+ attrs[current_attr].value_len = Z_STRLEN(copyval);
+ attrs[current_attr].value = Z_STRVAL(copyval);
+
+ /* copyval deliberately not dtor'd, we're stealing the string */
+ current_attr++;
+ }
+ }
+
+ if (libssh2_publickey_add_ex(data->pkey, algo, algo_len, blob, blob_len, overwrite, num_attrs, attrs)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add %s key", algo);
+ RETVAL_FALSE;
+ } else {
+ RETVAL_TRUE;
+ }
+
+ if (attrs) {
+ unsigned long i;
+
+ for(i = 0; i < num_attrs; i++) {
+ /* name doesn't need freeing */
+ efree(attrs[i].value);
+ }
+ efree(attrs);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool ssh2_publickey_remove(resource pkey, string algoname, string blob)
+Remove a publickey entry */
+PHP_FUNCTION(ssh2_publickey_remove)
+{
+ zval *zpkey_data;
+ php_ssh2_pkey_subsys_data *data;
+ char *algo, *blob;
+ int algo_len, blob_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &zpkey_data, &algo, &algo_len, &blob, &blob_len) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(data, php_ssh2_pkey_subsys_data*, &zpkey_data, -1, PHP_SSH2_PKEY_SUBSYS_RES_NAME, le_ssh2_pkey_subsys);
+
+ if (libssh2_publickey_remove_ex(data->pkey, algo, algo_len, blob, blob_len)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to remove %s key", algo);
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto array ssh2_publickey_list(resource pkey)
+List currently installed publickey entries */
+PHP_FUNCTION(ssh2_publickey_list)
+{
+ zval *zpkey_data;
+ php_ssh2_pkey_subsys_data *data;
+ unsigned long num_keys, i;
+ libssh2_publickey_list *keys;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zpkey_data) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(data, php_ssh2_pkey_subsys_data*, &zpkey_data, -1, PHP_SSH2_PKEY_SUBSYS_RES_NAME, le_ssh2_pkey_subsys);
+
+ if (libssh2_publickey_list_fetch(data->pkey, &num_keys, &keys)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to list keys on remote server");
+ RETURN_FALSE;
+ }
+
+ array_init(return_value);
+ for(i = 0; i < num_keys; i++) {
+ zval *key, *attrs;
+ unsigned long j;
+
+ MAKE_STD_ZVAL(key);
+ array_init(key);
+
+ add_assoc_stringl(key, "name", keys[i].name, keys[i].name_len, 1);
+ add_assoc_stringl(key, "blob", keys[i].blob, keys[i].blob_len, 1);
+
+ MAKE_STD_ZVAL(attrs);
+ array_init(attrs);
+ for(j = 0; j < keys[i].num_attrs; j++) {
+ zval *attr;
+
+ MAKE_STD_ZVAL(attr);
+ ZVAL_STRINGL(attr, keys[i].attrs[j].value, keys[i].attrs[j].value_len, 1);
+ zend_hash_add(Z_ARRVAL_P(attrs), keys[i].attrs[j].name, keys[i].attrs[j].name_len + 1, (void**)&attr, sizeof(zval*), NULL);
+ }
+ add_assoc_zval(key, "attrs", attrs);
+
+ add_next_index_zval(return_value, key);
+ }
+
+ libssh2_publickey_list_free(data->pkey, keys);
+}
+/* }}} */
+
+/* {{{ proto array ssh2_auth_agent(resource session, string username)
+Authenticate using the ssh agent */
+PHP_FUNCTION(ssh2_auth_agent)
+{
+#ifdef PHP_SSH2_AGENT_AUTH
+ zval *zsession;
+ char *username;
+ int username_len;
+
+ LIBSSH2_SESSION *session;
+ char *userauthlist;
+ LIBSSH2_AGENT *agent = NULL;
+ int rc;
+ struct libssh2_agent_publickey *identity, *prev_identity = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsession, &username, &username_len) == FAILURE) {
+ return;
+ }
+
+ SSH2_FETCH_NONAUTHENTICATED_SESSION(session, zsession);
+
+ /* check what authentication methods are available */
+ userauthlist = libssh2_userauth_list(session, username, username_len);
+
+ if (strstr(userauthlist, "publickey") == NULL) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "\"publickey\" authentication is not supported");
+ RETURN_FALSE;
+ }
+
+ /* Connect to the ssh-agent */
+ agent = libssh2_agent_init(session);
+
+ if (!agent) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure initializing ssh-agent support");
+ RETURN_FALSE;
+ }
+
+ if (libssh2_agent_connect(agent)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure connecting to ssh-agent");
+ libssh2_agent_free(agent);
+ RETURN_FALSE;
+ }
+
+ if (libssh2_agent_list_identities(agent)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure requesting identities to ssh-agent");
+ libssh2_agent_disconnect(agent);
+ libssh2_agent_free(agent);
+ RETURN_FALSE;
+ }
+
+ while (1) {
+ rc = libssh2_agent_get_identity(agent, &identity, prev_identity);
+
+ if (rc == 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't continue authentication");
+ libssh2_agent_disconnect(agent);
+ libssh2_agent_free(agent);
+ RETURN_FALSE;
+ }
+
+ if (rc < 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure obtaining identity from ssh-agent support");
+ libssh2_agent_disconnect(agent);
+ libssh2_agent_free(agent);
+ RETURN_FALSE;
+ }
+
+ if (!libssh2_agent_userauth(agent, username, identity)) {
+ libssh2_agent_disconnect(agent);
+ libssh2_agent_free(agent);
+ RETURN_TRUE;
+ }
+ prev_identity = identity;
+ }
+#else
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Upgrade the libssh2 library (needs 1.2.3 or higher) and reinstall the ssh2 extension for ssh2 agent support");
+ RETURN_FALSE;
+#endif /* PHP_SSH2_AGENT_AUTH */
+}
+/* }}} */
+
+/* ***********************
+ * Module Housekeeping *
+ *********************** */
+
+static void php_ssh2_session_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ LIBSSH2_SESSION *session = (LIBSSH2_SESSION*)rsrc->ptr;
+ php_ssh2_session_data **data = (php_ssh2_session_data**)libssh2_session_abstract(session);
+
+ libssh2_session_disconnect(session, "PECL/ssh2 (http://pecl.php.net/packages/ssh2)");
+
+ if (*data) {
+ if ((*data)->ignore_cb) {
+ zval_ptr_dtor(&(*data)->ignore_cb);
+ }
+ if ((*data)->debug_cb) {
+ zval_ptr_dtor(&(*data)->debug_cb);
+ }
+ if ((*data)->macerror_cb) {
+ zval_ptr_dtor(&(*data)->macerror_cb);
+ }
+ if ((*data)->disconnect_cb) {
+ zval_ptr_dtor(&(*data)->disconnect_cb);
+ }
+
+ closesocket((*data)->socket);
+
+ efree(*data);
+ *data = NULL;
+ }
+
+ libssh2_session_free(session);
+}
+
+static void php_ssh2_listener_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ php_ssh2_listener_data *data = (php_ssh2_listener_data*)rsrc->ptr;
+ LIBSSH2_LISTENER *listener = data->listener;
+
+ libssh2_channel_forward_cancel(listener);
+ zend_list_delete(data->session_rsrcid);
+ efree(data);
+}
+
+static void php_ssh2_pkey_subsys_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ php_ssh2_pkey_subsys_data *data = (php_ssh2_pkey_subsys_data*)rsrc->ptr;
+ LIBSSH2_PUBLICKEY *pkey = data->pkey;
+
+ libssh2_publickey_shutdown(pkey);
+ zend_list_delete(data->session_rsrcid);
+ efree(data);
+}
+
+/* {{{ PHP_MINIT_FUNCTION
+ */
+PHP_MINIT_FUNCTION(ssh2)
+{
+ le_ssh2_session = zend_register_list_destructors_ex(php_ssh2_session_dtor, NULL, PHP_SSH2_SESSION_RES_NAME, module_number);
+ le_ssh2_listener = zend_register_list_destructors_ex(php_ssh2_listener_dtor, NULL, PHP_SSH2_LISTENER_RES_NAME, module_number);
+ le_ssh2_sftp = zend_register_list_destructors_ex(php_ssh2_sftp_dtor, NULL, PHP_SSH2_SFTP_RES_NAME, module_number);
+ le_ssh2_pkey_subsys = zend_register_list_destructors_ex(php_ssh2_pkey_subsys_dtor, NULL, PHP_SSH2_PKEY_SUBSYS_RES_NAME, module_number);
+
+ REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_MD5", PHP_SSH2_FINGERPRINT_MD5, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_SHA1", PHP_SSH2_FINGERPRINT_SHA1, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_HEX", PHP_SSH2_FINGERPRINT_HEX, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_RAW", PHP_SSH2_FINGERPRINT_RAW, CONST_CS | CONST_PERSISTENT);
+
+ REGISTER_LONG_CONSTANT("SSH2_TERM_UNIT_CHARS", PHP_SSH2_TERM_UNIT_CHARS, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("SSH2_TERM_UNIT_PIXELS", PHP_SSH2_TERM_UNIT_PIXELS, CONST_CS | CONST_PERSISTENT);
+
+ REGISTER_STRING_CONSTANT("SSH2_DEFAULT_TERMINAL", PHP_SSH2_DEFAULT_TERMINAL, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("SSH2_DEFAULT_TERM_WIDTH", PHP_SSH2_DEFAULT_TERM_WIDTH, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("SSH2_DEFAULT_TERM_HEIGHT", PHP_SSH2_DEFAULT_TERM_HEIGHT, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("SSH2_DEFAULT_TERM_UNIT", PHP_SSH2_DEFAULT_TERM_UNIT, CONST_CS | CONST_PERSISTENT);
+
+ REGISTER_LONG_CONSTANT("SSH2_STREAM_STDIO", 0, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("SSH2_STREAM_STDERR", SSH_EXTENDED_DATA_STDERR, CONST_CS | CONST_PERSISTENT);
+
+ /* events/revents */
+ REGISTER_LONG_CONSTANT("SSH2_POLLIN", LIBSSH2_POLLFD_POLLIN, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("SSH2_POLLEXT", LIBSSH2_POLLFD_POLLEXT, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("SSH2_POLLOUT", LIBSSH2_POLLFD_POLLOUT, CONST_CS | CONST_PERSISTENT);
+
+ /* revents only */
+ REGISTER_LONG_CONSTANT("SSH2_POLLERR", LIBSSH2_POLLFD_POLLERR, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("SSH2_POLLHUP", LIBSSH2_POLLFD_POLLHUP, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("SSH2_POLLNVAL", LIBSSH2_POLLFD_POLLNVAL, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("SSH2_POLL_SESSION_CLOSED", LIBSSH2_POLLFD_SESSION_CLOSED, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("SSH2_POLL_CHANNEL_CLOSED", LIBSSH2_POLLFD_CHANNEL_CLOSED, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("SSH2_POLL_LISTENER_CLOSED", LIBSSH2_POLLFD_LISTENER_CLOSED, CONST_CS | CONST_PERSISTENT);
+
+ return (php_register_url_stream_wrapper("ssh2.shell", &php_ssh2_stream_wrapper_shell TSRMLS_CC) == SUCCESS &&
+ php_register_url_stream_wrapper("ssh2.exec", &php_ssh2_stream_wrapper_exec TSRMLS_CC) == SUCCESS &&
+ php_register_url_stream_wrapper("ssh2.tunnel", &php_ssh2_stream_wrapper_tunnel TSRMLS_CC) == SUCCESS &&
+ php_register_url_stream_wrapper("ssh2.scp", &php_ssh2_stream_wrapper_scp TSRMLS_CC) == SUCCESS &&
+ php_register_url_stream_wrapper("ssh2.sftp", &php_ssh2_sftp_wrapper TSRMLS_CC) == SUCCESS) ? SUCCESS : FAILURE;
+}
+/* }}} */
+
+/* {{{ PHP_MSHUTDOWN_FUNCTION
+ */
+PHP_MSHUTDOWN_FUNCTION(ssh2)
+{
+ return (php_unregister_url_stream_wrapper("ssh2.shell" TSRMLS_CC) == SUCCESS &&
+ php_unregister_url_stream_wrapper("ssh2.exec" TSRMLS_CC) == SUCCESS &&
+ php_unregister_url_stream_wrapper("ssh2.tunnel" TSRMLS_CC) == SUCCESS &&
+ php_unregister_url_stream_wrapper("ssh2.scp" TSRMLS_CC) == SUCCESS &&
+ php_unregister_url_stream_wrapper("ssh2.sftp" TSRMLS_CC) == SUCCESS) ? SUCCESS : FAILURE;
+}
+/* }}} */
+
+/* {{{ PHP_MINFO_FUNCTION
+ */
+PHP_MINFO_FUNCTION(ssh2)
+{
+ php_info_print_table_start();
+ php_info_print_table_header(2, "SSH2 support", "enabled");
+ php_info_print_table_row(2, "extension version", PHP_SSH2_VERSION);
+ php_info_print_table_row(2, "libssh2 version", LIBSSH2_VERSION);
+ php_info_print_table_row(2, "banner", LIBSSH2_SSH_BANNER);
+ php_info_print_table_end();
+}
+/* }}} */
+
+/* {{{ ssh2_functions[]
+ */
+zend_function_entry ssh2_functions[] = {
+ PHP_FE(ssh2_connect, NULL)
+ PHP_FE(ssh2_methods_negotiated, NULL)
+ PHP_FE(ssh2_fingerprint, NULL)
+
+ PHP_FE(ssh2_auth_none, NULL)
+ PHP_FE(ssh2_auth_password, NULL)
+ PHP_FE(ssh2_auth_pubkey_file, NULL)
+ PHP_FE(ssh2_auth_hostbased_file, NULL)
+
+ PHP_FE(ssh2_forward_listen, NULL)
+ PHP_FE(ssh2_forward_accept, NULL)
+
+ /* Stream Stuff */
+ PHP_FE(ssh2_shell, NULL)
+ PHP_FE(ssh2_exec, NULL)
+ PHP_FE(ssh2_tunnel, NULL)
+ PHP_FE(ssh2_scp_recv, NULL)
+ PHP_FE(ssh2_scp_send, NULL)
+ PHP_FE(ssh2_fetch_stream, NULL)
+ PHP_FE(ssh2_poll, php_ssh2_first_arg_force_ref)
+
+ /* SFTP Stuff */
+ PHP_FE(ssh2_sftp, NULL)
+
+ /* SFTP Wrapper Ops */
+ PHP_FE(ssh2_sftp_rename, NULL)
+ PHP_FE(ssh2_sftp_unlink, NULL)
+ PHP_FE(ssh2_sftp_mkdir, NULL)
+ PHP_FE(ssh2_sftp_rmdir, NULL)
+ PHP_FE(ssh2_sftp_chmod, NULL)
+ PHP_FE(ssh2_sftp_stat, NULL)
+ PHP_FE(ssh2_sftp_lstat, NULL)
+ PHP_FE(ssh2_sftp_symlink, NULL)
+ PHP_FE(ssh2_sftp_readlink, NULL)
+ PHP_FE(ssh2_sftp_realpath, NULL)
+
+ /* Publickey subsystem */
+ PHP_FE(ssh2_publickey_init, NULL)
+ PHP_FE(ssh2_publickey_add, NULL)
+ PHP_FE(ssh2_publickey_remove, NULL)
+ PHP_FE(ssh2_publickey_list, NULL)
+
+ PHP_FE(ssh2_auth_agent, NULL)
+
+ {NULL, NULL, NULL}
+};
+/* }}} */
+
+/* {{{ ssh2_module_entry
+ */
+zend_module_entry ssh2_module_entry = {
+#if ZEND_MODULE_API_NO >= 20010901
+ STANDARD_MODULE_HEADER,
+#endif
+ "ssh2",
+ ssh2_functions,
+ PHP_MINIT(ssh2),
+ PHP_MSHUTDOWN(ssh2),
+ NULL, /* RINIT */
+ NULL, /* RSHUTDOWN */
+ PHP_MINFO(ssh2),
+#if ZEND_MODULE_API_NO >= 20010901
+ PHP_SSH2_VERSION,
+#endif
+ STANDARD_MODULE_PROPERTIES
+};
+/* }}} */
+
+#ifdef COMPILE_DL_SSH2
+ZEND_GET_MODULE(ssh2)
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
|
[-]
[+]
|
Added |
ssh2-0.12.tgz/ssh2-0.12/ssh2_fopen_wrappers.c
^
|
@@ -0,0 +1,1384 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 4 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Sara Golemon <pollita@php.net> |
+ +----------------------------------------------------------------------+
+
+ $Id: ssh2_fopen_wrappers.c 327861 2012-10-02 20:18:07Z langemeijer $
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ssh2.h"
+
+/* **********************
+ * channel_stream_ops *
+ ********************** */
+
+static size_t php_ssh2_channel_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
+{
+ php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract;
+ size_t writestate;
+ LIBSSH2_SESSION *session;
+
+ libssh2_channel_set_blocking(abstract->channel, abstract->is_blocking);
+ session = (LIBSSH2_SESSION *)zend_fetch_resource(NULL TSRMLS_CC, abstract->session_rsrc, PHP_SSH2_SESSION_RES_NAME, NULL, 1, le_ssh2_session);
+
+#ifdef PHP_SSH2_SESSION_TIMEOUT
+ if (abstract->is_blocking) {
+ libssh2_session_set_timeout(session, abstract->timeout);
+ }
+#endif
+
+ writestate = libssh2_channel_write_ex(abstract->channel, abstract->streamid, buf, count);
+
+#ifdef PHP_SSH2_SESSION_TIMEOUT
+ if (abstract->is_blocking) {
+ libssh2_session_set_timeout(session, 0);
+ }
+#endif
+ if (writestate == LIBSSH2_ERROR_EAGAIN) {
+ writestate = 0;
+ }
+
+ if (writestate < 0) {
+ char *error_msg = NULL;
+ if (libssh2_session_last_error(session, &error_msg, NULL, 0) == writestate) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure '%s' (%ld)", error_msg, writestate);
+ }
+
+ stream->eof = 1;
+ writestate = 0;
+ }
+
+ return writestate;
+}
+
+static size_t php_ssh2_channel_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
+{
+ php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract;
+ ssize_t readstate;
+ LIBSSH2_SESSION *session;
+
+ stream->eof = libssh2_channel_eof(abstract->channel);
+ libssh2_channel_set_blocking(abstract->channel, abstract->is_blocking);
+ session = (LIBSSH2_SESSION *)zend_fetch_resource(NULL TSRMLS_CC, abstract->session_rsrc, PHP_SSH2_SESSION_RES_NAME, NULL, 1, le_ssh2_session);
+
+#ifdef PHP_SSH2_SESSION_TIMEOUT
+ if (abstract->is_blocking) {
+ libssh2_session_set_timeout(session, abstract->timeout);
+ }
+#endif
+
+ readstate = libssh2_channel_read_ex(abstract->channel, abstract->streamid, buf, count);
+
+#ifdef PHP_SSH2_SESSION_TIMEOUT
+ if (abstract->is_blocking) {
+ libssh2_session_set_timeout(session, 0);
+ }
+#endif
+ if (readstate == LIBSSH2_ERROR_EAGAIN) {
+ readstate = 0;
+ }
+
+ if (readstate < 0) {
+ char *error_msg = NULL;
+ if (libssh2_session_last_error(session, &error_msg, NULL, 0) == readstate) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure '%s' (%ld)", error_msg, readstate);
+ }
+
+ stream->eof = 1;
+ readstate = 0;
+ }
+ return readstate;
+}
+
+static int php_ssh2_channel_stream_close(php_stream *stream, int close_handle TSRMLS_DC)
+{
+ php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract;
+
+ if (!abstract->refcount || (--(*(abstract->refcount)) == 0)) {
+ /* Last one out, turn off the lights */
+ if (abstract->refcount) {
+ efree(abstract->refcount);
+ }
+ libssh2_channel_eof(abstract->channel);
+ libssh2_channel_free(abstract->channel);
+ zend_list_delete(abstract->session_rsrc);
+ }
+ efree(abstract);
+
+ return 0;
+}
+
+static int php_ssh2_channel_stream_flush(php_stream *stream TSRMLS_DC)
+{
+ php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract;
+
+ return libssh2_channel_flush_ex(abstract->channel, abstract->streamid);
+}
+
+static int php_ssh2_channel_stream_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
+{
+ php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract;
+ int ret;
+
+ switch (option) {
+ case PHP_STREAM_OPTION_BLOCKING:
+ ret = abstract->is_blocking;
+ abstract->is_blocking = value;
+ return ret;
+ break;
+
+ case PHP_STREAM_OPTION_READ_TIMEOUT:
+ ret = abstract->timeout;
+#ifdef PHP_SSH2_SESSION_TIMEOUT
+ struct timeval tv = *(struct timeval*)ptrparam;
+ abstract->timeout = tv.tv_sec * 1000 + (tv.tv_usec / 1000);
+#else
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No support for ssh2 stream timeout. Please recompile with libssh2 >= 1.2.9");
+#endif
+ return ret;
+ break;
+
+#if PHP_MAJOR_VERSION >= 5
+ case PHP_STREAM_OPTION_CHECK_LIVENESS:
+ return stream->eof = libssh2_channel_eof(abstract->channel);
+ break;
+#endif
+ }
+
+ return -1;
+}
+
+php_stream_ops php_ssh2_channel_stream_ops = {
+ php_ssh2_channel_stream_write,
+ php_ssh2_channel_stream_read,
+ php_ssh2_channel_stream_close,
+ php_ssh2_channel_stream_flush,
+ PHP_SSH2_CHANNEL_STREAM_NAME,
+ NULL, /* seek */
+ NULL, /* cast */
+ NULL, /* stat */
+ php_ssh2_channel_stream_set_option,
+};
+
+/* *********************
+ * Magic Path Helper *
+ ********************* */
+
+/* {{{ php_ssh2_fopen_wraper_parse_path
+ * Parse an ssh2.*:// path
+ */
+php_url *php_ssh2_fopen_wraper_parse_path( char *path, char *type, php_stream_context *context,
+ LIBSSH2_SESSION **psession, int *presource_id,
+ LIBSSH2_SFTP **psftp, int *psftp_rsrcid
+ TSRMLS_DC)
+{
+ php_ssh2_sftp_data *sftp_data = NULL;
+ LIBSSH2_SESSION *session;
+ php_url *resource;
+ zval *methods = NULL, *callbacks = NULL, zsession, **tmpzval;
+ long resource_id;
+ char *s, *username = NULL, *password = NULL, *pubkey_file = NULL, *privkey_file = NULL;
+ int username_len = 0, password_len = 0;
+
+ resource = php_url_parse(path);
+ if (!resource) {
+ return NULL;
+ }
+
+ if (strncmp(resource->scheme, "ssh2.", sizeof("ssh2.") - 1)) {
+ /* Not an ssh wrapper */
+ php_url_free(resource);
+ return NULL;
+ }
+
+ if (strcmp(resource->scheme + sizeof("ssh2.") - 1, type)) {
+ /* Wrong ssh2. wrapper type */
+ php_url_free(resource);
+ return NULL;
+ }
+
+ if (!resource->host) {
+ return NULL;
+ }
+
+ /*
+ Find resource->path in the path string, then copy the entire string from the original path.
+ This includes ?query#fragment in the path string
+ */
+ s = resource->path;
+ resource->path = estrdup(strstr(path, resource->path));
+ efree(s);
+
+ /* Look for a resource ID to reuse a session */
+ s = resource->host;
+ if (strncmp(resource->host, "Resource id #", sizeof("Resource id #") - 1) == 0) {
+ s = resource->host + sizeof("Resource id #") - 1;
+ }
+ if (is_numeric_string(s, strlen(s), &resource_id, NULL, 0) == IS_LONG) {
+ php_ssh2_sftp_data *sftp_data;
+
+ if (psftp) {
+ sftp_data = (php_ssh2_sftp_data*)zend_fetch_resource(NULL TSRMLS_CC, resource_id, PHP_SSH2_SFTP_RES_NAME, NULL, 1, le_ssh2_sftp);
+ if (sftp_data) {
+ /* Want the sftp layer */
+ zend_list_addref(resource_id);
+ *psftp_rsrcid = resource_id;
+ *psftp = sftp_data->sftp;
+ *presource_id = sftp_data->session_rsrcid;
+ *psession = sftp_data->session;
+ return resource;
+ }
+ }
+ session = (LIBSSH2_SESSION *)zend_fetch_resource(NULL TSRMLS_CC, resource_id, PHP_SSH2_SESSION_RES_NAME, NULL, 1, le_ssh2_session);
+ if (session) {
+ if (psftp) {
+ /* We need an sftp layer too */
+ LIBSSH2_SFTP *sftp = libssh2_sftp_init(session);
+
+ if (!sftp) {
+ php_url_free(resource);
+ return NULL;
+ }
+ sftp_data = emalloc(sizeof(php_ssh2_sftp_data));
+ sftp_data->sftp = sftp;
+ sftp_data->session = session;
+ sftp_data->session_rsrcid = resource_id;
+ zend_list_addref(resource_id);
+ *psftp_rsrcid = ZEND_REGISTER_RESOURCE(NULL, sftp_data, le_ssh2_sftp);
+ *psftp = sftp;
+ *presource_id = resource_id;
+ *psession = session;
+ return resource;
+ }
+ zend_list_addref(resource_id);
+ *presource_id = resource_id;
+ *psession = session;
+ return resource;
+ }
+ }
+
+ /* Fallback on finding it in the context */
+ if (resource->host[0] == 0 && context && psftp &&
+ php_stream_context_get_option(context, "ssh2", "sftp", &tmpzval) == SUCCESS &&
+ Z_TYPE_PP(tmpzval) == IS_RESOURCE) {
+ php_ssh2_sftp_data *sftp_data;
+ sftp_data = (php_ssh2_sftp_data *)zend_fetch_resource(tmpzval TSRMLS_CC, -1, PHP_SSH2_SFTP_RES_NAME, NULL, 1, le_ssh2_sftp);
+ if (sftp_data) {
+ zend_list_addref(Z_LVAL_PP(tmpzval));
+ *psftp_rsrcid = Z_LVAL_PP(tmpzval);
+ *psftp = sftp_data->sftp;
+ *presource_id = sftp_data->session_rsrcid;
+ *psession = sftp_data->session;
+ return resource;
+ }
+ }
+ if (resource->host[0] == 0 && context &&
+ php_stream_context_get_option(context, "ssh2", "session", &tmpzval) == SUCCESS &&
+ Z_TYPE_PP(tmpzval) == IS_RESOURCE) {
+ session = (LIBSSH2_SESSION *)zend_fetch_resource(tmpzval TSRMLS_CC, -1, PHP_SSH2_SESSION_RES_NAME, NULL, 1, le_ssh2_session);
+ if (session) {
+ if (psftp) {
+ /* We need an SFTP layer too! */
+ LIBSSH2_SFTP *sftp = libssh2_sftp_init(session);
+ php_ssh2_sftp_data *sftp_data;
+
+ if (!sftp) {
+ php_url_free(resource);
+ return NULL;
+ }
+ sftp_data = emalloc(sizeof(php_ssh2_sftp_data));
+ sftp_data->sftp = sftp;
+ sftp_data->session = session;
+ sftp_data->session_rsrcid = Z_LVAL_PP(tmpzval);
+ zend_list_addref(Z_LVAL_PP(tmpzval));
+ *psftp_rsrcid = ZEND_REGISTER_RESOURCE(NULL, sftp_data, le_ssh2_sftp);
+ *psftp = sftp;
+ *presource_id = Z_LVAL_PP(tmpzval);
+ *psession = session;
+ return resource;
+ }
+ zend_list_addref(Z_LVAL_PP(tmpzval));
+ *psession = session;
+ *presource_id = Z_LVAL_PP(tmpzval);
+ return resource;
+ }
+ }
+
+ /* Make our own connection then */
+ if (!resource->port) {
+ resource->port = 22;
+ }
+
+ if (context &&
+ php_stream_context_get_option(context, "ssh2", "methods", &tmpzval) == SUCCESS &&
+ Z_TYPE_PP(tmpzval) == IS_ARRAY) {
+ methods = *tmpzval;
+ }
+
+ if (context &&
+ php_stream_context_get_option(context, "ssh2", "callbacks", &tmpzval) == SUCCESS &&
+ Z_TYPE_PP(tmpzval) == IS_ARRAY) {
+ callbacks = *tmpzval;
+ }
+
+ if (context &&
+ php_stream_context_get_option(context, "ssh2", "username", &tmpzval) == SUCCESS &&
+ Z_TYPE_PP(tmpzval) == IS_STRING) {
+ username = Z_STRVAL_PP(tmpzval);
+ username_len = Z_STRLEN_PP(tmpzval);
+ }
+
+ if (context &&
+ php_stream_context_get_option(context, "ssh2", "password", &tmpzval) == SUCCESS &&
+ Z_TYPE_PP(tmpzval) == IS_STRING) {
+ password = Z_STRVAL_PP(tmpzval);
+ password_len = Z_STRLEN_PP(tmpzval);
+ }
+
+ if (context &&
+ php_stream_context_get_option(context, "ssh2", "pubkey_file", &tmpzval) == SUCCESS &&
+ Z_TYPE_PP(tmpzval) == IS_STRING) {
+ pubkey_file = Z_STRVAL_PP(tmpzval);
+ }
+
+ if (context &&
+ php_stream_context_get_option(context, "ssh2", "privkey_file", &tmpzval) == SUCCESS &&
+ Z_TYPE_PP(tmpzval) == IS_STRING) {
+ privkey_file = Z_STRVAL_PP(tmpzval);
+ }
+
+ if (resource->user) {
+ int len = strlen(resource->user);
+
+ if (len) {
+ username = resource->user;
+ username_len = len;
+ }
+ }
+
+ if (resource->pass) {
+ int len = strlen(resource->pass);
+
+ if (len) {
+ password = resource->pass;
+ password_len = len;
+ }
+ }
+
+ if (!username) {
+ /* username is a minimum */
+ php_url_free(resource);
+ return NULL;
+ }
+
+ session = php_ssh2_session_connect(resource->host, resource->port, methods, callbacks TSRMLS_CC);
+ if (!session) {
+ /* Unable to connect! */
+ php_url_free(resource);
+ return NULL;
+ }
+
+ /* Authenticate */
+ if (pubkey_file && privkey_file) {
+ if (SSH2_OPENBASEDIR_CHECKPATH(pubkey_file) || SSH2_OPENBASEDIR_CHECKPATH(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;
+ }
+ }
+
+ if (password) {
+ /* Attempt password authentication */
+ if (libssh2_userauth_password_ex(session, username, username_len, password, password_len, NULL) == 0) {
+ goto session_authed;
+ }
+ }
+
+ /* Auth failure */
+ php_url_free(resource);
+ zend_list_delete(Z_LVAL(zsession));
+ return NULL;
+
+session_authed:
+ ZEND_REGISTER_RESOURCE(&zsession, session, le_ssh2_session);
+
+ if (psftp) {
+ LIBSSH2_SFTP *sftp;
+ zval zsftp;
+
+ sftp = libssh2_sftp_init(session);
+ if (!sftp) {
+ php_url_free(resource);
+ zend_list_delete(Z_LVAL(zsession));
+ return NULL;
+ }
+
+ sftp_data = emalloc(sizeof(php_ssh2_sftp_data));
+ sftp_data->session = session;
+ sftp_data->sftp = sftp;
+ sftp_data->session_rsrcid = Z_LVAL(zsession);
+
+ ZEND_REGISTER_RESOURCE(&zsftp, sftp_data, le_ssh2_sftp);
+ *psftp_rsrcid = Z_LVAL(zsftp);
+ *psftp = sftp;
+ }
+
+ *presource_id = Z_LVAL(zsession);
+ *psession = session;
+
+ return resource;
+}
+/* }}} */
+
+/* *****************
+ * Shell Wrapper *
+ ***************** */
+
+/* {{{ php_ssh2_shell_open
+ * Make a stream from a session
+ */
+static php_stream *php_ssh2_shell_open(LIBSSH2_SESSION *session, int resource_id, char *term, int term_len, zval *environment, long width, long height, long type TSRMLS_DC)
+{
+ LIBSSH2_CHANNEL *channel;
+ php_ssh2_channel_data *channel_data;
+ php_stream *stream;
+
+ channel = libssh2_channel_open_session(session);
+ if (!channel) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to request a channel from remote host");
+ return NULL;
+ }
+
+ if (environment) {
+ char *key;
+ int key_type, key_len;
+ long idx;
+
+ for(zend_hash_internal_pointer_reset(HASH_OF(environment));
+ (key_type = zend_hash_get_current_key_ex(HASH_OF(environment), &key, &key_len, &idx, 0, NULL)) != HASH_KEY_NON_EXISTANT;
+ zend_hash_move_forward(HASH_OF(environment))) {
+ if (key_type == HASH_KEY_IS_STRING) {
+ zval **value;
+
+ if (zend_hash_get_current_data(HASH_OF(environment), (void**)&value) == SUCCESS) {
+ zval copyval = **value;
+
+ zval_copy_ctor(©val);
+ convert_to_string(©val);
+ if (libssh2_channel_setenv_ex(channel, key, key_len, Z_STRVAL(copyval), Z_STRLEN(copyval))) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting %s=%s on remote end", key, Z_STRVAL(copyval));
+ }
+ zval_dtor(©val);
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Skipping numeric index in environment array");
+ }
+ }
+ }
+
+ if (type == PHP_SSH2_TERM_UNIT_CHARS) {
+ if (libssh2_channel_request_pty_ex(channel, term, term_len, NULL, 0, width, height, 0, 0)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %s pty at %ldx%ld characters", term, width, height);
+ libssh2_channel_free(channel);
+ return NULL;
+ }
+ } else {
+ if (libssh2_channel_request_pty_ex(channel, term, term_len, NULL, 0, 0, 0, width, height)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %s pty at %ldx%ld pixels", term, width, height);
+ libssh2_channel_free(channel);
+ return NULL;
+ }
+ }
+
+ if (libssh2_channel_shell(channel)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to request shell from remote host");
+ libssh2_channel_free(channel);
+ return NULL;
+ }
+
+ /* Turn it into a stream */
+ channel_data = emalloc(sizeof(php_ssh2_channel_data));
+ channel_data->channel = channel;
+ channel_data->streamid = 0;
+ channel_data->is_blocking = 0;
+ channel_data->timeout = 0;
+ channel_data->session_rsrc = resource_id;
+ channel_data->refcount = NULL;
+
+ stream = php_stream_alloc(&php_ssh2_channel_stream_ops, channel_data, 0, "r+");
+
+ return stream;
+}
+/* }}} */
+
+/* {{{ php_ssh2_fopen_wrapper_shell
+ * ssh2.shell:// fopen wrapper
+ */
+static php_stream *php_ssh2_fopen_wrapper_shell(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ LIBSSH2_SESSION *session = NULL;
+ php_stream *stream;
+ zval **tmpzval, *environment = NULL;
+ char *terminal = PHP_SSH2_DEFAULT_TERMINAL;
+ long width = PHP_SSH2_DEFAULT_TERM_WIDTH;
+ long height = PHP_SSH2_DEFAULT_TERM_HEIGHT;
+ long type = PHP_SSH2_DEFAULT_TERM_UNIT;
+ int resource_id = 0, terminal_len = sizeof(PHP_SSH2_DEFAULT_TERMINAL) - 1;
+ php_url *resource;
+ char *s, *e;
+
+ resource = php_ssh2_fopen_wraper_parse_path(path, "shell", context, &session, &resource_id, NULL, NULL TSRMLS_CC);
+ if (!resource || !session) {
+ return NULL;
+ }
+
+ if (context &&
+ php_stream_context_get_option(context, "ssh2", "env", &tmpzval) == SUCCESS &&
+ tmpzval && *tmpzval && Z_TYPE_PP(tmpzval) == IS_ARRAY) {
+ environment = *tmpzval;
+ }
+
+ if (context &&
+ php_stream_context_get_option(context, "ssh2", "term", &tmpzval) == SUCCESS &&
+ tmpzval && *tmpzval && Z_TYPE_PP(tmpzval) == IS_STRING) {
+ terminal = Z_STRVAL_PP(tmpzval);
+ terminal_len = Z_STRLEN_PP(tmpzval);
+ }
+
+ if (context &&
+ php_stream_context_get_option(context, "ssh2", "term_width", &tmpzval) == SUCCESS &&
+ tmpzval && *tmpzval) {
+ zval *copyval;
+ ALLOC_INIT_ZVAL(copyval);
+ *copyval = **tmpzval;
+ convert_to_long(copyval);
+ width = Z_LVAL_P(copyval);
+ zval_ptr_dtor(©val);
+ }
+
+ if (context &&
+ php_stream_context_get_option(context, "ssh2", "term_height", &tmpzval) == SUCCESS &&
+ tmpzval && *tmpzval) {
+ zval *copyval;
+ ALLOC_INIT_ZVAL(copyval);
+ *copyval = **tmpzval;
+ convert_to_long(copyval);
+ height = Z_LVAL_P(copyval);
+ zval_ptr_dtor(©val);
+ }
+
+ if (context &&
+ php_stream_context_get_option(context, "ssh2", "term_units", &tmpzval) == SUCCESS &&
+ tmpzval && *tmpzval) {
+ zval *copyval;
+ ALLOC_INIT_ZVAL(copyval);
+ *copyval = **tmpzval;
+ convert_to_long(copyval);
+ type = Z_LVAL_P(copyval);
+ zval_ptr_dtor(©val);
+ }
+
+ s = resource->path ? resource->path : NULL;
+ e = s ? s + strlen(s) : NULL;
+
+ if (s && s[0] == '/') {
+ /* Terminal type encoded into URL overrides context terminal type */
+ char *p;
+
+ s++;
+ p = strchr(s, '/');
+ if (p) {
+ if (p - s) {
+ terminal = s;
+ terminal_len = p - terminal;
+ s += terminal_len + 1;
+ } else {
+ /* "null" terminal given, skip it */
+ s++;
+ }
+ } else {
+ int len;
+
+ if ((len = strlen(path + 1))) {
+ terminal = s;
+ terminal_len = len;
+ s += len;
+ }
+ }
+ }
+
+ /* TODO: Accept resolution and environment vars as URL style parameters
+ * ssh2.shell://hostorresource/terminal/99x99c?envvar=envval&envvar=envval....
+ */
+ stream = php_ssh2_shell_open(session, resource_id, terminal, terminal_len, environment, width, height, type TSRMLS_CC);
+ if (!stream) {
+ zend_list_delete(resource_id);
+ }
+ php_url_free(resource);
+
+ return stream;
+}
+/* }}} */
+
+static php_stream_wrapper_ops php_ssh2_shell_stream_wops = {
+ php_ssh2_fopen_wrapper_shell,
+ NULL, /* stream_close */
+ NULL, /* stat */
+ NULL, /* stat_url */
+ NULL, /* opendir */
+ "ssh2.shell"
+};
+
+php_stream_wrapper php_ssh2_stream_wrapper_shell = {
+ &php_ssh2_shell_stream_wops,
+ NULL,
+ 0
+};
+
+/* {{{ proto stream ssh2_shell(resource session[, string term_type[, array env[, int width, int height[, int width_height_type]]]])
+ * Open a shell at the remote end and allocate a channel for it
+ */
+PHP_FUNCTION(ssh2_shell)
+{
+ LIBSSH2_SESSION *session;
+ php_stream *stream;
+ zval *zsession;
+ zval *environment = NULL;
+ char *term = PHP_SSH2_DEFAULT_TERMINAL;
+ int term_len = sizeof(PHP_SSH2_DEFAULT_TERMINAL) - 1;
+ long width = PHP_SSH2_DEFAULT_TERM_WIDTH;
+ long height = PHP_SSH2_DEFAULT_TERM_HEIGHT;
+ long type = PHP_SSH2_DEFAULT_TERM_UNIT;
+ int argc = ZEND_NUM_ARGS();
+
+ if (argc == 5) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "width specified without height parameter");
+ RETURN_FALSE;
+ }
+
+ if (zend_parse_parameters(argc TSRMLS_CC, "r|sa!lll", &zsession, &term, &term_len, &environment, &width, &height, &type) == FAILURE) {
+ return;
+ }
+
+ SSH2_FETCH_AUTHENTICATED_SESSION(session, zsession);
+
+ stream = php_ssh2_shell_open(session, Z_LVAL_P(zsession), term, term_len, environment, width, height, type TSRMLS_CC);
+ if (!stream) {
+ RETURN_FALSE;
+ }
+
+ /* Ensure that channels are freed BEFORE the sessions they belong to */
+ zend_list_addref(Z_LVAL_P(zsession));
+
+ php_stream_to_zval(stream, return_value);
+}
+/* }}} */
+
+/* ****************
+ * Exec Wrapper *
+ **************** */
+
+/* {{{ php_ssh2_exec_command
+ * Make a stream from a session
+ */
+static php_stream *php_ssh2_exec_command(LIBSSH2_SESSION *session, int resource_id, char *command, char *term, int term_len, zval *environment, long width, long height, long type TSRMLS_DC)
+{
+ LIBSSH2_CHANNEL *channel;
+ php_ssh2_channel_data *channel_data;
+ php_stream *stream;
+
+ channel = libssh2_channel_open_session(session);
+ if (!channel) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to request a channel from remote host");
+ return NULL;
+ }
+
+ if (environment) {
+ char *key;
+ int key_type, key_len;
+ long idx;
+
+ for(zend_hash_internal_pointer_reset(HASH_OF(environment));
+ (key_type = zend_hash_get_current_key_ex(HASH_OF(environment), &key, &key_len, &idx, 0, NULL)) != HASH_KEY_NON_EXISTANT;
+ zend_hash_move_forward(HASH_OF(environment))) {
+ if (key_type == HASH_KEY_IS_STRING) {
+ zval **value;
+
+ if (zend_hash_get_current_data(HASH_OF(environment), (void**)&value) == SUCCESS) {
+ zval copyval = **value;
+
+ zval_copy_ctor(©val);
+ convert_to_string(©val);
+ if (libssh2_channel_setenv_ex(channel, key, key_len, Z_STRVAL(copyval), Z_STRLEN(copyval))) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting %s=%s on remote end", key, Z_STRVAL(copyval));
+ }
+ zval_dtor(©val);
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Skipping numeric index in environment array");
+ }
+ }
+ }
+
+ if (term) {
+ if (type == PHP_SSH2_TERM_UNIT_CHARS) {
+ if (libssh2_channel_request_pty_ex(channel, term, term_len, NULL, 0, width, height, 0, 0)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %s pty at %ldx%ld characters", term, width, height);
+ libssh2_channel_free(channel);
+ return NULL;
+ }
+ } else {
+ if (libssh2_channel_request_pty_ex(channel, term, term_len, NULL, 0, 0, 0, width, height)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %s pty at %ldx%ld pixels", term, width, height);
+ libssh2_channel_free(channel);
+ return NULL;
+ }
+ }
+ }
+
+ if (libssh2_channel_exec(channel, command)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to request command execution on remote host");
+ libssh2_channel_free(channel);
+ return NULL;
+ }
+
+ /* Turn it into a stream */
+ channel_data = emalloc(sizeof(php_ssh2_channel_data));
+ channel_data->channel = channel;
+ channel_data->streamid = 0;
+ channel_data->is_blocking = 0;
+ channel_data->timeout = 0;
+ channel_data->session_rsrc = resource_id;
+ channel_data->refcount = NULL;
+
+ stream = php_stream_alloc(&php_ssh2_channel_stream_ops, channel_data, 0, "r+");
+
+ return stream;
+}
+/* }}} */
+
+/* {{{ php_ssh2_fopen_wrapper_exec
+ * ssh2.exec:// fopen wrapper
+ */
+static php_stream *php_ssh2_fopen_wrapper_exec(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ LIBSSH2_SESSION *session = NULL;
+ php_stream *stream;
+ zval **tmpzval, *environment = NULL;
+ int resource_id = 0;
+ php_url *resource;
+ char *terminal = NULL;
+ int terminal_len = 0;
+ long width = PHP_SSH2_DEFAULT_TERM_WIDTH;
+ long height = PHP_SSH2_DEFAULT_TERM_HEIGHT;
+ long type = PHP_SSH2_DEFAULT_TERM_UNIT;
+
+ resource = php_ssh2_fopen_wraper_parse_path(path, "exec", context, &session, &resource_id, NULL, NULL TSRMLS_CC);
+ if (!resource || !session) {
+ return NULL;
+ }
+ if (!resource->path) {
+ php_url_free(resource);
+ zend_list_delete(resource_id);
+ return NULL;
+ }
+
+ if (context &&
+ php_stream_context_get_option(context, "ssh2", "env", &tmpzval) == SUCCESS &&
+ tmpzval && *tmpzval && Z_TYPE_PP(tmpzval) == IS_ARRAY) {
+ environment = *tmpzval;
+ }
+
+ if (context &&
+ php_stream_context_get_option(context, "ssh2", "term", &tmpzval) == SUCCESS &&
+ tmpzval && *tmpzval && Z_TYPE_PP(tmpzval) == IS_STRING) {
+ terminal = Z_STRVAL_PP(tmpzval);
+ terminal_len = Z_STRLEN_PP(tmpzval);
+ }
+
+ if (context &&
+ php_stream_context_get_option(context, "ssh2", "term_width", &tmpzval) == SUCCESS &&
+ tmpzval && *tmpzval) {
+ zval *copyval;
+ ALLOC_INIT_ZVAL(copyval);
+ *copyval = **tmpzval;
+ convert_to_long(copyval);
+ width = Z_LVAL_P(copyval);
+ zval_ptr_dtor(©val);
+ }
+
+ if (context &&
+ php_stream_context_get_option(context, "ssh2", "term_height", &tmpzval) == SUCCESS &&
+ tmpzval && *tmpzval) {
+ zval *copyval;
+ ALLOC_INIT_ZVAL(copyval);
+ *copyval = **tmpzval;
+ convert_to_long(copyval);
+ height = Z_LVAL_P(copyval);
+ zval_ptr_dtor(©val);
+ }
+
+ if (context &&
+ php_stream_context_get_option(context, "ssh2", "term_units", &tmpzval) == SUCCESS &&
+ tmpzval && *tmpzval) {
+ zval *copyval;
+ ALLOC_INIT_ZVAL(copyval);
+ *copyval = **tmpzval;
+ convert_to_long(copyval);
+ type = Z_LVAL_P(copyval);
+ zval_ptr_dtor(©val);
+ }
+
+ stream = php_ssh2_exec_command(session, resource_id, resource->path + 1, terminal, terminal_len, environment, width, height, type TSRMLS_CC);
+ if (!stream) {
+ zend_list_delete(resource_id);
+ }
+ php_url_free(resource);
+
+ return stream;
+}
+/* }}} */
+
+static php_stream_wrapper_ops php_ssh2_exec_stream_wops = {
+ php_ssh2_fopen_wrapper_exec,
+ NULL, /* stream_close */
+ NULL, /* stat */
+ NULL, /* stat_url */
+ NULL, /* opendir */
+ "ssh2.exec"
+};
+
+php_stream_wrapper php_ssh2_stream_wrapper_exec = {
+ &php_ssh2_exec_stream_wops,
+ NULL,
+ 0
+};
+
+/* {{{ proto stream ssh2_exec(resource session, string command[, string pty[, array env[, int width[, int heightp[, int width_height_type]]]]])
+ * Execute a command at the remote end and allocate a channel for it
+ *
+ * This function has a dirty little secret.... pty and env can be in either order.... shhhh... don't tell anyone
+ */
+PHP_FUNCTION(ssh2_exec)
+{
+ LIBSSH2_SESSION *session;
+ php_stream *stream;
+ zval *zsession;
+ zval *environment = NULL;
+ zval *zpty = NULL;
+ char *command;
+ int command_len;
+ long width = PHP_SSH2_DEFAULT_TERM_WIDTH;
+ long height = PHP_SSH2_DEFAULT_TERM_HEIGHT;
+ long type = PHP_SSH2_DEFAULT_TERM_UNIT;
+ char *term = NULL;
+ int term_len = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|z!z!lll", &zsession, &command, &command_len, &zpty, &environment, &width, &height, &type) == FAILURE) {
+ return;
+ }
+
+ if (zpty && Z_TYPE_P(zpty) == IS_ARRAY) {
+ /* Swap pty and environment -- old call style */
+ zval *tmp = zpty;
+ zpty = environment;
+ environment = tmp;
+ }
+
+ if (environment && Z_TYPE_P(environment) != IS_ARRAY) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "ssh2_exec() expects arg 4 to be of type array");
+ RETURN_FALSE;
+ }
+
+ if (zpty) {
+ convert_to_string(zpty);
+ term = Z_STRVAL_P(zpty);
+ term_len = Z_STRLEN_P(zpty);
+ }
+
+ SSH2_FETCH_AUTHENTICATED_SESSION(session, zsession);
+
+ stream = php_ssh2_exec_command(session, Z_LVAL_P(zsession), command, term, term_len, environment, width, height, type TSRMLS_CC);
+ if (!stream) {
+ RETURN_FALSE;
+ }
+
+ /* Ensure that channels are freed BEFORE the sessions they belong to */
+ zend_list_addref(Z_LVAL_P(zsession));
+
+ php_stream_to_zval(stream, return_value);
+}
+/* }}} */
+
+/* ***************
+ * SCP Wrapper *
+ *************** */
+
+/* {{{ php_ssh2_scp_xfer
+ * Make a stream from a session
+ */
+static php_stream *php_ssh2_scp_xfer(LIBSSH2_SESSION *session, int resource_id, char *filename TSRMLS_DC)
+{
+ LIBSSH2_CHANNEL *channel;
+ php_ssh2_channel_data *channel_data;
+ php_stream *stream;
+
+ channel = libssh2_scp_recv(session, filename, NULL);
+ if (!channel) {
+ char *error = "";
+ libssh2_session_last_error(session, &error, NULL, 0);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to request a channel from remote host: %s", error);
+ return NULL;
+ }
+
+ /* Turn it into a stream */
+ channel_data = emalloc(sizeof(php_ssh2_channel_data));
+ channel_data->channel = channel;
+ channel_data->streamid = 0;
+ channel_data->is_blocking = 0;
+ channel_data->timeout = 0;
+ channel_data->session_rsrc = resource_id;
+ channel_data->refcount = NULL;
+
+ stream = php_stream_alloc(&php_ssh2_channel_stream_ops, channel_data, 0, "r");
+
+ return stream;
+}
+/* }}} */
+
+/* {{{ php_ssh2_fopen_wrapper_scp
+ * ssh2.scp:// fopen wrapper (Read mode only, if you want to know why write mode isn't supported as a stream, take a look at the SCP protocol)
+ */
+static php_stream *php_ssh2_fopen_wrapper_scp(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ LIBSSH2_SESSION *session = NULL;
+ php_stream *stream;
+ int resource_id = 0;
+ php_url *resource;
+
+ if (strchr(mode, '+') || strchr(mode, 'a') || strchr(mode, 'w')) {
+ return NULL;
+ }
+
+ resource = php_ssh2_fopen_wraper_parse_path(path, "scp", context, &session, &resource_id, NULL, NULL TSRMLS_CC);
+ if (!resource || !session) {
+ return NULL;
+ }
+ if (!resource->path) {
+ php_url_free(resource);
+ zend_list_delete(resource_id);
+ return NULL;
+ }
+
+ stream = php_ssh2_scp_xfer(session, resource_id, resource->path TSRMLS_CC);
+ if (!stream) {
+ zend_list_delete(resource_id);
+ }
+ php_url_free(resource);
+
+ return stream;
+}
+/* }}} */
+
+static php_stream_wrapper_ops php_ssh2_scp_stream_wops = {
+ php_ssh2_fopen_wrapper_scp,
+ NULL, /* stream_close */
+ NULL, /* stat */
+ NULL, /* stat_url */
+ NULL, /* opendir */
+ "ssh2.scp"
+};
+
+php_stream_wrapper php_ssh2_stream_wrapper_scp = {
+ &php_ssh2_scp_stream_wops,
+ NULL,
+ 0
+};
+
+/* {{{ proto bool ssh2_scp_recv(resource session, string remote_file, string local_file)
+ * Request a file via SCP
+ */
+PHP_FUNCTION(ssh2_scp_recv)
+{
+ LIBSSH2_SESSION *session;
+ LIBSSH2_CHANNEL *remote_file;
+ struct stat sb;
+ php_stream *local_file;
+ zval *zsession;
+ char *remote_filename, *local_filename;
+ int remote_filename_len, local_filename_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &zsession, &remote_filename, &remote_filename_len,
+ &local_filename, &local_filename_len) == FAILURE) {
+ return;
+ }
+
+ SSH2_FETCH_AUTHENTICATED_SESSION(session, zsession);
+
+ remote_file = libssh2_scp_recv(session, remote_filename, &sb);
+ if (!remote_file) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to receive remote file");
+ RETURN_FALSE;
+ }
+ libssh2_channel_set_blocking(remote_file, 1);
+
+ local_file = php_stream_open_wrapper(local_filename, "wb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL);
+ if (!local_file) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to write to local file");
+ libssh2_channel_free(remote_file);
+ RETURN_FALSE;
+ }
+
+ while (sb.st_size) {
+ char buffer[8192];
+ int bytes_read;
+
+ bytes_read = libssh2_channel_read(remote_file, buffer, sb.st_size > 8192 ? 8192 : sb.st_size);
+ if (bytes_read < 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error reading from remote file");
+ libssh2_channel_free(remote_file);
+ php_stream_close(local_file);
+ RETURN_FALSE;
+ }
+ php_stream_write(local_file, buffer, bytes_read);
+ sb.st_size -= bytes_read;
+ }
+
+ libssh2_channel_free(remote_file);
+ php_stream_close(local_file);
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto stream ssh2_scp_send(resource session, string local_file, string remote_file[, int create_mode = 0644])
+ * Send a file via SCP
+ */
+PHP_FUNCTION(ssh2_scp_send)
+{
+ LIBSSH2_SESSION *session;
+ LIBSSH2_CHANNEL *remote_file;
+ php_stream *local_file;
+ zval *zsession;
+ char *local_filename, *remote_filename;
+ int local_filename_len, remote_filename_len;
+ long create_mode = 0644;
+ php_stream_statbuf ssb;
+ int argc = ZEND_NUM_ARGS();
+
+ if (zend_parse_parameters(argc TSRMLS_CC, "rss|l", &zsession, &local_filename, &local_filename_len,
+ &remote_filename, &remote_filename_len, &create_mode) == FAILURE) {
+ return;
+ }
+
+ SSH2_FETCH_AUTHENTICATED_SESSION(session, zsession);
+
+ local_file = php_stream_open_wrapper(local_filename, "rb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL);
+ if (!local_file) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to read source file");
+ RETURN_FALSE;
+ }
+
+ if (php_stream_stat(local_file, &ssb)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed statting local file");
+ php_stream_close(local_file);
+ RETURN_FALSE;
+ }
+
+ if (argc < 4) {
+ create_mode = ssb.sb.st_mode & 0777;
+ }
+
+ remote_file = libssh2_scp_send_ex(session, remote_filename, create_mode, ssb.sb.st_size, ssb.sb.st_atime, ssb.sb.st_mtime);
+ if (!remote_file) {
+ int last_error = 0;
+ char *error_msg = NULL;
+
+ last_error = libssh2_session_last_error(session, &error_msg, NULL, 0);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure creating remote file: %s", error_msg);
+ php_stream_close(local_file);
+ RETURN_FALSE;
+ }
+ libssh2_channel_set_blocking(remote_file, 1);
+
+ while (ssb.sb.st_size) {
+ char buffer[8192];
+ size_t toread = MIN(8192, ssb.sb.st_size);
+ size_t bytesread = php_stream_read(local_file, buffer, toread);
+
+ if (bytesread <= 0 || bytesread > toread) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed copying file 2");
+ php_stream_close(local_file);
+ libssh2_channel_free(remote_file);
+ RETURN_FALSE;
+ }
+
+ size_t sent = 0;
+ size_t justsent = 0;
+
+ while (bytesread - sent > 0) {
+ if ((justsent = libssh2_channel_write(remote_file, (buffer + sent), bytesread - sent)) < 0) {
+
+ switch (justsent) {
+ case LIBSSH2_ERROR_EAGAIN:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Operation would block");
+ break;
+
+ case LIBSSH2_ERROR_ALLOC:
+ php_error_docref(NULL TSRMLS_CC,E_WARNING, "An internal memory allocation call failed");
+ break;
+
+ case LIBSSH2_ERROR_SOCKET_SEND:
+ php_error_docref(NULL TSRMLS_CC,E_WARNING, "Unable to send data on socket");
+ break;
+
+ case LIBSSH2_ERROR_CHANNEL_CLOSED:
+ php_error_docref(NULL TSRMLS_CC,E_WARNING, "The channel has been closed");
+ break;
+
+ case LIBSSH2_ERROR_CHANNEL_EOF_SENT:
+ php_error_docref(NULL TSRMLS_CC,E_WARNING, "The channel has been requested to be closed");
+ break;
+ }
+
+ php_stream_close(local_file);
+ libssh2_channel_free(remote_file);
+ RETURN_FALSE;
+ }
+ sent = sent + justsent;
+ }
+ ssb.sb.st_size -= bytesread;
+ }
+
+ libssh2_channel_flush_ex(remote_file, LIBSSH2_CHANNEL_FLUSH_ALL);
+ php_stream_close(local_file);
+ libssh2_channel_free(remote_file);
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* ***************************
+ * Direct TCP/IP Transport *
+ *************************** */
+
+/* {{{ php_ssh2_direct_tcpip
+ * Make a stream from a session
+ */
+static php_stream *php_ssh2_direct_tcpip(LIBSSH2_SESSION *session, int resource_id, char *host, int port TSRMLS_DC)
+{
+ LIBSSH2_CHANNEL *channel;
+ php_ssh2_channel_data *channel_data;
+ php_stream *stream;
+
+ channel = libssh2_channel_direct_tcpip(session, host, port);
+ if (!channel) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to request a channel from remote host");
+ return NULL;
+ }
+
+ /* Turn it into a stream */
+ channel_data = emalloc(sizeof(php_ssh2_channel_data));
+ channel_data->channel = channel;
+ channel_data->streamid = 0;
+ channel_data->is_blocking = 0;
+ channel_data->timeout = 0;
+ channel_data->session_rsrc = resource_id;
+ channel_data->refcount = NULL;
+
+ stream = php_stream_alloc(&php_ssh2_channel_stream_ops, channel_data, 0, "r+");
+
+ return stream;
+}
+/* }}} */
+
+/* {{{ php_ssh2_fopen_wrapper_tunnel
+ * ssh2.tunnel:// fopen wrapper
+ */
+static php_stream *php_ssh2_fopen_wrapper_tunnel(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ LIBSSH2_SESSION *session = NULL;
+ php_stream *stream = NULL;
+ php_url *resource;
+ char *host = NULL;
+ int port = 0;
+ int resource_id = 0;
+
+ resource = php_ssh2_fopen_wraper_parse_path(path, "tunnel", context, &session, &resource_id, NULL, NULL TSRMLS_CC);
+ if (!resource || !session) {
+ return NULL;
+ }
+
+ if (resource->path && resource->path[0] == '/') {
+ char *colon;
+
+ host = resource->path + 1;
+ if (*host == '[') {
+ /* IPv6 Encapsulated Format */
+ host++;
+ colon = strstr(host, "]:");
+ if (colon) {
+ *colon = 0;
+ colon += 2;
+ }
+ } else {
+ colon = strchr(host, ':');
+ if (colon) {
+ *(colon++) = 0;
+ }
+ }
+ if (colon) {
+ port = atoi(colon);
+ }
+ }
+
+ if ((port <= 0) || (port > 65535) || !host || (strlen(host) == 0)) {
+ /* Invalid connection criteria */
+ php_url_free(resource);
+ zend_list_delete(resource_id);
+ return NULL;
+ }
+
+ stream = php_ssh2_direct_tcpip(session, resource_id, host, port TSRMLS_CC);
+ if (!stream) {
+ zend_list_delete(resource_id);
+ }
+ php_url_free(resource);
+
+ return stream;
+}
+/* }}} */
+
+static php_stream_wrapper_ops php_ssh2_tunnel_stream_wops = {
+ php_ssh2_fopen_wrapper_tunnel,
+ NULL, /* stream_close */
+ NULL, /* stat */
+ NULL, /* stat_url */
+ NULL, /* opendir */
+ "ssh2.tunnel"
+};
+
+php_stream_wrapper php_ssh2_stream_wrapper_tunnel = {
+ &php_ssh2_tunnel_stream_wops,
+ NULL,
+ 0
+};
+
+/* {{{ proto stream ssh2_tunnel(resource session, string host, int port)
+ * Tunnel to remote TCP/IP host/port
+ */
+PHP_FUNCTION(ssh2_tunnel)
+{
+ LIBSSH2_SESSION *session;
+ php_stream *stream;
+ zval *zsession;
+ char *host;
+ int host_len;
+ long port;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsl", &zsession, &host, &host_len, &port) == FAILURE) {
+ return;
+ }
+
+ SSH2_FETCH_AUTHENTICATED_SESSION(session, zsession);
+
+ stream = php_ssh2_direct_tcpip(session, Z_LVAL_P(zsession), host, port TSRMLS_CC);
+ if (!stream) {
+ RETURN_FALSE;
+ }
+
+ /* Ensure that channels are freed BEFORE the sessions they belong to */
+ zend_list_addref(Z_LVAL_P(zsession));
+
+ php_stream_to_zval(stream, return_value);
+}
+/* }}} */
+
+/* ******************
+ * Generic Helper *
+ ****************** */
+
+/* {{{ proto stream ssh2_fetch_stream(stream channel, int streamid)
+ * Fetch an extended data stream
+ */
+PHP_FUNCTION(ssh2_fetch_stream)
+{
+ php_ssh2_channel_data *data, *stream_data;
+ php_stream *parent, *stream;
+ zval *zparent;
+ long streamid;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zparent, &streamid) == FAILURE) {
+ return;
+ }
+
+ if (streamid < 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stream ID requested");
+ RETURN_FALSE;
+ }
+
+ php_stream_from_zval(parent, &zparent);
+
+ if (parent->ops != &php_ssh2_channel_stream_ops) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Provided stream is not of type " PHP_SSH2_CHANNEL_STREAM_NAME);
+ RETURN_FALSE;
+ }
+
+ data = (php_ssh2_channel_data*)parent->abstract;
+
+ if (!data->refcount) {
+ data->refcount = emalloc(sizeof(unsigned char));
+ *(data->refcount) = 1;
+ }
+
+ if (*(data->refcount) == 255) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many streams associated to a single channel");
+ RETURN_FALSE;
+ }
+
+ (*(data->refcount))++;
+
+ stream_data = emalloc(sizeof(php_ssh2_channel_data));
+ memcpy(stream_data, data, sizeof(php_ssh2_channel_data));
+ stream_data->streamid = streamid;
+
+ stream = php_stream_alloc(&php_ssh2_channel_stream_ops, stream_data, 0, "r+");
+ if (!stream) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error opening substream");
+ efree(stream_data);
+ *(data->refcount)--;
+ RETURN_FALSE;
+ }
+
+ php_stream_to_zval(stream, return_value);
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
|
[-]
[+]
|
Added |
ssh2-0.12.tgz/ssh2-0.12/ssh2_sftp.c
^
|
@@ -0,0 +1,884 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 4 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Sara Golemon <pollita@php.net> |
+ +----------------------------------------------------------------------+
+
+ $Id: ssh2_sftp.c 326206 2012-06-17 20:54:01Z langemeijer $
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ssh2.h"
+#include "ext/standard/php_string.h"
+
+/* *************************
+ * Resource Housekeeping *
+ ************************* */
+
+void php_ssh2_sftp_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ php_ssh2_sftp_data *data = (php_ssh2_sftp_data*)rsrc->ptr;
+
+ if (!data) {
+ return;
+ }
+
+ libssh2_sftp_shutdown(data->sftp);
+
+ zend_list_delete(data->session_rsrcid);
+
+ efree(data);
+}
+
+/* *****************
+ * SFTP File Ops *
+ ***************** */
+
+inline unsigned long php_ssh2_parse_fopen_modes(char *openmode) {
+ unsigned long flags = 0;
+
+ if (strchr(openmode, 'a')) {
+ flags |= LIBSSH2_FXF_APPEND;
+ }
+
+ if (strchr(openmode, 'w')) {
+ flags |= LIBSSH2_FXF_WRITE | LIBSSH2_FXF_TRUNC | LIBSSH2_FXF_CREAT;
+ }
+
+ if (strchr(openmode, 'r')) {
+ flags |= LIBSSH2_FXF_READ;
+ }
+
+ if (strchr(openmode, '+')) {
+ flags |= LIBSSH2_FXF_READ | LIBSSH2_FXF_WRITE;
+ }
+
+ if (strchr(openmode, 'x')) {
+ flags |= LIBSSH2_FXF_WRITE | LIBSSH2_FXF_TRUNC | LIBSSH2_FXF_EXCL | LIBSSH2_FXF_CREAT;
+ }
+
+ return flags;
+}
+
+inline int php_ssh2_sftp_attr2ssb(php_stream_statbuf *ssb, LIBSSH2_SFTP_ATTRIBUTES *attrs)
+{
+ memset(ssb, 0, sizeof(php_stream_statbuf));
+ if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) {
+ ssb->sb.st_size = attrs->filesize;
+ }
+
+ if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) {
+ ssb->sb.st_uid = attrs->uid;
+ ssb->sb.st_gid = attrs->gid;
+ }
+ if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
+ ssb->sb.st_mode = attrs->permissions;
+ }
+ if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
+ ssb->sb.st_atime = attrs->atime;
+ ssb->sb.st_mtime = attrs->mtime;
+ }
+
+ return 0;
+}
+
+typedef struct _php_ssh2_sftp_handle_data {
+ LIBSSH2_SFTP_HANDLE *handle;
+
+ long sftp_rsrcid;
+} php_ssh2_sftp_handle_data;
+
+/* {{{ php_ssh2_sftp_stream_write
+ */
+static size_t php_ssh2_sftp_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
+{
+ php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
+ ssize_t bytes_written;
+
+ bytes_written = libssh2_sftp_write(data->handle, buf, count);
+
+ return (size_t)(bytes_written<0 ? 0 : bytes_written);
+}
+/* }}} */
+
+/* {{{ php_ssh2_sftp_stream_read
+ */
+static size_t php_ssh2_sftp_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
+{
+ php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
+ ssize_t bytes_read;
+
+ bytes_read = libssh2_sftp_read(data->handle, buf, count);
+
+ stream->eof = (bytes_read <= 0 && bytes_read != LIBSSH2_ERROR_EAGAIN);
+
+ return (size_t)(bytes_read<0 ? 0 : bytes_read);
+}
+/* }}} */
+
+/* {{{ php_ssh2_sftp_stream_close
+ */
+static int php_ssh2_sftp_stream_close(php_stream *stream, int close_handle TSRMLS_DC)
+{
+ php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
+
+ libssh2_sftp_close(data->handle);
+ zend_list_delete(data->sftp_rsrcid);
+ efree(data);
+
+ return 0;
+}
+/* }}} */
+
+/* {{{ php_ssh2_sftp_stream_seek
+ */
+static int php_ssh2_sftp_stream_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC)
+{
+ php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
+
+ switch (whence) {
+ case SEEK_END:
+ {
+ LIBSSH2_SFTP_ATTRIBUTES attrs;
+
+ if (libssh2_sftp_fstat(data->handle, &attrs)) {
+ return -1;
+ }
+ if ((attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) == 0) {
+ return -1;
+ }
+ offset += attrs.filesize;
+ }
+ case SEEK_CUR:
+ {
+ off_t current_offset = libssh2_sftp_tell(data->handle);
+
+ if (current_offset < 0) {
+ return -1;
+ }
+
+ offset += current_offset;
+ }
+ }
+
+ libssh2_sftp_seek(data->handle, offset);
+
+ if (newoffset) {
+ *newoffset = offset;
+ }
+
+ return 0;
+}
+/* }}} */
+
+/* {{{ php_ssh2_sftp_stream_fstat
+ */
+static int php_ssh2_sftp_stream_fstat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
+{
+ php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
+ LIBSSH2_SFTP_ATTRIBUTES attrs;
+
+ if (libssh2_sftp_fstat(data->handle, &attrs)) {
+ return -1;
+ }
+
+ return php_ssh2_sftp_attr2ssb(ssb, &attrs);
+}
+/* }}} */
+
+static php_stream_ops php_ssh2_sftp_stream_ops = {
+ php_ssh2_sftp_stream_write,
+ php_ssh2_sftp_stream_read,
+ php_ssh2_sftp_stream_close,
+ NULL, /* flush */
+ PHP_SSH2_SFTP_STREAM_NAME,
+ php_ssh2_sftp_stream_seek,
+ NULL, /* cast */
+ php_ssh2_sftp_stream_fstat,
+ NULL, /* set_option */
+};
+
+/* {{{ php_ssh2_sftp_stream_opener
+ */
+static php_stream *php_ssh2_sftp_stream_opener( php_stream_wrapper *wrapper, char *filename, char *mode,
+ int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ php_ssh2_sftp_handle_data *data;
+ LIBSSH2_SESSION *session = NULL;
+ LIBSSH2_SFTP *sftp = NULL;
+ LIBSSH2_SFTP_HANDLE *handle;
+ php_stream *stream;
+ int resource_id = 0, sftp_rsrcid = 0;
+ php_url *resource;
+ unsigned long flags;
+ long perms = 0644;
+
+ resource = php_ssh2_fopen_wraper_parse_path(filename, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
+ if (!resource || !session || !sftp) {
+ return NULL;
+ }
+
+ flags = php_ssh2_parse_fopen_modes(mode);
+
+ handle = libssh2_sftp_open(sftp, resource->path, flags, perms);
+ if (!handle) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open %s on remote host", filename);
+ php_url_free(resource);
+ zend_list_delete(sftp_rsrcid);
+ return NULL;
+ }
+
+ data = emalloc(sizeof(php_ssh2_sftp_handle_data));
+ data->handle = handle;
+ data->sftp_rsrcid = sftp_rsrcid;
+
+ stream = php_stream_alloc(&php_ssh2_sftp_stream_ops, data, 0, mode);
+ if (!stream) {
+ libssh2_sftp_close(handle);
+ zend_list_delete(sftp_rsrcid);
+ efree(data);
+ }
+ php_url_free(resource);
+
+ return stream;
+}
+/* }}} */
+
+/* **********************
+ * SFTP Directory Ops *
+ ********************** */
+
+/* {{{ php_ssh2_sftp_dirstream_read
+ */
+static size_t php_ssh2_sftp_dirstream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
+{
+ php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
+ php_stream_dirent *ent = (php_stream_dirent*)buf;
+ size_t bytesread = libssh2_sftp_readdir(data->handle, ent->d_name, sizeof(ent->d_name) - 1, NULL);
+ char *basename = NULL;
+ size_t basename_len = 0;
+
+ if (bytesread <= 0) {
+ return 0;
+ }
+ ent->d_name[bytesread] = 0;
+
+#ifdef ZEND_ENGINE_2
+ php_basename(ent->d_name, bytesread, NULL, 0, &basename, &basename_len TSRMLS_CC);
+#else
+/* CURSE YOU BC BREAKS! */
+ basename = php_basename(ent->d_name, bytesread, NULL, 0);
+ if (basename) {
+ basename_len = strlen(basename);
+ }
+#endif
+ if (!basename) {
+ return 0;
+ }
+
+ if (!basename_len) {
+ efree(basename);
+ return 0;
+ }
+ bytesread = MIN(sizeof(ent->d_name) - 1, basename_len);
+ memcpy(ent->d_name, basename, bytesread);
+ ent->d_name[bytesread] = 0;
+ efree(basename);
+
+ return sizeof(php_stream_dirent);
+}
+/* }}} */
+
+/* {{{ php_ssh2_sftp_dirstream_close
+ */
+static int php_ssh2_sftp_dirstream_close(php_stream *stream, int close_handle TSRMLS_DC)
+{
+ php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
+
+ libssh2_sftp_close(data->handle);
+ zend_list_delete(data->sftp_rsrcid);
+ efree(data);
+
+ return 0;
+}
+/* }}} */
+
+static php_stream_ops php_ssh2_sftp_dirstream_ops = {
+ NULL, /* write */
+ php_ssh2_sftp_dirstream_read,
+ php_ssh2_sftp_dirstream_close,
+ NULL, /* flush */
+ PHP_SSH2_SFTP_DIRSTREAM_NAME,
+ NULL, /* seek */
+ NULL, /* cast */
+ NULL, /* fstat */
+ NULL, /* set_option */
+};
+
+/* {{{ php_ssh2_sftp_dirstream_opener
+ */
+static php_stream *php_ssh2_sftp_dirstream_opener( php_stream_wrapper *wrapper, char *filename, char *mode,
+ int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ php_ssh2_sftp_handle_data *data;
+ LIBSSH2_SESSION *session = NULL;
+ LIBSSH2_SFTP *sftp = NULL;
+ LIBSSH2_SFTP_HANDLE *handle;
+ php_stream *stream;
+ int resource_id = 0, sftp_rsrcid = 0;
+ php_url *resource;
+
+ resource = php_ssh2_fopen_wraper_parse_path(filename, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
+ if (!resource || !session || !sftp) {
+ return NULL;
+ }
+
+ handle = libssh2_sftp_opendir(sftp, resource->path);
+ if (!handle) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open %s on remote host", filename);
+ php_url_free(resource);
+ zend_list_delete(sftp_rsrcid);
+ return NULL;
+ }
+
+ data = emalloc(sizeof(php_ssh2_sftp_handle_data));
+ data->handle = handle;
+ data->sftp_rsrcid = sftp_rsrcid;
+
+ stream = php_stream_alloc(&php_ssh2_sftp_dirstream_ops, data, 0, mode);
+ if (!stream) {
+ libssh2_sftp_close(handle);
+ zend_list_delete(sftp_rsrcid);
+ efree(data);
+ }
+ php_url_free(resource);
+
+ return stream;
+}
+/* }}} */
+
+/* ****************
+ * SFTP Wrapper *
+ **************** */
+
+#ifdef ZEND_ENGINE_2
+/* {{{ php_ssh2_sftp_urlstat
+ */
+static int php_ssh2_sftp_urlstat(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC)
+{
+ LIBSSH2_SFTP_ATTRIBUTES attrs;
+ LIBSSH2_SESSION *session = NULL;
+ LIBSSH2_SFTP *sftp = NULL;
+ int resource_id = 0, sftp_rsrcid = 0;
+ php_url *resource;
+
+ resource = php_ssh2_fopen_wraper_parse_path(url, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
+ if (!resource || !session || !sftp || !resource->path) {
+ return -1;
+ }
+
+ if (libssh2_sftp_stat_ex(sftp, resource->path, strlen(resource->path),
+ (flags & PHP_STREAM_URL_STAT_LINK) ? LIBSSH2_SFTP_LSTAT : LIBSSH2_SFTP_STAT, &attrs)) {
+ php_url_free(resource);
+ zend_list_delete(sftp_rsrcid);
+ return -1;
+ }
+
+ php_url_free(resource);
+
+ /* parse_path addrefs the resource, but we're not holding on to it so we have to delref it before we leave */
+ zend_list_delete(sftp_rsrcid);
+
+ return php_ssh2_sftp_attr2ssb(ssb, &attrs);
+}
+/* }}} */
+
+/* {{{ php_ssh2_sftp_unlink
+ */
+static int php_ssh2_sftp_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC)
+{
+ LIBSSH2_SESSION *session = NULL;
+ LIBSSH2_SFTP *sftp = NULL;
+ int resource_id = 0, sftp_rsrcid = 0;
+ php_url *resource;
+ int result;
+
+ resource = php_ssh2_fopen_wraper_parse_path(url, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
+ if (!resource || !session || !sftp || !resource->path) {
+ if (resource) {
+ php_url_free(resource);
+ }
+ return 0;
+ }
+
+ result = libssh2_sftp_unlink(sftp, resource->path);
+ php_url_free(resource);
+
+ zend_list_delete(sftp_rsrcid);
+
+ /* libssh2 uses 0 for success and the streams API uses 0 for failure, so invert */
+ return (result == 0) ? -1 : 0;
+}
+/* }}} */
+
+/* {{{ php_ssh2_sftp_rename
+ */
+static int php_ssh2_sftp_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC)
+{
+ LIBSSH2_SESSION *session = NULL;
+ LIBSSH2_SFTP *sftp = NULL;
+ int resource_id = 0, sftp_rsrcid = 0;
+ php_url *resource, *resource_to;
+ int result;
+
+ if (strncmp(url_from, "ssh2.sftp://", sizeof("ssh2.sftp://") - 1) ||
+ strncmp(url_to, "ssh2.sftp://", sizeof("ssh2.sftp://") - 1)) {
+ return 0;
+ }
+
+ resource_to = php_url_parse(url_to);
+ if (!resource_to || !resource_to->path) {
+ if (resource_to) {
+ php_url_free(resource_to);
+ }
+ return 0;
+ }
+
+ resource = php_ssh2_fopen_wraper_parse_path(url_from, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
+ if (!resource || !session || !sftp || !resource->path) {
+ if (resource) {
+ php_url_free(resource);
+ }
+ php_url_free(resource_to);
+ return 0;
+ }
+
+ result = libssh2_sftp_rename(sftp, resource->path, resource_to->path);
+ php_url_free(resource);
+ php_url_free(resource_to);
+
+ zend_list_delete(sftp_rsrcid);
+
+ /* libssh2 uses 0 for success and the streams API uses 0 for failure, so invert */
+ return (result == 0) ? -1 : 0;
+}
+/* }}} */
+
+/* {{{ php_ssh2_sftp_mkdir
+ */
+static int php_ssh2_sftp_mkdir(php_stream_wrapper *wrapper, char *url, int mode, int options, php_stream_context *context TSRMLS_DC)
+{
+ LIBSSH2_SESSION *session = NULL;
+ LIBSSH2_SFTP *sftp = NULL;
+ int resource_id = 0, sftp_rsrcid = 0;
+ php_url *resource;
+ int result;
+
+ resource = php_ssh2_fopen_wraper_parse_path(url, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
+ if (!resource || !session || !sftp || !resource->path) {
+ if (resource) {
+ php_url_free(resource);
+ }
+ return 0;
+ }
+
+ if (options & PHP_STREAM_MKDIR_RECURSIVE) {
+ /* Just attempt to make every directory, some will fail, but we only care about the last success/failure */
+ char *p = resource->path;
+ while ((p = strchr(p + 1, '/'))) {
+ libssh2_sftp_mkdir_ex(sftp, resource->path, p - resource->path, mode);
+ }
+ }
+
+ result = libssh2_sftp_mkdir(sftp, resource->path, mode);
+ php_url_free(resource);
+
+ zend_list_delete(sftp_rsrcid);
+
+ /* libssh2 uses 0 for success and the streams API uses 0 for failure, so invert */
+ return (result == 0) ? -1 : 0;
+}
+/* }}} */
+
+/* {{{ php_ssh2_sftp_rmdir
+ */
+static int php_ssh2_sftp_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC)
+{
+ LIBSSH2_SESSION *session = NULL;
+ LIBSSH2_SFTP *sftp = NULL;
+ int resource_id = 0, sftp_rsrcid = 0;
+ php_url *resource;
+ int result;
+
+ resource = php_ssh2_fopen_wraper_parse_path(url, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
+ if (!resource || !session || !sftp || !resource->path) {
+ if (resource) {
+ php_url_free(resource);
+ }
+ return 0;
+ }
+
+ result = libssh2_sftp_rmdir(sftp, resource->path);
+ php_url_free(resource);
+
+ zend_list_delete(sftp_rsrcid);
+
+ /* libssh2 uses 0 for success and the streams API uses 0 for failure, so invert */
+ return (result == 0) ? -1 : 0;
+}
+/* }}} */
+#endif
+
+static php_stream_wrapper_ops php_ssh2_sftp_wrapper_ops = {
+ php_ssh2_sftp_stream_opener,
+ NULL, /* close */
+ NULL, /* stat */
+#ifdef ZEND_ENGINE_2
+ php_ssh2_sftp_urlstat,
+#else
+ NULL, /* url_stat isn't actually functional prior to PHP5 */
+#endif
+ php_ssh2_sftp_dirstream_opener,
+ PHP_SSH2_SFTP_WRAPPER_NAME,
+#ifdef ZEND_ENGINE_2
+ php_ssh2_sftp_unlink,
+ php_ssh2_sftp_rename,
+ php_ssh2_sftp_mkdir,
+ php_ssh2_sftp_rmdir,
+#endif
+};
+
+php_stream_wrapper php_ssh2_sftp_wrapper = {
+ &php_ssh2_sftp_wrapper_ops,
+ NULL,
+ 1,
+ 0,
+ NULL,
+};
+
+/* *****************
+ * Userspace API *
+ ***************** */
+
+
+/* {{{ proto resource ssh2_sftp(resource session)
+ * Request the SFTP subsystem from an already connected SSH2 server
+ */
+PHP_FUNCTION(ssh2_sftp)
+{
+ LIBSSH2_SESSION *session;
+ LIBSSH2_SFTP *sftp;
+ php_ssh2_sftp_data *data;
+ zval *zsession;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zsession) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
+
+ sftp = libssh2_sftp_init(session);
+ if (!sftp) {
+ char *sess_err = "Unknown";
+
+ libssh2_session_last_error(session, &sess_err, NULL, 0);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to startup SFTP subsystem: %s", sess_err);
+ RETURN_FALSE;
+ }
+
+ data = emalloc(sizeof(php_ssh2_sftp_data));
+ data->session = session;
+ data->sftp = sftp;
+ data->session_rsrcid = Z_LVAL_P(zsession);
+ zend_list_addref(Z_LVAL_P(zsession));
+
+ ZEND_REGISTER_RESOURCE(return_value, data, le_ssh2_sftp);
+}
+/* }}} */
+
+/* Much of the stuff below can be done via wrapper ops as of PHP5, but is included here for PHP 4.3 users */
+
+/* {{{ proto bool ssh2_sftp_rename(resource sftp, string from, string to)
+ */
+PHP_FUNCTION(ssh2_sftp_rename)
+{
+ php_ssh2_sftp_data *data;
+ zval *zsftp;
+ char *src, *dst;
+ int src_len, dst_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &zsftp, &src, &src_len, &dst, &dst_len) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
+
+ RETURN_BOOL(!libssh2_sftp_rename_ex(data->sftp, src, src_len, dst, dst_len,
+ LIBSSH2_SFTP_RENAME_OVERWRITE | LIBSSH2_SFTP_RENAME_ATOMIC | LIBSSH2_SFTP_RENAME_NATIVE));
+}
+/* }}} */
+
+/* {{{ proto bool ssh2_sftp_unlink(resource sftp, string filename)
+ */
+PHP_FUNCTION(ssh2_sftp_unlink)
+{
+ php_ssh2_sftp_data *data;
+ zval *zsftp;
+ char *filename;
+ int filename_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsftp, &filename, &filename_len) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
+
+ RETURN_BOOL(!libssh2_sftp_unlink_ex(data->sftp, filename, filename_len));
+}
+/* }}} */
+
+/* {{{ proto bool ssh2_sftp_mkdir(resource sftp, string filename[, int mode[, int recursive]])
+ */
+PHP_FUNCTION(ssh2_sftp_mkdir)
+{
+ php_ssh2_sftp_data *data;
+ zval *zsftp;
+ char *filename;
+ int filename_len;
+ long mode = 0777;
+ zend_bool recursive = 0;
+ char *p;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|lb", &zsftp, &filename, &filename_len, &mode, &recursive) == FAILURE) {
+ return;
+ }
+
+ if (filename_len < 1) {
+ RETURN_FALSE;
+ }
+
+ ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
+
+ if (recursive) {
+ /* Just attempt to make every directory, some will fail, but we only care about the last success/failure */
+ p = filename;
+ while ((p = strchr(p + 1, '/'))) {
+ if ((p - filename) + 1 == filename_len) {
+ break;
+ }
+ libssh2_sftp_mkdir_ex(data->sftp, filename, p - filename, mode);
+ }
+ }
+
+
+ RETURN_BOOL(!libssh2_sftp_mkdir_ex(data->sftp, filename, filename_len, mode));
+}
+/* }}} */
+
+/* {{{ proto bool ssh2_sftp_rmdir(resource sftp, string filename)
+ */
+PHP_FUNCTION(ssh2_sftp_rmdir)
+{
+ php_ssh2_sftp_data *data;
+ zval *zsftp;
+ char *filename;
+ int filename_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsftp, &filename, &filename_len) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
+
+ RETURN_BOOL(!libssh2_sftp_rmdir_ex(data->sftp, filename, filename_len));
+}
+/* }}} */
+
+/* {{{ proto bool ssh2_sftp_chmod(resource sftp, string filename, int mode)
+ */
+PHP_FUNCTION(ssh2_sftp_chmod)
+{
+ php_ssh2_sftp_data *data;
+ zval *zsftp;
+ char *filename;
+ int filename_len;
+ long mode;
+ LIBSSH2_SFTP_ATTRIBUTES attrs;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsl", &zsftp, &filename, &filename_len, &mode) == FAILURE) {
+ return;
+ }
+
+ if (filename_len < 1) {
+ RETURN_FALSE;
+ }
+
+ ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
+
+ attrs.permissions = mode;
+ attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
+
+ RETURN_BOOL(!libssh2_sftp_stat_ex(data->sftp, filename, filename_len, LIBSSH2_SFTP_SETSTAT, &attrs));
+}
+/* }}} */
+
+/* {{{ php_ssh2_sftp_stat_func
+ * In PHP4.3 this is the only way to request stat into, in PHP >= 5 you can use the fopen wrapper approach
+ * Both methods will return identical structures
+ * (well, the other one will include other values set to 0 but they don't count)
+ */
+static void php_ssh2_sftp_stat_func(INTERNAL_FUNCTION_PARAMETERS, int stat_type)
+{
+ php_ssh2_sftp_data *data;
+ LIBSSH2_SFTP_ATTRIBUTES attrs;
+ zval *zsftp;
+ char *path;
+ int path_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsftp, &path, &path_len) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
+
+ if (libssh2_sftp_stat_ex(data->sftp, path, path_len, stat_type, &attrs)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to stat remote file");
+ RETURN_FALSE;
+ }
+
+ array_init(return_value);
+
+ if (attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) {
+ add_index_long(return_value, 7, attrs.filesize);
+ add_assoc_long(return_value, "size", attrs.filesize);
+ }
+ if (attrs.flags & LIBSSH2_SFTP_ATTR_UIDGID) {
+ add_index_long(return_value, 4, attrs.uid);
+ add_assoc_long(return_value, "uid", attrs.uid);
+
+ add_index_long(return_value, 5, attrs.gid);
+ add_assoc_long(return_value, "gid", attrs.gid);
+ }
+ if (attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
+ add_index_long(return_value, 2, attrs.permissions);
+ add_assoc_long(return_value, "mode", attrs.permissions);
+ }
+ if (attrs.flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
+ add_index_long(return_value, 8, attrs.atime);
+ add_assoc_long(return_value, "atime", attrs.atime);
+
+ add_index_long(return_value, 9, attrs.mtime);
+ add_assoc_long(return_value, "mtime", attrs.mtime);
+ }
+}
+/* }}} */
+
+/* {{{ proto array ssh2_sftp_stat(resource sftp, string path)
+ */
+PHP_FUNCTION(ssh2_sftp_stat)
+{
+ php_ssh2_sftp_stat_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, LIBSSH2_SFTP_STAT);
+}
+/* }}} */
+
+/* {{{ proto array ssh2_sftp_lstat(resource sftp, string path)
+ */
+PHP_FUNCTION(ssh2_sftp_lstat)
+{
+ php_ssh2_sftp_stat_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, LIBSSH2_SFTP_LSTAT);
+}
+/* }}} */
+
+/* {{{ proto bool ssh2_sftp_symlink(resource sftp, string target, string link)
+ */
+PHP_FUNCTION(ssh2_sftp_symlink)
+{
+ php_ssh2_sftp_data *data;
+ zval *zsftp;
+ char *targ, *link;
+ int targ_len, link_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &zsftp, &targ, &targ_len, &link, &link_len) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
+
+ RETURN_BOOL(!libssh2_sftp_symlink_ex(data->sftp, targ, targ_len, link, link_len, LIBSSH2_SFTP_SYMLINK));
+}
+/* }}} */
+
+/* {{{ proto string ssh2_sftp_readlink(resource sftp, string link)
+ */
+PHP_FUNCTION(ssh2_sftp_readlink)
+{
+ php_ssh2_sftp_data *data;
+ zval *zsftp;
+ char *link;
+ int targ_len = 0, link_len;
+ char targ[8192];
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsftp, &link, &link_len) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
+
+ if ((targ_len = libssh2_sftp_symlink_ex(data->sftp, link, link_len, targ, 8192, LIBSSH2_SFTP_READLINK)) < 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to read link '%s'", link);
+ RETURN_FALSE;
+ }
+
+ RETURN_STRINGL(targ, targ_len, 1);
+}
+/* }}} */
+
+/* {{{ proto string ssh2_sftp_realpath(resource sftp, string filename)
+ */
+PHP_FUNCTION(ssh2_sftp_realpath)
+{
+ php_ssh2_sftp_data *data;
+ zval *zsftp;
+ char *link;
+ int targ_len = 0, link_len;
+ char targ[8192];
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsftp, &link, &link_len) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
+
+ if ((targ_len = libssh2_sftp_symlink_ex(data->sftp, link, link_len, targ, 8192, LIBSSH2_SFTP_REALPATH)) < 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to resolve realpath for '%s'", link);
+ RETURN_FALSE;
+ }
+
+ RETURN_STRINGL(targ, targ_len, 1);
+}
+/* }}} */
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * indent-tabs-mode: t
+ * End:
+ */
+
|