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