chiark / gitweb /
util: rework strappenda(), and rename it strjoina()
[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                         if (errno != EPERM) {
339                                 r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", p);
340                                 goto fail;
341                         }
342
343                         /* Lacking permissions, maybe
344                          * CAP_SYS_ADMIN-less container? In this case,
345                          * just use a normal directory. */
346
347                         r = chmod_and_chown(p, 0700, u->uid, u->gid);
348                         if (r < 0) {
349                                 log_error_errno(r, "Failed to change runtime directory ownership and mode: %m");
350                                 goto fail;
351                         }
352                 }
353         }
354
355         u->runtime_path = p;
356         return 0;
357
358 fail:
359         if (p) {
360                 /* Try to clean up, but ignore errors */
361                 (void) rmdir(p);
362                 free(p);
363         }
364
365         u->runtime_path = NULL;
366         return r;
367 }
368
369 static int user_start_slice(User *u) {
370         char *job;
371         int r;
372
373         assert(u);
374
375         if (!u->slice) {
376                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
377                 char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
378                 sprintf(lu, UID_FMT, u->uid);
379
380                 r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
381                 if (r < 0)
382                         return r;
383
384                 r = manager_start_unit(u->manager, slice, &error, &job);
385                 if (r < 0) {
386                         log_error("Failed to start user slice: %s", bus_error_message(&error, r));
387                         free(slice);
388                 } else {
389                         u->slice = slice;
390
391                         free(u->slice_job);
392                         u->slice_job = job;
393                 }
394         }
395
396         if (u->slice)
397                 hashmap_put(u->manager->user_units, u->slice, u);
398
399         return 0;
400 }
401
402 static int user_start_service(User *u) {
403         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
404         char *job;
405         int r;
406
407         assert(u);
408
409         if (!u->service) {
410                 char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
411                 sprintf(lu, UID_FMT, u->uid);
412
413                 service = unit_name_build("user", lu, ".service");
414                 if (!service)
415                         return log_oom();
416
417                 r = manager_start_unit(u->manager, service, &error, &job);
418                 if (r < 0) {
419                         log_error("Failed to start user service: %s", bus_error_message(&error, r));
420                         free(service);
421                 } else {
422                         u->service = service;
423
424                         free(u->service_job);
425                         u->service_job = job;
426                 }
427         }
428
429         if (u->service)
430                 hashmap_put(u->manager->user_units, u->service, u);
431
432         return 0;
433 }
434
435 int user_start(User *u) {
436         int r;
437
438         assert(u);
439
440         if (u->started)
441                 return 0;
442
443         log_debug("New user %s logged in.", u->name);
444
445         /* Make XDG_RUNTIME_DIR */
446         r = user_mkdir_runtime_path(u);
447         if (r < 0)
448                 return r;
449
450         /* Create cgroup */
451         r = user_start_slice(u);
452         if (r < 0)
453                 return r;
454
455         /* Spawn user systemd */
456         r = user_start_service(u);
457         if (r < 0)
458                 return r;
459
460         if (!dual_timestamp_is_set(&u->timestamp))
461                 dual_timestamp_get(&u->timestamp);
462
463         u->started = true;
464
465         /* Save new user data */
466         user_save(u);
467
468         user_send_signal(u, true);
469
470         return 0;
471 }
472
473 static int user_stop_slice(User *u) {
474         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
475         char *job;
476         int r;
477
478         assert(u);
479
480         if (!u->slice)
481                 return 0;
482
483         r = manager_stop_unit(u->manager, u->slice, &error, &job);
484         if (r < 0) {
485                 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
486                 return r;
487         }
488
489         free(u->slice_job);
490         u->slice_job = job;
491
492         return r;
493 }
494
495 static int user_stop_service(User *u) {
496         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
497         char *job;
498         int r;
499
500         assert(u);
501
502         if (!u->service)
503                 return 0;
504
505         r = manager_stop_unit(u->manager, u->service, &error, &job);
506         if (r < 0) {
507                 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
508                 return r;
509         }
510
511         free(u->service_job);
512         u->service_job = job;
513
514         return r;
515 }
516
517 static int user_remove_runtime_path(User *u) {
518         int r;
519
520         assert(u);
521
522         if (!u->runtime_path)
523                 return 0;
524
525         r = rm_rf(u->runtime_path, false, false, false);
526         if (r < 0)
527                 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
528
529         /* Ignore cases where the directory isn't mounted, as that's
530          * quite possible, if we lacked the permissions to mount
531          * something */
532         r = umount2(u->runtime_path, MNT_DETACH);
533         if (r < 0 && errno != EINVAL && errno != ENOENT)
534                 log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
535
536         r = rm_rf(u->runtime_path, false, true, false);
537         if (r < 0)
538                 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
539
540         free(u->runtime_path);
541         u->runtime_path = NULL;
542
543         return r;
544 }
545
546 int user_stop(User *u, bool force) {
547         Session *s;
548         int r = 0, k;
549         assert(u);
550
551         /* Stop jobs have already been queued */
552         if (u->stopping) {
553                 user_save(u);
554                 return r;
555         }
556
557         LIST_FOREACH(sessions_by_user, s, u->sessions) {
558                 k = session_stop(s, force);
559                 if (k < 0)
560                         r = k;
561         }
562
563         /* Kill systemd */
564         k = user_stop_service(u);
565         if (k < 0)
566                 r = k;
567
568         /* Kill cgroup */
569         k = user_stop_slice(u);
570         if (k < 0)
571                 r = k;
572
573         u->stopping = true;
574
575         user_save(u);
576
577         return r;
578 }
579
580 int user_finalize(User *u) {
581         Session *s;
582         int r = 0, k;
583
584         assert(u);
585
586         if (u->started)
587                 log_debug("User %s logged out.", u->name);
588
589         LIST_FOREACH(sessions_by_user, s, u->sessions) {
590                 k = session_finalize(s);
591                 if (k < 0)
592                         r = k;
593         }
594
595         /* Kill XDG_RUNTIME_DIR */
596         k = user_remove_runtime_path(u);
597         if (k < 0)
598                 r = k;
599
600         /* Clean SysV + POSIX IPC objects */
601         if (u->manager->remove_ipc) {
602                 k = clean_ipc(u->uid);
603                 if (k < 0)
604                         r = k;
605         }
606
607         unlink(u->state_file);
608         user_add_to_gc_queue(u);
609
610         if (u->started) {
611                 user_send_signal(u, false);
612                 u->started = false;
613         }
614
615         return r;
616 }
617
618 int user_get_idle_hint(User *u, dual_timestamp *t) {
619         Session *s;
620         bool idle_hint = true;
621         dual_timestamp ts = { 0, 0 };
622
623         assert(u);
624
625         LIST_FOREACH(sessions_by_user, s, u->sessions) {
626                 dual_timestamp k;
627                 int ih;
628
629                 ih = session_get_idle_hint(s, &k);
630                 if (ih < 0)
631                         return ih;
632
633                 if (!ih) {
634                         if (!idle_hint) {
635                                 if (k.monotonic < ts.monotonic)
636                                         ts = k;
637                         } else {
638                                 idle_hint = false;
639                                 ts = k;
640                         }
641                 } else if (idle_hint) {
642
643                         if (k.monotonic > ts.monotonic)
644                                 ts = k;
645                 }
646         }
647
648         if (t)
649                 *t = ts;
650
651         return idle_hint;
652 }
653
654 int user_check_linger_file(User *u) {
655         _cleanup_free_ char *cc = NULL;
656         char *p = NULL;
657
658         cc = cescape(u->name);
659         if (!cc)
660                 return -ENOMEM;
661
662         p = strjoina("/var/lib/systemd/linger/", cc);
663
664         return access(p, F_OK) >= 0;
665 }
666
667 bool user_check_gc(User *u, bool drop_not_started) {
668         assert(u);
669
670         if (drop_not_started && !u->started)
671                 return false;
672
673         if (u->sessions)
674                 return true;
675
676         if (user_check_linger_file(u) > 0)
677                 return true;
678
679         if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
680                 return true;
681
682         if (u->service_job && manager_job_is_active(u->manager, u->service_job))
683                 return true;
684
685         return false;
686 }
687
688 void user_add_to_gc_queue(User *u) {
689         assert(u);
690
691         if (u->in_gc_queue)
692                 return;
693
694         LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
695         u->in_gc_queue = true;
696 }
697
698 UserState user_get_state(User *u) {
699         Session *i;
700
701         assert(u);
702
703         if (u->stopping)
704                 return USER_CLOSING;
705
706         if (u->slice_job || u->service_job)
707                 return USER_OPENING;
708
709         if (u->sessions) {
710                 bool all_closing = true;
711
712                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
713                         SessionState state;
714
715                         state = session_get_state(i);
716                         if (state == SESSION_ACTIVE)
717                                 return USER_ACTIVE;
718                         if (state != SESSION_CLOSING)
719                                 all_closing = false;
720                 }
721
722                 return all_closing ? USER_CLOSING : USER_ONLINE;
723         }
724
725         if (user_check_linger_file(u) > 0)
726                 return USER_LINGERING;
727
728         return USER_CLOSING;
729 }
730
731 int user_kill(User *u, int signo) {
732         assert(u);
733
734         if (!u->slice)
735                 return -ESRCH;
736
737         return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
738 }
739
740 void user_elect_display(User *u) {
741         Session *graphical = NULL, *text = NULL, *other = NULL, *s;
742
743         assert(u);
744
745         /* This elects a primary session for each user, which we call
746          * the "display". We try to keep the assignment stable, but we
747          * "upgrade" to better choices. */
748
749         LIST_FOREACH(sessions_by_user, s, u->sessions) {
750
751                 if (s->class != SESSION_USER)
752                         continue;
753
754                 if (s->stopping)
755                         continue;
756
757                 if (SESSION_TYPE_IS_GRAPHICAL(s->type))
758                         graphical = s;
759                 else if (s->type == SESSION_TTY)
760                         text = s;
761                 else
762                         other = s;
763         }
764
765         if (graphical &&
766             (!u->display ||
767              u->display->class != SESSION_USER ||
768              u->display->stopping ||
769              !SESSION_TYPE_IS_GRAPHICAL(u->display->type))) {
770                 u->display = graphical;
771                 return;
772         }
773
774         if (text &&
775             (!u->display ||
776              u->display->class != SESSION_USER ||
777              u->display->stopping ||
778              u->display->type != SESSION_TTY)) {
779                 u->display = text;
780                 return;
781         }
782
783         if (other &&
784             (!u->display ||
785              u->display->class != SESSION_USER ||
786              u->display->stopping))
787                 u->display = other;
788 }
789
790 static const char* const user_state_table[_USER_STATE_MAX] = {
791         [USER_OFFLINE] = "offline",
792         [USER_OPENING] = "opening",
793         [USER_LINGERING] = "lingering",
794         [USER_ONLINE] = "online",
795         [USER_ACTIVE] = "active",
796         [USER_CLOSING] = "closing"
797 };
798
799 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
800
801 int config_parse_tmpfs_size(
802                 const char* unit,
803                 const char *filename,
804                 unsigned line,
805                 const char *section,
806                 unsigned section_line,
807                 const char *lvalue,
808                 int ltype,
809                 const char *rvalue,
810                 void *data,
811                 void *userdata) {
812
813         size_t *sz = data;
814         const char *e;
815         int r;
816
817         assert(filename);
818         assert(lvalue);
819         assert(rvalue);
820         assert(data);
821
822         e = endswith(rvalue, "%");
823         if (e) {
824                 unsigned long ul;
825                 char *f;
826
827                 errno = 0;
828                 ul = strtoul(rvalue, &f, 10);
829                 if (errno != 0 || f != e) {
830                         log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
831                         return 0;
832                 }
833
834                 if (ul <= 0 || ul >= 100) {
835                         log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
836                         return 0;
837                 }
838
839                 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
840         } else {
841                 off_t o;
842
843                 r = parse_size(rvalue, 1024, &o);
844                 if (r < 0 || (off_t) (size_t) o != o) {
845                         log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
846                         return 0;
847                 }
848
849                 *sz = PAGE_ALIGN((size_t) o);
850         }
851
852         return 0;
853 }