access-lookup.c revision 183bea41fa640dc8117f3eb45ff935cd81377a84
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen/* Copyright (c) 2010-2011 Dovecot authors, see the included COPYING file */
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen#include "lib.h"
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen#include "ioloop.h"
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen#include "network.h"
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen#include "fdpass.h"
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen#include "access-lookup.h"
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen#include <unistd.h>
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen#define ACCESS_LOOKUP_TIMEOUT_MSECS (1000*60)
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainenstruct access_lookup {
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen int refcount;
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen int fd;
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen char *path;
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen struct io *io;
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen struct timeout *to;
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen access_lookup_callback_t *callback;
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen void *context;
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen};
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainenstatic void access_lookup_input(struct access_lookup *lookup)
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen{
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen unsigned char buf[3];
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen ssize_t ret;
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen bool success = FALSE;
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen ret = read(lookup->fd, buf, sizeof(buf));
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen if (ret < 0) {
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen i_error("read(%s) failed: %m", lookup->path);
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen } else if (ret == 0) {
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen /* connection close -> no success */
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen } else if (ret == 2 && buf[0] == '0' && buf[1] == '\n') {
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen /* no success */
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen } else if (ret == 2 && buf[0] == '1' && buf[1] == '\n') {
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen success = TRUE;
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen } else {
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen i_error("access(%s): Invalid input", lookup->path);
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen }
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen lookup->refcount++;
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen lookup->callback(success, lookup->context);
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen if (lookup->refcount > 1)
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen access_lookup_destroy(&lookup);
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen access_lookup_destroy(&lookup);
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen}
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainenstatic void access_lookup_timeout(struct access_lookup *lookup)
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen{
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen i_error("access(%s): Timed out while waiting for reply", lookup->path);
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen lookup->refcount++;
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen lookup->callback(FALSE, lookup->context);
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen if (lookup->refcount > 1)
access_lookup_destroy(&lookup);
access_lookup_destroy(&lookup);
}
struct access_lookup *
access_lookup(const char *path, int client_fd, const char *daemon_name,
access_lookup_callback_t *callback, void *context)
{
struct access_lookup *lookup;
const char *cmd;
ssize_t ret;
int fd;
fd = net_connect_unix(path);
if (fd == -1) {
i_error("connect(%s) failed: %m", path);
return NULL;
}
cmd = t_strconcat(daemon_name, "\n", NULL);
ret = fd_send(fd, client_fd, cmd, strlen(cmd));
if (ret != (ssize_t)strlen(cmd)) {
if (ret < 0)
i_error("fd_send(%s) failed: %m", path);
else
i_error("fd_send(%s) didn't write enough bytes", path);
(void)close(fd);
return NULL;
}
lookup = i_new(struct access_lookup, 1);
lookup->refcount = 1;
lookup->fd = fd;
lookup->path = i_strdup(path);
lookup->io = io_add(fd, IO_READ, access_lookup_input, lookup);
lookup->to = timeout_add(ACCESS_LOOKUP_TIMEOUT_MSECS,
access_lookup_timeout, lookup);
lookup->callback = callback;
lookup->context = context;
return lookup;
}
void access_lookup_destroy(struct access_lookup **_lookup)
{
struct access_lookup *lookup = *_lookup;
i_assert(lookup->refcount > 0);
if (--lookup->refcount > 0)
return;
*_lookup = NULL;
if (lookup->to != NULL)
timeout_remove(&lookup->to);
io_remove(&lookup->io);
if (close(lookup->fd) < 0)
i_error("close(%s) failed: %m", lookup->path);
i_free(lookup->path);
i_free(lookup);
}