s3: Update waf build to include missed dependancy on Lion.
[Samba/gebeck_regimport.git] / source3 / lib / messages_local.c
blobb398870e1f2b3354c3e06f4d5b85375c75197050
1 /*
2 Unix SMB/CIFS implementation.
3 Samba internal messaging functions
4 Copyright (C) 2007 by Volker Lendecke
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.
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.
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/>.
20 /**
21 @defgroup messages Internal messaging framework
23 @file messages.c
25 @brief Module for internal messaging between Samba daemons.
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.
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.
36 @caution Dispatch functions must be able to cope with incoming
37 messages on an *odd* byte boundary.
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.
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"
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;
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);
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)
69 struct messaging_tdb_context *ctx = talloc_get_type(private_data,
70 struct messaging_tdb_context);
72 ctx->received_messages++;
74 DEBUG(10, ("messaging_tdb_signal_handler: sig[%d] count[%d] msgs[%d]\n",
75 signum, count, ctx->received_messages));
77 message_dispatch(ctx->msg_ctx);
80 /****************************************************************************
81 Initialise the messaging functions.
82 ****************************************************************************/
84 NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx,
85 TALLOC_CTX *mem_ctx,
86 struct messaging_backend **presult)
88 struct messaging_backend *result;
89 struct messaging_tdb_context *ctx;
90 struct loadparm_context *lp_ctx;
92 if (!(result = talloc(mem_ctx, struct messaging_backend))) {
93 DEBUG(0, ("talloc failed\n"));
94 return NT_STATUS_NO_MEMORY;
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;
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;
109 result->private_data = ctx;
110 result->send_fn = messaging_tdb_send;
112 ctx->msg_ctx = msg_ctx;
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);
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;
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;
140 sec_init();
142 *presult = result;
143 return NT_STATUS_OK;
146 bool messaging_tdb_parent_init(TALLOC_CTX *mem_ctx)
148 struct tdb_wrap *db;
149 struct loadparm_context *lp_ctx;
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;
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.
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;
172 return true;
175 /*******************************************************************
176 Form a static tdb key from a pid.
177 ******************************************************************/
179 static TDB_DATA message_key_pid(TALLOC_CTX *mem_ctx, struct server_id pid)
181 char *key;
182 TDB_DATA kbuf;
184 key = talloc_asprintf(talloc_tos(), "PID/%s", procid_str_static(&pid));
186 SMB_ASSERT(key != NULL);
188 kbuf.dptr = (uint8 *)key;
189 kbuf.dsize = strlen(key)+1;
190 return kbuf;
194 Fetch the messaging array for a process
197 static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
198 TDB_DATA key,
199 TALLOC_CTX *mem_ctx,
200 struct messaging_array **presult)
202 struct messaging_array *result;
203 TDB_DATA data;
204 DATA_BLOB blob;
205 enum ndr_err_code ndr_err;
207 if (!(result = talloc_zero(mem_ctx, struct messaging_array))) {
208 return NT_STATUS_NO_MEMORY;
211 data = tdb_fetch_compat(msg_tdb, key);
213 if (data.dptr == NULL) {
214 *presult = result;
215 return NT_STATUS_OK;
218 blob = data_blob_const(data.dptr, data.dsize);
220 ndr_err = ndr_pull_struct_blob_all(
221 &blob, result, result,
222 (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
224 SAFE_FREE(data.dptr);
226 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
227 TALLOC_FREE(result);
228 return ndr_map_error2ntstatus(ndr_err);
231 if (DEBUGLEVEL >= 10) {
232 DEBUG(10, ("messaging_tdb_fetch:\n"));
233 NDR_PRINT_DEBUG(messaging_array, result);
236 *presult = result;
237 return NT_STATUS_OK;
241 Store a messaging array for a pid
244 static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
245 TDB_DATA key,
246 struct messaging_array *array)
248 TDB_DATA data;
249 DATA_BLOB blob;
250 enum ndr_err_code ndr_err;
251 TALLOC_CTX *mem_ctx;
252 int ret;
254 if (array->num_messages == 0) {
255 tdb_delete(msg_tdb, key);
256 return NT_STATUS_OK;
259 if (!(mem_ctx = talloc_new(array))) {
260 return NT_STATUS_NO_MEMORY;
263 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, array,
264 (ndr_push_flags_fn_t)ndr_push_messaging_array);
266 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
267 talloc_free(mem_ctx);
268 return ndr_map_error2ntstatus(ndr_err);
271 if (DEBUGLEVEL >= 10) {
272 DEBUG(10, ("messaging_tdb_store:\n"));
273 NDR_PRINT_DEBUG(messaging_array, array);
276 data.dptr = blob.data;
277 data.dsize = blob.length;
279 ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
280 TALLOC_FREE(mem_ctx);
282 return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
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 ****************************************************************************/
290 static NTSTATUS message_notify(struct server_id procid)
292 pid_t pid = procid.pid;
293 int ret;
294 uid_t euid = geteuid();
297 * Doing kill with a non-positive pid causes messages to be
298 * sent to places we don't want.
301 SMB_ASSERT(pid > 0);
302 if (pid <= 0) {
303 return NT_STATUS_INVALID_HANDLE;
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);
312 ret = kill(pid, SIGUSR1);
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;
321 if (ret == 0) {
322 return NT_STATUS_OK;
326 * Something has gone wrong
329 DEBUG(2,("message to process %d failed - %s\n", (int)pid,
330 strerror(errno)));
333 * No call to map_nt_error_from_unix -- don't want to link in
334 * errormap.o into lots of utils.
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;
343 /****************************************************************************
344 Send a message to a particular pid.
345 ****************************************************************************/
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)
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();
361 /* NULL pointer means implicit length zero. */
362 if (!data->data) {
363 SMB_ASSERT(data->length == 0);
367 * Doing kill with a non-positive pid causes messages to be
368 * sent to places we don't want.
371 SMB_ASSERT(procid_to_pid(&pid) > 0);
373 key = message_key_pid(frame, pid);
375 if (tdb_chainlock(tdb->tdb, key) != 0) {
376 TALLOC_FREE(frame);
377 return NT_STATUS_LOCK_NOT_GRANTED;
380 status = messaging_tdb_fetch(tdb->tdb, key, talloc_tos(), &msg_array);
382 if (!NT_STATUS_IS_OK(status)) {
383 goto done;
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;
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;
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;
407 msg_array->messages = rec;
408 msg_array->num_messages += 1;
410 status = messaging_tdb_store(tdb->tdb, key, msg_array);
412 if (!NT_STATUS_IS_OK(status)) {
413 goto done;
416 status = message_notify(pid);
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));
424 done:
425 tdb_chainunlock(tdb->tdb, key);
426 TALLOC_FREE(frame);
427 return status;
430 /****************************************************************************
431 Retrieve all messages for a process.
432 ****************************************************************************/
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)
439 struct messaging_array *result;
440 TDB_DATA key = message_key_pid(mem_ctx, id);
441 NTSTATUS status;
443 if (tdb_chainlock(msg_tdb, key) != 0) {
444 TALLOC_FREE(key.dptr);
445 return NT_STATUS_LOCK_NOT_GRANTED;
448 status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
451 * We delete the record here, tdb_set_max_dead keeps it around
453 tdb_delete(msg_tdb, key);
454 tdb_chainunlock(msg_tdb, key);
456 if (NT_STATUS_IS_OK(status)) {
457 *presult = result;
460 TALLOC_FREE(key.dptr);
462 return status;
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 ****************************************************************************/
472 static void message_dispatch(struct messaging_context *msg_ctx)
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;
481 if (ctx->received_messages == 0) {
482 return;
485 DEBUG(10, ("message_dispatch: received_messages = %d\n",
486 ctx->received_messages));
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;
495 ctx->received_messages = 0;
497 for (i=0; i<msg_array->num_messages; i++) {
498 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
501 TALLOC_FREE(msg_array);
504 /** @} **/