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