Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <errno.h>
4 : : #include <poll.h>
5 : : #include <string.h>
6 : : #include <sys/inotify.h>
7 : : #include <unistd.h>
8 : :
9 : : #include "sd-login.h"
10 : :
11 : : #include "alloc-util.h"
12 : : #include "cgroup-util.h"
13 : : #include "dirent-util.h"
14 : : #include "env-file.h"
15 : : #include "escape.h"
16 : : #include "fd-util.h"
17 : : #include "format-util.h"
18 : : #include "fs-util.h"
19 : : #include "hostname-util.h"
20 : : #include "io-util.h"
21 : : #include "login-util.h"
22 : : #include "macro.h"
23 : : #include "parse-util.h"
24 : : #include "path-util.h"
25 : : #include "socket-util.h"
26 : : #include "string-util.h"
27 : : #include "strv.h"
28 : : #include "user-util.h"
29 : : #include "util.h"
30 : :
31 : : /* Error codes:
32 : : *
33 : : * invalid input parameters → -EINVAL
34 : : * invalid fd → -EBADF
35 : : * process does not exist → -ESRCH
36 : : * cgroup does not exist → -ENOENT
37 : : * machine, session does not exist → -ENXIO
38 : : * requested metadata on object is missing → -ENODATA
39 : : */
40 : :
41 : 8 : _public_ int sd_pid_get_session(pid_t pid, char **session) {
42 : : int r;
43 : :
44 [ - + - + ]: 8 : assert_return(pid >= 0, -EINVAL);
45 [ - + - + ]: 8 : assert_return(session, -EINVAL);
46 : :
47 : 8 : r = cg_pid_get_session(pid, session);
48 [ - + + - ]: 8 : return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
49 : : }
50 : :
51 : 4 : _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
52 : : int r;
53 : :
54 [ - + - + ]: 4 : assert_return(pid >= 0, -EINVAL);
55 [ - + - + ]: 4 : assert_return(unit, -EINVAL);
56 : :
57 : 4 : r = cg_pid_get_unit(pid, unit);
58 [ - + + - ]: 4 : return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
59 : : }
60 : :
61 : 4 : _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
62 : : int r;
63 : :
64 [ - + - + ]: 4 : assert_return(pid >= 0, -EINVAL);
65 [ - + - + ]: 4 : assert_return(unit, -EINVAL);
66 : :
67 : 4 : r = cg_pid_get_user_unit(pid, unit);
68 [ + - - + ]: 4 : return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
69 : : }
70 : :
71 : 0 : _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
72 : : int r;
73 : :
74 [ # # # # ]: 0 : assert_return(pid >= 0, -EINVAL);
75 [ # # # # ]: 0 : assert_return(name, -EINVAL);
76 : :
77 : 0 : r = cg_pid_get_machine_name(pid, name);
78 [ # # # # ]: 0 : return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
79 : : }
80 : :
81 : 4 : _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
82 : : int r;
83 : :
84 [ - + - + ]: 4 : assert_return(pid >= 0, -EINVAL);
85 [ - + - + ]: 4 : assert_return(slice, -EINVAL);
86 : :
87 : 4 : r = cg_pid_get_slice(pid, slice);
88 [ - + + - ]: 4 : return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
89 : : }
90 : :
91 : 0 : _public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
92 : : int r;
93 : :
94 [ # # # # ]: 0 : assert_return(pid >= 0, -EINVAL);
95 [ # # # # ]: 0 : assert_return(slice, -EINVAL);
96 : :
97 : 0 : r = cg_pid_get_user_slice(pid, slice);
98 [ # # # # ]: 0 : return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
99 : : }
100 : :
101 : 4 : _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
102 : : int r;
103 : :
104 [ - + - + ]: 4 : assert_return(pid >= 0, -EINVAL);
105 [ - + - + ]: 4 : assert_return(uid, -EINVAL);
106 : :
107 : 4 : r = cg_pid_get_owner_uid(pid, uid);
108 [ - + + - ]: 4 : return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
109 : : }
110 : :
111 : 4 : _public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) {
112 : : char *c;
113 : : int r;
114 : :
115 [ - + - + ]: 4 : assert_return(pid >= 0, -EINVAL);
116 [ - + - + ]: 4 : assert_return(cgroup, -EINVAL);
117 : :
118 : 4 : r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &c);
119 [ - + ]: 4 : if (r < 0)
120 : 0 : return r;
121 : :
122 : : /* The internal APIs return the empty string for the root
123 : : * cgroup, let's return the "/" in the public APIs instead, as
124 : : * that's easier and less ambiguous for people to grok. */
125 [ - + ]: 4 : if (isempty(c)) {
126 : 0 : free(c);
127 : 0 : c = strdup("/");
128 [ # # ]: 0 : if (!c)
129 : 0 : return -ENOMEM;
130 : :
131 : : }
132 : :
133 : 4 : *cgroup = c;
134 : 4 : return 0;
135 : : }
136 : :
137 : 8 : _public_ int sd_peer_get_session(int fd, char **session) {
138 : 8 : struct ucred ucred = {};
139 : : int r;
140 : :
141 [ - + - + ]: 8 : assert_return(fd >= 0, -EBADF);
142 [ - + - + ]: 8 : assert_return(session, -EINVAL);
143 : :
144 : 8 : r = getpeercred(fd, &ucred);
145 [ - + ]: 8 : if (r < 0)
146 : 0 : return r;
147 : :
148 : 8 : return cg_pid_get_session(ucred.pid, session);
149 : : }
150 : :
151 : 0 : _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
152 : : struct ucred ucred;
153 : : int r;
154 : :
155 [ # # # # ]: 0 : assert_return(fd >= 0, -EBADF);
156 [ # # # # ]: 0 : assert_return(uid, -EINVAL);
157 : :
158 : 0 : r = getpeercred(fd, &ucred);
159 [ # # ]: 0 : if (r < 0)
160 : 0 : return r;
161 : :
162 : 0 : return cg_pid_get_owner_uid(ucred.pid, uid);
163 : : }
164 : :
165 : 0 : _public_ int sd_peer_get_unit(int fd, char **unit) {
166 : : struct ucred ucred;
167 : : int r;
168 : :
169 [ # # # # ]: 0 : assert_return(fd >= 0, -EBADF);
170 [ # # # # ]: 0 : assert_return(unit, -EINVAL);
171 : :
172 : 0 : r = getpeercred(fd, &ucred);
173 [ # # ]: 0 : if (r < 0)
174 : 0 : return r;
175 : :
176 : 0 : return cg_pid_get_unit(ucred.pid, unit);
177 : : }
178 : :
179 : 0 : _public_ int sd_peer_get_user_unit(int fd, char **unit) {
180 : : struct ucred ucred;
181 : : int r;
182 : :
183 [ # # # # ]: 0 : assert_return(fd >= 0, -EBADF);
184 [ # # # # ]: 0 : assert_return(unit, -EINVAL);
185 : :
186 : 0 : r = getpeercred(fd, &ucred);
187 [ # # ]: 0 : if (r < 0)
188 : 0 : return r;
189 : :
190 : 0 : return cg_pid_get_user_unit(ucred.pid, unit);
191 : : }
192 : :
193 : 0 : _public_ int sd_peer_get_machine_name(int fd, char **machine) {
194 : : struct ucred ucred;
195 : : int r;
196 : :
197 [ # # # # ]: 0 : assert_return(fd >= 0, -EBADF);
198 [ # # # # ]: 0 : assert_return(machine, -EINVAL);
199 : :
200 : 0 : r = getpeercred(fd, &ucred);
201 [ # # ]: 0 : if (r < 0)
202 : 0 : return r;
203 : :
204 : 0 : return cg_pid_get_machine_name(ucred.pid, machine);
205 : : }
206 : :
207 : 0 : _public_ int sd_peer_get_slice(int fd, char **slice) {
208 : : struct ucred ucred;
209 : : int r;
210 : :
211 [ # # # # ]: 0 : assert_return(fd >= 0, -EBADF);
212 [ # # # # ]: 0 : assert_return(slice, -EINVAL);
213 : :
214 : 0 : r = getpeercred(fd, &ucred);
215 [ # # ]: 0 : if (r < 0)
216 : 0 : return r;
217 : :
218 : 0 : return cg_pid_get_slice(ucred.pid, slice);
219 : : }
220 : :
221 : 0 : _public_ int sd_peer_get_user_slice(int fd, char **slice) {
222 : : struct ucred ucred;
223 : : int r;
224 : :
225 [ # # # # ]: 0 : assert_return(fd >= 0, -EBADF);
226 [ # # # # ]: 0 : assert_return(slice, -EINVAL);
227 : :
228 : 0 : r = getpeercred(fd, &ucred);
229 [ # # ]: 0 : if (r < 0)
230 : 0 : return r;
231 : :
232 : 0 : return cg_pid_get_user_slice(ucred.pid, slice);
233 : : }
234 : :
235 : 0 : _public_ int sd_peer_get_cgroup(int fd, char **cgroup) {
236 : : struct ucred ucred;
237 : : int r;
238 : :
239 [ # # # # ]: 0 : assert_return(fd >= 0, -EBADF);
240 [ # # # # ]: 0 : assert_return(cgroup, -EINVAL);
241 : :
242 : 0 : r = getpeercred(fd, &ucred);
243 [ # # ]: 0 : if (r < 0)
244 : 0 : return r;
245 : :
246 : 0 : return sd_pid_get_cgroup(ucred.pid, cgroup);
247 : : }
248 : :
249 : 24 : static int file_of_uid(uid_t uid, char **p) {
250 : :
251 [ - + - + ]: 24 : assert_return(uid_is_valid(uid), -EINVAL);
252 [ - + ]: 24 : assert(p);
253 : :
254 [ - + ]: 24 : if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
255 : 0 : return -ENOMEM;
256 : :
257 : 24 : return 0;
258 : : }
259 : :
260 : 4 : _public_ int sd_uid_get_state(uid_t uid, char**state) {
261 : 4 : _cleanup_free_ char *p = NULL, *s = NULL;
262 : : int r;
263 : :
264 [ - + - + ]: 4 : assert_return(state, -EINVAL);
265 : :
266 : 4 : r = file_of_uid(uid, &p);
267 [ - + ]: 4 : if (r < 0)
268 : 0 : return r;
269 : :
270 : 4 : r = parse_env_file(NULL, p, "STATE", &s);
271 [ - + ]: 4 : if (r == -ENOENT) {
272 : 0 : r = free_and_strdup(&s, "offline");
273 [ # # ]: 0 : if (r < 0)
274 : 0 : return r;
275 [ - + ]: 4 : } else if (r < 0)
276 : 0 : return r;
277 [ - + ]: 4 : else if (isempty(s))
278 : 0 : return -EIO;
279 : :
280 : 4 : *state = TAKE_PTR(s);
281 : 4 : return 0;
282 : : }
283 : :
284 : 4 : _public_ int sd_uid_get_display(uid_t uid, char **session) {
285 : 4 : _cleanup_free_ char *p = NULL, *s = NULL;
286 : : int r;
287 : :
288 [ - + - + ]: 4 : assert_return(session, -EINVAL);
289 : :
290 : 4 : r = file_of_uid(uid, &p);
291 [ - + ]: 4 : if (r < 0)
292 : 0 : return r;
293 : :
294 : 4 : r = parse_env_file(NULL, p, "DISPLAY", &s);
295 [ - + ]: 4 : if (r == -ENOENT)
296 : 0 : return -ENODATA;
297 [ - + ]: 4 : if (r < 0)
298 : 0 : return r;
299 [ - + ]: 4 : if (isempty(s))
300 : 0 : return -ENODATA;
301 : :
302 : 4 : *session = TAKE_PTR(s);
303 : :
304 : 4 : return 0;
305 : : }
306 : :
307 : 36 : static int file_of_seat(const char *seat, char **_p) {
308 : : char *p;
309 : : int r;
310 : :
311 [ - + ]: 36 : assert(_p);
312 : :
313 [ + + ]: 36 : if (seat) {
314 [ - + ]: 32 : if (!filename_is_valid(seat))
315 : 0 : return -EINVAL;
316 : :
317 : 32 : p = path_join("/run/systemd/seats", seat);
318 : : } else {
319 [ + - ]: 4 : _cleanup_free_ char *buf = NULL;
320 : :
321 : 4 : r = sd_session_get_seat(NULL, &buf);
322 [ - + ]: 4 : if (r < 0)
323 : 0 : return r;
324 : :
325 : 4 : p = path_join("/run/systemd/seats", buf);
326 : : }
327 [ - + ]: 36 : if (!p)
328 : 0 : return -ENOMEM;
329 : :
330 : 36 : *_p = TAKE_PTR(p);
331 : 36 : return 0;
332 : : }
333 : :
334 : 8 : _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
335 : 8 : _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
336 : : size_t l;
337 : : int r;
338 : : const char *word, *variable, *state;
339 : :
340 [ - + - + ]: 8 : assert_return(uid_is_valid(uid), -EINVAL);
341 : :
342 : 8 : r = file_of_seat(seat, &p);
343 [ - + ]: 8 : if (r < 0)
344 : 0 : return r;
345 : :
346 [ + + ]: 8 : variable = require_active ? "ACTIVE_UID" : "UIDS";
347 : :
348 : 8 : r = parse_env_file(NULL, p, variable, &s);
349 [ - + ]: 8 : if (r == -ENOENT)
350 : 0 : return 0;
351 [ - + ]: 8 : if (r < 0)
352 : 0 : return r;
353 [ - + ]: 8 : if (isempty(s))
354 : 0 : return 0;
355 : :
356 [ - + ]: 8 : if (asprintf(&t, UID_FMT, uid) < 0)
357 : 0 : return -ENOMEM;
358 : :
359 [ + - ]: 8 : FOREACH_WORD(word, l, s, state)
360 [ + - ]: 8 : if (strneq(t, word, l))
361 : 8 : return 1;
362 : :
363 : 0 : return 0;
364 : : }
365 : :
366 : 16 : static int uid_get_array(uid_t uid, const char *variable, char ***array) {
367 : 16 : _cleanup_free_ char *p = NULL, *s = NULL;
368 : : char **a;
369 : : int r;
370 : :
371 [ - + ]: 16 : assert(variable);
372 : :
373 : 16 : r = file_of_uid(uid, &p);
374 [ - + ]: 16 : if (r < 0)
375 : 0 : return r;
376 : :
377 : 16 : r = parse_env_file(NULL, p, variable, &s);
378 [ + - + - : 16 : if (r == -ENOENT || (r >= 0 && isempty(s))) {
- + ]
379 [ # # ]: 0 : if (array)
380 : 0 : *array = NULL;
381 : 0 : return 0;
382 : : }
383 [ - + ]: 16 : if (r < 0)
384 : 0 : return r;
385 : :
386 : 16 : a = strv_split(s, " ");
387 [ - + ]: 16 : if (!a)
388 : 0 : return -ENOMEM;
389 : :
390 : 16 : strv_uniq(a);
391 : 16 : r = (int) strv_length(a);
392 : :
393 [ + + ]: 16 : if (array)
394 : 8 : *array = a;
395 : : else
396 : 8 : strv_free(a);
397 : :
398 : 16 : return r;
399 : : }
400 : :
401 : 8 : _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
402 [ - + ]: 8 : return uid_get_array(
403 : : uid,
404 : : require_active == 0 ? "ONLINE_SESSIONS" :
405 [ # # ]: 0 : require_active > 0 ? "ACTIVE_SESSIONS" :
406 : : "SESSIONS",
407 : : sessions);
408 : : }
409 : :
410 : 8 : _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
411 [ - + ]: 8 : return uid_get_array(
412 : : uid,
413 : : require_active == 0 ? "ONLINE_SEATS" :
414 [ # # ]: 0 : require_active > 0 ? "ACTIVE_SEATS" :
415 : : "SEATS",
416 : : seats);
417 : : }
418 : :
419 : 44 : static int file_of_session(const char *session, char **_p) {
420 : : char *p;
421 : : int r;
422 : :
423 [ - + ]: 44 : assert(_p);
424 : :
425 [ + + ]: 44 : if (session) {
426 [ - + ]: 40 : if (!session_id_valid(session))
427 : 0 : return -EINVAL;
428 : :
429 : 40 : p = path_join("/run/systemd/sessions", session);
430 : : } else {
431 [ + - ]: 4 : _cleanup_free_ char *buf = NULL;
432 : :
433 : 4 : r = sd_pid_get_session(0, &buf);
434 [ - + ]: 4 : if (r < 0)
435 : 0 : return r;
436 : :
437 : 4 : p = path_join("/run/systemd/sessions", buf);
438 : : }
439 : :
440 [ - + ]: 44 : if (!p)
441 : 0 : return -ENOMEM;
442 : :
443 : 44 : *_p = p;
444 : 44 : return 0;
445 : : }
446 : :
447 : 4 : _public_ int sd_session_is_active(const char *session) {
448 : 4 : _cleanup_free_ char *p = NULL, *s = NULL;
449 : : int r;
450 : :
451 : 4 : r = file_of_session(session, &p);
452 [ - + ]: 4 : if (r < 0)
453 : 0 : return r;
454 : :
455 : 4 : r = parse_env_file(NULL, p, "ACTIVE", &s);
456 [ - + ]: 4 : if (r == -ENOENT)
457 : 0 : return -ENXIO;
458 [ - + ]: 4 : if (r < 0)
459 : 0 : return r;
460 [ - + ]: 4 : if (isempty(s))
461 : 0 : return -EIO;
462 : :
463 : 4 : return parse_boolean(s);
464 : : }
465 : :
466 : 4 : _public_ int sd_session_is_remote(const char *session) {
467 : 4 : _cleanup_free_ char *p = NULL, *s = NULL;
468 : : int r;
469 : :
470 : 4 : r = file_of_session(session, &p);
471 [ - + ]: 4 : if (r < 0)
472 : 0 : return r;
473 : :
474 : 4 : r = parse_env_file(NULL, p, "REMOTE", &s);
475 [ - + ]: 4 : if (r == -ENOENT)
476 : 0 : return -ENXIO;
477 [ - + ]: 4 : if (r < 0)
478 : 0 : return r;
479 [ - + ]: 4 : if (isempty(s))
480 : 0 : return -ENODATA;
481 : :
482 : 4 : return parse_boolean(s);
483 : : }
484 : :
485 : 4 : _public_ int sd_session_get_state(const char *session, char **state) {
486 : 4 : _cleanup_free_ char *p = NULL, *s = NULL;
487 : : int r;
488 : :
489 [ - + - + ]: 4 : assert_return(state, -EINVAL);
490 : :
491 : 4 : r = file_of_session(session, &p);
492 [ - + ]: 4 : if (r < 0)
493 : 0 : return r;
494 : :
495 : 4 : r = parse_env_file(NULL, p, "STATE", &s);
496 [ - + ]: 4 : if (r == -ENOENT)
497 : 0 : return -ENXIO;
498 [ - + ]: 4 : if (r < 0)
499 : 0 : return r;
500 [ - + ]: 4 : if (isempty(s))
501 : 0 : return -EIO;
502 : :
503 : 4 : *state = TAKE_PTR(s);
504 : :
505 : 4 : return 0;
506 : : }
507 : :
508 : 4 : _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
509 : : int r;
510 : 4 : _cleanup_free_ char *p = NULL, *s = NULL;
511 : :
512 [ - + - + ]: 4 : assert_return(uid, -EINVAL);
513 : :
514 : 4 : r = file_of_session(session, &p);
515 [ - + ]: 4 : if (r < 0)
516 : 0 : return r;
517 : :
518 : 4 : r = parse_env_file(NULL, p, "UID", &s);
519 [ - + ]: 4 : if (r == -ENOENT)
520 : 0 : return -ENXIO;
521 [ - + ]: 4 : if (r < 0)
522 : 0 : return r;
523 [ - + ]: 4 : if (isempty(s))
524 : 0 : return -EIO;
525 : :
526 : 4 : return parse_uid(s, uid);
527 : : }
528 : :
529 : 28 : static int session_get_string(const char *session, const char *field, char **value) {
530 : 28 : _cleanup_free_ char *p = NULL, *s = NULL;
531 : : int r;
532 : :
533 [ - + - + ]: 28 : assert_return(value, -EINVAL);
534 [ - + ]: 28 : assert(field);
535 : :
536 : 28 : r = file_of_session(session, &p);
537 [ - + ]: 28 : if (r < 0)
538 : 0 : return r;
539 : :
540 : 28 : r = parse_env_file(NULL, p, field, &s);
541 [ - + ]: 28 : if (r == -ENOENT)
542 : 0 : return -ENXIO;
543 [ - + ]: 28 : if (r < 0)
544 : 0 : return r;
545 [ + + ]: 28 : if (isempty(s))
546 : 8 : return -ENODATA;
547 : :
548 : 20 : *value = TAKE_PTR(s);
549 : 20 : return 0;
550 : : }
551 : :
552 : 8 : _public_ int sd_session_get_seat(const char *session, char **seat) {
553 : 8 : return session_get_string(session, "SEAT", seat);
554 : : }
555 : :
556 : 0 : _public_ int sd_session_get_tty(const char *session, char **tty) {
557 : 0 : return session_get_string(session, "TTY", tty);
558 : : }
559 : :
560 : 0 : _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
561 : 0 : _cleanup_free_ char *vtnr_string = NULL;
562 : : unsigned u;
563 : : int r;
564 : :
565 [ # # # # ]: 0 : assert_return(vtnr, -EINVAL);
566 : :
567 : 0 : r = session_get_string(session, "VTNR", &vtnr_string);
568 [ # # ]: 0 : if (r < 0)
569 : 0 : return r;
570 : :
571 : 0 : r = safe_atou(vtnr_string, &u);
572 [ # # ]: 0 : if (r < 0)
573 : 0 : return r;
574 : :
575 : 0 : *vtnr = u;
576 : 0 : return 0;
577 : : }
578 : :
579 : 0 : _public_ int sd_session_get_service(const char *session, char **service) {
580 : 0 : return session_get_string(session, "SERVICE", service);
581 : : }
582 : :
583 : 4 : _public_ int sd_session_get_type(const char *session, char **type) {
584 : 4 : return session_get_string(session, "TYPE", type);
585 : : }
586 : :
587 : 4 : _public_ int sd_session_get_class(const char *session, char **class) {
588 : 4 : return session_get_string(session, "CLASS", class);
589 : : }
590 : :
591 : 0 : _public_ int sd_session_get_desktop(const char *session, char **desktop) {
592 : 0 : _cleanup_free_ char *escaped = NULL;
593 : : char *t;
594 : : int r;
595 : :
596 [ # # # # ]: 0 : assert_return(desktop, -EINVAL);
597 : :
598 : 0 : r = session_get_string(session, "DESKTOP", &escaped);
599 [ # # ]: 0 : if (r < 0)
600 : 0 : return r;
601 : :
602 : 0 : r = cunescape(escaped, 0, &t);
603 [ # # ]: 0 : if (r < 0)
604 : 0 : return r;
605 : :
606 : 0 : *desktop = t;
607 : 0 : return 0;
608 : : }
609 : :
610 : 4 : _public_ int sd_session_get_display(const char *session, char **display) {
611 : 4 : return session_get_string(session, "DISPLAY", display);
612 : : }
613 : :
614 : 4 : _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
615 : 4 : return session_get_string(session, "REMOTE_USER", remote_user);
616 : : }
617 : :
618 : 4 : _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
619 : 4 : return session_get_string(session, "REMOTE_HOST", remote_host);
620 : : }
621 : :
622 : 8 : _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
623 : 8 : _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
624 : : int r;
625 : :
626 [ - + # # : 8 : assert_return(session || uid, -EINVAL);
- + ]
627 : :
628 : 8 : r = file_of_seat(seat, &p);
629 [ - + ]: 8 : if (r < 0)
630 : 0 : return r;
631 : :
632 : 8 : r = parse_env_file(NULL, p,
633 : : "ACTIVE", &s,
634 : : "ACTIVE_UID", &t);
635 [ - + ]: 8 : if (r == -ENOENT)
636 : 0 : return -ENXIO;
637 [ - + ]: 8 : if (r < 0)
638 : 0 : return r;
639 : :
640 [ + - - + ]: 8 : if (session && !s)
641 : 0 : return -ENODATA;
642 : :
643 [ + + - + ]: 8 : if (uid && !t)
644 : 0 : return -ENODATA;
645 : :
646 [ + + + - ]: 8 : if (uid && t) {
647 : 4 : r = parse_uid(t, uid);
648 [ - + ]: 4 : if (r < 0)
649 : 0 : return r;
650 : : }
651 : :
652 [ + - + - ]: 8 : if (session && s)
653 : 8 : *session = TAKE_PTR(s);
654 : :
655 : 8 : return 0;
656 : : }
657 : :
658 : 8 : _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
659 : 8 : _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
660 : 8 : _cleanup_strv_free_ char **a = NULL;
661 : 8 : _cleanup_free_ uid_t *b = NULL;
662 : 8 : unsigned n = 0;
663 : : int r;
664 : :
665 : 8 : r = file_of_seat(seat, &p);
666 [ - + ]: 8 : if (r < 0)
667 : 0 : return r;
668 : :
669 : 8 : r = parse_env_file(NULL, p,
670 : : "SESSIONS", &s,
671 : : "UIDS", &t);
672 [ - + ]: 8 : if (r == -ENOENT)
673 : 0 : return -ENXIO;
674 [ - + ]: 8 : if (r < 0)
675 : 0 : return r;
676 : :
677 [ + - ]: 8 : if (s) {
678 : 8 : a = strv_split(s, " ");
679 [ - + ]: 8 : if (!a)
680 : 0 : return -ENOMEM;
681 : : }
682 : :
683 [ + + + - ]: 8 : if (uids && t) {
684 : : const char *word, *state;
685 : : size_t l;
686 : :
687 [ + + ]: 8 : FOREACH_WORD(word, l, t, state)
688 : 4 : n++;
689 : :
690 [ + - ]: 4 : if (n > 0) {
691 : 4 : unsigned i = 0;
692 : :
693 : 4 : b = new(uid_t, n);
694 [ - + ]: 4 : if (!b)
695 : 0 : return -ENOMEM;
696 : :
697 [ + + ]: 8 : FOREACH_WORD(word, l, t, state) {
698 [ + - ]: 4 : _cleanup_free_ char *k = NULL;
699 : :
700 : 4 : k = strndup(word, l);
701 [ - + ]: 4 : if (!k)
702 : 0 : return -ENOMEM;
703 : :
704 : 4 : r = parse_uid(k, b + i);
705 [ - + ]: 4 : if (r < 0)
706 : 0 : return r;
707 : :
708 : 4 : i++;
709 : : }
710 : : }
711 : : }
712 : :
713 : 8 : r = (int) strv_length(a);
714 : :
715 [ + + ]: 8 : if (sessions)
716 : 4 : *sessions = TAKE_PTR(a);
717 : :
718 [ + + ]: 8 : if (uids)
719 : 4 : *uids = TAKE_PTR(b);
720 : :
721 [ + + ]: 8 : if (n_uids)
722 : 4 : *n_uids = n;
723 : :
724 : 8 : return r;
725 : : }
726 : :
727 : 12 : static int seat_get_can(const char *seat, const char *variable) {
728 : 12 : _cleanup_free_ char *p = NULL, *s = NULL;
729 : : int r;
730 : :
731 [ - + ]: 12 : assert(variable);
732 : :
733 : 12 : r = file_of_seat(seat, &p);
734 [ - + ]: 12 : if (r < 0)
735 : 0 : return r;
736 : :
737 : 12 : r = parse_env_file(NULL, p,
738 : : variable, &s);
739 [ - + ]: 12 : if (r == -ENOENT)
740 : 0 : return -ENXIO;
741 [ - + ]: 12 : if (r < 0)
742 : 0 : return r;
743 [ - + ]: 12 : if (isempty(s))
744 : 0 : return -ENODATA;
745 : :
746 : 12 : return parse_boolean(s);
747 : : }
748 : :
749 : 4 : _public_ int sd_seat_can_multi_session(const char *seat) {
750 : 4 : return seat_get_can(seat, "CAN_MULTI_SESSION");
751 : : }
752 : :
753 : 4 : _public_ int sd_seat_can_tty(const char *seat) {
754 : 4 : return seat_get_can(seat, "CAN_TTY");
755 : : }
756 : :
757 : 4 : _public_ int sd_seat_can_graphical(const char *seat) {
758 : 4 : return seat_get_can(seat, "CAN_GRAPHICAL");
759 : : }
760 : :
761 : 8 : _public_ int sd_get_seats(char ***seats) {
762 : : int r;
763 : :
764 : 8 : r = get_files_in_directory("/run/systemd/seats/", seats);
765 [ - + ]: 8 : if (r == -ENOENT) {
766 [ # # ]: 0 : if (seats)
767 : 0 : *seats = NULL;
768 : 0 : return 0;
769 : : }
770 : 8 : return r;
771 : : }
772 : :
773 : 8 : _public_ int sd_get_sessions(char ***sessions) {
774 : : int r;
775 : :
776 : 8 : r = get_files_in_directory("/run/systemd/sessions/", sessions);
777 [ - + ]: 8 : if (r == -ENOENT) {
778 [ # # ]: 0 : if (sessions)
779 : 0 : *sessions = NULL;
780 : 0 : return 0;
781 : : }
782 : 8 : return r;
783 : : }
784 : :
785 : 8 : _public_ int sd_get_uids(uid_t **users) {
786 : 8 : _cleanup_closedir_ DIR *d;
787 : : struct dirent *de;
788 : 8 : int r = 0;
789 : 8 : unsigned n = 0;
790 : 8 : _cleanup_free_ uid_t *l = NULL;
791 : :
792 : 8 : d = opendir("/run/systemd/users/");
793 [ - + ]: 8 : if (!d) {
794 [ # # ]: 0 : if (errno == ENOENT) {
795 [ # # ]: 0 : if (users)
796 : 0 : *users = NULL;
797 : 0 : return 0;
798 : : }
799 : 0 : return -errno;
800 : : }
801 : :
802 [ + + - + ]: 32 : FOREACH_DIRENT_ALL(de, d, return -errno) {
803 : : int k;
804 : : uid_t uid;
805 : :
806 : 24 : dirent_ensure_type(d, de);
807 : :
808 [ + + ]: 24 : if (!dirent_is_file(de))
809 : 16 : continue;
810 : :
811 : 8 : k = parse_uid(de->d_name, &uid);
812 [ - + ]: 8 : if (k < 0)
813 : 0 : continue;
814 : :
815 [ + + ]: 8 : if (users) {
816 [ + - ]: 4 : if ((unsigned) r >= n) {
817 : : uid_t *t;
818 : :
819 : 4 : n = MAX(16, 2*r);
820 : 4 : t = reallocarray(l, sizeof(uid_t), n);
821 [ - + ]: 4 : if (!t)
822 : 0 : return -ENOMEM;
823 : :
824 : 4 : l = t;
825 : : }
826 : :
827 [ - + ]: 4 : assert((unsigned) r < n);
828 : 4 : l[r++] = uid;
829 : : } else
830 : 4 : r++;
831 : : }
832 : :
833 [ + + ]: 8 : if (users)
834 : 4 : *users = TAKE_PTR(l);
835 : :
836 : 8 : return r;
837 : : }
838 : :
839 : 8 : _public_ int sd_get_machine_names(char ***machines) {
840 : 8 : _cleanup_strv_free_ char **l = NULL;
841 : : char **a, **b;
842 : : int r;
843 : :
844 : 8 : r = get_files_in_directory("/run/systemd/machines/", &l);
845 [ - + ]: 8 : if (r == -ENOENT) {
846 [ # # ]: 0 : if (machines)
847 : 0 : *machines = NULL;
848 : 0 : return 0;
849 : : }
850 [ - + ]: 8 : if (r < 0)
851 : 0 : return r;
852 : :
853 [ - + ]: 8 : if (l) {
854 : 0 : r = 0;
855 : :
856 : : /* Filter out the unit: symlinks */
857 [ # # ]: 0 : for (a = b = l; *a; a++) {
858 [ # # # # ]: 0 : if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
859 : 0 : free(*a);
860 : : else {
861 : 0 : *b = *a;
862 : 0 : b++;
863 : 0 : r++;
864 : : }
865 : : }
866 : :
867 : 0 : *b = NULL;
868 : : }
869 : :
870 [ + + ]: 8 : if (machines)
871 : 4 : *machines = TAKE_PTR(l);
872 : :
873 : 8 : return r;
874 : : }
875 : :
876 : 0 : _public_ int sd_machine_get_class(const char *machine, char **class) {
877 : 0 : _cleanup_free_ char *c = NULL;
878 : : const char *p;
879 : : int r;
880 : :
881 [ # # # # ]: 0 : assert_return(class, -EINVAL);
882 : :
883 [ # # ]: 0 : if (streq(machine, ".host")) {
884 : 0 : c = strdup("host");
885 [ # # ]: 0 : if (!c)
886 : 0 : return -ENOMEM;
887 : : } else {
888 [ # # ]: 0 : if (!machine_name_is_valid(machine))
889 : 0 : return -EINVAL;
890 : :
891 [ # # # # : 0 : p = strjoina("/run/systemd/machines/", machine);
# # # # #
# # # ]
892 : 0 : r = parse_env_file(NULL, p, "CLASS", &c);
893 [ # # ]: 0 : if (r == -ENOENT)
894 : 0 : return -ENXIO;
895 [ # # ]: 0 : if (r < 0)
896 : 0 : return r;
897 [ # # ]: 0 : if (!c)
898 : 0 : return -EIO;
899 : : }
900 : :
901 : 0 : *class = TAKE_PTR(c);
902 : 0 : return 0;
903 : : }
904 : :
905 : 0 : _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
906 : 0 : _cleanup_free_ char *netif = NULL;
907 : 0 : size_t l, allocated = 0, nr = 0;
908 : 0 : int *ni = NULL;
909 : : const char *p, *word, *state;
910 : : int r;
911 : :
912 [ # # # # ]: 0 : assert_return(machine_name_is_valid(machine), -EINVAL);
913 [ # # # # ]: 0 : assert_return(ifindices, -EINVAL);
914 : :
915 [ # # # # : 0 : p = strjoina("/run/systemd/machines/", machine);
# # # # #
# # # ]
916 : 0 : r = parse_env_file(NULL, p, "NETIF", &netif);
917 [ # # ]: 0 : if (r == -ENOENT)
918 : 0 : return -ENXIO;
919 [ # # ]: 0 : if (r < 0)
920 : 0 : return r;
921 [ # # ]: 0 : if (!netif) {
922 : 0 : *ifindices = NULL;
923 : 0 : return 0;
924 : : }
925 : :
926 [ # # ]: 0 : FOREACH_WORD(word, l, netif, state) {
927 : 0 : char buf[l+1];
928 : : int ifi;
929 : :
930 : 0 : *(char*) (mempcpy(buf, word, l)) = 0;
931 : :
932 [ # # ]: 0 : if (parse_ifindex(buf, &ifi) < 0)
933 : 0 : continue;
934 : :
935 [ # # ]: 0 : if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
936 : 0 : free(ni);
937 : 0 : return -ENOMEM;
938 : : }
939 : :
940 : 0 : ni[nr++] = ifi;
941 : : }
942 : :
943 : 0 : *ifindices = ni;
944 : 0 : return nr;
945 : : }
946 : :
947 : 0 : static int MONITOR_TO_FD(sd_login_monitor *m) {
948 : 0 : return (int) (unsigned long) m - 1;
949 : : }
950 : :
951 : 0 : static sd_login_monitor* FD_TO_MONITOR(int fd) {
952 : 0 : return (sd_login_monitor*) (unsigned long) (fd + 1);
953 : : }
954 : :
955 : 0 : _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
956 : 0 : _cleanup_close_ int fd = -1;
957 : 0 : bool good = false;
958 : : int k;
959 : :
960 [ # # # # ]: 0 : assert_return(m, -EINVAL);
961 : :
962 : 0 : fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
963 [ # # ]: 0 : if (fd < 0)
964 : 0 : return -errno;
965 : :
966 [ # # # # ]: 0 : if (!category || streq(category, "seat")) {
967 : 0 : k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
968 [ # # ]: 0 : if (k < 0)
969 : 0 : return -errno;
970 : :
971 : 0 : good = true;
972 : : }
973 : :
974 [ # # # # ]: 0 : if (!category || streq(category, "session")) {
975 : 0 : k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
976 [ # # ]: 0 : if (k < 0)
977 : 0 : return -errno;
978 : :
979 : 0 : good = true;
980 : : }
981 : :
982 [ # # # # ]: 0 : if (!category || streq(category, "uid")) {
983 : 0 : k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
984 [ # # ]: 0 : if (k < 0)
985 : 0 : return -errno;
986 : :
987 : 0 : good = true;
988 : : }
989 : :
990 [ # # # # ]: 0 : if (!category || streq(category, "machine")) {
991 : 0 : k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
992 [ # # ]: 0 : if (k < 0)
993 : 0 : return -errno;
994 : :
995 : 0 : good = true;
996 : : }
997 : :
998 [ # # ]: 0 : if (!good)
999 : 0 : return -EINVAL;
1000 : :
1001 : 0 : *m = FD_TO_MONITOR(fd);
1002 : 0 : fd = -1;
1003 : :
1004 : 0 : return 0;
1005 : : }
1006 : :
1007 : 0 : _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1008 : : int fd;
1009 : :
1010 [ # # ]: 0 : if (!m)
1011 : 0 : return NULL;
1012 : :
1013 : 0 : fd = MONITOR_TO_FD(m);
1014 : 0 : close_nointr(fd);
1015 : :
1016 : 0 : return NULL;
1017 : : }
1018 : :
1019 : 0 : _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1020 : : int r;
1021 : :
1022 [ # # # # ]: 0 : assert_return(m, -EINVAL);
1023 : :
1024 : 0 : r = flush_fd(MONITOR_TO_FD(m));
1025 [ # # ]: 0 : if (r < 0)
1026 : 0 : return r;
1027 : :
1028 : 0 : return 0;
1029 : : }
1030 : :
1031 : 0 : _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1032 : :
1033 [ # # # # ]: 0 : assert_return(m, -EINVAL);
1034 : :
1035 : 0 : return MONITOR_TO_FD(m);
1036 : : }
1037 : :
1038 : 0 : _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1039 : :
1040 [ # # # # ]: 0 : assert_return(m, -EINVAL);
1041 : :
1042 : : /* For now we will only return POLLIN here, since we don't
1043 : : * need anything else ever for inotify. However, let's have
1044 : : * this API to keep our options open should we later on need
1045 : : * it. */
1046 : 0 : return POLLIN;
1047 : : }
1048 : :
1049 : 0 : _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1050 : :
1051 [ # # # # ]: 0 : assert_return(m, -EINVAL);
1052 [ # # # # ]: 0 : assert_return(timeout_usec, -EINVAL);
1053 : :
1054 : : /* For now we will only return (uint64_t) -1, since we don't
1055 : : * need any timeout. However, let's have this API to keep our
1056 : : * options open should we later on need it. */
1057 : 0 : *timeout_usec = (uint64_t) -1;
1058 : 0 : return 0;
1059 : : }
|