int mk_kernel_version() { int a, b, c; int len; int pos; char *p, *t; char *tmp; struct utsname uts; if (uname(&uts) == -1) { mk_libc_error("uname"); } len = strlen(uts.release); /* Fixme: this don't support Linux Kernel 10.x.x :P */ a = (*uts.release - '0'); /* Second number */ p = (uts.release) + 2; pos = mk_string_char_search(p, '.', len - 2); if (pos <= 0) { /* Some Debian systems uses a different notation, e.g: 3.14-2-amd64 */ pos = mk_string_char_search(p, '-', len - 2); if (pos <= 0) { return -1; } } tmp = mk_string_copy_substr(p, 0, pos); if (!tmp) { return -1; } b = atoi(tmp); mk_mem_free(tmp); /* Last number (it needs filtering) */ t = p = p + pos + 1; do { t++; } while (isdigit(*t)); tmp = mk_string_copy_substr(p, 0, t - p); if (!tmp) { return -1; } c = atoi(tmp); mk_mem_free(tmp); MK_TRACE("Kernel detected: %i.%i.%i", a, b, c); return MK_KERNEL_VERSION(a, b, c); }
int mk_user_init(struct client_session *cs, struct session_request *sr) { int limit; const int offset = 2; /* The user is defined after the '/~' string, so offset = 2 */ const int user_len = 255; char user[user_len], *user_uri; struct passwd *s_user; if (sr->uri_processed.len <= 2) { return -1; } limit = mk_string_char_search(sr->uri_processed.data + offset, '/', sr->uri_processed.len); if (limit == -1) { limit = (sr->uri_processed.len) - offset; } if (limit + offset >= (user_len)) { return -1; } memcpy(user, sr->uri_processed.data + offset, limit); user[limit] = '\0'; MK_TRACE("user: '******'", user); /* Check system user */ if ((s_user = getpwnam(user)) == NULL) { mk_request_error(MK_CLIENT_NOT_FOUND, cs, sr); return -1; } if (sr->uri_processed.len > (unsigned int) (offset+limit)) { user_uri = mk_mem_malloc(sr->uri_processed.len); if (!user_uri) { return -1; } memcpy(user_uri, sr->uri_processed.data + (offset + limit), sr->uri_processed.len - offset - limit); user_uri[sr->uri_processed.len - offset - limit] = '\0'; mk_string_build(&sr->real_path.data, &sr->real_path.len, "%s/%s%s", s_user->pw_dir, config->user_dir, user_uri); mk_mem_free(user_uri); } else { mk_string_build(&sr->real_path.data, &sr->real_path.len, "%s/%s", s_user->pw_dir, config->user_dir); } sr->user_home = MK_TRUE; return 0; }
/* If the URI contains hexa format characters it will return * convert the Hexa values to ASCII character */ char *mk_utils_url_decode(mk_ptr_t uri) { int tmp, hex_result; unsigned int i; int buf_idx = 0; char *buf; char hex[3]; if ((tmp = mk_string_char_search(uri.data, '%', uri.len)) < 0) { return NULL; } i = tmp; buf = mk_mem_malloc_z(uri.len); if (i > 0) { strncpy(buf, uri.data, i); buf_idx = i; } while (i < uri.len) { if (uri.data[i] == '%' && i + 2 < uri.len) { memset(hex, '\0', sizeof(hex)); strncpy(hex, uri.data + i + 1, 2); hex[2] = '\0'; hex_result = mk_utils_hex2int(hex, 2); if (hex_result != -1) { buf[buf_idx] = hex_result; } else { mk_mem_free(buf); return NULL; } i += 2; } else { buf[buf_idx] = uri.data[i]; } i++; buf_idx++; } buf[buf_idx] = '\0'; return buf; }
int mk_http_method_get(char *body) { int int_method, pos = 0; int max_len_method = 8; mk_ptr_t method; /* Max method length is 7 (GET/POST/HEAD/PUT/DELETE/OPTIONS) */ pos = mk_string_char_search(body, ' ', max_len_method); if (mk_unlikely(pos <= 2 || pos >= max_len_method)) { return MK_HTTP_METHOD_UNKNOWN; } method.data = body; method.len = (unsigned long) pos; int_method = mk_http_method_check(method); return int_method; }
int mk_http_method_get(char *body) { int int_method, pos = 0; int max_len_method = 7; mk_pointer method; /* Max method length is 6 (GET/POST/HEAD/PUT/DELETE) */ pos = mk_string_char_search(body, ' ', 7); if (pos <= 2 || pos >= max_len_method) { return HTTP_METHOD_UNKNOWN; } method.data = body; method.len = (unsigned long) pos; int_method = mk_http_method_check(method); return int_method; }
static int mk_http_range_parse(struct session_request *sr) { int eq_pos, sep_pos, len; char *buffer = 0; struct response_headers *sh; if (!sr->range.data) return -1; if ((eq_pos = mk_string_char_search(sr->range.data, '=', sr->range.len)) < 0) return -1; if (strncasecmp(sr->range.data, "Bytes", eq_pos) != 0) return -1; if ((sep_pos = mk_string_char_search(sr->range.data, '-', sr->range.len)) < 0) return -1; len = sr->range.len; sh = &sr->headers; /* =-xxx */ if (eq_pos + 1 == sep_pos) { sh->ranges[0] = -1; sh->ranges[1] = (unsigned long) atol(sr->range.data + sep_pos + 1); if (sh->ranges[1] <= 0) { return -1; } sh->content_length = sh->ranges[1]; return 0; } /* =yyy-xxx */ if ((eq_pos + 1 != sep_pos) && (len > sep_pos + 1)) { buffer = mk_string_copy_substr(sr->range.data, eq_pos + 1, sep_pos); sh->ranges[0] = (unsigned long) atol(buffer); mk_mem_free(buffer); buffer = mk_string_copy_substr(sr->range.data, sep_pos + 1, len); sh->ranges[1] = (unsigned long) atol(buffer); mk_mem_free(buffer); if (sh->ranges[1] < 0 || (sh->ranges[0] > sh->ranges[1])) { return -1; } sh->content_length = abs(sh->ranges[1] - sh->ranges[0]) + 1; return 0; } /* =yyy- */ if ((eq_pos + 1 != sep_pos) && (len == sep_pos + 1)) { buffer = mk_string_copy_substr(sr->range.data, eq_pos + 1, len); sr->headers.ranges[0] = (unsigned long) atol(buffer); mk_mem_free(buffer); sh->content_length = (sh->content_length - sh->ranges[0]); return 0; } return -1; }
/* Return a struct with method, URI , protocol version and all static headers defined here sent in request */ static int mk_request_header_process(struct session_request *sr) { int uri_init = 0, uri_end = 0; int query_init = 0; int prot_init = 0, prot_end = 0, pos_sep = 0; int fh_limit; char *headers; char *temp = 0; mk_ptr_t host; /* Method */ sr->method_p = mk_http_method_check_str(sr->method); /* Request URI */ temp = index(sr->body.data, ' '); if (mk_unlikely(!temp)) { MK_TRACE("Error, invalid first header"); return -1; } uri_init = (temp - sr->body.data) + 1; temp = index(sr->body.data, '\n'); if (mk_unlikely(!temp)) { MK_TRACE("Error, invalid header CRLF"); return -1; } fh_limit = (temp - sr->body.data); uri_end = mk_string_char_search_r(sr->body.data, ' ', fh_limit) - 1; if (mk_unlikely(uri_end <= 0)) { MK_TRACE("Error, first header bad formed"); return -1; } prot_init = uri_end + 2; if (mk_unlikely(uri_end < uri_init)) { return -1; } /* Query String */ query_init = mk_string_char_search(sr->body.data + uri_init, '?', prot_init); if (query_init > 0) { int init, end; init = query_init + uri_init; if (init <= uri_end) { end = uri_end; uri_end = init - 1; sr->query_string = mk_ptr_create(sr->body.data, init + 1, end + 1); } } /* Request URI Part 2 */ sr->uri = mk_ptr_create(sr->body.data, uri_init, uri_end + 1); if (mk_unlikely(sr->uri.len < 1)) { return -1; } /* HTTP Version */ prot_end = fh_limit - 1; if (mk_unlikely(prot_init == prot_end)) { return -1; } if (prot_end != prot_init && prot_end > 0) { sr->protocol = mk_http_protocol_check(sr->body.data + prot_init, prot_end - prot_init); sr->protocol_p = mk_http_protocol_check_str(sr->protocol); } headers = sr->body.data + prot_end + mk_crlf.len; /* * Process URI, if it contains ASCII encoded strings like '%20', * it will return a new memory buffer with the decoded string, otherwise * it returns NULL */ temp = mk_utils_url_decode(sr->uri); if (temp) { sr->uri_processed.data = temp; sr->uri_processed.len = strlen(temp); } else { sr->uri_processed.data = sr->uri.data; sr->uri_processed.len = sr->uri.len; } /* Creating Table of Content (index) for HTTP headers */ sr->headers_len = sr->body.len - (prot_end + mk_crlf.len); if (mk_request_header_toc_parse(&sr->headers_toc, headers, sr->headers_len) < 0) { MK_TRACE("Invalid headers"); return -1; } /* Host */ host = mk_request_header_get(&sr->headers_toc, mk_rh_host.data, mk_rh_host.len); if (host.data) { if ((pos_sep = mk_string_char_search_r(host.data, ':', host.len)) >= 0) { /* TCP port should not be higher than 65535 */ char *p; short int port_len, port_size = 6; char port[port_size]; /* just the host */ sr->host.data = host.data; sr->host.len = pos_sep; /* including the port */ sr->host_port = host; /* Port string length */ port_len = (host.len - pos_sep - 1); if (port_len >= port_size) { return -1; } /* Copy to buffer */ memcpy(port, host.data + pos_sep + 1, port_len); port[port_len] = '\0'; /* Validate that the input port is numeric */ p = port; while (*p) { if (!isdigit(*p)) return -1; p++; } /* Convert to base 10 */ errno = 0; sr->port = strtol(port, (char **) NULL, 10); if ((errno == ERANGE && (sr->port == LONG_MAX || sr->port == LONG_MIN)) || sr->port == 0) { return -1; } } else { sr->host = host; /* maybe null */ sr->port = config->standard_port; } } else { sr->host.data = NULL; } /* Looking for headers that ONLY Monkey uses */ sr->connection = mk_request_header_get(&sr->headers_toc, mk_rh_connection.data, mk_rh_connection.len); sr->range = mk_request_header_get(&sr->headers_toc, mk_rh_range.data, mk_rh_range.len); sr->if_modified_since = mk_request_header_get(&sr->headers_toc, mk_rh_if_modified_since.data, mk_rh_if_modified_since.len); /* Default Keepalive is off */ if (sr->protocol == MK_HTTP_PROTOCOL_10) { sr->keep_alive = MK_FALSE; sr->close_now = MK_TRUE; } else if(sr->protocol == MK_HTTP_PROTOCOL_11) { sr->keep_alive = MK_TRUE; sr->close_now = MK_FALSE; } if (sr->connection.data) { if (mk_string_search_n(sr->connection.data, "Keep-Alive", MK_STR_INSENSITIVE, sr->connection.len) >= 0) { sr->keep_alive = MK_TRUE; sr->close_now = MK_FALSE; } else if (mk_string_search_n(sr->connection.data, "Close", MK_STR_INSENSITIVE, sr->connection.len) >= 0) { sr->keep_alive = MK_FALSE; sr->close_now = MK_TRUE; } else { /* Set as a non-valid connection header value */ sr->connection.len = 0; } } return 0; }