File: | build-scan/../src/shared/ask-password-api.c |
Warning: | line 77, column 33 Potential leak of memory pointed to by 'p' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | ||||
2 | |||||
3 | #include <errno(*__errno_location ()).h> | ||||
4 | #include <fcntl.h> | ||||
5 | #include <inttypes.h> | ||||
6 | #include <limits.h> | ||||
7 | #include <poll.h> | ||||
8 | #include <signal.h> | ||||
9 | #include <stdbool.h> | ||||
10 | #include <stddef.h> | ||||
11 | #include <stdint.h> | ||||
12 | #include <stdio.h> | ||||
13 | #include <stdlib.h> | ||||
14 | #include <string.h> | ||||
15 | #include <sys/inotify.h> | ||||
16 | #include <sys/signalfd.h> | ||||
17 | #include <sys/socket.h> | ||||
18 | #include <sys/stat.h> | ||||
19 | #include <sys/time.h> | ||||
20 | #include <sys/uio.h> | ||||
21 | #include <sys/un.h> | ||||
22 | #include <termios.h> | ||||
23 | #include <unistd.h> | ||||
24 | |||||
25 | #include "alloc-util.h" | ||||
26 | #include "ask-password-api.h" | ||||
27 | #include "fd-util.h" | ||||
28 | #include "fileio.h" | ||||
29 | #include "format-util.h" | ||||
30 | #include "io-util.h" | ||||
31 | #include "log.h" | ||||
32 | #include "macro.h" | ||||
33 | #include "missing.h" | ||||
34 | #include "mkdir.h" | ||||
35 | #include "process-util.h" | ||||
36 | #include "random-util.h" | ||||
37 | #include "signal-util.h" | ||||
38 | #include "socket-util.h" | ||||
39 | #include "string-util.h" | ||||
40 | #include "strv.h" | ||||
41 | #include "terminal-util.h" | ||||
42 | #include "time-util.h" | ||||
43 | #include "umask-util.h" | ||||
44 | #include "utf8.h" | ||||
45 | #include "util.h" | ||||
46 | |||||
47 | #define KEYRING_TIMEOUT_USEC((5 * ((usec_t) (60ULL*((usec_t) 1000000ULL)))) / 2) ((5 * USEC_PER_MINUTE((usec_t) (60ULL*((usec_t) 1000000ULL)))) / 2) | ||||
48 | |||||
49 | static int lookup_key(const char *keyname, key_serial_t *ret) { | ||||
50 | key_serial_t serial; | ||||
51 | |||||
52 | assert(keyname)do { if ((__builtin_expect(!!(!(keyname)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("keyname"), "../src/shared/ask-password-api.c" , 52, __PRETTY_FUNCTION__); } while (0); | ||||
53 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/shared/ask-password-api.c" , 53, __PRETTY_FUNCTION__); } while (0); | ||||
54 | |||||
55 | serial = request_keymissing_request_key("user", keyname, NULL((void*)0), 0); | ||||
56 | if (serial == -1) | ||||
57 | return negative_errno(); | ||||
58 | |||||
59 | *ret = serial; | ||||
60 | return 0; | ||||
61 | } | ||||
62 | |||||
63 | static int retrieve_key(key_serial_t serial, char ***ret) { | ||||
64 | _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0); | ||||
65 | long m = 100, n; | ||||
66 | char **l; | ||||
67 | |||||
68 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/shared/ask-password-api.c" , 68, __PRETTY_FUNCTION__); } while (0); | ||||
69 | |||||
70 | for (;;) { | ||||
71 | p = new(char, m)((char*) malloc_multiply(sizeof(char), (m))); | ||||
72 | if (!p) | ||||
73 | return -ENOMEM12; | ||||
74 | |||||
75 | n = keyctlmissing_keyctl(KEYCTL_READ11, (unsigned long) serial, (unsigned long) p, (unsigned long) m, 0); | ||||
76 | if (n < 0) | ||||
77 | return -errno(*__errno_location ()); | ||||
| |||||
78 | |||||
79 | if (n < m) | ||||
80 | break; | ||||
81 | |||||
82 | explicit_bzero(p, m); | ||||
83 | free(p); | ||||
84 | m *= 2; | ||||
85 | } | ||||
86 | |||||
87 | l = strv_parse_nulstr(p, n); | ||||
88 | if (!l) | ||||
89 | return -ENOMEM12; | ||||
90 | |||||
91 | explicit_bzero(p, n); | ||||
92 | |||||
93 | *ret = l; | ||||
94 | return 0; | ||||
95 | } | ||||
96 | |||||
97 | static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) { | ||||
98 | _cleanup_strv_free_erase___attribute__((cleanup(strv_free_erasep))) char **l = NULL((void*)0); | ||||
99 | _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0); | ||||
100 | key_serial_t serial; | ||||
101 | size_t n; | ||||
102 | int r; | ||||
103 | |||||
104 | assert(keyname)do { if ((__builtin_expect(!!(!(keyname)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("keyname"), "../src/shared/ask-password-api.c" , 104, __PRETTY_FUNCTION__); } while (0); | ||||
105 | assert(passwords)do { if ((__builtin_expect(!!(!(passwords)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("passwords"), "../src/shared/ask-password-api.c" , 105, __PRETTY_FUNCTION__); } while (0); | ||||
106 | |||||
107 | if (!(flags & ASK_PASSWORD_PUSH_CACHE)) | ||||
108 | return 0; | ||||
109 | |||||
110 | r = lookup_key(keyname, &serial); | ||||
111 | if (r >= 0) { | ||||
112 | r = retrieve_key(serial, &l); | ||||
113 | if (r < 0) | ||||
114 | return r; | ||||
115 | } else if (r != -ENOKEY126) | ||||
116 | return r; | ||||
117 | |||||
118 | r = strv_extend_strv(&l, passwords, true1); | ||||
119 | if (r <= 0) | ||||
120 | return r; | ||||
121 | |||||
122 | r = strv_make_nulstr(l, &p, &n); | ||||
123 | if (r < 0) | ||||
124 | return r; | ||||
125 | |||||
126 | serial = add_keymissing_add_key("user", keyname, p, n, KEY_SPEC_USER_KEYRING-4); | ||||
127 | explicit_bzero(p, n); | ||||
128 | if (serial == -1) | ||||
129 | return -errno(*__errno_location ()); | ||||
130 | |||||
131 | if (keyctlmissing_keyctl(KEYCTL_SET_TIMEOUT15, | ||||
132 | (unsigned long) serial, | ||||
133 | (unsigned long) DIV_ROUND_UP(KEYRING_TIMEOUT_USEC, USEC_PER_SEC)({ const typeof((((5 * ((usec_t) (60ULL*((usec_t) 1000000ULL) ))) / 2))) __unique_prefix_X7 = ((((5 * ((usec_t) (60ULL*((usec_t ) 1000000ULL)))) / 2))); const typeof((((usec_t) 1000000ULL)) ) __unique_prefix_Y8 = ((((usec_t) 1000000ULL))); (__unique_prefix_X7 / __unique_prefix_Y8 + !!(__unique_prefix_X7 % __unique_prefix_Y8 )); }), 0, 0) < 0) | ||||
134 | log_debug_errno(errno, "Failed to adjust timeout: %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/shared/ask-password-api.c", 134, __func__, "Failed to adjust timeout: %m") : -abs(_e); }); | ||||
135 | |||||
136 | log_debug("Added key to keyring as %" PRIi32 ".", serial)({ 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/shared/ask-password-api.c", 136, __func__, "Added key to keyring as %" "i" ".", serial) : -abs(_e); }); | ||||
137 | |||||
138 | return 1; | ||||
139 | } | ||||
140 | |||||
141 | static int add_to_keyring_and_log(const char *keyname, AskPasswordFlags flags, char **passwords) { | ||||
142 | int r; | ||||
143 | |||||
144 | assert(keyname)do { if ((__builtin_expect(!!(!(keyname)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("keyname"), "../src/shared/ask-password-api.c" , 144, __PRETTY_FUNCTION__); } while (0); | ||||
145 | assert(passwords)do { if ((__builtin_expect(!!(!(passwords)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("passwords"), "../src/shared/ask-password-api.c" , 145, __PRETTY_FUNCTION__); } while (0); | ||||
146 | |||||
147 | r = add_to_keyring(keyname, flags, passwords); | ||||
148 | if (r < 0) | ||||
149 | return log_debug_errno(r, "Failed to add password to keyring: %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/shared/ask-password-api.c", 149, __func__, "Failed to add password to keyring: %m" ) : -abs(_e); }); | ||||
150 | |||||
151 | return 0; | ||||
152 | } | ||||
153 | |||||
154 | int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret) { | ||||
155 | |||||
156 | key_serial_t serial; | ||||
157 | int r; | ||||
158 | |||||
159 | assert(keyname)do { if ((__builtin_expect(!!(!(keyname)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("keyname"), "../src/shared/ask-password-api.c" , 159, __PRETTY_FUNCTION__); } while (0); | ||||
160 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/shared/ask-password-api.c" , 160, __PRETTY_FUNCTION__); } while (0); | ||||
161 | |||||
162 | if (!(flags & ASK_PASSWORD_ACCEPT_CACHED)) | ||||
163 | return -EUNATCH49; | ||||
164 | |||||
165 | r = lookup_key(keyname, &serial); | ||||
166 | if (r == -ENOSYS38) /* when retrieving the distinction doesn't matter */ | ||||
167 | return -ENOKEY126; | ||||
168 | if (r
| ||||
169 | return r; | ||||
170 | |||||
171 | return retrieve_key(serial, ret); | ||||
172 | } | ||||
173 | |||||
174 | static void backspace_chars(int ttyfd, size_t p) { | ||||
175 | |||||
176 | if (ttyfd < 0) | ||||
177 | return; | ||||
178 | |||||
179 | while (p > 0) { | ||||
180 | p--; | ||||
181 | |||||
182 | loop_write(ttyfd, "\b \b", 3, false0); | ||||
183 | } | ||||
184 | } | ||||
185 | |||||
186 | static void backspace_string(int ttyfd, const char *str) { | ||||
187 | size_t m; | ||||
188 | |||||
189 | assert(str)do { if ((__builtin_expect(!!(!(str)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("str"), "../src/shared/ask-password-api.c" , 189, __PRETTY_FUNCTION__); } while (0); | ||||
190 | |||||
191 | if (ttyfd < 0) | ||||
192 | return; | ||||
193 | |||||
194 | /* Backspaces through enough characters to entirely undo printing of the specified string. */ | ||||
195 | |||||
196 | m = utf8_n_codepoints(str); | ||||
197 | if (m == (size_t) -1) | ||||
198 | m = strlen(str); /* Not a valid UTF-8 string? If so, let's backspace the number of bytes output. Most | ||||
199 | * likely this happened because we are not in an UTF-8 locale, and in that case that | ||||
200 | * is the correct thing to do. And even if it's not, terminals tend to stop | ||||
201 | * backspacing at the leftmost column, hence backspacing too much should be mostly | ||||
202 | * OK. */ | ||||
203 | |||||
204 | backspace_chars(ttyfd, m); | ||||
205 | } | ||||
206 | |||||
207 | int ask_password_tty( | ||||
208 | int ttyfd, | ||||
209 | const char *message, | ||||
210 | const char *keyname, | ||||
211 | usec_t until, | ||||
212 | AskPasswordFlags flags, | ||||
213 | const char *flag_file, | ||||
214 | char **ret) { | ||||
215 | |||||
216 | enum { | ||||
217 | POLL_TTY, | ||||
218 | POLL_INOTIFY, | ||||
219 | _POLL_MAX, | ||||
220 | }; | ||||
221 | |||||
222 | bool_Bool reset_tty = false0, dirty = false0, use_color = false0; | ||||
223 | _cleanup_close___attribute__((cleanup(closep))) int cttyfd = -1, notify = -1; | ||||
224 | struct termios old_termios, new_termios; | ||||
225 | char passphrase[LINE_MAX2048 + 1] = {}, *x; | ||||
226 | struct pollfd pollfd[_POLL_MAX]; | ||||
227 | size_t p = 0, codepoint = 0; | ||||
228 | int r; | ||||
229 | |||||
230 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/shared/ask-password-api.c" , 230, __PRETTY_FUNCTION__); } while (0); | ||||
231 | |||||
232 | if (flags & ASK_PASSWORD_NO_TTY) | ||||
233 | return -EUNATCH49; | ||||
234 | |||||
235 | if (!message) | ||||
236 | message = "Password:"; | ||||
237 | |||||
238 | if (flag_file) { | ||||
239 | notify = inotify_init1(IN_CLOEXECIN_CLOEXEC|IN_NONBLOCKIN_NONBLOCK); | ||||
240 | if (notify < 0) | ||||
241 | return -errno(*__errno_location ()); | ||||
242 | |||||
243 | if (inotify_add_watch(notify, flag_file, IN_ATTRIB0x00000004 /* for the link count */) < 0) | ||||
244 | return -errno(*__errno_location ()); | ||||
245 | } | ||||
246 | |||||
247 | /* If the caller didn't specify a TTY, then use the controlling tty, if we can. */ | ||||
248 | if (ttyfd < 0) | ||||
249 | ttyfd = cttyfd = open("/dev/tty", O_RDWR02|O_NOCTTY0400|O_CLOEXEC02000000); | ||||
250 | |||||
251 | if (ttyfd >= 0) { | ||||
252 | if (tcgetattr(ttyfd, &old_termios) < 0) | ||||
253 | return -errno(*__errno_location ()); | ||||
254 | |||||
255 | if (flags & ASK_PASSWORD_CONSOLE_COLOR) | ||||
256 | use_color = dev_console_colors_enabled(); | ||||
257 | else | ||||
258 | use_color = colors_enabled(); | ||||
259 | |||||
260 | if (use_color) | ||||
261 | (void) loop_write(ttyfd, ANSI_HIGHLIGHT"\x1B[0;1;39m", STRLEN(ANSI_HIGHLIGHT)(sizeof("""\x1B[0;1;39m""") - 1), false0); | ||||
262 | |||||
263 | (void) loop_write(ttyfd, message, strlen(message), false0); | ||||
264 | (void) loop_write(ttyfd, " ", 1, false0); | ||||
265 | |||||
266 | if (use_color) | ||||
267 | (void) loop_write(ttyfd, ANSI_NORMAL"\x1B[0m", STRLEN(ANSI_NORMAL)(sizeof("""\x1B[0m""") - 1), false0); | ||||
268 | |||||
269 | new_termios = old_termios; | ||||
270 | new_termios.c_lflag &= ~(ICANON0000002|ECHO0000010); | ||||
271 | new_termios.c_cc[VMIN6] = 1; | ||||
272 | new_termios.c_cc[VTIME5] = 0; | ||||
273 | |||||
274 | if (tcsetattr(ttyfd, TCSADRAIN1, &new_termios) < 0) { | ||||
275 | r = -errno(*__errno_location ()); | ||||
276 | goto finish; | ||||
277 | } | ||||
278 | |||||
279 | reset_tty = true1; | ||||
280 | } | ||||
281 | |||||
282 | pollfd[POLL_TTY] = (struct pollfd) { | ||||
283 | .fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO0, | ||||
284 | .events = POLLIN0x001, | ||||
285 | }; | ||||
286 | pollfd[POLL_INOTIFY] = (struct pollfd) { | ||||
287 | .fd = notify, | ||||
288 | .events = POLLIN0x001, | ||||
289 | }; | ||||
290 | |||||
291 | for (;;) { | ||||
292 | int sleep_for = -1, k; | ||||
293 | ssize_t n; | ||||
294 | char c; | ||||
295 | |||||
296 | if (until > 0) { | ||||
297 | usec_t y; | ||||
298 | |||||
299 | y = now(CLOCK_MONOTONIC1); | ||||
300 | |||||
301 | if (y > until) { | ||||
302 | r = -ETIME62; | ||||
303 | goto finish; | ||||
304 | } | ||||
305 | |||||
306 | sleep_for = (int) DIV_ROUND_UP(until - y, USEC_PER_MSEC)({ const typeof((until - y)) __unique_prefix_X9 = ((until - y )); const typeof((((usec_t) 1000ULL))) __unique_prefix_Y10 = ( (((usec_t) 1000ULL))); (__unique_prefix_X9 / __unique_prefix_Y10 + !!(__unique_prefix_X9 % __unique_prefix_Y10)); }); | ||||
307 | } | ||||
308 | |||||
309 | if (flag_file) | ||||
310 | if (access(flag_file, F_OK0) < 0) { | ||||
311 | r = -errno(*__errno_location ()); | ||||
312 | goto finish; | ||||
313 | } | ||||
314 | |||||
315 | k = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for); | ||||
316 | if (k < 0) { | ||||
317 | if (errno(*__errno_location ()) == EINTR4) | ||||
318 | continue; | ||||
319 | |||||
320 | r = -errno(*__errno_location ()); | ||||
321 | goto finish; | ||||
322 | } else if (k == 0) { | ||||
323 | r = -ETIME62; | ||||
324 | goto finish; | ||||
325 | } | ||||
326 | |||||
327 | if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0) | ||||
328 | (void) flush_fd(notify); | ||||
329 | |||||
330 | if (pollfd[POLL_TTY].revents == 0) | ||||
331 | continue; | ||||
332 | |||||
333 | n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO0, &c, 1); | ||||
334 | if (n < 0) { | ||||
335 | if (IN_SET(errno, EINTR, EAGAIN)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){4, 11})/sizeof(int)]; switch((*__errno_location ())) { case 4: case 11: _found = 1; break; default: break; } _found; })) | ||||
336 | continue; | ||||
337 | |||||
338 | r = -errno(*__errno_location ()); | ||||
339 | goto finish; | ||||
340 | |||||
341 | } | ||||
342 | |||||
343 | /* We treat EOF, newline and NUL byte all as valid end markers */ | ||||
344 | if (n == 0 || c == '\n' || c == 0) | ||||
345 | break; | ||||
346 | |||||
347 | if (c == 21) { /* C-u */ | ||||
348 | |||||
349 | if (!(flags & ASK_PASSWORD_SILENT)) | ||||
350 | backspace_string(ttyfd, passphrase); | ||||
351 | |||||
352 | explicit_bzero(passphrase, sizeof(passphrase)); | ||||
353 | p = codepoint = 0; | ||||
354 | |||||
355 | } else if (IN_SET(c, '\b', 127)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){'\b', 127})/sizeof(int)]; switch(c) { case '\b': case 127: _found = 1; break; default: break; } _found; })) { | ||||
356 | |||||
357 | if (p > 0) { | ||||
358 | size_t q; | ||||
359 | |||||
360 | if (!(flags & ASK_PASSWORD_SILENT)) | ||||
361 | backspace_chars(ttyfd, 1); | ||||
362 | |||||
363 | /* Remove a full UTF-8 codepoint from the end. For that, figure out where the last one | ||||
364 | * begins */ | ||||
365 | q = 0; | ||||
366 | for (;;) { | ||||
367 | size_t z; | ||||
368 | |||||
369 | z = utf8_encoded_valid_unichar(passphrase + q); | ||||
370 | if (z == 0) { | ||||
371 | q = (size_t) -1; /* Invalid UTF8! */ | ||||
372 | break; | ||||
373 | } | ||||
374 | |||||
375 | if (q + z >= p) /* This one brings us over the edge */ | ||||
376 | break; | ||||
377 | |||||
378 | q += z; | ||||
379 | } | ||||
380 | |||||
381 | p = codepoint = q == (size_t) -1 ? p - 1 : q; | ||||
382 | explicit_bzero(passphrase + p, sizeof(passphrase) - p); | ||||
383 | |||||
384 | } else if (!dirty && !(flags & ASK_PASSWORD_SILENT)) { | ||||
385 | |||||
386 | flags |= ASK_PASSWORD_SILENT; | ||||
387 | |||||
388 | /* There are two ways to enter silent mode. Either by pressing backspace as first key | ||||
389 | * (and only as first key), or ... */ | ||||
390 | |||||
391 | if (ttyfd >= 0) | ||||
392 | (void) loop_write(ttyfd, "(no echo) ", 10, false0); | ||||
393 | |||||
394 | } else if (ttyfd >= 0) | ||||
395 | (void) loop_write(ttyfd, "\a", 1, false0); | ||||
396 | |||||
397 | } else if (c == '\t' && !(flags & ASK_PASSWORD_SILENT)) { | ||||
398 | |||||
399 | backspace_string(ttyfd, passphrase); | ||||
400 | flags |= ASK_PASSWORD_SILENT; | ||||
401 | |||||
402 | /* ... or by pressing TAB at any time. */ | ||||
403 | |||||
404 | if (ttyfd >= 0) | ||||
405 | (void) loop_write(ttyfd, "(no echo) ", 10, false0); | ||||
406 | |||||
407 | } else if (p >= sizeof(passphrase)-1) { | ||||
408 | |||||
409 | /* Reached the size limit */ | ||||
410 | if (ttyfd >= 0) | ||||
411 | (void) loop_write(ttyfd, "\a", 1, false0); | ||||
412 | |||||
413 | } else { | ||||
414 | passphrase[p++] = c; | ||||
415 | |||||
416 | if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0) { | ||||
417 | /* Check if we got a complete UTF-8 character now. If so, let's output one '*'. */ | ||||
418 | n = utf8_encoded_valid_unichar(passphrase + codepoint); | ||||
419 | if (n >= 0) { | ||||
420 | codepoint = p; | ||||
421 | (void) loop_write(ttyfd, (flags & ASK_PASSWORD_ECHO) ? &c : "*", 1, false0); | ||||
422 | } | ||||
423 | } | ||||
424 | |||||
425 | dirty = true1; | ||||
426 | } | ||||
427 | |||||
428 | /* Let's forget this char, just to not keep needlessly copies of key material around */ | ||||
429 | c = 'x'; | ||||
430 | } | ||||
431 | |||||
432 | x = strndup(passphrase, p); | ||||
433 | explicit_bzero(passphrase, sizeof(passphrase)); | ||||
434 | if (!x) { | ||||
435 | r = -ENOMEM12; | ||||
436 | goto finish; | ||||
437 | } | ||||
438 | |||||
439 | if (keyname) | ||||
440 | (void) add_to_keyring_and_log(keyname, flags, STRV_MAKE(x)((char**) ((const char*[]) { x, ((void*)0) }))); | ||||
441 | |||||
442 | *ret = x; | ||||
443 | r = 0; | ||||
444 | |||||
445 | finish: | ||||
446 | if (ttyfd >= 0 && reset_tty) { | ||||
447 | (void) loop_write(ttyfd, "\n", 1, false0); | ||||
448 | (void) tcsetattr(ttyfd, TCSADRAIN1, &old_termios); | ||||
449 | } | ||||
450 | |||||
451 | return r; | ||||
452 | } | ||||
453 | |||||
454 | static int create_socket(char **name) { | ||||
455 | union sockaddr_union sa = { | ||||
456 | .un.sun_family = AF_UNIX1, | ||||
457 | }; | ||||
458 | _cleanup_close___attribute__((cleanup(closep))) int fd = -1; | ||||
459 | static const int one = 1; | ||||
460 | char *c; | ||||
461 | int r; | ||||
462 | |||||
463 | assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("name"), "../src/shared/ask-password-api.c" , 463, __PRETTY_FUNCTION__); } while (0); | ||||
464 | |||||
465 | fd = socket(AF_UNIX1, SOCK_DGRAMSOCK_DGRAM|SOCK_CLOEXECSOCK_CLOEXEC|SOCK_NONBLOCKSOCK_NONBLOCK, 0); | ||||
466 | if (fd < 0) | ||||
467 | return -errno(*__errno_location ()); | ||||
468 | |||||
469 | snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%" PRIx64"l" "x", random_u64()); | ||||
470 | |||||
471 | RUN_WITH_UMASK(0177)for (__attribute__((cleanup(_reset_umask_))) struct _umask_struct_ _saved_umask_ = { umask(0177), 0 }; !_saved_umask_.quit ; _saved_umask_ .quit = 1) { | ||||
472 | if (bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)({ const struct sockaddr_un *_sa = &(sa.un); do { if ((__builtin_expect (!!(!(_sa->sun_family == 1)),0))) log_assert_failed_realm( LOG_REALM_SYSTEMD, ("_sa->sun_family == AF_UNIX"), "../src/shared/ask-password-api.c" , 472, __PRETTY_FUNCTION__); } while (0); __builtin_offsetof( struct sockaddr_un, sun_path) + (_sa->sun_path[0] == 0 ? 1 + strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : strnlen (_sa->sun_path, sizeof(_sa->sun_path))); })) < 0) | ||||
473 | return -errno(*__errno_location ()); | ||||
474 | } | ||||
475 | |||||
476 | if (setsockopt(fd, SOL_SOCKET1, SO_PASSCRED16, &one, sizeof(one)) < 0) | ||||
477 | return -errno(*__errno_location ()); | ||||
478 | |||||
479 | c = strdup(sa.un.sun_path); | ||||
480 | if (!c) | ||||
481 | return -ENOMEM12; | ||||
482 | |||||
483 | *name = c; | ||||
484 | |||||
485 | r = fd; | ||||
486 | fd = -1; | ||||
487 | |||||
488 | return r; | ||||
489 | } | ||||
490 | |||||
491 | int ask_password_agent( | ||||
492 | const char *message, | ||||
493 | const char *icon, | ||||
494 | const char *id, | ||||
495 | const char *keyname, | ||||
496 | usec_t until, | ||||
497 | AskPasswordFlags flags, | ||||
498 | char ***ret) { | ||||
499 | |||||
500 | enum { | ||||
501 | FD_SOCKET, | ||||
502 | FD_SIGNAL, | ||||
503 | _FD_MAX | ||||
504 | }; | ||||
505 | |||||
506 | _cleanup_close___attribute__((cleanup(closep))) int socket_fd = -1, signal_fd = -1, fd = -1; | ||||
507 | char temp[] = "/run/systemd/ask-password/tmp.XXXXXX"; | ||||
508 | char final[sizeof(temp)] = ""; | ||||
509 | _cleanup_free___attribute__((cleanup(freep))) char *socket_name = NULL((void*)0); | ||||
510 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **l = NULL((void*)0); | ||||
511 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); | ||||
512 | struct pollfd pollfd[_FD_MAX]; | ||||
513 | sigset_t mask, oldmask; | ||||
514 | int r; | ||||
515 | |||||
516 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/shared/ask-password-api.c" , 516, __PRETTY_FUNCTION__); } while (0); | ||||
517 | |||||
518 | if (flags & ASK_PASSWORD_NO_AGENT) | ||||
519 | return -EUNATCH49; | ||||
520 | |||||
521 | assert_se(sigemptyset(&mask) >= 0)do { if ((__builtin_expect(!!(!(sigemptyset(&mask) >= 0 )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("sigemptyset(&mask) >= 0" ), "../src/shared/ask-password-api.c", 521, __PRETTY_FUNCTION__ ); } while (0); | ||||
522 | assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0)do { if ((__builtin_expect(!!(!(sigset_add_many(&mask, 2, 15, -1) >= 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0") , "../src/shared/ask-password-api.c", 522, __PRETTY_FUNCTION__ ); } while (0); | ||||
523 | assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0)do { if ((__builtin_expect(!!(!(sigprocmask(0, &mask, & oldmask) >= 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0") , "../src/shared/ask-password-api.c", 523, __PRETTY_FUNCTION__ ); } while (0); | ||||
524 | |||||
525 | (void) mkdir_p_label("/run/systemd/ask-password", 0755); | ||||
526 | |||||
527 | fd = mkostemp_safe(temp); | ||||
528 | if (fd < 0) { | ||||
529 | r = fd; | ||||
530 | goto finish; | ||||
531 | } | ||||
532 | |||||
533 | (void) fchmod(fd, 0644); | ||||
534 | |||||
535 | f = fdopen(fd, "w"); | ||||
536 | if (!f) { | ||||
537 | r = -errno(*__errno_location ()); | ||||
538 | goto finish; | ||||
539 | } | ||||
540 | |||||
541 | fd = -1; | ||||
542 | |||||
543 | signal_fd = signalfd(-1, &mask, SFD_NONBLOCKSFD_NONBLOCK|SFD_CLOEXECSFD_CLOEXEC); | ||||
544 | if (signal_fd < 0) { | ||||
545 | r = -errno(*__errno_location ()); | ||||
546 | goto finish; | ||||
547 | } | ||||
548 | |||||
549 | socket_fd = create_socket(&socket_name); | ||||
550 | if (socket_fd < 0) { | ||||
551 | r = socket_fd; | ||||
552 | goto finish; | ||||
553 | } | ||||
554 | |||||
555 | fprintf(f, | ||||
556 | "[Ask]\n" | ||||
557 | "PID="PID_FMT"%" "i""\n" | ||||
558 | "Socket=%s\n" | ||||
559 | "AcceptCached=%i\n" | ||||
560 | "Echo=%i\n" | ||||
561 | "NotAfter="USEC_FMT"%" "l" "u""\n", | ||||
562 | getpid_cached(), | ||||
563 | socket_name, | ||||
564 | (flags & ASK_PASSWORD_ACCEPT_CACHED) ? 1 : 0, | ||||
565 | (flags & ASK_PASSWORD_ECHO) ? 1 : 0, | ||||
566 | until); | ||||
567 | |||||
568 | if (message) | ||||
569 | fprintf(f, "Message=%s\n", message); | ||||
570 | |||||
571 | if (icon) | ||||
572 | fprintf(f, "Icon=%s\n", icon); | ||||
573 | |||||
574 | if (id) | ||||
575 | fprintf(f, "Id=%s\n", id); | ||||
576 | |||||
577 | r = fflush_and_check(f); | ||||
578 | if (r < 0) | ||||
579 | goto finish; | ||||
580 | |||||
581 | memcpy(final, temp, sizeof(temp)); | ||||
582 | |||||
583 | final[sizeof(final)-11] = 'a'; | ||||
584 | final[sizeof(final)-10] = 's'; | ||||
585 | final[sizeof(final)-9] = 'k'; | ||||
586 | |||||
587 | if (rename(temp, final) < 0) { | ||||
588 | r = -errno(*__errno_location ()); | ||||
589 | goto finish; | ||||
590 | } | ||||
591 | |||||
592 | zero(pollfd)(({ size_t _l_ = (sizeof(pollfd)); void *_x_ = (&(pollfd) ); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); })); | ||||
593 | pollfd[FD_SOCKET].fd = socket_fd; | ||||
594 | pollfd[FD_SOCKET].events = POLLIN0x001; | ||||
595 | pollfd[FD_SIGNAL].fd = signal_fd; | ||||
596 | pollfd[FD_SIGNAL].events = POLLIN0x001; | ||||
597 | |||||
598 | for (;;) { | ||||
599 | char passphrase[LINE_MAX2048+1]; | ||||
600 | struct msghdr msghdr; | ||||
601 | struct iovec iovec; | ||||
602 | struct ucred *ucred; | ||||
603 | union { | ||||
604 | struct cmsghdr cmsghdr; | ||||
605 | uint8_t buf[CMSG_SPACE(sizeof(struct ucred))((((sizeof(struct ucred)) + sizeof (size_t) - 1) & (size_t ) ~(sizeof (size_t) - 1)) + (((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)))]; | ||||
606 | } control; | ||||
607 | ssize_t n; | ||||
608 | int k; | ||||
609 | usec_t t; | ||||
610 | |||||
611 | t = now(CLOCK_MONOTONIC1); | ||||
612 | |||||
613 | if (until > 0 && until <= t) { | ||||
614 | r = -ETIME62; | ||||
615 | goto finish; | ||||
616 | } | ||||
617 | |||||
618 | k = poll(pollfd, _FD_MAX, until > 0 ? (int) ((until-t)/USEC_PER_MSEC((usec_t) 1000ULL)) : -1); | ||||
619 | if (k < 0) { | ||||
620 | if (errno(*__errno_location ()) == EINTR4) | ||||
621 | continue; | ||||
622 | |||||
623 | r = -errno(*__errno_location ()); | ||||
624 | goto finish; | ||||
625 | } | ||||
626 | |||||
627 | if (k <= 0) { | ||||
628 | r = -ETIME62; | ||||
629 | goto finish; | ||||
630 | } | ||||
631 | |||||
632 | if (pollfd[FD_SIGNAL].revents & POLLIN0x001) { | ||||
633 | r = -EINTR4; | ||||
634 | goto finish; | ||||
635 | } | ||||
636 | |||||
637 | if (pollfd[FD_SOCKET].revents != POLLIN0x001) { | ||||
638 | r = -EIO5; | ||||
639 | goto finish; | ||||
640 | } | ||||
641 | |||||
642 | zero(iovec)(({ size_t _l_ = (sizeof(iovec)); void *_x_ = (&(iovec)); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); })); | ||||
643 | iovec.iov_base = passphrase; | ||||
644 | iovec.iov_len = sizeof(passphrase); | ||||
645 | |||||
646 | zero(control)(({ size_t _l_ = (sizeof(control)); void *_x_ = (&(control )); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); })); | ||||
647 | zero(msghdr)(({ size_t _l_ = (sizeof(msghdr)); void *_x_ = (&(msghdr) ); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); })); | ||||
648 | msghdr.msg_iov = &iovec; | ||||
649 | msghdr.msg_iovlen = 1; | ||||
650 | msghdr.msg_control = &control; | ||||
651 | msghdr.msg_controllen = sizeof(control); | ||||
652 | |||||
653 | n = recvmsg(socket_fd, &msghdr, 0); | ||||
654 | if (n < 0) { | ||||
655 | if (IN_SET(errno, EAGAIN, EINTR)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){11, 4})/sizeof(int)]; switch((*__errno_location ())) { case 11: case 4: _found = 1; break; default: break; } _found; })) | ||||
656 | continue; | ||||
657 | |||||
658 | r = -errno(*__errno_location ()); | ||||
659 | goto finish; | ||||
660 | } | ||||
661 | |||||
662 | cmsg_close_all(&msghdr); | ||||
663 | |||||
664 | if (n <= 0) { | ||||
665 | log_debug("Message too short")({ 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/shared/ask-password-api.c", 665, __func__, "Message too short" ) : -abs(_e); }); | ||||
666 | continue; | ||||
667 | } | ||||
668 | |||||
669 | if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred))((((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t ) ~(sizeof (size_t) - 1)) + (sizeof(struct ucred))) || | ||||
670 | control.cmsghdr.cmsg_level != SOL_SOCKET1 || | ||||
671 | control.cmsghdr.cmsg_type != SCM_CREDENTIALSSCM_CREDENTIALS || | ||||
672 | control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))((((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t ) ~(sizeof (size_t) - 1)) + (sizeof(struct ucred)))) { | ||||
673 | log_debug("Received message without credentials. Ignoring.")({ 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/shared/ask-password-api.c", 673, __func__, "Received message without credentials. Ignoring." ) : -abs(_e); }); | ||||
674 | continue; | ||||
675 | } | ||||
676 | |||||
677 | ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr)((&control.cmsghdr)->__cmsg_data); | ||||
678 | if (ucred->uid != 0) { | ||||
679 | log_debug("Got request from unprivileged user. Ignoring.")({ 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/shared/ask-password-api.c", 679, __func__, "Got request from unprivileged user. Ignoring." ) : -abs(_e); }); | ||||
680 | continue; | ||||
681 | } | ||||
682 | |||||
683 | if (passphrase[0] == '+') { | ||||
684 | /* An empty message refers to the empty password */ | ||||
685 | if (n == 1) | ||||
686 | l = strv_new("", NULL((void*)0)); | ||||
687 | else | ||||
688 | l = strv_parse_nulstr(passphrase+1, n-1); | ||||
689 | explicit_bzero(passphrase, n); | ||||
690 | if (!l) { | ||||
691 | r = -ENOMEM12; | ||||
692 | goto finish; | ||||
693 | } | ||||
694 | |||||
695 | if (strv_isempty(l)) { | ||||
696 | l = strv_free(l); | ||||
697 | log_debug("Invalid packet")({ 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/shared/ask-password-api.c", 697, __func__, "Invalid packet" ) : -abs(_e); }); | ||||
698 | continue; | ||||
699 | } | ||||
700 | |||||
701 | break; | ||||
702 | } | ||||
703 | |||||
704 | if (passphrase[0] == '-') { | ||||
705 | r = -ECANCELED125; | ||||
706 | goto finish; | ||||
707 | } | ||||
708 | |||||
709 | log_debug("Invalid packet")({ 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/shared/ask-password-api.c", 709, __func__, "Invalid packet" ) : -abs(_e); }); | ||||
710 | } | ||||
711 | |||||
712 | if (keyname) | ||||
713 | (void) add_to_keyring_and_log(keyname, flags, l); | ||||
714 | |||||
715 | *ret = TAKE_PTR(l)({ typeof(l) _ptr_ = (l); (l) = ((void*)0); _ptr_; }); | ||||
716 | r = 0; | ||||
717 | |||||
718 | finish: | ||||
719 | if (socket_name) | ||||
720 | (void) unlink(socket_name); | ||||
721 | |||||
722 | (void) unlink(temp); | ||||
723 | |||||
724 | if (final[0]) | ||||
725 | (void) unlink(final); | ||||
726 | |||||
727 | assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0)do { if ((__builtin_expect(!!(!(sigprocmask(2, &oldmask, ( (void*)0)) == 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0"), "../src/shared/ask-password-api.c" , 727, __PRETTY_FUNCTION__); } while (0); | ||||
728 | return r; | ||||
729 | } | ||||
730 | |||||
731 | int ask_password_auto( | ||||
732 | const char *message, | ||||
733 | const char *icon, | ||||
734 | const char *id, | ||||
735 | const char *keyname, | ||||
736 | usec_t until, | ||||
737 | AskPasswordFlags flags, | ||||
738 | char ***ret) { | ||||
739 | |||||
740 | int r; | ||||
741 | |||||
742 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/shared/ask-password-api.c" , 742, __PRETTY_FUNCTION__); } while (0); | ||||
| |||||
743 | |||||
744 | if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) { | ||||
745 | r = ask_password_keyring(keyname, flags, ret); | ||||
746 | if (r != -ENOKEY126) | ||||
747 | return r; | ||||
748 | } | ||||
749 | |||||
750 | if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO0)) { | ||||
751 | char *s = NULL((void*)0), **l = NULL((void*)0); | ||||
752 | |||||
753 | r = ask_password_tty(-1, message, keyname, until, flags, NULL((void*)0), &s); | ||||
754 | if (r < 0) | ||||
755 | return r; | ||||
756 | |||||
757 | r = strv_push(&l, s); | ||||
758 | if (r < 0) { | ||||
759 | string_erase(s); | ||||
760 | free(s); | ||||
761 | return -ENOMEM12; | ||||
762 | } | ||||
763 | |||||
764 | *ret = l; | ||||
765 | return 0; | ||||
766 | } | ||||
767 | |||||
768 | if (!(flags & ASK_PASSWORD_NO_AGENT)) | ||||
769 | return ask_password_agent(message, icon, id, keyname, until, flags, ret); | ||||
770 | |||||
771 | return -EUNATCH49; | ||||
772 | } |
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
2 | #pragma once |
3 | |
4 | #include <alloca.h> |
5 | #include <stddef.h> |
6 | #include <stdlib.h> |
7 | #include <string.h> |
8 | |
9 | #include "macro.h" |
10 | |
11 | #define new(t, n)((t*) malloc_multiply(sizeof(t), (n))) ((t*) malloc_multiply(sizeof(t), (n))) |
12 | |
13 | #define new0(t, n)((t*) calloc((n), sizeof(t))) ((t*) calloc((n), sizeof(t))) |
14 | |
15 | #define newa(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 15, __PRETTY_FUNCTION__); } while (0); (t*) __builtin_alloca (sizeof(t)*(n)); }) \ |
16 | ({ \ |
17 | assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 17, __PRETTY_FUNCTION__); } while (0); \ |
18 | (t*) alloca(sizeof(t)*(n))__builtin_alloca (sizeof(t)*(n)); \ |
19 | }) |
20 | |
21 | #define newa0(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 21, __PRETTY_FUNCTION__); } while (0); (t*) ({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_) ; }); }) \ |
22 | ({ \ |
23 | assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 23, __PRETTY_FUNCTION__); } while (0); \ |
24 | (t*) alloca0(sizeof(t)*(n))({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_); }); \ |
25 | }) |
26 | |
27 | #define newdup(t, p, n)((t*) memdup_multiply(p, sizeof(t), (n))) ((t*) memdup_multiply(p, sizeof(t), (n))) |
28 | |
29 | #define newdup_suffix0(t, p, n)((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) |
30 | |
31 | #define malloc0(n)(calloc(1, (n))) (calloc(1, (n))) |
32 | |
33 | static inline void *mfree(void *memory) { |
34 | free(memory); |
35 | return NULL((void*)0); |
36 | } |
37 | |
38 | #define free_and_replace(a, b)({ free(a); (a) = (b); (b) = ((void*)0); 0; }) \ |
39 | ({ \ |
40 | free(a); \ |
41 | (a) = (b); \ |
42 | (b) = NULL((void*)0); \ |
43 | 0; \ |
44 | }) |
45 | |
46 | void* memdup(const void *p, size_t l) _alloc_(2); |
47 | void* memdup_suffix0(const void *p, size_t l) _alloc_(2); |
48 | |
49 | static inline void freep(void *p) { |
50 | free(*(void**) p); |
51 | } |
52 | |
53 | #define _cleanup_free___attribute__((cleanup(freep))) _cleanup_(freep)__attribute__((cleanup(freep))) |
54 | |
55 | static inline bool_Bool size_multiply_overflow(size_t size, size_t need) { |
56 | return _unlikely_(need != 0 && size > (SIZE_MAX / need))(__builtin_expect(!!(need != 0 && size > ((18446744073709551615UL ) / need)),0)); |
57 | } |
58 | |
59 | _malloc___attribute__ ((malloc)) _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) { |
60 | if (size_multiply_overflow(size, need)) |
61 | return NULL((void*)0); |
62 | |
63 | return malloc(size * need); |
64 | } |
65 | |
66 | #if !HAVE_REALLOCARRAY1 |
67 | _alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) { |
68 | if (size_multiply_overflow(size, need)) |
69 | return NULL((void*)0); |
70 | |
71 | return realloc(p, size * need); |
72 | } |
73 | #endif |
74 | |
75 | _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) { |
76 | if (size_multiply_overflow(size, need)) |
77 | return NULL((void*)0); |
78 | |
79 | return memdup(p, size * need); |
80 | } |
81 | |
82 | _alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) { |
83 | if (size_multiply_overflow(size, need)) |
84 | return NULL((void*)0); |
85 | |
86 | return memdup_suffix0(p, size * need); |
87 | } |
88 | |
89 | void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); |
90 | void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); |
91 | |
92 | #define GREEDY_REALLOC(array, allocated, need)greedy_realloc((void**) &(array), &(allocated), (need ), sizeof((array)[0])) \ |
93 | greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0])) |
94 | |
95 | #define GREEDY_REALLOC0(array, allocated, need)greedy_realloc0((void**) &(array), &(allocated), (need ), sizeof((array)[0])) \ |
96 | greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0])) |
97 | |
98 | #define alloca0(n)({ char *_new_; size_t _len_ = n; _new_ = __builtin_alloca (_len_ ); (void *) memset(_new_, 0, _len_); }) \ |
99 | ({ \ |
100 | char *_new_; \ |
101 | size_t _len_ = n; \ |
102 | _new_ = alloca(_len_)__builtin_alloca (_len_); \ |
103 | (void *) memset(_new_, 0, _len_); \ |
104 | }) |
105 | |
106 | /* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ |
107 | #define alloca_align(size, align)({ void *_ptr_; size_t _mask_ = (align) - 1; _ptr_ = __builtin_alloca ((size) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); }) \ |
108 | ({ \ |
109 | void *_ptr_; \ |
110 | size_t _mask_ = (align) - 1; \ |
111 | _ptr_ = alloca((size) + _mask_)__builtin_alloca ((size) + _mask_); \ |
112 | (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ |
113 | }) |
114 | |
115 | #define alloca0_align(size, align)({ void *_new_; size_t _size_ = (size); _new_ = ({ void *_ptr_ ; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_ ) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_ ); }); (void*)memset(_new_, 0, _size_); }) \ |
116 | ({ \ |
117 | void *_new_; \ |
118 | size_t _size_ = (size); \ |
119 | _new_ = alloca_align(_size_, (align))({ void *_ptr_; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); }); \ |
120 | (void*)memset(_new_, 0, _size_); \ |
121 | }) |
122 | |
123 | /* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to |
124 | * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */ |
125 | #define TAKE_PTR(ptr)({ typeof(ptr) _ptr_ = (ptr); (ptr) = ((void*)0); _ptr_; }) \ |
126 | ({ \ |
127 | typeof(ptr) _ptr_ = (ptr); \ |
128 | (ptr) = NULL((void*)0); \ |
129 | _ptr_; \ |
130 | }) |