diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 13:19:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 13:20:02 +0000 |
commit | 58daab21cd043e1dc37024a7f99b396788372918 (patch) | |
tree | 96771e43bb69f7c1c2b0b4f7374cb74d7866d0cb /fluent-bit/lib/monkey/plugins/auth | |
parent | Releasing debian version 1.43.2-1. (diff) | |
download | netdata-58daab21cd043e1dc37024a7f99b396788372918.tar.xz netdata-58daab21cd043e1dc37024a7f99b396788372918.zip |
Merging upstream version 1.44.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'fluent-bit/lib/monkey/plugins/auth')
-rw-r--r-- | fluent-bit/lib/monkey/plugins/auth/ABOUT | 2 | ||||
-rw-r--r-- | fluent-bit/lib/monkey/plugins/auth/CMakeLists.txt | 10 | ||||
-rw-r--r-- | fluent-bit/lib/monkey/plugins/auth/OPTIONAL | 0 | ||||
-rw-r--r-- | fluent-bit/lib/monkey/plugins/auth/auth.c | 254 | ||||
-rw-r--r-- | fluent-bit/lib/monkey/plugins/auth/auth.h | 106 | ||||
-rw-r--r-- | fluent-bit/lib/monkey/plugins/auth/base64.c | 172 | ||||
-rw-r--r-- | fluent-bit/lib/monkey/plugins/auth/base64.h | 11 | ||||
-rw-r--r-- | fluent-bit/lib/monkey/plugins/auth/conf.c | 244 | ||||
-rw-r--r-- | fluent-bit/lib/monkey/plugins/auth/conf.h | 25 | ||||
-rw-r--r-- | fluent-bit/lib/monkey/plugins/auth/sha1.c | 288 | ||||
-rw-r--r-- | fluent-bit/lib/monkey/plugins/auth/sha1.h | 22 | ||||
-rw-r--r-- | fluent-bit/lib/monkey/plugins/auth/tools/CMakeLists.txt | 15 | ||||
-rw-r--r-- | fluent-bit/lib/monkey/plugins/auth/tools/mk_passwd.c | 209 |
13 files changed, 1358 insertions, 0 deletions
diff --git a/fluent-bit/lib/monkey/plugins/auth/ABOUT b/fluent-bit/lib/monkey/plugins/auth/ABOUT new file mode 100644 index 000000000..66a5384c3 --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/auth/ABOUT @@ -0,0 +1,2 @@ +HTTP Basic Authentication +========================= diff --git a/fluent-bit/lib/monkey/plugins/auth/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/auth/CMakeLists.txt new file mode 100644 index 000000000..a6fd27a06 --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/auth/CMakeLists.txt @@ -0,0 +1,10 @@ +set(src + auth.c + base64.c + conf.c + sha1.c + ) + +add_subdirectory(tools) + +MONKEY_PLUGIN(auth "${src}") diff --git a/fluent-bit/lib/monkey/plugins/auth/OPTIONAL b/fluent-bit/lib/monkey/plugins/auth/OPTIONAL new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/auth/OPTIONAL diff --git a/fluent-bit/lib/monkey/plugins/auth/auth.c b/fluent-bit/lib/monkey/plugins/auth/auth.c new file mode 100644 index 000000000..b0f983bfb --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/auth/auth.c @@ -0,0 +1,254 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Monkey HTTP Server + * ================== + * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <monkey/mk_api.h> + +#include <sys/stat.h> + +#include "auth.h" +#include "conf.h" +#include "sha1.h" +#include "base64.h" + +static int mk_auth_validate_user(struct users_file *users, + const char *credentials, unsigned int len) +{ + int sep; + size_t auth_len; + unsigned char *decoded = NULL; + unsigned char digest[SHA1_DIGEST_LEN]; + struct mk_list *head; + struct user *entry; + + SHA_CTX sha; /* defined in sha1/sha1.h */ + + /* Validate value length */ + if (len <= auth_header_basic.len + 1) { + return -1; + } + + /* Validate 'basic' credential type */ + if (strncmp(credentials, auth_header_basic.data, + auth_header_basic.len) != 0) { + return -1; + } + + /* Decode credentials: incoming credentials comes in base64 encode */ + decoded = base64_decode((unsigned char *) credentials + auth_header_basic.len, + len - auth_header_basic.len, + &auth_len); + if (decoded == NULL) { + PLUGIN_TRACE("Failed to decode credentials."); + goto error; + } + + if (auth_len <= 3) { + goto error; + } + + sep = mk_api->str_search_n((char *) decoded, ":", 1, auth_len); + if (sep == -1 || sep == 0 || (unsigned int) sep == auth_len - 1) { + goto error; + } + + /* Get SHA1 hash */ + SHA1_Init(&sha); + SHA1_Update(&sha, (unsigned char *) decoded + sep + 1, auth_len - (sep + 1)); + SHA1_Final(digest, &sha); + + mk_list_foreach(head, &users->_users) { + entry = mk_list_entry(head, struct user, _head); + /* match user */ + if (strlen(entry->user) != (unsigned int) sep) { + continue; + } + if (strncmp(entry->user, (char *) decoded, sep) != 0) { + continue; + } + + PLUGIN_TRACE("User match '%s'", entry->user); + + /* match password */ + if (memcmp(entry->passwd_decoded, digest, SHA1_DIGEST_LEN) == 0) { + PLUGIN_TRACE("User '%s' matched password", entry->user); + mk_api->mem_free(decoded); + return 0; + } + PLUGIN_TRACE("Invalid password"); + break; + } + + error: + if (decoded) { + mk_api->mem_free(decoded); + } + return -1; +} + +int mk_auth_plugin_init(struct plugin_api **api, char *confdir) +{ + (void) confdir; + + mk_api = *api; + + /* Init and load global users list */ + mk_list_init(&vhosts_list); + mk_list_init(&users_file_list); + mk_auth_conf_init_users_list(); + + /* Set HTTP headers key */ + auth_header_basic.data = MK_AUTH_HEADER_BASIC; + auth_header_basic.len = sizeof(MK_AUTH_HEADER_BASIC) - 1; + + return 0; +} + +int mk_auth_plugin_exit() +{ + return 0; +} + +void mk_auth_worker_init() +{ + char *user; + + /* Init thread buffer for given credentials */ + user = mk_api->mem_alloc(MK_AUTH_CREDENTIALS_LEN - 1); + pthread_setspecific(_mkp_data, (void *) user); +} + +/* Object handler */ +int mk_auth_stage30(struct mk_plugin *plugin, + struct mk_http_session *cs, + struct mk_http_request *sr, + int n_params, + struct mk_list *params) +{ + int val; + short int is_restricted = MK_FALSE; + struct mk_list *vh_head; + struct mk_list *loc_head; + struct vhost *vh_entry = NULL; + struct location *loc_entry; + struct mk_http_header *header; + (void) plugin; + (void) n_params; + (void) params; + + PLUGIN_TRACE("[FD %i] Handler received request"); + + /* Match auth_vhost with global vhost */ + mk_list_foreach(vh_head, &vhosts_list) { + vh_entry = mk_list_entry(vh_head, struct vhost, _head); + if (vh_entry->host == sr->host_conf) { + PLUGIN_TRACE("[FD %i] host matched %s", + cs->socket, + mk_api->config->server_signature); + break; + } + } + + if (!vh_entry) { + return MK_PLUGIN_RET_NOT_ME; + } + + /* Check vhost locations */ + mk_list_foreach(loc_head, &vh_entry->locations) { + loc_entry = mk_list_entry(loc_head, struct location, _head); + if (sr->uri_processed.len < loc_entry->path.len) { + continue; + } + if (strncmp(sr->uri_processed.data, + loc_entry->path.data, loc_entry->path.len) == 0) { + is_restricted = MK_TRUE; + PLUGIN_TRACE("[FD %i] Location matched %s", + cs->socket, + loc_entry->path.data); + break; + } + } + + /* For non-restricted location do not take any action, just returns */ + if (is_restricted == MK_FALSE) { + return MK_PLUGIN_RET_NOT_ME; + } + + /* Check authorization header */ + header = mk_api->header_get(MK_HEADER_AUTHORIZATION, + sr, NULL, 0); + + if (header) { + /* Validate user */ + val = mk_auth_validate_user(loc_entry->users, + header->val.data, header->val.len); + if (val == 0) { + /* user validated, success */ + PLUGIN_TRACE("[FD %i] user validated!", cs->socket); + return MK_PLUGIN_RET_NOT_ME; + } + } + + /* Restricted access: requires auth */ + PLUGIN_TRACE("[FD %i] unauthorized user, credentials required", + cs->socket); + + sr->headers.content_length = 0; + mk_api->header_set_http_status(sr, MK_CLIENT_UNAUTH); + mk_api->header_add(sr, + loc_entry->auth_http_header.data, + loc_entry->auth_http_header.len); + + mk_api->header_prepare(plugin, cs, sr); + return MK_PLUGIN_RET_END; +} + +int mk_auth_stage30_hangup(struct mk_plugin *plugin, + struct mk_http_session *cs, + struct mk_http_request *sr) +{ + (void) plugin; + (void) cs; + (void) sr; + + return 0; +} + +struct mk_plugin_stage mk_plugin_stage_auth = { + .stage30 = &mk_auth_stage30, + .stage30_hangup = &mk_auth_stage30_hangup +}; + +struct mk_plugin mk_plugin_auth = { + /* Identification */ + .shortname = "auth", + .name = "Basic Authentication", + .version = MK_VERSION_STR, + .hooks = MK_PLUGIN_STAGE, + + /* Init / Exit */ + .init_plugin = mk_auth_plugin_init, + .exit_plugin = mk_auth_plugin_exit, + + /* Init Levels */ + .master_init = NULL, + .worker_init = mk_auth_worker_init, + + /* Type */ + .stage = &mk_plugin_stage_auth +}; diff --git a/fluent-bit/lib/monkey/plugins/auth/auth.h b/fluent-bit/lib/monkey/plugins/auth/auth.h new file mode 100644 index 000000000..f6eebe83e --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/auth/auth.h @@ -0,0 +1,106 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Monkey HTTP Server + * ================== + * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MK_AUTH_H +#define MK_AUTH_H + +#include <monkey/mk_api.h> + +/* Header stuff */ +#define MK_AUTH_HEADER_BASIC "Basic " +#define MK_AUTH_HEADER_TITLE "WWW-Authenticate: Basic realm=\"%s\"" + +/* Credentials length */ +#define MK_AUTH_CREDENTIALS_LEN 256 + +/* + * The plugin hold one struct per virtual host and link to the + * locations and users file associated: + * + * +---------------------------------+ + * struct vhost > vhost (1:N) | + * | +---------+----------+ | + * | | | | | + * struct location > location location location | + * | | | | | + * | +----+----+ + | + * | | | | + * struct users > users users | + * +---------------------------------+ + * + */ + +/* List of virtual hosts to handle locations */ +struct mk_list vhosts_list; + +/* main index for locations under a virtualhost */ +struct vhost { + struct mk_vhost *host; + struct mk_list locations; + struct mk_list _head; +}; + +/* + * A location restrict a filesystem path with a list + * of allowed users + */ +struct location { + mk_ptr_t path; + mk_ptr_t title; + mk_ptr_t auth_http_header; + + struct users_file *users; + struct mk_list _head; +}; + +/* Head index for user files list */ +struct mk_list users_file_list; + +/* + * Represents a users file, each entry represents a physical + * file and belongs to a node of the users_file_list list + */ +struct users_file { + time_t last_updated; /* last time this entry was modified */ + char *path; /* file path */ + struct mk_list _users; /* list of users */ + struct mk_list _head; /* head for main mk_list users_file_list */ +}; + +/* + * a list of users, this list belongs to a + * struct location + */ +struct user { + char user[128]; + char passwd_raw[256]; + unsigned char *passwd_decoded; + + struct mk_list _head; +}; + +struct mk_list users_file_list; + +/* Thread key */ +mk_ptr_t auth_header_request; +mk_ptr_t auth_header_basic; + +#define SHA1_DIGEST_LEN 20 + +#endif diff --git a/fluent-bit/lib/monkey/plugins/auth/base64.c b/fluent-bit/lib/monkey/plugins/auth/base64.c new file mode 100644 index 000000000..e3149fe73 --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/auth/base64.c @@ -0,0 +1,172 @@ +/* + * Base64 encoding/decoding (RFC1341) + * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifdef _FORCE_SYSMALLOC +#undef MALLOC_JEMALLOC +#endif + +#include <monkey/mk_api.h> +#include "base64.h" + +#if defined(MALLOC_JEMALLOC) +#define __mem_alloc mk_api->mem_alloc +#define __mem_free mk_api->mem_free +#else +#define __mem_alloc malloc +#define __mem_free free +#endif + +static const unsigned char base64_table[65] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/** + * base64_encode - Base64 encode + * @src: Data to be encoded + * @len: Length of the data to be encoded + * @out_len: Pointer to output length variable, or %NULL if not used + * Returns: Allocated buffer of out_len bytes of encoded data, + * or %NULL on failure + * + * Caller is responsible for freeing the returned buffer. Returned buffer is + * nul terminated to make it easier to use as a C string. The nul terminator is + * not included in out_len. + */ +unsigned char * base64_encode(const unsigned char *src, size_t len, + size_t *out_len) +{ + unsigned char *out, *pos; + const unsigned char *end, *in; + size_t olen; + int line_len; + + olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ + olen += olen / 72; /* line feeds */ + olen++; /* nul termination */ + if (olen < len) + return NULL; /* integer overflow */ + if (mk_api != NULL) { + out = __mem_alloc(olen); + } + else { + out = __mem_alloc(olen); + } + + if (out == NULL) + return NULL; + + end = src + len; + in = src; + pos = out; + line_len = 0; + while (end - in >= 3) { + *pos++ = base64_table[in[0] >> 2]; + *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; + *pos++ = base64_table[in[2] & 0x3f]; + in += 3; + line_len += 4; + if (line_len >= 72) { + *pos++ = '\n'; + line_len = 0; + } + } + + if (end - in) { + *pos++ = base64_table[in[0] >> 2]; + if (end - in == 1) { + *pos++ = base64_table[(in[0] & 0x03) << 4]; + *pos++ = '='; + } else { + *pos++ = base64_table[((in[0] & 0x03) << 4) | + (in[1] >> 4)]; + *pos++ = base64_table[(in[1] & 0x0f) << 2]; + } + *pos++ = '='; + line_len += 4; + } + + if (line_len) + *pos++ = '\n'; + + *pos = '\0'; + if (out_len) + *out_len = pos - out; + return out; +} + + +/** + * base64_decode - Base64 decode + * @src: Data to be decoded + * @len: Length of the data to be decoded + * @out_len: Pointer to output length variable + * Returns: Allocated buffer of out_len bytes of decoded data, + * or %NULL on failure + * + * Caller is responsible for freeing the returned buffer. + */ +unsigned char * base64_decode(const unsigned char *src, size_t len, + size_t *out_len) +{ + unsigned char dtable[256], *out, *pos, block[4], tmp; + size_t i, count, olen; + int pad = 0; + + memset(dtable, 0x80, 256); + for (i = 0; i < sizeof(base64_table) - 1; i++) + dtable[base64_table[i]] = (unsigned char) i; + dtable['='] = 0; + + count = 0; + for (i = 0; i < len; i++) { + if (dtable[src[i]] != 0x80) + count++; + } + + if (count == 0 || count % 4) + return NULL; + + olen = (count / 4 * 3) + 1; + pos = out = __mem_alloc(olen); + if (out == NULL) + return NULL; + + count = 0; + for (i = 0; i < len; i++) { + tmp = dtable[src[i]]; + if (tmp == 0x80) + continue; + + if (src[i] == '=') + pad++; + block[count] = tmp; + count++; + if (count == 4) { + *pos++ = (block[0] << 2) | (block[1] >> 4); + *pos++ = (block[1] << 4) | (block[2] >> 2); + *pos++ = (block[2] << 6) | block[3]; + count = 0; + if (pad) { + if (pad == 1) + pos--; + else if (pad == 2) + pos -= 2; + else { + /* Invalid padding */ + __mem_free(out); + return NULL; + } + break; + } + } + } + *pos = '\0'; + + *out_len = pos - out; + return out; +} diff --git a/fluent-bit/lib/monkey/plugins/auth/base64.h b/fluent-bit/lib/monkey/plugins/auth/base64.h new file mode 100644 index 000000000..45001d47f --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/auth/base64.h @@ -0,0 +1,11 @@ +#ifndef AUTH_BASE64_H +#define AUTH_BASE64_H + + +unsigned char * base64_encode(const unsigned char *src, size_t len, + size_t *out_len); +unsigned char *base64_decode(const unsigned char *src, size_t len, + size_t *out_len); + + +#endif diff --git a/fluent-bit/lib/monkey/plugins/auth/conf.c b/fluent-bit/lib/monkey/plugins/auth/conf.c new file mode 100644 index 000000000..6dede1dd4 --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/auth/conf.c @@ -0,0 +1,244 @@ + /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Monkey HTTP Server + * ================== + * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <monkey/mk_api.h> +#include "base64.h" +#include "auth.h" +#include "conf.h" + +/* + * Register a users file into the main list, if the users + * file already exists it just return the node in question, + * otherwise add the node to the list and return the node + * created. + */ +static struct users_file *mk_auth_conf_add_users(char *users_path) +{ + struct file_info finfo; + struct mk_list *head; + struct users_file *entry; + struct user *cred; + int i, sep, len; + int offset = 0; + size_t decoded_len; + char *buf; + + mk_list_foreach(head, &users_file_list) { + entry = mk_list_entry(head, struct users_file, _head); + if (strcmp(entry->path, users_path) == 0) { + return entry; + } + } + + if (mk_api->file_get_info(users_path, &finfo, MK_FILE_READ) != 0) { + mk_warn("Auth: Invalid users file '%s'", users_path); + return NULL; + } + + if (finfo.is_directory == MK_TRUE) { + mk_warn("Auth: Not a credentials file '%s'", users_path); + return NULL; + } + + if (finfo.read_access == MK_FALSE) { + mk_warn("Auth: Could not read file '%s'", users_path); + return NULL; + } + + /* We did not find the path in our list, let's create a new node */ + entry = mk_api->mem_alloc(sizeof(struct users_file)); + entry->last_updated = finfo.last_modification; + entry->path = users_path; + + /* Read file and add users to the list */ + mk_list_init(&entry->_users); + + /* Read credentials file */ + buf = mk_api->file_to_buffer(users_path); + if (!buf) { + mk_warn("Auth: No users loaded '%s'", users_path); + return NULL; + } + + /* Read users list buffer lines */ + len = strlen(buf); + for (i = 0; i < len; i++) { + if (buf[i] == '\n' || (i) == len -1) { + sep = mk_api->str_search(buf + offset, ":", 1); + + if (sep >= (int)sizeof(cred->user)) { + mk_warn("Auth: username too long"); + offset = i + 1; + continue; + } + if (i - offset - sep - 1 - 5 >= (int)sizeof(cred->passwd_raw)) { + mk_warn("Auth: password hash too long"); + offset = i + 1; + continue; + } + + cred = mk_api->mem_alloc(sizeof(struct user)); + + /* Copy username */ + strncpy(cred->user, buf + offset, sep); + cred->user[sep] = '\0'; + + /* Copy raw password */ + offset += sep + 1 + 5; + strncpy(cred->passwd_raw, + buf + offset, + i - (offset)); + cred->passwd_raw[i - offset] = '\0'; + + /* Decode raw password */ + cred->passwd_decoded = base64_decode((unsigned char *)(cred->passwd_raw), + strlen(cred->passwd_raw), + &decoded_len); + + offset = i + 1; + + if (!cred->passwd_decoded) { + mk_warn("Auth: invalid user '%s' in '%s'", + cred->user, users_path); + mk_api->mem_free(cred); + continue; + } + mk_list_add(&cred->_head, &entry->_users); + } + } + mk_api->mem_free(buf); + + /* Link node to global list */ + mk_list_add(&entry->_head, &users_file_list); + + return entry; +} + +/* + * Read all vhost configuration nodes and looks for users files under an [AUTH] + * section, if present, it add that file to the unique list. It parse all user's + * files mentioned to avoid duplicated lists in memory. + */ +int mk_auth_conf_init_users_list() +{ + /* Section data */ + char *location; + char *title; + char *users_path; + /* auth vhost list */ + struct vhost *auth_vhost; + + /* vhost configuration */ + struct mk_list *head_hosts; + struct mk_list *hosts = &mk_api->config->hosts; + struct mk_list *head_sections; + struct mk_vhost *entry_host; + struct mk_rconf_section *section; + + /* vhost [AUTH] locations */ + struct location *loc; + + /* User files list */ + struct users_file *uf; + + PLUGIN_TRACE("Loading user's files"); + + mk_list_foreach(head_hosts, hosts) { + entry_host = mk_list_entry(head_hosts, struct mk_vhost, _head); + if (!entry_host->config) { + continue; + } + + auth_vhost = mk_api->mem_alloc(sizeof(struct vhost)); + auth_vhost->host = entry_host; /* link virtual host entry */ + mk_list_init(&auth_vhost->locations); /* init locations list */ + + /* + * check vhost 'config' and look for [AUTH] sections, we don't use + * mk_config_section_get() because we can have multiple [AUTH] + * sections. + */ + mk_list_foreach(head_sections, &entry_host->config->sections) { + section = mk_list_entry(head_sections, struct mk_rconf_section, _head); + + if (strcasecmp(section->name, "AUTH") == 0) { + location = NULL; + title = NULL; + users_path = NULL; + + /* Get section keys */ + location = mk_api->config_section_get_key(section, + "Location", + MK_RCONF_STR); + title = mk_api->config_section_get_key(section, + "Title", + MK_RCONF_STR); + + users_path = mk_api->config_section_get_key(section, + "Users", + MK_RCONF_STR); + + /* get or create users file entry */ + uf = mk_auth_conf_add_users(users_path); + if (!uf) { + continue; + } + + /* Location node */ + loc = mk_api->mem_alloc(sizeof(struct location)); + mk_api->pointer_set(&loc->path, location); + mk_api->pointer_set(&loc->title, title); + + loc->auth_http_header.data = NULL; + mk_api->str_build(&loc->auth_http_header.data, + &loc->auth_http_header.len, + MK_AUTH_HEADER_TITLE, title); + + loc->users = uf; + + /* Add new location to auth_vhost node */ + mk_list_add(&loc->_head, &auth_vhost->locations); + } + } + + /* Link auth_vhost node to global list vhosts_list */ + mk_list_add(&auth_vhost->_head, &vhosts_list); + } + +#ifdef TRACE + struct mk_list *vh_head, *loc_head; + struct vhost *vh_entry; + struct location *loc_entry; + + mk_list_foreach(vh_head, &vhosts_list) { + vh_entry = mk_list_entry(vh_head, struct vhost, _head); + PLUGIN_TRACE("Auth VHost: %p", vh_entry->host); + + mk_list_foreach(loc_head, &vh_entry->locations) { + loc_entry = mk_list_entry(loc_head, struct location, _head); + PLUGIN_TRACE("---"); + PLUGIN_TRACE(" location: %s", loc_entry->path); + PLUGIN_TRACE(" title : %s", loc_entry->title); + PLUGIN_TRACE(" users : %s", loc_entry->users->path); + } + } +#endif + + return 0; +} diff --git a/fluent-bit/lib/monkey/plugins/auth/conf.h b/fluent-bit/lib/monkey/plugins/auth/conf.h new file mode 100644 index 000000000..90fd8f79a --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/auth/conf.h @@ -0,0 +1,25 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Monkey HTTP Server + * ================== + * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MK_AUTH_CONF_H +#define MK_AUTH_CONF_H + +int mk_auth_conf_init_users_list(); + +#endif diff --git a/fluent-bit/lib/monkey/plugins/auth/sha1.c b/fluent-bit/lib/monkey/plugins/auth/sha1.c new file mode 100644 index 000000000..53c7946e8 --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/auth/sha1.c @@ -0,0 +1,288 @@ +/* + * Code adapted to fill Monkey Project requirements, no big changes + * just a few header files added + */ + +#include <arpa/inet.h> +#include <string.h> + +/* + * SHA1 routine optimized to do word accesses rather than byte accesses, + * and to avoid unnecessary copies into the context array. + * + * This was initially based on the Mozilla SHA1 implementation, although + * none of the original Mozilla code remains. + */ + +#include "sha1.h" + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +/* + * Force usage of rol or ror by selecting the one with the smaller constant. + * It _can_ generate slightly smaller code (a constant of 1 is special), but + * perhaps more importantly it's possibly faster on any uarch that does a + * rotate with a loop. + */ + +#define SHA_ASM(op, x, n) ({ unsigned int __res; __asm__(op " %1,%0":"=r" (__res):"i" (n), "0" (x)); __res; }) +#define SHA_ROL(x,n) SHA_ASM("rol", x, n) +#define SHA_ROR(x,n) SHA_ASM("ror", x, n) + +#else + +#define SHA_ROT(X,l,r) (((X) << (l)) | ((X) >> (r))) +#define SHA_ROL(X,n) SHA_ROT(X,n,32-(n)) +#define SHA_ROR(X,n) SHA_ROT(X,32-(n),n) + +#endif + +/* + * If you have 32 registers or more, the compiler can (and should) + * try to change the array[] accesses into registers. However, on + * machines with less than ~25 registers, that won't really work, + * and at least gcc will make an unholy mess of it. + * + * So to avoid that mess which just slows things down, we force + * the stores to memory to actually happen (we might be better off + * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as + * suggested by Artur Skawina - that will also make gcc unable to + * try to do the silly "optimize away loads" part because it won't + * see what the value will be). + * + * Ben Herrenschmidt reports that on PPC, the C version comes close + * to the optimized asm with this (ie on PPC you don't want that + * 'volatile', since there are lots of registers). + * + * On ARM we get the best code generation by forcing a full memory barrier + * between each SHA_ROUND, otherwise gcc happily get wild with spilling and + * the stack frame size simply explode and performance goes down the drain. + */ + +#if defined(__i386__) || defined(__x86_64__) + #define setW(x, val) (*(volatile unsigned int *)&W(x) = (val)) +#elif defined(__GNUC__) && defined(__arm__) + #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0) +#else + #define setW(x, val) (W(x) = (val)) +#endif + +/* + * Performance might be improved if the CPU architecture is OK with + * unaligned 32-bit loads and a fast ntohl() is available. + * Otherwise fall back to byte loads and shifts which is portable, + * and is faster on architectures with memory alignment issues. + */ + +#if defined(__i386__) || defined(__x86_64__) || \ + defined(_M_IX86) || defined(_M_X64) || \ + defined(__ppc__) || defined(__ppc64__) || \ + defined(__powerpc__) || defined(__powerpc64__) || \ + defined(__s390__) || defined(__s390x__) + +#define get_be32(p) ntohl(*(unsigned int *)(p)) +#define put_be32(p, v) do { *(unsigned int *)(p) = htonl(v); } while (0) + +#else + +#define get_be32(p) ( \ + (*((unsigned char *)(p) + 0) << 24) | \ + (*((unsigned char *)(p) + 1) << 16) | \ + (*((unsigned char *)(p) + 2) << 8) | \ + (*((unsigned char *)(p) + 3) << 0) ) +#define put_be32(p, v) do { \ + unsigned int __v = (v); \ + *((unsigned char *)(p) + 0) = __v >> 24; \ + *((unsigned char *)(p) + 1) = __v >> 16; \ + *((unsigned char *)(p) + 2) = __v >> 8; \ + *((unsigned char *)(p) + 3) = __v >> 0; } while (0) + +#endif + +/* This "rolls" over the 512-bit array */ +#define W(x) (array[(x)&15]) + +/* + * Where do we get the source from? The first 16 iterations get it from + * the input data, the next mix it from the 512-bit array. + */ +#define SHA_SRC(t) get_be32(data + t) +#define SHA_MIX(t) SHA_ROL(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1) + +#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \ + unsigned int TEMP = input(t); setW(t, TEMP); \ + E += TEMP + SHA_ROL(A,5) + (fn) + (constant); \ + B = SHA_ROR(B, 2); } while (0) + +#define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) +#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) +#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E ) +#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E ) +#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E ) + +static void blk_SHA1_Block(blk_SHA_CTX *ctx, const unsigned int *data) +{ + unsigned int A,B,C,D,E; + unsigned int array[16]; + + A = ctx->H[0]; + B = ctx->H[1]; + C = ctx->H[2]; + D = ctx->H[3]; + E = ctx->H[4]; + + /* Round 1 - iterations 0-16 take their input from 'data' */ + T_0_15( 0, A, B, C, D, E); + T_0_15( 1, E, A, B, C, D); + T_0_15( 2, D, E, A, B, C); + T_0_15( 3, C, D, E, A, B); + T_0_15( 4, B, C, D, E, A); + T_0_15( 5, A, B, C, D, E); + T_0_15( 6, E, A, B, C, D); + T_0_15( 7, D, E, A, B, C); + T_0_15( 8, C, D, E, A, B); + T_0_15( 9, B, C, D, E, A); + T_0_15(10, A, B, C, D, E); + T_0_15(11, E, A, B, C, D); + T_0_15(12, D, E, A, B, C); + T_0_15(13, C, D, E, A, B); + T_0_15(14, B, C, D, E, A); + T_0_15(15, A, B, C, D, E); + + /* Round 1 - tail. Input from 512-bit mixing array */ + T_16_19(16, E, A, B, C, D); + T_16_19(17, D, E, A, B, C); + T_16_19(18, C, D, E, A, B); + T_16_19(19, B, C, D, E, A); + + /* Round 2 */ + T_20_39(20, A, B, C, D, E); + T_20_39(21, E, A, B, C, D); + T_20_39(22, D, E, A, B, C); + T_20_39(23, C, D, E, A, B); + T_20_39(24, B, C, D, E, A); + T_20_39(25, A, B, C, D, E); + T_20_39(26, E, A, B, C, D); + T_20_39(27, D, E, A, B, C); + T_20_39(28, C, D, E, A, B); + T_20_39(29, B, C, D, E, A); + T_20_39(30, A, B, C, D, E); + T_20_39(31, E, A, B, C, D); + T_20_39(32, D, E, A, B, C); + T_20_39(33, C, D, E, A, B); + T_20_39(34, B, C, D, E, A); + T_20_39(35, A, B, C, D, E); + T_20_39(36, E, A, B, C, D); + T_20_39(37, D, E, A, B, C); + T_20_39(38, C, D, E, A, B); + T_20_39(39, B, C, D, E, A); + + /* Round 3 */ + T_40_59(40, A, B, C, D, E); + T_40_59(41, E, A, B, C, D); + T_40_59(42, D, E, A, B, C); + T_40_59(43, C, D, E, A, B); + T_40_59(44, B, C, D, E, A); + T_40_59(45, A, B, C, D, E); + T_40_59(46, E, A, B, C, D); + T_40_59(47, D, E, A, B, C); + T_40_59(48, C, D, E, A, B); + T_40_59(49, B, C, D, E, A); + T_40_59(50, A, B, C, D, E); + T_40_59(51, E, A, B, C, D); + T_40_59(52, D, E, A, B, C); + T_40_59(53, C, D, E, A, B); + T_40_59(54, B, C, D, E, A); + T_40_59(55, A, B, C, D, E); + T_40_59(56, E, A, B, C, D); + T_40_59(57, D, E, A, B, C); + T_40_59(58, C, D, E, A, B); + T_40_59(59, B, C, D, E, A); + + /* Round 4 */ + T_60_79(60, A, B, C, D, E); + T_60_79(61, E, A, B, C, D); + T_60_79(62, D, E, A, B, C); + T_60_79(63, C, D, E, A, B); + T_60_79(64, B, C, D, E, A); + T_60_79(65, A, B, C, D, E); + T_60_79(66, E, A, B, C, D); + T_60_79(67, D, E, A, B, C); + T_60_79(68, C, D, E, A, B); + T_60_79(69, B, C, D, E, A); + T_60_79(70, A, B, C, D, E); + T_60_79(71, E, A, B, C, D); + T_60_79(72, D, E, A, B, C); + T_60_79(73, C, D, E, A, B); + T_60_79(74, B, C, D, E, A); + T_60_79(75, A, B, C, D, E); + T_60_79(76, E, A, B, C, D); + T_60_79(77, D, E, A, B, C); + T_60_79(78, C, D, E, A, B); + T_60_79(79, B, C, D, E, A); + + ctx->H[0] += A; + ctx->H[1] += B; + ctx->H[2] += C; + ctx->H[3] += D; + ctx->H[4] += E; +} + +void blk_SHA1_Init(blk_SHA_CTX *ctx) +{ + ctx->size = 0; + + /* Initialize H with the magic constants (see FIPS180 for constants) */ + ctx->H[0] = 0x67452301; + ctx->H[1] = 0xefcdab89; + ctx->H[2] = 0x98badcfe; + ctx->H[3] = 0x10325476; + ctx->H[4] = 0xc3d2e1f0; +} + +void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *data, unsigned long len) +{ + unsigned int lenW = ctx->size & 63; + + ctx->size += len; + + /* Read the data into W and process blocks as they get full */ + if (lenW) { + unsigned int left = 64 - lenW; + if (len < left) + left = len; + memcpy(lenW + (char *)ctx->W, data, left); + lenW = (lenW + left) & 63; + len -= left; + data = ((const char *)data + left); + if (lenW) + return; + blk_SHA1_Block(ctx, ctx->W); + } + while (len >= 64) { + blk_SHA1_Block(ctx, data); + data = ((const char *)data + 64); + len -= 64; + } + if (len) + memcpy(ctx->W, data, len); +} + +void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx) +{ + static const unsigned char pad[64] = { 0x80 }; + unsigned int padlen[2]; + int i; + + /* Pad with a binary 1 (ie 0x80), then zeroes, then length */ + padlen[0] = htonl((uint32_t)(ctx->size >> 29)); + padlen[1] = htonl((uint32_t)(ctx->size << 3)); + + i = ctx->size & 63; + blk_SHA1_Update(ctx, pad, 1+ (63 & (55 - i))); + blk_SHA1_Update(ctx, padlen, 8); + + /* Output hash */ + for (i = 0; i < 5; i++) + put_be32(hashout + i*4, ctx->H[i]); +} diff --git a/fluent-bit/lib/monkey/plugins/auth/sha1.h b/fluent-bit/lib/monkey/plugins/auth/sha1.h new file mode 100644 index 000000000..4a75ab351 --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/auth/sha1.h @@ -0,0 +1,22 @@ +/* + * SHA1 routine optimized to do word accesses rather than byte accesses, + * and to avoid unnecessary copies into the context array. + * + * This was initially based on the Mozilla SHA1 implementation, although + * none of the original Mozilla code remains. + */ + +typedef struct { + unsigned long long size; + unsigned int H[5]; + unsigned int W[16]; +} blk_SHA_CTX; + +void blk_SHA1_Init(blk_SHA_CTX *ctx); +void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *dataIn, unsigned long len); +void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx); + +#define SHA_CTX blk_SHA_CTX +#define SHA1_Init blk_SHA1_Init +#define SHA1_Update blk_SHA1_Update +#define SHA1_Final blk_SHA1_Final diff --git a/fluent-bit/lib/monkey/plugins/auth/tools/CMakeLists.txt b/fluent-bit/lib/monkey/plugins/auth/tools/CMakeLists.txt new file mode 100644 index 000000000..63b445cf7 --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/auth/tools/CMakeLists.txt @@ -0,0 +1,15 @@ +set(src + ../sha1.c + ../base64.c + mk_passwd.c + ) + +include_directories(../) +add_definitions(-D_FORCE_SYSMALLOC) +add_executable(mk_passwd ${src}) + +if(BUILD_LOCAL) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/") +else() + install(TARGETS mk_passwd RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_SBINDIR}) +endif() diff --git a/fluent-bit/lib/monkey/plugins/auth/tools/mk_passwd.c b/fluent-bit/lib/monkey/plugins/auth/tools/mk_passwd.c new file mode 100644 index 000000000..6dba1d3f1 --- /dev/null +++ b/fluent-bit/lib/monkey/plugins/auth/tools/mk_passwd.c @@ -0,0 +1,209 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +#ifdef MALLOC_JEMALLOC +#undef MALLOC_JEMALLOC +#endif + +#include <monkey/monkey.h> +#include <monkey/mk_core.h> + +#include <getopt.h> + +#include "sha1.h" +#include "base64.h" + +#define MAX_LINE_LEN 256 + +struct mk_passwd_user { + char *row; + struct mk_list _head; +}; + +/* Store a file as a linked list of its lines */ +static struct mk_list passwd_file; + +/* Load file to memory from disk + * If create_file == MK_TRUE, the file will be rewritten */ +void read_file(char *filename, int create_file) +{ + FILE *filein = fopen(filename, "r"); + char line[MAX_LINE_LEN]; + struct mk_passwd_user *entry; + + mk_list_init(&passwd_file); + + if (filein == NULL && create_file == MK_FALSE) { + printf("Error opening file %s\n", filename); + exit(1); + } + + if (filein == NULL || create_file == MK_TRUE) { + if (filein != NULL) + fclose(filein); + return; + } + + while (fgets(line, MAX_LINE_LEN, filein) != NULL) { + entry = malloc(sizeof(*entry)); + entry->row = strdup(line); + mk_list_add(&entry->_head, &passwd_file); + } + fclose(filein); +} + +/* Store data to disk */ +void dump_file(char *filename) +{ + FILE *fileout = fopen(filename, "w"); + struct mk_list *it, *tmp; + struct mk_passwd_user *entry; + + if (!fileout) { + printf("Error opening: %s", filename); + exit(EXIT_FAILURE); + } + + mk_list_foreach_safe(it, tmp, &passwd_file) { + entry = mk_list_entry(it, struct mk_passwd_user, _head); + fprintf(fileout, "%s", entry->row); + mk_list_del(&entry->_head); + free(entry->row); + free(entry); + } + fclose(fileout); +} + +/* Return sha1 hash of password + * A new line is appended at the hash */ +unsigned char *sha1_hash(const char *password) +{ + + unsigned char sha_hash[20]; + blk_SHA_CTX sha; + + blk_SHA1_Init(&sha); + blk_SHA1_Update(&sha, password, strlen(password)); + blk_SHA1_Final(sha_hash, &sha); + + return base64_encode(sha_hash, 20, NULL); +} + +void update_user(const char *username, const char *password, int create_user) +{ + struct mk_list *it, *tmp; + struct mk_passwd_user *entry; + unsigned char *hash_passwd; + int i; + + mk_list_foreach_safe(it, tmp, &passwd_file) { + entry = mk_list_entry(it, struct mk_passwd_user, _head); + for (i = 0; entry->row[i] != '\0' && entry->row[i] != ':' && username[i] != '\0' && entry->row[i] == username[i]; i++); + if (entry->row[i] != ':' || username[i] != '\0') + continue; + + /* Found a match */ + + /* Delete user */ + if (create_user == MK_FALSE) { + printf("[-] Deleting user %s\n", username); + mk_list_del(&entry->_head); + free(entry->row); + free(entry); + return; + } + + /* Update user */ + printf("[+] Password changed for user %s\n", username); + hash_passwd = sha1_hash(password); + free(entry->row); + entry->row = malloc(512); + snprintf(entry->row, 512, "%s:{SHA1}%s", username, hash_passwd); + free(hash_passwd); + + return; + } + + /* Create user */ + if (create_user == MK_TRUE) { + printf("[+] Adding user %s\n", username); + entry = malloc(sizeof(struct mk_passwd_user)); + entry->row = malloc(512); + hash_passwd = sha1_hash(password); + snprintf(entry->row, 512, "%s:{SHA1}%s", username, hash_passwd); + free(hash_passwd); + + mk_list_add(&entry->_head, &passwd_file); + } +} + +static void print_help(int full_help) +{ + printf("Usage: mk_passwd [-c] [-D] filename username password\n"); + if (full_help == MK_TRUE) { + printf("\nOptions:\n"); + printf(" -h, --help\tshow this help message and exit\n"); + printf(" -c\t\tCreate a new mkpasswd file, overwriting any existing file.\n"); + printf(" -D\t\tRemove the given user from the password file.\n"); + } +} + +int main(int argc, char *argv[]) +{ + int opt; + int create_user = MK_TRUE; + int create_file = MK_FALSE; + int show_help = MK_FALSE; + char *filename = NULL; + char *username = NULL; + char *password = NULL; + + /* Command line options */ + static const struct option long_opts[] = { + {"create", no_argument, NULL, 'c'}, + {"delete_user", no_argument, NULL, 'D'}, + {"help", no_argument, NULL, 'h'}, + }; + + /* Parse options */ + while ((opt = getopt_long(argc, argv, "hbDc", long_opts, NULL)) != -1) { + switch (opt) { + case 'c': + create_file = MK_TRUE; + break; + case 'D': + create_user = MK_FALSE; + break; + case 'h': + show_help = MK_TRUE; + break; + } + } + + /* Retrieve filename, username and password */ + while (optind < argc) { + if (filename == NULL) + filename = argv[optind++]; + else if (username == NULL) + username = argv[optind++]; + else if (password == NULL) + password = argv[optind++]; + } + + if (show_help == MK_TRUE) { + print_help(MK_TRUE); + exit(0); + } + + /* If delete_user option is provided, do not provide a password */ + if ((password != NULL) ^ (create_user == MK_TRUE)) { + print_help(MK_FALSE); + exit(1); + } + + /* Process request */ + read_file(filename, create_file); + update_user(username, password, create_user); + dump_file(filename); + + return 0; +} |