• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

taosdata / TDengine / #4935

22 Jan 2026 06:38AM UTC coverage: 66.708% (+0.02%) from 66.691%
#4935

push

travis-ci

web-flow
merge: from main to 3.0 #34371

121 of 271 new or added lines in 17 files covered. (44.65%)

9066 existing lines in 149 files now uncovered.

203884 of 305637 relevant lines covered (66.71%)

125811266.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

58.63
/source/dnode/mgmt/node_util/src/dmFile.c
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http:www.gnu.org/licenses/>.
14
 */
15

16
#define _DEFAULT_SOURCE
17
#include "crypt.h"
18
#include "dmUtil.h"
19
#include "tchecksum.h"
20
#include "tencrypt.h"
21
#include "tgrant.h"
22
#include "tjson.h"
23
#include "tglobal.h"
24

25
#if defined(TD_ENTERPRISE) && defined(TD_HAS_TAOSK)
26
#include "taoskInt.h"
27
#endif
28

29
#define MAXLEN               1024
30
#define DM_KEY_INDICATOR     "this indicator!"
31
#define DM_ENCRYPT_CODE_FILE "encryptCode.cfg"
32
#define DM_CHECK_CODE_FILE   "checkCode.bin"
33

34
static int32_t dmDecodeFile(SJson *pJson, bool *deployed, bool *encrypted) {
5,420✔
35
  int32_t code = 0;
5,420✔
36
  int32_t value = 0;
5,420✔
37

38
  tjsonGetInt32ValueFromDouble(pJson, "deployed", value, code);
5,420✔
39
  if (code < 0) return code;
5,420✔
40
  *deployed = (value != 0);
5,420✔
41

42
  // Read encrypted flag (optional, defaults to false for backward compatibility)
43
  if (encrypted != NULL) {
5,420✔
44
    int32_t encryptedValue = 0;
3,368✔
45
    tjsonGetInt32ValueFromDouble(pJson, "encrypted", encryptedValue, code);
3,368✔
46
    *encrypted = (encryptedValue != 0);
3,368✔
47
    // Reset code to 0 for backward compatibility if encrypted field not found
48
    code = 0;
3,368✔
49
  }
50

51
  return code;
5,420✔
52
}
53

54
int32_t dmReadFile(const char *path, const char *name, bool *pDeployed) {
1,090,392✔
55
  int32_t   code = -1;
1,090,392✔
56
  char     *content = NULL;
1,090,392✔
57
  int32_t   contentLen = 0;
1,090,392✔
58
  SJson    *pJson = NULL;
1,090,392✔
59
  char      file[PATH_MAX] = {0};
1,090,392✔
60
  int32_t   nBytes = snprintf(file, sizeof(file), "%s%s%s.json", path, TD_DIRSEP, name);
1,090,392✔
61
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
1,090,392✔
62
    code = TSDB_CODE_OUT_OF_BUFFER;
×
63
    goto _OVER;
×
64
  }
65

66
  if (taosStatFile(file, NULL, NULL, NULL) < 0) {
1,090,392✔
67
    dInfo("file:%s not exist", file);
1,088,340✔
68
    code = 0;
1,088,340✔
69
    goto _OVER;
1,088,340✔
70
  }
71

72
  // Use taosReadCfgFile for automatic decryption support (returns null-terminated string)
73
  code = taosReadCfgFile(file, &content, &contentLen);
2,052✔
74
  if (code != 0) {
2,052✔
75
    dError("failed to read file:%s since %s", file, tstrerror(code));
×
76
    goto _OVER;
×
77
  }
78

79
  pJson = tjsonParse(content);
2,052✔
80
  if (pJson == NULL) {
2,052✔
81
    code = TSDB_CODE_INVALID_JSON_FORMAT;
×
82
    goto _OVER;
×
83
  }
84

85
  if (dmDecodeFile(pJson, pDeployed, NULL) < 0) {
2,052✔
86
    code = TSDB_CODE_INVALID_JSON_FORMAT;
×
87
    goto _OVER;
×
88
  }
89

90
  code = 0;
2,052✔
91
  dInfo("succceed to read mnode file %s", file);
2,052✔
92

93
_OVER:
1,087,478✔
94
  if (content != NULL) taosMemoryFree(content);
1,090,392✔
95
  if (pJson != NULL) cJSON_Delete(pJson);
1,090,392✔
96

97
  if (code != 0) {
1,090,392✔
98
    dError("failed to read dnode file:%s since %s", file, tstrerror(code));
×
99
  }
100
  return code;
1,090,392✔
101
}
102

