]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/sd-login.c
bus: handle env vars safely
[thirdparty/systemd.git] / src / login / sd-login.c
CommitLineData
74b91131
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
74b91131
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
74b91131 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
74b91131
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <unistd.h>
23#include <string.h>
24#include <errno.h>
034a2a52 25#include <sys/inotify.h>
dace83cb 26#include <sys/poll.h>
74b91131
LP
27
28#include "util.h"
29#include "cgroup-util.h"
30#include "macro.h"
31#include "sd-login.h"
034a2a52 32#include "strv.h"
a5c32cff 33#include "fileio.h"
74b91131 34
034a2a52
LP
35_public_ int sd_pid_get_session(pid_t pid, char **session) {
36 int r;
37 char *cgroup, *p;
38
ba1261bc
LP
39 if (pid < 0)
40 return -EINVAL;
41
034a2a52
LP
42 if (!session)
43 return -EINVAL;
44
ba1261bc 45 r = cg_pid_get_cgroup(pid, NULL, &cgroup);
034a2a52
LP
46 if (r < 0)
47 return r;
48
49 if (!startswith(cgroup, "/user/")) {
50 free(cgroup);
74b91131
LP
51 return -ENOENT;
52 }
53
034a2a52 54 p = strchr(cgroup + 6, '/');
74b91131 55 if (!p) {
034a2a52 56 free(cgroup);
74b91131
LP
57 return -ENOENT;
58 }
59
60 p++;
034a2a52
LP
61 if (startswith(p, "shared/") || streq(p, "shared")) {
62 free(cgroup);
63 return -ENOENT;
64 }
65
74b91131 66 p = strndup(p, strcspn(p, "/"));
034a2a52 67 free(cgroup);
74b91131
LP
68
69 if (!p)
70 return -ENOMEM;
71
72 *session = p;
73 return 0;
74}
75
94fb446e 76_public_ int sd_pid_get_unit(pid_t pid, char **unit) {
9847946e 77
ba1261bc 78 if (pid < 0)
9847946e
LP
79 return -EINVAL;
80
ba1261bc
LP
81 if (!unit)
82 return -EINVAL;
9847946e 83
ba1261bc 84 return cg_pid_get_unit(pid, unit);
9847946e
LP
85}
86
034a2a52
LP
87_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
88 int r;
89 char *root, *cgroup, *p, *cc;
90 struct stat st;
91
ba1261bc
LP
92 if (pid < 0)
93 return -EINVAL;
94
034a2a52
LP
95 if (!uid)
96 return -EINVAL;
97
ba1261bc 98 r = cg_pid_get_cgroup(pid, &root, &cgroup);
034a2a52
LP
99 if (r < 0)
100 return r;
101
102 if (!startswith(cgroup, "/user/")) {
103 free(cgroup);
104 free(root);
105 return -ENOENT;
106 }
107
108 p = strchr(cgroup + 6, '/');
109 if (!p) {
110 free(cgroup);
111 return -ENOENT;
112 }
113
114 p++;
115 p += strcspn(p, "/");
116 *p = 0;
117
118 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, cgroup, &cc);
119 free(root);
120 free(cgroup);
121
122 if (r < 0)
123 return -ENOMEM;
124
125 r = lstat(cc, &st);
126 free(cc);
127
128 if (r < 0)
129 return -errno;
130
131 if (!S_ISDIR(st.st_mode))
132 return -ENOTDIR;
133
134 *uid = st.st_uid;
135 return 0;
136}
137
74b91131
LP
138_public_ int sd_uid_get_state(uid_t uid, char**state) {
139 char *p, *s = NULL;
140 int r;
141
142 if (!state)
143 return -EINVAL;
144
145 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
146 return -ENOMEM;
147
148 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
149 free(p);
150
151 if (r == -ENOENT) {
152 free(s);
153 s = strdup("offline");
154 if (!s)
155 return -ENOMEM;
156
157 *state = s;
158 return 0;
159 } else if (r < 0) {
160 free(s);
161 return r;
162 } else if (!s)
163 return -EIO;
164
165 *state = s;
166 return 0;
167}
168
034a2a52 169_public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
74b91131
LP
170 char *p, *w, *t, *state, *s = NULL;
171 size_t l;
172 int r;
034a2a52 173 const char *variable;
74b91131
LP
174
175 if (!seat)
176 return -EINVAL;
177
034a2a52
LP
178 variable = require_active ? "ACTIVE_UID" : "UIDS";
179
74b91131
LP
180 p = strappend("/run/systemd/seats/", seat);
181 if (!p)
182 return -ENOMEM;
183
034a2a52 184 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
74b91131
LP
185 free(p);
186
187 if (r < 0) {
188 free(s);
189 return r;
190 }
191
192 if (!s)
193 return -EIO;
194
195 if (asprintf(&t, "%lu", (unsigned long) uid) < 0) {
196 free(s);
197 return -ENOMEM;
198 }
199
200 FOREACH_WORD(w, l, s, state) {
641906e9 201 if (strneq(t, w, l)) {
74b91131
LP
202 free(s);
203 free(t);
204
205 return 1;
206 }
207 }
208
209 free(s);
210 free(t);
211
212 return 0;
213}
214
034a2a52
LP
215static int uid_get_array(uid_t uid, const char *variable, char ***array) {
216 char *p, *s = NULL;
217 char **a;
218 int r;
219
034a2a52
LP
220 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
221 return -ENOMEM;
222
223 r = parse_env_file(p, NEWLINE,
224 variable, &s,
225 NULL);
226 free(p);
227
228 if (r < 0) {
229 free(s);
230
231 if (r == -ENOENT) {
d60ef526
LP
232 if (array)
233 *array = NULL;
034a2a52
LP
234 return 0;
235 }
236
237 return r;
238 }
239
240 if (!s) {
d60ef526
LP
241 if (array)
242 *array = NULL;
034a2a52
LP
243 return 0;
244 }
245
246 a = strv_split(s, " ");
247 free(s);
248
249 if (!a)
250 return -ENOMEM;
251
d60ef526
LP
252 strv_uniq(a);
253 r = strv_length(a);
254
255 if (array)
256 *array = a;
257 else
258 strv_free(a);
259
260 return r;
034a2a52
LP
261}
262
263_public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
d18dff43
LP
264 return uid_get_array(
265 uid,
266 require_active == 0 ? "ONLINE_SESSIONS" :
267 require_active > 0 ? "ACTIVE_SESSIONS" :
268 "SESSIONS",
269 sessions);
74b91131
LP
270}
271
034a2a52 272_public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
d18dff43
LP
273 return uid_get_array(
274 uid,
275 require_active == 0 ? "ONLINE_SEATS" :
276 require_active > 0 ? "ACTIVE_SEATS" :
277 "SEATS",
278 seats);
74b91131
LP
279}
280
50b1678a
LP
281static int file_of_session(const char *session, char **_p) {
282 char *p;
74b91131 283 int r;
74b91131 284
50b1678a
LP
285 assert(_p);
286
287 if (session)
288 p = strappend("/run/systemd/sessions/", session);
289 else {
290 char *buf;
291
292 r = sd_pid_get_session(0, &buf);
293 if (r < 0)
294 return r;
295
296 p = strappend("/run/systemd/sessions/", buf);
297 free(buf);
298 }
74b91131 299
74b91131
LP
300 if (!p)
301 return -ENOMEM;
302
50b1678a
LP
303 *_p = p;
304 return 0;
305}
306
307_public_ int sd_session_is_active(const char *session) {
308 int r;
309 char *p, *s = NULL;
310
311 r = file_of_session(session, &p);
312 if (r < 0)
313 return r;
314
74b91131
LP
315 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
316 free(p);
317
318 if (r < 0) {
319 free(s);
320 return r;
321 }
322
323 if (!s)
324 return -EIO;
325
326 r = parse_boolean(s);
327 free(s);
328
329 return r;
330}
331
0604381b
LP
332_public_ int sd_session_get_state(const char *session, char **state) {
333 char *p, *s = NULL;
334 int r;
335
336 if (!state)
337 return -EINVAL;
338
339 r = file_of_session(session, &p);
340 if (r < 0)
341 return r;
342
343 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
344 free(p);
345
346 if (r < 0) {
347 free(s);
348 return r;
349 } else if (!s)
350 return -EIO;
351
352 *state = s;
353 return 0;
354}
355
74b91131
LP
356_public_ int sd_session_get_uid(const char *session, uid_t *uid) {
357 int r;
358 char *p, *s = NULL;
74b91131 359
74b91131
LP
360 if (!uid)
361 return -EINVAL;
362
50b1678a
LP
363 r = file_of_session(session, &p);
364 if (r < 0)
365 return r;
74b91131
LP
366
367 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
368 free(p);
369
370 if (r < 0) {
371 free(s);
372 return r;
373 }
374
375 if (!s)
376 return -EIO;
377
ddd88763 378 r = parse_uid(s, uid);
74b91131
LP
379 free(s);
380
ddd88763 381 return r;
74b91131
LP
382}
383
51f58f08 384static int session_get_string(const char *session, const char *field, char **value) {
74b91131
LP
385 char *p, *s = NULL;
386 int r;
387
51f58f08 388 if (!value)
74b91131
LP
389 return -EINVAL;
390
50b1678a
LP
391 r = file_of_session(session, &p);
392 if (r < 0)
393 return r;
74b91131 394
51f58f08 395 r = parse_env_file(p, NEWLINE, field, &s, NULL);
74b91131
LP
396 free(p);
397
398 if (r < 0) {
399 free(s);
400 return r;
401 }
402
403 if (isempty(s))
404 return -ENOENT;
405
51f58f08 406 *value = s;
74b91131
LP
407 return 0;
408}
409
51f58f08
LP
410_public_ int sd_session_get_seat(const char *session, char **seat) {
411 return session_get_string(session, "SEAT", seat);
412}
eff40633 413
c84f5e4a
LP
414_public_ int sd_session_get_tty(const char *session, char **tty) {
415 return session_get_string(session, "TTY", tty);
416}
417
51f58f08
LP
418_public_ int sd_session_get_service(const char *session, char **service) {
419 return session_get_string(session, "SERVICE", service);
420}
eff40633 421
51f58f08
LP
422_public_ int sd_session_get_type(const char *session, char **type) {
423 return session_get_string(session, "TYPE", type);
424}
eff40633 425
51f58f08
LP
426_public_ int sd_session_get_class(const char *session, char **class) {
427 return session_get_string(session, "CLASS", class);
eff40633
LP
428}
429
fc8af9ff
LP
430_public_ int sd_session_get_display(const char *session, char **display) {
431 return session_get_string(session, "DISPLAY", display);
432}
433
50b1678a
LP
434static int file_of_seat(const char *seat, char **_p) {
435 char *p;
436 int r;
437
438 assert(_p);
439
440 if (seat)
441 p = strappend("/run/systemd/seats/", seat);
442 else {
443 char *buf;
444
445 r = sd_session_get_seat(NULL, &buf);
446 if (r < 0)
447 return r;
448
449 p = strappend("/run/systemd/seats/", buf);
450 free(buf);
451 }
452
453 if (!p)
454 return -ENOMEM;
455
456 *_p = p;
457 return 0;
458}
459
74b91131
LP
460_public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
461 char *p, *s = NULL, *t = NULL;
462 int r;
463
74b91131
LP
464 if (!session && !uid)
465 return -EINVAL;
466
50b1678a
LP
467 r = file_of_seat(seat, &p);
468 if (r < 0)
469 return r;
74b91131
LP
470
471 r = parse_env_file(p, NEWLINE,
472 "ACTIVE", &s,
473 "ACTIVE_UID", &t,
474 NULL);
475 free(p);
476
477 if (r < 0) {
478 free(s);
479 free(t);
480 return r;
481 }
482
483 if (session && !s) {
484 free(t);
034a2a52 485 return -ENOENT;
74b91131
LP
486 }
487
488 if (uid && !t) {
489 free(s);
034a2a52 490 return -ENOENT;
74b91131
LP
491 }
492
493 if (uid && t) {
034a2a52 494 r = parse_uid(t, uid);
74b91131
LP
495 if (r < 0) {
496 free(t);
497 free(s);
498 return r;
499 }
74b91131
LP
500 }
501
502 free(t);
503
504 if (session && s)
505 *session = s;
506 else
507 free(s);
508
509 return 0;
510}
034a2a52
LP
511
512_public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
513 char *p, *s = NULL, *t = NULL, **a = NULL;
514 uid_t *b = NULL;
515 unsigned n = 0;
516 int r;
517
50b1678a
LP
518 r = file_of_seat(seat, &p);
519 if (r < 0)
520 return r;
034a2a52
LP
521
522 r = parse_env_file(p, NEWLINE,
523 "SESSIONS", &s,
524 "ACTIVE_SESSIONS", &t,
525 NULL);
526 free(p);
527
528 if (r < 0) {
529 free(s);
530 free(t);
531 return r;
532 }
533
d60ef526 534 if (s) {
034a2a52
LP
535 a = strv_split(s, " ");
536 if (!a) {
537 free(s);
538 free(t);
539 return -ENOMEM;
540 }
541 }
542
543 free(s);
544
545 if (uids && t) {
546 char *w, *state;
547 size_t l;
034a2a52
LP
548
549 FOREACH_WORD(w, l, t, state)
550 n++;
551
de3756ab
LP
552 if (n == 0)
553 b = NULL;
554 else {
555 unsigned i = 0;
034a2a52 556
de3756ab
LP
557 b = new(uid_t, n);
558 if (!b) {
8ea913b2 559 strv_free(a);
034a2a52
LP
560 return -ENOMEM;
561 }
562
de3756ab
LP
563 FOREACH_WORD(w, l, t, state) {
564 char *k;
034a2a52 565
de3756ab
LP
566 k = strndup(w, l);
567 if (!k) {
568 free(t);
569 free(b);
570 strv_free(a);
571 return -ENOMEM;
572 }
573
574 r = parse_uid(k, b + i);
575 free(k);
576 if (r < 0)
577 continue;
578
579 i++;
580 }
034a2a52
LP
581 }
582 }
583
584 free(t);
585
d60ef526
LP
586 r = strv_length(a);
587
034a2a52
LP
588 if (sessions)
589 *sessions = a;
d60ef526
LP
590 else
591 strv_free(a);
034a2a52
LP
592
593 if (uids)
594 *uids = b;
595
596 if (n_uids)
597 *n_uids = n;
598
d60ef526 599 return r;
034a2a52
LP
600}
601
20747498 602static int seat_get_can(const char *seat, const char *variable) {
add30678
LP
603 char *p, *s = NULL;
604 int r;
605
50b1678a
LP
606 r = file_of_seat(seat, &p);
607 if (r < 0)
608 return r;
add30678
LP
609
610 r = parse_env_file(p, NEWLINE,
20747498 611 variable, &s,
add30678
LP
612 NULL);
613 free(p);
614
615 if (r < 0) {
616 free(s);
617 return r;
618 }
619
620 if (s) {
621 r = parse_boolean(s);
622 free(s);
623 } else
624 r = 0;
625
626 return r;
627}
628
20747498
LP
629_public_ int sd_seat_can_multi_session(const char *seat) {
630 return seat_get_can(seat, "CAN_MULTI_SESSION");
631}
632
633_public_ int sd_seat_can_tty(const char *seat) {
634 return seat_get_can(seat, "CAN_TTY");
635}
636
637_public_ int sd_seat_can_graphical(const char *seat) {
638 return seat_get_can(seat, "CAN_GRAPHICAL");
639}
640
034a2a52 641_public_ int sd_get_seats(char ***seats) {
034a2a52
LP
642 return get_files_in_directory("/run/systemd/seats/", seats);
643}
644
645_public_ int sd_get_sessions(char ***sessions) {
034a2a52
LP
646 return get_files_in_directory("/run/systemd/sessions/", sessions);
647}
648
649_public_ int sd_get_uids(uid_t **users) {
650 DIR *d;
651 int r = 0;
652 unsigned n = 0;
653 uid_t *l = NULL;
654
034a2a52 655 d = opendir("/run/systemd/users/");
8ea913b2
LP
656 if (!d)
657 return -errno;
658
034a2a52 659 for (;;) {
7d5e9c0f
LP
660 struct dirent *de;
661 union dirent_storage buf;
034a2a52
LP
662 int k;
663 uid_t uid;
664
7d5e9c0f 665 k = readdir_r(d, &buf.de, &de);
034a2a52
LP
666 if (k != 0) {
667 r = -k;
668 goto finish;
669 }
670
671 if (!de)
672 break;
673
674 dirent_ensure_type(d, de);
675
676 if (!dirent_is_file(de))
677 continue;
678
679 k = parse_uid(de->d_name, &uid);
680 if (k < 0)
681 continue;
682
d60ef526
LP
683 if (users) {
684 if ((unsigned) r >= n) {
685 uid_t *t;
034a2a52 686
d60ef526
LP
687 n = MAX(16, 2*r);
688 t = realloc(l, sizeof(uid_t) * n);
689 if (!t) {
690 r = -ENOMEM;
691 goto finish;
692 }
034a2a52 693
d60ef526
LP
694 l = t;
695 }
034a2a52 696
d60ef526
LP
697 assert((unsigned) r < n);
698 l[r++] = uid;
699 } else
700 r++;
034a2a52
LP
701 }
702
703finish:
704 if (d)
705 closedir(d);
706
d60ef526
LP
707 if (r >= 0) {
708 if (users)
709 *users = l;
710 } else
034a2a52
LP
711 free(l);
712
713 return r;
714}
715
716static inline int MONITOR_TO_FD(sd_login_monitor *m) {
717 return (int) (unsigned long) m - 1;
718}
719
720static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
721 return (sd_login_monitor*) (unsigned long) (fd + 1);
722}
723
724_public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
034a2a52
LP
725 int fd, k;
726 bool good = false;
727
728 if (!m)
729 return -EINVAL;
730
731 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
732 if (fd < 0)
bcb161b0 733 return -errno;
034a2a52
LP
734
735 if (!category || streq(category, "seat")) {
736 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
737 if (k < 0) {
738 close_nointr_nofail(fd);
739 return -errno;
740 }
741
742 good = true;
743 }
744
745 if (!category || streq(category, "session")) {
746 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
747 if (k < 0) {
748 close_nointr_nofail(fd);
749 return -errno;
750 }
751
752 good = true;
753 }
754
755 if (!category || streq(category, "uid")) {
756 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
757 if (k < 0) {
758 close_nointr_nofail(fd);
759 return -errno;
760 }
761
762 good = true;
763 }
764
765 if (!good) {
766 close_nointr(fd);
767 return -EINVAL;
768 }
769
770 *m = FD_TO_MONITOR(fd);
771 return 0;
772}
773
774_public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
775 int fd;
776
777 if (!m)
778 return NULL;
779
780 fd = MONITOR_TO_FD(m);
781 close_nointr(fd);
782
783 return NULL;
784}
785
786_public_ int sd_login_monitor_flush(sd_login_monitor *m) {
787
788 if (!m)
789 return -EINVAL;
790
791 return flush_fd(MONITOR_TO_FD(m));
792}
793
794_public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
795
796 if (!m)
797 return -EINVAL;
798
799 return MONITOR_TO_FD(m);
800}
dace83cb
LP
801
802_public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
803
804 if (!m)
805 return -EINVAL;
806
667c24a6
LP
807 /* For now we will only return POLLIN here, since we don't
808 * need anything else ever for inotify. However, let's have
809 * this API to keep our options open should we later on need
810 * it. */
dace83cb
LP
811 return POLLIN;
812}
667c24a6
LP
813
814_public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
815
816 if (!m)
817 return -EINVAL;
818 if (!timeout_usec)
819 return -EINVAL;
820
821 /* For now we will only return (uint64_t) -1, since we don't
822 * need any timeout. However, let's have this API to keep our
823 * options open should we later on need it. */
824 *timeout_usec = (uint64_t) -1;
825 return 0;
826}