LINUX.ORG.RU

Разработка системы выключения или перезарузки без sudo во Fluxbox [не рекомендуется]

 , , , без sudo,


0

0

Придумал (может быть, я не первый) такой способ выключения и перезагрузки с использованием cron, без sudo:

https://studio.youtube.com/video/0VsXXP5t80I/

  1. Пользователь сохраняет в домашней директории файл с управляющим символом, используя для этого скрипт или просто команду, например:

echo 1 > shutdown.txt

  1. Cron от пользователя root выполняет свой скрипт и читает файл пользователя, выполняет выключение или перезагрузку.

*Примерная реализация

crontab -e: */1 * * * * sh /root/shutdown_1.sh

В /root/shutdown_1.sh

Как написали ниже, у такого способа имеется уязвимость:

SHUTDOWN_COMP=`md5sum /home/user/shutdown.txt | grep -o 1`; 
if [  "$SHUTDOWN_COMP" = "b026324c" ]
then
echo 0 > /home/user/shutdown.txt & SHUTDOWN_COMP="0" & /sbin/poweroff; 
fi

Update

Скрипт от root меняется на такой:

SHUTDOWN_COMP=`grep -o 098 /home/user/shutdown.txt`; 
if [  "$SHUTDOWN_COMP" = "098" ]
then
/sbin/poweroff; 
fi

Пользовательский (не root) cron после перезагрузки меняет состояние файла /home/user/shutdown.txt или удаляет его. То есть, crontab -e:

@reboot echo 0 > /home/user/shutdown.txt

Post Scriptum

Пробую. Пока работает корректно.


  •                                               *
    

Update *

  •                                               *
    

Последнее обновление. Финальное. *

  •                                               *
    

Система перезагрузки и выключения без sudo *

  •                                               *
    
  •                                               *
    

Прислушался к советам в комментариях и пока получилась такая система: 1) две программы на языке C. Обе работают через cron. Первая проверяет наличие файла /run/shudown.txt только при старте системы. Если его нет, то создаёт его. Проверерку, вероятно, можно удалить.

Запись в cron:

@reboot  /usr/local/bin/check

Файл: check.c

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main ()
{

    FILE *file;
/*Проверим сущестование файла: если нет, то создадим,
установим права и владельца.*/
    if  (fopen("/run/shutdown.txt", "r") == NULL) {
    creat("/run/shutdown.txt",  0644);
    chown("/run/shutdown.txt", 1000, 0);
    return 0;
}}

Вторая программа для проверки управляющих символов. Запись в cron:

*/1 * * * * /usr/local/bin/shutdownreboot

Второй файл: shutdownreboot.c

#include <stdio.h>
#include <stdlib.h>
int main ()

{
    char c;
    FILE *file;
/*Откроем файл, прочитаем управляющий символ, перезагрузим или  выключим.*/
    file = fopen("/run/shutdown.txt", "r");
    c = getc (file);
    if (c == '4') 
    system("/sbin/reboot");
    if (c == '2')
    system("/sbin/poweroff");
    fclose(file);
}

И два пользовательских скрипта (кнопки), содержащих команды для записи в /run/shutdown.txt:

echo 4 > /run/shutdown.txt

и

echo 2 > /run/shutdown.txt

P.S. Код на git: https://gitflic.ru/project/dcc0/system-reboot-control

Решил сделать статью на habr: https://habr.com/ru/post/703924/



Последнее исправление: AnonymUser (всего исправлений: 29)

Во-первых, оформи текст нормально. Как правильно копировать вывод терминала

Во-вторых, у тебя в крон-задаче уязвимость, юзер может организовать запарывание любого системного файла, подставив в момент между вызовов md5sum и echo 0 симлинк /home/user/shutdown.txt -> /etc/fstab например, после чего в fstab запишется 0 вместо того что там было.

firkax ★★★★★
()
Ответ на: комментарий от hateWin

systemd ненужно

Идея с файлом вполне разумная, только конечно надо не кроном а inotify и хранить его так чтоб юзер не мог туда симлинки и другие плохие вещи подсовывать.

Другой вариант - setuid-враппер, доступный выбранной группе юзеров.

firkax ★★★★★
()

sudo chmod u+s /sbin/poweroff и поверофф работает из-под любого пользователя.

только смотри чтобы поверофф был исполняемым бинарем, а не линком. а то еще куча функций простому пользователю откроется.

pfg ★★★★★
()
Последнее исправление: pfg (всего исправлений: 2)
Ответ на: комментарий от firkax

systemd ненужно

Идея с файлом вполне разумная, только конечно надо не кроном а inotify и хранить его так чтоб юзер не мог туда симлинки и другие плохие вещи подсовывать.

Другой вариант - setuid-враппер, доступный выбранной группе юзеров.

