Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
/* It parse data sent by POST or PUT methods */
int mk_method_parse_data(struct client_session *cs, struct session_request *sr)
{
    mk_pointer tmp;
    long content_length_post = 0;

    content_length_post = mk_method_validate_content_length(cs->body, cs->body_length);

    /* Length Required */
    if (content_length_post == -1) {
        mk_request_error(MK_CLIENT_LENGTH_REQUIRED, cs, sr);
        return -1;
    }

    /* Bad request */
    if (content_length_post <= 0) {
        mk_request_error(MK_CLIENT_BAD_REQUEST, cs, sr);
        return -1;
    }

    /* Content length too large */
    if (content_length_post >= cs->body_size) {
        mk_request_error(MK_CLIENT_REQUEST_ENTITY_TOO_LARGE, cs, sr);
        return -1;
    }

    tmp = mk_request_header_get(&sr->headers_toc, 
                                mk_rh_content_type.data,
                                mk_rh_content_type.len);
    if (!tmp.data) {
        mk_request_error(MK_CLIENT_BAD_REQUEST, cs, sr);
        return -1;
    }
    sr->content_type = tmp;
    sr->content_length = content_length_post;

    return 0;
}
Ejemplo n.º 3
0
int mk_http_init(struct client_session *cs, struct session_request *sr)
{
    int ret;
    int bytes = 0;
    struct mimetype *mime;

    MK_TRACE("HTTP Protocol Init");

    /* Request to root path of the virtualhost in question */
    if (sr->uri_processed.len == 1 && sr->uri_processed.data[0] == '/') {
        sr->real_path.data = sr->host_conf->documentroot.data;
        sr->real_path.len = sr->host_conf->documentroot.len;
    }

    /* Compose real path */
    if (sr->user_home == MK_FALSE) {
        int len;

        len = sr->host_conf->documentroot.len + sr->uri_processed.len;
        if (len < MK_PATH_BASE) {
            memcpy(sr->real_path_static,
                   sr->host_conf->documentroot.data,
                   sr->host_conf->documentroot.len);
            memcpy(sr->real_path_static + sr->host_conf->documentroot.len,
                   sr->uri_processed.data,
                   sr->uri_processed.len);
            sr->real_path_static[len] = '\0';
            sr->real_path.data = sr->real_path_static;
            sr->real_path.len = len;
        }
        else {
            ret = mk_buffer_cat(&sr->real_path,
                                sr->host_conf->documentroot.data,
                                sr->host_conf->documentroot.len,
                                sr->uri_processed.data,
                                sr->uri_processed.len);

            if (ret < 0) {
                MK_TRACE("Error composing real path");
                return EXIT_ERROR;
            }
        }
    }

    /* Check backward directory request */
    if (memmem(sr->uri_processed.data, sr->uri_processed.len,
               MK_HTTP_DIRECTORY_BACKWARD,
               sizeof(MK_HTTP_DIRECTORY_BACKWARD) - 1)) {
        return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr);
    }


    if (mk_file_get_info(sr->real_path.data, &sr->file_info) != 0) {
        /* if the requested resource doesn't exist,
         * check if some plugin would like to handle it
         */
        MK_TRACE("No file, look for handler plugin");
        ret = mk_plugin_stage_run(MK_PLUGIN_STAGE_30, cs->socket, NULL, cs, sr);
        if (ret == MK_PLUGIN_RET_CLOSE_CONX) {
            if (sr->headers.status > 0) {
                return mk_request_error(sr->headers.status, cs, sr);
            }
            else {
                return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr);
            }
        }
        else if (ret == MK_PLUGIN_RET_CONTINUE) {
            return MK_PLUGIN_RET_CONTINUE;
        }
        else if (ret == MK_PLUGIN_RET_END) {
            return EXIT_NORMAL;
        }

        if (sr->file_info.exists == MK_FALSE) {
            return mk_request_error(MK_CLIENT_NOT_FOUND, cs, sr);
        }
        else if (sr->stage30_blocked == MK_FALSE) {
            return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr);
        }
    }

    /* is it a valid directory ? */
    if (sr->file_info.is_directory == MK_TRUE) {
        /* Send redirect header if end slash is not found */
        if (mk_http_directory_redirect_check(cs, sr) == -1) {
            MK_TRACE("Directory Redirect");

            /* Redirect has been sent */
            return -1;
        }

        /* looking for an index file */
        mk_ptr_t index_file;
        char tmppath[MK_MAX_PATH];
        index_file = mk_request_index(sr->real_path.data, tmppath, MK_MAX_PATH);

        if (index_file.data) {
            if (sr->real_path.data != sr->real_path_static) {
                mk_ptr_t_free(&sr->real_path);
                sr->real_path = index_file;
                sr->real_path.data = mk_string_dup(index_file.data);
            }
            /* If it's static and it still fits */
            else if (index_file.len < MK_PATH_BASE) {
                memcpy(sr->real_path_static, index_file.data, index_file.len);
                sr->real_path_static[index_file.len] = '\0';
                sr->real_path.len = index_file.len;
            }
            /* It was static, but didn't fit */
            else {
                sr->real_path = index_file;
                sr->real_path.data = mk_string_dup(index_file.data);
            }

            mk_file_get_info(sr->real_path.data, &sr->file_info);
        }
    }

    /* Check symbolic link file */
    if (sr->file_info.is_link == MK_TRUE) {
        if (config->symlink == MK_FALSE) {
            return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr);
        }
        else {
            int n;
            char linked_file[MK_MAX_PATH];
            n = readlink(sr->real_path.data, linked_file, MK_MAX_PATH);
            if (n < 0) {
                return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr);
            }
        }
    }

    /* Plugin Stage 30: look for handlers for this request */
    if (sr->stage30_blocked == MK_FALSE) {
        ret  = mk_plugin_stage_run(MK_PLUGIN_STAGE_30, cs->socket, NULL, cs, sr);
        MK_TRACE("[FD %i] STAGE_30 returned %i", cs->socket, ret);
        switch (ret) {
        case MK_PLUGIN_RET_CONTINUE:
            return MK_PLUGIN_RET_CONTINUE;
        case MK_PLUGIN_RET_CLOSE_CONX:
            if (sr->headers.status > 0) {
                return mk_request_error(sr->headers.status, cs, sr);
            }
            else {
                return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr);
            }
        case MK_PLUGIN_RET_END:
            return EXIT_NORMAL;
        }
    }

    /*
     * Monkey listens for PUT and DELETE methods in addition to GET, POST and
     * HEAD, but it does not care about them, so if any plugin did not worked
     * on it, Monkey will return error 501 (501 Not Implemented).
     */
    if (sr->method == MK_HTTP_METHOD_PUT || sr->method == MK_HTTP_METHOD_DELETE ||
            sr->method == MK_HTTP_METHOD_UNKNOWN) {
        return mk_request_error(MK_SERVER_NOT_IMPLEMENTED, cs, sr);
    }

    /* counter connections */
    sr->headers.pconnections_left = (int)
                                    (config->max_keep_alive_request - cs->counter_connections);

    /* Set default value */
    mk_header_set_http_status(sr, MK_HTTP_OK);
    sr->headers.location = NULL;
    sr->headers.content_length = 0;

    /*
     * For OPTIONS method, we let the plugin handle it and
     * return without any content.
     */
    if (sr->method == MK_HTTP_METHOD_OPTIONS) {
        sr->headers.allow_methods.data = MK_HTTP_METHOD_AVAILABLE;
        sr->headers.allow_methods.len = strlen(MK_HTTP_METHOD_AVAILABLE);

        mk_ptr_t_reset(&sr->headers.content_type);
        mk_header_send(cs->socket, cs, sr);
        return EXIT_NORMAL;
    }
    else {
        mk_ptr_t_reset(&sr->headers.allow_methods);
    }

    /* read permissions and check file */
    if (sr->file_info.read_access == MK_FALSE) {
        return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr);
    }

    /* Matching MimeType  */
    mime = mk_mimetype_find(&sr->real_path);
    if (!mime) {
        mime = mimetype_default;
    }

    if (sr->file_info.is_directory == MK_TRUE) {
        return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr);
    }

    /* get file size */
    if (sr->file_info.size < 0) {
        return mk_request_error(MK_CLIENT_NOT_FOUND, cs, sr);
    }

    sr->headers.last_modified = sr->file_info.last_modification;

    if (sr->if_modified_since.data && sr->method == MK_HTTP_METHOD_GET) {
        time_t date_client;       /* Date sent by client */
        time_t date_file_server;  /* Date server file */

        date_client = mk_utils_gmt2utime(sr->if_modified_since.data);
        date_file_server = sr->file_info.last_modification;

        if (date_file_server <= date_client && date_client > 0 &&
                date_client <= log_current_utime) {

            mk_header_set_http_status(sr, MK_NOT_MODIFIED);
            mk_header_send(cs->socket, cs, sr);
            return EXIT_NORMAL;
        }
    }

    /* Object size for log and response headers */
    sr->headers.content_length = sr->file_info.size;
    sr->headers.real_length = sr->file_info.size;

    /* Open file */
    if (mk_likely(sr->file_info.size > 0)) {
        sr->fd_file = mk_vhost_open(sr);
        if (sr->fd_file == -1) {
            MK_TRACE("open() failed");
            return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr);
        }
        sr->bytes_to_send = sr->file_info.size;
    }

    /* Process methods */
    if (sr->method == MK_HTTP_METHOD_GET || sr->method == MK_HTTP_METHOD_HEAD) {
        sr->headers.content_type = mime->type;

        /* HTTP Ranges */
        if (sr->range.data != NULL && config->resume == MK_TRUE) {
            if (mk_http_range_parse(sr) < 0) {
                sr->headers.ranges[0] = -1;
                sr->headers.ranges[1] = -1;
                return mk_request_error(MK_CLIENT_BAD_REQUEST, cs, sr);
            }
            if (sr->headers.ranges[0] >= 0 || sr->headers.ranges[1] >= 0) {
                mk_header_set_http_status(sr, MK_HTTP_PARTIAL);
            }

            /* Calc bytes to send & offset */
            if (mk_http_range_set(sr, sr->file_info.size) != 0) {
                sr->headers.content_length = -1;
                sr->headers.ranges[0] = -1;
                sr->headers.ranges[1] = -1;
                return mk_request_error(MK_CLIENT_REQUESTED_RANGE_NOT_SATISF, cs, sr);
            }
        }
    }
    else {
        /* without content-type */
        mk_ptr_t_reset(&sr->headers.content_type);
    }

    /* Send headers */
    mk_header_send(cs->socket, cs, sr);

    if (mk_unlikely(sr->headers.content_length == 0)) {
        return 0;
    }

    /* Send file content */
    if (sr->method == MK_HTTP_METHOD_GET || sr->method == MK_HTTP_METHOD_POST) {
        bytes = mk_http_send_file(cs, sr);
    }

    return bytes;
}