From 5b7bd59fc91f213fa9806af32baa13c24e96d066 Mon Sep 17 00:00:00 2001
From: "Dmitriy A. Gerasimov" <dmitriy.gerasimov@demlabs.net>
Date: Sun, 5 Jan 2020 23:57:36 +0700
Subject: [PATCH] [+] GDB based auth module (only copy-pasted without refactor)
 [*] Small fixes

---
 CMakeLists.txt                   |   10 +-
 dap_chain_net_srv_vpn.c          |   11 +-
 dap_chain_net_srv_vpn_cdb.c      |   20 +-
 dap_chain_net_srv_vpn_cdb_auth.c | 1184 ++++++++++++++++++++++++++++++
 dap_chain_net_srv_vpn_cdb_auth.h |   31 +
 5 files changed, 1236 insertions(+), 20 deletions(-)
 create mode 100644 dap_chain_net_srv_vpn_cdb_auth.c
 create mode 100644 dap_chain_net_srv_vpn_cdb_auth.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9cba6b8..8207a6e 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,16 +3,18 @@ project (dap_chain_net_srv_vpn)
   
 set(DAP_CHAIN_NET_SRV_VPN_SRCS 
 	dap_chain_net_srv_vpn.c
-    dap_chain_net_srv_vpn_cdb.c
-    dap_chain_net_srv_vpn_cdb_server_list.c
+        dap_chain_net_srv_vpn_cdb.c
+        dap_chain_net_srv_vpn_cdb_auth.c
+        dap_chain_net_srv_vpn_cdb_server_list.c
 	dap_chain_net_vpn_client.c
 	dap_chain_net_vpn_client_tun.c
         )
 
 set(DAP_CHAIN_NET_SRV_VPN_HEADERS
 	dap_chain_net_srv_vpn.h
-    dap_chain_net_srv_vpn_cdb.h
-    dap_chain_net_srv_vpn_cdb_server_list.h
+        dap_chain_net_srv_vpn_cdb.h
+        dap_chain_net_srv_vpn_cdb_auth.h
+        dap_chain_net_srv_vpn_cdb_server_list.h
 	dap_chain_net_vpn_client.h
 	dap_chain_net_vpn_client_tun.h
     )
diff --git a/dap_chain_net_srv_vpn.c b/dap_chain_net_srv_vpn.c
index b364609..0e2eb17 100755
--- a/dap_chain_net_srv_vpn.c
+++ b/dap_chain_net_srv_vpn.c
@@ -937,15 +937,16 @@ void s_ch_packet_in(dap_stream_ch_t* a_ch, void* arg)
                 in_saddr.s_addr = ((struct iphdr*) l_vpn_pkt->data)->saddr;
                 in_daddr.s_addr = ((struct iphdr*) l_vpn_pkt->data)->daddr;
 
-                char str_daddr[42], str_saddr[42];
-                strncpy(str_saddr, inet_ntoa(in_saddr), sizeof(str_saddr));
-                strncpy(str_daddr, inet_ntoa(in_daddr), sizeof(str_daddr));
+                char str_daddr[43], str_saddr[43];
+                strncpy(str_saddr, inet_ntoa(in_saddr), sizeof(str_saddr)-1);
+                strncpy(str_daddr, inet_ntoa(in_daddr), sizeof(str_daddr)-1);
                 int ret;
                 //if( ch_sf_raw_write(STREAM_SF_PACKET_OP_CODE_RAW_SEND, sf_pkt->data, sf_pkt->op_data.data_size)<0){
