Check for fstatat.
[Samba/gebeck_regimport.git] / source3 / lib / messages_local.c
blob6b63d7292542ed85176656c7a0a8987ad9492c1c
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 void *messaging_tdb_event(TALLOC_CTX *mem_ctx, struct messaging_context *msg,
81 struct tevent_context *ev)
83 struct messaging_tdb_context *msg_tdb = talloc_get_type_abort(
84 msg->local->private_data, struct messaging_tdb_context);
86 return tevent_add_signal(ev, mem_ctx, SIGUSR1, 0,
87 messaging_tdb_signal_handler, msg_tdb);
90 /****************************************************************************
91 Initialise the messaging functions.
92 ****************************************************************************/
94 NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx,
95 TALLOC_CTX *mem_ctx,
96 struct messaging_backend **presult)
98 struct messaging_backend *result;
99 struct messaging_tdb_context *ctx;
100 struct loadparm_context *lp_ctx;
102 if (!(result = talloc(mem_ctx, struct messaging_backend))) {
103 DEBUG(0, ("talloc failed\n"));
104 return NT_STATUS_NO_MEMORY;
107 lp_ctx = loadparm_init_s3(result, loadparm_s3_helpers());
108 if (lp_ctx == NULL) {
109 DEBUG(0, ("loadparm_init_s3 failed\n"));
110 return NT_STATUS_INTERNAL_ERROR;
113 ctx = talloc_zero(result, struct messaging_tdb_context);
114 if (!ctx) {
115 DEBUG(0, ("talloc failed\n"));
116 TALLOC_FREE(result);
117 return NT_STATUS_NO_MEMORY;
119 result->private_data = ctx;
120 result->send_fn = messaging_tdb_send;
122 ctx->msg_ctx = msg_ctx;
124 ctx->tdb = tdb_wrap_open(ctx, lock_path("messages.tdb"), 0,
125 TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_VOLATILE|TDB_INCOMPATIBLE_HASH,
126 O_RDWR|O_CREAT,0600, lp_ctx);
127 talloc_unlink(result, lp_ctx);
129 if (!ctx->tdb) {
130 NTSTATUS status = map_nt_error_from_unix(errno);
131 DEBUG(2, ("ERROR: Failed to initialise messages database: "
132 "%s\n", strerror(errno)));
133 TALLOC_FREE(result);
134 return status;
137 ctx->se = tevent_add_signal(msg_ctx->event_ctx,
138 ctx,
139 SIGUSR1, 0,
140 messaging_tdb_signal_handler,
141 ctx);
142 if (!ctx->se) {
143 NTSTATUS status = map_nt_error_from_unix(errno);
144 DEBUG(0, ("ERROR: Failed to initialise messages signal handler: "
145 "%s\n", strerror(errno)));
146 TALLOC_FREE(result);
147 return status;
150 sec_init();
152 *presult = result;
153 return NT_STATUS_OK;
156 bool messaging_tdb_parent_init(TALLOC_CTX *mem_ctx)
158 struct tdb_wrap *db;
159 struct loadparm_context *lp_ctx;
161 lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers());
162 if (lp_ctx == NULL) {
163 DEBUG(0, ("loadparm_init_s3 failed\n"));
164 return false;
168 * Open the tdb in the parent process (smbd) so that our
169 * CLEAR_IF_FIRST optimization in tdb_reopen_all can properly
170 * work.
173 db = tdb_wrap_open(mem_ctx, lock_path("messages.tdb"), 0,
174 TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_VOLATILE|TDB_INCOMPATIBLE_HASH,
175 O_RDWR|O_CREAT,0600, lp_ctx);
176 talloc_unlink(mem_ctx, lp_ctx);
177 if (db == NULL) {
178 DEBUG(1, ("could not open messaging.tdb: %s\n",
179 strerror(errno)));
180 return false;
182 return true;
185 /*******************************************************************
186 Form a static tdb key from a pid.
187 ******************************************************************/
189 static TDB_DATA message_key_pid(TALLOC_CTX *mem_ctx, struct server_id pid)
191 char *key;
192 TDB_DATA kbuf;
194 key = talloc_asprintf(talloc_tos(), "PID/%s", procid_str_static(&pid));
196 SMB_ASSERT(key != NULL);
198 kbuf.dptr = (uint8 *)key;
199 kbuf.dsize = strlen(key)+1;
200 return kbuf;
204 Fetch the messaging array for a process
207 static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
208 TDB_DATA key,
209 TALLOC_CTX *mem_ctx,
210 struct messaging_array **presult)
212 struct messaging_array *result;
213 TDB_DATA data;
214 DATA_BLOB blob;
215 enum ndr_err_code ndr_err;
217 if (!(result = talloc_zero(mem_ctx, struct messaging_array))) {
218 return NT_STATUS_NO_MEMORY;
221 data = tdb_fetch(msg_tdb, key);
223 if (data.dptr == NULL) {
224 *presult = result;
225 return NT_STATUS_OK;
228 blob = data_blob_const(data.dptr, data.dsize);
230 ndr_err = ndr_pull_struct_blob_all(
231 &blob, result, result,
232 (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
234 SAFE_FREE(data.dptr);
236 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
237 TALLOC_FREE(result);
238 return ndr_map_error2ntstatus(ndr_err);
241 if (DEBUGLEVEL >= 10) {
242 DEBUG(10, ("messaging_tdb_fetch:\n"));
243 NDR_PRINT_DEBUG(messaging_array, result);
246 *presult = result;
247 return NT_STATUS_OK;
251 Store a messaging array for a pid
254 static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
255 TDB_DATA key,
256 struct messaging_array *array)
258 TDB_DATA data;
259 DATA_BLOB blob;
260 enum ndr_err_code ndr_err;
261 TALLOC_CTX *mem_ctx;
262 int ret;
264 if (array->num_messages == 0) {
265 tdb_delete(msg_tdb, key);
266 return NT_STATUS_OK;
269 if (!(mem_ctx = talloc_new(array))) {
270 return NT_STATUS_NO_MEMORY;
273 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, array,
274 (ndr_push_flags_fn_t)ndr_push_messaging_array);
276 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
277 talloc_free(mem_ctx);
278 return ndr_map_error2ntstatus(ndr_err);
281 if (DEBUGLEVEL >= 10) {
282 DEBUG(10, ("messaging_tdb_store:\n"));
283 NDR_PRINT_DEBUG(messaging_array, array);
286 data.dptr = blob.data;
287 data.dsize = blob.length;
289 ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
290 TALLOC_FREE(mem_ctx);
292 return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
295 /****************************************************************************
296 Notify a process that it has a message. If the process doesn't exist
297 then delete its record in the database.
298 ****************************************************************************/
300 static NTSTATUS message_notify(struct server_id procid)
302 pid_t pid = procid.pid;
303 int ret;
304 uid_t euid = geteuid();
307 * Doing kill with a non-positive pid causes messages to be
308 * sent to places we don't want.
311 SMB_ASSERT(pid > 0);
312 if (pid <= 0) {
313 return NT_STATUS_INVALID_HANDLE;
316 if (euid != 0) {
317 /* If we're not root become so to send the message. */
318 save_re_uid();
319 set_effective_uid(0);
322 ret = kill(pid, SIGUSR1);
324 if (euid != 0) {
325 /* Go back to who we were. */
326 int saved_errno = errno;
327 restore_re_uid_fromroot();
328 errno = saved_errno;
331 if (ret == 0) {
332 return NT_STATUS_OK;
336 * Something has gone wrong
339 DEBUG(2,("message to process %d failed - %s\n", (int)pid,
340 strerror(errno)));
343 * No call to map_nt_error_from_unix -- don't want to link in
344 * errormap.o into lots of utils.
347 if (errno == ESRCH) return NT_STATUS_INVALID_HANDLE;
348 if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
349 if (errno == EPERM) return NT_STATUS_ACCESS_DENIED;
350 return NT_STATUS_UNSUCCESSFUL;
353 /****************************************************************************
354 Send a message to a particular pid.
355 ****************************************************************************/
357 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
358 struct server_id pid, int msg_type,
359 const DATA_BLOB *data,
360 struct messaging_backend *backend)
362 struct messaging_tdb_context *ctx = talloc_get_type(backend->private_data,
363 struct messaging_tdb_context);
364 struct messaging_array *msg_array;
365 struct messaging_rec *rec;
366 NTSTATUS status;
367 TDB_DATA key;
368 struct tdb_wrap *tdb = ctx->tdb;
369 TALLOC_CTX *frame = talloc_stackframe();
371 /* NULL pointer means implicit length zero. */
372 if (!data->data) {
373 SMB_ASSERT(data->length == 0);
377 * Doing kill with a non-positive pid causes messages to be
378 * sent to places we don't want.
381 SMB_ASSERT(procid_to_pid(&pid) > 0);
383 key = message_key_pid(frame, pid);
385 if (tdb_chainlock(tdb->tdb, key) != 0) {
386 TALLOC_FREE(frame);
387 return NT_STATUS_LOCK_NOT_GRANTED;
390 status = messaging_tdb_fetch(tdb->tdb, key, talloc_tos(), &msg_array);
392 if (!NT_STATUS_IS_OK(status)) {
393 goto done;
396 if ((msg_type & MSG_FLAG_LOWPRIORITY)
397 && (msg_array->num_messages > 1000)) {
398 DEBUG(5, ("Dropping message for PID %s\n",
399 procid_str_static(&pid)));
400 status = NT_STATUS_INSUFFICIENT_RESOURCES;
401 goto done;
404 if (!(rec = talloc_realloc(talloc_tos(), msg_array->messages,
405 struct messaging_rec,
406 msg_array->num_messages+1))) {
407 status = NT_STATUS_NO_MEMORY;
408 goto done;
411 rec[msg_array->num_messages].msg_version = MESSAGE_VERSION;
412 rec[msg_array->num_messages].msg_type = msg_type & MSG_TYPE_MASK;
413 rec[msg_array->num_messages].dest = pid;
414 rec[msg_array->num_messages].src = msg_ctx->id;
415 rec[msg_array->num_messages].buf = *data;
417 msg_array->messages = rec;
418 msg_array->num_messages += 1;
420 status = messaging_tdb_store(tdb->tdb, key, msg_array);
422 if (!NT_STATUS_IS_OK(status)) {
423 goto done;
426 status = message_notify(pid);
428 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
429 DEBUG(2, ("pid %s doesn't exist - deleting messages record\n",
430 procid_str_static(&pid)));
431 tdb_delete(tdb->tdb, message_key_pid(talloc_tos(), pid));
434 done:
435 tdb_chainunlock(tdb->tdb, key);
436 TALLOC_FREE(frame);
437 return status;
440 /****************************************************************************
441 Retrieve all messages for a process.
442 ****************************************************************************/
444 static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb,
445 struct server_id id,
446 TALLOC_CTX *mem_ctx,
447 struct messaging_array **presult)
449 struct messaging_array *result;
450 TDB_DATA key = message_key_pid(mem_ctx, id);
451 NTSTATUS status;
453 if (tdb_chainlock(msg_tdb, key) != 0) {
454 TALLOC_FREE(key.dptr);
455 return NT_STATUS_LOCK_NOT_GRANTED;
458 status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
461 * We delete the record here, tdb_set_max_dead keeps it around
463 tdb_delete(msg_tdb, key);
464 tdb_chainunlock(msg_tdb, key);
466 if (NT_STATUS_IS_OK(status)) {
467 *presult = result;
470 TALLOC_FREE(key.dptr);
472 return status;
475 /****************************************************************************
476 Receive and dispatch any messages pending for this process.
477 JRA changed Dec 13 2006. Only one message handler now permitted per type.
478 *NOTE*: Dispatch functions must be able to cope with incoming
479 messages on an *odd* byte boundary.
480 ****************************************************************************/
482 static void message_dispatch(struct messaging_context *msg_ctx)
484 struct messaging_tdb_context *ctx = talloc_get_type(msg_ctx->local->private_data,
485 struct messaging_tdb_context);
486 struct messaging_array *msg_array = NULL;
487 struct tdb_wrap *tdb = ctx->tdb;
488 NTSTATUS status;
489 uint32 i;
491 if (ctx->received_messages == 0) {
492 return;
495 DEBUG(10, ("message_dispatch: received_messages = %d\n",
496 ctx->received_messages));
498 status = retrieve_all_messages(tdb->tdb, msg_ctx->id, NULL, &msg_array);
499 if (!NT_STATUS_IS_OK(status)) {
500 DEBUG(0, ("message_dispatch: failed to retrieve messages: %s\n",
501 nt_errstr(status)));
502 return;
505 ctx->received_messages = 0;
507 for (i=0; i<msg_array->num_messages; i++) {
508 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
511 TALLOC_FREE(msg_array);
514 /** @} **/