kdc: call authsam_zero_bad_pwd_count on successful AS-REQ
[Samba.git] / source3 / lib / messages_local.c
blob1fe89c3bfaacf013a80ff16d938a012a1c264ba7
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;
95 const char *fname;
97 if (have_context) {
98 DEBUG(0, ("No two messaging contexts per process\n"));
99 return NT_STATUS_OBJECT_NAME_COLLISION;
102 if (!(result = talloc(mem_ctx, struct messaging_backend))) {
103 DEBUG(0, ("talloc failed\n"));
104 return NT_STATUS_NO_MEMORY;
107 lp_ctx = loadparm_init_s3(result, loadparm_s3_helpers());
108 if (lp_ctx == NULL) {
109 DEBUG(0, ("loadparm_init_s3 failed\n"));
110 TALLOC_FREE(result);
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;
124 ctx->have_context = &have_context;
126 fname = lock_path("messages.tdb");
128 ctx->tdb = tdb_wrap_open(
129 ctx, fname, lpcfg_tdb_hash_size(lp_ctx, fname),
130 lpcfg_tdb_flags(lp_ctx, TDB_CLEAR_IF_FIRST|TDB_DEFAULT|
131 TDB_VOLATILE| TDB_INCOMPATIBLE_HASH),
132 O_RDWR|O_CREAT,0600);
134 talloc_unlink(result, lp_ctx);
136 if (!ctx->tdb) {
137 NTSTATUS status = map_nt_error_from_unix(errno);
138 DEBUG(2, ("ERROR: Failed to initialise messages database: "
139 "%s\n", strerror(errno)));
140 TALLOC_FREE(result);
141 return status;
144 ctx->se = tevent_add_signal(msg_ctx->event_ctx,
145 ctx,
146 SIGUSR1, 0,
147 messaging_tdb_signal_handler,
148 ctx);
149 if (!ctx->se) {
150 NTSTATUS status = map_nt_error_from_unix(errno);
151 DEBUG(0, ("ERROR: Failed to initialise messages signal handler: "
152 "%s\n", strerror(errno)));
153 TALLOC_FREE(result);
154 return status;
157 sec_init();
159 have_context = true;
160 talloc_set_destructor(ctx, messaging_tdb_context_destructor);
162 *presult = result;
163 return NT_STATUS_OK;
166 static int messaging_tdb_context_destructor(struct messaging_tdb_context *ctx)
168 SMB_ASSERT(*ctx->have_context);
169 *ctx->have_context = false;
170 return 0;
173 bool messaging_tdb_parent_init(TALLOC_CTX *mem_ctx)
175 struct tdb_wrap *db;
176 struct loadparm_context *lp_ctx;
177 const char *fname;
179 lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers());
180 if (lp_ctx == NULL) {
181 DEBUG(0, ("loadparm_init_s3 failed\n"));
182 return false;
186 * Open the tdb in the parent process (smbd) so that our
187 * CLEAR_IF_FIRST optimization in tdb_reopen_all can properly
188 * work.
191 fname = lock_path("messages.tdb");
192 db = tdb_wrap_open(
193 mem_ctx, fname, lpcfg_tdb_hash_size(lp_ctx, fname),
194 lpcfg_tdb_flags(lp_ctx, TDB_CLEAR_IF_FIRST|TDB_DEFAULT|
195 TDB_VOLATILE|TDB_INCOMPATIBLE_HASH),
196 O_RDWR|O_CREAT,0600);
197 talloc_unlink(mem_ctx, lp_ctx);
198 if (db == NULL) {
199 DEBUG(1, ("could not open messaging.tdb: %s\n",
200 strerror(errno)));
201 return false;
203 return true;
206 /*******************************************************************
207 Form a static tdb key from a pid.
208 ******************************************************************/
210 static TDB_DATA message_key_pid(TALLOC_CTX *mem_ctx, struct server_id pid)
212 char *key;
213 TDB_DATA kbuf;
215 key = talloc_asprintf(mem_ctx, "PID/%s", procid_str_static(&pid));
217 SMB_ASSERT(key != NULL);
219 kbuf.dptr = (uint8 *)key;
220 kbuf.dsize = strlen(key)+1;
221 return kbuf;
225 Fetch the messaging array for a process
228 static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
229 TDB_DATA key,
230 TALLOC_CTX *mem_ctx,
231 struct messaging_array **presult)
233 struct messaging_array *result;
234 TDB_DATA data;
235 DATA_BLOB blob;
236 enum ndr_err_code ndr_err;
238 if (!(result = talloc_zero(mem_ctx, struct messaging_array))) {
239 return NT_STATUS_NO_MEMORY;
242 data = tdb_fetch(msg_tdb, key);
244 if (data.dptr == NULL) {
245 *presult = result;
246 return NT_STATUS_OK;
249 blob = data_blob_const(data.dptr, data.dsize);
251 ndr_err = ndr_pull_struct_blob_all(
252 &blob, result, result,
253 (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
255 SAFE_FREE(data.dptr);
257 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
258 TALLOC_FREE(result);
259 return ndr_map_error2ntstatus(ndr_err);
262 if (DEBUGLEVEL >= 10) {
263 DEBUG(10, ("messaging_tdb_fetch:\n"));
264 NDR_PRINT_DEBUG(messaging_array, result);
267 *presult = result;
268 return NT_STATUS_OK;
272 Store a messaging array for a pid
275 static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
276 TDB_DATA key,
277 struct messaging_array *array)
279 TDB_DATA data;
280 DATA_BLOB blob;
281 enum ndr_err_code ndr_err;
282 TALLOC_CTX *mem_ctx;
283 int ret;
285 if (array->num_messages == 0) {
286 tdb_delete(msg_tdb, key);
287 return NT_STATUS_OK;
290 if (!(mem_ctx = talloc_new(array))) {
291 return NT_STATUS_NO_MEMORY;
294 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, array,
295 (ndr_push_flags_fn_t)ndr_push_messaging_array);
297 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
298 talloc_free(mem_ctx);
299 return ndr_map_error2ntstatus(ndr_err);
302 if (DEBUGLEVEL >= 10) {
303 DEBUG(10, ("messaging_tdb_store:\n"));
304 NDR_PRINT_DEBUG(messaging_array, array);
307 data.dptr = blob.data;
308 data.dsize = blob.length;
310 ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
311 TALLOC_FREE(mem_ctx);
313 return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
316 /****************************************************************************
317 Notify a process that it has a message. If the process doesn't exist
318 then delete its record in the database.
319 ****************************************************************************/
321 static NTSTATUS message_notify(struct server_id procid)
323 pid_t pid = procid.pid;
324 int ret;
325 uid_t euid = geteuid();
328 * Doing kill with a non-positive pid causes messages to be
329 * sent to places we don't want.
332 SMB_ASSERT(pid > 0);
333 if (pid <= 0) {
334 return NT_STATUS_INVALID_HANDLE;
337 if (euid != 0) {
338 /* If we're not root become so to send the message. */
339 save_re_uid();
340 set_effective_uid(0);
343 ret = kill(pid, SIGUSR1);
345 if (euid != 0) {
346 /* Go back to who we were. */
347 int saved_errno = errno;
348 restore_re_uid_fromroot();
349 errno = saved_errno;
352 if (ret == 0) {
353 return NT_STATUS_OK;
357 * Something has gone wrong
360 DEBUG(2,("message to process %d failed - %s\n", (int)pid,
361 strerror(errno)));
364 * No call to map_nt_error_from_unix -- don't want to link in
365 * errormap.o into lots of utils.
368 if (errno == ESRCH) return NT_STATUS_INVALID_HANDLE;
369 if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
370 if (errno == EPERM) return NT_STATUS_ACCESS_DENIED;
371 return NT_STATUS_UNSUCCESSFUL;
374 /****************************************************************************
375 Send a message to a particular pid.
376 ****************************************************************************/
378 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
379 struct server_id pid, int msg_type,
380 const DATA_BLOB *data,
381 struct messaging_backend *backend)
383 struct messaging_tdb_context *ctx = talloc_get_type(backend->private_data,
384 struct messaging_tdb_context);
385 struct messaging_array *msg_array;
386 struct messaging_rec *rec;
387 NTSTATUS status;
388 TDB_DATA key;
389 struct tdb_wrap *tdb = ctx->tdb;
390 TALLOC_CTX *frame = talloc_stackframe();
392 /* NULL pointer means implicit length zero. */
393 if (!data->data) {
394 SMB_ASSERT(data->length == 0);
398 * Doing kill with a non-positive pid causes messages to be
399 * sent to places we don't want.
402 SMB_ASSERT(procid_to_pid(&pid) > 0);
404 key = message_key_pid(frame, pid);
406 if (tdb_chainlock(tdb->tdb, key) != 0) {
407 TALLOC_FREE(frame);
408 return NT_STATUS_LOCK_NOT_GRANTED;
411 status = messaging_tdb_fetch(tdb->tdb, key, frame, &msg_array);
413 if (!NT_STATUS_IS_OK(status)) {
414 goto done;
417 if ((msg_type & MSG_FLAG_LOWPRIORITY)
418 && (msg_array->num_messages > 1000)) {
419 DEBUG(5, ("Dropping message for PID %s\n",
420 procid_str_static(&pid)));
421 status = NT_STATUS_INSUFFICIENT_RESOURCES;
422 goto done;
425 if (!(rec = talloc_realloc(frame, msg_array->messages,
426 struct messaging_rec,
427 msg_array->num_messages+1))) {
428 status = NT_STATUS_NO_MEMORY;
429 goto done;
432 rec[msg_array->num_messages].msg_version = MESSAGE_VERSION;
433 rec[msg_array->num_messages].msg_type = msg_type & MSG_TYPE_MASK;
434 rec[msg_array->num_messages].dest = pid;
435 rec[msg_array->num_messages].src = msg_ctx->id;
436 rec[msg_array->num_messages].buf = *data;
438 msg_array->messages = rec;
439 msg_array->num_messages += 1;
441 status = messaging_tdb_store(tdb->tdb, key, msg_array);
443 if (!NT_STATUS_IS_OK(status)) {
444 goto done;
447 status = message_notify(pid);
449 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
450 DEBUG(2, ("pid %s doesn't exist - deleting messages record\n",
451 procid_str_static(&pid)));
452 tdb_delete(tdb->tdb, message_key_pid(frame, pid));
455 done:
456 tdb_chainunlock(tdb->tdb, key);
457 TALLOC_FREE(frame);
458 return status;
461 /****************************************************************************
462 Retrieve all messages for a process.
463 ****************************************************************************/
465 static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb,
466 struct server_id id,
467 TALLOC_CTX *mem_ctx,
468 struct messaging_array **presult)
470 struct messaging_array *result;
471 TDB_DATA key = message_key_pid(mem_ctx, id);
472 NTSTATUS status;
474 if (tdb_chainlock(msg_tdb, key) != 0) {
475 TALLOC_FREE(key.dptr);
476 return NT_STATUS_LOCK_NOT_GRANTED;
479 status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
482 * We delete the record here, tdb_set_max_dead keeps it around
484 tdb_delete(msg_tdb, key);
485 tdb_chainunlock(msg_tdb, key);
487 if (NT_STATUS_IS_OK(status)) {
488 *presult = result;
491 TALLOC_FREE(key.dptr);
493 return status;
496 /****************************************************************************
497 Receive and dispatch any messages pending for this process.
498 JRA changed Dec 13 2006. Only one message handler now permitted per type.
499 *NOTE*: Dispatch functions must be able to cope with incoming
500 messages on an *odd* byte boundary.
501 ****************************************************************************/
503 static void message_dispatch(struct messaging_context *msg_ctx)
505 struct messaging_tdb_context *ctx = talloc_get_type(msg_ctx->local->private_data,
506 struct messaging_tdb_context);
507 struct messaging_array *msg_array = NULL;
508 struct tdb_wrap *tdb = ctx->tdb;
509 NTSTATUS status;
510 uint32 i;
512 if (ctx->received_messages == 0) {
513 return;
516 DEBUG(10, ("message_dispatch: received_messages = %d\n",
517 ctx->received_messages));
519 status = retrieve_all_messages(tdb->tdb, msg_ctx->id, NULL, &msg_array);
520 if (!NT_STATUS_IS_OK(status)) {
521 DEBUG(0, ("message_dispatch: failed to retrieve messages: %s\n",
522 nt_errstr(status)));
523 return;
526 ctx->received_messages = 0;
528 for (i=0; i<msg_array->num_messages; i++) {
529 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
532 TALLOC_FREE(msg_array);
535 /** @} **/