r25068: Older samba3 DCs will return DCERPC_FAULT_OP_RNG_ERROR for every opcode on the
[Samba.git] / source / lib / messages_local.c
blob1f50e5bb6f27abe893b23e0f444d8f64a15cf9d7
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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /**
22 @defgroup messages Internal messaging framework
24 @file messages.c
26 @brief Module for internal messaging between Samba daemons.
28 The idea is that if a part of Samba wants to do communication with
29 another Samba process then it will do a message_register() of a
30 dispatch function, and use message_send_pid() to send messages to
31 that process.
33 The dispatch function is given the pid of the sender, and it can
34 use that to reply by message_send_pid(). See ping_message() for a
35 simple example.
37 @caution Dispatch functions must be able to cope with incoming
38 messages on an *odd* byte boundary.
40 This system doesn't have any inherent size limitations but is not
41 very efficient for large messages or when messages are sent in very
42 quick succession.
46 #include "includes.h"
47 #include "librpc/gen_ndr/messaging.h"
48 #include "librpc/gen_ndr/ndr_messaging.h"
50 static int received_signal;
52 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
53 struct server_id pid, int msg_type,
54 const DATA_BLOB *data,
55 struct messaging_backend *backend);
57 /****************************************************************************
58 Notifications come in as signals.
59 ****************************************************************************/
61 static void sig_usr1(void)
63 received_signal = 1;
64 sys_select_signal(SIGUSR1);
67 static int messaging_tdb_destructor(struct messaging_backend *tdb_ctx)
69 TDB_CONTEXT *tdb = (TDB_CONTEXT *)tdb_ctx->private_data;
70 tdb_close(tdb);
71 return 0;
74 /****************************************************************************
75 Initialise the messaging functions.
76 ****************************************************************************/
78 NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx,
79 TALLOC_CTX *mem_ctx,
80 struct messaging_backend **presult)
82 struct messaging_backend *result;
83 TDB_CONTEXT *tdb;
85 if (!(result = TALLOC_P(mem_ctx, struct messaging_backend))) {
86 DEBUG(0, ("talloc failed\n"));
87 return NT_STATUS_NO_MEMORY;
90 tdb = tdb_open_log(lock_path("messages.tdb"),
91 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
92 O_RDWR|O_CREAT,0600);
94 if (!tdb) {
95 NTSTATUS status = map_nt_error_from_unix(errno);
96 DEBUG(0, ("ERROR: Failed to initialise messages database: "
97 "%s\n", strerror(errno)));
98 TALLOC_FREE(result);
99 return status;
102 sec_init();
104 /* Activate the per-hashchain freelist */
105 tdb_set_max_dead(tdb, 5);
107 CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1);
109 result->private_data = (void *)tdb;
110 result->send_fn = messaging_tdb_send;
112 talloc_set_destructor(result, messaging_tdb_destructor);
114 *presult = result;
115 return NT_STATUS_OK;
118 /*******************************************************************
119 Form a static tdb key from a pid.
120 ******************************************************************/
122 static TDB_DATA message_key_pid(struct server_id pid)
124 static char key[20];
125 TDB_DATA kbuf;
127 slprintf(key, sizeof(key)-1, "PID/%s", procid_str_static(&pid));
129 kbuf.dptr = (uint8 *)key;
130 kbuf.dsize = strlen(key)+1;
131 return kbuf;
135 Fetch the messaging array for a process
138 static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
139 TDB_DATA key,
140 TALLOC_CTX *mem_ctx,
141 struct messaging_array **presult)
143 struct messaging_array *result;
144 TDB_DATA data;
145 DATA_BLOB blob;
146 NTSTATUS status;
148 if (!(result = TALLOC_ZERO_P(mem_ctx, struct messaging_array))) {
149 return NT_STATUS_NO_MEMORY;
152 data = tdb_fetch(msg_tdb, key);
154 if (data.dptr == NULL) {
155 *presult = result;
156 return NT_STATUS_OK;
159 blob = data_blob_const(data.dptr, data.dsize);
161 status = ndr_pull_struct_blob(
162 &blob, result, result,
163 (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
165 SAFE_FREE(data.dptr);
167 if (!NT_STATUS_IS_OK(status)) {
168 TALLOC_FREE(result);
169 return status;
172 if (DEBUGLEVEL >= 10) {
173 DEBUG(10, ("messaging_tdb_fetch:\n"));
174 NDR_PRINT_DEBUG(messaging_array, result);
177 *presult = result;
178 return NT_STATUS_OK;
182 Store a messaging array for a pid
185 static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
186 TDB_DATA key,
187 struct messaging_array *array)
189 TDB_DATA data;
190 DATA_BLOB blob;
191 NTSTATUS status;
192 TALLOC_CTX *mem_ctx;
193 int ret;
195 if (array->num_messages == 0) {
196 tdb_delete(msg_tdb, key);
197 return NT_STATUS_OK;
200 if (!(mem_ctx = talloc_new(array))) {
201 return NT_STATUS_NO_MEMORY;
204 status = ndr_push_struct_blob(
205 &blob, mem_ctx, array,
206 (ndr_push_flags_fn_t)ndr_push_messaging_array);
208 if (!NT_STATUS_IS_OK(status)) {
209 talloc_free(mem_ctx);
210 return status;
213 if (DEBUGLEVEL >= 10) {
214 DEBUG(10, ("messaging_tdb_store:\n"));
215 NDR_PRINT_DEBUG(messaging_array, array);
218 data.dptr = blob.data;
219 data.dsize = blob.length;
221 ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
222 TALLOC_FREE(mem_ctx);
224 return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
227 /****************************************************************************
228 Notify a process that it has a message. If the process doesn't exist
229 then delete its record in the database.
230 ****************************************************************************/
232 static NTSTATUS message_notify(struct server_id procid)
234 pid_t pid = procid.pid;
235 int ret;
236 uid_t euid = geteuid();
239 * Doing kill with a non-positive pid causes messages to be
240 * sent to places we don't want.
243 SMB_ASSERT(pid > 0);
245 if (euid != 0) {
246 /* If we're not root become so to send the message. */
247 save_re_uid();
248 set_effective_uid(0);
251 ret = kill(pid, SIGUSR1);
253 if (euid != 0) {
254 /* Go back to who we were. */
255 int saved_errno = errno;
256 restore_re_uid_fromroot();
257 errno = saved_errno;
260 if (ret == 0) {
261 return NT_STATUS_OK;
265 * Something has gone wrong
268 DEBUG(2,("message to process %d failed - %s\n", (int)pid,
269 strerror(errno)));
272 * No call to map_nt_error_from_unix -- don't want to link in
273 * errormap.o into lots of utils.
276 if (errno == ESRCH) return NT_STATUS_INVALID_HANDLE;
277 if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
278 if (errno == EPERM) return NT_STATUS_ACCESS_DENIED;
279 return NT_STATUS_UNSUCCESSFUL;
282 /****************************************************************************
283 Send a message to a particular pid.
284 ****************************************************************************/
286 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
287 struct server_id pid, int msg_type,
288 const DATA_BLOB *data,
289 struct messaging_backend *backend)
291 struct messaging_array *msg_array;
292 struct messaging_rec *rec;
293 TALLOC_CTX *mem_ctx;
294 NTSTATUS status;
295 TDB_DATA key = message_key_pid(pid);
296 TDB_CONTEXT *tdb = (TDB_CONTEXT *)backend->private_data;
298 /* NULL pointer means implicit length zero. */
299 if (!data->data) {
300 SMB_ASSERT(data->length == 0);
304 * Doing kill with a non-positive pid causes messages to be
305 * sent to places we don't want.
308 SMB_ASSERT(procid_to_pid(&pid) > 0);
310 if (!(mem_ctx = talloc_init("message_send_pid"))) {
311 return NT_STATUS_NO_MEMORY;
314 if (tdb_chainlock(tdb, key) == -1) {
315 TALLOC_FREE(mem_ctx);
316 return NT_STATUS_LOCK_NOT_GRANTED;
319 status = messaging_tdb_fetch(tdb, key, mem_ctx, &msg_array);
321 if (!NT_STATUS_IS_OK(status)) {
322 goto done;
325 if ((msg_type & MSG_FLAG_LOWPRIORITY)
326 && (msg_array->num_messages > 1000)) {
327 DEBUG(5, ("Dropping message for PID %s\n",
328 procid_str_static(&pid)));
329 status = NT_STATUS_INSUFFICIENT_RESOURCES;
330 goto done;
333 if (!(rec = TALLOC_REALLOC_ARRAY(mem_ctx, msg_array->messages,
334 struct messaging_rec,
335 msg_array->num_messages+1))) {
336 status = NT_STATUS_NO_MEMORY;
337 goto done;
340 rec[msg_array->num_messages].msg_version = MESSAGE_VERSION;
341 rec[msg_array->num_messages].msg_type = msg_type & MSG_TYPE_MASK;
342 rec[msg_array->num_messages].dest = pid;
343 rec[msg_array->num_messages].src = procid_self();
344 rec[msg_array->num_messages].buf = *data;
346 msg_array->messages = rec;
347 msg_array->num_messages += 1;
349 status = messaging_tdb_store(tdb, key, msg_array);
351 if (!NT_STATUS_IS_OK(status)) {
352 goto done;
355 status = message_notify(pid);
357 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
358 DEBUG(2, ("pid %s doesn't exist - deleting messages record\n",
359 procid_str_static(&pid)));
360 tdb_delete(tdb, message_key_pid(pid));
363 done:
364 tdb_chainunlock(tdb, key);
365 TALLOC_FREE(mem_ctx);
366 return status;
369 /****************************************************************************
370 Retrieve all messages for the current process.
371 ****************************************************************************/
373 static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb,
374 TALLOC_CTX *mem_ctx,
375 struct messaging_array **presult)
377 struct messaging_array *result;
378 TDB_DATA key = message_key_pid(procid_self());
379 NTSTATUS status;
381 if (tdb_chainlock(msg_tdb, key) == -1) {
382 return NT_STATUS_LOCK_NOT_GRANTED;
385 status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
388 * We delete the record here, tdb_set_max_dead keeps it around
390 tdb_delete(msg_tdb, key);
391 tdb_chainunlock(msg_tdb, key);
393 if (NT_STATUS_IS_OK(status)) {
394 *presult = result;
397 return status;
400 /****************************************************************************
401 Receive and dispatch any messages pending for this process.
402 JRA changed Dec 13 2006. Only one message handler now permitted per type.
403 *NOTE*: Dispatch functions must be able to cope with incoming
404 messages on an *odd* byte boundary.
405 ****************************************************************************/
407 void message_dispatch(struct messaging_context *msg_ctx)
409 struct messaging_array *msg_array = NULL;
410 TDB_CONTEXT *tdb = (TDB_CONTEXT *)(msg_ctx->local->private_data);
411 uint32 i;
413 if (!received_signal)
414 return;
416 DEBUG(10, ("message_dispatch: received_signal = %d\n",
417 received_signal));
419 received_signal = 0;
421 if (!NT_STATUS_IS_OK(retrieve_all_messages(tdb, NULL, &msg_array))) {
422 return;
425 for (i=0; i<msg_array->num_messages; i++) {
426 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
429 TALLOC_FREE(msg_array);
432 /** @} **/