chiark / gitweb /
d1f91d6a29812488a50bd24aa8428e2e00e8716e
[elogind.git] / src / login / logind-user.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 <sys/mount.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <errno.h>
26
27 #include "util.h"
28 #include "mkdir.h"
29 #include "hashmap.h"
30 #include "strv.h"
31 #include "fileio.h"
32 #include "path-util.h"
33 #include "special.h"
34 #include "unit-name.h"
35 #include "bus-util.h"
36 #include "bus-error.h"
37 #include "conf-parser.h"
38 #include "clean-ipc.h"
39 #include "logind-user.h"
40 #include "smack-util.h"
41
42 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
43         User *u;
44
45         assert(m);
46         assert(name);
47
48         u = new0(User, 1);
49         if (!u)
50                 return NULL;
51
52         u->name = strdup(name);
53         if (!u->name)
54                 goto fail;
55
56         if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
57                 goto fail;
58
59         if (hashmap_put(m->users, UID_TO_PTR(uid), u) < 0)
60                 goto fail;
61
62         u->manager = m;
63         u->uid = uid;
64         u->gid = gid;
65
66         return u;
67
68 fail:
69         free(u->state_file);
70         free(u->name);
71         free(u);
72
73         return NULL;
74 }
75
76 void user_free(User *u) {
77         assert(u);
78
79         if (u->in_gc_queue)
80                 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
81
82         while (u->sessions)
83                 session_free(u->sessions);
84
85         if (u->slice) {
86                 hashmap_remove(u->manager->user_units, u->slice);
87                 free(u->slice);
88         }
89
90         if (u->service) {
91                 hashmap_remove(u->manager->user_units, u->service);
92                 free(u->service);
93         }
94
95         free(u->slice_job);
96         free(u->service_job);
97
98         free(u->runtime_path);
99
100         hashmap_remove(u->manager->users, UID_TO_PTR(u->uid));
101
102         free(u->name);
103         free(u->state_file);
104         free(u);
105 }
106
107 int user_save(User *u) {
108         _cleanup_free_ char *temp_path = NULL;
109         _cleanup_fclose_ FILE *f = NULL;
110         int r;
111
112         assert(u);
113         assert(u->state_file);
114
115         if (!u->started)
116                 return 0;
117
118         r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
119         if (r < 0)
120                 goto finish;
121
122         r = fopen_temporary(u->state_file, &f, &temp_path);
123         if (r < 0)
124                 goto finish;
125
126         fchmod(fileno(f), 0644);
127
128         fprintf(f,
129                 "# This is private data. Do not parse.\n"
130                 "NAME=%s\n"
131                 "STATE=%s\n",
132                 u->name,
133                 user_state_to_string(user_get_state(u)));
134
135         if (u->runtime_path)
136                 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
137
138         if (u->service)
139                 fprintf(f, "SERVICE=%s\n", u->service);
140         if (u->service_job)
141                 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
142
143         if (u->slice)
144                 fprintf(f, "SLICE=%s\n", u->slice);
145         if (u->slice_job)
146                 fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
147
148         if (u->display)
149                 fprintf(f, "DISPLAY=%s\n", u->display->id);
150
151         if (dual_timestamp_is_set(&u->timestamp))
152                 fprintf(f,
153                         "REALTIME="USEC_FMT"\n"
154                         "MONOTONIC="USEC_FMT"\n",
155                         u->timestamp.realtime,
156                         u->timestamp.monotonic);
157
158         if (u->sessions) {
159                 Session *i;
160                 bool first;
161
162                 fputs("SESSIONS=", f);
163                 first = true;
164                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
165                         if (first)
166                                 first = false;
167                         else
168                                 fputc(' ', f);
169
170                         fputs(i->id, f);
171                 }
172
173                 fputs("\nSEATS=", f);
174                 first = true;
175                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
176                         if (!i->seat)
177                                 continue;
178
179                         if (first)
180                                 first = false;
181                         else
182                                 fputc(' ', f);
183
184                         fputs(i->seat->id, f);
185                 }
186
187                 fputs("\nACTIVE_SESSIONS=", f);
188                 first = true;
189                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
190                         if (!session_is_active(i))
191                                 continue;
192
193                         if (first)
194                                 first = false;
195                         else
196                                 fputc(' ', f);
197
198                         fputs(i->id, f);
199                 }
200
201                 fputs("\nONLINE_SESSIONS=", f);
202                 first = true;
203                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
204                         if (session_get_state(i) == SESSION_CLOSING)
205                                 continue;
206
207                         if (first)
208                                 first = false;
209                         else
210                                 fputc(' ', f);
211
212                         fputs(i->id, f);
213                 }
214
215                 fputs("\nACTIVE_SEATS=", f);
216                 first = true;
217                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
218                         if (!session_is_active(i) || !i->seat)
219                                 continue;
220
221                         if (first)
222                                 first = false;
223                         else
224                                 fputc(' ', f);
225
226                         fputs(i->seat->id, f);
227                 }
228
229                 fputs("\nONLINE_SEATS=", f);
230                 first = true;
231                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
232                         if (session_get_state(i) == SESSION_CLOSING || !i->seat)
233                                 continue;
234
235                         if (first)
236                                 first = false;
237                         else
238                                 fputc(' ', f);
239
240                         fputs(i->seat->id, f);
241                 }
242                 fputc('\n', f);
243         }
244
245         fflush(f);
246
247         if (ferror(f) || rename(temp_path, u->state_file) < 0) {
248                 r = -errno;
249                 unlink(u->state_file);
250                 unlink(temp_path);
251         }
252
253 finish:
254         if (r < 0)
255                 log_error_errno(r, "Failed to save user data %s: %m", u->state_file);
256
257         return r;
258 }
259
260 int user_load(User *u) {
261         _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
262         Session *s = NULL;
263         int r;
264
265         assert(u);
266
267         r = parse_env_file(u->state_file, NEWLINE,
268                            "RUNTIME",     &u->runtime_path,
269                            "SERVICE",     &u->service,
270                            "SERVICE_JOB", &u->service_job,
271                            "SLICE",       &u->slice,
272                            "SLICE_JOB",   &u->slice_job,
273                            "DISPLAY",     &display,
274                            "REALTIME",    &realtime,
275                            "MONOTONIC",   &monotonic,
276                            NULL);
277         if (r < 0) {
278                 if (r == -ENOENT)
279                         return 0;
280
281                 log_error_errno(r, "Failed to read %s: %m", u->state_file);
282                 return r;
283         }
284
285         if (display)
286                 s = hashmap_get(u->manager->sessions, display);
287
288         if (s && s->display && display_is_local(s->display))
289                 u->display = s;
290
291         if (realtime) {
292                 unsigned long long l;
293                 if (sscanf(realtime, "%llu", &l) > 0)
294                         u->timestamp.realtime = l;
295         }
296
297         if (monotonic) {
298                 unsigned long long l;
299                 if (sscanf(monotonic, "%llu", &l) > 0)
300                         u->timestamp.monotonic = l;
301         }
302
303         return r;
304 }
305
306 static int user_mkdir_runtime_path(User *u) {
307         char *p;
308         int r;
309
310         assert(u);
311
312         r = mkdir_safe_label("/run/user", 0755, 0, 0);
313         if (r < 0)
314                 return log_error_errno(r, "Failed to create /run/user: %m");
315
316         if (!u->runtime_path) {
317                 if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
318                         return log_oom();
319         } else
320                 p = u->runtime_path;
321
322         if (path_is_mount_point(p, false) <= 0) {
323                 _cleanup_free_ char *t = NULL;
324
325                 mkdir(p, 0700);
326
327                 if (mac_smack_use())
328                         r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
329                 else
330                         r = asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
331                 if (r < 0) {
332                         r = log_oom();
333                         goto fail;
334                 }
335
336                 r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
337                 if (r < 0) {
338                         r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", p);
339                         goto fail;
340                 }
341         }
342
343         u->runtime_path = p;
344         return 0;
345
346 fail:
347         if (p) {
348                 /* Try to clean up, but ignore errors */
349                 (void) rmdir(p);
350                 free(p);
351         }
352
353         u->runtime_path = NULL;
354         return r;
355 }
356
357 static int user_start_slice(User *u) {
358         char *job;
359         int r;
360
361         assert(u);
362
363         if (!u->slice) {
364                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
365                 char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
366                 sprintf(lu, UID_FMT, u->uid);
367
368                 r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
369                 if (r < 0)
370                         return r;
371
372                 r = manager_start_unit(u->manager, slice, &error, &job);
373                 if (r < 0) {
374                         log_error("Failed to start user slice: %s", bus_error_message(&error, r));
375                         free(slice);
376                 } else {
377                         u->slice = slice;
378
379                         free(u->slice_job);
380                         u->slice_job = job;
381                 }
382         }
383
384         if (u->slice)
385                 hashmap_put(u->manager->user_units, u->slice, u);
386
387         return 0;
388 }
389
390 static int user_start_service(User *u) {
391         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
392         char *job;
393         int r;
394
395         assert(u);
396
397         if (!u->service) {
398                 char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
399                 sprintf(lu, UID_FMT, u->uid);
400
401                 service = unit_name_build("user", lu, ".service");
402                 if (!service)
403                         return log_oom();
404
405                 r = manager_start_unit(u->manager, service, &error, &job);
406                 if (r < 0) {
407                         log_error("Failed to start user service: %s", bus_error_message(&error, r));
408                         free(service);
409                 } else {
410                         u->service = service;
411
412                         free(u->service_job);
413                         u->service_job = job;
414                 }
415         }
416
417         if (u->service)
418                 hashmap_put(u->manager->user_units, u->service, u);
419
420         return 0;
421 }
422
423 int user_start(User *u) {
424         int r;
425
426         assert(u);
427
428         if (u->started)
429                 return 0;
430
431         log_debug("New user %s logged in.", u->name);
432
433         /* Make XDG_RUNTIME_DIR */
434         r = user_mkdir_runtime_path(u);
435         if (r < 0)
436                 return r;
437
438         /* Create cgroup */
439         r = user_start_slice(u);
440         if (r < 0)
441                 return r;
442
443         /* Spawn user systemd */
444         r = user_start_service(u);
445         if (r < 0)
446                 return r;
447
448         if (!dual_timestamp_is_set(&u->timestamp))
449                 dual_timestamp_get(&u->timestamp);
450
451         u->started = true;
452
453         /* Save new user data */
454         user_save(u);
455
456         user_send_signal(u, true);
457
458         return 0;
459 }
460
461 static int user_stop_slice(User *u) {
462         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
463         char *job;
464         int r;
465
466         assert(u);
467
468         if (!u->slice)
469                 return 0;
470
471         r = manager_stop_unit(u->manager, u->slice, &error, &job);
472         if (r < 0) {
473                 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
474                 return r;
475         }
476
477         free(u->slice_job);
478         u->slice_job = job;
479
480         return r;
481 }
482
483 static int user_stop_service(User *u) {
484         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
485         char *job;
486         int r;
487
488         assert(u);
489
490         if (!u->service)
491                 return 0;
492
493         r = manager_stop_unit(u->manager, u->service, &error, &job);
494         if (r < 0) {
495                 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
496                 return r;
497         }
498
499         free(u->service_job);
500         u->service_job = job;
501
502         return r;
503 }
504
505 static int user_remove_runtime_path(User *u) {
506         int r;
507
508         assert(u);
509
510         if (!u->runtime_path)
511                 return 0;
512
513         r = rm_rf(u->runtime_path, false, false, false);
514         if (r < 0)
515                 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
516
517         if (umount2(u->runtime_path, MNT_DETACH) < 0)
518                 log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
519
520         r = rm_rf(u->runtime_path, false, true, false);
521         if (r < 0)
522                 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
523
524         free(u->runtime_path);
525         u->runtime_path = NULL;
526
527         return r;
528 }
529
530 int user_stop(User *u, bool force) {
531         Session *s;
532         int r = 0, k;
533         assert(u);
534
535         /* Stop jobs have already been queued */
536         if (u->stopping) {
537                 user_save(u);
538                 return r;
539         }
540
541         LIST_FOREACH(sessions_by_user, s, u->sessions) {
542                 k = session_stop(s, force);
543                 if (k < 0)
544                         r = k;
545         }
546
547         /* Kill systemd */
548         k = user_stop_service(u);
549         if (k < 0)
550                 r = k;
551
552         /* Kill cgroup */
553         k = user_stop_slice(u);
554         if (k < 0)
555                 r = k;
556
557         u->stopping = true;
558
559         user_save(u);
560
561         return r;
562 }
563
564 int user_finalize(User *u) {
565         Session *s;
566         int r = 0, k;
567
568         assert(u);
569
570         if (u->started)
571                 log_debug("User %s logged out.", u->name);
572
573         LIST_FOREACH(sessions_by_user, s, u->sessions) {
574                 k = session_finalize(s);
575                 if (k < 0)
576                         r = k;
577         }
578
579         /* Kill XDG_RUNTIME_DIR */
580         k = user_remove_runtime_path(u);
581         if (k < 0)
582                 r = k;
583
584         /* Clean SysV + POSIX IPC objects */
585         if (u->manager->remove_ipc) {
586                 k = clean_ipc(u->uid);
587                 if (k < 0)
588                         r = k;
589         }
590
591         unlink(u->state_file);
592         user_add_to_gc_queue(u);
593
594         if (u->started) {
595                 user_send_signal(u, false);
596                 u->started = false;
597         }
598
599         return r;
600 }
601
602 int user_get_idle_hint(User *u, dual_timestamp *t) {
603         Session *s;
604         bool idle_hint = true;
605         dual_timestamp ts = { 0, 0 };
606
607         assert(u);
608
609         LIST_FOREACH(sessions_by_user, s, u->sessions) {
610                 dual_timestamp k;
611                 int ih;
612
613                 ih = session_get_idle_hint(s, &k);
614                 if (ih < 0)
615                         return ih;
616
617                 if (!ih) {
618                         if (!idle_hint) {
619                                 if (k.monotonic < ts.monotonic)
620                                         ts = k;
621                         } else {
622                                 idle_hint = false;
623                                 ts = k;
624                         }
625                 } else if (idle_hint) {
626
627                         if (k.monotonic > ts.monotonic)
628                                 ts = k;
629                 }
630         }
631
632         if (t)
633                 *t = ts;
634
635         return idle_hint;
636 }
637
638 int user_check_linger_file(User *u) {
639         _cleanup_free_ char *cc = NULL;
640         char *p = NULL;
641
642         cc = cescape(u->name);
643         if (!cc)
644                 return -ENOMEM;
645
646         p = strappenda("/var/lib/systemd/linger/", cc);
647
648         return access(p, F_OK) >= 0;
649 }
650
651 bool user_check_gc(User *u, bool drop_not_started) {
652         assert(u);
653
654         if (drop_not_started && !u->started)
655                 return false;
656
657         if (u->sessions)
658                 return true;
659
660         if (user_check_linger_file(u) > 0)
661                 return true;
662
663         if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
664                 return true;
665
666         if (u->service_job && manager_job_is_active(u->manager, u->service_job))
667                 return true;
668
669         return false;
670 }
671
672 void user_add_to_gc_queue(User *u) {
673         assert(u);
674
675         if (u->in_gc_queue)
676                 return;
677
678         LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
679         u->in_gc_queue = true;
680 }
681
682 UserState user_get_state(User *u) {
683         Session *i;
684
685         assert(u);
686
687         if (u->stopping)
688                 return USER_CLOSING;
689
690         if (u->slice_job || u->service_job)
691                 return USER_OPENING;
692
693         if (u->sessions) {
694                 bool all_closing = true;
695
696                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
697                         SessionState state;
698
699                         state = session_get_state(i);
700                         if (state == SESSION_ACTIVE)
701                                 return USER_ACTIVE;
702                         if (state != SESSION_CLOSING)
703                                 all_closing = false;
704                 }
705
706                 return all_closing ? USER_CLOSING : USER_ONLINE;
707         }
708
709         if (user_check_linger_file(u) > 0)
710                 return USER_LINGERING;
711
712         return USER_CLOSING;
713 }
714
715 int user_kill(User *u, int signo) {
716         assert(u);
717
718         if (!u->slice)
719                 return -ESRCH;
720
721         return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
722 }
723
724 void user_elect_display(User *u) {
725         Session *graphical = NULL, *text = NULL, *other = NULL, *s;
726
727         assert(u);
728
729         /* This elects a primary session for each user, which we call
730          * the "display". We try to keep the assignment stable, but we
731          * "upgrade" to better choices. */
732
733         LIST_FOREACH(sessions_by_user, s, u->sessions) {
734
735                 if (s->class != SESSION_USER)
736                         continue;
737
738                 if (s->stopping)
739                         continue;
740
741                 if (SESSION_TYPE_IS_GRAPHICAL(s->type))
742                         graphical = s;
743                 else if (s->type == SESSION_TTY)
744                         text = s;
745                 else
746                         other = s;
747         }
748
749         if (graphical &&
750             (!u->display ||
751              u->display->class != SESSION_USER ||
752              u->display->stopping ||
753              !SESSION_TYPE_IS_GRAPHICAL(u->display->type))) {
754                 u->display = graphical;
755                 return;
756         }
757
758         if (text &&
759             (!u->display ||
760              u->display->class != SESSION_USER ||
761              u->display->stopping ||
762              u->display->type != SESSION_TTY)) {
763                 u->display = text;
764                 return;
765         }
766
767         if (other &&
768             (!u->display ||
769              u->display->class != SESSION_USER ||
770              u->display->stopping))
771                 u->display = other;
772 }
773
774 static const char* const user_state_table[_USER_STATE_MAX] = {
775         [USER_OFFLINE] = "offline",
776         [USER_OPENING] = "opening",
777         [USER_LINGERING] = "lingering",
778         [USER_ONLINE] = "online",
779         [USER_ACTIVE] = "active",
780         [USER_CLOSING] = "closing"
781 };
782
783 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
784
785 int config_parse_tmpfs_size(
786                 const char* unit,
787                 const char *filename,
788                 unsigned line,
789                 const char *section,
790                 unsigned section_line,
791                 const char *lvalue,
792                 int ltype,
793                 const char *rvalue,
794                 void *data,
795                 void *userdata) {
796
797         size_t *sz = data;
798         const char *e;
799         int r;
800
801         assert(filename);
802         assert(lvalue);
803         assert(rvalue);
804         assert(data);
805
806         e = endswith(rvalue, "%");
807         if (e) {
808                 unsigned long ul;
809                 char *f;
810
811                 errno = 0;
812                 ul = strtoul(rvalue, &f, 10);
813                 if (errno != 0 || f != e) {
814                         log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
815                         return 0;
816                 }
817
818                 if (ul <= 0 || ul >= 100) {
819                         log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
820                         return 0;
821                 }
822
823                 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
824         } else {
825                 off_t o;
826
827                 r = parse_size(rvalue, 1024, &o);
828                 if (r < 0 || (off_t) (size_t) o != o) {
829                         log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
830                         return 0;
831                 }
832
833                 *sz = PAGE_ALIGN((size_t) o);
834         }
835
836         return 0;
837 }