Example #1
0
struct duo_ctx *
duo_close(struct duo_ctx *ctx)
{
    if (ctx != NULL) {
                if (ctx->https != NULL)
                        https_close(&ctx->https);
                duo_reset(ctx);
                free(ctx->host);
        free(ctx);
    }
        return (NULL);
}
Example #2
0
static duo_code_t
duo_call(struct duo_ctx *ctx, const char *method, const char *uri)
{
        int i, code, err, ret;

        code = 0;
        ctx->body = NULL;
        ctx->body_len = 0;
        
        for (i = 0; i < 3; i++) {
                if (ctx->https == NULL &&
                    (err = https_open(&ctx->https, ctx->host)) != HTTPS_OK) {
                        if (err == HTTPS_ERR_SERVER) {
                                sleep(1 << i);
                                continue;
                        }
                        break;
                }
                if ((err = https_send(ctx->https, method, uri,
                            ctx->argc, ctx->argv)) == HTTPS_OK &&
                    (err = https_recv(ctx->https, &code,
                        &ctx->body, &ctx->body_len)) == HTTPS_OK) {
                        break;
                }
                https_close(&ctx->https);
        }
        duo_reset(ctx);

        if (code == 0) {
                ret = DUO_CONN_ERROR;
                _duo_seterr(ctx, "Couldn't connect to %s: %s\n",
                    ctx->host, https_geterr());
        } else if (code / 100 == 2) {
                /* 2xx indicates DUO_OK */
                ret = DUO_OK;
        } else if (code == 401) {
                /* 401 indicates an invalid ikey or skey */
                ret = DUO_CLIENT_ERROR;
                _duo_seterr(ctx, "Invalid ikey or skey");
        } else if (code / 100 == 5) {
                /* 5xx indicates an internal server error */
                ret = DUO_SERVER_ERROR;
                _duo_seterr(ctx, "HTTP %d", code);
        } else {
                /* abort on any other HTTP codes */
                ret = DUO_ABORT;
                _duo_seterr(ctx, "HTTP %d", code);
        }
        return (ret);
}
Example #3
0
HTTPScode
https_open(struct https_request **reqp, const char *host)
{
        struct https_request *req;
        BIO *b64, *sbio;
        char *p;
        int n;
        int connection_error = 0;
        const char *api_host;
        const char *api_port;

        /* Set up our handle */
        n = 1;
        if ((req = calloc(1, sizeof(*req))) == NULL ||
            (req->host = strdup(host)) == NULL ||
            (req->parser = malloc(sizeof(http_parser))) == NULL) {
                ctx->errstr = strerror(errno);
                https_close(&req);
                return (HTTPS_ERR_SYSTEM);
        }
        if ((p = strchr(req->host, ':')) != NULL) {
                *p = '\0';
                req->port = p + 1;
        } else {
                req->port = "443";
        }
        if ((req->body = BIO_new(BIO_s_mem())) == NULL) {
                ctx->errstr = _SSL_strerror();
                https_close(&req);
                return (HTTPS_ERR_LIB);
        }
        http_parser_init(req->parser, HTTP_RESPONSE);
        req->parser->data = req;

        /* Connect to server */
        if (ctx->proxy) {
            api_host = ctx->proxy;
            api_port = ctx->proxy_port;
        } else {
            api_host = req->host;
            api_port = req->port;
        }
        connection_error = _establish_connection(req, api_host, api_port);
        if (connection_error != HTTPS_OK) {
            https_close(&req);
            return connection_error;
        }

        /* Tunnel through proxy, if specified */
        if (ctx->proxy != NULL) {
                BIO_printf(req->cbio,
                    "CONNECT %s:%s HTTP/1.0\r\n"
                    "User-Agent: %s\r\n",
                    req->host, req->port, ctx->useragent);
                
                if (ctx->proxy_auth != NULL) {
                        b64 = BIO_push(BIO_new(BIO_f_base64()),
                            BIO_new(BIO_s_mem()));
                        BIO_set_flags(b64,BIO_FLAGS_BASE64_NO_NL);
                        BIO_write(b64, ctx->proxy_auth,
                            strlen(ctx->proxy_auth));
                        (void)BIO_flush(b64);
                        n = BIO_get_mem_data(b64, &p);

                        BIO_puts(req->cbio, "Proxy-Authorization: Basic ");
                        BIO_write(req->cbio, p, n);
                        BIO_puts(req->cbio, "\r\n");
                        BIO_free_all(b64);
                }
                BIO_puts(req->cbio, "\r\n");
                (void)BIO_flush(req->cbio);
                
                while ((n = BIO_read(req->cbio, ctx->parse_buf,
                            sizeof(ctx->parse_buf))) <= 0) {
                        _BIO_wait(req->cbio, 5000);
                }
                if (strncmp("HTTP/1.0 200", ctx->parse_buf, 12) != 0) {
                        snprintf(ctx->errbuf, sizeof(ctx->errbuf),
                            "Proxy error: %s", ctx->parse_buf);
                        ctx->errstr = strtok(ctx->errbuf, "\r\n");
                        https_close(&req);
                        if (n < 12 || atoi(ctx->parse_buf + 9) < 500)
                                return (HTTPS_ERR_CLIENT);
                        return (HTTPS_ERR_SERVER);
                }
        }
        /* Establish SSL connection */
        if ((sbio = BIO_new_ssl(ctx->ssl_ctx, 1)) == NULL) {
                https_close(&req);
                return (HTTPS_ERR_LIB);
        }
        req->cbio = BIO_push(sbio, req->cbio);
        BIO_get_ssl(req->cbio, &req->ssl);
        
        while (BIO_do_handshake(req->cbio) <= 0) {
                if ((n = _BIO_wait(req->cbio, 5000)) != 1) {
                        ctx->errstr = n ? _SSL_strerror() :
                            "SSL handshake timed out";
                        https_close(&req);
                        return (n ? HTTPS_ERR_SYSTEM : HTTPS_ERR_SERVER);
                }
        }
        /* Validate server certificate name */
        if (_SSL_check_server_cert(req->ssl, req->host) != 1) {
                ctx->errstr = "Certificate name validation failed";
                https_close(&req);
                return (HTTPS_ERR_LIB);
        }
        *reqp = req;
        
        return (HTTPS_OK);
}