tdb_wrap: Remove tdb_wrap_open_ again
[sfrench/samba-autobuild/.git] / source3 / lib / messages_local.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba internal messaging functions
4    Copyright (C) 2007 by Volker Lendecke
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 /**
21   @defgroup messages Internal messaging framework
22   @{
23   @file messages.c
24
25   @brief  Module for internal messaging between Samba daemons. 
26
27    The idea is that if a part of Samba wants to do communication with
28    another Samba process then it will do a message_register() of a
29    dispatch function, and use message_send_pid() to send messages to
30    that process.
31
32    The dispatch function is given the pid of the sender, and it can
33    use that to reply by message_send_pid().  See ping_message() for a
34    simple example.
35
36    @caution Dispatch functions must be able to cope with incoming
37    messages on an *odd* byte boundary.
38
39    This system doesn't have any inherent size limitations but is not
40    very efficient for large messages or when messages are sent in very
41    quick succession.
42
43 */
44
45 #include "includes.h"
46 #include "system/filesys.h"
47 #include "messages.h"
48 #include "lib/tdb_wrap/tdb_wrap.h"
49 #include "lib/param/param.h"
50
51 struct messaging_tdb_context {
52         struct messaging_context *msg_ctx;
53         struct tdb_wrap *tdb;
54         struct tevent_signal *se;
55         int received_messages;
56         bool *have_context;
57 };
58
59 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
60                                    struct server_id pid, int msg_type,
61                                    const DATA_BLOB *data,
62                                    struct messaging_backend *backend);
63 static void message_dispatch(struct messaging_context *msg_ctx);
64
65 static void messaging_tdb_signal_handler(struct tevent_context *ev_ctx,
66                                          struct tevent_signal *se,
67                                          int signum, int count,
68                                          void *_info, void *private_data)
69 {
70         struct messaging_tdb_context *ctx = talloc_get_type(private_data,
71                                             struct messaging_tdb_context);
72
73         ctx->received_messages++;
74
75         DEBUG(10, ("messaging_tdb_signal_handler: sig[%d] count[%d] msgs[%d]\n",
76                    signum, count, ctx->received_messages));
77
78         message_dispatch(ctx->msg_ctx);
79 }
80
81 static int messaging_tdb_context_destructor(struct messaging_tdb_context *ctx);
82
83 /****************************************************************************
84  Initialise the messaging functions. 
85 ****************************************************************************/
86
87 NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx,
88                             TALLOC_CTX *mem_ctx,
89                             struct messaging_backend **presult)
90 {
91         struct messaging_backend *result;
92         struct messaging_tdb_context *ctx;
93         struct loadparm_context *lp_ctx;
94         static bool have_context = false;
95         const char *fname;
96
97         if (have_context) {
98                 DEBUG(0, ("No two messaging contexts per process\n"));
99                 return NT_STATUS_OBJECT_NAME_COLLISION;
100         }
101
102         if (!(result = talloc(mem_ctx, struct messaging_backend))) {
103                 DEBUG(0, ("talloc failed\n"));
104                 return NT_STATUS_NO_MEMORY;
105         }
106
107         lp_ctx = loadparm_init_s3(result, loadparm_s3_helpers());
108         if (lp_ctx == NULL) {
109                 DEBUG(0, ("loadparm_init_s3 failed\n"));
110                 TALLOC_FREE(result);
111                 return NT_STATUS_INTERNAL_ERROR;
112         }
113
114         ctx = talloc_zero(result, struct messaging_tdb_context);
115         if (!ctx) {
116                 DEBUG(0, ("talloc failed\n"));
117                 TALLOC_FREE(result);
118                 return NT_STATUS_NO_MEMORY;
119         }
120         result->private_data = ctx;
121         result->send_fn = messaging_tdb_send;
122
123         ctx->msg_ctx = msg_ctx;
124         ctx->have_context = &have_context;
125
126         fname = lock_path("messages.tdb");
127
128         ctx->tdb = tdb_wrap_open(
129                 ctx, fname, lpcfg_tdb_hash_size(lp_ctx, fname),
130                 lpcfg_tdb_flags(lp_ctx, TDB_CLEAR_IF_FIRST|TDB_DEFAULT|
131                                 TDB_VOLATILE| TDB_INCOMPATIBLE_HASH),
132                 O_RDWR|O_CREAT,0600);
133
134         talloc_unlink(result, lp_ctx);
135
136         if (!ctx->tdb) {
137                 NTSTATUS status = map_nt_error_from_unix(errno);
138                 DEBUG(2, ("ERROR: Failed to initialise messages database: "
139                           "%s\n", strerror(errno)));
140                 TALLOC_FREE(result);
141                 return status;
142         }
143
144         ctx->se = tevent_add_signal(msg_ctx->event_ctx,
145                                     ctx,
146                                     SIGUSR1, 0,
147                                     messaging_tdb_signal_handler,
148                                     ctx);
149         if (!ctx->se) {
150                 NTSTATUS status = map_nt_error_from_unix(errno);
151                 DEBUG(0, ("ERROR: Failed to initialise messages signal handler: "
152                           "%s\n", strerror(errno)));
153                 TALLOC_FREE(result);
154                 return status;
155         }
156
157         sec_init();
158
159         have_context = true;
160         talloc_set_destructor(ctx, messaging_tdb_context_destructor);
161
162         *presult = result;
163         return NT_STATUS_OK;
164 }
165
166 static int messaging_tdb_context_destructor(struct messaging_tdb_context *ctx)
167 {
168         SMB_ASSERT(*ctx->have_context);
169         *ctx->have_context = false;
170         return 0;
171 }
172
173 bool messaging_tdb_parent_init(TALLOC_CTX *mem_ctx)
174 {
175         struct tdb_wrap *db;
176         struct loadparm_context *lp_ctx;
177         const char *fname;
178
179         lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers());
180         if (lp_ctx == NULL) {
181                 DEBUG(0, ("loadparm_init_s3 failed\n"));
182                 return false;
183         }
184
185         /*
186          * Open the tdb in the parent process (smbd) so that our
187          * CLEAR_IF_FIRST optimization in tdb_reopen_all can properly
188          * work.
189          */
190
191         fname = lock_path("messages.tdb");
192         db = tdb_wrap_open(
193                 mem_ctx, fname, lpcfg_tdb_hash_size(lp_ctx, fname),
194                 lpcfg_tdb_flags(lp_ctx, TDB_CLEAR_IF_FIRST|TDB_DEFAULT|
195                                 TDB_VOLATILE|TDB_INCOMPATIBLE_HASH),
196                 O_RDWR|O_CREAT,0600);
197         talloc_unlink(mem_ctx, lp_ctx);
198         if (db == NULL) {
199                 DEBUG(1, ("could not open messaging.tdb: %s\n",
200                           strerror(errno)));
201                 return false;
202         }
203         return true;
204 }
205
206 /*******************************************************************
207  Form a static tdb key from a pid.
208 ******************************************************************/
209
210 static TDB_DATA message_key_pid(TALLOC_CTX *mem_ctx, struct server_id pid)
211 {
212         char *key;
213         TDB_DATA kbuf;
214
215         key = talloc_asprintf(mem_ctx, "PID/%s", procid_str_static(&pid));
216
217         SMB_ASSERT(key != NULL);
218
219         kbuf.dptr = (uint8 *)key;
220         kbuf.dsize = strlen(key)+1;
221         return kbuf;
222 }
223
224 /*
225   Fetch the messaging array for a process
226  */
227
228 static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
229                                     TDB_DATA key,
230                                     TALLOC_CTX *mem_ctx,
231                                     struct messaging_array **presult)
232 {
233         struct messaging_array *result;
234         TDB_DATA data;
235         DATA_BLOB blob;
236         enum ndr_err_code ndr_err;
237
238         if (!(result = talloc_zero(mem_ctx, struct messaging_array))) {
239                 return NT_STATUS_NO_MEMORY;
240         }
241
242         data = tdb_fetch(msg_tdb, key);
243
244         if (data.dptr == NULL) {
245                 *presult = result;
246                 return NT_STATUS_OK;
247         }
248
249         blob = data_blob_const(data.dptr, data.dsize);
250
251         ndr_err = ndr_pull_struct_blob_all(
252                 &blob, result, result,
253                 (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
254
255         SAFE_FREE(data.dptr);
256
257         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
258                 TALLOC_FREE(result);
259                 return ndr_map_error2ntstatus(ndr_err);
260         }
261
262         if (DEBUGLEVEL >= 10) {
263                 DEBUG(10, ("messaging_tdb_fetch:\n"));
264                 NDR_PRINT_DEBUG(messaging_array, result);
265         }
266
267         *presult = result;
268         return NT_STATUS_OK;
269 }
270
271 /*
272   Store a messaging array for a pid
273 */
274
275 static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
276                                     TDB_DATA key,
277                                     struct messaging_array *array)
278 {
279         TDB_DATA data;
280         DATA_BLOB blob;
281         enum ndr_err_code ndr_err;
282         TALLOC_CTX *mem_ctx;
283         int ret;
284
285         if (array->num_messages == 0) {
286                 tdb_delete(msg_tdb, key);
287                 return NT_STATUS_OK;
288         }
289
290         if (!(mem_ctx = talloc_new(array))) {
291                 return NT_STATUS_NO_MEMORY;
292         }
293
294         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, array,
295                 (ndr_push_flags_fn_t)ndr_push_messaging_array);
296
297         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
298                 talloc_free(mem_ctx);
299                 return ndr_map_error2ntstatus(ndr_err);
300         }
301
302         if (DEBUGLEVEL >= 10) {
303                 DEBUG(10, ("messaging_tdb_store:\n"));
304                 NDR_PRINT_DEBUG(messaging_array, array);
305         }
306
307         data.dptr = blob.data;
308         data.dsize = blob.length;
309
310         ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
311         TALLOC_FREE(mem_ctx);
312
313         return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
314 }
315
316 /****************************************************************************
317  Notify a process that it has a message. If the process doesn't exist 
318  then delete its record in the database.
319 ****************************************************************************/
320
321 static NTSTATUS message_notify(struct server_id procid)
322 {
323         pid_t pid = procid.pid;
324         int ret;
325         uid_t euid = geteuid();
326
327         /*
328          * Doing kill with a non-positive pid causes messages to be
329          * sent to places we don't want.
330          */
331
332         SMB_ASSERT(pid > 0);
333         if (pid <= 0) {
334                 return NT_STATUS_INVALID_HANDLE;
335         }
336
337         if (euid != 0) {
338                 /* If we're not root become so to send the message. */
339                 save_re_uid();
340                 set_effective_uid(0);
341         }
342
343         ret = kill(pid, SIGUSR1);
344
345         if (euid != 0) {
346                 /* Go back to who we were. */
347                 int saved_errno = errno;
348                 restore_re_uid_fromroot();
349                 errno = saved_errno;
350         }
351
352         if (ret == 0) {
353                 return NT_STATUS_OK;
354         }
355
356         /*
357          * Something has gone wrong
358          */
359
360         DEBUG(2,("message to process %d failed - %s\n", (int)pid,
361                  strerror(errno)));
362
363         /*
364          * No call to map_nt_error_from_unix -- don't want to link in
365          * errormap.o into lots of utils.
366          */
367
368         if (errno == ESRCH)  return NT_STATUS_INVALID_HANDLE;
369         if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
370         if (errno == EPERM)  return NT_STATUS_ACCESS_DENIED;
371         return NT_STATUS_UNSUCCESSFUL;
372 }
373
374 /****************************************************************************
375  Send a message to a particular pid.
376 ****************************************************************************/
377
378 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
379                                    struct server_id pid, int msg_type,
380                                    const DATA_BLOB *data,
381                                    struct messaging_backend *backend)
382 {
383         struct messaging_tdb_context *ctx = talloc_get_type(backend->private_data,
384                                             struct messaging_tdb_context);
385         struct messaging_array *msg_array;
386         struct messaging_rec *rec;
387         NTSTATUS status;
388         TDB_DATA key;
389         struct tdb_wrap *tdb = ctx->tdb;
390         TALLOC_CTX *frame = talloc_stackframe();
391
392         /* NULL pointer means implicit length zero. */
393         if (!data->data) {
394                 SMB_ASSERT(data->length == 0);
395         }
396
397         /*
398          * Doing kill with a non-positive pid causes messages to be
399          * sent to places we don't want.
400          */
401
402         SMB_ASSERT(procid_to_pid(&pid) > 0);
403
404         key = message_key_pid(frame, pid);
405
406         if (tdb_chainlock(tdb->tdb, key) != 0) {
407                 TALLOC_FREE(frame);
408                 return NT_STATUS_LOCK_NOT_GRANTED;
409         }
410
411         status = messaging_tdb_fetch(tdb->tdb, key, frame, &msg_array);
412
413         if (!NT_STATUS_IS_OK(status)) {
414                 goto done;
415         }
416
417         if ((msg_type & MSG_FLAG_LOWPRIORITY)
418             && (msg_array->num_messages > 1000)) {
419                 DEBUG(5, ("Dropping message for PID %s\n",
420                           procid_str_static(&pid)));
421                 status = NT_STATUS_INSUFFICIENT_RESOURCES;
422                 goto done;
423         }
424
425         if (!(rec = talloc_realloc(frame, msg_array->messages,
426                                          struct messaging_rec,
427                                          msg_array->num_messages+1))) {
428                 status = NT_STATUS_NO_MEMORY;
429                 goto done;
430         }
431
432         rec[msg_array->num_messages].msg_version = MESSAGE_VERSION;
433         rec[msg_array->num_messages].msg_type = msg_type & MSG_TYPE_MASK;
434         rec[msg_array->num_messages].dest = pid;
435         rec[msg_array->num_messages].src = msg_ctx->id;
436         rec[msg_array->num_messages].buf = *data;
437
438         msg_array->messages = rec;
439         msg_array->num_messages += 1;
440
441         status = messaging_tdb_store(tdb->tdb, key, msg_array);
442
443         if (!NT_STATUS_IS_OK(status)) {
444                 goto done;
445         }
446
447         status = message_notify(pid);
448
449         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
450                 DEBUG(2, ("pid %s doesn't exist - deleting messages record\n",
451                           procid_str_static(&pid)));
452                 tdb_delete(tdb->tdb, message_key_pid(frame, pid));
453         }
454
455  done:
456         tdb_chainunlock(tdb->tdb, key);
457         TALLOC_FREE(frame);
458         return status;
459 }
460
461 /****************************************************************************
462  Retrieve all messages for a process.
463 ****************************************************************************/
464
465 static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb,
466                                       struct server_id id,
467                                       TALLOC_CTX *mem_ctx,
468                                       struct messaging_array **presult)
469 {
470         struct messaging_array *result;
471         TDB_DATA key = message_key_pid(mem_ctx, id);
472         NTSTATUS status;
473
474         if (tdb_chainlock(msg_tdb, key) != 0) {
475                 TALLOC_FREE(key.dptr);
476                 return NT_STATUS_LOCK_NOT_GRANTED;
477         }
478
479         status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
480
481         /*
482          * We delete the record here, tdb_set_max_dead keeps it around
483          */
484         tdb_delete(msg_tdb, key);
485         tdb_chainunlock(msg_tdb, key);
486
487         if (NT_STATUS_IS_OK(status)) {
488                 *presult = result;
489         }
490
491         TALLOC_FREE(key.dptr);
492
493         return status;
494 }
495
496 /****************************************************************************
497  Receive and dispatch any messages pending for this process.
498  JRA changed Dec 13 2006. Only one message handler now permitted per type.
499  *NOTE*: Dispatch functions must be able to cope with incoming
500  messages on an *odd* byte boundary.
501 ****************************************************************************/
502
503 static void message_dispatch(struct messaging_context *msg_ctx)
504 {
505         struct messaging_tdb_context *ctx = talloc_get_type(msg_ctx->local->private_data,
506                                             struct messaging_tdb_context);
507         struct messaging_array *msg_array = NULL;
508         struct tdb_wrap *tdb = ctx->tdb;
509         NTSTATUS status;
510         uint32 i;
511
512         if (ctx->received_messages == 0) {
513                 return;
514         }
515
516         DEBUG(10, ("message_dispatch: received_messages = %d\n",
517                    ctx->received_messages));
518
519         status = retrieve_all_messages(tdb->tdb, msg_ctx->id, NULL, &msg_array);
520         if (!NT_STATUS_IS_OK(status)) {
521                 DEBUG(0, ("message_dispatch: failed to retrieve messages: %s\n",
522                            nt_errstr(status)));
523                 return;
524         }
525
526         ctx->received_messages = 0;
527
528         for (i=0; i<msg_array->num_messages; i++) {
529                 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
530         }
531
532         TALLOC_FREE(msg_array);
533 }
534
535 /** @} **/