smbd: Avoid checking the_lock->id for fresh locks
[Samba.git] / source3 / lib / messages_local.c
blobacc5ba6e7dabe2c209bd6f5c1b73fb186d5c1e91
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;
56 bool *have_context;
59 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
60 struct server_id pid, int msg_type,
61 const DATA_BLOB *data,
62 struct messaging_backend *backend);
63 static void message_dispatch(struct messaging_context *msg_ctx);
65 static void messaging_tdb_signal_handler(struct tevent_context *ev_ctx,
66 struct tevent_signal *se,
67 int signum, int count,
68 void *_info, void *private_data)
70 struct messaging_tdb_context *ctx = talloc_get_type(private_data,
71 struct messaging_tdb_context);
73 ctx->received_messages++;
75 DEBUG(10, ("messaging_tdb_signal_handler: sig[%d] count[%d] msgs[%d]\n",
76 signum, count, ctx->received_messages));
78 message_dispatch(ctx->msg_ctx);
81 static int messaging_tdb_context_destructor(struct messaging_tdb_context *ctx);
83 /****************************************************************************
84 Initialise the messaging functions.
85 ****************************************************************************/
87 NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx,
88 TALLOC_CTX *mem_ctx,
89 struct messaging_backend **presult)
91 struct messaging_backend *result;
92 struct messaging_tdb_context *ctx;
93 struct loadparm_context *lp_ctx;
94 static bool have_context = false;
96 if (have_context) {
97 DEBUG(0, ("No two messaging contexts per process\n"));
98 return NT_STATUS_OBJECT_NAME_COLLISION;
101 if (!(result = talloc(mem_ctx, struct messaging_backend))) {
102 DEBUG(0, ("talloc failed\n"));
103 return NT_STATUS_NO_MEMORY;
106 lp_ctx = loadparm_init_s3(result, loadparm_s3_helpers());
107 if (lp_ctx == NULL) {
108 DEBUG(0, ("loadparm_init_s3 failed\n"));
109 TALLOC_FREE(result);
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;
123 ctx->have_context = &have_context;
125 ctx->tdb = tdb_wrap_open(ctx, lock_path("messages.tdb"), 0,
126 TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_VOLATILE|TDB_INCOMPATIBLE_HASH,
127 O_RDWR|O_CREAT,0600, lp_ctx);
128 talloc_unlink(result, lp_ctx);
130 if (!ctx->tdb) {
131 NTSTATUS status = map_nt_error_from_unix(errno);
132 DEBUG(2, ("ERROR: Failed to initialise messages database: "
133 "%s\n", strerror(errno)));
134 TALLOC_FREE(result);
135 return status;
138 ctx->se = tevent_add_signal(msg_ctx->event_ctx,
139 ctx,
140 SIGUSR1, 0,
141 messaging_tdb_signal_handler,
142 ctx);
143 if (!ctx->se) {
144 NTSTATUS status = map_nt_error_from_unix(errno);
145 DEBUG(0, ("ERROR: Failed to initialise messages signal handler: "
146 "%s\n", strerror(errno)));
147 TALLOC_FREE(result);
148 return status;
151 sec_init();
153 have_context = true;
154 talloc_set_destructor(ctx, messaging_tdb_context_destructor);
156 *presult = result;
157 return NT_STATUS_OK;
160 static int messaging_tdb_context_destructor(struct messaging_tdb_context *ctx)
162 SMB_ASSERT(*ctx->have_context);
163 *ctx->have_context = false;
164 return 0;
167 bool messaging_tdb_parent_init(TALLOC_CTX *mem_ctx)
169 struct tdb_wrap *db;
170 struct loadparm_context *lp_ctx;
172 lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers());
173 if (lp_ctx == NULL) {
174 DEBUG(0, ("loadparm_init_s3 failed\n"));
175 return false;
179 * Open the tdb in the parent process (smbd) so that our
180 * CLEAR_IF_FIRST optimization in tdb_reopen_all can properly
181 * work.
184 db = tdb_wrap_open(mem_ctx, lock_path("messages.tdb"), 0,
185 TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_VOLATILE|TDB_INCOMPATIBLE_HASH,
186 O_RDWR|O_CREAT,0600, lp_ctx);
187 talloc_unlink(mem_ctx, lp_ctx);
188 if (db == NULL) {
189 DEBUG(1, ("could not open messaging.tdb: %s\n",
190 strerror(errno)));
191 return false;
193 return true;
196 /*******************************************************************
197 Form a static tdb key from a pid.
198 ******************************************************************/
200 static TDB_DATA message_key_pid(TALLOC_CTX *mem_ctx, struct server_id pid)
202 char *key;
203 TDB_DATA kbuf;
205 key = talloc_asprintf(mem_ctx, "PID/%s", procid_str_static(&pid));
207 SMB_ASSERT(key != NULL);
209 kbuf.dptr = (uint8 *)key;
210 kbuf.dsize = strlen(key)+1;
211 return kbuf;
215 Fetch the messaging array for a process
218 static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
219 TDB_DATA key,
220 TALLOC_CTX *mem_ctx,
221 struct messaging_array **presult)
223 struct messaging_array *result;
224 TDB_DATA data;
225 DATA_BLOB blob;
226 enum ndr_err_code ndr_err;
228 if (!(result = talloc_zero(mem_ctx, struct messaging_array))) {
229 return NT_STATUS_NO_MEMORY;
232 data = tdb_fetch(msg_tdb, key);
234 if (data.dptr == NULL) {
235 *presult = result;
236 return NT_STATUS_OK;
239 blob = data_blob_const(data.dptr, data.dsize);
241 ndr_err = ndr_pull_struct_blob_all(
242 &blob, result, result,
243 (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
245 SAFE_FREE(data.dptr);
247 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
248 TALLOC_FREE(result);
249 return ndr_map_error2ntstatus(ndr_err);
252 if (DEBUGLEVEL >= 10) {
253 DEBUG(10, ("messaging_tdb_fetch:\n"));
254 NDR_PRINT_DEBUG(messaging_array, result);
257 *presult = result;
258 return NT_STATUS_OK;
262 Store a messaging array for a pid
265 static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
266 TDB_DATA key,
267 struct messaging_array *array)
269 TDB_DATA data;
270 DATA_BLOB blob;
271 enum ndr_err_code ndr_err;
272 TALLOC_CTX *mem_ctx;
273 int ret;
275 if (array->num_messages == 0) {
276 tdb_delete(msg_tdb, key);
277 return NT_STATUS_OK;
280 if (!(mem_ctx = talloc_new(array))) {
281 return NT_STATUS_NO_MEMORY;
284 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, array,
285 (ndr_push_flags_fn_t)ndr_push_messaging_array);
287 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
288 talloc_free(mem_ctx);
289 return ndr_map_error2ntstatus(ndr_err);
292 if (DEBUGLEVEL >= 10) {
293 DEBUG(10, ("messaging_tdb_store:\n"));
294 NDR_PRINT_DEBUG(messaging_array, array);
297 data.dptr = blob.data;
298 data.dsize = blob.length;
300 ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
301 TALLOC_FREE(mem_ctx);
303 return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
306 /****************************************************************************
307 Notify a process that it has a message. If the process doesn't exist
308 then delete its record in the database.
309 ****************************************************************************/
311 static NTSTATUS message_notify(struct server_id procid)
313 pid_t pid = procid.pid;
314 int ret;
315 uid_t euid = geteuid();
318 * Doing kill with a non-positive pid causes messages to be
319 * sent to places we don't want.
322 SMB_ASSERT(pid > 0);
323 if (pid <= 0) {
324 return NT_STATUS_INVALID_HANDLE;
327 if (euid != 0) {
328 /* If we're not root become so to send the message. */
329 save_re_uid();
330 set_effective_uid(0);
333 ret = kill(pid, SIGUSR1);
335 if (euid != 0) {
336 /* Go back to who we were. */
337 int saved_errno = errno;
338 restore_re_uid_fromroot();
339 errno = saved_errno;
342 if (ret == 0) {
343 return NT_STATUS_OK;
347 * Something has gone wrong
350 DEBUG(2,("message to process %d failed - %s\n", (int)pid,
351 strerror(errno)));
354 * No call to map_nt_error_from_unix -- don't want to link in
355 * errormap.o into lots of utils.
358 if (errno == ESRCH) return NT_STATUS_INVALID_HANDLE;
359 if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
360 if (errno == EPERM) return NT_STATUS_ACCESS_DENIED;
361 return NT_STATUS_UNSUCCESSFUL;
364 /****************************************************************************
365 Send a message to a particular pid.
366 ****************************************************************************/
368 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
369 struct server_id pid, int msg_type,
370 const DATA_BLOB *data,
371 struct messaging_backend *backend)
373 struct messaging_tdb_context *ctx = talloc_get_type(backend->private_data,
374 struct messaging_tdb_context);
375 struct messaging_array *msg_array;
376 struct messaging_rec *rec;
377 NTSTATUS status;
378 TDB_DATA key;
379 struct tdb_wrap *tdb = ctx->tdb;
380 TALLOC_CTX *frame = talloc_stackframe();
382 /* NULL pointer means implicit length zero. */
383 if (!data->data) {
384 SMB_ASSERT(data->length == 0);
388 * Doing kill with a non-positive pid causes messages to be
389 * sent to places we don't want.
392 SMB_ASSERT(procid_to_pid(&pid) > 0);
394 key = message_key_pid(frame, pid);
396 if (tdb_chainlock(tdb->tdb, key) != 0) {
397 TALLOC_FREE(frame);
398 return NT_STATUS_LOCK_NOT_GRANTED;
401 status = messaging_tdb_fetch(tdb->tdb, key, frame, &msg_array);
403 if (!NT_STATUS_IS_OK(status)) {
404 goto done;
407 if ((msg_type & MSG_FLAG_LOWPRIORITY)
408 && (msg_array->num_messages > 1000)) {
409 DEBUG(5, ("Dropping message for PID %s\n",
410 procid_str_static(&pid)));
411 status = NT_STATUS_INSUFFICIENT_RESOURCES;
412 goto done;
415 if (!(rec = talloc_realloc(frame, msg_array->messages,
416 struct messaging_rec,
417 msg_array->num_messages+1))) {
418 status = NT_STATUS_NO_MEMORY;
419 goto done;
422 rec[msg_array->num_messages].msg_version = MESSAGE_VERSION;
423 rec[msg_array->num_messages].msg_type = msg_type & MSG_TYPE_MASK;
424 rec[msg_array->num_messages].dest = pid;
425 rec[msg_array->num_messages].src = msg_ctx->id;
426 rec[msg_array->num_messages].buf = *data;
428 msg_array->messages = rec;
429 msg_array->num_messages += 1;
431 status = messaging_tdb_store(tdb->tdb, key, msg_array);
433 if (!NT_STATUS_IS_OK(status)) {
434 goto done;
437 status = message_notify(pid);
439 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
440 DEBUG(2, ("pid %s doesn't exist - deleting messages record\n",
441 procid_str_static(&pid)));
442 tdb_delete(tdb->tdb, message_key_pid(frame, pid));
445 done:
446 tdb_chainunlock(tdb->tdb, key);
447 TALLOC_FREE(frame);
448 return status;
451 /****************************************************************************
452 Retrieve all messages for a process.
453 ****************************************************************************/
455 static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb,
456 struct server_id id,
457 TALLOC_CTX *mem_ctx,
458 struct messaging_array **presult)
460 struct messaging_array *result;
461 TDB_DATA key = message_key_pid(mem_ctx, id);
462 NTSTATUS status;
464 if (tdb_chainlock(msg_tdb, key) != 0) {
465 TALLOC_FREE(key.dptr);
466 return NT_STATUS_LOCK_NOT_GRANTED;
469 status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
472 * We delete the record here, tdb_set_max_dead keeps it around
474 tdb_delete(msg_tdb, key);
475 tdb_chainunlock(msg_tdb, key);
477 if (NT_STATUS_IS_OK(status)) {
478 *presult = result;
481 TALLOC_FREE(key.dptr);
483 return status;
486 /****************************************************************************
487 Receive and dispatch any messages pending for this process.
488 JRA changed Dec 13 2006. Only one message handler now permitted per type.
489 *NOTE*: Dispatch functions must be able to cope with incoming
490 messages on an *odd* byte boundary.
491 ****************************************************************************/
493 static void message_dispatch(struct messaging_context *msg_ctx)
495 struct messaging_tdb_context *ctx = talloc_get_type(msg_ctx->local->private_data,
496 struct messaging_tdb_context);
497 struct messaging_array *msg_array = NULL;
498 struct tdb_wrap *tdb = ctx->tdb;
499 NTSTATUS status;
500 uint32 i;
502 if (ctx->received_messages == 0) {
503 return;
506 DEBUG(10, ("message_dispatch: received_messages = %d\n",
507 ctx->received_messages));
509 status = retrieve_all_messages(tdb->tdb, msg_ctx->id, NULL, &msg_array);
510 if (!NT_STATUS_IS_OK(status)) {
511 DEBUG(0, ("message_dispatch: failed to retrieve messages: %s\n",
512 nt_errstr(status)));
513 return;
516 ctx->received_messages = 0;
518 for (i=0; i<msg_array->num_messages; i++) {
519 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
522 TALLOC_FREE(msg_array);
525 /** @} **/