chiark / gitweb /
4ad250eb37e0338aaea0f2cf08cc19dfadbe5f1a
[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_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         return parse_boolean(s);
253 }
254
255 _public_ int sd_session_is_remote(const char *session) {
256         int r;
257         _cleanup_free_ char *p = NULL, *s = NULL;
258
259         r = file_of_session(session, &p);
260         if (r < 0)
261                 return r;
262
263         r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
264         if (r < 0)
265                 return r;
266
267         if (!s)
268                 return -EIO;
269
270         return parse_boolean(s);
271 }
272
273 _public_ int sd_session_get_state(const char *session, char **state) {
274         _cleanup_free_ char *p = NULL, *s = NULL;
275         int r;
276
277         assert_return(state, -EINVAL);
278
279         r = file_of_session(session, &p);
280         if (r < 0)
281                 return r;
282
283         r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
284
285         if (r < 0)
286                 return r;
287         else if (!s)
288                 return -EIO;
289
290         *state = s;
291         s = NULL;
292
293         return 0;
294 }
295
296 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
297         int r;
298         _cleanup_free_ char *p = NULL, *s = NULL;
299
300         assert_return(uid, -EINVAL);
301
302         r = file_of_session(session, &p);
303         if (r < 0)
304                 return r;
305
306         r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
307         if (r < 0)
308                 return r;
309
310         if (!s)
311                 return -EIO;
312
313         return parse_uid(s, uid);
314 }
315
316 static int session_get_string(const char *session, const char *field, char **value) {
317         _cleanup_free_ char *p = NULL, *s = NULL;
318         int r;
319
320         assert_return(value, -EINVAL);
321
322         r = file_of_session(session, &p);
323         if (r < 0)
324                 return r;
325
326         r = parse_env_file(p, NEWLINE, field, &s, NULL);
327
328         if (r < 0)
329                 return r;
330
331         if (isempty(s))
332                 return -ENOENT;
333
334         *value = s;
335         s = NULL;
336         return 0;
337 }
338
339 _public_ int sd_session_get_seat(const char *session, char **seat) {
340         return session_get_string(session, "SEAT", seat);
341 }
342
343 _public_ int sd_session_get_tty(const char *session, char **tty) {
344         return session_get_string(session, "TTY", tty);
345 }
346
347 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
348         _cleanup_free_ char *vtnr_string = NULL;
349         unsigned u;
350         int r;
351
352         r = session_get_string(session, "VTNR", &vtnr_string);
353         if (r < 0)
354                 return r;
355
356         r = safe_atou(vtnr_string, &u);
357         if (r < 0)
358                 return r;
359
360         *vtnr = u;
361         return 0;
362 }
363
364 _public_ int sd_session_get_service(const char *session, char **service) {
365         return session_get_string(session, "SERVICE", service);
366 }
367
368 _public_ int sd_session_get_type(const char *session, char **type) {
369         return session_get_string(session, "TYPE", type);
370 }
371
372 _public_ int sd_session_get_class(const char *session, char **class) {
373         return session_get_string(session, "CLASS", class);
374 }
375
376 _public_ int sd_session_get_display(const char *session, char **display) {
377         return session_get_string(session, "DISPLAY", display);
378 }
379
380 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
381         return session_get_string(session, "REMOTE_USER", remote_user);
382 }
383
384 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
385         return session_get_string(session, "REMOTE_HOST", remote_host);
386 }
387
388 static int file_of_seat(const char *seat, char **_p) {
389         char *p;
390         int r;
391
392         assert(_p);
393
394         if (seat)
395                 p = strappend("/run/systemd/seats/", seat);
396         else {
397                 _cleanup_free_ char *buf = NULL;
398
399                 r = sd_session_get_seat(NULL, &buf);
400                 if (r < 0)
401                         return r;
402
403                 p = strappend("/run/systemd/seats/", buf);
404         }
405
406         if (!p)
407                 return -ENOMEM;
408
409         *_p = p;
410         p = NULL;
411         return 0;
412 }
413
414 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
415         _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
416         int r;
417
418         assert_return(session || uid, -EINVAL);
419
420         r = file_of_seat(seat, &p);
421         if (r < 0)
422                 return r;
423
424         r = parse_env_file(p, NEWLINE,
425                            "ACTIVE", &s,
426                            "ACTIVE_UID", &t,
427                            NULL);
428         if (r < 0)
429                 return r;
430
431         if (session && !s)
432                 return -ENOENT;
433
434         if (uid && !t)
435                 return -ENOENT;
436
437         if (uid && t) {
438                 r = parse_uid(t, uid);
439                 if (r < 0)
440                         return r;
441         }
442
443         if (session && s) {
444                 *session = s;
445                 s = NULL;
446         }
447
448         return 0;
449 }
450
451 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
452         _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
453         _cleanup_strv_free_ char **a = NULL;
454         _cleanup_free_ uid_t *b = NULL;
455         unsigned n = 0;
456         int r;
457
458         r = file_of_seat(seat, &p);
459         if (r < 0)
460                 return r;
461
462         r = parse_env_file(p, NEWLINE,
463                            "SESSIONS", &s,
464                            "ACTIVE_SESSIONS", &t,
465                            NULL);
466
467         if (r < 0)
468                 return r;
469
470         if (s) {
471                 a = strv_split(s, " ");
472                 if (!a)
473                         return -ENOMEM;
474         }
475
476         if (uids && t) {
477                 char *w, *state;
478                 size_t l;
479
480                 FOREACH_WORD(w, l, t, state)
481                         n++;
482
483                 if (n > 0) {
484                         unsigned i = 0;
485
486                         b = new(uid_t, n);
487                         if (!b)
488                                 return -ENOMEM;
489
490                         FOREACH_WORD(w, l, t, state) {
491                                 _cleanup_free_ char *k = NULL;
492
493                                 k = strndup(w, l);
494                                 if (!k)
495                                         return -ENOMEM;
496
497                                 r = parse_uid(k, b + i);
498
499                                 if (r < 0)
500                                         continue;
501
502                                 i++;
503                         }
504                 }
505         }
506
507         r = strv_length(a);
508
509         if (sessions) {
510                 *sessions = a;
511                 a = NULL;
512         }
513
514         if (uids) {
515                 *uids = b;
516                 b = NULL;
517         }
518
519         if (n_uids)
520                 *n_uids = n;
521
522         return r;
523 }
524
525 static int seat_get_can(const char *seat, const char *variable) {
526         _cleanup_free_ char *p = NULL, *s = NULL;
527         int r;
528
529         assert_return(variable, -EINVAL);
530
531         r = file_of_seat(seat, &p);
532         if (r < 0)
533                 return r;
534
535         r = parse_env_file(p, NEWLINE,
536                            variable, &s,
537                            NULL);
538         if (r < 0)
539                 return r;
540         if (!s)
541                 return 0;
542
543         return parse_boolean(s);
544 }
545
546 _public_ int sd_seat_can_multi_session(const char *seat) {
547         return seat_get_can(seat, "CAN_MULTI_SESSION");
548 }
549
550 _public_ int sd_seat_can_tty(const char *seat) {
551         return seat_get_can(seat, "CAN_TTY");
552 }
553
554 _public_ int sd_seat_can_graphical(const char *seat) {
555         return seat_get_can(seat, "CAN_GRAPHICAL");
556 }
557
558 _public_ int sd_get_seats(char ***seats) {
559         return get_files_in_directory("/run/systemd/seats/", seats);
560 }
561
562 _public_ int sd_get_sessions(char ***sessions) {
563         return get_files_in_directory("/run/systemd/sessions/", sessions);
564 }
565
566 _public_ int sd_get_uids(uid_t **users) {
567         _cleanup_closedir_ DIR *d;
568         int r = 0;
569         unsigned n = 0;
570         _cleanup_free_ uid_t *l = NULL;
571
572         d = opendir("/run/systemd/users/");
573         if (!d)
574                 return -errno;
575
576         for (;;) {
577                 struct dirent *de;
578                 int k;
579                 uid_t uid;
580
581                 errno = 0;
582                 de = readdir(d);
583                 if (!de && errno != 0)
584                         return -errno;
585
586                 if (!de)
587                         break;
588
589                 dirent_ensure_type(d, de);
590
591                 if (!dirent_is_file(de))
592                         continue;
593
594                 k = parse_uid(de->d_name, &uid);
595                 if (k < 0)
596                         continue;
597
598                 if (users) {
599                         if ((unsigned) r >= n) {
600                                 uid_t *t;
601
602                                 n = MAX(16, 2*r);
603                                 t = realloc(l, sizeof(uid_t) * n);
604                                 if (!t)
605                                         return -ENOMEM;
606
607                                 l = t;
608                         }
609
610                         assert((unsigned) r < n);
611                         l[r++] = uid;
612                 } else
613                         r++;
614         }
615
616         if (users) {
617                 *users = l;
618                 l = NULL;
619         }
620
621         return r;
622 }
623
624 _public_ int sd_get_machine_names(char ***machines) {
625         char **l = NULL, **a, **b;
626         int r;
627
628         assert_return(machines, -EINVAL);
629
630         r = get_files_in_directory("/run/systemd/machines/", &l);
631         if (r < 0)
632                 return r;
633
634         if (l) {
635                 r = 0;
636
637                 /* Filter out the unit: symlinks */
638                 for (a = l, b = l; *a; a++) {
639                         if (startswith(*a, "unit:"))
640                                 free(*a);
641                         else {
642                                 *b = *a;
643                                 b++;
644                                 r++;
645                         }
646                 }
647
648                 *b = NULL;
649         }
650
651         *machines = l;
652         return r;
653 }
654
655 _public_ int sd_machine_get_class(const char *machine, char **class) {
656         _cleanup_free_ char *c = NULL;
657         const char *p;
658         int r;
659
660         assert_return(filename_is_safe(machine), -EINVAL);
661         assert_return(class, -EINVAL);
662
663         p = strappenda("/run/systemd/machines/", machine);
664         r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
665         if (r < 0)
666                 return r;
667         if (!c)
668                 return -EIO;
669
670         *class = c;
671         c = NULL;
672
673         return 0;
674 }
675
676 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
677         return (int) (unsigned long) m - 1;
678 }
679
680 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
681         return (sd_login_monitor*) (unsigned long) (fd + 1);
682 }
683
684 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
685         int fd, k;
686         bool good = false;
687
688         assert_return(m, -EINVAL);
689
690         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
691         if (fd < 0)
692                 return -errno;
693
694         if (!category || streq(category, "seat")) {
695                 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
696                 if (k < 0) {
697                         close_nointr_nofail(fd);
698                         return -errno;
699                 }
700
701                 good = true;
702         }
703
704         if (!category || streq(category, "session")) {
705                 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
706                 if (k < 0) {
707                         close_nointr_nofail(fd);
708                         return -errno;
709                 }
710
711                 good = true;
712         }
713
714         if (!category || streq(category, "uid")) {
715                 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
716                 if (k < 0) {
717                         close_nointr_nofail(fd);
718                         return -errno;
719                 }
720
721                 good = true;
722         }
723
724         if (!category || streq(category, "machine")) {
725                 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
726                 if (k < 0) {
727                         close_nointr_nofail(fd);
728                         return -errno;
729                 }
730
731                 good = true;
732         }
733
734         if (!good) {
735                 close_nointr(fd);
736                 return -EINVAL;
737         }
738
739         *m = FD_TO_MONITOR(fd);
740         return 0;
741 }
742
743 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
744         int fd;
745
746         assert_return(m, NULL);
747
748         fd = MONITOR_TO_FD(m);
749         close_nointr(fd);
750
751         return NULL;
752 }
753
754 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
755
756         assert_return(m, -EINVAL);
757
758         return flush_fd(MONITOR_TO_FD(m));
759 }
760
761 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
762
763         assert_return(m, -EINVAL);
764
765         return MONITOR_TO_FD(m);
766 }
767
768 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
769
770         assert_return(m, -EINVAL);
771
772         /* For now we will only return POLLIN here, since we don't
773          * need anything else ever for inotify.  However, let's have
774          * this API to keep our options open should we later on need
775          * it. */
776         return POLLIN;
777 }
778
779 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
780
781         assert_return(m, -EINVAL);
782         assert_return(timeout_usec, -EINVAL);
783
784         /* For now we will only return (uint64_t) -1, since we don't
785          * need any timeout. However, let's have this API to keep our
786          * options open should we later on need it. */
787         *timeout_usec = (uint64_t) -1;
788         return 0;
789 }