s3-util: Compare the maximum allowed length of a NetBIOS name
[Samba.git] / source3 / lib / messages_local.c
blob859eeb858e390d6ec0ee2aa88baf2ccb345383b6
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 "serverid.h"
49 #include "lib/tdb_wrap/tdb_wrap.h"
50 #include "lib/param/param.h"
52 struct messaging_tdb_context {
53 struct messaging_context *msg_ctx;
54 struct tdb_wrap *tdb;
55 struct tevent_signal *se;
56 int received_messages;
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 void *messaging_tdb_event(TALLOC_CTX *mem_ctx, struct messaging_context *msg,
82 struct tevent_context *ev)
84 struct messaging_tdb_context *msg_tdb = talloc_get_type_abort(
85 msg->local->private_data, struct messaging_tdb_context);
87 return tevent_add_signal(ev, mem_ctx, SIGUSR1, 0,
88 messaging_tdb_signal_handler, msg_tdb);
91 /****************************************************************************
92 Initialise the messaging functions.
93 ****************************************************************************/
95 NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx,
96 TALLOC_CTX *mem_ctx,
97 struct messaging_backend **presult)
99 struct messaging_backend *result;
100 struct messaging_tdb_context *ctx;
101 struct loadparm_context *lp_ctx;
103 if (!(result = talloc(mem_ctx, struct messaging_backend))) {
104 DEBUG(0, ("talloc failed\n"));
105 return NT_STATUS_NO_MEMORY;
108 lp_ctx = loadparm_init_s3(result, loadparm_s3_helpers());
109 if (lp_ctx == NULL) {
110 DEBUG(0, ("loadparm_init_s3 failed\n"));
111 return NT_STATUS_INTERNAL_ERROR;
114 ctx = talloc_zero(result, struct messaging_tdb_context);
115 if (!ctx) {
116 DEBUG(0, ("talloc failed\n"));
117 TALLOC_FREE(result);
118 return NT_STATUS_NO_MEMORY;
120 result->private_data = ctx;
121 result->send_fn = messaging_tdb_send;
123 ctx->msg_ctx = msg_ctx;
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 *presult = result;
154 return NT_STATUS_OK;
157 bool messaging_tdb_parent_init(TALLOC_CTX *mem_ctx)
159 struct tdb_wrap *db;
160 struct loadparm_context *lp_ctx;
162 lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers());
163 if (lp_ctx == NULL) {
164 DEBUG(0, ("loadparm_init_s3 failed\n"));
165 return false;
169 * Open the tdb in the parent process (smbd) so that our
170 * CLEAR_IF_FIRST optimization in tdb_reopen_all can properly
171 * work.
174 db = tdb_wrap_open(mem_ctx, lock_path("messages.tdb"), 0,
175 TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_VOLATILE|TDB_INCOMPATIBLE_HASH,
176 O_RDWR|O_CREAT,0600, lp_ctx);
177 talloc_unlink(mem_ctx, lp_ctx);
178 if (db == NULL) {
179 DEBUG(1, ("could not open messaging.tdb: %s\n",
180 strerror(errno)));
181 return false;
183 return true;
186 /*******************************************************************
187 Form a static tdb key from a pid.
188 ******************************************************************/
190 static TDB_DATA message_key_pid(TALLOC_CTX *mem_ctx, struct server_id pid)
192 char *key;
193 TDB_DATA kbuf;
195 key = talloc_asprintf(talloc_tos(), "PID/%s", procid_str_static(&pid));
197 SMB_ASSERT(key != NULL);
199 kbuf.dptr = (uint8 *)key;
200 kbuf.dsize = strlen(key)+1;
201 return kbuf;
204 /*******************************************************************
205 Called when a process has terminated abnormally. Remove all messages
206 pending for it.
207 ******************************************************************/
209 NTSTATUS messaging_tdb_cleanup(struct messaging_context *msg_ctx,
210 struct server_id pid)
212 struct messaging_tdb_context *ctx = talloc_get_type(
213 msg_ctx->local->private_data,
214 struct messaging_tdb_context);
215 struct tdb_wrap *tdb = ctx->tdb;
216 TDB_DATA key;
217 TALLOC_CTX *frame = talloc_stackframe();
219 key = message_key_pid(frame, pid);
221 * We have to lock the key to avoid
222 * races in case the server_id was
223 * re-used and is active (a remote
224 * possibility, true). We only
225 * clean up the database if we
226 * know server_id doesn't exist
227 * while checked under the chainlock.
229 if (tdb_chainlock(tdb->tdb, key) != 0) {
230 TALLOC_FREE(frame);
231 return NT_STATUS_LOCK_NOT_GRANTED;
233 if (!serverid_exists(&pid)) {
234 (void)tdb_delete(tdb->tdb, key);
236 tdb_chainunlock(tdb->tdb, key);
237 TALLOC_FREE(frame);
238 return NT_STATUS_OK;
242 Fetch the messaging array for a process
245 static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
246 TDB_DATA key,
247 TALLOC_CTX *mem_ctx,
248 struct messaging_array **presult)
250 struct messaging_array *result;
251 TDB_DATA data;
252 DATA_BLOB blob;
253 enum ndr_err_code ndr_err;
255 if (!(result = talloc_zero(mem_ctx, struct messaging_array))) {
256 return NT_STATUS_NO_MEMORY;
259 data = tdb_fetch(msg_tdb, key);
261 if (data.dptr == NULL) {
262 *presult = result;
263 return NT_STATUS_OK;
266 blob = data_blob_const(data.dptr, data.dsize);
268 ndr_err = ndr_pull_struct_blob_all(
269 &blob, result, result,
270 (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
272 SAFE_FREE(data.dptr);
274 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
275 TALLOC_FREE(result);
276 return ndr_map_error2ntstatus(ndr_err);
279 if (DEBUGLEVEL >= 10) {
280 DEBUG(10, ("messaging_tdb_fetch:\n"));
281 NDR_PRINT_DEBUG(messaging_array, result);
284 *presult = result;
285 return NT_STATUS_OK;
289 Store a messaging array for a pid
292 static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
293 TDB_DATA key,
294 struct messaging_array *array)
296 TDB_DATA data;
297 DATA_BLOB blob;
298 enum ndr_err_code ndr_err;
299 TALLOC_CTX *mem_ctx;
300 int ret;
302 if (array->num_messages == 0) {
303 tdb_delete(msg_tdb, key);
304 return NT_STATUS_OK;
307 if (!(mem_ctx = talloc_new(array))) {
308 return NT_STATUS_NO_MEMORY;
311 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, array,
312 (ndr_push_flags_fn_t)ndr_push_messaging_array);
314 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
315 talloc_free(mem_ctx);
316 return ndr_map_error2ntstatus(ndr_err);
319 if (DEBUGLEVEL >= 10) {
320 DEBUG(10, ("messaging_tdb_store:\n"));
321 NDR_PRINT_DEBUG(messaging_array, array);
324 data.dptr = blob.data;
325 data.dsize = blob.length;
327 ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
328 TALLOC_FREE(mem_ctx);
330 return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
333 /****************************************************************************
334 Notify a process that it has a message. If the process doesn't exist
335 then delete its record in the database.
336 ****************************************************************************/
338 static NTSTATUS message_notify(struct server_id procid)
340 pid_t pid = procid.pid;
341 int ret;
342 uid_t euid = geteuid();
345 * Doing kill with a non-positive pid causes messages to be
346 * sent to places we don't want.
349 SMB_ASSERT(pid > 0);
350 if (pid <= 0) {
351 return NT_STATUS_INVALID_HANDLE;
354 if (euid != 0) {
355 /* If we're not root become so to send the message. */
356 save_re_uid();
357 set_effective_uid(0);
360 ret = kill(pid, SIGUSR1);
362 if (euid != 0) {
363 /* Go back to who we were. */
364 int saved_errno = errno;
365 restore_re_uid_fromroot();
366 errno = saved_errno;
369 if (ret == 0) {
370 return NT_STATUS_OK;
374 * Something has gone wrong
377 DEBUG(2,("message to process %d failed - %s\n", (int)pid,
378 strerror(errno)));
381 * No call to map_nt_error_from_unix -- don't want to link in
382 * errormap.o into lots of utils.
385 if (errno == ESRCH) return NT_STATUS_INVALID_HANDLE;
386 if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
387 if (errno == EPERM) return NT_STATUS_ACCESS_DENIED;
388 return NT_STATUS_UNSUCCESSFUL;
391 /****************************************************************************
392 Send a message to a particular pid.
393 ****************************************************************************/
395 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
396 struct server_id pid, int msg_type,
397 const DATA_BLOB *data,
398 struct messaging_backend *backend)
400 struct messaging_tdb_context *ctx = talloc_get_type(backend->private_data,
401 struct messaging_tdb_context);
402 struct messaging_array *msg_array;
403 struct messaging_rec *rec;
404 NTSTATUS status;
405 TDB_DATA key;
406 struct tdb_wrap *tdb = ctx->tdb;
407 TALLOC_CTX *frame = talloc_stackframe();
409 /* NULL pointer means implicit length zero. */
410 if (!data->data) {
411 SMB_ASSERT(data->length == 0);
415 * Doing kill with a non-positive pid causes messages to be
416 * sent to places we don't want.
419 SMB_ASSERT(procid_to_pid(&pid) > 0);
421 key = message_key_pid(frame, pid);
423 if (tdb_chainlock(tdb->tdb, key) != 0) {
424 TALLOC_FREE(frame);
425 return NT_STATUS_LOCK_NOT_GRANTED;
428 status = messaging_tdb_fetch(tdb->tdb, key, talloc_tos(), &msg_array);
430 if (!NT_STATUS_IS_OK(status)) {
431 goto done;
434 if ((msg_type & MSG_FLAG_LOWPRIORITY)
435 && (msg_array->num_messages > 1000)) {
436 DEBUG(5, ("Dropping message for PID %s\n",
437 procid_str_static(&pid)));
438 status = NT_STATUS_INSUFFICIENT_RESOURCES;
439 goto done;
442 if (!(rec = talloc_realloc(talloc_tos(), msg_array->messages,
443 struct messaging_rec,
444 msg_array->num_messages+1))) {
445 status = NT_STATUS_NO_MEMORY;
446 goto done;
449 rec[msg_array->num_messages].msg_version = MESSAGE_VERSION;
450 rec[msg_array->num_messages].msg_type = msg_type & MSG_TYPE_MASK;
451 rec[msg_array->num_messages].dest = pid;
452 rec[msg_array->num_messages].src = msg_ctx->id;
453 rec[msg_array->num_messages].buf = *data;
455 msg_array->messages = rec;
456 msg_array->num_messages += 1;
458 status = messaging_tdb_store(tdb->tdb, key, msg_array);
460 if (!NT_STATUS_IS_OK(status)) {
461 goto done;
464 status = message_notify(pid);
466 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
467 DEBUG(2, ("pid %s doesn't exist - deleting messages record\n",
468 procid_str_static(&pid)));
469 tdb_delete(tdb->tdb, message_key_pid(talloc_tos(), pid));
472 done:
473 tdb_chainunlock(tdb->tdb, key);
474 TALLOC_FREE(frame);
475 return status;
478 /****************************************************************************
479 Retrieve all messages for a process.
480 ****************************************************************************/
482 static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb,
483 struct server_id id,
484 TALLOC_CTX *mem_ctx,
485 struct messaging_array **presult)
487 struct messaging_array *result;
488 TDB_DATA key = message_key_pid(mem_ctx, id);
489 NTSTATUS status;
491 if (tdb_chainlock(msg_tdb, key) != 0) {
492 TALLOC_FREE(key.dptr);
493 return NT_STATUS_LOCK_NOT_GRANTED;
496 status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
499 * We delete the record here, tdb_set_max_dead keeps it around
501 tdb_delete(msg_tdb, key);
502 tdb_chainunlock(msg_tdb, key);
504 if (NT_STATUS_IS_OK(status)) {
505 *presult = result;
508 TALLOC_FREE(key.dptr);
510 return status;
513 /****************************************************************************
514 Receive and dispatch any messages pending for this process.
515 JRA changed Dec 13 2006. Only one message handler now permitted per type.
516 *NOTE*: Dispatch functions must be able to cope with incoming
517 messages on an *odd* byte boundary.
518 ****************************************************************************/
520 static void message_dispatch(struct messaging_context *msg_ctx)
522 struct messaging_tdb_context *ctx = talloc_get_type(msg_ctx->local->private_data,
523 struct messaging_tdb_context);
524 struct messaging_array *msg_array = NULL;
525 struct tdb_wrap *tdb = ctx->tdb;
526 NTSTATUS status;
527 uint32 i;
529 if (ctx->received_messages == 0) {
530 return;
533 DEBUG(10, ("message_dispatch: received_messages = %d\n",
534 ctx->received_messages));
536 status = retrieve_all_messages(tdb->tdb, msg_ctx->id, NULL, &msg_array);
537 if (!NT_STATUS_IS_OK(status)) {
538 DEBUG(0, ("message_dispatch: failed to retrieve messages: %s\n",
539 nt_errstr(status)));
540 return;
543 ctx->received_messages = 0;
545 for (i=0; i<msg_array->num_messages; i++) {
546 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
549 TALLOC_FREE(msg_array);
552 /** @} **/