Line data Source code
1 : /* SPDX-License-Identifier: GPL-3.0-or-later */
2 : /* Copyright 2026 Peter Csaszar */
3 :
4 : /**
5 : * @file auth_transfer.c
6 : * @brief P10-04 — auth.exportAuthorization + auth.importAuthorization.
7 : */
8 :
9 : #include "auth_transfer.h"
10 :
11 : #include "tl_serial.h"
12 : #include "tl_registry.h"
13 : #include "logger.h"
14 : #include "raii.h"
15 :
16 : #include <stdlib.h>
17 : #include <string.h>
18 :
19 : /* TL constructor IDs (not yet in tl_registry). */
20 : #define CRC_auth_exportAuthorization 0xe5bfffcdu
21 : #define CRC_auth_exportedAuthorization 0xb434e2b8u
22 : #define CRC_auth_importAuthorization 0xa57a7dadu
23 : #define CRC_auth_authorization 0x2ea2c0d4u
24 : #define CRC_auth_authorizationSignUpRequired 0x44747e9au
25 :
26 : #define RESP_BUF_SIZE 65536
27 :
28 : /* ---- export ---- */
29 :
30 13 : int auth_transfer_export(const ApiConfig *cfg,
31 : MtProtoSession *home_s, Transport *home_t,
32 : int target_dc_id,
33 : AuthExported *out,
34 : RpcError *err) {
35 13 : if (!cfg || !home_s || !home_t || !out) return -1;
36 12 : if (err) { err->error_code = 0; err->error_msg[0] = '\0';
37 9 : err->migrate_dc = -1; err->flood_wait_secs = 0; }
38 12 : memset(out, 0, sizeof(*out));
39 :
40 : uint8_t query[64];
41 12 : TlWriter w; tl_writer_init(&w);
42 12 : tl_write_uint32(&w, CRC_auth_exportAuthorization);
43 12 : tl_write_int32 (&w, target_dc_id);
44 12 : if (w.len > sizeof(query)) { tl_writer_free(&w); return -1; }
45 12 : memcpy(query, w.data, w.len);
46 12 : size_t qlen = w.len;
47 12 : tl_writer_free(&w);
48 :
49 12 : RAII_STRING uint8_t *resp = (uint8_t *)malloc(RESP_BUF_SIZE);
50 12 : if (!resp) return -1;
51 12 : size_t resp_len = 0;
52 12 : if (api_call(cfg, home_s, home_t, query, qlen,
53 : resp, RESP_BUF_SIZE, &resp_len) != 0) {
54 0 : logger_log(LOG_ERROR, "auth_transfer_export: api_call failed");
55 0 : return -1;
56 : }
57 12 : if (resp_len < 4) return -1;
58 :
59 : uint32_t top;
60 12 : memcpy(&top, resp, 4);
61 12 : if (top == TL_rpc_error) {
62 1 : RpcError perr; rpc_parse_error(resp, resp_len, &perr);
63 1 : if (err) *err = perr;
64 1 : logger_log(LOG_ERROR, "auth_transfer_export: RPC %d: %s",
65 : perr.error_code, perr.error_msg);
66 1 : return -1;
67 : }
68 11 : if (top != CRC_auth_exportedAuthorization) {
69 0 : logger_log(LOG_ERROR,
70 : "auth_transfer_export: unexpected top 0x%08x", top);
71 0 : return -1;
72 : }
73 :
74 11 : TlReader r = tl_reader_init(resp, resp_len);
75 11 : tl_read_uint32(&r); /* constructor */
76 11 : out->id = tl_read_int64(&r);
77 :
78 11 : size_t bl = 0;
79 22 : RAII_STRING uint8_t *bytes = tl_read_bytes(&r, &bl);
80 11 : if (!bytes || bl == 0 || bl > AUTH_TRANSFER_BYTES_MAX) {
81 2 : logger_log(LOG_ERROR,
82 : "auth_transfer_export: bytes len %zu out of range", bl);
83 2 : return -1;
84 : }
85 9 : memcpy(out->bytes, bytes, bl);
86 9 : out->bytes_len = bl;
87 9 : logger_log(LOG_INFO,
88 : "auth_transfer_export: exported to DC%d (id=%lld, %zu bytes)",
89 9 : target_dc_id, (long long)out->id, bl);
90 9 : return 0;
91 : }
92 :
93 : /* ---- import ---- */
94 :
95 9 : int auth_transfer_import(const ApiConfig *cfg,
96 : MtProtoSession *s, Transport *t,
97 : const AuthExported *in,
98 : RpcError *err) {
99 9 : if (!cfg || !s || !t || !in) return -1;
100 8 : if (in->bytes_len == 0 || in->bytes_len > AUTH_TRANSFER_BYTES_MAX)
101 1 : return -1;
102 7 : if (err) { err->error_code = 0; err->error_msg[0] = '\0';
103 6 : err->migrate_dc = -1; err->flood_wait_secs = 0; }
104 :
105 7 : TlWriter w; tl_writer_init(&w);
106 7 : tl_write_uint32(&w, CRC_auth_importAuthorization);
107 7 : tl_write_int64 (&w, in->id);
108 7 : tl_write_bytes (&w, in->bytes, in->bytes_len);
109 :
110 7 : RAII_STRING uint8_t *query = (uint8_t *)malloc(w.len);
111 7 : if (!query) { tl_writer_free(&w); return -1; }
112 7 : memcpy(query, w.data, w.len);
113 7 : size_t qlen = w.len;
114 7 : tl_writer_free(&w);
115 :
116 7 : RAII_STRING uint8_t *resp = (uint8_t *)malloc(RESP_BUF_SIZE);
117 7 : if (!resp) return -1;
118 7 : size_t resp_len = 0;
119 7 : if (api_call(cfg, s, t, query, qlen,
120 : resp, RESP_BUF_SIZE, &resp_len) != 0) {
121 0 : logger_log(LOG_ERROR, "auth_transfer_import: api_call failed");
122 0 : return -1;
123 : }
124 7 : if (resp_len < 4) return -1;
125 :
126 : uint32_t top;
127 7 : memcpy(&top, resp, 4);
128 7 : if (top == TL_rpc_error) {
129 2 : RpcError perr; rpc_parse_error(resp, resp_len, &perr);
130 2 : if (err) *err = perr;
131 2 : logger_log(LOG_ERROR, "auth_transfer_import: RPC %d: %s",
132 : perr.error_code, perr.error_msg);
133 2 : return -1;
134 : }
135 5 : if (top != CRC_auth_authorization
136 2 : && top != CRC_auth_authorizationSignUpRequired) {
137 0 : logger_log(LOG_ERROR,
138 : "auth_transfer_import: unexpected top 0x%08x", top);
139 0 : return -1;
140 : }
141 5 : logger_log(LOG_INFO, "auth_transfer_import: foreign DC now authorized");
142 5 : return 0;
143 : }
|