responder_common.c revision e7ccfb139388c947ec2dee16cfe3005f5643b90d
/*
SSSD
Common Responder methods
Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <popt.h>
#include "util/strtonum.h"
#include "sbus/sssd_dbus.h"
#include "responder/common/responder.h"
#include "responder/common/responder_packet.h"
#include "providers/data_provider.h"
#include "monitor/monitor_interfaces.h"
#include "sbus/sbus_client.h"
#include "util/util_creds.h"
{
int v;
int ferr;
/* Get the current flags for this file descriptor */
errno = 0;
/* Set the close-on-exec flags on this fd */
if (ferr < 0) {
"Unable to set fd close-on-exec: [%d][%s]\n",
return error;
}
return EOK;
}
void *ptr)
{
"Failed to close fd [%d]: [%s]\n",
}
"Terminated client [%p][%d]\n",
}
{
int ret;
#ifdef HAVE_UCRED
return ret;
}
if (client_cred_len != sizeof(struct ucred)) {
"getsockopt returned unexpected message size.\n");
return ENOMSG;
}
"Client creds: euid[%d] egid[%d] pid[%d].\n",
#endif
if (ret != 0) {
/* This is not fatal, as SELinux may simply be disabled */
} else {
}
return ret;
}
{
if (!creds) return -1;
return cli_creds_get_uid(creds);
}
{
size_t c;
if (allowed_uids == NULL) {
return EINVAL;
}
for (c = 0; c < allowed_uids_count; c++) {
if (uid == allowed_uids[c]) {
return EOK;
}
}
return EACCES;
}
bool allow_sss_loop,
{
int ret;
size_t c;
int list_size;
char *endptr;
goto done;
}
goto done;
}
if (allow_sss_loop) {
"might not find sssd users.\n");
}
}
for (c = 0; c < list_size; c++) {
errno = 0;
if (*list[c] == '\0') {
goto done;
}
list[c]);
goto done;
}
"UID nor a user name which could be "
"resolved by getpwnam().\n", list[c]);
"UID nor a user name which could be "
"resolved by getpwnam().\n", list[c]);
goto done;
}
}
}
*_uid_count = list_size;
done:
}
}
return ret;
}
{
int ret;
/* not all data was sent, loop again */
return;
}
return;
}
/* ok all sent */
return;
}
{
enum sss_cli_command cmd;
}
{
int ret;
"Failed to alloc request, aborting client!\n");
return;
}
}
"Failed to alloc request, aborting client!\n");
return;
}
}
switch (ret) {
case EOK:
/* do not read anymore */
/* execute command */
"Failed to execute request, aborting client!\n");
}
/* past this point cctx can be freed at any time by callbacks
* in case of error, do not use it */
return;
case EAGAIN:
/* need to read still some data, loop again */
break;
case EINVAL:
"Invalid data from client, closing connection!\n");
break;
case ENODATA:
break;
default:
}
return;
}
{
/* Always reset the idle timer on any activity */
"Could not create idle timer for client. "
"This connection may not auto-terminate\n");
/* Non-fatal, continue */
}
if (flags & TEVENT_FD_READ) {
return;
}
if (flags & TEVENT_FD_WRITE) {
return;
}
}
struct accept_fd_ctx {
bool is_private;
};
struct tevent_timer *te,
struct timeval current_time,
void *data);
{
/* accept and attach new event handler */
struct accept_fd_ctx *accept_ctx =
int ret;
int client_fd;
if (accept_ctx->is_private) {
if (ret == -1) {
"stat on privileged pipe failed: [%d][%s].\n", errno,
return;
}
"privileged pipe has an illegal status.\n");
/* TODO: what is the best response to this condition? Terminate? */
return;
}
}
if (!cctx) {
struct sockaddr_un addr;
"Out of memory trying to setup client context%s!\n",
/* accept and close to signal the client we have a problem */
if (client_fd == -1) {
return;
}
return;
}
return;
}
"client cred may not be available.\n");
}
if (rctx->allowed_uids_count != 0) {
"but platform does not support " \
"reading peer credential from the " \
"socket. Access denied.\n");
return;
}
rctx->allowed_uids);
} else {
}
return;
}
}
"Failed to queue client handler%s\n",
return;
}
/* Set up the idle timer */
"Could not create idle timer for client. "
"This connection may not auto-terminate\n");
/* Non-fatal, continue */
}
"Client connected%s!\n",
return;
}
{
"Idle timer re-set for client [%p][%d]\n",
return EOK;
}
struct tevent_timer *te,
struct timeval current_time,
void *data)
{
/* This connection is idle. Terminate it */
"Terminating idle client [%p][%d]\n",
/* The cli_ctx destructor will handle the rest */
}
struct sbus_vtable *dp_intf,
const char *cli_name,
struct sss_domain_info *domain)
{
int ret;
/* Set up SBUS connection to the monitor */
return ret;
}
return ret;
}
return ret;
}
/* Identify ourselves to the DP */
cli_name);
return ret;
}
return EOK;
}
{
struct sockaddr_un addr;
int fd;
if (fd == -1) {
return EIO;
}
goto done;
}
goto done;
}
/* make sure we have no old sockets around */
"Cannot remove old socket (errno=%d), bind might fail!\n", ret);
}
"Unable to bind on socket '%s'\n", sock_name);
goto done;
}
"Unable to listen on socket '%s'\n", sock_name);
goto done;
}
done:
/* restore previous umask value */
} else {
}
return ret;
}
/* create a unix socket and listen to it */
{
struct accept_fd_ctx *accept_ctx;
/* for future use */
#if 0
char *default_pipe;
int ret;
if (!default_pipe) {
return ENOMEM;
}
return ret;
}
if (!default_pipe) {
return ENOMEM;
}
return ret;
}
#endif
/* Set the umask so that permissions are set right on the socket.
* It must be readable and writable by anybody on the system. */
return ret;
}
}
if(!accept_ctx) goto failed;
accept_ctx->is_private = false;
goto failed;
}
}
/* create privileged pipe */
goto failed;
}
}
if(!accept_ctx) goto failed;
accept_ctx->is_private = true;
"Failed to queue handler on privileged pipe\n");
goto failed;
}
}
return EOK;
return EIO;
}
static int sss_responder_ctx_destructor(void *ptr)
{
/* mark that we are shutting down the responder, so it is propagated
* into underlying contexts that are freed right before rctx */
rctx->shutting_down = true;
return 0;
}
struct confdb_ctx *cdb,
struct sss_nc_ctx **ncache)
{
int tmp_value;
int ret;
/* neg_timeout */
15, &tmp_value);
"Fatal failure of setup negative cache timeout.\n");
goto done;
}
if (tmp_value < 0) {
goto done;
}
/* local_timeout */
0, &tmp_value);
"Fatal failure of setup negative cache timeout.\n");
goto done;
}
if (tmp_value < 0) {
goto done;
}
/* negative cache init */
"Fatal failure of initializing negative cache.\n");
goto done;
}
done:
return ret;
}
struct tevent_context *ev,
struct confdb_ctx *cdb,
struct sss_cmd_table sss_cmds[],
const char *sss_pipe_name,
int pipe_fd,
const char *sss_priv_pipe_name,
int priv_pipe_fd,
const char *confdb_service_path,
const char *svc_name,
struct mon_cli_iface *monitor_intf,
const char *cli_name,
struct sbus_vtable *dp_intf,
struct resp_ctx **responder_ctx)
{
struct sss_domain_info *dom;
int ret;
if (!rctx) {
return ENOMEM;
}
rctx->shutting_down = false;
"Cannot get the client idle timeout [%d]: %s\n",
goto fail;
}
/* Ensure that the client timeout is at least ten seconds */
}
"Cannnot get the default domain timeout [%d]: %s\n",
goto fail;
}
if (rctx->domains_timeout < 0) {
}
goto fail;
}
&rctx->default_domain);
"Cannnot get the default domain [%d]: %s\n",
goto fail;
}
&tmp);
"Cannnot get the space substitution character [%d]: %s\n",
goto fail;
}
"only the first character %c will be used\n",
}
}
goto fail;
}
"fatal error initializing regex data for domain: %s\n",
goto fail;
}
/* skip local domain, it doesn't have a backend */
continue;
}
"fatal error setting up backend connector\n");
goto fail;
}
}
goto fail;
}
/* after all initializations we are ready to listen on our socket */
goto fail;
}
/* Create DP request table */
"Could not create hash table for the request queue\n");
goto fail;
}
goto fail;
}
*responder_ctx = rctx;
return EOK;
fail:
return ret;
}
{
}
return EOK;
}
struct sss_domain_info *
{
struct sss_domain_info *dom;
continue;
}
break;
}
}
if (!ret_dom) {
}
return ret_dom;
}
struct sss_domain_info **_ret_dom)
{
struct sss_domain_info *dom;
int ret;
return EINVAL;
}
continue;
}
if ((id_len >= dom_id_len) &&
if (IS_SUBDOMAIN(dom) &&
rctx->domains_timeout)) {
"is expired.\n", id);
goto done;
}
break;
}
}
"possible subdomains!\n", id);
} else {
}
done:
return ret;
}
{
}
{
int limret;
/* First, let's see if we have permission to just set
* the value as-is.
*/
if (limret == 0) {
return;
}
/* We couldn't set the soft and hard limits to this
* value. Let's see how high we CAN set it.
*/
/* Determine the maximum hard limit */
if (limret == 0) {
/* Choose the lesser of the requested and the hard limit */
} else {
}
if (limret == 0) {
} else {
"Could not set new fd limits. Proceeding with "
}
} else {
"Could not determine fd limits. "
"Proceeding with system values\n");
}
}