Blame src/plugins/https-utils.c

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