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