From: Stefan Eissing Date: Thu, 20 Mar 2025 09:31:30 +0000 (+0100) Subject: dynbuf: assert init on free X-Git-Tag: curl-8_13_0~94 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=646b2d6ca2337f6d24625e2c0f8b1ccb79991def;p=thirdparty%2Fcurl.git dynbuf: assert init on free Add a DEBUGASSERT() in Curl_dyn_free() that checks that Curl_dyn_init() has been performed before. Fix code places that did it wrong. Fixes #16725 Closes #16775 --- diff --git a/lib/curl_krb5.h b/lib/curl_krb5.h index ccf6b96a87..b9caf7f243 100644 --- a/lib/curl_krb5.h +++ b/lib/curl_krb5.h @@ -40,13 +40,15 @@ struct Curl_sec_client_mech { #define AUTH_ERROR 2 #ifdef HAVE_GSSAPI +void Curl_sec_conn_init(struct connectdata *); +void Curl_sec_conn_destroy(struct connectdata *); int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, char *, enum protection_level); -void Curl_sec_end(struct connectdata *); CURLcode Curl_sec_login(struct Curl_easy *, struct connectdata *); int Curl_sec_request_prot(struct connectdata *conn, const char *level); #else -#define Curl_sec_end(x) +#define Curl_sec_conn_init(x) Curl_nop_stmt +#define Curl_sec_conn_destroy(x) Curl_nop_stmt #endif #endif /* HEADER_CURL_KRB5_H */ diff --git a/lib/dynbuf.c b/lib/dynbuf.c index 353346dcd7..bdfe6a681d 100644 --- a/lib/dynbuf.c +++ b/lib/dynbuf.c @@ -60,6 +60,7 @@ void Curl_dyn_init(struct dynbuf *s, size_t toobig) void Curl_dyn_free(struct dynbuf *s) { DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); Curl_safefree(s->bufr); s->leng = s->allc = 0; } diff --git a/lib/easy.c b/lib/easy.c index 964de98d96..1b03fddce7 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -950,10 +950,6 @@ CURL *curl_easy_duphandle(CURL *d) */ outcurl->set.buffer_size = data->set.buffer_size; - /* copy all userdefined values */ - if(dupset(outcurl, data)) - goto fail; - Curl_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER); Curl_netrc_init(&outcurl->state.netrc); @@ -961,6 +957,16 @@ CURL *curl_easy_duphandle(CURL *d) outcurl->state.lastconnect_id = -1; outcurl->state.recent_conn_id = -1; outcurl->id = -1; + outcurl->mid = -1; + +#ifndef CURL_DISABLE_HTTP + Curl_llist_init(&outcurl->state.httphdrs, NULL); +#endif + Curl_initinfo(outcurl); + + /* copy all userdefined values */ + if(dupset(outcurl, data)) + goto fail; outcurl->progress.flags = data->progress.flags; outcurl->progress.callback = data->progress.callback; @@ -1054,10 +1060,6 @@ CURL *curl_easy_duphandle(CURL *d) goto fail; } #endif /* USE_ARES */ -#ifndef CURL_DISABLE_HTTP - Curl_llist_init(&outcurl->state.httphdrs, NULL); -#endif - Curl_initinfo(outcurl); outcurl->magic = CURLEASY_MAGIC_NUMBER; diff --git a/lib/ftp.c b/lib/ftp.c index cdb9b0e4e7..a60af878ed 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -4108,7 +4108,6 @@ static CURLcode ftp_disconnect(struct Curl_easy *data, Curl_safefree(ftpc->prevpath); Curl_safefree(ftpc->server_os); Curl_pp_disconnect(pp); - Curl_sec_end(conn); return CURLE_OK; } diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c index b1bac5f724..0b6e70c660 100644 --- a/lib/http_negotiate.c +++ b/lib/http_negotiate.c @@ -109,9 +109,10 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn, neg_ctx->sslContext = conn->sslContext; #endif /* Check if the connection is using SSL and get the channel binding data */ -#if defined(USE_SSL) && defined(HAVE_GSSAPI) +#ifdef HAVE_GSSAPI + Curl_dyn_init(&neg_ctx->channel_binding_data, SSL_CB_MAX_SIZE + 1); +#ifdef USE_SSL if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) { - Curl_dyn_init(&neg_ctx->channel_binding_data, SSL_CB_MAX_SIZE + 1); result = Curl_ssl_get_channel_binding( data, FIRSTSOCKET, &neg_ctx->channel_binding_data); if(result) { @@ -119,13 +120,14 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn, return result; } } -#endif +#endif /* USE_SSL */ +#endif /* HAVE_GSSAPI */ /* Initialize the security context and decode our challenge */ result = Curl_auth_decode_spnego_message(data, userp, passwdp, service, host, header, neg_ctx); -#if defined(USE_SSL) && defined(HAVE_GSSAPI) +#ifdef HAVE_GSSAPI Curl_dyn_free(&neg_ctx->channel_binding_data); #endif diff --git a/lib/imap.c b/lib/imap.c index 6091b76cc0..5e35f91fd5 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -1495,14 +1495,17 @@ static CURLcode imap_connect(struct Curl_easy *data, bool *done) /* We always support persistent connections in IMAP */ connkeep(conn, "IMAP default"); - PINGPONG_SETUP(pp, imap_statemachine, imap_endofresp); + if(!imapc->initialised) { + PINGPONG_SETUP(pp, imap_statemachine, imap_endofresp); - /* Set the default preferred authentication type and mechanism */ - imapc->preftype = IMAP_TYPE_ANY; - Curl_sasl_init(&imapc->sasl, data, &saslimap); + /* Set the default preferred authentication type and mechanism */ + imapc->preftype = IMAP_TYPE_ANY; + Curl_sasl_init(&imapc->sasl, data, &saslimap); - Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD); - Curl_pp_init(pp); + Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD); + Curl_pp_init(pp); + imapc->initialised = TRUE; + } /* Parse the URL options */ result = imap_parse_url_options(conn); @@ -1692,27 +1695,30 @@ static CURLcode imap_disconnect(struct Curl_easy *data, struct imap_conn *imapc = &conn->proto.imapc; (void)data; - /* We cannot send quit unconditionally. If this connection is stale or - bad in any way, sending quit and waiting around here will make the - disconnect wait in vain and cause more problems than we need to. */ + if(imapc->initialised) { + /* We cannot send quit unconditionally. If this connection is stale or + bad in any way, sending quit and waiting around here will make the + disconnect wait in vain and cause more problems than we need to. */ - /* The IMAP session may or may not have been allocated/setup at this - point! */ - if(!dead_connection && conn->bits.protoconnstart) { - if(!imap_perform_logout(data)) - (void)imap_block_statemach(data, conn, TRUE); /* ignore errors */ - } + /* The IMAP session may or may not have been allocated/setup at this + point! */ + if(!dead_connection && conn->bits.protoconnstart) { + if(!imap_perform_logout(data)) + (void)imap_block_statemach(data, conn, TRUE); /* ignore errors */ + } - /* Disconnect from the server */ - Curl_pp_disconnect(&imapc->pp); - Curl_dyn_free(&imapc->dyn); + /* Disconnect from the server */ + Curl_pp_disconnect(&imapc->pp); + Curl_dyn_free(&imapc->dyn); - /* Cleanup the SASL module */ - Curl_sasl_cleanup(conn, imapc->sasl.authused); + /* Cleanup the SASL module */ + Curl_sasl_cleanup(conn, imapc->sasl.authused); - /* Cleanup our connection based variables */ - Curl_safefree(imapc->mailbox); - Curl_safefree(imapc->mailbox_uidvalidity); + /* Cleanup our connection based variables */ + Curl_safefree(imapc->mailbox); + Curl_safefree(imapc->mailbox_uidvalidity); + memset(imapc, 0, sizeof(*imapc)); + } return CURLE_OK; } diff --git a/lib/imap.h b/lib/imap.h index 784ee97e55..b3821857d1 100644 --- a/lib/imap.h +++ b/lib/imap.h @@ -85,6 +85,7 @@ struct imap_conn { BIT(tls_supported); /* StartTLS capability supported by server */ BIT(login_disabled); /* LOGIN command disabled by server */ BIT(ir_supported); /* Initial response supported by server */ + BIT(initialised); /* members have been initialised */ }; extern const struct Curl_handler Curl_handler_imap; diff --git a/lib/krb5.c b/lib/krb5.c index c1c230e241..99fd91f910 100644 --- a/lib/krb5.c +++ b/lib/krb5.c @@ -855,7 +855,6 @@ static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn) mech->name); return CURLE_FAILED_INIT; } - Curl_dyn_init(&conn->in_buffer.buf, CURL_MAX_INPUT_LENGTH); } infof(data, "Trying mechanism %s...", mech->name); @@ -914,9 +913,16 @@ Curl_sec_login(struct Curl_easy *data, struct connectdata *conn) return choose_mech(data, conn); } +void +Curl_sec_conn_init(struct connectdata *conn) +{ + Curl_dyn_init(&conn->in_buffer.buf, CURL_MAX_INPUT_LENGTH); + conn->in_buffer.index = 0; + conn->in_buffer.eof_flag = 0; +} void -Curl_sec_end(struct connectdata *conn) +Curl_sec_conn_destroy(struct connectdata *conn) { if(conn->mech && conn->mech->end) conn->mech->end(conn->app_data); diff --git a/lib/pingpong.c b/lib/pingpong.c index 69bf421b75..5f4d42da40 100644 --- a/lib/pingpong.c +++ b/lib/pingpong.c @@ -151,11 +151,13 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data, /* initialize stuff to prepare for reading a fresh new response */ void Curl_pp_init(struct pingpong *pp) { + DEBUGASSERT(!pp->initialised); pp->nread_resp = 0; pp->response = Curl_now(); /* start response time-out now! */ pp->pending_resp = TRUE; Curl_dyn_init(&pp->sendbuf, DYN_PINGPPONG_CMD); Curl_dyn_init(&pp->recvbuf, DYN_PINGPPONG_CMD); + pp->initialised = TRUE; } /*********************************************************************** @@ -450,8 +452,11 @@ CURLcode Curl_pp_flushsend(struct Curl_easy *data, CURLcode Curl_pp_disconnect(struct pingpong *pp) { - Curl_dyn_free(&pp->sendbuf); - Curl_dyn_free(&pp->recvbuf); + if(pp->initialised) { + Curl_dyn_free(&pp->sendbuf); + Curl_dyn_free(&pp->recvbuf); + memset(pp, 0, sizeof(*pp)); + } return CURLE_OK; } diff --git a/lib/pingpong.h b/lib/pingpong.h index dcd565fafd..d9fdbdbac2 100644 --- a/lib/pingpong.h +++ b/lib/pingpong.h @@ -70,6 +70,7 @@ struct pingpong { CURLcode (*statemachine)(struct Curl_easy *data, struct connectdata *conn); bool (*endofresp)(struct Curl_easy *data, struct connectdata *conn, const char *ptr, size_t len, int *code); + BIT(initialised); }; #define PINGPONG_SETUP(pp,s,e) \ diff --git a/lib/rtsp.c b/lib/rtsp.c index af2781eeb0..1f7929cc52 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -130,14 +130,19 @@ const struct Curl_handler Curl_handler_rtsp = { static CURLcode rtsp_setup_connection(struct Curl_easy *data, struct connectdata *conn) { + struct rtsp_conn *rtspc = &conn->proto.rtspc; struct RTSP *rtsp; (void)conn; + if(!rtspc->initialised) { + Curl_dyn_init(&rtspc->buf, MAX_RTP_BUFFERSIZE); + rtspc->initialised = TRUE; + } + data->req.p.rtsp = rtsp = calloc(1, sizeof(struct RTSP)); if(!rtsp) return CURLE_OUT_OF_MEMORY; - Curl_dyn_init(&conn->proto.rtspc.buf, MAX_RTP_BUFFERSIZE); return CURLE_OK; } @@ -182,9 +187,13 @@ static CURLcode rtsp_connect(struct Curl_easy *data, bool *done) static CURLcode rtsp_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead) { + struct rtsp_conn *rtspc = &conn->proto.rtspc; (void) dead; (void) data; - Curl_dyn_free(&conn->proto.rtspc.buf); + if(rtspc->initialised) { + Curl_dyn_free(&conn->proto.rtspc.buf); + rtspc->initialised = FALSE; + } return CURLE_OK; } diff --git a/lib/rtsp.h b/lib/rtsp.h index 68f6f4fe01..2506ea9cb8 100644 --- a/lib/rtsp.h +++ b/lib/rtsp.h @@ -53,6 +53,7 @@ struct rtsp_conn { size_t rtp_len; rtp_parse_st state; BIT(in_header); + BIT(initialised); }; /**************************************************************************** diff --git a/lib/url.c b/lib/url.c index ffabad59cf..a745090b5f 100644 --- a/lib/url.c +++ b/lib/url.c @@ -90,6 +90,7 @@ #include "hsts.h" #include "noproxy.h" #include "cfilters.h" +#include "curl_krb5.h" #include "idn.h" /* And now for the protocols */ @@ -506,39 +507,38 @@ CURLcode Curl_open(struct Curl_easy **curl) data->magic = CURLEASY_MAGIC_NUMBER; + Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER); Curl_req_init(&data->req); + Curl_initinfo(data); +#ifndef CURL_DISABLE_HTTP + Curl_llist_init(&data->state.httphdrs, NULL); +#endif + Curl_netrc_init(&data->state.netrc); result = Curl_resolver_init(data, &data->state.async.resolver); if(result) { DEBUGF(fprintf(stderr, "Error: resolver_init failed\n")); - Curl_req_free(&data->req, data); - free(data); - return result; + goto out; } result = Curl_init_userdefined(data); - if(!result) { - Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER); - Curl_initinfo(data); - - /* most recent connection is not yet defined */ - data->state.lastconnect_id = -1; - data->state.recent_conn_id = -1; - /* and not assigned an id yet */ - data->id = -1; - data->mid = -1; + if(result) + goto out; + + /* most recent connection is not yet defined */ + data->state.lastconnect_id = -1; + data->state.recent_conn_id = -1; + /* and not assigned an id yet */ + data->id = -1; + data->mid = -1; #ifndef CURL_DISABLE_DOH - data->set.dohfor_mid = -1; + data->set.dohfor_mid = -1; #endif - data->progress.flags |= PGRS_HIDE; - data->state.current_speed = -1; /* init to negative == impossible */ -#ifndef CURL_DISABLE_HTTP - Curl_llist_init(&data->state.httphdrs, NULL); -#endif - Curl_netrc_init(&data->state.netrc); - } + data->progress.flags |= PGRS_HIDE; + data->state.current_speed = -1; /* init to negative == impossible */ +out: if(result) { Curl_resolver_cleanup(data->state.async.resolver); Curl_dyn_free(&data->state.headerb); @@ -578,6 +578,7 @@ void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn) Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */ Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */ #endif + Curl_sec_conn_destroy(conn); Curl_safefree(conn->user); Curl_safefree(conn->passwd); Curl_safefree(conn->sasl_authzid); @@ -3400,6 +3401,10 @@ static CURLcode create_conn(struct Curl_easy *data, any failure */ *in_connect = conn; + /* Do the unfailable inits first, before checks that may early return */ + /* GSSAPI related inits */ + Curl_sec_conn_init(conn); + result = parseurlandfillconn(data, conn); if(result) goto out; diff --git a/lib/vauth/spnego_gssapi.c b/lib/vauth/spnego_gssapi.c index 55232a8e4a..eb415183e8 100644 --- a/lib/vauth/spnego_gssapi.c +++ b/lib/vauth/spnego_gssapi.c @@ -156,10 +156,10 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, } /* Set channel binding data if available */ - if(nego->channel_binding_data.leng > 0) { + if(Curl_dyn_len(&nego->channel_binding_data)) { memset(&chan, 0, sizeof(struct gss_channel_bindings_struct)); - chan.application_data.length = nego->channel_binding_data.leng; - chan.application_data.value = nego->channel_binding_data.bufr; + chan.application_data.length = Curl_dyn_len(&nego->channel_binding_data); + chan.application_data.value = Curl_dyn_ptr(&nego->channel_binding_data); chan_bindings = &chan; } diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 299b7c8c3e..b20f82adbb 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -2086,10 +2086,14 @@ static CURLcode myssh_setup_connection(struct Curl_easy *data, struct SSHPROTO *ssh; struct ssh_conn *sshc = &conn->proto.sshc; + if(!sshc->initialised) { + Curl_dyn_init(&sshc->readdir_buf, CURL_PATH_MAX * 2); + sshc->initialised = TRUE; + } + data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO)); if(!ssh) return CURLE_OUT_OF_MEMORY; - Curl_dyn_init(&sshc->readdir_buf, CURL_PATH_MAX * 2); return CURLE_OK; } @@ -2295,47 +2299,50 @@ static CURLcode myssh_do_it(struct Curl_easy *data, bool *done) static void sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data) { (void)data; - if(sshc->ssh_session) { - ssh_free(sshc->ssh_session); - sshc->ssh_session = NULL; - } + if(sshc->initialised) { + if(sshc->ssh_session) { + ssh_free(sshc->ssh_session); + sshc->ssh_session = NULL; + } - /* worst-case scenario cleanup */ - DEBUGASSERT(sshc->ssh_session == NULL); - DEBUGASSERT(sshc->scp_session == NULL); + /* worst-case scenario cleanup */ + DEBUGASSERT(sshc->ssh_session == NULL); + DEBUGASSERT(sshc->scp_session == NULL); - if(sshc->readdir_tmp) { - ssh_string_free_char(sshc->readdir_tmp); - sshc->readdir_tmp = NULL; - } - if(sshc->quote_attrs) { - sftp_attributes_free(sshc->quote_attrs); - sshc->quote_attrs = NULL; - } - if(sshc->readdir_attrs) { - sftp_attributes_free(sshc->readdir_attrs); - sshc->readdir_attrs = NULL; - } - if(sshc->readdir_link_attrs) { - sftp_attributes_free(sshc->readdir_link_attrs); - sshc->readdir_link_attrs = NULL; - } - if(sshc->privkey) { - ssh_key_free(sshc->privkey); - sshc->privkey = NULL; - } - if(sshc->pubkey) { - ssh_key_free(sshc->pubkey); - sshc->pubkey = NULL; - } + if(sshc->readdir_tmp) { + ssh_string_free_char(sshc->readdir_tmp); + sshc->readdir_tmp = NULL; + } + if(sshc->quote_attrs) { + sftp_attributes_free(sshc->quote_attrs); + sshc->quote_attrs = NULL; + } + if(sshc->readdir_attrs) { + sftp_attributes_free(sshc->readdir_attrs); + sshc->readdir_attrs = NULL; + } + if(sshc->readdir_link_attrs) { + sftp_attributes_free(sshc->readdir_link_attrs); + sshc->readdir_link_attrs = NULL; + } + if(sshc->privkey) { + ssh_key_free(sshc->privkey); + sshc->privkey = NULL; + } + if(sshc->pubkey) { + ssh_key_free(sshc->pubkey); + sshc->pubkey = NULL; + } - Curl_safefree(sshc->rsa_pub); - Curl_safefree(sshc->rsa); - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - Curl_dyn_free(&sshc->readdir_buf); - Curl_safefree(sshc->readdir_linkPath); - SSH_STRING_FREE_CHAR(sshc->homedir); + Curl_safefree(sshc->rsa_pub); + Curl_safefree(sshc->rsa); + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + Curl_dyn_free(&sshc->readdir_buf); + Curl_safefree(sshc->readdir_linkPath); + SSH_STRING_FREE_CHAR(sshc->homedir); + sshc->initialised = FALSE; + } } /* BLOCKING, but the function is using the state machine so the only reason diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index c2e2223519..1587d251d1 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -1605,7 +1605,6 @@ static CURLcode sftp_readdir(struct Curl_easy *data, if((sshp->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) && ((sshp->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFLNK)) { - Curl_dyn_init(&sshp->readdir_link, CURL_PATH_MAX); result = Curl_dyn_addf(&sshp->readdir_link, "%s%s", sshp->path, sshp->readdir_filename); state(data, SSH_SFTP_READDIR_LINK); @@ -2430,7 +2429,6 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) sshc->actualcode = result ? result : CURLE_SSH; break; } - Curl_dyn_init(&sshp->readdir, CURL_PATH_MAX * 2); state(data, SSH_SFTP_READDIR); break; @@ -3024,13 +3022,23 @@ static CURLcode ssh_block_statemach(struct Curl_easy *data, static CURLcode ssh_setup_connection(struct Curl_easy *data, struct connectdata *conn) { + struct ssh_conn *sshc = &conn->proto.sshc; struct SSHPROTO *ssh; (void)conn; + if(!sshc->initialised) { + /* other ssh implementations do something here, let's keep + * the initialised flag correct even if this implementation does not. */ + sshc->initialised = TRUE; + } + data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO)); if(!ssh) return CURLE_OUT_OF_MEMORY; + Curl_dyn_init(&ssh->readdir, CURL_PATH_MAX * 2); + Curl_dyn_init(&ssh->readdir_link, CURL_PATH_MAX); + return CURLE_OK; } @@ -3331,60 +3339,62 @@ static int sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data, { int rc; - if(sshc->kh) { - libssh2_knownhost_free(sshc->kh); - sshc->kh = NULL; - } - - if(sshc->ssh_agent) { - rc = libssh2_agent_disconnect(sshc->ssh_agent); - if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) { - return rc; + if(sshc->initialised) { + if(sshc->kh) { + libssh2_knownhost_free(sshc->kh); + sshc->kh = NULL; } - if(rc < 0) { - char *err_msg = NULL; - (void)libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0); - infof(data, "Failed to disconnect from libssh2 agent: %d %s", - rc, err_msg); - } - libssh2_agent_free(sshc->ssh_agent); - sshc->ssh_agent = NULL; - /* NB: there is no need to free identities, they are part of internal - agent stuff */ - sshc->sshagent_identity = NULL; - sshc->sshagent_prev_identity = NULL; - } + if(sshc->ssh_agent) { + rc = libssh2_agent_disconnect(sshc->ssh_agent); + if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) { + return rc; + } + if(rc < 0) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Failed to disconnect from libssh2 agent: %d %s", + rc, err_msg); + } + libssh2_agent_free(sshc->ssh_agent); + sshc->ssh_agent = NULL; - if(sshc->ssh_session) { - rc = libssh2_session_free(sshc->ssh_session); - if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) { - return rc; + /* NB: there is no need to free identities, they are part of internal + agent stuff */ + sshc->sshagent_identity = NULL; + sshc->sshagent_prev_identity = NULL; } - if(rc < 0) { - char *err_msg = NULL; - (void)libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0); - infof(data, "Failed to free libssh2 session: %d %s", rc, err_msg); - } - sshc->ssh_session = NULL; - } - /* worst-case scenario cleanup */ - DEBUGASSERT(sshc->ssh_session == NULL); - DEBUGASSERT(sshc->ssh_channel == NULL); - DEBUGASSERT(sshc->sftp_session == NULL); - DEBUGASSERT(sshc->sftp_handle == NULL); - DEBUGASSERT(sshc->kh == NULL); - DEBUGASSERT(sshc->ssh_agent == NULL); - - Curl_safefree(sshc->rsa_pub); - Curl_safefree(sshc->rsa); - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - Curl_safefree(sshc->homedir); + if(sshc->ssh_session) { + rc = libssh2_session_free(sshc->ssh_session); + if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) { + return rc; + } + if(rc < 0) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Failed to free libssh2 session: %d %s", rc, err_msg); + } + sshc->ssh_session = NULL; + } + /* worst-case scenario cleanup */ + DEBUGASSERT(sshc->ssh_session == NULL); + DEBUGASSERT(sshc->ssh_channel == NULL); + DEBUGASSERT(sshc->sftp_session == NULL); + DEBUGASSERT(sshc->sftp_handle == NULL); + DEBUGASSERT(sshc->kh == NULL); + DEBUGASSERT(sshc->ssh_agent == NULL); + + Curl_safefree(sshc->rsa_pub); + Curl_safefree(sshc->rsa); + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + Curl_safefree(sshc->homedir); + sshc->initialised = FALSE; + } return 0; } @@ -3426,6 +3436,7 @@ static CURLcode ssh_done(struct Curl_easy *data, CURLcode status) Curl_safefree(sshp->path); Curl_dyn_free(&sshp->readdir); + Curl_dyn_free(&sshp->readdir_link); if(Curl_pgrsDone(data)) return CURLE_ABORTED_BY_CALLBACK; diff --git a/lib/vssh/ssh.h b/lib/vssh/ssh.h index bbbe95d7de..e882ff3d33 100644 --- a/lib/vssh/ssh.h +++ b/lib/vssh/ssh.h @@ -212,6 +212,7 @@ struct ssh_conn { byte handle[WOLFSSH_MAX_HANDLE]; curl_off_t offset; #endif /* USE_LIBSSH */ + BIT(initialised); }; #ifdef USE_LIBSSH