-                struct sockaddr_in sin = { 0 };
+                /*struct sockaddr_in sin = { 0 };
                 sin.sin_family = AF_INET;
                 sin.sin_port = 0;
-                sin.sin_addr.s_addr = in_daddr.s_addr;
+                sin.sin_addr.s_addr = in_daddr.s_addr;*/
+
 
                 //if((ret=sendto(CH_SF(ch)->raw_l3_sock , sf_pkt->data,sf_pkt->header.op_data.data_size,0,(struct sockaddr *) &sin, sizeof (sin)))<0){
                 if((ret = write(s_raw_server->tun_fd, l_vpn_pkt->data, l_vpn_pkt->header.op_data.data_size)) < 0) {
diff --git a/dap_chain_net_srv_vpn_cdb.c b/dap_chain_net_srv_vpn_cdb.c
index 9485bde..525837b 100644
--- a/dap_chain_net_srv_vpn_cdb.c
+++ b/dap_chain_net_srv_vpn_cdb.c
@@ -130,7 +130,7 @@ int dap_chain_net_srv_vpn_cdb_init(dap_http_t * a_http)
                                                             "tx_cond_create",
                                                             false)) {
             // Parse tx cond templates
-            size_t l_tx_cond_tpls_count = 0;
+            uint16_t l_tx_cond_tpls_count = 0;
 
             /* ! IMPORTANT ! This fetch is single-action and cannot be further reused, since it modifies the stored config data
              * ! it also must NOT be freed within this module !
@@ -238,11 +238,11 @@ static void s_auth_callback(enc_http_delegate_t* a_delegate, void * a_arg)
         memset(l_pkey_raw, 0, l_pkey_b64_length);
         size_t l_pkey_raw_size =
                 dap_enc_base64_decode(l_auth_info->pkey, l_pkey_b64_length, l_pkey_raw, DAP_ENC_DATA_TYPE_B64_URLSAFE);
-        char l_pkey_gdb_group[sizeof(DAP_CHAIN_NET_SRV_VPN_CDB_GDB_PREFIX) + 8] = { '\0' };
-        dap_snprintf(l_pkey_gdb_group, "%s.pkey", DAP_CHAIN_NET_SRV_VPN_CDB_GDB_PREFIX);
-        log_it(L_DEBUG, "2791: pkey group %s", l_pkey_gdb_group);
+        char *l_pkey_gdb_group=  dap_strdup_printf( "%s.pkey", DAP_CHAIN_NET_SRV_VPN_CDB_GDB_PREFIX);
+        log_it(L_DEBUG, "Pkey group %s", l_pkey_gdb_group);
         dap_chain_global_db_gr_set(l_auth_info->user, l_pkey_raw, l_pkey_raw_size, l_pkey_gdb_group);
         l_client_key = dap_enc_key_deserealize(l_pkey_raw, l_pkey_raw_size);
+        DAP_DELETE(l_pkey_gdb_group);
     }
 
     tx_cond_template_t *l_tpl;
@@ -250,11 +250,10 @@ static void s_auth_callback(enc_http_delegate_t* a_delegate, void * a_arg)
         size_t l_gdb_group_size = 0;
 
         // Try to load from gdb
-        char l_tx_cond_gdb_group[128] = {'\0'};
-        dap_snprintf(l_tx_cond_gdb_group, "%s.%s.tx_cond", l_tpl->net->pub.name, DAP_CHAIN_NET_SRV_VPN_CDB_GDB_PREFIX);
-        log_it(L_DEBUG, "2791: Checkout group %s", l_tx_cond_gdb_group);
+        char *l_tx_cond_gdb_group =  dap_strdup_printf( "%s.%s.tx_cond", l_tpl->net->pub.name, DAP_CHAIN_NET_SRV_VPN_CDB_GDB_PREFIX);
+        log_it(L_DEBUG, "Checkout group %s", l_tx_cond_gdb_group);
         dap_chain_hash_fast_t *l_tx_cond_hash =
-            (dap_hash_type_t*)dap_chain_global_db_gr_get(l_auth_info->user, &l_gdb_group_size, l_tx_cond_gdb_group);
+            (dap_chain_hash_fast_t*) dap_chain_global_db_gr_get(l_auth_info->user, &l_gdb_group_size, l_tx_cond_gdb_group);
 
         // Check for entry size
         if (l_gdb_group_size && l_gdb_group_size != sizeof(dap_chain_hash_fast_t)) {
@@ -281,10 +280,8 @@ static void s_auth_callback(enc_http_delegate_t* a_delegate, void * a_arg)
 
         // Try to create condition
         if (! l_tx_cond_hash ) {
-            // test
-            log_it(L_DEBUG, "2791: Create a tx");
             dap_chain_wallet_t *l_wallet_from = l_tpl->wallet;
-            log_it(L_DEBUG, "2791: From wallet %s", l_wallet_from->name);
+            log_it(L_DEBUG, "Create tx from wallet %s", l_wallet_from->name);
             dap_enc_key_t *l_key_from = dap_chain_wallet_get_key(l_wallet_from, 0);
 
             // where to take coins for service
@@ -316,6 +313,7 @@ static void s_auth_callback(enc_http_delegate_t* a_delegate, void * a_arg)
         }
         enc_http_reply_f(a_delegate,"\t</tx_cond_tpl>\n");
 
+        DAP_DELETE(l_tx_cond_gdb_group);
     }
     if (l_client_key)
         DAP_DELETE(l_client_key);
diff --git a/dap_chain_net_srv_vpn_cdb_auth.c b/dap_chain_net_srv_vpn_cdb_auth.c
new file mode 100644
index 0000000..445ba81
--- /dev/null
+++ b/dap_chain_net_srv_vpn_cdb_auth.c
@@ -0,0 +1,1184 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * CellFrame       https://cellframe.net
+ * Sources         https://gitlab.demlabs.net/cellframe
+ * Copyright  (c) 2017-2020
+ * All rights reserved.
+
+ This file is part of CellFrame SDK the open source project
+
+    CellFrame SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    CellFrame SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dap_common.h"
+#include "dap_chain_net_srv_vpn_cdb_auth.h"
+
+#define LOG_TAG "dap_chain_net_srv_vpn_cdb_auth"
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/wait.h>
+#include <rand/dap_rand.h>
+
+#include <time.h>
+
+#include "dap_common.h"
+#include "dap_client_remote.h"
+#include "dap_http_client.h"
+#include "dap_enc.h"
+#include "dap_enc_key.h"
+#include "dap_enc_ks.h"
+#include "dap_enc_http.h"
+#include "dap_enc_base64.h"
+#include "dap_server.h"
+#include "db_core.h"
+#include "db_auth.h"
+#include "http_status_code.h"
+
+#include "SimpleFIPS202.h"
+
+
+#define LOG_TAG "db_auth"
+
+#define OP_CODE_LOGIN_INCORRECT_PSWD "0xf2"
+#define OP_CODE_NOT_FOUND_LOGIN_IN_DB "0xf3"
+#define OP_CODE_SUBSCRIBE_EXPIRIED "0xf4"
+#define OP_CODE_INCORRECT_SYMOLS "0xf6"
+
+static db_auth_info_t *s_auths = NULL;
+static pthread_mutex_t s_mutex_on_auth_hash = PTHREAD_MUTEX_INITIALIZER;
+
+static const char *s_db_name = NULL;
+
+dap_enc_http_callback_t s_callback_success = NULL;
+
+/**
+ * @brief dap_chain_net_srv_vpn_cdb_auth_set_callback
+ * @param a_callback_success
+ */
+void dap_chain_net_srv_vpn_cdb_auth_set_callback(dap_enc_http_callback_t a_callback_success)
+{
+    s_callback_success = a_callback_success;
+}
+
+
+
+/**
+ * @brief s_auth_info_by_cookie Find user by its cookie
+ * @param cookie Cookie
+ * @return Zero if this cookie is not present
+ */
+db_auth_info_t* s_info_by_cookie(const char * cookie)
+{
+    db_auth_info_t * ret = NULL;
+
+    if ( cookie == NULL )
+    {
+        log_it(L_ERROR, "cookie is NULL in db_auth_info_by_cookie");
+        return NULL;
+    }
+    pthread_mutex_lock(&s_mutex_on_auth_hash);
+    HASH_FIND_STR(s_auths, cookie, ret);
+    pthread_mutex_unlock(&s_mutex_on_auth_hash);
+    if(ret == NULL)
+        log_it(L_NOTICE,"Cookie '%s' not present in the table",cookie);
+    else
+        log_it(L_INFO,"Cookie '%s' has been found in the table",cookie);
+    return ret;
+}
+
+db_auth_info_t* db_search_cookie_in_db(const char * cookie)
+{
+
+    mongoc_collection_t* collection_cookie = mongoc_client_get_collection
+            (mongo_client, s_db_name, "dap_cookie_history");
+
+    bson_t *query = bson_new();
+
+    BSON_APPEND_UTF8 (query, "cookie", cookie);
+
+    mongoc_cursor_t *cursor_dap_cookie = mongoc_collection_find
+            (collection_cookie, MONGOC_QUERY_NONE, 0, 0, 0, query, NULL, NULL);
+
+    bson_t *doc_dap_cookie_user;
+
+    if( mongoc_cursor_next (cursor_dap_cookie, (const bson_t**)&doc_dap_cookie_user) == false )
+    {
+        log_it(L_INFO, "Cookie not find in database");
+        return NULL;
+    }
+
+    bson_iter_t iter;
+
+    if ( !(bson_iter_init (&iter, doc_dap_cookie_user) && bson_iter_find (&iter, "login")) )
+    {
+        log_it(L_ERROR, "Login not found in document");
+        return NULL;
+    }
+
+    mongoc_collection_destroy(collection_cookie);
+    mongoc_cursor_destroy(cursor_dap_cookie);
+
+    if(doc_dap_cookie_user)
+        bson_destroy(doc_dap_cookie_user);
+
+    if(query)
+        bson_destroy(query);
+
+
+    /* ok user find now get information */
+
+    mongoc_collection_t* collection_dap_users = mongoc_client_get_collection
+            (mongo_client, s_db_name, "dap_users");
+
+    query = bson_new();
+
+    BSON_APPEND_UTF8 (query, "login", bson_iter_value(&iter)->value.v_utf8.str);
+
+    mongoc_cursor_t* cursor_dap_users = mongoc_collection_find
+            (collection_dap_users, MONGOC_QUERY_NONE, 0, 0, 0, query, NULL, NULL);
+
+
+    if( mongoc_cursor_next (cursor_dap_users, (const bson_t**)&doc_dap_cookie_user) == false )
+    {
+        log_it(L_INFO, "User not find in database");
+        return NULL;
+    }
+    // mongoc_collection_destroy(collection_cookie);
+
+    bson_iter_t sub_iter;
+
+    // ok cookie find, get user information;
+    db_auth_info_t * ai = DAP_NEW_Z(db_auth_info_t);
+
+    if (bson_iter_init (&iter, doc_dap_cookie_user) &&
+            bson_iter_find_descendant (&iter, "profile.first_name", &sub_iter))
+    {
+        strncpy(ai->first_name, bson_iter_value(&sub_iter)->value.v_utf8.str,
+                bson_iter_value(&sub_iter)->value.v_utf8.len);
+    }
+
+    if (bson_iter_init (&iter, doc_dap_cookie_user) &&
+            bson_iter_find_descendant (&iter, "profile.last_name", &sub_iter))
+    {
+        strncpy(ai->last_name,bson_iter_value(&sub_iter)->value.v_utf8.str,
+                bson_iter_value(&sub_iter)->value.v_utf8.len);
+    }
+
+    if (bson_iter_init (&iter, doc_dap_cookie_user) &&
+            bson_iter_find_descendant (&iter, "profile.email", &sub_iter))
+    {
+        strncpy(ai->email,bson_iter_value(&sub_iter)->value.v_utf8.str,
+                bson_iter_value(&sub_iter)->value.v_utf8.len);
+    }
+
+    strcpy(ai->cookie, cookie);
+
+    mongoc_collection_destroy(collection_dap_users);
+    mongoc_cursor_destroy(cursor_dap_users);
+
+    if(doc_dap_cookie_user)
+        bson_destroy(doc_dap_cookie_user);
+
+    if(query)
+        bson_destroy(query);
+
+    pthread_mutex_lock(&s_mutex_on_auth_hash);
+    HASH_ADD_STR(s_auths,cookie,ai);
+    pthread_mutex_unlock(&s_mutex_on_auth_hash);
+
+    return ai;
+}
+
+/**
+ * @brief db_auth_user_change_password
+ * @param user
+ * @param password
+ * @param new_password
+ * @return
+ * @details change password for user ( check correctly current pass, for change to new )
+ */
+bool db_auth_user_change_password(const char* user, const char* password,
+                                  const char* new_password)
+{
+    if ( check_user_password(user, password) == false )
+    {
+        log_it(L_WARNING, "Error change password. Old user password not correct" , user);
+        return false;
+    }
+
+    return db_auth_change_password(user, new_password);
+}
+
+/**
+ * @brief db_auth_user_change_password
+ * @param user
+ * @param password
+ * @param new_password
+ * @return
+ * @details change passwd without check correct old password ( for admins )
+ */
+bool db_auth_change_password(const char* user, const char* new_password)
+{
+    if ( exist_user_in_db(user) == false )
+    {
+        log_it(L_WARNING, "Error change password. User %s not find" , user);
+        return false;
+    }
+
+    mongoc_collection_t *collection_dap_users = mongoc_client_get_collection
+            (mongo_client, s_db_name, "dap_users");
+
+    bson_t *query = bson_new();
+
+    BSON_APPEND_UTF8 (query, "login", user);
+
+    mongoc_cursor_t *cursor_dap_users = mongoc_collection_find
+            (collection_dap_users, MONGOC_QUERY_NONE, 0, 0, 0, query, NULL, NULL);
+
+    bson_t *doc_dap_user;
+
+    mongoc_cursor_next (cursor_dap_users, (const bson_t**)&doc_dap_user);
+
+    bson_error_t error;
+
+
+
+    char * password_hash_b64 = dap_server_db_hash_password_b64(new_password);
+
+    if (password_hash_b64 == NULL) {
+        log_it(L_WARNING,"Bad hash(based64) for user password");
+        return false;
+    }
+
+    bson_t *update = BCON_NEW ("$set", "{",
+                                "passwordHash", BCON_UTF8 (password_hash_b64),
+                               "}");
+
+    if (!mongoc_collection_update (collection_dap_users, MONGOC_UPDATE_NONE, doc_dap_user, update, NULL, &error)) {
+        log_it(L_WARNING,"%s", error.message);
+        return false;
+    }
+
+    mongoc_collection_destroy(collection_dap_users);
+
+    if(query)
+        bson_destroy(query);
+
+    if(cursor_dap_users)
+        mongoc_cursor_destroy(cursor_dap_users);
+
+    if(doc_dap_user)
+        bson_destroy(doc_dap_user);
+
+     DAP_DELETE( password_hash_b64 );
+
+    log_it(L_INFO, "user: %s change password to %s", user, new_password);
+    return true;
+}
+
+
+/**
+ * @brief db_auth_set_field_str
+ * @param a_user
+ * @param a_field_name
+ * @param a_field_value
+ * @return
+ */
+bool db_auth_set_field_str(const char* a_user, const char* a_field_name, const char * a_field_value)
+{
+    if ( exist_user_in_db(a_user) == false )
+    {
+        log_it(L_WARNING, "Error set field str. User %s not find" , a_user);
+        return false;
+    }
+
+    mongoc_collection_t *l_collection_dap_users = mongoc_client_get_collection
+            (mongo_client, s_db_name, "dap_cookie_history");
+
+    bson_t *l_query = bson_new();
+
+    BSON_APPEND_UTF8 (l_query, "login", a_user);
+
+    mongoc_cursor_t *l_cursor_dap_users = mongoc_collection_find
+            (l_collection_dap_users, MONGOC_QUERY_NONE, 0, 0, 0, l_query, NULL, NULL);
+
+    bson_t *l_doc_dap_user;
+
+    mongoc_cursor_next (l_cursor_dap_users, (const bson_t**)&l_doc_dap_user);
+
+    bson_error_t l_error;
+
+    bson_t *l_update = BCON_NEW ("$set", "{",
+                                a_field_name, BCON_UTF8 (a_field_value),
+                               "}");
+
+    if (!mongoc_collection_update (l_collection_dap_users, MONGOC_UPDATE_NONE, l_doc_dap_user, l_update, NULL, &l_error)) {
+        log_it(L_WARNING,"%s", l_error.message);
+        return false;
+    }
+
+    mongoc_collection_destroy(l_collection_dap_users);
+
+    if(l_query)
+        bson_destroy(l_query);
+
+    if(l_cursor_dap_users)
+        mongoc_cursor_destroy(l_cursor_dap_users);
+
+    if(l_doc_dap_user)
+        bson_destroy(l_doc_dap_user);
+
+    log_it(L_INFO, "set field \"%s\" with string \"%s\"", a_field_name, a_field_value );
+    return true;
+}
+
+
+/**
+ * @brief check_user_password
+ * @param user
+ * @param password
+ * @return false if user password not correct
+ */
+bool check_user_password(const char* a_user, const char* a_password)
+{
+    if ( exist_user_in_db(a_user) == false ){
+        log_it(L_WARNING,"User %s is not present in DB",a_user);
+        return false;
+    }
+
+    bool is_correct_password = false;
+
+    mongoc_collection_t *collection = mongoc_client_get_collection (
+                mongo_client, s_db_name, "dap_users");
+
+    bson_t *query = bson_new();
+    BSON_APPEND_UTF8 (query, "login", a_user);
+
+    bson_iter_t iter;
+    bson_t *doc;
+
+    mongoc_cursor_t *cursor =  mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0,
+                                                       (const bson_t*)query, NULL, NULL);
+
+    mongoc_cursor_next (cursor, (const bson_t**)&doc);
+    char salt[16] = {0}; char salt_from_b64[8] = {0};
+
+    if ( bson_iter_init (&iter, doc) && bson_iter_find (&iter, "salt") )
+        memcpy(salt,bson_iter_value(&iter)->value.v_utf8.str,16);
+    else {
+        log_it(L_ERROR, "Not find Salt in user"); return NULL;
+    }
+
+    dap_enc_base64_decode(salt, 16, salt_from_b64,DAP_ENC_DATA_TYPE_B64);
+
+    char*  l_password_hash_b64 = dap_server_db_hash_password_b64(a_password);
+
+    if (!l_password_hash_b64) {
+        log_it(L_ERROR, "Can not memmory allocate");
+        return NULL;
+    }
+
+    if (bson_iter_init (&iter, doc) && bson_iter_find (&iter, "passwordHash"))
+    {
+        if ( memcmp(l_password_hash_b64, bson_iter_value(&iter)->value.v_utf8.str,
+                    DB_AUTH_HASH_LENGTH * 2) == 0 )
+            is_correct_password = true;
+    }
+
+    mongoc_collection_destroy(collection);
+
+    if(cursor)
+        mongoc_cursor_destroy(cursor);
+
+    if(query)
+        bson_destroy(query);
+
+    if(doc)
+        bson_destroy(doc);
+
+    DAP_DELETE( l_password_hash_b64 );
+
+    return is_correct_password;
+}
+
+
+static bool s_save_cookie_inform_in_db(const char* login, db_auth_info_t * a_auth_info)
+{
+    bool result = true;
+    mongoc_collection_t *collection = mongoc_client_get_collection (
+                mongo_client, s_db_name, "dap_cookie_history");
+
+    bson_error_t error;
+
+    bson_t *query = bson_new();
+    BSON_APPEND_UTF8 (query, "login", login);
+
+    mongoc_cursor_t *cursor_dap_cookie_history = mongoc_collection_find
+            (collection, MONGOC_QUERY_NONE, 0, 0, 0, query, NULL, NULL);
+
+    struct tm *utc_date_time;
+    time_t t = time(NULL);
+    utc_date_time = localtime(&t);
+
+    bson_t *doc_dap_cookie; bson_t *bson_doc = NULL;
+    if ( mongoc_cursor_next (cursor_dap_cookie_history, (const bson_t**)&doc_dap_cookie) )
+    {
+        bson_doc = BCON_NEW ("$set", "{",
+                             "login", BCON_UTF8 (login),
+                             "cookie", BCON_UTF8 (a_auth_info->cookie),
+                             "pkey", BCON_UTF8 (a_auth_info->pkey),
+                             "last_use", BCON_DATE_TIME(mktime (utc_date_time) * 1000),
+                             "}");
+
+        if (!mongoc_collection_update (collection, MONGOC_UPDATE_UPSERT, doc_dap_cookie, bson_doc, NULL, &error)) {
+            log_it(L_WARNING,"%s", error.message);
+            result = false;
+        }
+    }
+    else
+    {
+        bson_doc = BCON_NEW("login", BCON_UTF8 (login),
+                            "cookie", BCON_UTF8 (a_auth_info->cookie),
+                            "pkey", BCON_UTF8 (a_auth_info->pkey),
+                            "last_use", BCON_DATE_TIME(mktime (utc_date_time) * 1000));
+
+        if (!mongoc_collection_insert (collection, MONGOC_INSERT_NONE, bson_doc, NULL, &error))
+        {
+            log_it (L_WARNING, "%s\n", error.message);
+            result = false;
+        }
+    }
+
+    mongoc_collection_destroy(collection);
+    mongoc_cursor_destroy(cursor_dap_cookie_history);
+    bson_destroy(query);
+    if(doc_dap_cookie)
+        bson_destroy(doc_dap_cookie);
+    if(bson_doc)
+        bson_destroy(bson_doc);
+
+    return result;
+}
+
+
+/**
+ * @brief dap_server_db_hash_password
+ * @param password
+ * @return
+ */
+unsigned char* dap_server_db_hash_password(const char* a_password)
+{
+    static const unsigned char s_salt[]={ 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08 };
+    static const size_t s_salt_size=sizeof (s_salt);
+
+    unsigned char *md = DAP_NEW_Z_SIZE(unsigned char, DB_AUTH_HASH_LENGTH * 2);
+
+    size_t a_password_length = strlen(a_password);
+    size_t l_str_length = a_password_length + s_salt_size;
+    unsigned char *l_str = DAP_NEW_Z_SIZE(unsigned char, l_str_length);
+
+    memcpy(l_str, a_password, a_password_length);
+    memcpy(l_str + a_password_length, s_salt, s_salt_size);
+    SHA3_512(md, l_str, l_str_length);
+    SHA3_512(md + DB_AUTH_HASH_LENGTH, s_salt, s_salt_size);
+
+    DAP_DELETE( l_str );
+    return md;
+}
+
+char* dap_server_db_hash_password_b64(const char* a_password)
+{
+    unsigned char* l_hash = dap_server_db_hash_password( a_password);
+    char * l_hash_str = DAP_NEW_Z_SIZE(char, 4 * DB_AUTH_HASH_LENGTH+1 ) ;
+
+    if (!l_hash_str) {
+        DAP_DELETE( (char*)l_hash);
+        log_it(L_ERROR, "Can not memmory allocate");
+        return NULL;
+    }
+
+    dap_enc_base64_encode(l_hash, DB_AUTH_HASH_LENGTH * 2, l_hash_str,DAP_ENC_DATA_TYPE_B64_URLSAFE);
+    return  l_hash_str;
+}
+/**
+ * @brief db_auth_login Authorization with user/password
+ * @param login ( login = email )
+ * @param password Password
+ * @param domain
+ * @return codes: 1 = login ok, 2 = login not found in DataBase,
+ * 3 = incorrect password; 4 = subscribe client has been expiried
+ */
+int db_auth_login(const char* login, const char* password,
+                  const char* domain, db_auth_info_t** ai)
+{
+    *ai = NULL;
+    bson_t *doc;
+
+    mongoc_collection_t *collection = mongoc_client_get_collection (
+                mongo_client, s_db_name, "dap_users");
+
+    bson_t *query = bson_new();
+
+    if (strchr(login, '@'))
+        BSON_APPEND_UTF8 (query, "email", login);
+    else
+        BSON_APPEND_UTF8 (query, "login", login);
+
+    mongoc_cursor_t *cursor =  mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0,
+                                                       (const bson_t*)query, NULL, NULL);
+
+    if ( mongoc_cursor_next (cursor, (const bson_t**)&doc) == false )
+    {
+        mongoc_cursor_destroy (cursor);
+        bson_destroy (query);
+        mongoc_collection_destroy (collection);
+        log_it(L_WARNING, "%s not found in DataBase", login);
+        return 2;
+    }
+
+    bson_iter_t iter;
+
+    unsigned const char* password_hash = dap_server_db_hash_password(password);
+    if (!password_hash) {
+        log_it(L_ERROR, "Can not memmory allocate");
+        return 0;
+    }
+
+    unsigned char * password_hash_b64 = calloc(4 * DB_AUTH_HASH_LENGTH, sizeof(char));
+
+    if (!password_hash_b64) {
+        free((char*)password_hash);
+        log_it(L_ERROR, "Can not memmory allocate");
+        return 0;
+    }
+
+    dap_enc_base64_encode(password_hash, DB_AUTH_HASH_LENGTH * 2, password_hash_b64,DAP_ENC_DATA_TYPE_B64_URLSAFE);
+
+    if (bson_iter_init (&iter, doc) && bson_iter_find (&iter, "expire_date")) {
+        if ( bson_iter_date_time(&iter) / 1000 < time(NULL) )
+        {
+            log_it(L_WARNING, "Subscribe %s has been expiried", login);
+            return 4;
+        }
+    }else
+        log_it(L_NOTICE, "Haven't found expire_date in collection");
+
+    if (bson_iter_init (&iter, doc) && bson_iter_find (&iter, "passwordHash")) {
+        if ( memcmp(password_hash_b64, bson_iter_value(&iter)->value.v_utf8.str,
+                    DB_AUTH_HASH_LENGTH * 2) == 0 )
+        {
+            {
+                bool b_error = false;
+                mongoc_collection_t *collection_dap_domain = mongoc_client_get_collection
+                        (mongo_client, s_db_name, "dap_domains");
+
+                bson_t *query = bson_new();
+
+                BSON_APPEND_UTF8 (query, "domain", domain);
+
+                mongoc_cursor_t *cursor_dap_domains =
+                        mongoc_collection_find (collection_dap_domain, MONGOC_QUERY_NONE, 0, 0, 0, query, NULL, NULL);
+
+                bson_t *doc_dap_domain;
+
+                if ( mongoc_cursor_next (cursor_dap_domains, (const bson_t**)&doc_dap_domain) == false )
+                {
+                    log_it(L_WARNING, "Login Error! "
+                                      "Domains not found in DataBase (collection dap_domains)");
+
+                    b_error = true;
+                }
+
+                mongoc_cursor_destroy (cursor_dap_domains);
+                bson_destroy (query);
+                if(doc_dap_domain)
+                    bson_destroy (doc_dap_domain);
+                mongoc_collection_destroy (collection_dap_domain);
+
+                //if(b_error)
+                //    return 0;
+            }
+
+            log_it(L_INFO,"Login accepted");
+
+            *ai = DAP_NEW_Z(db_auth_info_t);
+            strncpy((*ai)->user,login,sizeof((*ai)->user)-1);
+            strncpy((*ai)->password,password,sizeof((*ai)->password)-1);
+
+            if ( !bson_iter_init (&iter, doc) )
+                log_it(L_ERROR,"Error iter init");
+
+            bson_oid_t oid;
+
+            if ( bson_iter_find(&iter, "_id") )
+            {
+                bson_oid_init_from_data(&oid, (const uint8_t*) &bson_iter_value(&iter)->value.v_oid.bytes);
+                bson_oid_to_string(&oid, (*ai)->id);
+            }
+            else
+                log_it(L_ERROR,"Not find Id");
+
+            bson_iter_t sub_iter;
+
+            if (bson_iter_init (&iter, doc) &&
+                    bson_iter_find_descendant (&iter, "profile.first_name", &sub_iter))
+                strncpy((*ai)->first_name,bson_iter_value(&sub_iter)->value.v_utf8.str,
+                        sizeof((*ai)->first_name)-1);
+
+            if (bson_iter_init (&iter, doc) &&
+                    bson_iter_find_descendant (&iter, "profile.last_name", &sub_iter))
+                strncpy((*ai)->last_name,bson_iter_value(&sub_iter)->value.v_utf8.str,
+                        sizeof((*ai)->last_name)-1);
+
+            if (bson_iter_init (&iter, doc) &&
+                    bson_iter_find_descendant (&iter, "profile.email", &sub_iter))
+                strncpy((*ai)->email,bson_iter_value(&sub_iter)->value.v_utf8.str,
+                        sizeof((*ai)->email)-1);
+
+            for(int i=0; i < sizeof((*ai)->cookie); i++)
+                (*ai)->cookie[i] = 65 + rand() % 25;
+
+            log_it(L_DEBUG,"Store cookie '%s' in the hash table",(*ai)->cookie);
+            s_save_cookie_inform_in_db(login, (*ai));
+            pthread_mutex_lock(&s_mutex_on_auth_hash);
+            HASH_ADD_STR(s_auths,cookie,(*ai));
+            pthread_mutex_unlock(&s_mutex_on_auth_hash);
+        }else{
+            log_it(L_WARNING, "Input password has hash %s but expected to have %s",password_hash_b64, bson_iter_value(&iter)->value.v_utf8.str );
+        }
+    }else{
+        log_it(L_WARNING, "No passwordHash in data");
+    }
+
+    free(password_hash_b64);
+    free((char*)password_hash);
+    mongoc_cursor_destroy (cursor);
+    if(query)
+        bson_destroy (query);
+
+    if(doc)
+        bson_destroy (doc);
+    mongoc_collection_destroy (collection);
+
+    if( *ai == NULL )
+    {
+        log_it (L_WARNING, "Incorrect password!");
+        return 3;
+    }
+    return 1;
+}
+
+/**
+ * @brief db_auth_register Register new user in database
+ * @param user Login name
+ * @param password Password
+ * @param first_name First name
+ * @param last_name Last name
+ * @param email Email
+ * @details registerUser
+ * @return
+ */
+db_auth_info_t * db_auth_register(const char *user,const char *password,
+                                  const char *domain, const char * first_name,
+                                  const char* last_name, const char * email,
+                                  const char * device_type,const char *app_version,
+                                  const char *hostaddr, const char *sys_uuid )
+{
+    mongoc_collection_t *collection_dap_domain = mongoc_client_get_collection
+            (mongo_client, s_db_name, "dap_domains");
+
+    bson_t *query = bson_new();
+
+    BSON_APPEND_UTF8 (query, "domain", domain);
+
+    mongoc_cursor_t *cursor_dap_domains = mongoc_collection_find
+            (collection_dap_domain, MONGOC_QUERY_NONE, 0, 0, 0, query, NULL, NULL);
+
+    bson_t *doc_dap_domain;
+
+    if ( mongoc_cursor_next (cursor_dap_domains, (const bson_t**)&doc_dap_domain) == false )
+    {
+        log_it(L_WARNING, "Domain not found in DataBase (collection dap_domains) ");
+        return NULL;
+    }
+
+    bson_iter_t iter;
+    bson_iter_init (&iter, doc_dap_domain);
+    if ( !bson_iter_find (&iter, "_id") )
+    {
+        log_it(L_ERROR, "Where field _id in document?!");
+        return NULL;
+    }
+
+    mongoc_collection_t *collection = mongoc_client_get_collection
+            (mongo_client, s_db_name, "dap_users");
+    bson_error_t error;
+
+
+
+    char * l_password_hash_b64 = dap_server_db_hash_password_b64(password);
+
+    if (!l_password_hash_b64) {
+        log_it(L_ERROR, "Can not memmory allocate");
+        return NULL;
+    }
+
+    if (*l_password_hash_b64 == 0) {
+        log_it(L_ERROR, "Bad hash(based64) for user password");
+        return NULL;
+    }
+
+    bson_t *doc = BCON_NEW("login", user,
+                           "passwordHash", l_password_hash_b64,
+                           "domainId", BCON_OID((bson_oid_t*)bson_iter_value(&iter)->value.v_oid.bytes),
+                           "email", email,
+                           "profile",
+                           "{",
+                           "first_name", first_name,
+                           "last_name", last_name,
+                           "}",
+                           "contacts" , "[","]");
+    free(l_password_hash_b64);
+
+    if (!mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, &error)) {
+        log_it (L_WARNING, "%s\n", error.message);
+
+        bson_destroy(query);
+        mongoc_collection_destroy (collection_dap_domain);
+        bson_destroy(doc_dap_domain);
+        mongoc_cursor_destroy(cursor_dap_domains);
+        bson_destroy (doc);
+        mongoc_collection_destroy (collection);
+        mongoc_cleanup();
+        return NULL;
+    }
+    else
+    {
+        db_auth_info_t * ai = DAP_NEW_Z(db_auth_info_t);
+        strncpy(ai->user,user,sizeof(ai->user)-1);
+        strncpy(ai->password,password,sizeof(ai->password)-1);
+        strncpy(ai->last_name,last_name,sizeof(ai->last_name)-1);
+        strncpy(ai->first_name,first_name,sizeof(ai->first_name)-1);
+        strncpy(ai->email,email,sizeof(ai->email)-1);
+
+        for(int i=0;i<sizeof(ai->cookie);i++)
+            ai->cookie[i]=65+rand()%25;
+
+        pthread_mutex_lock(&s_mutex_on_auth_hash);
+        HASH_ADD_STR(s_auths,cookie,ai);
+        pthread_mutex_unlock(&s_mutex_on_auth_hash);
+
+        bson_destroy(query);
+        mongoc_collection_destroy (collection_dap_domain);
+        bson_destroy(doc_dap_domain);
+        mongoc_cursor_destroy(cursor_dap_domains);
+        bson_destroy (doc);
+        mongoc_collection_destroy (collection);
+        mongoc_cleanup();
+
+        return ai;
+    }
+
+    return NULL;
+}
+
+
+/**
+ * @brief db_auth_register_channel
+ * @param login
+ * @param password
+ * @details register channel
+ * @return
+ */
+db_auth_info_t * db_auth_register_channel(const char* name_channel, const char* domain,
+                                          const char* password)
+{
+    mongoc_collection_t *collection_dap_domain = mongoc_client_get_collection
+            (mongo_client, s_db_name, "dap_domains");
+
+    bson_t *query = bson_new();
+
+    BSON_APPEND_UTF8 (query, "domain", domain);
+
+    mongoc_cursor_t *cursor_dap_domains =
+            mongoc_collection_find (collection_dap_domain, MONGOC_QUERY_NONE, 0, 0, 0, query, NULL, NULL);
+
+    bson_t *doc_dap_domain;
+
+    if ( mongoc_cursor_next (cursor_dap_domains, (const bson_t**)&doc_dap_domain) == false )
+    {
+        log_it(L_WARNING, "Domain not found in DataBase (collection dap_domains) ");
+        return NULL;
+    }
+
+    bson_iter_t iter;
+    bson_iter_init (&iter, doc_dap_domain);
+    if ( !bson_iter_find (&iter, "_id") )
+    {
+        log_it(L_ERROR, "Where field _id in document?!");
+        return NULL;
+    }
+
+    mongoc_collection_t *collection =
+            mongoc_client_get_collection (mongo_client, s_db_name, "dap_channels");
+    bson_error_t error;
+
+
+    char * l_password_hash_b64 = dap_server_db_hash_password_b64(password);
+
+    bson_t *doc = BCON_NEW("name_channel", name_channel,
+                           "passwordHash", l_password_hash_b64,
+                           "domainId", BCON_OID((bson_oid_t*)bson_iter_value(&iter)->value.v_oid.bytes),
+                           "subscribers", "[","]",
+                           "last_id_message", BCON_INT32(0),
+                           "messages","[","]");
+
+    DAP_DELETE( l_password_hash_b64 );
+    if (!mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, &error)) {
+        log_it (L_ERROR, "%s\n", error.message);
+        bson_destroy(query);
+        bson_destroy(doc_dap_domain);
+        mongoc_cursor_destroy(cursor_dap_domains);
+        mongoc_collection_destroy(collection_dap_domain);
+        bson_destroy (doc);
+        mongoc_collection_destroy (collection);
+        mongoc_cleanup();
+        return NULL;
+    }
+
+    db_auth_info_t * ai = DAP_NEW_Z(db_auth_info_t);
+    strncpy(ai->user,name_channel,sizeof(ai->user)-1);
+    strncpy(ai->password,password,sizeof(ai->password)-1);
+
+    for(size_t i=0;i<sizeof(ai->cookie);i++)
+        ai->cookie[i]=65+rand()%25;
+
+    pthread_mutex_lock(&s_mutex_on_auth_hash);
+    HASH_ADD_STR(s_auths,cookie,ai);
+    pthread_mutex_unlock(&s_mutex_on_auth_hash);
+
+    bson_destroy(query);
+    bson_destroy(doc_dap_domain);
+    mongoc_cursor_destroy(cursor_dap_domains);
+    mongoc_collection_destroy(collection_dap_domain);
+    bson_destroy (doc);
+    mongoc_collection_destroy (collection);
+    mongoc_cleanup();
+
+    return ai;
+}
+
+bool exist_user_in_db(const char* user)
+{
+    bool exist = true;
+    bson_t *doc = NULL;
+
+    mongoc_collection_t *collection = mongoc_client_get_collection (
+                mongo_client, s_db_name, "dap_users");
+
+    bson_t *query = bson_new();
+    BSON_APPEND_UTF8 (query, "login", user);
+
+    mongoc_cursor_t *cursor =  mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0,
+                                                       (const bson_t*)query, NULL, NULL);
+
+    if ( mongoc_cursor_next (cursor, (const bson_t**)&doc) == false )
+    {
+        exist = false;
+        log_it(L_WARNING, "Login not found in DataBase");
+    }
+
+    if(doc)
+        bson_destroy(doc);
+
+    mongoc_cursor_destroy(cursor);
+    bson_destroy(query);
+    mongoc_collection_destroy(collection);
+
+    return exist;
+}
+
+
+
+/**
+ * @brief db_auth_http_proc DB Auth http interface
+ * @param a_delegate HTTP Simple client instance
+ * @param a_arg Pointer to bool with okay status (true if everything is ok, by default)
+ */
+void db_auth_http_proc(enc_http_delegate_t *a_delegate, void * a_arg)
+{
+    http_status_code_t * return_code = (http_status_code_t*)a_arg;
+
+    if((a_delegate->request)&&(strcmp(a_delegate->action,"POST")==0)){
+        if(a_delegate->in_query==NULL){
+            log_it(L_WARNING,"Empty auth action");
+            *return_code = Http_Status_BadRequest;
+            return;
+        }else{
+            if(strcmp(a_delegate->in_query,"logout")==0 ){
+                db_auth_info_t * ai = s_info_by_cookie(a_delegate->cookie);
+                if(ai){
+                    log_it(L_DEBUG, "Cookie from %s user accepted, 0x%032llX session",ai->user,ai->id);
+                    pthread_mutex_lock(&s_mutex_on_auth_hash);
+                    HASH_DEL(s_auths,ai);
+                    pthread_mutex_unlock(&s_mutex_on_auth_hash);
+                    free(ai);
+                    enc_http_reply_f(a_delegate,
+                                     "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n"
+                                     "<return>Successfuly logouted</return>\n"
+                                     );
+                    *return_code = Http_Status_OK;
+                }else{
+                    log_it(L_NOTICE,"Logout action: session 0x%032llX is already logouted (by timeout?)",ai->id);
+                    enc_http_reply_f(a_delegate,
+                                     "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n"
+                                     "<err_str>No session in table</err_str>\n"
+                                     );
+                    *return_code = Http_Status_OK;
+                }
+
+            }else if(strcmp(a_delegate->in_query,"login")==0 ){
+                char l_user[256]={0};
+                char l_password[1024]={0};
+                char l_domain[64]={0};
+                char l_pkey[4096]={0};
+                char l_something[64] = {0};
+
+                if(sscanf(a_delegate->request_str,"%255s %1023s %63s %4095s %64s",l_user,l_password,l_domain,l_pkey,l_something)>=3){
+                    log_it(L_INFO, "Trying to login with username '%s'",l_user);
+
+                    if(!check_user_data_for_space(strlen(a_delegate->request_str), strlen(l_user) + strlen(l_password) + strlen(l_domain) + strlen(l_pkey) + strlen(l_something))){
+                        log_it(L_WARNING,"Wrong symbols in username or password or domain, misfit is %d", strlen(a_delegate->request_str) - strlen(l_user) - strlen(l_password) - strlen(l_domain) - strlen(l_pkey) - strlen(l_something));
+                        //log_it(L_WARNING, "l_user size: %d", strlen(l_user));
+                        //log_it(L_WARNING, "l_pass size: %d", strlen(l_password));
+                        //log_it(L_WARNING, "l_pkey size: %d", strlen(l_pkey));
+                        log_it(L_DEBUG,"%s@%s", l_user, l_password);
+
+                        enc_http_reply_f(a_delegate, OP_CODE_INCORRECT_SYMOLS);
+                        *return_code = Http_Status_BadRequest;
+                        return;
+                    }
+//                    if(db_input_validation(user)==0){
+//                        log_it(L_WARNING,"Wrong symbols in username '%s'",user);
+//                        enc_http_reply_f(dg, OP_CODE_INCORRECT_SYMOLS);
+//                        *return_code = Http_Status_BadRequest;
+//                        return;
+//                    }
+//                    if(db_input_validation(password)==0){
+//                        log_it(L_WARNING,"Wrong symbols in password");
+//                        enc_http_reply_f(dg, OP_CODE_INCORRECT_SYMOLS);
+//                        *return_code = Http_Status_BadRequest;
+//                        return;
+//                    }
+//                    if(db_input_validation(domain)==0){
+//                        log_it(L_WARNING,"Wrong symbols in domain");
+//                        enc_http_reply_f(dg, OP_CODE_INCORRECT_SYMOLS);
+//                        *return_code = Http_Status_BadRequest;
+//                        return;
+//                    }
+
+                    db_auth_info_t * l_auth_info = NULL;
+                    short login_result = db_auth_login(l_user, l_password, l_domain, &l_auth_info);
+                    switch (login_result) {
+                    case 1:
+                        l_auth_info->dap_http_client = a_delegate->http;
+                        l_auth_info->auth_date = time(NULL);
+                        if (l_pkey[0] )
+                            strncpy(l_auth_info->pkey,l_pkey, sizeof (l_auth_info->pkey)-1);
+                        enc_http_reply_f(a_delegate,
+                                         "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n"
+                                         "<auth_info>\n"
+                                         );
+                        enc_http_reply_f(a_delegate,"\t<first_name>%s</first_name>\n",l_auth_info->first_name);
+                        enc_http_reply_f(a_delegate,"\t<last_name>%s</last_name>\n",l_auth_info->last_name);
+                        enc_http_reply_f(a_delegate,"\t<cookie>%s</cookie>\n",l_auth_info->cookie);
+                        if (s_callback_success)
+                            s_callback_success (a_delegate, l_auth_info); // Here if smbd want to add smth to the output
+                        enc_http_reply_f(a_delegate,"</auth_info>");
+                        log_it(L_INFO, "Login: Successfuly logined user %s",l_user);
+                        *return_code = Http_Status_OK;
+                        break;
+                    case 2:
+                        enc_http_reply_f(a_delegate, OP_CODE_NOT_FOUND_LOGIN_IN_DB);
+                        *return_code = Http_Status_OK;
+                        break;
+                    case 3:
+                        enc_http_reply_f(a_delegate, OP_CODE_LOGIN_INCORRECT_PSWD);
+                        *return_code = Http_Status_OK;
+                        break;
+                    case 4:
+                        enc_http_reply_f(a_delegate, OP_CODE_SUBSCRIBE_EXPIRIED);
+                        *return_code = Http_Status_PaymentRequired;
+                        break;
+                    default:
+                        log_it(L_DEBUG, "Login: wrong password for user %s",l_user);
+                        *return_code = Http_Status_BadRequest;
+                        break;
+                    }
+                }else{
+                    log_it(L_DEBUG, "Login: wrong auth's request body ");
+                    *return_code = Http_Status_BadRequest;
+                }
+            }else if (strcmp(a_delegate->in_query,"register")==0){
+                char user[256];
+                char password[1024];
+                char domain[64];
+                char first_name[1024];
+                char last_name[1024];
+                // char phone_number[1024];
+
+                char email[1024];
+                char device_type[32];
+                char app_version[32];
+                char sys_uuid[128];
+
+                log_it(L_INFO, "Request str = %s", a_delegate->request_str);
+                if(sscanf(a_delegate->request_str,"%255s %63s %1023s %1023s %1023s %1023s %32s %128s"
+                          ,user,password,domain,first_name,last_name,email,device_type,app_version)>=7){
+                    if(db_input_validation(user)==0){
+                        log_it(L_WARNING,"Registration: Wrong symbols in the username '%s'",user);
+                        *return_code = Http_Status_BadRequest;
+                        return;
+                    }
+                    if(db_input_validation(password)==0){
+                        log_it(L_WARNING,"Registration: Wrong symbols in the password");
+                        *return_code = Http_Status_BadRequest;
+                        return;
+                    }
+                    if(db_input_validation(domain)==0){
+                        log_it(L_WARNING,"Registration: Wrong symbols in the password");
+                        *return_code = Http_Status_BadRequest;
+                        return;
+                    }
+                    if(db_input_validation(first_name)==0){
+                        log_it(L_WARNING,"Registration: Wrong symbols in the first name '%s'",first_name);
+                        *return_code = Http_Status_BadRequest;
+                        return;
+                    }
+                    if(db_input_validation(last_name)==0){
+                        log_it(L_WARNING,"Registration: Wrong symbols in the last name '%s'",last_name);
+                        *return_code = Http_Status_BadRequest;
+                        return;
+                    }
+                    if(db_input_validation(email)==0){
+                        log_it(L_WARNING,"Registration: Wrong symbols in the email '%s'",email);
+                        *return_code = Http_Status_BadRequest;
+                        return;
+                    }
+
+                    db_auth_info_t * ai = db_auth_register(user,password,domain,first_name,last_name,email,
+                                                           device_type,app_version,a_delegate->http->client->hostaddr,sys_uuid);
+
+                    if(ai != NULL)
+                    {
+                        enc_http_reply_f(a_delegate,
+                                         "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n"
+                                         "<auth_info>\n"
+                                         );
+                        enc_http_reply_f(a_delegate,"\t<first_name>%s</first_name>\n",ai->first_name);
+                        enc_http_reply_f(a_delegate,"\t<last_name>%s</last_name>\n",ai->last_name);
+                        enc_http_reply_f(a_delegate,"\t<cookie>%s</cookie>\n",ai->cookie);
+                        enc_http_reply_f(a_delegate,"</auth_info>");
+
+                        log_it(L_NOTICE,"Registration: new user %s \"%s %s\"<%s> is registred",user,first_name,last_name,email);
+                    }
+                    else {
+                        log_it(L_WARNING, "User not registered. Maybe login already exists");
+                    }
+                }else{
+                    log_it(L_ERROR, "Registration: Wrong auth's request body ");
+                    *return_code = Http_Status_BadRequest;
+                }
+            }else{
+                log_it(L_ERROR, "Unknown auth command was selected (query_string='%s')",a_delegate->in_query);
+                *return_code = Http_Status_BadRequest;
+            }
+        }
+    }else{
+        log_it(L_ERROR, "Wrong auth request action '%s'",a_delegate->action);
+        *return_code = Http_Status_BadRequest;
+    }
+}
+
+static bool mongod_is_running()
+{
+    int pfd[2];
+    pipe(pfd);
+
+    pid_t   childpid;
+
+    if((childpid = fork()) == -1)
+    {
+        log_it(L_ERROR,"Error fork()");
+        return false;
+    }
+
+    if(childpid == 0)
+    {
+        close(STDOUT_FILENO);
+        dup2(pfd[1], STDOUT_FILENO);
+        close(pfd[0]);
+        close(pfd[1]);
+        execlp("pgrep", "pgrep","mongod", NULL);
+        exit(0);
+    }
+
+    waitpid(childpid, 0, 0);
+
+    char readbuffer[10] = {'\0'};
+
+    int flags = fcntl(pfd[0], F_GETFL, 0);
+    fcntl(pfd[0], F_SETFL, flags | O_NONBLOCK);
+    read(pfd[0], readbuffer, sizeof(readbuffer));
+
+    if(readbuffer[0] == '\0')
+    {
+        log_it(L_ERROR,"MongoDB service not running. For start use: \"mongod\" in terminal");
+        return false;
+    }
+
+    close(pfd[0]);
+    close(pfd[1]);
+
+    return true;
+}
+
+
+
+/// Check user data for correct input.
+/// @param before_parsing Line size before parsing.
+/// @param after_parsing Line size after parsing.
+/// @return Returns true if user data is entered correctly
+/// (there are 2 separator spaces), otherwise false.
+bool check_user_data_for_space(size_t before_parsing, size_t after_parsing)
+{
+    return (before_parsing - after_parsing) == 3;
+}
+
+
+
+
+int dap_chain_net_srv_vpn_cdb_auth_add_proc(dap_http_t * a_http, const char * a_url)
+{
+
+}
+
+
+
+
diff --git a/dap_chain_net_srv_vpn_cdb_auth.h b/dap_chain_net_srv_vpn_cdb_auth.h
new file mode 100644
index 0000000..4d979ba
--- /dev/null
+++ b/dap_chain_net_srv_vpn_cdb_auth.h
@@ -0,0 +1,31 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * CellFrame       https://cellframe.net
+ * Sources         https://gitlab.demlabs.net/cellframe
+ * Copyright  (c) 2017-2020
+ * All rights reserved.
+
+ This file is part of CellFrame SDK the open source project
+
+    CellFrame SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    CellFrame SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include "dap_http.h"
+#include "dap_enc_http.h"
+
+int dap_chain_net_srv_vpn_cdb_auth_add_proc(dap_http_t * a_http, const char * a_url);
+void dap_chain_net_srv_vpn_cdb_auth_set_callback(dap_enc_http_callback_t a_callback_success);
-- 
GitLab