Skip to content

Commit e007fb0

Browse files
author
Pan
committed
Added error checking to session. Added unit tests for invalid api use and errors should not segfault.
1 parent 32e077a commit e007fb0

File tree

2 files changed

+43
-7
lines changed

2 files changed

+43
-7
lines changed

ssh/session.pyx

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ cimport c_ssh
3232
cdef bint _check_connected(c_ssh.ssh_session session) nogil except -1:
3333
if not c_ssh.ssh_is_connected(session):
3434
with gil:
35-
raise InvalidAPIUse(
36-
"Session is not connected - cannot authenticate")
35+
raise InvalidAPIUse("Session is not connected")
3736
return 0
3837

3938

@@ -77,6 +76,7 @@ cdef class Session:
7776
cdef c_ssh.ssh_channel _channel
7877
cdef Channel channel
7978
with nogil:
79+
_check_connected(self._session)
8080
_channel = c_ssh.ssh_channel_new(self._session)
8181
channel = Channel.from_ptr(_channel, self)
8282
return channel
@@ -124,11 +124,12 @@ cdef class Session:
124124
cdef const char *message
125125
cdef bytes b_message
126126
with nogil:
127+
_check_connected(self._session)
127128
message = c_ssh.ssh_get_disconnect_message(self._session)
128129
b_message = message
129130
return b_message
130131

131-
def ssh_get_fd(self):
132+
def get_fd(self):
132133
cdef c_ssh.socket_t _sock
133134
with nogil:
134135
_sock = c_ssh.ssh_get_fd(self._session)
@@ -138,13 +139,15 @@ cdef class Session:
138139
cdef char *_banner
139140
cdef bytes banner
140141
with nogil:
142+
_check_connected(self._session)
141143
_banner = c_ssh.ssh_get_issue_banner(self._session)
142144
banner = _banner
143145
return banner
144146

145147
def get_openssh_version(self):
146148
cdef int rc
147149
with nogil:
150+
_check_connected(self._session)
148151
rc = c_ssh.ssh_get_openssh_version(self._session)
149152
return rc
150153

@@ -212,7 +215,9 @@ cdef class Session:
212215
return handle_ssh_error_codes(rc, self._session)
213216

214217
def options_set(self, Option option, value):
215-
"""Set an option for session.
218+
"""Set an option for session. This function can only be used for
219+
string options like host. For numeric options, port etc, use the
220+
individual functions.
216221
217222
:param option: An SSH option object from one of
218223
:py:mod:`ssh.options`.
@@ -227,6 +232,9 @@ cdef class Session:
227232
return handle_ssh_error_codes(rc, self._session)
228233

229234
def options_get(self, Option option):
235+
"""Get option value. This function can only be used for string optinos.
236+
For numeric or other options use the individual functions.
237+
"""
230238
cdef char *_value
231239
cdef char **value = NULL
232240
cdef int rc
@@ -462,24 +470,28 @@ cdef class Session:
462470
cdef bytes b_known_host
463471
with nogil:
464472
_known_host = c_ssh.ssh_dump_knownhost(self._session)
473+
if _known_host is NULL:
474+
return
465475
b_known_host = _known_host
466476
return b_known_host
467477

468478
def get_clientbanner(self):
469479
cdef const_char *_banner
470480
cdef bytes banner
471481
with nogil:
472-
_check_connected(self._session)
473482
_banner = c_ssh.ssh_get_clientbanner(self._session)
483+
if _banner is NULL:
484+
return
474485
banner = _banner
475486
return banner
476487

477488
def get_serverbanner(self):
478489
cdef const_char *_banner
479490
cdef bytes banner
480491
with nogil:
481-
_check_connected(self._session)
482492
_banner = c_ssh.ssh_get_serverbanner(self._session)
493+
if _banner is NULL:
494+
return
483495
banner = _banner
484496
return banner
485497

@@ -488,6 +500,8 @@ cdef class Session:
488500
cdef bytes algo
489501
with nogil:
490502
_algo = c_ssh.ssh_get_kex_algo(self._session)
503+
if _algo is NULL:
504+
return
491505
algo = _algo
492506
return algo
493507

@@ -496,6 +510,8 @@ cdef class Session:
496510
cdef bytes cipher
497511
with nogil:
498512
_cipher = c_ssh.ssh_get_cipher_in(self._session)
513+
if _cipher is NULL:
514+
return
499515
cipher = _cipher
500516
return cipher
501517

@@ -504,6 +520,8 @@ cdef class Session:
504520
cdef bytes cipher
505521
with nogil:
506522
_cipher = c_ssh.ssh_get_cipher_out(self._session)
523+
if _cipher is NULL:
524+
return
507525
cipher = _cipher
508526
return cipher
509527

@@ -512,6 +530,8 @@ cdef class Session:
512530
cdef bytes hmac
513531
with nogil:
514532
_hmac = c_ssh.ssh_get_hmac_in(self._session)
533+
if _hmac is NULL:
534+
return
515535
hmac = _hmac
516536
return hmac
517537

@@ -520,6 +540,8 @@ cdef class Session:
520540
cdef bytes hmac
521541
with nogil:
522542
_hmac = c_ssh.ssh_get_hmac_out(self._session)
543+
if _hmac is NULL:
544+
return
523545
hmac = _hmac
524546
return hmac
525547

tests/test_session.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,27 @@
2828

2929
class SessionTest(SSHTestCase):
3030

31-
def test_error_should_not_segfault(self):
31+
def test_should_not_segfault(self):
3232
session = Session()
33+
self.assertEqual(session.get_error(), '')
3334
self.assertRaises(InvalidAPIUse, session.userauth_none)
3435
self.assertRaises(InvalidAPIUse, session.userauth_publickey, self.pkey)
3536
key = import_pubkey_file(self.user_pub_key)
3637
self.assertRaises(InvalidAPIUse, session.userauth_try_publickey, key)
3738
self.assertRaises(InvalidAPIUse, session.userauth_publickey_auto, '')
39+
self.assertRaises(InvalidAPIUse, session.channel_new)
40+
self.assertRaises(InvalidAPIUse, session.get_disconnect_message)
41+
self.assertRaises(InvalidAPIUse, session.get_issue_banner)
42+
self.assertRaises(InvalidAPIUse, session.get_openssh_version)
43+
self.assertIsNone(session.dump_knownhost())
44+
self.assertIsNone(session.get_clientbanner())
45+
self.assertIsNone(session.get_serverbanner())
46+
self.assertIsNone(session.get_kex_algo())
47+
self.assertIsNone(session.get_cipher_in())
48+
self.assertIsNone(session.get_cipher_out())
49+
self.assertIsNone(session.get_hmac_in())
50+
self.assertIsNone(session.get_hmac_out())
51+
self.assertIsNotNone(session.get_error_code())
3852

3953
def test_socket_connect(self):
4054
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

0 commit comments

Comments
 (0)