s4:librpc/rpc: make PyErr_SetDCERPCStatus() static
[Samba/gebeck_regimport.git] / source3 / lib / messages_local.c
blob21910b1e65f3f4662d3b73bfeae239bdd3c9f539
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 "librpc/gen_ndr/messaging.h"
47 #include "librpc/gen_ndr/ndr_messaging.h"
49 struct messaging_tdb_context {
50 struct messaging_context *msg_ctx;
51 struct tdb_wrap *tdb;
52 struct tevent_signal *se;
53 int received_messages;
56 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
57 struct server_id pid, int msg_type,
58 const DATA_BLOB *data,
59 struct messaging_backend *backend);
60 static void message_dispatch(struct messaging_context *msg_ctx);
62 static void messaging_tdb_signal_handler(struct tevent_context *ev_ctx,
63 struct tevent_signal *se,
64 int signum, int count,
65 void *_info, void *private_data)
67 struct messaging_tdb_context *ctx = talloc_get_type(private_data,
68 struct messaging_tdb_context);
70 ctx->received_messages++;
72 DEBUG(10, ("messaging_tdb_signal_handler: sig[%d] count[%d] msgs[%d]\n",
73 signum, count, ctx->received_messages));
75 message_dispatch(ctx->msg_ctx);
78 /****************************************************************************
79 Initialise the messaging functions.
80 ****************************************************************************/
82 NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx,
83 TALLOC_CTX *mem_ctx,
84 struct messaging_backend **presult)
86 struct messaging_backend *result;
87 struct messaging_tdb_context *ctx;
89 if (!(result = TALLOC_P(mem_ctx, struct messaging_backend))) {
90 DEBUG(0, ("talloc failed\n"));
91 return NT_STATUS_NO_MEMORY;
94 ctx = TALLOC_ZERO_P(result, struct messaging_tdb_context);
95 if (!ctx) {
96 DEBUG(0, ("talloc failed\n"));
97 TALLOC_FREE(result);
98 return NT_STATUS_NO_MEMORY;
100 result->private_data = ctx;
101 result->send_fn = messaging_tdb_send;
103 ctx->msg_ctx = msg_ctx;
105 ctx->tdb = tdb_wrap_open(ctx, lock_path("messages.tdb"), 0,
106 TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_VOLATILE,
107 O_RDWR|O_CREAT,0600);
109 if (!ctx->tdb) {
110 NTSTATUS status = map_nt_error_from_unix(errno);
111 DEBUG(0, ("ERROR: Failed to initialise messages database: "
112 "%s\n", strerror(errno)));
113 TALLOC_FREE(result);
114 return status;
117 ctx->se = tevent_add_signal(msg_ctx->event_ctx,
118 ctx,
119 SIGUSR1, 0,
120 messaging_tdb_signal_handler,
121 ctx);
122 if (!ctx->se) {
123 NTSTATUS status = map_nt_error_from_unix(errno);
124 DEBUG(0, ("ERROR: Failed to initialise messages signal handler: "
125 "%s\n", strerror(errno)));
126 TALLOC_FREE(result);
127 return status;
130 sec_init();
132 *presult = result;
133 return NT_STATUS_OK;
136 bool messaging_tdb_parent_init(void)
138 struct tdb_wrap *db;
141 * Open the tdb in the parent process (smbd) so that our
142 * CLEAR_IF_FIRST optimization in tdb_reopen_all can properly
143 * work.
146 db = tdb_wrap_open(talloc_autofree_context(),
147 lock_path("messages.tdb"), 0,
148 TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_VOLATILE,
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_P(mem_ctx, struct messaging_array))) {
191 return NT_STATUS_NO_MEMORY;
194 data = tdb_fetch(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(
204 &blob, result, NULL, 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(
247 &blob, mem_ctx, NULL, array,
248 (ndr_push_flags_fn_t)ndr_push_messaging_array);
250 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
251 talloc_free(mem_ctx);
252 return ndr_map_error2ntstatus(ndr_err);
255 if (DEBUGLEVEL >= 10) {
256 DEBUG(10, ("messaging_tdb_store:\n"));
257 NDR_PRINT_DEBUG(messaging_array, array);
260 data.dptr = blob.data;
261 data.dsize = blob.length;
263 ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
264 TALLOC_FREE(mem_ctx);
266 return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
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 ****************************************************************************/
274 static NTSTATUS message_notify(struct server_id procid)
276 pid_t pid = procid.pid;
277 int ret;
278 uid_t euid = geteuid();
281 * Doing kill with a non-positive pid causes messages to be
282 * sent to places we don't want.
285 SMB_ASSERT(pid > 0);
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);
293 ret = kill(pid, SIGUSR1);
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;
302 if (ret == 0) {
303 return NT_STATUS_OK;
307 * Something has gone wrong
310 DEBUG(2,("message to process %d failed - %s\n", (int)pid,
311 strerror(errno)));
314 * No call to map_nt_error_from_unix -- don't want to link in
315 * errormap.o into lots of utils.
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;
324 /****************************************************************************
325 Send a message to a particular pid.
326 ****************************************************************************/
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)
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();
342 /* NULL pointer means implicit length zero. */
343 if (!data->data) {
344 SMB_ASSERT(data->length == 0);
348 * Doing kill with a non-positive pid causes messages to be
349 * sent to places we don't want.
352 SMB_ASSERT(procid_to_pid(&pid) > 0);
354 key = message_key_pid(frame, pid);
356 if (tdb_chainlock(tdb->tdb, key) == -1) {
357 TALLOC_FREE(frame);
358 return NT_STATUS_LOCK_NOT_GRANTED;
361 status = messaging_tdb_fetch(tdb->tdb, key, talloc_tos(), &msg_array);
363 if (!NT_STATUS_IS_OK(status)) {
364 goto done;
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;
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;
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 = procid_self();
386 rec[msg_array->num_messages].buf = *data;
388 msg_array->messages = rec;
389 msg_array->num_messages += 1;
391 status = messaging_tdb_store(tdb->tdb, key, msg_array);
393 if (!NT_STATUS_IS_OK(status)) {
394 goto done;
397 status = message_notify(pid);
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));
405 done:
406 tdb_chainunlock(tdb->tdb, key);
407 TALLOC_FREE(frame);
408 return status;
411 /****************************************************************************
412 Retrieve all messages for the current process.
413 ****************************************************************************/
415 static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb,
416 TALLOC_CTX *mem_ctx,
417 struct messaging_array **presult)
419 struct messaging_array *result;
420 TDB_DATA key = message_key_pid(mem_ctx, procid_self());
421 NTSTATUS status;
423 if (tdb_chainlock(msg_tdb, key) == -1) {
424 TALLOC_FREE(key.dptr);
425 return NT_STATUS_LOCK_NOT_GRANTED;
428 status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
431 * We delete the record here, tdb_set_max_dead keeps it around
433 tdb_delete(msg_tdb, key);
434 tdb_chainunlock(msg_tdb, key);
436 if (NT_STATUS_IS_OK(status)) {
437 *presult = result;
440 TALLOC_FREE(key.dptr);
442 return status;
445 /****************************************************************************
446 Receive and dispatch any messages pending for this process.
447 JRA changed Dec 13 2006. Only one message handler now permitted per type.
448 *NOTE*: Dispatch functions must be able to cope with incoming
449 messages on an *odd* byte boundary.
450 ****************************************************************************/
452 static void message_dispatch(struct messaging_context *msg_ctx)
454 struct messaging_tdb_context *ctx = talloc_get_type(msg_ctx->local->private_data,
455 struct messaging_tdb_context);
456 struct messaging_array *msg_array = NULL;
457 struct tdb_wrap *tdb = ctx->tdb;
458 NTSTATUS status;
459 uint32 i;
461 if (ctx->received_messages == 0) {
462 return;
465 DEBUG(10, ("message_dispatch: received_messages = %d\n",
466 ctx->received_messages));
468 status = retrieve_all_messages(tdb->tdb, NULL, &msg_array);
469 if (!NT_STATUS_IS_OK(status)) {
470 DEBUG(0, ("message_dispatch: failed to retrieve messages: %s\n",
471 nt_errstr(status)));
472 return;
475 ctx->received_messages = 0;
477 for (i=0; i<msg_array->num_messages; i++) {
478 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
481 TALLOC_FREE(msg_array);
484 /** @} **/