#if defined(__linux__) || defined(ANDROID)
#include <cerrno>
#include <cstring>
#include <sys/socket.h>
#include "../include/credentials.hpp"
#include <vsomeip/internal/logger.hpp>
#ifdef ANDROID
#include "../../configuration/include/internal_android.hpp"
#else
#include "../../configuration/include/internal.hpp"
#endif
namespace vsomeip_v3 {
void credentials::activate_credentials(const int _fd) {
int optval = 1;
if (setsockopt(_fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
VSOMEIP_ERROR << __func__ << ": vSomeIP Security: Activating socket option for receiving "
<< "credentials failed.";
}
}
void credentials::deactivate_credentials(const int _fd) {
int optval = 0;
if (setsockopt(_fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
VSOMEIP_ERROR << __func__ << ": vSomeIP Security: Deactivating socket option for receiving "
<< "credentials failed.";
}
}
boost::optional<credentials::received_t> credentials::receive_credentials(const int _fd) {
struct msghdr msgh;
struct iovec iov[2];
union {
struct cmsghdr cmh;
char control[CMSG_SPACE(sizeof(struct ucred))];
} control_un;
msgh.msg_name = NULL;
msgh.msg_namelen = 0;
msgh.msg_iov = iov;
msgh.msg_iovlen = 2;
msgh.msg_control = control_un.control;
msgh.msg_controllen = sizeof(control_un.control);
client_t client = VSOMEIP_ROUTING_CLIENT;
uint8_t client_host_length(0);
iov[0].iov_base = &client;
iov[0].iov_len = sizeof(client_t);
iov[1].iov_base = &client_host_length;
iov[1].iov_len = sizeof(uint8_t);
control_un.cmh.cmsg_len = CMSG_LEN(sizeof(struct ucred));
control_un.cmh.cmsg_level = SOL_SOCKET;
control_un.cmh.cmsg_type = SCM_CREDENTIALS;
ssize_t nr = recvmsg(_fd, &msgh, 0);
if (nr == -1) {
VSOMEIP_ERROR << __func__ << ": vSomeIP Security: Receiving credentials failed. No data. errno: " << std::strerror(errno);
return boost::none;
}
struct cmsghdr* cmhp = CMSG_FIRSTHDR(&msgh);
if (cmhp == NULL || cmhp->cmsg_len != CMSG_LEN(sizeof(struct ucred))
|| cmhp->cmsg_level != SOL_SOCKET || cmhp->cmsg_type != SCM_CREDENTIALS) {
VSOMEIP_ERROR << __func__ << ": vSomeIP Security: Receiving credentials failed. Invalid data.";
return boost::none;
}
struct ucred ucred = *reinterpret_cast<struct ucred*>(CMSG_DATA(cmhp));
msgh.msg_iov = iov;
msgh.msg_iovlen = 1;
msgh.msg_control = nullptr;
msgh.msg_controllen = 0;
std::string client_host(client_host_length, '\0');
iov[0].iov_base = &client_host.front();
iov[0].iov_len = client_host.length();
nr = recvmsg(_fd, &msgh, 0);
if (nr == -1) {
VSOMEIP_ERROR << __func__ << ": vSomeIP Security: Receiving client host failed. No data. errno: " << std::strerror(errno);
return boost::none;
}
return received_t{client, ucred.uid, ucred.gid, client_host};
}
void credentials::send_credentials(const int _fd, client_t _client, std::string _client_host) {
struct msghdr msgh;
struct iovec iov[3];
uint8_t client_host_length = (uint8_t)_client_host.length();
msgh.msg_iov = &iov[0];
msgh.msg_iovlen = 3;
iov[0].iov_base = &_client;
iov[0].iov_len = sizeof(client_t);
iov[1].iov_base = &client_host_length;
iov[1].iov_len = sizeof(uint8_t);
iov[2].iov_base = &_client_host[0];
iov[2].iov_len = client_host_length;
msgh.msg_name = NULL;
msgh.msg_namelen = 0;
msgh.msg_control = NULL;
msgh.msg_controllen = 0;
ssize_t ns = sendmsg(_fd, &msgh, 0);
if (ns == -1) {
VSOMEIP_ERROR << __func__ << ": vSomeIP Security: Sending credentials failed. errno: " << std::strerror(errno);
}
}
}
#endif