103
int32_t dmReadFileJsonWithEncrypted(const char *path, const char *name, SJson **ppJson, bool *deployed,
545,196✔
104
                                    bool *encrypted) {
105
  int32_t   code = -1;
545,196✔
106
  char     *content = NULL;
545,196✔
107
  int32_t   contentLen = 0;
545,196✔
108
  char      file[PATH_MAX] = {0};
545,196✔
109
  int32_t   nBytes = snprintf(file, sizeof(file), "%s%s%s.json", path, TD_DIRSEP, name);
545,196✔
110
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
545,196✔
111
    code = TSDB_CODE_OUT_OF_BUFFER;
×
112
    goto _OVER;
×
113
  }
114

115
  if (taosStatFile(file, NULL, NULL, NULL) < 0) {
545,196✔
116
    dInfo("file:%s not exist", file);
541,828✔
117
    code = 0;
541,828✔
118
    goto _OVER;
541,828✔
119
  }
120

121
  // Use taosReadCfgFile for automatic decryption support (returns null-terminated string)
122
  code = taosReadCfgFile(file, &content, &contentLen);
3,368✔
123
  if (code != 0) {
3,368✔
124
    dError("failed to read file:%s since %s", file, tstrerror(code));
×
125
    goto _OVER;
×
126
  }
127

128
  *ppJson = tjsonParse(content);
3,368✔
129
  if (*ppJson == NULL) {
3,368✔
130
    code = TSDB_CODE_INVALID_JSON_FORMAT;
×
131
    goto _OVER;
×
132
  }
133

134
  if (dmDecodeFile(*ppJson, deployed, encrypted) < 0) {
3,368✔
135
    code = TSDB_CODE_INVALID_JSON_FORMAT;
×
136
    goto _OVER;
×
137
  }
138

139
  code = 0;
3,368✔
140
  dInfo("succeed to read file:%s, deployed:%d, encrypted:%d", file, *deployed, encrypted ? *encrypted : 0);
3,368✔
141

142
_OVER:
543,739✔
143
  if (content != NULL) taosMemoryFree(content);
545,196✔
144

145
  if (code != 0) {
545,196✔
146
    if (*ppJson != NULL) cJSON_Delete(*ppJson);
×
147
    dError("failed to read dnode file:%s since %s", file, tstrerror(code));
×
148
  }
149
  return code;
545,196✔
150
}
151

152
int32_t dmReadFileJson(const char *path, const char *name, SJson **ppJson, bool *deployed) {
545,196✔
153
  bool encrypted = false;
545,196✔
154
  return dmReadFileJsonWithEncrypted(path, name, ppJson, deployed, &encrypted);
545,196✔
155
}
156

