master-login.c revision 2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74c
/* Copyright (c) 2009-2016 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "ostream.h"
#include "fdpass.h"
#include "fd-close-on-exec.h"
#include "llist.h"
#include "str.h"
#include "strescape.h"
#include "master-service-private.h"
#include "master-login.h"
#include "master-login-auth.h"
#include <unistd.h>
#define master_login_conn_is_closed(conn) \
#define master_login_conn_has_clients(conn) \
struct master_login_connection {
struct master_login *login;
int refcount;
int fd;
bool login_success:1;
};
struct master_login_postlogin {
struct master_login_client *client;
int fd;
char *username;
};
struct master_login {
struct master_service *service;
struct master_login_connection *conns;
struct master_login_auth *auth;
char *postlogin_socket_path;
unsigned int postlogin_timeout_secs;
bool stopping:1;
};
struct master_login *
const struct master_login_settings *set)
{
struct master_login *login;
set->postlogin_timeout_secs > 0);
return login;
}
{
}
}
static int
struct master_auth_request *req_r,
unsigned char data[MASTER_AUTH_MAX_DATA_SIZE],
int *client_fd_r)
{
*client_fd_r = -1;
if (ret == 0) {
/* disconnected */
i_error("Login client disconnected too early");
} else if (ret > 0) {
/* request wasn't fully read */
i_error("fd_read() partial input (%d/%d)",
} else {
return 0;
i_error("fd_read() failed: %m");
}
return -1;
}
i_error("Too large auth data_size sent");
return -1;
}
/* @UNSAFE */
if (ret == 0) {
/* disconnected */
if (master_login_conn_has_clients(conn)) {
i_error("Login client disconnected too early "
"(while reading data)");
}
} else if (ret > 0) {
/* request wasn't fully read */
i_error("Data read partially %d/%u",
} else {
i_error("read(data) failed: %m");
}
return -1;
}
}
if (*client_fd_r == -1) {
i_error("Auth request missing a file descriptor");
return -1;
}
i_error("fstat(fd_read client) failed: %m");
return -1;
}
i_error("Auth request inode mismatch: %s != %s",
return -1;
}
return 1;
}
{
i_error("close(fd_read client) failed: %m");
/* this client failed (login callback wasn't called).
reset prefix to default. */
}
/* FIXME: currently we create a separate connection for each request,
so close the connection after we're done with this client */
}
}
const char *const *auth_args)
{
bool close_sockets;
if (close_sockets) {
/* we're dying as soon as this connection closes. */
/* try stopping again */
}
}
{
i_error("close(postlogin) failed: %m");
}
{
char buf[1024];
const char *const *auth_args;
int fd = -1;
if (fd != -1) {
/* post-login script replaced fd */
i_error("close(client) failed: %m");
}
}
/* finished reading the input */
} else {
if (ret < 0) {
return;
i_error("fd_read(%s) failed: %m",
i_error("fd_read(%s) failed: disconnected",
} else {
i_info("Post-login script denied access to user %s",
}
return;
}
}
{
i_error("%s: Timeout waiting for post-login script to finish, aborting",
}
const char *const *auth_args)
{
struct master_login_postlogin *pl;
unsigned int i;
int fd;
if (fd == -1) {
i_error("net_connect_unix(%s) failed: %m%s",
return -1;
}
}
if (ret < 0) {
i_error("write(%s) failed: %m",
} else {
i_error("write(%s) failed: partial write",
}
i_close_fd(&fd);
return -1;
}
return 0;
}
static void
void *context)
{
struct master_auth_reply reply;
i_error("login client: Username missing from auth reply");
}
return;
}
auth_args[0]);
else {
/* we've sent the reply. the connection is no longer needed,
so disconnect it (before login process disconnects us and
logs an error) */
/* execute post-login scripts before finishing auth */
}
}
{
struct master_auth_request req;
struct master_login_client *client;
unsigned char data[MASTER_AUTH_MAX_DATA_SIZE];
size_t i, session_len = 0;
if (ret <= 0) {
if (ret < 0) {
}
if (client_fd != -1) {
i_error("close(fd_read client) failed: %m");
}
return;
}
/* extract the session ID from the request data */
if (data[i] == '\0') {
session_len = i++;
break;
}
}
/* @UNSAFE: we have a request. do userdb lookup for it. */
}
{
struct master_login_connection *conn;
/* NOTE: currently there's a separate connection for each request. */
}
{
return;
i_error("close(master login) failed: %m");
}
{
return;
if (!conn->login_success)
}
{
}
}