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 2 : _public_ int sd_pid_get_session(pid_t pid, char **session) {
42 : int r;
43 :
44 2 : assert_return(pid >= 0, -EINVAL);
45 2 : assert_return(session, -EINVAL);
46 :
47 2 : r = cg_pid_get_session(pid, session);
48 2 : return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
49 : }
50 :
51 1 : _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
52 : int r;
53 :
54 1 : assert_return(pid >= 0, -EINVAL);
55 1 : assert_return(unit, -EINVAL);
56 :
57 1 : r = cg_pid_get_unit(pid, unit);
58 1 : return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
59 : }
60 :
61 1 : _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
62 : int r;
63 :
64 1 : assert_return(pid >= 0, -EINVAL);
65 1 : assert_return(unit, -EINVAL);
66 :
67 1 : r = cg_pid_get_user_unit(pid, unit);
68 1 : 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 1 : _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
82 : int r;
83 :
84 1 : assert_return(pid >= 0, -EINVAL);
85 1 : assert_return(slice, -EINVAL);
86 :
87 1 : r = cg_pid_get_slice(pid, slice);
88 1 : 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 1 : _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
102 : int r;
103 :
104 1 : assert_return(pid >= 0, -EINVAL);
105 1 : assert_return(uid, -EINVAL);
106 :
107 1 : r = cg_pid_get_owner_uid(pid, uid);
108 1 : return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
109 : }
110 :
111 1 : _public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) {
112 : char *c;
113 : int r;
114 :
115 1 : assert_return(pid >= 0, -EINVAL);
116 1 : assert_return(cgroup, -EINVAL);
117 :
118 1 : r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &c);
119 1 : 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 1 : if (isempty(c)) {
126 0 : free(c);
127 0 : c = strdup("/");
128 0 : if (!c)
129 0 : return -ENOMEM;
130 :
131 : }
132 :
133 1 : *cgroup = c;
134 1 : return 0;
135 : }
136 :
137 2 : _public_ int sd_peer_get_session(int fd, char **session) {
138 2 : struct ucred ucred = {};
139 : int r;
140 :
141 2 : assert_return(fd >= 0, -EBADF);
142 2 : assert_return(session, -EINVAL);
143 :
144 2 : r = getpeercred(fd, &ucred);
145 2 : if (r < 0)
146 0 : return r;
147 :
148 2 : 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 6 : static int file_of_uid(uid_t uid, char **p) {
250 :
251 6 : assert_return(uid_is_valid(uid), -EINVAL);
252 6 : assert(p);
253 :
254 6 : if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
255 0 : return -ENOMEM;
256 :
257 6 : return 0;
258 : }
259 :
260 1 : _public_ int sd_uid_get_state(uid_t uid, char**state) {
261 1 : _cleanup_free_ char *p = NULL, *s = NULL;
262 : int r;
263 :
264 1 : assert_return(state, -EINVAL);
265 :
266 1 : r = file_of_uid(uid, &p);
267 1 : if (r < 0)
268 0 : return r;
269 :
270 1 : r = parse_env_file(NULL, p, "STATE", &s);
271 1 : if (r == -ENOENT) {
272 0 : r = free_and_strdup(&s, "offline");
273 0 : if (r < 0)
274 0 : return r;
275 1 : } else if (r < 0)
276 0 : return r;
277 1 : else if (isempty(s))
278 0 : return -EIO;
279 :
280 1 : *state = TAKE_PTR(s);
281 1 : return 0;
282 : }
283 :
284 1 : _public_ int sd_uid_get_display(uid_t uid, char **session) {
285 1 : _cleanup_free_ char *p = NULL, *s = NULL;
286 : int r;
287 :
288 1 : assert_return(session, -EINVAL);
289 :
290 1 : r = file_of_uid(uid, &p);
291 1 : if (r < 0)
292 0 : return r;
293 :
294 1 : r = parse_env_file(NULL, p, "DISPLAY", &s);
295 1 : if (r == -ENOENT)
296 0 : return -ENODATA;
297 1 : if (r < 0)
298 0 : return r;
299 1 : if (isempty(s))
300 0 : return -ENODATA;
301 :
302 1 : *session = TAKE_PTR(s);
303 :
304 1 : return 0;
305 : }
306 :
307 9 : static int file_of_seat(const char *seat, char **_p) {
308 : char *p;
309 : int r;
310 :
311 9 : assert(_p);
312 :
313 9 : if (seat) {
314 8 : if (!filename_is_valid(seat))
315 0 : return -EINVAL;
316 :
317 8 : p = path_join("/run/systemd/seats", seat);
318 : } else {
319 1 : _cleanup_free_ char *buf = NULL;
320 :
321 1 : r = sd_session_get_seat(NULL, &buf);
322 1 : if (r < 0)
323 0 : return r;
324 :
325 1 : p = path_join("/run/systemd/seats", buf);
326 : }
327 9 : if (!p)
328 0 : return -ENOMEM;
329 :
330 9 : *_p = TAKE_PTR(p);
331 9 : return 0;
332 : }
333 :
334 2 : _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
335 2 : _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
336 : size_t l;
337 : int r;
338 : const char *word, *variable, *state;
339 :
340 2 : assert_return(uid_is_valid(uid), -EINVAL);
341 :
342 2 : r = file_of_seat(seat, &p);
343 2 : if (r < 0)
344 0 : return r;
345 :
346 2 : variable = require_active ? "ACTIVE_UID" : "UIDS";
347 :
348 2 : r = parse_env_file(NULL, p, variable, &s);
349 2 : if (r == -ENOENT)
350 0 : return 0;
351 2 : if (r < 0)
352 0 : return r;
353 2 : if (isempty(s))
354 0 : return 0;
355 :
356 2 : if (asprintf(&t, UID_FMT, uid) < 0)
357 0 : return -ENOMEM;
358 :
359 2 : FOREACH_WORD(word, l, s, state)
360 2 : if (strneq(t, word, l))
361 2 : return 1;
362 :
363 0 : return 0;
364 : }
365 :
366 4 : static int uid_get_array(uid_t uid, const char *variable, char ***array) {
367 4 : _cleanup_free_ char *p = NULL, *s = NULL;
368 : char **a;
369 : int r;
370 :
371 4 : assert(variable);
372 :
373 4 : r = file_of_uid(uid, &p);
374 4 : if (r < 0)
375 0 : return r;
376 :
377 4 : r = parse_env_file(NULL, p, variable, &s);
378 4 : if (r == -ENOENT || (r >= 0 && isempty(s))) {
379 0 : if (array)
380 0 : *array = NULL;
381 0 : return 0;
382 : }
383 4 : if (r < 0)
384 0 : return r;
385 :
386 4 : a = strv_split(s, " ");
387 4 : if (!a)
388 0 : return -ENOMEM;
389 :
390 4 : strv_uniq(a);
391 4 : r = (int) strv_length(a);
392 :
393 4 : if (array)
394 2 : *array = a;
395 : else
396 2 : strv_free(a);
397 :
398 4 : return r;
399 : }
400 :
401 2 : _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
402 2 : 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 2 : _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
411 2 : 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 11 : static int file_of_session(const char *session, char **_p) {
420 : char *p;
421 : int r;
422 :
423 11 : assert(_p);
424 :
425 11 : if (session) {
426 10 : if (!session_id_valid(session))
427 0 : return -EINVAL;
428 :
429 10 : p = path_join("/run/systemd/sessions", session);
430 : } else {
431 1 : _cleanup_free_ char *buf = NULL;
432 :
433 1 : r = sd_pid_get_session(0, &buf);
434 1 : if (r < 0)
435 0 : return r;
436 :
437 1 : p = path_join("/run/systemd/sessions", buf);
438 : }
439 :
440 11 : if (!p)
441 0 : return -ENOMEM;
442 :
443 11 : *_p = p;
444 11 : return 0;
445 : }
446 :
447 1 : _public_ int sd_session_is_active(const char *session) {
448 1 : _cleanup_free_ char *p = NULL, *s = NULL;
449 : int r;
450 :
451 1 : r = file_of_session(session, &p);
452 1 : if (r < 0)
453 0 : return r;
454 :
455 1 : r = parse_env_file(NULL, p, "ACTIVE", &s);
456 1 : if (r == -ENOENT)
457 0 : return -ENXIO;
458 1 : if (r < 0)
459 0 : return r;
460 1 : if (isempty(s))
461 0 : return -EIO;
462 :
463 1 : return parse_boolean(s);
464 : }
465 :
466 1 : _public_ int sd_session_is_remote(const char *session) {
467 1 : _cleanup_free_ char *p = NULL, *s = NULL;
468 : int r;
469 :
470 1 : r = file_of_session(session, &p);
471 1 : if (r < 0)
472 0 : return r;
473 :
474 1 : r = parse_env_file(NULL, p, "REMOTE", &s);
475 1 : if (r == -ENOENT)
476 0 : return -ENXIO;
477 1 : if (r < 0)
478 0 : return r;
479 1 : if (isempty(s))
480 0 : return -ENODATA;
481 :
482 1 : return parse_boolean(s);
483 : }
484 :
485 1 : _public_ int sd_session_get_state(const char *session, char **state) {
486 1 : _cleanup_free_ char *p = NULL, *s = NULL;
487 : int r;
488 :
489 1 : assert_return(state, -EINVAL);
490 :
491 1 : r = file_of_session(session, &p);
492 1 : if (r < 0)
493 0 : return r;
494 :
495 1 : r = parse_env_file(NULL, p, "STATE", &s);
496 1 : if (r == -ENOENT)
497 0 : return -ENXIO;
498 1 : if (r < 0)
499 0 : return r;
500 1 : if (isempty(s))
501 0 : return -EIO;
502 :
503 1 : *state = TAKE_PTR(s);
504 :
505 1 : return 0;
506 : }
507 :
508 1 : _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
509 : int r;
510 1 : _cleanup_free_ char *p = NULL, *s = NULL;
511 :
512 1 : assert_return(uid, -EINVAL);
513 :
514 1 : r = file_of_session(session, &p);
515 1 : if (r < 0)
516 0 : return r;
517 :
518 1 : r = parse_env_file(NULL, p, "UID", &s);
519 1 : if (r == -ENOENT)
520 0 : return -ENXIO;
521 1 : if (r < 0)
522 0 : return r;
523 1 : if (isempty(s))
524 0 : return -EIO;
525 :
526 1 : return parse_uid(s, uid);
527 : }
528 :
529 7 : static int session_get_string(const char *session, const char *field, char **value) {
530 7 : _cleanup_free_ char *p = NULL, *s = NULL;
531 : int r;
532 :
533 7 : assert_return(value, -EINVAL);
534 7 : assert(field);
535 :
536 7 : r = file_of_session(session, &p);
537 7 : if (r < 0)
538 0 : return r;
539 :
540 7 : r = parse_env_file(NULL, p, field, &s);
541 7 : if (r == -ENOENT)
542 0 : return -ENXIO;
543 7 : if (r < 0)
544 0 : return r;
545 7 : if (isempty(s))
546 2 : return -ENODATA;
547 :
548 5 : *value = TAKE_PTR(s);
549 5 : return 0;
550 : }
551 :
552 2 : _public_ int sd_session_get_seat(const char *session, char **seat) {
553 2 : 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 1 : _public_ int sd_session_get_type(const char *session, char **type) {
584 1 : return session_get_string(session, "TYPE", type);
585 : }
586 :
587 1 : _public_ int sd_session_get_class(const char *session, char **class) {
588 1 : 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 1 : _public_ int sd_session_get_display(const char *session, char **display) {
611 1 : return session_get_string(session, "DISPLAY", display);
612 : }
613 :
614 1 : _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
615 1 : return session_get_string(session, "REMOTE_USER", remote_user);
616 : }
617 :
618 1 : _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
619 1 : return session_get_string(session, "REMOTE_HOST", remote_host);
620 : }
621 :
622 2 : _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
623 2 : _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
624 : int r;
625 :
626 2 : assert_return(session || uid, -EINVAL);
627 :
628 2 : r = file_of_seat(seat, &p);
629 2 : if (r < 0)
630 0 : return r;
631 :
632 2 : r = parse_env_file(NULL, p,
633 : "ACTIVE", &s,
634 : "ACTIVE_UID", &t);
635 2 : if (r == -ENOENT)
636 0 : return -ENXIO;
637 2 : if (r < 0)
638 0 : return r;
639 :
640 2 : if (session && !s)
641 0 : return -ENODATA;
642 :
643 2 : if (uid && !t)
644 0 : return -ENODATA;
645 :
646 2 : if (uid && t) {
647 1 : r = parse_uid(t, uid);
648 1 : if (r < 0)
649 0 : return r;
650 : }
651 :
652 2 : if (session && s)
653 2 : *session = TAKE_PTR(s);
654 :
655 2 : return 0;
656 : }
657 :
658 2 : _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
659 2 : _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
660 2 : _cleanup_strv_free_ char **a = NULL;
661 2 : _cleanup_free_ uid_t *b = NULL;
662 2 : unsigned n = 0;
663 : int r;
664 :
665 2 : r = file_of_seat(seat, &p);
666 2 : if (r < 0)
667 0 : return r;
668 :
669 2 : r = parse_env_file(NULL, p,
670 : "SESSIONS", &s,
671 : "UIDS", &t);
672 2 : if (r == -ENOENT)
673 0 : return -ENXIO;
674 2 : if (r < 0)
675 0 : return r;
676 :
677 2 : if (s) {
678 2 : a = strv_split(s, " ");
679 2 : if (!a)
680 0 : return -ENOMEM;
681 : }
682 :
683 2 : if (uids && t) {
684 : const char *word, *state;
685 : size_t l;
686 :
687 2 : FOREACH_WORD(word, l, t, state)
688 1 : n++;
689 :
690 1 : if (n > 0) {
691 1 : unsigned i = 0;
692 :
693 1 : b = new(uid_t, n);
694 1 : if (!b)
695 0 : return -ENOMEM;
696 :
697 2 : FOREACH_WORD(word, l, t, state) {
698 1 : _cleanup_free_ char *k = NULL;
699 :
700 1 : k = strndup(word, l);
701 1 : if (!k)
702 0 : return -ENOMEM;
703 :
704 1 : r = parse_uid(k, b + i);
705 1 : if (r < 0)
706 0 : return r;
707 :
708 1 : i++;
709 : }
710 : }
711 : }
712 :
713 2 : r = (int) strv_length(a);
714 :
715 2 : if (sessions)
716 1 : *sessions = TAKE_PTR(a);
717 :
718 2 : if (uids)
719 1 : *uids = TAKE_PTR(b);
720 :
721 2 : if (n_uids)
722 1 : *n_uids = n;
723 :
724 2 : return r;
725 : }
726 :
727 3 : static int seat_get_can(const char *seat, const char *variable) {
728 3 : _cleanup_free_ char *p = NULL, *s = NULL;
729 : int r;
730 :
731 3 : assert(variable);
732 :
733 3 : r = file_of_seat(seat, &p);
734 3 : if (r < 0)
735 0 : return r;
736 :
737 3 : r = parse_env_file(NULL, p,
738 : variable, &s);
739 3 : if (r == -ENOENT)
740 0 : return -ENXIO;
741 3 : if (r < 0)
742 0 : return r;
743 3 : if (isempty(s))
744 0 : return -ENODATA;
745 :
746 3 : return parse_boolean(s);
747 : }
748 :
749 1 : _public_ int sd_seat_can_multi_session(const char *seat) {
750 1 : return seat_get_can(seat, "CAN_MULTI_SESSION");
751 : }
752 :
753 1 : _public_ int sd_seat_can_tty(const char *seat) {
754 1 : return seat_get_can(seat, "CAN_TTY");
755 : }
756 :
757 1 : _public_ int sd_seat_can_graphical(const char *seat) {
758 1 : return seat_get_can(seat, "CAN_GRAPHICAL");
759 : }
760 :
761 2 : _public_ int sd_get_seats(char ***seats) {
762 : int r;
763 :
764 2 : r = get_files_in_directory("/run/systemd/seats/", seats);
765 2 : if (r == -ENOENT) {
766 0 : if (seats)
767 0 : *seats = NULL;
768 0 : return 0;
769 : }
770 2 : return r;
771 : }
772 :
773 2 : _public_ int sd_get_sessions(char ***sessions) {
774 : int r;
775 :
776 2 : r = get_files_in_directory("/run/systemd/sessions/", sessions);
777 2 : if (r == -ENOENT) {
778 0 : if (sessions)
779 0 : *sessions = NULL;
780 0 : return 0;
781 : }
782 2 : return r;
783 : }
784 :
785 2 : _public_ int sd_get_uids(uid_t **users) {
786 2 : _cleanup_closedir_ DIR *d;
787 : struct dirent *de;
788 2 : int r = 0;
789 2 : unsigned n = 0;
790 2 : _cleanup_free_ uid_t *l = NULL;
791 :
792 2 : d = opendir("/run/systemd/users/");
793 2 : 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 8 : FOREACH_DIRENT_ALL(de, d, return -errno) {
803 : int k;
804 : uid_t uid;
805 :
806 6 : dirent_ensure_type(d, de);
807 :
808 6 : if (!dirent_is_file(de))
809 4 : continue;
810 :
811 2 : k = parse_uid(de->d_name, &uid);
812 2 : if (k < 0)
813 0 : continue;
814 :
815 2 : if (users) {
816 1 : if ((unsigned) r >= n) {
817 : uid_t *t;
818 :
819 1 : n = MAX(16, 2*r);
820 1 : t = reallocarray(l, sizeof(uid_t), n);
821 1 : if (!t)
822 0 : return -ENOMEM;
823 :
824 1 : l = t;
825 : }
826 :
827 1 : assert((unsigned) r < n);
828 1 : l[r++] = uid;
829 : } else
830 1 : r++;
831 : }
832 :
833 2 : if (users)
834 1 : *users = TAKE_PTR(l);
835 :
836 2 : return r;
837 : }
838 :
839 2 : _public_ int sd_get_machine_names(char ***machines) {
840 2 : _cleanup_strv_free_ char **l = NULL;
841 : char **a, **b;
842 : int r;
843 :
844 2 : r = get_files_in_directory("/run/systemd/machines/", &l);
845 2 : if (r == -ENOENT) {
846 0 : if (machines)
847 0 : *machines = NULL;
848 0 : return 0;
849 : }
850 2 : if (r < 0)
851 0 : return r;
852 :
853 2 : 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 2 : if (machines)
871 1 : *machines = TAKE_PTR(l);
872 :
873 2 : 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 : }
|