Skip to content

Commit 44ea2e4

Browse files
author
Pan
committed
Added callbacks implementation and test.
Updated event implementation and tests. Updated session.
1 parent 685c1ee commit 44ea2e4

10 files changed

+140
-49
lines changed

ssh/c_callbacks.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ cdef extern from "libssh/callbacks.h" nogil:
102102
ssh_gssapi_verify_mic_callback gssapi_verify_mic_function
103103
ctypedef ssh_server_callbacks_struct *ssh_server_callbacks
104104
int ssh_set_server_callbacks(ssh_session session, ssh_server_callbacks cb)
105+
void ssh_callbacks_init(void *cb)
105106
struct ssh_socket_callbacks_struct:
106107
void *userdata
107108
ssh_callback_data data

ssh/callbacks.pxd

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# This file is part of ssh-python.
2+
# Copyright (C) 2018 Panos Kittenis
3+
#
4+
# This library is free software; you can redistribute it and/or
5+
# modify it under the terms of the GNU Lesser General Public
6+
# License as published by the Free Software Foundation, version 2.1.
7+
#
8+
# This library is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+
# Lesser General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU Lesser General Public
14+
# License along with this library; if not, write to the Free Software
15+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-130
16+
17+
cimport c_callbacks
18+
19+
20+
cdef class Callbacks:
21+
cdef c_callbacks.ssh_callbacks _cb

ssh/callbacks.pyx

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# This file is part of ssh-python.
2+
# Copyright (C) 2018 Panos Kittenis
3+
#
4+
# This library is free software; you can redistribute it and/or
5+
# modify it under the terms of the GNU Lesser General Public
6+
# License as published by the Free Software Foundation, version 2.1.
7+
#
8+
# This library is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+
# Lesser General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU Lesser General Public
14+
# License along with this library; if not, write to the Free Software
15+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-130
16+
17+
from libc.stdlib cimport malloc, free
18+
from libc.string cimport memset
19+
20+
from session cimport Session
21+
from utils cimport handle_ssh_error_codes
22+
23+
cimport c_callbacks
24+
# from c_ssh cimport ssh_auth_callback
25+
26+
27+
# cdef int auth_callback(const char *prompt, char *buf, size_t len,
28+
# int echo, int verify, void *userdata):
29+
# # (void) verify;
30+
# # (void) userdata;
31+
32+
# return 0
33+
# # ssh_getpass(prompt, buf, len, echo, verify);
34+
35+
36+
cdef class Callbacks:
37+
38+
def __cinit__(self):
39+
self._cb = <c_callbacks.ssh_callbacks>malloc(sizeof(c_callbacks.ssh_callbacks_struct))
40+
if self._cb is NULL:
41+
raise MemoryError
42+
memset(self._cb, 0, sizeof(c_callbacks.ssh_callbacks_struct))
43+
c_callbacks.ssh_callbacks_init(self._cb)
44+
# self._cb.userdata = NULL
45+
# self._cb.auth_function = NULL # <c_callbacks.ssh_auth_callback>auth_callback
46+
# self._cb.log_function = NULL
47+
# self._cb.connect_status_function = NULL
48+
# self._cb.global_request_function = NULL
49+
# self._cb.channel_open_request_x11_function = NULL
50+
# self._cb.channel_open_request_auth_agent_function = NULL
51+
52+
def __dealloc__(self):
53+
if self._cb is not NULL:
54+
free(self._cb)
55+
self._cb = NULL
56+
57+
def set_callbacks(self, Session session not None):
58+
cdef int rc
59+
with nogil:
60+
rc = c_callbacks.ssh_set_callbacks(
61+
session._session, self._cb)
62+
return handle_ssh_error_codes(rc, session._session)

ssh/event.pxd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-130
1616

1717
from session cimport Session
18-
from channel cimport Channel
18+
from connector cimport Connector
1919

2020
cimport c_ssh
2121

@@ -24,7 +24,7 @@ cdef class Event:
2424
cdef c_ssh.ssh_event _event
2525
cdef object _sock
2626
cdef Session session
27-
cdef Channel channel
27+
cdef Connector connector
2828

2929
@staticmethod
3030
cdef Event from_ptr(c_ssh.ssh_event _event)

ssh/event.pyx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,12 @@ cdef class Event:
4141
return self.session
4242

4343
@property
44-
def channel(self):
45-
return self.channel
44+
def connector(self):
45+
return self.connector
46+
47+
@property
48+
def socket(self):
49+
return self._sock
4650

4751
@staticmethod
4852
cdef Event from_ptr(c_ssh.ssh_event _event):
@@ -58,16 +62,15 @@ cdef class Event:
5862
except Exception:
5963
return -1
6064

61-
def add_fd(self, socket, short events=0, callback=None):
62-
cdef c_ssh.socket_t _sock = PyObject_AsFileDescriptor(socket)
65+
def add_fd(self, sock, short events, callback=None):
66+
cdef c_ssh.socket_t _sock = PyObject_AsFileDescriptor(sock)
6367
cdef c_ssh.ssh_event_callback cb = <c_ssh.ssh_event_callback>&Event.event_callback
6468
cdef int rc
6569
cdef void *_cb = NULL if callback is None else <void *>callback
66-
cb = NULL if callback is None else cb
6770
rc = c_ssh.ssh_event_add_fd(
6871
self._event, _sock, events, cb, _cb)
6972
if rc == 0:
70-
self._sock = socket
73+
self._sock = sock
7174
return rc
7275

7376
def remove_fd(self, socket):
@@ -94,7 +97,7 @@ cdef class Event:
9497
self._event, connector._connector)
9598
if rc == 0:
9699
self.connector = connector
97-
return rc
100+
return handle_ssh_error_codes(rc, connector.session._session)
98101

99102
def dopoll(self, int timeout):
100103
cdef int rc
@@ -117,4 +120,4 @@ cdef class Event:
117120
self._event, connector._connector)
118121
if rc == 0:
119122
self.connector = None
120-
return rc
123+
return handle_ssh_error_codes(rc, connector.session._session)

ssh/session.pyx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ cdef class Session:
110110
return
111111
return Channel.from_ptr(_channel, self)
112112

113-
def cancel_forward(self, address, int port):
113+
def cancel_forward(self, address not None, int port):
114114
cdef bytes b_address = to_bytes(address)
115115
cdef char *c_address = b_address
116116
cdef int rc
@@ -119,7 +119,7 @@ cdef class Session:
119119
self._session, c_address, port)
120120
return handle_ssh_error_codes(rc, self._session)
121121

122-
def listen_forward(self, address, int port, int bound_port):
122+
def listen_forward(self, address not None, int port, int bound_port):
123123
cdef bytes b_address = to_bytes(address)
124124
cdef char *c_address = b_address
125125
cdef int rc
@@ -338,23 +338,23 @@ cdef class Session:
338338
rc = c_ssh.ssh_userauth_list(self._session, NULL)
339339
return handle_ssh_error_codes(rc, self._session)
340340

341-
def userauth_try_publickey(self, SSHKey pubkey):
341+
def userauth_try_publickey(self, SSHKey pubkey not None):
342342
cdef int rc
343343
with nogil:
344344
_check_connected(self._session)
345345
rc = c_ssh.ssh_userauth_try_publickey(
346346
self._session, NULL, pubkey._key)
347347
return handle_auth_error_codes(rc, self._session)
348348

349-
def userauth_publickey(self, SSHKey privkey):
349+
def userauth_publickey(self, SSHKey privkey not None):
350350
cdef int rc
351351
with nogil:
352352
_check_connected(self._session)
353353
rc = c_ssh.ssh_userauth_publickey(
354354
self._session, NULL, privkey._key)
355355
return handle_auth_error_codes(rc, self._session)
356356

