diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h index 78d4ced..1023943 100644 --- a/src/libssh2_priv.h +++ b/src/libssh2_priv.h @@ -631,6 +631,7 @@ struct _LIBSSH2_SESSION /* Error tracking */ const char *err_msg; int err_code; + int err_flags; /* struct members for packet-level reading */ struct transportpacket packet; @@ -950,6 +951,10 @@ _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) /* Something very bad is going on */ #define LIBSSH2_MAC_INVALID -1 +/* Flags for _libssh2_error_flags */ +/* Error message is allocated on the heap */ +#define LIBSSH2_ERR_FLAG_DUP 1 + /* SSH Packet Types -- Defined by internet draft */ /* Transport Layer */ #define SSH_MSG_DISCONNECT 1 diff --git a/src/misc.c b/src/misc.c index 283daea..320df44 100644 --- a/src/misc.c +++ b/src/misc.c @@ -51,10 +51,29 @@ #include #include -int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char* errmsg) +int _libssh2_error_flags(LIBSSH2_SESSION* session, int errcode, const char* errmsg, int errflags) { - session->err_msg = errmsg; + if (session->err_flags & LIBSSH2_ERR_FLAG_DUP) + LIBSSH2_FREE(session, (char *)session->err_msg); + session->err_code = errcode; + session->err_flags = 0; + + if ((errmsg != NULL) && ((errflags & LIBSSH2_ERR_FLAG_DUP) != 0)) { + size_t len = strlen(errmsg); + char *copy = LIBSSH2_ALLOC(session, len + 1); + if (copy) { + memcpy(copy, errmsg, len + 1); + session->err_flags = LIBSSH2_ERR_FLAG_DUP; + session->err_msg = copy; + } + else + /* Out of memory: this code path is very unlikely */ + session->err_msg = "former error forgotten (OOM)"; + } + else + session->err_msg = errmsg; + #ifdef LIBSSH2DEBUG if((errcode == LIBSSH2_ERROR_EAGAIN) && !session->api_block_mode) /* if this is EAGAIN and we're in non-blocking mode, don't generate @@ -67,6 +86,11 @@ int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char* errmsg) return errcode; } +int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char* errmsg) +{ + return _libssh2_error_flags(session, errcode, errmsg, 0); +} + #ifdef WIN32 static int wsa2errno(void) { diff --git a/src/misc.h b/src/misc.h index f99b773..54ae546 100644 --- a/src/misc.h +++ b/src/misc.h @@ -49,6 +49,7 @@ struct list_node { struct list_head *head; }; +int _libssh2_error_flags(LIBSSH2_SESSION* session, int errcode, const char* errmsg, int errflags); int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char* errmsg); void _libssh2_list_init(struct list_head *head); diff --git a/src/session.c b/src/session.c index 9e9343f..cc77a7a 100644 --- a/src/session.c +++ b/src/session.c @@ -1058,6 +1058,11 @@ session_free(LIBSSH2_SESSION *session) LIBSSH2_FREE(session, session->server_hostkey); } + /* error string */ + if (session->err_msg && ((session->err_flags & LIBSSH2_ERR_FLAG_DUP) != 0)) { + LIBSSH2_FREE(session, (char *)session->err_msg); + } + LIBSSH2_FREE(session, session); return 0;