s3-waf: create a smbldap.so library.
[Samba/id10ts.git] / source3 / lib / serverid.c
blob274b44b86fbabb36b3ea685ffeab795ae9486ce8
1 /*
2 Unix SMB/CIFS implementation.
3 Implementation of a reliable server_exists()
4 Copyright (C) Volker Lendecke 2010
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.
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.
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/>.
20 #include "includes.h"
21 #include "system/filesys.h"
22 #include "serverid.h"
23 #include "util_tdb.h"
24 #include "dbwrap/dbwrap.h"
25 #include "dbwrap/dbwrap_open.h"
26 #include "lib/util/tdb_wrap.h"
27 #include "lib/param/param.h"
29 struct serverid_key {
30 pid_t pid;
31 uint32_t task_id;
32 uint32_t vnn;
35 struct serverid_data {
36 uint64_t unique_id;
37 uint32_t msg_flags;
40 bool serverid_parent_init(TALLOC_CTX *mem_ctx)
42 struct tdb_wrap *db;
43 struct loadparm_context *lp_ctx;
45 lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_context());
46 if (lp_ctx == NULL) {
47 DEBUG(0, ("loadparm_init_s3 failed\n"));
48 return false;
52 * Open the tdb in the parent process (smbd) so that our
53 * CLEAR_IF_FIRST optimization in tdb_reopen_all can properly
54 * work.
57 db = tdb_wrap_open(mem_ctx, lock_path("serverid.tdb"),
58 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDWR|O_CREAT,
59 0644, lp_ctx);
60 talloc_unlink(mem_ctx, lp_ctx);
61 if (db == NULL) {
62 DEBUG(1, ("could not open serverid.tdb: %s\n",
63 strerror(errno)));
64 return false;
66 return true;
69 static struct db_context *serverid_db(void)
71 static struct db_context *db;
73 if (db != NULL) {
74 return db;
76 db = db_open(NULL, lock_path("serverid.tdb"), 0,
77 TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDWR|O_CREAT, 0644);
78 return db;
81 static void serverid_fill_key(const struct server_id *id,
82 struct serverid_key *key)
84 ZERO_STRUCTP(key);
85 key->pid = id->pid;
86 key->task_id = id->task_id;
87 key->vnn = id->vnn;
90 bool serverid_register(const struct server_id id, uint32_t msg_flags)
92 struct db_context *db;
93 struct serverid_key key;
94 struct serverid_data data;
95 struct db_record *rec;
96 TDB_DATA tdbkey, tdbdata;
97 NTSTATUS status;
98 bool ret = false;
100 db = serverid_db();
101 if (db == NULL) {
102 return false;
105 serverid_fill_key(&id, &key);
106 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
108 rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
109 if (rec == NULL) {
110 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
111 return false;
114 ZERO_STRUCT(data);
115 data.unique_id = id.unique_id;
116 data.msg_flags = msg_flags;
118 tdbdata = make_tdb_data((uint8_t *)&data, sizeof(data));
119 status = dbwrap_record_store(rec, tdbdata, 0);
120 if (!NT_STATUS_IS_OK(status)) {
121 DEBUG(1, ("Storing serverid.tdb record failed: %s\n",
122 nt_errstr(status)));
123 goto done;
125 ret = true;
126 done:
127 TALLOC_FREE(rec);
128 return ret;
131 bool serverid_register_msg_flags(const struct server_id id, bool do_reg,
132 uint32_t msg_flags)
134 struct db_context *db;
135 struct serverid_key key;
136 struct serverid_data *data;
137 struct db_record *rec;
138 TDB_DATA tdbkey;
139 TDB_DATA value;
140 NTSTATUS status;
141 bool ret = false;
143 db = serverid_db();
144 if (db == NULL) {
145 return false;
148 serverid_fill_key(&id, &key);
149 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
151 rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
152 if (rec == NULL) {
153 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
154 return false;
157 value = dbwrap_record_get_value(rec);
159 if (value.dsize != sizeof(struct serverid_data)) {
160 DEBUG(1, ("serverid record has unexpected size %d "
161 "(wanted %d)\n", (int)value.dsize,
162 (int)sizeof(struct serverid_data)));
163 goto done;
166 data = (struct serverid_data *)value.dptr;
168 if (do_reg) {
169 data->msg_flags |= msg_flags;
170 } else {
171 data->msg_flags &= ~msg_flags;
174 status = dbwrap_record_store(rec, value, 0);
175 if (!NT_STATUS_IS_OK(status)) {
176 DEBUG(1, ("Storing serverid.tdb record failed: %s\n",
177 nt_errstr(status)));
178 goto done;
180 ret = true;
181 done:
182 TALLOC_FREE(rec);
183 return ret;
186 bool serverid_deregister(struct server_id id)
188 struct db_context *db;
189 struct serverid_key key;
190 struct db_record *rec;
191 TDB_DATA tdbkey;
192 NTSTATUS status;
193 bool ret = false;
195 db = serverid_db();
196 if (db == NULL) {
197 return false;
200 serverid_fill_key(&id, &key);
201 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
203 rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
204 if (rec == NULL) {
205 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
206 return false;
209 status = dbwrap_record_delete(rec);
210 if (!NT_STATUS_IS_OK(status)) {
211 DEBUG(1, ("Deleting serverid.tdb record failed: %s\n",
212 nt_errstr(status)));
213 goto done;
215 ret = true;
216 done:
217 TALLOC_FREE(rec);
218 return ret;
221 struct serverid_exists_state {
222 const struct server_id *id;
223 bool exists;
226 static int server_exists_parse(TDB_DATA key, TDB_DATA data, void *priv)
228 struct serverid_exists_state *state =
229 (struct serverid_exists_state *)priv;
231 if (data.dsize != sizeof(struct serverid_data)) {
232 return -1;
236 * Use memcmp, not direct compare. data.dptr might not be
237 * aligned.
239 state->exists = (memcmp(&state->id->unique_id, data.dptr,
240 sizeof(state->id->unique_id)) == 0);
241 return 0;
244 bool serverid_exists(const struct server_id *id)
246 struct db_context *db;
247 struct serverid_exists_state state;
248 struct serverid_key key;
249 TDB_DATA tdbkey;
251 if (procid_is_me(id)) {
252 return true;
255 if (!process_exists(*id)) {
256 return false;
259 db = serverid_db();
260 if (db == NULL) {
261 return false;
264 serverid_fill_key(id, &key);
265 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
267 state.id = id;
268 state.exists = false;
270 if (dbwrap_parse_record(db, tdbkey, server_exists_parse, &state) != 0) {
271 return false;
273 return state.exists;
276 bool serverids_exist(const struct server_id *ids, int num_ids, bool *results)
278 struct db_context *db;
279 int i;
281 if (!processes_exist(ids, num_ids, results)) {
282 return false;
285 db = serverid_db();
286 if (db == NULL) {
287 return false;
290 for (i=0; i<num_ids; i++) {
291 struct serverid_exists_state state;
292 struct serverid_key key;
293 TDB_DATA tdbkey;
295 if (!results[i]) {
296 continue;
299 serverid_fill_key(&ids[i], &key);
300 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
302 state.id = &ids[i];
303 state.exists = false;
304 dbwrap_parse_record(db, tdbkey, server_exists_parse, &state);
305 results[i] = state.exists;
307 return true;
310 static bool serverid_rec_parse(const struct db_record *rec,
311 struct server_id *id, uint32_t *msg_flags)
313 struct serverid_key key;
314 struct serverid_data data;
315 TDB_DATA tdbkey;
316 TDB_DATA tdbdata;
318 tdbkey = dbwrap_record_get_key(rec);
319 tdbdata = dbwrap_record_get_value(rec);
321 if (tdbkey.dsize != sizeof(key)) {
322 DEBUG(1, ("Found invalid key length %d in serverid.tdb\n",
323 (int)tdbkey.dsize));
324 return false;
326 if (tdbdata.dsize != sizeof(data)) {
327 DEBUG(1, ("Found invalid value length %d in serverid.tdb\n",
328 (int)tdbdata.dsize));
329 return false;
332 memcpy(&key, tdbkey.dptr, sizeof(key));
333 memcpy(&data, tdbdata.dptr, sizeof(data));
335 id->pid = key.pid;
336 id->task_id = key.task_id;
337 id->vnn = key.vnn;
338 id->unique_id = data.unique_id;
339 *msg_flags = data.msg_flags;
340 return true;
343 struct serverid_traverse_read_state {
344 int (*fn)(const struct server_id *id, uint32_t msg_flags,
345 void *private_data);
346 void *private_data;
349 static int serverid_traverse_read_fn(struct db_record *rec, void *private_data)
351 struct serverid_traverse_read_state *state =
352 (struct serverid_traverse_read_state *)private_data;
353 struct server_id id;
354 uint32_t msg_flags;
356 if (!serverid_rec_parse(rec, &id, &msg_flags)) {
357 return 0;
359 return state->fn(&id, msg_flags,state->private_data);
362 bool serverid_traverse_read(int (*fn)(const struct server_id *id,
363 uint32_t msg_flags, void *private_data),
364 void *private_data)
366 struct db_context *db;
367 struct serverid_traverse_read_state state;
368 NTSTATUS status;
370 db = serverid_db();
371 if (db == NULL) {
372 return false;
374 state.fn = fn;
375 state.private_data = private_data;
377 status = dbwrap_traverse_read(db, serverid_traverse_read_fn, &state,
378 NULL);
379 return NT_STATUS_IS_OK(status);
382 struct serverid_traverse_state {
383 int (*fn)(struct db_record *rec, const struct server_id *id,
384 uint32_t msg_flags, void *private_data);
385 void *private_data;
388 static int serverid_traverse_fn(struct db_record *rec, void *private_data)
390 struct serverid_traverse_state *state =
391 (struct serverid_traverse_state *)private_data;
392 struct server_id id;
393 uint32_t msg_flags;
395 if (!serverid_rec_parse(rec, &id, &msg_flags)) {
396 return 0;
398 return state->fn(rec, &id, msg_flags, state->private_data);
401 bool serverid_traverse(int (*fn)(struct db_record *rec,
402 const struct server_id *id,
403 uint32_t msg_flags, void *private_data),
404 void *private_data)
406 struct db_context *db;
407 struct serverid_traverse_state state;
408 NTSTATUS status;
410 db = serverid_db();
411 if (db == NULL) {
412 return false;
414 state.fn = fn;
415 state.private_data = private_data;
417 status = dbwrap_traverse(db, serverid_traverse_fn, &state, NULL);
418 return NT_STATUS_IS_OK(status);