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