|
Packit |
8ea169 |
/*
|
|
Packit |
8ea169 |
Copyright (C) 2012 ABRT Team
|
|
Packit |
8ea169 |
Copyright (C) 2012 Red Hat, Inc.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
This program is free software; you can redistribute it and/or modify
|
|
Packit |
8ea169 |
it under the terms of the GNU General Public License as published by
|
|
Packit |
8ea169 |
the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
8ea169 |
(at your option) any later version.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
This program is distributed in the hope that it will be useful,
|
|
Packit |
8ea169 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8ea169 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8ea169 |
GNU General Public License for more details.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
You should have received a copy of the GNU General Public License along
|
|
Packit |
8ea169 |
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit |
8ea169 |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#include "https-utils.h"
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static bool ssl_allow_insecure = false;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Caller must free lang->locale if not NULL */
|
|
Packit |
8ea169 |
void get_language(struct language *lang)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
lang->locale = NULL;
|
|
Packit |
8ea169 |
lang->encoding = NULL;
|
|
Packit |
8ea169 |
/*
|
|
Packit |
8ea169 |
* Note: ->accept_language and ->accept_charset will always be non-NULL:
|
|
Packit |
8ea169 |
* if we don't know them, they'll be ""; otherwise,
|
|
Packit |
8ea169 |
* they will be fully formed HTTP headers, with \r\n at the end.
|
|
Packit |
8ea169 |
* IOW: they are formatted for adding them to HTTP headers as-is.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *locale = setlocale(LC_ALL, NULL);
|
|
Packit |
8ea169 |
if (!locale)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
lang->accept_language = xzalloc(1);
|
|
Packit |
8ea169 |
lang->accept_charset = xzalloc(1);
|
|
Packit |
8ea169 |
return;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
lang->locale = xstrdup(locale);
|
|
Packit |
8ea169 |
lang->accept_language = xasprintf("Accept-Language: %s\r\n", locale);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
lang->encoding = strchr(lang->locale, '.');
|
|
Packit |
8ea169 |
if (!lang->encoding)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
lang->accept_charset = xzalloc(1);
|
|
Packit |
8ea169 |
return;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
*lang->encoding = '\0';
|
|
Packit |
8ea169 |
++lang->encoding;
|
|
Packit |
8ea169 |
lang->accept_charset = xasprintf("Accept-Charset: %s\r\n", lang->encoding);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void alert_server_error(const char *peer_name)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (!peer_name)
|
|
Packit |
8ea169 |
alert(_("An error occurred on the server side."));
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *msg = xasprintf(_("A server-side error occurred on '%s'"), peer_name);
|
|
Packit |
8ea169 |
alert(msg);
|
|
Packit |
8ea169 |
free(msg);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void alert_connection_error(const char *peer_name)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (!peer_name)
|
|
Packit |
8ea169 |
alert(_("An error occurred while connecting to the server"));
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *msg = xasprintf(_("An error occurred while connecting to '%s'"), peer_name);
|
|
Packit |
8ea169 |
alert(msg);
|
|
Packit |
8ea169 |
free(msg);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static SECStatus ssl_bad_cert_handler(void *arg, PRFileDesc *sock)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
PRErrorCode err = PR_GetError();
|
|
Packit |
8ea169 |
CERTCertificate *cert = SSL_PeerCertificate(sock);
|
|
Packit |
8ea169 |
char *subject = CERT_NameToAscii(&cert->subject);
|
|
Packit |
8ea169 |
char *subject_cn = CERT_GetCommonName(&cert->subject);
|
|
Packit |
8ea169 |
char *issuer = CERT_NameToAscii(&cert->issuer);
|
|
Packit |
8ea169 |
CERT_DestroyCertificate(cert);
|
|
Packit |
8ea169 |
char *target_host = SSL_RevealURL(sock);
|
|
Packit |
8ea169 |
if (!target_host)
|
|
Packit |
8ea169 |
target_host = xstrdup("(unknown)");
|
|
Packit |
8ea169 |
switch (err)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
case SEC_ERROR_CA_CERT_INVALID:
|
|
Packit |
8ea169 |
error_msg(_("Issuer certificate is invalid: '%s'."), issuer);
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
case SEC_ERROR_UNTRUSTED_ISSUER:
|
|
Packit |
8ea169 |
error_msg(_("Certificate is signed by an untrusted issuer: '%s'."), issuer);
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
case SSL_ERROR_BAD_CERT_DOMAIN:
|
|
Packit |
8ea169 |
error_msg(_("Certificate subject name '%s' does not match target host name '%s'."),
|
|
Packit |
8ea169 |
subject_cn, target_host);
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
case SEC_ERROR_EXPIRED_CERTIFICATE:
|
|
Packit |
8ea169 |
error_msg(_("Remote certificate has expired."));
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
case SEC_ERROR_UNKNOWN_ISSUER:
|
|
Packit |
8ea169 |
error_msg(_("Certificate issuer is not recognized: '%s'."), issuer);
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
default:
|
|
Packit |
8ea169 |
error_msg(_("Bad certificate received. Subject '%s', issuer '%s'."),
|
|
Packit |
8ea169 |
subject, issuer);
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
PR_Free(target_host);
|
|
Packit |
8ea169 |
return ssl_allow_insecure ? SECSuccess : SECFailure;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static SECStatus ssl_handshake_callback(PRFileDesc *sock, void *arg)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return SECSuccess;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static const char *ssl_get_configdir()
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
struct stat buf;
|
|
Packit |
8ea169 |
if (getenv("SSL_DIR"))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (0 == stat(getenv("SSL_DIR"), &buf) &&
|
|
Packit |
8ea169 |
S_ISDIR(buf.st_mode))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return getenv("SSL_DIR");
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
if (0 == stat("/etc/pki/nssdb", &buf) &&
|
|
Packit |
8ea169 |
S_ISDIR(buf.st_mode))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return "/etc/pki/nssdb";
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void ssl_connect(struct https_cfg *cfg, PRFileDesc **tcp_sock, PRFileDesc **ssl_sock)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
PRAddrInfo *addrinfo = PR_GetAddrInfoByName(cfg->url, PR_AF_UNSPEC, PR_AI_ADDRCONFIG);
|
|
Packit |
8ea169 |
if (!addrinfo)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_connection_error(cfg->url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Can't resolve host name '%s'. NSS error %d."), cfg->url, PR_GetError());
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Hack */
|
|
Packit |
8ea169 |
ssl_allow_insecure = cfg->ssl_allow_insecure;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void *enumptr = NULL;
|
|
Packit |
8ea169 |
PRNetAddr addr;
|
|
Packit |
8ea169 |
*tcp_sock = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
while ((enumptr = PR_EnumerateAddrInfo(enumptr, addrinfo, cfg->port, &addr)) != NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (addr.raw.family == PR_AF_INET || addr.raw.family == PR_AF_INET6)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
*tcp_sock = PR_OpenTCPSocket(addr.raw.family);
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
PR_FreeAddrInfo(addrinfo);
|
|
Packit |
8ea169 |
if (!*tcp_sock)
|
|
Packit |
8ea169 |
/* Host exists, but has neither IPv4 nor IPv6?? */
|
|
Packit |
8ea169 |
error_msg_and_die(_("Can't resolve host name '%s'."), cfg->url);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* These operations are expected to always succeed: */
|
|
Packit |
8ea169 |
PRSocketOptionData sock_option;
|
|
Packit |
8ea169 |
sock_option.option = PR_SockOpt_Nonblocking;
|
|
Packit |
8ea169 |
sock_option.value.non_blocking = PR_FALSE;
|
|
Packit |
8ea169 |
if (PR_SUCCESS != PR_SetSocketOption(*tcp_sock, &sock_option))
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to set socket blocking mode."));
|
|
Packit |
8ea169 |
*ssl_sock = SSL_ImportFD(NULL, *tcp_sock);
|
|
Packit |
8ea169 |
if (!*ssl_sock)
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to wrap TCP socket by SSL."));
|
|
Packit |
8ea169 |
if (SECSuccess != SSL_OptionSet(*ssl_sock, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE))
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to enable client handshake to SSL socket."));
|
|
Packit |
8ea169 |
// https://bugzilla.redhat.com/show_bug.cgi?id=1189952
|
|
Packit |
8ea169 |
//if (SECSuccess != SSL_OptionSet(*ssl_sock, SSL_ENABLE_SSL2, PR_TRUE))
|
|
Packit |
8ea169 |
// error_msg_and_die(_("Failed to enable SSL2."));
|
|
Packit |
8ea169 |
if (SECSuccess != SSL_OptionSet(*ssl_sock, SSL_ENABLE_SSL3, PR_TRUE))
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to enable SSL3."));
|
|
Packit |
8ea169 |
if (SECSuccess != SSL_OptionSet(*ssl_sock, SSL_ENABLE_TLS, PR_TRUE))
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to enable TLS."));
|
|
Packit |
8ea169 |
if (SECSuccess != SSL_SetURL(*ssl_sock, cfg->url))
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to set URL to SSL socket."));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* This finally sends packets down the wire.
|
|
Packit |
8ea169 |
* If we fail here, then server denied our connect, or is down, etc.
|
|
Packit |
8ea169 |
* Need a good error message.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
if (PR_SUCCESS != PR_Connect(*ssl_sock, &addr, PR_INTERVAL_NO_TIMEOUT))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_connection_error(cfg->url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Can't connect to '%s'"), cfg->url);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* These should not fail either. (Why we don't set them earlier?) */
|
|
Packit |
8ea169 |
if (SECSuccess != SSL_BadCertHook(*ssl_sock,
|
|
Packit |
8ea169 |
(SSLBadCertHandler)ssl_bad_cert_handler,
|
|
Packit |
8ea169 |
NULL))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to set certificate hook."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
if (SECSuccess != SSL_HandshakeCallback(*ssl_sock,
|
|
Packit |
8ea169 |
(SSLHandshakeCallback)ssl_handshake_callback,
|
|
Packit |
8ea169 |
NULL))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to set handshake callback."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
if (SECSuccess != SSL_ResetHandshake(*ssl_sock, /*asServer:*/PR_FALSE))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to reset handshake."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* This performs SSL/TLS negotiation */
|
|
Packit |
8ea169 |
if (SECSuccess != SSL_ForceHandshake(*ssl_sock))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_connection_error(cfg->url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to complete SSL handshake: NSS error %d."),
|
|
Packit |
8ea169 |
PR_GetError());
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void ssl_disconnect(PRFileDesc *ssl_sock)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
PRStatus pr_status = PR_Close(ssl_sock);
|
|
Packit |
8ea169 |
if (PR_SUCCESS != pr_status)
|
|
Packit |
8ea169 |
error_msg(_("Failed to close SSL socket."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/**
|
|
Packit |
8ea169 |
* Parse a header's value from HTTP message. Only alnum values are supported.
|
|
Packit |
8ea169 |
* @returns
|
|
Packit |
8ea169 |
* Caller must free the returned value.
|
|
Packit |
8ea169 |
* If no header is found, NULL is returned.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
char *http_get_header_value(const char *message,
|
|
Packit |
8ea169 |
const char *header_name)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *headers_end = strstr(message, "\r\n\r\n");
|
|
Packit |
8ea169 |
if (!headers_end)
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
char *search_string = xasprintf("\r\n%s:", header_name);
|
|
Packit |
8ea169 |
char *header = strcasestr(message, search_string);
|
|
Packit |
8ea169 |
if (!header || header > headers_end)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
free(search_string);
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
header += strlen(search_string);
|
|
Packit |
8ea169 |
free(search_string);
|
|
Packit |
8ea169 |
while (*header == ' ')
|
|
Packit |
8ea169 |
++header;
|
|
Packit |
8ea169 |
int len = 0;
|
|
Packit |
8ea169 |
while (header[len] && header[len] != '\r' && header[len] != '\n')
|
|
Packit |
8ea169 |
++len;
|
|
Packit |
8ea169 |
while (header[len - 1] == ' ') /* strip spaces from right */
|
|
Packit |
8ea169 |
--len;
|
|
Packit |
8ea169 |
return xstrndup(header, len);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/**
|
|
Packit |
8ea169 |
* Parse body from HTTP message.
|
|
Packit |
8ea169 |
* Caller must free the returned value.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
char *http_get_body(const char *message)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *body = strstr(message, "\r\n\r\n");
|
|
Packit |
8ea169 |
if (!body)
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
body += strlen("\r\n\r\n");
|
|
Packit |
8ea169 |
strtrimch(body, ' ');
|
|
Packit |
8ea169 |
return xstrdup(body);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int http_get_response_code(const char *message)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (0 != strncmp(message, "HTTP/", strlen("HTTP/")))
|
|
Packit |
8ea169 |
goto err;
|
|
Packit |
8ea169 |
char *space = strchr(message, ' ');
|
|
Packit |
8ea169 |
if (!space)
|
|
Packit |
8ea169 |
goto err;
|
|
Packit |
8ea169 |
int response_code;
|
|
Packit |
8ea169 |
if (1 != sscanf(space + 1, "%d", &response_code))
|
|
Packit |
8ea169 |
goto err;
|
|
Packit |
8ea169 |
return response_code;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
err:
|
|
Packit |
8ea169 |
alert_server_error(NULL);
|
|
Packit |
8ea169 |
/* Show bad header to the user */
|
|
Packit |
8ea169 |
char *sanitized = sanitize_utf8(message, (SANITIZE_ALL & ~SANITIZE_TAB));
|
|
Packit |
8ea169 |
error_msg_and_die(_("Malformed HTTP response header: '%s'"), sanitized ? sanitized : message);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void http_print_headers(FILE *file, const char *message)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const char *headers_end = strstr(message, "\r\n\r\n");
|
|
Packit |
8ea169 |
const char *c;
|
|
Packit |
8ea169 |
if (!headers_end)
|
|
Packit |
8ea169 |
headers_end = message + strlen(message);
|
|
Packit |
8ea169 |
for (c = message; c != headers_end + 2; ++c)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (*c == '\r')
|
|
Packit |
8ea169 |
continue;
|
|
Packit |
8ea169 |
putc(*c, file);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/**
|
|
Packit |
8ea169 |
* @returns
|
|
Packit |
8ea169 |
* Caller must free the returned value.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
char *tcp_read_response(PRFileDesc *tcp_sock)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
struct strbuf *strbuf = strbuf_new();
|
|
Packit |
8ea169 |
char buf[32768];
|
|
Packit |
8ea169 |
PRInt32 received = 0;
|
|
Packit |
8ea169 |
do {
|
|
Packit |
8ea169 |
received = PR_Recv(tcp_sock, buf, sizeof(buf) - 1, /*flags:*/0,
|
|
Packit |
8ea169 |
PR_INTERVAL_NO_TIMEOUT);
|
|
Packit |
8ea169 |
if (received > 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
buf[received] = '\0';
|
|
Packit |
8ea169 |
strbuf_append_str(strbuf, buf);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
if (received == -1)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_connection_error(NULL);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Receiving of data failed: NSS error %d."),
|
|
Packit |
8ea169 |
PR_GetError());
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
} while (received > 0);
|
|
Packit |
8ea169 |
return strbuf_free_nobuf(strbuf);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/**
|
|
Packit |
8ea169 |
* Joins HTTP response body if the Transfer-Encoding is chunked.
|
|
Packit |
8ea169 |
* @param body raw HTTP response body (response without headers)
|
|
Packit |
8ea169 |
* the function operates on the input, but returns it
|
|
Packit |
8ea169 |
* to the initial state when done
|
|
Packit |
8ea169 |
* @returns Joined HTTP response body. Caller must free the value.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
char *http_join_chunked(char *body, int bodylen)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
struct strbuf *result = strbuf_new();
|
|
Packit |
8ea169 |
unsigned len;
|
|
Packit |
8ea169 |
int blen = bodylen > 0 ? bodylen : strlen(body);
|
|
Packit |
8ea169 |
char prevchar;
|
|
Packit |
8ea169 |
char *cursor = body;
|
|
Packit |
8ea169 |
while (cursor - body < blen)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (sscanf(cursor, "%x", &len) != 1)
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* jump to next line */
|
|
Packit |
8ea169 |
cursor = strchr(cursor, '\n');
|
|
Packit |
8ea169 |
if (!cursor)
|
|
Packit |
8ea169 |
error_msg_and_die(_("Malformed chunked response."));
|
|
Packit |
8ea169 |
++cursor;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* split chunk and append to result */
|
|
Packit |
8ea169 |
prevchar = cursor[len];
|
|
Packit |
8ea169 |
cursor[len] = '\0';
|
|
Packit |
8ea169 |
strbuf_append_str(result, cursor);
|
|
Packit |
8ea169 |
cursor[len] = prevchar;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* len + strlen("\r\n") */
|
|
Packit |
8ea169 |
cursor += len + 2;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return strbuf_free_nobuf(result);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void nss_init(SECMODModule **mod)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
SECStatus sec_status;
|
|
Packit |
8ea169 |
const char *configdir = ssl_get_configdir();
|
|
Packit |
8ea169 |
if (configdir)
|
|
Packit |
8ea169 |
sec_status = NSS_Initialize(configdir, "", "", "", NSS_INIT_READONLY);
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
sec_status = NSS_NoDB_Init(NULL);
|
|
Packit |
8ea169 |
if (SECSuccess != sec_status)
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to initialize NSS."));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
// Initialize the trusted certificate store.
|
|
Packit |
8ea169 |
char module_name[] = "library=libnssckbi.so name=\"Root Certs\"";
|
|
Packit |
8ea169 |
*mod = SECMOD_LoadUserModule(module_name, NULL, PR_FALSE);
|
|
Packit |
8ea169 |
if (*mod == NULL || !(*mod)->loaded)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const PRErrorCode err = PR_GetError();
|
|
Packit |
8ea169 |
error_msg_and_die("error: NSPR error code %d: %s\n", err, PR_ErrorToName(err));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void nss_close(SECMODModule *mod)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
SSL_ClearSessionCache();
|
|
Packit |
8ea169 |
SECMOD_UnloadUserModule(mod);
|
|
Packit |
8ea169 |
SECMOD_DestroyModule(mod);
|
|
Packit |
8ea169 |
SECStatus sec_status = NSS_Shutdown();
|
|
Packit |
8ea169 |
if (SECSuccess != sec_status)
|
|
Packit |
8ea169 |
error_msg(_("Failed to shutdown NSS."));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
PR_Cleanup();
|
|
Packit |
8ea169 |
}
|