}
static void
-doveadm_cmd_server_post(struct client_connection_tcp *conn, const char *cmd_name)
+doveadm_cmd_server_post(struct client_connection_tcp *conn,
+ struct doveadm_cmd_context *cctx)
{
const char *str = NULL;
+ if (cctx->referral != NULL) {
+ o_stream_nsend_str(conn->output, t_strdup_printf(
+ "\n-REFERRAL %s\n", cctx->referral));
+ return;
+ }
+
if (doveadm_exit_code == 0) {
o_stream_nsend(conn->output, "\n+\n", 3);
return;
} else {
o_stream_nsend_str(conn->output, "\n-\n");
i_error("BUG: Command '%s' returned unknown error code %d",
- cmd_name, doveadm_exit_code);
+ cctx->cmd->name, doveadm_exit_code);
}
}
i_getopt_reset();
if (doveadm_cmdline_run(argc, argv, cctx) < 0)
doveadm_exit_code = EX_USAGE;
- doveadm_cmd_server_post(conn, cctx->cmd->name);
+ doveadm_cmd_server_post(conn, cctx);
}
static int doveadm_cmd_handle(struct client_connection_tcp *conn,
const char **user_r, const char **host_r,
struct ip_addr *hostip_r, in_port_t *port_r,
enum doveadm_proxy_ssl_flags *ssl_flags_r,
+ const char **referral_r,
const char **error_r)
{
struct auth_master_connection *auth_conn;
const char *auth_socket_path, *proxy_host, *proxy_hostip, *const *fields;
unsigned int i;
in_port_t proxy_port;
- bool proxying;
+ bool proxying, nologin;
int ret;
*user_r = input->username;
*host_r = ctx->set->doveadm_socket_path;
*port_r = ctx->set->doveadm_port;
+ *referral_r = NULL;
if (ctx->set->doveadm_port == 0)
return 0;
so just continue with the default host */
} else {
proxy_host = NULL; proxy_hostip = NULL; proxying = FALSE;
- proxy_port = ctx->set->doveadm_port;
+ proxy_port = ctx->set->doveadm_port; nologin = FALSE;
for (i = 0; fields[i] != NULL; i++) {
const char *p, *key, *value;
if (strcmp(key, "proxy") == 0)
proxying = TRUE;
+ else if (strcmp(key, "nologin") == 0)
+ nologin = TRUE;
else if (strcmp(key, "host") == 0)
proxy_host = value;
else if (strcmp(key, "hostip") == 0)
auth_socket_path, proxy_hostip);
ret = -1;
}
- if (!proxying)
- ret = 0;
- else if (proxy_host == NULL) {
+ if (!proxying) {
+ if (!nologin)
+ ret = 0;
+ else if (proxy_host == NULL) {
+ /* Allow accessing nologin users via doveadm
+ protocol, since it's only admins that access
+ them. */
+ ret = 0;
+ } else {
+ /* Referral */
+ *referral_r = t_strdup_printf("%s@%s",
+ *user_r, proxy_host);
+ ret = 1;
+ }
+ } else if (proxy_host == NULL) {
*error_r = t_strdup_printf("%s: Proxy is missing destination host",
auth_socket_path);
if (strstr(auth_socket_path, "/auth-userdb") != NULL) {
{
struct doveadm_server *server;
struct server_connection *conn;
- const char *user, *host;
+ const char *user, *host, *referral;
struct ip_addr hostip;
enum doveadm_proxy_ssl_flags ssl_flags = 0;
char *username_dup;
i_zero(&hostip);
ret = doveadm_mail_server_user_get_host(ctx, input, &user, &host, &hostip,
- &port, &ssl_flags, error_r);
+ &port, &ssl_flags, &referral, error_r);
if (ret < 0)
return ret;
if (ret == 0 &&
/* run it ourself */
return 0;
}
+ if (referral != NULL) {
+ ctx->cctx->referral = referral;
+ return 1;
+ }
/* server sends the sticky headers for each row as well,
so undo any sticks we might have added already */
server_connection_input_cmd_error(struct server_connection *conn,
const char *line)
{
+ const char *code, *args = strchr(line, ' ');
+ if (args != NULL)
+ code = t_strdup_until(line, args++);
+ else {
+ code = line;
+ args = "";
+ }
struct doveadm_server_reply reply = {
- .exit_code = doveadm_str_to_exit_code(line),
+ .exit_code = doveadm_str_to_exit_code(code),
.error = line,
};
- if (reply.exit_code == DOVEADM_EX_UNKNOWN &&
- str_to_int(line, &reply.exit_code) < 0) {
- /* old doveadm-server */
- reply.exit_code = EX_TEMPFAIL;
+ switch (reply.exit_code) {
+ case DOVEADM_EX_REFERRAL:
+ reply.error = args;
+ break;
+ case DOVEADM_EX_UNKNOWN:
+ if (str_to_int(line, &reply.exit_code) < 0) {
+ /* old doveadm-server */
+ reply.exit_code = EX_TEMPFAIL;
+ }
+ break;
}
server_connection_callback(conn, &reply);
}