Как выполнить команду bash с привилегиями sudo в Java?

Я использую ProcessBuilder для выполнения команд bash:

import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        try {
            Process pb = new ProcessBuilder("gedit").start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Но я хочу сделать что-то вроде этого:

Process pb = new ProcessBuilder("sudo", "gedit").start();

Как передать пароль суперпользователя в bash?

("gksudo", "gedit") не сработает, потому что он был удален с Ubuntu 13.04, и мне нужно сделать это с помощью доступных по умолчанию команд.

РЕДАКТИРОВАТЬ

gksudo вернулся в Ubuntu 13.04 с последним обновлением.

6 ответов

Решение

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

Используйте это на свой страх и риск, не рекомендуется, не судитесь со мной и т.д....

public static void main(String[] args) throws IOException {

    String[] cmd = {"/bin/bash","-c","echo password| sudo -S ls"};
    Process pb = Runtime.getRuntime().exec(cmd);

    String line;
    BufferedReader input = new BufferedReader(new InputStreamReader(pb.getInputStream()));
    while ((line = input.readLine()) != null) {
        System.out.println(line);
    }
    input.close();
}

Отредактируйте /etc/sudoers с помощью visudo и предоставьте вашему пользователю право NOPASSWD для конкретного скрипта:

имя пользователя ALL=(ALL) NOPASSWD: /opt/yourscript.sh

Мое решение не раскрывает пароль в командной строке, оно просто передает пароль в выходной поток процесса. Это более гибкое решение, поскольку позволяет запрашивать пароль у пользователя, когда это необходимо.

public static boolean runWithPrivileges() {
    InputStreamReader input;
    OutputStreamWriter output;

    try {
        //Create the process and start it.
        Process pb = new ProcessBuilder(new String[]{"/bin/bash", "-c", "/usr/bin/sudo -S /bin/cat /etc/sudoers 2>&1"}).start();
        output = new OutputStreamWriter(pb.getOutputStream());
        input = new InputStreamReader(pb.getInputStream());

        int bytes, tryies = 0;
        char buffer[] = new char[1024];
        while ((bytes = input.read(buffer, 0, 1024)) != -1) {
            if(bytes == 0)
                continue;
            //Output the data to console, for debug purposes
            String data = String.valueOf(buffer, 0, bytes);
            System.out.println(data);
            // Check for password request
            if (data.contains("[sudo] password")) {
                // Here you can request the password to user using JOPtionPane or System.console().readPassword();
                // I'm just hard coding the password, but in real it's not good.
                char password[] = new char[]{'t','e','s','t'};
                output.write(password);
                output.write('\n');
                output.flush();
                // erase password data, to avoid security issues.
                Arrays.fill(password, '\0');
                tryies++;
            }
        }

        return tryies < 3;
    } catch (IOException ex) {
    }

    return false;
}

Не пытайтесь записать системный пароль прямо в файл, особенно для пользователя, у которого есть привилегия sudo, так же, как ответил @jointEffort, выданная привилегия должна решаться системными администраторами, а не авторами приложений. sudo позволяют предоставить привилегии для конкретной команды конкретному пользователю, что достаточно точно, проверьте этот пост

и вы можете управлять привилегией в отдельном файле, отличном от основного файла sudoers, если хотите просто добавить #includedirs /etc/sudoers.d/ в основном /etc/sudoers файл (большинство дистрибутивов Linux уже сделали это) и сделать файл как ifconfig-user с:

 USER_NAME ALL=(ALL) NOPASSWD: /sbin/ifconfig

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

Я знаю, что это старая тема, но я просто хочу поместить это здесь:

ты можешь использовать sudo -S *command* в качестве команды, которую вы передаете, чтобы создать экземпляр процесса. Затем получите выходной поток и напишите ему пароль, а в конце добавьте новую строку и символ c. вернуть (\n\r). Возврат может не потребоваться, но я передал его на всякий случай. Также хорошей идеей будет очистить поток, чтобы убедиться, что все записано в него. Я сделал это несколько раз, и это работает как шарм. И НЕ забывайте закрывать потоки:).

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

Process pb = new ProcessBuilder("gedit").start();
OutputStream out = pb.getOutputStream();
out.write(password);
Другие вопросы по тегам