/********************************************************************* * * Function : parse_http_request * * Description : Parse out the host and port from the URL. Find the * hostname & path, port (if ':'), and/or password (if '@') * * Parameters : * 1 : req = HTTP request line to break down * 2 : http = pointer to the http structure to hold elements * * Returns : JB_ERR_OK on success * JB_ERR_CGI_PARAMS on malformed command/URL * or >100 domains deep. * *********************************************************************/ jb_err parse_http_request(const char *req, struct http_request *http) { char *buf; char *v[3]; int n; jb_err err; memset(http, '\0', sizeof(*http)); buf = strdup_or_die(req); n = ssplit(buf, " \r\n", v, SZ(v)); if (n != 3) { freez(buf); return JB_ERR_PARSE; } /* * Fail in case of unknown methods * which we might not handle correctly. * * XXX: There should be a config option * to forward requests with unknown methods * anyway. Most of them don't need special * steps. */ if (unknown_method(v[0])) { log_error(LOG_LEVEL_ERROR, "Unknown HTTP method detected: %s", v[0]); freez(buf); return JB_ERR_PARSE; } if (JB_ERR_OK != normalize_http_version(v[2])) { freez(buf); return JB_ERR_PARSE; } http->ssl = !strcmpic(v[0], "CONNECT"); err = parse_http_url(v[1], http, !http->ssl); if (err) { freez(buf); return err; } /* * Copy the details into the structure */ http->cmd = strdup_or_die(req); http->gpc = strdup_or_die(v[0]); http->ver = strdup_or_die(v[2]); http->ocmd = strdup_or_die(http->cmd); freez(buf); return JB_ERR_OK; }
/********************************************************************* * * Function : is_untrusted_url * * Description : Should we "distrust" this URL (and block it)? * * Yes if it matches a line in the trustfile, or if the * referrer matches a line starting with "+" in the * trustfile. * No otherwise. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : 0 => trusted, 1 => untrusted * *********************************************************************/ int is_untrusted_url(struct client_state *csp) { struct file_list *fl; struct block_spec *b; struct url_spec **trusted_url; struct http_request rhttp[1]; const char * referer; jb_err err; /* * If we don't have a trustlist, we trust everybody */ if (((fl = csp->tlist) == NULL) || ((b = fl->f) == NULL)) { return 0; } memset(rhttp, '\0', sizeof(*rhttp)); /* * Do we trust the request URL itself? */ for (b = b->next; b ; b = b->next) { if (url_match(b->url, csp->http)) { return b->reject; } } if (NULL == (referer = get_header_value(csp->headers, "Referer:"))) { /* no referrer was supplied */ return 1; } /* * If not, do we maybe trust its referrer? */ err = parse_http_url(referer, rhttp, csp); if (err) { return 1; } for (trusted_url = csp->config->trust_list; *trusted_url != NULL; trusted_url++) { if (url_match(*trusted_url, rhttp)) { /* if the URL's referrer is from a trusted referrer, then * add the target spec to the trustfile as an unblocked * domain and return NULL (which means it's OK). */ FILE *fp; if (NULL != (fp = fopen(csp->config->trustfile, "a"))) { char * path; char * path_end; char * new_entry = strdup("~"); string_append(&new_entry, csp->http->hostport); path = csp->http->path; if ( (path[0] == '/') && (path[1] == '~') && ((path_end = strchr(path + 2, '/')) != NULL)) { /* since this path points into a user's home space * be sure to include this spec in the trustfile. */ int path_len = path_end - path; /* save offset */ path = strdup(path); /* Copy string */ if (path != NULL) { path_end = path + path_len; /* regenerate ptr to new buffer */ *(path_end + 1) = '\0'; /* Truncate path after '/' */ } string_join(&new_entry, path); } if (new_entry != NULL) { fprintf(fp, "%s\n", new_entry); free(new_entry); } else { /* FIXME: No way to handle out-of memory, so mostly ignoring it */ log_error(LOG_LEVEL_ERROR, "Out of memory adding pattern to trust file"); } fclose(fp); } return 0; } } return 1; }