LCOV - code coverage report
Current view: top level - src/core - mtproto_session.c (source / functions) Coverage Total Hit
Test: coverage-functional.info Lines: 69.4 % 49 34
Test Date: 2026-05-06 13:17:08 Functions: 75.0 % 8 6

            Line data    Source code
       1              : /* SPDX-License-Identifier: GPL-3.0-or-later */
       2              : /* Copyright 2026 Peter Csaszar */
       3              : 
       4              : /**
       5              :  * @file mtproto_session.c
       6              :  * @brief MTProto session state management.
       7              :  */
       8              : 
       9              : #include "mtproto_session.h"
      10              : #include "crypto.h"
      11              : #include "raii.h"
      12              : #include "fs_util.h"
      13              : 
      14              : #include <stdio.h>
      15              : #include <stdlib.h>
      16              : #include <string.h>
      17              : #include <time.h>
      18              : 
      19              : /**
      20              :  * @brief Initialize a new MTProto session with a random session_id.
      21              :  * @param s Session to initialize.
      22              :  */
      23          552 : void mtproto_session_init(MtProtoSession *s) {
      24          552 :     if (!s) return;
      25          552 :     memset(s, 0, sizeof(*s));
      26              : 
      27              :     /* Random session_id */
      28          552 :     crypto_rand_bytes((unsigned char *)&s->session_id, sizeof(s->session_id));
      29              :     /* Ensure non-zero */
      30          552 :     if (s->session_id == 0) s->session_id = 1;
      31              : }
      32              : 
      33            1 : void mtproto_session_renew_id(MtProtoSession *s) {
      34            1 :     if (!s) return;
      35            1 :     crypto_rand_bytes((unsigned char *)&s->session_id, sizeof(s->session_id));
      36            1 :     if (s->session_id == 0) s->session_id = 1;
      37            1 :     s->seq_no     = 0;
      38            1 :     s->last_msg_id = 0;
      39              : }
      40              : 
      41              : /**
      42              :  * @brief Generate the next monotonically increasing message ID.
      43              :  *
      44              :  * Message IDs are approximately unix_time * 2^32, must be divisible by 4
      45              :  * (client→server), and strictly increasing.
      46              :  *
      47              :  * @param s Session.
      48              :  * @return Next message ID, or 0 if s is NULL.
      49              :  */
      50          328 : uint64_t mtproto_session_next_msg_id(MtProtoSession *s) {
      51          328 :     if (!s) return 0;
      52              : 
      53              :     /* msg_id ≈ unix_time * 2^32 with cryptographic randomness in the
      54              :      * lower 32 bits. Must be monotonically increasing and divisible by
      55              :      * 4 for client→server. */
      56          328 :     uint64_t now = (uint64_t)time(NULL);
      57          328 :     uint32_t low = 0;
      58          328 :     crypto_rand_bytes((unsigned char *)&low, sizeof(low));
      59          328 :     uint64_t msg_id = (now << 32) | ((uint64_t)low & 0xFFFFFFFC);
      60              : 
      61              :     /* Ensure monotonic increase */
      62          328 :     if (msg_id <= s->last_msg_id) {
      63           77 :         msg_id = s->last_msg_id + 4;
      64              :     }
      65              : 
      66              :     /* Client→server: msg_id mod 4 == 0 */
      67          328 :     msg_id &= ~(uint64_t)3;
      68              : 
      69          328 :     s->last_msg_id = msg_id;
      70          328 :     return msg_id;
      71              : }
      72              : 
      73              : /**
      74              :  * @brief Get the next sequence number.
      75              :  *
      76              :  * For content-related messages, increments the internal counter.
      77              :  *
      78              :  * @param s Session.
      79              :  * @param content_related 1 for RPC calls, 0 for acks/pings.
      80              :  * @return Next sequence number, or 0 if s is NULL.
      81              :  */
      82          313 : uint32_t mtproto_session_next_seq_no(MtProtoSession *s, int content_related) {
      83          313 :     if (!s) return 0;
      84          313 :     uint32_t result = s->seq_no * 2 + (content_related ? 1 : 0);
      85          313 :     if (content_related) s->seq_no++;
      86          313 :     return result;
      87              : }
      88              : 
      89              : /**
      90              :  * @brief Set the 256-byte authorization key on the session.
      91              :  * @param s   Session.
      92              :  * @param key 256-byte key to copy.
      93              :  */
      94          242 : void mtproto_session_set_auth_key(MtProtoSession *s, const uint8_t key[256]) {
      95          242 :     if (!s || !key) return;
      96          242 :     memcpy(s->auth_key, key, 256);
      97          242 :     s->has_auth_key = 1;
      98              : }
      99              : 
     100              : /**
     101              :  * @brief Set the server salt.
     102              :  * @param s    Session.
     103              :  * @param salt Server salt value.
     104              :  */
     105          242 : void mtproto_session_set_salt(MtProtoSession *s, uint64_t salt) {
     106          242 :     if (!s) return;
     107          242 :     s->server_salt = salt;
     108              : }
     109              : 
     110              : /**
     111              :  * @brief Save the auth key to a file with mode 0600.
     112              :  *
     113              :  * @param s    Session (must have auth_key).
     114              :  * @param path File path to write.
     115              :  * @return 0 on success, -1 on error.
     116              :  */
     117            0 : int mtproto_session_save_auth_key(const MtProtoSession *s, const char *path) {
     118            0 :     if (!s || !path || !s->has_auth_key) return -1;
     119            0 :     RAII_FILE FILE *f = fopen(path, "wb");
     120            0 :     if (!f) return -1;
     121              : 
     122              :     /* Set restrictive permissions (auth key is sensitive) */
     123            0 :     if (fs_ensure_permissions(path, 0600) != 0) {
     124              :         /* Non-fatal but log-worthy — file was already created */
     125              :     }
     126              : 
     127            0 :     size_t written = fwrite(s->auth_key, 1, 256, f);
     128            0 :     return (written == 256) ? 0 : -1;
     129              : }
     130              : 
     131              : /**
     132              :  * @brief Load an auth key from a file.
     133              :  *
     134              :  * @param s    Session (auth_key and has_auth_key will be set on success).
     135              :  * @param path File path to read.
     136              :  * @return 0 on success, -1 on error (file not found, too short, etc.).
     137              :  */
     138            0 : int mtproto_session_load_auth_key(MtProtoSession *s, const char *path) {
     139            0 :     if (!s || !path) return -1;
     140            0 :     RAII_FILE FILE *f = fopen(path, "rb");
     141            0 :     if (!f) return -1;
     142            0 :     size_t nread = fread(s->auth_key, 1, 256, f);
     143            0 :     if (nread != 256) return -1;
     144            0 :     s->has_auth_key = 1;
     145            0 :     return 0;
     146              : }
        

Generated by: LCOV version 2.0-1