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