~ubuntu-branches/debian/jessie/systemd/jessie

« back to all changes in this revision

Viewing changes to src/login/logind-session.c

  • Committer: Package Import Robot
  • Author(s): Tollef Fog Heen, Tollef Fog Heen, Michael Biebl
  • Date: 2012-04-03 19:59:17 UTC
  • mfrom: (1.1.10) (6.1.3 experimental)
  • Revision ID: package-import@ubuntu.com-20120403195917-l532urrbg4pkreas
Tags: 44-1
[ Tollef Fog Heen ]
* New upstream version.
  - Backport 3492207: journal: PAGE_SIZE is not known on ppc and other
    archs
  - Backport 5a2a2a1: journal: react with immediate rotation to a couple
    of more errors
  - Backport 693ce21: util: never follow symlinks in rm_rf_children()
    Fixes CVE-2012-1174, closes: #664364
* Drop output message from init-functions hook, it's pointless.
* Only rmdir /lib/init/rw if it exists.
* Explicitly order debian-fixup before sysinit.target to prevent a
  possible race condition with the creation of sockets.  Thanks to
  Michael Biebl for debugging this.
* Always restart the initctl socket on upgrades, to mask sysvinit
  removing it.

[ Michael Biebl ]
* Remove workaround for non-interactive sessions from pam config again.
* Create compat /dev/initctl symlink in case we are upgrading from a system
  running a newer version of sysvinit (using /run/initctl) and sysvinit is
  replaced with systemd-sysv during the upgrade. Closes: #663219
* Install new man pages.
* Build-Depend on valac (>= 0.12) instead of valac-0.12. Closes: #663323

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 <errno.h>
 
23
#include <string.h>
 
24
#include <unistd.h>
 
25
#include <sys/epoll.h>
 
26
#include <fcntl.h>
 
27
 
 
28
#include "logind-session.h"
 
29
#include "strv.h"
 
30
#include "util.h"
 
31
#include "cgroup-util.h"
 
32
 
 
33
#define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
 
34
 
 
35
Session* session_new(Manager *m, User *u, const char *id) {
 
36
        Session *s;
 
37
 
 
38
        assert(m);
 
39
        assert(id);
 
40
 
 
41
        s = new0(Session, 1);
 
42
        if (!s)
 
43
                return NULL;
 
44
 
 
45
        s->state_file = strappend("/run/systemd/sessions/", id);
 
46
        if (!s->state_file) {
 
47
                free(s);
 
48
                return NULL;
 
49
        }
 
50
 
 
51
        s->id = file_name_from_path(s->state_file);
 
52
 
 
53
        if (hashmap_put(m->sessions, s->id, s) < 0) {
 
54
                free(s->id);
 
55
                free(s);
 
56
                return NULL;
 
57
        }
 
58
 
 
59
        s->manager = m;
 
60
        s->fifo_fd = -1;
 
61
        s->user = u;
 
62
 
 
63
        LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
 
64
 
 
65
        return s;
 
66
}
 
67
 
 
68
void session_free(Session *s) {
 
69
        assert(s);
 
70
 
 
71
        if (s->in_gc_queue)
 
72
                LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
 
73
 
 
74
        if (s->user) {
 
75
                LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
 
76
 
 
77
                if (s->user->display == s)
 
78
                        s->user->display = NULL;
 
79
        }
 
80
 
 
81
        if (s->seat) {
 
82
                if (s->seat->active == s)
 
83
                        s->seat->active = NULL;
 
84
 
 
85
                LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
 
86
        }
 
87
 
 
88
        if (s->cgroup_path)
 
89
                hashmap_remove(s->manager->cgroups, s->cgroup_path);
 
90
 
 
91
        free(s->cgroup_path);
 
92
        strv_free(s->controllers);
 
93
 
 
94
        free(s->tty);
 
95
        free(s->display);
 
96
        free(s->remote_host);
 
97
        free(s->remote_user);
 
98
        free(s->service);
 
99
 
 
100
        hashmap_remove(s->manager->sessions, s->id);
 
101
 
 
102
        session_remove_fifo(s);
 
103
 
 
104
        free(s->state_file);
 
105
        free(s);
 
106
}
 
107
 
 
108
int session_save(Session *s) {
 
109
        FILE *f;
 
110
        int r = 0;
 
111
        char *temp_path;
 
112
 
 
113
        assert(s);
 
114
 
 
115
        if (!s->started)
 
116
                return 0;
 
117
 
 
118
        r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0);
 
119
        if (r < 0)
 
120
                goto finish;
 
121
 
 
122
        r = fopen_temporary(s->state_file, &f, &temp_path);
 
123
        if (r < 0)
 
124
                goto finish;
 
125
 
 
126
        assert(s->user);
 
127
 
 
128
        fchmod(fileno(f), 0644);
 
129
 
 
130
        fprintf(f,
 
131
                "# This is private data. Do not parse.\n"
 
132
                "UID=%lu\n"
 
133
                "USER=%s\n"
 
134
                "ACTIVE=%i\n"
 
135
                "REMOTE=%i\n"
 
136
                "KILL_PROCESSES=%i\n",
 
137
                (unsigned long) s->user->uid,
 
138
                s->user->name,
 
139
                session_is_active(s),
 
140
                s->remote,
 
141
                s->kill_processes);
 
142
 
 
143
        if (s->type >= 0)
 
144
                fprintf(f,
 
145
                        "TYPE=%s\n",
 
146
                        session_type_to_string(s->type));
 
147
 
 
148
        if (s->class >= 0)
 
149
                fprintf(f,
 
150
                        "CLASS=%s\n",
 
151
                        session_class_to_string(s->class));
 
152
 
 
153
        if (s->cgroup_path)
 
154
                fprintf(f,
 
155
                        "CGROUP=%s\n",
 
156
                        s->cgroup_path);
 
157
 
 
158
        if (s->fifo_path)
 
159
                fprintf(f,
 
160
                        "FIFO=%s\n",
 
161
                        s->fifo_path);
 
162
 
 
163
        if (s->seat)
 
164
                fprintf(f,
 
165
                        "SEAT=%s\n",
 
166
                        s->seat->id);
 
167
 
 
168
        if (s->tty)
 
169
                fprintf(f,
 
170
                        "TTY=%s\n",
 
171
                        s->tty);
 
172
 
 
173
        if (s->display)
 
174
                fprintf(f,
 
175
                        "DISPLAY=%s\n",
 
176
                        s->display);
 
177
 
 
178
        if (s->remote_host)
 
179
                fprintf(f,
 
180
                        "REMOTE_HOST=%s\n",
 
181
                        s->remote_host);
 
182
 
 
183
        if (s->remote_user)
 
184
                fprintf(f,
 
185
                        "REMOTE_USER=%s\n",
 
186
                        s->remote_user);
 
187
 
 
188
        if (s->service)
 
189
                fprintf(f,
 
190
                        "SERVICE=%s\n",
 
191
                        s->service);
 
192
 
 
193
        if (s->seat && seat_can_multi_session(s->seat))
 
194
                fprintf(f,
 
195
                        "VTNR=%i\n",
 
196
                        s->vtnr);
 
197
 
 
198
        if (s->leader > 0)
 
199
                fprintf(f,
 
200
                        "LEADER=%lu\n",
 
201
                        (unsigned long) s->leader);
 
202
 
 
203
        if (s->audit_id > 0)
 
204
                fprintf(f,
 
205
                        "AUDIT=%llu\n",
 
206
                        (unsigned long long) s->audit_id);
 
207
 
 
208
        fflush(f);
 
209
 
 
210
        if (ferror(f) || rename(temp_path, s->state_file) < 0) {
 
211
                r = -errno;
 
212
                unlink(s->state_file);
 
213
                unlink(temp_path);
 
214
        }
 
215
 
 
216
        fclose(f);
 
217
        free(temp_path);
 
218
 
 
219
finish:
 
220
        if (r < 0)
 
221
                log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
 
222
 
 
223
        return r;
 
224
}
 
