| File: | build-scan/../src/libsystemd/sd-bus/bus-socket.c |
| Warning: | line 792, column 30 Potential leak of memory pointed to by 'prefix' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
| 2 | /*** | |||
| 3 | ***/ | |||
| 4 | ||||
| 5 | #include <endian.h> | |||
| 6 | #include <poll.h> | |||
| 7 | #include <stdlib.h> | |||
| 8 | #include <unistd.h> | |||
| 9 | ||||
| 10 | #include "sd-bus.h" | |||
| 11 | #include "sd-daemon.h" | |||
| 12 | ||||
| 13 | #include "alloc-util.h" | |||
| 14 | #include "bus-internal.h" | |||
| 15 | #include "bus-message.h" | |||
| 16 | #include "bus-socket.h" | |||
| 17 | #include "fd-util.h" | |||
| 18 | #include "format-util.h" | |||
| 19 | #include "fs-util.h" | |||
| 20 | #include "hexdecoct.h" | |||
| 21 | #include "io-util.h" | |||
| 22 | #include "macro.h" | |||
| 23 | #include "missing.h" | |||
| 24 | #include "path-util.h" | |||
| 25 | #include "process-util.h" | |||
| 26 | #include "selinux-util.h" | |||
| 27 | #include "signal-util.h" | |||
| 28 | #include "stdio-util.h" | |||
| 29 | #include "string-util.h" | |||
| 30 | #include "user-util.h" | |||
| 31 | #include "utf8.h" | |||
| 32 | #include "util.h" | |||
| 33 | ||||
| 34 | #define SNDBUF_SIZE(8*1024*1024) (8*1024*1024) | |||
| 35 | ||||
| 36 | static void iovec_advance(struct iovec iov[], unsigned *idx, size_t size) { | |||
| 37 | ||||
| 38 | while (size > 0) { | |||
| 39 | struct iovec *i = iov + *idx; | |||
| 40 | ||||
| 41 | if (i->iov_len > size) { | |||
| 42 | i->iov_base = (uint8_t*) i->iov_base + size; | |||
| 43 | i->iov_len -= size; | |||
| 44 | return; | |||
| 45 | } | |||
| 46 | ||||
| 47 | size -= i->iov_len; | |||
| 48 | ||||
| 49 | i->iov_base = NULL((void*)0); | |||
| 50 | i->iov_len = 0; | |||
| 51 | ||||
| 52 | (*idx)++; | |||
| 53 | } | |||
| 54 | } | |||
| 55 | ||||
| 56 | static int append_iovec(sd_bus_message *m, const void *p, size_t sz) { | |||
| 57 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/libsystemd/sd-bus/bus-socket.c" , 57, __PRETTY_FUNCTION__); } while (0); | |||
| 58 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/libsystemd/sd-bus/bus-socket.c" , 58, __PRETTY_FUNCTION__); } while (0); | |||
| 59 | assert(sz > 0)do { if ((__builtin_expect(!!(!(sz > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("sz > 0"), "../src/libsystemd/sd-bus/bus-socket.c" , 59, __PRETTY_FUNCTION__); } while (0); | |||
| 60 | ||||
| 61 | m->iovec[m->n_iovec].iov_base = (void*) p; | |||
| 62 | m->iovec[m->n_iovec].iov_len = sz; | |||
| 63 | m->n_iovec++; | |||
| 64 | ||||
| 65 | return 0; | |||
| 66 | } | |||
| 67 | ||||
| 68 | static int bus_message_setup_iovec(sd_bus_message *m) { | |||
| 69 | struct bus_body_part *part; | |||
| 70 | unsigned n, i; | |||
| 71 | int r; | |||
| 72 | ||||
| 73 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/libsystemd/sd-bus/bus-socket.c" , 73, __PRETTY_FUNCTION__); } while (0); | |||
| 74 | assert(m->sealed)do { if ((__builtin_expect(!!(!(m->sealed)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m->sealed"), "../src/libsystemd/sd-bus/bus-socket.c" , 74, __PRETTY_FUNCTION__); } while (0); | |||
| 75 | ||||
| 76 | if (m->n_iovec > 0) | |||
| 77 | return 0; | |||
| 78 | ||||
| 79 | assert(!m->iovec)do { if ((__builtin_expect(!!(!(!m->iovec)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("!m->iovec"), "../src/libsystemd/sd-bus/bus-socket.c" , 79, __PRETTY_FUNCTION__); } while (0); | |||
| 80 | ||||
| 81 | n = 1 + m->n_body_parts; | |||
| 82 | if (n < ELEMENTSOF(m->iovec_fixed)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(m->iovec_fixed), typeof(&*(m->iovec_fixed)) ), sizeof(m->iovec_fixed)/sizeof((m->iovec_fixed)[0]), ( (void)0)))) | |||
| 83 | m->iovec = m->iovec_fixed; | |||
| 84 | else { | |||
| 85 | m->iovec = new(struct iovec, n)((struct iovec*) malloc_multiply(sizeof(struct iovec), (n))); | |||
| 86 | if (!m->iovec) { | |||
| 87 | r = -ENOMEM12; | |||
| 88 | goto fail; | |||
| 89 | } | |||
| 90 | } | |||
| 91 | ||||
| 92 | r = append_iovec(m, m->header, BUS_MESSAGE_BODY_BEGIN(m)); | |||
| 93 | if (r < 0) | |||
| 94 | goto fail; | |||
| 95 | ||||
| 96 | MESSAGE_FOREACH_PART(part, i, m)for ((i) = 0, (part) = &(m)->body; (i) < (m)->n_body_parts ; (i)++, (part) = (part)->next) { | |||
| 97 | r = bus_body_part_map(part); | |||
| 98 | if (r < 0) | |||
| 99 | goto fail; | |||
| 100 | ||||
| 101 | r = append_iovec(m, part->data, part->size); | |||
| 102 | if (r < 0) | |||
| 103 | goto fail; | |||
| 104 | } | |||
| 105 | ||||
| 106 | assert(n == m->n_iovec)do { if ((__builtin_expect(!!(!(n == m->n_iovec)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("n == m->n_iovec"), "../src/libsystemd/sd-bus/bus-socket.c" , 106, __PRETTY_FUNCTION__); } while (0); | |||
| 107 | ||||
| 108 | return 0; | |||
| 109 | ||||
| 110 | fail: | |||
| 111 | m->poisoned = true1; | |||
| 112 | return r; | |||
| 113 | } | |||
| 114 | ||||
| 115 | bool_Bool bus_socket_auth_needs_write(sd_bus *b) { | |||
| 116 | ||||
| 117 | unsigned i; | |||
| 118 | ||||
| 119 | if (b->auth_index >= ELEMENTSOF(b->auth_iovec)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(b->auth_iovec), typeof(&*(b->auth_iovec))), sizeof(b->auth_iovec)/sizeof((b->auth_iovec)[0]), ((void )0)))) | |||
| 120 | return false0; | |||
| 121 | ||||
| 122 | for (i = b->auth_index; i < ELEMENTSOF(b->auth_iovec)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(b->auth_iovec), typeof(&*(b->auth_iovec))), sizeof(b->auth_iovec)/sizeof((b->auth_iovec)[0]), ((void )0))); i++) { | |||
| 123 | struct iovec *j = b->auth_iovec + i; | |||
| 124 | ||||
| 125 | if (j->iov_len > 0) | |||
| 126 | return true1; | |||
| 127 | } | |||
| 128 | ||||
| 129 | return false0; | |||
| 130 | } | |||
| 131 | ||||
| 132 | static int bus_socket_write_auth(sd_bus *b) { | |||
| 133 | ssize_t k; | |||
| 134 | ||||
| 135 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 135, __PRETTY_FUNCTION__); } while (0); | |||
| 136 | assert(b->state == BUS_AUTHENTICATING)do { if ((__builtin_expect(!!(!(b->state == BUS_AUTHENTICATING )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("b->state == BUS_AUTHENTICATING" ), "../src/libsystemd/sd-bus/bus-socket.c", 136, __PRETTY_FUNCTION__ ); } while (0); | |||
| 137 | ||||
| 138 | if (!bus_socket_auth_needs_write(b)) | |||
| 139 | return 0; | |||
| 140 | ||||
| 141 | if (b->prefer_writev) | |||
| 142 | k = writev(b->output_fd, b->auth_iovec + b->auth_index, ELEMENTSOF(b->auth_iovec)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(b->auth_iovec), typeof(&*(b->auth_iovec))), sizeof(b->auth_iovec)/sizeof((b->auth_iovec)[0]), ((void )0))) - b->auth_index); | |||
| 143 | else { | |||
| 144 | struct msghdr mh; | |||
| 145 | zero(mh)(({ size_t _l_ = (sizeof(mh)); void *_x_ = (&(mh)); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); })); | |||
| 146 | ||||
| 147 | mh.msg_iov = b->auth_iovec + b->auth_index; | |||
| 148 | mh.msg_iovlen = ELEMENTSOF(b->auth_iovec)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(b->auth_iovec), typeof(&*(b->auth_iovec))), sizeof(b->auth_iovec)/sizeof((b->auth_iovec)[0]), ((void )0))) - b->auth_index; | |||
| 149 | ||||
| 150 | k = sendmsg(b->output_fd, &mh, MSG_DONTWAITMSG_DONTWAIT|MSG_NOSIGNALMSG_NOSIGNAL); | |||
| 151 | if (k < 0 && errno(*__errno_location ()) == ENOTSOCK88) { | |||
| 152 | b->prefer_writev = true1; | |||
| 153 | k = writev(b->output_fd, b->auth_iovec + b->auth_index, ELEMENTSOF(b->auth_iovec)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(b->auth_iovec), typeof(&*(b->auth_iovec))), sizeof(b->auth_iovec)/sizeof((b->auth_iovec)[0]), ((void )0))) - b->auth_index); | |||
| 154 | } | |||
| 155 | } | |||
| 156 | ||||
| 157 | if (k < 0) | |||
| 158 | return errno(*__errno_location ()) == EAGAIN11 ? 0 : -errno(*__errno_location ()); | |||
| 159 | ||||
| 160 | iovec_advance(b->auth_iovec, &b->auth_index, (size_t) k); | |||
| 161 | return 1; | |||
| 162 | } | |||
| 163 | ||||
| 164 | static int bus_socket_auth_verify_client(sd_bus *b) { | |||
| 165 | char *d, *e, *f, *start; | |||
| 166 | sd_id128_t peer; | |||
| 167 | unsigned i; | |||
| 168 | int r; | |||
| 169 | ||||
| 170 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 170, __PRETTY_FUNCTION__); } while (0); | |||
| 171 | ||||
| 172 | /* | |||
| 173 | * We expect three response lines: | |||
| 174 | * "DATA\r\n" | |||
| 175 | * "OK <server-id>\r\n" | |||
| 176 | * "AGREE_UNIX_FD\r\n" (optional) | |||
| 177 | */ | |||
| 178 | ||||
| 179 | d = memmem_safe(b->rbuffer, b->rbuffer_size, "\r\n", 2); | |||
| 180 | if (!d) | |||
| 181 | return 0; | |||
| 182 | ||||
| 183 | e = memmem(d + 2, b->rbuffer_size - (d - (char*) b->rbuffer) - 2, "\r\n", 2); | |||
| 184 | if (!e) | |||
| 185 | return 0; | |||
| 186 | ||||
| 187 | if (b->accept_fd) { | |||
| 188 | f = memmem(e + 2, b->rbuffer_size - (e - (char*) b->rbuffer) - 2, "\r\n", 2); | |||
| 189 | if (!f) | |||
| 190 | return 0; | |||
| 191 | ||||
| 192 | start = f + 2; | |||
| 193 | } else { | |||
| 194 | f = NULL((void*)0); | |||
| 195 | start = e + 2; | |||
| 196 | } | |||
| 197 | ||||
| 198 | /* Nice! We got all the lines we need. First check the DATA line. */ | |||
| 199 | ||||
| 200 | if (d - (char*) b->rbuffer == 4) { | |||
| 201 | if (memcmp(b->rbuffer, "DATA", 4)) | |||
| 202 | return -EPERM1; | |||
| 203 | } else if (d - (char*) b->rbuffer == 3 + 32) { | |||
| 204 | /* | |||
| 205 | * Old versions of the server-side implementation of `sd-bus` replied with "OK <id>" to | |||
| 206 | * "AUTH" requests from a client, even if the "AUTH" line did not contain inlined | |||
| 207 | * arguments. Therefore, we also accept "OK <id>" here, even though it is technically the | |||
| 208 | * wrong reply. We ignore the "<id>" parameter, though, since it has no real value. | |||
| 209 | */ | |||
| 210 | if (memcmp(b->rbuffer, "OK ", 3)) | |||
| 211 | return -EPERM1; | |||
| 212 | } else { | |||
| 213 | return -EPERM1; | |||
| 214 | } | |||
| 215 | ||||
| 216 | /* Now check the OK line. */ | |||
| 217 | ||||
| 218 | if (e - d != 2 + 3 + 32) | |||
| 219 | return -EPERM1; | |||
| 220 | ||||
| 221 | if (memcmp(d + 2, "OK ", 3)) | |||
| 222 | return -EPERM1; | |||
| 223 | ||||
| 224 | b->auth = b->anonymous_auth ? BUS_AUTH_ANONYMOUS : BUS_AUTH_EXTERNAL; | |||
| 225 | ||||
| 226 | for (i = 0; i < 32; i += 2) { | |||
| 227 | int x, y; | |||
| 228 | ||||
| 229 | x = unhexchar(d[2 + 3 + i]); | |||
| 230 | y = unhexchar(d[2 + 3 + i + 1]); | |||
| 231 | ||||
| 232 | if (x < 0 || y < 0) | |||
| 233 | return -EINVAL22; | |||
| 234 | ||||
| 235 | peer.bytes[i/2] = ((uint8_t) x << 4 | (uint8_t) y); | |||
| 236 | } | |||
| 237 | ||||
| 238 | if (!sd_id128_is_null(b->server_id) && | |||
| 239 | !sd_id128_equal(b->server_id, peer)) | |||
| 240 | return -EPERM1; | |||
| 241 | ||||
| 242 | b->server_id = peer; | |||
| 243 | ||||
| 244 | /* And possibly check the third line, too */ | |||
| 245 | ||||
| 246 | if (f) | |||
| 247 | b->can_fds = | |||
| 248 | (f - e == STRLEN("\r\nAGREE_UNIX_FD")(sizeof("""\r\nAGREE_UNIX_FD""") - 1)) && | |||
| 249 | memcmp(e + 2, "AGREE_UNIX_FD", | |||
| 250 | STRLEN("AGREE_UNIX_FD")(sizeof("""AGREE_UNIX_FD""") - 1)) == 0; | |||
| 251 | ||||
| 252 | b->rbuffer_size -= (start - (char*) b->rbuffer); | |||
| 253 | memmove(b->rbuffer, start, b->rbuffer_size); | |||
| 254 | ||||
| 255 | r = bus_start_running(b); | |||
| 256 | if (r < 0) | |||
| 257 | return r; | |||
| 258 | ||||
| 259 | return 1; | |||
| 260 | } | |||
| 261 | ||||
| 262 | static bool_Bool line_equals(const char *s, size_t m, const char *line) { | |||
| 263 | size_t l; | |||
| 264 | ||||
| 265 | l = strlen(line); | |||
| 266 | if (l != m) | |||
| 267 | return false0; | |||
| 268 | ||||
| 269 | return memcmp(s, line, l) == 0; | |||
| 270 | } | |||
| 271 | ||||
| 272 | static bool_Bool line_begins(const char *s, size_t m, const char *word) { | |||
| 273 | const char *p; | |||
| 274 | ||||
| 275 | p = memory_startswith(s, m, word); | |||
| 276 | return p && (p == (s + m) || *p == ' '); | |||
| 277 | } | |||
| 278 | ||||
| 279 | static int verify_anonymous_token(sd_bus *b, const char *p, size_t l) { | |||
| 280 | _cleanup_free___attribute__((cleanup(freep))) char *token = NULL((void*)0); | |||
| 281 | size_t len; | |||
| 282 | int r; | |||
| 283 | ||||
| 284 | if (!b->anonymous_auth) | |||
| 285 | return 0; | |||
| 286 | ||||
| 287 | if (l <= 0) | |||
| 288 | return 1; | |||
| 289 | ||||
| 290 | assert(p[0] == ' ')do { if ((__builtin_expect(!!(!(p[0] == ' ')),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p[0] == ' '"), "../src/libsystemd/sd-bus/bus-socket.c" , 290, __PRETTY_FUNCTION__); } while (0); | |||
| 291 | p++; l--; | |||
| 292 | ||||
| 293 | if (l % 2 != 0) | |||
| 294 | return 0; | |||
| 295 | ||||
| 296 | r = unhexmem(p, l, (void **) &token, &len); | |||
| 297 | if (r < 0) | |||
| 298 | return 0; | |||
| 299 | ||||
| 300 | if (memchr(token, 0, len)) | |||
| 301 | return 0; | |||
| 302 | ||||
| 303 | return !!utf8_is_valid(token); | |||
| 304 | } | |||
| 305 | ||||
| 306 | static int verify_external_token(sd_bus *b, const char *p, size_t l) { | |||
| 307 | _cleanup_free___attribute__((cleanup(freep))) char *token = NULL((void*)0); | |||
| 308 | size_t len; | |||
| 309 | uid_t u; | |||
| 310 | int r; | |||
| 311 | ||||
| 312 | /* We don't do any real authentication here. Instead, we if | |||
| 313 | * the owner of this bus wanted authentication he should have | |||
| 314 | * checked SO_PEERCRED before even creating the bus object. */ | |||
| 315 | ||||
| 316 | if (!b->anonymous_auth && !b->ucred_valid) | |||
| 317 | return 0; | |||
| 318 | ||||
| 319 | if (l <= 0) | |||
| 320 | return 1; | |||
| 321 | ||||
| 322 | assert(p[0] == ' ')do { if ((__builtin_expect(!!(!(p[0] == ' ')),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p[0] == ' '"), "../src/libsystemd/sd-bus/bus-socket.c" , 322, __PRETTY_FUNCTION__); } while (0); | |||
| 323 | p++; l--; | |||
| 324 | ||||
| 325 | if (l % 2 != 0) | |||
| 326 | return 0; | |||
| 327 | ||||
| 328 | r = unhexmem(p, l, (void**) &token, &len); | |||
| 329 | if (r < 0) | |||
| 330 | return 0; | |||
| 331 | ||||
| 332 | if (memchr(token, 0, len)) | |||
| 333 | return 0; | |||
| 334 | ||||
| 335 | r = parse_uid(token, &u); | |||
| 336 | if (r < 0) | |||
| 337 | return 0; | |||
| 338 | ||||
| 339 | /* We ignore the passed value if anonymous authentication is | |||
| 340 | * on anyway. */ | |||
| 341 | if (!b->anonymous_auth && u != b->ucred.uid) | |||
| 342 | return 0; | |||
| 343 | ||||
| 344 | return 1; | |||
| 345 | } | |||
| 346 | ||||
| 347 | static int bus_socket_auth_write(sd_bus *b, const char *t) { | |||
| 348 | char *p; | |||
| 349 | size_t l; | |||
| 350 | ||||
| 351 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 351, __PRETTY_FUNCTION__); } while (0); | |||
| 352 | assert(t)do { if ((__builtin_expect(!!(!(t)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("t"), "../src/libsystemd/sd-bus/bus-socket.c" , 352, __PRETTY_FUNCTION__); } while (0); | |||
| 353 | ||||
| 354 | /* We only make use of the first iovec */ | |||
| 355 | assert(IN_SET(b->auth_index, 0, 1))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){0, 1})/sizeof(int)]; switch(b->auth_index ) { case 0: case 1: _found = 1; break; default: break; } _found ; }))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("IN_SET(b->auth_index, 0, 1)" ), "../src/libsystemd/sd-bus/bus-socket.c", 355, __PRETTY_FUNCTION__ ); } while (0); | |||
| 356 | ||||
| 357 | l = strlen(t); | |||
| 358 | p = malloc(b->auth_iovec[0].iov_len + l); | |||
| 359 | if (!p) | |||
| 360 | return -ENOMEM12; | |||
| 361 | ||||
| 362 | memcpy_safe(p, b->auth_iovec[0].iov_base, b->auth_iovec[0].iov_len); | |||
| 363 | memcpy(p + b->auth_iovec[0].iov_len, t, l); | |||
| 364 | ||||
| 365 | b->auth_iovec[0].iov_base = p; | |||
| 366 | b->auth_iovec[0].iov_len += l; | |||
| 367 | ||||
| 368 | free(b->auth_buffer); | |||
| 369 | b->auth_buffer = p; | |||
| 370 | b->auth_index = 0; | |||
| 371 | return 0; | |||
| 372 | } | |||
| 373 | ||||
| 374 | static int bus_socket_auth_write_ok(sd_bus *b) { | |||
| 375 | char t[3 + 32 + 2 + 1]; | |||
| 376 | ||||
| 377 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 377, __PRETTY_FUNCTION__); } while (0); | |||
| 378 | ||||
| 379 | xsprintf(t, "OK " SD_ID128_FORMAT_STR "\r\n", SD_ID128_FORMAT_VAL(b->server_id))do { if ((__builtin_expect(!!(!(((size_t) snprintf(t, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (t), typeof(&*(t))), sizeof(t)/sizeof((t)[0]), ((void)0)) ), "OK " "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" "\r\n", (b->server_id).bytes[0], (b->server_id).bytes[ 1], (b->server_id).bytes[2], (b->server_id).bytes[3], ( b->server_id).bytes[4], (b->server_id).bytes[5], (b-> server_id).bytes[6], (b->server_id).bytes[7], (b->server_id ).bytes[8], (b->server_id).bytes[9], (b->server_id).bytes [10], (b->server_id).bytes[11], (b->server_id).bytes[12 ], (b->server_id).bytes[13], (b->server_id).bytes[14], ( b->server_id).bytes[15]) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(t), typeof(&*(t))) , sizeof(t)/sizeof((t)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "t" "[] must be big enough" ), "../src/libsystemd/sd-bus/bus-socket.c", 379, __PRETTY_FUNCTION__ ); } while (0); | |||
| 380 | ||||
| 381 | return bus_socket_auth_write(b, t); | |||
| 382 | } | |||
| 383 | ||||
| 384 | static int bus_socket_auth_verify_server(sd_bus *b) { | |||
| 385 | char *e; | |||
| 386 | const char *line; | |||
| 387 | size_t l; | |||
| 388 | bool_Bool processed = false0; | |||
| 389 | int r; | |||
| 390 | ||||
| 391 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 391, __PRETTY_FUNCTION__); } while (0); | |||
| 392 | ||||
| 393 | if (b->rbuffer_size < 1) | |||
| 394 | return 0; | |||
| 395 | ||||
| 396 | /* First char must be a NUL byte */ | |||
| 397 | if (*(char*) b->rbuffer != 0) | |||
| 398 | return -EIO5; | |||
| 399 | ||||
| 400 | if (b->rbuffer_size < 3) | |||
| 401 | return 0; | |||
| 402 | ||||
| 403 | /* Begin with the first line */ | |||
| 404 | if (b->auth_rbegin <= 0) | |||
| 405 | b->auth_rbegin = 1; | |||
| 406 | ||||
| 407 | for (;;) { | |||
| 408 | /* Check if line is complete */ | |||
| 409 | line = (char*) b->rbuffer + b->auth_rbegin; | |||
| 410 | e = memmem(line, b->rbuffer_size - b->auth_rbegin, "\r\n", 2); | |||
| 411 | if (!e) | |||
| 412 | return processed; | |||
| 413 | ||||
| 414 | l = e - line; | |||
| 415 | ||||
| 416 | if (line_begins(line, l, "AUTH ANONYMOUS")) { | |||
| 417 | ||||
| 418 | r = verify_anonymous_token(b, | |||
| 419 | line + strlen("AUTH ANONYMOUS"), | |||
| 420 | l - strlen("AUTH ANONYMOUS")); | |||
| 421 | if (r < 0) | |||
| 422 | return r; | |||
| 423 | if (r == 0) | |||
| 424 | r = bus_socket_auth_write(b, "REJECTED\r\n"); | |||
| 425 | else { | |||
| 426 | b->auth = BUS_AUTH_ANONYMOUS; | |||
| 427 | if (l <= strlen("AUTH ANONYMOUS")) | |||
| 428 | r = bus_socket_auth_write(b, "DATA\r\n"); | |||
| 429 | else | |||
| 430 | r = bus_socket_auth_write_ok(b); | |||
| 431 | } | |||
| 432 | ||||
| 433 | } else if (line_begins(line, l, "AUTH EXTERNAL")) { | |||
| 434 | ||||
| 435 | r = verify_external_token(b, | |||
| 436 | line + strlen("AUTH EXTERNAL"), | |||
| 437 | l - strlen("AUTH EXTERNAL")); | |||
| 438 | if (r < 0) | |||
| 439 | return r; | |||
| 440 | if (r == 0) | |||
| 441 | r = bus_socket_auth_write(b, "REJECTED\r\n"); | |||
| 442 | else { | |||
| 443 | b->auth = BUS_AUTH_EXTERNAL; | |||
| 444 | if (l <= strlen("AUTH EXTERNAL")) | |||
| 445 | r = bus_socket_auth_write(b, "DATA\r\n"); | |||
| 446 | else | |||
| 447 | r = bus_socket_auth_write_ok(b); | |||
| 448 | } | |||
| 449 | ||||
| 450 | } else if (line_begins(line, l, "AUTH")) | |||
| 451 | r = bus_socket_auth_write(b, "REJECTED EXTERNAL ANONYMOUS\r\n"); | |||
| 452 | else if (line_equals(line, l, "CANCEL") || | |||
| 453 | line_begins(line, l, "ERROR")) { | |||
| 454 | ||||
| 455 | b->auth = _BUS_AUTH_INVALID; | |||
| 456 | r = bus_socket_auth_write(b, "REJECTED\r\n"); | |||
| 457 | ||||
| 458 | } else if (line_equals(line, l, "BEGIN")) { | |||
| 459 | ||||
| 460 | if (b->auth == _BUS_AUTH_INVALID) | |||
| 461 | r = bus_socket_auth_write(b, "ERROR\r\n"); | |||
| 462 | else { | |||
| 463 | /* We can't leave from the auth phase | |||
| 464 | * before we haven't written | |||
| 465 | * everything queued, so let's check | |||
| 466 | * that */ | |||
| 467 | ||||
| 468 | if (bus_socket_auth_needs_write(b)) | |||
| 469 | return 1; | |||
| 470 | ||||
| 471 | b->rbuffer_size -= (e + 2 - (char*) b->rbuffer); | |||
| 472 | memmove(b->rbuffer, e + 2, b->rbuffer_size); | |||
| 473 | return bus_start_running(b); | |||
| 474 | } | |||
| 475 | ||||
| 476 | } else if (line_begins(line, l, "DATA")) { | |||
| 477 | ||||
| 478 | if (b->auth == _BUS_AUTH_INVALID) | |||
| 479 | r = bus_socket_auth_write(b, "ERROR\r\n"); | |||
| 480 | else { | |||
| 481 | if (b->auth == BUS_AUTH_ANONYMOUS) | |||
| 482 | r = verify_anonymous_token(b, line + 4, l - 4); | |||
| 483 | else | |||
| 484 | r = verify_external_token(b, line + 4, l - 4); | |||
| 485 | ||||
| 486 | if (r < 0) | |||
| 487 | return r; | |||
| 488 | if (r == 0) { | |||
| 489 | b->auth = _BUS_AUTH_INVALID; | |||
| 490 | r = bus_socket_auth_write(b, "REJECTED\r\n"); | |||
| 491 | } else | |||
| 492 | r = bus_socket_auth_write_ok(b); | |||
| 493 | } | |||
| 494 | } else if (line_equals(line, l, "NEGOTIATE_UNIX_FD")) { | |||
| 495 | if (b->auth == _BUS_AUTH_INVALID || !b->accept_fd) | |||
| 496 | r = bus_socket_auth_write(b, "ERROR\r\n"); | |||
| 497 | else { | |||
| 498 | b->can_fds = true1; | |||
| 499 | r = bus_socket_auth_write(b, "AGREE_UNIX_FD\r\n"); | |||
| 500 | } | |||
| 501 | } else | |||
| 502 | r = bus_socket_auth_write(b, "ERROR\r\n"); | |||
| 503 | ||||
| 504 | if (r < 0) | |||
| 505 | return r; | |||
| 506 | ||||
| 507 | b->auth_rbegin = e + 2 - (char*) b->rbuffer; | |||
| 508 | ||||
| 509 | processed = true1; | |||
| 510 | } | |||
| 511 | } | |||
| 512 | ||||
| 513 | static int bus_socket_auth_verify(sd_bus *b) { | |||
| 514 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 514, __PRETTY_FUNCTION__); } while (0); | |||
| 515 | ||||
| 516 | if (b->is_server) | |||
| 517 | return bus_socket_auth_verify_server(b); | |||
| 518 | else | |||
| 519 | return bus_socket_auth_verify_client(b); | |||
| 520 | } | |||
| 521 | ||||
| 522 | static int bus_socket_read_auth(sd_bus *b) { | |||
| 523 | struct msghdr mh; | |||
| 524 | struct iovec iov = {}; | |||
| 525 | size_t n; | |||
| 526 | ssize_t k; | |||
| 527 | int r; | |||
| 528 | void *p; | |||
| 529 | union { | |||
| 530 | struct cmsghdr cmsghdr; | |||
| 531 | uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)((((sizeof(int) * 1024) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)) + (((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)))]; | |||
| 532 | } control; | |||
| 533 | bool_Bool handle_cmsg = false0; | |||
| 534 | ||||
| 535 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 535, __PRETTY_FUNCTION__); } while (0); | |||
| 536 | assert(b->state == BUS_AUTHENTICATING)do { if ((__builtin_expect(!!(!(b->state == BUS_AUTHENTICATING )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("b->state == BUS_AUTHENTICATING" ), "../src/libsystemd/sd-bus/bus-socket.c", 536, __PRETTY_FUNCTION__ ); } while (0); | |||
| 537 | ||||
| 538 | r = bus_socket_auth_verify(b); | |||
| 539 | if (r != 0) | |||
| 540 | return r; | |||
| 541 | ||||
| 542 | n = MAX(256u, b->rbuffer_size * 2)__extension__ ({ const typeof((256u)) __unique_prefix_A10 = ( (256u)); const typeof((b->rbuffer_size * 2)) __unique_prefix_B11 = ((b->rbuffer_size * 2)); __unique_prefix_A10 > __unique_prefix_B11 ? __unique_prefix_A10 : __unique_prefix_B11; }); | |||
| 543 | ||||
| 544 | if (n > BUS_AUTH_SIZE_MAX(64*1024)) | |||
| 545 | n = BUS_AUTH_SIZE_MAX(64*1024); | |||
| 546 | ||||
| 547 | if (b->rbuffer_size >= n) | |||
| 548 | return -ENOBUFS105; | |||
| 549 | ||||
| 550 | p = realloc(b->rbuffer, n); | |||
| 551 | if (!p) | |||
| 552 | return -ENOMEM12; | |||
| 553 | ||||
| 554 | b->rbuffer = p; | |||
| 555 | ||||
| 556 | iov.iov_base = (uint8_t*) b->rbuffer + b->rbuffer_size; | |||
| 557 | iov.iov_len = n - b->rbuffer_size; | |||
| 558 | ||||
| 559 | if (b->prefer_readv) | |||
| 560 | k = readv(b->input_fd, &iov, 1); | |||
| 561 | else { | |||
| 562 | zero(mh)(({ size_t _l_ = (sizeof(mh)); void *_x_ = (&(mh)); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); })); | |||
| 563 | mh.msg_iov = &iov; | |||
| 564 | mh.msg_iovlen = 1; | |||
| 565 | mh.msg_control = &control; | |||
| 566 | mh.msg_controllen = sizeof(control); | |||
| 567 | ||||
| 568 | k = recvmsg(b->input_fd, &mh, MSG_DONTWAITMSG_DONTWAIT|MSG_CMSG_CLOEXECMSG_CMSG_CLOEXEC); | |||
| 569 | if (k < 0 && errno(*__errno_location ()) == ENOTSOCK88) { | |||
| 570 | b->prefer_readv = true1; | |||
| 571 | k = readv(b->input_fd, &iov, 1); | |||
| 572 | } else | |||
| 573 | handle_cmsg = true1; | |||
| 574 | } | |||
| 575 | if (k < 0) | |||
| 576 | return errno(*__errno_location ()) == EAGAIN11 ? 0 : -errno(*__errno_location ()); | |||
| 577 | if (k == 0) | |||
| 578 | return -ECONNRESET104; | |||
| 579 | ||||
| 580 | b->rbuffer_size += k; | |||
| 581 | ||||
| 582 | if (handle_cmsg) { | |||
| 583 | struct cmsghdr *cmsg; | |||
| 584 | ||||
| 585 | CMSG_FOREACH(cmsg, &mh)for ((cmsg) = ((size_t) (&mh)->msg_controllen >= sizeof (struct cmsghdr) ? (struct cmsghdr *) (&mh)->msg_control : (struct cmsghdr *) 0); (cmsg); (cmsg) = __cmsg_nxthdr ((& mh), (cmsg))) | |||
| 586 | if (cmsg->cmsg_level == SOL_SOCKET1 && | |||
| 587 | cmsg->cmsg_type == SCM_RIGHTSSCM_RIGHTS) { | |||
| 588 | int j; | |||
| 589 | ||||
| 590 | /* Whut? We received fds during the auth | |||
| 591 | * protocol? Somebody is playing games with | |||
| 592 | * us. Close them all, and fail */ | |||
| 593 | j = (cmsg->cmsg_len - CMSG_LEN(0)((((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t ) ~(sizeof (size_t) - 1)) + (0))) / sizeof(int); | |||
| 594 | close_many((int*) CMSG_DATA(cmsg)((cmsg)->__cmsg_data), j); | |||
| 595 | return -EIO5; | |||
| 596 | } else | |||
| 597 | log_debug("Got unexpected auxiliary data with level=%d and type=%d",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-bus/bus-socket.c", 598, __func__, "Got unexpected auxiliary data with level=%d and type=%d" , cmsg->cmsg_level, cmsg->cmsg_type) : -abs(_e); }) | |||
| 598 | cmsg->cmsg_level, cmsg->cmsg_type)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-bus/bus-socket.c", 598, __func__, "Got unexpected auxiliary data with level=%d and type=%d" , cmsg->cmsg_level, cmsg->cmsg_type) : -abs(_e); }); | |||
| 599 | } | |||
| 600 | ||||
| 601 | r = bus_socket_auth_verify(b); | |||
| 602 | if (r != 0) | |||
| 603 | return r; | |||
| 604 | ||||
| 605 | return 1; | |||
| 606 | } | |||
| 607 | ||||
| 608 | void bus_socket_setup(sd_bus *b) { | |||
| 609 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 609, __PRETTY_FUNCTION__); } while (0); | |||
| 610 | ||||
| 611 | /* Increase the buffers to 8 MB */ | |||
| 612 | (void) fd_inc_rcvbuf(b->input_fd, SNDBUF_SIZE(8*1024*1024)); | |||
| 613 | (void) fd_inc_sndbuf(b->output_fd, SNDBUF_SIZE(8*1024*1024)); | |||
| 614 | ||||
| 615 | b->message_version = 1; | |||
| 616 | b->message_endian = 0; | |||
| 617 | } | |||
| 618 | ||||
| 619 | static void bus_get_peercred(sd_bus *b) { | |||
| 620 | int r; | |||
| 621 | ||||
| 622 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 622, __PRETTY_FUNCTION__); } while (0); | |||
| 623 | assert(!b->ucred_valid)do { if ((__builtin_expect(!!(!(!b->ucred_valid)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("!b->ucred_valid"), "../src/libsystemd/sd-bus/bus-socket.c" , 623, __PRETTY_FUNCTION__); } while (0); | |||
| 624 | assert(!b->label)do { if ((__builtin_expect(!!(!(!b->label)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("!b->label"), "../src/libsystemd/sd-bus/bus-socket.c" , 624, __PRETTY_FUNCTION__); } while (0); | |||
| 625 | assert(b->n_groups == (size_t) -1)do { if ((__builtin_expect(!!(!(b->n_groups == (size_t) -1 )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("b->n_groups == (size_t) -1" ), "../src/libsystemd/sd-bus/bus-socket.c", 625, __PRETTY_FUNCTION__ ); } while (0); | |||
| 626 | ||||
| 627 | /* Get the peer for socketpair() sockets */ | |||
| 628 | b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0; | |||
| 629 | ||||
| 630 | /* Get the SELinux context of the peer */ | |||
| 631 | r = getpeersec(b->input_fd, &b->label); | |||
| 632 | if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENOPROTOOPT)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-95, -92})/sizeof(int)]; switch(r) { case -95: case -92: _found = 1; break; default: break; } _found; } )) | |||
| 633 | log_debug_errno(r, "Failed to determine peer security context: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-bus/bus-socket.c", 633, __func__, "Failed to determine peer security context: %m" ) : -abs(_e); }); | |||
| 634 | ||||
| 635 | /* Get the list of auxiliary groups of the peer */ | |||
| 636 | r = getpeergroups(b->input_fd, &b->groups); | |||
| 637 | if (r >= 0) | |||
| 638 | b->n_groups = (size_t) r; | |||
| 639 | else if (!IN_SET(r, -EOPNOTSUPP, -ENOPROTOOPT)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-95, -92})/sizeof(int)]; switch(r) { case -95: case -92: _found = 1; break; default: break; } _found; } )) | |||
| 640 | log_debug_errno(r, "Failed to determine peer's group list: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-bus/bus-socket.c", 640, __func__, "Failed to determine peer's group list: %m" ) : -abs(_e); }); | |||
| 641 | } | |||
| 642 | ||||
| 643 | static int bus_socket_start_auth_client(sd_bus *b) { | |||
| 644 | static const char sasl_auth_anonymous[] = { | |||
| 645 | /* | |||
| 646 | * We use an arbitrary trace-string for the ANONYMOUS authentication. It can be used by the | |||
| 647 | * message broker to aid debugging of clients. We fully anonymize the connection and use a | |||
| 648 | * static default. | |||
| 649 | */ | |||
| 650 | "\0AUTH ANONYMOUS\r\n" | |||
| 651 | /* HEX a n o n y m o u s */ | |||
| 652 | "DATA 616e6f6e796d6f7573\r\n" | |||
| 653 | }; | |||
| 654 | static const char sasl_auth_external[] = { | |||
| 655 | "\0AUTH EXTERNAL\r\n" | |||
| 656 | "DATA\r\n" | |||
| 657 | }; | |||
| 658 | static const char sasl_negotiate_unix_fd[] = { | |||
| 659 | "NEGOTIATE_UNIX_FD\r\n" | |||
| 660 | }; | |||
| 661 | static const char sasl_begin[] = { | |||
| 662 | "BEGIN\r\n" | |||
| 663 | }; | |||
| 664 | size_t i = 0; | |||
| 665 | ||||
| 666 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 666, __PRETTY_FUNCTION__); } while (0); | |||
| 667 | ||||
| 668 | if (b->anonymous_auth) | |||
| 669 | b->auth_iovec[i++] = IOVEC_MAKE((char*) sasl_auth_anonymous, sizeof(sasl_auth_anonymous) - 1)(struct iovec) { .iov_base = ((char*) sasl_auth_anonymous), . iov_len = (sizeof(sasl_auth_anonymous) - 1) }; | |||
| 670 | else | |||
| 671 | b->auth_iovec[i++] = IOVEC_MAKE((char*) sasl_auth_external, sizeof(sasl_auth_external) - 1)(struct iovec) { .iov_base = ((char*) sasl_auth_external), .iov_len = (sizeof(sasl_auth_external) - 1) }; | |||
| 672 | ||||
| 673 | if (b->accept_fd) | |||
| 674 | b->auth_iovec[i++] = IOVEC_MAKE_STRING(sasl_negotiate_unix_fd)(struct iovec) { .iov_base = ((char*) sasl_negotiate_unix_fd) , .iov_len = (strlen(sasl_negotiate_unix_fd)) }; | |||
| 675 | ||||
| 676 | b->auth_iovec[i++] = IOVEC_MAKE_STRING(sasl_begin)(struct iovec) { .iov_base = ((char*) sasl_begin), .iov_len = (strlen(sasl_begin)) }; | |||
| 677 | ||||
| 678 | return bus_socket_write_auth(b); | |||
| 679 | } | |||
| 680 | ||||
| 681 | int bus_socket_start_auth(sd_bus *b) { | |||
| 682 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 682, __PRETTY_FUNCTION__); } while (0); | |||
| 683 | ||||
| 684 | bus_get_peercred(b); | |||
| 685 | ||||
| 686 | bus_set_state(b, BUS_AUTHENTICATING); | |||
| 687 | b->auth_timeout = now(CLOCK_MONOTONIC1) + BUS_AUTH_TIMEOUT((usec_t) (90*((usec_t) 1000000ULL))); | |||
| 688 | ||||
| 689 | if (sd_is_socket(b->input_fd, AF_UNIX1, 0, 0) <= 0) | |||
| 690 | b->accept_fd = false0; | |||
| 691 | ||||
| 692 | if (b->output_fd != b->input_fd) | |||
| 693 | if (sd_is_socket(b->output_fd, AF_UNIX1, 0, 0) <= 0) | |||
| 694 | b->accept_fd = false0; | |||
| 695 | ||||
| 696 | if (b->is_server) | |||
| 697 | return bus_socket_read_auth(b); | |||
| 698 | else | |||
| 699 | return bus_socket_start_auth_client(b); | |||
| 700 | } | |||
| 701 | ||||
| 702 | static int bus_socket_inotify_setup(sd_bus *b) { | |||
| 703 | _cleanup_free___attribute__((cleanup(freep))) int *new_watches = NULL((void*)0); | |||
| 704 | _cleanup_free___attribute__((cleanup(freep))) char *absolute = NULL((void*)0); | |||
| 705 | size_t n_allocated = 0, n = 0, done = 0, i; | |||
| 706 | unsigned max_follow = 32; | |||
| 707 | const char *p; | |||
| 708 | int wd, r; | |||
| 709 | ||||
| 710 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 710, __PRETTY_FUNCTION__); } while (0); | |||
| 711 | assert(b->watch_bind)do { if ((__builtin_expect(!!(!(b->watch_bind)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b->watch_bind"), "../src/libsystemd/sd-bus/bus-socket.c" , 711, __PRETTY_FUNCTION__); } while (0); | |||
| 712 | assert(b->sockaddr.sa.sa_family == AF_UNIX)do { if ((__builtin_expect(!!(!(b->sockaddr.sa.sa_family == 1)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("b->sockaddr.sa.sa_family == AF_UNIX" ), "../src/libsystemd/sd-bus/bus-socket.c", 712, __PRETTY_FUNCTION__ ); } while (0); | |||
| 713 | assert(b->sockaddr.un.sun_path[0] != 0)do { if ((__builtin_expect(!!(!(b->sockaddr.un.sun_path[0] != 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("b->sockaddr.un.sun_path[0] != 0" ), "../src/libsystemd/sd-bus/bus-socket.c", 713, __PRETTY_FUNCTION__ ); } while (0); | |||
| 714 | ||||
| 715 | /* Sets up an inotify fd in case watch_bind is enabled: wait until the configured AF_UNIX file system socket | |||
| 716 | * appears before connecting to it. The implemented is pretty simplistic: we just subscribe to relevant changes | |||
| 717 | * to all prefix components of the path, and every time we get an event for that we try to reconnect again, | |||
| 718 | * without actually caring what precisely the event we got told us. If we still can't connect we re-subscribe | |||
| 719 | * to all relevant changes of anything in the path, so that our watches include any possibly newly created path | |||
| 720 | * components. */ | |||
| 721 | ||||
| 722 | if (b->inotify_fd < 0) { | |||
| 723 | b->inotify_fd = inotify_init1(IN_NONBLOCKIN_NONBLOCK|IN_CLOEXECIN_CLOEXEC); | |||
| 724 | if (b->inotify_fd < 0) | |||
| 725 | return -errno(*__errno_location ()); | |||
| 726 | ||||
| 727 | b->inotify_fd = fd_move_above_stdio(b->inotify_fd); | |||
| 728 | } | |||
| 729 | ||||
| 730 | /* Make sure the path is NUL terminated */ | |||
| 731 | p = strndupa(b->sockaddr.un.sun_path, sizeof(b->sockaddr.un.sun_path))(__extension__ ({ const char *__old = (b->sockaddr.un.sun_path ); size_t __len = strnlen (__old, (sizeof(b->sockaddr.un.sun_path ))); char *__new = (char *) __builtin_alloca (__len + 1); __new [__len] = '\0'; (char *) memcpy (__new, __old, __len); })); | |||
| 732 | ||||
| 733 | /* Make sure the path is absolute */ | |||
| 734 | r = path_make_absolute_cwd(p, &absolute); | |||
| 735 | if (r < 0) | |||
| 736 | goto fail; | |||
| 737 | ||||
| 738 | /* Watch all parent directories, and don't mind any prefix that doesn't exist yet. For the innermost directory | |||
| 739 | * that exists we want to know when files are created or moved into it. For all parents of it we just care if | |||
| 740 | * they are removed or renamed. */ | |||
| 741 | ||||
| 742 | if (!GREEDY_REALLOC(new_watches, n_allocated, n + 1)greedy_realloc((void**) &(new_watches), &(n_allocated ), (n + 1), sizeof((new_watches)[0]))) { | |||
| 743 | r = -ENOMEM12; | |||
| 744 | goto fail; | |||
| 745 | } | |||
| 746 | ||||
| 747 | /* Start with the top-level directory, which is a bit simpler than the rest, since it can't be a symlink, and | |||
| 748 | * always exists */ | |||
| 749 | wd = inotify_add_watch(b->inotify_fd, "/", IN_CREATE0x00000100|IN_MOVED_TO0x00000080); | |||
| 750 | if (wd < 0) { | |||
| 751 | r = log_debug_errno(errno, "Failed to add inotify watch on /: %m")({ int _level = ((7)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/libsystemd/sd-bus/bus-socket.c", 751, __func__, "Failed to add inotify watch on /: %m") : -abs (_e); }); | |||
| 752 | goto fail; | |||
| 753 | } else | |||
| 754 | new_watches[n++] = wd; | |||
| 755 | ||||
| 756 | for (;;) { | |||
| 757 | _cleanup_free___attribute__((cleanup(freep))) char *component = NULL((void*)0), *prefix = NULL((void*)0), *destination = NULL((void*)0); | |||
| 758 | size_t n_slashes, n_component; | |||
| 759 | char *c = NULL((void*)0); | |||
| 760 | ||||
| 761 | n_slashes = strspn(absolute + done, "/"); | |||
| 762 | n_component = n_slashes + strcspn(absolute + done + n_slashes, "/"); | |||
| 763 | ||||
| 764 | if (n_component == 0) /* The end */ | |||
| 765 | break; | |||
| 766 | ||||
| 767 | component = strndup(absolute + done, n_component); | |||
| 768 | if (!component) { | |||
| 769 | r = -ENOMEM12; | |||
| 770 | goto fail; | |||
| 771 | } | |||
| 772 | ||||
| 773 | /* A trailing slash? That's a directory, and not a socket then */ | |||
| 774 | if (path_equal(component, "/")) { | |||
| 775 | r = -EISDIR21; | |||
| 776 | goto fail; | |||
| 777 | } | |||
| 778 | ||||
| 779 | /* A single dot? Let's eat this up */ | |||
| 780 | if (path_equal(component, "/.")) { | |||
| 781 | done += n_component; | |||
| 782 | continue; | |||
| 783 | } | |||
| 784 | ||||
| 785 | prefix = strndup(absolute, done + n_component); | |||
| 786 | if (!prefix) { | |||
| 787 | r = -ENOMEM12; | |||
| 788 | goto fail; | |||
| 789 | } | |||
| 790 | ||||
| 791 | if (!GREEDY_REALLOC(new_watches, n_allocated, n + 1)greedy_realloc((void**) &(new_watches), &(n_allocated ), (n + 1), sizeof((new_watches)[0]))) { | |||
| 792 | r = -ENOMEM12; | |||
| ||||
| 793 | goto fail; | |||
| 794 | } | |||
| 795 | ||||
| 796 | wd = inotify_add_watch(b->inotify_fd, prefix, IN_DELETE_SELF0x00000400|IN_MOVE_SELF0x00000800|IN_ATTRIB0x00000004|IN_CREATE0x00000100|IN_MOVED_TO0x00000080|IN_DONT_FOLLOW0x02000000); | |||
| 797 | log_debug("Added inotify watch for %s on bus %s: %i", prefix, strna(b->description), wd)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-bus/bus-socket.c", 797, __func__, "Added inotify watch for %s on bus %s: %i" , prefix, strna(b->description), wd) : -abs(_e); }); | |||
| 798 | ||||
| 799 | if (wd < 0) { | |||
| 800 | if (IN_SET(errno, ENOENT, ELOOP)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){2, 40})/sizeof(int)]; switch((*__errno_location ())) { case 2: case 40: _found = 1; break; default: break; } _found; })) | |||
| 801 | break; /* This component doesn't exist yet, or the path contains a cyclic symlink right now */ | |||
| 802 | ||||
| 803 | r = log_debug_errno(errno, "Failed to add inotify watch on %s: %m", empty_to_root(prefix))({ int _level = ((7)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/libsystemd/sd-bus/bus-socket.c", 803, __func__, "Failed to add inotify watch on %s: %m", empty_to_root (prefix)) : -abs(_e); }); | |||
| 804 | goto fail; | |||
| 805 | } else | |||
| 806 | new_watches[n++] = wd; | |||
| 807 | ||||
| 808 | /* Check if this is possibly a symlink. If so, let's follow it and watch it too. */ | |||
| 809 | r = readlink_malloc(prefix, &destination); | |||
| 810 | if (r == -EINVAL22) { /* not a symlink */ | |||
| 811 | done += n_component; | |||
| 812 | continue; | |||
| 813 | } | |||
| 814 | if (r < 0) | |||
| 815 | goto fail; | |||
| 816 | ||||
| 817 | if (isempty(destination)) { /* Empty symlink target? Yuck! */ | |||
| 818 | r = -EINVAL22; | |||
| 819 | goto fail; | |||
| 820 | } | |||
| 821 | ||||
| 822 | if (max_follow <= 0) { /* Let's make sure we don't follow symlinks forever */ | |||
| 823 | r = -ELOOP40; | |||
| 824 | goto fail; | |||
| 825 | } | |||
| 826 | ||||
| 827 | if (path_is_absolute(destination)) { | |||
| 828 | /* For absolute symlinks we build the new path and start anew */ | |||
| 829 | c = strjoin(destination, absolute + done + n_component)strjoin_real((destination), absolute + done + n_component, (( void*)0)); | |||
| 830 | done = 0; | |||
| 831 | } else { | |||
| 832 | _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0); | |||
| 833 | ||||
| 834 | /* For relative symlinks we replace the last component, and try again */ | |||
| 835 | t = strndup(absolute, done); | |||
| 836 | if (!t) | |||
| 837 | return -ENOMEM12; | |||
| 838 | ||||
| 839 | c = strjoin(t, "/", destination, absolute + done + n_component)strjoin_real((t), "/", destination, absolute + done + n_component , ((void*)0)); | |||
| 840 | } | |||
| 841 | if (!c) { | |||
| 842 | r = -ENOMEM12; | |||
| 843 | goto fail; | |||
| 844 | } | |||
| 845 | ||||
| 846 | free(absolute); | |||
| 847 | absolute = c; | |||
| 848 | ||||
| 849 | max_follow--; | |||
| 850 | } | |||
| 851 | ||||
| 852 | /* And now, let's remove all watches from the previous iteration we don't need anymore */ | |||
| 853 | for (i = 0; i < b->n_inotify_watches; i++) { | |||
| 854 | bool_Bool found = false0; | |||
| 855 | size_t j; | |||
| 856 | ||||
| 857 | for (j = 0; j < n; j++) | |||
| 858 | if (new_watches[j] == b->inotify_watches[i]) { | |||
| 859 | found = true1; | |||
| 860 | break; | |||
| 861 | } | |||
| 862 | ||||
| 863 | if (found) | |||
| 864 | continue; | |||
| 865 | ||||
| 866 | (void) inotify_rm_watch(b->inotify_fd, b->inotify_watches[i]); | |||
| 867 | } | |||
| 868 | ||||
| 869 | free_and_replace(b->inotify_watches, new_watches)({ free(b->inotify_watches); (b->inotify_watches) = (new_watches ); (new_watches) = ((void*)0); 0; }); | |||
| 870 | b->n_inotify_watches = n; | |||
| 871 | ||||
| 872 | return 0; | |||
| 873 | ||||
| 874 | fail: | |||
| 875 | bus_close_inotify_fd(b); | |||
| 876 | return r; | |||
| 877 | } | |||
| 878 | ||||
| 879 | int bus_socket_connect(sd_bus *b) { | |||
| 880 | bool_Bool inotify_done = false0; | |||
| 881 | int r; | |||
| 882 | ||||
| 883 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 883, __PRETTY_FUNCTION__); } while (0); | |||
| 884 | ||||
| 885 | for (;;) { | |||
| 886 | assert(b->input_fd < 0)do { if ((__builtin_expect(!!(!(b->input_fd < 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b->input_fd < 0"), "../src/libsystemd/sd-bus/bus-socket.c" , 886, __PRETTY_FUNCTION__); } while (0); | |||
| 887 | assert(b->output_fd < 0)do { if ((__builtin_expect(!!(!(b->output_fd < 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("b->output_fd < 0" ), "../src/libsystemd/sd-bus/bus-socket.c", 887, __PRETTY_FUNCTION__ ); } while (0); | |||
| 888 | assert(b->sockaddr.sa.sa_family != AF_UNSPEC)do { if ((__builtin_expect(!!(!(b->sockaddr.sa.sa_family != 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("b->sockaddr.sa.sa_family != AF_UNSPEC" ), "../src/libsystemd/sd-bus/bus-socket.c", 888, __PRETTY_FUNCTION__ ); } while (0); | |||
| 889 | ||||
| 890 | b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAMSOCK_STREAM|SOCK_CLOEXECSOCK_CLOEXEC|SOCK_NONBLOCKSOCK_NONBLOCK, 0); | |||
| 891 | if (b->input_fd < 0) | |||
| 892 | return -errno(*__errno_location ()); | |||
| 893 | ||||
| 894 | b->input_fd = fd_move_above_stdio(b->input_fd); | |||
| 895 | ||||
| 896 | b->output_fd = b->input_fd; | |||
| 897 | bus_socket_setup(b); | |||
| 898 | ||||
| 899 | if (connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size) < 0) { | |||
| 900 | if (errno(*__errno_location ()) == EINPROGRESS115) { | |||
| 901 | ||||
| 902 | /* If we have any inotify watches open, close them now, we don't need them anymore, as | |||
| 903 | * we have successfully initiated a connection */ | |||
| 904 | bus_close_inotify_fd(b); | |||
| 905 | ||||
| 906 | /* Note that very likely we are already in BUS_OPENING state here, as we enter it when | |||
| 907 | * we start parsing the address string. The only reason we set the state explicitly | |||
| 908 | * here, is to undo BUS_WATCH_BIND, in case we did the inotify magic. */ | |||
| 909 | bus_set_state(b, BUS_OPENING); | |||
| 910 | return 1; | |||
| 911 | } | |||
| 912 | ||||
| 913 | if (IN_SET(errno, ENOENT, ECONNREFUSED)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){2, 111})/sizeof(int)]; switch((*__errno_location ())) { case 2: case 111: _found = 1; break; default: break; } _found; }) && /* ENOENT → unix socket doesn't exist at all; ECONNREFUSED → unix socket stale */ | |||
| 914 | b->watch_bind && | |||
| 915 | b->sockaddr.sa.sa_family == AF_UNIX1 && | |||
| 916 | b->sockaddr.un.sun_path[0] != 0) { | |||
| 917 | ||||
| 918 | /* This connection attempt failed, let's release the socket for now, and start with a | |||
| 919 | * fresh one when reconnecting. */ | |||
| 920 | bus_close_io_fds(b); | |||
| 921 | ||||
| 922 | if (inotify_done
| |||
| 923 | /* inotify set up already, don't do it again, just return now, and remember | |||
| 924 | * that we are waiting for inotify events now. */ | |||
| 925 | bus_set_state(b, BUS_WATCH_BIND); | |||
| 926 | return 1; | |||
| 927 | } | |||
| 928 | ||||
| 929 | /* This is a file system socket, and the inotify logic is enabled. Let's create the necessary inotify fd. */ | |||
| 930 | r = bus_socket_inotify_setup(b); | |||
| 931 | if (r < 0) | |||
| 932 | return r; | |||
| 933 | ||||
| 934 | /* Let's now try to connect a second time, because in theory there's otherwise a race | |||
| 935 | * here: the socket might have been created in the time between our first connect() and | |||
| 936 | * the time we set up the inotify logic. But let's remember that we set up inotify now, | |||
| 937 | * so that we don't do the connect() more than twice. */ | |||
| 938 | inotify_done = true1; | |||
| 939 | ||||
| 940 | } else | |||
| 941 | return -errno(*__errno_location ()); | |||
| 942 | } else | |||
| 943 | break; | |||
| 944 | } | |||
| 945 | ||||
| 946 | /* Yay, established, we don't need no inotify anymore! */ | |||
| 947 | bus_close_inotify_fd(b); | |||
| 948 | ||||
| 949 | return bus_socket_start_auth(b); | |||
| 950 | } | |||
| 951 | ||||
| 952 | int bus_socket_exec(sd_bus *b) { | |||
| 953 | int s[2], r; | |||
| 954 | ||||
| 955 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 955, __PRETTY_FUNCTION__); } while (0); | |||
| 956 | assert(b->input_fd < 0)do { if ((__builtin_expect(!!(!(b->input_fd < 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b->input_fd < 0"), "../src/libsystemd/sd-bus/bus-socket.c" , 956, __PRETTY_FUNCTION__); } while (0); | |||
| 957 | assert(b->output_fd < 0)do { if ((__builtin_expect(!!(!(b->output_fd < 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("b->output_fd < 0" ), "../src/libsystemd/sd-bus/bus-socket.c", 957, __PRETTY_FUNCTION__ ); } while (0); | |||
| 958 | assert(b->exec_path)do { if ((__builtin_expect(!!(!(b->exec_path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b->exec_path"), "../src/libsystemd/sd-bus/bus-socket.c" , 958, __PRETTY_FUNCTION__); } while (0); | |||
| 959 | assert(b->busexec_pid == 0)do { if ((__builtin_expect(!!(!(b->busexec_pid == 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("b->busexec_pid == 0" ), "../src/libsystemd/sd-bus/bus-socket.c", 959, __PRETTY_FUNCTION__ ); } while (0); | |||
| 960 | ||||
| 961 | r = socketpair(AF_UNIX1, SOCK_STREAMSOCK_STREAM|SOCK_NONBLOCKSOCK_NONBLOCK|SOCK_CLOEXECSOCK_CLOEXEC, 0, s); | |||
| 962 | if (r < 0) | |||
| 963 | return -errno(*__errno_location ()); | |||
| 964 | ||||
| 965 | r = safe_fork_full("(sd-busexec)", s+1, 1, FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &b->busexec_pid); | |||
| 966 | if (r < 0) { | |||
| 967 | safe_close_pair(s); | |||
| 968 | return r; | |||
| 969 | } | |||
| 970 | if (r == 0) { | |||
| 971 | /* Child */ | |||
| 972 | ||||
| 973 | if (rearrange_stdio(s[1], s[1], STDERR_FILENO2) < 0) | |||
| 974 | _exit(EXIT_FAILURE1); | |||
| 975 | ||||
| 976 | if (b->exec_argv) | |||
| 977 | execvp(b->exec_path, b->exec_argv); | |||
| 978 | else { | |||
| 979 | const char *argv[] = { b->exec_path, NULL((void*)0) }; | |||
| 980 | execvp(b->exec_path, (char**) argv); | |||
| 981 | } | |||
| 982 | ||||
| 983 | _exit(EXIT_FAILURE1); | |||
| 984 | } | |||
| 985 | ||||
| 986 | safe_close(s[1]); | |||
| 987 | b->output_fd = b->input_fd = fd_move_above_stdio(s[0]); | |||
| 988 | ||||
| 989 | bus_socket_setup(b); | |||
| 990 | ||||
| 991 | return bus_socket_start_auth(b); | |||
| 992 | } | |||
| 993 | ||||
| 994 | int bus_socket_take_fd(sd_bus *b) { | |||
| 995 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 995, __PRETTY_FUNCTION__); } while (0); | |||
| 996 | ||||
| 997 | bus_socket_setup(b); | |||
| 998 | ||||
| 999 | return bus_socket_start_auth(b); | |||
| 1000 | } | |||
| 1001 | ||||
| 1002 | int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) { | |||
| 1003 | struct iovec *iov; | |||
| 1004 | ssize_t k; | |||
| 1005 | size_t n; | |||
| 1006 | unsigned j; | |||
| 1007 | int r; | |||
| 1008 | ||||
| 1009 | assert(bus)do { if ((__builtin_expect(!!(!(bus)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("bus"), "../src/libsystemd/sd-bus/bus-socket.c" , 1009, __PRETTY_FUNCTION__); } while (0); | |||
| 1010 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/libsystemd/sd-bus/bus-socket.c" , 1010, __PRETTY_FUNCTION__); } while (0); | |||
| 1011 | assert(idx)do { if ((__builtin_expect(!!(!(idx)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("idx"), "../src/libsystemd/sd-bus/bus-socket.c" , 1011, __PRETTY_FUNCTION__); } while (0); | |||
| 1012 | assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){BUS_RUNNING, BUS_HELLO})/sizeof(int)]; switch (bus->state) { case BUS_RUNNING: case BUS_HELLO: _found = 1 ; break; default: break; } _found; }))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)" ), "../src/libsystemd/sd-bus/bus-socket.c", 1012, __PRETTY_FUNCTION__ ); } while (0); | |||
| 1013 | ||||
| 1014 | if (*idx >= BUS_MESSAGE_SIZE(m)) | |||
| 1015 | return 0; | |||
| 1016 | ||||
| 1017 | r = bus_message_setup_iovec(m); | |||
| 1018 | if (r < 0) | |||
| 1019 | return r; | |||
| 1020 | ||||
| 1021 | n = m->n_iovec * sizeof(struct iovec); | |||
| 1022 | iov = alloca(n)__builtin_alloca (n); | |||
| 1023 | memcpy_safe(iov, m->iovec, n); | |||
| 1024 | ||||
| 1025 | j = 0; | |||
| 1026 | iovec_advance(iov, &j, *idx); | |||
| 1027 | ||||
| 1028 | if (bus->prefer_writev) | |||
| 1029 | k = writev(bus->output_fd, iov, m->n_iovec); | |||
| 1030 | else { | |||
| 1031 | struct msghdr mh = { | |||
| 1032 | .msg_iov = iov, | |||
| 1033 | .msg_iovlen = m->n_iovec, | |||
| 1034 | }; | |||
| 1035 | ||||
| 1036 | if (m->n_fds > 0 && *idx == 0) { | |||
| 1037 | struct cmsghdr *control; | |||
| 1038 | ||||
| 1039 | mh.msg_control = control = alloca(CMSG_SPACE(sizeof(int) * m->n_fds))__builtin_alloca (((((sizeof(int) * m->n_fds) + sizeof (size_t ) - 1) & (size_t) ~(sizeof (size_t) - 1)) + (((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t ) - 1)))); | |||
| 1040 | mh.msg_controllen = control->cmsg_len = CMSG_LEN(sizeof(int) * m->n_fds)((((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t ) ~(sizeof (size_t) - 1)) + (sizeof(int) * m->n_fds)); | |||
| 1041 | control->cmsg_level = SOL_SOCKET1; | |||
| 1042 | control->cmsg_type = SCM_RIGHTSSCM_RIGHTS; | |||
| 1043 | memcpy(CMSG_DATA(control)((control)->__cmsg_data), m->fds, sizeof(int) * m->n_fds); | |||
| 1044 | } | |||
| 1045 | ||||
| 1046 | k = sendmsg(bus->output_fd, &mh, MSG_DONTWAITMSG_DONTWAIT|MSG_NOSIGNALMSG_NOSIGNAL); | |||
| 1047 | if (k < 0 && errno(*__errno_location ()) == ENOTSOCK88) { | |||
| 1048 | bus->prefer_writev = true1; | |||
| 1049 | k = writev(bus->output_fd, iov, m->n_iovec); | |||
| 1050 | } | |||
| 1051 | } | |||
| 1052 | ||||
| 1053 | if (k < 0) | |||
| 1054 | return errno(*__errno_location ()) == EAGAIN11 ? 0 : -errno(*__errno_location ()); | |||
| 1055 | ||||
| 1056 | *idx += (size_t) k; | |||
| 1057 | return 1; | |||
| 1058 | } | |||
| 1059 | ||||
| 1060 | static int bus_socket_read_message_need(sd_bus *bus, size_t *need) { | |||
| 1061 | uint32_t a, b; | |||
| 1062 | uint8_t e; | |||
| 1063 | uint64_t sum; | |||
| 1064 | ||||
| 1065 | assert(bus)do { if ((__builtin_expect(!!(!(bus)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("bus"), "../src/libsystemd/sd-bus/bus-socket.c" , 1065, __PRETTY_FUNCTION__); } while (0); | |||
| 1066 | assert(need)do { if ((__builtin_expect(!!(!(need)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("need"), "../src/libsystemd/sd-bus/bus-socket.c" , 1066, __PRETTY_FUNCTION__); } while (0); | |||
| 1067 | assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){BUS_RUNNING, BUS_HELLO})/sizeof(int)]; switch (bus->state) { case BUS_RUNNING: case BUS_HELLO: _found = 1 ; break; default: break; } _found; }))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)" ), "../src/libsystemd/sd-bus/bus-socket.c", 1067, __PRETTY_FUNCTION__ ); } while (0); | |||
| 1068 | ||||
| 1069 | if (bus->rbuffer_size < sizeof(struct bus_header)) { | |||
| 1070 | *need = sizeof(struct bus_header) + 8; | |||
| 1071 | ||||
| 1072 | /* Minimum message size: | |||
| 1073 | * | |||
| 1074 | * Header + | |||
| 1075 | * | |||
| 1076 | * Method Call: +2 string headers | |||
| 1077 | * Signal: +3 string headers | |||
| 1078 | * Method Error: +1 string headers | |||
| 1079 | * +1 uint32 headers | |||
| 1080 | * Method Reply: +1 uint32 headers | |||
| 1081 | * | |||
| 1082 | * A string header is at least 9 bytes | |||
| 1083 | * A uint32 header is at least 8 bytes | |||
| 1084 | * | |||
| 1085 | * Hence the minimum message size of a valid message | |||
| 1086 | * is header + 8 bytes */ | |||
| 1087 | ||||
| 1088 | return 0; | |||
| 1089 | } | |||
| 1090 | ||||
| 1091 | a = ((const uint32_t*) bus->rbuffer)[1]; | |||
| 1092 | b = ((const uint32_t*) bus->rbuffer)[3]; | |||
| 1093 | ||||
| 1094 | e = ((const uint8_t*) bus->rbuffer)[0]; | |||
| 1095 | if (e == BUS_LITTLE_ENDIAN) { | |||
| 1096 | a = le32toh(a)__uint32_identity (a); | |||
| 1097 | b = le32toh(b)__uint32_identity (b); | |||
| 1098 | } else if (e == BUS_BIG_ENDIAN) { | |||
| 1099 | a = be32toh(a)__bswap_32 (a); | |||
| 1100 | b = be32toh(b)__bswap_32 (b); | |||
| 1101 | } else | |||
| 1102 | return -EBADMSG74; | |||
| 1103 | ||||
| 1104 | sum = (uint64_t) sizeof(struct bus_header) + (uint64_t) ALIGN_TO(b, 8) + (uint64_t) a; | |||
| 1105 | if (sum >= BUS_MESSAGE_SIZE_MAX(128*1024*1024)) | |||
| 1106 | return -ENOBUFS105; | |||
| 1107 | ||||
| 1108 | *need = (size_t) sum; | |||
| 1109 | return 0; | |||
| 1110 | } | |||
| 1111 | ||||
| 1112 | static int bus_socket_make_message(sd_bus *bus, size_t size) { | |||
| 1113 | sd_bus_message *t = NULL((void*)0); | |||
| 1114 | void *b; | |||
| 1115 | int r; | |||
| 1116 | ||||
| 1117 | assert(bus)do { if ((__builtin_expect(!!(!(bus)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("bus"), "../src/libsystemd/sd-bus/bus-socket.c" , 1117, __PRETTY_FUNCTION__); } while (0); | |||
| 1118 | assert(bus->rbuffer_size >= size)do { if ((__builtin_expect(!!(!(bus->rbuffer_size >= size )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("bus->rbuffer_size >= size" ), "../src/libsystemd/sd-bus/bus-socket.c", 1118, __PRETTY_FUNCTION__ ); } while (0); | |||
| 1119 | assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){BUS_RUNNING, BUS_HELLO})/sizeof(int)]; switch (bus->state) { case BUS_RUNNING: case BUS_HELLO: _found = 1 ; break; default: break; } _found; }))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)" ), "../src/libsystemd/sd-bus/bus-socket.c", 1119, __PRETTY_FUNCTION__ ); } while (0); | |||
| 1120 | ||||
| 1121 | r = bus_rqueue_make_room(bus); | |||
| 1122 | if (r < 0) | |||
| 1123 | return r; | |||
| 1124 | ||||
| 1125 | if (bus->rbuffer_size > size) { | |||
| 1126 | b = memdup((const uint8_t*) bus->rbuffer + size, | |||
| 1127 | bus->rbuffer_size - size); | |||
| 1128 | if (!b) | |||
| 1129 | return -ENOMEM12; | |||
| 1130 | } else | |||
| 1131 | b = NULL((void*)0); | |||
| 1132 | ||||
| 1133 | r = bus_message_from_malloc(bus, | |||
| 1134 | bus->rbuffer, size, | |||
| 1135 | bus->fds, bus->n_fds, | |||
| 1136 | NULL((void*)0), | |||
| 1137 | &t); | |||
| 1138 | if (r == -EBADMSG74) | |||
| 1139 | log_debug_errno(r, "Received invalid message from connection %s, dropping.", strna(bus->description))({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-bus/bus-socket.c", 1139, __func__, "Received invalid message from connection %s, dropping." , strna(bus->description)) : -abs(_e); }); | |||
| 1140 | else if (r < 0) { | |||
| 1141 | free(b); | |||
| 1142 | return r; | |||
| 1143 | } | |||
| 1144 | ||||
| 1145 | bus->rbuffer = b; | |||
| 1146 | bus->rbuffer_size -= size; | |||
| 1147 | ||||
| 1148 | bus->fds = NULL((void*)0); | |||
| 1149 | bus->n_fds = 0; | |||
| 1150 | ||||
| 1151 | if (t) { | |||
| 1152 | bus->rqueue[bus->rqueue_size++] = bus_message_ref_queued(t, bus); | |||
| 1153 | sd_bus_message_unref(t); | |||
| 1154 | } | |||
| 1155 | ||||
| 1156 | return 1; | |||
| 1157 | } | |||
| 1158 | ||||
| 1159 | int bus_socket_read_message(sd_bus *bus) { | |||
| 1160 | struct msghdr mh; | |||
| 1161 | struct iovec iov = {}; | |||
| 1162 | ssize_t k; | |||
| 1163 | size_t need; | |||
| 1164 | int r; | |||
| 1165 | void *b; | |||
| 1166 | union { | |||
| 1167 | struct cmsghdr cmsghdr; | |||
| 1168 | uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)((((sizeof(int) * 1024) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)) + (((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)))]; | |||
| 1169 | } control; | |||
| 1170 | bool_Bool handle_cmsg = false0; | |||
| 1171 | ||||
| 1172 | assert(bus)do { if ((__builtin_expect(!!(!(bus)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("bus"), "../src/libsystemd/sd-bus/bus-socket.c" , 1172, __PRETTY_FUNCTION__); } while (0); | |||
| 1173 | assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){BUS_RUNNING, BUS_HELLO})/sizeof(int)]; switch (bus->state) { case BUS_RUNNING: case BUS_HELLO: _found = 1 ; break; default: break; } _found; }))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)" ), "../src/libsystemd/sd-bus/bus-socket.c", 1173, __PRETTY_FUNCTION__ ); } while (0); | |||
| 1174 | ||||
| 1175 | r = bus_socket_read_message_need(bus, &need); | |||
| 1176 | if (r < 0) | |||
| 1177 | return r; | |||
| 1178 | ||||
| 1179 | if (bus->rbuffer_size >= need) | |||
| 1180 | return bus_socket_make_message(bus, need); | |||
| 1181 | ||||
| 1182 | b = realloc(bus->rbuffer, need); | |||
| 1183 | if (!b) | |||
| 1184 | return -ENOMEM12; | |||
| 1185 | ||||
| 1186 | bus->rbuffer = b; | |||
| 1187 | ||||
| 1188 | iov.iov_base = (uint8_t*) bus->rbuffer + bus->rbuffer_size; | |||
| 1189 | iov.iov_len = need - bus->rbuffer_size; | |||
| 1190 | ||||
| 1191 | if (bus->prefer_readv) | |||
| 1192 | k = readv(bus->input_fd, &iov, 1); | |||
| 1193 | else { | |||
| 1194 | zero(mh)(({ size_t _l_ = (sizeof(mh)); void *_x_ = (&(mh)); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); })); | |||
| 1195 | mh.msg_iov = &iov; | |||
| 1196 | mh.msg_iovlen = 1; | |||
| 1197 | mh.msg_control = &control; | |||
| 1198 | mh.msg_controllen = sizeof(control); | |||
| 1199 | ||||
| 1200 | k = recvmsg(bus->input_fd, &mh, MSG_DONTWAITMSG_DONTWAIT|MSG_CMSG_CLOEXECMSG_CMSG_CLOEXEC); | |||
| 1201 | if (k < 0 && errno(*__errno_location ()) == ENOTSOCK88) { | |||
| 1202 | bus->prefer_readv = true1; | |||
| 1203 | k = readv(bus->input_fd, &iov, 1); | |||
| 1204 | } else | |||
| 1205 | handle_cmsg = true1; | |||
| 1206 | } | |||
| 1207 | if (k < 0) | |||
| 1208 | return errno(*__errno_location ()) == EAGAIN11 ? 0 : -errno(*__errno_location ()); | |||
| 1209 | if (k == 0) | |||
| 1210 | return -ECONNRESET104; | |||
| 1211 | ||||
| 1212 | bus->rbuffer_size += k; | |||
| 1213 | ||||
| 1214 | if (handle_cmsg) { | |||
| 1215 | struct cmsghdr *cmsg; | |||
| 1216 | ||||
| 1217 | CMSG_FOREACH(cmsg, &mh)for ((cmsg) = ((size_t) (&mh)->msg_controllen >= sizeof (struct cmsghdr) ? (struct cmsghdr *) (&mh)->msg_control : (struct cmsghdr *) 0); (cmsg); (cmsg) = __cmsg_nxthdr ((& mh), (cmsg))) | |||
| 1218 | if (cmsg->cmsg_level == SOL_SOCKET1 && | |||
| 1219 | cmsg->cmsg_type == SCM_RIGHTSSCM_RIGHTS) { | |||
| 1220 | int n, *f, i; | |||
| 1221 | ||||
| 1222 | n = (cmsg->cmsg_len - CMSG_LEN(0)((((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t ) ~(sizeof (size_t) - 1)) + (0))) / sizeof(int); | |||
| 1223 | ||||
| 1224 | if (!bus->can_fds) { | |||
| 1225 | /* Whut? We received fds but this | |||
| 1226 | * isn't actually enabled? Close them, | |||
| 1227 | * and fail */ | |||
| 1228 | ||||
| 1229 | close_many((int*) CMSG_DATA(cmsg)((cmsg)->__cmsg_data), n); | |||
| 1230 | return -EIO5; | |||
| 1231 | } | |||
| 1232 | ||||
| 1233 | f = reallocarray(bus->fds, bus->n_fds + n, sizeof(int)); | |||
| 1234 | if (!f) { | |||
| 1235 | close_many((int*) CMSG_DATA(cmsg)((cmsg)->__cmsg_data), n); | |||
| 1236 | return -ENOMEM12; | |||
| 1237 | } | |||
| 1238 | ||||
| 1239 | for (i = 0; i < n; i++) | |||
| 1240 | f[bus->n_fds++] = fd_move_above_stdio(((int*) CMSG_DATA(cmsg)((cmsg)->__cmsg_data))[i]); | |||
| 1241 | bus->fds = f; | |||
| 1242 | } else | |||
| 1243 | log_debug("Got unexpected auxiliary data with level=%d and type=%d",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-bus/bus-socket.c", 1244, __func__, "Got unexpected auxiliary data with level=%d and type=%d" , cmsg->cmsg_level, cmsg->cmsg_type) : -abs(_e); }) | |||
| 1244 | cmsg->cmsg_level, cmsg->cmsg_type)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-bus/bus-socket.c", 1244, __func__, "Got unexpected auxiliary data with level=%d and type=%d" , cmsg->cmsg_level, cmsg->cmsg_type) : -abs(_e); }); | |||
| 1245 | } | |||
| 1246 | ||||
| 1247 | r = bus_socket_read_message_need(bus, &need); | |||
| 1248 | if (r < 0) | |||
| 1249 | return r; | |||
| 1250 | ||||
| 1251 | if (bus->rbuffer_size >= need) | |||
| 1252 | return bus_socket_make_message(bus, need); | |||
| 1253 | ||||
| 1254 | return 1; | |||
| 1255 | } | |||
| 1256 | ||||
| 1257 | int bus_socket_process_opening(sd_bus *b) { | |||
| 1258 | int error = 0; | |||
| 1259 | socklen_t slen = sizeof(error); | |||
| 1260 | struct pollfd p = { | |||
| 1261 | .fd = b->output_fd, | |||
| 1262 | .events = POLLOUT0x004, | |||
| 1263 | }; | |||
| 1264 | int r; | |||
| 1265 | ||||
| 1266 | assert(b->state == BUS_OPENING)do { if ((__builtin_expect(!!(!(b->state == BUS_OPENING)), 0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("b->state == BUS_OPENING" ), "../src/libsystemd/sd-bus/bus-socket.c", 1266, __PRETTY_FUNCTION__ ); } while (0); | |||
| 1267 | ||||
| 1268 | r = poll(&p, 1, 0); | |||
| 1269 | if (r < 0) | |||
| 1270 | return -errno(*__errno_location ()); | |||
| 1271 | ||||
| 1272 | if (!(p.revents & (POLLOUT0x004|POLLERR0x008|POLLHUP0x010))) | |||
| 1273 | return 0; | |||
| 1274 | ||||
| 1275 | r = getsockopt(b->output_fd, SOL_SOCKET1, SO_ERROR4, &error, &slen); | |||
| 1276 | if (r < 0) | |||
| 1277 | b->last_connect_error = errno(*__errno_location ()); | |||
| 1278 | else if (error != 0) | |||
| 1279 | b->last_connect_error = error; | |||
| 1280 | else if (p.revents & (POLLERR0x008|POLLHUP0x010)) | |||
| 1281 | b->last_connect_error = ECONNREFUSED111; | |||
| 1282 | else | |||
| 1283 | return bus_socket_start_auth(b); | |||
| 1284 | ||||
| 1285 | return bus_next_address(b); | |||
| 1286 | } | |||
| 1287 | ||||
| 1288 | int bus_socket_process_authenticating(sd_bus *b) { | |||
| 1289 | int r; | |||
| 1290 | ||||
| 1291 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 1291, __PRETTY_FUNCTION__); } while (0); | |||
| 1292 | assert(b->state == BUS_AUTHENTICATING)do { if ((__builtin_expect(!!(!(b->state == BUS_AUTHENTICATING )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("b->state == BUS_AUTHENTICATING" ), "../src/libsystemd/sd-bus/bus-socket.c", 1292, __PRETTY_FUNCTION__ ); } while (0); | |||
| 1293 | ||||
| 1294 | if (now(CLOCK_MONOTONIC1) >= b->auth_timeout) | |||
| 1295 | return -ETIMEDOUT110; | |||
| 1296 | ||||
| 1297 | r = bus_socket_write_auth(b); | |||
| 1298 | if (r != 0) | |||
| 1299 | return r; | |||
| 1300 | ||||
| 1301 | return bus_socket_read_auth(b); | |||
| 1302 | } | |||
| 1303 | ||||
| 1304 | int bus_socket_process_watch_bind(sd_bus *b) { | |||
| 1305 | int r, q; | |||
| 1306 | ||||
| 1307 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/libsystemd/sd-bus/bus-socket.c" , 1307, __PRETTY_FUNCTION__); } while (0); | |||
| ||||
| 1308 | assert(b->state == BUS_WATCH_BIND)do { if ((__builtin_expect(!!(!(b->state == BUS_WATCH_BIND )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("b->state == BUS_WATCH_BIND" ), "../src/libsystemd/sd-bus/bus-socket.c", 1308, __PRETTY_FUNCTION__ ); } while (0); | |||
| 1309 | assert(b->inotify_fd >= 0)do { if ((__builtin_expect(!!(!(b->inotify_fd >= 0)),0) )) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("b->inotify_fd >= 0" ), "../src/libsystemd/sd-bus/bus-socket.c", 1309, __PRETTY_FUNCTION__ ); } while (0); | |||
| 1310 | ||||
| 1311 | r = flush_fd(b->inotify_fd); | |||
| 1312 | if (r <= 0) | |||
| 1313 | return r; | |||
| 1314 | ||||
| 1315 | log_debug("Got inotify event on bus %s.", strna(b->description))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-bus/bus-socket.c", 1315, __func__, "Got inotify event on bus %s." , strna(b->description)) : -abs(_e); }); | |||
| 1316 | ||||
| 1317 | /* We flushed events out of the inotify fd. In that case, maybe the socket is valid now? Let's try to connect | |||
| 1318 | * to it again */ | |||
| 1319 | ||||
| 1320 | r = bus_socket_connect(b); | |||
| 1321 | if (r < 0) | |||
| 1322 | return r; | |||
| 1323 | ||||
| 1324 | q = bus_attach_io_events(b); | |||
| 1325 | if (q < 0) | |||
| 1326 | return q; | |||
| 1327 | ||||
| 1328 | q = bus_attach_inotify_event(b); | |||
| 1329 | if (q < 0) | |||
| 1330 | return q; | |||
| 1331 | ||||
| 1332 | return r; | |||
| 1333 | } |