157
static int32_t dmEncodeFile(SJson *pJson, bool deployed, bool encrypted) {
56,477✔
158
  if (tjsonAddDoubleToObject(pJson, "deployed", deployed) < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
56,477✔
159
  if (tjsonAddDoubleToObject(pJson, "encrypted", encrypted ? 1 : 0) < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
56,477✔
160
  return 0;
56,477✔
161
}
162

163
int32_t dmWriteFileWithEncrypted(const char *path, const char *name, bool deployed, bool encrypted) {
56,477✔
164
  int32_t   code = -1;
56,477✔
165
  char     *buffer = NULL;
56,477✔
166
  SJson    *pJson = NULL;
56,477✔
167
  char      realfile[PATH_MAX] = {0};
56,477✔
168

169
  int32_t nBytes = snprintf(realfile, sizeof(realfile), "%s%s%s.json", path, TD_DIRSEP, name);
56,477✔
170
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
56,477✔
171
    code = TSDB_CODE_OUT_OF_BUFFER;
×
172
    goto _OVER;
×
173
  }
174

175
  pJson = tjsonCreateObject();
56,477✔
176
  if (pJson == NULL) {
56,477✔
177
    code = terrno;
×
178
    goto _OVER;
×
179
  }
180

181
  if ((code = dmEncodeFile(pJson, deployed, encrypted)) != 0) goto _OVER;
56,477✔
182

183
  buffer = tjsonToString(pJson);
56,477✔
184
  if (buffer == NULL) {
56,477✔
185
    code = TSDB_CODE_INVALID_JSON_FORMAT;
×
186
    goto _OVER;
×
187
  }
188

189
  int32_t len = strlen(buffer);
56,477✔
190
  
191
  // Use encrypted write if tsCfgKey is enabled
192
  code = taosWriteCfgFile(realfile, buffer, len);
56,477✔
193
  if (code != 0) {
56,477✔
194
    goto _OVER;
×
195
  }
196

197
  dInfo("succeed to write file:%s, deployed:%d, encrypted:%d", realfile, deployed, encrypted);
56,477✔
198

199
_OVER:
56,477✔
200

201
  if (pJson != NULL) tjsonDelete(pJson);
56,477✔
202
  if (buffer != NULL) taosMemoryFree(buffer);
56,477✔
203

204
  if (code != 0) {
56,477✔
NEW
205
    dError("failed to write file:%s since %s, deployed:%d, encrypted:%d", realfile, tstrerror(code), deployed,
×
206
           encrypted);
207
  }
208
  return code;
56,477✔
209
}
210

211
int32_t dmWriteFile(const char *path, const char *name, bool deployed) {
56,477✔
212
  return dmWriteFileWithEncrypted(path, name, deployed, false);
56,477✔
213
}
214

215
int32_t dmWriteFileJson(const char *path, const char *name, SJson *pJson) {
144,901✔
216
  int32_t   code = -1;
144,901✔
217
  char     *buffer = NULL;
144,901✔
218
  char      realfile[PATH_MAX] = {0};
144,901✔
219

220
  int32_t nBytes = snprintf(realfile, sizeof(realfile), "%s%s%s.json", path, TD_DIRSEP, name);
144,901✔
221
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
144,901✔
222
    code = TSDB_CODE_OUT_OF_BUFFER;
×
223
    goto _OVER;
×
224
  }
225

226
  buffer = tjsonToString(pJson);
144,901✔
227
  if (buffer == NULL) {
144,901✔
228
    code = TSDB_CODE_INVALID_JSON_FORMAT;
×
229
    goto _OVER;
×
230
  }
231

232
  int32_t len = strlen(buffer);
144,901✔
233
  
234
  // Use encrypted write if tsCfgKey is enabled
235
  code = taosWriteCfgFile(realfile, buffer, len);
144,901✔
236
  if (code != 0) {
144,901✔
237
    goto _OVER;
×
238
  }
239

240
  dInfo("succeed to write file:%s", realfile);
144,901✔
241

242
_OVER:
144,847✔
243

244
  if (pJson != NULL) tjsonDelete(pJson);
144,901✔
245
  if (buffer != NULL) taosMemoryFree(buffer);
144,901✔
246

247
  if (code != 0) {
144,901✔
248
    dError("failed to write file:%s since %s", realfile, tstrerror(code));
×
249
  }
250
  return code;
144,901✔
251
}
252

253

254
int32_t dmCheckRunning(const char *dataDir, TdFilePtr *pFile) {
545,196✔
255
  int32_t code = 0;
545,196✔
256
  char    filepath[PATH_MAX] = {0};
545,196✔
257
  snprintf(filepath, sizeof(filepath), "%s%s.running", dataDir, TD_DIRSEP);
545,196✔
258

259
  *pFile = taosOpenFile(filepath, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC | TD_FILE_CLOEXEC);
545,196✔
260
  if (*pFile == NULL) {
545,196✔
261
    code = terrno;
×
262
    dError("failed to open file:%s since %s", filepath, tstrerror(code));
×
263
    return code;
×
264
  }
265

266
  int32_t retryTimes = 0;
545,196✔
267
  int32_t ret = 0;
545,196✔
268
  do {
269
    ret = taosLockFile(*pFile);
547,948✔
270
    if (ret == 0) break;
547,948✔
271

272
    code = terrno;
2,871✔
273
    taosMsleep(1000);
2,871✔
274
    retryTimes++;
2,871✔
275
    dError("failed to lock file:%s since %s, retryTimes:%d", filepath, tstrerror(code), retryTimes);
2,871✔
276
  } while (retryTimes < 12);
2,871✔
277

278
  if (ret < 0) {
545,196✔
279
    code = TAOS_SYSTEM_ERROR(ERRNO);
119✔
280
    (void)taosCloseFile(pFile);
119✔
281
    *pFile = NULL;
119✔
282
    return code;
119✔
283
  }
284

285
  dDebug("lock file:%s to prevent repeated starts", filepath);
545,077✔
286
  return code;
545,077✔
287
}
288

289
extern int32_t generateEncryptCode(const char *key, const char *machineId, char **encryptCode);
290

