Example #1
0
struct http_challenge *http_header_get_proxy_challenge(const struct http_header *header, struct http_challenge *challenge)
{
    const struct http_header *p;

    http_challenge_init(challenge);

    p = NULL;
    while ((p = http_header_next(header, p, "Proxy-Authenticate")) != NULL) {
        const char *tmp;

        tmp = p->value;
        while (*tmp != '\0') {
            struct http_challenge tmp_info;

            tmp = http_read_challenge(tmp, &tmp_info);
            if (tmp == NULL) {
                http_challenge_free(challenge);
                return NULL;
            }
            if (auth_scheme_is_better(tmp_info.scheme, challenge->scheme)) {
                http_challenge_free(challenge);
                *challenge = tmp_info;
            } else {
                http_challenge_free(&tmp_info);
            }
        }
    }

    return challenge;
}
Example #2
0
static const char *http_read_challenge(const char *s, struct http_challenge *challenge)
{
    const char *p;
    char *scheme;

    http_challenge_init(challenge);

    scheme = NULL;
    s = read_token(s, &scheme);
    if (s == NULL)
        goto bail;
    if (str_equal_i(scheme, "Basic")) {
        challenge->scheme = AUTH_BASIC;
    } else if (str_equal_i(scheme, "Digest")) {
        challenge->scheme = AUTH_DIGEST;
    } else {
        challenge->scheme = AUTH_UNKNOWN;
    }
    free(scheme);
    scheme = NULL;

    /* RFC 2617, section 1.2, requires at least one auth-param:
         challenge = auth-scheme 1*SP 1#auth-param
       But there are some schemes (NTLM and Negotiate) that can be without
       auth-params, so we allow that here. A comma indicates the end of this
       challenge and the beginning of the next (see the comment in the loop
       below). */
    while (is_space_char(*s))
        s++;
    if (*s == ',') {
        s++;
        while (is_space_char(*s))
            s++;
        if (*s == '\0')
            goto bail;
        return s;
    }

    while (*s != '\0') {
        char *name, *value;

        p = read_token(s, &name);
        if (p == NULL)
            goto bail;
        while (is_space_char(*p))
            p++;
        /* It's possible that we've hit the end of one challenge and the
           beginning of another. Section 14.33 says that the header value can be
           1#challenge, in other words several challenges separated by commas.
           Because the auth-params are also separated by commas, the only way we
           can tell is if we find a token not followed by an equals sign. */
        if (*p != '=')
            break;
        p++;
        while (is_space_char(*p))
            p++;
        p = read_token_or_quoted_string(p, &value);
        if (p == NULL) {
            free(name);
            goto bail;
        }
        if (str_equal_i(name, "realm"))
            challenge->realm = Strdup(value);
        else if (challenge->scheme == AUTH_DIGEST) {
            if (str_equal_i(name, "nonce")) {
                if (challenge->digest.nonce != NULL)
                    goto bail;
                challenge->digest.nonce = Strdup(value);
            } else if (str_equal_i(name, "opaque")) {
                if (challenge->digest.opaque != NULL)
                    goto bail;
                challenge->digest.opaque = Strdup(value);
            } else if (str_equal_i(name, "algorithm")) {
                if (str_equal_i(value, "MD5"))
                    challenge->digest.algorithm = ALGORITHM_MD5;
                else
                    challenge->digest.algorithm = ALGORITHM_UNKNOWN;
            } else if (str_equal_i(name, "qop")) {
                char **tokens;
                size_t n;
                int i;
                const char *tmp;

                tmp = read_token_list(value, &tokens, &n);
                if (tmp == NULL) {
                    free(name);
                    free(value);
                    goto bail;
                }
                for (i = 0; i < n; i++) {
                    if (str_equal_i(tokens[i], "auth"))
                        challenge->digest.qop |= QOP_AUTH;
                    else if (str_equal_i(tokens[i], "auth-int"))
                        challenge->digest.qop |= QOP_AUTH_INT;
                }
                for (i = 0; i < n; i++)
                    free(tokens[i]);
                free(tokens);
                if (*tmp != '\0') {
                    free(name);
                    free(value);
                    goto bail;
                }
            }
        }
        free(name);
        free(value);
        while (is_space_char(*p))
            p++;
        if (*p == ',') {
            p++;
            while (is_space_char(*p))
                p++;
            if (*p == '\0')
                goto bail;
        }
        s = p;
    }

    return s;

bail:
    if (scheme != NULL)
        free(scheme);
    http_challenge_free(challenge);

    return NULL;
}
Example #3
0
/* Return a usable socket descriptor after proxy negotiation, or -1 on any
   error. If any bytes are received through the proxy after negotiation, they
   are written to stdout. */
