]>
Commit | Line | Data |
---|---|---|
1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ | |
2 | ||
3 | #include <pthread.h> | |
4 | #include <sys/socket.h> | |
5 | ||
6 | #include "sd-bus.h" | |
7 | ||
8 | #include "bus-error.h" | |
9 | #include "log.h" | |
10 | #include "memory-util.h" | |
11 | #include "string-util.h" | |
12 | #include "tests.h" | |
13 | ||
14 | struct context { | |
15 | int fds[2]; | |
16 | ||
17 | bool client_negotiate_unix_fds; | |
18 | bool server_negotiate_unix_fds; | |
19 | ||
20 | bool client_anonymous_auth; | |
21 | bool server_anonymous_auth; | |
22 | }; | |
23 | ||
24 | static int _server(struct context *c) { | |
25 | _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; | |
26 | sd_id128_t id; | |
27 | bool quit = false; | |
28 | int r; | |
29 | ||
30 | assert_se(sd_id128_randomize(&id) >= 0); | |
31 | ||
32 | assert_se(sd_bus_new(&bus) >= 0); | |
33 | assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0); | |
34 | assert_se(sd_bus_set_server(bus, 1, id) >= 0); | |
35 | assert_se(sd_bus_set_anonymous(bus, c->server_anonymous_auth) >= 0); | |
36 | assert_se(sd_bus_negotiate_fds(bus, c->server_negotiate_unix_fds) >= 0); | |
37 | assert_se(sd_bus_start(bus) >= 0); | |
38 | ||
39 | while (!quit) { | |
40 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; | |
41 | ||
42 | r = sd_bus_process(bus, &m); | |
43 | if (r < 0) | |
44 | return log_error_errno(r, "Failed to process requests: %m"); | |
45 | ||
46 | if (r == 0) { | |
47 | r = sd_bus_wait(bus, UINT64_MAX); | |
48 | if (r < 0) | |
49 | return log_error_errno(r, "Failed to wait: %m"); | |
50 | continue; | |
51 | } | |
52 | ||
53 | if (!m) | |
54 | continue; | |
55 | ||
56 | log_info("Got message! member=%s", strna(sd_bus_message_get_member(m))); | |
57 | ||
58 | if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Exit")) { | |
59 | ||
60 | assert_se((sd_bus_can_send(bus, 'h') >= 1) == | |
61 | (c->server_negotiate_unix_fds && c->client_negotiate_unix_fds)); | |
62 | ||
63 | r = sd_bus_message_new_method_return(m, &reply); | |
64 | if (r < 0) | |
65 | return log_error_errno(r, "Failed to allocate return: %m"); | |
66 | ||
67 | quit = true; | |
68 | ||
69 | } else if (sd_bus_message_is_method_call(m, NULL, NULL)) { | |
70 | r = sd_bus_message_new_method_error( | |
71 | m, | |
72 | &reply, | |
73 | &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method.")); | |
74 | if (r < 0) | |
75 | return log_error_errno(r, "Failed to allocate return: %m"); | |
76 | } | |
77 | ||
78 | if (reply) { | |
79 | r = sd_bus_send(bus, reply, NULL); | |
80 | if (r < 0) | |
81 | return log_error_errno(r, "Failed to send reply: %m"); | |
82 | } | |
83 | } | |
84 | ||
85 | return 0; | |
86 | } | |
87 | ||
88 | static void* server(void *p) { | |
89 | return INT_TO_PTR(_server(p)); | |
90 | } | |
91 | ||
92 | static int client(struct context *c) { | |
93 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; | |
94 | _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; | |
95 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; | |
96 | int r; | |
97 | ||
98 | assert_se(sd_bus_new(&bus) >= 0); | |
99 | assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0); | |
100 | assert_se(sd_bus_negotiate_fds(bus, c->client_negotiate_unix_fds) >= 0); | |
101 | assert_se(sd_bus_set_anonymous(bus, c->client_anonymous_auth) >= 0); | |
102 | assert_se(sd_bus_start(bus) >= 0); | |
103 | ||
104 | r = sd_bus_message_new_method_call( | |
105 | bus, | |
106 | &m, | |
107 | "org.freedesktop.systemd.test", | |
108 | "/", | |
109 | "org.freedesktop.systemd.test", | |
110 | "Exit"); | |
111 | if (r < 0) | |
112 | return log_error_errno(r, "Failed to allocate method call: %m"); | |
113 | ||
114 | r = sd_bus_call(bus, m, 0, &error, &reply); | |
115 | if (r < 0) | |
116 | return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r)); | |
117 | ||
118 | return 0; | |
119 | } | |
120 | ||
121 | static int test_one(bool client_negotiate_unix_fds, bool server_negotiate_unix_fds, | |
122 | bool client_anonymous_auth, bool server_anonymous_auth) { | |
123 | ||
124 | struct context c; | |
125 | pthread_t s; | |
126 | void *p; | |
127 | int r, q; | |
128 | ||
129 | zero(c); | |
130 | ||
131 | assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0); | |
132 | ||
133 | c.client_negotiate_unix_fds = client_negotiate_unix_fds; | |
134 | c.server_negotiate_unix_fds = server_negotiate_unix_fds; | |
135 | c.client_anonymous_auth = client_anonymous_auth; | |
136 | c.server_anonymous_auth = server_anonymous_auth; | |
137 | ||
138 | r = pthread_create(&s, NULL, server, &c); | |
139 | if (r != 0) | |
140 | return -r; | |
141 | ||
142 | r = client(&c); | |
143 | ||
144 | q = pthread_join(s, &p); | |
145 | if (q != 0) | |
146 | return -q; | |
147 | ||
148 | if (r < 0) | |
149 | return r; | |
150 | ||
151 | if (PTR_TO_INT(p) < 0) | |
152 | return PTR_TO_INT(p); | |
153 | ||
154 | return 0; | |
155 | } | |
156 | ||
157 | int main(int argc, char *argv[]) { | |
158 | int r; | |
159 | ||
160 | test_setup_logging(LOG_DEBUG); | |
161 | ||
162 | r = test_one(true, true, false, false); | |
163 | assert_se(r >= 0); | |
164 | ||
165 | r = test_one(true, false, false, false); | |
166 | assert_se(r >= 0); | |
167 | ||
168 | r = test_one(false, true, false, false); | |
169 | assert_se(r >= 0); | |
170 | ||
171 | r = test_one(false, false, false, false); | |
172 | assert_se(r >= 0); | |
173 | ||
174 | r = test_one(true, true, true, true); | |
175 | assert_se(r >= 0); | |
176 | ||
177 | r = test_one(true, true, false, true); | |
178 | assert_se(r >= 0); | |
179 | ||
180 | r = test_one(true, true, true, false); | |
181 | assert_se(r == -EPERM); | |
182 | ||
183 | return EXIT_SUCCESS; | |
184 | } |