225
 
 
226
int session_load(Session *s) {
 
227
        char *remote = NULL,
 
228
                *kill_processes = NULL,
 
229
                *seat = NULL,
 
230
                *vtnr = NULL,
 
231
                *leader = NULL,
 
232
                *audit_id = NULL,
 
233
                *type = NULL,
 
234
                *class = NULL;
 
235
 
 
236
        int k, r;
 
237
 
 
238
        assert(s);
 
239
 
 
240
        r = parse_env_file(s->state_file, NEWLINE,
 
241
                           "REMOTE",         &remote,
 
242
                           "KILL_PROCESSES", &kill_processes,
 
243
                           "CGROUP",         &s->cgroup_path,
 
244
                           "FIFO",           &s->fifo_path,
 
245
                           "SEAT",           &seat,
 
246
                           "TTY",            &s->tty,
 
247
                           "DISPLAY",        &s->display,
 
248
                           "REMOTE_HOST",    &s->remote_host,
 
249
                           "REMOTE_USER",    &s->remote_user,
 
250
                           "SERVICE",        &s->service,
 
251
                           "VTNR",           &vtnr,
 
252
                           "LEADER",         &leader,
 
253
                           "TYPE",           &type,
 
254
                           "CLASS",          &class,
 
255
                           NULL);
 
256
 
 
257
        if (r < 0)
 
258
                goto finish;
 
259
 
 
260
        if (remote) {
 
261
                k = parse_boolean(remote);
 
262
                if (k >= 0)
 
263
                        s->remote = k;
 
264
        }
 
265
 
 
266
        if (kill_processes) {
 
267
                k = parse_boolean(kill_processes);
 
268
                if (k >= 0)
 
269
                        s->kill_processes = k;
 
270
        }
 
271
 
 
272
        if (seat && !s->seat) {
 
273
                Seat *o;
 
274
 
 
275
                o = hashmap_get(s->manager->seats, seat);
 
276
                if (o)
 
277
                        seat_attach_session(o, s);
 
278
        }
 
279
 
 
280
        if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
 
281
                int v;
 
282
 
 
283
                k = safe_atoi(vtnr, &v);
 
284
                if (k >= 0 && v >= 1)
 
285
                        s->vtnr = v;
 
286
        }
 
287
 
 
288
        if (leader) {
 
289
                pid_t pid;
 
290
 
 
291
                k = parse_pid(leader, &pid);
 
292
                if (k >= 0 && pid >= 1) {
 
293
                        s->leader = pid;
 
294
 
 
295
                        audit_session_from_pid(pid, &s->audit_id);
 
296
                }
 
297
        }
 
298
 
 
299
        if (type) {
 
300
                SessionType t;
 
301
 
 
302
                t = session_type_from_string(type);
 
303
                if (t >= 0)
 
304
                        s->type = t;
 
305
        }
 
306
 
 
307
        if (class) {
 
308
                SessionClass c;
 
309
 
 
310
                c = session_class_from_string(class);
 
311
                if (c >= 0)
 
312
                        s->class = c;
 
313
        }
 
314
 
 
315
        if (s->fifo_path) {
 
316
                int fd;
 
317
 
 
318
                /* If we open an unopened pipe for reading we will not
 
319
                   get an EOF. to trigger an EOF we hence open it for
 
320
                   reading, but close it right-away which then will
 
321
                   trigger the EOF. */
 
322
 
 
323
                fd = session_create_fifo(s);
 
324
                if (fd >= 0)
 
325
                        close_nointr_nofail(fd);
 
326
        }
 
327
 
 
328
 
 
329
finish:
 
330
        free(remote);
 
331
        free(kill_processes);
 
332
        free(seat);
 
333
        free(vtnr);
 
334
        free(leader);
 
335
        free(audit_id);
 
336
 
 
337
        return r;
 
338
}
 
