chiark / gitweb /
rename basic.la to shared.la and put selinux deps in shared-selinx.la
[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 General Public License as published by
10   the Free Software Foundation; either version 2 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   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <string.h>
23 #include <unistd.h>
24 #include <errno.h>
25
26 #include "logind-user.h"
27 #include "util.h"
28 #include "mkdir.h"
29 #include "cgroup-util.h"
30 #include "hashmap.h"
31 #include "strv.h"
32
33 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
34         User *u;
35
36         assert(m);
37         assert(name);
38
39         u = new0(User, 1);
40         if (!u)
41                 return NULL;
42
43         u->name = strdup(name);
44         if (!u->name) {
45                 free(u);
46                 return NULL;
47         }
48
49         if (asprintf(&u->state_file, "/run/systemd/users/%lu", (unsigned long) uid) < 0) {
50                 free(u->name);
51                 free(u);
52                 return NULL;
53         }
54
55         if (hashmap_put(m->users, ULONG_TO_PTR((unsigned long) uid), u) < 0) {
56                 free(u->state_file);
57                 free(u->name);
58                 free(u);
59                 return NULL;
60         }
61
62         u->manager = m;
63         u->uid = uid;
64         u->gid = gid;
65
66         return u;
67 }
68
69 void user_free(User *u) {
70         assert(u);
71
72         if (u->in_gc_queue)
73                 LIST_REMOVE(User, gc_queue, u->manager->user_gc_queue, u);
74
75         while (u->sessions)
76                 session_free(u->sessions);
77
78         free(u->cgroup_path);
79
80         free(u->service);
81         free(u->runtime_path);
82
83         hashmap_remove(u->manager->users, ULONG_TO_PTR((unsigned long) u->uid));
84
85         free(u->name);
86         free(u->state_file);
87         free(u);
88 }
89
90 int user_save(User *u) {
91         FILE *f;
92         int r;
93         char *temp_path;
94
95         assert(u);
96         assert(u->state_file);
97
98         if (!u->started)
99                 return 0;
100
101         r = safe_mkdir("/run/systemd/users", 0755, 0, 0);
102         if (r < 0)
103                 goto finish;
104
105         r = fopen_temporary(u->state_file, &f, &temp_path);
106         if (r < 0)
107                 goto finish;
108
109         fchmod(fileno(f), 0644);
110
111         fprintf(f,
112                 "# This is private data. Do not parse.\n"
113                 "NAME=%s\n"
114                 "STATE=%s\n",
115                 u->name,
116                 user_state_to_string(user_get_state(u)));
117
118         if (u->cgroup_path)
119                 fprintf(f,
120                         "CGROUP=%s\n",
121                         u->cgroup_path);
122
123         if (u->runtime_path)
124                 fprintf(f,
125                         "RUNTIME=%s\n",
126                         u->runtime_path);
127
128         if (u->service)
129                 fprintf(f,
130                         "SERVICE=%s\n",
131                         u->service);
132
133         if (u->display)
134                 fprintf(f,
135                         "DISPLAY=%s\n",
136                         u->display->id);
137
138         if (u->sessions) {
139                 Session *i;
140
141                 fputs("SESSIONS=", f);
142                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
143                         fprintf(f,
144                                 "%s%c",
145                                 i->id,
146                                 i->sessions_by_user_next ? ' ' : '\n');
147                 }
148
149                 fputs("SEATS=", f);
150                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
151                         if (i->seat)
152                                 fprintf(f,
153                                         "%s%c",
154                                         i->seat->id,
155                                         i->sessions_by_user_next ? ' ' : '\n');
156                 }
157
158                 fputs("ACTIVE_SESSIONS=", f);
159                 LIST_FOREACH(sessions_by_user, i, u->sessions)
160                         if (session_is_active(i))
161                                 fprintf(f,
162                                         "%lu%c",
163                                         (unsigned long) i->user->uid,
164                                         i->sessions_by_user_next ? ' ' : '\n');
165
166                 fputs("ACTIVE_SEATS=", f);
167                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
168                         if (session_is_active(i) && i->seat)
169                                 fprintf(f,
170                                         "%s%c",
171                                         i->seat->id,
172                                         i->sessions_by_user_next ? ' ' : '\n');
173                 }
174         }
175
176         fflush(f);
177
178         if (ferror(f) || rename(temp_path, u->state_file) < 0) {
179                 r = -errno;
180                 unlink(u->state_file);
181                 unlink(temp_path);
182         }
183
184         fclose(f);
185         free(temp_path);
186
187 finish:
188         if (r < 0)
189                 log_error("Failed to save user data for %s: %s", u->name, strerror(-r));
190
191         return r;
192 }
193
194 int user_load(User *u) {
195         int r;
196         char *display = NULL;
197         Session *s = NULL;
198
199         assert(u);
200
201         r = parse_env_file(u->state_file, NEWLINE,
202                            "CGROUP", &u->cgroup_path,
203                            "RUNTIME", &u->runtime_path,
204                            "SERVICE", &u->service,
205                            "DISPLAY", &display,
206                            NULL);
207         if (r < 0) {
208                 free(display);
209
210                 if (r == -ENOENT)
211                         return 0;
212
213                 log_error("Failed to read %s: %s", u->state_file, strerror(-r));
214                 return r;
215         }
216
217         if (display) {
218                 s = hashmap_get(u->manager->sessions, display);
219                 free(display);
220         }
221
222         if (s && s->display && display_is_local(s->display))
223                 u->display = s;
224
225         return r;
226 }
227
228 static int user_mkdir_runtime_path(User *u) {
229         char *p;
230         int r;
231
232         assert(u);
233
234         r = safe_mkdir("/run/user", 0755, 0, 0);
235         if (r < 0) {
236                 log_error("Failed to create /run/user: %s", strerror(-r));
237                 return r;
238         }
239
240         if (!u->runtime_path) {
241                 p = strappend("/run/user/", u->name);
242
243                 if (!p) {
244                         log_error("Out of memory");
245                         return -ENOMEM;
246                 }
247         } else
248                 p = u->runtime_path;
249
250         r = safe_mkdir(p, 0700, u->uid, u->gid);
251         if (r < 0) {
252                 log_error("Failed to create runtime directory %s: %s", p, strerror(-r));
253                 free(p);
254                 u->runtime_path = NULL;
255                 return r;
256         }
257
258         u->runtime_path = p;
259         return 0;
260 }
261
262 static int user_create_cgroup(User *u) {
263         char **k;
264         char *p;
265         int r;
266
267         assert(u);
268
269         if (!u->cgroup_path) {
270                 if (asprintf(&p, "%s/%s", u->manager->cgroup_path, u->name) < 0) {
271                         log_error("Out of memory");
272                         return -ENOMEM;
273                 }
274         } else
275                 p = u->cgroup_path;
276
277         r = cg_create(SYSTEMD_CGROUP_CONTROLLER, p);
278         if (r < 0) {
279                 log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
280                 free(p);
281                 u->cgroup_path = NULL;
282                 return r;
283         }
284
285         u->cgroup_path = p;
286
287         STRV_FOREACH(k, u->manager->controllers) {
288
289                 if (strv_contains(u->manager->reset_controllers, *k))
290                         continue;
291
292                 r = cg_create(*k, p);
293                 if (r < 0)
294                         log_warning("Failed to create cgroup %s:%s: %s", *k, p, strerror(-r));
295         }
296
297         return 0;
298 }
299
300 static int user_start_service(User *u) {
301         assert(u);
302
303         /* FIXME: Fill me in later ... */
304
305         return 0;
306 }
307
308 int user_start(User *u) {
309         int r;
310
311         assert(u);
312
313         if (u->started)
314                 return 0;
315
316         log_debug("New user %s logged in.", u->name);
317
318         /* Make XDG_RUNTIME_DIR */
319         r = user_mkdir_runtime_path(u);
320         if (r < 0)
321                 return r;
322
323         /* Create cgroup */
324         r = user_create_cgroup(u);
325         if (r < 0)
326                 return r;
327
328         /* Spawn user systemd */
329         r = user_start_service(u);
330         if (r < 0)
331                 return r;
332
333         dual_timestamp_get(&u->timestamp);
334
335         u->started = true;
336
337         /* Save new user data */
338         user_save(u);
339
340         user_send_signal(u, true);
341
342         return 0;
343 }
344
345 static int user_stop_service(User *u) {
346         assert(u);
347
348         if (!u->service)
349                 return 0;
350
351         return 0;
352 }
353
354 static int user_shall_kill(User *u) {
355         assert(u);
356
357         if (!u->manager->kill_user_processes)
358                 return false;
359
360         if (strv_contains(u->manager->kill_exclude_users, u->name))
361                 return false;
362
363         if (strv_isempty(u->manager->kill_only_users))
364                 return true;
365
366         return strv_contains(u->manager->kill_only_users, u->name);
367 }
368
369 static int user_terminate_cgroup(User *u) {
370         int r;
371         char **k;
372
373         assert(u);
374
375         if (!u->cgroup_path)
376                 return 0;
377
378         cg_trim(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, false);
379
380         if (user_shall_kill(u)) {
381
382                 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
383                 if (r < 0)
384                         log_error("Failed to kill user cgroup: %s", strerror(-r));
385         } else {
386
387                 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
388                 if (r < 0)
389                         log_error("Failed to check user cgroup: %s", strerror(-r));
390                 else if (r > 0) {
391                         r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
392                         if (r < 0)
393                                 log_error("Failed to delete user cgroup: %s", strerror(-r));
394                 } else
395                         r = -EBUSY;
396         }
397
398         STRV_FOREACH(k, u->manager->controllers)
399                 cg_trim(*k, u->cgroup_path, true);
400
401         free(u->cgroup_path);
402         u->cgroup_path = NULL;
403
404         return r;
405 }
406
407 static int user_remove_runtime_path(User *u) {
408         int r;
409
410         assert(u);
411
412         if (!u->runtime_path)
413                 return 0;
414
415         r = rm_rf(u->runtime_path, false, true, false);
416         if (r < 0)
417                 log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
418
419         free(u->runtime_path);
420         u->runtime_path = NULL;
421
422         return r;
423 }
424
425 int user_stop(User *u) {
426         Session *s;
427         int r = 0, k;
428         assert(u);
429
430         if (u->started)
431                 log_debug("User %s logged out.", u->name);
432
433         LIST_FOREACH(sessions_by_user, s, u->sessions) {
434                 k = session_stop(s);
435                 if (k < 0)
436                         r = k;
437         }
438
439         /* Kill systemd */
440         k = user_stop_service(u);
441         if (k < 0)
442                 r = k;
443
444         /* Kill cgroup */
445         k = user_terminate_cgroup(u);
446         if (k < 0)
447                 r = k;
448
449         /* Kill XDG_RUNTIME_DIR */
450         k = user_remove_runtime_path(u);
451         if (k < 0)
452                 r = k;
453
454         unlink(u->state_file);
455         user_add_to_gc_queue(u);
456
457         if (u->started)
458                 user_send_signal(u, false);
459
460         u->started = false;
461
462         return r;
463 }
464
465 int user_get_idle_hint(User *u, dual_timestamp *t) {
466         Session *s;
467         bool idle_hint = true;
468         dual_timestamp ts = { 0, 0 };
469
470         assert(u);
471
472         LIST_FOREACH(sessions_by_user, s, u->sessions) {
473                 dual_timestamp k;
474                 int ih;
475
476                 ih = session_get_idle_hint(s, &k);
477                 if (ih < 0)
478                         return ih;
479
480                 if (!ih) {
481                         if (!idle_hint) {
482                                 if (k.monotonic < ts.monotonic)
483                                         ts = k;
484                         } else {
485                                 idle_hint = false;
486                                 ts = k;
487                         }
488                 } else if (idle_hint) {
489
490                         if (k.monotonic > ts.monotonic)
491                                 ts = k;
492                 }
493         }
494
495         if (t)
496                 *t = ts;
497
498         return idle_hint;
499 }
500
501 int user_check_gc(User *u, bool drop_not_started) {
502         int r;
503         char *p;
504
505         assert(u);
506
507         if (drop_not_started && !u->started)
508                 return 0;
509
510         if (u->sessions)
511                 return 1;
512
513         if (asprintf(&p, "/var/lib/systemd/linger/%s", u->name) < 0)
514                 return -ENOMEM;
515
516         r = access(p, F_OK) >= 0;
517         free(p);
518
519         if (r > 0)
520                 return 1;
521
522         if (u->cgroup_path) {
523                 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, false);
524                 if (r < 0)
525                         return r;
526
527                 if (r <= 0)
528                         return 1;
529         }
530
531         return 0;
532 }
533
534 void user_add_to_gc_queue(User *u) {
535         assert(u);
536
537         if (u->in_gc_queue)
538                 return;
539
540         LIST_PREPEND(User, gc_queue, u->manager->user_gc_queue, u);
541         u->in_gc_queue = true;
542 }
543
544 UserState user_get_state(User *u) {
545         Session *i;
546
547         assert(u);
548
549         if (!u->sessions)
550                 return USER_LINGERING;
551
552         LIST_FOREACH(sessions_by_user, i, u->sessions)
553                 if (session_is_active(i))
554                         return USER_ACTIVE;
555
556         return USER_ONLINE;
557 }
558
559 int user_kill(User *u, int signo) {
560         int r = 0, q;
561         Set *pid_set = NULL;
562
563         assert(u);
564
565         if (!u->cgroup_path)
566                 return -ESRCH;
567
568         pid_set = set_new(trivial_hash_func, trivial_compare_func);
569         if (!pid_set)
570                 return -ENOMEM;
571
572         q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
573         if (q < 0)
574                 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
575                         r = q;
576
577         if (pid_set)
578                 set_free(pid_set);
579
580         return r;
581 }
582
583 static const char* const user_state_table[_USER_STATE_MAX] = {
584         [USER_OFFLINE] = "offline",
585         [USER_LINGERING] = "lingering",
586         [USER_ONLINE] = "online",
587         [USER_ACTIVE] = "active"
588 };
589
590 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);