Coverage Report

Created: 2026-07-25 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/lib/util/server_id_db.c
Line
Count
Source
1
/*
2
 * Map names to server_ids
3
 *
4
 * Copyright Volker Lendecke <vl@samba.org> 2014
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
20
#include "replace.h"
21
#include "system/filesys.h"
22
#include "lib/util/server_id.h"
23
#include "lib/util/server_id_db.h"
24
#include "lib/tdb_wrap/tdb_wrap.h"
25
#include "lib/util/strv.h"
26
#include "lib/util/util_tdb.h"
27
#include "lib/util/samba_util.h"
28
29
static TDB_DATA talloc_tdb_data(void *ptr)
30
0
{
31
0
  return (TDB_DATA) { .dptr = ptr, .dsize = talloc_get_size(ptr) };
32
0
}
33
34
struct server_id_db {
35
  struct server_id pid;
36
  struct tdb_wrap *tdb;
37
  char *names;
38
};
39
40
static int server_id_db_destructor(struct server_id_db *db);
41
42
struct server_id_db *server_id_db_init(TALLOC_CTX *mem_ctx,
43
               struct server_id pid,
44
               const char *base_path,
45
               int hash_size, int tdb_flags)
46
0
{
47
0
  struct server_id_db *db;
48
0
  size_t pathlen = strlen(base_path) + 11;
49
0
  char path[pathlen];
50
51
0
  db = talloc(mem_ctx, struct server_id_db);
52
0
  if (db == NULL) {
53
0
    return NULL;
54
0
  }
55
0
  db->pid = pid;
56
0
  db->names = NULL;
57
58
0
  snprintf(path, pathlen, "%s/names.tdb", base_path);
59
60
0
  db->tdb = tdb_wrap_open(db, path, hash_size, tdb_flags,
61
0
        O_RDWR|O_CREAT, 0660);
62
0
  if (db->tdb == NULL) {
63
0
    TALLOC_FREE(db);
64
0
    return NULL;
65
0
  }
66
67
0
  talloc_set_destructor(db, server_id_db_destructor);
68
69
0
  return db;
70
0
}
71
72
void server_id_db_reinit(struct server_id_db *db, struct server_id pid)
73
0
{
74
0
  db->pid = pid;
75
0
  TALLOC_FREE(db->names);
76
0
}
77
78
struct server_id server_id_db_pid(struct server_id_db *db)
79
0
{
80
0
  return db->pid;
81
0
}
82
83
static int server_id_db_destructor(struct server_id_db *db)
84
0
{
85
0
  char *name = NULL;
86
87
0
  while ((name = strv_next(db->names, name)) != NULL) {
88
0
    server_id_db_remove(db, name);
89
0
  }
90
91
0
  return 0;
92
0
}
93
94
int server_id_db_add(struct server_id_db *db, const char *name)
95
0
{
96
0
  struct tdb_context *tdb = db->tdb->tdb;
97
0
  TDB_DATA key;
98
0
  char *n;
99
0
  int ret;
100
101
0
  n = strv_find(db->names, name);
102
0
  if (n != NULL) {
103
0
    return EEXIST;
104
0
  }
105
106
0
  ret = strv_add(db, &db->names, name);
107
0
  if (ret != 0) {
108
0
    return ret;
109
0
  }
110
111
0
  key = string_term_tdb_data(name);
112
113
0
  {
114
0
    struct server_id_buf _buf;
115
0
    char *idbuf = server_id_str_buf_unique(db->pid, &_buf);
116
0
    size_t idlen = strlen(idbuf) + 1;
117
118
0
    ret = tdb_append(
119
0
      tdb, key,
120
0
      (TDB_DATA) { .dptr = (uint8_t *)idbuf, .dsize = idlen });
121
0
  }
122
123
0
  if (ret != 0) {
124
0
    enum TDB_ERROR err = tdb_error(tdb);
125
0
    strv_delete(&db->names, strv_find(db->names, name));
126
0
    return map_unix_error_from_tdb(err);
127
0
  }
128
129
0
  return 0;
130
0
}
131
132
int server_id_db_prune_name(struct server_id_db *db, const char *name,
133
          struct server_id server)
134
0
{
135
0
  struct tdb_context *tdb = db->tdb->tdb;
136
0
  struct server_id_buf _buf;
137
0
  char *idbuf = server_id_str_buf_unique(server, &_buf);
138
0
  TDB_DATA key;
139
0
  uint8_t *data;
140
0
  size_t datalen;
141
0
  char *ids, *id;
142
0
  int ret;
143
144
0
  key = string_term_tdb_data(name);
145
146
0
  ret = tdb_chainlock(tdb, key);
147
0
  if (ret == -1) {
148
0
    enum TDB_ERROR err = tdb_error(tdb);
149
0
    return map_unix_error_from_tdb(err);
150
0
  }
151
152
0
  ret = tdb_fetch_talloc(tdb, key, db, &data);
153
0
  if (ret != 0) {
154
0
    tdb_chainunlock(tdb, key);
155
0
    return ret;
156
0
  }
157
158
0
  datalen = talloc_get_size(data);
159
0
  if ((datalen == 0) || (data[datalen-1] != '\0')) {
160
0
    tdb_chainunlock(tdb, key);
161
0
    TALLOC_FREE(data);
162
0
    return EINVAL;
163
0
  }
164
165
0
  ids = (char *)data;
166
167
0
  id = strv_find(ids, idbuf);
168
0
  if (id == NULL) {
169
0
    tdb_chainunlock(tdb, key);
170
0
    TALLOC_FREE(data);
171
0
    return ENOENT;
172
0
  }
173
174
0
  strv_delete(&ids, id);
175
176
0
  if (talloc_get_size(ids) == 0) {
177
0
    ret = tdb_delete(tdb, key);
178
0
  } else {
179
0
    ret = tdb_store(tdb, key, talloc_tdb_data(ids), TDB_MODIFY);
180
0
  }
181
0
  TALLOC_FREE(data);
182
183
0
  tdb_chainunlock(tdb, key);
184
185
0
  if (ret == -1) {
186
0
    enum TDB_ERROR err = tdb_error(tdb);
187
0
    return map_unix_error_from_tdb(err);
188
0
  }
189
190
0
  return 0;
191
0
}
192
193
int server_id_db_remove(struct server_id_db *db, const char *name)
194
0
{
195
0
  char *n;
196
0
  int ret;
197
198
0
  n = strv_find(db->names, name);
199
0
  if (n == NULL) {
200
0
    return ENOENT;
201
0
  }
202
203
0
  ret = server_id_db_prune_name(db, name, db->pid);
204
0
  if (ret != 0) {
205
0
    return ret;
206
0
  }
207
208
0
  strv_delete(&db->names, n);
209
0
  return 0;
210
0
}
211
212
int server_id_db_lookup(struct server_id_db *db, const char *name,
213
      TALLOC_CTX *mem_ctx, unsigned *pnum_servers,
214
      struct server_id **pservers)
215
0
{
216
0
  struct tdb_context *tdb = db->tdb->tdb;
217
0
  TDB_DATA key;
218
0
  uint8_t *data;
219
0
  size_t datalen;
220
0
  char *ids, *id;
221
0
  unsigned num_servers;
222
0
  struct server_id *servers;
223
0
  int i, ret;
224
225
0
  key = string_term_tdb_data(name);
226
227
0
  ret = tdb_fetch_talloc(tdb, key, mem_ctx, &data);
228
0
  if (ret != 0) {
229
0
    return ret;
230
0
  }
231
232
0
  datalen = talloc_get_size(data);
233
0
  if ((datalen == 0) || (data[datalen-1] != '\0')) {
234
0
    TALLOC_FREE(data);
235
0
    return EINVAL;
236
0
  }
237
238
0
  ids = (char *)data;
239
0
  num_servers = strv_count(ids);
240
241
0
  servers = talloc_array(mem_ctx, struct server_id, num_servers);
242
0
  if (servers == NULL) {
243
0
    TALLOC_FREE(data);
244
0
    return ENOMEM;
245
0
  }
246
247
0
  i = 0;
248
249
0
  for (id = ids; id != NULL; id = strv_next(ids, id)) {
250
0
    servers[i++] = server_id_from_string(NONCLUSTER_VNN, id);
251
0
  }
252
253
0
  TALLOC_FREE(data);
254
255
0
  *pnum_servers = num_servers;
256
0
  *pservers = servers;
257
258
0
  return 0;
259
0
}
260
261
bool server_id_db_lookup_one(struct server_id_db *db, const char *name,
262
           struct server_id *server)
263
0
{
264
0
  int ret;
265
0
  unsigned num_servers;
266
0
  struct server_id *servers;
267
268
0
  ret = server_id_db_lookup(db, name, db, &num_servers, &servers);
269
0
  if (ret != 0) {
270
0
    return false;
271
0
  }
272
0
  if (num_servers == 0) {
273
0
    TALLOC_FREE(servers);
274
0
    return false;
275
0
  }
276
0
  *server = servers[0];
277
0
  TALLOC_FREE(servers);
278
0
  return true;
279
0
}
280
281
struct server_id_db_traverse_state {
282
  TALLOC_CTX *mem_ctx;
283
  int (*fn)(const char *name,
284
      unsigned num_servers,
285
      const struct server_id *servers,
286
      void *private_data);
287
  void *private_data;
288
};
289
290
static int server_id_db_traverse_fn(struct tdb_context *tdb,
291
            TDB_DATA key, TDB_DATA data,
292
            void *private_data)
293
0
{
294
0
  struct server_id_db_traverse_state *state = private_data;
295
0
  const char *name;
296
0
  char *ids, *id;
297
0
  unsigned num_servers;
298
0
  struct server_id *servers;
299
0
  int i, ret;
300
301
0
  if (key.dsize == 0) {
302
0
    return 0;
303
0
  }
304
0
  if (key.dptr[key.dsize-1] != '\0') {
305
0
    return 0;
306
0
  }
307
0
  name = (const char *)key.dptr;
308
309
0
  ids = (char *)talloc_memdup(state->mem_ctx, data.dptr, data.dsize);
310
0
  if (ids == NULL) {
311
0
    return 0;
312
0
  }
313
314
0
  num_servers = strv_count(ids);
315
0
  servers = talloc_array(ids, struct server_id, num_servers);
316
317
0
  i = 0;
318
319
0
  for (id = ids; id != NULL; id = strv_next(ids, id)) {
320
0
    servers[i++] = server_id_from_string(NONCLUSTER_VNN, id);
321
0
  }
322
323
0
  ret = state->fn(name, num_servers, servers, state->private_data);
324
325
0
  TALLOC_FREE(ids);
326
327
0
  return ret;
328
0
}
329
330
int server_id_db_traverse_read(struct server_id_db *db,
331
             int (*fn)(const char *name,
332
           unsigned num_servers,
333
           const struct server_id *servers,
334
           void *private_data),
335
             void *private_data)
336
0
{
337
0
  struct server_id_db_traverse_state state;
338
0
  int ret;
339
340
0
  state = (struct server_id_db_traverse_state) {
341
0
    .fn = fn, .private_data = private_data,
342
0
    .mem_ctx = talloc_new(db)
343
0
  };
344
345
0
  if (state.mem_ctx == NULL) {
346
0
    return ENOMEM;
347
0
  }
348
349
0
  ret = tdb_traverse_read(db->tdb->tdb, server_id_db_traverse_fn,
350
0
        &state);
351
  TALLOC_FREE(state.mem_ctx);
352
0
  return ret;
353
0
}