login-proxy-state.c revision dc1bc1685e4a0d58ae7bacaecc282d0ebde2d7da
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2009-2010 Dovecot authors, see the included COPYING file */
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen#include "lib.h"
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen#include "network.h"
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen#include "hash.h"
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen#include "strescape.h"
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen#include "login-proxy-state.h"
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen#include <unistd.h>
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen#include <fcntl.h>
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainenstruct login_proxy_state {
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen struct hash_table *hash;
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen pool_t pool;
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen const char *notify_path;
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen int notify_fd;
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen unsigned int notify_fd_broken:1;
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen};
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainenstatic unsigned int login_proxy_record_hash(const void *p)
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen{
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen const struct login_proxy_record *rec = p;
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen return net_ip_hash(&rec->ip) ^ rec->port;
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen}
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainenstatic int login_proxy_record_cmp(const void *p1, const void *p2)
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen{
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen const struct login_proxy_record *rec1 = p1, *rec2 = p2;
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen if (!net_ip_compare(&rec1->ip, &rec2->ip))
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen return 1;
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen return (int)rec1->port - (int)rec2->port;
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen}
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainenstruct login_proxy_state *login_proxy_state_init(const char *notify_path)
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen{
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen struct login_proxy_state *state;
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen state = i_new(struct login_proxy_state, 1);
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen state->pool = pool_alloconly_create("login proxy state", 1024);
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen state->hash = hash_table_create(default_pool, state->pool, 0,
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen login_proxy_record_hash,
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen login_proxy_record_cmp);
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen state->notify_path = p_strdup(state->pool, notify_path);
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen state->notify_fd = -1;
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen return state;
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen}
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainenvoid login_proxy_state_deinit(struct login_proxy_state **_state)
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen{
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen struct login_proxy_state *state = *_state;
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen *_state = NULL;
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen if (state->notify_fd != -1) {
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen if (close(state->notify_fd) < 0)
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen i_error("close(%s) failed: %m", state->notify_path);
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen }
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen hash_table_destroy(&state->hash);
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen pool_unref(&state->pool);
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen i_free(state);
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen}
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainenstruct login_proxy_record *
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainenlogin_proxy_state_get(struct login_proxy_state *state,
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen const struct ip_addr *ip, unsigned int port)
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen{
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen struct login_proxy_record *rec, key;
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen memset(&key, 0, sizeof(key));
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen key.ip = *ip;
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen key.port = port;
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen rec = hash_table_lookup(state->hash, &key);
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen if (rec == NULL) {
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen rec = p_new(state->pool, struct login_proxy_record, 1);
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen rec->ip = *ip;
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen rec->port = port;
7dc4bf28c0c4c673a198070edd1ed54e14ae39aeTimo Sirainen hash_table_insert(state->hash, rec, rec);
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen }
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen return rec;
088cb24027234024aff2c1ce5b6870c5a308a44bTimo Sirainen}
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainenstatic int login_proxy_state_notify_open(struct login_proxy_state *state)
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen{
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen if (state->notify_fd_broken)
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen return -1;
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen state->notify_fd = open(state->notify_path, O_WRONLY);
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen if (state->notify_fd == -1) {
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen i_error("open(%s) failed: %m", state->notify_path);
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen state->notify_fd_broken = TRUE;
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen return -1;
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen }
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen return 0;
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen}
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainenvoid login_proxy_state_notify(struct login_proxy_state *state,
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen const char *user)
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen{
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen unsigned int len;
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen ssize_t ret;
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen if (state->notify_fd == -1) {
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen if (login_proxy_state_notify_open(state) < 0)
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen return;
2129efcd74a72d051d182171b7e07916308e386dTimo Sirainen }
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen T_BEGIN {
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen const char *cmd;
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen cmd = t_strconcat(str_tabescape(user), "\n", NULL);
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen len = strlen(cmd);
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen ret = write(state->notify_fd, cmd, len);
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen } T_END;
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen
dc1bc1685e4a0d58ae7bacaecc282d0ebde2d7daTimo Sirainen if (ret != (ssize_t)len) {
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen if (ret < 0)
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen i_error("write(%s) failed: %m", state->notify_path);
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen else {
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen i_error("write(%s) wrote partial update",
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen state->notify_path);
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen }
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen }
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen}