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