2013-10-23 10:26:17 -04:00
/*
This file is part of telegram - client .
Telegram - client 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 2 of the License , or
( at your option ) any later version .
Telegram - client 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 this telegram - client . If not , see < http : //www.gnu.org/licenses/>.
Copyright Nikolay Durov , Andrey Lopatin 2012 - 2013
Copyright Vitaly Valtman 2013
*/
2014-01-13 08:05:25 -05:00
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
2013-10-11 16:52:20 -04:00
# define _FILE_OFFSET_BITS 64
# include <assert.h>
# include <string.h>
# include <stdio.h>
# include <stdlib.h>
# include <signal.h>
# include <unistd.h>
# include <fcntl.h>
2014-02-25 09:25:57 -05:00
# if defined(__FreeBSD__) || defined(__OpenBSD__)
2013-12-16 13:30:36 -05:00
# include <sys/endian.h>
2013-12-20 08:57:00 -05:00
# endif
2013-10-11 16:52:20 -04:00
# include <sys/types.h>
# include <netdb.h>
# include <openssl/rand.h>
# include <openssl/rsa.h>
# include <openssl/pem.h>
# include <openssl/sha.h>
# include <sys/socket.h>
2013-12-16 13:30:36 -05:00
# include <netinet/in.h>
2013-10-11 16:52:20 -04:00
# include <netinet/tcp.h>
# include <poll.h>
2014-02-04 11:35:16 -05:00
# include "telegram.h"
2013-10-11 16:52:20 -04:00
# include "include.h"
# include "queries.h"
2014-08-14 14:03:33 -04:00
//#include "loop.h"
2013-10-16 15:19:39 -04:00
# include "structures.h"
2013-11-14 19:08:24 -05:00
# include "binlog.h"
2014-08-12 05:59:59 -04:00
# include "auto.h"
2014-08-13 11:55:16 -04:00
# include "tgl.h"
2014-08-14 14:03:33 -04:00
# include "mtproto-client.h"
# include "tools.h"
# include "tree.h"
# include "updates.h"
# include <event2/event.h>
2013-10-11 16:52:20 -04:00
2013-12-16 13:30:36 -05:00
# if defined(__FreeBSD__)
# define __builtin_bswap32(x) bswap32(x)
# endif
2014-02-25 09:25:57 -05:00
# if defined(__OpenBSD__)
# define __builtin_bswap32(x) __swap32gen(x)
# endif
2013-10-11 16:52:20 -04:00
# define sha1 SHA1
# include "mtproto-common.h"
# define MAX_NET_RES (1L << 16)
2014-08-14 14:03:33 -04:00
//extern int log_level;
2013-10-11 16:52:20 -04:00
2014-08-14 14:03:33 -04:00
//int verbosity;
static int auth_success ;
2014-08-14 18:16:01 -04:00
//static enum dc_state c_state;
2014-08-14 14:03:33 -04:00
static char nonce [ 256 ] ;
static char new_nonce [ 256 ] ;
static char server_nonce [ 256 ] ;
//extern int binlog_enabled;
//extern int disable_auto_accept;
//extern int allow_weak_random;
2013-11-21 14:35:49 -05:00
2014-08-14 14:03:33 -04:00
static int total_packets_sent ;
static long long total_data_sent ;
2013-11-21 14:35:49 -05:00
2014-08-14 14:03:33 -04:00
static int rpc_execute ( struct connection * c , int op , int len ) ;
static int rpc_becomes_ready ( struct connection * c ) ;
static int rpc_close ( struct connection * c ) ;
2013-10-11 16:52:20 -04:00
2014-08-14 14:03:33 -04:00
static long long precise_time ;
2013-10-11 16:52:20 -04:00
2014-08-14 14:03:33 -04:00
static double get_utime ( int clock_id ) {
2013-10-11 16:52:20 -04:00
struct timespec T ;
2014-08-20 18:33:19 -04:00
tgl_my_clock_gettime ( clock_id , & T ) ;
2013-10-11 16:52:20 -04:00
double res = T . tv_sec + ( double ) T . tv_nsec * 1e-9 ;
if ( clock_id = = CLOCK_REALTIME ) {
precise_time = ( long long ) ( res * ( 1LL < < 32 ) ) ;
}
return res ;
}
2014-08-14 14:03:33 -04:00
//#define STATS_BUFF_SIZE (64 << 10)
//static int stats_buff_len;
//static char stats_buff[STATS_BUFF_SIZE];
2013-10-11 16:52:20 -04:00
# define MAX_RESPONSE_SIZE (1L << 24)
2014-08-14 14:03:33 -04:00
static char Response [ MAX_RESPONSE_SIZE ] ;
//static int Response_len;
2013-10-11 16:52:20 -04:00
/*
*
* STATE MACHINE
*
*/
2014-03-21 11:29:53 -04:00
# define TG_SERVER_PUBKEY_FILENAME "tg-server.pub"
2014-08-14 14:03:33 -04:00
static char * rsa_public_key_name ; // = TG_SERVER_PUBKEY_FILENAME;
static RSA * pubKey ;
static long long pk_fingerprint ;
2013-10-11 16:52:20 -04:00
static int rsa_load_public_key ( const char * public_key_name ) {
pubKey = NULL ;
FILE * f = fopen ( public_key_name , " r " ) ;
if ( f = = NULL ) {
2014-08-13 21:31:24 -04:00
vlogprintf ( E_WARNING , " Couldn't open public key file: %s \n " , public_key_name ) ;
2013-10-11 16:52:20 -04:00
return - 1 ;
}
pubKey = PEM_read_RSAPublicKey ( f , NULL , NULL , NULL ) ;
fclose ( f ) ;
if ( pubKey = = NULL ) {
2014-08-13 21:31:24 -04:00
vlogprintf ( E_WARNING , " PEM_read_RSAPublicKey returns NULL. \n " ) ;
2013-10-11 16:52:20 -04:00
return - 1 ;
}
2014-08-20 18:33:19 -04:00
vlogprintf ( E_WARNING , " public key '%s' loaded successfully \n " , rsa_public_key_name ) ;
2014-02-04 11:35:16 -05:00
2013-10-11 16:52:20 -04:00
return 0 ;
}
/*
*
* UNAUTHORIZED ( DH KEY EXCHANGE ) PROTOCOL PART
*
*/
2014-08-14 14:03:33 -04:00
static BIGNUM dh_prime , dh_g , g_a , auth_key_num ;
static char s_power [ 256 ] ;
2013-10-11 16:52:20 -04:00
2014-08-14 14:03:33 -04:00
static struct {
2013-10-11 16:52:20 -04:00
long long auth_key_id ;
long long out_msg_id ;
int msg_len ;
} unenc_msg_header ;
# define ENCRYPT_BUFFER_INTS 16384
2014-08-14 14:03:33 -04:00
static int encrypt_buffer [ ENCRYPT_BUFFER_INTS ] ;
2013-10-11 16:52:20 -04:00
# define DECRYPT_BUFFER_INTS 16384
2014-08-14 14:03:33 -04:00
static int decrypt_buffer [ ENCRYPT_BUFFER_INTS ] ;
2013-10-11 16:52:20 -04:00
2014-08-14 14:03:33 -04:00
static int encrypt_packet_buffer ( void ) {
2014-08-20 18:33:19 -04:00
return tgl_pad_rsa_encrypt ( ( char * ) packet_buffer , ( packet_ptr - packet_buffer ) * 4 , ( char * ) encrypt_buffer , ENCRYPT_BUFFER_INTS * 4 , pubKey - > n , pubKey - > e ) ;
2013-10-11 16:52:20 -04:00
}
2014-08-14 14:03:33 -04:00
static int encrypt_packet_buffer_aes_unauth ( const char server_nonce [ 16 ] , const char hidden_client_nonce [ 32 ] ) {
2014-08-20 18:33:19 -04:00
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 ) ;
2013-10-11 16:52:20 -04:00
}
2014-08-14 14:03:33 -04:00
static int rpc_send_packet ( struct connection * c ) {
2013-10-11 16:52:20 -04:00
int len = ( packet_ptr - packet_buffer ) * 4 ;
2014-08-14 14:03:33 -04:00
//c->out_packet_num ++;
tgl_state . net_methods - > incr_out_packet_num ( c ) ;
2013-10-11 16:52:20 -04:00
long long next_msg_id = ( long long ) ( ( 1LL < < 32 ) * get_utime ( CLOCK_REALTIME ) ) & - 4 ;
if ( next_msg_id < = unenc_msg_header . out_msg_id ) {
unenc_msg_header . out_msg_id + = 4 ;
} else {
unenc_msg_header . out_msg_id = next_msg_id ;
}
unenc_msg_header . msg_len = len ;
int total_len = len + 20 ;
assert ( total_len > 0 & & ! ( total_len & 0xfc000003 ) ) ;
total_len > > = 2 ;
2014-08-14 18:16:01 -04:00
vlogprintf ( E_DEBUG , " writing packet: total_len = %d, len = %d \n " , total_len , len ) ;
2013-10-11 16:52:20 -04:00
if ( total_len < 0x7f ) {
2014-08-14 14:03:33 -04:00
assert ( tgl_state . net_methods - > write_out ( c , & total_len , 1 ) = = 1 ) ;
2013-10-11 16:52:20 -04:00
} else {
total_len = ( total_len < < 8 ) | 0x7f ;
2014-08-14 14:03:33 -04:00
assert ( tgl_state . net_methods - > write_out ( c , & total_len , 4 ) = = 4 ) ;
2013-10-11 16:52:20 -04:00
}
2014-08-14 14:03:33 -04:00
tgl_state . net_methods - > write_out ( c , & unenc_msg_header , 20 ) ;
tgl_state . net_methods - > write_out ( c , packet_buffer , len ) ;
tgl_state . net_methods - > flush_out ( c ) ;
2013-11-21 14:35:49 -05:00
total_packets_sent + + ;
total_data_sent + = total_len ;
2013-10-11 16:52:20 -04:00
return 1 ;
}
2014-08-14 14:03:33 -04:00
static int rpc_send_message ( struct connection * c , void * data , int len ) {
2013-10-11 16:52:20 -04:00
assert ( len > 0 & & ! ( len & 0xfc000003 ) ) ;
int total_len = len > > 2 ;
if ( total_len < 0x7f ) {
2014-08-14 14:03:33 -04:00
assert ( tgl_state . net_methods - > write_out ( c , & total_len , 1 ) = = 1 ) ;
2013-10-11 16:52:20 -04:00
} else {
total_len = ( total_len < < 8 ) | 0x7f ;
2014-08-14 14:03:33 -04:00
assert ( tgl_state . net_methods - > write_out ( c , & total_len , 4 ) = = 4 ) ;
2013-10-11 16:52:20 -04:00
}
2014-08-14 14:03:33 -04:00
tgl_state . net_methods - > incr_out_packet_num ( c ) ;
assert ( tgl_state . net_methods - > write_out ( c , data , len ) = = len ) ;
tgl_state . net_methods - > flush_out ( c ) ;
2013-11-21 14:35:49 -05:00
total_packets_sent + + ;
total_data_sent + = total_len ;
2013-10-11 16:52:20 -04:00
return 1 ;
}
2014-08-14 14:03:33 -04:00
static int send_req_pq_packet ( struct connection * c ) {
struct dc * D = tgl_state . net_methods - > get_dc ( c ) ;
assert ( D - > state = = st_init ) ;
tglt_secure_random ( nonce , 16 ) ;
2013-10-11 16:52:20 -04:00
unenc_msg_header . out_msg_id = 0 ;
clear_packet ( ) ;
out_int ( CODE_req_pq ) ;
out_ints ( ( int * ) nonce , 4 ) ;
rpc_send_packet ( c ) ;
2014-08-14 14:03:33 -04:00
D - > state = st_reqpq_sent ;
2013-10-11 16:52:20 -04:00
return 1 ;
}
2014-08-14 14:03:33 -04:00
static unsigned long long gcd ( unsigned long long a , unsigned long long b ) {
2013-10-11 16:52:20 -04:00
return b ? gcd ( b , a % b ) : a ;
}
//typedef unsigned int uint128_t __attribute__ ((mode(TI)));
2014-08-14 14:03:33 -04:00
static int process_respq_answer ( struct connection * c , char * packet , int len ) {
unsigned long long what ;
unsigned p1 , p2 ;
2013-10-11 16:52:20 -04:00
int i ;
2014-08-14 18:16:01 -04:00
vlogprintf ( E_DEBUG , " process_respq_answer(), len=%d, op=0x%08x \n " , len , * ( int * ) ( packet + 20 ) ) ;
2013-10-11 16:52:20 -04:00
assert ( len > = 76 ) ;
assert ( ! * ( long long * ) packet ) ;
assert ( * ( int * ) ( packet + 16 ) = = len - 20 ) ;
assert ( ! ( len & 3 ) ) ;
assert ( * ( int * ) ( packet + 20 ) = = CODE_resPQ ) ;
assert ( ! memcmp ( packet + 24 , nonce , 16 ) ) ;
memcpy ( server_nonce , packet + 40 , 16 ) ;
char * from = packet + 56 ;
int clen = * from + + ;
assert ( clen < = 8 ) ;
what = 0 ;
for ( i = 0 ; i < clen ; i + + ) {
what = ( what < < 8 ) + ( unsigned char ) * from + + ;
}
while ( ( ( unsigned long ) from ) & 3 ) + + from ;
p1 = 0 , p2 = 0 ;
int it = 0 ;
unsigned long long g = 0 ;
for ( i = 0 ; i < 3 | | it < 1000 ; i + + ) {
int q = ( ( lrand48 ( ) & 15 ) + 17 ) % what ;
unsigned long long x = ( long long ) lrand48 ( ) % ( what - 1 ) + 1 , y = x ;
int lim = 1 < < ( i + 18 ) ;
int j ;
for ( j = 1 ; j < lim ; j + + ) {
+ + it ;
unsigned long long a = x , b = x , c = q ;
while ( b ) {
if ( b & 1 ) {
c + = a ;
if ( c > = what ) {
c - = what ;
}
}
a + = a ;
if ( a > = what ) {
a - = what ;
}
b > > = 1 ;
}
x = c ;
unsigned long long z = x < y ? what + x - y : x - y ;
g = gcd ( z , what ) ;
if ( g ! = 1 ) {
break ;
}
if ( ! ( j & ( j - 1 ) ) ) {
y = x ;
}
}
if ( g > 1 & & g < what ) break ;
}
assert ( g > 1 & & g < what ) ;
p1 = g ;
p2 = what / g ;
if ( p1 > p2 ) {
unsigned t = p1 ; p1 = p2 ; p2 = t ;
}
/// ++p1; ///
assert ( * ( int * ) ( from ) = = CODE_vector ) ;
int fingerprints_num = * ( int * ) ( from + 4 ) ;
assert ( fingerprints_num > = 1 & & fingerprints_num < = 64 & & len = = fingerprints_num * 8 + 8 + ( from - packet ) ) ;
long long * fingerprints = ( long long * ) ( from + 8 ) ;
for ( i = 0 ; i < fingerprints_num ; i + + ) {
if ( fingerprints [ i ] = = pk_fingerprint ) {
2013-10-13 06:18:08 -04:00
//logprintf ( "found our public key at position %d\n", i);
2013-10-11 16:52:20 -04:00
break ;
}
}
if ( i = = fingerprints_num ) {
2014-08-13 21:31:24 -04:00
vlogprintf ( E_ERROR , " fatal: don't have any matching keys (%016llx expected) \n " , pk_fingerprint ) ;
2013-10-11 16:52:20 -04:00
exit ( 2 ) ;
}
// create inner part (P_Q_inner_data)
clear_packet ( ) ;
packet_ptr + = 5 ;
out_int ( CODE_p_q_inner_data ) ;
out_cstring ( packet + 57 , clen ) ;
//out_int (0x0f01); // pq=15
if ( p1 < 256 ) {
clen = 1 ;
} else if ( p1 < 65536 ) {
clen = 2 ;
} else if ( p1 < 16777216 ) {
clen = 3 ;
} else {
clen = 4 ;
}
p1 = __builtin_bswap32 ( p1 ) ;
out_cstring ( ( char * ) & p1 + 4 - clen , clen ) ;
p1 = __builtin_bswap32 ( p1 ) ;
if ( p2 < 256 ) {
clen = 1 ;
} else if ( p2 < 65536 ) {
clen = 2 ;
} else if ( p2 < 16777216 ) {
clen = 3 ;
} else {
clen = 4 ;
}
p2 = __builtin_bswap32 ( p2 ) ;
out_cstring ( ( char * ) & p2 + 4 - clen , clen ) ;
p2 = __builtin_bswap32 ( p2 ) ;
//out_int (0x0301); // p=3
//out_int (0x0501); // q=5
out_ints ( ( int * ) nonce , 4 ) ;
out_ints ( ( int * ) server_nonce , 4 ) ;
2014-08-14 14:03:33 -04:00
tglt_secure_random ( new_nonce , 32 ) ;
2013-10-11 16:52:20 -04:00
out_ints ( ( int * ) new_nonce , 8 ) ;
sha1 ( ( unsigned char * ) ( packet_buffer + 5 ) , ( packet_ptr - packet_buffer - 5 ) * 4 , ( unsigned char * ) packet_buffer ) ;
int l = encrypt_packet_buffer ( ) ;
clear_packet ( ) ;
out_int ( CODE_req_DH_params ) ;
out_ints ( ( int * ) nonce , 4 ) ;
out_ints ( ( int * ) server_nonce , 4 ) ;
//out_int (0x0301); // p=3
//out_int (0x0501); // q=5
if ( p1 < 256 ) {
clen = 1 ;
} else if ( p1 < 65536 ) {
clen = 2 ;
} else if ( p1 < 16777216 ) {
clen = 3 ;
} else {
clen = 4 ;
}
p1 = __builtin_bswap32 ( p1 ) ;
out_cstring ( ( char * ) & p1 + 4 - clen , clen ) ;
p1 = __builtin_bswap32 ( p1 ) ;
if ( p2 < 256 ) {
clen = 1 ;
} else if ( p2 < 65536 ) {
clen = 2 ;
} else if ( p2 < 16777216 ) {
clen = 3 ;
} else {
clen = 4 ;
}
p2 = __builtin_bswap32 ( p2 ) ;
out_cstring ( ( char * ) & p2 + 4 - clen , clen ) ;
p2 = __builtin_bswap32 ( p2 ) ;
out_long ( pk_fingerprint ) ;
out_cstring ( ( char * ) encrypt_buffer , l ) ;
2014-08-14 18:16:01 -04:00
tgl_state . net_methods - > get_dc ( c ) - > state = st_reqdh_sent ;
2013-10-11 16:52:20 -04:00
return rpc_send_packet ( c ) ;
}
2014-08-14 14:03:33 -04:00
static int check_prime ( BIGNUM * p ) {
2014-08-20 18:33:19 -04:00
int r = BN_is_prime ( p , BN_prime_checks , 0 , tgl_state . BN_ctx , 0 ) ;
2014-01-21 09:24:40 -05:00
ensure ( r > = 0 ) ;
return r ;
}
2014-08-14 14:03:33 -04:00
int tglmp_check_DH_params ( BIGNUM * p , int g ) {
2013-12-23 05:45:40 -05:00
if ( g < 2 | | g > 7 ) { return - 1 ; }
BIGNUM t ;
BN_init ( & t ) ;
BN_init ( & dh_g ) ;
2014-01-10 06:32:57 -05:00
ensure ( BN_set_word ( & dh_g , 4 * g ) ) ;
2013-12-23 05:45:40 -05:00
2014-08-20 18:33:19 -04:00
ensure ( BN_mod ( & t , p , & dh_g , tgl_state . BN_ctx ) ) ;
2013-12-23 05:45:40 -05:00
int x = BN_get_word ( & t ) ;
assert ( x > = 0 & & x < 4 * g ) ;
2014-01-21 09:24:40 -05:00
BN_free ( & dh_g ) ;
2013-12-23 05:45:40 -05:00
switch ( g ) {
case 2 :
if ( x ! = 7 ) { return - 1 ; }
break ;
case 3 :
if ( x % 3 ! = 2 ) { return - 1 ; }
break ;
case 4 :
break ;
case 5 :
if ( x % 5 ! = 1 & & x % 5 ! = 4 ) { return - 1 ; }
break ;
case 6 :
if ( x ! = 19 & & x ! = 23 ) { return - 1 ; }
break ;
case 7 :
if ( x % 7 ! = 3 & & x % 7 ! = 5 & & x % 7 ! = 6 ) { return - 1 ; }
break ;
}
2014-01-21 09:24:40 -05:00
if ( ! check_prime ( p ) ) { return - 1 ; }
2013-12-23 05:45:40 -05:00
BIGNUM b ;
BN_init ( & b ) ;
2014-01-10 06:32:57 -05:00
ensure ( BN_set_word ( & b , 2 ) ) ;
2014-08-20 18:33:19 -04:00
ensure ( BN_div ( & t , 0 , p , & b , tgl_state . BN_ctx ) ) ;
2014-01-21 09:24:40 -05:00
if ( ! check_prime ( & t ) ) { return - 1 ; }
BN_free ( & b ) ;
BN_free ( & t ) ;
2013-12-23 05:45:40 -05:00
return 0 ;
}
2014-08-14 14:03:33 -04:00
int tglmp_check_g ( unsigned char p [ 256 ] , BIGNUM * g ) {
2013-12-23 05:45:40 -05:00
static unsigned char s [ 256 ] ;
memset ( s , 0 , 256 ) ;
assert ( BN_num_bytes ( g ) < = 256 ) ;
BN_bn2bin ( g , s ) ;
int ok = 0 ;
int i ;
for ( i = 0 ; i < 64 ; i + + ) {
if ( s [ i ] ) {
ok = 1 ;
break ;
}
}
if ( ! ok ) { return - 1 ; }
ok = 0 ;
for ( i = 0 ; i < 64 ; i + + ) {
if ( s [ 255 - i ] ) {
ok = 1 ;
break ;
}
}
if ( ! ok ) { return - 1 ; }
2013-12-24 06:29:18 -05:00
ok = 0 ;
for ( i = 0 ; i < 64 ; i + + ) {
if ( s [ i ] < p [ i ] ) {
ok = 1 ;
break ;
} else if ( s [ i ] > p [ i ] ) {
2014-08-13 21:31:24 -04:00
vlogprintf ( E_WARNING , " i = %d (%d %d) \n " , i , ( int ) s [ i ] , ( int ) p [ i ] ) ;
2013-12-24 06:29:18 -05:00
return - 1 ;
}
}
if ( ! ok ) { return - 1 ; }
2013-12-23 05:45:40 -05:00
return 0 ;
}
2014-08-14 14:03:33 -04:00
int tglmp_check_g_bn ( BIGNUM * p , BIGNUM * g ) {
2013-12-24 06:29:18 -05:00
static unsigned char s [ 256 ] ;
memset ( s , 0 , 256 ) ;
assert ( BN_num_bytes ( p ) < = 256 ) ;
BN_bn2bin ( p , s ) ;
2014-08-14 14:03:33 -04:00
return tglmp_check_g ( s , g ) ;
2013-12-24 06:29:18 -05:00
}
2014-08-14 14:03:33 -04:00
static int process_dh_answer ( struct connection * c , char * packet , int len ) {
2014-08-13 21:31:24 -04:00
vlogprintf ( E_DEBUG , " process_dh_answer(), len=%d \n " , len ) ;
2014-08-14 14:03:33 -04:00
//if (len < 116) {
// vlogprintf (E_ERROR, "%u * %u = %llu", p1, p2, what);
//}
2013-10-11 16:52:20 -04:00
assert ( len > = 116 ) ;
assert ( ! * ( long long * ) packet ) ;
assert ( * ( int * ) ( packet + 16 ) = = len - 20 ) ;
assert ( ! ( len & 3 ) ) ;
assert ( * ( int * ) ( packet + 20 ) = = ( int ) CODE_server_DH_params_ok ) ;
assert ( ! memcmp ( packet + 24 , nonce , 16 ) ) ;
assert ( ! memcmp ( packet + 40 , server_nonce , 16 ) ) ;
2014-08-20 18:33:19 -04:00
tgl_init_aes_unauth ( server_nonce , new_nonce , AES_DECRYPT ) ;
2013-10-11 16:52:20 -04:00
in_ptr = ( int * ) ( packet + 56 ) ;
in_end = ( int * ) ( packet + len ) ;
int l = prefetch_strlen ( ) ;
assert ( l > 0 ) ;
2014-08-20 18:33:19 -04:00
l = tgl_pad_aes_decrypt ( fetch_str ( l ) , l , ( char * ) decrypt_buffer , DECRYPT_BUFFER_INTS * 4 - 16 ) ;
2013-10-11 16:52:20 -04:00
assert ( in_ptr = = in_end ) ;
assert ( l > = 60 ) ;
assert ( decrypt_buffer [ 5 ] = = ( int ) CODE_server_DH_inner_data ) ;
assert ( ! memcmp ( decrypt_buffer + 6 , nonce , 16 ) ) ;
assert ( ! memcmp ( decrypt_buffer + 10 , server_nonce , 16 ) ) ;
2013-12-23 05:09:57 -05:00
int g = decrypt_buffer [ 14 ] ;
2013-10-11 16:52:20 -04:00
in_ptr = decrypt_buffer + 15 ;
in_end = decrypt_buffer + ( l > > 2 ) ;
BN_init ( & dh_prime ) ;
BN_init ( & g_a ) ;
assert ( fetch_bignum ( & dh_prime ) > 0 ) ;
assert ( fetch_bignum ( & g_a ) > 0 ) ;
2014-08-14 14:03:33 -04:00
assert ( tglmp_check_g_bn ( & dh_prime , & g_a ) > = 0 ) ;
2013-10-11 16:52:20 -04:00
int server_time = * in_ptr + + ;
assert ( in_ptr < = in_end ) ;
2014-08-14 14:03:33 -04:00
assert ( tglmp_check_DH_params ( & dh_prime , g ) > = 0 ) ;
2013-12-23 05:45:40 -05:00
2013-10-11 16:52:20 -04:00
static char sha1_buffer [ 20 ] ;
sha1 ( ( unsigned char * ) decrypt_buffer + 20 , ( in_ptr - decrypt_buffer - 5 ) * 4 , ( unsigned char * ) sha1_buffer ) ;
assert ( ! memcmp ( decrypt_buffer , sha1_buffer , 20 ) ) ;
assert ( ( char * ) in_end - ( char * ) in_ptr < 16 ) ;
2014-08-14 14:03:33 -04:00
struct dc * D = tgl_state . net_methods - > get_dc ( c ) ;
D - > server_time_delta = server_time - time ( 0 ) ;
D - > server_time_udelta = server_time - get_utime ( CLOCK_MONOTONIC ) ;
2013-10-13 06:18:08 -04:00
//logprintf ( "server time is %d, delta = %d\n", server_time, server_time_delta);
2013-10-11 16:52:20 -04:00
// Build set_client_DH_params answer
clear_packet ( ) ;
packet_ptr + = 5 ;
out_int ( CODE_client_DH_inner_data ) ;
out_ints ( ( int * ) nonce , 4 ) ;
out_ints ( ( int * ) server_nonce , 4 ) ;
out_long ( 0LL ) ;
BN_init ( & dh_g ) ;
2014-01-10 06:32:57 -05:00
ensure ( BN_set_word ( & dh_g , g ) ) ;
2013-10-11 16:52:20 -04:00
2014-08-14 14:03:33 -04:00
tglt_secure_random ( s_power , 256 ) ;
2014-01-10 06:32:57 -05:00
BIGNUM * dh_power = BN_bin2bn ( ( unsigned char * ) s_power , 256 , 0 ) ;
ensure_ptr ( dh_power ) ;
2013-10-11 16:52:20 -04:00
BIGNUM * y = BN_new ( ) ;
2014-01-10 06:32:57 -05:00
ensure_ptr ( y ) ;
2014-08-20 18:33:19 -04:00
ensure ( BN_mod_exp ( y , & dh_g , dh_power , & dh_prime , tgl_state . BN_ctx ) ) ;
2013-10-11 16:52:20 -04:00
out_bignum ( y ) ;
BN_free ( y ) ;
BN_init ( & auth_key_num ) ;
2014-08-20 18:33:19 -04:00
ensure ( BN_mod_exp ( & auth_key_num , & g_a , dh_power , & dh_prime , tgl_state . BN_ctx ) ) ;
2013-10-11 16:52:20 -04:00
l = BN_num_bytes ( & auth_key_num ) ;
assert ( l > = 250 & & l < = 256 ) ;
2014-08-14 14:03:33 -04:00
assert ( BN_bn2bin ( & auth_key_num , ( unsigned char * ) D - > auth_key ) ) ;
memset ( D - > auth_key + l , 0 , 256 - l ) ;
2013-10-11 16:52:20 -04:00
BN_free ( dh_power ) ;
BN_free ( & auth_key_num ) ;
BN_free ( & dh_g ) ;
BN_free ( & g_a ) ;
BN_free ( & dh_prime ) ;
//hexdump (auth_key, auth_key + 256);
sha1 ( ( unsigned char * ) ( packet_buffer + 5 ) , ( packet_ptr - packet_buffer - 5 ) * 4 , ( unsigned char * ) packet_buffer ) ;
//hexdump ((char *)packet_buffer, (char *)packet_ptr);
l = encrypt_packet_buffer_aes_unauth ( server_nonce , new_nonce ) ;
clear_packet ( ) ;
out_int ( CODE_set_client_DH_params ) ;
out_ints ( ( int * ) nonce , 4 ) ;
out_ints ( ( int * ) server_nonce , 4 ) ;
out_cstring ( ( char * ) encrypt_buffer , l ) ;
2014-08-14 18:16:01 -04:00
tgl_state . net_methods - > get_dc ( c ) - > state = st_client_dh_sent ;
2013-10-11 16:52:20 -04:00
return rpc_send_packet ( c ) ;
}
2014-08-14 14:03:33 -04:00
static int process_auth_complete ( struct connection * c UU , char * packet , int len ) {
2014-08-13 21:31:24 -04:00
vlogprintf ( E_DEBUG , " process_dh_answer(), len=%d \n " , len ) ;
2013-10-11 16:52:20 -04:00
assert ( len = = 72 ) ;
assert ( ! * ( long long * ) packet ) ;
assert ( * ( int * ) ( packet + 16 ) = = len - 20 ) ;
assert ( ! ( len & 3 ) ) ;
assert ( * ( int * ) ( packet + 20 ) = = CODE_dh_gen_ok ) ;
assert ( ! memcmp ( packet + 24 , nonce , 16 ) ) ;
assert ( ! memcmp ( packet + 40 , server_nonce , 16 ) ) ;
static unsigned char tmp [ 44 ] , sha1_buffer [ 20 ] ;
memcpy ( tmp , new_nonce , 32 ) ;
tmp [ 32 ] = 1 ;
2013-11-21 14:35:49 -05:00
//GET_DC(c)->auth_key_id = *(long long *)(sha1_buffer + 12);
2014-08-14 14:03:33 -04:00
struct dc * D = tgl_state . net_methods - > get_dc ( c ) ;
bl_do_set_auth_key_id ( D - > id , ( unsigned char * ) D - > auth_key ) ;
sha1 ( ( unsigned char * ) D - > auth_key , 256 , sha1_buffer ) ;
2013-11-21 14:35:49 -05:00
2013-10-11 16:52:20 -04:00
memcpy ( tmp + 33 , sha1_buffer , 8 ) ;
sha1 ( tmp , 41 , sha1_buffer ) ;
assert ( ! memcmp ( packet + 56 , sha1_buffer + 4 , 16 ) ) ;
2014-08-14 14:03:33 -04:00
D - > server_salt = * ( long long * ) server_nonce ^ * ( long long * ) new_nonce ;
2013-11-21 14:35:49 -05:00
2013-10-11 16:52:20 -04:00
//kprintf ("OK\n");
//c->status = conn_error;
//sleep (1);
2014-08-14 18:16:01 -04:00
tgl_state . net_methods - > get_dc ( c ) - > state = st_authorized ;
2013-10-11 16:52:20 -04:00
//return 1;
2014-08-13 21:31:24 -04:00
vlogprintf ( E_DEBUG , " Auth success \n " ) ;
2013-10-11 16:52:20 -04:00
auth_success + + ;
2014-08-14 14:03:33 -04:00
D - > flags | = 1 ;
//write_auth_file ();
2013-11-14 19:08:24 -05:00
2013-10-11 16:52:20 -04:00
return 1 ;
}
/*
*
* AUTHORIZED ( MAIN ) PROTOCOL PART
*
*/
2014-08-14 14:03:33 -04:00
static struct encrypted_message enc_msg ;
2013-10-11 16:52:20 -04:00
2014-08-14 14:03:33 -04:00
static long long client_last_msg_id , server_last_msg_id ;
2013-10-11 16:52:20 -04:00
2014-08-14 14:03:33 -04:00
static double get_server_time ( struct dc * DC ) {
2013-10-11 16:52:20 -04:00
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 ;
}
2014-08-14 14:03:33 -04:00
static long long generate_next_msg_id ( struct dc * DC ) {
2013-10-11 16:52:20 -04:00
long long next_id = ( long long ) ( get_server_time ( DC ) * ( 1LL < < 32 ) ) & - 4 ;
if ( next_id < = client_last_msg_id ) {
next_id = client_last_msg_id + = 4 ;
} else {
client_last_msg_id = next_id ;
}
return next_id ;
}
2014-08-14 14:03:33 -04:00
static void init_enc_msg ( struct session * S , int useful ) {
2013-10-11 16:52:20 -04:00
struct dc * DC = S - > dc ;
assert ( DC - > auth_key_id ) ;
enc_msg . auth_key_id = DC - > auth_key_id ;
2013-11-14 19:08:24 -05:00
// assert (DC->server_salt);
2013-10-11 16:52:20 -04:00
enc_msg . server_salt = DC - > server_salt ;
if ( ! S - > session_id ) {
2014-08-14 14:03:33 -04:00
tglt_secure_random ( & S - > session_id , 8 ) ;
2013-10-11 16:52:20 -04:00
}
enc_msg . session_id = S - > session_id ;
//enc_msg.auth_key_id2 = auth_key_id;
enc_msg . msg_id = generate_next_msg_id ( DC ) ;
//enc_msg.msg_id -= 0x10000000LL * (lrand48 () & 15);
//kprintf ("message id %016llx\n", enc_msg.msg_id);
enc_msg . seq_no = S - > seq_no ;
if ( useful ) {
enc_msg . seq_no | = 1 ;
}
S - > seq_no + = 2 ;
} ;
2014-08-14 14:03:33 -04:00
static int aes_encrypt_message ( struct dc * DC , struct encrypted_message * enc ) {
2013-10-11 16:52:20 -04:00
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 ) ;
//printf ("enc_len is %d\n", enc_len);
2014-08-13 21:31:24 -04:00
vlogprintf ( E_DEBUG , " sending message with sha1 %08x \n " , * ( int * ) sha1_buffer ) ;
2013-10-11 16:52:20 -04:00
memcpy ( enc - > msg_key , sha1_buffer + 4 , 16 ) ;
2014-08-20 18:33:19 -04:00
tgl_init_aes_auth ( DC - > auth_key , enc - > msg_key , AES_ENCRYPT ) ;
2013-10-11 16:52:20 -04:00
//hexdump ((char *)enc, (char *)enc + enc_len + 24);
2014-08-20 18:33:19 -04:00
return tgl_pad_aes_encrypt ( ( char * ) & enc - > server_salt , enc_len , ( char * ) & enc - > server_salt , MAX_MESSAGE_INTS * 4 + ( MINSZ - UNENCSZ ) ) ;
2013-10-11 16:52:20 -04:00
}
2014-08-14 14:03:33 -04:00
long long tglmp_encrypt_send_message ( struct connection * c , int * msg , int msg_ints , int useful ) {
struct dc * DC = tgl_state . net_methods - > get_dc ( c ) ;
struct session * S = tgl_state . net_methods - > get_session ( c ) ;
2013-10-11 16:52:20 -04:00
assert ( S ) ;
2014-08-14 14:03:33 -04:00
2013-10-11 16:52:20 -04:00
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 ( S , useful ) ;
//hexdump ((char *)msg, (char *)msg + (msg_ints * 4));
int l = aes_encrypt_message ( DC , & enc_msg ) ;
//hexdump ((char *)&enc_msg, (char *)&enc_msg + l + 24);
assert ( l > 0 ) ;
rpc_send_message ( c , & enc_msg , l + UNENCSZ ) ;
return client_last_msg_id ;
}
2014-08-14 14:03:33 -04:00
static int good_messages ;
2013-10-16 15:19:39 -04:00
2014-08-14 14:03:33 -04:00
static void rpc_execute_answer ( struct connection * c , long long msg_id UU ) ;
2013-10-16 15:19:39 -04:00
2014-08-14 14:03:33 -04:00
//int unread_messages;
//int pts;
//int qts;
//int last_date;
//int seq;
2013-10-16 15:19:39 -04:00
2014-08-14 14:03:33 -04:00
static void work_container ( struct connection * c , long long msg_id UU ) {
2014-08-13 21:31:24 -04:00
vlogprintf ( E_DEBUG , " work_container: msg_id = %lld \n " , msg_id ) ;
2013-10-11 16:52:20 -04:00
assert ( fetch_int ( ) = = CODE_msg_container ) ;
int n = fetch_int ( ) ;
int i ;
for ( i = 0 ; i < n ; i + + ) {
long long id = fetch_long ( ) ;
2014-01-02 13:52:41 -05:00
//int seqno = fetch_int ();
fetch_int ( ) ; // seq_no
if ( id & 1 ) {
2014-08-14 14:03:33 -04:00
tgln_insert_msg_id ( tgl_state . net_methods - > get_session ( c ) , id ) ;
2013-10-11 16:52:20 -04:00
}
int bytes = fetch_int ( ) ;
2013-10-26 15:57:22 -04:00
int * t = in_end ;
in_end = in_ptr + ( bytes / 4 ) ;
2013-10-11 16:52:20 -04:00
rpc_execute_answer ( c , id ) ;
2013-10-26 15:57:22 -04:00
assert ( in_ptr = = in_end ) ;
in_end = t ;
2013-10-11 16:52:20 -04:00
}
}
2014-08-14 14:03:33 -04:00
static void work_new_session_created ( struct connection * c , long long msg_id UU ) {
2014-08-13 21:31:24 -04:00
vlogprintf ( E_DEBUG , " work_new_session_created: msg_id = %lld \n " , msg_id ) ;
2013-10-11 16:52:20 -04:00
assert ( fetch_int ( ) = = ( int ) CODE_new_session_created ) ;
fetch_long ( ) ; // first message id
//DC->session_id = fetch_long ();
fetch_long ( ) ; // unique_id
2014-08-14 14:03:33 -04:00
tgl_state . net_methods - > get_dc ( c ) - > server_salt = fetch_long ( ) ;
2013-11-14 19:08:24 -05:00
2013-10-11 16:52:20 -04:00
}
2014-08-14 14:03:33 -04:00
static void work_msgs_ack ( struct connection * c UU , long long msg_id UU ) {
2014-08-13 21:31:24 -04:00
vlogprintf ( E_DEBUG , " work_msgs_ack: msg_id = %lld \n " , msg_id ) ;
2013-10-11 16:52:20 -04:00
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 ( ) ;
2014-08-13 21:31:24 -04:00
vlogprintf ( E_DEBUG + 1 , " ack for %lld \n " , id ) ;
2014-08-14 14:03:33 -04:00
tglq_query_ack ( id ) ;
2013-10-11 16:52:20 -04:00
}
}
2014-08-14 14:03:33 -04:00
static void work_rpc_result ( struct connection * c UU , long long msg_id UU ) {
2014-08-13 21:31:24 -04:00
vlogprintf ( E_DEBUG , " work_rpc_result: msg_id = %lld \n " , msg_id ) ;
2013-10-11 16:52:20 -04:00
assert ( fetch_int ( ) = = ( int ) CODE_rpc_result ) ;
long long id = fetch_long ( ) ;
int op = prefetch_int ( ) ;
if ( op = = CODE_rpc_error ) {
2014-08-14 14:03:33 -04:00
tglq_query_error ( id ) ;
2013-10-11 16:52:20 -04:00
} else {
2014-08-14 14:03:33 -04:00
tglq_query_result ( id ) ;
2013-10-11 16:52:20 -04:00
}
}
2013-11-11 13:35:31 -05:00
# define MAX_PACKED_SIZE (1 << 24)
2014-08-14 14:03:33 -04:00
static void work_packed ( struct connection * c , long long msg_id ) {
2013-10-18 12:00:47 -04:00
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 ) ;
2014-08-20 18:33:19 -04:00
int total_out = tgl_inflate ( s , l , buf , MAX_PACKED_SIZE ) ;
2013-10-18 12:00:47 -04:00
int * end = in_ptr ;
int * eend = in_end ;
2014-01-10 11:54:47 -05:00
//assert (total_out % 4 == 0);
2013-10-18 12:00:47 -04:00
in_ptr = buf ;
2014-01-10 11:54:47 -05:00
in_end = in_ptr + total_out / 4 ;
2013-10-18 12:00:47 -04:00
rpc_execute_answer ( c , msg_id ) ;
in_ptr = end ;
in_end = eend ;
in_gzip = 0 ;
}
2014-08-14 14:03:33 -04:00
static void work_bad_server_salt ( struct connection * c UU , long long msg_id UU ) {
2013-10-25 17:08:52 -04:00
assert ( fetch_int ( ) = = ( int ) CODE_bad_server_salt ) ;
long long id = fetch_long ( ) ;
2014-08-14 14:03:33 -04:00
tglq_query_restart ( id ) ;
2013-10-25 17:08:52 -04:00
fetch_int ( ) ; // seq_no
fetch_int ( ) ; // error_code
long long new_server_salt = fetch_long ( ) ;
2014-08-14 14:03:33 -04:00
tgl_state . net_methods - > get_dc ( c ) - > server_salt = new_server_salt ;
2013-10-25 17:08:52 -04:00
}
2014-08-14 14:03:33 -04:00
static void work_pong ( struct connection * c UU , long long msg_id UU ) {
2013-10-26 11:32:20 -04:00
assert ( fetch_int ( ) = = CODE_pong ) ;
fetch_long ( ) ; // msg_id
fetch_long ( ) ; // ping_id
}
2014-08-14 14:03:33 -04:00
static void work_detailed_info ( struct connection * c UU , long long msg_id UU ) {
2013-11-25 12:21:08 -05:00
assert ( fetch_int ( ) = = CODE_msg_detailed_info ) ;
2013-10-26 11:32:20 -04:00
fetch_long ( ) ; // msg_id
fetch_long ( ) ; // answer_msg_id
fetch_int ( ) ; // bytes
fetch_int ( ) ; // status
}
2014-08-14 14:03:33 -04:00
static void work_new_detailed_info ( struct connection * c UU , long long msg_id UU ) {
2014-01-02 13:52:41 -05:00
assert ( fetch_int ( ) = = ( int ) CODE_msg_new_detailed_info ) ;
2013-11-25 12:21:08 -05:00
fetch_long ( ) ; // answer_msg_id
fetch_int ( ) ; // bytes
fetch_int ( ) ; // status
}
2014-08-14 14:03:33 -04:00
static void work_bad_msg_notification ( struct connection * c UU , long long msg_id UU ) {
2014-01-02 13:52:41 -05:00
assert ( fetch_int ( ) = = ( int ) CODE_bad_msg_notification ) ;
long long m1 = fetch_long ( ) ;
int s = fetch_int ( ) ;
int e = fetch_int ( ) ;
2014-08-13 21:31:24 -04:00
vlogprintf ( E_NOTICE , " bad_msg_notification: msg_id = %lld, seq = %d, error = %d \n " , m1 , s , e ) ;
2014-01-02 13:52:41 -05:00
}
2014-08-14 14:03:33 -04:00
static void rpc_execute_answer ( struct connection * c , long long msg_id UU ) {
2013-10-11 16:52:20 -04:00
int op = prefetch_int ( ) ;
switch ( op ) {
case CODE_msg_container :
work_container ( c , msg_id ) ;
return ;
case CODE_new_session_created :
work_new_session_created ( c , msg_id ) ;
return ;
case CODE_msgs_ack :
work_msgs_ack ( c , msg_id ) ;
return ;
case CODE_rpc_result :
work_rpc_result ( c , msg_id ) ;
return ;
2013-10-16 15:19:39 -04:00
case CODE_update_short :
2014-08-14 14:03:33 -04:00
tglu_work_update_short ( c , msg_id ) ;
2013-10-16 15:19:39 -04:00
return ;
case CODE_updates :
2014-08-14 14:03:33 -04:00
tglu_work_updates ( c , msg_id ) ;
2013-10-16 15:19:39 -04:00
return ;
case CODE_update_short_message :
2014-08-14 14:03:33 -04:00
tglu_work_update_short_message ( c , msg_id ) ;
2013-10-16 15:19:39 -04:00
return ;
case CODE_update_short_chat_message :
2014-08-14 14:03:33 -04:00
tglu_work_update_short_chat_message ( c , msg_id ) ;
2013-10-16 15:19:39 -04:00
return ;
2013-10-18 12:00:47 -04:00
case CODE_gzip_packed :
work_packed ( c , msg_id ) ;
return ;
2013-10-25 17:08:52 -04:00
case CODE_bad_server_salt :
work_bad_server_salt ( c , msg_id ) ;
return ;
2013-10-26 11:32:20 -04:00
case CODE_pong :
work_pong ( c , msg_id ) ;
return ;
2013-11-25 12:21:08 -05:00
case CODE_msg_detailed_info :
work_detailed_info ( c , msg_id ) ;
return ;
case CODE_msg_new_detailed_info :
work_new_detailed_info ( c , msg_id ) ;
2013-10-26 11:32:20 -04:00
return ;
2013-11-04 12:34:27 -05:00
case CODE_updates_too_long :
2014-08-14 14:03:33 -04:00
tglu_work_updates_to_long ( c , msg_id ) ;
2013-11-04 12:34:27 -05:00
return ;
2014-01-02 13:52:41 -05:00
case CODE_bad_msg_notification :
work_bad_msg_notification ( c , msg_id ) ;
return ;
2013-10-11 16:52:20 -04:00
}
2014-08-13 21:31:24 -04:00
vlogprintf ( E_WARNING , " Unknown message: %08x \n " , op ) ;
2013-10-26 15:57:22 -04:00
in_ptr = in_end ; // Will not fail due to assertion in_ptr == in_end
2013-10-11 16:52:20 -04:00
}
2014-08-14 14:03:33 -04:00
static int process_rpc_message ( struct connection * c UU , struct encrypted_message * enc , int len ) {
2013-10-11 16:52:20 -04:00
const int MINSZ = offsetof ( struct encrypted_message , message ) ;
const int UNENCSZ = offsetof ( struct encrypted_message , server_salt ) ;
2014-08-13 21:31:24 -04:00
vlogprintf ( E_DEBUG , " process_rpc_message(), len=%d \n " , len ) ;
2013-10-11 16:52:20 -04:00
assert ( len > = MINSZ & & ( len & 15 ) = = ( UNENCSZ & 15 ) ) ;
2014-08-14 14:03:33 -04:00
struct dc * DC = tgl_state . net_methods - > get_dc ( c ) ;
2013-10-11 16:52:20 -04:00
assert ( enc - > auth_key_id = = DC - > auth_key_id ) ;
assert ( DC - > auth_key_id ) ;
2014-08-20 18:33:19 -04:00
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 ) ;
2013-10-11 16:52:20 -04:00
assert ( l = = len - UNENCSZ ) ;
//assert (enc->auth_key_id2 == enc->auth_key_id);
assert ( ! ( enc - > msg_len & 3 ) & & enc - > msg_len > 0 & & enc - > msg_len < = len - MINSZ & & len - MINSZ - enc - > msg_len < = 12 ) ;
static unsigned char sha1_buffer [ 20 ] ;
sha1 ( ( void * ) & enc - > server_salt , enc - > msg_len + ( MINSZ - UNENCSZ ) , sha1_buffer ) ;
assert ( ! memcmp ( & enc - > msg_key , sha1_buffer + 4 , 16 ) ) ;
//assert (enc->server_salt == server_salt); //in fact server salt can change
if ( DC - > server_salt ! = enc - > server_salt ) {
DC - > server_salt = enc - > server_salt ;
2014-08-14 14:03:33 -04:00
//write_auth_file ();
2013-10-11 16:52:20 -04:00
}
2013-10-18 14:08:20 -04:00
2013-10-11 16:52:20 -04:00
int this_server_time = enc - > msg_id > > 32LL ;
2013-10-18 14:08:20 -04:00
if ( ! DC - > server_time_delta ) {
2014-01-02 13:52:41 -05:00
DC - > server_time_delta = this_server_time - get_utime ( CLOCK_REALTIME ) ;
2013-10-18 14:08:20 -04:00
DC - > server_time_udelta = this_server_time - get_utime ( CLOCK_MONOTONIC ) ;
}
2013-10-11 16:52:20 -04:00
double st = get_server_time ( DC ) ;
2014-01-02 13:52:41 -05:00
if ( this_server_time < st - 300 | | this_server_time > st + 30 ) {
2014-08-13 21:31:24 -04:00
vlogprintf ( E_WARNING , " salt = %lld, session_id = %lld, msg_id = %lld, 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 ) ) ;
2014-01-02 13:52:41 -05:00
in_ptr = enc - > message ;
in_end = in_ptr + ( enc - > msg_len / 4 ) ;
}
2013-10-11 16:52:20 -04:00
assert ( this_server_time > = st - 300 & & this_server_time < = st + 30 ) ;
//assert (enc->msg_id > server_last_msg_id && (enc->msg_id & 3) == 1);
2014-08-14 14:03:33 -04:00
vlogprintf ( E_DEBUG , " received mesage id %016llx \n " , enc - > msg_id ) ;
2013-10-11 16:52:20 -04:00
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);
+ + good_messages ;
in_ptr = enc - > message ;
in_end = in_ptr + ( enc - > msg_len / 4 ) ;
2014-08-14 14:03:33 -04:00
struct session * S = tgl_state . net_methods - > get_session ( c ) ;
2014-01-02 13:52:41 -05:00
if ( enc - > msg_id & 1 ) {
2014-08-14 14:03:33 -04:00
tgln_insert_msg_id ( S , enc - > msg_id ) ;
2013-10-11 16:52:20 -04:00
}
2014-08-14 14:03:33 -04:00
assert ( S - > session_id = = enc - > session_id ) ;
2013-10-11 16:52:20 -04:00
rpc_execute_answer ( c , enc - > msg_id ) ;
2013-10-26 11:32:20 -04:00
assert ( in_ptr = = in_end ) ;
2013-10-11 16:52:20 -04:00
return 0 ;
}
2014-08-14 14:03:33 -04:00
static int rpc_execute ( struct connection * c , int op , int len ) {
vlogprintf ( E_DEBUG , " outbound rpc connection from dc #%d : received rpc answer %d with %d content bytes \n " , tgl_state . net_methods - > get_dc ( c ) - > id , op , len ) ;
2013-11-08 13:58:28 -05:00
/* if (op < 0) {
2014-08-14 14:03:33 -04:00
assert ( tgl_state . net_methods - > read_in ( c , Response , Response_len ) = = Response_len ) ;
2013-11-07 12:37:12 -05:00
return 0 ;
2013-11-08 13:58:28 -05:00
} */
2013-10-11 16:52:20 -04:00
if ( len > = MAX_RESPONSE_SIZE /* - 12*/ | | len < 0 /*12*/ ) {
2014-08-14 14:03:33 -04:00
vlogprintf ( E_WARNING , " answer too long (%d bytes), skipping \n " , len ) ;
2013-10-11 16:52:20 -04:00
return 0 ;
}
int Response_len = len ;
2014-08-14 14:03:33 -04:00
vlogprintf ( E_DEBUG , " Response_len = %d \n " , Response_len ) ;
assert ( tgl_state . net_methods - > read_in ( c , Response , Response_len ) = = Response_len ) ;
2013-10-11 16:52:20 -04:00
Response [ Response_len ] = 0 ;
2014-02-25 09:25:57 -05:00
# if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__)
2014-08-14 14:03:33 -04:00
// setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4);
2013-11-11 06:34:45 -05:00
# endif
2014-08-14 14:03:33 -04:00
struct dc * D = tgl_state . net_methods - > get_dc ( c ) ;
int o = D - > state ;
if ( D - > flags & 1 ) { o = st_authorized ; }
2013-10-11 16:52:20 -04:00
switch ( o ) {
case st_reqpq_sent :
process_respq_answer ( c , Response /* + 8*/ , Response_len /* - 12*/ ) ;
2014-02-25 09:25:57 -05:00
# if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__)
2014-08-14 14:03:33 -04:00
// setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4);
2013-11-11 06:34:45 -05:00
# endif
2013-10-11 16:52:20 -04:00
return 0 ;
case st_reqdh_sent :
process_dh_answer ( c , Response /* + 8*/ , Response_len /* - 12*/ ) ;
2014-02-25 09:25:57 -05:00
# if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__)
2014-08-14 14:03:33 -04:00
// setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4);
2013-11-11 06:34:45 -05:00
# endif
2013-10-11 16:52:20 -04:00
return 0 ;
case st_client_dh_sent :
process_auth_complete ( c , Response /* + 8*/ , Response_len /* - 12*/ ) ;
2014-02-25 09:25:57 -05:00
# if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__)
2014-08-14 14:03:33 -04:00
// setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4);
2013-11-11 06:34:45 -05:00
# endif
2013-10-11 16:52:20 -04:00
return 0 ;
case st_authorized :
2013-11-14 19:08:24 -05:00
if ( op < 0 & & op > = - 999 ) {
2014-08-14 14:03:33 -04:00
vlogprintf ( E_WARNING , " Server error %d \n " , op ) ;
2013-11-14 19:08:24 -05:00
} else {
process_rpc_message ( c , ( void * ) ( Response /* + 8*/ ) , Response_len /* - 12*/ ) ;
}
2014-02-25 09:25:57 -05:00
# if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__)
2014-08-14 14:03:33 -04:00
// setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4);
2013-11-11 06:34:45 -05:00
# endif
2013-10-11 16:52:20 -04:00
return 0 ;
default :
2014-08-14 18:16:01 -04:00
vlogprintf ( E_ERROR , " fatal: cannot receive answer in state %d \n " , D - > state ) ;
2013-10-11 16:52:20 -04:00
exit ( 2 ) ;
}
return 0 ;
}
2014-08-14 14:03:33 -04:00
static int tc_close ( struct connection * c , int who ) {
vlogprintf ( E_DEBUG , " outbound rpc connection from dc #%d : closing by %d \n " , tgl_state . net_methods - > get_dc ( c ) - > id , who ) ;
2013-10-11 16:52:20 -04:00
return 0 ;
}
2014-08-14 14:03:33 -04:00
static int tc_becomes_ready ( struct connection * c ) {
vlogprintf ( E_DEBUG , " outbound rpc connection from dc #%d becomed ready \n " , tgl_state . net_methods - > get_dc ( c ) - > id ) ;
2014-08-14 18:16:01 -04:00
//char byte = 0xef;
//assert (tgl_state.net_methods->write_out (c, &byte, 1) == 1);
//tgl_state.net_methods->flush_out (c);
2013-10-11 16:52:20 -04:00
2014-02-25 09:25:57 -05:00
# if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__)
2014-08-14 14:03:33 -04:00
// setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4);
2013-11-11 06:34:45 -05:00
# endif
2014-08-14 14:03:33 -04:00
struct dc * D = tgl_state . net_methods - > get_dc ( c ) ;
int o = D - > state ;
if ( D - > flags & 1 ) { o = st_authorized ; }
2013-10-11 16:52:20 -04:00
switch ( o ) {
case st_init :
send_req_pq_packet ( c ) ;
break ;
2014-08-14 18:16:01 -04:00
case st_authorized :
break ;
2013-10-11 16:52:20 -04:00
default :
2014-08-14 18:16:01 -04:00
vlogprintf ( E_DEBUG , " c_state = %d \n " , D - > state ) ;
2013-10-11 16:52:20 -04:00
assert ( 0 ) ;
}
return 0 ;
}
2014-08-14 14:03:33 -04:00
static int rpc_becomes_ready ( struct connection * c ) {
2013-10-11 16:52:20 -04:00
return tc_becomes_ready ( c ) ;
}
2014-08-14 14:03:33 -04:00
static int rpc_close ( struct connection * c ) {
2013-10-11 16:52:20 -04:00
return tc_close ( c , 0 ) ;
}
2014-02-25 09:58:54 -05:00
# define RANDSEED_PASSWORD_FILENAME NULL
# define RANDSEED_PASSWORD_LENGTH 0
2014-08-14 14:03:33 -04:00
void tglmp_on_start ( const char * key ) {
2014-08-20 18:33:19 -04:00
tgl_prng_seed ( RANDSEED_PASSWORD_FILENAME , RANDSEED_PASSWORD_LENGTH ) ;
2013-10-11 16:52:20 -04:00
2014-08-14 14:03:33 -04:00
if ( key ) {
if ( rsa_load_public_key ( key ) < 0 ) {
2014-02-04 11:35:16 -05:00
perror ( " rsa_load_public_key " ) ;
exit ( 1 ) ;
}
} else {
2014-02-25 09:58:54 -05:00
if ( rsa_load_public_key ( TG_SERVER_PUBKEY_FILENAME ) < 0
& & rsa_load_public_key ( " /etc/ " PROG_NAME " /server.pub " ) < 0 ) {
2014-02-04 11:35:16 -05:00
perror ( " rsa_load_public_key " ) ;
exit ( 1 ) ;
}
2013-10-11 16:52:20 -04:00
}
2014-08-20 18:33:19 -04:00
pk_fingerprint = tgl_do_compute_rsa_key_fingerprint ( pubKey ) ;
2013-10-11 16:52:20 -04:00
}
2014-08-14 14:03:33 -04:00
//int auth_ok (void) {
// return auth_success;
//}
2013-10-11 16:52:20 -04:00
2014-08-14 14:03:33 -04:00
void tgl_dc_authorize ( struct dc * DC ) {
//c_state = 0;
//auth_success = 0;
2013-10-11 16:52:20 -04:00
if ( ! DC - > sessions [ 0 ] ) {
2014-08-14 14:03:33 -04:00
tglmp_dc_create_session ( DC ) ;
2013-10-11 16:52:20 -04:00
}
2014-08-14 14:03:33 -04:00
vlogprintf ( E_DEBUG , " Starting authorization for DC #%d: %s:%d \n " , DC - > id , DC - > ip , DC - > port ) ;
//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 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 ) ;
2013-10-11 16:52:20 -04:00
}
2014-08-14 14:03:33 -04:00
tglmp_encrypt_send_message ( S - > c , packet_buffer , packet_ptr - packet_buffer , 0 ) ;
return 0 ;
}
static void send_all_acks_gateway ( evutil_socket_t fd , short what , void * arg ) {
send_all_acks ( arg ) ;
}
void tgln_insert_msg_id ( struct session * S , long long id ) {
if ( ! S - > ack_tree ) {
static struct timeval ptimeout = { ACK_TIMEOUT , 0 } ;
event_add ( S - > ev , & ptimeout ) ;
}
if ( ! tree_lookup_long ( S - > ack_tree , id ) ) {
S - > ack_tree = tree_insert_long ( S - > ack_tree , id , lrand48 ( ) ) ;
}
}
//extern struct dc *DC_list[];
struct dc * tglmp_alloc_dc ( int id , char * ip , int port UU ) {
assert ( ! tgl_state . DC_list [ id ] ) ;
struct dc * DC = talloc0 ( sizeof ( * DC ) ) ;
DC - > id = id ;
DC - > ip = ip ;
DC - > port = port ;
tgl_state . DC_list [ id ] = DC ;
2014-08-15 10:57:43 -04:00
if ( id > tgl_state . max_dc_num ) {
tgl_state . max_dc_num = id ;
}
2014-08-14 14:03:33 -04:00
return DC ;
}
static struct mtproto_methods mtproto_methods = {
. execute = rpc_execute ,
. ready = rpc_becomes_ready ,
. close = rpc_close
} ;
void tglmp_dc_create_session ( struct dc * DC ) {
struct session * S = talloc0 ( sizeof ( * S ) ) ;
assert ( RAND_pseudo_bytes ( ( unsigned char * ) & S - > session_id , 8 ) > = 0 ) ;
S - > dc = DC ;
2014-08-15 10:57:43 -04:00
S - > c = tgl_state . net_methods - > create_connection ( DC - > ip , DC - > port , S , DC , & mtproto_methods ) ;
2014-08-14 14:03:33 -04:00
if ( ! S - > c ) {
vlogprintf ( E_DEBUG , " Can not create connection to DC. Is network down? \n " ) ;
exit ( 1 ) ;
}
S - > ev = evtimer_new ( tgl_state . ev_base , send_all_acks_gateway , S ) ;
assert ( ! DC - > sessions [ 0 ] ) ;
DC - > sessions [ 0 ] = S ;
}
void tgl_do_send_ping ( struct connection * c ) {
int x [ 3 ] ;
x [ 0 ] = CODE_ping ;
* ( long long * ) ( x + 1 ) = lrand48 ( ) * ( 1ll < < 32 ) + lrand48 ( ) ;
tglmp_encrypt_send_message ( c , x , 3 , 0 ) ;
2013-10-11 16:52:20 -04:00
}