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