/*
* Copyright (c) Likewise Software. All rights Reserved.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the license, or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details. You should have received a copy
* of the GNU Lesser General Public License along with this program. If
* not, see .
*
* LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
* TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
* WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
* TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
* LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU
* HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
* TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
* license@likewisesoftware.com
*/
/*
* Module Name:
*
* connection-security.c
*
* Abstract:
*
* Connection API
* Connection security token logic
*
* Authors: Brian Koropoff (bkoropoff@likewisesoftware.com)
*
*/
#include
#include "connection-private.h"
#include "util-private.h"
#include "assoc-private.h"
#include "security-private.h"
#include
#include
#include
#include
#include
#include
static
LWMsgStatus
lwmsg_local_token_construct(
LWMsgSecurityToken* token
)
{
return LWMSG_STATUS_SUCCESS;
}
static
void
lwmsg_local_token_destruct(
LWMsgSecurityToken* token
)
{
return;
}
static
const char*
lwmsg_local_token_get_type(
LWMsgSecurityToken* token
)
{
return "local";
}
static
LWMsgBool
lwmsg_local_token_equal(
LWMsgSecurityToken* token,
LWMsgSecurityToken* other
)
{
LocalTokenPrivate* my_priv = lwmsg_security_token_get_private(token);
LocalTokenPrivate* other_priv = lwmsg_security_token_get_private(token);
return (my_priv->euid == other_priv->euid &&
my_priv->egid == other_priv->egid);
}
static
size_t
lwmsg_local_token_hash(
LWMsgSecurityToken* token
)
{
LocalTokenPrivate* priv = lwmsg_security_token_get_private(token);
static const int shift = ((sizeof(size_t) / 2) * 8);
return (((size_t) priv->egid) << shift) ^ ((size_t) priv->euid);
}
static
LWMsgBool
lwmsg_local_token_can_access(
LWMsgSecurityToken* token,
LWMsgSecurityToken* other
)
{
return lwmsg_security_token_equal(token, other);
}
static
LWMsgStatus
lwmsg_local_token_copy(
LWMsgSecurityToken* token,
LWMsgSecurityToken** out_token
)
{
LocalTokenPrivate* priv = lwmsg_security_token_get_private(token);
return lwmsg_local_token_new(priv->euid, priv->egid, priv->pid, out_token);
}
LWMsgStatus
lwmsg_local_token_get_eid(
LWMsgSecurityToken* token,
uid_t *out_euid,
gid_t *out_egid
)
{
LWMsgStatus status = LWMSG_STATUS_SUCCESS;
LocalTokenPrivate* priv = lwmsg_security_token_get_private(token);
if (strcmp(lwmsg_security_token_get_type(token), "local"))
{
BAIL_ON_ERROR(status = LWMSG_STATUS_INVALID_PARAMETER);
}
if (out_euid)
{
*out_euid = priv->euid;
}
if (out_egid)
{
*out_egid = priv->egid;
}
error:
return status;
}
LWMsgStatus
lwmsg_local_token_get_pid(
LWMsgSecurityToken* token,
pid_t *out_pid
)
{
LWMsgStatus status = LWMSG_STATUS_SUCCESS;
LocalTokenPrivate* priv = lwmsg_security_token_get_private(token);
if (strcmp(lwmsg_security_token_get_type(token), "local"))
{
BAIL_ON_ERROR(status = LWMSG_STATUS_INVALID_PARAMETER);
}
if (out_pid)
{
*out_pid = priv->pid;
}
error:
return status;
}
static LWMsgSecurityTokenClass local_class =
{
.private_size = sizeof(LocalTokenPrivate),
.construct = lwmsg_local_token_construct,
.destruct = lwmsg_local_token_destruct,
.get_type = lwmsg_local_token_get_type,
.equal = lwmsg_local_token_equal,
.can_access = lwmsg_local_token_can_access,
.copy = lwmsg_local_token_copy,
.hash = lwmsg_local_token_hash
};
LWMsgStatus
lwmsg_local_token_new(
uid_t euid,
gid_t egid,
pid_t pid,
LWMsgSecurityToken** out_token
)
{
LWMsgStatus status = LWMSG_STATUS_SUCCESS;
LWMsgSecurityToken* token = NULL;
LocalTokenPrivate* priv = NULL;
BAIL_ON_ERROR(status = lwmsg_security_token_new(&local_class, &token));
priv = lwmsg_security_token_get_private(token);
priv->euid = euid;
priv->egid = egid;
priv->pid = pid;
*out_token = token;
error:
return status;
}
LWMsgStatus
lwmsg_local_token_from_socket_peer(
int fd,
LWMsgSecurityToken** out_token
)
{
LWMsgStatus status = LWMSG_STATUS_SUCCESS;
uid_t uid;
gid_t gid;
pid_t pid = (pid_t)-1;
#if !defined(HAVE_PEERID_METHOD)
BAIL_ON_ERROR(status = LWMSG_STATUS_UNIMPLEMENTED);
#elif defined(HAVE_GETPEEREID) && HAVE_DECL_GETPEEREID
if (getpeereid(fd, &uid, &gid))
{
BAIL_ON_ERROR(status = lwmsg_error_map_errno(errno));
}
#elif HAVE_DECL_SO_PEERCRED
struct ucred creds;
socklen_t creds_len = sizeof(struct ucred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &creds_len))
{
BAIL_ON_ERROR(status = lwmsg_error_map_errno(errno));
}
uid = creds.uid;
gid = creds.gid;
pid = creds.pid;
#endif
BAIL_ON_ERROR(status = lwmsg_local_token_new(uid, gid, pid, out_token));
error:
return status;
}
LWMsgStatus
lwmsg_connection_get_endpoint_owner(
LWMsgAssoc* assoc,
const char* endpoint,
uid_t *uid,
gid_t *gid
)
{
LWMsgStatus status = LWMSG_STATUS_SUCCESS;
struct stat endpoint_stat;
if (stat(endpoint, &endpoint_stat))
{
BAIL_ON_ERROR(status = lwmsg_error_raise_errno(&assoc->context.error, errno));
}
if (!S_ISSOCK(endpoint_stat.st_mode))
{
ASSOC_RAISE_ERROR(assoc, status = LWMSG_STATUS_INVALID_PARAMETER,
"%s: not a socket", endpoint);
}
*uid = endpoint_stat.st_uid;
*gid = endpoint_stat.st_gid;
error:
return status;
}