chiark / gitweb /
sd-login: use the same code for verfiying machine names everywhere
[elogind.git] / src / libsystemd / sd-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_peer_get_session(int fd, char **session) {
85         struct ucred ucred;
86         int r;
87
88         assert_return(fd >= 0, -EINVAL);
89         assert_return(session, -EINVAL);
90
91         r = getpeercred(fd, &ucred);
92         if (r < 0)
93                 return r;
94
95         return cg_pid_get_session(ucred.pid, session);
96 }
97
98 _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
99         struct ucred ucred;
100         int r;
101
102         assert_return(fd >= 0, -EINVAL);
103         assert_return(uid, -EINVAL);
104
105         r = getpeercred(fd, &ucred);
106         if (r < 0)
107                 return r;
108
109         return cg_pid_get_owner_uid(ucred.pid, uid);
110 }
111
112 _public_ int sd_peer_get_unit(int fd, char **unit) {
113         struct ucred ucred;
114         int r;
115
116         assert_return(fd >= 0, -EINVAL);
117         assert_return(unit, -EINVAL);
118
119         r = getpeercred(fd, &ucred);
120         if (r < 0)
121                 return r;
122
123         return cg_pid_get_unit(ucred.pid, unit);
124 }
125
126 _public_ int sd_peer_get_user_unit(int fd, char **unit) {
127         struct ucred ucred;
128         int r;
129
130         assert_return(fd >= 0, -EINVAL);
131         assert_return(unit, -EINVAL);
132
133         r = getpeercred(fd, &ucred);
134         if (r < 0)
135                 return r;
136
137         return cg_pid_get_user_unit(ucred.pid, unit);
138 }
139
140 _public_ int sd_peer_get_machine_name(int fd, char **machine) {
141         struct ucred ucred;
142         int r;
143
144         assert_return(fd >= 0, -EINVAL);
145         assert_return(machine, -EINVAL);
146
147         r = getpeercred(fd, &ucred);
148         if (r < 0)
149                 return r;
150
151         return cg_pid_get_machine_name(ucred.pid, machine);
152 }
153
154 _public_ int sd_peer_get_slice(int fd, char **slice) {
155         struct ucred ucred;
156         int r;
157
158         assert_return(fd >= 0, -EINVAL);
159         assert_return(slice, -EINVAL);
160
161         r = getpeercred(fd, &ucred);
162         if (r < 0)
163                 return r;
164
165         return cg_pid_get_slice(ucred.pid, slice);
166 }
167
168 static int file_of_uid(uid_t uid, char **p) {
169         assert(p);
170
171         if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
172                 return -ENOMEM;
173
174         return 0;
175 }
176
177 _public_ int sd_uid_get_state(uid_t uid, char**state) {
178         _cleanup_free_ char *p = NULL;
179         char *s = NULL;
180         int r;
181
182         assert_return(state, -EINVAL);
183
184         r = file_of_uid(uid, &p);
185         if (r < 0)
186                 return r;
187
188         r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
189         if (r == -ENOENT) {
190                 free(s);
191                 s = strdup("offline");
192                 if (!s)
193                         return -ENOMEM;
194
195         } else if (r < 0) {
196                 free(s);
197                 return r;
198         } else if (!s)
199                 return -EIO;
200
201         *state = s;
202         return 0;
203 }
204
205 _public_ int sd_uid_get_display(uid_t uid, char **session) {
206         _cleanup_free_ char *p = NULL, *s = NULL;
207         int r;
208
209         assert_return(session, -EINVAL);
210
211         r = file_of_uid(uid, &p);
212         if (r < 0)
213                 return r;
214
215         r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
216         if (r < 0)
217                 return r;
218
219         if (isempty(s))
220                 return -ENOENT;
221
222         *session = s;
223         s = NULL;
224
225         return 0;
226 }
227
228 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
229         char *w, *state;
230         _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
231         size_t l;
232         int r;
233         const char *variable;
234
235         assert_return(seat, -EINVAL);
236
237         variable = require_active ? "ACTIVE_UID" : "UIDS";
238
239         p = strappend("/run/systemd/seats/", seat);
240         if (!p)
241                 return -ENOMEM;
242
243         r = parse_env_file(p, NEWLINE, variable, &s, NULL);
244
245         if (r < 0)
246                 return r;
247
248         if (!s)
249                 return -EIO;
250
251         if (asprintf(&t, UID_FMT, uid) < 0)
252                 return -ENOMEM;
253
254         FOREACH_WORD(w, l, s, state) {
255                 if (strneq(t, w, l))
256                         return 1;
257         }
258
259         return 0;
260 }
261
262 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
263         _cleanup_free_ char *p = NULL, *s = NULL;
264         char **a;
265         int r;
266
267         r = file_of_uid(uid, &p);
268         if (r < 0)
269                 return r;
270
271         r = parse_env_file(p, NEWLINE,
272                            variable, &s,
273                            NULL);
274         if (r < 0) {
275                 if (r == -ENOENT) {
276                         if (array)
277                                 *array = NULL;
278                         return 0;
279                 }
280
281                 return r;
282         }
283
284         if (!s) {
285                 if (array)
286                         *array = NULL;
287                 return 0;
288         }
289
290         a = strv_split(s, " ");
291
292         if (!a)
293                 return -ENOMEM;
294
295         strv_uniq(a);
296         r = strv_length(a);
297
298         if (array)
299                 *array = a;
300         else
301                 strv_free(a);
302
303         return r;
304 }
305
306 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
307         return uid_get_array(
308                         uid,
309                         require_active == 0 ? "ONLINE_SESSIONS" :
310                         require_active > 0  ? "ACTIVE_SESSIONS" :
311                                               "SESSIONS",
312                         sessions);
313 }
314
315 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
316         return uid_get_array(
317                         uid,
318                         require_active == 0 ? "ONLINE_SEATS" :
319                         require_active > 0  ? "ACTIVE_SEATS" :
320                                               "SEATS",
321                         seats);
322 }
323
324 static int file_of_session(const char *session, char **_p) {
325         char *p;
326         int r;
327
328         assert(_p);
329
330         if (session) {
331                 if (!session_id_valid(session))
332                         return -EINVAL;
333
334                 p = strappend("/run/systemd/sessions/", session);
335         } else {
336                 _cleanup_free_ char *buf = NULL;
337
338                 r = sd_pid_get_session(0, &buf);
339                 if (r < 0)
340                         return r;
341
342                 p = strappend("/run/systemd/sessions/", buf);
343         }
344
345         if (!p)
346                 return -ENOMEM;
347
348         *_p = p;
349         return 0;
350 }
351
352 _public_ int sd_session_is_active(const char *session) {
353         int r;
354         _cleanup_free_ char *p = NULL, *s = NULL;
355
356         r = file_of_session(session, &p);
357         if (r < 0)
358                 return r;
359
360         r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
361         if (r < 0)
362                 return r;
363
364         if (!s)
365                 return -EIO;
366
367         return parse_boolean(s);
368 }
369
370 _public_ int sd_session_is_remote(const char *session) {
371         int r;
372         _cleanup_free_ char *p = NULL, *s = NULL;
373
374         r = file_of_session(session, &p);
375         if (r < 0)
376                 return r;
377
378         r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
379         if (r < 0)
380                 return r;
381
382         if (!s)
383                 return -EIO;
384
385         return parse_boolean(s);
386 }
387
388 _public_ int sd_session_get_state(const char *session, char **state) {
389         _cleanup_free_ char *p = NULL, *s = NULL;
390         int r;
391
392         assert_return(state, -EINVAL);
393
394         r = file_of_session(session, &p);
395         if (r < 0)
396                 return r;
397
398         r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
399         if (r < 0)
400                 return r;
401         else if (!s)
402                 return -EIO;
403
404         *state = s;
405         s = NULL;
406
407         return 0;
408 }
409
410 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
411         int r;
412         _cleanup_free_ char *p = NULL, *s = NULL;
413
414         assert_return(uid, -EINVAL);
415
416         r = file_of_session(session, &p);
417         if (r < 0)
418                 return r;
419
420         r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
421         if (r < 0)
422                 return r;
423
424         if (!s)
425                 return -EIO;
426
427         return parse_uid(s, uid);
428 }
429
430 static int session_get_string(const char *session, const char *field, char **value) {
431         _cleanup_free_ char *p = NULL, *s = NULL;
432         int r;
433
434         assert_return(value, -EINVAL);
435
436         r = file_of_session(session, &p);
437         if (r < 0)
438                 return r;
439
440         r = parse_env_file(p, NEWLINE, field, &s, NULL);
441         if (r < 0)
442                 return r;
443
444         if (isempty(s))
445                 return -ENOENT;
446
447         *value = s;
448         s = NULL;
449         return 0;
450 }
451
452 _public_ int sd_session_get_seat(const char *session, char **seat) {
453         return session_get_string(session, "SEAT", seat);
454 }
455
456 _public_ int sd_session_get_tty(const char *session, char **tty) {
457         return session_get_string(session, "TTY", tty);
458 }
459
460 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
461         _cleanup_free_ char *vtnr_string = NULL;
462         unsigned u;
463         int r;
464
465         r = session_get_string(session, "VTNR", &vtnr_string);
466         if (r < 0)
467                 return r;
468
469         r = safe_atou(vtnr_string, &u);
470         if (r < 0)
471                 return r;
472
473         *vtnr = u;
474         return 0;
475 }
476
477 _public_ int sd_session_get_service(const char *session, char **service) {
478         return session_get_string(session, "SERVICE", service);
479 }
480
481 _public_ int sd_session_get_type(const char *session, char **type) {
482         return session_get_string(session, "TYPE", type);
483 }
484
485 _public_ int sd_session_get_class(const char *session, char **class) {
486         return session_get_string(session, "CLASS", class);
487 }
488
489 _public_ int sd_session_get_display(const char *session, char **display) {
490         return session_get_string(session, "DISPLAY", display);
491 }
492
493 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
494         return session_get_string(session, "REMOTE_USER", remote_user);
495 }
496
497 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
498         return session_get_string(session, "REMOTE_HOST", remote_host);
499 }
500
501 static int file_of_seat(const char *seat, char **_p) {
502         char *p;
503         int r;
504
505         assert(_p);
506
507         if (seat)
508                 p = strappend("/run/systemd/seats/", seat);
509         else {
510                 _cleanup_free_ char *buf = NULL;
511
512                 r = sd_session_get_seat(NULL, &buf);
513                 if (r < 0)
514                         return r;
515
516                 p = strappend("/run/systemd/seats/", buf);
517         }
518
519         if (!p)
520                 return -ENOMEM;
521
522         *_p = p;
523         p = NULL;
524         return 0;
525 }
526
527 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
528         _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
529         int r;
530
531         assert_return(session || uid, -EINVAL);
532
533         r = file_of_seat(seat, &p);
534         if (r < 0)
535                 return r;
536
537         r = parse_env_file(p, NEWLINE,
538                            "ACTIVE", &s,
539                            "ACTIVE_UID", &t,
540                            NULL);
541         if (r < 0)
542                 return r;
543
544         if (session && !s)
545                 return -ENOENT;
546
547         if (uid && !t)
548                 return -ENOENT;
549
550         if (uid && t) {
551                 r = parse_uid(t, uid);
552                 if (r < 0)
553                         return r;
554         }
555
556         if (session && s) {
557                 *session = s;
558                 s = NULL;
559         }
560
561         return 0;
562 }
563
564 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
565         _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
566         _cleanup_strv_free_ char **a = NULL;
567         _cleanup_free_ uid_t *b = NULL;
568         unsigned n = 0;
569         int r;
570
571         r = file_of_seat(seat, &p);
572         if (r < 0)
573                 return r;
574
575         r = parse_env_file(p, NEWLINE,
576                            "SESSIONS", &s,
577                            "ACTIVE_SESSIONS", &t,
578                            NULL);
579
580         if (r < 0)
581                 return r;
582
583         if (s) {
584                 a = strv_split(s, " ");
585                 if (!a)
586                         return -ENOMEM;
587         }
588
589         if (uids && t) {
590                 char *w, *state;
591                 size_t l;
592
593                 FOREACH_WORD(w, l, t, state)
594                         n++;
595
596                 if (n > 0) {
597                         unsigned i = 0;
598
599                         b = new(uid_t, n);
600                         if (!b)
601                                 return -ENOMEM;
602
603                         FOREACH_WORD(w, l, t, state) {
604                                 _cleanup_free_ char *k = NULL;
605
606                                 k = strndup(w, l);
607                                 if (!k)
608                                         return -ENOMEM;
609
610                                 r = parse_uid(k, b + i);
611
612                                 if (r < 0)
613                                         continue;
614
615                                 i++;
616                         }
617                 }
618         }
619
620         r = strv_length(a);
621
622         if (sessions) {
623                 *sessions = a;
624                 a = NULL;
625         }
626
627         if (uids) {
628                 *uids = b;
629                 b = NULL;
630         }
631
632         if (n_uids)
633                 *n_uids = n;
634
635         return r;
636 }
637
638 static int seat_get_can(const char *seat, const char *variable) {
639         _cleanup_free_ char *p = NULL, *s = NULL;
640         int r;
641
642         assert_return(variable, -EINVAL);
643
644         r = file_of_seat(seat, &p);
645         if (r < 0)
646                 return r;
647
648         r = parse_env_file(p, NEWLINE,
649                            variable, &s,
650                            NULL);
651         if (r < 0)
652                 return r;
653         if (!s)
654                 return 0;
655
656         return parse_boolean(s);
657 }
658
659 _public_ int sd_seat_can_multi_session(const char *seat) {
660         return seat_get_can(seat, "CAN_MULTI_SESSION");
661 }
662
663 _public_ int sd_seat_can_tty(const char *seat) {
664         return seat_get_can(seat, "CAN_TTY");
665 }
666
667 _public_ int sd_seat_can_graphical(const char *seat) {
668         return seat_get_can(seat, "CAN_GRAPHICAL");
669 }
670
671 _public_ int sd_get_seats(char ***seats) {
672         return get_files_in_directory("/run/systemd/seats/", seats);
673 }
674
675 _public_ int sd_get_sessions(char ***sessions) {
676         return get_files_in_directory("/run/systemd/sessions/", sessions);
677 }
678
679 _public_ int sd_get_uids(uid_t **users) {
680         _cleanup_closedir_ DIR *d;
681         int r = 0;
682         unsigned n = 0;
683         _cleanup_free_ uid_t *l = NULL;
684
685         d = opendir("/run/systemd/users/");
686         if (!d)
687                 return -errno;
688
689         for (;;) {
690                 struct dirent *de;
691                 int k;
692                 uid_t uid;
693
694                 errno = 0;
695                 de = readdir(d);
696                 if (!de && errno != 0)
697                         return -errno;
698
699                 if (!de)
700                         break;
701
702                 dirent_ensure_type(d, de);
703
704                 if (!dirent_is_file(de))
705                         continue;
706
707                 k = parse_uid(de->d_name, &uid);
708                 if (k < 0)
709                         continue;
710
711                 if (users) {
712                         if ((unsigned) r >= n) {
713                                 uid_t *t;
714
715                                 n = MAX(16, 2*r);
716                                 t = realloc(l, sizeof(uid_t) * n);
717                                 if (!t)
718                                         return -ENOMEM;
719
720                                 l = t;
721                         }
722
723                         assert((unsigned) r < n);
724                         l[r++] = uid;
725                 } else
726                         r++;
727         }
728
729         if (users) {
730                 *users = l;
731                 l = NULL;
732         }
733
734         return r;
735 }
736
737 _public_ int sd_get_machine_names(char ***machines) {
738         char **l = NULL, **a, **b;
739         int r;
740
741         assert_return(machines, -EINVAL);
742
743         r = get_files_in_directory("/run/systemd/machines/", &l);
744         if (r < 0)
745                 return r;
746
747         if (l) {
748                 r = 0;
749
750                 /* Filter out the unit: symlinks */
751                 for (a = l, b = l; *a; a++) {
752                         if (startswith(*a, "unit:"))
753                                 free(*a);
754                         else {
755                                 *b = *a;
756                                 b++;
757                                 r++;
758                         }
759                 }
760
761                 *b = NULL;
762         }
763
764         *machines = l;
765         return r;
766 }
767
768 _public_ int sd_machine_get_class(const char *machine, char **class) {
769         _cleanup_free_ char *c = NULL;
770         const char *p;
771         int r;
772
773         assert_return(machine_name_is_valid(machine), -EINVAL);
774         assert_return(class, -EINVAL);
775
776         p = strappenda("/run/systemd/machines/", machine);
777         r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
778         if (r < 0)
779                 return r;
780         if (!c)
781                 return -EIO;
782
783         *class = c;
784         c = NULL;
785
786         return 0;
787 }
788
789 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
790         return (int) (unsigned long) m - 1;
791 }
792
793 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
794         return (sd_login_monitor*) (unsigned long) (fd + 1);
795 }
796
797 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
798         int fd, k;
799         bool good = false;
800
801         assert_return(m, -EINVAL);
802
803         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
804         if (fd < 0)
805                 return -errno;
806
807         if (!category || streq(category, "seat")) {
808                 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
809                 if (k < 0) {
810                         safe_close(fd);
811                         return -errno;
812                 }
813
814                 good = true;
815         }
816
817         if (!category || streq(category, "session")) {
818                 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
819                 if (k < 0) {
820                         safe_close(fd);
821                         return -errno;
822                 }
823
824                 good = true;
825         }
826
827         if (!category || streq(category, "uid")) {
828                 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
829                 if (k < 0) {
830                         safe_close(fd);
831                         return -errno;
832                 }
833
834                 good = true;
835         }
836
837         if (!category || streq(category, "machine")) {
838                 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
839                 if (k < 0) {
840                         safe_close(fd);
841                         return -errno;
842                 }
843
844                 good = true;
845         }
846
847         if (!good) {
848                 close_nointr(fd);
849                 return -EINVAL;
850         }
851
852         *m = FD_TO_MONITOR(fd);
853         return 0;
854 }
855
856 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
857         int fd;
858
859         assert_return(m, NULL);
860
861         fd = MONITOR_TO_FD(m);
862         close_nointr(fd);
863
864         return NULL;
865 }
866
867 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
868
869         assert_return(m, -EINVAL);
870
871         return flush_fd(MONITOR_TO_FD(m));
872 }
873
874 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
875
876         assert_return(m, -EINVAL);
877
878         return MONITOR_TO_FD(m);
879 }
880
881 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
882
883         assert_return(m, -EINVAL);
884
885         /* For now we will only return POLLIN here, since we don't
886          * need anything else ever for inotify.  However, let's have
887          * this API to keep our options open should we later on need
888          * it. */
889         return POLLIN;
890 }
891
892 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
893
894         assert_return(m, -EINVAL);
895         assert_return(timeout_usec, -EINVAL);
896
897         /* For now we will only return (uint64_t) -1, since we don't
898          * need any timeout. However, let's have this API to keep our
899          * options open should we later on need it. */
900         *timeout_usec = (uint64_t) -1;
901         return 0;
902 }