static int do_proxy_http(void)
{
    struct socket_buffer sockbuf;
    char *request;
    char *status_line, *header;
    char *remainder;
    size_t len;
    int sd, code;
    int n;

    sd = do_connect(SOCK_STREAM);
    if (sd == -1) {
        loguser("Proxy connection failed: %s.\n", socket_strerror(socket_errno()));
        return -1;
    }

    status_line = NULL;
    header = NULL;

    /* First try a request with no authentication. */
    request = http_connect_request(&httpconnect, &n);
    if (send(sd, request, n, 0) < 0) {
        loguser("Error sending proxy request: %s.\n", socket_strerror(socket_errno()));
        free(request);
        return -1;
    }
    free(request);

    socket_buffer_init(&sockbuf, sd);

    if (http_read_status_line(&sockbuf, &status_line) != 0) {
        loguser("Error reading proxy response Status-Line.\n");
        goto bail;
    }
    code = http_parse_status_line_code(status_line);
    logdebug("Proxy returned status code %d.\n", code);
    free(status_line);
    status_line = NULL;
    if (http_read_header(&sockbuf, &header) != 0) {
        loguser("Error reading proxy response header.\n");
        goto bail;
    }

    if (code == 407 && o.proxy_auth != NULL) {
        struct http_header *h;
        struct http_challenge challenge;

        close(sd);
        sd = -1;

        if (http_parse_header(&h, header) != 0) {
            loguser("Error parsing proxy response header.\n");
            goto bail;
        }
        free(header);
        header = NULL;

        if (http_header_get_proxy_challenge(h, &challenge) == NULL) {
            loguser("Error getting Proxy-Authenticate challenge.\n");
            http_header_free(h);
            goto bail;
        }
        http_header_free(h);

        sd = do_connect(SOCK_STREAM);
        if (sd == -1) {
            loguser("Proxy reconnection failed: %s.\n", socket_strerror(socket_errno()));
            goto bail;
        }

        request = http_connect_request_auth(&httpconnect, &n, &challenge);
        if (request == NULL) {
            loguser("Error building Proxy-Authorization header.\n");
            http_challenge_free(&challenge);
            goto bail;
        }
        logdebug("Reconnection header:\n%s", request);
        if (send(sd, request, n, 0) < 0) {
            loguser("Error sending proxy request: %s.\n", socket_strerror(socket_errno()));
            free(request);
            http_challenge_free(&challenge);
            goto bail;
        }
        free(request);
        http_challenge_free(&challenge);

        socket_buffer_init(&sockbuf, sd);

        if (http_read_status_line(&sockbuf, &status_line) != 0) {
            loguser("Error reading proxy response Status-Line.\n");
            goto bail;
        }
        code = http_parse_status_line_code(status_line);
        logdebug("Proxy returned status code %d.\n", code);
        free(status_line);
        status_line = NULL;
        if (http_read_header(&sockbuf, &header) != 0) {
            loguser("Error reading proxy response header.\n");
            goto bail;
        }
    }

    free(header);
    header = NULL;

    if (code != 200) {
        loguser("Proxy returned status code %d.\n", code);
        return -1;
    }

    remainder = socket_buffer_remainder(&sockbuf, &len);
    Write(STDOUT_FILENO, remainder, len);

    return sd;

bail:
    if (sd != -1)
        close(sd);
    if (status_line != NULL)
        free(status_line);
    if (header != NULL)
        free(header);

    return -1;
}