r23344: Better error message
[obnox/samba-ctdb.git] / source3 / lib / messages_local.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba internal messaging functions
4    Copyright (C) 2007 by Volker Lendecke
5    
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.
10    
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.
15    
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.
19 */
20
21 /**
22   @defgroup messages Internal messaging framework
23   @{
24   @file messages.c
25   
26   @brief  Module for internal messaging between Samba daemons. 
27
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.
32
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.
36
37    @caution Dispatch functions must be able to cope with incoming
38    messages on an *odd* byte boundary.
39
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.
43
44 */
45
46 #include "includes.h"
47 #include "librpc/gen_ndr/messaging.h"
48 #include "librpc/gen_ndr/ndr_messaging.h"
49
50 /* the locking database handle */
51 static int received_signal;
52
53 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
54                                    struct server_id pid, int msg_type,
55                                    const DATA_BLOB *data,
56                                    struct messaging_backend *backend);
57
58 /****************************************************************************
59  Notifications come in as signals.
60 ****************************************************************************/
61
62 static void sig_usr1(void)
63 {
64         received_signal = 1;
65         sys_select_signal(SIGUSR1);
66 }
67
68 static int messaging_tdb_destructor(struct messaging_backend *tdb_ctx)
69 {
70         TDB_CONTEXT *tdb = (TDB_CONTEXT *)tdb_ctx->private_data;
71         tdb_close(tdb);
72         return 0;
73 }
74
75 /****************************************************************************
76  Initialise the messaging functions. 
77 ****************************************************************************/
78
79 NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx,
80                             TALLOC_CTX *mem_ctx,
81                             struct messaging_backend **presult)
82 {
83         struct messaging_backend *result;
84         TDB_CONTEXT *tdb;
85
86         if (!(result = TALLOC_P(mem_ctx, struct messaging_backend))) {
87                 DEBUG(0, ("talloc failed\n"));
88                 return NT_STATUS_NO_MEMORY;
89         }
90
91         tdb = tdb_open_log(lock_path("messages.tdb"), 
92                            0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, 
93                            O_RDWR|O_CREAT,0600);
94
95         if (!tdb) {
96                 NTSTATUS status = map_nt_error_from_unix(errno);
97                 DEBUG(0, ("ERROR: Failed to initialise messages database: "
98                           "%s\n", strerror(errno)));
99                 TALLOC_FREE(result);
100                 return status;
101         }
102
103         sec_init();
104
105         /* Activate the per-hashchain freelist */
106         tdb_set_max_dead(tdb, 5);
107
108         CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1);
109
110         result->private_data = (void *)tdb;
111         result->send_fn = messaging_tdb_send;
112
113         talloc_set_destructor(result, messaging_tdb_destructor);
114
115         *presult = result;
116         return NT_STATUS_OK;
117 }
118
119 /*******************************************************************
120  Form a static tdb key from a pid.
121 ******************************************************************/
122
123 static TDB_DATA message_key_pid(struct server_id pid)
124 {
125         static char key[20];
126         TDB_DATA kbuf;
127
128         slprintf(key, sizeof(key)-1, "PID/%s", procid_str_static(&pid));
129         
130         kbuf.dptr = (uint8 *)key;
131         kbuf.dsize = strlen(key)+1;
132         return kbuf;
133 }
134
135 /*
136   Fetch the messaging array for a process
137  */
138
139 static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
140                                     TDB_DATA key,
141                                     TALLOC_CTX *mem_ctx,
142                                     struct messaging_array **presult)
143 {
144         struct messaging_array *result;
145         TDB_DATA data;
146         DATA_BLOB blob;
147         NTSTATUS status;
148
149         if (!(result = TALLOC_ZERO_P(mem_ctx, struct messaging_array))) {
150                 return NT_STATUS_NO_MEMORY;
151         }
152
153         data = tdb_fetch(msg_tdb, key);
154
155         if (data.dptr == NULL) {
156                 *presult = result;
157                 return NT_STATUS_OK;
158         }
159
160         blob = data_blob_const(data.dptr, data.dsize);
161
162         status = ndr_pull_struct_blob(
163                 &blob, result, result,
164                 (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
165
166         SAFE_FREE(data.dptr);
167
168         if (!NT_STATUS_IS_OK(status)) {
169                 TALLOC_FREE(result);
170                 return status;
171         }
172
173         if (DEBUGLEVEL >= 10) {
174                 DEBUG(10, ("messaging_tdb_fetch:\n"));
175                 NDR_PRINT_DEBUG(messaging_array, result);
176         }
177
178         *presult = result;
179         return NT_STATUS_OK;
180 }
181
182 /*
183   Store a messaging array for a pid
184 */
185
186 static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
187                                     TDB_DATA key,
188                                     struct messaging_array *array)
189 {
190         TDB_DATA data;
191         DATA_BLOB blob;
192         NTSTATUS status;
193         TALLOC_CTX *mem_ctx;
194         int ret;
195
196         if (array->num_messages == 0) {
197                 tdb_delete(msg_tdb, key);
198                 return NT_STATUS_OK;
199         }
200
201         if (!(mem_ctx = talloc_new(array))) {
202                 return NT_STATUS_NO_MEMORY;
203         }
204
205         status = ndr_push_struct_blob(
206                 &blob, mem_ctx, array,
207                 (ndr_push_flags_fn_t)ndr_push_messaging_array);
208
209         if (!NT_STATUS_IS_OK(status)) {
210                 talloc_free(mem_ctx);
211                 return status;
212         }
213
214         if (DEBUGLEVEL >= 10) {
215                 DEBUG(10, ("messaging_tdb_store:\n"));
216                 NDR_PRINT_DEBUG(messaging_array, array);
217         }
218
219         data.dptr = blob.data;
220         data.dsize = blob.length;
221
222         ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
223         TALLOC_FREE(mem_ctx);
224
225         return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
226 }
227
228 /****************************************************************************
229  Notify a process that it has a message. If the process doesn't exist 
230  then delete its record in the database.
231 ****************************************************************************/
232
233 static NTSTATUS message_notify(struct server_id procid)
234 {
235         pid_t pid = procid.pid;
236         int ret;
237         uid_t euid = geteuid();
238
239         /*
240          * Doing kill with a non-positive pid causes messages to be
241          * sent to places we don't want.
242          */
243
244         SMB_ASSERT(pid > 0);
245
246         if (euid != 0) {
247                 /* If we're not root become so to send the message. */
248                 save_re_uid();
249                 set_effective_uid(0);
250         }
251
252         ret = kill(pid, SIGUSR1);
253
254         if (euid != 0) {
255                 /* Go back to who we were. */
256                 int saved_errno = errno;
257                 restore_re_uid_fromroot();
258                 errno = saved_errno;
259         }
260
261         if (ret == 0) {
262                 return NT_STATUS_OK;
263         }
264
265         /*
266          * Something has gone wrong
267          */
268
269         DEBUG(2,("message to process %d failed - %s\n", (int)pid,
270                  strerror(errno)));
271
272         /*
273          * No call to map_nt_error_from_unix -- don't want to link in
274          * errormap.o into lots of utils.
275          */
276
277         if (errno == ESRCH)  return NT_STATUS_INVALID_HANDLE;
278         if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
279         if (errno == EPERM)  return NT_STATUS_ACCESS_DENIED;
280         return NT_STATUS_UNSUCCESSFUL;
281 }
282
283 /****************************************************************************
284  Send a message to a particular pid.
285 ****************************************************************************/
286
287 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
288                                    struct server_id pid, int msg_type,
289                                    const DATA_BLOB *data,
290                                    struct messaging_backend *backend)
291 {
292         struct messaging_array *msg_array;
293         struct messaging_rec *rec;
294         TALLOC_CTX *mem_ctx;
295         NTSTATUS status;
296         TDB_DATA key = message_key_pid(pid);
297         TDB_CONTEXT *tdb = (TDB_CONTEXT *)backend->private_data;
298
299         /* NULL pointer means implicit length zero. */
300         if (!data->data) {
301                 SMB_ASSERT(data->length == 0);
302         }
303
304         /*
305          * Doing kill with a non-positive pid causes messages to be
306          * sent to places we don't want.
307          */
308
309         SMB_ASSERT(procid_to_pid(&pid) > 0);
310
311         if (!(mem_ctx = talloc_init("message_send_pid"))) {
312                 return NT_STATUS_NO_MEMORY;
313         }
314
315         if (tdb_chainlock(tdb, key) == -1) {
316                 TALLOC_FREE(mem_ctx);
317                 return NT_STATUS_LOCK_NOT_GRANTED;
318         }
319
320         status = messaging_tdb_fetch(tdb, key, mem_ctx, &msg_array);
321
322         if (!NT_STATUS_IS_OK(status)) {
323                 goto done;
324         }
325
326         if ((msg_type & MSG_FLAG_LOWPRIORITY)
327             && (msg_array->num_messages > 1000)) {
328                 DEBUG(5, ("Dropping message for PID %s\n",
329                           procid_str_static(&pid)));
330                 status = NT_STATUS_INSUFFICIENT_RESOURCES;
331                 goto done;
332         }
333
334         if (!(rec = TALLOC_REALLOC_ARRAY(mem_ctx, msg_array->messages,
335                                          struct messaging_rec,
336                                          msg_array->num_messages+1))) {
337                 status = NT_STATUS_NO_MEMORY;
338                 goto done;
339         }
340
341         rec[msg_array->num_messages].msg_version = MESSAGE_VERSION;
342         rec[msg_array->num_messages].msg_type = msg_type & MSG_TYPE_MASK;
343         rec[msg_array->num_messages].dest = pid;
344         rec[msg_array->num_messages].src = procid_self();
345         rec[msg_array->num_messages].buf = *data;
346
347         msg_array->messages = rec;
348         msg_array->num_messages += 1;
349
350         status = messaging_tdb_store(tdb, key, msg_array);
351
352         if (!NT_STATUS_IS_OK(status)) {
353                 goto done;
354         }
355         
356         status = message_notify(pid);
357
358         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
359                 DEBUG(2, ("pid %s doesn't exist - deleting messages record\n",
360                           procid_str_static(&pid)));
361                 tdb_delete(tdb, message_key_pid(pid));
362         }
363
364  done:
365         tdb_chainunlock(tdb, key);
366         TALLOC_FREE(mem_ctx);
367         return status;
368 }
369
370 /****************************************************************************
371  Retrieve all messages for the current process.
372 ****************************************************************************/
373
374 static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb,
375                                       TALLOC_CTX *mem_ctx,
376                                       struct messaging_array **presult)
377 {
378         struct messaging_array *result;
379         TDB_DATA key = message_key_pid(procid_self());
380         NTSTATUS status;
381
382         if (tdb_chainlock(msg_tdb, key) == -1) {
383                 return NT_STATUS_LOCK_NOT_GRANTED;
384         }
385
386         status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
387
388         /*
389          * We delete the record here, tdb_set_max_dead keeps it around
390          */
391         tdb_delete(msg_tdb, key);
392         tdb_chainunlock(msg_tdb, key);
393
394         if (NT_STATUS_IS_OK(status)) {
395                 *presult = result;
396         }
397
398         return status;
399 }
400
401 /****************************************************************************
402  Receive and dispatch any messages pending for this process.
403  JRA changed Dec 13 2006. Only one message handler now permitted per type.
404  *NOTE*: Dispatch functions must be able to cope with incoming
405  messages on an *odd* byte boundary.
406 ****************************************************************************/
407
408 void message_dispatch(struct messaging_context *msg_ctx)
409 {
410         struct messaging_array *msg_array = NULL;
411         TDB_CONTEXT *tdb = (TDB_CONTEXT *)(msg_ctx->local->private_data);
412         uint32 i;
413
414         if (!received_signal)
415                 return;
416
417         DEBUG(10, ("message_dispatch: received_signal = %d\n",
418                    received_signal));
419
420         received_signal = 0;
421
422         if (!NT_STATUS_IS_OK(retrieve_all_messages(tdb, NULL, &msg_array))) {
423                 return;
424         }
425
426         for (i=0; i<msg_array->num_messages; i++) {
427                 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
428         }
429
430         TALLOC_FREE(msg_array);
431 }
432
433 /** @} **/