291
static int32_t dmWriteCheckCodeFile(char *file, char *realfile, char *key, bool toLogFile) {
153✔
292
  TdFilePtr pFile = NULL;
153✔
293
  char     *result = NULL;
153✔
294
  int32_t   code = -1;
153✔
295

296
  int32_t len = ENCRYPTED_LEN(sizeof(DM_KEY_INDICATOR));
153✔
297
  result = taosMemoryMalloc(len);
153✔
298
  if (result == NULL) {
153✔
299
    return terrno;
×
300
  }
301

302
  SCryptOpts opts = {0};
153✔
303
  tstrncpy(opts.key, key, ENCRYPT_KEY_LEN + 1);
153✔
304
  opts.len = len;
153✔
305
  opts.source = DM_KEY_INDICATOR;
153✔
306
  opts.result = result;
153✔
307
  opts.unitLen = 16;
153✔
308
  if (Builtin_CBC_Encrypt(&opts) <= 0) {
153✔
309
    code = terrno;
×
310
    encryptError("failed to encrypt checkCode, since %s", tstrerror(code));
×
311
    goto _OVER;
×
312
  }
313

314
  pFile = taosOpenFile(file, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC | TD_FILE_WRITE_THROUGH);
153✔
315
  if (pFile == NULL) {
153✔
316
    code = terrno;
×
317
    goto _OVER;
×
318
  }
319

320
  if (taosWriteFile(pFile, opts.result, len) <= 0) {
153✔
321
    code = terrno;
×
322
    goto _OVER;
×
323
  }
324

325
  if (taosFsyncFile(pFile) < 0) {
153✔
326
    code = TAOS_SYSTEM_ERROR(ERRNO);
×
327
    goto _OVER;
×
328
  }
329

330
  if (taosCloseFile(&pFile) != 0) {
153✔
331
    code = TAOS_SYSTEM_ERROR(ERRNO);
×
332
    goto _OVER;
×
333
  }
334

335
  TAOS_CHECK_GOTO(taosRenameFile(file, realfile), NULL, _OVER);
153✔
336

337
  encryptDebug("succeed to write checkCode file:%s", realfile);
153✔
338

339
  code = 0;
153✔
340
_OVER:
153✔
341
  if (pFile != NULL) taosCloseFile(&pFile);
153✔
342
  if (result != NULL) taosMemoryFree(result);
153✔
343

344
  return code;
153✔
345
}
346

347
static int32_t dmWriteEncryptCodeFile(char *file, char *realfile, char *encryptCode, bool toLogFile) {
153✔
348
  TdFilePtr pFile = NULL;
153✔
349
  int32_t   code = -1;
153✔
350

351
  pFile = taosOpenFile(file, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC | TD_FILE_WRITE_THROUGH);
153✔
352
  if (pFile == NULL) {
153✔
353
    code = terrno;
×
354
    goto _OVER;
×
355
  }
356

357
  int32_t len = strlen(encryptCode);
153✔
358
  if (taosWriteFile(pFile, encryptCode, len) <= 0) {
153✔
359
    code = terrno;
×
360
    goto _OVER;
×
361
  }
362
  if (taosFsyncFile(pFile) < 0) {
153✔
363
    code = terrno;
×
364
    goto _OVER;
×
365
  }
366

367
  if (taosCloseFile(&pFile) != 0) {
153✔
368
    code = TAOS_SYSTEM_ERROR(ERRNO);
×
369
    goto _OVER;
×
370
  }
371

372
  TAOS_CHECK_GOTO(taosRenameFile(file, realfile), NULL, _OVER);
153✔
373

374
  encryptDebug("succeed to write encryptCode file:%s", realfile);
153✔
375

376
  code = 0;
153✔
377
_OVER:
153✔
378
  if (pFile != NULL) taosCloseFile(&pFile);
153✔
379

380
  return code;
153✔
381
}
382

