diff options
Diffstat (limited to 'protocols/Telegram/tgl/mtproto-client.c')
-rw-r--r-- | protocols/Telegram/tgl/mtproto-client.c | 1489 |
1 files changed, 0 insertions, 1489 deletions
diff --git a/protocols/Telegram/tgl/mtproto-client.c b/protocols/Telegram/tgl/mtproto-client.c deleted file mode 100644 index 37530b5afb..0000000000 --- a/protocols/Telegram/tgl/mtproto-client.c +++ /dev/null @@ -1,1489 +0,0 @@ -/* - This file is part of tgl-library - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - Copyright Nikolay Durov, Andrey Lopatin 2012-2013 - Vitaly Valtman 2013-2015 -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define _FILE_OFFSET_BITS 64 - -#include <assert.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <signal.h> -#if defined(WIN32) || defined(_WIN32) -#include <io.h> -#include <stdint.h> -#include <winsock2.h> -#include <ws2tcpip.h> -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#undef WIN32_LEAN_AND_MEAN -#else -#include <unistd.h> -#include <netdb.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <poll.h> -#endif -#include <fcntl.h> -#if defined(__FreeBSD__) || defined(__OpenBSD__) -#include <sys/endian.h> -#endif -#include <sys/types.h> -#include <openssl/rand.h> -#include <openssl/rsa.h> -#include <openssl/pem.h> -#include <openssl/sha.h> - -//#include "telegram.h" -#include "queries.h" -//#include "loop.h" -#include "tgl-structures.h" -#include "tgl-binlog.h" -#include "auto.h" -#include "auto/auto-types.h" -#include "auto/auto-skip.h" -#include "tgl.h" -#include "mtproto-client.h" -#include "tools.h" -#include "tree.h" -#include "updates.h" -#include "mtproto-utils.h" -#include "auto.h" -#include "tgl-methods-in.h" - -#if defined(__FreeBSD__) -#define __builtin_bswap32(x) bswap32(x) -#endif - -#if defined(__OpenBSD__) -#define __builtin_bswap32(x) __swap32gen(x) -#endif - -#define sha1 SHA1 - -#include "mtproto-common.h" - -#define MAX_NET_RES (1L << 16) -//extern int log_level; - -static long long generate_next_msg_id (struct tgl_state *TLS, struct tgl_dc *DC, struct tgl_session *S); -static double get_server_time (struct tgl_dc *DC); - -#if !defined(HAVE___BUILTIN_BSWAP32) && !defined(__FreeBSD__) && !defined(__OpenBSD__) -static inline unsigned __builtin_bswap32(unsigned x) { - return ((x << 24) & 0xff000000 ) | - ((x << 8) & 0x00ff0000 ) | - ((x >> 8) & 0x0000ff00 ) | - ((x >> 24) & 0x000000ff ); -} -#endif - -// for statistic only -static int total_packets_sent; -static long long total_data_sent; - - -static int rpc_execute (struct tgl_state *TLS, struct connection *c, int op, int len); -static int rpc_becomes_ready (struct tgl_state *TLS, struct connection *c); -static int rpc_close (struct tgl_state *TLS, struct connection *c); - -static double get_utime (int clock_id) { - struct timespec T; - tgl_my_clock_gettime (clock_id, &T); - return T.tv_sec + (double) T.tv_nsec * 1e-9; -} - - -#define MAX_RESPONSE_SIZE (1L << 24) - -static RSA *rsa_load_public_key (struct tgl_state *TLS, const char *public_key_name) { -#if defined(_MSC_VER) && _MSC_VER >= 1400 - FILE * f = NULL; - errno_t err = fopen_s(&f, public_key_name, "r"); - if (err != 0) { -#else - FILE *f = fopen (public_key_name, "r"); - if (f == NULL) { -#endif - vlogprintf (E_WARNING, "Couldn't open public key file: %s\n", public_key_name); - return NULL; - } - RSA *res = PEM_read_RSAPublicKey (f, NULL, NULL, NULL); - fclose (f); - if (res == NULL) { - vlogprintf (E_WARNING, "PEM_read_RSAPublicKey returns NULL.\n"); - return NULL; - } - - vlogprintf (E_NOTICE, "public key '%s' loaded successfully\n", public_key_name); - - return res; -} - - - - -/* - * - * UNAUTHORIZED (DH KEY EXCHANGE) PROTOCOL PART - * - */ - -#define ENCRYPT_BUFFER_INTS 16384 -static int encrypt_buffer[ENCRYPT_BUFFER_INTS]; - -#define DECRYPT_BUFFER_INTS 16384 -static int decrypt_buffer[ENCRYPT_BUFFER_INTS]; - -static int encrypt_packet_buffer (struct tgl_state *TLS, struct tgl_dc *DC) { - RSA *key = TLS->rsa_key_loaded[DC->rsa_key_idx]; - return tgl_pad_rsa_encrypt (TLS, (char *) packet_buffer, (packet_ptr - packet_buffer) * 4, (char *) encrypt_buffer, ENCRYPT_BUFFER_INTS * 4, key->n, key->e); -} - -static int encrypt_packet_buffer_aes_unauth (const char server_nonce[16], const char hidden_client_nonce[32]) { - tgl_init_aes_unauth (server_nonce, hidden_client_nonce, AES_ENCRYPT); - return tgl_pad_aes_encrypt ((char *) packet_buffer, (packet_ptr - packet_buffer) * 4, (char *) encrypt_buffer, ENCRYPT_BUFFER_INTS * 4); -} - -// -// Used in unauthorized part of protocol -// -static int rpc_send_packet (struct tgl_state *TLS, struct connection *c) { - static struct { - long long auth_key_id; - long long out_msg_id; - int msg_len; - } unenc_msg_header; - - int len = (packet_ptr - packet_buffer) * 4; - TLS->net_methods->incr_out_packet_num (c); - - struct tgl_dc *DC = TLS->net_methods->get_dc (c); - struct tgl_session *S = TLS->net_methods->get_session (c); - - unenc_msg_header.out_msg_id = generate_next_msg_id (TLS, DC, S); - unenc_msg_header.msg_len = len; - - int total_len = len + 20; - assert (total_len > 0 && !(total_len & 0xfc000003)); - total_len >>= 2; - vlogprintf (E_DEBUG, "writing packet: total_len = %d, len = %d\n", total_len, len); - if (total_len < 0x7f) { - assert (TLS->net_methods->write_out (c, &total_len, 1) == 1); - } else { - total_len = (total_len << 8) | 0x7f; - assert (TLS->net_methods->write_out (c, &total_len, 4) == 4); - } - TLS->net_methods->write_out (c, &unenc_msg_header, 20); - TLS->net_methods->write_out (c, packet_buffer, len); - TLS->net_methods->flush_out (c); - - total_packets_sent ++; - total_data_sent += total_len; - return 1; -} - -static int rpc_send_message (struct tgl_state *TLS, struct connection *c, void *data, int len) { - assert (len > 0 && !(len & 0xfc000003)); - - int total_len = len >> 2; - if (total_len < 0x7f) { - assert (TLS->net_methods->write_out (c, &total_len, 1) == 1); - } else { - total_len = (total_len << 8) | 0x7f; - assert (TLS->net_methods->write_out (c, &total_len, 4) == 4); - } - - TLS->net_methods->incr_out_packet_num (c); - assert (TLS->net_methods->write_out (c, data, len) == len); - TLS->net_methods->flush_out (c); - - total_packets_sent ++; - total_data_sent += total_len; - return 1; -} - -// -// State machine. See description at -// https://core.telegram.org/mtproto/auth_key -// - - -static int check_unauthorized_header (struct tgl_state *TLS) { - long long auth_key_id = fetch_long (); - if (auth_key_id) { - vlogprintf (E_ERROR, "ERROR: auth_key_id should be NULL\n"); - return -1; - } - fetch_long (); // msg_id - int len = fetch_int (); - if (len != 4 * (in_end - in_ptr)) { - vlogprintf (E_ERROR, "ERROR: length mismatch\n"); - return -1; - } - return 0; -} - -/* {{{ REQ_PQ */ -// req_pq#60469778 nonce:int128 = ResPQ -static int send_req_pq_packet (struct tgl_state *TLS, struct connection *c) { - struct tgl_dc *DC = TLS->net_methods->get_dc (c); - assert (DC->state == st_init); - - tglt_secure_random (DC->nonce, 16); - clear_packet (); - out_int (CODE_req_pq); - out_ints ((int *)DC->nonce, 4); - rpc_send_packet (TLS, c); - - DC->state = st_reqpq_sent; - return 1; -} - -// req_pq#60469778 nonce:int128 = ResPQ -static int send_req_pq_temp_packet (struct tgl_state *TLS, struct connection *c) { - struct tgl_dc *DC = TLS->net_methods->get_dc (c); - assert (DC->state == st_authorized); - - tglt_secure_random (DC->nonce, 16); - clear_packet (); - out_int (CODE_req_pq); - out_ints ((int *)DC->nonce, 4); - rpc_send_packet (TLS, c); - - DC->state = st_reqpq_sent_temp; - return 1; -} -/* }}} */ - -/* {{{ REQ DH */ -// req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params; -// p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data; -// p_q_inner_data_temp#3c6a84d4 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 expires_in:int = P_Q_inner_data; -static void send_req_dh_packet (struct tgl_state *TLS, struct connection *c, BIGNUM *pq, int temp_key) { - struct tgl_dc *DC = TLS->net_methods->get_dc (c); - - BIGNUM *p = BN_new (); - BIGNUM *q = BN_new (); - assert (bn_factorize (pq, p, q) >= 0); - - clear_packet (); - packet_ptr += 5; - out_int (temp_key ? CODE_p_q_inner_data_temp : CODE_p_q_inner_data); - - out_bignum (pq); - out_bignum (p); - out_bignum (q); - - out_ints ((int *) DC->nonce, 4); - out_ints ((int *) DC->server_nonce, 4); - tglt_secure_random (DC->new_nonce, 32); - out_ints ((int *) DC->new_nonce, 8); - if (temp_key) { - out_int (TLS->temp_key_expire_time); - } - sha1 ((unsigned char *) (packet_buffer + 5), (packet_ptr - packet_buffer - 5) * 4, (unsigned char *) packet_buffer); - - int l = encrypt_packet_buffer (TLS, DC); - - clear_packet (); - out_int (CODE_req_DH_params); - out_ints ((int *) DC->nonce, 4); - out_ints ((int *) DC->server_nonce, 4); - out_bignum (p); - out_bignum (q); - - out_long (TLS->rsa_key_fingerprint[DC->rsa_key_idx]); - out_cstring ((char *) encrypt_buffer, l); - - BN_free (p); - BN_free (q); - DC->state = temp_key ? st_reqdh_sent_temp : st_reqdh_sent; - rpc_send_packet (TLS, c); -} -/* }}} */ - -/* {{{ SEND DH PARAMS */ -// set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer; -// client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data -static void send_dh_params (struct tgl_state *TLS, struct connection *c, BIGNUM *dh_prime, BIGNUM *g_a, int g, int temp_key) { - struct tgl_dc *DC = TLS->net_methods->get_dc (c); - - clear_packet (); - packet_ptr += 5; - out_int (CODE_client_DH_inner_data); - out_ints ((int *) DC->nonce, 4); - out_ints ((int *) DC->server_nonce, 4); - out_long (0); - - BIGNUM *dh_g = BN_new (); - ensure (BN_set_word (dh_g, g)); - - static unsigned char s_power[256]; - tglt_secure_random (s_power, 256); - BIGNUM *dh_power = BN_bin2bn ((unsigned char *)s_power, 256, 0); - ensure_ptr (dh_power); - - BIGNUM *y = BN_new (); - ensure_ptr (y); - ensure (BN_mod_exp (y, dh_g, dh_power, dh_prime, TLS->BN_ctx)); - out_bignum (y); - BN_free (y); - - BIGNUM *auth_key_num = BN_new (); - ensure (BN_mod_exp (auth_key_num, g_a, dh_power, dh_prime, TLS->BN_ctx)); - int l = BN_num_bytes (auth_key_num); - assert (l >= 250 && l <= 256); - assert (BN_bn2bin (auth_key_num, (unsigned char *)(temp_key ? DC->temp_auth_key : DC->auth_key))); - if (l < 256) { - char *key = temp_key ? DC->temp_auth_key : DC->auth_key; - memmove (key + 256 - l, key, l); - memset (key, 0, 256 - l); - } - - BN_free (dh_power); - BN_free (auth_key_num); - BN_free (dh_g); - - sha1 ((unsigned char *) (packet_buffer + 5), (packet_ptr - packet_buffer - 5) * 4, (unsigned char *) packet_buffer); - - l = encrypt_packet_buffer_aes_unauth (DC->server_nonce, DC->new_nonce); - - clear_packet (); - out_int (CODE_set_client_DH_params); - out_ints ((int *) DC->nonce, 4); - out_ints ((int *) DC->server_nonce, 4); - out_cstring ((char *) encrypt_buffer, l); - - DC->state = temp_key ? st_client_dh_sent_temp : st_client_dh_sent;; - rpc_send_packet (TLS, c); -} -/* }}} */ - -/* {{{ RECV RESPQ */ -// resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector long = ResPQ -static int process_respq_answer (struct tgl_state *TLS, struct connection *c, char *packet, int len, int temp_key) { - assert (!(len & 3)); - in_ptr = (int *)packet; - in_end = in_ptr + (len / 4); - if (check_unauthorized_header (TLS) < 0) { - return -1; - } - - int *in_save = in_ptr; - if (skip_type_any (TYPE_TO_PARAM (res_p_q)) < 0 || in_ptr != in_end) { - vlogprintf (E_ERROR, "can not parse req_p_q answer\n"); - return -1; - } - in_ptr = in_save; - - struct tgl_dc *DC = TLS->net_methods->get_dc (c); - - assert (fetch_int() == CODE_res_p_q); - - static int tmp[4]; - fetch_ints (tmp, 4); - if (memcmp (tmp, DC->nonce, 16)) { - vlogprintf (E_ERROR, "nonce mismatch\n"); - return -1; - } - fetch_ints (DC->server_nonce, 4); - - BIGNUM *pq = BN_new (); - assert (fetch_bignum (pq) >= 0); - - assert (fetch_int () == CODE_vector); - int fingerprints_num = fetch_int (); - assert (fingerprints_num >= 0); - DC->rsa_key_idx = -1; - - int i; - for (i = 0; i < fingerprints_num; i++) { - int j; - long long fprint = fetch_long (); - for (j = 0; j < TLS->rsa_key_num; j++) { - if (TLS->rsa_key_loaded[j]) { - if (fprint == TLS->rsa_key_fingerprint[j]) { - DC->rsa_key_idx = j; - break; - } - } - } - } - assert (in_ptr == in_end); - if (DC->rsa_key_idx == -1) { - vlogprintf (E_ERROR, "fatal: don't have any matching keys\n"); - return -1; - } - - send_req_dh_packet (TLS, c, pq, temp_key); - - BN_free (pq); - return 1; -} -/* }}} */ - -/* {{{ RECV DH */ -// server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params; -// server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params; -// server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data; -static int process_dh_answer (struct tgl_state *TLS, struct connection *c, char *packet, int len, int temp_key) { - assert (!(len & 3)); - in_ptr = (int *)packet; - in_end = in_ptr + (len / 4); - if (check_unauthorized_header (TLS) < 0) { - return -1; - } - - int *in_save = in_ptr; - if (skip_type_any (TYPE_TO_PARAM (server_d_h_params)) < 0 || in_ptr != in_end) { - vlogprintf (E_ERROR, "can not parse server_DH_params answer\n"); - return -1; - } - in_ptr = in_save; - - struct tgl_dc *DC = TLS->net_methods->get_dc (c); - - unsigned op = fetch_int (); - assert (op == CODE_server__d_h_params_ok || op == CODE_server__d_h_params_fail); - - int tmp[4]; - fetch_ints (tmp, 4); - if (memcmp (tmp, DC->nonce, 16)) { - vlogprintf (E_ERROR, "nonce mismatch\n"); - return -1; - } - assert (!memcmp (tmp, DC->nonce, 16)); - fetch_ints (tmp, 4); - if (memcmp (tmp, DC->server_nonce, 16)) { - vlogprintf (E_ERROR, "nonce mismatch\n"); - return -1; - } - assert (!memcmp (tmp, DC->server_nonce, 16)); - - if (op == CODE_server__d_h_params_fail) { - vlogprintf (E_ERROR, "DH params fail\n"); - return -1; - } - - tgl_init_aes_unauth (DC->server_nonce, DC->new_nonce, AES_DECRYPT); - - int l = prefetch_strlen (); - assert (l >= 0); - if (!l) { - vlogprintf (E_ERROR, "non-empty encrypted part expected\n"); - return -1; - } - l = tgl_pad_aes_decrypt (fetch_str (l), l, (char *) decrypt_buffer, DECRYPT_BUFFER_INTS * 4 - 16); - assert (in_ptr == in_end); - - in_ptr = decrypt_buffer + 5; - in_end = decrypt_buffer + (l >> 2); - if (skip_type_any (TYPE_TO_PARAM (server_d_h_inner_data)) < 0) { - vlogprintf (E_ERROR, "can not parse server_DH_inner_data answer\n"); - return -1; - } - in_ptr = decrypt_buffer + 5; - - assert (fetch_int () == (int)CODE_server_DH_inner_data); - fetch_ints (tmp, 4); - if (memcmp (tmp, DC->nonce, 16)) { - vlogprintf (E_ERROR, "nonce mismatch\n"); - return -1; - } - assert (!memcmp (tmp, DC->nonce, 16)); - fetch_ints (tmp, 4); - if (memcmp (tmp, DC->server_nonce, 16)) { - vlogprintf (E_ERROR, "nonce mismatch\n"); - return -1; - } - assert (!memcmp (tmp, DC->server_nonce, 16)); - int g = fetch_int (); - - BIGNUM *dh_prime = BN_new (); - BIGNUM *g_a = BN_new (); - assert (fetch_bignum (dh_prime) > 0); - assert (fetch_bignum (g_a) > 0); - - if (tglmp_check_DH_params (TLS, dh_prime, g) < 0) { - vlogprintf (E_ERROR, "bad DH params\n"); - return -1; - } - if (tglmp_check_g_a (TLS, dh_prime, g_a) < 0) { - vlogprintf (E_ERROR, "bad dh_prime\n"); - return -1; - } - - int server_time = fetch_int (); - assert (in_ptr <= in_end); - - static char sha1_buffer[20]; - sha1 ((unsigned char *) decrypt_buffer + 20, (in_ptr - decrypt_buffer - 5) * 4, (unsigned char *) sha1_buffer); - if (memcmp (decrypt_buffer, sha1_buffer, 20)) { - vlogprintf (E_ERROR, "bad encrypted message SHA1\n"); - return -1; - } - if ((char *) in_end - (char *) in_ptr >= 16) { - vlogprintf (E_ERROR, "too much padding\n"); - return -1; - } - - DC->server_time_delta = server_time - get_utime (CLOCK_REALTIME); - DC->server_time_udelta = server_time - get_utime (CLOCK_MONOTONIC); - - send_dh_params (TLS, c, dh_prime, g_a, g, temp_key); - - BN_free (dh_prime); - BN_free (g_a); - - return 1; -} -/* }}} */ - -static void create_temp_auth_key (struct tgl_state *TLS, struct connection *c) { - assert (TLS->enable_pfs); - send_req_pq_temp_packet (TLS, c); -} - -int tglmp_encrypt_inner_temp (struct tgl_state *TLS, struct connection *c, int *msg, int msg_ints, int useful, void *data, long long msg_id); -static long long msg_id_override; -static void mpc_on_get_config (struct tgl_state *TLS, void *extra, int success); -static void bind_temp_auth_key (struct tgl_state *TLS, struct connection *c); - -/* {{{ RECV AUTH COMPLETE */ - -// dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer; -// dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer; -// dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer; -static int process_auth_complete (struct tgl_state *TLS, struct connection *c, char *packet, int len, int temp_key) { - struct tgl_dc *DC = TLS->net_methods->get_dc (c); - - assert (!(len & 3)); - in_ptr = (int *)packet; - in_end = in_ptr + (len / 4); - if (check_unauthorized_header (TLS) < 0) { - return -1; - } - - int *in_save = in_ptr; - if (skip_type_any (TYPE_TO_PARAM (set_client_d_h_params_answer)) < 0 || in_ptr != in_end) { - vlogprintf (E_ERROR, "can not parse server_DH_params answer\n"); - return -1; - } - in_ptr = in_save; - - unsigned op = fetch_int (); - assert (op == CODE_dh_gen_ok || op == CODE_dh_gen_retry || op == CODE_dh_gen_fail); - - int tmp[4]; - fetch_ints (tmp, 4); - if (memcmp (DC->nonce, tmp, 16)) { - vlogprintf (E_ERROR, "nonce mismatch\n"); - return -1; - } - fetch_ints (tmp, 4); - if (memcmp (DC->server_nonce, tmp, 16)) { - vlogprintf (E_ERROR, "nonce mismatch\n"); - return -1; - } - if (op != CODE_dh_gen_ok) { - vlogprintf (E_ERROR, "something bad. Retry regen\n"); - return -1; - } - - fetch_ints (tmp, 4); - - static unsigned char th[44], sha1_buffer[20]; - memcpy (th, DC->new_nonce, 32); - th[32] = 1; - if (!temp_key) { - sha1 ((unsigned char *)DC->auth_key, 256, sha1_buffer); - } else { - sha1 ((unsigned char *)DC->temp_auth_key, 256, sha1_buffer); - } - memcpy (th + 33, sha1_buffer, 8); - sha1 (th, 41, sha1_buffer); - if (memcmp (tmp, sha1_buffer + 4, 16)) { - vlogprintf (E_ERROR, "hash mismatch\n"); - return -1; - } - - if (!temp_key) { - bl_do_set_auth_key (TLS, DC->id, (unsigned char *)DC->auth_key); - sha1 ((unsigned char *)DC->auth_key, 256, sha1_buffer); - } else { - sha1 ((unsigned char *)DC->temp_auth_key, 256, sha1_buffer); - DC->temp_auth_key_id = *(long long *)(sha1_buffer + 12); - } - - DC->server_salt = *(long long *)DC->server_nonce ^ *(long long *)DC->new_nonce; - - DC->state = st_authorized; - - vlogprintf (E_DEBUG, "Auth success\n"); - if (temp_key) { - bind_temp_auth_key (TLS, c); - } else { - DC->flags |= 1; - if (TLS->enable_pfs) { - create_temp_auth_key (TLS, c); - } else { - DC->temp_auth_key_id = DC->auth_key_id; - memcpy (DC->temp_auth_key, DC->auth_key, 256); - DC->flags |= 2; - if (!(DC->flags & 4)) { - tgl_do_help_get_config_dc (TLS, DC, mpc_on_get_config, DC); - } - } - } - - return 1; -} -/* }}} */ - -static void bind_temp_auth_key (struct tgl_state *TLS, struct connection *c) { - struct tgl_dc *DC = TLS->net_methods->get_dc (c); - if (DC->temp_auth_key_bind_query_id) { - tglq_query_delete (TLS, DC->temp_auth_key_bind_query_id); - } - struct tgl_session *S = TLS->net_methods->get_session (c); - long long msg_id = generate_next_msg_id (TLS, DC, S); - - clear_packet (); - out_int (CODE_bind_auth_key_inner); - long long rand; - tglt_secure_random (&rand, 8); - out_long (rand); - out_long (DC->temp_auth_key_id); - out_long (DC->auth_key_id); - - if (!S->session_id) { - tglt_secure_random (&S->session_id, 8); - } - out_long (S->session_id); - int expires = (int)time (0) + DC->server_time_delta + TLS->temp_key_expire_time; - out_int (expires); - - static int data[1000]; - int len = tglmp_encrypt_inner_temp (TLS, c, packet_buffer, packet_ptr - packet_buffer, 0, data, msg_id); - msg_id_override = msg_id; - DC->temp_auth_key_bind_query_id = msg_id; - tgl_do_send_bind_temp_key (TLS, DC, rand, expires, (void *)data, len, msg_id); - msg_id_override = 0; -} - -/* - * - * AUTHORIZED (MAIN) PROTOCOL PART - * - */ - -static struct encrypted_message enc_msg; - -static double get_server_time (struct tgl_dc *DC) { - //if (!DC->server_time_udelta) { - // DC->server_time_udelta = get_utime (CLOCK_REALTIME) - get_utime (CLOCK_MONOTONIC); - //} - return get_utime (CLOCK_MONOTONIC) + DC->server_time_udelta; -} - -static long long generate_next_msg_id (struct tgl_state *TLS, struct tgl_dc *DC, struct tgl_session *S) { - long long next_id = (long long) (get_server_time (DC) * (1LL << 32)) & -4; - if (next_id <= S->last_msg_id) { - next_id = S->last_msg_id += 4; - } else { - S->last_msg_id = next_id; - } - return next_id; -} - -static void init_enc_msg (struct tgl_state *TLS, struct tgl_session *S, int useful) { - struct tgl_dc *DC = S->dc; - assert (DC->state == st_authorized); - assert (DC->temp_auth_key_id); - vlogprintf (E_DEBUG, "temp_auth_key_id = 0x%016llx, auth_key_id = 0x%016llx\n", DC->temp_auth_key_id, DC->auth_key_id); - enc_msg.auth_key_id = DC->temp_auth_key_id; - enc_msg.server_salt = DC->server_salt; - if (!S->session_id) { - tglt_secure_random (&S->session_id, 8); - } - enc_msg.session_id = S->session_id; - enc_msg.msg_id = msg_id_override ? msg_id_override : generate_next_msg_id (TLS, DC, S); - enc_msg.seq_no = S->seq_no; - if (useful) { - enc_msg.seq_no |= 1; - } - S->seq_no += 2; -}; - -static void init_enc_msg_inner_temp (struct tgl_dc *DC, long long msg_id) { - enc_msg.auth_key_id = DC->auth_key_id; - tglt_secure_random (&enc_msg.server_salt, 8); - tglt_secure_random (&enc_msg.session_id, 8); - enc_msg.msg_id = msg_id; - enc_msg.seq_no = 0; -}; - - -static int aes_encrypt_message (struct tgl_state *TLS, char *key, struct encrypted_message *enc) { - unsigned char sha1_buffer[20]; - const int MINSZ = offsetof (struct encrypted_message, message); - const int UNENCSZ = offsetof (struct encrypted_message, server_salt); - - int enc_len = (MINSZ - UNENCSZ) + enc->msg_len; - assert (enc->msg_len >= 0 && enc->msg_len <= MAX_MESSAGE_INTS * 4 - 16 && !(enc->msg_len & 3)); - sha1 ((unsigned char *) &enc->server_salt, enc_len, sha1_buffer); - vlogprintf (E_DEBUG, "sending message with sha1 %08x\n", *(int *)sha1_buffer); - memcpy (enc->msg_key, sha1_buffer + 4, 16); - tgl_init_aes_auth (key, enc->msg_key, AES_ENCRYPT); - return tgl_pad_aes_encrypt ((char *) &enc->server_salt, enc_len, (char *) &enc->server_salt, MAX_MESSAGE_INTS * 4 + (MINSZ - UNENCSZ)); -} - -long long tglmp_encrypt_send_message (struct tgl_state *TLS, struct connection *c, int *msg, int msg_ints, int flags) { - struct tgl_dc *DC = TLS->net_methods->get_dc (c); - struct tgl_session *S = TLS->net_methods->get_session (c); - assert (S); - if (!(DC->flags & 4) && !(flags & 2)) { - return generate_next_msg_id (TLS, DC, S); - } - - const int UNENCSZ = offsetof (struct encrypted_message, server_salt); - if (msg_ints <= 0 || msg_ints > MAX_MESSAGE_INTS - 4) { - return -1; - } - if (msg) { - memcpy (enc_msg.message, msg, msg_ints * 4); - enc_msg.msg_len = msg_ints * 4; - } else { - if ((enc_msg.msg_len & 0x80000003) || enc_msg.msg_len > MAX_MESSAGE_INTS * 4 - 16) { - return -1; - } - } - init_enc_msg (TLS, S, flags & 1); - - int l = aes_encrypt_message (TLS, DC->temp_auth_key, &enc_msg); - assert (l > 0); - rpc_send_message (TLS, c, &enc_msg, l + UNENCSZ); - - return S->last_msg_id; -} - -int tglmp_encrypt_inner_temp (struct tgl_state *TLS, struct connection *c, int *msg, int msg_ints, int useful, void *data, long long msg_id) { - struct tgl_dc *DC = TLS->net_methods->get_dc (c); - struct tgl_session *S = TLS->net_methods->get_session (c); - assert (S); - - const int UNENCSZ = offsetof (struct encrypted_message, server_salt); - if (msg_ints <= 0 || msg_ints > MAX_MESSAGE_INTS - 4) { - return -1; - } - memcpy (enc_msg.message, msg, msg_ints * 4); - enc_msg.msg_len = msg_ints * 4; - - init_enc_msg_inner_temp (DC, msg_id); - - int l = aes_encrypt_message (TLS, DC->auth_key, &enc_msg); - assert (l > 0); - //rpc_send_message (c, &enc_msg, l + UNENCSZ); - memcpy (data, &enc_msg, l + UNENCSZ); - - return l + UNENCSZ; -} - -static int rpc_execute_answer (struct tgl_state *TLS, struct connection *c, long long msg_id); - -static int work_container (struct tgl_state *TLS, struct connection *c, long long msg_id) { - vlogprintf (E_DEBUG, "work_container: msg_id = %"_PRINTF_INT64_"d\n", msg_id); - assert (fetch_int () == CODE_msg_container); - int n = fetch_int (); - int i; - for (i = 0; i < n; i++) { - long long id = fetch_long (); - //int seqno = fetch_int (); - fetch_int (); // seq_no - if (id & 1) { - tgln_insert_msg_id (TLS, TLS->net_methods->get_session (c), id); - } - int bytes = fetch_int (); - int *t = in_end; - in_end = in_ptr + (bytes / 4); - int r = rpc_execute_answer (TLS, c, id); - if (r < 0) { return -1; } - assert (in_ptr == in_end); - in_end = t; - } - return 0; -} - -static int work_new_session_created (struct tgl_state *TLS, struct connection *c, long long msg_id) { - vlogprintf (E_DEBUG, "work_new_session_created: msg_id = %"_PRINTF_INT64_"d\n", msg_id); - assert (fetch_int () == (int)CODE_new_session_created); - fetch_long (); // first message id - fetch_long (); // unique_id - TLS->net_methods->get_dc (c)->server_salt = fetch_long (); - if (TLS->started && !(TLS->locks & TGL_LOCK_DIFF) && (TLS->DC_working->flags & TGLDCF_LOGGED_IN)) { - tgl_do_get_difference (TLS, 0, 0, 0); - } - return 0; -} - -static int work_msgs_ack (struct tgl_state *TLS, struct connection *c, long long msg_id) { - vlogprintf (E_DEBUG, "work_msgs_ack: msg_id = %"_PRINTF_INT64_"d\n", msg_id); - assert (fetch_int () == CODE_msgs_ack); - assert (fetch_int () == CODE_vector); - int n = fetch_int (); - int i; - for (i = 0; i < n; i++) { - long long id = fetch_long (); - vlogprintf (E_DEBUG + 1, "ack for %"_PRINTF_INT64_"d\n", id); - tglq_query_ack (TLS, id); - } - return 0; -} - -static int work_rpc_result (struct tgl_state *TLS, struct connection *c, long long msg_id) { - vlogprintf (E_DEBUG, "work_rpc_result: msg_id = %"_PRINTF_INT64_"d\n", msg_id); - assert (fetch_int () == (int)CODE_rpc_result); - long long id = fetch_long (); - int op = prefetch_int (); - if (op == CODE_rpc_error) { - return tglq_query_error (TLS, id); - } else { - return tglq_query_result (TLS, id); - } -} - -#define MAX_PACKED_SIZE (1 << 24) -static int work_packed (struct tgl_state *TLS, struct connection *c, long long msg_id) { - assert (fetch_int () == CODE_gzip_packed); - static int in_gzip; - static int buf[MAX_PACKED_SIZE >> 2]; - assert (!in_gzip); - in_gzip = 1; - - int l = prefetch_strlen (); - char *s = fetch_str (l); - - int total_out = tgl_inflate (s, l, buf, MAX_PACKED_SIZE); - int *end = in_ptr; - int *eend = in_end; - //assert (total_out % 4 == 0); - in_ptr = buf; - in_end = in_ptr + total_out / 4; - int r = rpc_execute_answer (TLS, c, msg_id); - in_ptr = end; - in_end = eend; - in_gzip = 0; - return r; -} - -static int work_bad_server_salt (struct tgl_state *TLS, struct connection *c, long long msg_id) { - assert (fetch_int () == (int)CODE_bad_server_salt); - long long id = fetch_long (); - tglq_query_restart (TLS, id); - fetch_int (); // seq_no - fetch_int (); // error_code - long long new_server_salt = fetch_long (); - TLS->net_methods->get_dc (c)->server_salt = new_server_salt; - return 0; -} - -static int work_pong (struct tgl_state *TLS, struct connection *c, long long msg_id) { - assert (fetch_int () == CODE_pong); - fetch_long (); // msg_id - fetch_long (); // ping_id - return 0; -} - -static int work_detailed_info (struct tgl_state *TLS, struct connection *c, long long msg_id) { - assert (fetch_int () == CODE_msg_detailed_info); - fetch_long (); // msg_id - fetch_long (); // answer_msg_id - fetch_int (); // bytes - fetch_int (); // status - return 0; -} - -static int work_new_detailed_info (struct tgl_state *TLS, struct connection *c, long long msg_id) { - assert (fetch_int () == (int)CODE_msg_new_detailed_info); - fetch_long (); // answer_msg_id - fetch_int (); // bytes - fetch_int (); // status - return 0; -} - -static int work_bad_msg_notification (struct tgl_state *TLS, struct connection *c, long long msg_id) { - assert (fetch_int () == (int)CODE_bad_msg_notification); - long long m1 = fetch_long (); - int s = fetch_int (); - int e = fetch_int (); - vlogprintf (E_NOTICE, "bad_msg_notification: msg_id = %"_PRINTF_INT64_"d, seq = %d, error = %d\n", m1, s, e); - switch (e) { - // Too low msg id - case 16: - tglq_regen_query (TLS, m1); - break; - // Too high msg id - case 17: - tglq_regen_query (TLS, m1); - break; - default: - vlogprintf (E_NOTICE, "bad_msg_notification: msg_id = %"_PRINTF_INT64_"d, seq = %d, error = %d\n", m1, s, e); - break; - } - - return -1; -} - -static int rpc_execute_answer (struct tgl_state *TLS, struct connection *c, long long msg_id) { - int op = prefetch_int (); - switch (op) { - case CODE_msg_container: - return work_container (TLS, c, msg_id); - case CODE_new_session_created: - return work_new_session_created (TLS, c, msg_id); - case CODE_msgs_ack: - return work_msgs_ack (TLS, c, msg_id); - case CODE_rpc_result: - return work_rpc_result (TLS, c, msg_id); - case CODE_update_short: - case CODE_updates: - case CODE_update_short_message: - case CODE_update_short_chat_message: - case CODE_updates_too_long: - tglu_work_any_updates (TLS); - return 0; - case CODE_gzip_packed: - return work_packed (TLS, c, msg_id); - case CODE_bad_server_salt: - return work_bad_server_salt (TLS, c, msg_id); - case CODE_pong: - return work_pong (TLS, c, msg_id); - case CODE_msg_detailed_info: - return work_detailed_info (TLS, c, msg_id); - case CODE_msg_new_detailed_info: - return work_new_detailed_info (TLS, c, msg_id); - case CODE_bad_msg_notification: - return work_bad_msg_notification (TLS, c, msg_id); - } - vlogprintf (E_WARNING, "Unknown message: %08x\n", op); - in_ptr = in_end; // Will not fail due to assertion in_ptr == in_end - return 0; -} - -static struct mtproto_methods mtproto_methods; -void tgls_free_session (struct tgl_state *TLS, struct tgl_session *S); -/* -static char *get_ipv6 (struct tgl_state *TLS, int num) { - static char res[1<< 10]; - if (TLS->test_mode) { - switch (num) { - case 1: - strcpy (res, TG_SERVER_TEST_IPV6_1); - break; - case 2: - strcpy (res, TG_SERVER_TEST_IPV6_2); - break; - case 3: - strcpy (res, TG_SERVER_TEST_IPV6_3); - break; - default: - assert (0); - } - } else { - switch (num) { - case 1: - strcpy (res, TG_SERVER_IPV6_1); - break; - case 2: - strcpy (res, TG_SERVER_IPV6_2); - break; - case 3: - strcpy (res, TG_SERVER_IPV6_3); - break; - case 4: - strcpy (res, TG_SERVER_IPV6_4); - break; - case 5: - strcpy (res, TG_SERVER_IPV6_5); - break; - default: - assert (0); - } - } - return res; -} -*/ - -static void create_session_connect (struct tgl_state *TLS, struct tgl_session *S) { - struct tgl_dc *DC = S->dc; - - if (TLS->ipv6_enabled) { - S->c = TLS->net_methods->create_connection (TLS, DC->options[1]->ip, DC->options[1]->port, S, DC, &mtproto_methods); - } else { - S->c = TLS->net_methods->create_connection (TLS, DC->options[0]->ip, DC->options[0]->port, S, DC, &mtproto_methods); - } -} - -static void fail_connection (struct tgl_state *TLS, struct connection *c) { - struct tgl_session *S = TLS->net_methods->get_session (c); - TLS->net_methods->free (c); - create_session_connect (TLS, S); -} - -static void fail_session (struct tgl_state *TLS, struct tgl_session *S) { - vlogprintf (E_NOTICE, "failing session %"_PRINTF_INT64_"d\n", S->session_id); - struct tgl_dc *DC = S->dc; - tgls_free_session (TLS, S); - DC->sessions[0] = NULL; - tglmp_dc_create_session (TLS, DC); -} - -static int process_rpc_message (struct tgl_state *TLS, struct connection *c, struct encrypted_message *enc, int len) { - const int MINSZ = offsetof (struct encrypted_message, message); - const int UNENCSZ = offsetof (struct encrypted_message, server_salt); - vlogprintf (E_DEBUG, "process_rpc_message(), len=%d\n", len); - if (len < MINSZ || (len & 15) != (UNENCSZ & 15)) { - vlogprintf (E_WARNING, "Incorrect packet from server. Closing connection\n"); - fail_connection (TLS, c); - return -1; - } - assert (len >= MINSZ && (len & 15) == (UNENCSZ & 15)); - struct tgl_dc *DC = TLS->net_methods->get_dc (c); - if (enc->auth_key_id != DC->temp_auth_key_id && enc->auth_key_id != DC->auth_key_id) { - vlogprintf (E_WARNING, "received msg from dc %d with auth_key_id %"_PRINTF_INT64_"d (perm_auth_key_id %"_PRINTF_INT64_"d temp_auth_key_id %"_PRINTF_INT64_"d). Dropping\n", - DC->id, enc->auth_key_id, DC->auth_key_id, DC->temp_auth_key_id); - return 0; - } - if (enc->auth_key_id == DC->temp_auth_key_id) { - assert (enc->auth_key_id == DC->temp_auth_key_id); - assert (DC->temp_auth_key_id); - tgl_init_aes_auth (DC->temp_auth_key + 8, enc->msg_key, AES_DECRYPT); - } else { - assert (enc->auth_key_id == DC->auth_key_id); - assert (DC->auth_key_id); - tgl_init_aes_auth (DC->auth_key + 8, enc->msg_key, AES_DECRYPT); - } - - int l = tgl_pad_aes_decrypt ((char *)&enc->server_salt, len - UNENCSZ, (char *)&enc->server_salt, len - UNENCSZ); - assert (l == len - UNENCSZ); - - if (!(!(enc->msg_len & 3) && enc->msg_len > 0 && enc->msg_len <= len - MINSZ && len - MINSZ - enc->msg_len <= 12)) { - vlogprintf (E_WARNING, "Incorrect packet from server. Closing connection\n"); - fail_connection (TLS, c); - return -1; - } - assert (!(enc->msg_len & 3) && enc->msg_len > 0 && enc->msg_len <= len - MINSZ && len - MINSZ - enc->msg_len <= 12); - - struct tgl_session *S = TLS->net_methods->get_session (c); - if (!S || S->session_id != enc->session_id) { - vlogprintf (E_WARNING, "Message to bad session. Drop.\n"); - return 0; - } - - static unsigned char sha1_buffer[20]; - sha1 ((void *)&enc->server_salt, enc->msg_len + (MINSZ - UNENCSZ), sha1_buffer); - if (memcmp (&enc->msg_key, sha1_buffer + 4, 16)) { - vlogprintf (E_WARNING, "Incorrect packet from server. Closing connection\n"); - fail_connection (TLS, c); - return -1; - } - assert (!memcmp (&enc->msg_key, sha1_buffer + 4, 16)); - - int this_server_time = enc->msg_id >> 32LL; - if (!S->received_messages) { - DC->server_time_delta = this_server_time - get_utime (CLOCK_REALTIME); - if (DC->server_time_udelta) { - vlogprintf (E_WARNING, "adjusting CLOCK_MONOTONIC delta to %lf\n", - DC->server_time_udelta - this_server_time + get_utime (CLOCK_MONOTONIC)); - } - DC->server_time_udelta = this_server_time - get_utime (CLOCK_MONOTONIC); - } - - double st = get_server_time (DC); - if (this_server_time < st - 300 || this_server_time > st + 30) { - vlogprintf (E_WARNING, "bad msg time: salt = %"_PRINTF_INT64_"d, session_id = %"_PRINTF_INT64_"d, msg_id = %"_PRINTF_INT64_"d, seq_no = %d, st = %lf, now = %lf\n", enc->server_salt, enc->session_id, enc->msg_id, enc->seq_no, st, get_utime (CLOCK_REALTIME)); - fail_session (TLS, S); - return -1; - } - S->received_messages ++; - - if (DC->server_salt != enc->server_salt) { - DC->server_salt = enc->server_salt; - } - - assert (this_server_time >= st - 300 && this_server_time <= st + 30); - //assert (enc->msg_id > server_last_msg_id && (enc->msg_id & 3) == 1); - vlogprintf (E_DEBUG, "received mesage id %016llx\n", enc->msg_id); - //server_last_msg_id = enc->msg_id; - - //*(long long *)(longpoll_query + 3) = *(long long *)((char *)(&enc->msg_id) + 0x3c); - //*(long long *)(longpoll_query + 5) = *(long long *)((char *)(&enc->msg_id) + 0x3c); - - assert (l >= (MINSZ - UNENCSZ) + 8); - //assert (enc->message[0] == CODE_rpc_result && *(long long *)(enc->message + 1) == client_last_msg_id); - - in_ptr = enc->message; - in_end = in_ptr + (enc->msg_len / 4); - - if (enc->msg_id & 1) { - tgln_insert_msg_id (TLS, S, enc->msg_id); - } - assert (S->session_id == enc->session_id); - - if (rpc_execute_answer (TLS, c, enc->msg_id) < 0) { - fail_session (TLS, S); - return -1; - } - assert (in_ptr == in_end); - return 0; -} - - -static int rpc_execute (struct tgl_state *TLS, struct connection *c, int op, int len) { - struct tgl_dc *DC = TLS->net_methods->get_dc (c); - - if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { - vlogprintf (E_WARNING, "answer too long (%d bytes), skipping\n", len); - return 0; - } - - int Response_len = len; - - static char Response[MAX_RESPONSE_SIZE]; - vlogprintf (E_DEBUG, "Response_len = %d\n", Response_len); - assert (TLS->net_methods->read_in (c, Response, Response_len) == Response_len); - -#if !defined(WIN32) || !defined(_WIN32) - setsockopt(c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]) { 0 }, 4); -#endif -#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) -// setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); -#endif - int o = DC->state; - //if (DC->flags & 1) { o = st_authorized;} - if (o != st_authorized) { - vlogprintf (E_DEBUG, "%s: state = %d\n", __func__, o); - } - switch (o) { - case st_reqpq_sent: - process_respq_answer (TLS, c, Response/* + 8*/, Response_len/* - 12*/, 0); - return 0; - case st_reqdh_sent: - process_dh_answer (TLS, c, Response/* + 8*/, Response_len/* - 12*/, 0); - return 0; - case st_client_dh_sent: - process_auth_complete (TLS, c, Response/* + 8*/, Response_len/* - 12*/, 0); - return 0; - case st_reqpq_sent_temp: - process_respq_answer (TLS, c, Response/* + 8*/, Response_len/* - 12*/, 1); - return 0; - case st_reqdh_sent_temp: - process_dh_answer (TLS, c, Response/* + 8*/, Response_len/* - 12*/, 1); - return 0; - case st_client_dh_sent_temp: - process_auth_complete (TLS, c, Response/* + 8*/, Response_len/* - 12*/, 1); - return 0; - case st_authorized: - if (op < 0 && op >= -999) { - vlogprintf (E_WARNING, "Server error %d\n", op); - } else { - return process_rpc_message (TLS, c, (void *)(Response/* + 8*/), Response_len/* - 12*/); - } - return 0; - default: - vlogprintf (E_ERROR, "fatal: cannot receive answer in state %d\n", DC->state); - exit (2); - } - - return 0; -} - - -static int tc_close (struct tgl_state *TLS, struct connection *c, int who) { - vlogprintf (E_DEBUG, "outbound rpc connection from dc #%d : closing by %d\n", TLS->net_methods->get_dc(c)->id, who); - return 0; -} - -static void mpc_on_get_config (struct tgl_state *TLS, void *extra, int success) { - assert (success); - struct tgl_dc *DC = extra; - DC->flags |= 4; -} - -static int tc_becomes_ready (struct tgl_state *TLS, struct connection *c) { - vlogprintf (E_NOTICE, "outbound rpc connection from dc #%d becomed ready\n", TLS->net_methods->get_dc(c)->id); - //char byte = 0xef; - //assert (TLS->net_methods->write_out (c, &byte, 1) == 1); - //TLS->net_methods->flush_out (c); - - struct tgl_dc *DC = TLS->net_methods->get_dc (c); - if (DC->flags & 1) { DC->state = st_authorized; } - int o = DC->state; - if (o == st_authorized && !TLS->enable_pfs) { - DC->temp_auth_key_id = DC->auth_key_id; - memcpy (DC->temp_auth_key, DC->auth_key, 256); - DC->flags |= 2; - } - switch (o) { - case st_init: - send_req_pq_packet (TLS, c); - break; - case st_authorized: - if (!(DC->flags & 2)) { - assert (TLS->enable_pfs); - if (!DC->temp_auth_key_id) { - assert (!DC->temp_auth_key_id); - create_temp_auth_key (TLS, c); - } else { - bind_temp_auth_key (TLS, c); - } - } else if (!(DC->flags & 4)) { - tgl_do_help_get_config_dc (TLS, DC, mpc_on_get_config, DC); - } - break; - default: - vlogprintf (E_DEBUG, "c_state = %d\n", DC->state); - DC->state = st_init; // previous connection was reset - send_req_pq_packet (TLS, c); - break; - } - return 0; -} - -static int rpc_becomes_ready (struct tgl_state *TLS, struct connection *c) { - return tc_becomes_ready (TLS, c); -} - -static int rpc_close (struct tgl_state *TLS, struct connection *c) { - return tc_close (TLS, c, 0); -} - - -#define RANDSEED_PASSWORD_FILENAME NULL -#define RANDSEED_PASSWORD_LENGTH 0 -void tglmp_on_start (struct tgl_state *TLS) { - tgl_prng_seed (TLS, RANDSEED_PASSWORD_FILENAME, RANDSEED_PASSWORD_LENGTH); - - int i; - int ok = 0; - for (i = 0; i < TLS->rsa_key_num; i++) { - char *key = TLS->rsa_key_list[i]; - RSA *res = rsa_load_public_key (TLS, key); - if (!res) { - vlogprintf (E_WARNING, "Can not load key %s\n", key); - TLS->rsa_key_loaded[i] = NULL; - } else { - ok = 1; - TLS->rsa_key_loaded[i] = res; - TLS->rsa_key_fingerprint[i] = tgl_do_compute_rsa_key_fingerprint (res); - } - } - - if (!ok) { - vlogprintf (E_ERROR, "No public keys found\n"); - exit (1); - } -} - -void tgl_dc_authorize (struct tgl_state *TLS, struct tgl_dc *DC) { - //c_state = 0; - if (!DC->sessions[0]) { - tglmp_dc_create_session (TLS, DC); - } - vlogprintf (E_DEBUG, "Starting authorization for DC #%d\n", DC->id); - //net_loop (0, auth_ok); -} - -#define long_cmp(a,b) ((a) > (b) ? 1 : (a) == (b) ? 0 : -1) -DEFINE_TREE(long,long long,long_cmp,0) - -static int send_all_acks (struct tgl_state *TLS, struct tgl_session *S) { - clear_packet (); - out_int (CODE_msgs_ack); - out_int (CODE_vector); - out_int (tree_count_long (S->ack_tree)); - while (S->ack_tree) { - long long x = tree_get_min_long (S->ack_tree); - out_long (x); - S->ack_tree = tree_delete_long (S->ack_tree, x); - } - tglmp_encrypt_send_message (TLS, S->c, packet_buffer, packet_ptr - packet_buffer, 0); - return 0; -} - -static void send_all_acks_gateway (struct tgl_state *TLS, void *arg) { - send_all_acks (TLS, arg); -} - - -void tgln_insert_msg_id (struct tgl_state *TLS, struct tgl_session *S, long long id) { - if (!S->ack_tree) { - TLS->timer_methods->insert (S->ev, ACK_TIMEOUT); - } - if (!tree_lookup_long (S->ack_tree, id)) { - S->ack_tree = tree_insert_long (S->ack_tree, id, lrand48 ()); - } -} - -//extern struct tgl_dc *DC_list[]; - - -static void regen_temp_key_gw (struct tgl_state *TLS, void *arg) { - tglmp_regenerate_temp_auth_key (TLS, arg); -} - -struct tgl_dc *tglmp_alloc_dc (struct tgl_state *TLS, int flags, int id, char *ip, int port) { - //assert (!TLS->DC_list[id]); - - if (!TLS->DC_list[id]) { - struct tgl_dc *DC = talloc0 (sizeof (*DC)); - DC->id = id; - TLS->DC_list[id] = DC; - if (id > TLS->max_dc_num) { - TLS->max_dc_num = id; - } - DC->ev = TLS->timer_methods->alloc (TLS, regen_temp_key_gw, DC); - TLS->timer_methods->insert (DC->ev, 0); - } - - struct tgl_dc *DC = TLS->DC_list[id]; - - struct tgl_dc_option *O = DC->options[flags & 3]; - - struct tgl_dc_option *O2 = O; - while (O2) { - if (!strcmp (O2->ip, ip)) { - tfree_str (ip); - return DC; - } - O2 = O2->next; - } - - struct tgl_dc_option *T = talloc (sizeof (*T)); - T->ip = ip; - T->port = port; - T->next = O; - DC->options[flags & 3] = T; - - - return DC; -} - -static struct mtproto_methods mtproto_methods = { - .execute = rpc_execute, - .ready = rpc_becomes_ready, - .close = rpc_close -}; - -void tglmp_dc_create_session (struct tgl_state *TLS, struct tgl_dc *DC) { - struct tgl_session *S = talloc0 (sizeof (*S)); - assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0); - S->dc = DC; - //S->c = TLS->net_methods->create_connection (TLS, DC->ip, DC->port, S, DC, &mtproto_methods); - - create_session_connect (TLS, S); - S->ev = TLS->timer_methods->alloc (TLS, send_all_acks_gateway, S); - assert (!DC->sessions[0]); - DC->sessions[0] = S; -} - -void tgl_do_send_ping (struct tgl_state *TLS, struct connection *c) { - int x[3]; - x[0] = CODE_ping; - *(long long *)(x + 1) = lrand48 () * (1ll << 32) + lrand48 (); - tglmp_encrypt_send_message (TLS, c, x, 3, 0); -} - -void tgl_dc_iterator (struct tgl_state *TLS, void (*iterator)(struct tgl_dc *DC)) { - int i; - for (i = 0; i <= TLS->max_dc_num; i++) { - iterator (TLS->DC_list[i]); - } -} - -void tgl_dc_iterator_ex (struct tgl_state *TLS, void (*iterator)(struct tgl_dc *DC, void *extra), void *extra) { - int i; - for (i = 0; i <= TLS->max_dc_num; i++) { - iterator (TLS->DC_list[i], extra); - } -} - - -void tglmp_regenerate_temp_auth_key (struct tgl_state *TLS, struct tgl_dc *DC) { - DC->flags &= ~6; - DC->temp_auth_key_id = 0; - memset (DC->temp_auth_key, 0, 256); - - if (!DC->sessions[0]) { - tgl_dc_authorize (TLS, DC); - return; - } - - - struct tgl_session *S = DC->sessions[0]; - tglt_secure_random (&S->session_id, 8); - S->seq_no = 0; - - TLS->timer_methods->remove (S->ev); - S->ack_tree = tree_clear_long (S->ack_tree); - - if (DC->state != st_authorized) { - return; - } - - if (S->c) { - create_temp_auth_key (TLS, S->c); - } -} - -void tgls_free_session (struct tgl_state *TLS, struct tgl_session *S) { - S->ack_tree = tree_clear_long (S->ack_tree); - if (S->ev) { TLS->timer_methods->free (S->ev); } - if (S->c) { - TLS->net_methods->free (S->c); - } - tfree (S, sizeof (*S)); -} - -void tgls_free_dc (struct tgl_state *TLS, struct tgl_dc *DC) { - //if (DC->ip) { tfree_str (DC->ip); } - - struct tgl_session *S = DC->sessions[0]; - if (S) { tgls_free_session (TLS, S); } - - if (DC->ev) { TLS->timer_methods->free (DC->ev); } - tfree (DC, sizeof (*DC)); -} - -void tgls_free_pubkey (struct tgl_state *TLS) { - int i; - for (i = 0; i < TLS->rsa_key_num; i++) { - if (TLS->rsa_key_loaded[i]) { - RSA_free (TLS->rsa_key_loaded[i]); - TLS->rsa_key_loaded[i] = NULL; - } - } -} |