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