Skip to content

Commit

Permalink
SECRETS: Update confdb when starting the process
Browse files Browse the repository at this point in the history
In order to get up-to-date configurations let's update the confdb file
when initializing secrets service.

It's done by socket-activating sssd-update-confdb process, which is
implemented now as:
- sends a single byte to the sssd-update-confdb socket, which will
  trigger the service
- waits till one byte comes back
- initialize secrets service as it was done before

Related:
https://fedorahosted.org/sssd/ticket/3138

Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
  • Loading branch information
fidencio committed Sep 22, 2016
1 parent 2b5594c commit 8297f82
Showing 1 changed file with 279 additions and 3 deletions.
282 changes: 279 additions & 3 deletions src/responder/secrets/secsrv.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,19 @@
#include "responder/secrets/secsrv.h"
#include "resolv/async_resolv.h"

#include "util/sss_sockets.h"

#define DEFAULT_SEC_FD_LIMIT 2048

struct sec_update_confdb_state {
struct TALLOC_CTX *mem_ctx;
struct tevent_context *ev;
struct confdb_ctx *cdb;

int sd;
struct tevent_fd *fde;
};

static int sec_get_config(struct sec_ctx *sctx)
{
int ret;
Expand Down Expand Up @@ -137,6 +148,271 @@ static int sec_process_init(TALLOC_CTX *mem_ctx,
return ret;
}

static int sec_update_confdb_state_destructor(void *data)
{
struct sec_update_confdb_state *state;

state = talloc_get_type(data, struct sec_update_confdb_state);

if (!state) return 0 ;

if (state->sd != -1) {
DEBUG(SSSDBG_TRACE_FUNC, "closing socket [%d]\n", state->sd);
close(state->sd);
state->sd = -1;
}

state->mem_ctx = NULL;
state->ev = NULL;
state->cdb = NULL;

return 0;
}

static int sec_update_confdb_fd_send_data(int fd)
{
char data = '1';
ssize_t len;

errno = 0;
len = send(fd, &data, 1, 0);
if (len == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
return EAGAIN;
} else {
return errno;
}
}

if (len == 0) {
return EIO;
}

return EOK;
}

static void sec_update_confdb_fd_send(void *data)
{
struct tevent_req *req;
struct sec_update_confdb_state *state;
int ret;

req = talloc_get_type(data, struct tevent_req);
state = tevent_req_data(req, struct sec_update_confdb_state);

ret = sec_update_confdb_fd_send_data(state->sd);
if (ret == EAGAIN) {
/* not all data was sent, loop again */
return;
}

if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting client!\n");

tevent_req_error(req, ret);
return;
}

/* ok all sent */
TEVENT_FD_NOT_WRITEABLE(state->fde);
TEVENT_FD_READABLE(state->fde);
}

static int sec_update_confdb_fd_recv_data(int fd)
{
char data;
ssize_t len;

errno = 0;
len = recv(fd, &data, 1, 0);
if (len == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
return EAGAIN;
} else {
return errno;
}
}

if (len == 0) {
return ENODATA;
}

return EOK;
}

static void sec_update_confdb_fd_recv(void *data)
{
struct tevent_req *req;
struct sec_update_confdb_state *state;
int ret;

req = talloc_get_type(data, struct tevent_req);
state = tevent_req_data(req, struct sec_update_confdb_state);

ret = sec_update_confdb_fd_recv_data(state->sd);

switch(ret) {
case ENODATA:
DEBUG(SSSDBG_TRACE_ALL,
"Client closed connection\n");
tevent_req_error(req, EIO);
return;
case EAGAIN:
DEBUG(SSSDBG_TRACE_ALL,
"Interrupted before any data could be read, retry later\n");
return;
case EOK:
/* all fine */
break;
default:
DEBUG(SSSDBG_FATAL_FAILURE,
"Failed to receive data (%d, %s), aborting client\n",
ret, strerror(ret));
tevent_req_error(req, ret);
return;
}


TEVENT_FD_NOT_READABLE(state->fde);

ret = sec_process_init(state->mem_ctx, state->ev, state->cdb);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"sec_process_init failed: [%d]: %s.\n",
ret, strerror(ret));
tevent_req_error(req, ret);
return;
}

