Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 35 additions & 32 deletions src/nix/unix/daemon.cc
Original file line number Diff line number Diff line change
Expand Up @@ -174,22 +174,23 @@ static bool matchUser(std::string_view user, const struct group & gr)
*
* Otherwise: No.
*/
static bool matchUser(const std::string & user, const std::string & group, const Strings & users)
static bool
matchUser(const std::optional<std::string> & user, const std::optional<std::string> & group, const Strings & users)
{
if (find(users.begin(), users.end(), "*") != users.end())
return true;

if (find(users.begin(), users.end(), user) != users.end())
if (user && find(users.begin(), users.end(), *user) != users.end())
return true;

for (auto & i : users)
if (i.substr(0, 1) == "@") {
if (group == i.substr(1))
if (group && *group == i.substr(1))
return true;
struct group * gr = getgrnam(i.c_str() + 1);
if (!gr)
continue;
if (matchUser(user, *gr))
if (user && matchUser(*user, *gr))
return true;
}

Expand All @@ -198,20 +199,17 @@ static bool matchUser(const std::string & user, const std::string & group, const

struct PeerInfo
{
bool pidKnown;
pid_t pid;
bool uidKnown;
uid_t uid;
bool gidKnown;
gid_t gid;
std::optional<pid_t> pid;
std::optional<uid_t> uid;
std::optional<gid_t> gid;
};

/**
* Get the identity of the caller, if possible.
*/
static PeerInfo getPeerInfo(int remote)
{
PeerInfo peer = {false, 0, false, 0, false, 0};
PeerInfo peer;

#if defined(SO_PEERCRED)

Expand All @@ -221,9 +219,11 @@ static PeerInfo getPeerInfo(int remote)
ucred cred;
# endif
socklen_t credLen = sizeof(cred);
if (getsockopt(remote, SOL_SOCKET, SO_PEERCRED, &cred, &credLen) == -1)
throw SysError("getting peer credentials");
peer = {true, cred.pid, true, cred.uid, true, cred.gid};
if (getsockopt(remote, SOL_SOCKET, SO_PEERCRED, &cred, &credLen) == 0) {
peer.pid = cred.pid;
peer.uid = cred.uid;
peer.gid = cred.gid;
}
Comment on lines +222 to +226
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now this will fail silent, but it will fail in a deauthorizing manner.

If we had a "disallow users" this would not be the case, but thankfully we don't.


#elif defined(LOCAL_PEERCRED)

Expand All @@ -233,9 +233,8 @@ static PeerInfo getPeerInfo(int remote)

xucred cred;
socklen_t credLen = sizeof(cred);
if (getsockopt(remote, SOL_LOCAL, LOCAL_PEERCRED, &cred, &credLen) == -1)
throw SysError("getting peer credentials");
peer = {false, 0, true, cred.cr_uid, false, 0};
if (getsockopt(remote, SOL_LOCAL, LOCAL_PEERCRED, &cred, &credLen) == 0)
peer.uid = cred.cr_uid;

#endif

Expand Down Expand Up @@ -266,15 +265,19 @@ static ref<Store> openUncachedStore()
*
* If the potential client is not allowed to talk to us, we throw an `Error`.
*/
static std::pair<TrustedFlag, std::string> authPeer(const PeerInfo & peer)
static std::pair<TrustedFlag, std::optional<std::string>> authPeer(const PeerInfo & peer)
{
TrustedFlag trusted = NotTrusted;

struct passwd * pw = peer.uidKnown ? getpwuid(peer.uid) : 0;
std::string user = pw ? pw->pw_name : std::to_string(peer.uid);
auto pw = peer.uid ? getpwuid(*peer.uid) : nullptr;
auto user = pw ? std::optional<std::string>(pw->pw_name)
: peer.uid ? std::optional(std::to_string(*peer.uid))
: std::nullopt;

struct group * gr = peer.gidKnown ? getgrgid(peer.gid) : 0;
std::string group = gr ? gr->gr_name : std::to_string(peer.gid);
auto gr = peer.gid ? getgrgid(*peer.gid) : 0;
auto group = gr ? std::optional<std::string>(gr->gr_name)
: peer.gid ? std::optional(std::to_string(*peer.gid))
: std::nullopt;

const Strings & trustedUsers = authorizationSettings.trustedUsers;
const Strings & allowedUsers = authorizationSettings.allowedUsers;
Expand All @@ -283,7 +286,7 @@ static std::pair<TrustedFlag, std::string> authPeer(const PeerInfo & peer)
trusted = Trusted;

if ((!trusted && !matchUser(user, group, allowedUsers)) || group == settings.buildUsersGroup)
throw Error("user '%1%' is not allowed to connect to the Nix daemon", user);
throw Error("user '%1%' is not allowed to connect to the Nix daemon", user.value_or("<unknown>"));

return {trusted, std::move(user)};
}
Expand Down Expand Up @@ -360,23 +363,23 @@ static void daemonLoop(std::optional<TrustedFlag> forceTrustClientOpt)

unix::closeOnExec(remote.get());

PeerInfo peer{.pidKnown = false};
PeerInfo peer;
TrustedFlag trusted;
std::string user;
std::optional<std::string> userName;

if (forceTrustClientOpt)
trusted = *forceTrustClientOpt;
else {
peer = getPeerInfo(remote.get());
auto [_trusted, _user] = authPeer(peer);
auto [_trusted, _userName] = authPeer(peer);
trusted = _trusted;
user = _user;
userName = _userName;
};

printInfo(
(std::string) "accepted connection from pid %1%, user %2%" + (trusted ? " (trusted)" : ""),
peer.pidKnown ? std::to_string(peer.pid) : "<unknown>",
peer.uidKnown ? user : "<unknown>");
peer.pid ? std::to_string(*peer.pid) : "<unknown>",
userName.value_or("<unknown>"));

// Fork a child to handle the connection.
ProcessOptions options;
Expand All @@ -396,8 +399,8 @@ static void daemonLoop(std::optional<TrustedFlag> forceTrustClientOpt)
setSigChldAction(false);

// For debugging, stuff the pid into argv[1].
if (peer.pidKnown && savedArgv[1]) {
auto processName = std::to_string(peer.pid);
if (peer.pid && savedArgv[1]) {
auto processName = std::to_string(*peer.pid);
strncpy(savedArgv[1], processName.c_str(), strlen(savedArgv[1]));
}

Expand All @@ -414,7 +417,7 @@ static void daemonLoop(std::optional<TrustedFlag> forceTrustClientOpt)
} catch (Error & error) {
auto ei = error.info();
// FIXME: add to trace?
ei.msg = HintFmt("error processing connection: %1%", ei.msg.str());
ei.msg = HintFmt("while processing connection: %1%", ei.msg.str());
logError(ei);
}
}
Expand Down
Loading