auth-master.c revision 3d422a98304352692cb1f3585ac6481d5c4b4155
/* Copyright (c) 2005-2013 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "lib-signals.h"
#include "array.h"
#include "ioloop.h"
#include "eacces-error.h"
#include "net.h"
#include "istream.h"
#include "ostream.h"
#include "str.h"
#include "strescape.h"
#include "master-interface.h"
#include "auth-master.h"
#include <stdlib.h>
#include <unistd.h>
#define AUTH_PROTOCOL_MAJOR 1
#define AUTH_PROTOCOL_MINOR 0
#define AUTH_MASTER_IDLE_SECS 60
#define MAX_INBUF_SIZE 8192
#define MAX_OUTBUF_SIZE 1024
#define DEFAULT_USERDB_LOOKUP_PREFIX "userdb lookup"
struct auth_master_connection {
char *auth_socket_path;
enum auth_master_flags flags;
int fd;
const char *prefix;
unsigned int request_counter;
void *context);
void *reply_context;
unsigned int sent_handshake:1;
unsigned int handshaked:1;
unsigned int aborted:1;
};
struct auth_master_lookup_ctx {
struct auth_master_connection *conn;
const char *user;
const char *expected_reply;
int return_value;
const char **fields;
};
struct auth_master_user_list_ctx {
struct auth_master_connection *conn;
bool finished;
bool failed;
};
struct auth_master_connection *
{
struct auth_master_connection *conn;
return conn;
}
{
}
}
{
}
{
return conn->auth_socket_path;
}
{
}
{
i_error("userdb lookup: "
"Auth protocol version mismatch "
return -1;
}
break;
}
}
return 0;
}
{
return 1;
return 0;
i_error("user %s: Auth %s lookup failed",
} else if (debug) {
i_debug("user %s: Auth %s lookup returned temporary failure: %s",
}
return -1;
}
return -1;
}
static const char *const *args_hide_passwords(const char *const *args)
{
const char *p, *p2;
unsigned int i;
/* if there are any keys that contain "pass" string */
break;
}
return args;
/* there are. replace their values with <hidden> */
"=<hidden>", NULL);
} else {
}
}
}
void *context)
{
unsigned int i, len;
ctx->return_value =
if (ctx->return_value >= 0) {
for (i = 0; i < len; i++)
} else {
/* put the reason string into first field */
for (i = 0; i < len; i++) {
break;
}
}
}
if (debug) {
}
return TRUE;
}
static bool
{
id = "";
else {
args++;
}
i_error("%s: %s is an auth client socket. "
"It should be a master socket.",
} else {
}
return FALSE;
}
{
const char *line;
bool ret;
case 0:
return;
case -1:
/* disconnected */
i_error("%s: Disconnected unexpectedly",
return;
case -2:
/* buffer full */
i_error("%s: BUG: Received more than %d bytes",
return;
}
if (!conn->handshaked) {
if (auth_input_handshake(conn) < 0)
return;
}
T_BEGIN {
} T_END;
if (!ret)
return;
}
}
{
int fd;
/* max. 1 second wait here. */
if (fd == -1) {
i_error("userdb lookup: %s",
eacces_error_get("connect",
conn->auth_socket_path));
} else {
i_error("userdb lookup: connect(%s) failed: %m",
}
return -1;
}
return 0;
}
{
if (!conn->handshaked)
else
}
{
}
{
return;
}
{
}
}
else {
}
}
}
static bool is_valid_string(const char *str)
{
const char *p;
/* make sure we're not sending any characters that have a special
meaning. */
for (p = str; *p != '\0'; p++) {
if (*p == '\t' || *p == '\n' || *p == '\r')
return FALSE;
}
return TRUE;
}
const char *cmd)
{
const char *str;
if (auth_master_connect(conn) < 0)
return -1;
}
if (!conn->sent_handshake) {
}
i_error("write(auth socket) failed: %m");
return -1;
}
return 0;
}
{
return -1;
}
return 0;
}
const char *cmd)
{
return -1;
return auth_master_run_cmd_post(conn);
}
static unsigned int
{
if (++conn->request_counter == 0) {
/* avoid zero */
conn->request_counter++;
}
return conn->request_counter;
}
static void
{
}
if (info->local_port != 0)
if (info->remote_port != 0)
}
const char *const **fields_r)
{
struct auth_master_lookup_ctx ctx;
/* non-allowed characters, the user can't exist */
*username_r = NULL;
return 0;
}
*username_r = NULL;
if (ctx.return_value > 0) {
i_error("Userdb lookup didn't return username");
}
} else {
}
return ctx.return_value;
}
struct auth_user_reply *reply_r)
{
i_error("Invalid uid in reply");
i_error("Invalid gid in reply");
else {
}
}
}
{
struct auth_master_lookup_ctx ctx;
/* non-allowed characters, the user can't exist */
return 0;
}
return ctx.return_value;
}
static bool
void *context)
{
return TRUE;
}
{
}
}
}
static bool
void *context)
{
i_error("User listing returned failure");
}
/* we'll just read all the users into memory. otherwise we'd
have to use a separate connection for listing and there's
a higher chance of a failure since the connection could be
open to dovecot-auth for a long time. */
} else {
i_error("User listing returned invalid input");
}
return FALSE;
}
struct auth_master_user_list_ctx *
const char *user_mask,
const struct auth_user_info *info)
{
struct auth_master_user_list_ctx *ctx;
if (*user_mask != '\0')
return ctx;
}
{
const char *line;
return NULL;
/* try to read already buffered input */
T_BEGIN {
} T_END;
} else {
/* wait for more data */
}
return NULL;
}
{
return ret;
}