1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <sys/stat.h>
6 #include <sys/types.h>
7 #include <unistd.h>
8 
9 #include "alloc-util.h"
10 #include "env-file.h"
11 #include "errno-list.h"
12 #include "errno-util.h"
13 #include "escape.h"
14 #include "fd-util.h"
15 #include "fileio.h"
16 #include "format-util.h"
17 #include "io-util.h"
18 #include "logind-dbus.h"
19 #include "logind-inhibit.h"
20 #include "mkdir-label.h"
21 #include "parse-util.h"
22 #include "path-util.h"
23 #include "string-table.h"
24 #include "string-util.h"
25 #include "tmpfile-util.h"
26 #include "user-util.h"
27 #include "util.h"
28 
29 static void inhibitor_remove_fifo(Inhibitor *i);
30 
inhibitor_new(Inhibitor ** ret,Manager * m,const char * id)31 int inhibitor_new(Inhibitor **ret, Manager *m, const char* id) {
32         _cleanup_(inhibitor_freep) Inhibitor *i = NULL;
33         int r;
34 
35         assert(ret);
36         assert(m);
37         assert(id);
38 
39         i = new(Inhibitor, 1);
40         if (!i)
41                 return -ENOMEM;
42 
43         *i = (Inhibitor) {
44                 .manager = m,
45                 .what = _INHIBIT_WHAT_INVALID,
46                 .mode = _INHIBIT_MODE_INVALID,
47                 .uid = UID_INVALID,
48                 .fifo_fd = -1,
49         };
50 
51         i->state_file = path_join("/run/systemd/inhibit", id);
52         if (!i->state_file)
53                 return -ENOMEM;
54 
55         i->id = basename(i->state_file);
56 
57         r = hashmap_put(m->inhibitors, i->id, i);
58         if (r < 0)
59                 return r;
60 
61         *ret = TAKE_PTR(i);
62         return 0;
63 }
64 
inhibitor_free(Inhibitor * i)65 Inhibitor* inhibitor_free(Inhibitor *i) {
66 
67         if (!i)
68                 return NULL;
69 
70         free(i->who);
71         free(i->why);
72 
73         sd_event_source_unref(i->event_source);
74         safe_close(i->fifo_fd);
75 
76         hashmap_remove(i->manager->inhibitors, i->id);
77 
78         /* Note that we don't remove neither the state file nor the fifo path here, since we want both to
79          * survive daemon restarts */
80         free(i->state_file);
81         free(i->fifo_path);
82 
83         return mfree(i);
84 }
85 
inhibitor_save(Inhibitor * i)86 static int inhibitor_save(Inhibitor *i) {
87         _cleanup_free_ char *temp_path = NULL;
88         _cleanup_fclose_ FILE *f = NULL;
89         int r;
90 
91         assert(i);
92 
93         r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0, MKDIR_WARN_MODE);
94         if (r < 0)
95                 goto fail;
96 
97         r = fopen_temporary(i->state_file, &f, &temp_path);
98         if (r < 0)
99                 goto fail;
100 
101         (void) fchmod(fileno(f), 0644);
102 
103         fprintf(f,
104                 "# This is private data. Do not parse.\n"
105                 "WHAT=%s\n"
106                 "MODE=%s\n"
107                 "UID="UID_FMT"\n"
108                 "PID="PID_FMT"\n",
109                 inhibit_what_to_string(i->what),
110                 inhibit_mode_to_string(i->mode),
111                 i->uid,
112                 i->pid);
113 
114         if (i->who) {
115                 _cleanup_free_ char *cc = NULL;
116 
117                 cc = cescape(i->who);
118                 if (!cc) {
119                         r = -ENOMEM;
120                         goto fail;
121                 }
122 
123                 fprintf(f, "WHO=%s\n", cc);
124         }
125 
126         if (i->why) {
127                 _cleanup_free_ char *cc = NULL;
128 
129                 cc = cescape(i->why);
130                 if (!cc) {
131                         r = -ENOMEM;
132                         goto fail;
133                 }
134 
135                 fprintf(f, "WHY=%s\n", cc);
136         }
137 
138         if (i->fifo_path)
139                 fprintf(f, "FIFO=%s\n", i->fifo_path);
140 
141         r = fflush_and_check(f);
142         if (r < 0)
143                 goto fail;
144 
145         if (rename(temp_path, i->state_file) < 0) {
146                 r = -errno;
147                 goto fail;
148         }
149 
150         return 0;
151 
152 fail:
153         (void) unlink(i->state_file);
154 
155         if (temp_path)
156                 (void) unlink(temp_path);
157 
158         return log_error_errno(r, "Failed to save inhibit data %s: %m", i->state_file);
159 }
160 
bus_manager_send_inhibited_change(Inhibitor * i)161 static int bus_manager_send_inhibited_change(Inhibitor *i) {
162         const char *property;
163 
164         assert(i);
165 
166         property = i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited";
167 
168         return manager_send_changed(i->manager, property, NULL);
169 }
170 
inhibitor_start(Inhibitor * i)171 int inhibitor_start(Inhibitor *i) {
172         assert(i);
173 
174         if (i->started)
175                 return 0;
176 
177         dual_timestamp_get(&i->since);
178 
179         log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s started.",
180                   strna(i->who), strna(i->why),
181                   i->pid, i->uid,
182                   inhibit_mode_to_string(i->mode));
183 
184         i->started = true;
185 
186         inhibitor_save(i);
187 
188         bus_manager_send_inhibited_change(i);
189 
190         return 0;
191 }
192 
inhibitor_stop(Inhibitor * i)193 void inhibitor_stop(Inhibitor *i) {
194         assert(i);
195 
196         if (i->started)
197                 log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s stopped.",
198                           strna(i->who), strna(i->why),
199                           i->pid, i->uid,
200                           inhibit_mode_to_string(i->mode));
201 
202         inhibitor_remove_fifo(i);
203 
204         if (i->state_file)
205                 (void) unlink(i->state_file);
206 
207         i->started = false;
208 
209         bus_manager_send_inhibited_change(i);
210 }
211 
inhibitor_load(Inhibitor * i)212 int inhibitor_load(Inhibitor *i) {
213         _cleanup_free_ char *what = NULL, *uid = NULL, *pid = NULL, *who = NULL, *why = NULL, *mode = NULL;
214         InhibitWhat w;
215         InhibitMode mm;
216         char *cc;
217         ssize_t l;
218         int r;
219 
220         r = parse_env_file(NULL, i->state_file,
221                            "WHAT", &what,
222                            "UID", &uid,
223                            "PID", &pid,
224                            "WHO", &who,
225                            "WHY", &why,
226                            "MODE", &mode,
227                            "FIFO", &i->fifo_path);
228         if (r < 0)
229                 return log_error_errno(r, "Failed to read %s: %m", i->state_file);
230 
231         w = what ? inhibit_what_from_string(what) : 0;
232         if (w >= 0)
233                 i->what = w;
234 
235         mm = mode ? inhibit_mode_from_string(mode) : INHIBIT_BLOCK;
236         if  (mm >= 0)
237                 i->mode = mm;
238 
239         if (uid) {
240                 r = parse_uid(uid, &i->uid);
241                 if (r < 0)
242                         log_debug_errno(r, "Failed to parse UID of inhibitor: %s", uid);
243         }
244 
245         if (pid) {
246                 r = parse_pid(pid, &i->pid);
247                 if (r < 0)
248                         log_debug_errno(r, "Failed to parse PID of inhibitor: %s", pid);
249         }
250 
251         if (who) {
252                 l = cunescape(who, 0, &cc);
253                 if (l < 0)
254                         return log_debug_errno(l, "Failed to unescape \"who\" of inhibitor: %m");
255 
256                 free_and_replace(i->who, cc);
257         }
258 
259         if (why) {
260                 l = cunescape(why, 0, &cc);
261                 if (l < 0)
262                         return log_debug_errno(l, "Failed to unescape \"why\" of inhibitor: %m");
263 
264                 free_and_replace(i->why, cc);
265         }
266 
267         if (i->fifo_path) {
268                 _cleanup_close_ int fd = -1;
269 
270                 /* Let's re-open the FIFO on both sides, and close the writing side right away */
271                 fd = inhibitor_create_fifo(i);
272                 if (fd < 0)
273                         return log_error_errno(fd, "Failed to reopen FIFO: %m");
274         }
275 
276         return 0;
277 }
278 
inhibitor_dispatch_fifo(sd_event_source * s,int fd,uint32_t revents,void * userdata)279 static int inhibitor_dispatch_fifo(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
280         Inhibitor *i = userdata;
281 
282         assert(s);
283         assert(fd == i->fifo_fd);
284         assert(i);
285 
286         inhibitor_stop(i);
287         inhibitor_free(i);
288 
289         return 0;
290 }
291 
inhibitor_create_fifo(Inhibitor * i)292 int inhibitor_create_fifo(Inhibitor *i) {
293         int r;
294 
295         assert(i);
296 
297         /* Create FIFO */
298         if (!i->fifo_path) {
299                 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0, MKDIR_WARN_MODE);
300                 if (r < 0)
301                         return r;
302 
303                 i->fifo_path = strjoin("/run/systemd/inhibit/", i->id, ".ref");
304                 if (!i->fifo_path)
305                         return -ENOMEM;
306 
307                 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
308                         return -errno;
309         }
310 
311         /* Open reading side */
312         if (i->fifo_fd < 0) {
313                 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
314                 if (i->fifo_fd < 0)
315                         return -errno;
316         }
317 
318         if (!i->event_source) {
319                 r = sd_event_add_io(i->manager->event, &i->event_source, i->fifo_fd, 0, inhibitor_dispatch_fifo, i);
320                 if (r < 0)
321                         return r;
322 
323                 r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE-10);
324                 if (r < 0)
325                         return r;
326 
327                 (void) sd_event_source_set_description(i->event_source, "inhibitor-ref");
328         }
329 
330         /* Open writing side */
331         return RET_NERRNO(open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NONBLOCK));
332 }
333 
inhibitor_remove_fifo(Inhibitor * i)334 static void inhibitor_remove_fifo(Inhibitor *i) {
335         assert(i);
336 
337         i->event_source = sd_event_source_unref(i->event_source);
338         i->fifo_fd = safe_close(i->fifo_fd);
339 
340         if (i->fifo_path) {
341                 (void) unlink(i->fifo_path);
342                 i->fifo_path = mfree(i->fifo_path);
343         }
344 }
345 
inhibitor_is_orphan(Inhibitor * i)346 bool inhibitor_is_orphan(Inhibitor *i) {
347         assert(i);
348 
349         if (!i->started)
350                 return true;
351 
352         if (!i->fifo_path)
353                 return true;
354 
355         if (i->fifo_fd < 0)
356                 return true;
357 
358         if (pipe_eof(i->fifo_fd) != 0)
359                 return true;
360 
361         return false;
362 }
363 
manager_inhibit_what(Manager * m,InhibitMode mm)364 InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) {
365         Inhibitor *i;
366         InhibitWhat what = 0;
367 
368         assert(m);
369 
370         HASHMAP_FOREACH(i, m->inhibitors)
371                 if (i->mode == mm && i->started)
372                         what |= i->what;
373 
374         return what;
375 }
376 
pid_is_active(Manager * m,pid_t pid)377 static int pid_is_active(Manager *m, pid_t pid) {
378         Session *s;
379         int r;
380 
381         /* Get client session.  This is not what you are looking for these days.
382          * FIXME #6852 */
383         r = manager_get_session_by_pid(m, pid, &s);
384         if (r < 0)
385                 return r;
386 
387         /* If there's no session assigned to it, then it's globally
388          * active on all ttys */
389         if (r == 0)
390                 return 1;
391 
392         return session_is_active(s);
393 }
394 
manager_is_inhibited(Manager * m,InhibitWhat w,InhibitMode mm,dual_timestamp * since,bool ignore_inactive,bool ignore_uid,uid_t uid,Inhibitor ** offending)395 bool manager_is_inhibited(
396                 Manager *m,
397                 InhibitWhat w,
398                 InhibitMode mm,
399                 dual_timestamp *since,
400                 bool ignore_inactive,
401                 bool ignore_uid,
402                 uid_t uid,
403                 Inhibitor **offending) {
404 
405         Inhibitor *i;
406         struct dual_timestamp ts = DUAL_TIMESTAMP_NULL;
407         bool inhibited = false;
408 
409         assert(m);
410         assert(w > 0 && w < _INHIBIT_WHAT_MAX);
411 
412         HASHMAP_FOREACH(i, m->inhibitors) {
413                 if (!i->started)
414                         continue;
415 
416                 if (!(i->what & w))
417                         continue;
418 
419                 if (i->mode != mm)
420                         continue;
421 
422                 if (ignore_inactive && pid_is_active(m, i->pid) <= 0)
423                         continue;
424 
425                 if (ignore_uid && i->uid == uid)
426                         continue;
427 
428                 if (!inhibited ||
429                     i->since.monotonic < ts.monotonic)
430                         ts = i->since;
431 
432                 inhibited = true;
433 
434                 if (offending)
435                         *offending = i;
436         }
437 
438         if (since)
439                 *since = ts;
440 
441         return inhibited;
442 }
443 
inhibit_what_to_string(InhibitWhat w)444 const char *inhibit_what_to_string(InhibitWhat w) {
445         static thread_local char buffer[STRLEN(
446             "shutdown:"
447             "sleep:"
448             "idle:"
449             "handle-power-key:"
450             "handle-suspend-key:"
451             "handle-hibernate-key:"
452             "handle-lid-switch:"
453             "handle-reboot-key")+1];
454         char *p;
455 
456         if (w < 0 || w >= _INHIBIT_WHAT_MAX)
457                 return NULL;
458 
459         p = buffer;
460         if (w & INHIBIT_SHUTDOWN)
461                 p = stpcpy(p, "shutdown:");
462         if (w & INHIBIT_SLEEP)
463                 p = stpcpy(p, "sleep:");
464         if (w & INHIBIT_IDLE)
465                 p = stpcpy(p, "idle:");
466         if (w & INHIBIT_HANDLE_POWER_KEY)
467                 p = stpcpy(p, "handle-power-key:");
468         if (w & INHIBIT_HANDLE_SUSPEND_KEY)
469                 p = stpcpy(p, "handle-suspend-key:");
470         if (w & INHIBIT_HANDLE_HIBERNATE_KEY)
471                 p = stpcpy(p, "handle-hibernate-key:");
472         if (w & INHIBIT_HANDLE_LID_SWITCH)
473                 p = stpcpy(p, "handle-lid-switch:");
474         if (w & INHIBIT_HANDLE_REBOOT_KEY)
475                 p = stpcpy(p, "handle-reboot-key:");
476 
477         if (p > buffer)
478                 *(p-1) = 0;
479         else
480                 *p = 0;
481 
482         return buffer;
483 }
484 
inhibit_what_from_string(const char * s)485 int inhibit_what_from_string(const char *s) {
486         InhibitWhat what = 0;
487 
488         for (const char *p = s;;) {
489                 _cleanup_free_ char *word = NULL;
490                 int r;
491 
492                 /* A sanity check that our return values fit in an int */
493                 assert_cc((int) _INHIBIT_WHAT_MAX == _INHIBIT_WHAT_MAX);
494 
495                 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
496                 if (r < 0)
497                         return r;
498                 if (r == 0)
499                         return what;
500 
501                 if (streq(word, "shutdown"))
502                         what |= INHIBIT_SHUTDOWN;
503                 else if (streq(word, "sleep"))
504                         what |= INHIBIT_SLEEP;
505                 else if (streq(word, "idle"))
506                         what |= INHIBIT_IDLE;
507                 else if (streq(word, "handle-power-key"))
508                         what |= INHIBIT_HANDLE_POWER_KEY;
509                 else if (streq(word, "handle-suspend-key"))
510                         what |= INHIBIT_HANDLE_SUSPEND_KEY;
511                 else if (streq(word, "handle-hibernate-key"))
512                         what |= INHIBIT_HANDLE_HIBERNATE_KEY;
513                 else if (streq(word, "handle-lid-switch"))
514                         what |= INHIBIT_HANDLE_LID_SWITCH;
515                 else if (streq(word, "handle-reboot-key"))
516                         what |= INHIBIT_HANDLE_REBOOT_KEY;
517                 else
518                         return _INHIBIT_WHAT_INVALID;
519         }
520 }
521 
522 static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
523         [INHIBIT_BLOCK] = "block",
524         [INHIBIT_DELAY] = "delay"
525 };
526 
527 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);
528