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/>.
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 "lib/messages_dgm.h"
26 #include "lib/param/param.h"
27 #include "poll_funcs/poll_funcs_tevent.h"
28 #include "unix_msg/unix_msg.h"
32 * This will carry enough for a socket path
34 char buf
[sizeof(struct sockaddr_un
)];
37 struct messaging_dgm_context
{
39 struct poll_funcs
*msg_callbacks
;
41 struct unix_msg_ctx
*dgm_ctx
;
42 struct sun_path_buf cache_dir
;
45 void (*recv_cb
)(const uint8_t *msg
,
50 void *recv_cb_private_data
;
52 bool *have_dgm_context
;
55 static struct messaging_dgm_context
*global_dgm_context
;
57 static void messaging_dgm_recv(struct unix_msg_ctx
*ctx
,
58 uint8_t *msg
, size_t msg_len
,
59 int *fds
, size_t num_fds
,
62 static int messaging_dgm_lockfile_name(struct sun_path_buf
*buf
,
63 const char *cache_dir
,
68 ret
= snprintf(buf
->buf
, sizeof(buf
->buf
), "%s/lck/%u", cache_dir
,
70 if (ret
>= sizeof(buf
->buf
)) {
76 static int messaging_dgm_context_destructor(struct messaging_dgm_context
*c
);
78 static int messaging_dgm_lockfile_create(const char *cache_dir
,
79 uid_t dir_owner
, pid_t pid
,
80 int *plockfile_fd
, uint64_t unique
)
83 struct sun_path_buf dir
;
84 struct sun_path_buf lockfile_name
;
91 ret
= messaging_dgm_lockfile_name(&lockfile_name
, cache_dir
, pid
);
96 /* shorter than lockfile_name, can't overflow */
97 snprintf(dir
.buf
, sizeof(dir
.buf
), "%s/lck", cache_dir
);
99 ok
= directory_create_or_exist_strict(dir
.buf
, dir_owner
, 0755);
102 DEBUG(1, ("%s: Could not create lock directory: %s\n",
103 __func__
, strerror(ret
)));
107 /* no O_EXCL, existence check is via the fcntl lock */
109 lockfile_fd
= open(lockfile_name
.buf
, O_NONBLOCK
|O_CREAT
|O_WRONLY
,
111 if (lockfile_fd
== -1) {
113 DEBUG(1, ("%s: open failed: %s\n", __func__
, strerror(errno
)));
117 lck
= (struct flock
) {
122 ret
= fcntl(lockfile_fd
, F_SETLK
, &lck
);
125 DEBUG(1, ("%s: fcntl failed: %s\n", __func__
, strerror(ret
)));
129 unique_len
= snprintf(buf
, sizeof(buf
), "%ju\n", (uintmax_t)unique
);
131 /* shorten a potentially preexisting file */
133 ret
= ftruncate(lockfile_fd
, unique_len
);
136 DEBUG(1, ("%s: ftruncate failed: %s\n", __func__
,
141 written
= write(lockfile_fd
, buf
, unique_len
);
142 if (written
!= unique_len
) {
144 DEBUG(1, ("%s: write failed: %s\n", __func__
, strerror(ret
)));
148 *plockfile_fd
= lockfile_fd
;
152 unlink(lockfile_name
.buf
);
158 static int messaging_dgm_lockfile_remove(const char *cache_dir
, pid_t pid
)
160 struct sun_path_buf lockfile_name
;
163 ret
= messaging_dgm_lockfile_name(&lockfile_name
, cache_dir
, pid
);
168 ret
= unlink(lockfile_name
.buf
);
171 DEBUG(10, ("%s: unlink(%s) failed: %s\n", __func__
,
172 lockfile_name
.buf
, strerror(ret
)));
178 int messaging_dgm_init(struct tevent_context
*ev
,
179 struct server_id pid
,
180 const char *cache_dir
,
182 void (*recv_cb
)(const uint8_t *msg
,
187 void *recv_cb_private_data
)
189 struct messaging_dgm_context
*ctx
;
192 struct sun_path_buf socket_dir
;
193 struct sockaddr_un socket_address
;
196 static bool have_dgm_context
= false;
198 if (have_dgm_context
) {
202 ctx
= talloc_zero(NULL
, struct messaging_dgm_context
);
207 ctx
->recv_cb
= recv_cb
;
208 ctx
->recv_cb_private_data
= recv_cb_private_data
;
210 ret
= snprintf(socket_dir
.buf
, sizeof(socket_dir
.buf
),
211 "%s/msg", cache_dir
);
212 if (ret
>= sizeof(socket_dir
.buf
)) {
217 /* shorter than socket_dir, can't overflow */
218 strlcpy(ctx
->cache_dir
.buf
, cache_dir
, sizeof(ctx
->cache_dir
.buf
));
220 socket_address
= (struct sockaddr_un
) { .sun_family
= AF_UNIX
};
221 sockname_len
= snprintf(socket_address
.sun_path
,
222 sizeof(socket_address
.sun_path
),
223 "%s/%u", socket_dir
.buf
, (unsigned)pid
.pid
);
224 if (sockname_len
>= sizeof(socket_address
.sun_path
)) {
229 ret
= messaging_dgm_lockfile_create(cache_dir
, dir_owner
, pid
.pid
,
230 &ctx
->lockfile_fd
, pid
.unique_id
);
232 DEBUG(1, ("%s: messaging_dgm_create_lockfile failed: %s\n",
233 __func__
, strerror(ret
)));
238 ctx
->msg_callbacks
= poll_funcs_init_tevent(ctx
);
239 if (ctx
->msg_callbacks
== NULL
) {
243 ctx
->tevent_handle
= poll_funcs_tevent_register(
244 ctx
, ctx
->msg_callbacks
, ev
);
245 if (ctx
->tevent_handle
== NULL
) {
249 ok
= directory_create_or_exist_strict(socket_dir
.buf
, dir_owner
, 0700);
251 DEBUG(1, ("Could not create socket directory\n"));
256 unlink(socket_address
.sun_path
);
258 generate_random_buffer((uint8_t *)&cookie
, sizeof(cookie
));
260 ret
= unix_msg_init(&socket_address
, ctx
->msg_callbacks
, 1024, cookie
,
261 messaging_dgm_recv
, ctx
, &ctx
->dgm_ctx
);
263 DEBUG(1, ("unix_msg_init failed: %s\n", strerror(ret
)));
267 talloc_set_destructor(ctx
, messaging_dgm_context_destructor
);
269 ctx
->have_dgm_context
= &have_dgm_context
;
271 global_dgm_context
= ctx
;
279 static int messaging_dgm_context_destructor(struct messaging_dgm_context
*c
)
282 * First delete the socket to avoid races. The lockfile is the
283 * indicator that we're still around.
285 unix_msg_free(c
->dgm_ctx
);
287 if (getpid() == c
->pid
) {
288 (void)messaging_dgm_lockfile_remove(c
->cache_dir
.buf
, c
->pid
);
290 close(c
->lockfile_fd
);
292 if (c
->have_dgm_context
!= NULL
) {
293 *c
->have_dgm_context
= false;
299 void messaging_dgm_destroy(void)
301 TALLOC_FREE(global_dgm_context
);
304 int messaging_dgm_send(pid_t pid
,
305 const struct iovec
*iov
, int iovlen
,
306 const int *fds
, size_t num_fds
)
308 struct messaging_dgm_context
*ctx
= global_dgm_context
;
309 struct sockaddr_un dst
;
317 dst
= (struct sockaddr_un
) { .sun_family
= AF_UNIX
};
319 dst_pathlen
= snprintf(dst
.sun_path
, sizeof(dst
.sun_path
),
320 "%s/msg/%u", ctx
->cache_dir
.buf
, (unsigned)pid
);
321 if (dst_pathlen
>= sizeof(dst
.sun_path
)) {
325 DEBUG(10, ("%s: Sending message to %u\n", __func__
, (unsigned)pid
));
327 ret
= unix_msg_send(ctx
->dgm_ctx
, &dst
, iov
, iovlen
, fds
, num_fds
);
332 static void messaging_dgm_recv(struct unix_msg_ctx
*ctx
,
333 uint8_t *msg
, size_t msg_len
,
334 int *fds
, size_t num_fds
,
337 struct messaging_dgm_context
*dgm_ctx
= talloc_get_type_abort(
338 private_data
, struct messaging_dgm_context
);
340 dgm_ctx
->recv_cb(msg
, msg_len
, fds
, num_fds
,
341 dgm_ctx
->recv_cb_private_data
);
344 int messaging_dgm_cleanup(pid_t pid
)
346 struct messaging_dgm_context
*ctx
= global_dgm_context
;
347 struct sun_path_buf lockfile_name
, socket_name
;
349 struct flock lck
= {};
355 ret
= messaging_dgm_lockfile_name(&lockfile_name
, ctx
->cache_dir
.buf
,
361 /* same length as lockfile_name, can't overflow */
362 snprintf(socket_name
.buf
, sizeof(socket_name
.buf
), "%s/msg/%u",
363 ctx
->cache_dir
.buf
, (unsigned)pid
);
365 fd
= open(lockfile_name
.buf
, O_NONBLOCK
|O_WRONLY
, 0);
369 DEBUG(10, ("%s: open(%s) failed: %s\n", __func__
,
370 lockfile_name
.buf
, strerror(ret
)));
375 lck
.l_type
= F_WRLCK
;
376 lck
.l_whence
= SEEK_SET
;
380 ret
= fcntl(fd
, F_SETLK
, &lck
);
383 DEBUG(10, ("%s: Could not get lock: %s\n", __func__
,
389 (void)unlink(socket_name
.buf
);
390 (void)unlink(lockfile_name
.buf
);
395 int messaging_dgm_wipe(void)
397 struct messaging_dgm_context
*ctx
= global_dgm_context
;
398 struct sun_path_buf msgdir_name
;
401 pid_t our_pid
= getpid();
409 * We scan the socket directory and not the lock directory. Otherwise
410 * we would race against messaging_dgm_lockfile_create's open(O_CREAT)
414 ret
= snprintf(msgdir_name
.buf
, sizeof(msgdir_name
.buf
),
415 "%s/msg", ctx
->cache_dir
.buf
);
416 if (ret
>= sizeof(msgdir_name
.buf
)) {
420 msgdir
= opendir(msgdir_name
.buf
);
421 if (msgdir
== NULL
) {
426 while ((dp
= readdir(msgdir
)) != NULL
) {
429 pid
= strtoul(dp
->d_name
, NULL
, 10);
432 * . and .. and other malformed entries
436 if (pid
== our_pid
) {
438 * fcntl(F_GETLK) will succeed for ourselves, we hold
439 * that lock ourselves.
444 ret
= messaging_dgm_cleanup(pid
);
445 DEBUG(10, ("messaging_dgm_cleanup(%lu) returned %s\n",
446 pid
, ret
? strerror(ret
) : "ok"));
453 void *messaging_dgm_register_tevent_context(TALLOC_CTX
*mem_ctx
,
454 struct tevent_context
*ev
)
456 struct messaging_dgm_context
*ctx
= global_dgm_context
;
461 return poll_funcs_tevent_register(mem_ctx
, ctx
->msg_callbacks
, ev
);