357-
def userauth_agent(self, username):
357+
def userauth_agent(self, username not None):
358358
cdef bytes b_username = to_bytes(username)
359359
cdef char *c_username = b_username
360360
cdef int rc
@@ -363,7 +363,7 @@ cdef class Session:
363363
rc = c_ssh.ssh_userauth_agent(self._session, c_username)
364364
return handle_ssh_error_codes(rc, self._session)
365365

366-
def userauth_publickey_auto(self, passphrase):
366+
def userauth_publickey_auto(self, passphrase not None):
367367
cdef bytes b_passphrase = to_bytes(passphrase)
368368
cdef char *c_passphrase = b_passphrase
369369
cdef int rc
@@ -373,7 +373,7 @@ cdef class Session:
373373
self._session, NULL, c_passphrase)
374374
return handle_ssh_error_codes(rc, self._session)
375375

376-
def userauth_password(self, username, password):
376+
def userauth_password(self, username not None, password not None):
377377
cdef bytes b_username = to_bytes(username)
378378
cdef bytes b_password = to_bytes(password)
379379
cdef char *c_username = b_username
@@ -385,7 +385,7 @@ cdef class Session:
385385
self._session, c_username, c_password)
386386
return handle_ssh_error_codes(rc, self._session)
387387

388-
def userauth_kbdint(self, username, submethods):
388+
def userauth_kbdint(self, username not None, submethods not None):
389389
cdef bytes b_username = to_bytes(username)
390390
cdef bytes b_submethods = to_bytes(submethods)
391391
cdef char *c_username = b_username

ssh/utils.pxd

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
# License along with this library; if not, write to the Free Software
1515
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1616

17+
from c_ssh cimport ssh_session
18+
1719
cdef bytes to_bytes(_str)
1820
cdef object to_str(char *c_str)
1921
cdef object to_str_len(char *c_str, int length)
2022
cdef int handle_ok_error_codes(int errcode) except -1
21-
cdef int handle_ssh_error_codes(int errcode, void *caller) except -1
22-
cdef int handle_auth_error_codes(int errcode, void *caller) except -1
23+
cdef int handle_ssh_error_codes(int errcode, ssh_session) except -1
24+
cdef int handle_auth_error_codes(int errcode, ssh_session) except -1

ssh/utils.pyx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from cpython.version cimport PY_MAJOR_VERSION
1818

1919
from c_ssh cimport ssh_error_types_e, ssh_get_error, ssh_auth_e, \
20-
SSH_OK, SSH_ERROR, SSH_AGAIN, SSH_EOF
20+
SSH_OK, SSH_ERROR, SSH_AGAIN, SSH_EOF, ssh_session
2121

2222
from exceptions import RequestDenied, FatalError, OtherError, \
2323
AuthenticationPartial, AuthenticationDenied, AuthenticationError, \
@@ -63,31 +63,31 @@ cdef int handle_ok_error_codes(int errcode) except -1:
6363
return errcode
6464

6565

66-
cdef int handle_ssh_error_codes(int errcode, void *caller) except -1:
66+
cdef int handle_ssh_error_codes(int errcode, ssh_session session) except -1:
6767
if errcode == ssh_error_types_e.SSH_NO_ERROR:
6868
return 0
6969
elif errcode == ssh_error_types_e.SSH_REQUEST_DENIED:
70-
raise RequestDenied(ssh_get_error(caller))
70+
raise RequestDenied(ssh_get_error(session))
7171
elif errcode == ssh_error_types_e.SSH_FATAL:
72-
raise FatalError(ssh_get_error(caller))
72+
raise FatalError(ssh_get_error(session))
7373
else:
7474
if errcode < 0:
75-
raise OtherError(ssh_get_error(caller))
75+
raise OtherError(ssh_get_error(session))
7676
return errcode
7777

7878