383
static int32_t dmCompareEncryptKey(char *file, char *key, bool toLogFile) {
×
384
  char     *content = NULL;
×
385
  int64_t   size = 0;
×
386
  TdFilePtr pFile = NULL;
×
387
  char     *result = NULL;
×
388
  int32_t   code = -1;
×
389

390
  pFile = taosOpenFile(file, TD_FILE_READ);
×
391
  if (pFile == NULL) {
×
392
    code = terrno;
×
393
    encryptError("failed to open dnode file:%s since %s", file, tstrerror(code));
×
394
    goto _OVER;
×
395
  }
396

397
  code = taosFStatFile(pFile, &size, NULL);
×
398
  if (code != 0) {
×
399
    encryptError("failed to fstat dnode file:%s since %s", file, tstrerror(code));
×
400
    goto _OVER;
×
401
  }
402

403
  content = taosMemoryMalloc(size);
×
404
  if (content == NULL) {
×
405
    code = terrno;
×
406
    goto _OVER;
×
407
  }
408

409
  if (taosReadFile(pFile, content, size) != size) {
×
410
    code = terrno;
×
411
    encryptError("failed to read dnode file:%s since %s", file, tstrerror(code));
×
412
    goto _OVER;
×
413
  }
414

415
  encryptDebug("succeed to read checkCode file:%s", file);
×
416

417
  int len = ENCRYPTED_LEN(size);
×
418
  result = taosMemoryMalloc(len);
×
419
  if (result == NULL) {
×
420
    code = terrno;
×
421
    encryptError("failed to alloc memory file:%s since %s", file, tstrerror(code));
×
422
    goto _OVER;
×
423
  }
424

425
  SCryptOpts opts = {0};
×
426
  tstrncpy(opts.key, key, ENCRYPT_KEY_LEN + 1);
×
427
  opts.len = len;
×
428
  opts.source = content;
×
429
  opts.result = result;
×
430
  opts.unitLen = 16;
×
431
  if (Builtin_CBC_Decrypt(&opts) <= 0) {
×
432
    code = terrno;
×
433
    encryptError("failed to decrypt checkCode since %s", tstrerror(code));
×
434
    goto _OVER;
×
435
  }
436

437
  if (strcmp(opts.result, DM_KEY_INDICATOR) != 0) {
×
438
    code = TSDB_CODE_DNODE_ENCRYPTKEY_CHANGED;
×
439
    encryptError("failed to compare decrypted result");
×
440
    goto _OVER;
×
441
  }
442

443
  encryptDebug("succeed to compare checkCode file:%s", file);
×
444
  code = 0;
×
445
_OVER:
×
446
  if (result != NULL) taosMemoryFree(result);
×
447
  if (content != NULL) taosMemoryFree(content);
×
448
  if (pFile != NULL) taosCloseFile(&pFile);
×
449

450
  return code;
×
451
}
452

453
int32_t dmUpdateEncryptKey(char *key, bool toLogFile) {
153✔
454
#if defined(TD_ENTERPRISE) || defined(TD_ASTRA_TODO)
455
  int32_t code = -1;
153✔
456
  int32_t lino = 0;
153✔
457
  char   *machineId = NULL;
153✔
458
  char   *encryptCode = NULL;
153✔
459

460
  char folder[PATH_MAX] = {0};
153✔
461

462
  char encryptFile[PATH_MAX] = {0};
153✔
463
  char realEncryptFile[PATH_MAX] = {0};
153✔
464

465
  char checkFile[PATH_MAX] = {0};
153✔
466
  char realCheckFile[PATH_MAX] = {0};
153✔
467

468
  int32_t nBytes = snprintf(folder, sizeof(folder), "%s%sdnode", tsDataDir, TD_DIRSEP);
153✔
469
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
153✔
470
    return TSDB_CODE_OUT_OF_BUFFER;
×
471
  }
472

473
  nBytes = snprintf(encryptFile, sizeof(realEncryptFile), "%s%s%s.bak", folder, TD_DIRSEP, DM_ENCRYPT_CODE_FILE);
153✔
474
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
153✔
475
    return TSDB_CODE_OUT_OF_BUFFER;
×
476
  }
477

478
  nBytes = snprintf(realEncryptFile, sizeof(realEncryptFile), "%s%s%s", folder, TD_DIRSEP, DM_ENCRYPT_CODE_FILE);
153✔
479
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
153✔
480
    return TSDB_CODE_OUT_OF_BUFFER;
×
481
  }
482

483
  nBytes = snprintf(checkFile, sizeof(checkFile), "%s%s%s.bak", folder, TD_DIRSEP, DM_CHECK_CODE_FILE);
153✔
484
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
153✔
485
    return TSDB_CODE_OUT_OF_BUFFER;
×
486
  }
487

488
  snprintf(realCheckFile, sizeof(realCheckFile), "%s%s%s", folder, TD_DIRSEP, DM_CHECK_CODE_FILE);
153✔
489
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
153✔
490
    return TSDB_CODE_OUT_OF_BUFFER;
×
491
  }
492

493
  if (taosMkDir(folder) != 0) {
153✔
494
    code = terrno;
×
495
    encryptError("failed to create dir:%s since %s", folder, tstrerror(code));
×
496
    goto _OVER;
×
497
  }
498

499
  if (taosCheckExistFile(realCheckFile)) {
153✔
500
    if ((code = dmCompareEncryptKey(realCheckFile, key, toLogFile)) != 0) {
×
501
      goto _OVER;
×
502
    }
503
  }
504

505
  TAOS_CHECK_GOTO(tGetMachineId(&machineId), &lino, _OVER);
153✔
506

507
  TAOS_CHECK_GOTO(generateEncryptCode(key, machineId, &encryptCode), &lino, _OVER);
153✔
508

