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