tevent_req_done(req);
}

static void sec_update_confdb_fd_handler(struct tevent_context *ev,
struct tevent_fd *fde,
uint16_t flags, void *data)
{
if (flags & TEVENT_FD_READ) {
sec_update_confdb_fd_recv(data);
return;
}

if (flags & TEVENT_FD_WRITE) {
sec_update_confdb_fd_send(data);
return;
}
}

static void sec_update_confdb_connect_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct sec_update_confdb_state *state;
int ret;

req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct sec_update_confdb_state);

ret = sssd_async_socket_init_recv(subreq, &state->sd);
talloc_zfree(subreq);

if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"sssd_async_socket_init request failed: [%d]: %s.\n",
ret, strerror(ret));

tevent_req_error(req, ret);
return;
}

/* EOK */

state->fde = tevent_add_fd(state->ev, state, state->sd,
TEVENT_FD_WRITE,
sec_update_confdb_fd_handler, req);
if (!state->fde) {
tevent_req_error(req, EIO);
return;
}

tevent_req_done(req);
}

static struct tevent_req *
sec_update_confdb_connect(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct confdb_ctx *cdb,
struct sockaddr_storage *addr,
int addr_len, int timeout)
{
struct tevent_req *req, *subreq;
struct sec_update_confdb_state *state;

req = tevent_req_create(mem_ctx, &state, struct sec_update_confdb_state);
if (!req) {
DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
return NULL;
}

talloc_set_destructor((TALLOC_CTX *)state, sec_update_confdb_state_destructor);

state->mem_ctx = mem_ctx;
state->ev = ev;
state->cdb = cdb;
state->sd = -1;

subreq = sssd_async_socket_init_send(state, ev, addr, addr_len, timeout);
if (!subreq) {
DEBUG(SSSDBG_CRIT_FAILURE, "sssd_async_socket_init_send failed.\n");

tevent_req_error(req, ENOMEM);
tevent_req_post(req, ev);

goto end;
}

tevent_req_set_callback(subreq, sec_update_confdb_connect_done, req);

end:
return req;
}

static int sec_update_confdb(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct confdb_ctx *cdb)
{
struct tevent_req *req;
struct sockaddr_storage *sockaddr;

sockaddr = talloc_zero(mem_ctx, struct sockaddr_storage);
if (sockaddr == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
return ENOMEM;
}

/* Updating confdb will be done in a few steps:
*
* 1) Connect to the update-confdb.socket
* 2) Send a single byte to update-confdb.socket,
* which will actually trigger the update.
* 3) Receive a single byte as a confirmation that
* the update happened without issues
* 4) Finish the initialization using the up-to-date
* values from the confdb.
*/

((struct sockaddr_un *)sockaddr)->sun_family = AF_UNIX;
memcpy(&((struct sockaddr_un *) sockaddr)->sun_path,
SSS_UPDATE_CONFDB_SOCKET_NAME,
strlen(SSS_UPDATE_CONFDB_SOCKET_NAME));

req = sec_update_confdb_connect(mem_ctx, ev, cdb, sockaddr,
SUN_LEN((struct sockaddr_un *) sockaddr),
CONFDB_RESPONDER_CLI_IDLE_DEFAULT_TIMEOUT);

if (!req) return ENOMEM;

return EOK;
}

int main(int argc, const char *argv[])
{
int opt;
Expand Down Expand Up @@ -187,9 +463,9 @@ int main(int argc, const char *argv[])
"Could not set up to exit when parent process does\n");
}

ret = sec_process_init(main_ctx,
main_ctx->event_ctx,
main_ctx->confdb_ctx);
ret = sec_update_confdb(main_ctx,
main_ctx->event_ctx,
main_ctx->confdb_ctx);
if (ret != EOK) return 3;

/* loop on main */
Expand Down

0 comments on commit 8297f82

Please sign in to comment.