#include "config.h" #include #include #include #include /* Convert a string to a integer. */ int str2int(const char *str) { int i = 0, value = 0; if (str == NULL) { return -1; } else if (*str == '\0') { return -1; } else while (*(str + i) != '\0') { if ((*(str + i) >= '0') && (*(str + i) <= '9')) { value *= 10; value += (*(str + i) - '0'); i++; } else { return -1; } } return value; } /* Remove the leading and trailing spaces in a string. */ char *remove_spaces(char *str) { int pos; if (str != NULL) { while ((*str == ' ') || (*str == '\t')) { str++; } pos = strlen(str) - 1; while (pos >= 0) { switch (*(str + pos)) { case ' ': case '\t': case '\r': case '\n': *(str + pos) = '\0'; pos--; break; default: pos = -1; } } } return str; } /* Remove comment from a string. */ char *strip_line(char *str) { char *hash; if (str != NULL) { if ((hash = strchr(str, '#')) != NULL) { *hash = '\0'; } return remove_spaces(str); } return NULL; } /* Covert a string to lowercase. */ char *strlower(char *line) { char *c; if (line != NULL) { c = line; while (*c != '\0') { if ((*c >= 'A') && (*c <= 'Z')) { *c += 32; } c++; } } return line; } /* Split a string in 2 strings. */ int split_string(const char *str, char **key, char **value, char c) { if (str != NULL) { *key = (char*)str; if ((*value = strchr(*key, c)) != NULL) { *(*value)++ = '\0'; *key = remove_spaces(*key); *value = remove_spaces(*value); return 0; } } return -1; } int split_configline(const char *str, char **key, char **value) { *key = remove_spaces((char*)str); *value = *key; int eq = 0; while (**value != '\0') { if ((**value == ' ') || (**value == '=')) { if (**value == '=') eq++; **value = '\0'; do { (*value)++; if (**value == '=') eq++; } while ((**value == ' ') || (**value == '=')); if (eq > 1) return -1; return 0; } (*value)++; } value = NULL; return -1; } /* Check the validity of an URL. */ bool valid_uri(char *uri) { if (uri == NULL) { return false; } else if (*uri != '/') { return false; } do { if (*(uri + 1) == '.') { if ((*uri == '.') || (*uri == '/')) { return false; } } if ((*uri < 32) || (*uri > 126)) { return false; } uri++; } while (*uri != '\0'); return true; } /* Convert a hexadecimal char to an integer. */ static short hex_to_int(char c) { if ((c >= '0') && (c <= '9')) { return c - '0'; } else if ((c >= 'A') && (c <= 'F')) { return c - 'A' + 10; } else if ((c >= 'a') && (c <= 'f')) { return c - 'a' + 10; } return -1; } /* Decode the URL encoded characters (%XX). */ void url_decode(char *line) { short low, high; char *dest = line; if (line != NULL) { while (*line != '\0') { if (*line == '%') { if ((high = hex_to_int(*(line + 1))) != -1) { if ((low = hex_to_int(*(line + 2))) != -1) { line += 2; *line = (char)(high<<4) + low; } } } *(dest++) = *(line++); } *dest = *line; } } /* Remove characters with ASCII value < 32. */ void remove_dangerous_chars(char *line) { short low, high; char *dest = line; if (line != NULL) { while (*line != '\0') { if ((*line > 0) && (*line < 32)) { line++; continue; } else if (*line == '%') { if ((high = hex_to_int(*(line + 1))) != -1) { if ((low = hex_to_int(*(line + 2))) != -1) { if (((high<<4) + low) < 32) { line += 3; continue; } } } } *(dest++) = *(line++); } *dest = *line; } } /* Prevent Command injection. */ int prevent_CMDi(char *line) { int result = 0; short low, high; char value; if (line != NULL) { while (*line != '\0') { if ((value = *line) == '%') { if ((high = hex_to_int(*(line + 1))) != -1) { if ((low = hex_to_int(*(line + 2))) != -1) { value = (char)(high<<4) + low; } } } if ((value == '|') || (value == ';') || (value == '`')) { *line = '_'; result += 1; } line++; } } return result; } /* Prevent SQL injection */ int prevent_SQLi(char *line, int length, char **newline) { int changed = 0, i, add, left, newlength = 0; char *temp, value; short low, high; if ((line == NULL) || (length == 0)) { return 0; } add = left = 32; if ((*newline = (char*)malloc(length + add)) == NULL) { return -1; } for (i = 0; i < length; i++) { value = *(line + i); if ((value == '%') && (i + 2 < length)) { if ((high = hex_to_int(*(line + i + 1))) != -1) { if ((low = hex_to_int(*(line + i + 2))) != -1) { value = (char)(high<<4) + low; } } } if ((value == '\'') || (value == '`') || (value == '\\')) { *(*newline + newlength++) = '\\'; if (left-- == 0) { add += left = 32; if ((temp = (char*)realloc(*newline, length + add)) == NULL) { free(*newline); return -1; } else { *newline = temp; } } changed++; } *(*newline + (newlength++)) = *(line + i); } if (changed == 0) { free(*newline); *newline = NULL; newlength = 0; } return newlength; } /* Prevent cross-site scripting. */ int prevent_XSS(char *line) { int result = 0; short low, high; char value; if (line != NULL) { while (*line != '\0') { if ((value = *line) == '%') { if ((high = hex_to_int(*(line + 1))) != -1) { if ((low = hex_to_int(*(line + 2))) != -1) { value = (char)(high<<4) + low; } } } if ((value == '\"') || (value == '<') || (value == '>') || (value == '\'')) { *line = '_'; result += 1; } line++; } } return result; } /* Return an errormessage. */ const char *http_error(int code) { int i; static const struct { int code; const char *message; } error[] = { /* {100, "Continue"}, {101, "Switching Protocols"}, {102, "Processing"}, */ {200, "OK"}, {201, "Created"}, /* {202, "Accepted"}, {203, "Non-Authoritative Information"}, */ {204, "No Content"}, /* {205, "Reset Content"}, */ {206, "Partial Content"}, /* {207, "Multi-Status"}, {300, "Multiple Choices"}, */ {301, "Moved Permanently"}, {302, "Found"}, /* {303, "See Other"}, */ {304, "Not Modified"}, /* {305, "Use Proxy"}, {307, "Temporary Redirect"}, */ {400, "Bad Request"}, {401, "Unauthorized"}, /* {402, "Payment Required"}, */ {403, "Forbidden"}, {404, "Not Found"}, {405, "Method Not Allowed"}, /* {406, "Not Acceptable"}, {407, "Proxy Authentication Required"}, */ {408, "Request Timeout"}, /* {409, "Conflict"}, {410, "Gone"}, */ {411, "Length Required"}, {412, "Precondition Failed"}, {413, "Request Entity Too Large"}, /* {414, "uri too long"}, {415, "Unsupported Media Type"}, */ {416, "Requested Range Not Satisfiable"}, /* {417, "Expectation Failed"}, {422, "Unprocessable Entity"}, {423, "Locked"}, {424, "Failed Dependency"}, {426, "Upgrade Required"}, */ {500, "Internal Server Error"}, {501, "Not Implemented"}, /* {502, "Bad Gateway"}, */ {503, "Service Unavailable"}, /* {504, "Gateway Timeout"}, */ {505, "HTTP Version Not Supported"} }; for (i=0; error[i].code != 0; i++) { if (error[i].code == code) { return error[i].message; } } return NULL; } /* Decode an base64 encoded string. */ bool decode_base64(char *base64) { bool retval = true, found; const char *table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int l, i, t, byte = 0, bit = 0; if (base64 == NULL) { return false; } l = strlen(base64); for (i = 0; i < l; i++) { if (*(base64 + i) != '=') { found = false; for (t = 0; t < 64; t++) { if (*(base64 + i) == *(table + t)) { switch (bit) { case 0: *(base64 + byte) = (t << 2); break; case 2: *(base64 + byte) = (*(base64 + byte) & 192) | t; break; case 4: *(base64 + byte) = (*(base64 + byte) & 240) | (t >> 2); *(base64 + byte + 1) = (t << 6); break; case 6: *(base64 + byte) = (*(base64 + byte) & 252) | (t >> 4); *(base64 + byte + 1) = (t << 4); break; } bit += 6; if (bit >= 8) { bit -= 8; byte++; } found = true; break; } } if (found == false) { retval = false; break; } } else { break; } } if (bit <= 2) { *(base64 + byte) = '\0'; } else { *(base64 + byte + 1) = '\0'; } return retval; } char *file_extension(char *filename) { char *c; if (filename != NULL) { c = filename + strlen(filename) - 1; while (c >= filename) { if (*c == '.') { return c + 1; } c--; } } return NULL; } int str_replace(char *src, char *from, char *to, char **dst) { char *pos; int replaced = 0, len_from, len_to; len_from = strlen(from); len_to = strlen(to); if ((src != NULL) && (from != NULL) && (to != NULL)) { while ((pos = strstr(src, from)) != NULL) { if ((*dst = (char*)malloc(strlen(src) - len_from + len_to + 1)) == NULL) { if (*dst != NULL) { free(*dst); } return -1; } *pos = '\0'; sprintf(*dst, "%s%s%s", src, to, pos + len_from); if (replaced > 0) { free(src); } if (replaced++ == 1000) { if (*dst != NULL) { free(*dst); } return -1; } src = *dst; } } return replaced; } bool min_strlen(char *str, int n) { int i = 0; while (i < n) { if (*(str + i) == '\0') { return false; } i++; } return true; }