ldb:ldb.c/"ldb_request" - make "ldb_request" always return an error string
[Samba/id10ts.git] / source3 / lib / messages_local.c
blob67234d4d76dca6bfd6c4881c9cc058fe3d518caa
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/util/tdb_wrap.h"
50 struct messaging_tdb_context {
51 struct messaging_context *msg_ctx;
52 struct tdb_wrap *tdb;
53 struct tevent_signal *se;
54 int received_messages;
57 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
58 struct server_id pid, int msg_type,
59 const DATA_BLOB *data,
60 struct messaging_backend *backend);
61 static void message_dispatch(struct messaging_context *msg_ctx);
63 static void messaging_tdb_signal_handler(struct tevent_context *ev_ctx,
64 struct tevent_signal *se,
65 int signum, int count,
66 void *_info, void *private_data)
68 struct messaging_tdb_context *ctx = talloc_get_type(private_data,
69 struct messaging_tdb_context);
71 ctx->received_messages++;
73 DEBUG(10, ("messaging_tdb_signal_handler: sig[%d] count[%d] msgs[%d]\n",
74 signum, count, ctx->received_messages));
76 message_dispatch(ctx->msg_ctx);
79 /****************************************************************************
80 Initialise the messaging functions.
81 ****************************************************************************/
83 NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx,
84 TALLOC_CTX *mem_ctx,
85 struct messaging_backend **presult)
87 struct messaging_backend *result;
88 struct messaging_tdb_context *ctx;
90 if (!(result = talloc(mem_ctx, struct messaging_backend))) {
91 DEBUG(0, ("talloc failed\n"));
92 return NT_STATUS_NO_MEMORY;
95 ctx = talloc_zero(result, struct messaging_tdb_context);
96 if (!ctx) {
97 DEBUG(0, ("talloc failed\n"));
98 TALLOC_FREE(result);
99 return NT_STATUS_NO_MEMORY;
101 result->private_data = ctx;
102 result->send_fn = messaging_tdb_send;
104 ctx->msg_ctx = msg_ctx;
106 ctx->tdb = tdb_wrap_open(ctx, lock_path("messages.tdb"), 0,
107 TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_VOLATILE|TDB_INCOMPATIBLE_HASH,
108 O_RDWR|O_CREAT,0600);
110 if (!ctx->tdb) {
111 NTSTATUS status = map_nt_error_from_unix(errno);
112 DEBUG(2, ("ERROR: Failed to initialise messages database: "
113 "%s\n", strerror(errno)));
114 TALLOC_FREE(result);
115 return status;
118 ctx->se = tevent_add_signal(msg_ctx->event_ctx,
119 ctx,
120 SIGUSR1, 0,
121 messaging_tdb_signal_handler,
122 ctx);
123 if (!ctx->se) {
124 NTSTATUS status = map_nt_error_from_unix(errno);
125 DEBUG(0, ("ERROR: Failed to initialise messages signal handler: "
126 "%s\n", strerror(errno)));
127 TALLOC_FREE(result);
128 return status;
131 sec_init();
133 *presult = result;
134 return NT_STATUS_OK;
137 bool messaging_tdb_parent_init(TALLOC_CTX *mem_ctx)
139 struct tdb_wrap *db;
142 * Open the tdb in the parent process (smbd) so that our
143 * CLEAR_IF_FIRST optimization in tdb_reopen_all can properly
144 * work.
147 db = tdb_wrap_open(mem_ctx, lock_path("messages.tdb"), 0,
148 TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_VOLATILE|TDB_INCOMPATIBLE_HASH,
149 O_RDWR|O_CREAT,0600);
150 if (db == NULL) {
151 DEBUG(1, ("could not open messaging.tdb: %s\n",
152 strerror(errno)));
153 return false;
155 return true;
158 /*******************************************************************
159 Form a static tdb key from a pid.
160 ******************************************************************/
162 static TDB_DATA message_key_pid(TALLOC_CTX *mem_ctx, struct server_id pid)
164 char *key;
165 TDB_DATA kbuf;
167 key = talloc_asprintf(talloc_tos(), "PID/%s", procid_str_static(&pid));
169 SMB_ASSERT(key != NULL);
171 kbuf.dptr = (uint8 *)key;
172 kbuf.dsize = strlen(key)+1;
173 return kbuf;
177 Fetch the messaging array for a process
180 static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
181 TDB_DATA key,
182 TALLOC_CTX *mem_ctx,
183 struct messaging_array **presult)
185 struct messaging_array *result;
186 TDB_DATA data;
187 DATA_BLOB blob;
188 enum ndr_err_code ndr_err;
190 if (!(result = talloc_zero(mem_ctx, struct messaging_array))) {
191 return NT_STATUS_NO_MEMORY;
194 data = tdb_fetch_compat(msg_tdb, key);
196 if (data.dptr == NULL) {
197 *presult = result;
198 return NT_STATUS_OK;
201 blob = data_blob_const(data.dptr, data.dsize);
203 ndr_err = ndr_pull_struct_blob_all(
204 &blob, result, result,
205 (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
207 SAFE_FREE(data.dptr);
209 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
210 TALLOC_FREE(result);
211 return ndr_map_error2ntstatus(ndr_err);
214 if (DEBUGLEVEL >= 10) {
215 DEBUG(10, ("messaging_tdb_fetch:\n"));
216 NDR_PRINT_DEBUG(messaging_array, result);
219 *presult = result;
220 return NT_STATUS_OK;
224 Store a messaging array for a pid
227 static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
228 TDB_DATA key,
229 struct messaging_array *array)
231 TDB_DATA data;
232 DATA_BLOB blob;
233 enum ndr_err_code ndr_err;
234 TALLOC_CTX *mem_ctx;
235 int ret;
237 if (array->num_messages == 0) {
238 tdb_delete(msg_tdb, key);
239 return NT_STATUS_OK;
242 if (!(mem_ctx = talloc_new(array))) {
243 return NT_STATUS_NO_MEMORY;
246 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, array,
247 (ndr_push_flags_fn_t)ndr_push_messaging_array);
249 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
250 talloc_free(mem_ctx);
251 return ndr_map_error2ntstatus(ndr_err);
254 if (DEBUGLEVEL >= 10) {
255 DEBUG(10, ("messaging_tdb_store:\n"));
256 NDR_PRINT_DEBUG(messaging_array, array);
259 data.dptr = blob.data;
260 data.dsize = blob.length;
262 ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
263 TALLOC_FREE(mem_ctx);
265 return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
268 /****************************************************************************
269 Notify a process that it has a message. If the process doesn't exist
270 then delete its record in the database.
271 ****************************************************************************/
273 static NTSTATUS message_notify(struct server_id procid)
275 pid_t pid = procid.pid;
276 int ret;
277 uid_t euid = geteuid();
280 * Doing kill with a non-positive pid causes messages to be
281 * sent to places we don't want.
284 SMB_ASSERT(pid > 0);
285 if (pid <= 0) {
286 return NT_STATUS_INVALID_HANDLE;
289 if (euid != 0) {
290 /* If we're not root become so to send the message. */
291 save_re_uid();
292 set_effective_uid(0);
295 ret = kill(pid, SIGUSR1);
297 if (euid != 0) {
298 /* Go back to who we were. */
299 int saved_errno = errno;
300 restore_re_uid_fromroot();
301 errno = saved_errno;
304 if (ret == 0) {
305 return NT_STATUS_OK;
309 * Something has gone wrong
312 DEBUG(2,("message to process %d failed - %s\n", (int)pid,
313 strerror(errno)));
316 * No call to map_nt_error_from_unix -- don't want to link in
317 * errormap.o into lots of utils.
320 if (errno == ESRCH) return NT_STATUS_INVALID_HANDLE;
321 if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
322 if (errno == EPERM) return NT_STATUS_ACCESS_DENIED;
323 return NT_STATUS_UNSUCCESSFUL;
326 /****************************************************************************
327 Send a message to a particular pid.
328 ****************************************************************************/
330 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
331 struct server_id pid, int msg_type,
332 const DATA_BLOB *data,
333 struct messaging_backend *backend)
335 struct messaging_tdb_context *ctx = talloc_get_type(backend->private_data,
336 struct messaging_tdb_context);
337 struct messaging_array *msg_array;
338 struct messaging_rec *rec;
339 NTSTATUS status;
340 TDB_DATA key;
341 struct tdb_wrap *tdb = ctx->tdb;
342 TALLOC_CTX *frame = talloc_stackframe();
344 /* NULL pointer means implicit length zero. */
345 if (!data->data) {
346 SMB_ASSERT(data->length == 0);
350 * Doing kill with a non-positive pid causes messages to be
351 * sent to places we don't want.
354 SMB_ASSERT(procid_to_pid(&pid) > 0);
356 key = message_key_pid(frame, pid);
358 if (tdb_chainlock(tdb->tdb, key) != 0) {
359 TALLOC_FREE(frame);
360 return NT_STATUS_LOCK_NOT_GRANTED;
363 status = messaging_tdb_fetch(tdb->tdb, key, talloc_tos(), &msg_array);
365 if (!NT_STATUS_IS_OK(status)) {
366 goto done;
369 if ((msg_type & MSG_FLAG_LOWPRIORITY)
370 && (msg_array->num_messages > 1000)) {
371 DEBUG(5, ("Dropping message for PID %s\n",
372 procid_str_static(&pid)));
373 status = NT_STATUS_INSUFFICIENT_RESOURCES;
374 goto done;
377 if (!(rec = talloc_realloc(talloc_tos(), msg_array->messages,
378 struct messaging_rec,
379 msg_array->num_messages+1))) {
380 status = NT_STATUS_NO_MEMORY;
381 goto done;
384 rec[msg_array->num_messages].msg_version = MESSAGE_VERSION;
385 rec[msg_array->num_messages].msg_type = msg_type & MSG_TYPE_MASK;
386 rec[msg_array->num_messages].dest = pid;
387 rec[msg_array->num_messages].src = msg_ctx->id;
388 rec[msg_array->num_messages].buf = *data;
390 msg_array->messages = rec;
391 msg_array->num_messages += 1;
393 status = messaging_tdb_store(tdb->tdb, key, msg_array);
395 if (!NT_STATUS_IS_OK(status)) {
396 goto done;
399 status = message_notify(pid);
401 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
402 DEBUG(2, ("pid %s doesn't exist - deleting messages record\n",
403 procid_str_static(&pid)));
404 tdb_delete(tdb->tdb, message_key_pid(talloc_tos(), pid));
407 done:
408 tdb_chainunlock(tdb->tdb, key);
409 TALLOC_FREE(frame);
410 return status;
413 /****************************************************************************
414 Retrieve all messages for a process.
415 ****************************************************************************/
417 static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb,
418 struct server_id id,
419 TALLOC_CTX *mem_ctx,
420 struct messaging_array **presult)
422 struct messaging_array *result;
423 TDB_DATA key = message_key_pid(mem_ctx, id);
424 NTSTATUS status;
426 if (tdb_chainlock(msg_tdb, key) != 0) {
427 TALLOC_FREE(key.dptr);
428 return NT_STATUS_LOCK_NOT_GRANTED;
431 status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
434 * We delete the record here, tdb_set_max_dead keeps it around
436 tdb_delete(msg_tdb, key);
437 tdb_chainunlock(msg_tdb, key);
439 if (NT_STATUS_IS_OK(status)) {
440 *presult = result;
443 TALLOC_FREE(key.dptr);
445 return status;
448 /****************************************************************************
449 Receive and dispatch any messages pending for this process.
450 JRA changed Dec 13 2006. Only one message handler now permitted per type.
451 *NOTE*: Dispatch functions must be able to cope with incoming
452 messages on an *odd* byte boundary.
453 ****************************************************************************/
455 static void message_dispatch(struct messaging_context *msg_ctx)
457 struct messaging_tdb_context *ctx = talloc_get_type(msg_ctx->local->private_data,
458 struct messaging_tdb_context);
459 struct messaging_array *msg_array = NULL;
460 struct tdb_wrap *tdb = ctx->tdb;
461 NTSTATUS status;
462 uint32 i;
464 if (ctx->received_messages == 0) {
465 return;
468 DEBUG(10, ("message_dispatch: received_messages = %d\n",
469 ctx->received_messages));
471 status = retrieve_all_messages(tdb->tdb, msg_ctx->id, NULL, &msg_array);
472 if (!NT_STATUS_IS_OK(status)) {
473 DEBUG(0, ("message_dispatch: failed to retrieve messages: %s\n",
474 nt_errstr(status)));
475 return;
478 ctx->received_messages = 0;
480 for (i=0; i<msg_array->num_messages; i++) {
481 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
484 TALLOC_FREE(msg_array);
487 /** @} **/