responder_common.c revision 72aa8e7b1d234b6b68446d42efa1cff22b70c81b
/*
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 <unistd.h>
#include <fcntl.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"
{
int v;
int ferr;
/* Get the current flags for this file descriptor */
errno = 0;
/* Set the non-blocking flag on this fd */
if (ferr < 0) {
DEBUG(0, ("Unable to set fd non-blocking: [%d][%s]\n",
return error;
}
return EOK;
}
{
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) {
DEBUG(0, ("Unable to set fd close-on-exec: [%d][%s]\n",
return error;
}
return EOK;
}
{
("Failed to close fd [%d]: [%s]\n",
}
("Terminated client [%p][%d]\n",
return 0;
}
{
#ifdef HAVE_UCRED
int ret;
struct ucred client_cred;
return ret;
}
if (client_cred_len != sizeof(struct ucred)) {
return ENOMSG;
}
#endif
return EOK;
}
{
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;
}
errno = 0;
"UID nor a user name which cloud 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;
}
DEBUG(0, ("Failed to send data, aborting client!\n"));
return;
}
/* ok all sent */
return;
}
{
int ret;
DEBUG(0, ("Failed to alloc request, aborting client!\n"));
return;
}
}
DEBUG(0, ("Failed to alloc request, aborting client!\n"));
return;
}
}
switch (ret) {
case EOK:
/* do not read anymore */
/* execute command */
DEBUG(0, ("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:
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) {
return;
}
/* TODO: what is the best response to this condition? Terminate? */
return;
}
}
if (!cctx) {
struct sockaddr_un addr;
DEBUG(0, ("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);
cctx->client_euid));
} else {
}
return;
}
}
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_interface *intf,
const char *cli_name,
struct sss_domain_info *domain)
{
int ret;
/* Set up SBUS connection to the monitor */
DEBUG(0, ("Could not locate DP address.\n"));
return ret;
}
DEBUG(0, ("Failed to connect to monitor services.\n"));
return ret;
}
/* Identify ourselves to the DP */
cli_name);
DEBUG(0, ("Failed to identify to the DP!\n"));
return ret;
}
return EOK;
}
/* create a unix socket and listen to it */
{
struct sockaddr_un addr;
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
return EIO;
}
/* Set the umask so that permissions are set right on the socket.
* It must be readable and writable by anybody on the system. */
umask(0111);
goto failed;
}
goto failed;
}
/* make sure we have no old sockets around */
goto failed;
}
goto failed;
}
if(!accept_ctx) goto failed;
accept_ctx->is_private = false;
DEBUG(0, ("Failed to queue handler on pipe\n"));
goto failed;
}
}
/* create privileged pipe */
return EIO;
}
umask(0177);
goto failed;
}
goto failed;
}
goto failed;
}
goto failed;
}
if(!accept_ctx) goto failed;
accept_ctx->is_private = true;
DEBUG(0, ("Failed to queue handler on privileged pipe\n"));
goto failed;
}
}
/* we want default permissions on created files to be very strict,
so set our umask to 0177 */
umask(0177);
return EOK;
/* we want default permissions on created files to be very strict,
so set our umask to 0177 */
umask(0177);
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 tevent_context *ev,
struct confdb_ctx *cdb,
struct sss_cmd_table sss_cmds[],
const char *sss_pipe_name,
const char *sss_priv_pipe_name,
const char *confdb_service_path,
const char *svc_name,
struct sbus_interface *monitor_intf,
const char *cli_name,
struct sbus_interface *dp_intf,
struct resp_ctx **responder_ctx)
{
struct sss_domain_info *dom;
int ret;
if (!rctx) {
DEBUG(0, ("fatal error initializing resp_ctx\n"));
return ENOMEM;
}
rctx->shutting_down = false;
("Cannot get the client idle timeout [%d]: %s\n",
return ret;
}
/* Ensure that the client timeout is at least ten seconds */
}
("Cannnot get the default domain timeout [%d]: %s\n",
return ret;
}
if (rctx->domains_timeout < 0) {
}
DEBUG(0, ("fatal error setting up domain map\n"));
return ret;
}
&rctx->default_domain);
("Cannnot get the default domain [%d]: %s\n",
return ret;
}
DEBUG(0, ("fatal error setting up message bus\n"));
return ret;
}
("fatal error initializing regex data for domain: %s\n",
return ret;
}
/* skip local domain, it doesn't have a backend */
continue;
}
DEBUG(0, ("fatal error setting up backend connector\n"));
return ret;
}
}
DEBUG(0, ("fatal error initializing resp_ctx\n"));
return ret;
}
/* after all initializations we are ready to listen on our socket */
DEBUG(0, ("fatal error initializing socket\n"));
return ret;
}
/* Create DP request table */
("Could not create hash table for the request queue\n"));
return ret;
}
*responder_ctx = rctx;
return EOK;
}
{
}
return EOK;
}
struct sss_domain_info *
const char *domain)
{
struct sss_domain_info *dom;
int i;
break;
}
for (i = 0; i < dom->subdomain_count; i++) {
/* Sub-domains may come and go, so we better copy the struct
* for each request. */
break;
}
}
}
/* FIXME: we might want to return a real error, e.g. if copy_subdomain
* fails. */
if (!ret_dom) {
"possible subdomains!\n", domain));
}
return ret_dom;
}
struct sbus_connection *conn)
{
struct resp_ctx);
}
{
int limret;
/* First, let's see if we have permission to just set
* the value as-is.
*/
if (limret == 0) {
("Maximum file descriptors set to [%d]\n",
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) {
("Current fd limit: [%d]\n",
/* Choose the lesser of the requested and the hard limit */
} else {
}
if (limret == 0) {
("Maximum file descriptors set to [%d]\n",
} else {
("Could not set new fd limits. Proceeding with [%d]\n",
}
} else {
("Could not determine fd limits. "
"Proceeding with system values\n"));
}
}