339
 
 
340
int session_activate(Session *s) {
 
341
        int r;
 
342
 
 
343
        assert(s);
 
344
 
 
345
        if (s->vtnr < 0)
 
346
                return -ENOTSUP;
 
347
 
 
348
        if (!s->seat)
 
349
                return -ENOTSUP;
 
350
 
 
351
        if (s->seat->active == s)
 
352
                return 0;
 
353
 
 
354
        assert(seat_is_vtconsole(s->seat));
 
355
 
 
356
        r = chvt(s->vtnr);
 
357
        if (r < 0)
 
358
                return r;
 
359
 
 
360
        return seat_set_active(s->seat, s);
 
361
}
 
362
 
 
363
static int session_link_x11_socket(Session *s) {
 
364
        char *t, *f, *c;
 
365
        size_t k;
 
366
 
 
367
        assert(s);
 
368
        assert(s->user);
 
369
        assert(s->user->runtime_path);
 
370
 
 
371
        if (s->user->display)
 
372
                return 0;
 
373
 
 
374
        if (!s->display || !display_is_local(s->display))
 
375
                return 0;
 
376
 
 
377
        k = strspn(s->display+1, "0123456789");
 
378
        f = new(char, sizeof("/tmp/.X11-unix/X") + k);
 
379
        if (!f) {
 
380
                log_error("Out of memory");
 
381
                return -ENOMEM;
 
382
        }
 
383
 
 
384
        c = stpcpy(f, "/tmp/.X11-unix/X");
 
385
        memcpy(c, s->display+1, k);
 
386
        c[k] = 0;
 
387
 
 
388
        if (access(f, F_OK) < 0) {
 
389
                log_warning("Session %s has display %s with nonexisting socket %s.", s->id, s->display, f);
 
390
                free(f);
 
391
                return -ENOENT;
 
392
        }
 
393
 
 
394
        t = strappend(s->user->runtime_path, "/X11-display");
 
395
        if (!t) {
 
396
                log_error("Out of memory");
 
397
                free(f);
 
398
                return -ENOMEM;
 
399
        }
 
400
 
 
401
        if (link(f, t) < 0) {
 
402
                if (errno == EEXIST) {
 
403
                        unlink(t);
 
404
 
 
405
                        if (link(f, t) >= 0)
 
406
                                goto done;
 
407
                }
 
408
 
 
409
                if (symlink(f, t) < 0) {
 
410
 
 
411
                        if (errno == EEXIST) {
 
412
                                unlink(t);
 
413
 
 
414
                                if (symlink(f, t) >= 0)
 
415
                                        goto done;
 
416
                        }
 
417
 
 
418
                        log_error("Failed to link %s to %s: %m", f, t);
 
419
                        free(f);
 
420
                        free(t);
 
421
                        return -errno;
 
422
                }
 
423
        }
 
424
 
 
425
done:
 
426
        log_info("Linked %s to %s.", f, t);
 
427
        free(f);
 
428
        free(t);
 
429
 
 
430
        s->user->display = s;
 
431
 
 
432
        return 0;
 
433
}
 
434
 
 
435
static int session_create_one_group(Session *s, const char *controller, const char *path) {
 
436
        int r;
 
437
 
 
438
        assert(s);
 
439
        assert(controller);
 
440
        assert(path);
 
441
 
 
442
        if (s->leader > 0) {
 
443
                r = cg_create_and_attach(controller, path, s->leader);
 
444
                if (r < 0)
 
445
                        r = cg_create(controller, path);
 
446
        } else
 
447
                r = cg_create(controller, path);
 
448
 
 
449
        if (r < 0)
 
450
                return r;
 
451
 
 
452
        r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
 
453
        if (r >= 0)
 
454
                r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
 
455
 
 
456
        return r;
 
457
}
 
458
 
 
459
static int session_create_cgroup(Session *s) {
 
460
        char **k;
 
461
        char *p;
 
462
        int r;
 
463
 
 
464
        assert(s);
 
465
        assert(s->user);
 
466
        assert(s->user->cgroup_path);
 
467
 
 
468
        if (!s->cgroup_path) {
 
469
                if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0) {
 
470
                        log_error("Out of memory");
 
471
                        return -ENOMEM;
 
472
                }
 
473
        } else
 
474
                p = s->cgroup_path;
 
475
 
 
476
        r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
 
