Как я могу предварительно авторизовать authopen в Rust?

Вопрос или проблема

Я пытаюсь создать образ диска для флеширования на Rust. Чтобы получить доступ к SD-карте, я пытаюсь использовать authopen, как описано в предыдущем ответе.

Вот небольшой пример кода на Rust, который я создал для воспроизведения проблемы:

use std::{
    io::{Write, IoSliceMut},
    process::{Command, Stdio},
};      

use security_framework::authorization::{Authorization, AuthorizationItemSetBuilder, Flags};
use nix::sys::socket::{socketpair, SockFlag, SockType, AddressFamily, recvmsg, MsgFlags, UnixAddr, RecvMsg};
use nix::unistd::{close, pipe};
use nix::cmsg_space;

const DISK: &str = "/dev/rdisk3";

fn main() {
    open_auth(DISK);
}

fn open_auth(path: &str) {
    let rights = AuthorizationItemSetBuilder::new()
        .add_right(format!("sys.openfile.readwrite.{}", path))
        .unwrap()
        .build();

    let auth = Authorization::new(
        Some(rights),
        None,
        Flags::INTERACTION_ALLOWED | Flags::EXTEND_RIGHTS | Flags::PREAUTHORIZE,
    )
    .unwrap();

    let form = auth.make_external_form().unwrap();
    let form_bytes: Vec<u8> = form.bytes.into_iter().map(|x| x as u8).collect();

    let (srx, stx) = socketpair(
        AddressFamily::Unix,
        SockType::Stream,
        None,
        SockFlag::empty(),
    )
    .unwrap();
    let (prx, ptx) = pipe().unwrap();

    let mut cmd = Command::new("/usr/libexec/authopen")
        .args(["-stdoutpipe", "-extauth", "-o", "02", path])
        .stdin(Stdio::piped())
        .stdout(stx)
        .spawn()
        .unwrap();

    let mut stdin = cmd.stdin.take().unwrap();
    stdin.write_all(&form_bytes).unwrap();
    drop(stdin);

    let mut buf = [0u8; 4];
    let mut io_vec = [IoSliceMut::new(&mut buf)];
    let mut cmsg = cmsg_space!(RawFd);
    println!("Размер: {}", cmsg.capacity());
    let msg: RecvMsg<'_, '_, UnixAddr> = recvmsg(
        srx.as_raw_fd(),
        &mut io_vec,
        Some(&mut cmsg),
        MsgFlags::empty(),
    )
    .unwrap();
    println!("RMSG: {:?}", msg);
    println!("Что-то: {:?}", msg.cmsgs().unwrap().collect::<Vec<_>>());

    println!("CMSG: {:?}", cmsg);
    println!("IOVEC: {:?}", io_vec);

    let output = cmd.wait().unwrap();
    println!("Сырой вывод: {output:#?}");
}

Вот вывод, который я получаю, когда пытаюсь запустить его:

Завершено dev profile [неоптимизированный + отладочная информация] цель(и) за 1.26s
     Запуск target/debug/temp
Размер: 16
authopen: /dev/rdisk3: Нет такого файла или директории
RMSG: RecvMsg { bytes: 2, cmsghdr: None, address: Some(UnixAddr { sun: sockaddr_un { sun_len: 0, sun_family: 0 } }), flags: MsgFlags(0x0), iobufs: PhantomData<&()>, mhdr: msghdr { msg_name: 0x7ff7b6161196, msg_namelen: 0, msg_iov: 0x7ff7b6161b98, msg_iovlen: 1, msg_control: 0x7fa2960040d0, msg_controllen: 0, msg_flags: 0 } }
Что-то: []
CMSG: []
IOVEC: [[0, 2, 0, 0]]
Сырой вывод: ExitStatus(
    unix_wait_status(
        256,
    ),
)

Как вы видите, ответ, который я получаю, похоже, неправильный. Я ожидал получить контрольное сообщение ScmRights, но получил лишь 2 байта ответа.

Я не занимался разработкой на macOS ранее, так что, возможно, я просто делаю что-то не так. Буду признателен за любую помощь.

