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