PageRenderTime 55ms CodeModel.GetById 9ms RepoModel.GetById 1ms app.codeStats 0ms

/php-pecl-ssh2-0.11.3/ssh2-0.11.3/ssh2.c

#
C | 1343 lines | 959 code | 201 blank | 183 comment | 190 complexity | d9800f20e0598cbd97f736df5ed4e2ba MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 4 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2006 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 2.02 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available at through the world-wide-web at |
  10. | http://www.php.net/license/2_02.txt. |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Author: Sara Golemon <pollita@php.net> |
  16. +----------------------------------------------------------------------+
  17. $Id: ssh2.c 317115 2011-09-21 17:40:23Z bjori $
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. #include "config.h"
  21. #endif
  22. #include "php.h"
  23. #include "ext/standard/info.h"
  24. #include "ext/standard/file.h"
  25. #include "php_ssh2.h"
  26. #include "main/php_network.h"
  27. #if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
  28. #include <openssl/applink.c>
  29. #endif
  30. /* Internal Constants */
  31. #ifndef SHA_DIGEST_LENGTH
  32. #define SHA_DIGEST_LENGTH 20
  33. #endif
  34. #ifndef MD5_DIGEST_LENGTH
  35. #define MD5_DIGEST_LENGTH 16
  36. #endif
  37. /* True global resources - no need for thread safety here */
  38. int le_ssh2_session;
  39. #ifdef PHP_SSH2_REMOTE_FORWARDING
  40. int le_ssh2_listener;
  41. #endif
  42. int le_ssh2_sftp;
  43. #ifdef PHP_SSH2_PUBLICKEY_SUBSYSTEM
  44. int le_ssh2_pkey_subsys;
  45. #endif
  46. ZEND_BEGIN_ARG_INFO(php_ssh2_first_arg_force_ref, 0)
  47. ZEND_ARG_PASS_INFO(1)
  48. ZEND_END_ARG_INFO()
  49. /* *************
  50. * Callbacks *
  51. ************* */
  52. #ifdef ZTS
  53. #define PHP_SSH2_TSRMLS_FETCH() TSRMLS_D = *(void****)abstract;
  54. #else
  55. #define PHP_SSH2_TSRMLS_FETCH()
  56. #endif
  57. /* {{{ php_ssh2_alloc_cb
  58. * Wrap emalloc()
  59. */
  60. static LIBSSH2_ALLOC_FUNC(php_ssh2_alloc_cb)
  61. {
  62. return emalloc(count);
  63. }
  64. /* }}} */
  65. /* {{{ php_ssh2_free_cb
  66. * Wrap efree()
  67. */
  68. static LIBSSH2_FREE_FUNC(php_ssh2_free_cb)
  69. {
  70. efree(ptr);
  71. }
  72. /* }}} */
  73. /* {{{ php_ssh2_realloc_cb
  74. * Wrap erealloc()
  75. */
  76. static LIBSSH2_REALLOC_FUNC(php_ssh2_realloc_cb)
  77. {
  78. return erealloc(ptr, count);
  79. }
  80. /* }}} */
  81. /* {{{ php_ssh2_debug_cb
  82. * Debug packets
  83. */
  84. LIBSSH2_DEBUG_FUNC(php_ssh2_debug_cb)
  85. {
  86. php_ssh2_session_data *data;
  87. zval *zdisplay, *zmessage, *zlanguage;
  88. zval **args[3];
  89. SSH2_TSRMLS_FETCH(*abstract);
  90. if (!abstract || !*abstract) {
  91. return;
  92. }
  93. data = (php_ssh2_session_data*)*abstract;
  94. if (!data->debug_cb) {
  95. return;
  96. }
  97. MAKE_STD_ZVAL(zmessage);
  98. ZVAL_STRINGL(zmessage, (char*)message, message_len, 1);
  99. args[0] = &zmessage;
  100. MAKE_STD_ZVAL(zlanguage);
  101. ZVAL_STRINGL(zlanguage, (char*)language, language_len, 1);
  102. args[1] = &zlanguage;
  103. MAKE_STD_ZVAL(zdisplay);
  104. ZVAL_LONG(zdisplay, always_display);
  105. args[2] = &zdisplay;
  106. if (FAILURE == call_user_function_ex(NULL, NULL, data->disconnect_cb, NULL, 3, args, 0, NULL TSRMLS_CC)) {
  107. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure calling disconnect callback");
  108. }
  109. zval_ptr_dtor(&zdisplay);
  110. zval_ptr_dtor(&zmessage);
  111. zval_ptr_dtor(&zlanguage);
  112. }
  113. /* }}} */
  114. /* {{{ php_ssh2_ignore_cb
  115. * Ignore packets
  116. */
  117. LIBSSH2_IGNORE_FUNC(php_ssh2_ignore_cb)
  118. {
  119. php_ssh2_session_data *data;
  120. zval *zretval = NULL, *zmessage;
  121. zval **args[1];
  122. SSH2_TSRMLS_FETCH(*abstract);
  123. if (!abstract || !*abstract) {
  124. return;
  125. }
  126. data = (php_ssh2_session_data*)*abstract;
  127. if (!data->ignore_cb) {
  128. return;
  129. }
  130. MAKE_STD_ZVAL(zmessage);
  131. ZVAL_STRINGL(zmessage, (char*)message, message_len, 1);
  132. args[0] = &zmessage;
  133. if (FAILURE == call_user_function_ex(NULL, NULL, data->ignore_cb, &zretval, 1, args, 0, NULL TSRMLS_CC)) {
  134. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure calling ignore callback");
  135. }
  136. zval_ptr_dtor(&zmessage);
  137. if (zretval) {
  138. zval_ptr_dtor(&zretval);
  139. }
  140. }
  141. /* }}} */
  142. /* {{{ php_ssh2_macerror_cb
  143. * Called when a MAC error occurs, offers the chance to ignore
  144. * WHY ARE YOU IGNORING MAC ERRORS??????
  145. */
  146. LIBSSH2_MACERROR_FUNC(php_ssh2_macerror_cb)
  147. {
  148. php_ssh2_session_data *data;
  149. zval *zretval = NULL, *zpacket;
  150. zval **args[1];
  151. int retval = -1;
  152. SSH2_TSRMLS_FETCH(*abstract);
  153. if (!abstract || !*abstract) {
  154. return -1;
  155. }
  156. data = (php_ssh2_session_data*)*abstract;
  157. if (!data->macerror_cb) {
  158. return -1;
  159. }
  160. MAKE_STD_ZVAL(zpacket);
  161. ZVAL_STRINGL(zpacket, (char*)packet, packet_len, 1);
  162. args[0] = &zpacket;
  163. if (FAILURE == call_user_function_ex(NULL, NULL, data->macerror_cb, &zretval, 1, args, 0, NULL TSRMLS_CC)) {
  164. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure calling macerror callback");
  165. } else {
  166. retval = zval_is_true(zretval) ? 0 : -1;
  167. }
  168. zval_ptr_dtor(&zpacket);
  169. if (zretval) {
  170. zval_ptr_dtor(&zretval);
  171. }
  172. return retval;
  173. }
  174. /* }}} */
  175. /* {{{ php_ssh2_disconnect_cb
  176. * Connection closed by foreign host
  177. */
  178. LIBSSH2_DISCONNECT_FUNC(php_ssh2_disconnect_cb)
  179. {
  180. php_ssh2_session_data *data;
  181. zval *zreason, *zmessage, *zlanguage;
  182. zval **args[3];
  183. SSH2_TSRMLS_FETCH(*abstract);
  184. if (!abstract || !*abstract) {
  185. return;
  186. }
  187. data = (php_ssh2_session_data*)*abstract;
  188. if (!data->disconnect_cb) {
  189. return;
  190. }
  191. MAKE_STD_ZVAL(zreason);
  192. ZVAL_LONG(zreason, reason);
  193. args[0] = &zreason;
  194. MAKE_STD_ZVAL(zmessage);
  195. ZVAL_STRINGL(zmessage, (char*)message, message_len, 1);
  196. args[1] = &zmessage;
  197. MAKE_STD_ZVAL(zlanguage);
  198. ZVAL_STRINGL(zlanguage, (char*)language, language_len, 1);
  199. args[2] = &zlanguage;
  200. if (FAILURE == call_user_function_ex(NULL, NULL, data->disconnect_cb, NULL, 3, args, 0, NULL TSRMLS_CC)) {
  201. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure calling disconnect callback");
  202. }
  203. zval_ptr_dtor(&zreason);
  204. zval_ptr_dtor(&zmessage);
  205. zval_ptr_dtor(&zlanguage);
  206. }
  207. /* }}} */
  208. /* *****************
  209. * Userspace API *
  210. ***************** */
  211. /* {{{ php_ssh2_set_callback
  212. * Try to set a method if it's passed in with the hash table
  213. */
  214. 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)
  215. {
  216. zval **handler, *copyval;
  217. void *internal_handler;
  218. if (zend_hash_find(ht, callback, callback_len + 1, (void**)&handler) == FAILURE) {
  219. return 0;
  220. }
  221. if (!handler || !*handler || !zend_is_callable(*handler, 0, NULL ZEND_IS_CALLABLE_TSRMLS_CC)) {
  222. return -1;
  223. }
  224. ALLOC_INIT_ZVAL(copyval);
  225. *copyval = **handler;
  226. zval_copy_ctor(copyval);
  227. switch (callback_type) {
  228. case LIBSSH2_CALLBACK_IGNORE:
  229. internal_handler = php_ssh2_ignore_cb;
  230. if (data->ignore_cb) {
  231. zval_ptr_dtor(&data->ignore_cb);
  232. }
  233. data->ignore_cb = copyval;
  234. break;
  235. case LIBSSH2_CALLBACK_DEBUG:
  236. internal_handler = php_ssh2_debug_cb;
  237. if (data->debug_cb) {
  238. zval_ptr_dtor(&data->debug_cb);
  239. }
  240. data->debug_cb = copyval;
  241. break;
  242. case LIBSSH2_CALLBACK_MACERROR:
  243. internal_handler = php_ssh2_macerror_cb;
  244. if (data->macerror_cb) {
  245. zval_ptr_dtor(&data->macerror_cb);
  246. }
  247. data->macerror_cb = copyval;
  248. break;
  249. case LIBSSH2_CALLBACK_DISCONNECT:
  250. internal_handler = php_ssh2_disconnect_cb;
  251. if (data->disconnect_cb) {
  252. zval_ptr_dtor(&data->disconnect_cb);
  253. }
  254. data->disconnect_cb = copyval;
  255. break;
  256. default:
  257. zval_ptr_dtor(&copyval);
  258. return -1;
  259. }
  260. libssh2_session_callback_set(session, callback_type, internal_handler);
  261. return 0;
  262. }
  263. /* }}} */
  264. /* {{{ php_ssh2_set_method
  265. * Try to set a method if it's passed in with the hash table
  266. */
  267. static int php_ssh2_set_method(LIBSSH2_SESSION *session, HashTable *ht, char *method, int method_len, int method_type)
  268. {
  269. zval **value;
  270. if (zend_hash_find(ht, method, method_len + 1, (void**)&value) == FAILURE) {
  271. return 0;
  272. }
  273. if (!value || !*value || (Z_TYPE_PP(value) != IS_STRING)) {
  274. return -1;
  275. }
  276. return libssh2_session_method_pref(session, method_type, Z_STRVAL_PP(value));
  277. }
  278. /* }}} */
  279. /* {{{ php_ssh2_session_connect
  280. * Connect to an SSH server with requested methods
  281. */
  282. LIBSSH2_SESSION *php_ssh2_session_connect(char *host, int port, zval *methods, zval *callbacks TSRMLS_DC)
  283. {
  284. LIBSSH2_SESSION *session;
  285. int socket;
  286. php_ssh2_session_data *data;
  287. struct timeval tv;
  288. tv.tv_sec = FG(default_socket_timeout);
  289. tv.tv_usec = 0;
  290. #if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 0)
  291. socket = php_network_connect_socket_to_host(host, port, SOCK_STREAM, 0, &tv, NULL, NULL, NULL, 0 TSRMLS_CC);
  292. #elif PHP_MAJOR_VERSION == 5
  293. socket = php_network_connect_socket_to_host(host, port, SOCK_STREAM, 0, &tv, NULL, NULL TSRMLS_CC);
  294. #else
  295. socket = php_hostconnect(host, port, SOCK_STREAM, &tv TSRMLS_CC);
  296. #endif
  297. if (socket <= 0) {
  298. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to %s on port %d", host, port);
  299. return NULL;
  300. }
  301. data = ecalloc(1, sizeof(php_ssh2_session_data));
  302. SSH2_TSRMLS_SET(data);
  303. data->socket = socket;
  304. session = libssh2_session_init_ex(php_ssh2_alloc_cb, php_ssh2_free_cb, php_ssh2_realloc_cb, data);
  305. if (!session) {
  306. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to initialize SSH2 session");
  307. efree(data);
  308. closesocket(socket);
  309. return NULL;
  310. }
  311. libssh2_banner_set(session, LIBSSH2_SSH_DEFAULT_BANNER " PHP");
  312. /* Override method preferences */
  313. if (methods) {
  314. zval **container;
  315. if (php_ssh2_set_method(session, HASH_OF(methods), "kex", sizeof("kex") - 1, LIBSSH2_METHOD_KEX)) {
  316. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding KEX method");
  317. }
  318. if (php_ssh2_set_method(session, HASH_OF(methods), "hostkey", sizeof("hostkey") - 1, LIBSSH2_METHOD_HOSTKEY)) {
  319. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding HOSTKEY method");
  320. }
  321. if (zend_hash_find(HASH_OF(methods), "client_to_server", sizeof("client_to_server"), (void**)&container) == SUCCESS &&
  322. container && *container && Z_TYPE_PP(container) == IS_ARRAY) {
  323. if (php_ssh2_set_method(session, HASH_OF(*container), "crypt", sizeof("crypt") - 1, LIBSSH2_METHOD_CRYPT_CS)) {
  324. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding client to server CRYPT method");
  325. }
  326. if (php_ssh2_set_method(session, HASH_OF(*container), "mac", sizeof("mac") - 1, LIBSSH2_METHOD_MAC_CS)) {
  327. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding client to server MAC method");
  328. }
  329. if (php_ssh2_set_method(session, HASH_OF(*container), "comp", sizeof("comp") - 1, LIBSSH2_METHOD_COMP_CS)) {
  330. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding client to server COMP method");
  331. }
  332. if (php_ssh2_set_method(session, HASH_OF(*container), "lang", sizeof("lang") - 1, LIBSSH2_METHOD_LANG_CS)) {
  333. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding client to server LANG method");
  334. }
  335. }
  336. if (zend_hash_find(HASH_OF(methods), "server_to_client", sizeof("server_to_client"), (void**)&container) == SUCCESS &&
  337. container && *container && Z_TYPE_PP(container) == IS_ARRAY) {
  338. if (php_ssh2_set_method(session, HASH_OF(*container), "crypt", sizeof("crypt") - 1, LIBSSH2_METHOD_CRYPT_SC)) {
  339. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding server to client CRYPT method");
  340. }
  341. if (php_ssh2_set_method(session, HASH_OF(*container), "mac", sizeof("mac") - 1, LIBSSH2_METHOD_MAC_SC)) {
  342. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding server to client MAC method");
  343. }
  344. if (php_ssh2_set_method(session, HASH_OF(*container), "comp", sizeof("comp") - 1, LIBSSH2_METHOD_COMP_SC)) {
  345. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding server to client COMP method");
  346. }
  347. if (php_ssh2_set_method(session, HASH_OF(*container), "lang", sizeof("lang") - 1, LIBSSH2_METHOD_LANG_SC)) {
  348. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed overriding server to client LANG method");
  349. }
  350. }
  351. }
  352. /* Register Callbacks */
  353. if (callbacks) {
  354. /* ignore debug disconnect macerror */
  355. if (php_ssh2_set_callback(session, HASH_OF(callbacks), "ignore", sizeof("ignore") - 1, LIBSSH2_CALLBACK_IGNORE, data TSRMLS_CC)) {
  356. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting IGNORE callback");
  357. }
  358. if (php_ssh2_set_callback(session, HASH_OF(callbacks), "debug", sizeof("debug") - 1, LIBSSH2_CALLBACK_DEBUG, data TSRMLS_CC)) {
  359. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting DEBUG callback");
  360. }
  361. if (php_ssh2_set_callback(session, HASH_OF(callbacks), "macerror", sizeof("macerror") - 1, LIBSSH2_CALLBACK_MACERROR, data TSRMLS_CC)) {
  362. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting MACERROR callback");
  363. }
  364. if (php_ssh2_set_callback(session, HASH_OF(callbacks), "disconnect", sizeof("disconnect") - 1, LIBSSH2_CALLBACK_DISCONNECT, data TSRMLS_CC)) {
  365. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting DISCONNECT callback");
  366. }
  367. }
  368. if (libssh2_session_startup(session, socket)) {
  369. int last_error = 0;
  370. char *error_msg = NULL;
  371. last_error = libssh2_session_last_error(session, &error_msg, NULL, 0);
  372. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error starting up SSH connection(%d): %s", last_error, error_msg);
  373. closesocket(socket);
  374. libssh2_session_free(session);
  375. efree(data);
  376. return NULL;
  377. }
  378. return session;
  379. }
  380. /* }}} */
  381. /* {{{ proto resource ssh2_connect(string host[, int port[, array methods[, array callbacks]]])
  382. * Establish a connection to a remote SSH server and return a resource on success, false on error
  383. */
  384. PHP_FUNCTION(ssh2_connect)
  385. {
  386. LIBSSH2_SESSION *session;
  387. zval *methods = NULL, *callbacks = NULL;
  388. char *host;
  389. long port = PHP_SSH2_DEFAULT_PORT;
  390. int host_len;
  391. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|la!a!", &host, &host_len, &port, &methods, &callbacks) == FAILURE) {
  392. RETURN_FALSE;
  393. }
  394. session = php_ssh2_session_connect(host, port, methods, callbacks TSRMLS_CC);
  395. if (!session) {
  396. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to %s", host);
  397. RETURN_FALSE;
  398. }
  399. ZEND_REGISTER_RESOURCE(return_value, session, le_ssh2_session);
  400. }
  401. /* }}} */
  402. /* {{{ proto array ssh2_methods_negotiated(resource session)
  403. * Return list of negotiaed methods
  404. */
  405. PHP_FUNCTION(ssh2_methods_negotiated)
  406. {
  407. LIBSSH2_SESSION *session;
  408. zval *zsession, *endpoint;
  409. char *kex, *hostkey, *crypt_cs, *crypt_sc, *mac_cs, *mac_sc, *comp_cs, *comp_sc, *lang_cs, *lang_sc;
  410. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zsession) == FAILURE) {
  411. RETURN_FALSE;
  412. }
  413. ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
  414. #if defined(LIBSSH2_APINO) && LIBSSH2_APINO < 200412301450
  415. libssh2_session_methods(session, &kex, &hostkey, &crypt_cs, &crypt_sc, &mac_cs, &mac_sc, &comp_cs, &comp_sc, &lang_cs, &lang_sc);
  416. #else
  417. kex = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_KEX);
  418. hostkey = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_HOSTKEY);
  419. crypt_cs = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_CRYPT_CS);
  420. crypt_sc = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_CRYPT_SC);
  421. mac_cs = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_MAC_CS);
  422. mac_sc = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_MAC_SC);
  423. comp_cs = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_COMP_CS);
  424. comp_sc = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_COMP_SC);
  425. lang_cs = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_LANG_CS);
  426. lang_sc = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_LANG_SC);
  427. #endif
  428. array_init(return_value);
  429. add_assoc_string(return_value, "kex", kex, 1);
  430. add_assoc_string(return_value, "hostkey", hostkey, 1);
  431. ALLOC_INIT_ZVAL(endpoint);
  432. array_init(endpoint);
  433. add_assoc_string(endpoint, "crypt", crypt_cs, 1);
  434. add_assoc_string(endpoint, "mac", mac_cs, 1);
  435. add_assoc_string(endpoint, "comp", comp_cs, 1);
  436. add_assoc_string(endpoint, "lang", lang_cs, 1);
  437. add_assoc_zval(return_value, "client_to_server", endpoint);
  438. ALLOC_INIT_ZVAL(endpoint);
  439. array_init(endpoint);
  440. add_assoc_string(endpoint, "crypt", crypt_sc, 1);
  441. add_assoc_string(endpoint, "mac", mac_sc, 1);
  442. add_assoc_string(endpoint, "comp", comp_sc, 1);
  443. add_assoc_string(endpoint, "lang", lang_sc, 1);
  444. add_assoc_zval(return_value, "server_to_client", endpoint);
  445. }
  446. /* }}} */
  447. /* {{{ proto string ssh2_fingerprint(resource session[, int flags])
  448. * Returns a server hostkey hash from an active session
  449. * Defaults to MD5 fingerprint encoded as ASCII hex values
  450. */
  451. PHP_FUNCTION(ssh2_fingerprint)
  452. {
  453. LIBSSH2_SESSION *session;
  454. zval *zsession;
  455. const char *fingerprint;
  456. long flags = 0;
  457. int i, fingerprint_len;
  458. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zsession, &flags) == FAILURE) {
  459. RETURN_FALSE;
  460. }
  461. fingerprint_len = (flags & PHP_SSH2_FINGERPRINT_SHA1) ? SHA_DIGEST_LENGTH : MD5_DIGEST_LENGTH;
  462. ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
  463. fingerprint = (char*)libssh2_hostkey_hash(session, (flags & PHP_SSH2_FINGERPRINT_SHA1) ? LIBSSH2_HOSTKEY_HASH_SHA1 : LIBSSH2_HOSTKEY_HASH_MD5);
  464. if (!fingerprint) {
  465. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to retreive fingerprint from specified session");
  466. RETURN_FALSE;
  467. }
  468. for(i = 0; i < fingerprint_len; i++) {
  469. if (fingerprint[i] != '\0') {
  470. goto fingerprint_good;
  471. }
  472. }
  473. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No fingerprint available using specified hash");
  474. RETURN_NULL();
  475. fingerprint_good:
  476. if (flags & PHP_SSH2_FINGERPRINT_RAW) {
  477. RETURN_STRINGL(fingerprint, fingerprint_len, 1);
  478. } else {
  479. char *hexchars;
  480. hexchars = emalloc((fingerprint_len * 2) + 1);
  481. for(i = 0; i < fingerprint_len; i++) {
  482. snprintf(hexchars + (2 * i), 3, "%02X", (unsigned char)fingerprint[i]);
  483. }
  484. RETURN_STRINGL(hexchars, 2 * fingerprint_len, 0);
  485. }
  486. }
  487. /* }}} */
  488. /* {{{ proto array ssh2_auth_none(resource session, string username)
  489. * Attempt "none" authentication, returns a list of allowed methods on failed authentication,
  490. * false on utter failure, or true on success
  491. */
  492. PHP_FUNCTION(ssh2_auth_none)
  493. {
  494. LIBSSH2_SESSION *session;
  495. zval *zsession;
  496. char *username, *methods, *s, *p;
  497. int username_len;
  498. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsession, &username, &username_len) == FAILURE) {
  499. RETURN_FALSE;
  500. }
  501. ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
  502. s = methods = libssh2_userauth_list(session, username, username_len);
  503. if (!methods) {
  504. /* Either bad failure, or unexpected success */
  505. RETURN_BOOL(libssh2_userauth_authenticated(session));
  506. }
  507. array_init(return_value);
  508. while ((p = strchr(s, ','))) {
  509. if ((p - s) > 0) {
  510. add_next_index_stringl(return_value, s, p - s, 1);
  511. }
  512. s = p + 1;
  513. }
  514. if (strlen(s)) {
  515. add_next_index_string(return_value, s, 1);
  516. }
  517. }
  518. /* }}} */
  519. /* {{{ proto bool ssh2_auth_password(resource session, string username, string password)
  520. * Authenticate over SSH using a plain password
  521. */
  522. PHP_FUNCTION(ssh2_auth_password)
  523. {
  524. LIBSSH2_SESSION *session;
  525. zval *zsession;
  526. char *username, *password;
  527. int username_len, password_len;
  528. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &zsession, &username, &username_len, &password, &password_len) == FAILURE) {
  529. RETURN_FALSE;
  530. }
  531. ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
  532. /* TODO: Support password change callback */
  533. if (libssh2_userauth_password_ex(session, username, username_len, password, password_len, NULL)) {
  534. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Authentication failed for %s using password", username);
  535. RETURN_FALSE;
  536. }
  537. RETURN_TRUE;
  538. }
  539. /* }}} */
  540. /* {{{ proto bool ssh2_auth_pubkey_file(resource session, string username, string pubkeyfile, string privkeyfile[, string passphrase])
  541. * Authenticate using a public key
  542. */
  543. PHP_FUNCTION(ssh2_auth_pubkey_file)
  544. {
  545. LIBSSH2_SESSION *session;
  546. zval *zsession;
  547. char *username, *pubkey, *privkey, *passphrase = NULL;
  548. int username_len, pubkey_len, privkey_len, passphrase_len;
  549. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsss|s", &zsession, &username, &username_len,
  550. &pubkey, &pubkey_len,
  551. &privkey, &privkey_len,
  552. &passphrase, &passphrase_len) == FAILURE) {
  553. RETURN_FALSE;
  554. }
  555. if (SSH2_OPENBASEDIR_CHECKPATH(pubkey) || SSH2_OPENBASEDIR_CHECKPATH(privkey)) {
  556. RETURN_FALSE;
  557. }
  558. ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
  559. /* TODO: Support passphrase callback */
  560. if (libssh2_userauth_publickey_fromfile_ex(session, username, username_len, pubkey, privkey, passphrase)) {
  561. char *buf;
  562. int len;
  563. libssh2_session_last_error(session, &buf, &len, 0);
  564. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Authentication failed for %s using public key: %s", username, buf);
  565. RETURN_FALSE;
  566. }
  567. RETURN_TRUE;
  568. }
  569. /* }}} */
  570. #ifdef PHP_SSH2_HOSTBASED_AUTH
  571. /* {{{ proto bool ssh2_auth_hostbased_file(resource session, string username, string local_hostname, string pubkeyfile, string privkeyfile[, string passphrase[, string local_username]])
  572. * Authenticate using a hostkey
  573. */
  574. PHP_FUNCTION(ssh2_auth_hostbased_file)
  575. {
  576. LIBSSH2_SESSION *session;
  577. zval *zsession;
  578. char *username, *hostname, *pubkey, *privkey, *passphrase = NULL, *local_username = NULL;
  579. int username_len, hostname_len, pubkey_len, privkey_len, passphrase_len, local_username_len;
  580. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rssss|s!s!", &zsession, &username, &username_len,
  581. &hostname, &hostname_len,
  582. &pubkey, &pubkey_len,
  583. &privkey, &privkey_len,
  584. &passphrase, &passphrase_len,
  585. &local_username, &local_username_len) == FAILURE) {
  586. RETURN_FALSE;
  587. }
  588. if (SSH2_OPENBASEDIR_CHECKPATH(pubkey) || SSH2_OPENBASEDIR_CHECKPATH(privkey)) {
  589. RETURN_FALSE;
  590. }
  591. ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
  592. if (!local_username) {
  593. local_username = username;
  594. local_username_len = username_len;
  595. }
  596. /* TODO: Support passphrase callback */
  597. if (libssh2_userauth_hostbased_fromfile_ex(session, username, username_len, pubkey, privkey, passphrase, hostname, hostname_len, local_username, local_username_len)) {
  598. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Authentication failed for %s using hostbased public key", username);
  599. RETURN_FALSE;
  600. }
  601. RETURN_TRUE;
  602. }
  603. /* }}} */
  604. #endif /* PHP_SSH2_HOSTBASED_AUTH */
  605. #ifdef PHP_SSH2_REMOTE_FORWARDING
  606. /* {{{ proto resource ssh2_forward_listen(resource session, int port[, string host[, long max_connections]])
  607. * Bind a port on the remote server and listen for connections
  608. */
  609. PHP_FUNCTION(ssh2_forward_listen)
  610. {
  611. zval *zsession;
  612. LIBSSH2_SESSION *session;
  613. LIBSSH2_LISTENER *listener;
  614. php_ssh2_listener_data *data;
  615. long port;
  616. char *host = NULL;
  617. int host_len;
  618. long max_connections = PHP_SSH2_LISTEN_MAX_QUEUED;
  619. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|sl", &zsession, &port, &host, &host_len, &max_connections) == FAILURE) {
  620. RETURN_FALSE;
  621. }
  622. ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
  623. listener = libssh2_channel_forward_listen_ex(session, host, port, NULL, max_connections);
  624. if (!listener) {
  625. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure listening on remote port");
  626. RETURN_FALSE;
  627. }
  628. data = emalloc(sizeof(php_ssh2_listener_data));
  629. data->session = session;
  630. data->session_rsrcid = Z_LVAL_P(zsession);
  631. zend_list_addref(data->session_rsrcid);
  632. data->listener = listener;
  633. ZEND_REGISTER_RESOURCE(return_value, data, le_ssh2_listener);
  634. }
  635. /* }}} */
  636. /* {{{ proto stream ssh2_forward_accept(resource listener[, string &shost[, long &sport]])
  637. * Accept a connection created by a listener
  638. */
  639. PHP_FUNCTION(ssh2_forward_accept)
  640. {
  641. zval *zlistener;
  642. php_ssh2_listener_data *data;
  643. LIBSSH2_CHANNEL *channel;
  644. php_ssh2_channel_data *channel_data;
  645. php_stream *stream;
  646. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zlistener) == FAILURE) {
  647. RETURN_FALSE;
  648. }
  649. ZEND_FETCH_RESOURCE(data, php_ssh2_listener_data*, &zlistener, -1, PHP_SSH2_LISTENER_RES_NAME, le_ssh2_listener);
  650. channel = libssh2_channel_forward_accept(data->listener);
  651. if (!channel) {
  652. RETURN_FALSE;
  653. }
  654. channel_data = emalloc(sizeof(php_ssh2_channel_data));
  655. channel_data->channel = channel;
  656. channel_data->streamid = 0;
  657. channel_data->is_blocking = 0;
  658. channel_data->session_rsrc = data->session_rsrcid;
  659. channel_data->refcount = NULL;
  660. stream = php_stream_alloc(&php_ssh2_channel_stream_ops, channel_data, 0, "r+");
  661. if (!stream) {
  662. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure allocating stream");
  663. efree(channel_data);
  664. libssh2_channel_free(channel);
  665. RETURN_FALSE;
  666. }
  667. zend_list_addref(channel_data->session_rsrc);
  668. php_stream_to_zval(stream, return_value);
  669. }
  670. /* }}} */
  671. #endif /* PHP_SSH2_REMOTE_FORWARDING */
  672. #ifdef PHP_SSH2_POLL
  673. /* {{{ proto int ssh2_poll(array &polldes[, int timeout])
  674. * Poll the channels/listeners/streams for events
  675. * Returns number of descriptors which returned non-zero revents
  676. * Input array should be of the form:
  677. * array(
  678. * 0 => array(
  679. * [resource] => $channel,$listener, or $stream
  680. * [events] => SSH2_POLL* flags bitwise ORed together
  681. * ),
  682. * 1 => ...
  683. * )
  684. * Each subarray will be populated with an revents element on return
  685. */
  686. PHP_FUNCTION(ssh2_poll)
  687. {
  688. zval *zdesc, **subarray;
  689. long timeout = PHP_SSH2_DEFAULT_POLL_TIMEOUT;
  690. LIBSSH2_POLLFD *pollfds;
  691. int numfds, i = 0, fds_ready;
  692. int le_stream = php_file_le_stream();
  693. int le_pstream = php_file_le_pstream();
  694. zval ***pollmap;
  695. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &zdesc, &timeout) == FAILURE) {
  696. RETURN_NULL();
  697. }
  698. numfds = zend_hash_num_elements(Z_ARRVAL_P(zdesc));
  699. pollfds = safe_emalloc(sizeof(LIBSSH2_POLLFD), numfds, 0);
  700. pollmap = safe_emalloc(sizeof(zval**), numfds, 0);
  701. for(zend_hash_internal_pointer_reset(Z_ARRVAL_P(zdesc));
  702. zend_hash_get_current_data(Z_ARRVAL_P(zdesc), (void**)&subarray) == SUCCESS;
  703. zend_hash_move_forward(Z_ARRVAL_P(zdesc))) {
  704. zval **tmpzval;
  705. int res_type = 0;
  706. void *res;
  707. if (Z_TYPE_PP(subarray) != IS_ARRAY) {
  708. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid element in poll array, not a sub array");
  709. numfds--;
  710. continue;
  711. }
  712. if (zend_hash_find(Z_ARRVAL_PP(subarray), "events", sizeof("events"), (void**)&tmpzval) == FAILURE ||
  713. Z_TYPE_PP(tmpzval) != IS_LONG) {
  714. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid data in subarray, no events element, or not a bitmask");
  715. numfds--;
  716. continue;
  717. }
  718. pollfds[i].events = Z_LVAL_PP(tmpzval);
  719. if (zend_hash_find(Z_ARRVAL_PP(subarray), "resource", sizeof("resource"), (void**)&tmpzval) == FAILURE ||
  720. Z_TYPE_PP(tmpzval) != IS_RESOURCE) {
  721. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid data in subarray, no resource element, or not of type resource");
  722. numfds--;
  723. continue;
  724. }
  725. zend_list_find(Z_LVAL_PP(tmpzval), &res_type);
  726. res = zend_fetch_resource(tmpzval TSRMLS_CC, -1, "Poll Resource", NULL, 1, res_type);
  727. if (res_type == le_ssh2_listener) {
  728. pollfds[i].type = LIBSSH2_POLLFD_LISTENER;
  729. pollfds[i].fd.listener = ((php_ssh2_listener_data*)res)->listener;
  730. } else if ((res_type == le_stream || res_type == le_pstream) &&
  731. ((php_stream*)res)->ops == &php_ssh2_channel_stream_ops) {
  732. pollfds[i].type = LIBSSH2_POLLFD_CHANNEL;
  733. pollfds[i].fd.channel = ((php_ssh2_channel_data*)(((php_stream*)res)->abstract))->channel;
  734. /* TODO: Add the ability to select against other stream types */
  735. } else {
  736. 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));
  737. numfds--;
  738. continue;
  739. }
  740. pollmap[i] = subarray;
  741. i++;
  742. }
  743. fds_ready = libssh2_poll(pollfds, numfds, timeout * 1000);
  744. for(i = 0; i < numfds; i++) {
  745. zval *subarray = *pollmap[i];
  746. if (!Z_ISREF_P(subarray) && Z_REFCOUNT_P(subarray) > 1) {
  747. /* Make a new copy of the subarray zval* */
  748. MAKE_STD_ZVAL(subarray);
  749. *subarray = **pollmap[i];
  750. /* Point the pData to the new zval* and duplicate its resources */
  751. *pollmap[i] = subarray;
  752. zval_copy_ctor(subarray);
  753. /* Fixup its refcount */
  754. Z_UNSET_ISREF_P(subarray);
  755. Z_SET_REFCOUNT_P(subarray, 1);
  756. }
  757. zend_hash_del(Z_ARRVAL_P(subarray), "revents", sizeof("revents"));
  758. add_assoc_long(subarray, "revents", pollfds[i].revents);
  759. }
  760. efree(pollmap);
  761. efree(pollfds);
  762. RETURN_LONG(fds_ready);
  763. }
  764. /* }}} */
  765. #endif /* PHP_SSH2_POLL */
  766. #ifdef PHP_SSH2_PUBLICKEY_SUBSYSTEM
  767. /* ***********************
  768. * Publickey Subsystem *
  769. *********************** */
  770. /* {{{ proto resource ssh2_publickey_init(resource connection)
  771. Initialize the publickey subsystem */
  772. PHP_FUNCTION(ssh2_publickey_init)
  773. {
  774. zval *zsession;
  775. LIBSSH2_SESSION *session;
  776. LIBSSH2_PUBLICKEY *pkey;
  777. php_ssh2_pkey_subsys_data *data;
  778. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zsession) == FAILURE) {
  779. RETURN_FALSE;
  780. }
  781. ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
  782. pkey = libssh2_publickey_init(session);
  783. if (!pkey) {
  784. int last_error = 0;
  785. char *error_msg = NULL;
  786. last_error = libssh2_session_last_error(session, &error_msg, NULL, 0);
  787. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to initialize publickey subsystem(%d) %s", last_error, error_msg);
  788. RETURN_FALSE;
  789. }
  790. data = emalloc(sizeof(php_ssh2_pkey_subsys_data));
  791. data->session = session;
  792. data->session_rsrcid = Z_LVAL_P(zsession);
  793. zend_list_addref(data->session_rsrcid);
  794. data->pkey = pkey;
  795. ZEND_REGISTER_RESOURCE(return_value, data, le_ssh2_pkey_subsys);
  796. }
  797. /* }}} */
  798. /* {{{ proto bool ssh2_publickey_add(resource pkey, string algoname, string blob[, bool overwrite=FALSE [,array attributes=NULL]])
  799. Add an additional publickey */
  800. PHP_FUNCTION(ssh2_publickey_add)
  801. {
  802. zval *zpkey_data, *zattrs = NULL;
  803. php_ssh2_pkey_subsys_data *data;
  804. char *algo, *blob;
  805. int algo_len, blob_len;
  806. unsigned long num_attrs = 0;
  807. libssh2_publickey_attribute *attrs = NULL;
  808. zend_bool overwrite = 0;
  809. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss|ba", &zpkey_data, &algo, &algo_len, &blob, &blob_len, &overwrite, &zattrs) == FAILURE) {
  810. RETURN_FALSE;
  811. }
  812. ZEND_FETCH_RESOURCE(data, php_ssh2_pkey_subsys_data*, &zpkey_data, -1, PHP_SSH2_PKEY_SUBSYS_RES_NAME, le_ssh2_pkey_subsys);
  813. if (zattrs) {
  814. HashPosition pos;
  815. zval **attr_val;
  816. unsigned long current_attr = 0;
  817. num_attrs = zend_hash_num_elements(Z_ARRVAL_P(zattrs));
  818. attrs = safe_emalloc(num_attrs, sizeof(libssh2_publickey_attribute), 0);
  819. for(zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(zattrs), &pos);
  820. zend_hash_get_current_data_ex(Z_ARRVAL_P(zattrs), (void**)&attr_val, &pos) == SUCCESS;
  821. zend_hash_move_forward_ex(Z_ARRVAL_P(zattrs), &pos)) {
  822. char *key;
  823. int key_len, type;
  824. long idx;
  825. zval copyval = **attr_val;
  826. type = zend_hash_get_current_key_ex(Z_ARRVAL_P(zattrs), &key, &key_len, &idx, 0, &pos);
  827. if (type == HASH_KEY_NON_EXISTANT) {
  828. /* All but impossible */
  829. break;
  830. }
  831. if (type == HASH_KEY_IS_LONG) {
  832. /* Malformed, ignore */
  833. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Malformed attirbute array, contains numeric index");
  834. num_attrs--;
  835. continue;
  836. }
  837. if (key_len == 0 || (key_len == 1 && *key == '*')) {
  838. /* Empty key, ignore */
  839. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty attribute key");
  840. num_attrs--;
  841. continue;
  842. }
  843. zval_copy_ctor(&copyval);
  844. Z_UNSET_ISREF_P(&copyval);
  845. Z_SET_REFCOUNT_P(&copyval, 1);
  846. convert_to_string(&copyval);
  847. if (*key == '*') {
  848. attrs[current_attr].mandatory = 1;
  849. attrs[current_attr].name = key + 1;
  850. attrs[current_attr].name_len = key_len - 2;
  851. } else {
  852. attrs[current_attr].mandatory = 0;
  853. attrs[current_attr].name = key;
  854. attrs[current_attr].name_len = key_len - 1;
  855. }
  856. attrs[current_attr].value_len = Z_STRLEN(copyval);
  857. attrs[current_attr].value = Z_STRVAL(copyval);
  858. /* copyval deliberately not dtor'd, we're stealing the string */
  859. current_attr++;
  860. }
  861. }
  862. if (libssh2_publickey_add_ex(data->pkey, algo, algo_len, blob, blob_len, overwrite, num_attrs, attrs)) {
  863. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add %s key", algo);
  864. RETVAL_FALSE;
  865. } else {
  866. RETVAL_TRUE;
  867. }
  868. if (attrs) {
  869. unsigned long i;
  870. for(i = 0; i < num_attrs; i++) {
  871. /* name doesn't need freeing */
  872. efree(attrs[i].value);
  873. }
  874. efree(attrs);
  875. }
  876. }
  877. /* }}} */
  878. /* {{{ proto bool ssh2_publickey_remove(resource pkey, string algoname, string blob)
  879. Remove a publickey entry */
  880. PHP_FUNCTION(ssh2_publickey_remove)
  881. {
  882. zval *zpkey_data;
  883. php_ssh2_pkey_subsys_data *data;
  884. char *algo, *blob;
  885. int algo_len, blob_len;
  886. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &zpkey_data, &algo, &algo_len, &blob, &blob_len) == FAILURE) {
  887. RETURN_FALSE;
  888. }
  889. ZEND_FETCH_RESOURCE(data, php_ssh2_pkey_subsys_data*, &zpkey_data, -1, PHP_SSH2_PKEY_SUBSYS_RES_NAME, le_ssh2_pkey_subsys);
  890. if (libssh2_publickey_remove_ex(data->pkey, algo, algo_len, blob, blob_len)) {
  891. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to remove %s key", algo);
  892. RETURN_FALSE;
  893. }
  894. RETURN_TRUE;
  895. }
  896. /* }}} */
  897. /* {{{ proto array ssh2_publickey_list(resource pkey)
  898. List currently installed publickey entries */
  899. PHP_FUNCTION(ssh2_publickey_list)
  900. {
  901. zval *zpkey_data;
  902. php_ssh2_pkey_subsys_data *data;
  903. unsigned long num_keys, i;
  904. libssh2_publickey_list *keys;
  905. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zpkey_data) == FAILURE) {
  906. RETURN_FALSE;
  907. }
  908. ZEND_FETCH_RESOURCE(data, php_ssh2_pkey_subsys_data*, &zpkey_data, -1, PHP_SSH2_PKEY_SUBSYS_RES_NAME, le_ssh2_pkey_subsys);
  909. if (libssh2_publickey_list_fetch(data->pkey, &num_keys, &keys)) {
  910. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to list keys on remote server");
  911. RETURN_FALSE;
  912. }
  913. array_init(return_value);
  914. for(i = 0; i < num_keys; i++) {
  915. zval *key, *attrs;
  916. unsigned long j;
  917. MAKE_STD_ZVAL(key);
  918. array_init(key);
  919. add_assoc_stringl(key, "name", keys[i].name, keys[i].name_len, 1);
  920. add_assoc_stringl(key, "blob", keys[i].blob, keys[i].blob_len, 1);
  921. MAKE_STD_ZVAL(attrs);
  922. array_init(attrs);
  923. for(j = 0; j < keys[i].num_attrs; j++) {
  924. zval *attr;
  925. MAKE_STD_ZVAL(attr);
  926. ZVAL_STRINGL(attr, keys[i].attrs[j].value, keys[i].attrs[j].value_len, 1);
  927. zend_hash_add(Z_ARRVAL_P(attrs), keys[i].attrs[j].name, keys[i].attrs[j].name_len + 1, (void**)&attr, sizeof(zval*), NULL);
  928. }
  929. add_assoc_zval(key, "attrs", attrs);
  930. add_next_index_zval(return_value, key);
  931. }
  932. libssh2_publickey_list_free(data->pkey, keys);
  933. }
  934. /* }}} */
  935. #endif /* PHP_SSH2_PUBLICKEY_SUBSYSTEM */
  936. /* ***********************
  937. * Module Housekeeping *
  938. *********************** */
  939. static void php_ssh2_session_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  940. {
  941. LIBSSH2_SESSION *session = (LIBSSH2_SESSION*)rsrc->ptr;
  942. php_ssh2_session_data **data = (php_ssh2_session_data**)libssh2_session_abstract(session);
  943. libssh2_session_disconnect(session, "PECL/ssh2 (http://pecl.php.net/packages/ssh2)");
  944. if (*data) {
  945. if ((*data)->ignore_cb) {
  946. zval_ptr_dtor(&(*data)->ignore_cb);
  947. }
  948. if ((*data)->debug_cb) {
  949. zval_ptr_dtor(&(*data)->debug_cb);
  950. }
  951. if ((*data)->macerror_cb) {
  952. zval_ptr_dtor(&(*data)->macerror_cb);
  953. }
  954. if ((*data)->disconnect_cb) {
  955. zval_ptr_dtor(&(*data)->disconnect_cb);
  956. }
  957. closesocket((*data)->socket);
  958. efree(*data);
  959. *data = NULL;
  960. }
  961. libssh2_session_free(session);
  962. }
  963. #ifdef PHP_SSH2_REMOTE_FORWARDING
  964. static void php_ssh2_listener_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  965. {
  966. php_ssh2_listener_data *data = (php_ssh2_listener_data*)rsrc->ptr;
  967. LIBSSH2_LISTENER *listener = data->listener;
  968. libssh2_channel_forward_cancel(listener);
  969. zend_list_delete(data->session_rsrcid);
  970. efree(data);
  971. }
  972. #endif /* PHP_SSH2_REMOTE_FORWARDING */
  973. #ifdef PHP_SSH2_PUBLICKEY_SUBSYSTEM
  974. static void php_ssh2_pkey_subsys_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  975. {
  976. php_ssh2_pkey_subsys_data *data = (php_ssh2_pkey_subsys_data*)rsrc->ptr;
  977. LIBSSH2_PUBLICKEY *pkey = data->pkey;
  978. libssh2_publickey_shutdown(pkey);
  979. zend_list_delete(data->session_rsrcid);
  980. efree(data);
  981. }
  982. #endif /* PHP_SSH2_PUBLICKEY_SUBSYSTEM */
  983. /* {{{ PHP_MINIT_FUNCTION
  984. */
  985. PHP_MINIT_FUNCTION(ssh2)
  986. {
  987. le_ssh2_session = zend_register_list_destructors_ex(php_ssh2_session_dtor, NULL, PHP_SSH2_SESSION_RES_NAME, module_number);
  988. #ifdef PHP_SSH2_REMOTE_FORWARDING
  989. le_ssh2_listener = zend_register_list_destructors_ex(php_ssh2_listener_dtor, NULL, PHP_SSH2_LISTENER_RES_NAME, module_number);
  990. #endif /* PHP_SSH2_REMOTE_FORWARDING */
  991. le_ssh2_sftp = zend_register_list_destructors_ex(php_ssh2_sftp_dtor, NULL, PHP_SSH2_SFTP_RES_NAME, module_number);
  992. #ifdef PHP_SSH2_PUBLICKEY_SUBSYSTEM
  993. le_ssh2_pkey_subsys = zend_register_list_destructors_ex(php_ssh2_pkey_subsys_dtor, NULL, PHP_SSH2_PKEY_SUBSYS_RES_NAME, module_number);
  994. #endif /* PHP_SSH2_PUBLICKEY_SUBSYSTEM */
  995. REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_MD5", PHP_SSH2_FINGERPRINT_MD5, CONST_CS | CONST_PERSISTENT);
  996. REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_SHA1", PHP_SSH2_FINGERPRINT_SHA1, CONST_CS | CONST_PERSISTENT);
  997. REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_HEX", PHP_SSH2_FINGERPRINT_HEX, CONST_CS | CONST_PERSISTENT);
  998. REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_RAW", PHP_SSH2_FINGERPRINT_RAW, CONST_CS | CONST_PERSISTENT);
  999. REGISTER_LONG_CONSTANT("SSH2_TERM_UNIT_CHARS", PHP_SSH2_TERM_UNIT_CHARS, CONST_CS | CONST_PERSISTENT);
  1000. REGISTER_LONG_CONSTANT("SSH2_TERM_UNIT_PIXELS", PHP_SSH2_TERM_UNIT_PIXELS, CONST_CS | CONST_PERSISTENT);
  1001. REGISTER_STRING_CONSTANT("SSH2_DEFAULT_TERMINAL", PHP_SSH2_DEFAULT_TERMINAL, CONST_CS | CONST_PERSISTENT);
  1002. REGISTER_LONG_CONSTANT("SSH2_DEFAULT_TERM_WIDTH", PHP_SSH2_DEFAULT_TERM_WIDTH, CONST_CS | CONST_PERSISTENT);
  1003. REGISTER_LONG_CONSTANT("SSH2_DEFAULT_TERM_HEIGHT", PHP_SSH2_DEFAULT_TERM_HEIGHT, CONST_CS | CONST_PERSISTENT);
  1004. REGISTER_LONG_CONSTANT("SSH2_DEFAULT_TERM_UNIT", PHP_SSH2_DEFAULT_TERM_UNIT, CONST_CS | CONST_PERSISTENT);
  1005. REGISTER_LONG_CONSTANT("SSH2_STREAM_STDIO", 0, CONST_CS | CONST_PERSISTENT);
  1006. REGISTER_LONG_CONSTANT("SSH2_STREAM_STDERR", SSH_EXTENDED_DATA_STDERR, CONST_CS | CONST_PERSISTENT);
  1007. #ifdef PHP_SSH2_POLL
  1008. /* events/revents */
  1009. REGISTER_LONG_CONSTANT("SSH2_POLLIN", LIBSSH2_POLLFD_POLLIN, CONST_CS | CONST_PERSISTENT);
  1010. REGISTER_LONG_CONSTANT("SSH2_POLLEXT", LIBSSH2_POLLFD_POLLEXT, CONST_CS | CONST_PERSISTENT);
  1011. REGISTER_LONG_CONSTANT("SSH2_POLLOUT", LIBSSH2_POLLFD_POLLOUT, CONST_CS | CONST_PERSISTENT);
  1012. /* revents only */
  1013. REGISTER_LONG_CONSTANT("SSH2_POLLERR", LIBSSH2_POLLFD_POLLERR, CONST_CS | CONST_PERSISTENT);
  1014. REGISTER_LONG_CONSTANT("SSH2_POLLHUP", LIBSSH2_POLLFD_POLLHUP, CONST_CS | CONST_PERSISTENT);
  1015. REGISTER_LONG_CONSTANT("SSH2_POLLNVAL", LIBSSH2_POLLFD_POLLNVAL, CONST_CS | CONST_PERSISTENT);
  1016. #if (defined(LIBSSH2_APINO) && (LIBSSH2_APINO > 200503221619)) || (defined(LIBSSH2_VERSION_NUM) && LIBSSH2_VERSION_NUM >= 0x001000)
  1017. REGISTER_LONG_CONSTANT("SSH2_POLL_SESSION_CLOSED", LIBSSH2_POLLFD_SESSION_CLOSED, CONST_CS | CONST_PERSISTENT);
  1018. REGISTER_LONG_CONSTANT("SSH2_POLL_CHANNEL_CLOSED", LIBSSH2_POLLFD_CHANNEL_CLOSED, CONST_CS | CONST_PERSISTENT);
  1019. REGISTER_LONG_CONSTANT("SSH2_POLL_LISTENER_CLOSED", LIBSSH2_POLLFD_LISTENER_CLOSED, CONST_CS | CONST_PERSISTENT);
  1020. #endif /* >= LIBSSH2-0.10 */
  1021. #endif /* POLL */
  1022. return (php_register_url_stream_wrapper("ssh2.shell", &php_ssh2_stream_wrapper_shell TSRMLS_CC) == SUCCESS &&
  1023. php_register_url_stream_wrapper("ssh2.exec", &php_ssh2_stream_wrapper_exec TSRMLS_CC) == SUCCESS &&
  1024. php_register_url_stream_wrapper("ssh2.tunnel", &php_ssh2_stream_wrapper_tunnel TSRMLS_CC) == SUCCESS &&
  1025. php_register_url_stream_wrapper("ssh2.scp", &php_ssh2_stream_wrapper_scp TSRMLS_CC) == SUCCESS &&
  1026. php_register_url_stream_wrapper("ssh2.sftp", &php_ssh2_sftp_wrapper TSRMLS_CC) == SUCCESS) ? SUCCESS : FAILURE;
  1027. }
  1028. /* }}} */
  1029. /* {{{ PHP_MSHUTDOWN_FUNCTION
  1030. */
  1031. PHP_MSHUTDOWN_FUNCTION(ssh2)
  1032. {
  1033. return (php_unregister_url_stream_wrapper("ssh2.shell" TSRMLS_CC) == SUCCESS &&
  1034. php_unregister_url_stream_wrapper("ssh2.exec" TSRMLS_CC) == SUCCESS &&
  1035. php_unregister_url_stream_wrapper("ssh2.tunnel" TSRMLS_CC) == SUCCESS &&
  1036. php_unregister_url_stream_wrapper("ssh2.scp" TSRMLS_CC) == SUCCESS &&
  1037. php_unregister_url_stream_wrapper("ssh2.sftp" TSRMLS_CC) == SUCCESS) ? SUCCESS : FAILURE;
  1038. }
  1039. /* }}} */
  1040. /* {{{ PHP_MINFO_FUNCTION
  1041. */
  1042. PHP_MINFO_FUNCTION(ssh2)
  1043. {
  1044. php_info_print_table_start();
  1045. php_info_print_table_header(2, "SSH2 support", "enabled");
  1046. php_info_print_table_row(2, "extension version", PHP_SSH2_VERSION);
  1047. php_info_print_table_row(2, "libssh2 version", LIBSSH2_VERSION);
  1048. php_info_print_table_row(2, "banner", LIBSSH2_SSH_BANNER);
  1049. #ifdef PHP_SSH2_REMOTE_FORWARDING
  1050. php_info_print_table_row(2, "remote forwarding", "enabled");
  1051. #endif
  1052. #ifdef PHP_SSH2_HOSTBASED_AUTH
  1053. php_info_print_table_row(2, "hostbased auth", "enabled");
  1054. #endif
  1055. #ifdef PHP_SSH2_POLL
  1056. php_info_print_table_row(2, "polling support", "enabled");
  1057. #endif
  1058. #ifdef PHP_SSH2_PUBLICKEY_SUBSYSTEM
  1059. php_info_print_table_row(2, "publickey subsystem", "enabled");
  1060. #endif
  1061. php_info_print_table_end();
  1062. }
  1063. /* }}} */
  1064. /* {{{ ssh2_functions[]
  1065. */
  1066. zend_function_entry ssh2_functions[] = {
  1067. PHP_FE(ssh2_connect, NULL)
  1068. PHP_FE(ssh2_methods_negotiated, NULL)
  1069. PHP_FE(ssh2_fingerprint, NULL)
  1070. PHP_FE(ssh2_auth_none, NULL)
  1071. PHP_FE(ssh2_auth_password, NULL)
  1072. PHP_FE(ssh2_auth_pubkey_file, NULL)
  1073. #ifdef PHP_SSH2_HOSTBASED_AUTH
  1074. PHP_FE(ssh2_auth_hostbased_file, NULL)
  1075. #endif /* PHP_SSH2_HOSTBASED_AUTH */
  1076. #ifdef PHP_SSH2_REMOTE_FORWARDING
  1077. PHP_FE(ssh2_forward_listen, NULL)
  1078. PHP_FE(ssh2_forward_accept, NULL)
  1079. #endif /* PHP_SSH2_REMOTE_FORWARDING */
  1080. /* Stream Stuff */
  1081. PHP_FE(ssh2_shell, NULL)
  1082. PHP_FE(ssh2_exec, NULL)
  1083. PHP_FE(ssh2_tunnel, NULL)
  1084. PHP_FE(ssh2_scp_recv, NULL)
  1085. PHP_FE(ssh2_scp_send, NULL)
  1086. PHP_FE(ssh2_fetch_stream, NULL)
  1087. #ifdef PHP_SSH2_POLL
  1088. PHP_FE(ssh2_poll, php_ssh2_first_arg_force_ref)
  1089. #endif
  1090. /* SFTP Stuff */
  1091. PHP_FE(ssh2_sftp, NULL)
  1092. /* SFTP Wrapper Ops */
  1093. PHP_FE(ssh2_sftp_rename, NULL)
  1094. PHP_FE(ssh2_sftp_unlink, NULL)
  1095. PHP_FE(ssh2_sftp_mkdir, NULL)
  1096. PHP_FE(ssh2_sftp_rmdir, NULL)
  1097. PHP_FE(ssh2_sftp_stat, NULL)
  1098. PHP_FE(ssh2_sftp_lstat, NULL)
  1099. PHP_FE(ssh2_sftp_symlink, NULL)
  1100. PHP_FE(ssh2_sftp_readlink, NULL)
  1101. PHP_FE(ssh2_sftp_realpath, NULL)
  1102. /* Publickey subsystem */
  1103. #ifdef PHP_SSH2_PUBLICKEY_SUBSYSTEM
  1104. PHP_FE(ssh2_publickey_init, NULL)
  1105. PHP_FE(ssh2_publickey_add, NULL)
  1106. PHP_FE(ssh2_publickey_remove, NULL)
  1107. PHP_FE(ssh2_publickey_list, NULL)
  1108. #endif
  1109. {NULL, NULL, NULL}
  1110. };
  1111. /* }}} */
  1112. /* {{{ ssh2_module_entry
  1113. */
  1114. zend_module_entry ssh2_module_entry = {
  1115. #if ZEND_MODULE_API_NO >= 20010901
  1116. STANDARD_MODULE_HEADER,
  1117. #endif
  1118. "ssh2",
  1119. ssh2_functions,
  1120. PHP_MINIT(ssh2),
  1121. PHP_MSHUTDOWN(ssh2),
  1122. NULL, /* RINIT */
  1123. NULL, /* RSHUTDOWN */
  1124. PHP_MINFO(ssh2),
  1125. #if ZEND_MODULE_API_NO >= 20010901
  1126. PHP_SSH2_VERSION,
  1127. #endif
  1128. STANDARD_MODULE_PROPERTIES
  1129. };
  1130. /* }}} */
  1131. #ifdef COMPILE_DL_SSH2
  1132. ZEND_GET_MODULE(ssh2)
  1133. #endif
  1134. /*
  1135. * Local variables:
  1136. * tab-width: 4
  1137. * c-basic-offset: 4
  1138. * End:
  1139. * vim600: noet sw=4 ts=4 fdm=marker
  1140. * vim<600: noet sw=4 ts=4
  1141. */