r17972: revert accidental commit to ads_verify_ticket()
[Samba.git] / source / lib / messages.c
blob93e12ebe35adabb3a89628246de238ba4443d736
1 /*
2 Unix SMB/CIFS implementation.
3 Samba internal messaging functions
4 Copyright (C) Andrew Tridgell 2000
5 Copyright (C) 2001 by Martin Pool
6 Copyright (C) 2002 by Jeremy Allison
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 /**
24 @defgroup messages Internal messaging framework
26 @file messages.c
28 @brief Module for internal messaging between Samba daemons.
30 The idea is that if a part of Samba wants to do communication with
31 another Samba process then it will do a message_register() of a
32 dispatch function, and use message_send_pid() to send messages to
33 that process.
35 The dispatch function is given the pid of the sender, and it can
36 use that to reply by message_send_pid(). See ping_message() for a
37 simple example.
39 @caution Dispatch functions must be able to cope with incoming
40 messages on an *odd* byte boundary.
42 This system doesn't have any inherent size limitations but is not
43 very efficient for large messages or when messages are sent in very
44 quick succession.
48 #include "includes.h"
50 /* the locking database handle */
51 static TDB_CONTEXT *tdb;
52 static int received_signal;
54 /* change the message version with any incompatible changes in the protocol */
55 #define MESSAGE_VERSION 1
57 struct message_rec {
58 int msg_version;
59 int msg_type;
60 struct process_id dest;
61 struct process_id src;
62 size_t len;
65 /* we have a linked list of dispatch handlers */
66 static struct dispatch_fns {
67 struct dispatch_fns *next, *prev;
68 int msg_type;
69 void (*fn)(int msg_type, struct process_id pid, void *buf, size_t len);
70 } *dispatch_fns;
72 /****************************************************************************
73 Free global objects.
74 ****************************************************************************/
76 void gfree_messages(void)
78 struct dispatch_fns *dfn, *next;
80 /* delete the dispatch_fns list */
81 dfn = dispatch_fns;
82 while( dfn ) {
83 next = dfn->next;
84 DLIST_REMOVE(dispatch_fns, dfn);
85 SAFE_FREE(dfn);
86 dfn = next;
90 /****************************************************************************
91 Notifications come in as signals.
92 ****************************************************************************/
94 static void sig_usr1(void)
96 received_signal = 1;
97 sys_select_signal(SIGUSR1);
100 /****************************************************************************
101 A useful function for testing the message system.
102 ****************************************************************************/
104 static void ping_message(int msg_type, struct process_id src,
105 void *buf, size_t len)
107 const char *msg = buf ? (const char *)buf : "none";
109 DEBUG(1,("INFO: Received PING message from PID %s [%s]\n",
110 procid_str_static(&src), msg));
111 message_send_pid(src, MSG_PONG, buf, len, True);
114 /****************************************************************************
115 Initialise the messaging functions.
116 ****************************************************************************/
118 BOOL message_init(void)
120 sec_init();
122 if (tdb)
123 return True;
125 tdb = tdb_open_log(lock_path("messages.tdb"),
126 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
127 O_RDWR|O_CREAT,0600);
129 if (!tdb) {
130 DEBUG(0,("ERROR: Failed to initialise messages database\n"));
131 return False;
134 CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1);
136 message_register(MSG_PING, ping_message);
138 /* Register some debugging related messages */
140 register_msg_pool_usage();
141 register_dmalloc_msgs();
143 return True;
146 /*******************************************************************
147 Form a static tdb key from a pid.
148 ******************************************************************/
150 static TDB_DATA message_key_pid(struct process_id pid)
152 static char key[20];
153 TDB_DATA kbuf;
155 slprintf(key, sizeof(key)-1, "PID/%s", procid_str_static(&pid));
157 kbuf.dptr = (char *)key;
158 kbuf.dsize = strlen(key)+1;
159 return kbuf;
162 /****************************************************************************
163 Notify a process that it has a message. If the process doesn't exist
164 then delete its record in the database.
165 ****************************************************************************/
167 static BOOL message_notify(struct process_id procid)
169 pid_t pid = procid.pid;
170 int ret;
171 uid_t euid = geteuid();
174 * Doing kill with a non-positive pid causes messages to be
175 * sent to places we don't want.
178 SMB_ASSERT(pid > 0);
180 if (euid != 0) {
181 become_root_uid_only();
184 ret = kill(pid, SIGUSR1);
186 if (euid != 0) {
187 unbecome_root_uid_only();
190 if (ret == -1) {
191 if (errno == ESRCH) {
192 DEBUG(2,("pid %d doesn't exist - deleting messages record\n", (int)pid));
193 tdb_delete(tdb, message_key_pid(procid));
194 } else {
195 DEBUG(2,("message to process %d failed - %s\n", (int)pid, strerror(errno)));
197 return False;
200 return True;
203 /****************************************************************************
204 Send a message to a particular pid.
205 ****************************************************************************/
207 static BOOL message_send_pid_internal(struct process_id pid, int msg_type,
208 const void *buf, size_t len,
209 BOOL duplicates_allowed,
210 unsigned int timeout)
212 TDB_DATA kbuf;
213 TDB_DATA dbuf;
214 TDB_DATA old_dbuf;
215 struct message_rec rec;
216 char *ptr;
217 struct message_rec prec;
219 /* NULL pointer means implicit length zero. */
220 if (!buf) {
221 SMB_ASSERT(len == 0);
225 * Doing kill with a non-positive pid causes messages to be
226 * sent to places we don't want.
229 SMB_ASSERT(procid_to_pid(&pid) > 0);
231 rec.msg_version = MESSAGE_VERSION;
232 rec.msg_type = msg_type;
233 rec.dest = pid;
234 rec.src = procid_self();
235 rec.len = buf ? len : 0;
237 kbuf = message_key_pid(pid);
239 dbuf.dptr = (char *)SMB_MALLOC(len + sizeof(rec));
240 if (!dbuf.dptr)
241 return False;
243 memcpy(dbuf.dptr, &rec, sizeof(rec));
244 if (len > 0 && buf)
245 memcpy((void *)((char*)dbuf.dptr+sizeof(rec)), buf, len);
247 dbuf.dsize = len + sizeof(rec);
249 if (duplicates_allowed) {
251 /* If duplicates are allowed we can just append the message and return. */
253 /* lock the record for the destination */
254 if (timeout) {
255 if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) {
256 DEBUG(0,("message_send_pid_internal: failed to get chainlock with timeout %ul.\n", timeout));
257 return False;
259 } else {
260 if (tdb_chainlock(tdb, kbuf) == -1) {
261 DEBUG(0,("message_send_pid_internal: failed to get chainlock.\n"));
262 return False;
265 tdb_append(tdb, kbuf, dbuf);
266 tdb_chainunlock(tdb, kbuf);
268 SAFE_FREE(dbuf.dptr);
269 errno = 0; /* paranoia */
270 return message_notify(pid);
273 /* lock the record for the destination */
274 if (timeout) {
275 if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) {
276 DEBUG(0,("message_send_pid_internal: failed to get chainlock with timeout %ul.\n", timeout));
277 return False;
279 } else {
280 if (tdb_chainlock(tdb, kbuf) == -1) {
281 DEBUG(0,("message_send_pid_internal: failed to get chainlock.\n"));
282 return False;
286 old_dbuf = tdb_fetch(tdb, kbuf);
288 if (!old_dbuf.dptr) {
289 /* its a new record */
291 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
292 tdb_chainunlock(tdb, kbuf);
294 SAFE_FREE(dbuf.dptr);
295 errno = 0; /* paranoia */
296 return message_notify(pid);
299 /* Not a new record. Check for duplicates. */
301 for(ptr = (char *)old_dbuf.dptr; ptr < old_dbuf.dptr + old_dbuf.dsize; ) {
303 * First check if the message header matches, then, if it's a non-zero
304 * sized message, check if the data matches. If so it's a duplicate and
305 * we can discard it. JRA.
308 if (!memcmp(ptr, &rec, sizeof(rec))) {
309 if (!len || (len && !memcmp( ptr + sizeof(rec), buf, len))) {
310 tdb_chainunlock(tdb, kbuf);
311 DEBUG(10,("message_send_pid_internal: discarding duplicate message.\n"));
312 SAFE_FREE(dbuf.dptr);
313 SAFE_FREE(old_dbuf.dptr);
314 return True;
317 memcpy(&prec, ptr, sizeof(prec));
318 ptr += sizeof(rec) + prec.len;
321 /* we're adding to an existing entry */
323 tdb_append(tdb, kbuf, dbuf);
324 tdb_chainunlock(tdb, kbuf);
326 SAFE_FREE(old_dbuf.dptr);
327 SAFE_FREE(dbuf.dptr);
329 errno = 0; /* paranoia */
330 return message_notify(pid);
333 /****************************************************************************
334 Send a message to a particular pid - no timeout.
335 ****************************************************************************/
337 BOOL message_send_pid(struct process_id pid, int msg_type, const void *buf, size_t len, BOOL duplicates_allowed)
339 return message_send_pid_internal(pid, msg_type, buf, len, duplicates_allowed, 0);
342 /****************************************************************************
343 Send a message to a particular pid, with timeout in seconds.
344 ****************************************************************************/
346 BOOL message_send_pid_with_timeout(struct process_id pid, int msg_type, const void *buf, size_t len,
347 BOOL duplicates_allowed, unsigned int timeout)
349 return message_send_pid_internal(pid, msg_type, buf, len, duplicates_allowed, timeout);
352 /****************************************************************************
353 Count the messages pending for a particular pid. Expensive....
354 ****************************************************************************/
356 unsigned int messages_pending_for_pid(struct process_id pid)
358 TDB_DATA kbuf;
359 TDB_DATA dbuf;
360 char *buf;
361 unsigned int message_count = 0;
363 kbuf = message_key_pid(pid);
365 dbuf = tdb_fetch(tdb, kbuf);
366 if (dbuf.dptr == NULL || dbuf.dsize == 0) {
367 SAFE_FREE(dbuf.dptr);
368 return 0;
371 for (buf = dbuf.dptr; dbuf.dsize > sizeof(struct message_rec);) {
372 struct message_rec rec;
373 memcpy(&rec, buf, sizeof(rec));
374 buf += (sizeof(rec) + rec.len);
375 dbuf.dsize -= (sizeof(rec) + rec.len);
376 message_count++;
379 SAFE_FREE(dbuf.dptr);
380 return message_count;
383 /****************************************************************************
384 Retrieve all messages for the current process.
385 ****************************************************************************/
387 static BOOL retrieve_all_messages(char **msgs_buf, size_t *total_len)
389 TDB_DATA kbuf;
390 TDB_DATA dbuf;
391 TDB_DATA null_dbuf;
393 ZERO_STRUCT(null_dbuf);
395 *msgs_buf = NULL;
396 *total_len = 0;
398 kbuf = message_key_pid(pid_to_procid(sys_getpid()));
400 if (tdb_chainlock(tdb, kbuf) == -1)
401 return False;
403 dbuf = tdb_fetch(tdb, kbuf);
405 * Replace with an empty record to keep the allocated
406 * space in the tdb.
408 tdb_store(tdb, kbuf, null_dbuf, TDB_REPLACE);
409 tdb_chainunlock(tdb, kbuf);
411 if (dbuf.dptr == NULL || dbuf.dsize == 0) {
412 SAFE_FREE(dbuf.dptr);
413 return False;
416 *msgs_buf = dbuf.dptr;
417 *total_len = dbuf.dsize;
419 return True;
422 /****************************************************************************
423 Parse out the next message for the current process.
424 ****************************************************************************/
426 static BOOL message_recv(char *msgs_buf, size_t total_len, int *msg_type,
427 struct process_id *src, char **buf, size_t *len)
429 struct message_rec rec;
430 char *ret_buf = *buf;
432 *buf = NULL;
433 *len = 0;
435 if (total_len - (ret_buf - msgs_buf) < sizeof(rec))
436 return False;
438 memcpy(&rec, ret_buf, sizeof(rec));
439 ret_buf += sizeof(rec);
441 if (rec.msg_version != MESSAGE_VERSION) {
442 DEBUG(0,("message version %d received (expected %d)\n", rec.msg_version, MESSAGE_VERSION));
443 return False;
446 if (rec.len > 0) {
447 if (total_len - (ret_buf - msgs_buf) < rec.len)
448 return False;
451 *len = rec.len;
452 *msg_type = rec.msg_type;
453 *src = rec.src;
454 *buf = ret_buf;
456 return True;
459 /****************************************************************************
460 Receive and dispatch any messages pending for this process.
461 Notice that all dispatch handlers for a particular msg_type get called,
462 so you can register multiple handlers for a message.
463 *NOTE*: Dispatch functions must be able to cope with incoming
464 messages on an *odd* byte boundary.
465 ****************************************************************************/
467 void message_dispatch(void)
469 int msg_type;
470 struct process_id src;
471 char *buf;
472 char *msgs_buf;
473 size_t len, total_len;
474 struct dispatch_fns *dfn;
475 int n_handled;
477 if (!received_signal)
478 return;
480 DEBUG(10,("message_dispatch: received_signal = %d\n", received_signal));
482 received_signal = 0;
484 if (!retrieve_all_messages(&msgs_buf, &total_len))
485 return;
487 for (buf = msgs_buf; message_recv(msgs_buf, total_len, &msg_type, &src, &buf, &len); buf += len) {
488 DEBUG(10,("message_dispatch: received msg_type=%d "
489 "src_pid=%u\n", msg_type,
490 (unsigned int) procid_to_pid(&src)));
491 n_handled = 0;
492 for (dfn = dispatch_fns; dfn; dfn = dfn->next) {
493 if (dfn->msg_type == msg_type) {
494 DEBUG(10,("message_dispatch: processing message of type %d.\n", msg_type));
495 dfn->fn(msg_type, src, len ? (void *)buf : NULL, len);
496 n_handled++;
499 if (!n_handled) {
500 DEBUG(5,("message_dispatch: warning: no handlers registed for "
501 "msg_type %d in pid %u\n",
502 msg_type, (unsigned int)sys_getpid()));
505 SAFE_FREE(msgs_buf);
508 /****************************************************************************
509 Register a dispatch function for a particular message type.
510 *NOTE*: Dispatch functions must be able to cope with incoming
511 messages on an *odd* byte boundary.
512 ****************************************************************************/
514 void message_register(int msg_type,
515 void (*fn)(int msg_type, struct process_id pid,
516 void *buf, size_t len))
518 struct dispatch_fns *dfn;
520 dfn = SMB_MALLOC_P(struct dispatch_fns);
522 if (dfn != NULL) {
524 ZERO_STRUCTPN(dfn);
526 dfn->msg_type = msg_type;
527 dfn->fn = fn;
529 DLIST_ADD(dispatch_fns, dfn);
531 else {
533 DEBUG(0,("message_register: Not enough memory. malloc failed!\n"));
537 /****************************************************************************
538 De-register the function for a particular message type.
539 ****************************************************************************/
541 void message_deregister(int msg_type)
543 struct dispatch_fns *dfn, *next;
545 for (dfn = dispatch_fns; dfn; dfn = next) {
546 next = dfn->next;
547 if (dfn->msg_type == msg_type) {
548 DLIST_REMOVE(dispatch_fns, dfn);
549 SAFE_FREE(dfn);
554 struct msg_all {
555 int msg_type;
556 uint32 msg_flag;
557 const void *buf;
558 size_t len;
559 BOOL duplicates;
560 int n_sent;
563 /****************************************************************************
564 Send one of the messages for the broadcast.
565 ****************************************************************************/
567 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
569 struct connections_data crec;
570 struct msg_all *msg_all = (struct msg_all *)state;
572 if (dbuf.dsize != sizeof(crec))
573 return 0;
575 memcpy(&crec, dbuf.dptr, sizeof(crec));
577 if (crec.cnum != -1)
578 return 0;
580 /* Don't send if the receiver hasn't registered an interest. */
582 if(!(crec.bcast_msg_flags & msg_all->msg_flag))
583 return 0;
585 /* If the msg send fails because the pid was not found (i.e. smbd died),
586 * the msg has already been deleted from the messages.tdb.*/
588 if (!message_send_pid(crec.pid, msg_all->msg_type,
589 msg_all->buf, msg_all->len,
590 msg_all->duplicates)) {
592 /* If the pid was not found delete the entry from connections.tdb */
594 if (errno == ESRCH) {
595 DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n",
596 procid_str_static(&crec.pid),
597 crec.cnum, crec.name));
598 tdb_delete(the_tdb, kbuf);
601 msg_all->n_sent++;
602 return 0;
606 * Send a message to all smbd processes.
608 * It isn't very efficient, but should be OK for the sorts of
609 * applications that use it. When we need efficient broadcast we can add
610 * it.
612 * @param n_sent Set to the number of messages sent. This should be
613 * equal to the number of processes, but be careful for races.
615 * @retval True for success.
617 BOOL message_send_all(TDB_CONTEXT *conn_tdb, int msg_type,
618 const void *buf, size_t len,
619 BOOL duplicates_allowed,
620 int *n_sent)
622 struct msg_all msg_all;
624 msg_all.msg_type = msg_type;
625 if (msg_type < 1000)
626 msg_all.msg_flag = FLAG_MSG_GENERAL;
627 else if (msg_type > 1000 && msg_type < 2000)
628 msg_all.msg_flag = FLAG_MSG_NMBD;
629 else if (msg_type > 2000 && msg_type < 2100)
630 msg_all.msg_flag = FLAG_MSG_PRINT_NOTIFY;
631 else if (msg_type > 2100 && msg_type < 3000)
632 msg_all.msg_flag = FLAG_MSG_PRINT_GENERAL;
633 else if (msg_type > 3000 && msg_type < 4000)
634 msg_all.msg_flag = FLAG_MSG_SMBD;
635 else
636 return False;
638 msg_all.buf = buf;
639 msg_all.len = len;
640 msg_all.duplicates = duplicates_allowed;
641 msg_all.n_sent = 0;
643 tdb_traverse(conn_tdb, traverse_fn, &msg_all);
644 if (n_sent)
645 *n_sent = msg_all.n_sent;
646 return True;
650 * Block and unblock receiving of messages. Allows removal of race conditions
651 * when doing a fork and changing message disposition.
654 void message_block(void)
656 BlockSignals(True, SIGUSR1);
659 void message_unblock(void)
661 BlockSignals(False, SIGUSR1);
663 /** @} **/