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