|
Packit |
284210 |
/*
|
|
Packit |
284210 |
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
|
Packit |
284210 |
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* You may not use this file except in compliance with
|
|
Packit |
284210 |
* the License. You may obtain a copy of the License at
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* If any of the files related to licensing are missing or if you have any
|
|
Packit |
284210 |
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
|
Packit |
284210 |
* directly using the email address security@modsecurity.org.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
|
|
Packit |
284210 |
#include "modsecurity.h"
|
|
Packit |
284210 |
#include <ctype.h>
|
|
Packit |
284210 |
#include <fcntl.h>
|
|
Packit |
284210 |
#include <stdlib.h>
|
|
Packit |
284210 |
#include <sys/types.h>
|
|
Packit |
284210 |
#include <sys/stat.h>
|
|
Packit |
284210 |
|
|
Packit |
284210 |
#include "msc_release.h"
|
|
Packit |
284210 |
#include "msc_util.h"
|
|
Packit |
284210 |
|
|
Packit |
284210 |
#include <apr_lib.h>
|
|
Packit |
284210 |
#include <apr_sha1.h>
|
|
Packit |
284210 |
#include "modsecurity_config.h"
|
|
Packit |
284210 |
|
|
Packit |
284210 |
#include "msc_remote_rules.h"
|
|
Packit |
284210 |
|
|
Packit |
284210 |
#ifdef WITH_CURL
|
|
Packit |
284210 |
#include "curl/curl.h"
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* NOTE: Be careful as these can ONLY be used on static values for X.
|
|
Packit |
284210 |
* (i.e. VALID_HEX(c++) will NOT work)
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
#define VALID_HEX(X) (((X >= '0')&&(X <= '9')) || ((X >= 'a')&&(X <= 'f')) || ((X >= 'A')&&(X <= 'F')))
|
|
Packit |
284210 |
#define ISODIGIT(X) ((X >= '0')&&(X <= '7'))
|
|
Packit |
284210 |
|
|
Packit |
284210 |
#if (defined(WIN32) || defined(NETWARE))
|
|
Packit |
284210 |
/** Windows does not define all the octal modes */
|
|
Packit |
284210 |
#define S_IXOTH 00001
|
|
Packit |
284210 |
#define S_IWOTH 00002
|
|
Packit |
284210 |
#define S_IROTH 00004
|
|
Packit |
284210 |
#define S_IXGRP 00010
|
|
Packit |
284210 |
#define S_IWGRP 00020
|
|
Packit |
284210 |
#define S_IRGRP 00040
|
|
Packit |
284210 |
#define S_IXUSR 00100
|
|
Packit |
284210 |
#define S_IWUSR 00200
|
|
Packit |
284210 |
#define S_IRUSR 00400
|
|
Packit |
284210 |
#define S_ISVTX 01000
|
|
Packit |
284210 |
#define S_ISGID 02000
|
|
Packit |
284210 |
#define S_ISUID 04000
|
|
Packit |
284210 |
#endif /* defined(WIN32 || NETWARE) */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Base64 tables used in decodeBase64Ext */
|
|
Packit |
284210 |
static const char b64_pad = '=';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
static const short b64_reverse_t[256] = {
|
|
Packit |
284210 |
-2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -2, -2, -1, -2, -2,
|
|
Packit |
284210 |
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
|
Packit |
284210 |
-1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, -2, -2, 63,
|
|
Packit |
284210 |
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, -2, -2, -2,
|
|
Packit |
284210 |
-2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
|
Packit |
284210 |
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, -2,
|
|
Packit |
284210 |
-2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
|
Packit |
284210 |
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2,
|
|
Packit |
284210 |
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
|
Packit |
284210 |
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
|
Packit |
284210 |
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
|
Packit |
284210 |
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
|
Packit |
284210 |
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
|
Packit |
284210 |
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
|
Packit |
284210 |
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
|
Packit |
284210 |
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2
|
|
Packit |
284210 |
};
|
|
Packit |
284210 |
|
|
Packit |
284210 |
static unsigned char *c2x(unsigned what, unsigned char *where);
|
|
Packit |
284210 |
static unsigned char x2c(unsigned char *what);
|
|
Packit |
284210 |
static unsigned char xsingle2c(unsigned char *what);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
#ifdef LINUX_S390
|
|
Packit |
284210 |
int swap_int32(int x) {
|
|
Packit |
284210 |
int swap = ((x>>24)&0xff) | ((x<<8)&0xff0000) |
|
|
Packit |
284210 |
((x>>8)&0xff00) | ((x<<24)&0xff000000);
|
|
Packit |
284210 |
return swap;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/** \brief Decode utf-8 to unicode format.
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \param mp Pointer to memory pool
|
|
Packit |
284210 |
* \param input Pointer to input data
|
|
Packit |
284210 |
* \param input_len Input data length
|
|
Packit |
284210 |
* \param changed Set if data is changed
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \retval rval On Success
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
char *utf8_unicode_inplace_ex(apr_pool_t *mp, unsigned char *input, long int input_len, int *changed) {
|
|
Packit |
284210 |
int unicode_len = 0, length = 0;
|
|
Packit |
284210 |
unsigned int d = 0, count = 0;
|
|
Packit |
284210 |
unsigned char c, *utf;
|
|
Packit |
284210 |
char *rval, *data;
|
|
Packit |
284210 |
unsigned int i, len, j;
|
|
Packit |
284210 |
unsigned int bytes_left = input_len;
|
|
Packit |
284210 |
unsigned char *unicode = NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*changed = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
len = input_len * 7 + 1;
|
|
Packit |
284210 |
data = rval = apr_palloc(mp, len);
|
|
Packit |
284210 |
if (rval == NULL) return NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (input == NULL) return NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for(i = 0; i < bytes_left;) {
|
|
Packit |
284210 |
unicode_len = 0; d = 0;
|
|
Packit |
284210 |
utf = (unsigned char *)&input[i];
|
|
Packit |
284210 |
|
|
Packit |
284210 |
c = *utf;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* If first byte begins with binary 0 it is single byte encoding */
|
|
Packit |
284210 |
if ((c & 0x80) == 0) {
|
|
Packit |
284210 |
/* single byte unicode (7 bit ASCII equivilent) has no validation */
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
if(count <= len) {
|
|
Packit |
284210 |
if(c == 0)
|
|
Packit |
284210 |
*data = x2c(&c);
|
|
Packit |
284210 |
else
|
|
Packit |
284210 |
*data++ = c;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
/* If first byte begins with binary 110 it is two byte encoding*/
|
|
Packit |
284210 |
else if ((c & 0xE0) == 0xC0) {
|
|
Packit |
284210 |
/* check we have at least two bytes */
|
|
Packit |
284210 |
if (bytes_left < 2) unicode_len = UNICODE_ERROR_CHARACTERS_MISSING;
|
|
Packit |
284210 |
/* check second byte starts with binary 10 */
|
|
Packit |
284210 |
else if (((*(utf + 1)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
unicode_len = 2;
|
|
Packit |
284210 |
count+=6;
|
|
Packit |
284210 |
if(count <= len) {
|
|
Packit |
284210 |
/* compute character number */
|
|
Packit |
284210 |
d = ((c & 0x1F) << 6) | (*(utf + 1) & 0x3F);
|
|
Packit |
284210 |
*data++ = '%';
|
|
Packit |
284210 |
*data++ = 'u';
|
|
Packit |
284210 |
unicode = apr_psprintf(mp, "%x", d);
|
|
Packit |
284210 |
length = strlen(unicode);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
switch(length) {
|
|
Packit |
284210 |
case 1:
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 2:
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 3:
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 4:
|
|
Packit |
284210 |
case 5:
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for(j=0; j
|
|
Packit |
284210 |
*data++ = unicode[j];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*changed = 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
/* If first byte begins with binary 1110 it is three byte encoding */
|
|
Packit |
284210 |
else if ((c & 0xF0) == 0xE0) {
|
|
Packit |
284210 |
/* check we have at least three bytes */
|
|
Packit |
284210 |
if (bytes_left < 3) unicode_len = UNICODE_ERROR_CHARACTERS_MISSING;
|
|
Packit |
284210 |
/* check second byte starts with binary 10 */
|
|
Packit |
284210 |
else if (((*(utf + 1)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
|
|
Packit |
284210 |
/* check third byte starts with binary 10 */
|
|
Packit |
284210 |
else if (((*(utf + 2)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
unicode_len = 3;
|
|
Packit |
284210 |
count+=6;
|
|
Packit |
284210 |
if(count <= len) {
|
|
Packit |
284210 |
/* compute character number */
|
|
Packit |
284210 |
d = ((c & 0x0F) << 12) | ((*(utf + 1) & 0x3F) << 6) | (*(utf + 2) & 0x3F);
|
|
Packit |
284210 |
*data++ = '%';
|
|
Packit |
284210 |
*data++ = 'u';
|
|
Packit |
284210 |
unicode = apr_psprintf(mp, "%x", d);
|
|
Packit |
284210 |
length = strlen(unicode);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
switch(length) {
|
|
Packit |
284210 |
case 1:
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 2:
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 3:
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 4:
|
|
Packit |
284210 |
case 5:
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for(j=0; j
|
|
Packit |
284210 |
*data++ = unicode[j];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*changed = 1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
/* If first byte begins with binary 11110 it is four byte encoding */
|
|
Packit |
284210 |
else if ((c & 0xF8) == 0xF0) {
|
|
Packit |
284210 |
/* restrict characters to UTF-8 range (U+0000 - U+10FFFF)*/
|
|
Packit |
284210 |
if (c >= 0xF5) {
|
|
Packit |
284210 |
*data++ = c;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
/* check we have at least four bytes */
|
|
Packit |
284210 |
if (bytes_left < 4) unicode_len = UNICODE_ERROR_CHARACTERS_MISSING;
|
|
Packit |
284210 |
/* check second byte starts with binary 10 */
|
|
Packit |
284210 |
else if (((*(utf + 1)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
|
|
Packit |
284210 |
/* check third byte starts with binary 10 */
|
|
Packit |
284210 |
else if (((*(utf + 2)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
|
|
Packit |
284210 |
/* check forth byte starts with binary 10 */
|
|
Packit |
284210 |
else if (((*(utf + 3)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
unicode_len = 4;
|
|
Packit |
284210 |
count+=7;
|
|
Packit |
284210 |
if(count <= len) {
|
|
Packit |
284210 |
/* compute character number */
|
|
Packit |
284210 |
d = ((c & 0x07) << 18) | ((*(utf + 1) & 0x3F) << 12) | ((*(utf + 2) & 0x3F) << 6) | (*(utf + 3) & 0x3F);
|
|
Packit |
284210 |
*data++ = '%';
|
|
Packit |
284210 |
*data++ = 'u';
|
|
Packit |
284210 |
unicode = apr_psprintf(mp, "%x", d);
|
|
Packit |
284210 |
length = strlen(unicode);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
switch(length) {
|
|
Packit |
284210 |
case 1:
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 2:
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 3:
|
|
Packit |
284210 |
*data++ = '0';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 4:
|
|
Packit |
284210 |
case 5:
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for(j=0; j
|
|
Packit |
284210 |
*data++ = unicode[j];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*changed = 1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
/* any other first byte is invalid (RFC 3629) */
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
if(count <= len)
|
|
Packit |
284210 |
*data++ = c;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* invalid UTF-8 character number range (RFC 3629) */
|
|
Packit |
284210 |
if ((d >= 0xD800) && (d <= 0xDFFF)) {
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
if(count <= len)
|
|
Packit |
284210 |
*data++ = c;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* check for overlong */
|
|
Packit |
284210 |
if ((unicode_len == 4) && (d < 0x010000)) {
|
|
Packit |
284210 |
/* four byte could be represented with less bytes */
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
if(count <= len)
|
|
Packit |
284210 |
*data++ = c;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else if ((unicode_len == 3) && (d < 0x0800)) {
|
|
Packit |
284210 |
/* three byte could be represented with less bytes */
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
if(count <= len)
|
|
Packit |
284210 |
*data++ = c;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else if ((unicode_len == 2) && (d < 0x80)) {
|
|
Packit |
284210 |
/* two byte could be represented with less bytes */
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
if(count <= len)
|
|
Packit |
284210 |
*data++ = c;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if(unicode_len > 0) {
|
|
Packit |
284210 |
i += unicode_len;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
i++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*data ='\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return rval;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/** \brief Validate IPv4 Netmask
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \param ip_strv6 Pointer to ipv6 address
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \retval netmask_v4 On Success
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
unsigned char is_netmask_v4(char *ip_strv4) {
|
|
Packit |
284210 |
unsigned char netmask_v4 = 32;
|
|
Packit |
284210 |
char *mask_str = NULL;
|
|
Packit |
284210 |
int cidr;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if(ip_strv4 == NULL)
|
|
Packit |
284210 |
return netmask_v4;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if ((mask_str = strchr(ip_strv4, '/'))) {
|
|
Packit |
284210 |
*(mask_str++) = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (strchr(mask_str, '.') != NULL) {
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
cidr = atoi(mask_str);
|
|
Packit |
284210 |
if ((cidr < 0) || (cidr > 32)) {
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
netmask_v4 = (unsigned char)cidr;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return netmask_v4;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/** \brief Validate IPv6 Netmask
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \param ip_strv6 Pointer to ipv6 address
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \retval netmask_v6 On Success
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
unsigned char is_netmask_v6(char *ip_strv6) {
|
|
Packit |
284210 |
unsigned char netmask_v6 = 128;
|
|
Packit |
284210 |
char *mask_str = NULL;
|
|
Packit |
284210 |
int cidr;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if(ip_strv6 == NULL)
|
|
Packit |
284210 |
return netmask_v6;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if ((mask_str = strchr(ip_strv6, '/'))) {
|
|
Packit |
284210 |
*(mask_str++) = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (strchr(mask_str, ':') != NULL) {
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
cidr = atoi(mask_str);
|
|
Packit |
284210 |
if ((cidr < 0) || (cidr > 128)) {
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
netmask_v6 = (unsigned char)cidr;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return netmask_v6;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/** \brief Interpret |HEX| syntax
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \param op_parm Pointer to operator input
|
|
Packit |
284210 |
* \param op_len Operator input lenght
|
|
Packit |
284210 |
* \param rule Pointer to rule struct
|
|
Packit |
284210 |
* \param error_msg Pointer to error message
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \retval string On Success
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
char *parse_pm_content(const char *op_parm, unsigned short int op_len, msre_rule *rule, char **error_msg) {
|
|
Packit |
284210 |
char *parm = NULL;
|
|
Packit |
284210 |
char *content = NULL;
|
|
Packit |
284210 |
unsigned short int offset = 0;
|
|
Packit |
284210 |
char converted = 0;
|
|
Packit |
284210 |
int i, x;
|
|
Packit |
284210 |
unsigned char bin = 0, esc = 0, bin_offset = 0;
|
|
Packit |
284210 |
unsigned char bin_parm[3], c = 0;
|
|
Packit |
284210 |
char *processed = NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
content = apr_pstrdup(rule->ruleset->mp, op_parm);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (content == NULL) {
|
|
Packit |
284210 |
*error_msg = apr_psprintf(rule->ruleset->mp, "Error allocating memory for pattern matching content.");
|
|
Packit |
284210 |
return NULL;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
while (offset < op_len && apr_isspace(content[offset])) {
|
|
Packit |
284210 |
offset++;
|
|
Packit |
284210 |
};
|
|
Packit |
284210 |
|
|
Packit |
284210 |
op_len = strlen(content);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (content[offset] == '\"' && content[op_len-1] == '\"') {
|
|
Packit |
284210 |
parm = apr_pstrdup(rule->ruleset->mp, content + offset + 1);
|
|
Packit |
284210 |
if (parm == NULL) {
|
|
Packit |
284210 |
*error_msg = apr_psprintf(rule->ruleset->mp, "Error allocating memory for pattern matching content.");
|
|
Packit |
284210 |
return NULL;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
parm[op_len - offset - 2] = '\0';
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
parm = apr_pstrdup(rule->ruleset->mp, content + offset);
|
|
Packit |
284210 |
if (parm == NULL) {
|
|
Packit |
284210 |
*error_msg = apr_psprintf(rule->ruleset->mp, "Error allocating memory for pattern matching content.");
|
|
Packit |
284210 |
return NULL;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
op_len = strlen(parm);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (op_len == 0) {
|
|
Packit |
284210 |
*error_msg = apr_psprintf(rule->ruleset->mp, "Content length is 0.");
|
|
Packit |
284210 |
return NULL;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for (i = 0, x = 0; i < op_len; i++) {
|
|
Packit |
284210 |
if (parm[i] == '|') {
|
|
Packit |
284210 |
if (bin) {
|
|
Packit |
284210 |
bin = 0;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
bin = 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
} else if(!esc && parm[i] == '\\') {
|
|
Packit |
284210 |
esc = 1;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
if (bin) {
|
|
Packit |
284210 |
if (apr_isdigit(parm[i]) ||
|
|
Packit |
284210 |
parm[i] == 'A' || parm[i] == 'a' ||
|
|
Packit |
284210 |
parm[i] == 'B' || parm[i] == 'b' ||
|
|
Packit |
284210 |
parm[i] == 'C' || parm[i] == 'c' ||
|
|
Packit |
284210 |
parm[i] == 'D' || parm[i] == 'd' ||
|
|
Packit |
284210 |
parm[i] == 'E' || parm[i] == 'e' ||
|
|
Packit |
284210 |
parm[i] == 'F' || parm[i] == 'f')
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
bin_parm[bin_offset] = (char)parm[i];
|
|
Packit |
284210 |
bin_offset++;
|
|
Packit |
284210 |
if (bin_offset == 2) {
|
|
Packit |
284210 |
c = strtol((char *)bin_parm, (char **) NULL, 16) & 0xFF;
|
|
Packit |
284210 |
bin_offset = 0;
|
|
Packit |
284210 |
parm[x] = c;
|
|
Packit |
284210 |
x++;
|
|
Packit |
284210 |
converted = 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
} else if (parm[i] == ' ') {
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
} else if (esc) {
|
|
Packit |
284210 |
if (parm[i] == ':' ||
|
|
Packit |
284210 |
parm[i] == ';' ||
|
|
Packit |
284210 |
parm[i] == '\\' ||
|
|
Packit |
284210 |
parm[i] == '\"')
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
parm[x] = parm[i];
|
|
Packit |
284210 |
x++;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
*error_msg = apr_psprintf(rule->ruleset->mp, "Unsupported escape sequence.");
|
|
Packit |
284210 |
return NULL;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
esc = 0;
|
|
Packit |
284210 |
converted = 1;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
parm[x] = parm[i];
|
|
Packit |
284210 |
x++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (converted) {
|
|
Packit |
284210 |
op_len = x;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
processed = apr_pstrmemdup(rule->ruleset->mp, parm, op_len);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (processed == NULL) {
|
|
Packit |
284210 |
*error_msg = apr_psprintf(rule->ruleset->mp, "Error allocating memory for pattern matching content.");
|
|
Packit |
284210 |
return NULL;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return processed;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/** \brief Remove quotes
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \param mptmp Pointer to the pool
|
|
Packit |
284210 |
* \param input Pointer to input string
|
|
Packit |
284210 |
* \param input_len Input data length
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \retval string On Success
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
char *remove_quotes(apr_pool_t *mptmp, const char *input, int input_len) {
|
|
Packit |
284210 |
char *parm = apr_palloc(mptmp, input_len);
|
|
Packit |
284210 |
char *ret = parm;
|
|
Packit |
284210 |
int len = input_len;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for(; *input !='\0' && len >=0; input++, len--) {
|
|
Packit |
284210 |
if(*input != '\'' && *input != '\"') {
|
|
Packit |
284210 |
*parm++ = *input;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*parm = '\0';
|
|
Packit |
284210 |
return ret;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/** \brief Remove escape char
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \param mptmp Pointer to the pool
|
|
Packit |
284210 |
* \param input Pointer to input string
|
|
Packit |
284210 |
* \param input_len Input data length
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \retval string On Success
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
char *remove_escape(apr_pool_t *mptmp, const char *input, int input_len) {
|
|
Packit |
284210 |
char *parm = apr_palloc(mptmp, input_len);
|
|
Packit |
284210 |
char *ret = parm;
|
|
Packit |
284210 |
int len = input_len;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for(; *input !='\0' && len >=0; input++, len--) {
|
|
Packit |
284210 |
if(*input != '\\') {
|
|
Packit |
284210 |
*parm++ = *input;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*parm = '\0';
|
|
Packit |
284210 |
return ret;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int parse_boolean(const char *input) {
|
|
Packit |
284210 |
if (input == NULL) return -1;
|
|
Packit |
284210 |
if (strcasecmp(input, "on") == 0) return 1;
|
|
Packit |
284210 |
if (strcasecmp(input, "true") == 0) return 1;
|
|
Packit |
284210 |
if (strcasecmp(input, "1") == 0) return 1;
|
|
Packit |
284210 |
if (strcasecmp(input, "off") == 0) return 0;
|
|
Packit |
284210 |
if (strcasecmp(input, "false") == 0) return 0;
|
|
Packit |
284210 |
if (strcasecmp(input, "0") == 0) return 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/** \brief Decode Base64 data with special chars
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \param plain_text Pointer to plain text data
|
|
Packit |
284210 |
* \param input Pointer to input data
|
|
Packit |
284210 |
* \param input_len Input data length
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \retval 0 On failure
|
|
Packit |
284210 |
* \retval string length On Success
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int decode_base64_ext(char *plain_text, const unsigned char *input, int input_len) {
|
|
Packit |
284210 |
const unsigned char *encoded = input;
|
|
Packit |
284210 |
int i = 0, j = 0, k = 0;
|
|
Packit |
284210 |
int ch = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
while ((ch = *encoded++) != '\0' && input_len-- > 0) {
|
|
Packit |
284210 |
if (ch == b64_pad) {
|
|
Packit |
284210 |
if (*encoded != '=' && (i % 4) == 1) {
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
continue;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
ch = b64_reverse_t[ch];
|
|
Packit |
284210 |
if (ch < 0 || ch == -1) {
|
|
Packit |
284210 |
continue;
|
|
Packit |
284210 |
} else if (ch == -2) {
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
switch(i % 4) {
|
|
Packit |
284210 |
case 0:
|
|
Packit |
284210 |
plain_text[j] = ch << 2;
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 1:
|
|
Packit |
284210 |
plain_text[j++] |= ch >> 4;
|
|
Packit |
284210 |
plain_text[j] = (ch & 0x0f) << 4;
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 2:
|
|
Packit |
284210 |
plain_text[j++] |= ch >>2;
|
|
Packit |
284210 |
plain_text[j] = (ch & 0x03) << 6;
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 3:
|
|
Packit |
284210 |
plain_text[j++] |= ch;
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
i++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
k = j;
|
|
Packit |
284210 |
if (ch == b64_pad) {
|
|
Packit |
284210 |
switch(i % 4) {
|
|
Packit |
284210 |
case 1:
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
case 2:
|
|
Packit |
284210 |
k++;
|
|
Packit |
284210 |
case 3:
|
|
Packit |
284210 |
plain_text[k] = 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
plain_text[j] = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return j;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/** \brief Convert const char to int
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \param c number string
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \retval n The converted number
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int convert_to_int(const char c)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
int n;
|
|
Packit |
284210 |
if ((c>='0') && (c<='9'))
|
|
Packit |
284210 |
n = c - '0';
|
|
Packit |
284210 |
else if ((c>='A') && (c<='F'))
|
|
Packit |
284210 |
n = c - 'A' + 10;
|
|
Packit |
284210 |
else if ((c>='a') && (c<='f'))
|
|
Packit |
284210 |
n = c - 'a' + 10;
|
|
Packit |
284210 |
else
|
|
Packit |
284210 |
n = 0;
|
|
Packit |
284210 |
return n;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/** \brief Set a match to tx.N
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \param msr Pointer to modsec resource
|
|
Packit |
284210 |
* \param capture If ON match will be saved
|
|
Packit |
284210 |
* \param match Pointer to captured string
|
|
Packit |
284210 |
*\parm tx_n The tx number to save the data
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* \retval 0 On Sucess|Fail
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int set_match_to_tx(modsec_rec *msr, int capture, const char *match, int tx_n) {
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (capture) {
|
|
Packit |
284210 |
msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (s == NULL) return -1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
s->name = apr_psprintf(msr->mp,"%d", tx_n);
|
|
Packit |
284210 |
s->name_len = strlen(s->name);
|
|
Packit |
284210 |
s->value = apr_pstrdup(msr->mp, match);
|
|
Packit |
284210 |
if (s->value == NULL) return -1;
|
|
Packit |
284210 |
s->value_len = strlen(s->value);
|
|
Packit |
284210 |
apr_table_setn(msr->tx_vars, s->name, (void *)s);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit |
284210 |
msr_log(msr, 9, "Added phrase match to TX.%d: %s",
|
|
Packit |
284210 |
tx_n, log_escape_nq_ex(msr->mp, s->value, s->value_len));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* Parses a string that contains a name-value pair in the form "name=value".
|
|
Packit |
284210 |
* IMP1 It does not check for whitespace between tokens.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int parse_name_eq_value(apr_pool_t *mp, const char *input, char **name, char **value) {
|
|
Packit |
284210 |
char *p = NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if ((name == NULL)||(value == NULL)) return -1;
|
|
Packit |
284210 |
if (input == NULL) return 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*name = NULL;
|
|
Packit |
284210 |
*value = NULL;
|
|
Packit |
284210 |
p = (char *)input;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
while((*p != '=')&&(*p != '\0')) p++;
|
|
Packit |
284210 |
if (*p == '\0') {
|
|
Packit |
284210 |
*name = (char *)input;
|
|
Packit |
284210 |
return 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*name = apr_pstrmemdup(mp, input, p - input);
|
|
Packit |
284210 |
if (*name == NULL) return -1;
|
|
Packit |
284210 |
p++;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*value = apr_pstrdup(mp, p);
|
|
Packit |
284210 |
if (*value == NULL) return -1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* IMP1 Assumes NUL-terminated
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
char *url_encode(apr_pool_t *mp, char *input, unsigned int input_len, int *changed) {
|
|
Packit |
284210 |
char *rval, *d;
|
|
Packit |
284210 |
unsigned int i, len;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*changed = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
len = input_len * 3 + 1;
|
|
Packit |
284210 |
d = rval = apr_palloc(mp, len);
|
|
Packit |
284210 |
if (rval == NULL) return NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* ENH Only encode the characters that really need to be encoded. */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for(i = 0; i < input_len; i++) {
|
|
Packit |
284210 |
unsigned char c = input[i];
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (c == ' ') {
|
|
Packit |
284210 |
*d++ = '+';
|
|
Packit |
284210 |
*changed = 1;
|
|
Packit |
284210 |
} else
|
|
Packit |
284210 |
if ( (c == 42) || ((c >= 48)&&(c <= 57)) || ((c >= 65)&&(c <= 90))
|
|
Packit |
284210 |
|| ((c >= 97)&&(c <= 122))
|
|
Packit |
284210 |
) {
|
|
Packit |
284210 |
*d++ = c;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
*d++ = '%';
|
|
Packit |
284210 |
c2x(c, (unsigned char *)d);
|
|
Packit |
284210 |
d += 2;
|
|
Packit |
284210 |
*changed = 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*d = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return rval;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* Appends an URL-encoded version of the source string to the
|
|
Packit |
284210 |
* destination string, but makes sure that no more than "maxlen"
|
|
Packit |
284210 |
* bytes are added.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
char *strnurlencat(char *destination, char *source, unsigned int maxlen) {
|
|
Packit |
284210 |
char *s = source;
|
|
Packit |
284210 |
char *d = destination;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* ENH Only encode the characters that really need to be encoded. */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Advance to the end of destination string. */
|
|
Packit |
284210 |
while(*d != '\0') d++;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Loop while there's bytes in the source string or
|
|
Packit |
284210 |
* until we reach the output limit.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
while((*s != '\0')&&(maxlen > 0)) {
|
|
Packit |
284210 |
unsigned char c = *s;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (c == ' ') {
|
|
Packit |
284210 |
*d++ = '+';
|
|
Packit |
284210 |
maxlen--;
|
|
Packit |
284210 |
} else
|
|
Packit |
284210 |
if ( (c == 42) || ((c >= 48)&&(c <= 57)) || ((c >= 65)&&(c <= 90))
|
|
Packit |
284210 |
|| ((c >= 97)&&(c <= 122))
|
|
Packit |
284210 |
) {
|
|
Packit |
284210 |
*d++ = c;
|
|
Packit |
284210 |
maxlen--;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
if (maxlen >= 3) {
|
|
Packit |
284210 |
*d++ = '%';
|
|
Packit |
284210 |
c2x(c, (unsigned char *)d);
|
|
Packit |
284210 |
d += 2;
|
|
Packit |
284210 |
maxlen -= 3;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
/* If there's not enough room for the encoded
|
|
Packit |
284210 |
* byte we ignore it.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
maxlen = 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
s++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*d++ = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return destination;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
char *file_basename(apr_pool_t *mp, const char *filename) {
|
|
Packit |
284210 |
char *d, *p;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (filename == NULL) return NULL;
|
|
Packit |
284210 |
d = apr_pstrdup(mp, filename);
|
|
Packit |
284210 |
if (d == NULL) return NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
p = strrchr(d, '/');
|
|
Packit |
284210 |
if (p != NULL) d = p + 1;
|
|
Packit |
284210 |
p = strrchr(d, '\\');
|
|
Packit |
284210 |
if (p != NULL) d = p + 1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return d;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
char *m_strcasestr(const char *haystack, const char *needle) {
|
|
Packit |
284210 |
char aux, lower_aux;
|
|
Packit |
284210 |
int length;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if ((aux = *needle++) != 0) {
|
|
Packit |
284210 |
aux = (char)tolower((unsigned char)aux);
|
|
Packit |
284210 |
length = strlen(needle);
|
|
Packit |
284210 |
do {
|
|
Packit |
284210 |
do {
|
|
Packit |
284210 |
if ((lower_aux = *haystack++) == 0)
|
|
Packit |
284210 |
return NULL;
|
|
Packit |
284210 |
} while ((char)tolower((unsigned char)lower_aux) != aux);
|
|
Packit |
284210 |
} while (strncasecmp(haystack, needle, length) != 0);
|
|
Packit |
284210 |
haystack--;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
return ((char *)haystack);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
#ifdef WIN32
|
|
Packit |
284210 |
#if !(NTDDI_VERSION >= NTDDI_VISTA)
|
|
Packit |
284210 |
int inet_pton(int family, const char *src, void *dst) {
|
|
Packit |
284210 |
struct addrinfo addr;
|
|
Packit |
284210 |
struct sockaddr_in *in = NULL;
|
|
Packit |
284210 |
#if APR_HAVE_IPV6
|
|
Packit |
284210 |
struct sockaddr_in6 *in6 = NULL;
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
struct addrinfo *addr_info = NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
memset(&addr, 0, sizeof(struct addrinfo));
|
|
Packit |
284210 |
addr.ai_family = family;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (getaddrinfo(src, NULL, &addr, &addr_info) != 0)
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (addr_info) {
|
|
Packit |
284210 |
if (addr_info->ai_family == AF_INET) {
|
|
Packit |
284210 |
in = (struct sockaddr_in*)addr_info->ai_addr;
|
|
Packit |
284210 |
if(in != NULL)
|
|
Packit |
284210 |
memcpy(dst, &in->sin_addr, 4);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#if APR_HAVE_IPV6
|
|
Packit |
284210 |
else if (addr_info->ai_family == AF_INET6) {
|
|
Packit |
284210 |
in6 = (struct sockaddr_in6*)addr_info->ai_addr;
|
|
Packit |
284210 |
if(in6 != NULL)
|
|
Packit |
284210 |
memcpy(dst, &in6->sin6_addr, 16);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
freeaddrinfo(addr_info);
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
freeaddrinfo(addr_info);
|
|
Packit |
284210 |
return 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
#ifdef WIN32
|
|
Packit |
284210 |
char *file_dirname(apr_pool_t *p, const char *filename) {
|
|
Packit |
284210 |
char *b, *c, *d;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (filename == NULL) return NULL;
|
|
Packit |
284210 |
b = apr_pstrdup(p, filename);
|
|
Packit |
284210 |
if (b == NULL) return NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
c = strrchr(b, '/');
|
|
Packit |
284210 |
if (c != NULL) {
|
|
Packit |
284210 |
d = strrchr(c, '\\');
|
|
Packit |
284210 |
if (d != NULL) *d = '\0';
|
|
Packit |
284210 |
else *c = '\0';
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
d = strrchr(b, '\\');
|
|
Packit |
284210 |
if (d != NULL) *d = '\0';
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return b;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#else
|
|
Packit |
284210 |
char *file_dirname(apr_pool_t *p, const char *filename) {
|
|
Packit |
284210 |
char *b, *c;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (filename == NULL) return NULL;
|
|
Packit |
284210 |
b = apr_pstrdup(p, filename);
|
|
Packit |
284210 |
if (b == NULL) return NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
c = strrchr(b, '/');
|
|
Packit |
284210 |
if (c != NULL) *c = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return b;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int sql_hex2bytes_inplace(unsigned char *data, int len) {
|
|
Packit |
284210 |
unsigned char *d, *begin = data;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if ((data == NULL)||(len == 0)) return 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for( d = data; *data; *d++ = *data++) {
|
|
Packit |
284210 |
if ( *data != '0' ) continue;
|
|
Packit |
284210 |
if ( tolower(*++data) != 'x' ) {
|
|
Packit |
284210 |
data--;
|
|
Packit |
284210 |
continue;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
data++;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
// Do we need to keep "0x" if no hexa after?
|
|
Packit |
284210 |
if ( !VALID_HEX(data[0]) || !VALID_HEX(data[1]) ) {
|
|
Packit |
284210 |
data-=2;
|
|
Packit |
284210 |
continue;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
while ( VALID_HEX(data[0]) && VALID_HEX(data[1]) ) {
|
|
Packit |
284210 |
*d++ = x2c(data);
|
|
Packit |
284210 |
data += 2;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*d = '\0';
|
|
Packit |
284210 |
return strlen((char *)begin);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int hex2bytes_inplace(unsigned char *data, int len) {
|
|
Packit |
284210 |
unsigned char *d = data;
|
|
Packit |
284210 |
int i, count = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if ((data == NULL)||(len == 0)) return 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for(i = 0; i <= len - 2; i += 2) {
|
|
Packit |
284210 |
*d++ = x2c(&data[i]);
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
*d = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return count;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* Converts a series of bytes into its hexadecimal
|
|
Packit |
284210 |
* representation.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
char *bytes2hex(apr_pool_t *pool, unsigned char *data, int len) {
|
|
Packit |
284210 |
static const unsigned char b2hex[] = "0123456789abcdef";
|
|
Packit |
284210 |
char *hex = NULL;
|
|
Packit |
284210 |
int i, j;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
hex = apr_palloc(pool, (len * 2) + 1);
|
|
Packit |
284210 |
if (hex == NULL) return NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
j = 0;
|
|
Packit |
284210 |
for(i = 0; i < len; i++) {
|
|
Packit |
284210 |
hex[j++] = b2hex[data[i] >> 4];
|
|
Packit |
284210 |
hex[j++] = b2hex[data[i] & 0x0f];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
hex[j] = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return hex;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int is_token_char(unsigned char c) {
|
|
Packit |
284210 |
/* ENH Is the performance important at all? We could use a table instead. */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* CTLs not allowed */
|
|
Packit |
284210 |
if ((c <= 32)||(c >= 127)) return 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
switch(c) {
|
|
Packit |
284210 |
case '(' :
|
|
Packit |
284210 |
case ')' :
|
|
Packit |
284210 |
case '<' :
|
|
Packit |
284210 |
case '>' :
|
|
Packit |
284210 |
case '@' :
|
|
Packit |
284210 |
case ',' :
|
|
Packit |
284210 |
case ';' :
|
|
Packit |
284210 |
case ':' :
|
|
Packit |
284210 |
case '\\' :
|
|
Packit |
284210 |
case '"' :
|
|
Packit |
284210 |
case '/' :
|
|
Packit |
284210 |
case '[' :
|
|
Packit |
284210 |
case ']' :
|
|
Packit |
284210 |
case '?' :
|
|
Packit |
284210 |
case '=' :
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int remove_lf_crlf_inplace(char *text) {
|
|
Packit |
284210 |
char *p = text;
|
|
Packit |
284210 |
int count = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (text == NULL) return -1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
while(*p != '\0') {
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
p++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (count > 0) {
|
|
Packit |
284210 |
if (*(p - 1) == '\n') {
|
|
Packit |
284210 |
*(p - 1) = '\0';
|
|
Packit |
284210 |
if (count > 1) {
|
|
Packit |
284210 |
if (*(p - 2) == '\r') {
|
|
Packit |
284210 |
*(p - 2) = '\0';
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* Converts a byte given as its hexadecimal representation
|
|
Packit |
284210 |
* into a proper byte. Handles uppercase and lowercase letters
|
|
Packit |
284210 |
* but does not check for overflows.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
static unsigned char x2c(unsigned char *what) {
|
|
Packit |
284210 |
register unsigned char digit;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
|
|
Packit |
284210 |
digit *= 16;
|
|
Packit |
284210 |
digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return digit;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* Converts a single hexadecimal digit into a decimal value.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
static unsigned char xsingle2c(unsigned char *what) {
|
|
Packit |
284210 |
register unsigned char digit;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return digit;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
char *guess_tmp_dir(apr_pool_t *p) {
|
|
Packit |
284210 |
char *filename = NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* ENH Use apr_temp_dir_get instead. */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
#ifdef WIN32
|
|
Packit |
284210 |
filename = apr_pcalloc(p, 256);
|
|
Packit |
284210 |
if (filename == NULL) return "";
|
|
Packit |
284210 |
if (GetTempPath(255, filename) != 0) return filename;
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
|
|
Packit |
284210 |
filename = getenv("TMPDIR");
|
|
Packit |
284210 |
if (filename != NULL) return filename;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
filename = getenv("TEMP");
|
|
Packit |
284210 |
if (filename != NULL) return filename;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
filename = getenv("TMP");
|
|
Packit |
284210 |
if (filename != NULL) return filename;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
#if defined NETWARE
|
|
Packit |
284210 |
return("sys:/tmp/");
|
|
Packit |
284210 |
#elif defined WIN32
|
|
Packit |
284210 |
return("");
|
|
Packit |
284210 |
#else
|
|
Packit |
284210 |
return("/tmp/");
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
char *current_logtime(apr_pool_t *mp) {
|
|
Packit |
284210 |
apr_time_exp_t t;
|
|
Packit |
284210 |
char tstr[100];
|
|
Packit |
284210 |
apr_size_t len;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
apr_time_exp_lt(&t, apr_time_now());
|
|
Packit |
284210 |
|
|
Packit |
284210 |
apr_strftime(tstr, &len, 80, "%d/%b/%Y:%H:%M:%S ", &t);
|
|
Packit |
284210 |
apr_snprintf(tstr + strlen(tstr), 80 - strlen(tstr), "%c%.2d%.2d",
|
|
Packit |
284210 |
t.tm_gmtoff < 0 ? '-' : '+',
|
|
Packit |
284210 |
t.tm_gmtoff / (60 * 60), (t.tm_gmtoff / 60) % 60);
|
|
Packit |
284210 |
return apr_pstrdup(mp, tstr);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
char *current_filetime(apr_pool_t *mp) {
|
|
Packit |
284210 |
apr_time_exp_t t;
|
|
Packit |
284210 |
char tstr[100];
|
|
Packit |
284210 |
apr_size_t len;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
apr_time_exp_lt(&t, apr_time_now());
|
|
Packit |
284210 |
|
|
Packit |
284210 |
apr_strftime(tstr, &len, 80, "%Y%m%d-%H%M%S", &t);
|
|
Packit |
284210 |
return apr_pstrdup(mp, tstr);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int msc_mkstemp_ex(char *templat, int mode) {
|
|
Packit |
284210 |
int fd = -1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* ENH Use apr_file_mktemp instead. */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
#if !(defined(WIN32)||defined(NETWARE))
|
|
Packit |
284210 |
fd = mkstemp(templat);
|
|
Packit |
284210 |
#ifdef HAVE_FCHMOD
|
|
Packit |
284210 |
if ((fd != -1) && (mode != 0)) {
|
|
Packit |
284210 |
if (fchmod(fd, mode) == -1) {
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#endif /* HAVE_FCHMOD */
|
|
Packit |
284210 |
#else
|
|
Packit |
284210 |
if (mktemp(templat) == NULL) return -1;
|
|
Packit |
284210 |
fd = open(templat, O_WRONLY | O_APPEND | O_CREAT | O_BINARY, mode);
|
|
Packit |
284210 |
#endif /* !(defined(WIN32)||defined(NETWARE)) */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return fd;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int msc_mkstemp(char *templat) {
|
|
Packit |
284210 |
return msc_mkstemp_ex(templat, CREATEMODE_UNISTD);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* Converts the input string to lowercase (in-place).
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
char *strtolower_inplace(unsigned char *str) {
|
|
Packit |
284210 |
unsigned char *c = str;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (str == NULL) return NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
while(*c != 0) {
|
|
Packit |
284210 |
*c = tolower(*c);
|
|
Packit |
284210 |
c++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return (char *)str;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* Converts a single byte into its hexadecimal representation.
|
|
Packit |
284210 |
* Will overwrite two bytes at the destination.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
static unsigned char *c2x(unsigned what, unsigned char *where) {
|
|
Packit |
284210 |
static const char c2x_table[] = "0123456789abcdef";
|
|
Packit |
284210 |
|
|
Packit |
284210 |
what = what & 0xff;
|
|
Packit |
284210 |
*where++ = c2x_table[what >> 4];
|
|
Packit |
284210 |
*where++ = c2x_table[what & 0x0f];
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return where;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
static char *_log_escape(apr_pool_t *p, const unsigned char *input,
|
|
Packit |
284210 |
unsigned long int input_length, int escape_quotes, int escape_colon, int escape_re);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
char *log_escape_re(apr_pool_t *mp, const char *text) {
|
|
Packit |
284210 |
return _log_escape(mp, (const unsigned char *)text, text ? strlen(text) : 0, 1, 1, 1);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
char *log_escape(apr_pool_t *mp, const char *text) {
|
|
Packit |
284210 |
return _log_escape(mp, (const unsigned char *)text, text ? strlen(text) : 0, 1, 0, 0);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
char *log_escape_nq(apr_pool_t *mp, const char *text) {
|
|
Packit |
284210 |
#ifdef VERSION_IIS
|
|
Packit |
284210 |
int l = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
// this is a workaround for unknown bug that causes 'text' sometimes to lack zero-termination
|
|
Packit |
284210 |
//
|
|
Packit |
284210 |
__try
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
l = text ? strlen(text) : 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
l = -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
if(l < 0)
|
|
Packit |
284210 |
return _log_escape(mp, "BUG: see log_escape_nq()", 24, 0, 0, 0);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return _log_escape(mp, (const unsigned char *)text, l, 0, 0, 0);
|
|
Packit |
284210 |
#else
|
|
Packit |
284210 |
return _log_escape(mp, (const unsigned char *)text, text ? strlen(text) : 0, 0, 0, 0);
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
char *log_escape_ex(apr_pool_t *mp, const char *text, unsigned long int text_length) {
|
|
Packit |
284210 |
return _log_escape(mp, (const unsigned char *)text, text_length, 1, 0, 0);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
char *log_escape_nq_ex(apr_pool_t *mp, const char *text, unsigned long int text_length) {
|
|
Packit |
284210 |
return _log_escape(mp, (const unsigned char *)text, text_length, 0, 0, 0);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
char *log_escape_raw(apr_pool_t *mp, const unsigned char *text, unsigned long int text_length) {
|
|
Packit |
284210 |
unsigned char *ret = apr_palloc(mp, text_length * 4 + 1);
|
|
Packit |
284210 |
unsigned long int i, j;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for (i = 0, j = 0; i < text_length; i++, j += 4) {
|
|
Packit |
284210 |
ret[j] = '\\';
|
|
Packit |
284210 |
ret[j+1] = 'x';
|
|
Packit |
284210 |
c2x(text[i], ret+j+2);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
ret[text_length * 4] = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return (char *)ret;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
char *log_escape_nul(apr_pool_t *mp, const unsigned char *text, unsigned long int text_length) {
|
|
Packit |
284210 |
unsigned char *ret = apr_palloc(mp, text_length * 4 + 1);
|
|
Packit |
284210 |
unsigned long int i, j;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for (i = 0, j = 0; i < text_length; i++) {
|
|
Packit |
284210 |
if (text[i] == '\0') {
|
|
Packit |
284210 |
ret[j] = '\\';
|
|
Packit |
284210 |
ret[j+1] = 'x';
|
|
Packit |
284210 |
c2x(text[i], ret+j+2);
|
|
Packit |
284210 |
j += 4;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
ret[j] = text[i];
|
|
Packit |
284210 |
j++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
ret[j] = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return (char *)ret;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* Transform text to ASCII printable or hex escaped
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
char *log_escape_hex(apr_pool_t *mp, const unsigned char *text, unsigned long int text_length) {
|
|
Packit |
284210 |
unsigned char *ret = apr_palloc(mp, text_length * 4 + 1);
|
|
Packit |
284210 |
unsigned long int i, j;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for (i = 0, j = 0; i < text_length; i++) {
|
|
Packit |
284210 |
if ( (text[i] == '"')
|
|
Packit |
284210 |
||(text[i] == '\\')
|
|
Packit |
284210 |
||(text[i] <= 0x1f)
|
|
Packit |
284210 |
||(text[i] >= 0x7f))
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
ret[j] = '\\';
|
|
Packit |
284210 |
ret[j+1] = 'x';
|
|
Packit |
284210 |
c2x(text[i], ret+j+2);
|
|
Packit |
284210 |
j += 4;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
ret[j] = text[i];
|
|
Packit |
284210 |
j ++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
ret[j] = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return (char *)ret;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* Transform input into a form safe for logging.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
static char *_log_escape(apr_pool_t *mp, const unsigned char *input, unsigned long int input_len,
|
|
Packit |
284210 |
int escape_quotes, int escape_colon, int escape_re)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
unsigned char *d = NULL;
|
|
Packit |
284210 |
char *ret = NULL;
|
|
Packit |
284210 |
unsigned long int i;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (input == NULL) return NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
ret = apr_palloc(mp, input_len * 4 + 1);
|
|
Packit |
284210 |
if (ret == NULL) return NULL;
|
|
Packit |
284210 |
d = (unsigned char *)ret;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
i = 0;
|
|
Packit |
284210 |
while(i < input_len) {
|
|
Packit |
284210 |
switch(input[i]) {
|
|
Packit |
284210 |
case ':' :
|
|
Packit |
284210 |
if (escape_colon) {
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = ':';
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
*d++ = input[i];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '"' :
|
|
Packit |
284210 |
if (escape_quotes) {
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = '"';
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
*d++ = input[i];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '+' :
|
|
Packit |
284210 |
if (escape_re) {
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = '+';
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
*d++ = input[i];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '.' :
|
|
Packit |
284210 |
if (escape_re) {
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = '.';
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
*d++ = input[i];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case ']' :
|
|
Packit |
284210 |
if (escape_re) {
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = ']';
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
*d++ = input[i];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '[' :
|
|
Packit |
284210 |
if (escape_re) {
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = '[';
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
*d++ = input[i];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '(' :
|
|
Packit |
284210 |
if (escape_re) {
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = '(';
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
*d++ = input[i];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case ')' :
|
|
Packit |
284210 |
if (escape_re) {
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = ')';
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
*d++ = input[i];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '?' :
|
|
Packit |
284210 |
if (escape_re) {
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = '?';
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
*d++ = input[i];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '/' :
|
|
Packit |
284210 |
if (escape_re) {
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = '/';
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
*d++ = input[i];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '\b' :
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = 'b';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '\n' :
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = 'n';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '\r' :
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = 'r';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '\t' :
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = 't';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '\v' :
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = 'v';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '\\' :
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
default :
|
|
Packit |
284210 |
if ((input[i] <= 0x1f)||(input[i] >= 0x7f)) {
|
|
Packit |
284210 |
*d++ = '\\';
|
|
Packit |
284210 |
*d++ = 'x';
|
|
Packit |
284210 |
c2x(input[i], d);
|
|
Packit |
284210 |
d += 2;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
*d++ = input[i];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
i++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*d = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return ret;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* JavaScript decoding.
|
|
Packit |
284210 |
* IMP1 Assumes NUL-terminated
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
|
|
Packit |
284210 |
int js_decode_nonstrict_inplace(unsigned char *input, long int input_len) {
|
|
Packit |
284210 |
unsigned char *d = (unsigned char *)input;
|
|
Packit |
284210 |
long int i, count;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (input == NULL) return -1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
i = count = 0;
|
|
Packit |
284210 |
while (i < input_len) {
|
|
Packit |
284210 |
if (input[i] == '\\') {
|
|
Packit |
284210 |
/* Character is an escape. */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if ( (i + 5 < input_len) && (input[i + 1] == 'u')
|
|
Packit |
284210 |
&& (VALID_HEX(input[i + 2])) && (VALID_HEX(input[i + 3]))
|
|
Packit |
284210 |
&& (VALID_HEX(input[i + 4])) && (VALID_HEX(input[i + 5])) )
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
/* \uHHHH */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Use only the lower byte. */
|
|
Packit |
284210 |
*d = x2c(&input[i + 4]);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Full width ASCII (ff01 - ff5e) needs 0x20 added */
|
|
Packit |
284210 |
if ( (*d > 0x00) && (*d < 0x5f)
|
|
Packit |
284210 |
&& ((input[i + 2] == 'f') || (input[i + 2] == 'F'))
|
|
Packit |
284210 |
&& ((input[i + 3] == 'f') || (input[i + 3] == 'F')))
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
(*d) += 0x20;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
d++;
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
i += 6;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else if ( (i + 3 < input_len) && (input[i + 1] == 'x')
|
|
Packit |
284210 |
&& VALID_HEX(input[i + 2]) && VALID_HEX(input[i + 3])) {
|
|
Packit |
284210 |
/* \xHH */
|
|
Packit |
284210 |
*d++ = x2c(&input[i + 2]);
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
i += 4;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else if ((i + 1 < input_len) && ISODIGIT(input[i + 1])) {
|
|
Packit |
284210 |
/* \OOO (only one byte, \000 - \377) */
|
|
Packit |
284210 |
char buf[4];
|
|
Packit |
284210 |
int j = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
while((i + 1 + j < input_len)&&(j < 3)) {
|
|
Packit |
284210 |
buf[j] = input[i + 1 + j];
|
|
Packit |
284210 |
j++;
|
|
Packit |
284210 |
if (!ISODIGIT(input[i + 1 + j])) break;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
buf[j] = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (j > 0) {
|
|
Packit |
284210 |
/* Do not use 3 characters if we will be > 1 byte */
|
|
Packit |
284210 |
if ((j == 3) && (buf[0] > '3')) {
|
|
Packit |
284210 |
j = 2;
|
|
Packit |
284210 |
buf[j] = '\0';
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
*d++ = (unsigned char)strtol(buf, NULL, 8);
|
|
Packit |
284210 |
i += 1 + j;
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else if (i + 1 < input_len) {
|
|
Packit |
284210 |
/* \C */
|
|
Packit |
284210 |
unsigned char c = input[i + 1];
|
|
Packit |
284210 |
switch(input[i + 1]) {
|
|
Packit |
284210 |
case 'a' :
|
|
Packit |
284210 |
c = '\a';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 'b' :
|
|
Packit |
284210 |
c = '\b';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 'f' :
|
|
Packit |
284210 |
c = '\f';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 'n' :
|
|
Packit |
284210 |
c = '\n';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 'r' :
|
|
Packit |
284210 |
c = '\r';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 't' :
|
|
Packit |
284210 |
c = '\t';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 'v' :
|
|
Packit |
284210 |
c = '\v';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
/* The remaining (\?,\\,\',\") are just a removal
|
|
Packit |
284210 |
* of the escape char which is default.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*d++ = c;
|
|
Packit |
284210 |
i += 2;
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
/* Not enough bytes */
|
|
Packit |
284210 |
while(i < input_len) {
|
|
Packit |
284210 |
*d++ = input[i++];
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
*d++ = input[i++];
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*d = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return count;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* IMP1 Assumes NUL-terminated
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_len, int *changed) {
|
|
Packit |
284210 |
unsigned char *d = input;
|
|
Packit |
284210 |
long int i, count, fact, j, xv;
|
|
Packit |
284210 |
int Code, hmap = -1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*changed = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (input == NULL) return -1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
i = count = 0;
|
|
Packit |
284210 |
while (i < input_len) {
|
|
Packit |
284210 |
if (input[i] == '%') {
|
|
Packit |
284210 |
/* Character is a percent sign. */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if ((i + 1 < input_len)&&( (input[i + 1] == 'u')||(input[i + 1] == 'U') )) {
|
|
Packit |
284210 |
/* IIS-specific %u encoding. */
|
|
Packit |
284210 |
if (i + 5 < input_len) {
|
|
Packit |
284210 |
/* We have at least 4 data bytes. */
|
|
Packit |
284210 |
if ( (VALID_HEX(input[i + 2]))&&(VALID_HEX(input[i + 3]))
|
|
Packit |
284210 |
&&(VALID_HEX(input[i + 4]))&&(VALID_HEX(input[i + 5])) )
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
|
|
Packit |
284210 |
Code = 0;
|
|
Packit |
284210 |
fact = 1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (unicode_map_table != NULL && unicode_codepage > 0) {
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for(j=5; j>=2; j--) {
|
|
Packit |
284210 |
if (isxdigit((input[i+j]))) {
|
|
Packit |
284210 |
if ((input[i+j])>=97) {
|
|
Packit |
284210 |
xv = ( (input[i+j]) - 97) + 10;
|
|
Packit |
284210 |
} else if ( (input[i+j]) >= 65) {
|
|
Packit |
284210 |
xv = ((input[i+j]) - 65) + 10;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
xv = (input[i+j]) - 48;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
Code += (xv * fact);
|
|
Packit |
284210 |
fact *= 16;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if(Code >= 0 && Code <= 65535) {
|
|
Packit |
284210 |
hmap = unicode_map_table[Code];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if(hmap != -1) {
|
|
Packit |
284210 |
*d = hmap;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
/* We first make use of the lower byte here, ignoring the higher byte. */
|
|
Packit |
284210 |
*d = x2c(&input[i + 4]);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Full width ASCII (ff01 - ff5e) needs 0x20 added */
|
|
Packit |
284210 |
if ( (*d > 0x00) && (*d < 0x5f)
|
|
Packit |
284210 |
&& ((input[i + 2] == 'f') || (input[i + 2] == 'F'))
|
|
Packit |
284210 |
&& ((input[i + 3] == 'f') || (input[i + 3] == 'F')))
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
(*d) += 0x20;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
d++;
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
i += 6;
|
|
Packit |
284210 |
*changed = 1;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
/* Invalid data, skip %u. */
|
|
Packit |
284210 |
*d++ = input[i++];
|
|
Packit |
284210 |
*d++ = input[i++];
|
|
Packit |
284210 |
count += 2;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
/* Not enough bytes (4 data bytes), skip %u. */
|
|
Packit |
284210 |
*d++ = input[i++];
|
|
Packit |
284210 |
*d++ = input[i++];
|
|
Packit |
284210 |
count += 2;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
/* Standard URL encoding. */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Are there enough bytes available? */
|
|
Packit |
284210 |
if (i + 2 < input_len) {
|
|
Packit |
284210 |
/* Yes. */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Decode a %xx combo only if it is valid.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
char c1 = input[i + 1];
|
|
Packit |
284210 |
char c2 = input[i + 2];
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (VALID_HEX(c1) && VALID_HEX(c2)) {
|
|
Packit |
284210 |
*d++ = x2c(&input[i + 1]);
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
i += 3;
|
|
Packit |
284210 |
*changed = 1;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
/* Not a valid encoding, skip this % */
|
|
Packit |
284210 |
*d++ = input[i++];
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
/* Not enough bytes available, skip this % */
|
|
Packit |
284210 |
*d++ = input[i++];
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
/* Character is not a percent sign. */
|
|
Packit |
284210 |
if (input[i] == '+') {
|
|
Packit |
284210 |
*d++ = ' ';
|
|
Packit |
284210 |
*changed = 1;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
*d++ = input[i];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
i++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*d = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return count;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* IMP1 Assumes NUL-terminated
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int urldecode_nonstrict_inplace_ex(unsigned char *input, long int input_len, int *invalid_count, int *changed) {
|
|
Packit |
284210 |
unsigned char *d = (unsigned char *)input;
|
|
Packit |
284210 |
long int i, count;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*changed = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (input == NULL) return -1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
i = count = 0;
|
|
Packit |
284210 |
while (i < input_len) {
|
|
Packit |
284210 |
if (input[i] == '%') {
|
|
Packit |
284210 |
/* Character is a percent sign. */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Are there enough bytes available? */
|
|
Packit |
284210 |
if (i + 2 < input_len) {
|
|
Packit |
284210 |
char c1 = input[i + 1];
|
|
Packit |
284210 |
char c2 = input[i + 2];
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (VALID_HEX(c1) && VALID_HEX(c2)) {
|
|
Packit |
284210 |
/* Valid encoding - decode it. */
|
|
Packit |
284210 |
*d++ = x2c(&input[i + 1]);
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
i += 3;
|
|
Packit |
284210 |
*changed = 1;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
/* Not a valid encoding, skip this % */
|
|
Packit |
284210 |
*d++ = input[i++];
|
|
Packit |
284210 |
count ++;
|
|
Packit |
284210 |
(*invalid_count)++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
/* Not enough bytes available, copy the raw bytes. */
|
|
Packit |
284210 |
*d++ = input[i++];
|
|
Packit |
284210 |
count ++;
|
|
Packit |
284210 |
(*invalid_count)++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
/* Character is not a percent sign. */
|
|
Packit |
284210 |
if (input[i] == '+') {
|
|
Packit |
284210 |
*d++ = ' ';
|
|
Packit |
284210 |
*changed = 1;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
*d++ = input[i];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
i++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*d = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return count;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* IMP1 Assumes NUL-terminated
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int html_entities_decode_inplace(apr_pool_t *mp, unsigned char *input, int input_len) {
|
|
Packit |
284210 |
unsigned char *d = input;
|
|
Packit |
284210 |
int i, count;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if ((input == NULL)||(input_len <= 0)) return 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
i = count = 0;
|
|
Packit |
284210 |
while((i < input_len)&&(count < input_len)) {
|
|
Packit |
284210 |
int z, copy = 1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Require an ampersand and at least one character to
|
|
Packit |
284210 |
* start looking into the entity.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
if ((input[i] == '&')&&(i + 1 < input_len)) {
|
|
Packit |
284210 |
int k, j = i + 1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (input[j] == '#') {
|
|
Packit |
284210 |
/* Numerical entity. */
|
|
Packit |
284210 |
copy++;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (!(j + 1 < input_len)) goto HTML_ENT_OUT; /* Not enough bytes. */
|
|
Packit |
284210 |
j++;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if ((input[j] == 'x')||(input[j] == 'X')) {
|
|
Packit |
284210 |
/* Hexadecimal entity. */
|
|
Packit |
284210 |
copy++;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (!(j + 1 < input_len)) goto HTML_ENT_OUT; /* Not enough bytes. */
|
|
Packit |
284210 |
j++; /* j is the position of the first digit now. */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
k = j;
|
|
Packit |
284210 |
while((j < input_len)&&(isxdigit(input[j]))) j++;
|
|
Packit |
284210 |
if (j > k) { /* Do we have at least one digit? */
|
|
Packit |
284210 |
/* Decode the entity. */
|
|
Packit |
284210 |
char *x = apr_pstrmemdup(mp, (const char *)&input[k], j - k);
|
|
Packit |
284210 |
*d++ = (unsigned char)strtol(x, NULL, 16);
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Skip over the semicolon if it's there. */
|
|
Packit |
284210 |
if ((j < input_len)&&(input[j] == ';')) i = j + 1;
|
|
Packit |
284210 |
else i = j;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
continue;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
goto HTML_ENT_OUT;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
/* Decimal entity. */
|
|
Packit |
284210 |
k = j;
|
|
Packit |
284210 |
while((j < input_len)&&(isdigit(input[j]))) j++;
|
|
Packit |
284210 |
if (j > k) { /* Do we have at least one digit? */
|
|
Packit |
284210 |
/* Decode the entity. */
|
|
Packit |
284210 |
char *x = apr_pstrmemdup(mp, (const char *)&input[k], j - k);
|
|
Packit |
284210 |
*d++ = (unsigned char)strtol(x, NULL, 10);
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Skip over the semicolon if it's there. */
|
|
Packit |
284210 |
if ((j < input_len)&&(input[j] == ';')) i = j + 1;
|
|
Packit |
284210 |
else i = j;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
continue;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
goto HTML_ENT_OUT;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
/* Text entity. */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
k = j;
|
|
Packit |
284210 |
while((j < input_len)&&(isalnum(input[j]))) j++;
|
|
Packit |
284210 |
if (j > k) { /* Do we have at least one digit? */
|
|
Packit |
284210 |
char *x = apr_pstrmemdup(mp, (const char *)&input[k], j - k);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Decode the entity. */
|
|
Packit |
284210 |
/* ENH What about others? */
|
|
Packit |
284210 |
if (strcasecmp(x, "quot") == 0) *d++ = '"';
|
|
Packit |
284210 |
else
|
|
Packit |
284210 |
if (strcasecmp(x, "amp") == 0) *d++ = '&';
|
|
Packit |
284210 |
else
|
|
Packit |
284210 |
if (strcasecmp(x, "lt") == 0) *d++ = '<';
|
|
Packit |
284210 |
else
|
|
Packit |
284210 |
if (strcasecmp(x, "gt") == 0) *d++ = '>';
|
|
Packit |
284210 |
else
|
|
Packit |
284210 |
if (strcasecmp(x, "nbsp") == 0) *d++ = NBSP;
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
/* We do no want to convert this entity, copy the raw data over. */
|
|
Packit |
284210 |
copy = j - k + 1;
|
|
Packit |
284210 |
goto HTML_ENT_OUT;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Skip over the semicolon if it's there. */
|
|
Packit |
284210 |
if ((j < input_len)&&(input[j] == ';')) i = j + 1;
|
|
Packit |
284210 |
else i = j;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
continue;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
HTML_ENT_OUT:
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for(z = 0; ((z < copy) && (count < input_len)); z++) {
|
|
Packit |
284210 |
*d++ = input[i++];
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*d = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return count;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* IMP1 Assumes NUL-terminated
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int ansi_c_sequences_decode_inplace(unsigned char *input, int input_len) {
|
|
Packit |
284210 |
unsigned char *d = input;
|
|
Packit |
284210 |
int i, count;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
i = count = 0;
|
|
Packit |
284210 |
while(i < input_len) {
|
|
Packit |
284210 |
if ((input[i] == '\\')&&(i + 1 < input_len)) {
|
|
Packit |
284210 |
int c = -1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
switch(input[i + 1]) {
|
|
Packit |
284210 |
case 'a' :
|
|
Packit |
284210 |
c = '\a';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 'b' :
|
|
Packit |
284210 |
c = '\b';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 'f' :
|
|
Packit |
284210 |
c = '\f';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 'n' :
|
|
Packit |
284210 |
c = '\n';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 'r' :
|
|
Packit |
284210 |
c = '\r';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 't' :
|
|
Packit |
284210 |
c = '\t';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case 'v' :
|
|
Packit |
284210 |
c = '\v';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '\\' :
|
|
Packit |
284210 |
c = '\\';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '?' :
|
|
Packit |
284210 |
c = '?';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '\'' :
|
|
Packit |
284210 |
c = '\'';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
case '"' :
|
|
Packit |
284210 |
c = '"';
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (c != -1) i += 2;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Hexadecimal or octal? */
|
|
Packit |
284210 |
if (c == -1) {
|
|
Packit |
284210 |
if ((input[i + 1] == 'x')||(input[i + 1] == 'X')) {
|
|
Packit |
284210 |
/* Hexadecimal. */
|
|
Packit |
284210 |
if ((i + 3 < input_len)&&(isxdigit(input[i + 2]))&&(isxdigit(input[i + 3]))) {
|
|
Packit |
284210 |
/* Two digits. */
|
|
Packit |
284210 |
c = x2c(&input[i + 2]);
|
|
Packit |
284210 |
i += 4;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
/* Invalid encoding, do nothing. */
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else
|
|
Packit |
284210 |
if (ISODIGIT(input[i + 1])) { /* Octal. */
|
|
Packit |
284210 |
char buf[4];
|
|
Packit |
284210 |
int j = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
while((i + 1 + j < input_len)&&(j < 3)) {
|
|
Packit |
284210 |
buf[j] = input[i + 1 + j];
|
|
Packit |
284210 |
j++;
|
|
Packit |
284210 |
if (!ISODIGIT(input[i + 1 + j])) break;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
buf[j] = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (j > 0) {
|
|
Packit |
284210 |
c = strtol(buf, NULL, 8);
|
|
Packit |
284210 |
i += 1 + j;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (c == -1) {
|
|
Packit |
284210 |
/* Didn't recognise encoding, copy raw bytes. */
|
|
Packit |
284210 |
*d++ = input[i + 1];
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
i += 2;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
/* Converted the encoding. */
|
|
Packit |
284210 |
*d++ = c;
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
/* Input character not a backslash, copy it. */
|
|
Packit |
284210 |
*d++ = input[i++];
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*d = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return count;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* IMP1 Assumes NUL-terminated
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int normalize_path_inplace(unsigned char *input, int input_len, int win, int *changed) {
|
|
Packit |
284210 |
unsigned char *src;
|
|
Packit |
284210 |
unsigned char *dst;
|
|
Packit |
284210 |
unsigned char *end;
|
|
Packit |
284210 |
int ldst = 0;
|
|
Packit |
284210 |
int hitroot = 0;
|
|
Packit |
284210 |
int done = 0;
|
|
Packit |
284210 |
int relative;
|
|
Packit |
284210 |
int trailing;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*changed = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Need at least one byte to normalize */
|
|
Packit |
284210 |
if (input_len <= 0) return 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/*
|
|
Packit |
284210 |
* ENH: Deal with UNC and drive letters?
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
|
|
Packit |
284210 |
src = dst = input;
|
|
Packit |
284210 |
end = input + (input_len - 1);
|
|
Packit |
284210 |
ldst = 1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
relative = ((*input == '/') || (win && (*input == '\\'))) ? 0 : 1;
|
|
Packit |
284210 |
trailing = ((*end == '/') || (win && (*end == '\\'))) ? 1 : 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
|
|
Packit |
284210 |
while (!done && (src <= end) && (dst <= end)) {
|
|
Packit |
284210 |
/* Convert backslash to forward slash on Windows only. */
|
|
Packit |
284210 |
if (win) {
|
|
Packit |
284210 |
if (*src == '\\') {
|
|
Packit |
284210 |
*src = '/';
|
|
Packit |
284210 |
*changed = 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
if ((src < end) && (*(src + 1) == '\\')) {
|
|
Packit |
284210 |
*(src + 1) = '/';
|
|
Packit |
284210 |
*changed = 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Always normalize at the end of the input. */
|
|
Packit |
284210 |
if (src == end) {
|
|
Packit |
284210 |
done = 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Skip normalization if this is NOT the end of the path segment. */
|
|
Packit |
284210 |
else if (*(src + 1) != '/') {
|
|
Packit |
284210 |
goto copy; /* Skip normalization. */
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/*** Normalize the path segment. ***/
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Could it be an empty path segment? */
|
|
Packit |
284210 |
if ((src != end) && *src == '/') {
|
|
Packit |
284210 |
/* Ignore */
|
|
Packit |
284210 |
*changed = 1;
|
|
Packit |
284210 |
goto copy; /* Copy will take care of this. */
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Could it be a back or self reference? */
|
|
Packit |
284210 |
else if (*src == '.') {
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Back-reference? */
|
|
Packit |
284210 |
if ((dst > input) && (*(dst - 1) == '.')) {
|
|
Packit |
284210 |
/* If a relative path and either our normalization has
|
|
Packit |
284210 |
* already hit the rootdir, or this is a backref with no
|
|
Packit |
284210 |
* previous path segment, then mark that the rootdir was hit
|
|
Packit |
284210 |
* and just copy the backref as no normilization is possible.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
if (relative && (hitroot || ((dst - 2) <= input))) {
|
|
Packit |
284210 |
hitroot = 1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
goto copy; /* Skip normalization. */
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Remove backreference and the previous path segment. */
|
|
Packit |
284210 |
dst -= 3;
|
|
Packit |
284210 |
while ((dst > input) && (*dst != '/')) {
|
|
Packit |
284210 |
dst--;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* But do not allow going above rootdir. */
|
|
Packit |
284210 |
if (dst <= input) {
|
|
Packit |
284210 |
hitroot = 1;
|
|
Packit |
284210 |
dst = input;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Need to leave the root slash if this
|
|
Packit |
284210 |
* is not a relative path and the end was reached
|
|
Packit |
284210 |
* on a backreference.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
if (!relative && (src == end)) {
|
|
Packit |
284210 |
dst++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (done) goto length; /* Skip the copy. */
|
|
Packit |
284210 |
src++;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*changed = 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Relative Self-reference? */
|
|
Packit |
284210 |
else if (dst == input) {
|
|
Packit |
284210 |
*changed = 1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Ignore. */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (done) goto length; /* Skip the copy. */
|
|
Packit |
284210 |
src++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Self-reference? */
|
|
Packit |
284210 |
else if (*(dst - 1) == '/') {
|
|
Packit |
284210 |
*changed = 1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Ignore. */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (done) goto length; /* Skip the copy. */
|
|
Packit |
284210 |
dst--;
|
|
Packit |
284210 |
src++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Found a regular path segment. */
|
|
Packit |
284210 |
else if (dst > input) {
|
|
Packit |
284210 |
hitroot = 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
copy:
|
|
Packit |
284210 |
/*** Copy the byte if required. ***/
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Skip to the last forward slash when multiple are used. */
|
|
Packit |
284210 |
if (*src == '/') {
|
|
Packit |
284210 |
unsigned char *oldsrc = src;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
while ( (src < end)
|
|
Packit |
284210 |
&& ((*(src + 1) == '/') || (win && (*(src + 1) == '\\'))) )
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
src++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
if (oldsrc != src) *changed = 1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Do not copy the forward slash to the root
|
|
Packit |
284210 |
* if it is not a relative path. Instead
|
|
Packit |
284210 |
* move over the slash to the next segment.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
if (relative && (dst == input)) {
|
|
Packit |
284210 |
src++;
|
|
Packit |
284210 |
goto length; /* Skip the copy */
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*(dst++) = *(src++);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
length:
|
|
Packit |
284210 |
ldst = (dst - input);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Make sure that there is not a trailing slash in the
|
|
Packit |
284210 |
* normalized form if there was not one in the original form.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
if (!trailing && (dst > input) && *(dst - 1) == '/') {
|
|
Packit |
284210 |
ldst--;
|
|
Packit |
284210 |
dst--;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Always NUL terminate */
|
|
Packit |
284210 |
*dst = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return ldst;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
char *modsec_build(apr_pool_t *mp) {
|
|
Packit |
284210 |
return apr_psprintf(mp, "%02i%02i%02i%1i%02i",
|
|
Packit |
284210 |
atoi(MODSEC_VERSION_MAJOR),
|
|
Packit |
284210 |
atoi(MODSEC_VERSION_MINOR),
|
|
Packit |
284210 |
atoi(MODSEC_VERSION_MAINT),
|
|
Packit |
284210 |
get_modsec_build_type(NULL),
|
|
Packit |
284210 |
atoi(MODSEC_VERSION_RELEASE));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
int is_empty_string(const char *string) {
|
|
Packit |
284210 |
unsigned int i;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (string == NULL) return 1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for(i = 0; string[i] != '\0'; i++) {
|
|
Packit |
284210 |
if (!isspace(string[i])) {
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
char *resolve_relative_path(apr_pool_t *pool, const char *parent_filename, const char *filename) {
|
|
Packit |
284210 |
if (filename == NULL) return NULL;
|
|
Packit |
284210 |
// TODO Support paths on operating systems other than Unix.
|
|
Packit |
284210 |
if (filename[0] == '/') return (char *)filename;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return apr_pstrcat(pool, apr_pstrndup(pool, parent_filename,
|
|
Packit |
284210 |
strlen(parent_filename) - strlen(apr_filepath_name_get(parent_filename))),
|
|
Packit |
284210 |
filename, NULL);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* Decode a string that contains CSS-escaped characters.
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* References:
|
|
Packit |
284210 |
* http://www.w3.org/TR/REC-CSS2/syndata.html#q4
|
|
Packit |
284210 |
* http://www.unicode.org/roadmaps/
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int css_decode_inplace(unsigned char *input, long int input_len) {
|
|
Packit |
284210 |
unsigned char *d = (unsigned char *)input;
|
|
Packit |
284210 |
long int i, j, count;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (input == NULL) return -1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
i = count = 0;
|
|
Packit |
284210 |
while (i < input_len) {
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Is the character a backslash? */
|
|
Packit |
284210 |
if (input[i] == '\\') {
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Is there at least one more byte? */
|
|
Packit |
284210 |
if (i + 1 < input_len) {
|
|
Packit |
284210 |
i++; /* We are not going to need the backslash. */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Check for 1-6 hex characters following the backslash */
|
|
Packit |
284210 |
j = 0;
|
|
Packit |
284210 |
while ( (j < 6)
|
|
Packit |
284210 |
&& (i + j < input_len)
|
|
Packit |
284210 |
&& (VALID_HEX(input[i + j])))
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
j++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (j > 0) { /* We have at least one valid hexadecimal character. */
|
|
Packit |
284210 |
int fullcheck = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* For now just use the last two bytes. */
|
|
Packit |
284210 |
switch (j) {
|
|
Packit |
284210 |
/* Number of hex characters */
|
|
Packit |
284210 |
case 1:
|
|
Packit |
284210 |
*d++ = xsingle2c(&input[i]);
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
case 2:
|
|
Packit |
284210 |
case 3:
|
|
Packit |
284210 |
/* Use the last two from the end. */
|
|
Packit |
284210 |
*d++ = x2c(&input[i + j - 2]);
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
case 4:
|
|
Packit |
284210 |
/* Use the last two from the end, but request
|
|
Packit |
284210 |
* a full width check.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
*d = x2c(&input[i + j - 2]);
|
|
Packit |
284210 |
fullcheck = 1;
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
case 5:
|
|
Packit |
284210 |
/* Use the last two from the end, but request
|
|
Packit |
284210 |
* a full width check if the number is greater
|
|
Packit |
284210 |
* or equal to 0xFFFF.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
*d = x2c(&input[i + j - 2]);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Do full check if first byte is 0 */
|
|
Packit |
284210 |
if (input[i] == '0') {
|
|
Packit |
284210 |
fullcheck = 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
d++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
case 6:
|
|
Packit |
284210 |
/* Use the last two from the end, but request
|
|
Packit |
284210 |
* a full width check if the number is greater
|
|
Packit |
284210 |
* or equal to 0xFFFF.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
*d = x2c(&input[i + j - 2]);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Do full check if first/second bytes are 0 */
|
|
Packit |
284210 |
if ( (input[i] == '0')
|
|
Packit |
284210 |
&& (input[i + 1] == '0')
|
|
Packit |
284210 |
) {
|
|
Packit |
284210 |
fullcheck = 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
d++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Full width ASCII (0xff01 - 0xff5e) needs 0x20 added */
|
|
Packit |
284210 |
if (fullcheck) {
|
|
Packit |
284210 |
if ( (*d > 0x00) && (*d < 0x5f)
|
|
Packit |
284210 |
&& ((input[i + j - 3] == 'f') ||
|
|
Packit |
284210 |
(input[i + j - 3] == 'F'))
|
|
Packit |
284210 |
&& ((input[i + j - 4] == 'f') ||
|
|
Packit |
284210 |
(input[i + j - 4] == 'F')))
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
(*d) += 0x20;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
d++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* We must ignore a single whitespace after a hex escape */
|
|
Packit |
284210 |
if ((i + j < input_len) && isspace(input[i + j])) {
|
|
Packit |
284210 |
j++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Move over. */
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
i += j;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* No hexadecimal digits after backslash */
|
|
Packit |
284210 |
else if (input[i] == '\n') {
|
|
Packit |
284210 |
/* A newline character following backslash is ignored. */
|
|
Packit |
284210 |
i++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* The character after backslash is not a hexadecimal digit, nor a newline. */
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
/* Use one character after backslash as is. */
|
|
Packit |
284210 |
*d++ = input[i++];
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* No characters after backslash. */
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
/* Do not include backslash in output (continuation to nothing) */
|
|
Packit |
284210 |
i++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Character is not a backslash. */
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
/* Copy one normal character to output. */
|
|
Packit |
284210 |
*d++ = input[i++];
|
|
Packit |
284210 |
count++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Terminate output string. */
|
|
Packit |
284210 |
*d = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return count;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* Translate UNIX octal umask/mode to APR apr_fileperms_t
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
apr_fileperms_t mode2fileperms(int mode) {
|
|
Packit |
284210 |
apr_fileperms_t perms = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (mode & S_IXOTH) perms |= APR_WEXECUTE;
|
|
Packit |
284210 |
if (mode & S_IWOTH) perms |= APR_WWRITE;
|
|
Packit |
284210 |
if (mode & S_IROTH) perms |= APR_WREAD;
|
|
Packit |
284210 |
if (mode & S_IXGRP) perms |= APR_GEXECUTE;
|
|
Packit |
284210 |
if (mode & S_IWGRP) perms |= APR_GWRITE;
|
|
Packit |
284210 |
if (mode & S_IRGRP) perms |= APR_GREAD;
|
|
Packit |
284210 |
if (mode & S_IXUSR) perms |= APR_UEXECUTE;
|
|
Packit |
284210 |
if (mode & S_IWUSR) perms |= APR_UWRITE;
|
|
Packit |
284210 |
if (mode & S_IRUSR) perms |= APR_UREAD;
|
|
Packit |
284210 |
if (mode & S_ISVTX) perms |= APR_WSTICKY;
|
|
Packit |
284210 |
if (mode & S_ISGID) perms |= APR_GSETID;
|
|
Packit |
284210 |
if (mode & S_ISUID) perms |= APR_USETID;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return perms;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* Generate a single variable.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
char *construct_single_var(modsec_rec *msr, char *name) {
|
|
Packit |
284210 |
char *varname = NULL;
|
|
Packit |
284210 |
char *param = NULL;
|
|
Packit |
284210 |
msre_var *var = NULL;
|
|
Packit |
284210 |
msre_var *vx = NULL;
|
|
Packit |
284210 |
char *my_error_msg = NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Extract variable name and its parameter from the script. */
|
|
Packit |
284210 |
varname = apr_pstrdup(msr->mp, name);
|
|
Packit |
284210 |
param = strchr(varname, '.');
|
|
Packit |
284210 |
if (param != NULL) {
|
|
Packit |
284210 |
*param = '\0';
|
|
Packit |
284210 |
param++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Resolve variable. */
|
|
Packit |
284210 |
var = msre_create_var_ex(msr->mp, msr->modsecurity->msre,
|
|
Packit |
284210 |
varname, param, msr, &my_error_msg);
|
|
Packit |
284210 |
if (var == NULL) return NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Generate variable. */
|
|
Packit |
284210 |
vx = generate_single_var(msr, var, NULL, NULL, msr->msc_rule_mptmp);
|
|
Packit |
284210 |
if (vx == NULL) return NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return (char *)vx->value;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* @brief Transforms an apr_array_header_t to a text buffer
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* Converts an apr_array_header_t into a plain/text buffer in a Key: Pair
|
|
Packit |
284210 |
* format. The generated buffer is not null terminated.
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* If called with `buffer_length` set to 0 or with `buffer` set to NULL,
|
|
Packit |
284210 |
* it will _not_ fill any buffer, instead, it will return the length, that
|
|
Packit |
284210 |
* will be needed to save the entire content of `arr` into a buffer.
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* @warning return is not NULL-terminated.
|
|
Packit |
284210 |
* @note memory management is in the responsibility of the caller.
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* @param arr apr_array_header_t to be iterated.
|
|
Packit |
284210 |
* @param buffer pointer to the destination buffer.
|
|
Packit |
284210 |
* @param buffer_length length that will fully fill the buffer.
|
|
Packit |
284210 |
* @retval -1 Something went wrong in the process. Do not trust in
|
|
Packit |
284210 |
* buffer content.
|
|
Packit |
284210 |
* @retval n>0 size of the [needed|] buffer.
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int msc_headers_to_buffer(const apr_array_header_t *arr, char *buffer,
|
|
Packit |
284210 |
int buffer_length)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
int headers_length = 0;
|
|
Packit |
284210 |
int write_to_buffer = 0;
|
|
Packit |
284210 |
int i = 0;
|
|
Packit |
284210 |
const apr_table_entry_t *te = NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (buffer != NULL && buffer_length > 0) {
|
|
Packit |
284210 |
write_to_buffer = 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
te = (apr_table_entry_t *)arr->elts;
|
|
Packit |
284210 |
for (i = 0; i < arr->nelts; i++) {
|
|
Packit |
284210 |
char *value = te[i].val;
|
|
Packit |
284210 |
char *key = te[i].key;
|
|
Packit |
284210 |
headers_length = headers_length + strlen(value) + strlen(key) + /* \n: */ 1 +
|
|
Packit |
284210 |
/* colum */ 1 + /* space: */ 1 ;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (write_to_buffer == 1) {
|
|
Packit |
284210 |
if (buffer_length < headers_length) {
|
|
Packit |
284210 |
headers_length = -1;
|
|
Packit |
284210 |
goto not_enough_memory;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
sprintf(buffer, "%s%s: %s\n", buffer, key, value);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
headers_length++; /* Save space for an extra '\n' between the hedaers and the request body */
|
|
Packit |
284210 |
if (write_to_buffer) {
|
|
Packit |
284210 |
if (buffer_length < headers_length) {
|
|
Packit |
284210 |
headers_length = -1;
|
|
Packit |
284210 |
goto not_enough_memory;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
buffer[headers_length-1] = '\n';
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
not_enough_memory:
|
|
Packit |
284210 |
return headers_length;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
int read_line(char *buf, int len, FILE *fp)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
char *tmp;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (buf == NULL)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
memset(buf, '\0', len*sizeof(char));
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (fgets(buf, len, fp) == NULL)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
*buf = '\0';
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
if ((tmp = strrchr(buf, '\n')) != NULL)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
*tmp = '\0';
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
int create_radix_tree(apr_pool_t *mp, TreeRoot **rtree, char **error_msg)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
*rtree = apr_palloc(mp, sizeof(TreeRoot));
|
|
Packit |
284210 |
if (*rtree == NULL)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
*error_msg = apr_psprintf(mp, "Failed allocating " \
|
|
Packit |
284210 |
"memory to TreeRoot.");
|
|
Packit |
284210 |
goto root_node_failed;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
memset(*rtree, 0, sizeof(TreeRoot));
|
|
Packit |
284210 |
|
|
Packit |
284210 |
(*rtree)->ipv4_tree = CPTCreateRadixTree(mp);
|
|
Packit |
284210 |
if ((*rtree)->ipv4_tree == NULL)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
*error_msg = apr_psprintf(mp, "IPmatch: Tree initialization " \
|
|
Packit |
284210 |
"failed.");
|
|
Packit |
284210 |
goto ipv4_tree_failed;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
(*rtree)->ipv6_tree = CPTCreateRadixTree(mp);
|
|
Packit |
284210 |
if ((*rtree)->ipv6_tree == NULL)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
*error_msg = apr_psprintf(mp, "IPmatch: Tree initialization " \
|
|
Packit |
284210 |
"failed.");
|
|
Packit |
284210 |
goto ipv6_tree_failed;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
ipv6_tree_failed:
|
|
Packit |
284210 |
ipv4_tree_failed:
|
|
Packit |
284210 |
root_node_failed:
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
|
|
Packit |
284210 |
int ip_tree_from_file(TreeRoot **rtree, char *uri,
|
|
Packit |
284210 |
apr_pool_t *mp, char **error_msg)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
TreeNode *tnode = NULL;
|
|
Packit |
284210 |
apr_status_t rc;
|
|
Packit |
284210 |
int line = 0;
|
|
Packit |
284210 |
apr_file_t *fd;
|
|
Packit |
284210 |
char *start;
|
|
Packit |
284210 |
char *end;
|
|
Packit |
284210 |
char buf[HUGE_STRING_LEN + 1]; // FIXME: 2013-10-29 zimmerle: dynamic?
|
|
Packit |
284210 |
char errstr[1024]; //
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (create_radix_tree(mp, rtree, error_msg))
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
rc = apr_file_open(&fd, uri, APR_READ | APR_BUFFERED | APR_FILE_NOCLEANUP,
|
|
Packit |
284210 |
0, mp);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (rc != APR_SUCCESS)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
*error_msg = apr_psprintf(mp, "Could not open ipmatch file \"%s\": %s",
|
|
Packit |
284210 |
uri, apr_strerror(rc, errstr, 1024));
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
while ((rc = apr_file_gets(buf, HUGE_STRING_LEN, fd)) != APR_EOF)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
line++;
|
|
Packit |
284210 |
if (rc != APR_SUCCESS)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
*error_msg = apr_psprintf(mp, "Could not read \"%s\" line %d: %s",
|
|
Packit |
284210 |
uri, line, apr_strerror(rc, errstr, 1024));
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
start = buf;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
while ((apr_isspace(*start) != 0) && (*start != '\0'))
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
start++;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for (end = start; end != NULL || *end != '\0' || *end != '\n'; end++)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
if (apr_isxdigit(*end) || *end == '.' || *end == '/' || *end == ':')
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
continue;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (*end != '\n')
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
*error_msg = apr_psprintf(mp, "Invalid char \"%c\" in line %d " \
|
|
Packit |
284210 |
"of file %s", *end, line, uri);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*end = '\0';
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if ((start == end) || (*start == '#'))
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
continue;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (strchr(start, ':') == NULL)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
tnode = TreeAddIP(start, (*rtree)->ipv4_tree, IPV4_TREE);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#if APR_HAVE_IPV6
|
|
Packit |
284210 |
else
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
tnode = TreeAddIP(start, (*rtree)->ipv6_tree, IPV6_TREE);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (tnode == NULL)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
*error_msg = apr_psprintf(mp, "Could not add entry " \
|
|
Packit |
284210 |
"\"%s\" in line %d of file %s to IP list", start, line, uri);
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (fd != NULL)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
apr_file_close(fd);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
#ifdef WITH_CURL
|
|
Packit |
284210 |
int ip_tree_from_uri(TreeRoot **rtree, char *uri,
|
|
Packit |
284210 |
apr_pool_t *mp, char **error_msg)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
TreeNode *tnode = NULL;
|
|
Packit |
284210 |
apr_status_t rc;
|
|
Packit |
284210 |
int line = 0;
|
|
Packit |
284210 |
apr_file_t *fd;
|
|
Packit |
284210 |
char *start;
|
|
Packit |
284210 |
int res;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
struct msc_curl_memory_buffer_t chunk;
|
|
Packit |
284210 |
char *word = NULL;
|
|
Packit |
284210 |
char *brkt = NULL;
|
|
Packit |
284210 |
char *sep = "\n";
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (create_radix_tree(mp, rtree, error_msg))
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
res = msc_remote_download_content(mp, uri, NULL, &chunk, error_msg);
|
|
Packit |
284210 |
if (res)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
return res;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for (word = strtok_r(chunk.memory, sep, &brkt);
|
|
Packit |
284210 |
word;
|
|
Packit |
284210 |
word = strtok_r(NULL, sep, &brkt))
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
int i = 0;
|
|
Packit |
284210 |
line++;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Ignore empty lines and comments */
|
|
Packit |
284210 |
if (*word == '#') continue;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for (i = 0; i < strlen(word); i++)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
if (apr_isxdigit(word[i]) || word[i] == '.' || word[i] == '/' || word[i] == ':' || word[i] == '\n')
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
continue;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*error_msg = apr_psprintf(mp, "Invalid char \"%c\" in line %d " \
|
|
Packit |
284210 |
"of uri %s", word[i], line, uri);
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (strchr(word, ':') == NULL)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
tnode = TreeAddIP(word, (*rtree)->ipv4_tree, IPV4_TREE);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#if APR_HAVE_IPV6
|
|
Packit |
284210 |
else
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
tnode = TreeAddIP(word, (*rtree)->ipv6_tree, IPV6_TREE);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (tnode == NULL)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
*error_msg = apr_psprintf(mp, "Could not add entry " \
|
|
Packit |
284210 |
"\"%s\" in line %d of file %s to IP list", word, line, uri);
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
msc_remote_clean_chunk(&chunk);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
|
|
Packit |
284210 |
int tree_contains_ip(apr_pool_t *mp, TreeRoot *rtree,
|
|
Packit |
284210 |
const char *value, modsec_rec *msr, char **error_msg)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
struct in_addr in;
|
|
Packit |
284210 |
#if APR_HAVE_IPV6
|
|
Packit |
284210 |
struct in6_addr in6;
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (rtree == NULL)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (strchr(value, ':') == NULL) {
|
|
Packit |
284210 |
if (inet_pton(AF_INET, value, &in) <= 0) {
|
|
Packit |
284210 |
*error_msg = apr_psprintf(mp, "IPmatch: bad IPv4 " \
|
|
Packit |
284210 |
"specification \"%s\".", value);
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (CPTIpMatch(msr, (unsigned char *)&in.s_addr, rtree->ipv4_tree,
|
|
Packit |
284210 |
IPV4_TREE) != NULL) {
|
|
Packit |
284210 |
return 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#if APR_HAVE_IPV6
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
if (inet_pton(AF_INET6, value, &in6) <= 0) {
|
|
Packit |
284210 |
*error_msg = apr_psprintf(mp, "IPmatch: bad IPv6 " \
|
|
Packit |
284210 |
"specification \"%s\".", value);
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (CPTIpMatch(msr, (unsigned char *)&in6.s6_addr, rtree->ipv6_tree,
|
|
Packit |
284210 |
IPV6_TREE) != NULL) {
|
|
Packit |
284210 |
return 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
int ip_tree_from_param(apr_pool_t *mp,
|
|
Packit |
284210 |
char *param, TreeRoot **rtree, char **error_msg)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
char *saved = NULL;
|
|
Packit |
284210 |
char *str = NULL;
|
|
Packit |
284210 |
TreeNode *tnode = NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (create_radix_tree(mp, rtree, error_msg))
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
str = apr_strtok(param, ",", &saved);
|
|
Packit |
284210 |
while (str != NULL)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
if (strchr(str, ':') == NULL)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
tnode = TreeAddIP(str, (*rtree)->ipv4_tree, IPV4_TREE);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#if APR_HAVE_IPV6
|
|
Packit |
284210 |
else
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
tnode = TreeAddIP(str, (*rtree)->ipv6_tree, IPV6_TREE);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
if (tnode == NULL)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
*error_msg = apr_psprintf(mp, "Could not add entry " \
|
|
Packit |
284210 |
"\"%s\" from: %s.", str, param);
|
|
Packit |
284210 |
return -1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
str = apr_strtok(NULL, ",", &saved);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
#ifdef WITH_CURL
|
|
Packit |
284210 |
size_t msc_curl_write_memory_cb(void *contents, size_t size,
|
|
Packit |
284210 |
size_t nmemb, void *userp)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
size_t realsize = size * nmemb;
|
|
Packit |
284210 |
struct msc_curl_memory_buffer_t *mem = (struct msc_curl_memory_buffer_t *)userp;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (mem->size == 0)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
mem->memory = malloc(realsize + 1);
|
|
Packit |
284210 |
memset(mem->memory, '\0', sizeof(realsize + 1));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
mem->memory = realloc(mem->memory, mem->size + realsize + 1);
|
|
Packit |
284210 |
memset(mem->memory + mem->size, '\0', sizeof(realsize + 1));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (mem->memory == NULL) {
|
|
Packit |
284210 |
/* out of memory! */
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
memcpy(&(mem->memory[mem->size]), contents, realsize);
|
|
Packit |
284210 |
mem->size += realsize;
|
|
Packit |
284210 |
mem->memory[mem->size] = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return realsize;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
|
|
Packit |
284210 |
#ifdef WIN32
|
|
Packit |
284210 |
char* strtok_r(
|
|
Packit |
284210 |
char *str,
|
|
Packit |
284210 |
const char *delim,
|
|
Packit |
284210 |
char **nextp)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
char *ret;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (str == NULL)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
str = *nextp;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
str += strspn(str, delim);
|
|
Packit |
284210 |
if (*str == '\0')
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
return NULL;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
ret = str;
|
|
Packit |
284210 |
str += strcspn(str, delim);
|
|
Packit |
284210 |
if (*str)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
*str++ = '\0';
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
*nextp = str;
|
|
Packit |
284210 |
return ret;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
|