Skip to content

Commit 32e077a

Browse files
author
Pan
committed
Added exception. Added sanity checks for authentication functions to avoid segfaults. Added invalid api use tests.
1 parent 0828ebc commit 32e077a

File tree

3 files changed

+43
-5
lines changed

3 files changed

+43
-5
lines changed

ssh/exceptions.pyx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,7 @@ class SSHError(BaseSSHError):
6565

6666
class EOF(BaseSSHError):
6767
"""Raised on EOF errors"""
68+
69+
70+
class InvalidAPIUse(BaseSSHError):
71+
"""Raised on invalid uses of the API"""

ssh/session.pyx

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,19 @@ from utils cimport to_bytes, to_str, handle_ssh_error_codes, \
2424
from options cimport Option
2525
from key cimport SSHKey
2626

27-
from exceptions import OptionError
27+
from exceptions import OptionError, InvalidAPIUse
2828

2929
cimport c_ssh
3030

3131

32+
cdef bint _check_connected(c_ssh.ssh_session session) nogil except -1:
33+
if not c_ssh.ssh_is_connected(session):
34+
with gil:
35+
raise InvalidAPIUse(
36+
"Session is not connected - cannot authenticate")
37+
return 0
38+
39+
3240
cdef class Session:
3341
"""Libssh session class providing session related functions."""
3442

@@ -303,25 +311,29 @@ cdef class Session:
303311
def userauth_none(self):
304312
cdef int rc
305313
with nogil:
314+
_check_connected(self._session)
306315
rc = c_ssh.ssh_userauth_none(self._session, NULL)
307316
return handle_ssh_error_codes(rc, self._session)
308317

309318
def userauth_list(self):
310319
cdef int rc
311320
with nogil:
321+
_check_connected(self._session)
312322
rc = c_ssh.ssh_userauth_list(self._session, NULL)
313323
return handle_ssh_error_codes(rc, self._session)
314324

315325
def userauth_try_publickey(self, SSHKey pubkey):
316326
cdef int rc
317327
with nogil:
328+
_check_connected(self._session)
318329
rc = c_ssh.ssh_userauth_try_publickey(
319330
self._session, NULL, pubkey._key)
320331
return handle_auth_error_codes(rc, self._session)
321332

322333
def userauth_publickey(self, SSHKey privkey):
323334
cdef int rc
324335
with nogil:
336+
_check_connected(self._session)
325337
rc = c_ssh.ssh_userauth_publickey(
326338
self._session, NULL, privkey._key)
327339
return handle_auth_error_codes(rc, self._session)
@@ -331,6 +343,7 @@ cdef class Session:
331343
cdef char *c_username = b_username
332344
cdef int rc
333345
with nogil:
346+
_check_connected(self._session)
334347
rc = c_ssh.ssh_userauth_agent(self._session, c_username)
335348
return handle_ssh_error_codes(rc, self._session)
336349

@@ -339,6 +352,7 @@ cdef class Session:
339352
cdef char *c_passphrase = b_passphrase
340353
cdef int rc
341354
with nogil:
355+
_check_connected(self._session)
342356
rc = c_ssh.ssh_userauth_publickey_auto(
343357
self._session, NULL, c_passphrase)
344358
return handle_ssh_error_codes(rc, self._session)
@@ -350,6 +364,7 @@ cdef class Session:
350364
cdef char *c_password = b_password
351365
cdef int rc
352366
with nogil:
367+
_check_connected(self._session)
353368
rc = c_ssh.ssh_userauth_password(
354369
self._session, c_username, c_password)
355370
return handle_ssh_error_codes(rc, self._session)
@@ -361,6 +376,7 @@ cdef class Session:
361376
cdef char *c_submethods = b_submethods
362377
cdef int rc
363378
with nogil:
379+
_check_connected(self._session)
364380
rc = c_ssh.ssh_userauth_kbdint(
365381
self._session, c_username, c_submethods)
366382
return handle_ssh_error_codes(rc, self._session)
@@ -369,6 +385,7 @@ cdef class Session:
369385
cdef bytes b_instruction
370386
cdef const_char *_instruction
371387
with nogil:
388+
_check_connected(self._session)
372389
_instruction = c_ssh.ssh_userauth_kbdint_getinstruction(
373390
self._session)
374391
b_instruction = to_str(<char *>_instruction)
@@ -378,13 +395,15 @@ cdef class Session:
378395
cdef bytes b_name
379396
cdef const_char *_name
380397
with nogil:
398+
_check_connected(self._session)
381399
_name = c_ssh.ssh_userauth_kbdint_getname(self._session)
382400
b_name = to_str(<char *>_name)
383401
return b_name
384402

