1
0
mirror of https://github.com/veracrypt/VeraCrypt.git synced 2026-07-05 20:48:00 -05:00

FreeBSD: support opendoas elevation

Reuse the OpenBSD doas PTY prompt flow on FreeBSD so opendoas receives the password through its controlling terminal.

Apply the same foreground process group validation on FreeBSD as on OpenBSD when attaching the private doas authentication PTY.

Detect the incompatible FreeBSD security/doas package by pkg origin and fail with explicit guidance.
This commit is contained in:
Mounir IDRASSI
2026-07-02 22:33:00 +09:00
parent 5e091eabfc
commit ed941ad16f
+57 -9
View File
@@ -147,6 +147,48 @@ namespace VeraCrypt
close (f); close (f);
} }
#ifdef TC_FREEBSD
static string TrimCommandOutput (const string &output)
{
size_t first = output.find_first_not_of (" \t\r\n");
if (first == string::npos)
return string();
size_t last = output.find_last_not_of (" \t\r\n");
return output.substr (first, last - first + 1);
}
static bool IsFreeBSDSecurityDoasPackage (const string &doasPath)
{
try
{
std::string errorMsg;
string pkgPath = Process::FindSystemBinary ("pkg", errorMsg);
if (pkgPath.empty())
return false;
list <string> args;
args.push_back ("which");
args.push_back ("-q");
args.push_back (doasPath);
string packageName = TrimCommandOutput (Process::Execute (pkgPath, args, 5000));
if (packageName.empty())
return false;
args.clear();
args.push_back ("info");
args.push_back ("-q");
args.push_back ("-o");
args.push_back (packageName);
string packageOrigin = TrimCommandOutput (Process::Execute (pkgPath, args, 5000));
return packageOrigin == "security/doas";
}
catch (...) { }
return false;
}
#endif
static PrivilegeHelper FindPrivilegeHelper () static PrivilegeHelper FindPrivilegeHelper ()
{ {
std::string errorMsg; std::string errorMsg;
@@ -156,7 +198,13 @@ namespace VeraCrypt
path = Process::FindSystemBinary ("doas", errorMsg); path = Process::FindSystemBinary ("doas", errorMsg);
if (!path.empty()) if (!path.empty())
{
#ifdef TC_FREEBSD
if (IsFreeBSDSecurityDoasPackage (path))
throw ElevationFailed (SRC_POS, "doas", 1, "The FreeBSD security/doas package is incompatible with VeraCrypt elevation. Install security/opendoas or sudo.");
#endif
return { PrivilegeHelperType::Doas, "doas", path }; return { PrivilegeHelperType::Doas, "doas", path };
}
throw SystemException (SRC_POS, "Neither sudo nor doas was found in system directories"); throw SystemException (SRC_POS, "Neither sudo nor doas was found in system directories");
} }
@@ -304,7 +352,7 @@ namespace VeraCrypt
throw SystemException (SRC_POS, "Failed to set doas authentication terminal as controlling terminal"); throw SystemException (SRC_POS, "Failed to set doas authentication terminal as controlling terminal");
} }
#endif #endif
#ifdef TC_OPENBSD #if defined (TC_OPENBSD) || defined (TC_FREEBSD)
if (tcsetpgrp (ttyFd, getpgrp()) == -1) if (tcsetpgrp (ttyFd, getpgrp()) == -1)
{ {
int err = errno; int err = errno;
@@ -569,7 +617,7 @@ namespace VeraCrypt
} }
} }
#ifdef TC_OPENBSD #if defined (TC_OPENBSD) || defined (TC_FREEBSD)
static bool ReadDoasAuthTerminalPromptData (int fd, vector <char> &authOutput) static bool ReadDoasAuthTerminalPromptData (int fd, vector <char> &authOutput)
{ {
char buffer[256]; char buffer[256];
@@ -1389,11 +1437,11 @@ namespace VeraCrypt
} }
#endif #endif
bool useDoasAuthTerminal = privilegeHelper.IsDoas() && !useCallerDoasTerminal; bool useDoasAuthTerminal = privilegeHelper.IsDoas() && !useCallerDoasTerminal;
#ifdef TC_OPENBSD #if defined (TC_OPENBSD) || defined (TC_FREEBSD)
// OpenBSD doas requires stderr to be a terminal while it // OpenBSD doas and FreeBSD opendoas require stderr to be
// prompts for the password. Keeping the private PTY slave // a terminal while prompting for the password. Keeping the
// on stderr satisfies that while stdin/stdout stay as the // private PTY slave on stderr satisfies that while stdin/stdout
// service pipes. // stay as the service pipes.
bool keepDoasStderrOnAuthTerminal = useDoasAuthTerminal; bool keepDoasStderrOnAuthTerminal = useDoasAuthTerminal;
#else #else
bool keepDoasStderrOnAuthTerminal = false; bool keepDoasStderrOnAuthTerminal = false;
@@ -1486,7 +1534,7 @@ namespace VeraCrypt
{ {
// doas reads authentication from the controlling terminal, not stdin. // doas reads authentication from the controlling terminal, not stdin.
bool writeDoasPassword = true; bool writeDoasPassword = true;
#ifdef TC_OPENBSD #if defined (TC_OPENBSD) || defined (TC_FREEBSD)
writeDoasPassword = WaitForDoasAuthTerminalPrompt (doasAuthTerminal, authOutput, timeout); writeDoasPassword = WaitForDoasAuthTerminalPrompt (doasAuthTerminal, authOutput, timeout);
#endif #endif
if (writeDoasPassword) if (writeDoasPassword)
@@ -1504,7 +1552,7 @@ namespace VeraCrypt
shared_ptr <Stream> outputStream (new FileStream (serviceOutputFd)); shared_ptr <Stream> outputStream (new FileStream (serviceOutputFd));
int authOutputFd = -1; int authOutputFd = -1;
#ifdef TC_OPENBSD #if defined (TC_OPENBSD) || defined (TC_FREEBSD)
if (doasAuthTerminal != -1) if (doasAuthTerminal != -1)
{ {
int authTerminalFlags = fcntl (doasAuthTerminal, F_GETFL, 0); int authTerminalFlags = fcntl (doasAuthTerminal, F_GETFL, 0);