Line data Source code
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 30596 : static TDB_DATA talloc_tdb_data(void *ptr)
30 : {
31 30596 : return (TDB_DATA) { .dptr = ptr, .dsize = talloc_get_size(ptr) };
32 : }
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 418836 : 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 418836 : {
47 17212 : struct server_id_db *db;
48 418836 : size_t pathlen = strlen(base_path) + 11;
49 418836 : char path[pathlen];
50 :
51 418836 : db = talloc(mem_ctx, struct server_id_db);
52 418836 : if (db == NULL) {
53 0 : return NULL;
54 : }
55 418836 : db->pid = pid;
56 418836 : db->names = NULL;
57 :
58 418836 : snprintf(path, pathlen, "%s/names.tdb", base_path);
59 :
60 418836 : db->tdb = tdb_wrap_open(db, path, hash_size, tdb_flags,
61 : O_RDWR|O_CREAT, 0660);
62 418836 : if (db->tdb == NULL) {
63 0 : TALLOC_FREE(db);
64 0 : return NULL;
65 : }
66 :
67 418836 : talloc_set_destructor(db, server_id_db_destructor);
68 :
69 418836 : return db;
70 : }
71 :
72 89779 : void server_id_db_reinit(struct server_id_db *db, struct server_id pid)
73 : {
74 89779 : db->pid = pid;
75 89779 : TALLOC_FREE(db->names);
76 89779 : }
77 :
78 0 : struct server_id server_id_db_pid(struct server_id_db *db)
79 : {
80 0 : return db->pid;
81 : }
82 :
83 493595 : static int server_id_db_destructor(struct server_id_db *db)
84 : {
85 493595 : char *name = NULL;
86 :
87 525290 : while ((name = strv_next(db->names, name)) != NULL) {
88 31695 : server_id_db_remove(db, name);
89 : }
90 :
91 493595 : return 0;
92 : }
93 :
94 31980 : int server_id_db_add(struct server_id_db *db, const char *name)
95 : {
96 31980 : struct tdb_context *tdb = db->tdb->tdb;
97 198 : TDB_DATA key;
98 198 : char *n;
99 198 : int ret;
100 :
101 31980 : n = strv_find(db->names, name);
102 31980 : if (n != NULL) {
103 0 : return EEXIST;
104 : }
105 :
106 31980 : ret = strv_add(db, &db->names, name);
107 31980 : if (ret != 0) {
108 0 : return ret;
109 : }
110 :
111 31980 : key = string_term_tdb_data(name);
112 :
113 31980 : {
114 31980 : size_t idlen = server_id_str_buf_unique(db->pid, NULL, 0);
115 31980 : char idbuf[idlen];
116 :
117 31980 : server_id_str_buf_unique(db->pid, idbuf, idlen);
118 :
119 32178 : ret = tdb_append(
120 : tdb, key,
121 31980 : (TDB_DATA) { .dptr = (uint8_t *)idbuf, .dsize = idlen });
122 : }
123 :
124 31980 : if (ret != 0) {
125 0 : enum TDB_ERROR err = tdb_error(tdb);
126 0 : strv_delete(&db->names, strv_find(db->names, name));
127 0 : return map_unix_error_from_tdb(err);
128 : }
129 :
130 31782 : return 0;
131 : }
132 :
133 32704 : int server_id_db_prune_name(struct server_id_db *db, const char *name,
134 : struct server_id server)
135 32704 : {
136 32704 : struct tdb_context *tdb = db->tdb->tdb;
137 32704 : size_t idbuf_len = server_id_str_buf_unique(server, NULL, 0);
138 32704 : char idbuf[idbuf_len];
139 262 : TDB_DATA key;
140 262 : uint8_t *data;
141 262 : size_t datalen;
142 262 : char *ids, *id;
143 262 : int ret;
144 :
145 32704 : key = string_term_tdb_data(name);
146 32704 : server_id_str_buf_unique(server, idbuf, idbuf_len);
147 :
148 32704 : ret = tdb_chainlock(tdb, key);
149 32704 : if (ret == -1) {
150 0 : enum TDB_ERROR err = tdb_error(tdb);
151 0 : return map_unix_error_from_tdb(err);
152 : }
153 :
154 32704 : ret = tdb_fetch_talloc(tdb, key, db, &data);
155 32704 : if (ret != 0) {
156 695 : tdb_chainunlock(tdb, key);
157 695 : return ret;
158 : }
159 :
160 32009 : datalen = talloc_get_size(data);
161 32009 : if ((datalen == 0) || (data[datalen-1] != '\0')) {
162 0 : tdb_chainunlock(tdb, key);
163 0 : TALLOC_FREE(data);
164 0 : return EINVAL;
165 : }
166 :
167 32009 : ids = (char *)data;
168 :
169 32009 : id = strv_find(ids, idbuf);
170 32009 : if (id == NULL) {
171 109 : tdb_chainunlock(tdb, key);
172 109 : TALLOC_FREE(data);
173 109 : return ENOENT;
174 : }
175 :
176 31900 : strv_delete(&ids, id);
177 :
178 31900 : if (talloc_get_size(ids) == 0) {
179 1304 : ret = tdb_delete(tdb, key);
180 : } else {
181 30596 : ret = tdb_store(tdb, key, talloc_tdb_data(ids), TDB_MODIFY);
182 : }
183 31900 : TALLOC_FREE(data);
184 :
185 31900 : tdb_chainunlock(tdb, key);
186 :
187 31900 : if (ret == -1) {
188 0 : enum TDB_ERROR err = tdb_error(tdb);
189 0 : return map_unix_error_from_tdb(err);
190 : }
191 :
192 31702 : return 0;
193 : }
194 :
195 31753 : int server_id_db_remove(struct server_id_db *db, const char *name)
196 : {
197 188 : char *n;
198 188 : int ret;
199 :
200 31753 : n = strv_find(db->names, name);
201 31753 : if (n == NULL) {
202 0 : return ENOENT;
203 : }
204 :
205 31753 : ret = server_id_db_prune_name(db, name, db->pid);
206 31753 : if (ret != 0) {
207 740 : return ret;
208 : }
209 :
210 30949 : strv_delete(&db->names, n);
211 30949 : return 0;
212 : }
213 :
214 755728 : int server_id_db_lookup(struct server_id_db *db, const char *name,
215 : TALLOC_CTX *mem_ctx, unsigned *pnum_servers,
216 : struct server_id **pservers)
217 : {
218 755728 : struct tdb_context *tdb = db->tdb->tdb;
219 18601 : TDB_DATA key;
220 18601 : uint8_t *data;
221 18601 : size_t datalen;
222 18601 : char *ids, *id;
223 18601 : unsigned num_servers;
224 18601 : struct server_id *servers;
225 18601 : int i, ret;
226 :
227 755728 : key = string_term_tdb_data(name);
228 :
229 755728 : ret = tdb_fetch_talloc(tdb, key, mem_ctx, &data);
230 755728 : if (ret != 0) {
231 705086 : return ret;
232 : }
233 :
234 32407 : datalen = talloc_get_size(data);
235 32407 : if ((datalen == 0) || (data[datalen-1] != '\0')) {
236 0 : TALLOC_FREE(data);
237 0 : return EINVAL;
238 : }
239 :
240 32407 : ids = (char *)data;
241 32407 : num_servers = strv_count(ids);
242 :
243 32407 : servers = talloc_array(mem_ctx, struct server_id, num_servers);
244 32407 : if (servers == NULL) {
245 0 : TALLOC_FREE(data);
246 0 : return ENOMEM;
247 : }
248 :
249 32041 : i = 0;
250 :
251 64904 : for (id = ids; id != NULL; id = strv_next(ids, id)) {
252 32497 : servers[i++] = server_id_from_string(NONCLUSTER_VNN, id);
253 : }
254 :
255 32407 : TALLOC_FREE(data);
256 :
257 32407 : *pnum_servers = num_servers;
258 32407 : *pservers = servers;
259 :
260 32407 : return 0;
261 : }
262 :
263 20651 : bool server_id_db_lookup_one(struct server_id_db *db, const char *name,
264 : struct server_id *server)
265 : {
266 344 : int ret;
267 344 : unsigned num_servers;
268 344 : struct server_id *servers;
269 :
270 20651 : ret = server_id_db_lookup(db, name, db, &num_servers, &servers);
271 20651 : if (ret != 0) {
272 2 : return false;
273 : }
274 20649 : if (num_servers == 0) {
275 0 : TALLOC_FREE(servers);
276 0 : return false;
277 : }
278 20649 : *server = servers[0];
279 20649 : TALLOC_FREE(servers);
280 20649 : return true;
281 : }
282 :
283 : struct server_id_db_traverse_state {
284 : TALLOC_CTX *mem_ctx;
285 : int (*fn)(const char *name,
286 : unsigned num_servers,
287 : const struct server_id *servers,
288 : void *private_data);
289 : void *private_data;
290 : };
291 :
292 22275 : static int server_id_db_traverse_fn(struct tdb_context *tdb,
293 : TDB_DATA key, TDB_DATA data,
294 : void *private_data)
295 : {
296 22275 : struct server_id_db_traverse_state *state = private_data;
297 1150 : const char *name;
298 1150 : char *ids, *id;
299 1150 : unsigned num_servers;
300 1150 : struct server_id *servers;
301 1150 : int i, ret;
302 :
303 22275 : if (key.dsize == 0) {
304 0 : return 0;
305 : }
306 22275 : if (key.dptr[key.dsize-1] != '\0') {
307 0 : return 0;
308 : }
309 22275 : name = (const char *)key.dptr;
310 :
311 22275 : ids = (char *)talloc_memdup(state->mem_ctx, data.dptr, data.dsize);
312 22275 : if (ids == NULL) {
313 0 : return 0;
314 : }
315 :
316 22275 : num_servers = strv_count(ids);
317 22275 : servers = talloc_array(ids, struct server_id, num_servers);
318 :
319 22275 : i = 0;
320 :
321 49947 : for (id = ids; id != NULL; id = strv_next(ids, id)) {
322 26522 : servers[i++] = server_id_from_string(NONCLUSTER_VNN, id);
323 : }
324 :
325 22275 : ret = state->fn(name, num_servers, servers, state->private_data);
326 :
327 22275 : TALLOC_FREE(ids);
328 :
329 22275 : return ret;
330 : }
331 :
332 1031 : int server_id_db_traverse_read(struct server_id_db *db,
333 : int (*fn)(const char *name,
334 : unsigned num_servers,
335 : const struct server_id *servers,
336 : void *private_data),
337 : void *private_data)
338 : {
339 60 : struct server_id_db_traverse_state state;
340 60 : int ret;
341 :
342 1091 : state = (struct server_id_db_traverse_state) {
343 : .fn = fn, .private_data = private_data,
344 1031 : .mem_ctx = talloc_new(db)
345 : };
346 :
347 1031 : if (state.mem_ctx == NULL) {
348 0 : return ENOMEM;
349 : }
350 :
351 1031 : ret = tdb_traverse_read(db->tdb->tdb, server_id_db_traverse_fn,
352 : &state);
353 1031 : TALLOC_FREE(state.mem_ctx);
354 971 : return ret;
355 : }
|