1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "alloc-util.h"
9 #include "errno-util.h"
11 #include "glyph-util.h"
14 #include "iovec-util.h"
16 #include "path-util.h"
17 #include "process-util.h"
18 #include "selinux-util.h"
19 #include "serialize.h"
21 #include "socket-util.h"
22 #include "string-table.h"
23 #include "string-util.h"
25 #include "time-util.h"
26 #include "umask-util.h"
27 #include "user-util.h"
29 #include "varlink-internal.h"
30 #include "varlink-org.varlink.service.h"
31 #include "varlink-io.systemd.h"
34 #define VARLINK_DEFAULT_CONNECTIONS_MAX 4096U
35 #define VARLINK_DEFAULT_CONNECTIONS_PER_UID_MAX 1024U
37 #define VARLINK_DEFAULT_TIMEOUT_USEC (45U*USEC_PER_SEC)
38 #define VARLINK_BUFFER_MAX (16U*1024U*1024U)
39 #define VARLINK_READ_SIZE (64U*1024U)
40 #define VARLINK_COLLECT_MAX 1024U
42 typedef enum VarlinkState
{
43 /* Client side states */
45 VARLINK_AWAITING_REPLY
,
46 VARLINK_AWAITING_REPLY_MORE
,
50 VARLINK_COLLECTING_REPLY
,
51 VARLINK_PROCESSING_REPLY
,
53 /* Server side states */
55 VARLINK_PROCESSING_METHOD
,
56 VARLINK_PROCESSING_METHOD_MORE
,
57 VARLINK_PROCESSING_METHOD_ONEWAY
,
58 VARLINK_PROCESSED_METHOD
,
59 VARLINK_PENDING_METHOD
,
60 VARLINK_PENDING_METHOD_MORE
,
62 /* Common states (only during shutdown) */
63 VARLINK_PENDING_DISCONNECT
,
64 VARLINK_PENDING_TIMEOUT
,
65 VARLINK_PROCESSING_DISCONNECT
,
66 VARLINK_PROCESSING_TIMEOUT
,
67 VARLINK_PROCESSING_FAILURE
,
71 _VARLINK_STATE_INVALID
= -EINVAL
,
74 /* Tests whether we are not yet disconnected. Note that this is true during all states where the connection
75 * is still good for something, and false only when it's dead for good. This means: when we are
76 * asynchronously connecting to a peer and the connect() is still pending, then this will return 'true', as
77 * the connection is still good, and we are likely to be able to properly operate on it soon. */
78 #define VARLINK_STATE_IS_ALIVE(state) \
80 VARLINK_IDLE_CLIENT, \
81 VARLINK_AWAITING_REPLY, \
82 VARLINK_AWAITING_REPLY_MORE, \
86 VARLINK_COLLECTING_REPLY, \
87 VARLINK_PROCESSING_REPLY, \
88 VARLINK_IDLE_SERVER, \
89 VARLINK_PROCESSING_METHOD, \
90 VARLINK_PROCESSING_METHOD_MORE, \
91 VARLINK_PROCESSING_METHOD_ONEWAY, \
92 VARLINK_PROCESSED_METHOD, \
93 VARLINK_PENDING_METHOD, \
94 VARLINK_PENDING_METHOD_MORE)
96 typedef struct VarlinkJsonQueueItem VarlinkJsonQueueItem
;
98 /* A queued message we shall write into the socket, along with the file descriptors to send at the same
99 * time. This queue item binds them together so that message/fd boundaries are maintained throughout the
101 struct VarlinkJsonQueueItem
{
102 LIST_FIELDS(VarlinkJsonQueueItem
, queue
);
111 VarlinkServer
*server
;
114 bool connecting
; /* This boolean indicates whether the socket fd we are operating on is currently
115 * processing an asynchronous connect(). In that state we watch the socket for
116 * EPOLLOUT, but we refrain from calling read() or write() on the socket as that
117 * will trigger ENOTCONN. Note that this boolean is kept separate from the
118 * VarlinkState above on purpose: while the connect() is still not complete we
119 * already want to allow queuing of messages and similar. Thus it's nice to keep
120 * these two state concepts separate: the VarlinkState encodes what our own view of
121 * the connection is, i.e. whether we think it's a server, a client, and has
122 * something queued already, while 'connecting' tells us a detail about the
123 * transport used below, that should have no effect on how we otherwise accept and
124 * process operations from the user.
126 * Or to say this differently: VARLINK_STATE_IS_ALIVE(state) tells you whether the
127 * connection is good to use, even if it might not be fully connected
128 * yet. connecting=true then informs you that actually we are still connecting, and
129 * the connection is actually not established yet and thus any requests you enqueue
130 * now will still work fine but will be queued only, not sent yet, but that
131 * shouldn't stop you from using the connection, since eventually whatever you queue
134 * Or to say this even differently: 'state' is a high-level ("application layer"
135 * high, if you so will) state, while 'conecting' is a low-level ("transport layer"
136 * low, if you so will) state, and while they are not entirely unrelated and
137 * sometimes propagate effects to each other they are only asynchronously connected
143 char *input_buffer
; /* valid data starts at input_buffer_index, ends at input_buffer_index+input_buffer_size */
144 size_t input_buffer_index
;
145 size_t input_buffer_size
;
146 size_t input_buffer_unscanned
;
148 void *input_control_buffer
;
149 size_t input_control_buffer_size
;
151 char *output_buffer
; /* valid data starts at output_buffer_index, ends at output_buffer_index+output_buffer_size */
152 size_t output_buffer_index
;
153 size_t output_buffer_size
;
155 int *input_fds
; /* file descriptors associated with the data in input_buffer (for fd passing) */
158 int *output_fds
; /* file descriptors associated with the data in output_buffer (for fd passing) */
161 /* Further messages to output not yet formatted into text, and thus not included in output_buffer
162 * yet. We keep them separate from output_buffer, to not violate fd message boundaries: we want that
163 * each fd that is sent is associated with its fds, and that fds cannot be accidentally associated
164 * with preceding or following messages. */
165 LIST_HEAD(VarlinkJsonQueueItem
, output_queue
);
166 VarlinkJsonQueueItem
*output_queue_tail
;
168 /* The fds to associate with the next message that is about to be enqueued. The user first pushes the
169 * fds it intends to send via varlink_push_fd() into this queue, and then once the message data is
170 * submitted we'll combine the fds and the message data into one. */
174 VarlinkReply reply_callback
;
176 JsonVariant
*current
;
177 JsonVariant
*current_collected
;
178 VarlinkReplyFlags current_reply_flags
;
179 VarlinkSymbol
*current_method
;
183 bool ucred_acquired
:1;
185 bool write_disconnected
:1;
186 bool read_disconnected
:1;
187 bool prefer_read_write
:1;
190 bool allow_fd_passing_input
:1;
191 bool allow_fd_passing_output
:1;
193 bool output_buffer_sensitive
:1; /* whether to erase the output buffer after writing it to the socket */
194 bool input_sensitive
:1; /* Whether incoming messages might be sensitive */
196 int af
; /* address family if socket; AF_UNSPEC if not socket; negative if not known */
205 sd_event_source
*io_event_source
;
206 sd_event_source
*time_event_source
;
207 sd_event_source
*quit_event_source
;
208 sd_event_source
*defer_event_source
;
213 typedef struct VarlinkServerSocket VarlinkServerSocket
;
215 struct VarlinkServerSocket
{
216 VarlinkServer
*server
;
221 sd_event_source
*event_source
;
223 LIST_FIELDS(VarlinkServerSocket
, sockets
);
226 struct VarlinkServer
{
228 VarlinkServerFlags flags
;
230 LIST_HEAD(VarlinkServerSocket
, sockets
);
232 Hashmap
*methods
; /* Fully qualified symbol name of a method → VarlinkMethod */
233 Hashmap
*interfaces
; /* Fully qualified interface name → VarlinkInterface* */
234 Hashmap
*symbols
; /* Fully qualified symbol name of method/error → VarlinkSymbol* */
235 VarlinkConnect connect_callback
;
236 VarlinkDisconnect disconnect_callback
;
239 int64_t event_priority
;
241 unsigned n_connections
;
242 Hashmap
*by_uid
; /* UID_TO_PTR(uid) → UINT_TO_PTR(n_connections) */
247 unsigned connections_max
;
248 unsigned connections_per_uid_max
;
253 static const char* const varlink_state_table
[_VARLINK_STATE_MAX
] = {
254 [VARLINK_IDLE_CLIENT
] = "idle-client",
255 [VARLINK_AWAITING_REPLY
] = "awaiting-reply",
256 [VARLINK_AWAITING_REPLY_MORE
] = "awaiting-reply-more",
257 [VARLINK_CALLING
] = "calling",
258 [VARLINK_CALLED
] = "called",
259 [VARLINK_COLLECTING
] = "collecting",
260 [VARLINK_COLLECTING_REPLY
] = "collecting-reply",
261 [VARLINK_PROCESSING_REPLY
] = "processing-reply",
262 [VARLINK_IDLE_SERVER
] = "idle-server",
263 [VARLINK_PROCESSING_METHOD
] = "processing-method",
264 [VARLINK_PROCESSING_METHOD_MORE
] = "processing-method-more",
265 [VARLINK_PROCESSING_METHOD_ONEWAY
] = "processing-method-oneway",
266 [VARLINK_PROCESSED_METHOD
] = "processed-method",
267 [VARLINK_PENDING_METHOD
] = "pending-method",
268 [VARLINK_PENDING_METHOD_MORE
] = "pending-method-more",
269 [VARLINK_PENDING_DISCONNECT
] = "pending-disconnect",
270 [VARLINK_PENDING_TIMEOUT
] = "pending-timeout",
271 [VARLINK_PROCESSING_DISCONNECT
] = "processing-disconnect",
272 [VARLINK_PROCESSING_TIMEOUT
] = "processing-timeout",
273 [VARLINK_PROCESSING_FAILURE
] = "processing-failure",
274 [VARLINK_DISCONNECTED
] = "disconnected",
277 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(varlink_state
, VarlinkState
);
279 #define varlink_log_errno(v, error, fmt, ...) \
280 log_debug_errno(error, "%s: " fmt, varlink_description(v), ##__VA_ARGS__)
282 #define varlink_log(v, fmt, ...) \
283 log_debug("%s: " fmt, varlink_description(v), ##__VA_ARGS__)
285 #define varlink_server_log_errno(s, error, fmt, ...) \
286 log_debug_errno(error, "%s: " fmt, varlink_server_description(s), ##__VA_ARGS__)
288 #define varlink_server_log(s, fmt, ...) \
289 log_debug("%s: " fmt, varlink_server_description(s), ##__VA_ARGS__)
291 static int varlink_format_queue(Varlink
*v
);
292 static void varlink_server_test_exit_on_idle(VarlinkServer
*s
);
294 static const char *varlink_description(Varlink
*v
) {
295 return (v
? v
->description
: NULL
) ?: "varlink";
298 static const char *varlink_server_description(VarlinkServer
*s
) {
299 return (s
? s
->description
: NULL
) ?: "varlink";
302 static VarlinkJsonQueueItem
*varlink_json_queue_item_free(VarlinkJsonQueueItem
*q
) {
306 json_variant_unref(q
->data
);
307 close_many(q
->fds
, q
->n_fds
);
312 static VarlinkJsonQueueItem
*varlink_json_queue_item_new(JsonVariant
*m
, const int fds
[], size_t n_fds
) {
313 VarlinkJsonQueueItem
*q
;
316 assert(fds
|| n_fds
== 0);
318 q
= malloc(offsetof(VarlinkJsonQueueItem
, fds
) + sizeof(int) * n_fds
);
322 *q
= (VarlinkJsonQueueItem
) {
323 .data
= json_variant_ref(m
),
327 memcpy_safe(q
->fds
, fds
, n_fds
* sizeof(int));
332 static void varlink_set_state(Varlink
*v
, VarlinkState state
) {
334 assert(state
>= 0 && state
< _VARLINK_STATE_MAX
);
337 varlink_log(v
, "Setting state %s",
338 varlink_state_to_string(state
));
340 varlink_log(v
, "Changing state %s %s %s",
341 varlink_state_to_string(v
->state
),
342 special_glyph(SPECIAL_GLYPH_ARROW_RIGHT
),
343 varlink_state_to_string(state
));
348 static int varlink_new(Varlink
**ret
) {
361 .state
= _VARLINK_STATE_INVALID
,
363 .ucred
= UCRED_INVALID
,
365 .timestamp
= USEC_INFINITY
,
366 .timeout
= VARLINK_DEFAULT_TIMEOUT_USEC
,
370 .peer_pidfd
= -EBADF
,
377 int varlink_connect_address(Varlink
**ret
, const char *address
) {
378 _cleanup_(varlink_unrefp
) Varlink
*v
= NULL
;
379 union sockaddr_union sockaddr
;
382 assert_return(ret
, -EINVAL
);
383 assert_return(address
, -EINVAL
);
387 return log_debug_errno(r
, "Failed to create varlink object: %m");
389 v
->fd
= socket(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
391 return log_debug_errno(errno
, "Failed to create AF_UNIX socket: %m");
393 v
->fd
= fd_move_above_stdio(v
->fd
);
396 r
= sockaddr_un_set_path(&sockaddr
.un
, address
);
398 if (r
!= -ENAMETOOLONG
)
399 return log_debug_errno(r
, "Failed to set socket address '%s': %m", address
);
401 /* This is a file system path, and too long to fit into sockaddr_un. Let's connect via O_PATH
404 r
= connect_unix_path(v
->fd
, AT_FDCWD
, address
);
406 r
= RET_NERRNO(connect(v
->fd
, &sockaddr
.sa
, r
));
409 if (!IN_SET(r
, -EAGAIN
, -EINPROGRESS
))
410 return log_debug_errno(r
, "Failed to connect to %s: %m", address
);
412 v
->connecting
= true; /* We are asynchronously connecting, i.e. the connect() is being
413 * processed in the background. As long as that's the case the socket
414 * is in a special state: it's there, we can poll it for EPOLLOUT, but
415 * if we attempt to write() to it before we see EPOLLOUT we'll get
416 * ENOTCONN (and not EAGAIN, like we would for a normal connected
417 * socket that isn't writable at the moment). Since ENOTCONN on write()
418 * hence can mean two different things (i.e. connection not complete
419 * yet vs. already disconnected again), we store as a boolean whether
420 * we are still in connect(). */
423 varlink_set_state(v
, VARLINK_IDLE_CLIENT
);
429 int varlink_connect_exec(Varlink
**ret
, const char *_command
, char **_argv
) {
430 _cleanup_close_pair_
int pair
[2] = EBADF_PAIR
;
431 _cleanup_(sigkill_waitp
) pid_t pid
= 0;
432 _cleanup_free_
char *command
= NULL
;
433 _cleanup_strv_free_
char **argv
= NULL
;
436 assert_return(ret
, -EINVAL
);
437 assert_return(_command
, -EINVAL
);
439 /* Copy the strings, in case they point into our own argv[], which we'll invalidate shortly because
440 * we rename the child process */
441 command
= strdup(_command
);
445 if (strv_isempty(_argv
))
446 argv
= strv_new(command
);
448 argv
= strv_copy(_argv
);
452 log_debug("Forking off Varlink child process '%s'.", command
);
454 if (socketpair(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0, pair
) < 0)
455 return log_debug_errno(errno
, "Failed to allocate AF_UNIX socket pair: %m");
457 r
= fd_nonblock(pair
[1], false);
459 return log_debug_errno(r
, "Failed to disable O_NONBLOCK for varlink socket: %m");
463 /* stdio_fds= */ NULL
,
464 /* except_fds= */ (int[]) { pair
[1] },
465 /* n_except_fds= */ 1,
466 FORK_RESET_SIGNALS
|FORK_CLOSE_ALL_FDS
|FORK_DEATHSIG_SIGTERM
|FORK_REOPEN_LOG
|FORK_LOG
|FORK_RLIMIT_NOFILE_SAFE
,
469 return log_debug_errno(r
, "Failed to spawn process: %m");
471 char spid
[DECIMAL_STR_MAX(pid_t
)+1];
472 const char *setenv_list
[] = {
475 "LISTEN_FDNAMES", "varlink",
482 r
= move_fd(pair
[1], 3, /* cloexec= */ false);
484 log_debug_errno(r
, "Failed to move file descriptor to 3: %m");
488 xsprintf(spid
, PID_FMT
, pid
);
490 STRV_FOREACH_PAIR(a
, b
, setenv_list
) {
491 if (setenv(*a
, *b
, /* override= */ true) < 0) {
492 log_debug_errno(errno
, "Failed to set environment variable '%s': %m", *a
);
497 execvp(command
, argv
);
498 log_debug_errno(r
, "Failed to invoke process '%s': %m", command
);
502 pair
[1] = safe_close(pair
[1]);
507 return log_debug_errno(r
, "Failed to create varlink object: %m");
509 v
->fd
= TAKE_FD(pair
[0]);
511 v
->exec_pid
= TAKE_PID(pid
);
512 varlink_set_state(v
, VARLINK_IDLE_CLIENT
);
518 static int varlink_connect_ssh(Varlink
**ret
, const char *where
) {
519 _cleanup_close_pair_
int pair
[2] = EBADF_PAIR
;
520 _cleanup_(sigkill_waitp
) pid_t pid
= 0;
523 assert_return(ret
, -EINVAL
);
524 assert_return(where
, -EINVAL
);
526 /* Connects to an SSH server via OpenSSH 9.4's -W switch to connect to a remote AF_UNIX socket. For
527 * now we do not expose this function directly, but only via varlink_connect_url(). */
529 const char *ssh
= secure_getenv("SYSTEMD_SSH") ?: "ssh";
530 if (!path_is_valid(ssh
))
531 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "SSH path is not valid, refusing: %s", ssh
);
533 const char *e
= strchr(where
, ':');
535 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "SSH specification lacks a : separator between host and path, refusing: %s", where
);
537 _cleanup_free_
char *h
= strndup(where
, e
- where
);
539 return log_oom_debug();
541 _cleanup_free_
char *c
= strdup(e
+ 1);
543 return log_oom_debug();
545 if (!path_is_absolute(c
))
546 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Remote AF_UNIX socket path is not absolute, refusing: %s", c
);
548 _cleanup_free_
char *p
= NULL
;
549 r
= path_simplify_alloc(c
, &p
);
553 if (!path_is_normalized(p
))
554 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Specified path is not normalized, refusing: %s", p
);
556 log_debug("Forking off SSH child process '%s -W %s %s'.", ssh
, p
, h
);
558 if (socketpair(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0, pair
) < 0)
559 return log_debug_errno(errno
, "Failed to allocate AF_UNIX socket pair: %m");
563 /* stdio_fds= */ (int[]) { pair
[1], pair
[1], STDERR_FILENO
},
564 /* except_fds= */ NULL
,
565 /* n_except_fds= */ 0,
566 FORK_RESET_SIGNALS
|FORK_CLOSE_ALL_FDS
|FORK_DEATHSIG_SIGTERM
|FORK_REOPEN_LOG
|FORK_LOG
|FORK_RLIMIT_NOFILE_SAFE
|FORK_REARRANGE_STDIO
,
569 return log_debug_errno(r
, "Failed to spawn process: %m");
573 execlp(ssh
, "ssh", "-W", p
, h
, NULL
);
574 log_debug_errno(errno
, "Failed to invoke %s: %m", ssh
);
578 pair
[1] = safe_close(pair
[1]);
583 return log_debug_errno(r
, "Failed to create varlink object: %m");
585 v
->fd
= TAKE_FD(pair
[0]);
587 v
->exec_pid
= TAKE_PID(pid
);
588 varlink_set_state(v
, VARLINK_IDLE_CLIENT
);
594 int varlink_connect_url(Varlink
**ret
, const char *url
) {
595 _cleanup_free_
char *c
= NULL
;
604 assert_return(ret
, -EINVAL
);
605 assert_return(url
, -EINVAL
);
607 // FIXME: Maybe add support for vsock: and ssh-exec: URL schemes here.
609 /* The Varlink URL scheme is a bit underdefined. We support only the spec-defined unix: transport for
610 * now, plus exec:, ssh: transports we made up ourselves. Strictly speaking this shouldn't even be
611 * called "URL", since it has nothing to do with Internet URLs by RFC. */
613 p
= startswith(url
, "unix:");
615 scheme
= SCHEME_UNIX
;
616 else if ((p
= startswith(url
, "exec:")))
617 scheme
= SCHEME_EXEC
;
618 else if ((p
= startswith(url
, "ssh:")))
621 return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT
), "URL scheme not supported.");
623 /* The varlink.org reference C library supports more than just file system paths. We might want to
624 * support that one day too. For now simply refuse that. */
625 if (p
[strcspn(p
, ";?#")] != '\0')
626 return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT
), "URL parameterization with ';', '?', '#' not supported.");
628 if (scheme
== SCHEME_SSH
)
629 return varlink_connect_ssh(ret
, p
);
631 if (scheme
== SCHEME_EXEC
|| p
[0] != '@') { /* no path validity checks for abstract namespace sockets */
633 if (!path_is_absolute(p
))
634 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Specified path not absolute, refusing.");
636 r
= path_simplify_alloc(p
, &c
);
640 if (!path_is_normalized(c
))
641 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Specified path is not normalized, refusing.");
644 if (scheme
== SCHEME_EXEC
)
645 return varlink_connect_exec(ret
, c
, NULL
);
647 return varlink_connect_address(ret
, c
?: p
);
650 int varlink_connect_fd(Varlink
**ret
, int fd
) {
654 assert_return(ret
, -EINVAL
);
655 assert_return(fd
>= 0, -EBADF
);
657 r
= fd_nonblock(fd
, true);
659 return log_debug_errno(r
, "Failed to make fd %d nonblocking: %m", fd
);
663 return log_debug_errno(r
, "Failed to create varlink object: %m");
667 varlink_set_state(v
, VARLINK_IDLE_CLIENT
);
669 /* Note that if this function is called we assume the passed socket (if it is one) is already
670 * properly connected, i.e. any asynchronous connect() done on it already completed. Because of that
671 * we'll not set the 'connecting' boolean here, i.e. we don't need to avoid write()ing to the socket
672 * until the connection is fully set up. Behaviour here is hence a bit different from
673 * varlink_connect_address() above, as there we do handle asynchronous connections ourselves and
674 * avoid doing write() on it before we saw EPOLLOUT for the first time. */
680 static void varlink_detach_event_sources(Varlink
*v
) {
683 v
->io_event_source
= sd_event_source_disable_unref(v
->io_event_source
);
684 v
->time_event_source
= sd_event_source_disable_unref(v
->time_event_source
);
685 v
->quit_event_source
= sd_event_source_disable_unref(v
->quit_event_source
);
686 v
->defer_event_source
= sd_event_source_disable_unref(v
->defer_event_source
);
689 static void varlink_clear_current(Varlink
*v
) {
692 /* Clears the currently processed incoming message */
693 v
->current
= json_variant_unref(v
->current
);
694 v
->current_collected
= json_variant_unref(v
->current_collected
);
695 v
->current_method
= NULL
;
696 v
->current_reply_flags
= 0;
698 close_many(v
->input_fds
, v
->n_input_fds
);
699 v
->input_fds
= mfree(v
->input_fds
);
703 static void varlink_clear(Varlink
*v
) {
706 varlink_detach_event_sources(v
);
708 v
->fd
= safe_close(v
->fd
);
710 varlink_clear_current(v
);
712 v
->input_buffer
= v
->input_sensitive
? erase_and_free(v
->input_buffer
) : mfree(v
->input_buffer
);
713 v
->output_buffer
= v
->output_buffer_sensitive
? erase_and_free(v
->output_buffer
) : mfree(v
->output_buffer
);
715 v
->input_control_buffer
= mfree(v
->input_control_buffer
);
716 v
->input_control_buffer_size
= 0;
718 close_many(v
->output_fds
, v
->n_output_fds
);
719 v
->output_fds
= mfree(v
->output_fds
);
722 close_many(v
->pushed_fds
, v
->n_pushed_fds
);
723 v
->pushed_fds
= mfree(v
->pushed_fds
);
726 LIST_CLEAR(queue
, v
->output_queue
, varlink_json_queue_item_free
);
727 v
->output_queue_tail
= NULL
;
729 v
->event
= sd_event_unref(v
->event
);
731 if (v
->exec_pid
> 0) {
732 sigterm_wait(v
->exec_pid
);
736 v
->peer_pidfd
= safe_close(v
->peer_pidfd
);
739 static Varlink
* varlink_destroy(Varlink
*v
) {
743 /* If this is called the server object must already been unreffed here. Why that? because when we
744 * linked up the varlink connection with the server object we took one ref in each direction */
749 free(v
->description
);
753 DEFINE_TRIVIAL_REF_UNREF_FUNC(Varlink
, varlink
, varlink_destroy
);
755 static int varlink_test_disconnect(Varlink
*v
) {
758 /* Tests whether we the connection has been terminated. We are careful to not stop processing it
759 * prematurely, since we want to handle half-open connections as well as possible and want to flush
760 * out and read data before we close down if we can. */
762 /* Already disconnected? */
763 if (!VARLINK_STATE_IS_ALIVE(v
->state
))
766 /* Wait until connection setup is complete, i.e. until asynchronous connect() completes */
770 /* Still something to write and we can write? Stay around */
771 if (v
->output_buffer_size
> 0 && !v
->write_disconnected
)
774 /* Both sides gone already? Then there's no need to stick around */
775 if (v
->read_disconnected
&& v
->write_disconnected
)
778 /* If we are waiting for incoming data but the read side is shut down, disconnect. */
779 if (IN_SET(v
->state
, VARLINK_AWAITING_REPLY
, VARLINK_AWAITING_REPLY_MORE
, VARLINK_CALLING
, VARLINK_COLLECTING
, VARLINK_IDLE_SERVER
) && v
->read_disconnected
)
782 /* Similar, if are a client that hasn't written anything yet but the write side is dead, also
783 * disconnect. We also explicitly check for POLLHUP here since we likely won't notice the write side
784 * being down if we never wrote anything. */
785 if (v
->state
== VARLINK_IDLE_CLIENT
&& (v
->write_disconnected
|| v
->got_pollhup
))
788 /* We are on the server side and still want to send out more replies, but we saw POLLHUP already, and
789 * either got no buffered bytes to write anymore or already saw a write error. In that case we should
790 * shut down the varlink link. */
791 if (IN_SET(v
->state
, VARLINK_PENDING_METHOD
, VARLINK_PENDING_METHOD_MORE
) && (v
->write_disconnected
|| v
->output_buffer_size
== 0) && v
->got_pollhup
)
797 varlink_set_state(v
, VARLINK_PENDING_DISCONNECT
);
801 static int varlink_write(Varlink
*v
) {
807 if (!VARLINK_STATE_IS_ALIVE(v
->state
))
809 if (v
->connecting
) /* Writing while we are still wait for a non-blocking connect() to complete will
810 * result in ENOTCONN, hence exit early here */
812 if (v
->write_disconnected
)
815 /* If needed let's convert some output queue json variants into text form */
816 r
= varlink_format_queue(v
);
820 if (v
->output_buffer_size
== 0)
825 if (v
->n_output_fds
> 0) { /* If we shall send fds along, we must use sendmsg() */
827 .iov_base
= v
->output_buffer
+ v
->output_buffer_index
,
828 .iov_len
= v
->output_buffer_size
,
833 .msg_controllen
= CMSG_SPACE(sizeof(int) * v
->n_output_fds
),
836 mh
.msg_control
= alloca0(mh
.msg_controllen
);
838 struct cmsghdr
*control
= CMSG_FIRSTHDR(&mh
);
839 control
->cmsg_len
= CMSG_LEN(sizeof(int) * v
->n_output_fds
);
840 control
->cmsg_level
= SOL_SOCKET
;
841 control
->cmsg_type
= SCM_RIGHTS
;
842 memcpy(CMSG_DATA(control
), v
->output_fds
, sizeof(int) * v
->n_output_fds
);
844 n
= sendmsg(v
->fd
, &mh
, MSG_DONTWAIT
|MSG_NOSIGNAL
);
846 /* We generally prefer recv()/send() (mostly because of MSG_NOSIGNAL) but also want to be compatible
847 * with non-socket IO, hence fall back automatically.
849 * Use a local variable to help gcc figure out that we set 'n' in all cases. */
850 bool prefer_write
= v
->prefer_read_write
;
852 n
= send(v
->fd
, v
->output_buffer
+ v
->output_buffer_index
, v
->output_buffer_size
, MSG_DONTWAIT
|MSG_NOSIGNAL
);
853 if (n
< 0 && errno
== ENOTSOCK
)
854 prefer_write
= v
->prefer_read_write
= true;
857 n
= write(v
->fd
, v
->output_buffer
+ v
->output_buffer_index
, v
->output_buffer_size
);
863 if (ERRNO_IS_DISCONNECT(errno
)) {
864 /* If we get informed about a disconnect on write, then let's remember that, but not
865 * act on it just yet. Let's wait for read() to report the issue first. */
866 v
->write_disconnected
= true;
873 if (v
->output_buffer_sensitive
)
874 explicit_bzero_safe(v
->output_buffer
+ v
->output_buffer_index
, n
);
876 v
->output_buffer_size
-= n
;
878 if (v
->output_buffer_size
== 0) {
879 v
->output_buffer_index
= 0;
880 v
->output_buffer_sensitive
= false; /* We can reset the sensitive flag once the buffer is empty */
882 v
->output_buffer_index
+= n
;
884 close_many(v
->output_fds
, v
->n_output_fds
);
887 v
->timestamp
= now(CLOCK_MONOTONIC
);
891 #define VARLINK_FDS_MAX (16U*1024U)
893 static int varlink_read(Varlink
*v
) {
902 if (!IN_SET(v
->state
, VARLINK_AWAITING_REPLY
, VARLINK_AWAITING_REPLY_MORE
, VARLINK_CALLING
, VARLINK_COLLECTING
, VARLINK_IDLE_SERVER
))
904 if (v
->connecting
) /* read() on a socket while we are in connect() will fail with EINVAL, hence exit early here */
908 if (v
->input_buffer_unscanned
> 0)
910 if (v
->read_disconnected
)
913 if (v
->input_buffer_size
>= VARLINK_BUFFER_MAX
)
918 if (MALLOC_SIZEOF_SAFE(v
->input_buffer
) <= v
->input_buffer_index
+ v
->input_buffer_size
) {
921 add
= MIN(VARLINK_BUFFER_MAX
- v
->input_buffer_size
, VARLINK_READ_SIZE
);
923 if (v
->input_buffer_index
== 0) {
925 if (!GREEDY_REALLOC(v
->input_buffer
, v
->input_buffer_size
+ add
))
931 b
= new(char, v
->input_buffer_size
+ add
);
935 memcpy(b
, v
->input_buffer
+ v
->input_buffer_index
, v
->input_buffer_size
);
937 free_and_replace(v
->input_buffer
, b
);
938 v
->input_buffer_index
= 0;
942 p
= v
->input_buffer
+ v
->input_buffer_index
+ v
->input_buffer_size
;
943 rs
= MALLOC_SIZEOF_SAFE(v
->input_buffer
) - (v
->input_buffer_index
+ v
->input_buffer_size
);
945 if (v
->allow_fd_passing_input
) {
946 iov
= IOVEC_MAKE(p
, rs
);
948 /* Allocate the fd buffer on the heap, since we need a lot of space potentially */
949 if (!v
->input_control_buffer
) {
950 v
->input_control_buffer_size
= CMSG_SPACE(sizeof(int) * VARLINK_FDS_MAX
);
951 v
->input_control_buffer
= malloc(v
->input_control_buffer_size
);
952 if (!v
->input_control_buffer
)
956 mh
= (struct msghdr
) {
959 .msg_control
= v
->input_control_buffer
,
960 .msg_controllen
= v
->input_control_buffer_size
,
963 n
= recvmsg_safe(v
->fd
, &mh
, MSG_DONTWAIT
|MSG_CMSG_CLOEXEC
);
965 bool prefer_read
= v
->prefer_read_write
;
967 n
= recv(v
->fd
, p
, rs
, MSG_DONTWAIT
);
968 if (n
< 0 && errno
== ENOTSOCK
)
969 prefer_read
= v
->prefer_read_write
= true;
972 n
= read(v
->fd
, p
, rs
);
978 if (ERRNO_IS_DISCONNECT(errno
)) {
979 v
->read_disconnected
= true;
985 if (n
== 0) { /* EOF */
987 if (v
->allow_fd_passing_input
)
990 v
->read_disconnected
= true;
994 if (v
->allow_fd_passing_input
) {
995 struct cmsghdr
* cmsg
;
997 cmsg
= cmsg_find(&mh
, SOL_SOCKET
, SCM_RIGHTS
, (socklen_t
) -1);
1001 /* We only allow file descriptors to be passed along with the first byte of a
1002 * message. If they are passed with any other byte this is a protocol violation. */
1003 if (v
->input_buffer_size
!= 0) {
1004 cmsg_close_all(&mh
);
1008 add
= (cmsg
->cmsg_len
- CMSG_LEN(0)) / sizeof(int);
1009 if (add
> INT_MAX
- v
->n_input_fds
) {
1010 cmsg_close_all(&mh
);
1014 if (!GREEDY_REALLOC(v
->input_fds
, v
->n_input_fds
+ add
)) {
1015 cmsg_close_all(&mh
);
1019 memcpy_safe(v
->input_fds
+ v
->n_input_fds
, CMSG_TYPED_DATA(cmsg
, int), add
* sizeof(int));
1020 v
->n_input_fds
+= add
;
1024 v
->input_buffer_size
+= n
;
1025 v
->input_buffer_unscanned
+= n
;
1030 static int varlink_parse_message(Varlink
*v
) {
1040 if (v
->input_buffer_unscanned
<= 0)
1043 assert(v
->input_buffer_unscanned
<= v
->input_buffer_size
);
1044 assert(v
->input_buffer_index
+ v
->input_buffer_size
<= MALLOC_SIZEOF_SAFE(v
->input_buffer
));
1046 begin
= v
->input_buffer
+ v
->input_buffer_index
;
1048 e
= memchr(begin
+ v
->input_buffer_size
- v
->input_buffer_unscanned
, 0, v
->input_buffer_unscanned
);
1050 v
->input_buffer_unscanned
= 0;
1056 r
= json_parse(begin
, 0, &v
->current
, NULL
, NULL
);
1057 if (v
->input_sensitive
)
1058 explicit_bzero_safe(begin
, sz
);
1060 /* If we encounter a parse failure flush all data. We cannot possibly recover from this,
1061 * hence drop all buffered data now. */
1062 v
->input_buffer_index
= v
->input_buffer_size
= v
->input_buffer_unscanned
= 0;
1063 return varlink_log_errno(v
, r
, "Failed to parse JSON: %m");
1066 if (v
->input_sensitive
) {
1067 /* Mark the parameters subfield as sensitive right-away, if that's requested */
1068 JsonVariant
*parameters
= json_variant_by_key(v
->current
, "parameters");
1070 json_variant_sensitive(parameters
);
1073 if (DEBUG_LOGGING
) {
1074 _cleanup_(erase_and_freep
) char *censored_text
= NULL
;
1076 /* Suppress sensitive fields in the debug output */
1077 r
= json_variant_format(v
->current
, /* flags= */ JSON_FORMAT_CENSOR_SENSITIVE
, &censored_text
);
1081 varlink_log(v
, "Received message: %s", censored_text
);
1084 v
->input_buffer_size
-= sz
;
1086 if (v
->input_buffer_size
== 0)
1087 v
->input_buffer_index
= 0;
1089 v
->input_buffer_index
+= sz
;
1091 v
->input_buffer_unscanned
= v
->input_buffer_size
;
1095 static int varlink_test_timeout(Varlink
*v
) {
1098 if (!IN_SET(v
->state
, VARLINK_AWAITING_REPLY
, VARLINK_AWAITING_REPLY_MORE
, VARLINK_CALLING
, VARLINK_COLLECTING
))
1100 if (v
->timeout
== USEC_INFINITY
)
1103 if (now(CLOCK_MONOTONIC
) < usec_add(v
->timestamp
, v
->timeout
))
1106 varlink_set_state(v
, VARLINK_PENDING_TIMEOUT
);
1111 static int varlink_dispatch_local_error(Varlink
*v
, const char *error
) {
1117 if (!v
->reply_callback
)
1120 r
= v
->reply_callback(v
, NULL
, error
, VARLINK_REPLY_ERROR
|VARLINK_REPLY_LOCAL
, v
->userdata
);
1122 varlink_log_errno(v
, r
, "Reply callback returned error, ignoring: %m");
1127 static int varlink_dispatch_timeout(Varlink
*v
) {
1130 if (v
->state
!= VARLINK_PENDING_TIMEOUT
)
1133 varlink_set_state(v
, VARLINK_PROCESSING_TIMEOUT
);
1134 varlink_dispatch_local_error(v
, VARLINK_ERROR_TIMEOUT
);
1140 static int varlink_dispatch_disconnect(Varlink
*v
) {
1143 if (v
->state
!= VARLINK_PENDING_DISCONNECT
)
1146 varlink_set_state(v
, VARLINK_PROCESSING_DISCONNECT
);
1147 varlink_dispatch_local_error(v
, VARLINK_ERROR_DISCONNECTED
);
1153 static int varlink_sanitize_parameters(JsonVariant
**v
) {
1158 /* Varlink always wants a parameters list, hence make one if the caller doesn't want any */
1160 return json_variant_new_object(v
, NULL
, 0);
1161 if (json_variant_is_null(*v
)) {
1164 r
= json_variant_new_object(&empty
, NULL
, 0);
1168 json_variant_unref(*v
);
1172 if (!json_variant_is_object(*v
))
1178 static int varlink_dispatch_reply(Varlink
*v
) {
1179 _cleanup_(json_variant_unrefp
) JsonVariant
*parameters
= NULL
;
1180 VarlinkReplyFlags flags
= 0;
1181 const char *error
= NULL
;
1188 if (!IN_SET(v
->state
, VARLINK_AWAITING_REPLY
, VARLINK_AWAITING_REPLY_MORE
, VARLINK_CALLING
, VARLINK_COLLECTING
))
1193 assert(v
->n_pending
> 0);
1195 if (!json_variant_is_object(v
->current
))
1198 JSON_VARIANT_OBJECT_FOREACH(k
, e
, v
->current
) {
1200 if (streq(k
, "error")) {
1203 if (!json_variant_is_string(e
))
1206 error
= json_variant_string(e
);
1207 flags
|= VARLINK_REPLY_ERROR
;
1209 } else if (streq(k
, "parameters")) {
1212 if (!json_variant_is_object(e
) && !json_variant_is_null(e
))
1215 parameters
= json_variant_ref(e
);
1217 } else if (streq(k
, "continues")) {
1218 if (FLAGS_SET(flags
, VARLINK_REPLY_CONTINUES
))
1221 if (!json_variant_is_boolean(e
))
1224 if (json_variant_boolean(e
))
1225 flags
|= VARLINK_REPLY_CONTINUES
;
1230 /* Replies with 'continue' set are only OK if we set 'more' when the method call was initiated */
1231 if (!IN_SET(v
->state
, VARLINK_AWAITING_REPLY_MORE
, VARLINK_COLLECTING
) && FLAGS_SET(flags
, VARLINK_REPLY_CONTINUES
))
1234 /* An error is final */
1235 if (error
&& FLAGS_SET(flags
, VARLINK_REPLY_CONTINUES
))
1238 r
= varlink_sanitize_parameters(¶meters
);
1242 v
->current_reply_flags
= flags
;
1244 if (IN_SET(v
->state
, VARLINK_AWAITING_REPLY
, VARLINK_AWAITING_REPLY_MORE
)) {
1245 varlink_set_state(v
, VARLINK_PROCESSING_REPLY
);
1247 if (v
->reply_callback
) {
1248 r
= v
->reply_callback(v
, parameters
, error
, flags
, v
->userdata
);
1250 varlink_log_errno(v
, r
, "Reply callback returned error, ignoring: %m");
1253 varlink_clear_current(v
);
1255 if (v
->state
== VARLINK_PROCESSING_REPLY
) {
1256 assert(v
->n_pending
> 0);
1258 if (!FLAGS_SET(flags
, VARLINK_REPLY_CONTINUES
))
1261 varlink_set_state(v
,
1262 FLAGS_SET(flags
, VARLINK_REPLY_CONTINUES
) ? VARLINK_AWAITING_REPLY_MORE
:
1263 v
->n_pending
== 0 ? VARLINK_IDLE_CLIENT
: VARLINK_AWAITING_REPLY
);
1265 } else if (v
->state
== VARLINK_COLLECTING
)
1266 varlink_set_state(v
, VARLINK_COLLECTING_REPLY
);
1268 assert(v
->state
== VARLINK_CALLING
);
1269 varlink_set_state(v
, VARLINK_CALLED
);
1275 varlink_set_state(v
, VARLINK_PROCESSING_FAILURE
);
1276 varlink_dispatch_local_error(v
, VARLINK_ERROR_PROTOCOL
);
1282 static int generic_method_get_info(
1284 JsonVariant
*parameters
,
1285 VarlinkMethodFlags flags
,
1288 _cleanup_strv_free_
char **interfaces
= NULL
;
1289 _cleanup_free_
char *product
= NULL
;
1294 if (json_variant_elements(parameters
) != 0)
1295 return varlink_error_invalid_parameter(link
, parameters
);
1297 product
= strjoin("systemd (", program_invocation_short_name
, ")");
1301 VarlinkInterface
*interface
;
1302 HASHMAP_FOREACH(interface
, ASSERT_PTR(link
->server
)->interfaces
) {
1303 r
= strv_extend(&interfaces
, interface
->name
);
1308 strv_sort(interfaces
);
1310 return varlink_replyb(link
, JSON_BUILD_OBJECT(
1311 JSON_BUILD_PAIR_STRING("vendor", "The systemd Project"),
1312 JSON_BUILD_PAIR_STRING("product", product
),
1313 JSON_BUILD_PAIR_STRING("version", PROJECT_VERSION_FULL
" (" GIT_VERSION
")"),
1314 JSON_BUILD_PAIR_STRING("url", "https://systemd.io/"),
1315 JSON_BUILD_PAIR_STRV("interfaces", interfaces
)));
1318 static int generic_method_get_interface_description(
1320 JsonVariant
*parameters
,
1321 VarlinkMethodFlags flags
,
1324 static const struct JsonDispatch dispatch_table
[] = {
1325 { "interface", JSON_VARIANT_STRING
, json_dispatch_const_string
, 0, JSON_MANDATORY
},
1328 _cleanup_free_
char *text
= NULL
;
1329 const VarlinkInterface
*interface
;
1330 const char *name
= NULL
;
1335 r
= json_dispatch(parameters
, dispatch_table
, 0, &name
);
1339 interface
= hashmap_get(ASSERT_PTR(link
->server
)->interfaces
, name
);
1341 return varlink_errorb(link
, VARLINK_ERROR_INTERFACE_NOT_FOUND
,
1343 JSON_BUILD_PAIR_STRING("interface", name
)));
1345 r
= varlink_idl_format(interface
, &text
);
1349 return varlink_replyb(link
,
1351 JSON_BUILD_PAIR_STRING("description", text
)));
1354 static int varlink_dispatch_method(Varlink
*v
) {
1355 _cleanup_(json_variant_unrefp
) JsonVariant
*parameters
= NULL
;
1356 VarlinkMethodFlags flags
= 0;
1357 const char *method
= NULL
;
1359 VarlinkMethod callback
;
1365 if (v
->state
!= VARLINK_IDLE_SERVER
)
1370 if (!json_variant_is_object(v
->current
))
1373 JSON_VARIANT_OBJECT_FOREACH(k
, e
, v
->current
) {
1375 if (streq(k
, "method")) {
1378 if (!json_variant_is_string(e
))
1381 method
= json_variant_string(e
);
1383 } else if (streq(k
, "parameters")) {
1386 if (!json_variant_is_object(e
) && !json_variant_is_null(e
))
1389 parameters
= json_variant_ref(e
);
1391 } else if (streq(k
, "oneway")) {
1393 if ((flags
& (VARLINK_METHOD_ONEWAY
|VARLINK_METHOD_MORE
)) != 0)
1396 if (!json_variant_is_boolean(e
))
1399 if (json_variant_boolean(e
))
1400 flags
|= VARLINK_METHOD_ONEWAY
;
1402 } else if (streq(k
, "more")) {
1404 if ((flags
& (VARLINK_METHOD_ONEWAY
|VARLINK_METHOD_MORE
)) != 0)
1407 if (!json_variant_is_boolean(e
))
1410 if (json_variant_boolean(e
))
1411 flags
|= VARLINK_METHOD_MORE
;
1420 r
= varlink_sanitize_parameters(¶meters
);
1424 varlink_set_state(v
, (flags
& VARLINK_METHOD_MORE
) ? VARLINK_PROCESSING_METHOD_MORE
:
1425 (flags
& VARLINK_METHOD_ONEWAY
) ? VARLINK_PROCESSING_METHOD_ONEWAY
:
1426 VARLINK_PROCESSING_METHOD
);
1430 /* First consult user supplied method implementations */
1431 callback
= hashmap_get(v
->server
->methods
, method
);
1433 if (streq(method
, "org.varlink.service.GetInfo"))
1434 callback
= generic_method_get_info
;
1435 else if (streq(method
, "org.varlink.service.GetInterfaceDescription"))
1436 callback
= generic_method_get_interface_description
;
1440 bool invalid
= false;
1442 v
->current_method
= hashmap_get(v
->server
->symbols
, method
);
1443 if (!v
->current_method
)
1444 varlink_log(v
, "No interface description defined for method '%s', not validating.", method
);
1446 const char *bad_field
;
1448 r
= varlink_idl_validate_method_call(v
->current_method
, parameters
, &bad_field
);
1450 /* Please adjust test/units/end.sh when updating the log message. */
1451 varlink_log_errno(v
, r
, "Parameters for method %s() didn't pass validation on field '%s': %m",
1452 method
, strna(bad_field
));
1454 if (IN_SET(v
->state
, VARLINK_PROCESSING_METHOD
, VARLINK_PROCESSING_METHOD_MORE
)) {
1455 r
= varlink_error_invalid_parameter_name(v
, bad_field
);
1464 r
= callback(v
, parameters
, flags
, v
->userdata
);
1466 varlink_log_errno(v
, r
, "Callback for %s returned error: %m", method
);
1468 /* We got an error back from the callback. Propagate it to the client if the method call remains unanswered. */
1469 if (IN_SET(v
->state
, VARLINK_PROCESSING_METHOD
, VARLINK_PROCESSING_METHOD_MORE
)) {
1470 r
= varlink_error_errno(v
, r
);
1476 } else if (IN_SET(v
->state
, VARLINK_PROCESSING_METHOD
, VARLINK_PROCESSING_METHOD_MORE
)) {
1477 r
= varlink_errorb(v
, VARLINK_ERROR_METHOD_NOT_FOUND
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method
))));
1484 case VARLINK_PROCESSED_METHOD
: /* Method call is fully processed */
1485 case VARLINK_PROCESSING_METHOD_ONEWAY
: /* ditto */
1486 varlink_clear_current(v
);
1487 varlink_set_state(v
, VARLINK_IDLE_SERVER
);
1490 case VARLINK_PROCESSING_METHOD
: /* Method call wasn't replied to, will be replied to later */
1491 varlink_set_state(v
, VARLINK_PENDING_METHOD
);
1494 case VARLINK_PROCESSING_METHOD_MORE
: /* No reply for a "more" message was sent, more to come */
1495 varlink_set_state(v
, VARLINK_PENDING_METHOD_MORE
);
1499 assert_not_reached();
1508 varlink_set_state(v
, VARLINK_PROCESSING_FAILURE
);
1509 varlink_dispatch_local_error(v
, VARLINK_ERROR_PROTOCOL
);
1515 int varlink_process(Varlink
*v
) {
1518 assert_return(v
, -EINVAL
);
1520 if (v
->state
== VARLINK_DISCONNECTED
)
1521 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENOTCONN
), "Not connected.");
1525 r
= varlink_write(v
);
1527 varlink_log_errno(v
, r
, "Write failed: %m");
1531 r
= varlink_dispatch_reply(v
);
1533 varlink_log_errno(v
, r
, "Reply dispatch failed: %m");
1537 r
= varlink_dispatch_method(v
);
1539 varlink_log_errno(v
, r
, "Method dispatch failed: %m");
1543 r
= varlink_parse_message(v
);
1545 varlink_log_errno(v
, r
, "Message parsing failed: %m");
1549 r
= varlink_read(v
);
1551 varlink_log_errno(v
, r
, "Read failed: %m");
1555 r
= varlink_test_disconnect(v
);
1560 r
= varlink_dispatch_disconnect(v
);
1565 r
= varlink_test_timeout(v
);
1570 r
= varlink_dispatch_timeout(v
);
1576 if (r
>= 0 && v
->defer_event_source
) {
1579 /* If we did some processing, make sure we are called again soon */
1580 q
= sd_event_source_set_enabled(v
->defer_event_source
, r
> 0 ? SD_EVENT_ON
: SD_EVENT_OFF
);
1582 r
= varlink_log_errno(v
, q
, "Failed to enable deferred event source: %m");
1586 if (VARLINK_STATE_IS_ALIVE(v
->state
))
1587 /* Initiate disconnection */
1588 varlink_set_state(v
, VARLINK_PENDING_DISCONNECT
);
1590 /* We failed while disconnecting, in that case close right away */
1598 int varlink_dispatch_again(Varlink
*v
) {
1601 assert_return(v
, -EINVAL
);
1603 /* If a method call handler could not process the method call just yet (for example because it needed
1604 * some Polkit authentication first), then it can leave the call unanswered, do its thing, and then
1605 * ask to be dispatched a second time, via this call. It will then be called again, for the same
1608 if (v
->state
== VARLINK_DISCONNECTED
)
1609 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENOTCONN
), "Not connected.");
1610 if (v
->state
!= VARLINK_PENDING_METHOD
)
1611 return varlink_log_errno(v
, SYNTHETIC_ERRNO(EBUSY
), "Connection has no pending method.");
1613 varlink_set_state(v
, VARLINK_IDLE_SERVER
);
1615 r
= sd_event_source_set_enabled(v
->defer_event_source
, SD_EVENT_ON
);
1617 return varlink_log_errno(v
, r
, "Failed to enable deferred event source: %m");
1622 int varlink_get_current_parameters(Varlink
*v
, JsonVariant
**ret
) {
1625 assert_return(v
, -EINVAL
);
1630 p
= json_variant_by_key(v
->current
, "parameters");
1635 *ret
= json_variant_ref(p
);
1640 static void handle_revents(Varlink
*v
, int revents
) {
1643 if (v
->connecting
) {
1644 /* If we have seen POLLOUT or POLLHUP on a socket we are asynchronously waiting a connect()
1645 * to complete on, we know we are ready. We don't read the connection error here though,
1646 * we'll get the error on the next read() or write(). */
1647 if ((revents
& (POLLOUT
|POLLHUP
)) == 0)
1650 varlink_log(v
, "Asynchronous connection completed.");
1651 v
->connecting
= false;
1653 /* Note that we don't care much about POLLIN/POLLOUT here, we'll just try reading and writing
1654 * what we can. However, we do care about POLLHUP to detect connection termination even if we
1655 * momentarily don't want to read nor write anything. */
1657 if (!FLAGS_SET(revents
, POLLHUP
))
1660 varlink_log(v
, "Got POLLHUP from socket.");
1661 v
->got_pollhup
= true;
1665 int varlink_wait(Varlink
*v
, usec_t timeout
) {
1669 assert_return(v
, -EINVAL
);
1671 if (v
->state
== VARLINK_DISCONNECTED
)
1672 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENOTCONN
), "Not connected.");
1674 r
= varlink_get_timeout(v
, &t
);
1677 if (t
!= USEC_INFINITY
) {
1680 n
= now(CLOCK_MONOTONIC
);
1684 t
= usec_sub_unsigned(t
, n
);
1687 if (timeout
!= USEC_INFINITY
&&
1688 (t
== USEC_INFINITY
|| timeout
< t
))
1691 fd
= varlink_get_fd(v
);
1695 events
= varlink_get_events(v
);
1699 r
= fd_wait_for_event(fd
, events
, t
);
1700 if (ERRNO_IS_NEG_TRANSIENT(r
)) /* Treat EINTR as not a timeout, but also nothing happened, and
1701 * the caller gets a chance to call back into us */
1706 handle_revents(v
, r
);
1710 int varlink_is_idle(Varlink
*v
) {
1711 assert_return(v
, -EINVAL
);
1713 /* Returns true if there's nothing pending on the connection anymore, i.e. we processed all incoming
1714 * or outgoing messages fully, or finished disconnection */
1716 return IN_SET(v
->state
, VARLINK_DISCONNECTED
, VARLINK_IDLE_CLIENT
, VARLINK_IDLE_SERVER
);
1719 int varlink_get_fd(Varlink
*v
) {
1721 assert_return(v
, -EINVAL
);
1723 if (v
->state
== VARLINK_DISCONNECTED
)
1724 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENOTCONN
), "Not connected.");
1726 return varlink_log_errno(v
, SYNTHETIC_ERRNO(EBADF
), "No valid fd.");
1731 int varlink_get_events(Varlink
*v
) {
1734 assert_return(v
, -EINVAL
);
1736 if (v
->state
== VARLINK_DISCONNECTED
)
1737 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENOTCONN
), "Not connected.");
1739 if (v
->connecting
) /* When processing an asynchronous connect(), we only wait for EPOLLOUT, which
1740 * tells us that the connection is now complete. Before that we should neither
1741 * write() or read() from the fd. */
1744 if (!v
->read_disconnected
&&
1745 IN_SET(v
->state
, VARLINK_AWAITING_REPLY
, VARLINK_AWAITING_REPLY_MORE
, VARLINK_CALLING
, VARLINK_COLLECTING
, VARLINK_IDLE_SERVER
) &&
1747 v
->input_buffer_unscanned
<= 0)
1750 if (!v
->write_disconnected
&&
1751 v
->output_buffer_size
> 0)
1757 int varlink_get_timeout(Varlink
*v
, usec_t
*ret
) {
1758 assert_return(v
, -EINVAL
);
1760 if (v
->state
== VARLINK_DISCONNECTED
)
1761 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENOTCONN
), "Not connected.");
1763 if (IN_SET(v
->state
, VARLINK_AWAITING_REPLY
, VARLINK_AWAITING_REPLY_MORE
, VARLINK_CALLING
, VARLINK_COLLECTING
) &&
1764 v
->timeout
!= USEC_INFINITY
) {
1766 *ret
= usec_add(v
->timestamp
, v
->timeout
);
1770 *ret
= USEC_INFINITY
;
1775 int varlink_flush(Varlink
*v
) {
1778 assert_return(v
, -EINVAL
);
1780 if (v
->state
== VARLINK_DISCONNECTED
)
1781 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENOTCONN
), "Not connected.");
1784 if (v
->output_buffer_size
== 0)
1786 if (v
->write_disconnected
)
1789 r
= varlink_write(v
);
1797 r
= fd_wait_for_event(v
->fd
, POLLOUT
, USEC_INFINITY
);
1798 if (ERRNO_IS_NEG_TRANSIENT(r
))
1801 return varlink_log_errno(v
, r
, "Poll failed on fd: %m");
1804 handle_revents(v
, r
);
1810 static void varlink_detach_server(Varlink
*v
) {
1811 VarlinkServer
*saved_server
;
1817 if (v
->server
->by_uid
&&
1818 v
->ucred_acquired
&&
1819 uid_is_valid(v
->ucred
.uid
)) {
1822 c
= PTR_TO_UINT(hashmap_get(v
->server
->by_uid
, UID_TO_PTR(v
->ucred
.uid
)));
1826 (void) hashmap_remove(v
->server
->by_uid
, UID_TO_PTR(v
->ucred
.uid
));
1828 (void) hashmap_replace(v
->server
->by_uid
, UID_TO_PTR(v
->ucred
.uid
), UINT_TO_PTR(c
- 1));
1831 assert(v
->server
->n_connections
> 0);
1832 v
->server
->n_connections
--;
1834 /* If this is a connection associated to a server, then let's disconnect the server and the
1835 * connection from each other. This drops the dangling reference that connect_callback() set up. But
1836 * before we release the references, let's call the disconnection callback if it is defined. */
1838 saved_server
= TAKE_PTR(v
->server
);
1840 if (saved_server
->disconnect_callback
)
1841 saved_server
->disconnect_callback(saved_server
, v
, saved_server
->userdata
);
1843 varlink_server_test_exit_on_idle(saved_server
);
1844 varlink_server_unref(saved_server
);
1848 int varlink_close(Varlink
*v
) {
1849 assert_return(v
, -EINVAL
);
1851 if (v
->state
== VARLINK_DISCONNECTED
)
1854 varlink_set_state(v
, VARLINK_DISCONNECTED
);
1856 /* Let's take a reference first, since varlink_detach_server() might drop the final (dangling) ref
1857 * which would destroy us before we can call varlink_clear() */
1859 varlink_detach_server(v
);
1866 Varlink
* varlink_close_unref(Varlink
*v
) {
1870 (void) varlink_close(v
);
1871 return varlink_unref(v
);
1874 Varlink
* varlink_flush_close_unref(Varlink
*v
) {
1878 (void) varlink_flush(v
);
1879 return varlink_close_unref(v
);
1882 static int varlink_format_json(Varlink
*v
, JsonVariant
*m
) {
1883 _cleanup_(erase_and_freep
) char *text
= NULL
;
1889 sz
= json_variant_format(m
, /* flags= */ 0, &text
);
1892 assert(text
[sz
] == '\0');
1894 if (v
->output_buffer_size
+ sz
+ 1 > VARLINK_BUFFER_MAX
)
1897 if (DEBUG_LOGGING
) {
1898 _cleanup_(erase_and_freep
) char *censored_text
= NULL
;
1900 /* Suppress sensitive fields in the debug output */
1901 r
= json_variant_format(m
, /* flags= */ JSON_FORMAT_CENSOR_SENSITIVE
, &censored_text
);
1905 varlink_log(v
, "Sending message: %s", censored_text
);
1908 if (v
->output_buffer_size
== 0) {
1910 free_and_replace(v
->output_buffer
, text
);
1912 v
->output_buffer_size
= sz
+ 1;
1913 v
->output_buffer_index
= 0;
1915 } else if (v
->output_buffer_index
== 0) {
1917 if (!GREEDY_REALLOC(v
->output_buffer
, v
->output_buffer_size
+ sz
+ 1))
1920 memcpy(v
->output_buffer
+ v
->output_buffer_size
, text
, sz
+ 1);
1921 v
->output_buffer_size
+= sz
+ 1;
1924 const size_t new_size
= v
->output_buffer_size
+ sz
+ 1;
1926 n
= new(char, new_size
);
1930 memcpy(mempcpy(n
, v
->output_buffer
+ v
->output_buffer_index
, v
->output_buffer_size
), text
, sz
+ 1);
1932 free_and_replace(v
->output_buffer
, n
);
1933 v
->output_buffer_size
= new_size
;
1934 v
->output_buffer_index
= 0;
1937 if (json_variant_is_sensitive_recursive(m
))
1938 v
->output_buffer_sensitive
= true; /* Propagate sensitive flag */
1940 text
= mfree(text
); /* No point in the erase_and_free() destructor declared above */
1945 static int varlink_enqueue_json(Varlink
*v
, JsonVariant
*m
) {
1946 VarlinkJsonQueueItem
*q
;
1951 /* If there are no file descriptors to be queued and no queue entries yet we can shortcut things and
1952 * append this entry directly to the output buffer */
1953 if (v
->n_pushed_fds
== 0 && !v
->output_queue
)
1954 return varlink_format_json(v
, m
);
1956 /* Otherwise add a queue entry for this */
1957 q
= varlink_json_queue_item_new(m
, v
->pushed_fds
, v
->n_pushed_fds
);
1961 v
->n_pushed_fds
= 0; /* fds now belong to the queue entry */
1963 LIST_INSERT_AFTER(queue
, v
->output_queue
, v
->output_queue_tail
, q
);
1964 v
->output_queue_tail
= q
;
1968 static int varlink_format_queue(Varlink
*v
) {
1973 /* Takes entries out of the output queue and formats them into the output buffer. But only if this
1974 * would not corrupt our fd message boundaries */
1976 while (v
->output_queue
) {
1977 _cleanup_free_
int *array
= NULL
;
1978 VarlinkJsonQueueItem
*q
= v
->output_queue
;
1980 if (v
->n_output_fds
> 0) /* unwritten fds? if we'd add more we'd corrupt the fd message boundaries, hence wait */
1984 array
= newdup(int, q
->fds
, q
->n_fds
);
1989 r
= varlink_format_json(v
, q
->data
);
1993 /* Take possession of the queue element's fds */
1994 free(v
->output_fds
);
1995 v
->output_fds
= TAKE_PTR(array
);
1996 v
->n_output_fds
= q
->n_fds
;
1999 LIST_REMOVE(queue
, v
->output_queue
, q
);
2000 if (!v
->output_queue
)
2001 v
->output_queue_tail
= NULL
;
2003 varlink_json_queue_item_free(q
);
2009 int varlink_send(Varlink
*v
, const char *method
, JsonVariant
*parameters
) {
2010 _cleanup_(json_variant_unrefp
) JsonVariant
*m
= NULL
;
2013 assert_return(v
, -EINVAL
);
2014 assert_return(method
, -EINVAL
);
2016 if (v
->state
== VARLINK_DISCONNECTED
)
2017 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENOTCONN
), "Not connected.");
2019 /* We allow enqueuing multiple method calls at once! */
2020 if (!IN_SET(v
->state
, VARLINK_IDLE_CLIENT
, VARLINK_AWAITING_REPLY
))
2021 return varlink_log_errno(v
, SYNTHETIC_ERRNO(EBUSY
), "Connection busy.");
2023 r
= varlink_sanitize_parameters(¶meters
);
2025 return varlink_log_errno(v
, r
, "Failed to sanitize parameters: %m");
2027 r
= json_build(&m
, JSON_BUILD_OBJECT(
2028 JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method
)),
2029 JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters
)),
2030 JSON_BUILD_PAIR("oneway", JSON_BUILD_BOOLEAN(true))));
2032 return varlink_log_errno(v
, r
, "Failed to build json message: %m");
2034 r
= varlink_enqueue_json(v
, m
);
2036 return varlink_log_errno(v
, r
, "Failed to enqueue json message: %m");
2038 /* No state change here, this is one-way only after all */
2039 v
->timestamp
= now(CLOCK_MONOTONIC
);
2043 int varlink_sendb(Varlink
*v
, const char *method
, ...) {
2044 _cleanup_(json_variant_unrefp
) JsonVariant
*parameters
= NULL
;
2048 assert_return(v
, -EINVAL
);
2050 va_start(ap
, method
);
2051 r
= json_buildv(¶meters
, ap
);
2055 return varlink_log_errno(v
, r
, "Failed to build json message: %m");
2057 return varlink_send(v
, method
, parameters
);
2060 int varlink_invoke(Varlink
*v
, const char *method
, JsonVariant
*parameters
) {
2061 _cleanup_(json_variant_unrefp
) JsonVariant
*m
= NULL
;
2064 assert_return(v
, -EINVAL
);
2065 assert_return(method
, -EINVAL
);
2067 if (v
->state
== VARLINK_DISCONNECTED
)
2068 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENOTCONN
), "Not connected.");
2070 /* We allow enqueuing multiple method calls at once! */
2071 if (!IN_SET(v
->state
, VARLINK_IDLE_CLIENT
, VARLINK_AWAITING_REPLY
))
2072 return varlink_log_errno(v
, SYNTHETIC_ERRNO(EBUSY
), "Connection busy.");
2074 r
= varlink_sanitize_parameters(¶meters
);
2076 return varlink_log_errno(v
, r
, "Failed to sanitize parameters: %m");
2078 r
= json_build(&m
, JSON_BUILD_OBJECT(
2079 JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method
)),
2080 JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters
))));
2082 return varlink_log_errno(v
, r
, "Failed to build json message: %m");
2084 r
= varlink_enqueue_json(v
, m
);
2086 return varlink_log_errno(v
, r
, "Failed to enqueue json message: %m");
2088 varlink_set_state(v
, VARLINK_AWAITING_REPLY
);
2090 v
->timestamp
= now(CLOCK_MONOTONIC
);
2095 int varlink_invokeb(Varlink
*v
, const char *method
, ...) {
2096 _cleanup_(json_variant_unrefp
) JsonVariant
*parameters
= NULL
;
2100 assert_return(v
, -EINVAL
);
2102 va_start(ap
, method
);
2103 r
= json_buildv(¶meters
, ap
);
2107 return varlink_log_errno(v
, r
, "Failed to build json message: %m");
2109 return varlink_invoke(v
, method
, parameters
);
2112 int varlink_observe(Varlink
*v
, const char *method
, JsonVariant
*parameters
) {
2113 _cleanup_(json_variant_unrefp
) JsonVariant
*m
= NULL
;
2116 assert_return(v
, -EINVAL
);
2117 assert_return(method
, -EINVAL
);
2119 if (v
->state
== VARLINK_DISCONNECTED
)
2120 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENOTCONN
), "Not connected.");
2122 /* Note that we don't allow enqueuing multiple method calls when we are in more/continues mode! We
2123 * thus insist on an idle client here. */
2124 if (v
->state
!= VARLINK_IDLE_CLIENT
)
2125 return varlink_log_errno(v
, SYNTHETIC_ERRNO(EBUSY
), "Connection busy.");
2127 r
= varlink_sanitize_parameters(¶meters
);
2129 return varlink_log_errno(v
, r
, "Failed to sanitize parameters: %m");
2131 r
= json_build(&m
, JSON_BUILD_OBJECT(
2132 JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method
)),
2133 JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters
)),
2134 JSON_BUILD_PAIR("more", JSON_BUILD_BOOLEAN(true))));
2136 return varlink_log_errno(v
, r
, "Failed to build json message: %m");
2138 r
= varlink_enqueue_json(v
, m
);
2140 return varlink_log_errno(v
, r
, "Failed to enqueue json message: %m");
2142 varlink_set_state(v
, VARLINK_AWAITING_REPLY_MORE
);
2144 v
->timestamp
= now(CLOCK_MONOTONIC
);
2149 int varlink_observeb(Varlink
*v
, const char *method
, ...) {
2150 _cleanup_(json_variant_unrefp
) JsonVariant
*parameters
= NULL
;
2154 assert_return(v
, -EINVAL
);
2156 va_start(ap
, method
);
2157 r
= json_buildv(¶meters
, ap
);
2161 return varlink_log_errno(v
, r
, "Failed to build json message: %m");
2163 return varlink_observe(v
, method
, parameters
);
2166 int varlink_call_full(
2169 JsonVariant
*parameters
,
2170 JsonVariant
**ret_parameters
,
2171 const char **ret_error_id
,
2172 VarlinkReplyFlags
*ret_flags
) {
2174 _cleanup_(json_variant_unrefp
) JsonVariant
*m
= NULL
;
2177 assert_return(v
, -EINVAL
);
2178 assert_return(method
, -EINVAL
);
2180 if (v
->state
== VARLINK_DISCONNECTED
)
2181 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENOTCONN
), "Not connected.");
2182 if (v
->state
!= VARLINK_IDLE_CLIENT
)
2183 return varlink_log_errno(v
, SYNTHETIC_ERRNO(EBUSY
), "Connection busy.");
2185 assert(v
->n_pending
== 0); /* n_pending can't be > 0 if we are in VARLINK_IDLE_CLIENT state */
2187 /* If there was still a reply pinned from a previous call, now it's the time to get rid of it, so
2188 * that we can assign a new reply shortly. */
2189 varlink_clear_current(v
);
2191 r
= varlink_sanitize_parameters(¶meters
);
2193 return varlink_log_errno(v
, r
, "Failed to sanitize parameters: %m");
2195 r
= json_build(&m
, JSON_BUILD_OBJECT(
2196 JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method
)),
2197 JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters
))));
2199 return varlink_log_errno(v
, r
, "Failed to build json message: %m");
2201 r
= varlink_enqueue_json(v
, m
);
2203 return varlink_log_errno(v
, r
, "Failed to enqueue json message: %m");
2205 varlink_set_state(v
, VARLINK_CALLING
);
2207 v
->timestamp
= now(CLOCK_MONOTONIC
);
2209 while (v
->state
== VARLINK_CALLING
) {
2210 r
= varlink_process(v
);
2216 r
= varlink_wait(v
, USEC_INFINITY
);
2223 case VARLINK_CALLED
: {
2226 varlink_set_state(v
, VARLINK_IDLE_CLIENT
);
2227 assert(v
->n_pending
== 1);
2230 JsonVariant
*e
= json_variant_by_key(v
->current
, "error"),
2231 *p
= json_variant_by_key(v
->current
, "parameters");
2233 /* If caller doesn't ask for the error string, then let's return an error code in case of failure */
2234 if (!ret_error_id
&& e
)
2235 return varlink_error_to_errno(json_variant_string(e
), p
);
2238 *ret_parameters
= p
;
2240 *ret_error_id
= e
? json_variant_string(e
) : NULL
;
2242 *ret_flags
= v
->current_reply_flags
;
2247 case VARLINK_PENDING_DISCONNECT
:
2248 case VARLINK_DISCONNECTED
:
2249 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ECONNRESET
), "Connection was closed.");
2251 case VARLINK_PENDING_TIMEOUT
:
2252 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ETIME
), "Connection timed out.");
2255 assert_not_reached();
2259 int varlink_callb_ap(
2262 JsonVariant
**ret_parameters
,
2263 const char **ret_error_id
,
2264 VarlinkReplyFlags
*ret_flags
,
2267 _cleanup_(json_variant_unrefp
) JsonVariant
*parameters
= NULL
;
2270 assert_return(v
, -EINVAL
);
2271 assert_return(method
, -EINVAL
);
2273 r
= json_buildv(¶meters
, ap
);
2275 return varlink_log_errno(v
, r
, "Failed to build json message: %m");
2277 return varlink_call_full(v
, method
, parameters
, ret_parameters
, ret_error_id
, ret_flags
);
2280 int varlink_call_and_log(
2283 JsonVariant
*parameters
,
2284 JsonVariant
**ret_parameters
) {
2286 JsonVariant
*reply
= NULL
;
2287 const char *error_id
= NULL
;
2290 assert_return(v
, -EINVAL
);
2291 assert_return(method
, -EINVAL
);
2293 r
= varlink_call(v
, method
, parameters
, &reply
, &error_id
);
2295 return log_error_errno(r
, "Failed to issue %s() varlink call: %m", method
);
2297 return log_error_errno(varlink_error_to_errno(error_id
, reply
),
2298 "Failed to issue %s() varlink call: %s", method
, error_id
);
2301 *ret_parameters
= TAKE_PTR(reply
);
2306 int varlink_callb_and_log(
2309 JsonVariant
**ret_parameters
,
2312 _cleanup_(json_variant_unrefp
) JsonVariant
*parameters
= NULL
;
2316 assert_return(v
, -EINVAL
);
2317 assert_return(method
, -EINVAL
);
2319 va_start(ap
, ret_parameters
);
2320 r
= json_buildv(¶meters
, ap
);
2323 return log_error_errno(r
, "Failed to build JSON message: %m");
2325 return varlink_call_and_log(v
, method
, parameters
, ret_parameters
);
2328 int varlink_collect_full(
2331 JsonVariant
*parameters
,
2332 JsonVariant
**ret_parameters
,
2333 const char **ret_error_id
,
2334 VarlinkReplyFlags
*ret_flags
) {
2336 _cleanup_(json_variant_unrefp
) JsonVariant
*m
= NULL
, *collected
= NULL
;
2339 assert_return(v
, -EINVAL
);
2340 assert_return(method
, -EINVAL
);
2342 if (v
->state
== VARLINK_DISCONNECTED
)
2343 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENOTCONN
), "Not connected.");
2344 if (v
->state
!= VARLINK_IDLE_CLIENT
)
2345 return varlink_log_errno(v
, SYNTHETIC_ERRNO(EBUSY
), "Connection busy.");
2347 assert(v
->n_pending
== 0); /* n_pending can't be > 0 if we are in VARLINK_IDLE_CLIENT state */
2349 /* If there was still a reply pinned from a previous call, now it's the time to get rid of it, so
2350 * that we can assign a new reply shortly. */
2351 varlink_clear_current(v
);
2353 r
= varlink_sanitize_parameters(¶meters
);
2355 return varlink_log_errno(v
, r
, "Failed to sanitize parameters: %m");
2357 r
= json_build(&m
, JSON_BUILD_OBJECT(
2358 JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method
)),
2359 JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters
)),
2360 JSON_BUILD_PAIR("more", JSON_BUILD_BOOLEAN(true))));
2362 return varlink_log_errno(v
, r
, "Failed to build json message: %m");
2364 r
= varlink_enqueue_json(v
, m
);
2366 return varlink_log_errno(v
, r
, "Failed to enqueue json message: %m");
2368 varlink_set_state(v
, VARLINK_COLLECTING
);
2370 v
->timestamp
= now(CLOCK_MONOTONIC
);
2373 while (v
->state
== VARLINK_COLLECTING
) {
2374 r
= varlink_process(v
);
2380 r
= varlink_wait(v
, USEC_INFINITY
);
2387 case VARLINK_COLLECTING_REPLY
: {
2390 JsonVariant
*e
= json_variant_by_key(v
->current
, "error"),
2391 *p
= json_variant_by_key(v
->current
, "parameters");
2393 /* Unless there is more to collect we reset state to idle */
2394 if (!FLAGS_SET(v
->current_reply_flags
, VARLINK_REPLY_CONTINUES
)) {
2395 varlink_set_state(v
, VARLINK_IDLE_CLIENT
);
2396 assert(v
->n_pending
== 1);
2402 return varlink_error_to_errno(json_variant_string(e
), p
);
2405 *ret_parameters
= p
;
2407 *ret_error_id
= json_variant_string(e
);
2409 *ret_flags
= v
->current_reply_flags
;
2414 if (json_variant_elements(collected
) >= VARLINK_COLLECT_MAX
)
2415 return varlink_log_errno(v
, SYNTHETIC_ERRNO(E2BIG
), "Number of reply messages grew too large (%zu) while collecting.", json_variant_elements(collected
));
2417 r
= json_variant_append_array(&collected
, p
);
2419 return varlink_log_errno(v
, r
, "Failed to append JSON object to array: %m");
2421 if (FLAGS_SET(v
->current_reply_flags
, VARLINK_REPLY_CONTINUES
)) {
2422 /* There's more to collect, continue */
2423 varlink_clear_current(v
);
2424 varlink_set_state(v
, VARLINK_COLLECTING
);
2429 /* Install the collection array in the connection object, so that we can hand
2430 * out a pointer to it without passing over ownership, to make it work more
2431 * alike regular method call replies */
2432 *ret_parameters
= v
->current_collected
= TAKE_PTR(collected
);
2434 *ret_error_id
= NULL
;
2436 *ret_flags
= v
->current_reply_flags
;
2441 case VARLINK_PENDING_DISCONNECT
:
2442 case VARLINK_DISCONNECTED
:
2443 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ECONNRESET
), "Connection was closed.");
2445 case VARLINK_PENDING_TIMEOUT
:
2446 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ETIME
), "Connection timed out.");
2449 assert_not_reached();
2454 int varlink_collectb(
2457 JsonVariant
**ret_parameters
,
2458 const char **ret_error_id
,
2461 _cleanup_(json_variant_unrefp
) JsonVariant
*parameters
= NULL
;
2465 assert_return(v
, -EINVAL
);
2467 va_start(ap
, ret_error_id
);
2468 r
= json_buildv(¶meters
, ap
);
2472 return varlink_log_errno(v
, r
, "Failed to build json message: %m");
2474 return varlink_collect_full(v
, method
, parameters
, ret_parameters
, ret_error_id
, NULL
);
2477 int varlink_reply(Varlink
*v
, JsonVariant
*parameters
) {
2478 _cleanup_(json_variant_unrefp
) JsonVariant
*m
= NULL
;
2481 assert_return(v
, -EINVAL
);
2483 if (v
->state
== VARLINK_DISCONNECTED
)
2485 if (!IN_SET(v
->state
,
2486 VARLINK_PROCESSING_METHOD
, VARLINK_PROCESSING_METHOD_MORE
,
2487 VARLINK_PENDING_METHOD
, VARLINK_PENDING_METHOD_MORE
))
2490 r
= varlink_sanitize_parameters(¶meters
);
2492 return varlink_log_errno(v
, r
, "Failed to sanitize parameters: %m");
2494 r
= json_build(&m
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters
))));
2496 return varlink_log_errno(v
, r
, "Failed to build json message: %m");
2498 if (v
->current_method
) {
2499 const char *bad_field
= NULL
;
2501 r
= varlink_idl_validate_method_reply(v
->current_method
, parameters
, &bad_field
);
2503 /* Please adjust test/units/end.sh when updating the log message. */
2504 varlink_log_errno(v
, r
, "Return parameters for method reply %s() didn't pass validation on field '%s', ignoring: %m",
2505 v
->current_method
->name
, strna(bad_field
));
2508 r
= varlink_enqueue_json(v
, m
);
2510 return varlink_log_errno(v
, r
, "Failed to enqueue json message: %m");
2512 if (IN_SET(v
->state
, VARLINK_PENDING_METHOD
, VARLINK_PENDING_METHOD_MORE
)) {
2513 /* We just replied to a method call that was let hanging for a while (i.e. we were outside of
2514 * the varlink_dispatch_method() stack frame), which means with this reply we are ready to
2515 * process further messages. */
2516 varlink_clear_current(v
);
2517 varlink_set_state(v
, VARLINK_IDLE_SERVER
);
2519 /* We replied to a method call from within the varlink_dispatch_method() stack frame), which
2520 * means we should it handle the rest of the state engine. */
2521 varlink_set_state(v
, VARLINK_PROCESSED_METHOD
);
2526 int varlink_replyb(Varlink
*v
, ...) {
2527 _cleanup_(json_variant_unrefp
) JsonVariant
*parameters
= NULL
;
2531 assert_return(v
, -EINVAL
);
2534 r
= json_buildv(¶meters
, ap
);
2540 return varlink_reply(v
, parameters
);
2543 int varlink_error(Varlink
*v
, const char *error_id
, JsonVariant
*parameters
) {
2544 _cleanup_(json_variant_unrefp
) JsonVariant
*m
= NULL
;
2547 assert_return(v
, -EINVAL
);
2548 assert_return(error_id
, -EINVAL
);
2550 if (v
->state
== VARLINK_DISCONNECTED
)
2551 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENOTCONN
), "Not connected.");
2552 if (!IN_SET(v
->state
,
2553 VARLINK_PROCESSING_METHOD
, VARLINK_PROCESSING_METHOD_MORE
,
2554 VARLINK_PENDING_METHOD
, VARLINK_PENDING_METHOD_MORE
))
2555 return varlink_log_errno(v
, SYNTHETIC_ERRNO(EBUSY
), "Connection busy.");
2557 /* Reset the list of pushed file descriptors before sending an error reply. We do this here to
2558 * simplify code that puts together a complex reply message with fds, and half-way something
2559 * fails. In that case the pushed fds need to be flushed out again. Under the assumption that it
2560 * never makes sense to send fds along with errors we simply flush them out here beforehand, so that
2561 * the callers don't need to do this explicitly. */
2562 varlink_reset_fds(v
);
2564 r
= varlink_sanitize_parameters(¶meters
);
2566 return varlink_log_errno(v
, r
, "Failed to sanitize parameters: %m");
2568 r
= json_build(&m
, JSON_BUILD_OBJECT(
2569 JSON_BUILD_PAIR("error", JSON_BUILD_STRING(error_id
)),
2570 JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters
))));
2572 return varlink_log_errno(v
, r
, "Failed to build json message: %m");
2574 VarlinkSymbol
*symbol
= hashmap_get(v
->server
->symbols
, error_id
);
2576 varlink_log(v
, "No interface description defined for error '%s', not validating.", error_id
);
2578 const char *bad_field
= NULL
;
2580 r
= varlink_idl_validate_error(symbol
, parameters
, &bad_field
);
2582 /* Please adjust test/units/end.sh when updating the log message. */
2583 varlink_log_errno(v
, r
, "Parameters for error %s didn't pass validation on field '%s', ignoring: %m",
2584 error_id
, strna(bad_field
));
2587 r
= varlink_enqueue_json(v
, m
);
2589 return varlink_log_errno(v
, r
, "Failed to enqueue json message: %m");
2591 if (IN_SET(v
->state
, VARLINK_PENDING_METHOD
, VARLINK_PENDING_METHOD_MORE
)) {
2592 varlink_clear_current(v
);
2593 varlink_set_state(v
, VARLINK_IDLE_SERVER
);
2595 varlink_set_state(v
, VARLINK_PROCESSED_METHOD
);
2600 int varlink_errorb(Varlink
*v
, const char *error_id
, ...) {
2601 _cleanup_(json_variant_unrefp
) JsonVariant
*parameters
= NULL
;
2605 assert_return(v
, -EINVAL
);
2606 assert_return(error_id
, -EINVAL
);
2608 va_start(ap
, error_id
);
2609 r
= json_buildv(¶meters
, ap
);
2613 return varlink_log_errno(v
, r
, "Failed to build json message: %m");
2615 return varlink_error(v
, error_id
, parameters
);
2618 int varlink_error_invalid_parameter(Varlink
*v
, JsonVariant
*parameters
) {
2621 assert_return(v
, -EINVAL
);
2622 assert_return(parameters
, -EINVAL
);
2624 /* We expect to be called in one of two ways: the 'parameters' argument is a string variant in which
2625 * case it is the parameter key name that is invalid. Or the 'parameters' argument is an object
2626 * variant in which case we'll pull out the first key. The latter mode is useful in functions that
2627 * don't expect any arguments. */
2629 /* varlink_error(...) expects a json object as the third parameter. Passing a string variant causes
2630 * parameter sanitization to fail, and it returns -EINVAL. */
2632 if (json_variant_is_string(parameters
)) {
2633 _cleanup_(json_variant_unrefp
) JsonVariant
*parameters_obj
= NULL
;
2635 r
= json_build(¶meters_obj
,
2637 JSON_BUILD_PAIR("parameter", JSON_BUILD_VARIANT(parameters
))));
2641 return varlink_error(v
, VARLINK_ERROR_INVALID_PARAMETER
, parameters_obj
);
2644 if (json_variant_is_object(parameters
) &&
2645 json_variant_elements(parameters
) > 0) {
2646 _cleanup_(json_variant_unrefp
) JsonVariant
*parameters_obj
= NULL
;
2648 r
= json_build(¶meters_obj
,
2650 JSON_BUILD_PAIR("parameter", JSON_BUILD_VARIANT(json_variant_by_index(parameters
, 0)))));
2654 return varlink_error(v
, VARLINK_ERROR_INVALID_PARAMETER
, parameters_obj
);
2660 int varlink_error_invalid_parameter_name(Varlink
*v
, const char *name
) {
2661 return varlink_errorb(
2663 VARLINK_ERROR_INVALID_PARAMETER
,
2664 JSON_BUILD_OBJECT(JSON_BUILD_PAIR("parameter", JSON_BUILD_STRING(name
))));
2667 int varlink_error_errno(Varlink
*v
, int error
) {
2668 return varlink_errorb(
2670 VARLINK_ERROR_SYSTEM
,
2671 JSON_BUILD_OBJECT(JSON_BUILD_PAIR("errno", JSON_BUILD_INTEGER(abs(error
)))));
2674 int varlink_notify(Varlink
*v
, JsonVariant
*parameters
) {
2675 _cleanup_(json_variant_unrefp
) JsonVariant
*m
= NULL
;
2678 assert_return(v
, -EINVAL
);
2680 if (v
->state
== VARLINK_DISCONNECTED
)
2681 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENOTCONN
), "Not connected.");
2683 /* If we want to reply with a notify connection but the caller didn't set "more", then return an
2684 * error indicating that we expected to be called with "more" set */
2685 if (IN_SET(v
->state
, VARLINK_PROCESSING_METHOD
, VARLINK_PENDING_METHOD
))
2686 return varlink_error(v
, VARLINK_ERROR_EXPECTED_MORE
, NULL
);
2688 if (!IN_SET(v
->state
, VARLINK_PROCESSING_METHOD_MORE
, VARLINK_PENDING_METHOD_MORE
))
2689 return varlink_log_errno(v
, SYNTHETIC_ERRNO(EBUSY
), "Connection busy.");
2691 r
= varlink_sanitize_parameters(¶meters
);
2693 return varlink_log_errno(v
, r
, "Failed to sanitize parameters: %m");
2695 r
= json_build(&m
, JSON_BUILD_OBJECT(
2696 JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters
)),
2697 JSON_BUILD_PAIR("continues", JSON_BUILD_BOOLEAN(true))));
2699 return varlink_log_errno(v
, r
, "Failed to build json message: %m");
2701 if (v
->current_method
) {
2702 const char *bad_field
= NULL
;
2704 r
= varlink_idl_validate_method_reply(v
->current_method
, parameters
, &bad_field
);
2706 /* Please adjust test/units/end.sh when updating the log message. */
2707 varlink_log_errno(v
, r
, "Return parameters for method reply %s() didn't pass validation on field '%s', ignoring: %m",
2708 v
->current_method
->name
, strna(bad_field
));
2711 r
= varlink_enqueue_json(v
, m
);
2713 return varlink_log_errno(v
, r
, "Failed to enqueue json message: %m");
2715 /* No state change, as more is coming */
2719 int varlink_notifyb(Varlink
*v
, ...) {
2720 _cleanup_(json_variant_unrefp
) JsonVariant
*parameters
= NULL
;
2724 assert_return(v
, -EINVAL
);
2727 r
= json_buildv(¶meters
, ap
);
2731 return varlink_log_errno(v
, r
, "Failed to build json message: %m");
2733 return varlink_notify(v
, parameters
);
2736 int varlink_dispatch(Varlink
*v
, JsonVariant
*parameters
, const JsonDispatch table
[], void *userdata
) {
2737 const char *bad_field
= NULL
;
2740 assert_return(v
, -EINVAL
);
2741 assert_return(table
, -EINVAL
);
2743 /* A wrapper around json_dispatch_full() that returns a nice InvalidParameter error if we hit a problem with some field. */
2745 r
= json_dispatch_full(parameters
, table
, /* bad= */ NULL
, /* flags= */ 0, userdata
, &bad_field
);
2748 return varlink_error_invalid_parameter_name(v
, bad_field
);
2755 int varlink_bind_reply(Varlink
*v
, VarlinkReply callback
) {
2756 assert_return(v
, -EINVAL
);
2758 if (callback
&& v
->reply_callback
&& callback
!= v
->reply_callback
)
2759 return varlink_log_errno(v
, SYNTHETIC_ERRNO(EBUSY
), "A different callback was already set.");
2761 v
->reply_callback
= callback
;
2766 void* varlink_set_userdata(Varlink
*v
, void *userdata
) {
2769 assert_return(v
, NULL
);
2772 v
->userdata
= userdata
;
2777 void* varlink_get_userdata(Varlink
*v
) {
2778 assert_return(v
, NULL
);
2783 static int varlink_acquire_ucred(Varlink
*v
) {
2788 if (v
->ucred_acquired
)
2791 r
= getpeercred(v
->fd
, &v
->ucred
);
2795 v
->ucred_acquired
= true;
2799 int varlink_get_peer_uid(Varlink
*v
, uid_t
*ret
) {
2802 assert_return(v
, -EINVAL
);
2803 assert_return(ret
, -EINVAL
);
2805 r
= varlink_acquire_ucred(v
);
2807 return varlink_log_errno(v
, r
, "Failed to acquire credentials: %m");
2809 if (!uid_is_valid(v
->ucred
.uid
))
2810 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENODATA
), "Peer UID is invalid.");
2812 *ret
= v
->ucred
.uid
;
2816 int varlink_get_peer_gid(Varlink
*v
, gid_t
*ret
) {
2819 assert_return(v
, -EINVAL
);
2820 assert_return(ret
, -EINVAL
);
2822 r
= varlink_acquire_ucred(v
);
2824 return varlink_log_errno(v
, r
, "Failed to acquire credentials: %m");
2826 if (!gid_is_valid(v
->ucred
.gid
))
2827 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENODATA
), "Peer GID is invalid.");
2829 *ret
= v
->ucred
.gid
;
2833 int varlink_get_peer_pid(Varlink
*v
, pid_t
*ret
) {
2836 assert_return(v
, -EINVAL
);
2837 assert_return(ret
, -EINVAL
);
2839 r
= varlink_acquire_ucred(v
);
2841 return varlink_log_errno(v
, r
, "Failed to acquire credentials: %m");
2843 if (!pid_is_valid(v
->ucred
.pid
))
2844 return varlink_log_errno(v
, SYNTHETIC_ERRNO(ENODATA
), "Peer uid is invalid.");
2846 *ret
= v
->ucred
.pid
;
2850 static int varlink_acquire_pidfd(Varlink
*v
) {
2853 if (v
->peer_pidfd
>= 0)
2856 v
->peer_pidfd
= getpeerpidfd(v
->fd
);
2857 if (v
->peer_pidfd
< 0)
2858 return v
->peer_pidfd
;
2863 int varlink_get_peer_pidref(Varlink
*v
, PidRef
*ret
) {
2866 assert_return(v
, -EINVAL
);
2867 assert_return(ret
, -EINVAL
);
2869 /* Returns r > 0 if we acquired the pidref via SO_PEERPIDFD (i.e. if we can use it for
2870 * authentication). Returns == 0 if we didn't, and the pidref should not be used for
2871 * authentication. */
2873 r
= varlink_acquire_pidfd(v
);
2877 if (v
->peer_pidfd
< 0) {
2880 r
= varlink_get_peer_pid(v
, &pid
);
2884 r
= pidref_set_pid(ret
, pid
);
2888 return 0; /* didn't get pidfd securely */
2891 r
= pidref_set_pidfd(ret
, v
->peer_pidfd
);
2895 return 1; /* got pidfd securely */
2898 int varlink_set_relative_timeout(Varlink
*v
, usec_t timeout
) {
2899 assert_return(v
, -EINVAL
);
2900 assert_return(timeout
> 0, -EINVAL
);
2902 v
->timeout
= timeout
;
2906 VarlinkServer
*varlink_get_server(Varlink
*v
) {
2907 assert_return(v
, NULL
);
2912 int varlink_set_description(Varlink
*v
, const char *description
) {
2913 assert_return(v
, -EINVAL
);
2915 return free_and_strdup(&v
->description
, description
);
2918 static int io_callback(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
2919 Varlink
*v
= ASSERT_PTR(userdata
);
2923 handle_revents(v
, revents
);
2924 (void) varlink_process(v
);
2929 static int time_callback(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
2930 Varlink
*v
= ASSERT_PTR(userdata
);
2934 (void) varlink_process(v
);
2938 static int defer_callback(sd_event_source
*s
, void *userdata
) {
2939 Varlink
*v
= ASSERT_PTR(userdata
);
2943 (void) varlink_process(v
);
2947 static int prepare_callback(sd_event_source
*s
, void *userdata
) {
2948 Varlink
*v
= ASSERT_PTR(userdata
);
2955 e
= varlink_get_events(v
);
2959 r
= sd_event_source_set_io_events(v
->io_event_source
, e
);
2961 return varlink_log_errno(v
, r
, "Failed to set source events: %m");
2963 r
= varlink_get_timeout(v
, &until
);
2966 have_timeout
= r
> 0;
2969 r
= sd_event_source_set_time(v
->time_event_source
, until
);
2971 return varlink_log_errno(v
, r
, "Failed to set source time: %m");
2974 r
= sd_event_source_set_enabled(v
->time_event_source
, have_timeout
? SD_EVENT_ON
: SD_EVENT_OFF
);
2976 return varlink_log_errno(v
, r
, "Failed to enable event source: %m");
2981 static int quit_callback(sd_event_source
*event
, void *userdata
) {
2982 Varlink
*v
= ASSERT_PTR(userdata
);
2992 int varlink_attach_event(Varlink
*v
, sd_event
*e
, int64_t priority
) {
2995 assert_return(v
, -EINVAL
);
2996 assert_return(!v
->event
, -EBUSY
);
2999 v
->event
= sd_event_ref(e
);
3001 r
= sd_event_default(&v
->event
);
3003 return varlink_log_errno(v
, r
, "Failed to create event source: %m");
3006 r
= sd_event_add_time(v
->event
, &v
->time_event_source
, CLOCK_MONOTONIC
, 0, 0, time_callback
, v
);
3010 r
= sd_event_source_set_priority(v
->time_event_source
, priority
);
3014 (void) sd_event_source_set_description(v
->time_event_source
, "varlink-time");
3016 r
= sd_event_add_exit(v
->event
, &v
->quit_event_source
, quit_callback
, v
);
3020 r
= sd_event_source_set_priority(v
->quit_event_source
, priority
);
3024 (void) sd_event_source_set_description(v
->quit_event_source
, "varlink-quit");
3026 r
= sd_event_add_io(v
->event
, &v
->io_event_source
, v
->fd
, 0, io_callback
, v
);
3030 r
= sd_event_source_set_prepare(v
->io_event_source
, prepare_callback
);
3034 r
= sd_event_source_set_priority(v
->io_event_source
, priority
);
3038 (void) sd_event_source_set_description(v
->io_event_source
, "varlink-io");
3040 r
= sd_event_add_defer(v
->event
, &v
->defer_event_source
, defer_callback
, v
);
3044 r
= sd_event_source_set_priority(v
->defer_event_source
, priority
);
3048 (void) sd_event_source_set_description(v
->defer_event_source
, "varlink-defer");
3053 varlink_log_errno(v
, r
, "Failed to setup event source: %m");
3054 varlink_detach_event(v
);
3058 void varlink_detach_event(Varlink
*v
) {
3062 varlink_detach_event_sources(v
);
3064 v
->event
= sd_event_unref(v
->event
);
3067 sd_event
*varlink_get_event(Varlink
*v
) {
3068 assert_return(v
, NULL
);
3073 int varlink_push_fd(Varlink
*v
, int fd
) {
3076 assert_return(v
, -EINVAL
);
3077 assert_return(fd
>= 0, -EBADF
);
3079 /* Takes an fd to send along with the *next* varlink message sent via this varlink connection. This
3080 * takes ownership of the specified fd. Use varlink_dup_fd() below to duplicate the fd first. */
3082 if (!v
->allow_fd_passing_output
)
3085 if (v
->n_pushed_fds
>= INT_MAX
)
3088 if (!GREEDY_REALLOC(v
->pushed_fds
, v
->n_pushed_fds
+ 1))
3091 i
= (int) v
->n_pushed_fds
;
3092 v
->pushed_fds
[v
->n_pushed_fds
++] = fd
;
3096 int varlink_push_dup_fd(Varlink
*v
, int fd
) {
3097 _cleanup_close_
int dp
= -1;
3100 assert_return(v
, -EINVAL
);
3101 assert_return(fd
>= 0, -EBADF
);
3103 /* Like varlink_push_fd() but duplicates the specified fd instead of taking possession of it */
3105 dp
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
3109 r
= varlink_push_fd(v
, dp
);
3117 int varlink_reset_fds(Varlink
*v
) {
3118 assert_return(v
, -EINVAL
);
3120 /* Closes all currently pending fds to send. This may be used whenever the caller is in the process
3121 * of putting together a message with fds, and then eventually something fails and they need to
3122 * rollback the fds. Note that this is implicitly called whenever an error reply is sent, see above. */
3124 close_many(v
->output_fds
, v
->n_output_fds
);
3125 v
->n_output_fds
= 0;
3129 int varlink_peek_fd(Varlink
*v
, size_t i
) {
3130 assert_return(v
, -EINVAL
);
3132 /* Returns one of the file descriptors that were received along with the current message. This does
3133 * not duplicate the fd nor invalidate it, it hence remains in our possession. */
3135 if (!v
->allow_fd_passing_input
)
3138 if (i
>= v
->n_input_fds
)
3141 return v
->input_fds
[i
];
3144 int varlink_peek_dup_fd(Varlink
*v
, size_t i
) {
3147 fd
= varlink_peek_fd(v
, i
);
3151 return RET_NERRNO(fcntl(fd
, F_DUPFD_CLOEXEC
, 3));
3154 int varlink_take_fd(Varlink
*v
, size_t i
) {
3155 assert_return(v
, -EINVAL
);
3157 /* Similar to varlink_peek_fd() but the file descriptor's ownership is passed to the caller, and
3158 * we'll invalidate the reference to it under our possession. If called twice in a row will return
3161 if (!v
->allow_fd_passing_input
)
3164 if (i
>= v
->n_input_fds
)
3167 return TAKE_FD(v
->input_fds
[i
]);
3170 static int verify_unix_socket(Varlink
*v
) {
3176 if (fstat(v
->fd
, &st
) < 0)
3178 if (!S_ISSOCK(st
.st_mode
)) {
3183 v
->af
= socket_get_family(v
->fd
);
3188 return v
->af
== AF_UNIX
? 0 : -ENOMEDIUM
;
3191 int varlink_set_allow_fd_passing_input(Varlink
*v
, bool b
) {
3194 assert_return(v
, -EINVAL
);
3196 if (v
->allow_fd_passing_input
== b
)
3200 v
->allow_fd_passing_input
= false;
3204 r
= verify_unix_socket(v
);
3208 v
->allow_fd_passing_input
= true;
3212 int varlink_set_allow_fd_passing_output(Varlink
*v
, bool b
) {
3215 assert_return(v
, -EINVAL
);
3217 if (v
->allow_fd_passing_output
== b
)
3221 v
->allow_fd_passing_output
= false;
3225 r
= verify_unix_socket(v
);
3229 v
->allow_fd_passing_output
= true;
3233 int varlink_set_input_sensitive(Varlink
*v
) {
3234 assert_return(v
, -EINVAL
);
3236 v
->input_sensitive
= true;
3240 int varlink_server_new(VarlinkServer
**ret
, VarlinkServerFlags flags
) {
3241 _cleanup_(varlink_server_unrefp
) VarlinkServer
*s
= NULL
;
3244 assert_return(ret
, -EINVAL
);
3245 assert_return((flags
& ~_VARLINK_SERVER_FLAGS_ALL
) == 0, -EINVAL
);
3247 s
= new(VarlinkServer
, 1);
3249 return log_oom_debug();
3251 *s
= (VarlinkServer
) {
3254 .connections_max
= varlink_server_connections_max(NULL
),
3255 .connections_per_uid_max
= varlink_server_connections_per_uid_max(NULL
),
3258 r
= varlink_server_add_interface_many(
3260 &vl_interface_io_systemd
,
3261 &vl_interface_org_varlink_service
);
3269 static VarlinkServer
* varlink_server_destroy(VarlinkServer
*s
) {
3275 varlink_server_shutdown(s
);
3277 while ((m
= hashmap_steal_first_key(s
->methods
)))
3280 hashmap_free(s
->methods
);
3281 hashmap_free(s
->interfaces
);
3282 hashmap_free(s
->symbols
);
3283 hashmap_free(s
->by_uid
);
3285 sd_event_unref(s
->event
);
3287 free(s
->description
);
3292 DEFINE_TRIVIAL_REF_UNREF_FUNC(VarlinkServer
, varlink_server
, varlink_server_destroy
);
3294 static int validate_connection(VarlinkServer
*server
, const struct ucred
*ucred
) {
3300 if (FLAGS_SET(server
->flags
, VARLINK_SERVER_ROOT_ONLY
))
3301 allowed
= ucred
->uid
== 0;
3303 if (FLAGS_SET(server
->flags
, VARLINK_SERVER_MYSELF_ONLY
))
3304 allowed
= allowed
> 0 || ucred
->uid
== getuid();
3306 if (allowed
== 0) { /* Allow access when it is explicitly allowed or when neither
3307 * VARLINK_SERVER_ROOT_ONLY nor VARLINK_SERVER_MYSELF_ONLY are specified. */
3308 varlink_server_log(server
, "Unprivileged client attempted connection, refusing.");
3312 if (server
->n_connections
>= server
->connections_max
) {
3313 varlink_server_log(server
, "Connection limit of %u reached, refusing.", server
->connections_max
);
3317 if (FLAGS_SET(server
->flags
, VARLINK_SERVER_ACCOUNT_UID
)) {
3320 if (!uid_is_valid(ucred
->uid
)) {
3321 varlink_server_log(server
, "Client with invalid UID attempted connection, refusing.");
3325 c
= PTR_TO_UINT(hashmap_get(server
->by_uid
, UID_TO_PTR(ucred
->uid
)));
3326 if (c
>= server
->connections_per_uid_max
) {
3327 varlink_server_log(server
, "Per-UID connection limit of %u reached, refusing.",
3328 server
->connections_per_uid_max
);
3336 static int count_connection(VarlinkServer
*server
, const struct ucred
*ucred
) {
3343 server
->n_connections
++;
3345 if (FLAGS_SET(server
->flags
, VARLINK_SERVER_ACCOUNT_UID
)) {
3346 assert(uid_is_valid(ucred
->uid
));
3348 r
= hashmap_ensure_allocated(&server
->by_uid
, NULL
);
3350 return varlink_server_log_errno(server
, r
, "Failed to allocate UID hash table: %m");
3352 c
= PTR_TO_UINT(hashmap_get(server
->by_uid
, UID_TO_PTR(ucred
->uid
)));
3354 varlink_server_log(server
, "Connections of user " UID_FMT
": %u (of %u max)",
3355 ucred
->uid
, c
, server
->connections_per_uid_max
);
3357 r
= hashmap_replace(server
->by_uid
, UID_TO_PTR(ucred
->uid
), UINT_TO_PTR(c
+ 1));
3359 return varlink_server_log_errno(server
, r
, "Failed to increment counter in UID hash table: %m");
3365 int varlink_server_add_connection(VarlinkServer
*server
, int fd
, Varlink
**ret
) {
3366 _cleanup_(varlink_unrefp
) Varlink
*v
= NULL
;
3367 struct ucred ucred
= UCRED_INVALID
;
3368 bool ucred_acquired
;
3371 assert_return(server
, -EINVAL
);
3372 assert_return(fd
>= 0, -EBADF
);
3374 if ((server
->flags
& (VARLINK_SERVER_ROOT_ONLY
|VARLINK_SERVER_ACCOUNT_UID
)) != 0) {
3375 r
= getpeercred(fd
, &ucred
);
3377 return varlink_server_log_errno(server
, r
, "Failed to acquire peer credentials of incoming socket, refusing: %m");
3379 ucred_acquired
= true;
3381 r
= validate_connection(server
, &ucred
);
3387 ucred_acquired
= false;
3389 r
= varlink_new(&v
);
3391 return varlink_server_log_errno(server
, r
, "Failed to allocate connection object: %m");
3393 r
= count_connection(server
, &ucred
);
3398 if (server
->flags
& VARLINK_SERVER_INHERIT_USERDATA
)
3399 v
->userdata
= server
->userdata
;
3401 if (ucred_acquired
) {
3403 v
->ucred_acquired
= true;
3406 _cleanup_free_
char *desc
= NULL
;
3407 if (asprintf(&desc
, "%s-%i", varlink_server_description(server
), v
->fd
) >= 0)
3408 v
->description
= TAKE_PTR(desc
);
3410 /* Link up the server and the connection, and take reference in both directions. Note that the
3411 * reference on the connection is left dangling. It will be dropped when the connection is closed,
3412 * which happens in varlink_close(), including in the event loop quit callback. */
3413 v
->server
= varlink_server_ref(server
);
3416 varlink_set_state(v
, VARLINK_IDLE_SERVER
);
3418 if (server
->event
) {
3419 r
= varlink_attach_event(v
, server
->event
, server
->event_priority
);
3421 varlink_log_errno(v
, r
, "Failed to attach new connection: %m");
3422 v
->fd
= -EBADF
; /* take the fd out of the connection again */
3434 static VarlinkServerSocket
*varlink_server_socket_free(VarlinkServerSocket
*ss
) {
3442 DEFINE_TRIVIAL_CLEANUP_FUNC(VarlinkServerSocket
*, varlink_server_socket_free
);
3444 static int connect_callback(sd_event_source
*source
, int fd
, uint32_t revents
, void *userdata
) {
3445 VarlinkServerSocket
*ss
= ASSERT_PTR(userdata
);
3446 _cleanup_close_
int cfd
= -EBADF
;
3452 varlink_server_log(ss
->server
, "New incoming connection.");
3454 cfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
3456 if (ERRNO_IS_ACCEPT_AGAIN(errno
))
3459 return varlink_server_log_errno(ss
->server
, errno
, "Failed to accept incoming socket: %m");
3462 r
= varlink_server_add_connection(ss
->server
, cfd
, &v
);
3468 if (FLAGS_SET(ss
->server
->flags
, VARLINK_SERVER_INPUT_SENSITIVE
))
3469 varlink_set_input_sensitive(v
);
3471 if (ss
->server
->connect_callback
) {
3472 r
= ss
->server
->connect_callback(ss
->server
, v
, ss
->server
->userdata
);
3474 varlink_log_errno(v
, r
, "Connection callback returned error, disconnecting client: %m");
3483 static int varlink_server_create_listen_fd_socket(VarlinkServer
*s
, int fd
, VarlinkServerSocket
**ret_ss
) {
3484 _cleanup_(varlink_server_socket_freep
) VarlinkServerSocket
*ss
= NULL
;
3491 ss
= new(VarlinkServerSocket
, 1);
3493 return log_oom_debug();
3495 *ss
= (VarlinkServerSocket
) {
3501 r
= sd_event_add_io(s
->event
, &ss
->event_source
, fd
, EPOLLIN
, connect_callback
, ss
);
3505 r
= sd_event_source_set_priority(ss
->event_source
, s
->event_priority
);
3510 *ret_ss
= TAKE_PTR(ss
);
3514 int varlink_server_listen_fd(VarlinkServer
*s
, int fd
) {
3515 _cleanup_(varlink_server_socket_freep
) VarlinkServerSocket
*ss
= NULL
;
3518 assert_return(s
, -EINVAL
);
3519 assert_return(fd
>= 0, -EBADF
);
3521 r
= fd_nonblock(fd
, true);
3525 r
= fd_cloexec(fd
, true);
3529 r
= varlink_server_create_listen_fd_socket(s
, fd
, &ss
);
3533 LIST_PREPEND(sockets
, s
->sockets
, TAKE_PTR(ss
));
3537 int varlink_server_listen_address(VarlinkServer
*s
, const char *address
, mode_t m
) {
3538 _cleanup_(varlink_server_socket_freep
) VarlinkServerSocket
*ss
= NULL
;
3539 union sockaddr_union sockaddr
;
3540 socklen_t sockaddr_len
;
3541 _cleanup_close_
int fd
= -EBADF
;
3544 assert_return(s
, -EINVAL
);
3545 assert_return(address
, -EINVAL
);
3546 assert_return((m
& ~0777) == 0, -EINVAL
);
3548 r
= sockaddr_un_set_path(&sockaddr
.un
, address
);
3553 fd
= socket(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
3557 fd
= fd_move_above_stdio(fd
);
3559 (void) sockaddr_un_unlink(&sockaddr
.un
);
3561 WITH_UMASK(~m
& 0777) {
3562 r
= mac_selinux_bind(fd
, &sockaddr
.sa
, sockaddr_len
);
3567 if (listen(fd
, SOMAXCONN_DELUXE
) < 0)
3570 r
= varlink_server_create_listen_fd_socket(s
, fd
, &ss
);
3574 r
= free_and_strdup(&ss
->address
, address
);
3578 LIST_PREPEND(sockets
, s
->sockets
, TAKE_PTR(ss
));
3583 int varlink_server_listen_auto(VarlinkServer
*s
) {
3584 _cleanup_strv_free_
char **names
= NULL
;
3587 assert_return(s
, -EINVAL
);
3589 /* Adds all passed fds marked as "varlink" to our varlink server. These fds can either refer to a
3590 * listening socket or to a connection socket.
3592 * See https://varlink.org/#activation for the environment variables this is backed by and the
3593 * recommended "varlink" identifier in $LISTEN_FDNAMES. */
3595 r
= sd_listen_fds_with_names(/* unset_environment= */ false, &names
);
3599 for (int i
= 0; i
< r
; i
++) {
3601 socklen_t l
= sizeof(b
);
3603 if (!streq(names
[i
], "varlink"))
3606 fd
= SD_LISTEN_FDS_START
+ i
;
3608 if (getsockopt(fd
, SOL_SOCKET
, SO_ACCEPTCONN
, &b
, &l
) < 0)
3611 assert(l
== sizeof(b
));
3613 if (b
) /* Listening socket? */
3614 r
= varlink_server_listen_fd(s
, fd
);
3615 else /* Otherwise assume connection socket */
3616 r
= varlink_server_add_connection(s
, fd
, NULL
);
3623 /* For debug purposes let's listen on an explicitly specified address */
3624 const char *e
= secure_getenv("SYSTEMD_VARLINK_LISTEN");
3626 r
= varlink_server_listen_address(s
, e
, FLAGS_SET(s
->flags
, VARLINK_SERVER_ROOT_ONLY
) ? 0600 : 0666);
3634 void* varlink_server_set_userdata(VarlinkServer
*s
, void *userdata
) {
3637 assert_return(s
, NULL
);
3640 s
->userdata
= userdata
;
3645 void* varlink_server_get_userdata(VarlinkServer
*s
) {
3646 assert_return(s
, NULL
);
3651 int varlink_server_loop_auto(VarlinkServer
*server
) {
3652 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
3655 assert_return(server
, -EINVAL
);
3656 assert_return(!server
->event
, -EBUSY
);
3658 /* Runs a Varlink service event loop populated with a passed fd. Exits on the last connection. */
3660 r
= sd_event_new(&event
);
3664 r
= varlink_server_set_exit_on_idle(server
, true);
3668 r
= varlink_server_attach_event(server
, event
, 0);
3672 r
= varlink_server_listen_auto(server
);
3676 return sd_event_loop(event
);
3679 static VarlinkServerSocket
* varlink_server_socket_destroy(VarlinkServerSocket
*ss
) {
3684 LIST_REMOVE(sockets
, ss
->server
->sockets
, ss
);
3686 sd_event_source_disable_unref(ss
->event_source
);
3694 int varlink_server_shutdown(VarlinkServer
*s
) {
3695 assert_return(s
, -EINVAL
);
3698 varlink_server_socket_destroy(s
->sockets
);
3703 static void varlink_server_test_exit_on_idle(VarlinkServer
*s
) {
3706 if (s
->exit_on_idle
&& s
->event
&& s
->n_connections
== 0)
3707 (void) sd_event_exit(s
->event
, 0);
3710 int varlink_server_set_exit_on_idle(VarlinkServer
*s
, bool b
) {
3711 assert_return(s
, -EINVAL
);
3713 s
->exit_on_idle
= b
;
3714 varlink_server_test_exit_on_idle(s
);
3718 static int varlink_server_add_socket_event_source(VarlinkServer
*s
, VarlinkServerSocket
*ss
, int64_t priority
) {
3719 _cleanup_(sd_event_source_unrefp
) sd_event_source
*es
= NULL
;
3725 assert(ss
->fd
>= 0);
3726 assert(!ss
->event_source
);
3728 r
= sd_event_add_io(s
->event
, &es
, ss
->fd
, EPOLLIN
, connect_callback
, ss
);
3732 r
= sd_event_source_set_priority(es
, priority
);
3736 ss
->event_source
= TAKE_PTR(es
);
3740 int varlink_server_attach_event(VarlinkServer
*s
, sd_event
*e
, int64_t priority
) {
3743 assert_return(s
, -EINVAL
);
3744 assert_return(!s
->event
, -EBUSY
);
3747 s
->event
= sd_event_ref(e
);
3749 r
= sd_event_default(&s
->event
);
3754 LIST_FOREACH(sockets
, ss
, s
->sockets
) {
3755 r
= varlink_server_add_socket_event_source(s
, ss
, priority
);
3760 s
->event_priority
= priority
;
3764 varlink_server_detach_event(s
);
3768 int varlink_server_detach_event(VarlinkServer
*s
) {
3769 assert_return(s
, -EINVAL
);
3771 LIST_FOREACH(sockets
, ss
, s
->sockets
)
3772 ss
->event_source
= sd_event_source_disable_unref(ss
->event_source
);
3774 s
->event
= sd_event_unref(s
->event
);
3778 sd_event
*varlink_server_get_event(VarlinkServer
*s
) {
3779 assert_return(s
, NULL
);
3784 static bool varlink_symbol_in_interface(const char *method
, const char *interface
) {
3790 p
= startswith(method
, interface
);
3797 return !strchr(p
+1, '.');
3800 int varlink_server_bind_method(VarlinkServer
*s
, const char *method
, VarlinkMethod callback
) {
3801 _cleanup_free_
char *m
= NULL
;
3804 assert_return(s
, -EINVAL
);
3805 assert_return(method
, -EINVAL
);
3806 assert_return(callback
, -EINVAL
);
3808 if (varlink_symbol_in_interface(method
, "org.varlink.service") ||
3809 varlink_symbol_in_interface(method
, "io.systemd"))
3810 return varlink_server_log_errno(s
, SYNTHETIC_ERRNO(EEXIST
), "Cannot bind server to '%s'.", method
);
3814 return log_oom_debug();
3816 r
= hashmap_ensure_put(&s
->methods
, &string_hash_ops
, m
, callback
);
3818 return log_oom_debug();
3820 return varlink_server_log_errno(s
, r
, "Failed to register callback: %m");
3827 int varlink_server_bind_method_many_internal(VarlinkServer
*s
, ...) {
3831 assert_return(s
, -EINVAL
);
3835 VarlinkMethod callback
;
3838 method
= va_arg(ap
, const char *);
3842 callback
= va_arg(ap
, VarlinkMethod
);
3844 r
= varlink_server_bind_method(s
, method
, callback
);
3853 int varlink_server_bind_connect(VarlinkServer
*s
, VarlinkConnect callback
) {
3854 assert_return(s
, -EINVAL
);
3856 if (callback
&& s
->connect_callback
&& callback
!= s
->connect_callback
)
3857 return varlink_server_log_errno(s
, SYNTHETIC_ERRNO(EBUSY
), "A different callback was already set.");
3859 s
->connect_callback
= callback
;
3863 int varlink_server_bind_disconnect(VarlinkServer
*s
, VarlinkDisconnect callback
) {
3864 assert_return(s
, -EINVAL
);
3866 if (callback
&& s
->disconnect_callback
&& callback
!= s
->disconnect_callback
)
3867 return varlink_server_log_errno(s
, SYNTHETIC_ERRNO(EBUSY
), "A different callback was already set.");
3869 s
->disconnect_callback
= callback
;
3873 int varlink_server_add_interface(VarlinkServer
*s
, const VarlinkInterface
*interface
) {
3876 assert_return(s
, -EINVAL
);
3877 assert_return(interface
, -EINVAL
);
3878 assert_return(interface
->name
, -EINVAL
);
3880 if (hashmap_contains(s
->interfaces
, interface
->name
))
3881 return varlink_server_log_errno(s
, SYNTHETIC_ERRNO(EEXIST
), "Duplicate registration of interface '%s'.", interface
->name
);
3883 r
= hashmap_ensure_put(&s
->interfaces
, &string_hash_ops
, interface
->name
, (void*) interface
);
3887 for (const VarlinkSymbol
*const*symbol
= interface
->symbols
; *symbol
; symbol
++) {
3888 _cleanup_free_
char *j
= NULL
;
3890 /* We only ever want to validate method calls/replies and errors against the interface
3891 * definitions, hence don't bother with the type symbols */
3892 if (!IN_SET((*symbol
)->symbol_type
, VARLINK_METHOD
, VARLINK_ERROR
))
3895 j
= strjoin(interface
->name
, ".", (*symbol
)->name
);
3899 r
= hashmap_ensure_put(&s
->symbols
, &string_hash_ops_free
, j
, (void*) *symbol
);
3909 int varlink_server_add_interface_many_internal(VarlinkServer
*s
, ...) {
3913 assert_return(s
, -EINVAL
);
3917 const VarlinkInterface
*interface
= va_arg(ap
, const VarlinkInterface
*);
3921 r
= varlink_server_add_interface(s
, interface
);
3930 unsigned varlink_server_connections_max(VarlinkServer
*s
) {
3933 /* If a server is specified, return the setting for that server, otherwise the default value */
3935 return s
->connections_max
;
3937 dts
= getdtablesize();
3940 /* Make sure we never use up more than ¾th of RLIMIT_NOFILE for IPC */
3941 if (VARLINK_DEFAULT_CONNECTIONS_MAX
> (unsigned) dts
/ 4 * 3)
3944 return VARLINK_DEFAULT_CONNECTIONS_MAX
;
3947 unsigned varlink_server_connections_per_uid_max(VarlinkServer
*s
) {
3951 return s
->connections_per_uid_max
;
3953 /* Make sure to never use up more than ¾th of available connections for a single user */
3954 m
= varlink_server_connections_max(NULL
);
3955 if (VARLINK_DEFAULT_CONNECTIONS_PER_UID_MAX
> m
)
3958 return VARLINK_DEFAULT_CONNECTIONS_PER_UID_MAX
;
3961 int varlink_server_set_connections_per_uid_max(VarlinkServer
*s
, unsigned m
) {
3962 assert_return(s
, -EINVAL
);
3963 assert_return(m
> 0, -EINVAL
);
3965 s
->connections_per_uid_max
= m
;
3969 int varlink_server_set_connections_max(VarlinkServer
*s
, unsigned m
) {
3970 assert_return(s
, -EINVAL
);
3971 assert_return(m
> 0, -EINVAL
);
3973 s
->connections_max
= m
;
3977 unsigned varlink_server_current_connections(VarlinkServer
*s
) {
3978 assert_return(s
, UINT_MAX
);
3980 return s
->n_connections
;
3983 int varlink_server_set_description(VarlinkServer
*s
, const char *description
) {
3984 assert_return(s
, -EINVAL
);
3986 return free_and_strdup(&s
->description
, description
);
3989 int varlink_server_serialize(VarlinkServer
*s
, FILE *f
, FDSet
*fds
) {
3996 LIST_FOREACH(sockets
, ss
, s
->sockets
) {
3999 assert(ss
->address
);
4000 assert(ss
->fd
>= 0);
4002 fprintf(f
, "varlink-server-socket-address=%s", ss
->address
);
4004 /* If we fail to serialize the fd, it will be considered an error during deserialization */
4005 copy
= fdset_put_dup(fds
, ss
->fd
);
4009 fprintf(f
, " varlink-server-socket-fd=%i", copy
);
4017 int varlink_server_deserialize_one(VarlinkServer
*s
, const char *value
, FDSet
*fds
) {
4018 _cleanup_(varlink_server_socket_freep
) VarlinkServerSocket
*ss
= NULL
;
4019 _cleanup_free_
char *address
= NULL
;
4020 const char *v
= ASSERT_PTR(value
);
4028 n
= strcspn(v
, " ");
4029 address
= strndup(v
, n
);
4031 return log_oom_debug();
4034 return varlink_server_log_errno(s
, SYNTHETIC_ERRNO(EINVAL
),
4035 "Failed to deserialize VarlinkServerSocket: %s: %m", value
);
4036 v
= startswith(v
+ n
+ 1, "varlink-server-socket-fd=");
4038 return varlink_server_log_errno(s
, SYNTHETIC_ERRNO(EINVAL
),
4039 "Failed to deserialize VarlinkServerSocket fd %s: %m", value
);
4041 n
= strcspn(v
, " ");
4042 buf
= strndupa_safe(v
, n
);
4046 return varlink_server_log_errno(s
, fd
, "Unable to parse VarlinkServerSocket varlink-server-socket-fd=%s: %m", buf
);
4047 if (!fdset_contains(fds
, fd
))
4048 return varlink_server_log_errno(s
, SYNTHETIC_ERRNO(EBADF
),
4049 "VarlinkServerSocket varlink-server-socket-fd= has unknown fd %d: %m", fd
);
4051 ss
= new(VarlinkServerSocket
, 1);
4053 return log_oom_debug();
4055 *ss
= (VarlinkServerSocket
) {
4057 .address
= TAKE_PTR(address
),
4058 .fd
= fdset_remove(fds
, fd
),
4061 r
= varlink_server_add_socket_event_source(s
, ss
, SD_EVENT_PRIORITY_NORMAL
);
4063 return varlink_server_log_errno(s
, r
, "Failed to add VarlinkServerSocket event source to the event loop: %m");
4065 LIST_PREPEND(sockets
, s
->sockets
, TAKE_PTR(ss
));
4069 int varlink_invocation(VarlinkInvocationFlags flags
) {
4070 _cleanup_strv_free_
char **names
= NULL
;
4072 socklen_t l
= sizeof(b
);
4074 /* Returns true if this is a "pure" varlink server invocation, i.e. with one fd passed. */
4076 const char *e
= secure_getenv("SYSTEMD_VARLINK_LISTEN"); /* Permit a manual override for testing purposes */
4080 r
= sd_listen_fds_with_names(/* unset_environment= */ false, &names
);
4086 return -ETOOMANYREFS
;
4088 if (!strv_equal(names
, STRV_MAKE("varlink")))
4091 if (FLAGS_SET(flags
, VARLINK_ALLOW_LISTEN
|VARLINK_ALLOW_ACCEPT
)) /* Both flags set? Then allow everything */
4094 if ((flags
& (VARLINK_ALLOW_LISTEN
|VARLINK_ALLOW_ACCEPT
)) == 0) /* Neither is set, then fail */
4097 if (getsockopt(SD_LISTEN_FDS_START
, SOL_SOCKET
, SO_ACCEPTCONN
, &b
, &l
) < 0)
4100 assert(l
== sizeof(b
));
4102 if (!FLAGS_SET(flags
, b
? VARLINK_ALLOW_LISTEN
: VARLINK_ALLOW_ACCEPT
))
4108 int varlink_error_to_errno(const char *error
, JsonVariant
*parameters
) {
4109 static const struct {
4113 { VARLINK_ERROR_DISCONNECTED
, -ECONNRESET
},
4114 { VARLINK_ERROR_TIMEOUT
, -ETIMEDOUT
},
4115 { VARLINK_ERROR_PROTOCOL
, -EPROTO
},
4116 { VARLINK_ERROR_INTERFACE_NOT_FOUND
, -EADDRNOTAVAIL
},
4117 { VARLINK_ERROR_METHOD_NOT_FOUND
, -ENXIO
},
4118 { VARLINK_ERROR_METHOD_NOT_IMPLEMENTED
, -ENOTTY
},
4119 { VARLINK_ERROR_INVALID_PARAMETER
, -EINVAL
},
4120 { VARLINK_ERROR_PERMISSION_DENIED
, -EACCES
},
4121 { VARLINK_ERROR_EXPECTED_MORE
, -EBADE
},
4127 FOREACH_ARRAY(t
, table
, ELEMENTSOF(table
))
4128 if (streq(error
, t
->error
))
4131 if (streq(error
, VARLINK_ERROR_SYSTEM
) && parameters
) {
4134 e
= json_variant_by_key(parameters
, "errno");
4135 if (json_variant_is_integer(e
)) {
4138 i
= json_variant_integer(e
);
4139 if (i
> 0 && i
< ERRNO_MAX
)
4144 return -EBADR
; /* Catch-all */