509
  if ((code = dmWriteEncryptCodeFile(encryptFile, realEncryptFile, encryptCode, toLogFile)) != 0) {
153✔
510
    goto _OVER;
×
511
  }
512

513
  if ((code = dmWriteCheckCodeFile(checkFile, realCheckFile, key, toLogFile)) != 0) {
153✔
514
    goto _OVER;
×
515
  }
516

517
  encryptInfo("Succeed to update encrypt key\n");
153✔
518

519
  code = 0;
153✔
520
_OVER:
153✔
521
  taosMemoryFree(encryptCode);
153✔
522
  taosMemoryFree(machineId);
153✔
523
  if (code != 0) {
153✔
524
    encryptError("failed to update encrypt key at line %d since %s", lino, tstrerror(code));
×
525
  }
526
  TAOS_RETURN(code);
153✔
527
#else
528
  return 0;
529
#endif
530
}
531

532
extern int32_t checkAndGetCryptKey(const char *encryptCode, const char *machineId, char **key);
533

534
extern int32_t dmGetEncryptKeyFromTaosk();
535

536
extern int32_t taoskLoadEncryptKeys(const char *masterKeyFile, const char *derivedKeyFile, char *svrKey, char *dbKey,
537
                                    char *cfgKey, char *metaKey, char *dataKey, int32_t *algorithm, int32_t *cfgAlgorithm,
538
                                    int32_t *metaAlgorithm, int32_t *fileVersion, int32_t *keyVersion, int64_t *createTime,
539
                                    int64_t *svrKeyUpdateTime, int64_t *dbKeyUpdateTime);
540

541
static int32_t dmReadEncryptCodeFile(char *file, char **output) {
×
542
  TdFilePtr pFile = NULL;
×
543
  int32_t   code = -1;
×
544
  char     *content = NULL;
×
545

546
  pFile = taosOpenFile(file, TD_FILE_READ);
×
547
  if (pFile == NULL) {
×
548
    code = terrno;
×
549
    dError("failed to open dnode file:%s since %s", file, tstrerror(code));
×
550
    goto _OVER;
×
551
  }
552

553
  int64_t size = 0;
×
554
  code = taosFStatFile(pFile, &size, NULL);
×
555
  if (code != 0) {
×
556
    dError("failed to fstat dnode file:%s since %s", file, tstrerror(code));
×
557
    goto _OVER;
×
558
  }
559

560
  content = taosMemoryMalloc(size + 1);
×
561
  if (content == NULL) {
×
562
    code = terrno;
×
563
    goto _OVER;
×
564
  }
565

566
  if (taosReadFile(pFile, content, size) != size) {
×
567
    code = terrno;
×
568
    dError("failed to read dnode file:%s since %s", file, tstrerror(code));
×
569
    goto _OVER;
×
570
  }
571

572
  content[size] = '\0';
×
573

574
  *output = content;
×
575
  content = NULL;
×
576

577
  dInfo("succeed to read encryptCode file:%s", file);
×
578
  code = 0;
×
579
_OVER:
×
580
  if (pFile != NULL) taosCloseFile(&pFile);
×
581
  taosMemoryFree(content);
×
582

583
  return code;
×
584
}
585

