Coverage Report

Created: 2025-07-09 06:39

/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
}