Лол

hateWin ★☆
()
  1. Каким местом тут вообще fluxbox?
  2. Ожидаемо дырявый велосипед. Пусть можно будет симлинками затирать любой файл, зато сэкономим пару килобайт на sudo.
  3. Ну хоть incron вместо cron бы что ли юзал
  4. Не проще проверять наличие файла, а не его содержимое, если всё равно там только 0 или 1?
  5. echo 0 > /home/user/shutdown.txt & SHUTDOWN_COMP="0" & /sbin/poweroff; Зачем менять переменную среды, если всё равно выключать комп? Зачем & вместо && — вдруг (вряд ли, но ВДРУГ, HDD залагал или ещё что) каким-то образом выключится раньше, чем нолик запишется в файл?

Самое главное, ради чего всё-таки такой велосипед с колёсами в виде неравнобедренного трекгольника и весь в дырках, если sudo уже есть, и в нём можно дать юзеру доступ только к poweroff и больше ни к чему?

CrX ★★★
()
Ответ на: комментарий от firkax

Да. Я начал делать так, потмоу что не умею notify. Но почитаю. Спасибо. С файлом так: echo из скрипта удалю и попробую уж пользователем менять состояние этого файла, например, при загрузке.

AnonymUser
() автор топика
Ответ на: комментарий от AnonymUser

Во-первых, для inotify тебе придётся выкинуть эту скриптоту и написать всё на нормальном языке (си). Во-вторых, проблема с симлинк-атаками не в том, кто меняет файл, а в том, где он лежит. Лежать он должен не в /home а где-то в /run, и туда (в данном случае - к файлу, но не к директории где он лежит) должны быть выданы права на запись избранным юзерам.

firkax ★★★★★
()
Ответ на: комментарий от firkax

То есть, получается:

  1. надо написать на C проверку на существование файла и проверку на наличие управляющего символа в файле?!
  2. добавить задание в incron?!
  3. файл положить в /run и дать права пользователю?!
  4. сделать команду изменения файла для пользователя?!
AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 1)
Ответ на: комментарий от firkax

Не знаю, насколько хорошо/плохо. Пока сделал на C так:

  1. файл для управляющего символа лежит в /run/shutdown.txt
  2. пользователь отправляет в него символ - 2
  3. сron от root выполняет программу раз в минуту, проверяет, если ли файл. Если файла нет, то создает и устанавливает нужные права. Затем выключает компьютер.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main ()

{
    char c;
    FILE *file;
/*Проверим сущестование файла: если нет, то создадим,
установим права и владельца.*/
    if  (fopen("/run/shutdown.txt", "r") == NULL) {
    creat("/run/shutdown.txt",  0644);
    chown("/run/shutdown.txt", 1000, 0);
    return 0;
}

/*Откроем файл, прочитаем управляющий символ и выключим.*/	
    file = fopen("/run/shutdown.txt", "r");
    c = getc (file);
    if (c == '2') 
    system("/sbin/poweroff");
    fclose(file);
}

AnonymUser
() автор топика
Ответ на: комментарий от AnonymUser

Если программа на C, то зачем треугольный костыль в виде запуска по крону раз в минуту? Почему бы в программе на C не задействовать inotify, и не ждать изменения файла по событию inotify?

emorozov
()
Последнее исправление: emorozov (всего исправлений: 1)
Ответ на: комментарий от emorozov

Можно и так. Наверное.
Я не работал с inotify , поэтому пользуюсь тем средством, которое знаю.

Без всего этого можно обойтись, если использовать loginctl reboot (подсказали на хабре). Тогда и inotify не нужен.

AnonymUser
() автор топика
Ответ на: комментарий от AnonymUser

Дело в том, что почти любой поллинг, то есть, когда программа что-то делает через какие-то промежутки времени, потому что не знает, когда произойдёт событие - это костылинг.

Во-первых, такты CPU и I/O дёргаются на напрасные проверки 99.9999% времени. Во-вторых, если поставить слишком длинный интервал, то удобство падает, программа реагирует с большой задержкой. Если поставить короткий - программа будет жечь напрасно ещё больше CPU.

В общем, почти всегда, когда есть возможность не поллить по таймеру, а реагировать на приходящее событие - это лучше.

Ну и раз удалось написать создание и чтение файла, то и inotify получится написать. Это не rocket science. Кстати, есть утилиты, чтобы и из командной строки inotify использовать.

emorozov
()
Ответ на: комментарий от emorozov

Не могу не согласиться, хотя если честно, я не сильно думал о загрузке CPU. И тем не менее, ситуация из жизни: на компьютере что-то делается, рендеринг, и пользователю надо уйти, работа по оценке завершится примерно через 2 часа , тогда такая кнопка с длинной задежкой может быть оправдана. Допустим, интервал 3 часа. Еще один способ выключения.