Ответ или решение

Для того чтобы правильно реализовать предварительное авторизованное открытие (pre-authorize) с использованием authopen в Rust, необходимо учесть несколько моментов, которые могли вызвать проблему в вашем коде. Давайте разберем основные шаги, которые помогут исправить вашу реализацию и добиться желаемого результата.

Шаг 1: Проверка пути к устройству

Первым делом, убедитесь, что путь к устройству /dev/rdisk3 действительно существует и вы можете к нему обратиться. Вы можете проверить это с помощью команды в терминале:

ls /dev/rdisk3

Если устройство не найдено, это может объяснить ошибку authopen: /dev/rdisk3: No such file or directory.

Шаг 2: Проверка прав доступа

Проверьте, есть ли у вашей программы достаточные права на доступ к файлу или устройству. Для работы с authopen, необходимо, чтобы у вас были соответствующие права на управление подключаемыми устройствами, такие как SD-карты.

Шаг 3: Исправление кода для управления сокетами

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

use std::{
    io::{Write, IoSliceMut},
    process::{Command, Stdio},
};
use security_framework::authorization::{Authorization, AuthorizationItemSetBuilder, Flags};
use nix::sys::socket::{socketpair, SockFlag, SockType, AddressFamily, recvmsg, MsgFlags, UnixAddr, RecvMsg};
use nix::unistd::close;
use nix::cmsg_space;

const DISK: &str = "/dev/rdisk3";

fn main() {
    open_auth(DISK);
}

fn open_auth(path: &str) {
    let rights = AuthorizationItemSetBuilder::new()
        .add_right(format!("sys.openfile.readwrite.{}", path))
        .unwrap()
        .build();

    let auth = Authorization::new(
        Some(rights),
        None,
        Flags::INTERACTION_ALLOWED | Flags::EXTEND_RIGHTS | Flags::PREAUTHORIZE,
    )
    .unwrap();

    let form = auth.make_external_form().unwrap();
    let form_bytes: Vec<u8> = form.bytes.into_iter().map(|x| x as u8).collect();

    let (srx, stx) = socketpair(
        AddressFamily::Unix,
        SockType::Stream,
        None,
        SockFlag::empty(),
    )
    .unwrap();

    let mut cmd = Command::new("/usr/libexec/authopen")
        .args(["-stdoutpipe", "-extauth", "-o", "02", path])
        .stdin(Stdio::piped())
        .stdout(stx)
        .spawn()
        .unwrap();

    let mut stdin = cmd.stdin.take().unwrap();
    stdin.write_all(&form_bytes).unwrap();
    drop(stdin); // Закрываем stdin, чтобы отправить EOF

    let mut buf = [0u8; 4];
    let mut io_vec = [IoSliceMut::new(&mut buf)];
    let mut cmsg = cmsg_space!(RawFd);

    let msg: RecvMsg<'_, '_, UnixAddr> = recvmsg(
        srx.as_raw_fd(),
        &mut io_vec,
        Some(&mut cmsg),
        MsgFlags::empty(),
    )
    .unwrap();

    println!("RMSG: {:?}", msg);
    if let Some(cmsgs) = msg.cmsgs() {
        for cmsg in cmsgs {
            println!("CMSG: {:?}", cmsg);
        }
    }

    let output = cmd.wait().unwrap();
    println!("Raw output: {output:#?}");

    close(srx).unwrap();
}

Шаг 4: Проверка контролируемых сообщений ScmRights

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

Шаг 5: Отладка вывода

После внесенных изменений, попробуйте снова запустить ваш проект и внимательно проверьте вывод. Убедитесь, что вы получаете корректные данные из recvmsg.

Заключение

Следуя вышеизложенным шагам, вы сможете исправить ошибки в вашем коде и успешно реализовать предварительное авторизованное открытие с использованием authopen. Не забывайте проверять существование устройства и права доступа, а также правильно обрабатывать сокеты. Если проблемы сохраняются, тщательно проверяйте вывод отладки и уточняйте детали для дальнейшего анализа.

Оцените материал
Добавить комментарий

Капча загружается...