Changes of Revision 10
[-] | Added | php5-ssh2.changes |
1
2 +------------------------------------------------------------------- 3 +Sun Feb 17 12:28:09 UTC 2013 - cs@linux-administrator.com 4 + 5 +- update to 0.12 6 + 7 |
||
[-] | Changed | php5-ssh2.spec ^ |
14 1
2 # norootforbuild 3 %define pkg_name ssh2 4 -%define pkg_version 0.11.3 5 +%define pkg_version 0.12 6 %define php_version %(php-config --version 2>/dev/null || echo PHPCONFIG_NOT_FOUND) 7 # 8 Name: php5-ssh2 9 -Version: 0.11.3 10 +Version: 0.12 11 Release: 0 12 # 13 License: PHP 14 |
||
[+] | 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: + */ + |