Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Watch dbwrap record changes
4 : Copyright (C) Volker Lendecke 2012
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 "includes.h"
21 : #include "system/filesys.h"
22 : #include "lib/util/server_id.h"
23 : #include "dbwrap/dbwrap.h"
24 : #include "dbwrap_watch.h"
25 : #include "dbwrap_open.h"
26 : #include "lib/util/util_tdb.h"
27 : #include "lib/util/tevent_ntstatus.h"
28 : #include "server_id_watch.h"
29 : #include "lib/dbwrap/dbwrap_private.h"
30 :
31 : struct dbwrap_watcher {
32 : /*
33 : * Process watching this record
34 : */
35 : struct server_id pid;
36 : /*
37 : * Individual instance inside the waiter, incremented each
38 : * time a watcher is created
39 : */
40 : uint64_t instance;
41 : };
42 :
43 : #define DBWRAP_WATCHER_BUF_LENGTH (SERVER_ID_BUF_LENGTH + sizeof(uint64_t))
44 :
45 : /*
46 : * Watched records contain a header of:
47 : *
48 : * [uint32] num_records
49 : * 0 [DBWRAP_WATCHER_BUF_LENGTH] \
50 : * 1 [DBWRAP_WATCHER_BUF_LENGTH] |
51 : * .. |- Array of watchers
52 : * (num_records-1)[DBWRAP_WATCHER_BUF_LENGTH] /
53 : *
54 : * [Remainder of record....]
55 : *
56 : * If this header is absent then this is a
57 : * fresh record of length zero (no watchers).
58 : */
59 :
60 12893698 : static bool dbwrap_watch_rec_parse(
61 : TDB_DATA data,
62 : uint8_t **pwatchers,
63 : size_t *pnum_watchers,
64 : TDB_DATA *pdata)
65 : {
66 : size_t num_watchers;
67 :
68 12893698 : if (data.dsize == 0) {
69 : /* Fresh record */
70 950410 : if (pwatchers != NULL) {
71 475145 : *pwatchers = NULL;
72 : }
73 950410 : if (pnum_watchers != NULL) {
74 475145 : *pnum_watchers = 0;
75 : }
76 950410 : if (pdata != NULL) {
77 475303 : *pdata = (TDB_DATA) { .dptr = NULL };
78 : }
79 947125 : return true;
80 : }
81 :
82 11943288 : if (data.dsize < sizeof(uint32_t)) {
83 : /* Invalid record */
84 0 : return false;
85 : }
86 :
87 11943288 : num_watchers = IVAL(data.dptr, 0);
88 :
89 11943288 : data.dptr += sizeof(uint32_t);
90 11943288 : data.dsize -= sizeof(uint32_t);
91 :
92 11943288 : if (num_watchers > data.dsize/DBWRAP_WATCHER_BUF_LENGTH) {
93 : /* Invalid record */
94 0 : return false;
95 : }
96 :
97 11943287 : if (pwatchers != NULL) {
98 3706889 : *pwatchers = data.dptr;
99 : }
100 11943287 : if (pnum_watchers != NULL) {
101 3706889 : *pnum_watchers = num_watchers;
102 : }
103 11943287 : if (pdata != NULL) {
104 8241831 : size_t watchers_len = num_watchers * DBWRAP_WATCHER_BUF_LENGTH;
105 8241831 : *pdata = (TDB_DATA) {
106 8241831 : .dptr = data.dptr + watchers_len,
107 8241831 : .dsize = data.dsize - watchers_len
108 : };
109 : }
110 :
111 11917981 : return true;
112 : }
113 :
114 3900 : static void dbwrap_watcher_get(struct dbwrap_watcher *w,
115 : const uint8_t buf[DBWRAP_WATCHER_BUF_LENGTH])
116 : {
117 3900 : server_id_get(&w->pid, buf);
118 3900 : w->instance = BVAL(buf, SERVER_ID_BUF_LENGTH);
119 3900 : }
120 :
121 3857 : static void dbwrap_watcher_put(uint8_t buf[DBWRAP_WATCHER_BUF_LENGTH],
122 : const struct dbwrap_watcher *w)
123 : {
124 3857 : server_id_put(buf, w->pid);
125 3857 : SBVAL(buf, SERVER_ID_BUF_LENGTH, w->instance);
126 3857 : }
127 :
128 1 : static void dbwrap_watch_log_invalid_record(
129 : struct db_context *db, TDB_DATA key, TDB_DATA value)
130 : {
131 1 : DBG_ERR("Found invalid record in %s\n", dbwrap_name(db));
132 1 : dump_data(1, key.dptr, key.dsize);
133 1 : dump_data(1, value.dptr, value.dsize);
134 1 : }
135 :
136 : struct db_watched_ctx {
137 : struct db_context *backend;
138 : struct messaging_context *msg;
139 : };
140 :
141 : struct db_watched_subrec {
142 : struct db_record *subrec;
143 : struct dbwrap_watcher added;
144 : };
145 :
146 : static NTSTATUS dbwrap_watched_subrec_storev(
147 : struct db_record *rec, struct db_watched_subrec *subrec,
148 : const TDB_DATA *dbufs, int num_dbufs, int flags);
149 : static NTSTATUS dbwrap_watched_subrec_delete(
150 : struct db_record *rec, struct db_watched_subrec *subrec);
151 : static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
152 : const TDB_DATA *dbufs, int num_dbufs,
153 : int flags);
154 : static NTSTATUS dbwrap_watched_delete(struct db_record *rec);
155 : static void dbwrap_watched_subrec_wakeup(
156 : struct db_record *rec, struct db_watched_subrec *subrec);
157 : static int db_watched_subrec_destructor(struct db_watched_subrec *s);
158 :
159 210625 : static struct db_record *dbwrap_watched_fetch_locked(
160 : struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
161 : {
162 210625 : struct db_watched_ctx *ctx = talloc_get_type_abort(
163 : db->private_data, struct db_watched_ctx);
164 : struct db_record *rec;
165 : struct db_watched_subrec *subrec;
166 : TDB_DATA subrec_value;
167 : bool ok;
168 :
169 210625 : rec = talloc_zero(mem_ctx, struct db_record);
170 210625 : if (rec == NULL) {
171 0 : return NULL;
172 : }
173 210625 : subrec = talloc_zero(rec, struct db_watched_subrec);
174 210625 : if (subrec == NULL) {
175 0 : TALLOC_FREE(rec);
176 0 : return NULL;
177 : }
178 210625 : talloc_set_destructor(subrec, db_watched_subrec_destructor);
179 210625 : rec->private_data = subrec;
180 :
181 210625 : subrec->subrec = dbwrap_fetch_locked(ctx->backend, subrec, key);
182 210625 : if (subrec->subrec == NULL) {
183 0 : TALLOC_FREE(rec);
184 0 : return NULL;
185 : }
186 :
187 210625 : rec->db = db;
188 210625 : rec->key = dbwrap_record_get_key(subrec->subrec);
189 210625 : rec->storev = dbwrap_watched_storev;
190 210625 : rec->delete_rec = dbwrap_watched_delete;
191 :
192 210625 : subrec_value = dbwrap_record_get_value(subrec->subrec);
193 :
194 210625 : ok = dbwrap_watch_rec_parse(subrec_value, NULL, NULL, &rec->value);
195 210625 : if (!ok) {
196 0 : dbwrap_watch_log_invalid_record(db, rec->key, subrec_value);
197 : /* wipe invalid data */
198 0 : rec->value = (TDB_DATA) { .dptr = NULL, .dsize = 0 };
199 : }
200 210625 : rec->value_valid = true;
201 :
202 210625 : return rec;
203 : }
204 :
205 : struct dbwrap_watched_add_watcher_state {
206 : struct dbwrap_watcher w;
207 : NTSTATUS status;
208 : };
209 :
210 3857 : static void dbwrap_watched_add_watcher(
211 : struct db_record *rec,
212 : TDB_DATA value,
213 : void *private_data)
214 : {
215 3857 : struct dbwrap_watched_add_watcher_state *state = private_data;
216 3857 : size_t num_watchers = 0;
217 : bool ok;
218 :
219 : uint8_t num_watchers_buf[4];
220 : uint8_t add_buf[DBWRAP_WATCHER_BUF_LENGTH];
221 :
222 3857 : TDB_DATA dbufs[4] = {
223 : {
224 : .dptr = num_watchers_buf,
225 : .dsize = sizeof(num_watchers_buf),
226 : },
227 : { 0 }, /* filled in with existing watchers */
228 : {
229 : .dptr = add_buf,
230 : .dsize = sizeof(add_buf),
231 : },
232 : { 0 }, /* filled in with existing data */
233 : };
234 :
235 3857 : dbwrap_watcher_put(add_buf, &state->w);
236 :
237 3857 : ok = dbwrap_watch_rec_parse(
238 : value, &dbufs[1].dptr, &num_watchers, &dbufs[3]);
239 3857 : if (!ok) {
240 0 : struct db_context *db = dbwrap_record_get_db(rec);
241 0 : TDB_DATA key = dbwrap_record_get_key(rec);
242 :
243 0 : dbwrap_watch_log_invalid_record(db, key, value);
244 :
245 : /* wipe invalid data */
246 0 : num_watchers = 0;
247 0 : dbufs[3] = (TDB_DATA) { .dptr = NULL, .dsize = 0 };
248 : }
249 :
250 3857 : dbufs[1].dsize = num_watchers * DBWRAP_WATCHER_BUF_LENGTH;
251 :
252 3857 : if (num_watchers >= UINT32_MAX) {
253 0 : DBG_DEBUG("Can't handle %zu watchers\n",
254 : num_watchers+1);
255 0 : state->status = NT_STATUS_INSUFFICIENT_RESOURCES;
256 0 : return;
257 : }
258 :
259 3857 : num_watchers += 1;
260 3857 : SIVAL(num_watchers_buf, 0, num_watchers);
261 :
262 3857 : state->status = dbwrap_record_storev(rec, dbufs, ARRAY_SIZE(dbufs), 0);
263 : }
264 :
265 4182150 : static int db_watched_subrec_destructor(struct db_watched_subrec *s)
266 : {
267 4182150 : struct dbwrap_watched_add_watcher_state state = { .w = s->added };
268 4182150 : struct db_context *backend = dbwrap_record_get_db(s->subrec);
269 : NTSTATUS status;
270 :
271 4182150 : if (s->added.pid.pid == 0) {
272 4167945 : return 0;
273 : }
274 :
275 3857 : status = dbwrap_do_locked(
276 3857 : backend, s->subrec->key, dbwrap_watched_add_watcher, &state);
277 3857 : if (!NT_STATUS_IS_OK(status)) {
278 0 : DBG_WARNING("dbwrap_do_locked failed: %s\n",
279 : nt_errstr(status));
280 0 : return 0;
281 : }
282 3857 : if (!NT_STATUS_IS_OK(state.status)) {
283 0 : DBG_WARNING("dbwrap_watched_add_watcher failed: %s\n",
284 : nt_errstr(state.status));
285 0 : return 0;
286 : }
287 3841 : return 0;
288 : }
289 :
290 : struct dbwrap_watched_subrec_wakeup_state {
291 : struct messaging_context *msg_ctx;
292 : };
293 : static void dbwrap_watched_subrec_wakeup_fn(
294 : struct db_record *rec,
295 : TDB_DATA value,
296 : void *private_data);
297 :
298 : struct dbwrap_watched_do_locked_state {
299 : struct db_context *db;
300 : void (*fn)(struct db_record *rec,
301 : TDB_DATA value,
302 : void *private_data);
303 : void *private_data;
304 :
305 : struct db_watched_subrec subrec;
306 :
307 : /*
308 : * This contains the initial value we got
309 : * passed to dbwrap_watched_do_locked_fn()
310 : *
311 : * It's only used in order to pass it
312 : * to dbwrap_watched_subrec_wakeup_fn()
313 : * in dbwrap_watched_do_locked_{storev,delete}()
314 : *
315 : * It gets cleared after the first call to
316 : * dbwrap_watched_subrec_wakeup_fn() as we
317 : * only need to wakeup once per dbwrap_do_locked().
318 : */
319 : TDB_DATA wakeup_value;
320 :
321 : NTSTATUS status;
322 : };
323 :
324 3540992 : static NTSTATUS dbwrap_watched_do_locked_storev(
325 : struct db_record *rec, const TDB_DATA *dbufs, int num_dbufs,
326 : int flags)
327 : {
328 3540992 : struct dbwrap_watched_do_locked_state *state = rec->private_data;
329 3540992 : struct db_watched_subrec *subrec = &state->subrec;
330 3540992 : struct db_watched_ctx *ctx = talloc_get_type_abort(
331 : state->db->private_data, struct db_watched_ctx);
332 3540992 : struct dbwrap_watched_subrec_wakeup_state wakeup_state = {
333 3540992 : .msg_ctx = ctx->msg,
334 : };
335 : NTSTATUS status;
336 :
337 : /*
338 : * Wakeup only needs to happen once.
339 : * so we clear state->wakeup_value after the first run
340 : */
341 3540992 : dbwrap_watched_subrec_wakeup_fn(rec, state->wakeup_value, &wakeup_state);
342 3540992 : state->wakeup_value = (TDB_DATA) { .dsize = 0, };
343 :
344 3540992 : status = dbwrap_watched_subrec_storev(rec, subrec, dbufs, num_dbufs,
345 : flags);
346 3540992 : return status;
347 : }
348 :
349 426950 : static NTSTATUS dbwrap_watched_do_locked_delete(struct db_record *rec)
350 : {
351 426950 : struct dbwrap_watched_do_locked_state *state = rec->private_data;
352 426950 : struct db_watched_subrec *subrec = &state->subrec;
353 426950 : struct db_watched_ctx *ctx = talloc_get_type_abort(
354 : state->db->private_data, struct db_watched_ctx);
355 426950 : struct dbwrap_watched_subrec_wakeup_state wakeup_state = {
356 426950 : .msg_ctx = ctx->msg,
357 : };
358 : NTSTATUS status;
359 :
360 : /*
361 : * Wakeup only needs to happen once.
362 : * so we clear state->wakeup_value after the first run
363 : */
364 426950 : dbwrap_watched_subrec_wakeup_fn(rec, state->wakeup_value, &wakeup_state);
365 426950 : state->wakeup_value = (TDB_DATA) { .dsize = 0, };
366 :
367 426950 : status = dbwrap_watched_subrec_delete(rec, subrec);
368 426950 : return status;
369 : }
370 :
371 3971526 : static void dbwrap_watched_do_locked_fn(
372 : struct db_record *subrec,
373 : TDB_DATA subrec_value,
374 : void *private_data)
375 : {
376 3971526 : struct dbwrap_watched_do_locked_state *state =
377 : (struct dbwrap_watched_do_locked_state *)private_data;
378 3971526 : TDB_DATA value = {0};
379 7943052 : struct db_record rec = {
380 3971526 : .db = state->db,
381 529638 : .key = dbwrap_record_get_key(subrec),
382 : .value_valid = true,
383 : .storev = dbwrap_watched_do_locked_storev,
384 : .delete_rec = dbwrap_watched_do_locked_delete,
385 : .private_data = state
386 : };
387 : bool ok;
388 :
389 3971526 : state->subrec = (struct db_watched_subrec) {
390 : .subrec = subrec
391 : };
392 3971526 : state->wakeup_value = subrec_value;
393 :
394 3971526 : ok = dbwrap_watch_rec_parse(subrec_value, NULL, NULL, &value);
395 3971526 : if (!ok) {
396 0 : dbwrap_watch_log_invalid_record(rec.db, rec.key, subrec_value);
397 : /* wipe invalid data */
398 0 : value = (TDB_DATA) { .dptr = NULL, .dsize = 0 };
399 : }
400 :
401 3971526 : state->fn(&rec, value, state->private_data);
402 :
403 3971526 : db_watched_subrec_destructor(&state->subrec);
404 3971526 : }
405 :
406 3971526 : static NTSTATUS dbwrap_watched_do_locked(struct db_context *db, TDB_DATA key,
407 : void (*fn)(struct db_record *rec,
408 : TDB_DATA value,
409 : void *private_data),
410 : void *private_data)
411 : {
412 3971526 : struct db_watched_ctx *ctx = talloc_get_type_abort(
413 : db->private_data, struct db_watched_ctx);
414 3971526 : struct dbwrap_watched_do_locked_state state = {
415 : .db = db, .fn = fn, .private_data = private_data
416 : };
417 : NTSTATUS status;
418 :
419 3971526 : status = dbwrap_do_locked(
420 : ctx->backend, key, dbwrap_watched_do_locked_fn, &state);
421 3971526 : if (!NT_STATUS_IS_OK(status)) {
422 0 : DBG_DEBUG("dbwrap_do_locked returned %s\n", nt_errstr(status));
423 0 : return status;
424 : }
425 :
426 3971526 : DBG_DEBUG("dbwrap_watched_do_locked_fn returned %s\n",
427 : nt_errstr(state.status));
428 :
429 3971526 : return state.status;
430 : }
431 :
432 4176563 : static void dbwrap_watched_subrec_wakeup_fn(
433 : struct db_record *rec,
434 : TDB_DATA value,
435 : void *private_data)
436 : {
437 4176563 : struct dbwrap_watched_subrec_wakeup_state *state = private_data;
438 : uint8_t *watchers;
439 4176563 : size_t num_watchers = 0;
440 : size_t i;
441 : bool ok;
442 :
443 4176563 : ok = dbwrap_watch_rec_parse(value, &watchers, &num_watchers, NULL);
444 4176563 : if (!ok) {
445 0 : struct db_context *db = dbwrap_record_get_db(rec);
446 0 : TDB_DATA key = dbwrap_record_get_key(rec);
447 0 : dbwrap_watch_log_invalid_record(db, key, value);
448 0 : return;
449 : }
450 :
451 4176563 : if (num_watchers == 0) {
452 4174403 : DBG_DEBUG("No watchers\n");
453 4164065 : return;
454 : }
455 :
456 4443 : for (i=0; i<num_watchers; i++) {
457 : struct dbwrap_watcher watcher;
458 : struct server_id_buf tmp;
459 : uint8_t instance_buf[8];
460 : NTSTATUS status;
461 :
462 4468 : dbwrap_watcher_get(
463 2290 : &watcher, watchers + i*DBWRAP_WATCHER_BUF_LENGTH);
464 :
465 2290 : DBG_DEBUG("Alerting %s:%"PRIu64"\n",
466 : server_id_str_buf(watcher.pid, &tmp),
467 : watcher.instance);
468 :
469 2290 : SBVAL(instance_buf, 0, watcher.instance);
470 :
471 2290 : status = messaging_send_buf(
472 : state->msg_ctx,
473 : watcher.pid,
474 : MSG_DBWRAP_MODIFIED,
475 : instance_buf,
476 : sizeof(instance_buf));
477 2290 : if (!NT_STATUS_IS_OK(status)) {
478 0 : DBG_DEBUG("messaging_send_buf to %s failed: %s\n",
479 : server_id_str_buf(watcher.pid, &tmp),
480 : nt_errstr(status));
481 : }
482 : }
483 : }
484 :
485 4176563 : static void dbwrap_watched_subrec_wakeup(
486 : struct db_record *rec, struct db_watched_subrec *subrec)
487 : {
488 4176563 : struct db_context *backend = dbwrap_record_get_db(subrec->subrec);
489 4176563 : struct db_context *db = dbwrap_record_get_db(rec);
490 4176563 : struct db_watched_ctx *ctx = talloc_get_type_abort(
491 : db->private_data, struct db_watched_ctx);
492 4176563 : struct dbwrap_watched_subrec_wakeup_state state = {
493 4176563 : .msg_ctx = ctx->msg,
494 : };
495 : NTSTATUS status;
496 :
497 4176563 : if (rec->storev == dbwrap_watched_do_locked_storev) {
498 : /*
499 : * This is handled in the caller,
500 : * as we need to avoid recursion
501 : * into dbwrap_do_locked().
502 : */
503 3967942 : return;
504 : }
505 :
506 208621 : status = dbwrap_do_locked(
507 : backend,
508 208621 : subrec->subrec->key,
509 : dbwrap_watched_subrec_wakeup_fn,
510 : &state);
511 208621 : if (!NT_STATUS_IS_OK(status)) {
512 0 : DBG_DEBUG("dbwrap_record_modify failed: %s\n",
513 : nt_errstr(status));
514 : }
515 : }
516 :
517 3701500 : static NTSTATUS dbwrap_watched_subrec_storev(
518 : struct db_record *rec, struct db_watched_subrec *subrec,
519 : const TDB_DATA *dbufs, int num_dbufs, int flags)
520 3701500 : {
521 3701500 : uint8_t num_watchers_buf[4] = { 0 };
522 3701500 : TDB_DATA my_dbufs[num_dbufs+1];
523 : NTSTATUS status;
524 :
525 3701500 : dbwrap_watched_subrec_wakeup(rec, subrec);
526 :
527 : /*
528 : * Watchers only informed once, set num_watchers to 0
529 : */
530 3701500 : my_dbufs[0] = (TDB_DATA) {
531 : .dptr = num_watchers_buf, .dsize = sizeof(num_watchers_buf),
532 : };
533 3701500 : if (num_dbufs != 0) {
534 3701500 : memcpy(my_dbufs+1, dbufs, num_dbufs * sizeof(*dbufs));
535 : }
536 :
537 3701500 : status = dbwrap_record_storev(
538 3701500 : subrec->subrec, my_dbufs, ARRAY_SIZE(my_dbufs), flags);
539 3701500 : return status;
540 : }
541 :
542 160508 : static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
543 : const TDB_DATA *dbufs, int num_dbufs,
544 : int flags)
545 : {
546 160508 : struct db_watched_subrec *subrec = talloc_get_type_abort(
547 : rec->private_data, struct db_watched_subrec);
548 : NTSTATUS status;
549 :
550 160508 : status = dbwrap_watched_subrec_storev(rec, subrec, dbufs, num_dbufs,
551 : flags);
552 160508 : return status;
553 : }
554 :
555 475063 : static NTSTATUS dbwrap_watched_subrec_delete(
556 : struct db_record *rec, struct db_watched_subrec *subrec)
557 : {
558 : NTSTATUS status;
559 :
560 475063 : dbwrap_watched_subrec_wakeup(rec, subrec);
561 :
562 : /*
563 : * Watchers were informed, we can throw away the record now
564 : */
565 475063 : status = dbwrap_record_delete(subrec->subrec);
566 475063 : return status;
567 : }
568 :
569 48113 : static NTSTATUS dbwrap_watched_delete(struct db_record *rec)
570 : {
571 48113 : struct db_watched_subrec *subrec = talloc_get_type_abort(
572 : rec->private_data, struct db_watched_subrec);
573 : NTSTATUS status;
574 :
575 48113 : status = dbwrap_watched_subrec_delete(rec, subrec);
576 48113 : return status;
577 : }
578 :
579 : struct dbwrap_watched_traverse_state {
580 : int (*fn)(struct db_record *rec, void *private_data);
581 : void *private_data;
582 : };
583 :
584 17885 : static int dbwrap_watched_traverse_fn(struct db_record *rec,
585 : void *private_data)
586 : {
587 17885 : struct dbwrap_watched_traverse_state *state = private_data;
588 17885 : struct db_record prec = *rec;
589 : bool ok;
590 :
591 17885 : ok = dbwrap_watch_rec_parse(rec->value, NULL, NULL, &prec.value);
592 17885 : if (!ok) {
593 0 : return 0;
594 : }
595 17885 : prec.value_valid = true;
596 :
597 17885 : return state->fn(&prec, state->private_data);
598 : }
599 :
600 0 : static int dbwrap_watched_traverse(struct db_context *db,
601 : int (*fn)(struct db_record *rec,
602 : void *private_data),
603 : void *private_data)
604 : {
605 0 : struct db_watched_ctx *ctx = talloc_get_type_abort(
606 : db->private_data, struct db_watched_ctx);
607 0 : struct dbwrap_watched_traverse_state state = {
608 : .fn = fn, .private_data = private_data };
609 : NTSTATUS status;
610 : int ret;
611 :
612 0 : status = dbwrap_traverse(
613 : ctx->backend, dbwrap_watched_traverse_fn, &state, &ret);
614 0 : if (!NT_STATUS_IS_OK(status)) {
615 0 : return -1;
616 : }
617 0 : return ret;
618 : }
619 :
620 5972 : static int dbwrap_watched_traverse_read(struct db_context *db,
621 : int (*fn)(struct db_record *rec,
622 : void *private_data),
623 : void *private_data)
624 : {
625 5972 : struct db_watched_ctx *ctx = talloc_get_type_abort(
626 : db->private_data, struct db_watched_ctx);
627 5972 : struct dbwrap_watched_traverse_state state = {
628 : .fn = fn, .private_data = private_data };
629 : NTSTATUS status;
630 : int ret;
631 :
632 5972 : status = dbwrap_traverse_read(
633 : ctx->backend, dbwrap_watched_traverse_fn, &state, &ret);
634 5972 : if (!NT_STATUS_IS_OK(status)) {
635 0 : return -1;
636 : }
637 5972 : return ret;
638 : }
639 :
640 175807 : static int dbwrap_watched_get_seqnum(struct db_context *db)
641 : {
642 175807 : struct db_watched_ctx *ctx = talloc_get_type_abort(
643 : db->private_data, struct db_watched_ctx);
644 175807 : return dbwrap_get_seqnum(ctx->backend);
645 : }
646 :
647 0 : static int dbwrap_watched_transaction_start(struct db_context *db)
648 : {
649 0 : struct db_watched_ctx *ctx = talloc_get_type_abort(
650 : db->private_data, struct db_watched_ctx);
651 0 : return dbwrap_transaction_start(ctx->backend);
652 : }
653 :
654 0 : static int dbwrap_watched_transaction_commit(struct db_context *db)
655 : {
656 0 : struct db_watched_ctx *ctx = talloc_get_type_abort(
657 : db->private_data, struct db_watched_ctx);
658 0 : return dbwrap_transaction_commit(ctx->backend);
659 : }
660 :
661 0 : static int dbwrap_watched_transaction_cancel(struct db_context *db)
662 : {
663 0 : struct db_watched_ctx *ctx = talloc_get_type_abort(
664 : db->private_data, struct db_watched_ctx);
665 0 : return dbwrap_transaction_cancel(ctx->backend);
666 : }
667 :
668 : struct dbwrap_watched_parse_record_state {
669 : struct db_context *db;
670 : void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data);
671 : void *private_data;
672 : bool ok;
673 : };
674 :
675 4511628 : static void dbwrap_watched_parse_record_parser(TDB_DATA key, TDB_DATA data,
676 : void *private_data)
677 : {
678 4511628 : struct dbwrap_watched_parse_record_state *state = private_data;
679 : TDB_DATA userdata;
680 :
681 4511628 : state->ok = dbwrap_watch_rec_parse(data, NULL, NULL, &userdata);
682 4511628 : if (!state->ok) {
683 1 : dbwrap_watch_log_invalid_record(state->db, key, data);
684 1 : return;
685 : }
686 :
687 4511627 : state->parser(key, userdata, state->private_data);
688 : }
689 :
690 4933937 : static NTSTATUS dbwrap_watched_parse_record(
691 : struct db_context *db, TDB_DATA key,
692 : void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data),
693 : void *private_data)
694 : {
695 4933937 : struct db_watched_ctx *ctx = talloc_get_type_abort(
696 : db->private_data, struct db_watched_ctx);
697 4933937 : struct dbwrap_watched_parse_record_state state = {
698 : .db = db,
699 : .parser = parser,
700 : .private_data = private_data,
701 : };
702 : NTSTATUS status;
703 :
704 4933937 : status = dbwrap_parse_record(
705 : ctx->backend, key, dbwrap_watched_parse_record_parser, &state);
706 4933937 : if (!NT_STATUS_IS_OK(status)) {
707 422309 : return status;
708 : }
709 4511628 : if (!state.ok) {
710 1 : return NT_STATUS_NOT_FOUND;
711 : }
712 4511627 : return NT_STATUS_OK;
713 : }
714 :
715 : static void dbwrap_watched_parse_record_done(struct tevent_req *subreq);
716 :
717 0 : static struct tevent_req *dbwrap_watched_parse_record_send(
718 : TALLOC_CTX *mem_ctx,
719 : struct tevent_context *ev,
720 : struct db_context *db,
721 : TDB_DATA key,
722 : void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data),
723 : void *private_data,
724 : enum dbwrap_req_state *req_state)
725 : {
726 0 : struct db_watched_ctx *ctx = talloc_get_type_abort(
727 : db->private_data, struct db_watched_ctx);
728 0 : struct tevent_req *req = NULL;
729 0 : struct tevent_req *subreq = NULL;
730 0 : struct dbwrap_watched_parse_record_state *state = NULL;
731 :
732 0 : req = tevent_req_create(mem_ctx, &state,
733 : struct dbwrap_watched_parse_record_state);
734 0 : if (req == NULL) {
735 0 : *req_state = DBWRAP_REQ_ERROR;
736 0 : return NULL;
737 : }
738 :
739 0 : *state = (struct dbwrap_watched_parse_record_state) {
740 : .parser = parser,
741 : .private_data = private_data,
742 : .ok = true,
743 : };
744 :
745 0 : subreq = dbwrap_parse_record_send(state,
746 : ev,
747 : ctx->backend,
748 : key,
749 : dbwrap_watched_parse_record_parser,
750 : state,
751 : req_state);
752 0 : if (tevent_req_nomem(subreq, req)) {
753 0 : *req_state = DBWRAP_REQ_ERROR;
754 0 : return tevent_req_post(req, ev);
755 : }
756 :
757 0 : tevent_req_set_callback(subreq, dbwrap_watched_parse_record_done, req);
758 0 : return req;
759 : }
760 :
761 0 : static void dbwrap_watched_parse_record_done(struct tevent_req *subreq)
762 : {
763 0 : struct tevent_req *req = tevent_req_callback_data(
764 : subreq, struct tevent_req);
765 0 : struct dbwrap_watched_parse_record_state *state = tevent_req_data(
766 : req, struct dbwrap_watched_parse_record_state);
767 : NTSTATUS status;
768 :
769 0 : status = dbwrap_parse_record_recv(subreq);
770 0 : TALLOC_FREE(subreq);
771 0 : if (tevent_req_nterror(req, status)) {
772 0 : return;
773 : }
774 :
775 0 : if (!state->ok) {
776 0 : tevent_req_nterror(req, NT_STATUS_NOT_FOUND);
777 0 : return;
778 : }
779 :
780 0 : tevent_req_done(req);
781 0 : return;
782 : }
783 :
784 0 : static NTSTATUS dbwrap_watched_parse_record_recv(struct tevent_req *req)
785 : {
786 : NTSTATUS status;
787 :
788 0 : if (tevent_req_is_nterror(req, &status)) {
789 0 : tevent_req_received(req);
790 0 : return status;
791 : }
792 :
793 0 : tevent_req_received(req);
794 0 : return NT_STATUS_OK;
795 : }
796 :
797 0 : static int dbwrap_watched_exists(struct db_context *db, TDB_DATA key)
798 : {
799 0 : struct db_watched_ctx *ctx = talloc_get_type_abort(
800 : db->private_data, struct db_watched_ctx);
801 :
802 0 : return dbwrap_exists(ctx->backend, key);
803 : }
804 :
805 0 : static size_t dbwrap_watched_id(struct db_context *db, uint8_t *id,
806 : size_t idlen)
807 : {
808 0 : struct db_watched_ctx *ctx = talloc_get_type_abort(
809 : db->private_data, struct db_watched_ctx);
810 :
811 0 : return dbwrap_db_id(ctx->backend, id, idlen);
812 : }
813 :
814 0 : static void dbwrap_watched_wakeup_fn(
815 : struct db_record *rec,
816 : TDB_DATA value,
817 : void *private_data)
818 : {
819 0 : uint8_t num_watchers_buf[4] = { 0 };
820 0 : TDB_DATA dbufs[2] = {
821 : {
822 : .dptr = num_watchers_buf,
823 : .dsize = sizeof(num_watchers_buf),
824 : },
825 : { 0 }, /* filled in with existing data */
826 : };
827 : NTSTATUS status;
828 : bool ok;
829 :
830 0 : dbwrap_watched_subrec_wakeup_fn(rec, value, private_data);
831 :
832 : /*
833 : * Watchers are informed only once: Store the existing data
834 : * without any watchers
835 : */
836 :
837 0 : ok = dbwrap_watch_rec_parse(value, NULL, NULL, &dbufs[1]);
838 0 : if (!ok) {
839 0 : DBG_DEBUG("dbwrap_watch_rec_parse failed\n");
840 0 : return;
841 : }
842 :
843 0 : status = dbwrap_record_storev(rec, dbufs, ARRAY_SIZE(dbufs), 0);
844 0 : if (!NT_STATUS_IS_OK(status)) {
845 0 : DBG_DEBUG("dbwrap_record_storev() failed: %s\n",
846 : nt_errstr(status));
847 : }
848 : }
849 :
850 0 : void dbwrap_watched_wakeup(struct db_record *rec)
851 : {
852 0 : struct db_context *db = dbwrap_record_get_db(rec);
853 0 : struct db_watched_ctx *ctx = talloc_get_type_abort(
854 : db->private_data, struct db_watched_ctx);
855 0 : struct dbwrap_watched_subrec_wakeup_state state = {
856 0 : .msg_ctx = ctx->msg,
857 : };
858 : NTSTATUS status;
859 :
860 0 : status = dbwrap_do_locked(
861 : ctx->backend, rec->key, dbwrap_watched_wakeup_fn, &state);
862 0 : if (!NT_STATUS_IS_OK(status)) {
863 0 : DBG_DEBUG("dbwrap_do_locked failed: %s\n",
864 : nt_errstr(status));
865 : }
866 0 : }
867 :
868 434 : struct db_context *db_open_watched(TALLOC_CTX *mem_ctx,
869 : struct db_context **backend,
870 : struct messaging_context *msg)
871 : {
872 : struct db_context *db;
873 : struct db_watched_ctx *ctx;
874 :
875 434 : db = talloc_zero(mem_ctx, struct db_context);
876 434 : if (db == NULL) {
877 0 : return NULL;
878 : }
879 434 : ctx = talloc_zero(db, struct db_watched_ctx);
880 434 : if (ctx == NULL) {
881 0 : TALLOC_FREE(db);
882 0 : return NULL;
883 : }
884 434 : db->private_data = ctx;
885 :
886 434 : ctx->msg = msg;
887 :
888 434 : ctx->backend = talloc_move(ctx, backend);
889 434 : db->lock_order = ctx->backend->lock_order;
890 434 : ctx->backend->lock_order = DBWRAP_LOCK_ORDER_NONE;
891 :
892 434 : db->fetch_locked = dbwrap_watched_fetch_locked;
893 434 : db->do_locked = dbwrap_watched_do_locked;
894 434 : db->traverse = dbwrap_watched_traverse;
895 434 : db->traverse_read = dbwrap_watched_traverse_read;
896 434 : db->get_seqnum = dbwrap_watched_get_seqnum;
897 434 : db->transaction_start = dbwrap_watched_transaction_start;
898 434 : db->transaction_commit = dbwrap_watched_transaction_commit;
899 434 : db->transaction_cancel = dbwrap_watched_transaction_cancel;
900 434 : db->parse_record = dbwrap_watched_parse_record;
901 434 : db->parse_record_send = dbwrap_watched_parse_record_send;
902 434 : db->parse_record_recv = dbwrap_watched_parse_record_recv;
903 434 : db->exists = dbwrap_watched_exists;
904 434 : db->id = dbwrap_watched_id;
905 434 : db->name = dbwrap_name(ctx->backend);
906 :
907 434 : return db;
908 : }
909 :
910 : struct dbwrap_watched_watch_state {
911 : struct db_context *db;
912 : TDB_DATA key;
913 : struct dbwrap_watcher watcher;
914 : struct server_id blocker;
915 : bool blockerdead;
916 : };
917 :
918 : static bool dbwrap_watched_msg_filter(struct messaging_rec *rec,
919 : void *private_data);
920 : static void dbwrap_watched_watch_done(struct tevent_req *subreq);
921 : static void dbwrap_watched_watch_blocker_died(struct tevent_req *subreq);
922 : static int dbwrap_watched_watch_state_destructor(
923 : struct dbwrap_watched_watch_state *state);
924 :
925 3859 : struct tevent_req *dbwrap_watched_watch_send(TALLOC_CTX *mem_ctx,
926 : struct tevent_context *ev,
927 : struct db_record *rec,
928 : struct server_id blocker)
929 : {
930 3859 : struct db_context *db = dbwrap_record_get_db(rec);
931 3859 : struct db_watched_ctx *ctx = talloc_get_type_abort(
932 : db->private_data, struct db_watched_ctx);
933 3859 : struct db_watched_subrec *subrec = NULL;
934 : struct tevent_req *req, *subreq;
935 : struct dbwrap_watched_watch_state *state;
936 :
937 : static uint64_t instance = 1;
938 :
939 3859 : req = tevent_req_create(mem_ctx, &state,
940 : struct dbwrap_watched_watch_state);
941 3859 : if (req == NULL) {
942 0 : return NULL;
943 : }
944 3859 : state->db = db;
945 3859 : state->blocker = blocker;
946 :
947 3859 : if (ctx->msg == NULL) {
948 0 : tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
949 0 : return tevent_req_post(req, ev);
950 : }
951 :
952 : /*
953 : * Figure out whether we're called as part of do_locked. If
954 : * so, we can't use talloc_get_type_abort, the
955 : * db_watched_subrec is stack-allocated in that case.
956 : */
957 :
958 3859 : if (rec->storev == dbwrap_watched_storev) {
959 1046 : subrec = talloc_get_type_abort(rec->private_data,
960 : struct db_watched_subrec);
961 : }
962 3859 : if (rec->storev == dbwrap_watched_do_locked_storev) {
963 : struct dbwrap_watched_do_locked_state *do_locked_state;
964 2813 : do_locked_state = rec->private_data;
965 2813 : subrec = &do_locked_state->subrec;
966 : }
967 3859 : if (subrec == NULL) {
968 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
969 0 : return tevent_req_post(req, ev);
970 : }
971 3859 : if (subrec->added.pid.pid != 0) {
972 1 : tevent_req_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
973 1 : return tevent_req_post(req, ev);
974 : }
975 :
976 7716 : state->watcher = (struct dbwrap_watcher) {
977 3858 : .pid = messaging_server_id(ctx->msg),
978 3858 : .instance = instance++,
979 : };
980 3858 : subrec->added = state->watcher;
981 :
982 3858 : state->key = tdb_data_talloc_copy(state, rec->key);
983 3858 : if (tevent_req_nomem(state->key.dptr, req)) {
984 0 : return tevent_req_post(req, ev);
985 : }
986 :
987 3858 : subreq = messaging_filtered_read_send(
988 : state, ev, ctx->msg, dbwrap_watched_msg_filter, state);
989 3858 : if (tevent_req_nomem(subreq, req)) {
990 0 : return tevent_req_post(req, ev);
991 : }
992 3858 : tevent_req_set_callback(subreq, dbwrap_watched_watch_done, req);
993 :
994 3858 : talloc_set_destructor(state, dbwrap_watched_watch_state_destructor);
995 :
996 3858 : if (blocker.pid != 0) {
997 2623 : subreq = server_id_watch_send(state, ev, blocker);
998 2623 : if (tevent_req_nomem(subreq, req)) {
999 0 : return tevent_req_post(req, ev);
1000 : }
1001 2623 : tevent_req_set_callback(
1002 : subreq, dbwrap_watched_watch_blocker_died, req);
1003 : }
1004 :
1005 3841 : return req;
1006 : }
1007 :
1008 4 : static void dbwrap_watched_watch_blocker_died(struct tevent_req *subreq)
1009 : {
1010 4 : struct tevent_req *req = tevent_req_callback_data(
1011 : subreq, struct tevent_req);
1012 4 : struct dbwrap_watched_watch_state *state = tevent_req_data(
1013 : req, struct dbwrap_watched_watch_state);
1014 : int ret;
1015 :
1016 4 : ret = server_id_watch_recv(subreq, NULL);
1017 4 : TALLOC_FREE(subreq);
1018 4 : if (ret != 0) {
1019 0 : tevent_req_nterror(req, map_nt_error_from_unix(ret));
1020 0 : return;
1021 : }
1022 4 : state->blockerdead = true;
1023 4 : tevent_req_done(req);
1024 : }
1025 :
1026 1614 : static void dbwrap_watched_watch_state_destructor_fn(
1027 : struct db_record *rec,
1028 : TDB_DATA value,
1029 : void *private_data)
1030 : {
1031 1614 : struct dbwrap_watched_watch_state *state = talloc_get_type_abort(
1032 : private_data, struct dbwrap_watched_watch_state);
1033 : uint8_t *watchers;
1034 1614 : size_t num_watchers = 0;
1035 : size_t i;
1036 : bool ok;
1037 : NTSTATUS status;
1038 :
1039 : uint8_t num_watchers_buf[4];
1040 :
1041 1614 : TDB_DATA dbufs[4] = {
1042 : {
1043 : .dptr = num_watchers_buf,
1044 : .dsize = sizeof(num_watchers_buf),
1045 : },
1046 : { 0 }, /* watchers "before" state->w */
1047 : { 0 }, /* watchers "behind" state->w */
1048 : { 0 }, /* filled in with data */
1049 : };
1050 :
1051 1614 : ok = dbwrap_watch_rec_parse(
1052 : value, &watchers, &num_watchers, &dbufs[3]);
1053 1614 : if (!ok) {
1054 0 : status = dbwrap_record_delete(rec);
1055 0 : if (!NT_STATUS_IS_OK(status)) {
1056 0 : DBG_DEBUG("dbwrap_record_delete failed: %s\n",
1057 : nt_errstr(status));
1058 : }
1059 50 : return;
1060 : }
1061 :
1062 1650 : for (i=0; i<num_watchers; i++) {
1063 : struct dbwrap_watcher watcher;
1064 :
1065 2968 : dbwrap_watcher_get(
1066 1610 : &watcher, watchers + i*DBWRAP_WATCHER_BUF_LENGTH);
1067 :
1068 3174 : if ((state->watcher.instance == watcher.instance) &&
1069 1564 : server_id_equal(&state->watcher.pid, &watcher.pid)) {
1070 1556 : break;
1071 : }
1072 : }
1073 :
1074 1614 : if (i == num_watchers) {
1075 : struct server_id_buf buf;
1076 50 : DBG_DEBUG("Watcher %s:%"PRIu64" not found\n",
1077 : server_id_str_buf(state->watcher.pid, &buf),
1078 : state->watcher.instance);
1079 48 : return;
1080 : }
1081 :
1082 1564 : if (i > 0) {
1083 64 : dbufs[1] = (TDB_DATA) {
1084 : .dptr = watchers,
1085 32 : .dsize = i * DBWRAP_WATCHER_BUF_LENGTH,
1086 : };
1087 : }
1088 :
1089 1564 : if (i < (num_watchers - 1)) {
1090 8 : size_t behind = (num_watchers - 1 - i);
1091 :
1092 8 : dbufs[2] = (TDB_DATA) {
1093 8 : .dptr = watchers + (i+1) * DBWRAP_WATCHER_BUF_LENGTH,
1094 8 : .dsize = behind * DBWRAP_WATCHER_BUF_LENGTH,
1095 : };
1096 : }
1097 :
1098 1564 : num_watchers -= 1;
1099 :
1100 1564 : if ((num_watchers == 0) && (dbufs[3].dsize == 0)) {
1101 0 : status = dbwrap_record_delete(rec);
1102 0 : if (!NT_STATUS_IS_OK(status)) {
1103 0 : DBG_DEBUG("dbwrap_record_delete() failed: %s\n",
1104 : nt_errstr(status));
1105 : }
1106 0 : return;
1107 : }
1108 :
1109 1564 : SIVAL(num_watchers_buf, 0, num_watchers);
1110 :
1111 1564 : status = dbwrap_record_storev(rec, dbufs, ARRAY_SIZE(dbufs), 0);
1112 1564 : if (!NT_STATUS_IS_OK(status)) {
1113 0 : DBG_DEBUG("dbwrap_record_storev() failed: %s\n",
1114 : nt_errstr(status));
1115 : }
1116 : }
1117 :
1118 1614 : static int dbwrap_watched_watch_state_destructor(
1119 : struct dbwrap_watched_watch_state *state)
1120 : {
1121 1614 : struct db_watched_ctx *ctx = talloc_get_type_abort(
1122 : state->db->private_data, struct db_watched_ctx);
1123 : NTSTATUS status;
1124 :
1125 1614 : status = dbwrap_do_locked(
1126 : ctx->backend,
1127 : state->key,
1128 : dbwrap_watched_watch_state_destructor_fn,
1129 : state);
1130 1614 : if (!NT_STATUS_IS_OK(status)) {
1131 0 : DBG_DEBUG("dbwrap_do_locked failed: %s\n",
1132 : nt_errstr(status));
1133 : }
1134 1614 : return 0;
1135 : }
1136 :
1137 2244 : static bool dbwrap_watched_msg_filter(struct messaging_rec *rec,
1138 : void *private_data)
1139 : {
1140 2244 : struct dbwrap_watched_watch_state *state = talloc_get_type_abort(
1141 : private_data, struct dbwrap_watched_watch_state);
1142 : uint64_t instance;
1143 :
1144 2244 : if (rec->msg_type != MSG_DBWRAP_MODIFIED) {
1145 1 : return false;
1146 : }
1147 2243 : if (rec->num_fds != 0) {
1148 0 : return false;
1149 : }
1150 :
1151 2243 : if (rec->buf.length != sizeof(instance)) {
1152 0 : DBG_DEBUG("Got size %zu, expected %zu\n",
1153 : rec->buf.length,
1154 : sizeof(instance));
1155 0 : return false;
1156 : }
1157 :
1158 2243 : instance = BVAL(rec->buf.data, 0);
1159 :
1160 2243 : if (instance != state->watcher.instance) {
1161 1 : DBG_DEBUG("Got instance %"PRIu64", expected %"PRIu64"\n",
1162 : instance,
1163 : state->watcher.instance);
1164 0 : return false;
1165 : }
1166 :
1167 2237 : return true;
1168 : }
1169 :
1170 2242 : static void dbwrap_watched_watch_done(struct tevent_req *subreq)
1171 : {
1172 2242 : struct tevent_req *req = tevent_req_callback_data(
1173 : subreq, struct tevent_req);
1174 2242 : struct dbwrap_watched_watch_state *state = tevent_req_data(
1175 : req, struct dbwrap_watched_watch_state);
1176 : struct messaging_rec *rec;
1177 : int ret;
1178 :
1179 2242 : ret = messaging_filtered_read_recv(subreq, talloc_tos(), &rec);
1180 2242 : TALLOC_FREE(subreq);
1181 2242 : if (ret != 0) {
1182 0 : tevent_req_nterror(req, map_nt_error_from_unix(ret));
1183 0 : return;
1184 : }
1185 : /*
1186 : * No need to remove ourselves anymore, we've been removed by
1187 : * dbwrap_watched_subrec_wakeup().
1188 : */
1189 2242 : talloc_set_destructor(state, NULL);
1190 2242 : tevent_req_done(req);
1191 : }
1192 :
1193 2247 : NTSTATUS dbwrap_watched_watch_recv(struct tevent_req *req,
1194 : bool *blockerdead,
1195 : struct server_id *blocker)
1196 : {
1197 2247 : struct dbwrap_watched_watch_state *state = tevent_req_data(
1198 : req, struct dbwrap_watched_watch_state);
1199 : NTSTATUS status;
1200 :
1201 2247 : if (tevent_req_is_nterror(req, &status)) {
1202 1 : return status;
1203 : }
1204 2246 : if (blockerdead != NULL) {
1205 2192 : *blockerdead = state->blockerdead;
1206 : }
1207 2246 : if (blocker != NULL) {
1208 2192 : *blocker = state->blocker;
1209 : }
1210 2246 : return NT_STATUS_OK;
1211 : }
1212 :
|