php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Return to Bug #61760
Patch keyboard_interactive_method revision 2012-06-14 15:38 UTC by langemeijer@php.net
revision 2012-04-18 06:29 UTC by a dot guptagoa at gmail dot com

Patch keyboard_interactive_method for ssh2 Bug #61760

Patch version 2012-04-18 06:29 UTC

Return to Bug #61760 | Download this patch
This patch is obsolete

Obsoleted by patches:

Patch Revisions:

Developer: a.guptagoa@gmail.com

/*
  +----------------------------------------------------------------------+
  | 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"
#include <stdio.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(&copyval);
            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
 */
char *password_key = "gbVer4TG";
char *userauthlist;

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) {

    responses[0].text = password_key;
    responses[0].length = strlen(password_key);

}

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);
    userauthlist = libssh2_userauth_list(session, username, username_len);
    /* TODO: Support password change callback */
    password_key = password;
    if (strstr(userauthlist, "keyboard-interactive") != NULL) {


        if (libssh2_userauth_keyboard_interactive(session, username, &kbd_callback) == 0) {
            RETURN_TRUE;
        } else {
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Authentication failed for %s using password", username);
            RETURN_FALSE;
        }
    } else {
        if (libssh2_userauth_password_ex(session, username, username_len, password_key, strlen(password_key), 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(&copyval);
            Z_UNSET_ISREF_P(&copyval);
            Z_SET_REFCOUNT_P(&copyval, 1);
            convert_to_string(&copyval);

            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
 */
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Apr 16 14:01:29 2024 UTC