/src/systemd/src/journal/journald-varlink.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
2 | | |
3 | | #include "sd-event.h" |
4 | | |
5 | | #include "journald-manager.h" |
6 | | #include "journald-sync.h" |
7 | | #include "journald-varlink.h" |
8 | | #include "log.h" |
9 | | #include "varlink-io.systemd.Journal.h" |
10 | | #include "varlink-io.systemd.service.h" |
11 | | #include "varlink-util.h" |
12 | | |
13 | 0 | void sync_req_varlink_reply(SyncReq *req) { |
14 | 0 | int r; |
15 | |
|
16 | 0 | assert(req); |
17 | | |
18 | | /* This is the "second half" of the Synchronize() varlink method. This function is called when we |
19 | | * determine that no messages that were enqueued to us when the request was initiated is pending |
20 | | * anymore. */ |
21 | |
|
22 | 0 | if (req->offline) |
23 | 0 | manager_full_sync(req->manager, /* wait = */ true); |
24 | | |
25 | | /* Disconnect the SyncReq from the Varlink connection object, and free it */ |
26 | 0 | _cleanup_(sd_varlink_unrefp) sd_varlink *vl = TAKE_PTR(req->link); |
27 | 0 | sd_varlink_set_userdata(vl, req->manager); /* reinstall manager object */ |
28 | 0 | req = sync_req_free(req); |
29 | |
|
30 | 0 | r = sd_varlink_reply(vl, NULL); |
31 | 0 | if (r < 0) |
32 | 0 | log_debug_errno(r, "Failed to reply to Synchronize() client, ignoring: %m"); |
33 | 0 | } |
34 | | |
35 | 0 | static int vl_method_synchronize(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { |
36 | 0 | int offline = -1; |
37 | |
|
38 | 0 | static const sd_json_dispatch_field dispatch_table[] = { |
39 | 0 | { "offline", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, 0, 0}, |
40 | 0 | {} |
41 | 0 | }; |
42 | |
|
43 | 0 | Manager *m = ASSERT_PTR(userdata); |
44 | 0 | int r; |
45 | |
|
46 | 0 | assert(link); |
47 | |
|
48 | 0 | r = sd_varlink_dispatch(link, parameters, dispatch_table, &offline); |
49 | 0 | if (r != 0) |
50 | 0 | return r; |
51 | | |
52 | 0 | if (offline > 0) { |
53 | | /* Do not allow unprivileged clients to offline the journal files, since that's potentially slow */ |
54 | 0 | r = varlink_check_privileged_peer(link); |
55 | 0 | if (r < 0) |
56 | 0 | return r; |
57 | 0 | } else if (offline < 0) { |
58 | 0 | uid_t uid = 0; |
59 | |
|
60 | 0 | r = sd_varlink_get_peer_uid(link, &uid); |
61 | 0 | if (r < 0) |
62 | 0 | return r; |
63 | | |
64 | 0 | offline = uid == 0; /* for compat, if not specified default to offlining, except for non-root */ |
65 | 0 | } |
66 | | |
67 | 0 | log_full(offline ? LOG_INFO : LOG_DEBUG, |
68 | 0 | "Received client request to sync journal (%s offlining).", offline ? "with" : "without"); |
69 | |
|
70 | 0 | _cleanup_(sync_req_freep) SyncReq *sr = NULL; |
71 | |
|
72 | 0 | r = sync_req_new(m, link, &sr); |
73 | 0 | if (r < 0) |
74 | 0 | return r; |
75 | | |
76 | 0 | sr->offline = offline; |
77 | 0 | sd_varlink_set_userdata(link, sr); |
78 | |
|
79 | 0 | sync_req_revalidate(TAKE_PTR(sr)); |
80 | 0 | return 0; |
81 | 0 | } |
82 | | |
83 | 0 | static int vl_method_rotate(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { |
84 | 0 | Manager *m = ASSERT_PTR(userdata); |
85 | 0 | int r; |
86 | |
|
87 | 0 | assert(link); |
88 | |
|
89 | 0 | r = sd_varlink_dispatch(link, parameters, /* dispatch_table = */ NULL, /* userdata = */ NULL); |
90 | 0 | if (r != 0) |
91 | 0 | return r; |
92 | | |
93 | 0 | r = varlink_check_privileged_peer(link); |
94 | 0 | if (r < 0) |
95 | 0 | return r; |
96 | | |
97 | 0 | log_info("Received client request to rotate journal, rotating."); |
98 | 0 | manager_full_rotate(m); |
99 | |
|
100 | 0 | return sd_varlink_reply(link, NULL); |
101 | 0 | } |
102 | | |
103 | 0 | static int vl_method_flush_to_var(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { |
104 | 0 | Manager *m = ASSERT_PTR(userdata); |
105 | 0 | int r; |
106 | |
|
107 | 0 | assert(link); |
108 | |
|
109 | 0 | r = sd_varlink_dispatch(link, parameters, /* dispatch_table = */ NULL, /* userdata = */ NULL); |
110 | 0 | if (r != 0) |
111 | 0 | return r; |
112 | | |
113 | 0 | r = varlink_check_privileged_peer(link); |
114 | 0 | if (r < 0) |
115 | 0 | return r; |
116 | | |
117 | 0 | if (m->namespace) |
118 | 0 | return sd_varlink_error(link, "io.systemd.Journal.NotSupportedByNamespaces", NULL); |
119 | | |
120 | 0 | log_info("Received client request to flush runtime journal."); |
121 | 0 | manager_full_flush(m); |
122 | |
|
123 | 0 | return sd_varlink_reply(link, NULL); |
124 | 0 | } |
125 | | |
126 | 0 | static int vl_method_relinquish_var(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { |
127 | 0 | Manager *m = ASSERT_PTR(userdata); |
128 | 0 | int r; |
129 | |
|
130 | 0 | assert(link); |
131 | |
|
132 | 0 | r = sd_varlink_dispatch(link, parameters, /* dispatch_table = */ NULL, /* userdata = */ NULL); |
133 | 0 | if (r != 0) |
134 | 0 | return r; |
135 | | |
136 | 0 | r = varlink_check_privileged_peer(link); |
137 | 0 | if (r < 0) |
138 | 0 | return r; |
139 | | |
140 | 0 | if (m->namespace) |
141 | 0 | return sd_varlink_error(link, "io.systemd.Journal.NotSupportedByNamespaces", NULL); |
142 | | |
143 | 0 | log_info("Received client request to relinquish %s access.", m->system_storage.path); |
144 | 0 | manager_relinquish_var(m); |
145 | |
|
146 | 0 | return sd_varlink_reply(link, NULL); |
147 | 0 | } |
148 | | |
149 | 0 | static int vl_connect(sd_varlink_server *server, sd_varlink *link, void *userdata) { |
150 | 0 | Manager *m = ASSERT_PTR(userdata); |
151 | |
|
152 | 0 | assert(server); |
153 | 0 | assert(link); |
154 | |
|
155 | 0 | (void) manager_start_or_stop_idle_timer(m); /* maybe we are no longer idle */ |
156 | |
|
157 | 0 | return 0; |
158 | 0 | } |
159 | | |
160 | 0 | static void vl_disconnect(sd_varlink_server *server, sd_varlink *link, void *userdata) { |
161 | 0 | Manager *m = ASSERT_PTR(userdata); |
162 | |
|
163 | 0 | assert(server); |
164 | 0 | assert(link); |
165 | |
|
166 | 0 | void *u = sd_varlink_get_userdata(link); |
167 | 0 | if (u != m) { |
168 | | /* If this is a Varlink connection that does not have the Server object as userdata, then it has a SyncReq object instead. Let's finish it. */ |
169 | |
|
170 | 0 | SyncReq *req = u; |
171 | 0 | sd_varlink_set_userdata(link, m); /* reinstall server object */ |
172 | 0 | sync_req_free(req); |
173 | 0 | } |
174 | |
|
175 | 0 | (void) manager_start_or_stop_idle_timer(m); /* maybe we are idle now */ |
176 | 0 | } |
177 | | |
178 | 0 | int manager_open_varlink(Manager *m, const char *socket, int fd) { |
179 | 0 | int r; |
180 | |
|
181 | 0 | assert(m); |
182 | |
|
183 | 0 | r = varlink_server_new( |
184 | 0 | &m->varlink_server, |
185 | 0 | SD_VARLINK_SERVER_ACCOUNT_UID|SD_VARLINK_SERVER_INHERIT_USERDATA, |
186 | 0 | m); |
187 | 0 | if (r < 0) |
188 | 0 | return log_error_errno(r, "Failed to allocate varlink server object: %m"); |
189 | | |
190 | 0 | r = sd_varlink_server_add_interface_many( |
191 | 0 | m->varlink_server, |
192 | 0 | &vl_interface_io_systemd_Journal, |
193 | 0 | &vl_interface_io_systemd_service); |
194 | 0 | if (r < 0) |
195 | 0 | return log_error_errno(r, "Failed to add Journal interface to varlink server: %m"); |
196 | | |
197 | 0 | r = sd_varlink_server_bind_method_many( |
198 | 0 | m->varlink_server, |
199 | 0 | "io.systemd.Journal.Synchronize", vl_method_synchronize, |
200 | 0 | "io.systemd.Journal.Rotate", vl_method_rotate, |
201 | 0 | "io.systemd.Journal.FlushToVar", vl_method_flush_to_var, |
202 | 0 | "io.systemd.Journal.RelinquishVar", vl_method_relinquish_var, |
203 | 0 | "io.systemd.service.Ping", varlink_method_ping, |
204 | 0 | "io.systemd.service.SetLogLevel", varlink_method_set_log_level, |
205 | 0 | "io.systemd.service.GetEnvironment", varlink_method_get_environment); |
206 | 0 | if (r < 0) |
207 | 0 | return r; |
208 | | |
209 | 0 | r = sd_varlink_server_bind_connect(m->varlink_server, vl_connect); |
210 | 0 | if (r < 0) |
211 | 0 | return r; |
212 | | |
213 | 0 | r = sd_varlink_server_bind_disconnect(m->varlink_server, vl_disconnect); |
214 | 0 | if (r < 0) |
215 | 0 | return r; |
216 | | |
217 | 0 | if (fd < 0) |
218 | 0 | r = sd_varlink_server_listen_address(m->varlink_server, socket, 0666); |
219 | 0 | else |
220 | 0 | r = sd_varlink_server_listen_fd(m->varlink_server, fd); |
221 | 0 | if (r < 0) |
222 | 0 | return r; |
223 | | |
224 | 0 | r = sd_varlink_server_attach_event(m->varlink_server, m->event, SD_EVENT_PRIORITY_NORMAL); |
225 | 0 | if (r < 0) |
226 | 0 | return r; |
227 | | |
228 | 0 | return 0; |
229 | 0 | } |