#include "istream.h"
#include "ostream.h"
#include "network.h"
+#include "hex-binary.h"
#include "hostpid.h"
#include "str.h"
#include "str-sanitize.h"
+#include "randgen.h"
#include "safe-memset.h"
#include "master-service.h"
#include "auth-stream.h"
conn->auth = auth;
conn->refcount = 1;
conn->connect_uid = ++connect_uid_counter;
+ random_fill(conn->cookie, sizeof(conn->cookie));
conn->fd = fd;
conn->input = i_stream_create_fd(fd, AUTH_CLIENT_MAX_LINE_LENGTH,
array_append(&auth_client_connections, &conn, 1);
str = t_str_new(128);
- str_printfa(str, "VERSION\t%u\t%u\n%sSPID\t%s\nCUID\t%u\nDONE\n",
+ str_printfa(str, "VERSION\t%u\t%u\n%sSPID\t%s\nCUID\t%u\nCOOKIE\t",
AUTH_CLIENT_PROTOCOL_MAJOR_VERSION,
AUTH_CLIENT_PROTOCOL_MINOR_VERSION,
str_c(conn->auth->mech_handshake),
my_pid, conn->connect_uid);
+ binary_to_hex_append(str, conn->cookie, sizeof(conn->cookie));
+ str_append(str, "\nDONE\n");
if (o_stream_send(conn->output, str_data(str), str_len(str)) < 0)
auth_client_connection_destroy(&conn);
#ifndef AUTH_CLIENT_CONNECTION_H
#define AUTH_CLIENT_CONNECTION_H
+#include "master-interface.h"
+
struct auth_client_connection {
struct auth *auth;
int refcount;
unsigned int pid;
unsigned int connect_uid;
+ uint8_t cookie[MASTER_AUTH_COOKIE_SIZE];
struct auth_request_handler *request_handler;
unsigned int version_received:1;
#include "hash.h"
#include "str.h"
#include "strescape.h"
-#include "hostpid.h"
#include "str-sanitize.h"
+#include "hostpid.h"
+#include "hex-binary.h"
#include "ioloop.h"
#include "network.h"
#include "istream.h"
struct auth_client_connection *client_conn;
const char *const *list;
unsigned int id, client_pid, client_id;
+ uint8_t cookie[MASTER_AUTH_COOKIE_SIZE];
+ buffer_t buf;
- /* <id> <client-pid> <client-id> */
+ /* <id> <client-pid> <client-id> <cookie> */
list = t_strsplit(args, "\t");
- if (list[0] == NULL || list[1] == NULL || list[2] == NULL) {
+ if (str_array_length(list) < 4) {
i_error("BUG: Master sent broken REQUEST");
return FALSE;
}
id = (unsigned int)strtoul(list[0], NULL, 10);
client_pid = (unsigned int)strtoul(list[1], NULL, 10);
client_id = (unsigned int)strtoul(list[2], NULL, 10);
+ buffer_create_data(&buf, cookie, sizeof(cookie));
+ if (hex_to_binary(list[3], &buf) < 0) {
+ i_error("BUG: Master sent broken REQUEST cookie");
+ return FALSE;
+ }
client_conn = auth_client_connection_lookup(client_pid);
if (client_conn == NULL) {
client_pid);
(void)o_stream_send_str(conn->output,
t_strdup_printf("NOTFOUND\t%u\n", id));
+ } else if (memcmp(client_conn->cookie, cookie, sizeof(cookie)) != 0) {
+ i_error("Master requested auth for client %u with invalid cookie",
+ client_pid);
+ (void)o_stream_send_str(conn->output,
+ t_strdup_printf("NOTFOUND\t%u\n", id));
} else {
auth_request_handler_master_request(
client_conn->request_handler, conn, id, client_id);
*server_pid_r = client->conn->server_pid;
*connect_uid_r = client->conn->connect_uid;
}
+
+const char *auth_client_get_cookie(struct auth_client *client)
+{
+ return client->conn->cookie;
+}
void auth_client_get_connect_id(struct auth_client *client,
unsigned int *server_pid_r,
unsigned int *connect_uid_r);
+const char *auth_client_get_cookie(struct auth_client *client);
/* Create a new authentication request. callback is called whenever something
happens for the request. */
i_error("BUG: Authentication server already sent handshake");
return -1;
}
+ if (args[0] == NULL) {
+ i_error("BUG: Authentication server sent broken CUID line");
+ return -1;
+ }
conn->connect_uid = (unsigned int)strtoul(args[0], NULL, 10);
return 0;
}
+static int
+auth_server_input_cookie(struct auth_server_connection *conn,
+ const char *const *args)
+{
+ if (conn->cookie != NULL) {
+ i_error("BUG: Authentication server already sent cookie");
+ return -1;
+ }
+ conn->cookie = p_strdup(conn->pool, args[0]);
+ return 0;
+}
+
static int auth_server_input_done(struct auth_server_connection *conn)
{
if (array_count(&conn->available_auth_mechs) == 0) {
i_error("BUG: Authentication server returned no mechanisms");
return -1;
}
+ if (conn->cookie == NULL) {
+ i_error("BUG: Authentication server didn't send a cookie");
+ return -1;
+ }
if (conn->to != NULL)
timeout_remove(&conn->to);
return auth_server_input_spid(conn, args + 1);
else if (strcmp(args[0], "CUID") == 0)
return auth_server_input_cuid(conn, args + 1);
+ else if (strcmp(args[0], "COOKIE") == 0)
+ return auth_server_input_cookie(conn, args + 1);
else if (strcmp(args[0], "DONE") == 0)
return auth_server_input_done(conn);
else {
unsigned int server_pid;
unsigned int connect_uid;
+ char *cookie;
ARRAY_DEFINE(available_auth_mechs, struct auth_mech_desc);
to make sure there's space to transfer the command tag */
#define MASTER_AUTH_MAX_DATA_SIZE (1024*2)
+/* Authentication client process's cookie size */
+#define MASTER_AUTH_COOKIE_SIZE (128/8)
+
/* Authentication request. File descriptor may be sent along with the
request. */
struct master_auth_request {
/* Request tag. Reply is sent back using same tag. */
unsigned int tag;
- /* Authentication process and authentication ID. */
+ /* Authentication process, authentication ID and auth cookie. */
pid_t auth_pid;
unsigned int auth_id;
+ uint8_t cookie[MASTER_AUTH_COOKIE_SIZE];
/* Local and remote IPs of the connection. The file descriptor
itself may be a local socketpair. */
#include "common.h"
#include "base64.h"
#include "buffer.h"
+#include "hex-binary.h"
#include "istream.h"
#include "write-full.h"
#include "strescape.h"
{
struct master_auth_request req;
const unsigned char *data;
+ const char *cookie;
size_t size;
buffer_t *buf;
+ buf = buffer_create_dynamic(pool_datastack_create(), 256);
+
memset(&req, 0, sizeof(req));
req.auth_pid = auth_client_request_get_server_pid(request);
req.auth_id = auth_client_request_get_id(request);
req.local_ip = client->local_ip;
req.remote_ip = client->ip;
- buf = buffer_create_dynamic(pool_datastack_create(), 256);
+ cookie = auth_client_get_cookie(auth_client);
+ if (hex_to_binary(cookie, buf) == 0 && buf->used == sizeof(req.cookie))
+ memcpy(req.cookie, buf->data, sizeof(req.cookie));
+
+ buffer_set_used_size(buf, 0);
buffer_append(buf, client->master_data_prefix,
client->master_data_prefix_len);
#include "common.h"
#include "hash.h"
#include "str.h"
+#include "hex-binary.h"
#include "ioloop.h"
#include "ostream.h"
#include "fdpass.h"
static unsigned int
auth_server_send_request(struct service_process_auth_server *server_process,
struct service_process_auth_source *source_process,
- unsigned int auth_id)
+ unsigned int auth_id,
+ const uint8_t cookie[MASTER_AUTH_COOKIE_SIZE])
{
unsigned int tag = 0;
string_t *str;
str_truncate(str, 0);
}
- str_printfa(str, "REQUEST\t%u\t%s\t%u\n",
+ str_printfa(str, "REQUEST\t%u\t%s\t%u\t",
tag, dec2str(source_process->process.pid), auth_id);
+ binary_to_hex_append(str, cookie, MASTER_AUTH_COOKIE_SIZE);
+ str_append_c(str, '\n');
+
o_stream_send(server_process->auth_output, str_data(str), str_len(str));
return tag;
}
auth_req->data_size = req.data_size;
memcpy(auth_req->data, data, req.data_size);
- tag = auth_server_send_request(auth_process, process, req.auth_id);
+ tag = auth_server_send_request(auth_process, process, req.auth_id,
+ req.cookie);
service_process_ref(&process->process);
hash_table_insert(auth_process->auth_requests,