477
        if (r < 0) {
 
478
                log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
 
479
                free(p);
 
480
                s->cgroup_path = NULL;
 
481
                return r;
 
482
        }
 
483
 
 
484
        s->cgroup_path = p;
 
485
 
 
486
        STRV_FOREACH(k, s->controllers) {
 
487
 
 
488
                if (strv_contains(s->reset_controllers, *k))
 
489
                        continue;
 
490
 
 
491
                r = session_create_one_group(s, *k, p);
 
492
                if (r < 0)
 
493
                        log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
 
494
        }
 
495
 
 
496
        STRV_FOREACH(k, s->manager->controllers) {
 
497
 
 
498
                if (strv_contains(s->reset_controllers, *k) ||
 
499
                    strv_contains(s->manager->reset_controllers, *k) ||
 
500
                    strv_contains(s->controllers, *k))
 
501
                        continue;
 
502
 
 
503
                r = session_create_one_group(s, *k, p);
 
504
                if (r < 0)
 
505
                        log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
 
506
        }
 
507
 
 
508
        if (s->leader > 0) {
 
509
 
 
510
                STRV_FOREACH(k, s->reset_controllers) {
 
511
                        r = cg_attach(*k, "/", s->leader);
 
512
                        if (r < 0)
 
513
                                log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
 
514
 
 
515
                }
 
516
 
 
517
                STRV_FOREACH(k, s->manager->reset_controllers) {
 
518
 
 
519
                        if (strv_contains(s->reset_controllers, *k) ||
 
520
                            strv_contains(s->controllers, *k))
 
521
                                continue;
 
522
 
 
523
                        r = cg_attach(*k, "/", s->leader);
 
524
                        if (r < 0)
 
525
                                log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
 
526
 
 
527
                }
 
528
        }
 
529
 
 
530
        hashmap_put(s->manager->cgroups, s->cgroup_path, s);
 
531
 
 
532
        return 0;
 
533
}
 
534
 
 
535
int session_start(Session *s) {
 
536
        int r;
 
537
 
 
538
        assert(s);
 
539
        assert(s->user);
 
540
 
 
541
        if (s->started)
 
542
                return 0;
 
543
 
 
544
        r = user_start(s->user);
 
545
        if (r < 0)
 
546
                return r;
 
547
 
 
548
        log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
 
549
                 "New session %s of user %s.", s->id, s->user->name);
 
550
 
 
551
        /* Create cgroup */
 
552
        r = session_create_cgroup(s);
 
553
        if (r < 0)
 
554
                return r;
 
555
 
 
556
        /* Create X11 symlink */
 
557
        session_link_x11_socket(s);
 
558
 
 
559
        dual_timestamp_get(&s->timestamp);
 
560
 
 
561
        if (s->seat)
 
562
                seat_read_active_vt(s->seat);
 
563
 
 
564
        s->started = true;
 
565
 
 
566
        /* Save session data */
 
567
        session_save(s);
 
568
        user_save(s->user);
 
569
 
 
570
        session_send_signal(s, true);
 
571
 
 
572
        if (s->seat) {
 
573
                seat_save(s->seat);
 
574
 
 
575
                if (s->seat->active == s)
 
576
                        seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
 
577
                else
 
578
                        seat_send_changed(s->seat, "Sessions\0");
 
579
        }
 
580
 
 
581
        user_send_changed(s->user, "Sessions\0");
 
582
 
 
583
        return 0;
 
584
}
 
585
 
 
586
static bool session_shall_kill(Session *s) {
 
587
        assert(s);
 
588
 
 
589
        if (!s->kill_processes)
 
590
                return false;
 
591
 
 
592
        if (strv_contains(s->manager->kill_exclude_users, s->user->name))
 
593
                return false;
 
594
 
 
595
        if (strv_isempty(s->manager->kill_only_users))
 
596
                return true;
 
597
 
 
598
        return strv_contains(s->manager->kill_only_users, s->user->name);
 
599
}
 
600
 
 
601
static int session_terminate_cgroup(Session *s) {
 
602
        int r;
 
603
        char **k;
 
604
 
 
605
        assert(s);
 
606
 
 
607
        if (!s->cgroup_path)
 
608
                return 0;
 
609
 
 
610
        cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
 
611
 
 
612
        if (session_shall_kill(s)) {
 
613
 
 
614
                r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
 
615
                if (r < 0)
 
616
                        log_error("Failed to kill session cgroup: %s", strerror(-r));
 
617
 
 
618
        } else {
 
619
                if (s->leader > 0) {
 
620
                        Session *t;
 
621
 
 
622
                        /* We still send a HUP to the leader process,
 
623
                         * even if we are not supposed to kill the
 
624
                         * whole cgroup. But let's first check the
 
625
                         * leader still exists and belongs to our
 
626
                         * session... */
 
627
 
 
628
                        r = manager_get_session_by_pid(s->manager, s->leader, &t);
 
629
                        if (r > 0 && t == s) {
 
630
                                kill(s->leader, SIGTERM); /* for normal processes */
 
631
                                kill(s->leader, SIGHUP);  /* for shells */
 
632
                                kill(s->leader, SIGCONT); /* in case they are stopped */
 
633
                        }
 
634
                }
 
635
 
 
636
                r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
 
637
                if (r < 0)
 
638
                        log_error("Failed to check session cgroup: %s", strerror(-r));
 
639
                else if (r > 0) {
 
640
                        r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
 
641
                        if (r < 0)
 
642
                                log_error("Failed to delete session cgroup: %s", strerror(-r));
 
643
                }
 
644
        }
 
645
 
 
646
        STRV_FOREACH(k, s->user->manager->controllers)
 
647
                cg_trim(*k, s->cgroup_path, true);
 
648
 
 
649
        hashmap_remove(s->manager->cgroups, s->cgroup_path);
 
650
 
 
651
        free(s->cgroup_path);
 
652
        s->cgroup_path = NULL;
 
653
 
 
654
        return 0;
 
655
}
 
656
 
 
657
static int session_unlink_x11_socket(Session *s) {
 
658
        char *t;
 
659
        int r;
 
660
 
 
661
        assert(s);
 
662
        assert(s->user);
 
663
 
 
664
        if (s->user->display != s)
 
665
                return 0;
 
666
 
 
667
        s->user->display = NULL;
 
668
 
 
669
        t = strappend(s->user->runtime_path, "/X11-display");
 
670
        if (!t) {
 
671
                log_error("Out of memory");
 
672
                return -ENOMEM;
 
673
        }
 
674
 
 
675
        r = unlink(t);
 
676
        free(t);
 
677
 
 
678
        return r < 0 ? -errno : 0;
 
679
}
 
680
 
 
681
int session_stop(Session *s) {
 
682
        int r = 0, k;
 
683
 
 
684
        assert(s);
 
685
 
 
686
        if (s->started)
 
687
                log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
 
688
                         "Removed session %s.", s->id);
 
689
 
 
690
        /* Kill cgroup */
 
691
        k = session_terminate_cgroup(s);
 
692
        if (k < 0)
 
693
                r = k;
 
694
 
 
695
        /* Remove X11 symlink */
 
696
        session_unlink_x11_socket(s);
 
697
 
 
698
        unlink(s->state_file);
 
699
        session_add_to_gc_queue(s);
 
700
        user_add_to_gc_queue(s->user);
 
701
 
 
702
        if (s->started)
 
703
                session_send_signal(s, false);
 
704
 
 
705
        if (s->seat) {
 
706
                if (s->seat->active == s)
 
707
                        seat_set_active(s->seat, NULL);
 
708
 
 
709
                seat_send_changed(s->seat, "Sessions\0");
 
710
        }
 
711
 
 
712
        user_send_changed(s->user, "Sessions\0");
 
713
 
 
714
        s->started = false;
 
715
 
 
716
        return r;
 
717
}
 
718
 
 
719
bool session_is_active(Session *s) {
 
720
        assert(s);
 
721
 
 
722
        if (!s->seat)
 
723
                return true;
 
724
 
 
725
        return s->seat->active == s;
 
726
}
 
727
 
 
728
int session_get_idle_hint(Session *s, dual_timestamp *t) {
 
729
        char *p;
 
730
        struct stat st;
 
731
        usec_t u, n;
 
732
        bool b;
 
733
        int k;
 
734
 
 
735
        assert(s);
 
736
 
 
737
        if (s->idle_hint) {
 
738
                if (t)
 
739
                        *t = s->idle_hint_timestamp;
 
740
 
 
741
                return s->idle_hint;
 
742
        }
 
743
 
 
744
        if (isempty(s->tty))
 
745
                goto dont_know;
 
746
 
 
747
        if (s->tty[0] != '/') {
 
748
                p = strappend("/dev/", s->tty);
 
749
                if (!p)
 
750
                        return -ENOMEM;
 
751
        } else
 
752
                p = NULL;
 
753
 
 
754
        if (!startswith(p ? p : s->tty, "/dev/")) {
 
755
                free(p);
 
756
                goto dont_know;
 
757
        }
 
758
 
 
759
        k = lstat(p ? p : s->tty, &st);
 
760
        free(p);
 
761
 
 
762
        if (k < 0)
 
763
                goto dont_know;
 
764
 
 
765
        u = timespec_load(&st.st_atim);
 
766
        n = now(CLOCK_REALTIME);
 
767
        b = u + IDLE_THRESHOLD_USEC < n;
 
768
 
 
769
        if (t)
 
770
                dual_timestamp_from_realtime(t, u + b ? IDLE_THRESHOLD_USEC : 0);
 
771
 
 
772
        return b;
 
773
 
 
774
dont_know:
 
775
        if (t)
 
776
                *t = s->idle_hint_timestamp;
 
777
 
 
778
        return 0;
 
779
}
 
780
 
 
781
void session_set_idle_hint(Session *s, bool b) {
 
782
        assert(s);
 
783
 
 
784
        if (s->idle_hint == b)
 
785
                return;
 
786
 
 
787
        s->idle_hint = b;
 
788
        dual_timestamp_get(&s->idle_hint_timestamp);
 
789
 
 
790
        session_send_changed(s,
 
791
                             "IdleHint\0"
 
792
                             "IdleSinceHint\0"
 
793
                             "IdleSinceHintMonotonic\0");
 
794
 
 
795
        if (s->seat)
 
796
                seat_send_changed(s->seat,
 
797
                                  "IdleHint\0"
 
798
                                  "IdleSinceHint\0"
 
799
                                  "IdleSinceHintMonotonic\0");
 
800
 
 
801
        user_send_changed(s->user,
 
802
                          "IdleHint\0"
 
803
                          "IdleSinceHint\0"
 
804
                          "IdleSinceHintMonotonic\0");
 
805
 
 
806
        manager_send_changed(s->manager,
 
807
                             "IdleHint\0"
 
808
                             "IdleSinceHint\0"
 
809
                             "IdleSinceHintMonotonic\0");
 
810
}
 
811
 
 
812
int session_create_fifo(Session *s) {
 
813
        int r;
 
814
 
 
815
        assert(s);
 
816
 
 
817
        /* Create FIFO */
 
818
        if (!s->fifo_path) {
 
819
                r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0);
 
820
                if (r < 0)
 
821
                        return r;
 
822
 
 
823
                if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
 
824
                        return -ENOMEM;
 
825
 
 
826
                if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
 
827
                        return -errno;
 
828
        }
 
829
 
 
830
        /* Open reading side */
 
831
        if (s->fifo_fd < 0) {
 
832
                struct epoll_event ev;
 
833
 
 
834
                s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
 
835
                if (s->fifo_fd < 0)
 
836
                        return -errno;
 
837
 
 
838
                r = hashmap_put(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1), s);
 
839
                if (r < 0)
 
840
                        return r;
 
841
 
 
842
                zero(ev);
 
843
                ev.events = 0;
 
844
                ev.data.u32 = FD_FIFO_BASE + s->fifo_fd;
 
845
 
 
846
                if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
 
847
                        return -errno;
 
848
        }
 
849
 
 
850
        /* Open writing side */
 