385403
def userauth_kbdint_getnprompts(self):
386404
cdef int rc
387405
with nogil:
406+
_check_connected(self._session)
388407
rc = c_ssh.ssh_userauth_kbdint_getnprompts(self._session)
389408
return rc
390409

@@ -393,6 +412,7 @@ cdef class Session:
393412
cdef bytes b_prompt
394413
cdef char *c_echo = echo
395414
with nogil:
415+
_check_connected(self._session)
396416
_prompt = c_ssh.ssh_userauth_kbdint_getprompt(
397417
self._session, i, c_echo)
398418
b_prompt = _prompt
@@ -401,13 +421,15 @@ cdef class Session:
401421
def userauth_kbdint_getnanswers(self):
402422
cdef int rc
403423
with nogil:
424+
_check_connected(self._session)
404425
rc = c_ssh.ssh_userauth_kbdint_getnanswers(self._session)
405426
return rc
406427

407428
def userauth_kbdint_getanswer(self, unsigned int i):
408429
cdef const_char *_answer
409430
cdef bytes b_answer
410431
with nogil:
432+
_check_connected(self._session)
411433
_answer = c_ssh.ssh_userauth_kbdint_getanswer(
412434
self._session, i)
413435
b_answer = _answer
@@ -417,13 +439,15 @@ cdef class Session:
417439
cdef char *c_answer = answer
418440
cdef int rc
419441
with nogil:
442+
_check_connected(self._session)
420443
rc = c_ssh.ssh_userauth_kbdint_setanswer(
421444
self._session, i, <const_char *>(c_answer))
422445
return handle_ssh_error_codes(rc, self._session)
423446

424447
def userauth_gssapi(self):
425448
cdef int rc
426449
with nogil:
450+
_check_connected(self._session)
427451
rc = c_ssh.ssh_userauth_gssapi(self._session)
428452
return handle_ssh_error_codes(rc, self._session)
429453

@@ -445,6 +469,7 @@ cdef class Session:
445469
cdef const_char *_banner
446470
cdef bytes banner
447471
with nogil:
472+
_check_connected(self._session)
448473
_banner = c_ssh.ssh_get_clientbanner(self._session)
449474
banner = _banner
450475
return banner
@@ -453,6 +478,7 @@ cdef class Session:
453478
cdef const_char *_banner
454479
cdef bytes banner
455480
with nogil:
481+
_check_connected(self._session)
456482
_banner = c_ssh.ssh_get_serverbanner(self._session)
457483
banner = _banner
458484
return banner

tests/test_session.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,19 @@
2323
from ssh.channel import Channel
2424
from ssh.key import SSHKey, import_pubkey_file, import_privkey_file
2525
from ssh import options
26-
from ssh.exceptions import RequestDenied, KeyImportError
26+
from ssh.exceptions import RequestDenied, KeyImportError, InvalidAPIUse
2727

2828

2929
class SessionTest(SSHTestCase):
3030

31+
def test_error_should_not_segfault(self):
32+
session = Session()
33+
self.assertRaises(InvalidAPIUse, session.userauth_none)
34+
self.assertRaises(InvalidAPIUse, session.userauth_publickey, self.pkey)
35+
key = import_pubkey_file(self.user_pub_key)
36+
self.assertRaises(InvalidAPIUse, session.userauth_try_publickey, key)
37+
self.assertRaises(InvalidAPIUse, session.userauth_publickey_auto, '')
38+
3139
def test_socket_connect(self):
3240
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
3341
sock.connect((self.host, self.port))
@@ -36,10 +44,10 @@ def test_socket_connect(self):
3644
session.options_set(options.HOST, self.host)
3745
session.options_set_port(self.port)
3846
self.assertEqual(session.set_socket(sock), 0)
39-
self.assertEqual(self.session.connect(), 0)
40-
self.assertRaises(RequestDenied, self.session.userauth_none)
47+
self.assertEqual(session.connect(), 0)
48+
self.assertRaises(RequestDenied, session.userauth_none)
4149
self.assertEqual(
42-
self.session.userauth_publickey(self.pkey), 0)
50+
session.userauth_publickey(self.pkey), 0)
4351

4452
def test_connect(self):
4553
self.assertEqual(self.session.connect(), 0)

0 commit comments

Comments
 (0)