79-
cdef int handle_auth_error_codes(int errcode, void *caller) except -1:
79+
cdef int handle_auth_error_codes(int errcode, ssh_session session) except -1:
8080
if errcode == ssh_auth_e.SSH_AUTH_SUCCESS:
8181
return ssh_auth_e.SSH_AUTH_SUCCESS
8282
elif errcode == ssh_auth_e.SSH_AUTH_DENIED:
83-
raise AuthenticationDenied(ssh_get_error(caller))
83+
raise AuthenticationDenied(ssh_get_error(session))
8484
elif errcode == ssh_auth_e.SSH_AUTH_ERROR:
85-
raise AuthenticationError(ssh_get_error(caller))
85+
raise AuthenticationError(ssh_get_error(session))
8686
elif errcode == ssh_auth_e.SSH_AUTH_PARTIAL:
87-
raise AuthenticationPartial(ssh_get_error(caller))
87+
raise AuthenticationPartial(ssh_get_error(session))
8888
elif errcode == ssh_auth_e.SSH_AUTH_AGAIN:
8989
return ssh_auth_e.SSH_AUTH_AGAIN
9090
else:
9191
if errcode < 0:
92-
raise OtherError(ssh_get_error(caller))
92+
raise OtherError(ssh_get_error(session))
9393
return errcode

tests/base_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def setUp(self):
6060
self.session.options_set_port(self.port)
6161
self.session.options_set(options.USER, self.user)
6262
self.pkey = import_privkey_file(self.user_key)
63-
self.session.options_set(options.LOG_VERBOSITY, '1')
63+
# self.session.options_set(options.LOG_VERBOSITY, '1')
6464

6565
def tearDown(self):
6666
del self.session

tests/test_event.py

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,17 @@
2222
from ssh.session import Session
2323
from ssh import options
2424
from ssh.event import Event
25+
from ssh.callbacks import Callbacks
2526
from ssh.connector import CONNECTOR_STDOUT, CONNECTOR_STDERR, \
2627
CONNECTOR_BOTH
28+
from ssh.exceptions import OtherError
29+
30+
31+
class CallbacksTest(SSHTestCase):
32+
33+
def test_callbacks(self):
34+
cb = Callbacks()
35+
self.assertEqual(cb.set_callbacks(self.session), 0)
2736

2837

2938
class EventTest(SSHTestCase):
@@ -39,22 +48,15 @@ def test_event_session(self):
3948

4049
def test_event_connector(self):
4150
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
42-
sock.connect((self.host, self.port))
43-
session = Session()
44-
session.options_set(options.USER, self.user)
45-
session.options_set(options.HOST, self.host)
46-
session.options_set_port(self.port)
47-
self.assertEqual(session.set_socket(sock), 0)
48-
self.assertEqual(session.connect(), 0)
49-
self.assertEqual(
50-
session.userauth_publickey(self.pkey), 0)
51-
5251
event = Event()
53-
connector = session.connector_new()
54-
chan = session.channel_new()
55-
connector.set_in_channel(chan, CONNECTOR_STDOUT)
56-
connector.set_out_fd(sock)
57-
self.assertEqual(event.add_connector(connector), 0)
58-
# self.assertEqual(connector, event.connector)
59-
# self.assertEqual(event.remove_connector(connector), 0)
60-
# self.assertIsNone(event.connector)
52+
self.assertEqual(event.add_fd(sock, 1), 0)
53+
self.assertEqual(sock, event.socket)
54+
self.assertEqual(event.remove_fd(sock), 0)
55+
self.assertIsNone(event.socket)
56+
self.assertEqual(event.add_fd(sock, 1, callback=lambda: 1), 0)
57+
connector = self.session.connector_new()
58+
self.assertIsNone(event.connector)
59+
self.assertRaises(OtherError, event.add_connector, connector)
60+
self.assertIsNone(event.connector)
61+
self.assertEqual(event.remove_connector(connector), 0)
62+
self.assertIsNone(event.connector)

0 commit comments

Comments
 (0)