login-connection.c revision 9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2
816bf6f8088b162b681101d93fd450127a0e586fJulian Kornberger/* Copyright (c) 2010-2015 Dovecot authors, see the included COPYING file */
a847d9812b328c048773e705606b10875a929034Eugen Kuksa
5e2a6a8992b4e9e77be3a94fc87af4dc14b0c8c4henning mueller#include "lib.h"
a4344d37747b6733bbd0d8df738b614cb385316cTim Reddehase#include "ioloop.h"
d1f0cb74e8bc61e9185488a431b86816cb1cc7edSascha Graef#include "net.h"
c273fbbb7863507673f695bc85709c0cb715011fTim Reddehase#include "str.h"
c273fbbb7863507673f695bc85709c0cb715011fTim Reddehase#include "istream.h"
5ec1c6ff5da427d945d7fb708567ce3526c4c741Tim Reddehase#include "ostream.h"
5ec1c6ff5da427d945d7fb708567ce3526c4c741Tim Reddehase#include "llist.h"
98ba1c38b1cce99ecc61117259f2ae05ffe98469Tim Reddehase#include "master-service.h"
5ec1c6ff5da427d945d7fb708567ce3526c4c741Tim Reddehase#include "director.h"
81a6387a4ab56a24194ecbabd6609c6bcca568b7Tim Reddehase#include "director-request.h"
10be32b36246121321399ec3ab26d4d723d550e3Tim Reddehase#include "auth-connection.h"
10be32b36246121321399ec3ab26d4d723d550e3Tim Reddehase#include "login-connection.h"
10be32b36246121321399ec3ab26d4d723d550e3Tim Reddehase
10be32b36246121321399ec3ab26d4d723d550e3Tim Reddehase#include <unistd.h>
10be32b36246121321399ec3ab26d4d723d550e3Tim Reddehase
6f84d8dbc4edca35b7e69c8296a257ea17e3b74fTim Reddehase#define AUTHREPLY_PROTOCOL_MAJOR_VERSION 1
6f84d8dbc4edca35b7e69c8296a257ea17e3b74fTim Reddehase#define AUTHREPLY_PROTOCOL_MINOR_VERSION 0
10be32b36246121321399ec3ab26d4d723d550e3Tim Reddehase
10be32b36246121321399ec3ab26d4d723d550e3Tim Reddehasestruct login_connection {
10be32b36246121321399ec3ab26d4d723d550e3Tim Reddehase struct login_connection *prev, *next;
10be32b36246121321399ec3ab26d4d723d550e3Tim Reddehase
10be32b36246121321399ec3ab26d4d723d550e3Tim Reddehase int refcount;
10be32b36246121321399ec3ab26d4d723d550e3Tim Reddehase enum login_connection_type type;
10be32b36246121321399ec3ab26d4d723d550e3Tim Reddehase
10be32b36246121321399ec3ab26d4d723d550e3Tim Reddehase int fd;
10be32b36246121321399ec3ab26d4d723d550e3Tim Reddehase struct io *io;
81a6387a4ab56a24194ecbabd6609c6bcca568b7Tim Reddehase struct istream *input;
81a6387a4ab56a24194ecbabd6609c6bcca568b7Tim Reddehase struct ostream *output;
81a6387a4ab56a24194ecbabd6609c6bcca568b7Tim Reddehase struct auth_connection *auth;
81a6387a4ab56a24194ecbabd6609c6bcca568b7Tim Reddehase struct director *dir;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase unsigned int handshaked:1;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase unsigned int destroyed:1;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase};
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehasestruct login_host_request {
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase struct login_connection *conn;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase char *line, *username;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase
81a6387a4ab56a24194ecbabd6609c6bcca568b7Tim Reddehase struct ip_addr local_ip;
4949048bda09e116ee3627383e831455954cbe41Tim Reddehase in_port_t local_port;
4949048bda09e116ee3627383e831455954cbe41Tim Reddehase in_port_t dest_port;
4949048bda09e116ee3627383e831455954cbe41Tim Reddehase bool director_proxy_maybe;
4949048bda09e116ee3627383e831455954cbe41Tim Reddehase};
4949048bda09e116ee3627383e831455954cbe41Tim Reddehase
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehasestatic struct login_connection *login_connections;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase
db8aaeeeb3b24f487a5d02c60d18e96e55f6ba85Tim Reddehasestatic void auth_input_line(const char *line, void *context);
db8aaeeeb3b24f487a5d02c60d18e96e55f6ba85Tim Reddehasestatic void login_connection_unref(struct login_connection **_conn);
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehasestatic void login_connection_input(struct login_connection *conn)
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase{
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase struct ostream *output;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase unsigned char buf[4096];
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase ssize_t ret;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase
4949048bda09e116ee3627383e831455954cbe41Tim Reddehase ret = read(conn->fd, buf, sizeof(buf));
4949048bda09e116ee3627383e831455954cbe41Tim Reddehase if (ret <= 0) {
db8aaeeeb3b24f487a5d02c60d18e96e55f6ba85Tim Reddehase if (ret < 0) {
4949048bda09e116ee3627383e831455954cbe41Tim Reddehase if (errno == EAGAIN)
4949048bda09e116ee3627383e831455954cbe41Tim Reddehase return;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase if (errno != ECONNRESET)
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase i_error("read(login connection) failed: %m");
db8aaeeeb3b24f487a5d02c60d18e96e55f6ba85Tim Reddehase }
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase login_connection_deinit(&conn);
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase return;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase }
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase output = auth_connection_get_output(conn->auth);
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase o_stream_nsend(output, buf, ret);
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase}
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase
4949048bda09e116ee3627383e831455954cbe41Tim Reddehasestatic void login_connection_authreply_input(struct login_connection *conn)
4949048bda09e116ee3627383e831455954cbe41Tim Reddehase{
db8aaeeeb3b24f487a5d02c60d18e96e55f6ba85Tim Reddehase const char *line;
4949048bda09e116ee3627383e831455954cbe41Tim Reddehase
4949048bda09e116ee3627383e831455954cbe41Tim Reddehase while ((line = i_stream_read_next_line(conn->input)) != NULL) T_BEGIN {
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase if (!conn->handshaked) {
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase if (!version_string_verify(line, "director-authreply-client",
db8aaeeeb3b24f487a5d02c60d18e96e55f6ba85Tim Reddehase AUTHREPLY_PROTOCOL_MAJOR_VERSION)) {
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase i_error("authreply client sent invalid handshake: %s", line);
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase login_connection_deinit(&conn);
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase return;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase }
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase conn->handshaked = TRUE;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase } else {
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase auth_input_line(line, conn);
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase }
4949048bda09e116ee3627383e831455954cbe41Tim Reddehase } T_END;
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa if (conn->input->eof) {
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa if (conn->input->stream_errno != 0 &&
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa conn->input->stream_errno != ECONNRESET) {
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa i_error("read(authreply connection) failed: %s",
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa i_stream_get_error(conn->input));
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa }
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa login_connection_deinit(&conn);
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa }
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa}
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksastatic void
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksalogin_connection_send_line(struct login_connection *conn, const char *line)
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa{
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa struct const_iovec iov[2];
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa if (conn->destroyed)
273b30f33fe1a753893887c8eb94f8078cc96928Eugen Kuksa return;
9ade3006d75c25cfa77d51526e4a6cdd2370be5cEugen Kuksa
9ade3006d75c25cfa77d51526e4a6cdd2370be5cEugen Kuksa iov[0].iov_base = line;
9ade3006d75c25cfa77d51526e4a6cdd2370be5cEugen Kuksa iov[0].iov_len = strlen(line);
9ade3006d75c25cfa77d51526e4a6cdd2370be5cEugen Kuksa iov[1].iov_base = "\n";
9ade3006d75c25cfa77d51526e4a6cdd2370be5cEugen Kuksa iov[1].iov_len = 1;
9ade3006d75c25cfa77d51526e4a6cdd2370be5cEugen Kuksa o_stream_nsendv(conn->output, iov, N_ELEMENTS(iov));
9ade3006d75c25cfa77d51526e4a6cdd2370be5cEugen Kuksa}
9ade3006d75c25cfa77d51526e4a6cdd2370be5cEugen Kuksa
9ade3006d75c25cfa77d51526e4a6cdd2370be5cEugen Kuksastatic bool login_host_request_is_self(struct login_host_request *request,
9ade3006d75c25cfa77d51526e4a6cdd2370be5cEugen Kuksa const struct ip_addr *dest_ip)
9ade3006d75c25cfa77d51526e4a6cdd2370be5cEugen Kuksa{
9ade3006d75c25cfa77d51526e4a6cdd2370be5cEugen Kuksa if (!net_ip_compare(dest_ip, &request->local_ip))
9ade3006d75c25cfa77d51526e4a6cdd2370be5cEugen Kuksa return FALSE;
9ade3006d75c25cfa77d51526e4a6cdd2370be5cEugen Kuksa if (request->dest_port != 0 && request->local_port != 0 &&
b7fe8f3179594e2ebccf6ee9f562e9c2e17aab96Eugen Kuksa request->dest_port != request->local_port)
b7fe8f3179594e2ebccf6ee9f562e9c2e17aab96Eugen Kuksa return FALSE;
b7fe8f3179594e2ebccf6ee9f562e9c2e17aab96Eugen Kuksa return TRUE;
b7fe8f3179594e2ebccf6ee9f562e9c2e17aab96Eugen Kuksa}
b7fe8f3179594e2ebccf6ee9f562e9c2e17aab96Eugen Kuksa
b7fe8f3179594e2ebccf6ee9f562e9c2e17aab96Eugen Kuksastatic void
b7fe8f3179594e2ebccf6ee9f562e9c2e17aab96Eugen Kuksalogin_host_callback(const struct ip_addr *ip, const char *hostname,
b7fe8f3179594e2ebccf6ee9f562e9c2e17aab96Eugen Kuksa const char *errormsg, void *context)
b7fe8f3179594e2ebccf6ee9f562e9c2e17aab96Eugen Kuksa{
b7fe8f3179594e2ebccf6ee9f562e9c2e17aab96Eugen Kuksa struct login_host_request *request = context;
b7fe8f3179594e2ebccf6ee9f562e9c2e17aab96Eugen Kuksa struct director *dir = request->conn->dir;
b7fe8f3179594e2ebccf6ee9f562e9c2e17aab96Eugen Kuksa const char *line, *line_params;
b7fe8f3179594e2ebccf6ee9f562e9c2e17aab96Eugen Kuksa unsigned int secs;
b7fe8f3179594e2ebccf6ee9f562e9c2e17aab96Eugen Kuksa
b7fe8f3179594e2ebccf6ee9f562e9c2e17aab96Eugen Kuksa if (ip == NULL) {
81a6387a4ab56a24194ecbabd6609c6bcca568b7Tim Reddehase if (strncmp(request->line, "OK\t", 3) == 0)
7c0f71e3e6e26af2cc91112fdbe3905879bfd893Tim Reddehase line_params = request->line + 3;
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase else if (strncmp(request->line, "PASS\t", 5) == 0)
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase line_params = request->line + 5;
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase else
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase i_panic("BUG: Unexpected line: %s", request->line);
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase
7c0f71e3e6e26af2cc91112fdbe3905879bfd893Tim Reddehase i_error("director: User %s host lookup failed: %s",
575f7ed30e509f1a650d73927f607e7b5b11a6dbEugen Kuksa request->username, errormsg);
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa line = t_strconcat("FAIL\t", t_strcut(line_params, '\t'),
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase "\ttemp", NULL);
b7fe8f3179594e2ebccf6ee9f562e9c2e17aab96Eugen Kuksa } else if (request->director_proxy_maybe &&
7c0f71e3e6e26af2cc91112fdbe3905879bfd893Tim Reddehase login_host_request_is_self(request, ip)) {
7c0f71e3e6e26af2cc91112fdbe3905879bfd893Tim Reddehase line = request->line;
7c0f71e3e6e26af2cc91112fdbe3905879bfd893Tim Reddehase } else {
d11de492e18415f91e383e1567beb4e1385d5938Tim Reddehase string_t *str = t_str_new(64);
7c0f71e3e6e26af2cc91112fdbe3905879bfd893Tim Reddehase
7c0f71e3e6e26af2cc91112fdbe3905879bfd893Tim Reddehase secs = dir->set->director_user_expire / 2;
7c0f71e3e6e26af2cc91112fdbe3905879bfd893Tim Reddehase str_printfa(str, "%s\tproxy_refresh=%u\t", request->line, secs);
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase if (hostname == NULL)
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase str_printfa(str, "host=%s", net_ip2addr(ip));
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase else {
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase str_printfa(str, "host=%s\thostip=%s",
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase hostname, net_ip2addr(ip));
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase }
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase line = str_c(str);
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase }
7c0f71e3e6e26af2cc91112fdbe3905879bfd893Tim Reddehase login_connection_send_line(request->conn, line);
cc3ee169b3cbf177eaf03e9a590ff9e30c338bd2Tim Reddehase
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase login_connection_unref(&request->conn);
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase i_free(request->username);
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase i_free(request->line);
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase i_free(request);
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase}
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehasestatic void auth_input_line(const char *line, void *context)
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase{
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase struct login_connection *conn = context;
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase struct login_host_request *request, temp_request;
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase const char *const *args, *line_params, *username = NULL, *tag = "";
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase bool proxy = FALSE, host = FALSE;
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase if (line == NULL) {
503ccb65bd740225668eb51be966d60fb4ae29e1Tim Reddehase /* auth connection died -> kill also this login connection */
575f7ed30e509f1a650d73927f607e7b5b11a6dbEugen Kuksa login_connection_deinit(&conn);
575f7ed30e509f1a650d73927f607e7b5b11a6dbEugen Kuksa return;
575f7ed30e509f1a650d73927f607e7b5b11a6dbEugen Kuksa }
575f7ed30e509f1a650d73927f607e7b5b11a6dbEugen Kuksa if (conn->type != LOGIN_CONNECTION_TYPE_USERDB &&
575f7ed30e509f1a650d73927f607e7b5b11a6dbEugen Kuksa strncmp(line, "OK\t", 3) == 0)
575f7ed30e509f1a650d73927f607e7b5b11a6dbEugen Kuksa line_params = line + 3;
575f7ed30e509f1a650d73927f607e7b5b11a6dbEugen Kuksa else if (conn->type == LOGIN_CONNECTION_TYPE_USERDB &&
575f7ed30e509f1a650d73927f607e7b5b11a6dbEugen Kuksa strncmp(line, "PASS\t", 5) == 0)
575f7ed30e509f1a650d73927f607e7b5b11a6dbEugen Kuksa line_params = line + 5;
575f7ed30e509f1a650d73927f607e7b5b11a6dbEugen Kuksa else {
575f7ed30e509f1a650d73927f607e7b5b11a6dbEugen Kuksa login_connection_send_line(conn, line);
575f7ed30e509f1a650d73927f607e7b5b11a6dbEugen Kuksa return;
575f7ed30e509f1a650d73927f607e7b5b11a6dbEugen Kuksa }
575f7ed30e509f1a650d73927f607e7b5b11a6dbEugen Kuksa
81a6387a4ab56a24194ecbabd6609c6bcca568b7Tim Reddehase /* OK <id> [<parameters>] */
81a6387a4ab56a24194ecbabd6609c6bcca568b7Tim Reddehase args = t_strsplit_tab(line_params);
98ba1c38b1cce99ecc61117259f2ae05ffe98469Tim Reddehase if (*args != NULL) {
98ba1c38b1cce99ecc61117259f2ae05ffe98469Tim Reddehase /* we should always get here, but in case we don't just
98ba1c38b1cce99ecc61117259f2ae05ffe98469Tim Reddehase forward as-is and let login process handle the error. */
d51cee8257d50d1f2d7c0818d968b32096f6b795Tim Reddehase args++;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase }
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase
db8aaeeeb3b24f487a5d02c60d18e96e55f6ba85Tim Reddehase memset(&temp_request, 0, sizeof(temp_request));
db8aaeeeb3b24f487a5d02c60d18e96e55f6ba85Tim Reddehase for (; *args != NULL; args++) {
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase if (strncmp(*args, "proxy", 5) == 0 &&
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase ((*args)[5] == '=' || (*args)[5] == '\0'))
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase proxy = TRUE;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase else if (strncmp(*args, "host=", 5) == 0)
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase host = TRUE;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase else if (strncmp(*args, "lip=", 4) == 0) {
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase if (net_addr2ip((*args) + 4, &temp_request.local_ip) < 0)
5ec1c6ff5da427d945d7fb708567ce3526c4c741Tim Reddehase i_error("auth sent invalid lip field: %s", (*args) + 6);
7dadc1a5aa3845c2ce19ad1daa2c63dfd7b59979Tim Reddehase } else if (strncmp(*args, "lport=", 6) == 0) {
7dadc1a5aa3845c2ce19ad1daa2c63dfd7b59979Tim Reddehase if (net_str2port((*args) + 6, &temp_request.local_port) < 0)
7dadc1a5aa3845c2ce19ad1daa2c63dfd7b59979Tim Reddehase i_error("auth sent invalid lport field: %s", (*args) + 6);
7dadc1a5aa3845c2ce19ad1daa2c63dfd7b59979Tim Reddehase } else if (strncmp(*args, "port=", 5) == 0) {
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase if (net_str2port((*args) + 5, &temp_request.dest_port) < 0)
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase i_error("auth sent invalid port field: %s", (*args) + 6);
db8aaeeeb3b24f487a5d02c60d18e96e55f6ba85Tim Reddehase } else if (strncmp(*args, "destuser=", 9) == 0)
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase username = *args + 9;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase else if (strncmp(*args, "director_tag=", 13) == 0)
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase tag = *args + 13;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase else if (strncmp(*args, "director_proxy_maybe", 20) == 0 &&
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase ((*args)[20] == '=' || (*args)[20] == '\0'))
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase temp_request.director_proxy_maybe = TRUE;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase else if (strncmp(*args, "user=", 5) == 0) {
7dadc1a5aa3845c2ce19ad1daa2c63dfd7b59979Tim Reddehase if (username == NULL)
d51cee8257d50d1f2d7c0818d968b32096f6b795Tim Reddehase username = *args + 5;
d51cee8257d50d1f2d7c0818d968b32096f6b795Tim Reddehase }
d51cee8257d50d1f2d7c0818d968b32096f6b795Tim Reddehase }
772288cf17d57e84a4799c56949263f7ff098773Tim Reddehase if ((!proxy && !temp_request.director_proxy_maybe) ||
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase host || username == NULL) {
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase login_connection_send_line(conn, line);
db8aaeeeb3b24f487a5d02c60d18e96e55f6ba85Tim Reddehase return;
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase }
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase if (*conn->dir->set->master_user_separator != '\0') {
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase /* with master user logins we still want to use only the
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase login username */
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase username = t_strcut(username,
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase *conn->dir->set->master_user_separator);
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase }
23f0ab4a423943eb59109df37074ef0c330d07c0Tim Reddehase
653f8d7c88abc38a2c42f12b80b3e3efd882e039Tim Reddehase /* we need to add the host. the lookup might be asynchronous */
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksa request = i_new(struct login_host_request, 1);
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksa *request = temp_request;
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksa request->conn = conn;
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksa request->line = i_strdup(line);
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksa request->username = i_strdup(username);
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksa
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksa conn->refcount++;
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksa director_request(conn->dir, username, tag, login_host_callback, request);
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksa}
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksa
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksastruct login_connection *
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksalogin_connection_init(struct director *dir, int fd,
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksa struct auth_connection *auth,
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksa enum login_connection_type type)
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa{
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa struct login_connection *conn;
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa conn = i_new(struct login_connection, 1);
dfc7323cf206c044e128ffc866be9d3c777be8b7Eugen Kuksa conn->refcount = 1;
dfc7323cf206c044e128ffc866be9d3c777be8b7Eugen Kuksa conn->fd = fd;
dfc7323cf206c044e128ffc866be9d3c777be8b7Eugen Kuksa conn->dir = dir;
dfc7323cf206c044e128ffc866be9d3c777be8b7Eugen Kuksa conn->output = o_stream_create_fd(conn->fd, (size_t)-1, FALSE);
dfc7323cf206c044e128ffc866be9d3c777be8b7Eugen Kuksa o_stream_set_no_error_handling(conn->output, TRUE);
dfc7323cf206c044e128ffc866be9d3c777be8b7Eugen Kuksa if (type != LOGIN_CONNECTION_TYPE_AUTHREPLY) {
dfc7323cf206c044e128ffc866be9d3c777be8b7Eugen Kuksa i_assert(auth != NULL);
dfc7323cf206c044e128ffc866be9d3c777be8b7Eugen Kuksa conn->auth = auth;
dfc7323cf206c044e128ffc866be9d3c777be8b7Eugen Kuksa conn->io = io_add(conn->fd, IO_READ,
dfc7323cf206c044e128ffc866be9d3c777be8b7Eugen Kuksa login_connection_input, conn);
dfc7323cf206c044e128ffc866be9d3c777be8b7Eugen Kuksa auth_connection_set_callback(conn->auth, auth_input_line, conn);
dfc7323cf206c044e128ffc866be9d3c777be8b7Eugen Kuksa } else {
dfc7323cf206c044e128ffc866be9d3c777be8b7Eugen Kuksa i_assert(auth == NULL);
dfc7323cf206c044e128ffc866be9d3c777be8b7Eugen Kuksa conn->input = i_stream_create_fd(conn->fd, IO_BLOCK_SIZE, FALSE);
dfc7323cf206c044e128ffc866be9d3c777be8b7Eugen Kuksa conn->io = io_add(conn->fd, IO_READ,
dfc7323cf206c044e128ffc866be9d3c777be8b7Eugen Kuksa login_connection_authreply_input, conn);
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa o_stream_nsend_str(conn->output, t_strdup_printf(
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa "VERSION\tdirector-authreply-server\t%d\t%d\n",
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa AUTHREPLY_PROTOCOL_MAJOR_VERSION,
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa AUTHREPLY_PROTOCOL_MINOR_VERSION));
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa }
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa conn->type = type;
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa DLLIST_PREPEND(&login_connections, conn);
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa return conn;
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa}
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksavoid login_connection_deinit(struct login_connection **_conn)
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa{
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa struct login_connection *conn = *_conn;
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa
c67b096189612bb816b4306ef88080b795b5cf41Eugen Kuksa *_conn = NULL;
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksa
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksa if (conn->destroyed)
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksa return;
a3bd54a5482d637ac89bbddbc27796d303544d4dEugen Kuksa conn->destroyed = TRUE;
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa DLLIST_REMOVE(&login_connections, conn);
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa io_remove(&conn->io);
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa if (conn->input != NULL)
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa i_stream_destroy(&conn->input);
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa o_stream_destroy(&conn->output);
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa if (close(conn->fd) < 0)
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa i_error("close(login connection) failed: %m");
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa conn->fd = -1;
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa if (conn->auth != NULL)
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa auth_connection_deinit(&conn->auth);
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa login_connection_unref(&conn);
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa master_service_client_connection_destroyed(master_service);
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa}
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksastatic void login_connection_unref(struct login_connection **_conn)
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa{
1d39ed6dd0248b5b0c969926bae5f6f66ff4d082Eugen Kuksa struct login_connection *conn = *_conn;
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa *_conn = NULL;
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa i_assert(conn->refcount > 0);
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa if (--conn->refcount == 0)
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa i_free(conn);
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa}
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksavoid login_connections_deinit(void)
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa{
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa while (login_connections != NULL) {
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa struct login_connection *conn = login_connections;
0af42668e3f55c0feaf10dc656fb423c4adaba80Eugen Kuksa
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa login_connection_deinit(&conn);
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa }
1f3a52128a4c9a5830936e25b071ce6a81fec1beEugen Kuksa}
273b30f33fe1a753893887c8eb94f8078cc96928Eugen Kuksa