1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
9 #include "varlink-idl.h"
11 /* A minimal Varlink implementation. We only implement the minimal, obvious bits here though. No validation,
12 * no introspection, no name service, just the stuff actually needed.
14 * You might wonder why we aren't using libvarlink here? Varlink is a very simple protocol, which allows us
15 * to write our own implementation relatively easily. However, the main reasons are these:
17 * • We want to use our own JSON subsystem, with all the benefits that brings (i.e. accurate unsigned+signed
18 * 64-bit integers, full fuzzing, logging during parsing and so on). If we'd want to use that with
19 * libvarlink we'd have to serialize and deserialize all the time from its own representation which is
20 * inefficient and nasty.
22 * • We want integration into sd-event, but also synchronous event-loop-less operation
24 * • We need proper per-UID accounting and access control, since we want to allow communication between
25 * unprivileged clients and privileged servers.
27 * • And of course, we don't want the name service and introspection stuff for now (though that might
31 typedef struct Varlink Varlink
;
32 typedef struct VarlinkServer VarlinkServer
;
34 typedef enum VarlinkReplyFlags
{
35 VARLINK_REPLY_ERROR
= 1 << 0,
36 VARLINK_REPLY_CONTINUES
= 1 << 1,
37 VARLINK_REPLY_LOCAL
= 1 << 2,
40 typedef enum VarlinkMethodFlags
{
41 VARLINK_METHOD_ONEWAY
= 1 << 0,
42 VARLINK_METHOD_MORE
= 2 << 1,
45 typedef enum VarlinkServerFlags
{
46 VARLINK_SERVER_ROOT_ONLY
= 1 << 0, /* Only accessible by root */
47 VARLINK_SERVER_MYSELF_ONLY
= 1 << 1, /* Only accessible by our own UID */
48 VARLINK_SERVER_ACCOUNT_UID
= 1 << 2, /* Do per user accounting */
49 VARLINK_SERVER_INHERIT_USERDATA
= 1 << 3, /* Initialize Varlink connection userdata from VarlinkServer userdata */
50 VARLINK_SERVER_INPUT_SENSITIVE
= 1 << 4, /* Automatically mark al connection input as sensitive */
51 _VARLINK_SERVER_FLAGS_ALL
= (1 << 5) - 1,
54 typedef int (*VarlinkMethod
)(Varlink
*link
, JsonVariant
*parameters
, VarlinkMethodFlags flags
, void *userdata
);
55 typedef int (*VarlinkReply
)(Varlink
*link
, JsonVariant
*parameters
, const char *error_id
, VarlinkReplyFlags flags
, void *userdata
);
56 typedef int (*VarlinkConnect
)(VarlinkServer
*server
, Varlink
*link
, void *userdata
);
57 typedef void (*VarlinkDisconnect
)(VarlinkServer
*server
, Varlink
*link
, void *userdata
);
59 int varlink_connect_address(Varlink
**ret
, const char *address
);
60 int varlink_connect_exec(Varlink
**ret
, const char *command
, char **argv
);
61 int varlink_connect_url(Varlink
**ret
, const char *url
);
62 int varlink_connect_fd(Varlink
**ret
, int fd
);
64 Varlink
* varlink_ref(Varlink
*link
);
65 Varlink
* varlink_unref(Varlink
*v
);
67 int varlink_get_fd(Varlink
*v
);
68 int varlink_get_events(Varlink
*v
);
69 int varlink_get_timeout(Varlink
*v
, usec_t
*ret
);
71 int varlink_attach_event(Varlink
*v
, sd_event
*e
, int64_t priority
);
72 void varlink_detach_event(Varlink
*v
);
73 sd_event
*varlink_get_event(Varlink
*v
);
75 int varlink_process(Varlink
*v
);
76 int varlink_wait(Varlink
*v
, usec_t timeout
);
78 int varlink_is_idle(Varlink
*v
);
80 int varlink_flush(Varlink
*v
);
81 int varlink_close(Varlink
*v
);
83 Varlink
* varlink_flush_close_unref(Varlink
*v
);
84 Varlink
* varlink_close_unref(Varlink
*v
);
86 /* Enqueue method call, not expecting a reply */
87 int varlink_send(Varlink
*v
, const char *method
, JsonVariant
*parameters
);
88 int varlink_sendb(Varlink
*v
, const char *method
, ...);
90 /* Send method call and wait for reply */
91 int varlink_call_full(Varlink
*v
, const char *method
, JsonVariant
*parameters
, JsonVariant
**ret_parameters
, const char **ret_error_id
, VarlinkReplyFlags
*ret_flags
);
92 static inline int varlink_call(Varlink
*v
, const char *method
, JsonVariant
*parameters
, JsonVariant
**ret_parameters
, const char **ret_error_id
) {
93 return varlink_call_full(v
, method
, parameters
, ret_parameters
, ret_error_id
, NULL
);
95 int varlink_call_and_log(Varlink
*v
, const char *method
, JsonVariant
*parameters
, JsonVariant
**ret_parameters
);
97 int varlink_callb_ap(Varlink
*v
, const char *method
, JsonVariant
**ret_parameters
, const char **ret_error_id
, VarlinkReplyFlags
*ret_flags
, va_list ap
);
98 static inline int varlink_callb_full(Varlink
*v
, const char *method
, JsonVariant
**ret_parameters
, const char **ret_error_id
, VarlinkReplyFlags
*ret_flags
, ...) {
102 va_start(ap
, ret_flags
);
103 r
= varlink_callb_ap(v
, method
, ret_parameters
, ret_error_id
, ret_flags
, ap
);
107 static inline int varlink_callb(Varlink
*v
, const char *method
, JsonVariant
**ret_parameters
, const char **ret_error_id
, ...) {
111 va_start(ap
, ret_error_id
);
112 r
= varlink_callb_ap(v
, method
, ret_parameters
, ret_error_id
, NULL
, ap
);
116 int varlink_callb_and_log(Varlink
*v
, const char *method
, JsonVariant
**ret_parameters
, ...);
118 /* Send method call and begin collecting all 'more' replies into an array, finishing when a final reply is sent */
119 int varlink_collect(Varlink
*v
, const char *method
, JsonVariant
*parameters
, JsonVariant
**ret_parameters
, const char **ret_error_id
, VarlinkReplyFlags
*ret_flags
);
120 int varlink_collectb(Varlink
*v
, const char *method
, JsonVariant
**ret_parameters
, const char **ret_error_id
, VarlinkReplyFlags
*ret_flags
, ...);
122 /* Enqueue method call, expect a reply, which is eventually delivered to the reply callback */
123 int varlink_invoke(Varlink
*v
, const char *method
, JsonVariant
*parameters
);
124 int varlink_invokeb(Varlink
*v
, const char *method
, ...);
126 /* Enqueue method call, expect a reply now, and possibly more later, which are all delivered to the reply callback */
127 int varlink_observe(Varlink
*v
, const char *method
, JsonVariant
*parameters
);
128 int varlink_observeb(Varlink
*v
, const char *method
, ...);
130 /* Enqueue a final reply */
131 int varlink_reply(Varlink
*v
, JsonVariant
*parameters
);
132 int varlink_replyb(Varlink
*v
, ...);
134 /* Enqueue a (final) error */
135 int varlink_error(Varlink
*v
, const char *error_id
, JsonVariant
*parameters
);
136 int varlink_errorb(Varlink
*v
, const char *error_id
, ...);
137 int varlink_error_invalid_parameter(Varlink
*v
, JsonVariant
*parameters
);
138 int varlink_error_invalid_parameter_name(Varlink
*v
, const char *name
);
139 int varlink_error_errno(Varlink
*v
, int error
);
141 /* Enqueue a "more" reply */
142 int varlink_notify(Varlink
*v
, JsonVariant
*parameters
);
143 int varlink_notifyb(Varlink
*v
, ...);
145 /* Ask for the current message to be dispatched again */
146 int varlink_dispatch_again(Varlink
*v
);
148 /* Get the currently processed incoming message */
149 int varlink_get_current_parameters(Varlink
*v
, JsonVariant
**ret
);
151 /* Parsing incoming data via json_dispatch() and generate a nice error on parse errors */
152 int varlink_dispatch(Varlink
*v
, JsonVariant
*parameters
, const JsonDispatch table
[], void *userdata
);
154 /* Write outgoing fds into the socket (to be associated with the next enqueued message) */
155 int varlink_push_fd(Varlink
*v
, int fd
);
156 int varlink_dup_fd(Varlink
*v
, int fd
);
157 int varlink_reset_fds(Varlink
*v
);
159 /* Read incoming fds from the socket (associated with the currently handled message) */
160 int varlink_peek_fd(Varlink
*v
, size_t i
);
161 int varlink_take_fd(Varlink
*v
, size_t i
);
163 int varlink_set_allow_fd_passing_input(Varlink
*v
, bool b
);
164 int varlink_set_allow_fd_passing_output(Varlink
*v
, bool b
);
166 /* Bind a disconnect, reply or timeout callback */
167 int varlink_bind_reply(Varlink
*v
, VarlinkReply reply
);
169 void* varlink_set_userdata(Varlink
*v
, void *userdata
);
170 void* varlink_get_userdata(Varlink
*v
);
172 int varlink_get_peer_uid(Varlink
*v
, uid_t
*ret
);
173 int varlink_get_peer_pid(Varlink
*v
, pid_t
*ret
);
174 int varlink_get_peer_pidref(Varlink
*v
, PidRef
*ret
);
176 int varlink_set_relative_timeout(Varlink
*v
, usec_t usec
);
178 VarlinkServer
* varlink_get_server(Varlink
*v
);
180 int varlink_set_description(Varlink
*v
, const char *d
);
182 /* Automatically mark the parameters part of incoming messages as security sensitive */
183 int varlink_set_input_sensitive(Varlink
*v
);
185 /* Create a varlink server */
186 int varlink_server_new(VarlinkServer
**ret
, VarlinkServerFlags flags
);
187 VarlinkServer
*varlink_server_ref(VarlinkServer
*s
);
188 VarlinkServer
*varlink_server_unref(VarlinkServer
*s
);
190 /* Add addresses or fds to listen on */
191 int varlink_server_listen_address(VarlinkServer
*s
, const char *address
, mode_t mode
);
192 int varlink_server_listen_fd(VarlinkServer
*s
, int fd
);
193 int varlink_server_listen_auto(VarlinkServer
*s
);
194 int varlink_server_add_connection(VarlinkServer
*s
, int fd
, Varlink
**ret
);
197 int varlink_server_bind_method(VarlinkServer
*s
, const char *method
, VarlinkMethod callback
);
198 int varlink_server_bind_method_many_internal(VarlinkServer
*s
, ...);
199 #define varlink_server_bind_method_many(s, ...) varlink_server_bind_method_many_internal(s, __VA_ARGS__, NULL)
200 int varlink_server_bind_connect(VarlinkServer
*s
, VarlinkConnect connect
);
201 int varlink_server_bind_disconnect(VarlinkServer
*s
, VarlinkDisconnect disconnect
);
203 /* Add interface definition */
204 int varlink_server_add_interface(VarlinkServer
*s
, const VarlinkInterface
*interface
);
205 int varlink_server_add_interface_many_internal(VarlinkServer
*s
, ...);
206 #define varlink_server_add_interface_many(s, ...) varlink_server_add_interface_many_internal(s, __VA_ARGS__, NULL)
208 void* varlink_server_set_userdata(VarlinkServer
*s
, void *userdata
);
209 void* varlink_server_get_userdata(VarlinkServer
*s
);
211 int varlink_server_attach_event(VarlinkServer
*v
, sd_event
*e
, int64_t priority
);
212 int varlink_server_detach_event(VarlinkServer
*v
);
213 sd_event
*varlink_server_get_event(VarlinkServer
*v
);
215 int varlink_server_loop_auto(VarlinkServer
*server
);
217 int varlink_server_shutdown(VarlinkServer
*server
);
219 int varlink_server_set_exit_on_idle(VarlinkServer
*s
, bool b
);
221 unsigned varlink_server_connections_max(VarlinkServer
*s
);
222 unsigned varlink_server_connections_per_uid_max(VarlinkServer
*s
);
224 int varlink_server_set_connections_per_uid_max(VarlinkServer
*s
, unsigned m
);
225 int varlink_server_set_connections_max(VarlinkServer
*s
, unsigned m
);
227 unsigned varlink_server_current_connections(VarlinkServer
*s
);
229 int varlink_server_set_description(VarlinkServer
*s
, const char *description
);
231 typedef enum VarlinkInvocationFlags
{
232 VARLINK_ALLOW_LISTEN
= 1 << 0,
233 VARLINK_ALLOW_ACCEPT
= 1 << 1,
234 _VARLINK_SERVER_INVOCATION_FLAGS_MAX
= (1 << 2) - 1,
235 _VARLINK_SERVER_INVOCATION_FLAGS_INVALID
= -EINVAL
,
236 } VarlinkInvocationFlags
;
238 int varlink_invocation(VarlinkInvocationFlags flags
);
240 int varlink_error_to_errno(const char *error
, JsonVariant
*parameters
);
242 DEFINE_TRIVIAL_CLEANUP_FUNC(Varlink
*, varlink_unref
);
243 DEFINE_TRIVIAL_CLEANUP_FUNC(Varlink
*, varlink_close_unref
);
244 DEFINE_TRIVIAL_CLEANUP_FUNC(Varlink
*, varlink_flush_close_unref
);
245 DEFINE_TRIVIAL_CLEANUP_FUNC(VarlinkServer
*, varlink_server_unref
);
247 /* These are local errors that never cross the wire, and are our own invention */
248 #define VARLINK_ERROR_DISCONNECTED "io.systemd.Disconnected"
249 #define VARLINK_ERROR_TIMEOUT "io.systemd.TimedOut"
250 #define VARLINK_ERROR_PROTOCOL "io.systemd.Protocol"
252 /* This one we invented, and use for generically propagating system errors (errno) to clients */
253 #define VARLINK_ERROR_SYSTEM "io.systemd.System"
255 /* This one we invented and is a weaker version of "org.varlink.service.PermissionDenied", and indicates that if user would allow interactive auth, we might allow access */
256 #define VARLINK_ERROR_INTERACTIVE_AUTHENTICATION_REQUIRED "io.systemd.InteractiveAuthenticationRequired"
258 /* These are errors defined in the Varlink spec */
259 #define VARLINK_ERROR_INTERFACE_NOT_FOUND "org.varlink.service.InterfaceNotFound"
260 #define VARLINK_ERROR_METHOD_NOT_FOUND "org.varlink.service.MethodNotFound"
261 #define VARLINK_ERROR_METHOD_NOT_IMPLEMENTED "org.varlink.service.MethodNotImplemented"
262 #define VARLINK_ERROR_INVALID_PARAMETER "org.varlink.service.InvalidParameter"
263 #define VARLINK_ERROR_PERMISSION_DENIED "org.varlink.service.PermissionDenied"
264 #define VARLINK_ERROR_EXPECTED_MORE "org.varlink.service.ExpectedMore"