586
int32_t dmGetEncryptKeyFromTaosk() {
555,041✔
587
#if (defined(TD_ENTERPRISE) && defined(TD_HAS_TAOSK)) || defined(TD_ASTRA_TODO)
588
  char keyFileDir[PATH_MAX] = {0};
555,041✔
589
  char masterKeyFile[PATH_MAX] = {0};
555,041✔
590
  char derivedKeyFile[PATH_MAX] = {0};
555,041✔
591

592
  // Build path to key file directory: tsDataDir/dnode/config/
593
  int32_t nBytes = snprintf(keyFileDir, sizeof(keyFileDir), "%s%sdnode%sconfig", tsDataDir, TD_DIRSEP, TD_DIRSEP);
555,041✔
594
  if (nBytes <= 0 || nBytes >= sizeof(keyFileDir)) {
555,041✔
595
    return TSDB_CODE_OUT_OF_BUFFER;
×
596
  }
597

598
  // Build path to master.bin
599
  nBytes = snprintf(masterKeyFile, sizeof(masterKeyFile), "%s%smaster.bin", keyFileDir, TD_DIRSEP);
555,041✔
600
  if (nBytes <= 0 || nBytes >= sizeof(masterKeyFile)) {
555,041✔
601
    return TSDB_CODE_OUT_OF_BUFFER;
×
602
  }
603

604
  // Build path to derived.bin
605
  nBytes = snprintf(derivedKeyFile, sizeof(derivedKeyFile), "%s%sderived.bin", keyFileDir, TD_DIRSEP);
555,041✔
606
  if (nBytes <= 0 || nBytes >= sizeof(derivedKeyFile)) {
555,041✔
607
    return TSDB_CODE_OUT_OF_BUFFER;
×
608
  }
609

610
  // Check if master.bin exists
611
  if (!taosCheckExistFile(masterKeyFile)) {
555,041✔
612
    dInfo("taosk master key file not found: %s, encryption not configured", masterKeyFile);
554,261✔
613
    return TSDB_CODE_DNODE_INVALID_ENCRYPT_CONFIG;
554,261✔
614
  }
615

616
  dInfo("loading encryption keys from taosk split files: %s, %s", masterKeyFile, derivedKeyFile);
780✔
617

618
  // Prepare variables for decrypted keys
619
  int32_t algorithm = 0;
780✔
620
  int32_t fileVersion = 0;
780✔
621
  int32_t keyVersion = 0;
780✔
622
  int64_t createTime = 0;
780✔
623
  int64_t svrKeyUpdateTime = 0;
780✔
624
  int64_t dbKeyUpdateTime = 0;
780✔
625
  int32_t cfgAlgorithm = 0;
780✔
626
  int32_t metaAlgorithm = 0;
780✔
627

628
  // Call enterprise function to decrypt and load multi-layer keys from split files
629
  int32_t code = taoskLoadEncryptKeys(masterKeyFile, derivedKeyFile,
780✔
630
                                      tsSvrKey,           // output: SVR_KEY (server master key)
631
                                      tsDbKey,            // output: DB_KEY (database master key)
632
                                      tsCfgKey,           // output: CFG_KEY (config encryption key)
633
                                      tsMetaKey,          // output: META_KEY (metadata encryption key)
634
                                      tsDataKey,          // output: DATA_KEY (data encryption key)
635
                                      &algorithm,         // output: encryption algorithm type for master keys
636
                                      &cfgAlgorithm,      // output: encryption algorithm type for CFG_KEY
637
                                      &metaAlgorithm,     // output: encryption algorithm type for META_KEY
638
                                      &fileVersion,       // output: file format version
639
                                      &keyVersion,        // output: key update version
640
                                      &createTime,        // output: key creation timestamp
641
                                      &svrKeyUpdateTime,  // output: SVR_KEY update timestamp
642
                                      &dbKeyUpdateTime    // output: DB_KEY update timestamp
643
  );
644

645
  if (code != 0) {
780✔
646
    dError("failed to load encryption keys from taosk since %s", tstrerror(code));
×
647
    TAOS_RETURN(code);
×
648
  }
649

650
  // Store decrypted keys in global variables
651
  tsUseTaoskEncryption = true;
780✔
652

653
  // Store metadata
654
  tsEncryptAlgorithmType = algorithm;
780✔
655
  tsCfgAlgorithm = cfgAlgorithm;
780✔
656
  tsMetaAlgorithm = metaAlgorithm;
780✔
657
  tsEncryptFileVersion = fileVersion;   // file format version for compatibility
780✔
658
  tsEncryptKeyVersion = keyVersion;     // key update version
780✔
659
  tsEncryptKeyCreateTime = createTime;
780✔
660
  tsSvrKeyUpdateTime = svrKeyUpdateTime;
780✔
661
  tsDbKeyUpdateTime = dbKeyUpdateTime;
780✔
662

663
  // For backward compatibility: copy DATA_KEY to tsEncryptKey (truncated to 16 bytes)
664
  int keyLen = strlen(tsDataKey);
780✔
665
  if (keyLen > ENCRYPT_KEY_LEN) {
780✔
666
    keyLen = ENCRYPT_KEY_LEN;
×
667
  }
668
  memset(tsEncryptKey, 0, ENCRYPT_KEY_LEN + 1);
780✔
669
  memcpy(tsEncryptKey, tsDataKey, keyLen);
780✔
670
  tsEncryptKey[ENCRYPT_KEY_LEN] = '\0';
780✔
671

672
  // Update encryption key status
673
  tsEncryptionKeyChksum = taosCalcChecksum(0, (const uint8_t *)tsEncryptKey, strlen(tsEncryptKey));
780✔
674
  tsEncryptionKeyStat = ENCRYPT_KEY_STAT_LOADED;
780✔
675

676
  dInfo("successfully loaded taosk encryption keys (algorithm:%d, cfg:%s, meta:%s, data:%s)", algorithm,
780✔
677
        (tsCfgKey[0] != '\0') ? "enabled" : "disabled", 
678
        (tsMetaKey[0] != '\0') ? "enabled" : "disabled", 
679
        (tsDataKey[0] != '\0') ? "enabled" : "disabled");
680

681
  TAOS_RETURN(0);
780✔
682
#else
683
  return 0;
684
#endif
685
}
686

