libstore: ignore broken symlinks in ssl-cert-file default
Also tweak `pathAccessible` to ignore other relevant errors too. It was
documented as ignoring permission errors but it was only ignoring
`EPERM`, which comes from the darwin sandbox, and not ignoring `EACCESS`
which is the real permission error. I figured it also makes sense to
ignore `ELOOP`.
Fixes: #560
Change-Id: Ibb849b68d07386eb80afb52b57f7d12b3a48a202
This commit is contained in:
parent
11950a0a79
commit
684f93e783
12
doc/manual/rl-next/ssl-cert-symlink.md
Normal file
12
doc/manual/rl-next/ssl-cert-symlink.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
synopsis: Ignore broken `/etc/ssl/certs/ca-certificates.crt` symlink
|
||||||
|
issues: [fj#560]
|
||||||
|
cls: [2144]
|
||||||
|
category: Fixes
|
||||||
|
credits: lilyball
|
||||||
|
---
|
||||||
|
|
||||||
|
[`ssl-cert-file`](@docroot@/command-ref/conf-file.md#conf-ssl-cert-file) now checks its default
|
||||||
|
value for a broken symlink before using it. This fixes a problem on macOS where uninstalling
|
||||||
|
nix-darwin may leave behind a broken symlink at `/etc/ssl/certs/ca-certificates.crt` that was
|
||||||
|
stopping Lix from using the cert at `/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt`.
|
|
@ -263,7 +263,7 @@ bool Settings::isWSL1()
|
||||||
Path Settings::getDefaultSSLCertFile()
|
Path Settings::getDefaultSSLCertFile()
|
||||||
{
|
{
|
||||||
for (auto & fn : {"/etc/ssl/certs/ca-certificates.crt", "/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"})
|
for (auto & fn : {"/etc/ssl/certs/ca-certificates.crt", "/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"})
|
||||||
if (pathAccessible(fn)) return fn;
|
if (pathAccessible(fn, true)) return fn;
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -214,6 +214,19 @@ struct stat lstat(const Path & path)
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<struct stat> maybeStat(const Path & path)
|
||||||
|
{
|
||||||
|
std::optional<struct stat> st{std::in_place};
|
||||||
|
if (stat(path.c_str(), &*st))
|
||||||
|
{
|
||||||
|
if (errno == ENOENT || errno == ENOTDIR)
|
||||||
|
st.reset();
|
||||||
|
else
|
||||||
|
throw SysError("getting status of '%s'", path);
|
||||||
|
}
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<struct stat> maybeLstat(const Path & path)
|
std::optional<struct stat> maybeLstat(const Path & path)
|
||||||
{
|
{
|
||||||
std::optional<struct stat> st{std::in_place};
|
std::optional<struct stat> st{std::in_place};
|
||||||
|
@ -232,14 +245,23 @@ bool pathExists(const Path & path)
|
||||||
return maybeLstat(path).has_value();
|
return maybeLstat(path).has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pathAccessible(const Path & path)
|
bool pathAccessible(const Path & path, bool resolveSymlinks)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return pathExists(path);
|
return resolveSymlinks ? maybeStat(path).has_value() : pathExists(path);
|
||||||
} catch (SysError & e) {
|
} catch (SysError & e) {
|
||||||
// swallow EPERM
|
switch (e.errNo) {
|
||||||
if (e.errNo == EPERM) return false;
|
case EPERM:
|
||||||
throw;
|
// operation not permitted error, can occur in darwin sandbox
|
||||||
|
case EACCES:
|
||||||
|
// permission error
|
||||||
|
case ELOOP:
|
||||||
|
// path component is a looping symlink
|
||||||
|
// this seems like a reasonable condition to handle as well
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,12 @@ bool isDirOrInDir(std::string_view path, std::string_view dir);
|
||||||
struct stat stat(const Path & path);
|
struct stat stat(const Path & path);
|
||||||
struct stat lstat(const Path & path);
|
struct stat lstat(const Path & path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `stat` the given path if it exists.
|
||||||
|
* @return std::nullopt if the path doesn't exist, or an optional containing the result of `stat` otherwise
|
||||||
|
*/
|
||||||
|
std::optional<struct stat> maybeStat(const Path & path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `lstat` the given path if it exists.
|
* `lstat` the given path if it exists.
|
||||||
* @return std::nullopt if the path doesn't exist, or an optional containing the result of `lstat` otherwise
|
* @return std::nullopt if the path doesn't exist, or an optional containing the result of `lstat` otherwise
|
||||||
|
@ -137,10 +143,11 @@ bool pathExists(const Path & path);
|
||||||
/**
|
/**
|
||||||
* A version of pathExists that returns false on a permission error.
|
* A version of pathExists that returns false on a permission error.
|
||||||
* Useful for inferring default paths across directories that might not
|
* Useful for inferring default paths across directories that might not
|
||||||
* be readable.
|
* be readable. Optionally resolves symlinks to determine if the real
|
||||||
|
* path exists.
|
||||||
* @return true iff the given path can be accessed and exists
|
* @return true iff the given path can be accessed and exists
|
||||||
*/
|
*/
|
||||||
bool pathAccessible(const Path & path);
|
bool pathAccessible(const Path & path, bool resolveSymlinks = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the contents (target) of a symbolic link. The result is not
|
* Read the contents (target) of a symbolic link. The result is not
|
||||||
|
|
Loading…
Reference in a new issue