r23779: Change from v2 or later to v3 or later.
[jra/samba/.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 3 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 static int received_signal;
51
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);
56
57 /****************************************************************************
58  Notifications come in as signals.
59 ****************************************************************************/
60
61 static void sig_usr1(void)
62 {
63         received_signal = 1;
64         sys_select_signal(SIGUSR1);
65 }
66
67 static int messaging_tdb_destructor(struct messaging_backend *tdb_ctx)
68 {
69         TDB_CONTEXT *tdb = (TDB_CONTEXT *)tdb_ctx->private_data;
70         tdb_close(tdb);
71         return 0;
72 }
73
74 /****************************************************************************
75  Initialise the messaging functions. 
76 ****************************************************************************/
77
78 NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx,
79                             TALLOC_CTX *mem_ctx,
80                             struct messaging_backend **presult)
81 {
82         struct messaging_backend *result;
83         TDB_CONTEXT *tdb;
84
85         if (!(result = TALLOC_P(mem_ctx, struct messaging_backend))) {
86                 DEBUG(0, ("talloc failed\n"));
87                 return NT_STATUS_NO_MEMORY;
88         }
89
90         tdb = tdb_open_log(lock_path("messages.tdb"), 
91                            0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, 
92                            O_RDWR|O_CREAT,0600);
93
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;
100         }
101
102         sec_init();
103
104         /* Activate the per-hashchain freelist */
105         tdb_set_max_dead(tdb, 5);
106
107         CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1);
108
109         result->private_data = (void *)tdb;
110         result->send_fn = messaging_tdb_send;
111
112         talloc_set_destructor(result, messaging_tdb_destructor);
113
114         *presult = result;
115         return NT_STATUS_OK;
116 }
117
118 /*******************************************************************
119  Form a static tdb key from a pid.
120 ******************************************************************/
121
122 static TDB_DATA message_key_pid(struct server_id pid)
123 {
124         static char key[20];
125         TDB_DATA kbuf;
126
127         slprintf(key, sizeof(key)-1, "PID/%s", procid_str_static(&pid));
128         
129         kbuf.dptr = (uint8 *)key;
130         kbuf.dsize = strlen(key)+1;
131         return kbuf;
132 }
133
134 /*
135   Fetch the messaging array for a process
136  */
137
138 static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
139                                     TDB_DATA key,
140                                     TALLOC_CTX *mem_ctx,
141                                     struct messaging_array **presult)
142 {
143         struct messaging_array *result;
144         TDB_DATA data;
145         DATA_BLOB blob;
146         NTSTATUS status;
147
148         if (!(result = TALLOC_ZERO_P(mem_ctx, struct messaging_array))) {
149                 return NT_STATUS_NO_MEMORY;
150         }
151
152         data = tdb_fetch(msg_tdb, key);
153
154         if (data.dptr == NULL) {
155                 *presult = result;
156                 return NT_STATUS_OK;
157         }
158
159         blob = data_blob_const(data.dptr, data.dsize);
160
161         status = ndr_pull_struct_blob(
162                 &blob, result, result,
163                 (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
164
165         SAFE_FREE(data.dptr);
166
167         if (!NT_STATUS_IS_OK(status)) {
168                 TALLOC_FREE(result);
169                 return status;
170         }
171
172         if (DEBUGLEVEL >= 10) {
173                 DEBUG(10, ("messaging_tdb_fetch:\n"));
174                 NDR_PRINT_DEBUG(messaging_array, result);
175         }
176
177         *presult = result;
178         return NT_STATUS_OK;
179 }
180
181 /*
182   Store a messaging array for a pid
183 */
184
185 static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
186                                     TDB_DATA key,
187                                     struct messaging_array *array)
188 {
189         TDB_DATA data;
190         DATA_BLOB blob;
191         NTSTATUS status;
192         TALLOC_CTX *mem_ctx;
193         int ret;
194
195         if (array->num_messages == 0) {
196                 tdb_delete(msg_tdb, key);
197                 return NT_STATUS_OK;
198         }
199
200         if (!(mem_ctx = talloc_new(array))) {
201                 return NT_STATUS_NO_MEMORY;
202         }
203
204         status = ndr_push_struct_blob(
205                 &blob, mem_ctx, array,
206                 (ndr_push_flags_fn_t)ndr_push_messaging_array);
207
208         if (!NT_STATUS_IS_OK(status)) {
209                 talloc_free(mem_ctx);
210                 return status;
211         }
212
213         if (DEBUGLEVEL >= 10) {
214                 DEBUG(10, ("messaging_tdb_store:\n"));
215                 NDR_PRINT_DEBUG(messaging_array, array);
216         }
217
218         data.dptr = blob.data;
219         data.dsize = blob.length;
220
221         ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
222         TALLOC_FREE(mem_ctx);
223
224         return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
225 }
226
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 ****************************************************************************/
231
232 static NTSTATUS message_notify(struct server_id procid)
233 {
234         pid_t pid = procid.pid;
235         int ret;
236         uid_t euid = geteuid();
237
238         /*
239          * Doing kill with a non-positive pid causes messages to be
240          * sent to places we don't want.
241          */
242
243         SMB_ASSERT(pid > 0);
244
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);
249         }
250
251         ret = kill(pid, SIGUSR1);
252
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;
258         }
259
260         if (ret == 0) {
261                 return NT_STATUS_OK;
262         }
263
264         /*
265          * Something has gone wrong
266          */
267
268         DEBUG(2,("message to process %d failed - %s\n", (int)pid,
269                  strerror(errno)));
270
271         /*
272          * No call to map_nt_error_from_unix -- don't want to link in
273          * errormap.o into lots of utils.
274          */
275
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;
280 }
281
282 /****************************************************************************
283  Send a message to a particular pid.
284 ****************************************************************************/
285
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)
290 {
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;
297
298         /* NULL pointer means implicit length zero. */
299         if (!data->data) {
300                 SMB_ASSERT(data->length == 0);
301         }
302
303         /*
304          * Doing kill with a non-positive pid causes messages to be
305          * sent to places we don't want.
306          */
307
308         SMB_ASSERT(procid_to_pid(&pid) > 0);
309
310         if (!(mem_ctx = talloc_init("message_send_pid"))) {
311                 return NT_STATUS_NO_MEMORY;
312         }
313
314         if (tdb_chainlock(tdb, key) == -1) {
315                 TALLOC_FREE(mem_ctx);
316                 return NT_STATUS_LOCK_NOT_GRANTED;
317         }
318
319         status = messaging_tdb_fetch(tdb, key, mem_ctx, &msg_array);
320
321         if (!NT_STATUS_IS_OK(status)) {
322                 goto done;
323         }
324
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;
331         }
332
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;
338         }
339
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;
345
346         msg_array->messages = rec;
347         msg_array->num_messages += 1;
348
349         status = messaging_tdb_store(tdb, key, msg_array);
350
351         if (!NT_STATUS_IS_OK(status)) {
352                 goto done;
353         }
354         
355         status = message_notify(pid);
356
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));
361         }
362
363  done:
364         tdb_chainunlock(tdb, key);
365         TALLOC_FREE(mem_ctx);
366         return status;
367 }
368
369 /****************************************************************************
370  Retrieve all messages for the current process.
371 ****************************************************************************/
372
373 static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb,
374                                       TALLOC_CTX *mem_ctx,
375                                       struct messaging_array **presult)
376 {
377         struct messaging_array *result;
378         TDB_DATA key = message_key_pid(procid_self());
379         NTSTATUS status;
380
381         if (tdb_chainlock(msg_tdb, key) == -1) {
382                 return NT_STATUS_LOCK_NOT_GRANTED;
383         }
384
385         status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
386
387         /*
388          * We delete the record here, tdb_set_max_dead keeps it around
389          */
390         tdb_delete(msg_tdb, key);
391         tdb_chainunlock(msg_tdb, key);
392
393         if (NT_STATUS_IS_OK(status)) {
394                 *presult = result;
395         }
396
397         return status;
398 }
399
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 ****************************************************************************/
406
407 void message_dispatch(struct messaging_context *msg_ctx)
408 {
409         struct messaging_array *msg_array = NULL;
410         TDB_CONTEXT *tdb = (TDB_CONTEXT *)(msg_ctx->local->private_data);
411         uint32 i;
412
413         if (!received_signal)
414                 return;
415
416         DEBUG(10, ("message_dispatch: received_signal = %d\n",
417                    received_signal));
418
419         received_signal = 0;
420
421         if (!NT_STATUS_IS_OK(retrieve_all_messages(tdb, NULL, &msg_array))) {
422                 return;
423         }
424
425         for (i=0; i<msg_array->num_messages; i++) {
426                 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
427         }
428
429         TALLOC_FREE(msg_array);
430 }
431
432 /** @} **/