struct http_credentials *http_header_get_proxy_credentials(const struct http_header *header, struct http_credentials *credentials) { const struct http_header *p; credentials->scheme = AUTH_UNKNOWN; p = NULL; while ((p = http_header_next(header, p, "Proxy-Authorization")) != NULL) { const char *tmp; tmp = p->value; while (*tmp != '\0') { struct http_credentials tmp_info; tmp = http_read_credentials(tmp, &tmp_info); if (tmp == NULL) { http_credentials_free(credentials); return NULL; } if (auth_scheme_is_better(tmp_info.scheme, credentials->scheme)) { http_credentials_free(credentials); *credentials = tmp_info; } else { http_credentials_free(&tmp_info); } } } return credentials; }
static const char *http_read_credentials(const char *s, struct http_credentials *credentials) { const char *p; char *scheme; credentials->scheme = AUTH_UNKNOWN; s = read_token(s, &scheme); if (s == NULL) return NULL; if (str_equal_i(scheme, "Basic")) { http_credentials_init_basic(credentials); } else if (str_equal_i(scheme, "Digest")) { http_credentials_init_digest(credentials); } else { free(scheme); return NULL; } free(scheme); while (is_space_char(*s)) s++; if (credentials->scheme == AUTH_BASIC) { p = s; /* Read base64. */ while (is_alpha_char(*p) || is_digit_char(*p) || *p == '+' || *p == '/' || *p == '=') p++; credentials->u.basic = mkstr(s, p); while (is_space_char(*p)) p++; s = p; } else if (credentials->scheme == AUTH_DIGEST) { char *name, *value; while (*s != '\0') { p = read_token(s, &name); if (p == NULL) goto bail; while (is_space_char(*p)) p++; /* It's not legal to combine multiple Authorization or Proxy-Authorization values. The productions are "Authorization" ":" credentials (section 14.8) "Proxy-Authorization" ":" credentials (section 14.34) Contrast this with WWW-Authenticate and Proxy-Authenticate and their handling in http_read_challenge. */ if (*p != '=') goto bail; 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, "username")) { if (credentials->u.digest.username != NULL) goto bail; credentials->u.digest.username = Strdup(value); } else if (str_equal_i(name, "realm")) { if (credentials->u.digest.realm != NULL) goto bail; credentials->u.digest.realm = Strdup(value); } else if (str_equal_i(name, "nonce")) { if (credentials->u.digest.nonce != NULL) goto bail; credentials->u.digest.nonce = Strdup(value); } else if (str_equal_i(name, "uri")) { if (credentials->u.digest.uri != NULL) goto bail; credentials->u.digest.uri = Strdup(value); } else if (str_equal_i(name, "response")) { if (credentials->u.digest.response != NULL) goto bail; credentials->u.digest.response = Strdup(value); } else if (str_equal_i(name, "algorithm")) { if (str_equal_i(value, "MD5")) credentials->u.digest.algorithm = ALGORITHM_MD5; else credentials->u.digest.algorithm = ALGORITHM_MD5; } else if (str_equal_i(name, "qop")) { if (str_equal_i(value, "auth")) credentials->u.digest.qop = QOP_AUTH; else if (str_equal_i(value, "auth-int")) credentials->u.digest.qop = QOP_AUTH_INT; else credentials->u.digest.qop = QOP_NONE; } else if (str_equal_i(name, "cnonce")) { if (credentials->u.digest.cnonce != NULL) goto bail; credentials->u.digest.cnonce = Strdup(value); } else if (str_equal_i(name, "nc")) { if (credentials->u.digest.nc != NULL) goto bail; credentials->u.digest.nc = Strdup(value); } 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: http_credentials_free(credentials); return NULL; }
static void http_server_handler(int c) { int code; struct socket_buffer sock; struct http_request request; char *buf; socket_buffer_init(&sock, c); #if HAVE_OPENSSL if (o.ssl) { sock.fdn.ssl = new_ssl(sock.fdn.fd); if (SSL_accept(sock.fdn.ssl) != 1) { loguser("Failed SSL connection: %s\n", ERR_error_string(ERR_get_error(), NULL)); fdinfo_close(&sock.fdn); return; } } #endif code = http_read_request_line(&sock, &buf); if (code != 0) { if (o.verbose) logdebug("Error reading Request-Line.\n"); send_string(&sock.fdn, http_code2str(code)); fdinfo_close(&sock.fdn); return; } if (o.debug > 1) logdebug("Request-Line: %s", buf); code = http_parse_request_line(buf, &request); free(buf); if (code != 0) { if (o.verbose) logdebug("Error parsing Request-Line.\n"); send_string(&sock.fdn, http_code2str(code)); fdinfo_close(&sock.fdn); return; } if (!method_is_known(request.method)) { if (o.debug > 1) logdebug("Bad method: %s.\n", request.method); http_request_free(&request); send_string(&sock.fdn, http_code2str(405)); fdinfo_close(&sock.fdn); return; } code = http_read_header(&sock, &buf); if (code != 0) { if (o.verbose) logdebug("Error reading header.\n"); http_request_free(&request); send_string(&sock.fdn, http_code2str(code)); fdinfo_close(&sock.fdn); return; } if (o.debug > 1) logdebug("Header:\n%s", buf); code = http_request_parse_header(&request, buf); free(buf); if (code != 0) { if (o.verbose) logdebug("Error parsing header.\n"); http_request_free(&request); send_string(&sock.fdn, http_code2str(code)); fdinfo_close(&sock.fdn); return; } /* Check authentication. */ if (o.proxy_auth) { struct http_credentials credentials; int ret, stale; if (http_header_get_proxy_credentials(request.header, &credentials) == NULL) { /* No credentials or a parsing error. */ send_proxy_authenticate(&sock.fdn, 0); http_request_free(&request); fdinfo_close(&sock.fdn); return; } ret = check_auth(&request, &credentials, &stale); http_credentials_free(&credentials); if (!ret) { /* Password doesn't match. */ /* RFC 2617, section 1.2: "If a proxy does not accept the credentials sent with a request, it SHOULD return a 407 (Proxy Authentication Required). */ send_proxy_authenticate(&sock.fdn, stale); http_request_free(&request); fdinfo_close(&sock.fdn); return; } } if (strcmp(request.method, "CONNECT") == 0) { code = handle_connect(&sock, &request); } else if (strcmp(request.method, "GET") == 0 || strcmp(request.method, "HEAD") == 0 || strcmp(request.method, "POST") == 0) { code = handle_method(&sock, &request); } else { code = 500; } http_request_free(&request); if (code != 0) { send_string(&sock.fdn, http_code2str(code)); fdinfo_close(&sock.fdn); return; } fdinfo_close(&sock.fdn); }