blob: d0c380440ffbac62537634231bb96618f9e1f637 [file] [log] [blame]
// Copyright 2012 The Goma Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "goma_ipc_peer.h"
#ifndef _WIN32
#include <sys/socket.h>
#if defined(__MACH__) || defined(__FreeBSD__)
#include <sys/param.h>
#include <sys/ucred.h>
#endif
#include <sys/un.h>
#ifdef __linux__
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <unistd.h>
#include <sys/syscall.h> /* For SYS_xxx definitions */
#endif
#endif // _WIN32
#include "glog/logging.h"
namespace devtools_goma {
#ifndef _WIN32
#ifdef __linux__
// hack for fakeroot
uid_t real_geteuid() {
return syscall(SYS_geteuid);
}
#else
uid_t real_geteuid() {
return geteuid();
}
#endif // __linux__
#endif // _WIN32
bool CheckGomaIPCPeer(const IOChannel* chan, pid_t* peer_pid) {
#ifdef _WIN32
// We only trust named pipe, and don't trust socket.
// see goma_ipc_addr.h.
return chan->is_secure();
#elif defined(__MACH__) || defined(__FreeBSD__)
// ScopedSocket's fd is valid socket descriptor.
// TODO: better interface on IOChannel?
int sock = static_cast<const ScopedSocket*>(chan)->get();
struct xucred peer_cred;
socklen_t peer_cred_len = sizeof(peer_cred);
if (getsockopt(sock, 0, LOCAL_PEERCRED, &peer_cred, &peer_cred_len) < 0) {
LOG(WARNING) << "cannot get peer credential. Not a unix socket?";
return false;
}
if (peer_cred.cr_version != XUCRED_VERSION) {
LOG(WARNING) << "credential version mismatch:"
<< " cr_version=" << peer_cred.cr_version
<< " XUCRED_VERSION=" << XUCRED_VERSION;
return false;
}
// darwin doesn't have pid in cred structure.
// TODO: find another way to get peer pid.
if (peer_cred.cr_uid != geteuid()) {
LOG(WARNING) << "uid mismatch peer=" << peer_cred.cr_uid
<< " self=" << geteuid();
return false;
}
return true;
#else
// ScopedSocket's fd is valid socket descriptor.
// TODO: better interface on IOChannel?
int sock = static_cast<const ScopedSocket*>(chan)->get();
struct ucred peer_cred;
socklen_t peer_cred_len = sizeof(peer_cred);
if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
reinterpret_cast<void*>(&peer_cred),
&peer_cred_len) < 0) {
LOG(WARNING) << "cannot get peer credential. Not a unix socket?";
return false;
}
VLOG(3) << "peer_cred pid=" << peer_cred.pid << " uid=" << peer_cred.uid;
if (peer_pid != nullptr)
*peer_pid = peer_cred.pid;
uid_t real_euid = real_geteuid();
uid_t euid = geteuid();
if (peer_cred.uid != real_euid && peer_cred.uid != euid) {
LOG(WARNING) << "uid mismatch peer=" << peer_cred.uid
<< " self=" << euid << "/real=" << real_euid;
return false;
}
return true;
#endif
}
} // namespace devtools_goma