bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "login-common.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "str.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "strescape.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "base64.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "net.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "ioloop.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "istream.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "ostream.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "master-service.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "auth-client.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "client-common.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "imap-urlauth-login-settings.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch#define IMAP_URLAUTH_PROTOCOL_MAJOR_VERSION 2
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#define IMAP_URLAUTH_PROTOCOL_MINOR_VERSION 0
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstruct imap_urlauth_client {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct client common;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const struct imap_urlauth_login_settings *set;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool version_received:1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch};
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschimap_urlauth_client_auth_result(struct client *client,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch enum client_auth_result result,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const struct client_auth_reply *reply ATTR_UNUSED,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *text ATTR_UNUSED)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (result != CLIENT_AUTH_RESULT_SUCCESS) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* failed or otherwise invalid status */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_send_raw(client, "FAILED\n");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_destroy(client, "Disconnected: Authentication failed");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* authentication succeeded */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void imap_urlauth_client_handle_input(struct client *client)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch#define AUTH_ARG_COUNT 6
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct imap_urlauth_client *uauth_client =
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (struct imap_urlauth_client *)client;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct net_unix_cred cred;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *line;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *const *args;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch pid_t pid;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (!uauth_client->version_received) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if ((line = i_stream_next_line(client->input)) == NULL)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (!version_string_verify(line, "imap-urlauth",
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch IMAP_URLAUTH_PROTOCOL_MAJOR_VERSION)) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("IMAP URLAUTH client not compatible with this server "
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch "(mixed old and new binaries?) %s", line);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_destroy(client, "Disconnected: Version mismatch");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch uauth_client->version_received = TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if ((line = i_stream_next_line(client->input)) == NULL)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* read authentication info from input;
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch "AUTH"\t<service>\t<session-pid>\t<auth-username>\t<session_id>\t<token> */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch args = t_strsplit_tabescaped(line);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (str_array_length(args) < AUTH_ARG_COUNT ||
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch strcmp(args[0], "AUTH") != 0 || str_to_pid(args[2], &pid) < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("IMAP URLAUTH client sent unexpected AUTH input: %s", line);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_destroy(client, "Disconnected: Unexpected input");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch /* only imap and submission have direct access to urlauth service */
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch if (strcmp(args[1], "imap") != 0 && strcmp(args[1], "submission") != 0) {
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch i_error("IMAP URLAUTH accessed from inappropriate service: %s", args[1]);
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch client_destroy(client, "Disconnected: Unexpected input");
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch return;
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch }
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* verify session pid if possible */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (net_getunixcred(client->fd, &cred) == 0 &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cred.pid != (pid_t)-1 && pid != cred.pid) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("IMAP URLAUTH client sent invalid session pid %ld in AUTH request: "
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch "it did not match peer credentials (pid=%ld, uid=%ld)",
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (long)pid, (long)cred.pid, (long)cred.uid);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_destroy(client, "Disconnected: Invalid AUTH request");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch T_BEGIN {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch string_t *auth_data = t_str_new(128);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch string_t *init_resp;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch unsigned int i;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch str_append(auth_data, args[1]);
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch for (i = 2; i < AUTH_ARG_COUNT; i++) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append_c(auth_data, '\0');
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append(auth_data, args[i]);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch init_resp = t_str_new(256);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch base64_encode(str_data(auth_data),
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_len(auth_data), init_resp);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (void)client_auth_begin(client, "DOVECOT-TOKEN",
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_c(init_resp));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } T_END;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void imap_urlauth_client_input(struct client *client)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (!client_read(client))
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_ref(client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch o_stream_cork(client->output);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (!auth_client_is_connected(auth_client)) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* we're not currently connected to auth process -
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch don't allow any commands */
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&client->to_auth_waiting);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client->input_blocked = TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_urlauth_client_handle_input(client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch o_stream_uncork(client->output);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch client_unref(&client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic struct client *imap_urlauth_client_alloc(pool_t pool)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct imap_urlauth_client *uauth_client;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch uauth_client = p_new(pool, struct imap_urlauth_client, 1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return &uauth_client->common;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void imap_urlauth_client_create
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch(struct client *client, void **other_sets)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct imap_urlauth_client *uauth_client =
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (struct imap_urlauth_client *)client;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch uauth_client->set = other_sets[0];
d920a34dfe72ce74a362dae8083e021b4a1720ecTimo Sirainen client->io = io_add_istream(client->input, client_input, client);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void imap_urlauth_login_preinit(void)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch login_set_roots = imap_urlauth_login_setting_roots;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void imap_urlauth_login_init(void)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void imap_urlauth_login_deinit(void)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch clients_destroy_all();
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic struct client_vfuncs imap_urlauth_vfuncs = {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_urlauth_client_alloc,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_urlauth_client_create,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch NULL,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch NULL,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch NULL,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch NULL,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch NULL,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch NULL,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_urlauth_client_input,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch NULL,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch NULL,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_urlauth_client_auth_result,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch NULL,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch NULL,
2b96880f2d789d125aff6a95eaa7b51f558a6a1cTimo Sirainen NULL,
2b96880f2d789d125aff6a95eaa7b51f558a6a1cTimo Sirainen NULL,
ae797f3368ebb86e7786ca25d7c9c703f672b9f5Timo Sirainen client_common_send_raw_data,
edfdc577ffe7408fd6463eb9dba11260d380ab53Timo Sirainen NULL,
b84eff65e25ae86dfd6f798386577209b94838c6Timo Sirainen client_common_default_free,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch};
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic const struct login_binary imap_urlauth_login_binary = {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch .protocol = "imap-urlauth",
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch .process_name = "imap-urlauth-login",
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch .default_login_socket = LOGIN_TOKEN_DEFAULT_SOCKET,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch .client_vfuncs = &imap_urlauth_vfuncs,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch .preinit = imap_urlauth_login_preinit,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch .init = imap_urlauth_login_init,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch .deinit = imap_urlauth_login_deinit,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch};
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschint main(int argc, char *argv[])
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return login_binary_run(&imap_urlauth_login_binary, argc, argv);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}