#include "apr.h"
#include "apr_strings.h"
#include "apr_lib.h"
+#include "apr_md5.h" /* for apr_password_validate */
#define APR_WANT_STDIO
#define APR_WANT_STRFUNC
#ifdef HAVE_GRP_H
#include <grp.h>
#endif
+#ifdef HAVE_SYS_LOADAVG_H
+#include <sys/loadavg.h>
+#endif
#include "ap_mpm.h"
while ((semi > intype) && apr_isspace(semi[-1])) {
semi--;
}
- return apr_pstrndup(p, intype, semi - intype);
+ return apr_pstrmemdup(p, intype, semi - intype);
}
}
AP_DECLARE(int) ap_is_matchexp(const char *str)
{
- register int x;
+ int x;
for (x = 0; str[x]; x++)
if ((str[x] == '*') || (str[x] == '?'))
while (name[l] != '\0') {
if (name[l] == '.' && name[l + 1] == '.' && IS_SLASH(name[l + 2])
&& (l == 0 || IS_SLASH(name[l - 1]))) {
- register int m = l + 3, n;
+ int m = l + 3, n;
l = l - 2;
if (l >= 0) {
AP_DECLARE(int) ap_count_dirs(const char *path)
{
- register int x, n;
+ int x, n;
for (x = 0, n = 0; path[x]; x++)
if (path[x] == '/')
return res;
}
- res = apr_pstrndup(atrans, *line, pos - *line);
+ res = apr_pstrmemdup(atrans, *line, pos - *line);
++pos;
static char *substring_conf(apr_pool_t *p, const char *start, int len,
char quote)
{
- char *result = apr_palloc(p, len + 2);
+ char *result = apr_palloc(p, len + 1);
char *resp = result;
int i;
char *res;
char quote;
- while (*str && apr_isspace(*str))
+ while (apr_isspace(*str))
++str;
if (!*str) {
res = substring_conf(p, str, strend - str, 0);
}
- while (*strend && apr_isspace(*strend))
+ while (apr_isspace(*strend))
++strend;
*line = strend;
return res;
AP_DECLARE(const char *) ap_pcfg_strerror(apr_pool_t *p, ap_configfile_t *cfp,
apr_status_t rc)
{
- char buf[MAX_STRING_LEN];
if (rc == APR_SUCCESS)
return NULL;
- return apr_psprintf(p, "Error reading %s at line %d: %s",
- cfp->name, cfp->line_number,
- rc == APR_ENOSPC ? "Line too long"
- : apr_strerror(rc, buf, sizeof(buf)));
+
+ if (rc == APR_ENOSPC)
+ return apr_psprintf(p, "Error reading %s at line %d: Line too long",
+ cfp->name, cfp->line_number);
+
+ return apr_psprintf(p, "Error reading %s at line %d: %pm",
+ cfp->name, cfp->line_number, &rc);
}
/* Read one line from open ap_configfile_t, strip LF, increase line number */
return token;
}
+typedef enum ap_etag_e {
+ AP_ETAG_NONE,
+ AP_ETAG_WEAK,
+ AP_ETAG_STRONG
+} ap_etag_e;
+
/* Find an item in canonical form (lowercase, no extra spaces) within
* an HTTP field value list. Returns 1 if found, 0 if not found.
* This would be much more efficient if we stored header fields as
* an array of list items as they are received instead of a plain string.
*/
-AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line,
- const char *tok)
+static int find_list_item(apr_pool_t *p, const char *line,
+ const char *tok, ap_etag_e type)
{
const unsigned char *pos;
const unsigned char *ptr = (const unsigned char *)line;
int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
- if (!line || !tok)
+ if (!line || !tok) {
+ return 0;
+ }
+ if (type == AP_ETAG_STRONG && *tok != '\"') {
return 0;
+ }
+ if (type == AP_ETAG_WEAK) {
+ if (*tok == 'W' && (*(tok+1)) == '/' && (*(tok+2)) == '\"') {
+ tok += 2;
+ }
+ else if (*tok != '\"') {
+ return 0;
+ }
+ }
do { /* loop for each item in line's list */
/* Find first non-comma, non-whitespace byte */
-
- while (*ptr == ',' || apr_isspace(*ptr))
+ while (*ptr == ',' || apr_isspace(*ptr)) {
++ptr;
+ }
+
+ /* Account for strong or weak Etags, depending on our search */
+ if (type == AP_ETAG_STRONG && *ptr != '\"') {
+ break;
+ }
+ if (type == AP_ETAG_WEAK) {
+ if (*ptr == 'W' && (*(ptr+1)) == '/' && (*(ptr+2)) == '\"') {
+ ptr += 2;
+ }
+ else if (*ptr != '\"') {
+ break;
+ }
+ }
if (*ptr)
good = 1; /* until proven otherwise for this item */
if (in_com || in_qstr)
good = good && (*pos++ == *ptr);
else
- good = good && (*pos++ == apr_tolower(*ptr));
+ good = good
+ && (apr_tolower(*pos++) == apr_tolower(*ptr));
addspace = 0;
break;
}
return good;
}
+/* Find an item in canonical form (lowercase, no extra spaces) within
+ * an HTTP field value list. Returns 1 if found, 0 if not found.
+ * This would be much more efficient if we stored header fields as
+ * an array of list items as they are received instead of a plain string.
+ */
+AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line,
+ const char *tok)
+{
+ return find_list_item(p, line, tok, AP_ETAG_NONE);
+}
+
+/* Find a strong Etag in canonical form (lowercase, no extra spaces) within
+ * an HTTP field value list. Returns 1 if found, 0 if not found.
+ */
+AP_DECLARE(int) ap_find_etag_strong(apr_pool_t *p, const char *line,
+ const char *tok)
+{
+ return find_list_item(p, line, tok, AP_ETAG_STRONG);
+}
+
+/* Find a weak ETag in canonical form (lowercase, no extra spaces) within
+ * an HTTP field value list. Returns 1 if found, 0 if not found.
+ */
+AP_DECLARE(int) ap_find_etag_weak(apr_pool_t *p, const char *line,
+ const char *tok)
+{
+ return find_list_item(p, line, tok, AP_ETAG_WEAK);
+}
+
+/* Grab a list of tokens of the format 1#token (from RFC7230) */
+AP_DECLARE(const char *) ap_parse_token_list_strict(apr_pool_t *p,
+ const char *str_in,
+ apr_array_header_t **tokens,
+ int skip_invalid)
+{
+ int in_leading_space = 1;
+ int in_trailing_space = 0;
+ int string_end = 0;
+ const char *tok_begin;
+ const char *cur;
+
+ if (!str_in) {
+ return NULL;
+ }
+
+ tok_begin = cur = str_in;
+
+ while (!string_end) {
+ const unsigned char c = (unsigned char)*cur;
+
+ if (!TEST_CHAR(c, T_HTTP_TOKEN_STOP) && c != '\0') {
+ /* Non-separator character; we are finished with leading
+ * whitespace. We must never have encountered any trailing
+ * whitespace before the delimiter (comma) */
+ in_leading_space = 0;
+ if (in_trailing_space) {
+ return "Encountered illegal whitespace in token";
+ }
+ }
+ else if (c == ' ' || c == '\t') {
+ /* "Linear whitespace" only includes ASCII CRLF, space, and tab;
+ * we can't get a CRLF since headers are split on them already,
+ * so only look for a space or a tab */
+ if (in_leading_space) {
+ /* We're still in leading whitespace */
+ ++tok_begin;
+ }
+ else {
+ /* We must be in trailing whitespace */
+ ++in_trailing_space;
+ }
+ }
+ else if (c == ',' || c == '\0') {
+ if (!in_leading_space) {
+ /* If we're out of the leading space, we know we've read some
+ * characters of a token */
+ if (*tokens == NULL) {
+ *tokens = apr_array_make(p, 4, sizeof(char *));
+ }
+ APR_ARRAY_PUSH(*tokens, char *) =
+ apr_pstrmemdup((*tokens)->pool, tok_begin,
+ (cur - tok_begin) - in_trailing_space);
+ }
+ /* We're allowed to have null elements, just don't add them to the
+ * array */
+
+ tok_begin = cur + 1;
+ in_leading_space = 1;
+ in_trailing_space = 0;
+ string_end = (c == '\0');
+ }
+ else {
+ /* Encountered illegal separator char */
+ if (skip_invalid) {
+ /* Skip to the next separator */
+ const char *temp;
+ temp = ap_strchr_c(cur, ',');
+ if(!temp) {
+ temp = ap_strchr_c(cur, '\0');
+ }
+
+ /* Act like we haven't seen a token so we reset */
+ cur = temp - 1;
+ in_leading_space = 1;
+ in_trailing_space = 0;
+ }
+ else {
+ return apr_psprintf(p, "Encountered illegal separator "
+ "'\\x%.2x'", (unsigned int)c);
+ }
+ }
+
+ ++cur;
+ }
+
+ return NULL;
+}
/* Retrieve a token, spacing over it and returning a pointer to
* the first non-white byte afterwards. Note that these tokens
const char *ptr = *accept_line;
const char *tok_start;
char *token;
- int tok_len;
/* Find first non-white byte */
- while (*ptr && apr_isspace(*ptr))
+ while (apr_isspace(*ptr))
++ptr;
tok_start = ptr;
break;
}
- tok_len = ptr - tok_start;
- token = apr_pstrndup(p, tok_start, tok_len);
+ token = apr_pstrmemdup(p, tok_start, ptr - tok_start);
/* Advance accept_line pointer to the next non-white byte */
- while (*ptr && apr_isspace(*ptr))
+ while (apr_isspace(*ptr))
++ptr;
*accept_line = ptr;
static char x2c(const char *what)
{
- register char digit;
+ char digit;
#if !APR_CHARSET_EBCDIC
digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10
static int unescape_url(char *url, const char *forbid, const char *reserved)
{
- register int badesc, badpath;
+ int badesc, badpath;
char *x, *y;
badesc = 0;
AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial)
{
- char *copy = apr_palloc(p, 3 * strlen(path) + 3);
+ /* Allocate +3 for potential "./" and trailing NULL.
+ * Allocate another +1 to allow the caller to add a trailing '/' (see
+ * comment in 'ap_sub_req_lookup_dirent')
+ */
+ char *copy = apr_palloc(p, 3 * strlen(path) + 3 + 1);
const unsigned char *s = (const unsigned char *)path;
unsigned char *d = (unsigned char *)copy;
unsigned c;
char *ret;
unsigned char *d;
const unsigned char *s;
+ apr_size_t length, escapes = 0;
if (!str) {
return NULL;
}
- ret = apr_palloc(p, 4 * strlen(str) + 1); /* Be safe */
+ /* Compute how many characters need to be escaped */
+ s = (const unsigned char *)str;
+ for (; *s; ++s) {
+ if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
+ escapes++;
+ }
+ }
+
+ /* Compute the length of the input string, including NULL */
+ length = s - (const unsigned char *)str + 1;
+
+ /* Fast path: nothing to escape */
+ if (escapes == 0) {
+ return apr_pmemdup(p, str, length);
+ }
+
+ /* Each escaped character needs up to 3 extra bytes (0 --> \x00) */
+ ret = apr_palloc(p, length + 3 * escapes);
d = (unsigned char *)ret;
s = (const unsigned char *)str;
for (; *s; ++s) {
-
if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
*d++ = '\\';
switch(*s) {
return (d - (unsigned char *)dest);
}
+AP_DECLARE(void) ap_bin2hex(const void *src, apr_size_t srclen, char *dest)
+{
+ const unsigned char *in = src;
+ apr_size_t i;
+
+ for (i = 0; i < srclen; i++) {
+ *dest++ = c2x_table[in[i] >> 4];
+ *dest++ = c2x_table[in[i] & 0xf];
+ }
+ *dest = '\0';
+}
+
+AP_DECLARE(int) ap_has_cntrl(const char *str)
+{
+ while (*str) {
+ if (apr_iscntrl(*str))
+ return 1;
+ str++;
+ }
+ return 0;
+}
+
AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path)
{
apr_finfo_t finfo;
*/
AP_DECLARE(int) ap_is_url(const char *u)
{
- register int x;
+ int x;
for (x = 0; u[x] != ':'; x++) {
if ((!u[x]) ||
- ((!apr_isalpha(u[x])) && (!apr_isdigit(u[x])) &&
+ ((!apr_isalnum(u[x])) &&
(u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
return 0;
}
APR_BLOCK_READ, HUGE_STRING_LEN);
if (rv != APR_SUCCESS) {
apr_brigade_destroy(bb);
- return (rv == AP_FILTER_ERROR) ? rv : HTTP_BAD_REQUEST;
+ return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
}
for (bucket = APR_BRIGADE_FIRST(bb);
ld->loadavg15 = -1.0;
#if HAVE_GETLOADAVG
- do {
+ {
double la[3];
int num;
if (num > 2) {
ld->loadavg15 = (float)la[2];
}
- } while(0);
+ }
#endif
}
+
+static const char * const pw_cache_note_name = "conn_cache_note";
+struct pw_cache {
+ /* varbuf contains concatenated password and hash */
+ struct ap_varbuf vb;
+ apr_size_t pwlen;
+ apr_status_t result;
+};
+
+AP_DECLARE(apr_status_t) ap_password_validate(request_rec *r,
+ const char *username,
+ const char *passwd,
+ const char *hash)
+{
+ struct pw_cache *cache;
+ apr_size_t hashlen;
+
+ cache = (struct pw_cache *)apr_table_get(r->connection->notes, pw_cache_note_name);
+ if (cache != NULL) {
+ if (strncmp(passwd, cache->vb.buf, cache->pwlen) == 0
+ && strcmp(hash, cache->vb.buf + cache->pwlen) == 0) {
+ return cache->result;
+ }
+ /* make ap_varbuf_grow below not copy the old data */
+ cache->vb.strlen = 0;
+ }
+ else {
+ cache = apr_palloc(r->connection->pool, sizeof(struct pw_cache));
+ ap_varbuf_init(r->connection->pool, &cache->vb, 0);
+ apr_table_setn(r->connection->notes, pw_cache_note_name, (void *)cache);
+ }
+ cache->pwlen = strlen(passwd);
+ hashlen = strlen(hash);
+ ap_varbuf_grow(&cache->vb, cache->pwlen + hashlen + 1);
+ memcpy(cache->vb.buf, passwd, cache->pwlen);
+ memcpy(cache->vb.buf + cache->pwlen, hash, hashlen + 1);
+ cache->result = apr_password_validate(passwd, hash);
+ return cache->result;
+}
+
+AP_DECLARE(char *) ap_get_exec_line(apr_pool_t *p,
+ const char *cmd,
+ const char * const * argv)
+{
+ char buf[MAX_STRING_LEN];
+ apr_procattr_t *procattr;
+ apr_proc_t *proc;
+ apr_file_t *fp;
+ apr_size_t nbytes = 1;
+ char c;
+ int k;
+
+ if (apr_procattr_create(&procattr, p) != APR_SUCCESS)
+ return NULL;
+ if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK,
+ APR_FULL_BLOCK) != APR_SUCCESS)
+ return NULL;
+ if (apr_procattr_dir_set(procattr,
+ ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS)
+ return NULL;
+ if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)
+ return NULL;
+ proc = apr_pcalloc(p, sizeof(apr_proc_t));
+ if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
+ return NULL;
+ fp = proc->out;
+
+ if (fp == NULL)
+ return NULL;
+ /* XXX: we are reading 1 byte at a time here */
+ for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
+ && nbytes == 1 && (k < MAX_STRING_LEN-1) ; ) {
+ if (c == '\n' || c == '\r')
+ break;
+ buf[k++] = c;
+ }
+ buf[k] = '\0';
+ apr_file_close(fp);
+
+ return apr_pstrndup(p, buf, k);
+}