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