Нашёл вот такой ман: https://askubuntu.ru/questions/381493/scenarij-bash-chtoby-nabljudat-izmenenie-fajla-i-vypolnit-komandu

Видимо, надо использовать inotifywait.

AnonymUser
() автор топика
Ответ на: комментарий от AnonymUser

В данном случае, потребение CPU пренебрежимо мало, но всё равно, из чувства перфекционизма, всегда стараюсь избавиться от поллинга, где только возможно.

Кстати, да, про ответ с askubuntu - я тоже использую подобное, когда рисую диаграммы в PlantUML: в одном окне запускаю nvim для редактирования исходника plantuml, а в другом окне - следующие команды на fish:

while true; inotifywait container.puml && plantuml -DRELATIVE_INCLUDE=. -tpng container.puml; end

В третьем окне - просмотрщик png, который тоже умеет сам перезагружать картинку при изменении (не помню, feh или sxiv).

emorozov
()
Последнее исправление: emorozov (всего исправлений: 1)
Ответ на: комментарий от emorozov

Я так понимаю, что моя задача в лучшем варианте решалась бы так: с inotify и incron. А может быть, даже только с incron. То есть не нужно писать отдельную фоновую программу с включением в нее библиотеки с inotify.

incron работает, как я понял также, как cron, но он проще и это уже готовое решение:

Вот статья: https://habr.com/ru/post/66569/

Тогда от root

 incrontab -e
/somedir/reboot.txt  IN_MODIFY reboot

Только добавить пользователя в /etc/incron.allow

И у incron мгновенное срабатывание, но это не всегда нужно.

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 2)

это издевательство над здравым смыслом? Зачем кронтаб? Что, никаких кнопок на компе нет, чтобы нормально приделать acpid? Например на моих «говёных» одноплатниках можно любой gpio, торчащий наружу настроить как выключатель, я обычно на сишечке делаю слушалку кнопки и когда три секунды удерживаешь предлагает отключиться, нажимаешь ок, оно от юзера через автосудо только для этой вписанной в sudoers проги передаёт init 0.

burato ★★★★★
()

Делюсь суперсекретной разработкой (тестировал и использую только на Ubuntu с openbox-ом с дремучих времён)

#!/bin/bash
RETURN_CODE=`zenity --window-icon="/home/user/.icons/Faenza/actions/24/system-shutdown-restart-panel.png" \
		--list --radiolist \
		--title="Выключение компьютера" \
		--text="Выберите предпочитаемое действие:" \
		--column="Выбор" --column="Действие" \
		TRUE "Выключение компьютера" FALSE "Перезагрузка" FALSE "Ждущий режим" FALSE "Спящий режим"`
if [ "$RETURN_CODE" = "Выключение компьютера" ]; then
#	echo "Надо выключать"
#dbus-send --system --print-reply --dest="org.freedesktop.ConsoleKit" /org/freedesktop/ConsoleKit/Manager org.freedesktop.ConsoleKit.Manager.Stop
dbus-send --system --print-reply --dest=org.freedesktop.login1 /org/freedesktop/login1 "org.freedesktop.login1.Manager.PowerOff" boolean:true
fi
if [ "$RETURN_CODE" = "Перезагрузка" ]; then
#	echo "Надо перезагружать"
#dbus-send --system --print-reply --dest="org.freedesktop.ConsoleKit" /org/freedesktop/ConsoleKit/Manager org.freedesktop.ConsoleKit.Manager.Restart
dbus-send --system --print-reply --dest=org.freedesktop.login1 /org/freedesktop/login1 "org.freedesktop.login1.Manager.Reboot" boolean:true
fi
if [ "$RETURN_CODE" = "Ждущий режим" ]; then
#	echo "Надо переводить в ждущий режим"
#dbus-send --system --print-reply --dest="org.freedesktop.UPower" /org/freedesktop/UPower org.freedesktop.UPower.Suspend
dbus-send --system --print-reply --dest=org.freedesktop.login1 /org/freedesktop/login1 "org.freedesktop.login1.Manager.Suspend" boolean:true
fi
if [ "$RETURN_CODE" = "Спящий режим" ]; then
#	echo "Надо переводить в спящий режим"
#dbus-send --system --print-reply --dest="org.freedesktop.UPower" /org/freedesktop/UPower org.freedesktop.UPower.Hibernate
dbus-send --system --print-reply --dest=org.freedesktop.login1 /org/freedesktop/login1 "org.freedesktop.login1.Manager.Hibernate" boolean:true
fi
По идее никаких уязвимостей (кроме тех что есть из коробки) тут нет.

peregrine ★★★★★
()