687
int32_t dmGetEncryptKey() {
555,041✔
688
#if defined(TD_ENTERPRISE) || defined(TD_ASTRA_TODO)
689
  int32_t code = -1;
555,041✔
690
  char    encryptFile[PATH_MAX] = {0};
555,041✔
691
  char    checkFile[PATH_MAX] = {0};
555,041✔
692
  char   *machineId = NULL;
555,041✔
693
  char   *encryptKey = NULL;
555,041✔
694
  char   *content = NULL;
555,041✔
695

696
  // First try to load from taosk key files (master.bin and derived.bin)
697
  code = dmGetEncryptKeyFromTaosk();
555,041✔
698
  if (code == 0) {
555,041✔
699
    tsEncryptKeysStatus = TSDB_ENCRYPT_KEY_STAT_LOADED;
780✔
700
    dInfo("encryption keys loaded from taosk key files");
780✔
701
    return 0;
780✔
702
  }
703

704
  tsEncryptKeysStatus = TSDB_ENCRYPT_KEY_STAT_NOT_EXIST;
554,261✔
705

706
  // Fallback to legacy encryptCode.cfg format (pre-taosk)
707
  dInfo("falling back to legacy encryptCode.cfg format");
554,261✔
708

709
  int32_t nBytes = snprintf(encryptFile, sizeof(encryptFile), "%s%sdnode%s%s", tsDataDir, TD_DIRSEP, TD_DIRSEP,
554,261✔
710
                            DM_ENCRYPT_CODE_FILE);
711
  if (nBytes <= 0 || nBytes >= sizeof(encryptFile)) {
554,261✔
712
    code = TSDB_CODE_OUT_OF_BUFFER;
×
713
    return code;
×
714
  }
715

716
  nBytes = snprintf(checkFile, sizeof(checkFile), "%s%sdnode%s%s", tsDataDir, TD_DIRSEP, TD_DIRSEP, DM_CHECK_CODE_FILE);
554,261✔
717
  if (nBytes <= 0 || nBytes >= sizeof(checkFile)) {
554,261✔
718
    code = TSDB_CODE_OUT_OF_BUFFER;
×
719
    return code;
×
720
  }
721

722
  if (!taosCheckExistFile(encryptFile)) {
554,261✔
723
    code = TSDB_CODE_DNODE_INVALID_ENCRYPT_CONFIG;
554,261✔
724
    dInfo("no exist, checkCode file:%s", encryptFile);
554,261✔
725
    return 0;
554,261✔
726
  }
727

728
  if ((code = dmReadEncryptCodeFile(encryptFile, &content)) != 0) {
×
729
    goto _OVER;
×
730
  }
731

732
  if ((code = tGetMachineId(&machineId)) != 0) {
×
733
    goto _OVER;
×
734
  }
735

736
  if ((code = checkAndGetCryptKey(content, machineId, &encryptKey)) != 0) {
×
737
    goto _OVER;
×
738
  }
739

740
  taosMemoryFreeClear(machineId);
×
741
  taosMemoryFreeClear(content);
×
742

743
  if (encryptKey[0] == '\0') {
×
744
    code = TSDB_CODE_DNODE_INVALID_ENCRYPTKEY;
×
745
    dError("failed to read key since %s", tstrerror(code));
×
746
    goto _OVER;
×
747
  }
748

749
  if ((code = dmCompareEncryptKey(checkFile, encryptKey, true)) != 0) {
×
750
    goto _OVER;
×
751
  }
752

753
  tstrncpy(tsEncryptKey, encryptKey, ENCRYPT_KEY_LEN + 1);
×
754
  taosMemoryFreeClear(encryptKey);
×
755
  tsEncryptionKeyChksum = taosCalcChecksum(0, tsEncryptKey, strlen(tsEncryptKey));
×
756
  tsEncryptionKeyStat = ENCRYPT_KEY_STAT_LOADED;
×
757

758
  code = 0;
×
759
_OVER:
×
760
  if (content != NULL) taosMemoryFree(content);
×
761
  if (encryptKey != NULL) taosMemoryFree(encryptKey);
×
762
  if (machineId != NULL) taosMemoryFree(machineId);
×
763
  if (code != 0) {
×
764
    dError("failed to get encrypt key since %s", tstrerror(code));
×
765
  }
766
  TAOS_RETURN(code);
×
767
#else
768
  return 0;
769
#endif
770
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc