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

taosdata / TDengine / #4898

26 Dec 2025 09:58AM UTC coverage: 65.061% (-0.7%) from 65.717%
#4898

push

travis-ci

web-flow
feat: support encryption of configuration files, data files and metadata files (#33801)

350 of 1333 new or added lines in 31 files covered. (26.26%)

2796 existing lines in 159 files now uncovered.

184024 of 282850 relevant lines covered (65.06%)

113940470.33 hits per line

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

50.34
/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) {
5,241✔
35
  int32_t code = 0;
5,241✔
36
  int32_t value = 0;
5,241✔
37

38
  tjsonGetInt32ValueFromDouble(pJson, "deployed", value, code);
5,241✔
39
  if (code < 0) return code;
5,241✔
40

41
  *deployed = (value != 0);
5,241✔
42
  return code;
5,241✔
43
}
44

45
int32_t dmReadFile(const char *path, const char *name, bool *pDeployed) {
1,157,732✔
46
  int32_t   code = -1;
1,157,732✔
47
  char     *content = NULL;
1,157,732✔
48
  int32_t   contentLen = 0;
1,157,732✔
49
  SJson    *pJson = NULL;
1,157,732✔
50
  char      file[PATH_MAX] = {0};
1,157,732✔
51
  int32_t   nBytes = snprintf(file, sizeof(file), "%s%s%s.json", path, TD_DIRSEP, name);
1,157,732✔
52
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
1,157,732✔
53
    code = TSDB_CODE_OUT_OF_BUFFER;
×
54
    goto _OVER;
×
55
  }
56

57
  if (taosStatFile(file, NULL, NULL, NULL) < 0) {
1,157,732✔
58
    dInfo("file:%s not exist", file);
1,155,541✔
59
    code = 0;
1,155,541✔
60
    goto _OVER;
1,155,541✔
61
  }
62

63
  // Use taosReadCfgFile for automatic decryption support (returns null-terminated string)
64
  code = taosReadCfgFile(file, &content, &contentLen);
2,191✔
65
  if (code != 0) {
2,191✔
66
    dError("failed to read file:%s since %s", file, tstrerror(code));
×
67
    goto _OVER;
×
68
  }
69

70
  pJson = tjsonParse(content);
2,191✔
71
  if (pJson == NULL) {
2,191✔
72
    code = TSDB_CODE_INVALID_JSON_FORMAT;
×
73
    goto _OVER;
×
74
  }
75

76
  if (dmDecodeFile(pJson, pDeployed) < 0) {
2,191✔
77
    code = TSDB_CODE_INVALID_JSON_FORMAT;
×
78
    goto _OVER;
×
79
  }
80

81
  code = 0;
2,191✔
82
  dInfo("succceed to read mnode file %s", file);
2,191✔
83

84
_OVER:
1,157,142✔
85
  if (content != NULL) taosMemoryFree(content);
1,157,732✔
86
  if (pJson != NULL) cJSON_Delete(pJson);
1,157,732✔
87

88
  if (code != 0) {
1,157,732✔
89
    dError("failed to read dnode file:%s since %s", file, tstrerror(code));
×
90
  }
91
  return code;
1,157,732✔
92
}
93

94
int32_t dmReadFileJson(const char *path, const char *name, SJson **ppJson, bool* deployed) {
578,866✔
95
  int32_t   code = -1;
578,866✔
96
  char     *content = NULL;
578,866✔
97
  int32_t   contentLen = 0;
578,866✔
98
  char      file[PATH_MAX] = {0};
578,866✔
99
  int32_t   nBytes = snprintf(file, sizeof(file), "%s%s%s.json", path, TD_DIRSEP, name);
578,866✔
100
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
578,866✔
101
    code = TSDB_CODE_OUT_OF_BUFFER;
×
102
    goto _OVER;
×
103
  }
104

105
  if (taosStatFile(file, NULL, NULL, NULL) < 0) {
578,866✔
106
    dInfo("file:%s not exist", file);
575,816✔
107
    code = 0;
575,816✔
108
    goto _OVER;
575,816✔
109
  }
110

111
  // Use taosReadCfgFile for automatic decryption support (returns null-terminated string)
112
  code = taosReadCfgFile(file, &content, &contentLen);
3,050✔
113
  if (code != 0) {
3,050✔
114
    dError("failed to read file:%s since %s", file, tstrerror(code));
×
115
    goto _OVER;
×
116
  }
117

118
  *ppJson = tjsonParse(content);
3,050✔
119
  if (*ppJson == NULL) {
3,050✔
120
    code = TSDB_CODE_INVALID_JSON_FORMAT;
×
121
    goto _OVER;
×
122
  }
123

124
  if (dmDecodeFile(*ppJson, deployed) < 0) {
3,050✔
125
    code = TSDB_CODE_INVALID_JSON_FORMAT;
×
126
    goto _OVER;
×
127
  }
128

129
  code = 0;
3,050✔
130
  dInfo("succceed to read mnode file %s", file);
3,050✔
131

132
_OVER:
578,571✔
133
  if (content != NULL) taosMemoryFree(content);
578,866✔
134

135
  if (code != 0) {
578,866✔
136
    if (*ppJson != NULL) cJSON_Delete(*ppJson);
×
137
    dError("failed to read dnode file:%s since %s", file, tstrerror(code));
×
138
  }
139
  return code;
578,866✔
140
}
141

142

143
static int32_t dmEncodeFile(SJson *pJson, bool deployed) {
64,635✔
144
  if (tjsonAddDoubleToObject(pJson, "deployed", deployed) < 0) return TSDB_CODE_INVALID_JSON_FORMAT;
64,635✔
145
  return 0;
64,635✔
146
}
147

148
int32_t dmWriteFile(const char *path, const char *name, bool deployed) {
64,635✔
149
  int32_t   code = -1;
64,635✔
150
  char     *buffer = NULL;
64,635✔
151
  SJson    *pJson = NULL;
64,635✔
152
  char      realfile[PATH_MAX] = {0};
64,635✔
153

154
  int32_t nBytes = snprintf(realfile, sizeof(realfile), "%s%s%s.json", path, TD_DIRSEP, name);
64,635✔
155
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
64,635✔
156
    code = TSDB_CODE_OUT_OF_BUFFER;
×
157
    goto _OVER;
×
158
  }
159

160
  pJson = tjsonCreateObject();
64,635✔
161
  if (pJson == NULL) {
64,635✔
162
    code = terrno;
×
163
    goto _OVER;
×
164
  }
165

166
  if ((code = dmEncodeFile(pJson, deployed)) != 0) goto _OVER;
64,635✔
167

168
  buffer = tjsonToString(pJson);
64,635✔
169
  if (buffer == NULL) {
64,635✔
170
    code = TSDB_CODE_INVALID_JSON_FORMAT;
×
171
    goto _OVER;
×
172
  }
173

174
  int32_t len = strlen(buffer);
64,635✔
175
  
176
  // Use encrypted write if tsCfgKey is enabled
177
  code = taosWriteCfgFile(realfile, buffer, len);
64,635✔
178
  if (code != 0) {
64,635✔
UNCOV
179
    goto _OVER;
×
180
  }
181

182
  dInfo("succeed to write file:%s", realfile);
64,635✔
183

184
_OVER:
64,635✔
185

186
  if (pJson != NULL) tjsonDelete(pJson);
64,635✔
187
  if (buffer != NULL) taosMemoryFree(buffer);
64,635✔
188

189
  if (code != 0) {
64,635✔
190
    dError("failed to write file:%s since %s", realfile, tstrerror(code));
×
191
  }
192
  return code;
64,635✔
193
}
194

195
int32_t dmWriteFileJson(const char *path, const char *name, SJson *pJson) {
166,208✔
196
  int32_t   code = -1;
166,208✔
197
  char     *buffer = NULL;
166,208✔
198
  char      realfile[PATH_MAX] = {0};
166,208✔
199

200
  int32_t nBytes = snprintf(realfile, sizeof(realfile), "%s%s%s.json", path, TD_DIRSEP, name);
166,208✔
201
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
166,208✔
202
    code = TSDB_CODE_OUT_OF_BUFFER;
×
203
    goto _OVER;
×
204
  }
205

206
  buffer = tjsonToString(pJson);
166,208✔
207
  if (buffer == NULL) {
166,208✔
208
    code = TSDB_CODE_INVALID_JSON_FORMAT;
×
209
    goto _OVER;
×
210
  }
211

212
  int32_t len = strlen(buffer);
166,208✔
213
  
214
  // Use encrypted write if tsCfgKey is enabled
215
  code = taosWriteCfgFile(realfile, buffer, len);
166,208✔
216
  if (code != 0) {
166,208✔
UNCOV
217
    goto _OVER;
×
218
  }
219

220
  dInfo("succeed to write file:%s", realfile);
166,208✔
221

222
_OVER:
166,142✔
223

224
  if (pJson != NULL) tjsonDelete(pJson);
166,208✔
225
  if (buffer != NULL) taosMemoryFree(buffer);
166,208✔
226

227
  if (code != 0) {
166,208✔
228
    dError("failed to write file:%s since %s", realfile, tstrerror(code));
×
229
  }
230
  return code;
166,208✔
231
}
232

233

234
int32_t dmCheckRunning(const char *dataDir, TdFilePtr *pFile) {
578,866✔
235
  int32_t code = 0;
578,866✔
236
  char    filepath[PATH_MAX] = {0};
578,866✔
237
  snprintf(filepath, sizeof(filepath), "%s%s.running", dataDir, TD_DIRSEP);
578,866✔
238

239
  *pFile = taosOpenFile(filepath, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC | TD_FILE_CLOEXEC);
578,866✔
240
  if (*pFile == NULL) {
578,866✔
241
    code = terrno;
×
242
    dError("failed to open file:%s since %s", filepath, tstrerror(code));
×
243
    return code;
×
244
  }
245

246
  int32_t retryTimes = 0;
578,866✔
247
  int32_t ret = 0;
578,866✔
248
  do {
249
    ret = taosLockFile(*pFile);
592,746✔
250
    if (ret == 0) break;
592,746✔
251

252
    code = terrno;
14,165✔
253
    taosMsleep(1000);
14,165✔
254
    retryTimes++;
14,165✔
255
    dError("failed to lock file:%s since %s, retryTimes:%d", filepath, tstrerror(code), retryTimes);
14,165✔
256
  } while (retryTimes < 12);
14,165✔
257

258
  if (ret < 0) {
578,866✔
259
    code = TAOS_SYSTEM_ERROR(ERRNO);
285✔
260
    (void)taosCloseFile(pFile);
285✔
261
    *pFile = NULL;
285✔
262
    return code;
285✔
263
  }
264

265
  dDebug("lock file:%s to prevent repeated starts", filepath);
578,581✔
266
  return code;
578,581✔
267
}
268

269
extern int32_t generateEncryptCode(const char *key, const char *machineId, char **encryptCode);
270

271
static int32_t dmWriteCheckCodeFile(char *file, char *realfile, char *key, bool toLogFile) {
163✔
272
  TdFilePtr pFile = NULL;
163✔
273
  char     *result = NULL;
163✔
274
  int32_t   code = -1;
163✔
275

276
  int32_t len = ENCRYPTED_LEN(sizeof(DM_KEY_INDICATOR));
163✔
277
  result = taosMemoryMalloc(len);
163✔
278
  if (result == NULL) {
163✔
279
    return terrno;
×
280
  }
281

282
  SCryptOpts opts = {0};
163✔
283
  tstrncpy(opts.key, key, ENCRYPT_KEY_LEN + 1);
163✔
284
  opts.len = len;
163✔
285
  opts.source = DM_KEY_INDICATOR;
163✔
286
  opts.result = result;
163✔
287
  opts.unitLen = 16;
163✔
288
  if (Builtin_CBC_Encrypt(&opts) <= 0) {
163✔
289
    code = terrno;
×
290
    encryptError("failed to encrypt checkCode, since %s", tstrerror(code));
×
291
    goto _OVER;
×
292
  }
293

294
  pFile = taosOpenFile(file, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC | TD_FILE_WRITE_THROUGH);
163✔
295
  if (pFile == NULL) {
163✔
296
    code = terrno;
×
297
    goto _OVER;
×
298
  }
299

300
  if (taosWriteFile(pFile, opts.result, len) <= 0) {
163✔
301
    code = terrno;
×
302
    goto _OVER;
×
303
  }
304

305
  if (taosFsyncFile(pFile) < 0) {
163✔
306
    code = TAOS_SYSTEM_ERROR(ERRNO);
×
307
    goto _OVER;
×
308
  }
309

310
  if (taosCloseFile(&pFile) != 0) {
163✔
311
    code = TAOS_SYSTEM_ERROR(ERRNO);
×
312
    goto _OVER;
×
313
  }
314

315
  TAOS_CHECK_GOTO(taosRenameFile(file, realfile), NULL, _OVER);
163✔
316

317
  encryptDebug("succeed to write checkCode file:%s", realfile);
163✔
318

319
  code = 0;
163✔
320
_OVER:
163✔
321
  if (pFile != NULL) taosCloseFile(&pFile);
163✔
322
  if (result != NULL) taosMemoryFree(result);
163✔
323

324
  return code;
163✔
325
}
326

327
static int32_t dmWriteEncryptCodeFile(char *file, char *realfile, char *encryptCode, bool toLogFile) {
163✔
328
  TdFilePtr pFile = NULL;
163✔
329
  int32_t   code = -1;
163✔
330

331
  pFile = taosOpenFile(file, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC | TD_FILE_WRITE_THROUGH);
163✔
332
  if (pFile == NULL) {
163✔
333
    code = terrno;
×
334
    goto _OVER;
×
335
  }
336

337
  int32_t len = strlen(encryptCode);
163✔
338
  if (taosWriteFile(pFile, encryptCode, len) <= 0) {
163✔
339
    code = terrno;
×
340
    goto _OVER;
×
341
  }
342
  if (taosFsyncFile(pFile) < 0) {
163✔
343
    code = terrno;
×
344
    goto _OVER;
×
345
  }
346

347
  if (taosCloseFile(&pFile) != 0) {
163✔
348
    code = TAOS_SYSTEM_ERROR(ERRNO);
×
349
    goto _OVER;
×
350
  }
351

352
  TAOS_CHECK_GOTO(taosRenameFile(file, realfile), NULL, _OVER);
163✔
353

354
  encryptDebug("succeed to write encryptCode file:%s", realfile);
163✔
355

356
  code = 0;
163✔
357
_OVER:
163✔
358
  if (pFile != NULL) taosCloseFile(&pFile);
163✔
359

360
  return code;
163✔
361
}
362

363
static int32_t dmCompareEncryptKey(char *file, char *key, bool toLogFile) {
×
364
  char     *content = NULL;
×
365
  int64_t   size = 0;
×
366
  TdFilePtr pFile = NULL;
×
367
  char     *result = NULL;
×
368
  int32_t   code = -1;
×
369

370
  pFile = taosOpenFile(file, TD_FILE_READ);
×
371
  if (pFile == NULL) {
×
372
    code = terrno;
×
373
    encryptError("failed to open dnode file:%s since %s", file, tstrerror(code));
×
374
    goto _OVER;
×
375
  }
376

377
  code = taosFStatFile(pFile, &size, NULL);
×
378
  if (code != 0) {
×
379
    encryptError("failed to fstat dnode file:%s since %s", file, tstrerror(code));
×
380
    goto _OVER;
×
381
  }
382

383
  content = taosMemoryMalloc(size);
×
384
  if (content == NULL) {
×
385
    code = terrno;
×
386
    goto _OVER;
×
387
  }
388

389
  if (taosReadFile(pFile, content, size) != size) {
×
390
    code = terrno;
×
391
    encryptError("failed to read dnode file:%s since %s", file, tstrerror(code));
×
392
    goto _OVER;
×
393
  }
394

395
  encryptDebug("succeed to read checkCode file:%s", file);
×
396

397
  int len = ENCRYPTED_LEN(size);
×
398
  result = taosMemoryMalloc(len);
×
399
  if (result == NULL) {
×
400
    code = terrno;
×
401
    encryptError("failed to alloc memory file:%s since %s", file, tstrerror(code));
×
402
    goto _OVER;
×
403
  }
404

405
  SCryptOpts opts = {0};
×
406
  tstrncpy(opts.key, key, ENCRYPT_KEY_LEN + 1);
×
407
  opts.len = len;
×
408
  opts.source = content;
×
409
  opts.result = result;
×
410
  opts.unitLen = 16;
×
411
  if (Builtin_CBC_Decrypt(&opts) <= 0) {
×
412
    code = terrno;
×
413
    encryptError("failed to decrypt checkCode since %s", tstrerror(code));
×
414
    goto _OVER;
×
415
  }
416

417
  if (strcmp(opts.result, DM_KEY_INDICATOR) != 0) {
×
418
    code = TSDB_CODE_DNODE_ENCRYPTKEY_CHANGED;
×
419
    encryptError("failed to compare decrypted result");
×
420
    goto _OVER;
×
421
  }
422

423
  encryptDebug("succeed to compare checkCode file:%s", file);
×
424
  code = 0;
×
425
_OVER:
×
426
  if (result != NULL) taosMemoryFree(result);
×
427
  if (content != NULL) taosMemoryFree(content);
×
428
  if (pFile != NULL) taosCloseFile(&pFile);
×
429

430
  return code;
×
431
}
432

433
int32_t dmUpdateEncryptKey(char *key, bool toLogFile) {
163✔
434
#if defined(TD_ENTERPRISE) || defined(TD_ASTRA_TODO)
435
  int32_t code = -1;
163✔
436
  int32_t lino = 0;
163✔
437
  char   *machineId = NULL;
163✔
438
  char   *encryptCode = NULL;
163✔
439

440
  char folder[PATH_MAX] = {0};
163✔
441

442
  char encryptFile[PATH_MAX] = {0};
163✔
443
  char realEncryptFile[PATH_MAX] = {0};
163✔
444

445
  char checkFile[PATH_MAX] = {0};
163✔
446
  char realCheckFile[PATH_MAX] = {0};
163✔
447

448
  int32_t nBytes = snprintf(folder, sizeof(folder), "%s%sdnode", tsDataDir, TD_DIRSEP);
163✔
449
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
163✔
450
    return TSDB_CODE_OUT_OF_BUFFER;
×
451
  }
452

453
  nBytes = snprintf(encryptFile, sizeof(realEncryptFile), "%s%s%s.bak", folder, TD_DIRSEP, DM_ENCRYPT_CODE_FILE);
163✔
454
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
163✔
455
    return TSDB_CODE_OUT_OF_BUFFER;
×
456
  }
457

458
  nBytes = snprintf(realEncryptFile, sizeof(realEncryptFile), "%s%s%s", folder, TD_DIRSEP, DM_ENCRYPT_CODE_FILE);
163✔
459
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
163✔
460
    return TSDB_CODE_OUT_OF_BUFFER;
×
461
  }
462

463
  nBytes = snprintf(checkFile, sizeof(checkFile), "%s%s%s.bak", folder, TD_DIRSEP, DM_CHECK_CODE_FILE);
163✔
464
  if (nBytes <= 0 || nBytes >= PATH_MAX) {
163✔
465
    return TSDB_CODE_OUT_OF_BUFFER;
×
466
  }
467

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

473
  if (taosMkDir(folder) != 0) {
163✔
474
    code = terrno;
×
475
    encryptError("failed to create dir:%s since %s", folder, tstrerror(code));
×
476
    goto _OVER;
×
477
  }
478

479
  if (taosCheckExistFile(realCheckFile)) {
163✔
480
    if ((code = dmCompareEncryptKey(realCheckFile, key, toLogFile)) != 0) {
×
481
      goto _OVER;
×
482
    }
483
  }
484

485
  TAOS_CHECK_GOTO(tGetMachineId(&machineId), &lino, _OVER);
163✔
486

487
  TAOS_CHECK_GOTO(generateEncryptCode(key, machineId, &encryptCode), &lino, _OVER);
163✔
488

489
  if ((code = dmWriteEncryptCodeFile(encryptFile, realEncryptFile, encryptCode, toLogFile)) != 0) {
163✔
490
    goto _OVER;
×
491
  }
492

493
  if ((code = dmWriteCheckCodeFile(checkFile, realCheckFile, key, toLogFile)) != 0) {
163✔
494
    goto _OVER;
×
495
  }
496

497
  encryptInfo("Succeed to update encrypt key\n");
163✔
498

499
  code = 0;
163✔
500
_OVER:
163✔
501
  taosMemoryFree(encryptCode);
163✔
502
  taosMemoryFree(machineId);
163✔
503
  if (code != 0) {
163✔
504
    encryptError("failed to update encrypt key at line %d since %s", lino, tstrerror(code));
×
505
  }
506
  TAOS_RETURN(code);
163✔
507
#else
508
  return 0;
509
#endif
510
}
511

512
extern int32_t checkAndGetCryptKey(const char *encryptCode, const char *machineId, char **key);
513

514
extern int32_t dmGetEncryptKeyFromTaosk();
515

516
extern int32_t taoskLoadEncryptKeys(const char *masterKeyFile, const char *derivedKeyFile, char *svrKey, char *dbKey,
517
                                    char *cfgKey, char *metaKey, char *dataKey, int32_t *algorithm, int32_t *cfgAlgorithm,
518
                                    int32_t *metaAlgorithm, int32_t *fileVersion, int32_t *keyVersion, int64_t *createTime,
519
                                    int64_t *svrKeyUpdateTime, int64_t *dbKeyUpdateTime);
520

521
static int32_t dmReadEncryptCodeFile(char *file, char **output) {
×
522
  TdFilePtr pFile = NULL;
×
523
  int32_t   code = -1;
×
524
  char     *content = NULL;
×
525

526
  pFile = taosOpenFile(file, TD_FILE_READ);
×
527
  if (pFile == NULL) {
×
528
    code = terrno;
×
529
    dError("failed to open dnode file:%s since %s", file, tstrerror(code));
×
530
    goto _OVER;
×
531
  }
532

533
  int64_t size = 0;
×
534
  code = taosFStatFile(pFile, &size, NULL);
×
535
  if (code != 0) {
×
536
    dError("failed to fstat dnode file:%s since %s", file, tstrerror(code));
×
537
    goto _OVER;
×
538
  }
539

540
  content = taosMemoryMalloc(size + 1);
×
541
  if (content == NULL) {
×
542
    code = terrno;
×
543
    goto _OVER;
×
544
  }
545

546
  if (taosReadFile(pFile, content, size) != size) {
×
547
    code = terrno;
×
548
    dError("failed to read dnode file:%s since %s", file, tstrerror(code));
×
549
    goto _OVER;
×
550
  }
551

552
  content[size] = '\0';
×
553

554
  *output = content;
×
555
  content = NULL;
×
556

557
  dInfo("succeed to read encryptCode file:%s", file);
×
558
  code = 0;
×
559
_OVER:
×
560
  if (pFile != NULL) taosCloseFile(&pFile);
×
561
  taosMemoryFree(content);
×
562

563
  return code;
×
564
}
565

566
int32_t dmGetEncryptKeyFromTaosk() {
588,912✔
567
#if (defined(TD_ENTERPRISE) && defined(TD_HAS_TAOSK)) || defined(TD_ASTRA_TODO)
568
  char keyFileDir[PATH_MAX] = {0};
588,912✔
569
  char masterKeyFile[PATH_MAX] = {0};
588,912✔
570
  char derivedKeyFile[PATH_MAX] = {0};
588,912✔
571

572
  // Build path to key file directory: tsDataDir/dnode/config/
573
  int32_t nBytes = snprintf(keyFileDir, sizeof(keyFileDir), "%s%sdnode%sconfig", tsDataDir, TD_DIRSEP, TD_DIRSEP);
588,912✔
574
  if (nBytes <= 0 || nBytes >= sizeof(keyFileDir)) {
588,912✔
NEW
575
    return TSDB_CODE_OUT_OF_BUFFER;
×
576
  }
577

578
  // Build path to master.bin
579
  nBytes = snprintf(masterKeyFile, sizeof(masterKeyFile), "%s%smaster.bin", keyFileDir, TD_DIRSEP);
588,912✔
580
  if (nBytes <= 0 || nBytes >= sizeof(masterKeyFile)) {
588,912✔
NEW
581
    return TSDB_CODE_OUT_OF_BUFFER;
×
582
  }
583

584
  // Build path to derived.bin
585
  nBytes = snprintf(derivedKeyFile, sizeof(derivedKeyFile), "%s%sderived.bin", keyFileDir, TD_DIRSEP);
588,912✔
586
  if (nBytes <= 0 || nBytes >= sizeof(derivedKeyFile)) {
588,912✔
NEW
587
    return TSDB_CODE_OUT_OF_BUFFER;
×
588
  }
589

590
  // Check if master.bin exists
591
  if (!taosCheckExistFile(masterKeyFile)) {
588,912✔
592
    dInfo("taosk master key file not found: %s, encryption not configured", masterKeyFile);
588,912✔
593
    return TSDB_CODE_DNODE_INVALID_ENCRYPT_CONFIG;
588,912✔
594
  }
595

NEW
596
  dInfo("loading encryption keys from taosk split files: %s, %s", masterKeyFile, derivedKeyFile);
×
597

598
  // Prepare variables for decrypted keys
NEW
599
  int32_t algorithm = 0;
×
NEW
600
  int32_t fileVersion = 0;
×
NEW
601
  int32_t keyVersion = 0;
×
NEW
602
  int64_t createTime = 0;
×
NEW
603
  int64_t svrKeyUpdateTime = 0;
×
NEW
604
  int64_t dbKeyUpdateTime = 0;
×
NEW
605
  int32_t cfgAlgorithm = 0;
×
NEW
606
  int32_t metaAlgorithm = 0;
×
607

608
  // Call enterprise function to decrypt and load multi-layer keys from split files
NEW
609
  int32_t code = taoskLoadEncryptKeys(masterKeyFile, derivedKeyFile,
×
610
                                      tsSvrKey,           // output: SVR_KEY (server master key)
611
                                      tsDbKey,            // output: DB_KEY (database master key)
612
                                      tsCfgKey,           // output: CFG_KEY (config encryption key)
613
                                      tsMetaKey,          // output: META_KEY (metadata encryption key)
614
                                      tsDataKey,          // output: DATA_KEY (data encryption key)
615
                                      &algorithm,         // output: encryption algorithm type for master keys
616
                                      &cfgAlgorithm,      // output: encryption algorithm type for CFG_KEY
617
                                      &metaAlgorithm,     // output: encryption algorithm type for META_KEY
618
                                      &fileVersion,       // output: file format version
619
                                      &keyVersion,        // output: key update version
620
                                      &createTime,        // output: key creation timestamp
621
                                      &svrKeyUpdateTime,  // output: SVR_KEY update timestamp
622
                                      &dbKeyUpdateTime    // output: DB_KEY update timestamp
623
  );
624

NEW
625
  if (code != 0) {
×
NEW
626
    dError("failed to load encryption keys from taosk since %s", tstrerror(code));
×
NEW
627
    TAOS_RETURN(code);
×
628
  }
629

630
  // Store decrypted keys in global variables
NEW
631
  tsUseTaoskEncryption = true;
×
632

633
  // Store metadata
NEW
634
  tsEncryptAlgorithmType = algorithm;
×
NEW
635
  tsCfgAlgorithm = cfgAlgorithm;
×
NEW
636
  tsMetaAlgorithm = metaAlgorithm;
×
NEW
637
  tsEncryptFileVersion = fileVersion;   // file format version for compatibility
×
NEW
638
  tsEncryptKeyVersion = keyVersion;     // key update version
×
NEW
639
  tsEncryptKeyCreateTime = createTime;
×
NEW
640
  tsSvrKeyUpdateTime = svrKeyUpdateTime;
×
NEW
641
  tsDbKeyUpdateTime = dbKeyUpdateTime;
×
642

643
  // For backward compatibility: copy DATA_KEY to tsEncryptKey (truncated to 16 bytes)
NEW
644
  int keyLen = strlen(tsDataKey);
×
NEW
645
  if (keyLen > ENCRYPT_KEY_LEN) {
×
NEW
646
    keyLen = ENCRYPT_KEY_LEN;
×
647
  }
NEW
648
  memset(tsEncryptKey, 0, ENCRYPT_KEY_LEN + 1);
×
NEW
649
  memcpy(tsEncryptKey, tsDataKey, keyLen);
×
NEW
650
  tsEncryptKey[ENCRYPT_KEY_LEN] = '\0';
×
651

652
  // Update encryption key status
NEW
653
  tsEncryptionKeyChksum = taosCalcChecksum(0, (const uint8_t *)tsEncryptKey, strlen(tsEncryptKey));
×
NEW
654
  tsEncryptionKeyStat = ENCRYPT_KEY_STAT_LOADED;
×
655

NEW
656
  dInfo("successfully loaded taosk encryption keys (algorithm:%d, cfg:%s, meta:%s, data:%s)", algorithm,
×
657
        (tsCfgKey[0] != '\0') ? "enabled" : "disabled", 
658
        (tsMetaKey[0] != '\0') ? "enabled" : "disabled", 
659
        (tsDataKey[0] != '\0') ? "enabled" : "disabled");
660

NEW
661
  TAOS_RETURN(0);
×
662
#else
663
  return 0;
664
#endif
665
}
666

667
int32_t dmGetEncryptKey() {
588,912✔
668
#if defined(TD_ENTERPRISE) || defined(TD_ASTRA_TODO)
669
  int32_t code = -1;
588,912✔
670
  char    encryptFile[PATH_MAX] = {0};
588,912✔
671
  char    checkFile[PATH_MAX] = {0};
588,912✔
672
  char   *machineId = NULL;
588,912✔
673
  char   *encryptKey = NULL;
588,912✔
674
  char   *content = NULL;
588,912✔
675

676
  // First try to load from taosk key files (master.bin and derived.bin)
677
  code = dmGetEncryptKeyFromTaosk();
588,912✔
678
  if (code == 0) {
588,912✔
NEW
679
    tsEncryptKeysStatus = TSDB_ENCRYPT_KEY_STAT_LOADED;
×
NEW
680
    dInfo("encryption keys loaded from taosk key files");
×
NEW
681
    return 0;
×
682
  }
683

684
  tsEncryptKeysStatus = TSDB_ENCRYPT_KEY_STAT_NOT_EXIST;
588,912✔
685

686
  // Fallback to legacy encryptCode.cfg format (pre-taosk)
687
  dInfo("falling back to legacy encryptCode.cfg format");
588,912✔
688

689
  int32_t nBytes = snprintf(encryptFile, sizeof(encryptFile), "%s%sdnode%s%s", tsDataDir, TD_DIRSEP, TD_DIRSEP,
588,912✔
690
                            DM_ENCRYPT_CODE_FILE);
691
  if (nBytes <= 0 || nBytes >= sizeof(encryptFile)) {
588,912✔
692
    code = TSDB_CODE_OUT_OF_BUFFER;
×
693
    return code;
×
694
  }
695

696
  nBytes = snprintf(checkFile, sizeof(checkFile), "%s%sdnode%s%s", tsDataDir, TD_DIRSEP, TD_DIRSEP, DM_CHECK_CODE_FILE);
588,912✔
697
  if (nBytes <= 0 || nBytes >= sizeof(checkFile)) {
588,912✔
698
    code = TSDB_CODE_OUT_OF_BUFFER;
×
699
    return code;
×
700
  }
701

702
  if (!taosCheckExistFile(encryptFile)) {
588,912✔
703
    code = TSDB_CODE_DNODE_INVALID_ENCRYPT_CONFIG;
588,912✔
704
    dInfo("no exist, checkCode file:%s", encryptFile);
588,912✔
705
    return 0;
588,912✔
706
  }
707

708
  if ((code = dmReadEncryptCodeFile(encryptFile, &content)) != 0) {
×
709
    goto _OVER;
×
710
  }
711

712
  if ((code = tGetMachineId(&machineId)) != 0) {
×
713
    goto _OVER;
×
714
  }
715

716
  if ((code = checkAndGetCryptKey(content, machineId, &encryptKey)) != 0) {
×
717
    goto _OVER;
×
718
  }
719

720
  taosMemoryFreeClear(machineId);
×
721
  taosMemoryFreeClear(content);
×
722

723
  if (encryptKey[0] == '\0') {
×
724
    code = TSDB_CODE_DNODE_INVALID_ENCRYPTKEY;
×
725
    dError("failed to read key since %s", tstrerror(code));
×
726
    goto _OVER;
×
727
  }
728

729
  if ((code = dmCompareEncryptKey(checkFile, encryptKey, true)) != 0) {
×
730
    goto _OVER;
×
731
  }
732

733
  tstrncpy(tsEncryptKey, encryptKey, ENCRYPT_KEY_LEN + 1);
×
734
  taosMemoryFreeClear(encryptKey);
×
735
  tsEncryptionKeyChksum = taosCalcChecksum(0, tsEncryptKey, strlen(tsEncryptKey));
×
736
  tsEncryptionKeyStat = ENCRYPT_KEY_STAT_LOADED;
×
737

738
  code = 0;
×
739
_OVER:
×
740
  if (content != NULL) taosMemoryFree(content);
×
741
  if (encryptKey != NULL) taosMemoryFree(encryptKey);
×
742
  if (machineId != NULL) taosMemoryFree(machineId);
×
743
  if (code != 0) {
×
744
    dError("failed to get encrypt key since %s", tstrerror(code));
×
745
  }
746
  TAOS_RETURN(code);
×
747
#else
748
  return 0;
749
#endif
750
}
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