retro-imager/mac/macfile.cpp

127 lines
3.5 KiB
C++
Raw Normal View History

2020-03-04 16:55:40 +01:00
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2020 Raspberry Pi (Trading) Limited
*/
#include "macfile.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <security/Authorization.h>
#include <QDebug>
MacFile::MacFile(QObject *parent)
: QFile(parent)
{
}
/* Prevent that Qt thinks /dev/rdisk does not permit seeks because it does not report size */
bool MacFile::isSequential() const
{
return false;
}
MacFile::authOpenResult MacFile::authOpen(const QByteArray &filename)
2020-03-04 16:55:40 +01:00
{
int fd = -1;
QByteArray right = "sys.openfile.readwrite."+filename;
AuthorizationItem item = {right, 0, nullptr, 0};
AuthorizationRights rights = {1, &item};
AuthorizationFlags flags = kAuthorizationFlagInteractionAllowed |
kAuthorizationFlagExtendRights |
kAuthorizationFlagPreAuthorize;
AuthorizationRef authRef;
if (AuthorizationCreate(&rights, nullptr, flags, &authRef) != 0)
return authOpenCancelled;
2020-03-04 16:55:40 +01:00
AuthorizationExternalForm externalForm;
if (AuthorizationMakeExternalForm(authRef, &externalForm) != 0)
{
AuthorizationFree(authRef, 0);
return authOpenError;
2020-03-04 16:55:40 +01:00
}
const char *cmd = "/usr/libexec/authopen";
QByteArray mode = QByteArray::number(O_RDWR);
int pipe[2];
int stdinpipe[2];
::socketpair(AF_UNIX, SOCK_STREAM, 0, pipe);
::pipe(stdinpipe);
pid_t pid = ::fork();
if (pid == 0)
{
// child
::close(pipe[0]);
::close(stdinpipe[1]);
::dup2(pipe[1], STDOUT_FILENO);
::dup2(stdinpipe[0], STDIN_FILENO);
::execl(cmd, cmd, "-stdoutpipe", "-extauth", "-o", mode.data(), filename.data(), NULL);
::exit(-1);
}
else
{
::close(pipe[1]);
::close(stdinpipe[0]);
::write(stdinpipe[1], externalForm.bytes, sizeof(externalForm.bytes));
::close(stdinpipe[1]);
const size_t bufSize = CMSG_SPACE(sizeof(int));
char buf[bufSize];
struct iovec io_vec[1];
io_vec[0].iov_base = buf;
io_vec[0].iov_len = bufSize;
const size_t cmsgSize = CMSG_SPACE(sizeof(int));
char cmsg[cmsgSize];
struct msghdr msg = {0};
msg.msg_iov = io_vec;
msg.msg_iovlen = 1;
msg.msg_control = cmsg;
msg.msg_controllen = cmsgSize;
ssize_t size;
do {
size = recvmsg(pipe[0], &msg, 0);
} while (size == -1 && errno == EINTR);
qDebug() << "RECEIVED SIZE:" << size;
if (size > 0) {
struct cmsghdr *chdr = CMSG_FIRSTHDR(&msg);
if (chdr && chdr->cmsg_type == SCM_RIGHTS) {
qDebug() << "SCMRIGHTS";
fd = *( (int*) (CMSG_DATA(chdr)) );
}
else
{
qDebug() << "NOT SCMRIGHTS";
}
}
pid_t wpid;
int status;
do {
wpid = ::waitpid(pid, &status, 0);
} while (wpid == -1 && errno == EINTR);
if (wpid == -1)
{
qDebug() << "waitpid() failed executing authopen";
return authOpenError;
2020-03-04 16:55:40 +01:00
}
if (WEXITSTATUS(status))
{
qDebug() << "authopen returned failure code" << WEXITSTATUS(status);
return authOpenError;
2020-03-04 16:55:40 +01:00
}
qDebug() << "fd received:" << fd;
}
AuthorizationFree(authRef, 0);
return open(fd, QIODevice::ReadWrite | QIODevice::ExistingOnly | QIODevice::Unbuffered, QFileDevice::AutoCloseHandle) ? authOpenSuccess : authOpenError;
2020-03-04 16:55:40 +01:00
}