]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/sd-login.c
libsystemd-login: add sd_session_get_remote_{host, user}
[thirdparty/systemd.git] / src / login / sd-login.c
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
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
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>
25 #include <sys/inotify.h>
26 #include <sys/poll.h>
27
28 #include "util.h"
29 #include "cgroup-util.h"
30 #include "macro.h"
31 #include "strv.h"
32 #include "fileio.h"
33 #include "login-shared.h"
34 #include "sd-login.h"
35
36 _public_ int sd_pid_get_session(pid_t pid, char **session) {
37
38 assert_return(pid >= 0, -EINVAL);
39 assert_return(session, -EINVAL);
40
41 return cg_pid_get_session(pid, session);
42 }
43
44 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
45
46 assert_return(pid >= 0, -EINVAL);
47 assert_return(unit, -EINVAL);
48
49 return cg_pid_get_unit(pid, unit);
50 }
51
52 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
53
54 assert_return(pid >= 0, -EINVAL);
55 assert_return(unit, -EINVAL);
56
57 return cg_pid_get_user_unit(pid, unit);
58 }
59
60 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
61
62 assert_return(pid >= 0, -EINVAL);
63 assert_return(name, -EINVAL);
64
65 return cg_pid_get_machine_name(pid, name);
66 }
67
68 _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
69
70 assert_return(pid >= 0, -EINVAL);
71 assert_return(slice, -EINVAL);
72
73 return cg_pid_get_slice(pid, slice);
74 }
75
76 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
77
78 assert_return(pid >= 0, -EINVAL);
79 assert_return(uid, -EINVAL);
80
81 return cg_pid_get_owner_uid(pid, uid);
82 }
83
84 _public_ int sd_uid_get_state(uid_t uid, char**state) {
85 char *p, *s = NULL;
86 int r;
87
88 assert_return(state, -EINVAL);
89
90 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
91 return -ENOMEM;
92
93 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
94 free(p);
95
96 if (r == -ENOENT) {
97 free(s);
98 s = strdup("offline");
99 if (!s)
100 return -ENOMEM;
101
102 *state = s;
103 return 0;
104 } else if (r < 0) {
105 free(s);
106 return r;
107 } else if (!s)
108 return -EIO;
109
110 *state = s;
111 return 0;
112 }
113
114 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
115 char *w, *state;
116 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
117 size_t l;
118 int r;
119 const char *variable;
120
121 assert_return(seat, -EINVAL);
122
123 variable = require_active ? "ACTIVE_UID" : "UIDS";
124
125 p = strappend("/run/systemd/seats/", seat);
126 if (!p)
127 return -ENOMEM;
128
129 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
130
131 if (r < 0)
132 return r;
133
134 if (!s)
135 return -EIO;
136
137 if (asprintf(&t, "%lu", (unsigned long) uid) < 0)
138 return -ENOMEM;
139
140 FOREACH_WORD(w, l, s, state) {
141 if (strneq(t, w, l))
142 return 1;
143 }
144
145 return 0;
146 }
147
148 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
149 _cleanup_free_ char *p = NULL, *s = NULL;
150 char **a;
151 int r;
152
153 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
154 return -ENOMEM;
155
156 r = parse_env_file(p, NEWLINE,
157 variable, &s,
158 NULL);
159 if (r < 0) {
160 if (r == -ENOENT) {
161 if (array)
162 *array = NULL;
163 return 0;
164 }
165
166 return r;
167 }
168
169 if (!s) {
170 if (array)
171 *array = NULL;
172 return 0;
173 }
174
175 a = strv_split(s, " ");
176
177 if (!a)
178 return -ENOMEM;
179
180 strv_uniq(a);
181 r = strv_length(a);
182
183 if (array)
184 *array = a;
185 else
186 strv_free(a);
187
188 return r;
189 }
190
191 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
192 return uid_get_array(
193 uid,
194 require_active == 0 ? "ONLINE_SESSIONS" :
195 require_active > 0 ? "ACTIVE_SESSIONS" :
196 "SESSIONS",
197 sessions);
198 }
199
200 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
201 return uid_get_array(
202 uid,
203 require_active == 0 ? "ONLINE_SEATS" :
204 require_active > 0 ? "ACTIVE_SEATS" :
205 "SEATS",
206 seats);
207 }
208
209 static int file_of_session(const char *session, char **_p) {
210 char *p;
211 int r;
212
213 assert(_p);
214
215 if (session) {
216 if (!session_id_valid(session))
217 return -EINVAL;
218
219 p = strappend("/run/systemd/sessions/", session);
220 } else {
221 _cleanup_free_ char *buf = NULL;
222
223 r = sd_pid_get_session(0, &buf);
224 if (r < 0)
225 return r;
226
227 p = strappend("/run/systemd/sessions/", buf);
228 }
229
230 if (!p)
231 return -ENOMEM;
232
233 *_p = p;
234 return 0;
235 }
236
237 _public_ int sd_session_is_active(const char *session) {
238 int r;
239 _cleanup_free_ char *p = NULL, *s = NULL;
240
241 r = file_of_session(session, &p);
242 if (r < 0)
243 return r;
244
245 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
246 if (r < 0)
247 return r;
248
249 if (!s)
250 return -EIO;
251
252 r = parse_boolean(s);
253
254 return r;
255 }
256
257 _public_ int sd_session_is_remote(const char *session) {
258 int r;
259 _cleanup_free_ char *p = NULL, *s = NULL;
260
261 r = file_of_session(session, &p);
262 if (r < 0)
263 return r;
264
265 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
266 if (r < 0)
267 return r;
268
269 if (!s)
270 return -EIO;
271
272 r = parse_boolean(s);
273
274 return r;
275 }
276
277 _public_ int sd_session_get_state(const char *session, char **state) {
278 _cleanup_free_ char *p = NULL, *s = NULL;
279 int r;
280
281 assert_return(state, -EINVAL);
282
283 r = file_of_session(session, &p);
284 if (r < 0)
285 return r;
286
287 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
288
289 if (r < 0)
290 return r;
291 else if (!s)
292 return -EIO;
293
294 *state = s;
295 s = NULL;
296
297 return 0;
298 }
299
300 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
301 int r;
302 _cleanup_free_ char *p = NULL, *s = NULL;
303
304 assert_return(uid, -EINVAL);
305
306 r = file_of_session(session, &p);
307 if (r < 0)
308 return r;
309
310 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
311
312 if (r < 0)
313 return r;
314
315 if (!s)
316 return -EIO;
317
318 r = parse_uid(s, uid);
319
320 return r;
321 }
322
323 static int session_get_string(const char *session, const char *field, char **value) {
324 _cleanup_free_ char *p = NULL, *s = NULL;
325 int r;
326
327 assert_return(value, -EINVAL);
328
329 r = file_of_session(session, &p);
330 if (r < 0)
331 return r;
332
333 r = parse_env_file(p, NEWLINE, field, &s, NULL);
334
335 if (r < 0)
336 return r;
337
338 if (isempty(s))
339 return -ENOENT;
340
341 *value = s;
342 s = NULL;
343 return 0;
344 }
345
346 _public_ int sd_session_get_seat(const char *session, char **seat) {
347 return session_get_string(session, "SEAT", seat);
348 }
349
350 _public_ int sd_session_get_tty(const char *session, char **tty) {
351 return session_get_string(session, "TTY", tty);
352 }
353
354 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
355 _cleanup_free_ char *vtnr_string = NULL;
356 unsigned u;
357 int r;
358
359 r = session_get_string(session, "VTNR", &vtnr_string);
360 if (r < 0)
361 return r;
362
363 r = safe_atou(vtnr_string, &u);
364 if (r < 0)
365 return r;
366
367 *vtnr = u;
368 return 0;
369 }
370
371 _public_ int sd_session_get_service(const char *session, char **service) {
372 return session_get_string(session, "SERVICE", service);
373 }
374
375 _public_ int sd_session_get_type(const char *session, char **type) {
376 return session_get_string(session, "TYPE", type);
377 }
378
379 _public_ int sd_session_get_class(const char *session, char **class) {
380 return session_get_string(session, "CLASS", class);
381 }
382
383 _public_ int sd_session_get_display(const char *session, char **display) {
384 return session_get_string(session, "DISPLAY", display);
385 }
386
387 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
388 return session_get_string(session, "REMOTE_USER", remote_user);
389 }
390
391 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
392 return session_get_string(session, "REMOTE_HOST", remote_host);
393 }
394
395 static int file_of_seat(const char *seat, char **_p) {
396 char *p;
397 int r;
398
399 assert(_p);
400
401 if (seat)
402 p = strappend("/run/systemd/seats/", seat);
403 else {
404 _cleanup_free_ char *buf = NULL;
405
406 r = sd_session_get_seat(NULL, &buf);
407 if (r < 0)
408 return r;
409
410 p = strappend("/run/systemd/seats/", buf);
411 }
412
413 if (!p)
414 return -ENOMEM;
415
416 *_p = p;
417 p = NULL;
418 return 0;
419 }
420
421 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
422 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
423 int r;
424
425 assert_return(session || uid, -EINVAL);
426
427 r = file_of_seat(seat, &p);
428 if (r < 0)
429 return r;
430
431 r = parse_env_file(p, NEWLINE,
432 "ACTIVE", &s,
433 "ACTIVE_UID", &t,
434 NULL);
435 if (r < 0)
436 return r;
437
438 if (session && !s)
439 return -ENOENT;
440
441 if (uid && !t)
442 return -ENOENT;
443
444 if (uid && t) {
445 r = parse_uid(t, uid);
446 if (r < 0)
447 return r;
448 }
449
450 if (session && s) {
451 *session = s;
452 s = NULL;
453 }
454
455 return 0;
456 }
457
458 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
459 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
460 _cleanup_strv_free_ char **a = NULL;
461 _cleanup_free_ uid_t *b = NULL;
462 unsigned n = 0;
463 int r;
464
465 r = file_of_seat(seat, &p);
466 if (r < 0)
467 return r;
468
469 r = parse_env_file(p, NEWLINE,
470 "SESSIONS", &s,
471 "ACTIVE_SESSIONS", &t,
472 NULL);
473
474 if (r < 0)
475 return r;
476
477 if (s) {
478 a = strv_split(s, " ");
479 if (!a)
480 return -ENOMEM;
481 }
482
483 if (uids && t) {
484 char *w, *state;
485 size_t l;
486
487 FOREACH_WORD(w, l, t, state)
488 n++;
489
490 if (n > 0) {
491 unsigned i = 0;
492
493 b = new(uid_t, n);
494 if (!b)
495 return -ENOMEM;
496
497 FOREACH_WORD(w, l, t, state) {
498 _cleanup_free_ char *k = NULL;
499
500 k = strndup(w, l);
501 if (!k)
502 return -ENOMEM;
503
504 r = parse_uid(k, b + i);
505
506 if (r < 0)
507 continue;
508
509 i++;
510 }
511 }
512 }
513
514 r = strv_length(a);
515
516 if (sessions) {
517 *sessions = a;
518 a = NULL;
519 }
520
521 if (uids) {
522 *uids = b;
523 b = NULL;
524 }
525
526 if (n_uids)
527 *n_uids = n;
528
529 return r;
530 }
531
532 static int seat_get_can(const char *seat, const char *variable) {
533 _cleanup_free_ char *p = NULL, *s = NULL;
534 int r;
535
536 r = file_of_seat(seat, &p);
537 if (r < 0)
538 return r;
539
540 r = parse_env_file(p, NEWLINE,
541 variable, &s,
542 NULL);
543 if (r < 0)
544 return r;
545
546 if (s)
547 r = parse_boolean(s);
548 else
549 r = 0;
550
551 return r;
552 }
553
554 _public_ int sd_seat_can_multi_session(const char *seat) {
555 return seat_get_can(seat, "CAN_MULTI_SESSION");
556 }
557
558 _public_ int sd_seat_can_tty(const char *seat) {
559 return seat_get_can(seat, "CAN_TTY");
560 }
561
562 _public_ int sd_seat_can_graphical(const char *seat) {
563 return seat_get_can(seat, "CAN_GRAPHICAL");
564 }
565
566 _public_ int sd_get_seats(char ***seats) {
567 return get_files_in_directory("/run/systemd/seats/", seats);
568 }
569
570 _public_ int sd_get_sessions(char ***sessions) {
571 return get_files_in_directory("/run/systemd/sessions/", sessions);
572 }
573
574 _public_ int sd_get_uids(uid_t **users) {
575 _cleanup_closedir_ DIR *d;
576 int r = 0;
577 unsigned n = 0;
578 _cleanup_free_ uid_t *l = NULL;
579
580 d = opendir("/run/systemd/users/");
581 if (!d)
582 return -errno;
583
584 for (;;) {
585 struct dirent *de;
586 int k;
587 uid_t uid;
588
589 errno = 0;
590 de = readdir(d);
591 if (!de && errno != 0)
592 return -errno;
593
594 if (!de)
595 break;
596
597 dirent_ensure_type(d, de);
598
599 if (!dirent_is_file(de))
600 continue;
601
602 k = parse_uid(de->d_name, &uid);
603 if (k < 0)
604 continue;
605
606 if (users) {
607 if ((unsigned) r >= n) {
608 uid_t *t;
609
610 n = MAX(16, 2*r);
611 t = realloc(l, sizeof(uid_t) * n);
612 if (!t)
613 return -ENOMEM;
614
615 l = t;
616 }
617
618 assert((unsigned) r < n);
619 l[r++] = uid;
620 } else
621 r++;
622 }
623
624 if (users) {
625 *users = l;
626 l = NULL;
627 }
628
629 return r;
630 }
631
632 _public_ int sd_get_machine_names(char ***machines) {
633 return get_files_in_directory("/run/systemd/machines/", machines);
634 }
635
636 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
637 return (int) (unsigned long) m - 1;
638 }
639
640 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
641 return (sd_login_monitor*) (unsigned long) (fd + 1);
642 }
643
644 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
645 int fd, k;
646 bool good = false;
647
648 assert_return(m, -EINVAL);
649
650 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
651 if (fd < 0)
652 return -errno;
653
654 if (!category || streq(category, "seat")) {
655 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
656 if (k < 0) {
657 close_nointr_nofail(fd);
658 return -errno;
659 }
660
661 good = true;
662 }
663
664 if (!category || streq(category, "session")) {
665 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
666 if (k < 0) {
667 close_nointr_nofail(fd);
668 return -errno;
669 }
670
671 good = true;
672 }
673
674 if (!category || streq(category, "uid")) {
675 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
676 if (k < 0) {
677 close_nointr_nofail(fd);
678 return -errno;
679 }
680
681 good = true;
682 }
683
684 if (!category || streq(category, "machine")) {
685 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
686 if (k < 0) {
687 close_nointr_nofail(fd);
688 return -errno;
689 }
690
691 good = true;
692 }
693
694 if (!good) {
695 close_nointr(fd);
696 return -EINVAL;
697 }
698
699 *m = FD_TO_MONITOR(fd);
700 return 0;
701 }
702
703 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
704 int fd;
705
706 assert_return(m, NULL);
707
708 fd = MONITOR_TO_FD(m);
709 close_nointr(fd);
710
711 return NULL;
712 }
713
714 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
715
716 assert_return(m, -EINVAL);
717
718 return flush_fd(MONITOR_TO_FD(m));
719 }
720
721 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
722
723 assert_return(m, -EINVAL);
724
725 return MONITOR_TO_FD(m);
726 }
727
728 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
729
730 assert_return(m, -EINVAL);
731
732 /* For now we will only return POLLIN here, since we don't
733 * need anything else ever for inotify. However, let's have
734 * this API to keep our options open should we later on need
735 * it. */
736 return POLLIN;
737 }
738
739 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
740
741 assert_return(m, -EINVAL);
742 assert_return(timeout_usec, -EINVAL);
743
744 /* For now we will only return (uint64_t) -1, since we don't
745 * need any timeout. However, let's have this API to keep our
746 * options open should we later on need it. */
747 *timeout_usec = (uint64_t) -1;
748 return 0;
749 }