851
        r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
 
852
        if (r < 0)
 
853
                return -errno;
 
854
 
 
855
        return r;
 
856
}
 
857
 
 
858
void session_remove_fifo(Session *s) {
 
859
        assert(s);
 
860
 
 
861
        if (s->fifo_fd >= 0) {
 
862
                assert_se(hashmap_remove(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
 
863
                assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
 
864
                close_nointr_nofail(s->fifo_fd);
 
865
                s->fifo_fd = -1;
 
866
        }
 
867
 
 
868
        if (s->fifo_path) {
 
869
                unlink(s->fifo_path);
 
870
                free(s->fifo_path);
 
871
                s->fifo_path = NULL;
 
872
        }
 
873
}
 
874
 
 
875
int session_check_gc(Session *s, bool drop_not_started) {
 
876
        int r;
 
877
 
 
878
        assert(s);
 
879
 
 
880
        if (drop_not_started && !s->started)
 
881
                return 0;
 
882
 
 
883
        if (s->fifo_fd >= 0) {
 
884
 
 
885
                r = pipe_eof(s->fifo_fd);
 
886
                if (r < 0)
 
887
                        return r;
 
888
 
 
889
                if (r == 0)
 
890
                        return 1;
 
891
        }
 
892
 
 
893
        if (s->cgroup_path) {
 
894
 
 
895
                r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
 
896
                if (r < 0)
 
897
                        return r;
 
898
 
 
899
                if (r <= 0)
 
900
                        return 1;
 
901
        }
 
902
 
 
903
        return 0;
 
904
}
 
905
 
 
906
void session_add_to_gc_queue(Session *s) {
 
907
        assert(s);
 
908
 
 
909
        if (s->in_gc_queue)
 
910
                return;
 
911
 
 
912
        LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
 
913
        s->in_gc_queue = true;
 
914
}
 
915
 
 
916
int session_kill(Session *s, KillWho who, int signo) {
 
917
        int r = 0;
 
918
        Set *pid_set = NULL;
 
919
 
 
920
        assert(s);
 
921
 
 
922
        if (!s->cgroup_path)
 
923
                return -ESRCH;
 
924
 
 
925
        if (s->leader <= 0 && who == KILL_LEADER)
 
926
                return -ESRCH;
 
927
 
 
928
        if (s->leader > 0)
 
929
                if (kill(s->leader, signo) < 0)
 
930
                        r = -errno;
 
931
 
 
932
        if (who == KILL_ALL) {
 
933
                int q;
 
934
 
 
935
                pid_set = set_new(trivial_hash_func, trivial_compare_func);
 
936
                if (!pid_set)
 
937
                        return -ENOMEM;
 
938
 
 
939
                if (s->leader > 0) {
 
940
                        q = set_put(pid_set, LONG_TO_PTR(s->leader));
 
941
                        if (q < 0)
 
942
                                r = q;
 
943
                }
 
944
 
 
945
                q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
 
946
                if (q < 0)
 
947
                        if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
 
948
                                r = q;
 
949
        }
 
950
 
 
951
        if (pid_set)
 
952
                set_free(pid_set);
 
953
 
 
954
        return r;
 
955
}
 
956
 
 
957
static const char* const session_type_table[_SESSION_TYPE_MAX] = {
 
958
        [SESSION_TTY] = "tty",
 
959
        [SESSION_X11] = "x11",
 
960
        [SESSION_UNSPECIFIED] = "unspecified"
 
961
};
 
962
 
 
963
DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
 
964
 
 
965
static const char* const session_class_table[_SESSION_CLASS_MAX] = {
 
966
        [SESSION_USER] = "user",
 
967
        [SESSION_GREETER] = "greeter",
 
968
        [SESSION_LOCK_SCREEN] = "lock-screen"
 
969
};
 
970
 
 
971
DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
 
972
 
 
973
static const char* const kill_who_table[_KILL_WHO_MAX] = {
 
974
        [KILL_LEADER] = "leader",
 
975
        [KILL_ALL] = "all"
 
976
};
 
977
 
 
978
DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);