bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan BoschThe imap-urlauth service provides URLAUTH access between different accounts. If
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschuser A has an URLAUTH that references a mail from user B, it makes a connection
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschto the imap-urlauth service to access user B's mail store to retrieve the
19557f192d37cd54a1a090a8a26d9d47265e4413Aki TuomiThe authentication and authorization of the URLAUTH is performed within
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschthis service. Because access to the mailbox and the associated mailbox keys is
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschnecessary to retrieve the message and for verification of the URLAUTH, the
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschurlauth services need root privileges. To mitigate security concerns, the
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschretrieval and verification of the URLs is performed in a worker service that
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschdrops root privileges and acts as target user B.
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan BoschThe imap-urlauth service thus consists of three separate stages:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch- imap-urlauth-login:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch This is the login service which operates identical to imap-login and
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch pop3-login equivalents, except for the fact that only token authentication is
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch allowed. It verifies that the connecting client is an IMAP service acting on
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch behaf of an authenticated user.
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch- imap-urlauth:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch Once the client is authenticated, the connection gets passed to the
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap-urlauth service (as implemented here). The goal of this stage is
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch to prevent the need for re-authenticating to the imap-urlauth service when
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch the clients wants to switch to a different target user. It normally runs as
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch $default_internal_user and starts workers to perform the actual work. To start
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch a worker, the imap-urlauth service establishes a control connection to the
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap-urlauth-worker service. In the handshake phase of the control protocol,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch the connection of the client is passed to the worker. Once the worker
211c638d81d382517d196ad47565e0d85012c927klemens finishes, a new worker is started and the client connection is transfered to
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch it, unless the client is disconnected.
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch- imap-urlauth-worker:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch The worker handles the URLAUTH requests from the client, so this is where the
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch mail store of the target user is accessed. The worker starts as root. In the
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch protocol interaction the client first indicates what the target user is.
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch The worker then performs a userdb lookup and drops privileges. The client can
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch then submit URLAUTH requests, which are limited to that user. Once the client
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch wants to access a different user, the worker terminates and the imap-urlauth
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch service starts a new worker for the next target user.
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic struct master_login *master_login = NULL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic const struct imap_urlauth_settings *imap_urlauth_settings;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_printfa(title, "%u connections", imap_urlauth_client_count);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* do nothing. imap_urlauth connections typically die pretty quick anyway. */
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Boschclient_create_from_input(const char *service, const char *username,
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch if (client_create(service, username, fd_in, fd_out,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void main_stdio_run(const char *username)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch username = username != NULL ? username : getenv("USER");
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch (void)client_create_from_input("", username, STDIN_FILENO, STDOUT_FILENO);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschlogin_client_connected(const struct master_login_client *client,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *username, const char *const *extra_fields)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch auth_user_fields_parse(extra_fields, pool_datastack_create(), &reply);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* check peer credentials if possible */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (reply.uid != (uid_t)-1 && net_getunixcred(client->fd, &cred) == 0 &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("Peer's credentials (uid=%ld) do not match "
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch "the user that logged in (uid=%ld).",
f87938eab9249ad84681f4fa747aab7b9a719670Timo Sirainen if (write(client->fd, msg, strlen(msg)) < 0) {
f87938eab9249ad84681f4fa747aab7b9a719670Timo Sirainen /* ignored */
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch fields = array_get(&reply.extra_fields, &count);
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch for (i = 0; i < count; i++) {
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch if (strncmp(fields[i], "client_service=", 15) == 0) {
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch i_error("Auth did not yield required client_service field (BUG).");
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch if (write(client->fd, msg, strlen(msg)) < 0) {
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch /* ignored */
f1edf7f20661ef9627acbf4054acddcba4d2eb3fStephan Bosch if (client_create_from_input(service, username, client->fd, client->fd) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void login_client_failed(const struct master_login_client *client,
f87938eab9249ad84681f4fa747aab7b9a719670Timo Sirainen if (write(client->fd, msg, strlen(msg)) < 0) {
f87938eab9249ad84681f4fa747aab7b9a719670Timo Sirainen /* ignored */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void client_connected(struct master_service_connection *conn)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* when running standalone, we shouldn't even get here */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch master_service_client_connection_accept(conn);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch static const struct setting_parser_info *set_roots[] = {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch login_set.postlogin_timeout_secs = MASTER_POSTLOGIN_TIMEOUT_DEFAULT;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch printf("NO imap_urlauth binary must not be started from "
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch "inetd, use imap-urlauth-login instead.\n");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch service_flags |= MASTER_SERVICE_FLAG_STANDALONE |
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch service_flags |= MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch master_service = master_service_init("imap-urlauth", service_flags,
2812f5744f44ffb070bb6f8bede8dcaa04fe6337Timo Sirainen while ((c = master_getopt(master_service)) > 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch master_service_init_log(master_service, "imap-urlauth: ");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (master_service_settings_read(master_service, &input, &output,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_fatal("Error reading configuration: %s", error);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch sets = master_service_settings_get_others(master_service);
b1c85a1f889a5e71f491e320bdac95df3c9fe550Martti Rannanjärvi if (t_abspath(auth_socket_path, &login_set.auth_socket_path, &error) < 0) {
b1c85a1f889a5e71f491e320bdac95df3c9fe550Martti Rannanjärvi i_fatal("t_abspath(%s) failed: %s", auth_socket_path, error);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch login_set.failure_callback = login_client_failed;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch master_service_set_die_callback(master_service, imap_urlauth_die);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* fake that we're running, so we know if client was destroyed
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch while handling its initial input */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch master_login = master_login_init(master_service, &login_set);