1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2016 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.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
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "php.h"
24 #include "ext/standard/info.h"
25 #include "ext/standard/file.h"
26 #include "php_ssh2.h"
27 #include "main/php_network.h"
28
29 #if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
30 #include <openssl/applink.c>
31 #endif
32
33 /* Internal Constants */
34 #ifndef SHA_DIGEST_LENGTH
35 #define SHA_DIGEST_LENGTH 20
36 #endif
37
38 #ifndef MD5_DIGEST_LENGTH
39 #define MD5_DIGEST_LENGTH 16
40 #endif
41
42 /* True global resources - no need for thread safety here */
43 int le_ssh2_session;
44 int le_ssh2_listener;
45 int le_ssh2_sftp;
46 int le_ssh2_pkey_subsys;
47
48 /* *************
49 * Callbacks *
50 ************* */
51
52 /* {{{ php_ssh2_alloc_cb
53 * Wrap emalloc()
54 */
LIBSSH2_ALLOC_FUNC(php_ssh2_alloc_cb)55 static LIBSSH2_ALLOC_FUNC(php_ssh2_alloc_cb)
56 {
57 return emalloc(count);
58 }
59 /* }}} */
60
61 /* {{{ php_ssh2_free_cb
62 * Wrap efree()
63 */
LIBSSH2_FREE_FUNC(php_ssh2_free_cb)64 static LIBSSH2_FREE_FUNC(php_ssh2_free_cb)
65 {
66 efree(ptr);
67 }
68 /* }}} */
69
70 /* {{{ php_ssh2_realloc_cb
71 * Wrap erealloc()
72 */
LIBSSH2_REALLOC_FUNC(php_ssh2_realloc_cb)73 static LIBSSH2_REALLOC_FUNC(php_ssh2_realloc_cb)
74 {
75 return erealloc(ptr, count);
76 }
77 /* }}} */
78
79 /* {{{ php_ssh2_debug_cb
80 * Debug packets
81 */
LIBSSH2_DEBUG_FUNC(php_ssh2_debug_cb)82 LIBSSH2_DEBUG_FUNC(php_ssh2_debug_cb)
83 {
84 php_ssh2_session_data *data;
85 zval args[3];
86
87 if (!abstract || !*abstract) {
88 return;
89 }
90 data = (php_ssh2_session_data*)*abstract;
91 if (!data->debug_cb) {
92 return;
93 }
94
95 ZVAL_STRINGL(&args[0], message, message_len);
96 ZVAL_STRINGL(&args[1], language, language_len);
97 ZVAL_LONG(&args[2], always_display);
98
99 zval retval;
100 if (FAILURE == call_user_function(NULL, NULL, data->debug_cb, &retval, 3, args)) {
101 php_error_docref(NULL, E_WARNING, "Failure calling debug callback");
102 }
103
104 if (!Z_ISUNDEF(retval)) {
105 zval_ptr_dtor(&retval);
106 }
107 }
108 /* }}} */
109
110 /* {{{ php_ssh2_ignore_cb
111 * Ignore packets
112 */
LIBSSH2_IGNORE_FUNC(php_ssh2_ignore_cb)113 LIBSSH2_IGNORE_FUNC(php_ssh2_ignore_cb)
114 {
115 php_ssh2_session_data *data;
116 zval zretval;
117 zval args[1];
118
119 if (!abstract || !*abstract) {
120 return;
121 }
122 data = (php_ssh2_session_data*)*abstract;
123 if (!data->ignore_cb) {
124 return;
125 }
126
127 ZVAL_STRINGL(&args[0], message, message_len);
128
129 if (FAILURE == call_user_function(NULL, NULL, data->ignore_cb, &zretval, 1, args)) {
130 php_error_docref(NULL, E_WARNING, "Failure calling ignore callback");
131 }
132 if (Z_TYPE_P(&zretval) != IS_UNDEF) {
133 zval_ptr_dtor(&zretval);
134 }
135 }
136 /* }}} */
137
138 /* {{{ php_ssh2_macerror_cb
139 * Called when a MAC error occurs, offers the chance to ignore
140 * WHY ARE YOU IGNORING MAC ERRORS??????
141 */
LIBSSH2_MACERROR_FUNC(php_ssh2_macerror_cb)142 LIBSSH2_MACERROR_FUNC(php_ssh2_macerror_cb)
143 {
144 php_ssh2_session_data *data;
145 zval zretval;
146 zval args[1];
147 int retval = -1;
148
149 if (!abstract || !*abstract) {
150 return -1;
151 }
152 data = (php_ssh2_session_data*)*abstract;
153 if (!data->macerror_cb) {
154 return -1;
155 }
156
157 ZVAL_STRINGL(&args[0], packet, packet_len);
158
159 if (FAILURE == call_user_function(NULL, NULL, data->macerror_cb, &zretval, 1, args)) {
160 php_error_docref(NULL, E_WARNING, "Failure calling macerror callback");
161 } else {
162 retval = zval_is_true(&zretval) ? 0 : -1;
163 }
164 if (Z_TYPE_P(&zretval) != IS_UNDEF) {
165 zval_ptr_dtor(&zretval);
166 }
167
168 return retval;
169 }
170 /* }}} */
171
172 /* {{{ php_ssh2_disconnect_cb
173 * Connection closed by foreign host
174 */
LIBSSH2_DISCONNECT_FUNC(php_ssh2_disconnect_cb)175 LIBSSH2_DISCONNECT_FUNC(php_ssh2_disconnect_cb)
176 {
177 php_ssh2_session_data *data;
178 zval args[3];
179
180 if (!abstract || !*abstract) {
181 return;
182 }
183 data = (php_ssh2_session_data*)*abstract;
184 if (!data->disconnect_cb) {
185 return;
186 }
187
188 ZVAL_LONG(&args[0], reason);
189 ZVAL_STRINGL(&args[1], message, message_len);
190 ZVAL_STRINGL(&args[2], language, language_len);
191
192 zval retval;
193 if (FAILURE == call_user_function(NULL, NULL, data->disconnect_cb, &retval, 3, args)) {
194 php_error_docref(NULL, E_WARNING, "Failure calling disconnect callback");
195 }
196
197 if (!Z_ISUNDEF(retval)) {
198 zval_ptr_dtor(&retval);
199 }
200 }
201 /* }}} */
202
203
204
205 /* *****************
206 * Userspace API *
207 ***************** */
208
209 /* {{{ php_ssh2_set_callback
210 * Try to set a method if it's passed in with the hash table
211 */
php_ssh2_set_callback(LIBSSH2_SESSION * session,HashTable * ht,char * callback,int callback_len,int callback_type,php_ssh2_session_data * data)212 static int php_ssh2_set_callback(LIBSSH2_SESSION *session, HashTable *ht, char *callback, int callback_len, int callback_type, php_ssh2_session_data *data)
213 {
214 zval *handler, *copyval;
215 void *internal_handler;
216 zend_string *callback_zstring;
217
218 callback_zstring = zend_string_init(callback, callback_len, 0);
219 if ((handler = zend_hash_find(ht, callback_zstring)) == NULL) {
220 zend_string_release(callback_zstring);
221 return 0;
222 }
223 zend_string_release(callback_zstring);
224
225 if (!zend_is_callable(handler, 0, NULL)) {
226 return -1;
227 }
228
229 copyval = emalloc(sizeof(zval));
230 ZVAL_COPY(copyval, handler);
231
232 switch (callback_type) {
233 case LIBSSH2_CALLBACK_IGNORE:
234 internal_handler = php_ssh2_ignore_cb;
235 if (data->ignore_cb) {
236 zval_ptr_dtor(data->ignore_cb);
237 }
238 data->ignore_cb = copyval;
239 break;
240 case LIBSSH2_CALLBACK_DEBUG:
241 internal_handler = php_ssh2_debug_cb;
242 if (data->debug_cb) {
243 zval_ptr_dtor(data->debug_cb);
244 }
245 data->debug_cb = copyval;
246 break;
247 case LIBSSH2_CALLBACK_MACERROR:
248 internal_handler = php_ssh2_macerror_cb;
249 if (data->macerror_cb) {
250 zval_ptr_dtor(data->macerror_cb);
251 }
252 data->macerror_cb = copyval;
253 break;
254 case LIBSSH2_CALLBACK_DISCONNECT:
255 internal_handler = php_ssh2_disconnect_cb;
256 if (data->disconnect_cb) {
257 zval_ptr_dtor(data->disconnect_cb);
258 }
259 data->disconnect_cb = copyval;
260 break;
261 default:
262 zval_ptr_dtor(copyval);
263 return -1;
264 }
265
266 libssh2_session_callback_set(session, callback_type, internal_handler);
267
268 return 0;
269 }
270 /* }}} */
271
272 /* {{{ php_ssh2_set_method
273 * Try to set a method if it's passed in with the hash table
274 */
php_ssh2_set_method(LIBSSH2_SESSION * session,HashTable * ht,char * method,int method_len,int method_type)275 static int php_ssh2_set_method(LIBSSH2_SESSION *session, HashTable *ht, char *method, int method_len, int method_type)
276 {
277 zval *value;
278 zend_string *method_zstring;
279
280
281 method_zstring = zend_string_init(method, method_len, 0);
282 if ((value = zend_hash_find(ht, method_zstring)) == NULL) {
283 zend_string_release(method_zstring);
284 return 0;
285 }
286 zend_string_release(method_zstring);
287
288 if ((Z_TYPE_P(value) != IS_STRING)) {
289 return -1;
290 }
291
292 return libssh2_session_method_pref(session, method_type, Z_STRVAL_P(value));
293 }
294 /* }}} */
295
296 /* {{{ php_ssh2_session_connect
297 * Connect to an SSH server with requested methods
298 */
php_ssh2_session_connect(char * host,int port,zval * methods,zval * callbacks)299 LIBSSH2_SESSION *php_ssh2_session_connect(char *host, int port, zval *methods, zval *callbacks)
300 {
301 LIBSSH2_SESSION *session;
302 int socket;
303 php_ssh2_session_data *data;
304 struct timeval tv;
305 zend_string *hash_lookup_zstring;
306
307 tv.tv_sec = FG(default_socket_timeout);
308 tv.tv_usec = 0;
309
310 socket = php_network_connect_socket_to_host(host, port, SOCK_STREAM, 0, &tv, NULL, NULL, NULL, 0, STREAM_SOCKOP_NONE);
311
312 if (socket <= 0) {
313 php_error_docref(NULL, E_WARNING, "Unable to connect to %s on port %d", host, port);
314 return NULL;
315 }
316
317 data = ecalloc(1, sizeof(php_ssh2_session_data));
318 data->socket = socket;
319
320 session = libssh2_session_init_ex(php_ssh2_alloc_cb, php_ssh2_free_cb, php_ssh2_realloc_cb, data);
321 if (!session) {
322 php_error_docref(NULL, E_WARNING, "Unable to initialize SSH2 session");
323 efree(data);
324 closesocket(socket);
325 return NULL;
326 }
327 libssh2_banner_set(session, LIBSSH2_SSH_DEFAULT_BANNER " PHP");
328
329 /* Override method preferences */
330 if (methods) {
331 zval *container;
332
333 if (php_ssh2_set_method(session, HASH_OF(methods), "kex", sizeof("kex") - 1, LIBSSH2_METHOD_KEX)) {
334 php_error_docref(NULL, E_WARNING, "Failed overriding KEX method");
335 }
336 if (php_ssh2_set_method(session, HASH_OF(methods), "hostkey", sizeof("hostkey") - 1, LIBSSH2_METHOD_HOSTKEY)) {
337 php_error_docref(NULL, E_WARNING, "Failed overriding HOSTKEY method");
338 }
339
340 hash_lookup_zstring = zend_string_init("client_to_server", sizeof("client_to_server") - 1, 0);
341 if ((container = zend_hash_find(HASH_OF(methods), hash_lookup_zstring)) != NULL && Z_TYPE_P(container) == IS_ARRAY) {
342 if (php_ssh2_set_method(session, HASH_OF(container), "crypt", sizeof("crypt") - 1, LIBSSH2_METHOD_CRYPT_CS)) {
343 php_error_docref(NULL, E_WARNING, "Failed overriding client to server CRYPT method");
344 }
345 if (php_ssh2_set_method(session, HASH_OF(container), "mac", sizeof("mac") - 1, LIBSSH2_METHOD_MAC_CS)) {
346 php_error_docref(NULL, E_WARNING, "Failed overriding client to server MAC method");
347 }
348 if (php_ssh2_set_method(session, HASH_OF(container), "comp", sizeof("comp") - 1, LIBSSH2_METHOD_COMP_CS)) {
349 php_error_docref(NULL, E_WARNING, "Failed overriding client to server COMP method");
350 }
351 if (php_ssh2_set_method(session, HASH_OF(container), "lang", sizeof("lang") - 1, LIBSSH2_METHOD_LANG_CS)) {
352 php_error_docref(NULL, E_WARNING, "Failed overriding client to server LANG method");
353 }
354 }
355 zend_string_release(hash_lookup_zstring);
356
357 hash_lookup_zstring = zend_string_init("server_to_client", sizeof("server_to_client") - 1, 0);
358 if ((container = zend_hash_find(HASH_OF(methods), hash_lookup_zstring)) != NULL && Z_TYPE_P(container) == IS_ARRAY) {
359 if (php_ssh2_set_method(session, HASH_OF(container), "crypt", sizeof("crypt") - 1, LIBSSH2_METHOD_CRYPT_SC)) {
360 php_error_docref(NULL, E_WARNING, "Failed overriding server to client CRYPT method");
361 }
362 if (php_ssh2_set_method(session, HASH_OF(container), "mac", sizeof("mac") - 1, LIBSSH2_METHOD_MAC_SC)) {
363 php_error_docref(NULL, E_WARNING, "Failed overriding server to client MAC method");
364 }
365 if (php_ssh2_set_method(session, HASH_OF(container), "comp", sizeof("comp") - 1, LIBSSH2_METHOD_COMP_SC)) {
366 php_error_docref(NULL, E_WARNING, "Failed overriding server to client COMP method");
367 }
368 if (php_ssh2_set_method(session, HASH_OF(container), "lang", sizeof("lang") - 1, LIBSSH2_METHOD_LANG_SC)) {
369 php_error_docref(NULL, E_WARNING, "Failed overriding server to client LANG method");
370 }
371 }
372 zend_string_release(hash_lookup_zstring);
373
374 }
375
376 /* Register Callbacks */
377 if (callbacks) {
378 /* ignore debug disconnect macerror */
379
380 if (php_ssh2_set_callback(session, HASH_OF(callbacks), "ignore", sizeof("ignore") - 1, LIBSSH2_CALLBACK_IGNORE, data)) {
381 php_error_docref(NULL, E_WARNING, "Failed setting IGNORE callback");
382 }
383
384 if (php_ssh2_set_callback(session, HASH_OF(callbacks), "debug", sizeof("debug") - 1, LIBSSH2_CALLBACK_DEBUG, data)) {
385 php_error_docref(NULL, E_WARNING, "Failed setting DEBUG callback");
386 }
387
388 if (php_ssh2_set_callback(session, HASH_OF(callbacks), "macerror", sizeof("macerror") - 1, LIBSSH2_CALLBACK_MACERROR, data)) {
389 php_error_docref(NULL, E_WARNING, "Failed setting MACERROR callback");
390 }
391
392 if (php_ssh2_set_callback(session, HASH_OF(callbacks), "disconnect", sizeof("disconnect") - 1, LIBSSH2_CALLBACK_DISCONNECT, data)) {
393 php_error_docref(NULL, E_WARNING, "Failed setting DISCONNECT callback");
394 }
395 }
396
397 if (libssh2_session_startup(session, socket)) {
398 int last_error = 0;
399 char *error_msg = NULL;
400
401 last_error = libssh2_session_last_error(session, &error_msg, NULL, 0);
402 php_error_docref(NULL, E_WARNING, "Error starting up SSH connection(%d): %s", last_error, error_msg);
403 closesocket(socket);
404 libssh2_session_free(session);
405 efree(data);
406 return NULL;
407 }
408
409 return session;
410 }
411 /* }}} */
412
413 /* {{{ proto resource ssh2_connect(string host[, int port[, array methods[, array callbacks]]])
414 * Establish a connection to a remote SSH server and return a resource on success, false on error
415 */
PHP_FUNCTION(ssh2_connect)416 PHP_FUNCTION(ssh2_connect)
417 {
418 LIBSSH2_SESSION *session;
419 zval *methods = NULL, *callbacks = NULL;
420 char *host;
421 zend_long port = PHP_SSH2_DEFAULT_PORT;
422 size_t host_len;
423
424 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|la!a!", &host, &host_len, &port, &methods, &callbacks) == FAILURE) {
425 return;
426 }
427
428 session = php_ssh2_session_connect(host, port, methods, callbacks);
429 if (!session) {
430 php_error_docref(NULL, E_WARNING, "Unable to connect to %s", host);
431 RETURN_FALSE;
432 }
433
434 RETURN_RES(zend_register_resource(session, le_ssh2_session));
435 }
436 /* }}} */
437
438 /* {{{ proto resource ssh2_disconnect(resource session)
439 * close a connection to a remote SSH server and return a true on success, false on error.
440 */
PHP_FUNCTION(ssh2_disconnect)441 PHP_FUNCTION(ssh2_disconnect)
442 {
443 zval *zsession;
444
445 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zsession) == FAILURE) {
446 RETURN_FALSE;
447 }
448
449 zend_list_close(Z_RES_P(zsession));
450
451 RETURN_TRUE;
452 }
453 /* }}} */
454
455 /* {{{ proto array ssh2_methods_negotiated(resource session)
456 * Return list of negotiaed methods
457 */
PHP_FUNCTION(ssh2_methods_negotiated)458 PHP_FUNCTION(ssh2_methods_negotiated)
459 {
460 LIBSSH2_SESSION *session;
461 zval *zsession, endpoint;
462 char *kex, *hostkey, *crypt_cs, *crypt_sc, *mac_cs, *mac_sc, *comp_cs, *comp_sc, *lang_cs, *lang_sc;
463
464 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zsession) == FAILURE) {
465 return;
466 }
467
468 if ((session = (LIBSSH2_SESSION *)zend_fetch_resource(Z_RES_P(zsession), PHP_SSH2_SESSION_RES_NAME, le_ssh2_session)) == NULL) {
469 RETURN_FALSE;
470 }
471
472 kex = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_KEX);
473 hostkey = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_HOSTKEY);
474 crypt_cs = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_CRYPT_CS);
475 crypt_sc = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_CRYPT_SC);
476 mac_cs = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_MAC_CS);
477 mac_sc = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_MAC_SC);
478 comp_cs = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_COMP_CS);
479 comp_sc = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_COMP_SC);
480 lang_cs = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_LANG_CS);
481 lang_sc = (char*)libssh2_session_methods(session, LIBSSH2_METHOD_LANG_SC);
482
483 array_init(return_value);
484 add_assoc_string(return_value, "kex", kex);
485 add_assoc_string(return_value, "hostkey", hostkey);
486
487 array_init(&endpoint);
488 add_assoc_string(&endpoint, "crypt", crypt_cs);
489 add_assoc_string(&endpoint, "mac", mac_cs);
490 add_assoc_string(&endpoint, "comp", comp_cs);
491 add_assoc_string(&endpoint, "lang", lang_cs);
492 add_assoc_zval(return_value, "client_to_server", &endpoint);
493
494 array_init(&endpoint);
495 add_assoc_string(&endpoint, "crypt", crypt_sc);
496 add_assoc_string(&endpoint, "mac", mac_sc);
497 add_assoc_string(&endpoint, "comp", comp_sc);
498 add_assoc_string(&endpoint, "lang", lang_sc);
499 add_assoc_zval(return_value, "server_to_client", &endpoint);
500 }
501 /* }}} */
502
503 /* {{{ proto string ssh2_fingerprint(resource session[, int flags])
504 * Returns a server hostkey hash from an active session
505 * Defaults to MD5 fingerprint encoded as ASCII hex values
506 */
PHP_FUNCTION(ssh2_fingerprint)507 PHP_FUNCTION(ssh2_fingerprint)
508 {
509 LIBSSH2_SESSION *session;
510 zval *zsession;
511 const char *fingerprint;
512 zend_long flags = 0;
513 int i, fingerprint_len;
514
515 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &zsession, &flags) == FAILURE) {
516 return;
517 }
518 fingerprint_len = (flags & PHP_SSH2_FINGERPRINT_SHA1) ? SHA_DIGEST_LENGTH : MD5_DIGEST_LENGTH;
519
520 if ((session = (LIBSSH2_SESSION *)zend_fetch_resource(Z_RES_P(zsession), PHP_SSH2_SESSION_RES_NAME, le_ssh2_session)) == NULL) {
521 RETURN_FALSE;
522 }
523
524 fingerprint = (char*)libssh2_hostkey_hash(session, (flags & PHP_SSH2_FINGERPRINT_SHA1) ? LIBSSH2_HOSTKEY_HASH_SHA1 : LIBSSH2_HOSTKEY_HASH_MD5);
525 if (!fingerprint) {
526 php_error_docref(NULL, E_WARNING, "Unable to retrieve fingerprint from specified session");
527 RETURN_FALSE;
528 }
529
530 for(i = 0; i < fingerprint_len; i++) {
531 if (fingerprint[i] != '\0') {
532 goto fingerprint_good;
533 }
534 }
535 php_error_docref(NULL, E_WARNING, "No fingerprint available using specified hash");
536 RETURN_NULL();
537 fingerprint_good:
538 if (flags & PHP_SSH2_FINGERPRINT_RAW) {
539 RETURN_STRINGL(fingerprint, fingerprint_len);
540 } else {
541 char *hexchars;
542
543 hexchars = emalloc((fingerprint_len * 2) + 1);
544 for(i = 0; i < fingerprint_len; i++) {
545 snprintf(hexchars + (2 * i), 3, "%02X", (unsigned char)fingerprint[i]);
546 }
547 ZVAL_STRINGL(return_value, hexchars, 2 * fingerprint_len);
548 efree(hexchars);
549 }
550 }
551 /* }}} */
552
553 /* {{{ proto array ssh2_auth_none(resource session, string username)
554 * Attempt "none" authentication, returns a list of allowed methods on failed authentication,
555 * false on utter failure, or true on success
556 */
PHP_FUNCTION(ssh2_auth_none)557 PHP_FUNCTION(ssh2_auth_none)
558 {
559 LIBSSH2_SESSION *session;
560 zval *zsession;
561 char *username, *methods, *s, *p;
562 size_t username_len;
563
564 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &zsession, &username, &username_len) == FAILURE) {
565 return;
566 }
567
568 if ((session = (LIBSSH2_SESSION *)zend_fetch_resource(Z_RES_P(zsession), PHP_SSH2_SESSION_RES_NAME, le_ssh2_session)) == NULL) {
569 RETURN_FALSE;
570 }
571
572 s = methods = libssh2_userauth_list(session, username, username_len);
573 if (!methods) {
574 /* Either bad failure, or unexpected success */
575 RETURN_BOOL(libssh2_userauth_authenticated(session));
576 }
577
578 array_init(return_value);
579 while ((p = strchr(s, ','))) {
580 if ((p - s) > 0) {
581 add_next_index_stringl(return_value, s, p - s);
582 }
583 s = p + 1;
584 }
585 if (strlen(s)) {
586 add_next_index_string(return_value, s);
587 }
588 }
589 /* }}} */
590
591 char *password_for_kbd_callback;
592
kbd_callback(const char * name,int name_len,const char * instruction,int instruction_len,int num_prompts,const LIBSSH2_USERAUTH_KBDINT_PROMPT * prompts,LIBSSH2_USERAUTH_KBDINT_RESPONSE * responses,void ** abstract)593 static void kbd_callback(const char *name, int name_len,
594 const char *instruction, int instruction_len,
595 int num_prompts,
596 const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
597 LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
598 void **abstract)
599 {
600 (void)name;
601 (void)name_len;
602 (void)instruction;
603 (void)instruction_len;
604 if (num_prompts == 1) {
605 responses[0].text = estrdup(password_for_kbd_callback);
606 responses[0].length = strlen(password_for_kbd_callback);
607 }
608 (void)prompts;
609 (void)abstract;
610 }
611
612 /* {{{ proto bool ssh2_auth_password(resource session, string username, string password)
613 * Authenticate over SSH using a plain password
614 */
PHP_FUNCTION(ssh2_auth_password)615 PHP_FUNCTION(ssh2_auth_password)
616 {
617 LIBSSH2_SESSION *session;
618 zval *zsession;
619 zend_string *username, *password;
620 char *userauthlist;
621
622 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS", &zsession, &username, &password) == FAILURE) {
623 return;
624 }
625
626 SSH2_FETCH_NONAUTHENTICATED_SESSION(session, zsession);
627
628 userauthlist = libssh2_userauth_list(session, username->val, username->len);
629
630 if (userauthlist != NULL) {
631 password_for_kbd_callback = password->val;
632 if (strstr(userauthlist, "keyboard-interactive") != NULL) {
633 if (libssh2_userauth_keyboard_interactive(session, username->val, &kbd_callback) == 0) {
634 RETURN_TRUE;
635 }
636 }
637
638 /* TODO: Support password change callback */
639 if (libssh2_userauth_password_ex(session, username->val, username->len, password->val, password->len, NULL)) {
640 php_error_docref(NULL, E_WARNING, "Authentication failed for %s using password", username->val);
641 RETURN_FALSE;
642 }
643 }
644
645 RETURN_TRUE;
646 }
647 /* }}} */
648
649 /* {{{ proto bool ssh2_auth_pubkey_file(resource session, string username, string pubkeyfile, string privkeyfile[, string passphrase])
650 * Authenticate using a public key
651 */
PHP_FUNCTION(ssh2_auth_pubkey_file)652 PHP_FUNCTION(ssh2_auth_pubkey_file)
653 {
654 LIBSSH2_SESSION *session;
655 zval *zsession;
656 zend_string *username, *pubkey, *privkey, *passphrase;
657 #ifndef PHP_WIN32
658 zend_string *newpath;
659 struct passwd *pws;
660 #endif
661
662 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSSS|S", &zsession, &username, &pubkey, &privkey, &passphrase) == FAILURE) {
663 return;
664 }
665
666 if (php_check_open_basedir(ZSTR_VAL(pubkey)) || php_check_open_basedir(ZSTR_VAL(privkey))) {
667 RETURN_FALSE;
668 }
669
670 SSH2_FETCH_NONAUTHENTICATED_SESSION(session, zsession);
671 #ifndef PHP_WIN32
672 /* Explode '~/paths' stopgap fix because libssh2 does not accept tilde for homedir
673 This should be ifdef'ed when a fix is available to support older libssh2 versions*/
674 pws = getpwuid(geteuid());
675 if (ZSTR_LEN(pubkey) >= 2 && *(ZSTR_VAL(pubkey)) == '~' && *(ZSTR_VAL(pubkey)+1) == '/') {
676 newpath = zend_string_alloc(strlen(pws->pw_dir) + ZSTR_LEN(pubkey), 0);
677 strcpy(ZSTR_VAL(newpath), pws->pw_dir);
678 strcat(ZSTR_VAL(newpath), ZSTR_VAL(pubkey)+1);
679 zend_string_release(pubkey);
680 pubkey = newpath;
681 }
682 if (ZSTR_LEN(privkey) >= 2 && *(ZSTR_VAL(privkey)) == '~' && *(ZSTR_VAL(privkey)+1) == '/') {
683 newpath = zend_string_alloc(strlen(pws->pw_dir) + ZSTR_LEN(privkey), 0);
684 strcpy(ZSTR_VAL(newpath), pws->pw_dir);
685 strcat(ZSTR_VAL(newpath), ZSTR_VAL(privkey)+1);
686 zend_string_release(privkey);
687 privkey = newpath;
688 }
689 #endif
690
691 /* TODO: Support passphrase callback */
692 if (libssh2_userauth_publickey_fromfile_ex(session, ZSTR_VAL(username), ZSTR_LEN(username), ZSTR_VAL(pubkey), ZSTR_VAL(privkey), ZSTR_VAL(passphrase))) {
693 char *buf;
694 int len;
695 libssh2_session_last_error(session, &buf, &len, 0);
696 php_error_docref(NULL, E_WARNING, "Authentication failed for %s using public key: %s", ZSTR_VAL(username), buf);
697 RETURN_FALSE;
698 }
699
700 RETURN_TRUE;
701 }
702 /* }}} */
703
704 /* {{{ proto bool ssh2_auth_hostbased_file(resource session, string username, string hostname, string pubkeyfile, string privkeyfile[, string passphrase[, string local_username]])
705 * Authenticate using a hostkey
706 */
PHP_FUNCTION(ssh2_auth_hostbased_file)707 PHP_FUNCTION(ssh2_auth_hostbased_file)
708 {
709 LIBSSH2_SESSION *session;
710 zval *zsession;
711 char *username, *hostname, *pubkey, *privkey, *passphrase = NULL, *local_username = NULL;
712 size_t username_len, hostname_len, pubkey_len, privkey_len, passphrase_len, local_username_len;
713
714 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rssss|s!s!", &zsession, &username, &username_len,
715 &hostname, &hostname_len,
716 &pubkey, &pubkey_len,
717 &privkey, &privkey_len,
718 &passphrase, &passphrase_len,
719 &local_username, &local_username_len) == FAILURE) {
720 return;
721 }
722
723 if (php_check_open_basedir(pubkey) || php_check_open_basedir(privkey)) {
724 RETURN_FALSE;
725 }
726
727 SSH2_FETCH_NONAUTHENTICATED_SESSION(session, zsession);
728
729 if (!local_username) {
730 local_username = username;
731 local_username_len = username_len;
732 }
733
734 /* TODO: Support passphrase callback */
735 if (libssh2_userauth_hostbased_fromfile_ex(session, username, username_len, pubkey, privkey, passphrase, hostname, hostname_len, local_username, local_username_len)) {
736 php_error_docref(NULL, E_WARNING, "Authentication failed for %s using hostbased public key", username);
737 RETURN_FALSE;
738 }
739
740 RETURN_TRUE;
741 }
742 /* }}} */
743
744 /* {{{ proto resource ssh2_forward_listen(resource session, int port[, string host[, long max_connections]])
745 * Bind a port on the remote server and listen for connections
746 */
PHP_FUNCTION(ssh2_forward_listen)747 PHP_FUNCTION(ssh2_forward_listen)
748 {
749 zval *zsession;
750 LIBSSH2_SESSION *session;
751 LIBSSH2_LISTENER *listener;
752 php_ssh2_listener_data *data;
753 zend_long port;
754 char *host = NULL;
755 size_t host_len;
756 zend_long max_connections = PHP_SSH2_LISTEN_MAX_QUEUED;
757
758 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl|sl", &zsession, &port, &host, &host_len, &max_connections) == FAILURE) {
759 return;
760 }
761
762 SSH2_FETCH_AUTHENTICATED_SESSION(session, zsession);
763
764 listener = libssh2_channel_forward_listen_ex(session, host, port, NULL, max_connections);
765
766 if (!listener) {
767 php_error_docref(NULL, E_WARNING, "Failure listening on remote port");
768 RETURN_FALSE;
769 }
770
771 data = emalloc(sizeof(php_ssh2_listener_data));
772 data->session = session;
773 data->session_rsrc = Z_RES_P(zsession);
774 Z_ADDREF_P(zsession);
775 data->listener = listener;
776
777 RETURN_RES(zend_register_resource(data, le_ssh2_listener));
778 }
779 /* }}} */
780
781 /* {{{ proto stream ssh2_forward_accept(resource listener[, string &shost[, long &sport]])
782 * Accept a connection created by a listener
783 */
PHP_FUNCTION(ssh2_forward_accept)784 PHP_FUNCTION(ssh2_forward_accept)
785 {
786 zval *zlistener;
787 php_ssh2_listener_data *data;
788 LIBSSH2_CHANNEL *channel;
789 php_ssh2_channel_data *channel_data;
790 php_stream *stream;
791
792 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zlistener) == FAILURE) {
793 return;
794 }
795
796 if ((data = (php_ssh2_listener_data *)zend_fetch_resource(Z_RES_P(zlistener), PHP_SSH2_LISTENER_RES_NAME, le_ssh2_listener)) == NULL) {
797 RETURN_FALSE;
798 }
799
800 channel = libssh2_channel_forward_accept(data->listener);
801
802 if (!channel) {
803 RETURN_FALSE;
804 }
805
806 channel_data = emalloc(sizeof(php_ssh2_channel_data));
807 channel_data->channel = channel;
808 channel_data->streamid = 0;
809 channel_data->is_blocking = 0;
810 channel_data->session_rsrc = data->session_rsrc;
811 channel_data->refcount = NULL;
812
813 stream = php_stream_alloc(&php_ssh2_channel_stream_ops, channel_data, 0, "r+");
814 if (!stream) {
815 php_error_docref(NULL, E_WARNING, "Failure allocating stream");
816 efree(channel_data);
817 libssh2_channel_free(channel);
818 RETURN_FALSE;
819 }
820
821 #if PHP_VERSION_ID < 70300
822 GC_REFCOUNT(channel_data->session_rsrc)++;
823 #else
824 GC_ADDREF(channel_data->session_rsrc);
825 #endif
826
827 php_stream_to_zval(stream, return_value);
828 }
829 /* }}} */
830
831 /* {{{ proto int ssh2_poll(array &polldes[, int timeout])
832 * Poll the channels/listeners/streams for events
833 * Returns number of descriptors which returned non-zero revents
834 * Input array should be of the form:
835 * array(
836 * 0 => array(
837 * [resource] => $channel,$listener, or $stream
838 * [events] => SSH2_POLL* flags bitwise ORed together
839 * ),
840 * 1 => ...
841 * )
842 * Each subarray will be populated with an revents element on return
843 */
PHP_FUNCTION(ssh2_poll)844 PHP_FUNCTION(ssh2_poll)
845 {
846 zval *zdesc, *subarray, **pollmap;
847 zend_long timeout = PHP_SSH2_DEFAULT_POLL_TIMEOUT;
848 LIBSSH2_POLLFD *pollfds;
849 int numfds, i = 0, fds_ready;
850 int le_stream = php_file_le_stream();
851 int le_pstream = php_file_le_pstream();
852 zend_string *hash_key_zstring;
853
854 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|l", &zdesc, &timeout) == FAILURE) {
855 return;
856 }
857
858 numfds = zend_hash_num_elements(Z_ARRVAL_P(zdesc));
859 pollfds = safe_emalloc(sizeof(LIBSSH2_POLLFD), numfds, 0);
860 pollmap = safe_emalloc(sizeof(zval**), numfds, 0);
861
862 for(zend_hash_internal_pointer_reset(Z_ARRVAL_P(zdesc));
863 (subarray = zend_hash_get_current_data(Z_ARRVAL_P(zdesc))) != NULL;
864 zend_hash_move_forward(Z_ARRVAL_P(zdesc))) {
865 zval *tmpzval;
866 int res_type = 0;
867 void *res;
868
869 if (Z_TYPE_P(subarray) != IS_ARRAY) {
870 php_error_docref(NULL, E_WARNING, "Invalid element in poll array, not a sub array");
871 numfds--;
872 continue;
873 }
874
875 hash_key_zstring = zend_string_init("events", sizeof("events") - 1, 0);
876 if ((tmpzval = zend_hash_find(Z_ARRVAL_P(subarray), hash_key_zstring)) == NULL || Z_TYPE_P(tmpzval) != IS_LONG) {
877 php_error_docref(NULL, E_WARNING, "Invalid data in subarray, no events element, or not a bitmask");
878 numfds--;
879 zend_string_release(hash_key_zstring);
880 continue;
881 }
882 zend_string_release(hash_key_zstring);
883
884 pollfds[i].events = Z_LVAL_P(tmpzval);
885 hash_key_zstring = zend_string_init("resource", sizeof("resource") - 1, 0);
886 if ((tmpzval = zend_hash_find(Z_ARRVAL_P(subarray), hash_key_zstring)) == NULL || Z_TYPE_P(tmpzval) != IS_REFERENCE
887 || (tmpzval = Z_REFVAL_P(tmpzval)) == NULL || Z_TYPE_P(tmpzval) != IS_RESOURCE) {
888 php_error_docref(NULL, E_WARNING, "Invalid data in subarray, no resource element, or not of type resource");
889 numfds--;
890 zend_string_release(hash_key_zstring);
891 continue;
892 }
893 zend_string_release(hash_key_zstring);
894
895 res_type = Z_RES_P(tmpzval)->type;
896 res = zend_fetch_resource_ex(tmpzval, "Poll Resource", res_type);
897 if (res_type == le_ssh2_listener) {
898 pollfds[i].type = LIBSSH2_POLLFD_LISTENER;
899 pollfds[i].fd.listener = ((php_ssh2_listener_data*)res)->listener;
900 } else if ((res_type == le_stream || res_type == le_pstream) &&
901 ((php_stream*)res)->ops == &php_ssh2_channel_stream_ops) {
902 pollfds[i].type = LIBSSH2_POLLFD_CHANNEL;
903 pollfds[i].fd.channel = ((php_ssh2_channel_data*)(((php_stream*)res)->abstract))->channel;
904 /* TODO: Add the ability to select against other stream types */
905 } else {
906 php_error_docref(NULL, E_WARNING, "Invalid resource type in subarray: %s", zend_rsrc_list_get_rsrc_type(Z_RES_P(tmpzval)));
907 numfds--;
908 continue;
909 }
910 pollmap[i] = subarray;
911 i++;
912 }
913
914 fds_ready = libssh2_poll(pollfds, numfds, timeout * 1000);
915
916 for(i = 0; i < numfds; i++) {
917 zval *subarray = pollmap[i];
918
919 if (Z_REFCOUNT_P(subarray) > 1) {
920 /* Make a new copy of the subarray zval* */
921 zval new_subarray;
922 ZVAL_DUP(&new_subarray, subarray);
923
924 /* Decrement refcount prior to swapping in new allocation */
925 Z_DELREF_P(subarray);
926 *pollmap[i] = new_subarray;
927 }
928 hash_key_zstring = zend_string_init("revents", sizeof("revents") - 1, 0);
929 zend_hash_del(Z_ARRVAL_P(subarray), hash_key_zstring);
930 zend_string_release(hash_key_zstring);
931
932 add_assoc_long(subarray, "revents", pollfds[i].revents);
933
934 }
935 efree(pollmap);
936 efree(pollfds);
937
938 RETURN_LONG(fds_ready);
939 }
940 /* }}} */
941
942 /* ***********************
943 * Publickey Subsystem *
944 *********************** */
945
946 /* {{{ proto resource ssh2_publickey_init(resource connection)
947 Initialize the publickey subsystem */
PHP_FUNCTION(ssh2_publickey_init)948 PHP_FUNCTION(ssh2_publickey_init)
949 {
950 zval *zsession;
951 LIBSSH2_SESSION *session;
952 LIBSSH2_PUBLICKEY *pkey;
953 php_ssh2_pkey_subsys_data *data;
954
955 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zsession) == FAILURE) {
956 return;
957 }
958
959 SSH2_FETCH_AUTHENTICATED_SESSION(session, zsession);
960
961 pkey = libssh2_publickey_init(session);
962
963 if (!pkey) {
964 int last_error = 0;
965 char *error_msg = NULL;
966
967 last_error = libssh2_session_last_error(session, &error_msg, NULL, 0);
968 php_error_docref(NULL, E_WARNING, "Unable to initialize publickey subsystem(%d) %s", last_error, error_msg);
969 RETURN_FALSE;
970 }
971
972 data = emalloc(sizeof(php_ssh2_pkey_subsys_data));
973 data->session = session;
974 data->session_rsrc = Z_RES_P(zsession);
975 Z_ADDREF_P(zsession);
976 data->pkey = pkey;
977
978 RETURN_RES(zend_register_resource(data, le_ssh2_pkey_subsys));
979 }
980 /* }}} */
981
982 /* {{{ proto bool ssh2_publickey_add(resource pkey, string algoname, string blob[, bool overwrite=FALSE [,array attributes=NULL]])
983 Add an additional publickey */
PHP_FUNCTION(ssh2_publickey_add)984 PHP_FUNCTION(ssh2_publickey_add)
985 {
986 zval *zpkey_data, *zattrs = NULL;
987 php_ssh2_pkey_subsys_data *data;
988 char *algo, *blob;
989 size_t algo_len, blob_len;
990 unsigned long num_attrs = 0;
991 libssh2_publickey_attribute *attrs = NULL;
992 zend_bool overwrite = 0;
993
994 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rss|ba", &zpkey_data, &algo, &algo_len, &blob, &blob_len, &overwrite, &zattrs) == FAILURE) {
995 return;
996 }
997
998 if ((data = (php_ssh2_pkey_subsys_data *)zend_fetch_resource(Z_RES_P(zpkey_data), PHP_SSH2_PKEY_SUBSYS_RES_NAME, le_ssh2_pkey_subsys)) == NULL) {
999 RETURN_FALSE;
1000 }
1001
1002 if (zattrs) {
1003 HashPosition pos;
1004 zval *attr_val;
1005 unsigned long current_attr = 0;
1006
1007 num_attrs = zend_hash_num_elements(Z_ARRVAL_P(zattrs));
1008 attrs = safe_emalloc(num_attrs, sizeof(libssh2_publickey_attribute), 0);
1009
1010 for(zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(zattrs), &pos);
1011 (attr_val = zend_hash_get_current_data_ex(Z_ARRVAL_P(zattrs), &pos)) != NULL;
1012 zend_hash_move_forward_ex(Z_ARRVAL_P(zattrs), &pos)) {
1013 zend_string *key;
1014 int type;
1015 zend_ulong idx;
1016 zval copyval = *attr_val;
1017
1018 type = zend_hash_get_current_key_ex(Z_ARRVAL_P(zattrs), &key, &idx, &pos);
1019 if (type == HASH_KEY_NON_EXISTENT) {
1020 /* All but impossible */
1021 break;
1022 }
1023 if (type == HASH_KEY_IS_LONG) {
1024 /* Malformed, ignore */
1025 php_error_docref(NULL, E_WARNING, "Malformed attirbute array, contains numeric index");
1026 num_attrs--;
1027 continue;
1028 }
1029
1030 if (!key || (key->len == 1 && key->val[0] == '*')) {
1031 /* Empty key, ignore */
1032 php_error_docref(NULL, E_WARNING, "Empty attribute key");
1033 num_attrs--;
1034 continue;
1035 }
1036
1037 zval_copy_ctor(©val);
1038 // TODO Sean-Der
1039 //Z_UNSET_ISREF_P(©val);
1040 //Z_SET_REFCOUNT_P(©val, 1);
1041 convert_to_string(©val);
1042
1043 if (key->val[0] == '*') {
1044 attrs[current_attr].mandatory = 1;
1045 attrs[current_attr].name = key->val + 1;
1046 attrs[current_attr].name_len = key->len - 2;
1047 } else {
1048 attrs[current_attr].mandatory = 0;
1049 attrs[current_attr].name = key->val;
1050 attrs[current_attr].name_len = key->len - 1;
1051 }
1052 attrs[current_attr].value_len = Z_STRLEN(copyval);
1053 attrs[current_attr].value = Z_STRVAL(copyval);
1054
1055 /* copyval deliberately not dtor'd, we're stealing the string */
1056 current_attr++;
1057 }
1058 }
1059
1060 if (libssh2_publickey_add_ex(data->pkey, (unsigned char *) algo, algo_len, (unsigned char *) blob, blob_len, overwrite, num_attrs, attrs)) {
1061 php_error_docref(NULL, E_WARNING, "Unable to add %s key", algo);
1062 RETVAL_FALSE;
1063 } else {
1064 RETVAL_TRUE;
1065 }
1066
1067 if (attrs) {
1068 unsigned long i;
1069
1070 for(i = 0; i < num_attrs; i++) {
1071 /* name doesn't need freeing */
1072 // TODO Sean-Der
1073 //efree(attrs[i].value);
1074 }
1075 efree(attrs);
1076 }
1077 }
1078 /* }}} */
1079
1080 /* {{{ proto bool ssh2_publickey_remove(resource pkey, string algoname, string blob)
1081 Remove a publickey entry */
PHP_FUNCTION(ssh2_publickey_remove)1082 PHP_FUNCTION(ssh2_publickey_remove)
1083 {
1084 zval *zpkey_data;
1085 php_ssh2_pkey_subsys_data *data;
1086 char *algo, *blob;
1087 size_t algo_len, blob_len;
1088
1089 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rss", &zpkey_data, &algo, &algo_len, &blob, &blob_len) == FAILURE) {
1090 return;
1091 }
1092
1093 if ((data = (php_ssh2_pkey_subsys_data *)zend_fetch_resource(Z_RES_P(zpkey_data), PHP_SSH2_PKEY_SUBSYS_RES_NAME, le_ssh2_pkey_subsys)) == NULL) {
1094 RETURN_FALSE;
1095 }
1096
1097 if (libssh2_publickey_remove_ex(data->pkey, (unsigned char *) algo, algo_len, (unsigned char *) blob, blob_len)) {
1098 php_error_docref(NULL, E_WARNING, "Unable to remove %s key", algo);
1099 RETURN_FALSE;
1100 }
1101
1102 RETURN_TRUE;
1103 }
1104 /* }}} */
1105
1106 /* {{{ proto array ssh2_publickey_list(resource pkey)
1107 List currently installed publickey entries */
PHP_FUNCTION(ssh2_publickey_list)1108 PHP_FUNCTION(ssh2_publickey_list)
1109 {
1110 zval *zpkey_data;
1111 php_ssh2_pkey_subsys_data *data;
1112 unsigned long num_keys, i;
1113 libssh2_publickey_list *keys;
1114 zend_string *hash_key_zstring;
1115
1116 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zpkey_data) == FAILURE) {
1117 return;
1118 }
1119
1120 if ((data = (php_ssh2_pkey_subsys_data *)zend_fetch_resource(Z_RES_P(zpkey_data), PHP_SSH2_PKEY_SUBSYS_RES_NAME, le_ssh2_pkey_subsys)) == NULL) {
1121 RETURN_FALSE;
1122 }
1123
1124 if (libssh2_publickey_list_fetch(data->pkey, &num_keys, &keys)) {
1125 php_error_docref(NULL, E_WARNING, "Unable to list keys on remote server");
1126 RETURN_FALSE;
1127 }
1128
1129 array_init(return_value);
1130 for(i = 0; i < num_keys; i++) {
1131 zval key, attrs;
1132 unsigned long j;
1133
1134 array_init(&key);
1135
1136 add_assoc_stringl(&key, "name", (char *) keys[i].name, keys[i].name_len);
1137 add_assoc_stringl(&key, "blob", (char *) keys[i].blob, keys[i].blob_len);
1138
1139 array_init(&attrs);
1140 for(j = 0; j < keys[i].num_attrs; j++) {
1141 zval attr;
1142
1143 ZVAL_STRINGL(&attr, keys[i].attrs[j].value, keys[i].attrs[j].value_len);
1144 hash_key_zstring = zend_string_init(keys[i].attrs[j].name, keys[i].attrs[j].name_len, 0);
1145 zend_hash_add(Z_ARRVAL_P(&attrs), hash_key_zstring, &attr);
1146 zend_string_release(hash_key_zstring);
1147 }
1148 add_assoc_zval(&key, "attrs", &attrs);
1149
1150 add_next_index_zval(return_value, &key);
1151 }
1152
1153 libssh2_publickey_list_free(data->pkey, keys);
1154 }
1155 /* }}} */
1156
1157 /* {{{ proto array ssh2_auth_agent(resource session, string username)
1158 Authenticate using the ssh agent */
PHP_FUNCTION(ssh2_auth_agent)1159 PHP_FUNCTION(ssh2_auth_agent)
1160 {
1161 #ifdef PHP_SSH2_AGENT_AUTH
1162 zval *zsession;
1163 char *username;
1164 size_t username_len;
1165
1166 LIBSSH2_SESSION *session;
1167 char *userauthlist;
1168 LIBSSH2_AGENT *agent = NULL;
1169 int rc;
1170 struct libssh2_agent_publickey *identity, *prev_identity = NULL;
1171
1172 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &zsession, &username, &username_len) == FAILURE) {
1173 return;
1174 }
1175
1176 SSH2_FETCH_NONAUTHENTICATED_SESSION(session, zsession);
1177
1178 /* check what authentication methods are available */
1179 userauthlist = libssh2_userauth_list(session, username, username_len);
1180
1181 if (userauthlist != NULL && strstr(userauthlist, "publickey") == NULL) {
1182 php_error_docref(NULL, E_WARNING, "\"publickey\" authentication is not supported");
1183 RETURN_FALSE;
1184 }
1185
1186 /* Connect to the ssh-agent */
1187 agent = libssh2_agent_init(session);
1188
1189 if (!agent) {
1190 php_error_docref(NULL, E_WARNING, "Failure initializing ssh-agent support");
1191 RETURN_FALSE;
1192 }
1193
1194 if (libssh2_agent_connect(agent)) {
1195 php_error_docref(NULL, E_WARNING, "Failure connecting to ssh-agent");
1196 libssh2_agent_free(agent);
1197 RETURN_FALSE;
1198 }
1199
1200 if (libssh2_agent_list_identities(agent)) {
1201 php_error_docref(NULL, E_WARNING, "Failure requesting identities to ssh-agent");
1202 libssh2_agent_disconnect(agent);
1203 libssh2_agent_free(agent);
1204 RETURN_FALSE;
1205 }
1206
1207 while (1) {
1208 rc = libssh2_agent_get_identity(agent, &identity, prev_identity);
1209
1210 if (rc == 1) {
1211 php_error_docref(NULL, E_WARNING, "Couldn't continue authentication");
1212 libssh2_agent_disconnect(agent);
1213 libssh2_agent_free(agent);
1214 RETURN_FALSE;
1215 }
1216
1217 if (rc < 0) {
1218 php_error_docref(NULL, E_WARNING, "Failure obtaining identity from ssh-agent support");
1219 libssh2_agent_disconnect(agent);
1220 libssh2_agent_free(agent);
1221 RETURN_FALSE;
1222 }
1223
1224 if (!libssh2_agent_userauth(agent, username, identity)) {
1225 libssh2_agent_disconnect(agent);
1226 libssh2_agent_free(agent);
1227 RETURN_TRUE;
1228 }
1229 prev_identity = identity;
1230 }
1231 #else
1232 php_error_docref(NULL, E_WARNING, "Upgrade the libssh2 library (needs 1.2.3 or higher) and reinstall the ssh2 extension for ssh2 agent support");
1233 RETURN_FALSE;
1234 #endif /* PHP_SSH2_AGENT_AUTH */
1235 }
1236 /* }}} */
1237
1238 /* ***********************
1239 * Module Housekeeping *
1240 *********************** */
1241
php_ssh2_session_dtor(zend_resource * rsrc)1242 static void php_ssh2_session_dtor(zend_resource *rsrc)
1243 {
1244 LIBSSH2_SESSION *session = (LIBSSH2_SESSION*)rsrc->ptr;
1245 php_ssh2_session_data **data = (php_ssh2_session_data**)libssh2_session_abstract(session);
1246
1247 libssh2_session_disconnect(session, "PECL/ssh2 (http://pecl.php.net/packages/ssh2)");
1248
1249 if (*data) {
1250 if ((*data)->ignore_cb) {
1251 zval_ptr_dtor((*data)->ignore_cb);
1252 }
1253 if ((*data)->debug_cb) {
1254 zval_ptr_dtor((*data)->debug_cb);
1255 }
1256 if ((*data)->macerror_cb) {
1257 zval_ptr_dtor((*data)->macerror_cb);
1258 }
1259 if ((*data)->disconnect_cb) {
1260 zval_ptr_dtor((*data)->disconnect_cb);
1261 }
1262
1263 closesocket((*data)->socket);
1264
1265 efree(*data);
1266 *data = NULL;
1267 }
1268
1269 libssh2_session_free(session);
1270 }
1271
php_ssh2_listener_dtor(zend_resource * rsrc)1272 static void php_ssh2_listener_dtor(zend_resource *rsrc)
1273 {
1274 php_ssh2_listener_data *data = (php_ssh2_listener_data*)rsrc->ptr;
1275 LIBSSH2_LISTENER *listener = data->listener;
1276
1277 libssh2_channel_forward_cancel(listener);
1278 zend_list_delete(data->session_rsrc);
1279 efree(data);
1280 }
1281
php_ssh2_pkey_subsys_dtor(zend_resource * rsrc)1282 static void php_ssh2_pkey_subsys_dtor(zend_resource *rsrc)
1283 {
1284 php_ssh2_pkey_subsys_data *data = (php_ssh2_pkey_subsys_data*)rsrc->ptr;
1285 LIBSSH2_PUBLICKEY *pkey = data->pkey;
1286
1287 libssh2_publickey_shutdown(pkey);
1288 zend_list_delete(data->session_rsrc);
1289 efree(data);
1290 }
1291
1292 /* {{{ PHP_MINIT_FUNCTION
1293 */
PHP_MINIT_FUNCTION(ssh2)1294 PHP_MINIT_FUNCTION(ssh2)
1295 {
1296 le_ssh2_session = zend_register_list_destructors_ex(php_ssh2_session_dtor, NULL, PHP_SSH2_SESSION_RES_NAME, module_number);
1297 le_ssh2_listener = zend_register_list_destructors_ex(php_ssh2_listener_dtor, NULL, PHP_SSH2_LISTENER_RES_NAME, module_number);
1298 le_ssh2_sftp = zend_register_list_destructors_ex(php_ssh2_sftp_dtor, NULL, PHP_SSH2_SFTP_RES_NAME, module_number);
1299 le_ssh2_pkey_subsys = zend_register_list_destructors_ex(php_ssh2_pkey_subsys_dtor, NULL, PHP_SSH2_PKEY_SUBSYS_RES_NAME, module_number);
1300
1301 REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_MD5", PHP_SSH2_FINGERPRINT_MD5, CONST_CS | CONST_PERSISTENT);
1302 REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_SHA1", PHP_SSH2_FINGERPRINT_SHA1, CONST_CS | CONST_PERSISTENT);
1303 REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_HEX", PHP_SSH2_FINGERPRINT_HEX, CONST_CS | CONST_PERSISTENT);
1304 REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_RAW", PHP_SSH2_FINGERPRINT_RAW, CONST_CS | CONST_PERSISTENT);
1305
1306 REGISTER_LONG_CONSTANT("SSH2_TERM_UNIT_CHARS", PHP_SSH2_TERM_UNIT_CHARS, CONST_CS | CONST_PERSISTENT);
1307 REGISTER_LONG_CONSTANT("SSH2_TERM_UNIT_PIXELS", PHP_SSH2_TERM_UNIT_PIXELS, CONST_CS | CONST_PERSISTENT);
1308
1309 REGISTER_STRING_CONSTANT("SSH2_DEFAULT_TERMINAL", PHP_SSH2_DEFAULT_TERMINAL, CONST_CS | CONST_PERSISTENT);
1310 REGISTER_LONG_CONSTANT("SSH2_DEFAULT_TERM_WIDTH", PHP_SSH2_DEFAULT_TERM_WIDTH, CONST_CS | CONST_PERSISTENT);
1311 REGISTER_LONG_CONSTANT("SSH2_DEFAULT_TERM_HEIGHT", PHP_SSH2_DEFAULT_TERM_HEIGHT, CONST_CS | CONST_PERSISTENT);
1312 REGISTER_LONG_CONSTANT("SSH2_DEFAULT_TERM_UNIT", PHP_SSH2_DEFAULT_TERM_UNIT, CONST_CS | CONST_PERSISTENT);
1313
1314 REGISTER_LONG_CONSTANT("SSH2_STREAM_STDIO", 0, CONST_CS | CONST_PERSISTENT);
1315 REGISTER_LONG_CONSTANT("SSH2_STREAM_STDERR", SSH_EXTENDED_DATA_STDERR, CONST_CS | CONST_PERSISTENT);
1316
1317 /* events/revents */
1318 REGISTER_LONG_CONSTANT("SSH2_POLLIN", LIBSSH2_POLLFD_POLLIN, CONST_CS | CONST_PERSISTENT);
1319 REGISTER_LONG_CONSTANT("SSH2_POLLEXT", LIBSSH2_POLLFD_POLLEXT, CONST_CS | CONST_PERSISTENT);
1320 REGISTER_LONG_CONSTANT("SSH2_POLLOUT", LIBSSH2_POLLFD_POLLOUT, CONST_CS | CONST_PERSISTENT);
1321
1322 /* revents only */
1323 REGISTER_LONG_CONSTANT("SSH2_POLLERR", LIBSSH2_POLLFD_POLLERR, CONST_CS | CONST_PERSISTENT);
1324 REGISTER_LONG_CONSTANT("SSH2_POLLHUP", LIBSSH2_POLLFD_POLLHUP, CONST_CS | CONST_PERSISTENT);
1325 REGISTER_LONG_CONSTANT("SSH2_POLLNVAL", LIBSSH2_POLLFD_POLLNVAL, CONST_CS | CONST_PERSISTENT);
1326 REGISTER_LONG_CONSTANT("SSH2_POLL_SESSION_CLOSED", LIBSSH2_POLLFD_SESSION_CLOSED, CONST_CS | CONST_PERSISTENT);
1327 REGISTER_LONG_CONSTANT("SSH2_POLL_CHANNEL_CLOSED", LIBSSH2_POLLFD_CHANNEL_CLOSED, CONST_CS | CONST_PERSISTENT);
1328 REGISTER_LONG_CONSTANT("SSH2_POLL_LISTENER_CLOSED", LIBSSH2_POLLFD_LISTENER_CLOSED, CONST_CS | CONST_PERSISTENT);
1329
1330 return (php_register_url_stream_wrapper("ssh2.shell", &php_ssh2_stream_wrapper_shell) == SUCCESS &&
1331 php_register_url_stream_wrapper("ssh2.exec", &php_ssh2_stream_wrapper_exec) == SUCCESS &&
1332 php_register_url_stream_wrapper("ssh2.tunnel", &php_ssh2_stream_wrapper_tunnel) == SUCCESS &&
1333 php_register_url_stream_wrapper("ssh2.scp", &php_ssh2_stream_wrapper_scp) == SUCCESS &&
1334 php_register_url_stream_wrapper("ssh2.sftp", &php_ssh2_sftp_wrapper) == SUCCESS) ? SUCCESS : FAILURE;
1335 }
1336 /* }}} */
1337
1338 /* {{{ PHP_MSHUTDOWN_FUNCTION
1339 */
PHP_MSHUTDOWN_FUNCTION(ssh2)1340 PHP_MSHUTDOWN_FUNCTION(ssh2)
1341 {
1342 return (php_unregister_url_stream_wrapper("ssh2.shell") == SUCCESS &&
1343 php_unregister_url_stream_wrapper("ssh2.exec") == SUCCESS &&
1344 php_unregister_url_stream_wrapper("ssh2.tunnel") == SUCCESS &&
1345 php_unregister_url_stream_wrapper("ssh2.scp") == SUCCESS &&
1346 php_unregister_url_stream_wrapper("ssh2.sftp") == SUCCESS) ? SUCCESS : FAILURE;
1347 }
1348 /* }}} */
1349
1350 /* {{{ PHP_MINFO_FUNCTION
1351 */
PHP_MINFO_FUNCTION(ssh2)1352 PHP_MINFO_FUNCTION(ssh2)
1353 {
1354 php_info_print_table_start();
1355 php_info_print_table_header(2, "SSH2 support", "enabled");
1356 php_info_print_table_row(2, "extension version", PHP_SSH2_VERSION);
1357 php_info_print_table_row(2, "libssh2 version", LIBSSH2_VERSION);
1358 php_info_print_table_row(2, "banner", LIBSSH2_SSH_BANNER);
1359 php_info_print_table_end();
1360 }
1361 /* }}} */
1362
1363 /* {{{ ZEND_BEGIN_ARG_INFO
1364 */
1365 ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_connect, 0, 0, 1)
1366 ZEND_ARG_INFO(0, host)
1367 ZEND_ARG_INFO(0, port)
1368 ZEND_ARG_INFO(0, methods)
1369 ZEND_ARG_INFO(0, callbacks)
1370 ZEND_END_ARG_INFO()
1371
1372 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_disconnect, 1)
1373 ZEND_ARG_INFO(0, session)
1374 ZEND_END_ARG_INFO()
1375
1376 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_methods_negotiated, 1)
1377 ZEND_ARG_INFO(0, session)
1378 ZEND_END_ARG_INFO()
1379
1380 ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_fingerprint, 0, 0, 1)
1381 ZEND_ARG_INFO(0, session)
1382 ZEND_ARG_INFO(0, flags)
1383 ZEND_END_ARG_INFO()
1384
1385 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_auth_none, 2)
1386 ZEND_ARG_INFO(0, session)
1387 ZEND_ARG_INFO(0, username)
1388 ZEND_END_ARG_INFO()
1389
1390 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_auth_password, 3)
1391 ZEND_ARG_INFO(0, session)
1392 ZEND_ARG_INFO(0, username)
1393 ZEND_ARG_INFO(0, password)
1394 ZEND_END_ARG_INFO()
1395
1396 ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_auth_pubkey_file, 0, 0, 4)
1397 ZEND_ARG_INFO(0, session)
1398 ZEND_ARG_INFO(0, username)
1399 ZEND_ARG_INFO(0, pubkeyfile)
1400 ZEND_ARG_INFO(0, privkeyfile)
1401 ZEND_ARG_INFO(0, passphrase)
1402 ZEND_END_ARG_INFO()
1403
1404 ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_auth_hostbased_file, 0, 0, 5)
1405 ZEND_ARG_INFO(0, session)
1406 ZEND_ARG_INFO(0, username)
1407 ZEND_ARG_INFO(0, hostname)
1408 ZEND_ARG_INFO(0, pubkeyfile)
1409 ZEND_ARG_INFO(0, privkeyfile)
1410 ZEND_ARG_INFO(0, passphrase)
1411 ZEND_ARG_INFO(0, local_username)
1412 ZEND_END_ARG_INFO()
1413
1414 ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_forward_listen, 0, 0, 2)
1415 ZEND_ARG_INFO(0, session)
1416 ZEND_ARG_INFO(0, port)
1417 ZEND_ARG_INFO(0, host)
1418 ZEND_ARG_INFO(0, max_connections)
1419 ZEND_END_ARG_INFO()
1420
1421 ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_forward_accept, 0, 0, 1)
1422 ZEND_ARG_INFO(0, listener)
1423 ZEND_ARG_INFO(1, host)
1424 ZEND_ARG_INFO(0, port)
1425 ZEND_END_ARG_INFO()
1426
1427 ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_shell, 0, 0, 1)
1428 ZEND_ARG_INFO(0, session)
1429 ZEND_ARG_INFO(0, termtype)
1430 ZEND_ARG_INFO(0, env)
1431 ZEND_ARG_INFO(0, width)
1432 ZEND_ARG_INFO(0, height)
1433 ZEND_ARG_INFO(0, width_height_type)
1434 ZEND_END_ARG_INFO()
1435
1436 ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_exec, 0, 0, 2)
1437 ZEND_ARG_INFO(0, session)
1438 ZEND_ARG_INFO(0, command)
1439 ZEND_ARG_INFO(0, pty)
1440 ZEND_ARG_INFO(0, env)
1441 ZEND_ARG_INFO(0, width)
1442 ZEND_ARG_INFO(0, height)
1443 ZEND_ARG_INFO(0, width_height_type)
1444 ZEND_END_ARG_INFO()
1445
1446 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_tunnel, 3)
1447 ZEND_ARG_INFO(0, session)
1448 ZEND_ARG_INFO(0, host)
1449 ZEND_ARG_INFO(0, port)
1450 ZEND_END_ARG_INFO()
1451
1452 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_scp_recv, 3)
1453 ZEND_ARG_INFO(0, session)
1454 ZEND_ARG_INFO(0, remote_file)
1455 ZEND_ARG_INFO(0, local_file)
1456 ZEND_END_ARG_INFO()
1457
1458 ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_scp_send, 0, 0, 3)
1459 ZEND_ARG_INFO(0, session)
1460 ZEND_ARG_INFO(0, local_file)
1461 ZEND_ARG_INFO(0, remote_file)
1462 ZEND_ARG_INFO(0, create_mode)
1463 ZEND_END_ARG_INFO()
1464
1465 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_fetch_stream, 2)
1466 ZEND_ARG_INFO(0, channel)
1467 ZEND_ARG_INFO(0, streamid)
1468 ZEND_END_ARG_INFO()
1469
1470 ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_poll, 0, 0, 1)
1471 ZEND_ARG_INFO(1, polldes)
1472 ZEND_ARG_INFO(0, timeout)
1473 ZEND_END_ARG_INFO()
1474
1475 ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_send_eof, 0, 0, 1)
1476 ZEND_ARG_INFO(0, channel)
1477 ZEND_END_ARG_INFO()
1478
1479 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_sftp, 1)
1480 ZEND_ARG_INFO(0, session)
1481 ZEND_END_ARG_INFO()
1482
1483 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_sftp_rename, 3)
1484 ZEND_ARG_INFO(0, sftp)
1485 ZEND_ARG_INFO(0, from)
1486 ZEND_ARG_INFO(0, to)
1487 ZEND_END_ARG_INFO()
1488
1489 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_sftp_unlink, 2)
1490 ZEND_ARG_INFO(0, sftp)
1491 ZEND_ARG_INFO(0, filename)
1492 ZEND_END_ARG_INFO()
1493
1494 ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_sftp_mkdir, 0, 0, 2)
1495 ZEND_ARG_INFO(0, sftp)
1496 ZEND_ARG_INFO(0, dirname)
1497 ZEND_ARG_INFO(0, mode)
1498 ZEND_ARG_INFO(0, recursive)
1499 ZEND_END_ARG_INFO()
1500
1501 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_sftp_rmdir, 2)
1502 ZEND_ARG_INFO(0, sftp)
1503 ZEND_ARG_INFO(0, dirname)
1504 ZEND_END_ARG_INFO()
1505
1506 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_sftp_chmod, 3)
1507 ZEND_ARG_INFO(0, sftp)
1508 ZEND_ARG_INFO(0, filename)
1509 ZEND_ARG_INFO(0, mode)
1510 ZEND_END_ARG_INFO()
1511
1512 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_sftp_stat, 2)
1513 ZEND_ARG_INFO(0, sftp)
1514 ZEND_ARG_INFO(0, path)
1515 ZEND_END_ARG_INFO()
1516
1517 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_sftp_lstat, 2)
1518 ZEND_ARG_INFO(0, sftp)
1519 ZEND_ARG_INFO(0, path)
1520 ZEND_END_ARG_INFO()
1521
1522 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_sftp_symlink, 3)
1523 ZEND_ARG_INFO(0, sftp)
1524 ZEND_ARG_INFO(0, target)
1525 ZEND_ARG_INFO(0, link)
1526 ZEND_END_ARG_INFO()
1527
1528 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_sftp_readlink, 2)
1529 ZEND_ARG_INFO(0, sftp)
1530 ZEND_ARG_INFO(0, link)
1531 ZEND_END_ARG_INFO()
1532
1533 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_sftp_realpath, 2)
1534 ZEND_ARG_INFO(0, sftp)
1535 ZEND_ARG_INFO(0, filename)
1536 ZEND_END_ARG_INFO()
1537
1538 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_publickey_init, 1)
1539 ZEND_ARG_INFO(0, session)
1540 ZEND_END_ARG_INFO()
1541
1542 ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_publickey_add, 0, 0, 3)
1543 ZEND_ARG_INFO(0, pkey)
1544 ZEND_ARG_INFO(0, algoname)
1545 ZEND_ARG_INFO(0, blob)
1546 ZEND_ARG_INFO(0, overwrite)
1547 ZEND_ARG_INFO(0, attributes)
1548 ZEND_END_ARG_INFO()
1549
1550 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_publickey_remove, 3)
1551 ZEND_ARG_INFO(0, pkey)
1552 ZEND_ARG_INFO(0, algoname)
1553 ZEND_ARG_INFO(0, blob)
1554 ZEND_END_ARG_INFO()
1555
1556 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_publickey_list, 1)
1557 ZEND_ARG_INFO(0, pkey)
1558 ZEND_END_ARG_INFO()
1559
1560 ZEND_BEGIN_ARG_INFO(arginfo_ssh2_auth_agent, 2)
1561 ZEND_ARG_INFO(0, session)
1562 ZEND_ARG_INFO(0, username)
1563 ZEND_END_ARG_INFO()
1564 /* }}} */
1565
1566 /* {{{ ssh2_functions[]
1567 */
1568 zend_function_entry ssh2_functions[] = {
1569 PHP_FE(ssh2_connect, arginfo_ssh2_connect)
1570 PHP_FE(ssh2_disconnect, arginfo_ssh2_disconnect)
1571 PHP_FE(ssh2_methods_negotiated, arginfo_ssh2_methods_negotiated)
1572 PHP_FE(ssh2_fingerprint, arginfo_ssh2_fingerprint)
1573
1574 PHP_FE(ssh2_auth_none, arginfo_ssh2_auth_none)
1575 PHP_FE(ssh2_auth_password, arginfo_ssh2_auth_password)
1576 PHP_FE(ssh2_auth_pubkey_file, arginfo_ssh2_auth_pubkey_file)
1577 PHP_FE(ssh2_auth_hostbased_file, arginfo_ssh2_auth_hostbased_file)
1578
1579 PHP_FE(ssh2_forward_listen, arginfo_ssh2_forward_listen)
1580 PHP_FE(ssh2_forward_accept, arginfo_ssh2_forward_accept)
1581
1582 /* Stream Stuff */
1583 PHP_FE(ssh2_shell, arginfo_ssh2_shell)
1584 PHP_FE(ssh2_exec, arginfo_ssh2_exec)
1585 PHP_FE(ssh2_tunnel, arginfo_ssh2_tunnel)
1586 PHP_FE(ssh2_scp_recv, arginfo_ssh2_scp_recv)
1587 PHP_FE(ssh2_scp_send, arginfo_ssh2_scp_send)
1588 PHP_FE(ssh2_fetch_stream, arginfo_ssh2_fetch_stream)
1589 PHP_FE(ssh2_poll, arginfo_ssh2_poll)
1590 PHP_FE(ssh2_send_eof, arginfo_ssh2_send_eof)
1591
1592 /* SFTP Stuff */
1593 PHP_FE(ssh2_sftp, arginfo_ssh2_sftp)
1594
1595 /* SFTP Wrapper Ops */
1596 PHP_FE(ssh2_sftp_rename, arginfo_ssh2_sftp_rename)
1597 PHP_FE(ssh2_sftp_unlink, arginfo_ssh2_sftp_unlink)
1598 PHP_FE(ssh2_sftp_mkdir, arginfo_ssh2_sftp_mkdir)
1599 PHP_FE(ssh2_sftp_rmdir, arginfo_ssh2_sftp_rmdir)
1600 PHP_FE(ssh2_sftp_chmod, arginfo_ssh2_sftp_chmod)
1601 PHP_FE(ssh2_sftp_stat, arginfo_ssh2_sftp_stat)
1602 PHP_FE(ssh2_sftp_lstat, arginfo_ssh2_sftp_lstat)
1603 PHP_FE(ssh2_sftp_symlink, arginfo_ssh2_sftp_symlink)
1604 PHP_FE(ssh2_sftp_readlink, arginfo_ssh2_sftp_readlink)
1605 PHP_FE(ssh2_sftp_realpath, arginfo_ssh2_sftp_realpath)
1606
1607 /* Publickey subsystem */
1608 PHP_FE(ssh2_publickey_init, arginfo_ssh2_publickey_init)
1609 PHP_FE(ssh2_publickey_add, arginfo_ssh2_publickey_add)
1610 PHP_FE(ssh2_publickey_remove, arginfo_ssh2_publickey_remove)
1611 PHP_FE(ssh2_publickey_list, arginfo_ssh2_publickey_list)
1612
1613 PHP_FE(ssh2_auth_agent, arginfo_ssh2_auth_agent)
1614
1615 {NULL, NULL, NULL}
1616 };
1617 /* }}} */
1618
1619 /* {{{ ssh2_module_entry
1620 */
1621 zend_module_entry ssh2_module_entry = {
1622 STANDARD_MODULE_HEADER,
1623 "ssh2",
1624 ssh2_functions,
1625 PHP_MINIT(ssh2),
1626 PHP_MSHUTDOWN(ssh2),
1627 NULL, /* RINIT */
1628 NULL, /* RSHUTDOWN */
1629 PHP_MINFO(ssh2),
1630 PHP_SSH2_VERSION,
1631 STANDARD_MODULE_PROPERTIES
1632 };
1633 /* }}} */
1634
1635 #ifdef COMPILE_DL_SSH2
1636 ZEND_GET_MODULE(ssh2)
1637 #endif
1638
1639 /*
1640 * Local variables:
1641 * tab-width: 4
1642 * c-basic-offset: 4
1643 * End:
1644 * vim600: noet sw=4 ts=4 fdm=marker
1645 * vim<600: noet sw=4 ts=4
1646 */
1647