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