provision/sambadns: remove redundant site parameter
[Samba.git] / source3 / lib / messages_dgm.c
blobc3ab0d166cfca3a11ac5672493bad6a1d98194f9
1 /*
2 * Unix SMB/CIFS implementation.
3 * Samba internal messaging functions
4 * Copyright (C) 2013 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 #include "includes.h"
21 #include "lib/util/data_blob.h"
22 #include "lib/util/debug.h"
23 #include "lib/unix_msg/unix_msg.h"
24 #include "system/filesys.h"
25 #include "messages.h"
26 #include "lib/param/param.h"
27 #include "poll_funcs/poll_funcs_tevent.h"
28 #include "unix_msg/unix_msg.h"
29 #include "librpc/gen_ndr/messaging.h"
31 struct messaging_dgm_context {
32 struct messaging_context *msg_ctx;
33 struct poll_funcs *msg_callbacks;
34 void *tevent_handle;
35 struct unix_msg_ctx *dgm_ctx;
36 char *cache_dir;
37 int lockfile_fd;
40 struct messaging_dgm_hdr {
41 uint32_t msg_version;
42 enum messaging_type msg_type;
43 struct server_id dst;
44 struct server_id src;
47 static NTSTATUS messaging_dgm_send(struct server_id src,
48 struct server_id pid, int msg_type,
49 const struct iovec *iov, int iovlen,
50 struct messaging_backend *backend);
51 static void messaging_dgm_recv(struct unix_msg_ctx *ctx,
52 uint8_t *msg, size_t msg_len,
53 void *private_data);
55 static int messaging_dgm_context_destructor(struct messaging_dgm_context *c);
57 static int messaging_dgm_lockfile_create(const char *cache_dir, pid_t pid,
58 int *plockfile_fd, uint64_t unique)
60 char buf[PATH_MAX];
61 char *dir, *to_free;
62 ssize_t dirlen;
63 char *lockfile_name;
64 int lockfile_fd;
65 struct flock lck = {};
66 int unique_len, ret;
67 ssize_t written;
68 bool ok;
70 dirlen = full_path_tos(cache_dir, "lck", buf, sizeof(buf),
71 &dir, &to_free);
72 if (dirlen == -1) {
73 return ENOMEM;
76 ok = directory_create_or_exist_strict(dir, sec_initial_uid(), 0755);
77 if (!ok) {
78 ret = errno;
79 DEBUG(1, ("%s: Could not create lock directory: %s\n",
80 __func__, strerror(ret)));
81 TALLOC_FREE(to_free);
82 return ret;
85 lockfile_name = talloc_asprintf(talloc_tos(), "%s/%u", dir,
86 (unsigned)pid);
87 TALLOC_FREE(to_free);
88 if (lockfile_name == NULL) {
89 DEBUG(1, ("%s: talloc_asprintf failed\n", __func__));
90 return ENOMEM;
93 /* no O_EXCL, existence check is via the fcntl lock */
95 lockfile_fd = open(lockfile_name, O_NONBLOCK|O_CREAT|O_WRONLY, 0644);
96 if (lockfile_fd == -1) {
97 ret = errno;
98 DEBUG(1, ("%s: open failed: %s\n", __func__, strerror(errno)));
99 goto fail_free;
102 lck.l_type = F_WRLCK;
103 lck.l_whence = SEEK_SET;
104 lck.l_start = 0;
105 lck.l_len = 0;
107 ret = fcntl(lockfile_fd, F_SETLK, &lck);
108 if (ret == -1) {
109 ret = errno;
110 DEBUG(1, ("%s: fcntl failed: %s\n", __func__, strerror(ret)));
111 goto fail_close;
114 unique_len = snprintf(buf, sizeof(buf), "%"PRIu64, unique);
116 /* shorten a potentially preexisting file */
118 ret = ftruncate(lockfile_fd, unique_len);
119 if (ret == -1) {
120 ret = errno;
121 DEBUG(1, ("%s: ftruncate failed: %s\n", __func__,
122 strerror(ret)));
123 goto fail_unlink;
126 written = write(lockfile_fd, buf, unique_len);
127 if (written != unique_len) {
128 ret = errno;
129 DEBUG(1, ("%s: write failed: %s\n", __func__, strerror(ret)));
130 goto fail_unlink;
133 TALLOC_FREE(lockfile_name);
134 *plockfile_fd = lockfile_fd;
135 return 0;
137 fail_unlink:
138 unlink(lockfile_name);
139 fail_close:
140 close(lockfile_fd);
141 fail_free:
142 TALLOC_FREE(lockfile_name);
143 return ret;
146 static int messaging_dgm_lockfile_remove(const char *cache_dir, pid_t pid)
148 fstring fname;
149 char buf[PATH_MAX];
150 char *lockfile_name, *to_free;
151 ssize_t len;
152 int ret;
154 fstr_sprintf(fname, "lck/%u", (unsigned)pid);
156 len = full_path_tos(cache_dir, fname, buf, sizeof(buf),
157 &lockfile_name, &to_free);
158 if (len == -1) {
159 return ENOMEM;
162 ret = unlink(lockfile_name);
163 if (ret == -1) {
164 ret = errno;
165 DEBUG(10, ("%s: unlink failed: %s\n", __func__,
166 strerror(ret)));
168 TALLOC_FREE(to_free);
169 return ret;
172 NTSTATUS messaging_dgm_init(struct messaging_context *msg_ctx,
173 TALLOC_CTX *mem_ctx,
174 struct messaging_backend **presult)
176 struct messaging_backend *result;
177 struct messaging_dgm_context *ctx;
178 struct server_id pid = messaging_server_id(msg_ctx);
179 int ret;
180 bool ok;
181 const char *cache_dir;
182 char *socket_dir, *socket_name;
183 uint64_t cookie;
185 cache_dir = lp_cache_directory();
186 if (cache_dir == NULL) {
187 NTSTATUS status = map_nt_error_from_unix(errno);
188 return status;
191 result = talloc(mem_ctx, struct messaging_backend);
192 if (result == NULL) {
193 goto fail_nomem;
195 ctx = talloc_zero(result, struct messaging_dgm_context);
196 if (ctx == NULL) {
197 goto fail_nomem;
200 result->private_data = ctx;
201 result->send_fn = messaging_dgm_send;
202 ctx->msg_ctx = msg_ctx;
204 ctx->cache_dir = talloc_strdup(ctx, cache_dir);
205 if (ctx->cache_dir == NULL) {
206 goto fail_nomem;
208 socket_dir = talloc_asprintf(ctx, "%s/msg", cache_dir);
209 if (socket_dir == NULL) {
210 goto fail_nomem;
212 socket_name = talloc_asprintf(ctx, "%s/%u", socket_dir,
213 (unsigned)pid.pid);
214 if (socket_name == NULL) {
215 goto fail_nomem;
218 sec_init();
220 ret = messaging_dgm_lockfile_create(cache_dir, pid.pid,
221 &ctx->lockfile_fd, pid.unique_id);
222 if (ret != 0) {
223 DEBUG(1, ("%s: messaging_dgm_create_lockfile failed: %s\n",
224 __func__, strerror(ret)));
225 TALLOC_FREE(result);
226 return map_nt_error_from_unix(ret);
229 ctx->msg_callbacks = poll_funcs_init_tevent(ctx);
230 if (ctx->msg_callbacks == NULL) {
231 TALLOC_FREE(result);
232 return NT_STATUS_NO_MEMORY;
235 ctx->tevent_handle = poll_funcs_tevent_register(
236 ctx, ctx->msg_callbacks,
237 messaging_tevent_context(msg_ctx));
238 if (ctx->tevent_handle == NULL) {
239 TALLOC_FREE(result);
240 return NT_STATUS_NO_MEMORY;
243 ok = directory_create_or_exist_strict(socket_dir, sec_initial_uid(),
244 0700);
245 if (!ok) {
246 DEBUG(1, ("Could not create socket directory\n"));
247 TALLOC_FREE(result);
248 return NT_STATUS_ACCESS_DENIED;
250 TALLOC_FREE(socket_dir);
252 unlink(socket_name);
254 generate_random_buffer((uint8_t *)&cookie, sizeof(cookie));
256 ret = unix_msg_init(socket_name, ctx->msg_callbacks, 1024, cookie,
257 messaging_dgm_recv, ctx, &ctx->dgm_ctx);
258 TALLOC_FREE(socket_name);
259 if (ret != 0) {
260 DEBUG(1, ("unix_msg_init failed: %s\n", strerror(ret)));
261 TALLOC_FREE(result);
262 return map_nt_error_from_unix(ret);
264 talloc_set_destructor(ctx, messaging_dgm_context_destructor);
266 *presult = result;
267 return NT_STATUS_OK;
269 fail_nomem:
270 TALLOC_FREE(result);
271 return NT_STATUS_NO_MEMORY;
274 static int messaging_dgm_context_destructor(struct messaging_dgm_context *c)
276 struct server_id pid = messaging_server_id(c->msg_ctx);
279 * First delete the socket to avoid races. The lockfile is the
280 * indicator that we're still around.
282 unix_msg_free(c->dgm_ctx);
284 if (getpid() == pid.pid) {
285 (void)messaging_dgm_lockfile_remove(c->cache_dir, pid.pid);
287 close(c->lockfile_fd);
288 return 0;
291 static NTSTATUS messaging_dgm_send(struct server_id src,
292 struct server_id pid, int msg_type,
293 const struct iovec *iov, int iovlen,
294 struct messaging_backend *backend)
296 struct messaging_dgm_context *ctx = talloc_get_type_abort(
297 backend->private_data, struct messaging_dgm_context);
298 fstring pid_str;
299 char buf[PATH_MAX];
300 char *dst_sock, *to_free;
301 struct messaging_dgm_hdr hdr;
302 struct iovec iov2[iovlen + 1];
303 ssize_t pathlen;
304 struct server_id_buf idbuf;
305 int ret;
307 fstr_sprintf(pid_str, "msg/%u", (unsigned)pid.pid);
309 pathlen = full_path_tos(ctx->cache_dir, pid_str, buf, sizeof(buf),
310 &dst_sock, &to_free);
311 if (pathlen == -1) {
312 return NT_STATUS_NO_MEMORY;
315 hdr.msg_version = MESSAGE_VERSION;
316 hdr.msg_type = msg_type & MSG_TYPE_MASK;
317 hdr.dst = pid;
318 hdr.src = src;
320 DEBUG(10, ("%s: Sending message 0x%x to %s\n", __func__,
321 (unsigned)hdr.msg_type,
322 server_id_str_buf(pid, &idbuf)));
324 iov2[0].iov_base = &hdr;
325 iov2[0].iov_len = sizeof(hdr);
326 memcpy(iov2+1, iov, iovlen*sizeof(struct iovec));
328 become_root();
329 ret = unix_msg_send(ctx->dgm_ctx, dst_sock, iov2, iovlen + 1);
330 unbecome_root();
332 TALLOC_FREE(to_free);
334 if (ret != 0) {
335 return map_nt_error_from_unix(ret);
337 return NT_STATUS_OK;
340 static void messaging_dgm_recv(struct unix_msg_ctx *ctx,
341 uint8_t *msg, size_t msg_len,
342 void *private_data)
344 struct messaging_dgm_context *dgm_ctx = talloc_get_type_abort(
345 private_data, struct messaging_dgm_context);
346 struct messaging_dgm_hdr *hdr;
347 struct messaging_rec rec;
348 struct server_id_buf idbuf;
350 if (msg_len < sizeof(*hdr)) {
351 DEBUG(1, ("message too short: %u\n", (unsigned)msg_len));
352 return;
356 * unix_msg guarantees alignment, so we can cast here
358 hdr = (struct messaging_dgm_hdr *)msg;
360 rec.msg_version = hdr->msg_version;
361 rec.msg_type = hdr->msg_type;
362 rec.dest = hdr->dst;
363 rec.src = hdr->src;
364 rec.buf.data = msg + sizeof(*hdr);
365 rec.buf.length = msg_len - sizeof(*hdr);
367 DEBUG(10, ("%s: Received message 0x%x len %u from %s\n", __func__,
368 (unsigned)hdr->msg_type, (unsigned)rec.buf.length,
369 server_id_str_buf(rec.src, &idbuf)));
371 messaging_dispatch_rec(dgm_ctx->msg_ctx, &rec);
374 NTSTATUS messaging_dgm_cleanup(struct messaging_context *msg_ctx, pid_t pid)
376 struct messaging_backend *be = messaging_local_backend(msg_ctx);
377 struct messaging_dgm_context *ctx = talloc_get_type_abort(
378 be->private_data, struct messaging_dgm_context);
379 char *lockfile_name, *socket_name;
380 int fd, ret;
381 struct flock lck = {};
382 NTSTATUS status = NT_STATUS_OK;
384 lockfile_name = talloc_asprintf(talloc_tos(), "%s/lck/%u",
385 ctx->cache_dir, (unsigned)pid);
386 if (lockfile_name == NULL) {
387 return NT_STATUS_NO_MEMORY;
389 socket_name = talloc_asprintf(lockfile_name, "%s/msg/%u",
390 ctx->cache_dir, (unsigned)pid);
391 if (socket_name == NULL) {
392 TALLOC_FREE(lockfile_name);
393 return NT_STATUS_NO_MEMORY;
396 fd = open(lockfile_name, O_NONBLOCK|O_WRONLY, 0);
397 if (fd == -1) {
398 status = map_nt_error_from_unix(errno);
399 DEBUG(10, ("%s: open(%s) failed: %s\n", __func__,
400 lockfile_name, strerror(errno)));
401 return status;
404 lck.l_type = F_WRLCK;
405 lck.l_whence = SEEK_SET;
406 lck.l_start = 0;
407 lck.l_len = 0;
409 ret = fcntl(fd, F_SETLK, &lck);
410 if (ret != 0) {
411 status = map_nt_error_from_unix(errno);
412 DEBUG(10, ("%s: Could not get lock: %s\n", __func__,
413 strerror(errno)));
414 TALLOC_FREE(lockfile_name);
415 close(fd);
416 return status;
419 (void)unlink(socket_name);
420 (void)unlink(lockfile_name);
421 (void)close(fd);
423 TALLOC_FREE(lockfile_name);
424 return NT_STATUS_OK;
427 NTSTATUS messaging_dgm_wipe(struct messaging_context *msg_ctx)
429 struct messaging_backend *be = messaging_local_backend(msg_ctx);
430 struct messaging_dgm_context *ctx = talloc_get_type_abort(
431 be->private_data, struct messaging_dgm_context);
432 char *msgdir_name;
433 DIR *msgdir;
434 struct dirent *dp;
435 pid_t our_pid = getpid();
438 * We scan the socket directory and not the lock directory. Otherwise
439 * we would race against messaging_dgm_lockfile_create's open(O_CREAT)
440 * and fcntl(SETLK).
443 msgdir_name = talloc_asprintf(talloc_tos(), "%s/msg", ctx->cache_dir);
444 if (msgdir_name == NULL) {
445 return NT_STATUS_NO_MEMORY;
448 msgdir = opendir(msgdir_name);
449 TALLOC_FREE(msgdir_name);
450 if (msgdir == NULL) {
451 return map_nt_error_from_unix(errno);
454 while ((dp = readdir(msgdir)) != NULL) {
455 NTSTATUS status;
456 unsigned long pid;
458 pid = strtoul(dp->d_name, NULL, 10);
459 if (pid == 0) {
461 * . and .. and other malformed entries
463 continue;
465 if (pid == our_pid) {
467 * fcntl(F_GETLK) will succeed for ourselves, we hold
468 * that lock ourselves.
470 continue;
473 status = messaging_dgm_cleanup(msg_ctx, pid);
474 DEBUG(10, ("messaging_dgm_cleanup(%lu) returned %s\n",
475 pid, nt_errstr(status)));
477 closedir(msgdir);
479 return NT_STATUS_OK;
482 void *messaging_dgm_register_tevent_context(TALLOC_CTX *mem_ctx,
483 struct messaging_context *msg_ctx,
484 struct tevent_context *ev)
486 struct messaging_backend *be = messaging_local_backend(msg_ctx);
487 struct messaging_dgm_context *ctx = talloc_get_type_abort(
488 be->private_data, struct messaging_dgm_context);
489 return poll_funcs_tevent_register(mem_ctx, ctx->msg_callbacks, ev);