auth-client-request.c revision d03a871a77f8ec36f48f5fea98d810e51b186fdb
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2003-2012 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen#include "str.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "strescape.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ostream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "auth-client-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "auth-server-connection.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "auth-client-request.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stdlib.h>
463e82bdf0e990f4f2252d2b53ea23a5abe5883cTimo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenstruct auth_client_request {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pool_t pool;
a0d34d3982507f513a9d800082481e9faeb9a943Timo Sirainen
a0d34d3982507f513a9d800082481e9faeb9a943Timo Sirainen struct auth_server_connection *conn;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen unsigned int id;
e6d7d19c328e7043ad35d5a52c1617bde915a16fTimo Sirainen time_t created;
d7095f3a4466fbb78b2d5eb3d322bc15a5b0ab1fTimo Sirainen
153de7823e64c67678b3fc95719c41a8ec5b864dTimo Sirainen struct auth_request_info request_info;
153de7823e64c67678b3fc95719c41a8ec5b864dTimo Sirainen
d7095f3a4466fbb78b2d5eb3d322bc15a5b0ab1fTimo Sirainen auth_request_callback_t *callback;
d7095f3a4466fbb78b2d5eb3d322bc15a5b0ab1fTimo Sirainen void *context;
8f7b00599e73fe71b1d2c6c65f8ae98aac1b23fbTimo Sirainen};
190237ce467d2389dfb809874b0fec86d3c7968dTimo Sirainen
d7095f3a4466fbb78b2d5eb3d322bc15a5b0ab1fTimo Sirainenstatic void auth_server_send_new_request(struct auth_server_connection *conn,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct auth_client_request *request)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen{
e6d7d19c328e7043ad35d5a52c1617bde915a16fTimo Sirainen struct auth_request_info *info = &request->request_info;
9315dd69233d554452df0c12bc57002d2042a8f4Timo Sirainen string_t *str;
9315dd69233d554452df0c12bc57002d2042a8f4Timo Sirainen
153de7823e64c67678b3fc95719c41a8ec5b864dTimo Sirainen str = t_str_new(512);
153de7823e64c67678b3fc95719c41a8ec5b864dTimo Sirainen str_printfa(str, "AUTH\t%u\t", request->id);
9315dd69233d554452df0c12bc57002d2042a8f4Timo Sirainen str_append_tabescaped(str, info->mech);
9315dd69233d554452df0c12bc57002d2042a8f4Timo Sirainen str_append(str, "\tservice=");
9315dd69233d554452df0c12bc57002d2042a8f4Timo Sirainen str_append_tabescaped(str, info->service);
153de7823e64c67678b3fc95719c41a8ec5b864dTimo Sirainen
9315dd69233d554452df0c12bc57002d2042a8f4Timo Sirainen if ((info->flags & AUTH_REQUEST_FLAG_SUPPORT_FINAL_RESP) != 0)
9315dd69233d554452df0c12bc57002d2042a8f4Timo Sirainen str_append(str, "\tfinal-resp-ok");
9315dd69233d554452df0c12bc57002d2042a8f4Timo Sirainen if ((info->flags & AUTH_REQUEST_FLAG_SECURED) != 0)
9315dd69233d554452df0c12bc57002d2042a8f4Timo Sirainen str_append(str, "\tsecured");
9315dd69233d554452df0c12bc57002d2042a8f4Timo Sirainen if ((info->flags & AUTH_REQUEST_FLAG_NO_PENALTY) != 0)
41bb0aa8e357876bc9a1916a37c9e3e78e5f8185Timo Sirainen str_append(str, "\tno-penalty");
538c58fc95200fcc5e91abdda8b912b574a2f968Timo Sirainen if ((info->flags & AUTH_REQUEST_FLAG_VALID_CLIENT_CERT) != 0)
538c58fc95200fcc5e91abdda8b912b574a2f968Timo Sirainen str_append(str, "\tvalid-client-cert");
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen if (info->session_id != NULL) {
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen str_append(str, "\tsession=");
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen str_append_tabescaped(str, info->session_id);
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen }
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen if (info->cert_username != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append(str, "\tcert_username=");
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen str_append_tabescaped(str, info->cert_username);
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen }
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen if (info->local_ip.family != 0)
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen str_printfa(str, "\tlip=%s", net_ip2addr(&info->local_ip));
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen if (info->remote_ip.family != 0)
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen str_printfa(str, "\trip=%s", net_ip2addr(&info->remote_ip));
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen if (info->local_port != 0)
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen str_printfa(str, "\tlport=%u", info->local_port);
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen if (info->remote_port != 0)
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen str_printfa(str, "\trport=%u", info->remote_port);
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen if (info->initial_resp_base64 != NULL) {
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen str_append(str, "\tresp=");
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen str_append_tabescaped(str, info->initial_resp_base64);
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen }
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen str_append_c(str, '\n');
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen if (o_stream_send(conn->output, str_data(str), str_len(str)) < 0)
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen i_error("Error sending request to auth server: %m");
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen}
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct auth_client_request *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenauth_client_request_new(struct auth_client *client,
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen const struct auth_request_info *request_info,
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen auth_request_callback_t *callback, void *context)
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen{
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen struct auth_client_request *request;
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen pool_t pool;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen pool = pool_alloconly_create("auth client request", 512);
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen request = p_new(pool, struct auth_client_request, 1);
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen request->pool = pool;
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen request->conn = client->conn;
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen request->request_info = *request_info;
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen request->request_info.mech = p_strdup(pool, request_info->mech);
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen request->request_info.service = p_strdup(pool, request_info->service);
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen request->request_info.session_id =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen p_strdup_empty(pool, request_info->session_id);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen request->request_info.cert_username =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen p_strdup_empty(pool, request_info->cert_username);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen request->request_info.initial_resp_base64 =
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen p_strdup_empty(pool, request_info->initial_resp_base64);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen request->callback = callback;
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen request->context = context;
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen request->id =
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen auth_server_connection_add_request(request->conn, request);
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen request->created = ioloop_time;
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen T_BEGIN {
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen auth_server_send_new_request(request->conn, request);
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen } T_END;
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen return request;
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen}
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainenvoid auth_client_request_continue(struct auth_client_request *request,
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen const char *data_base64)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen struct const_iovec iov[3];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *prefix;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen prefix = t_strdup_printf("CONT\t%u\t", request->id);
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen iov[0].iov_base = prefix;
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen iov[0].iov_len = strlen(prefix);
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen iov[1].iov_base = data_base64;
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen iov[1].iov_len = strlen(data_base64);
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen iov[2].iov_base = "\n";
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen iov[2].iov_len = 1;
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen if (o_stream_sendv(request->conn->output, iov, 3) < 0)
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen i_error("Error sending continue request to auth server: %m");
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen}
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainenstatic void ATTR_NULL(3, 4)
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainencall_callback(struct auth_client_request *request,
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen enum auth_request_status status,
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen const char *data_base64,
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen const char *const *args)
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen{
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen auth_request_callback_t *callback = request->callback;
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen if (status != AUTH_REQUEST_STATUS_CONTINUE)
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen request->callback = NULL;
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen callback(request, status, data_base64, args, request->context);
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen}
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenvoid auth_client_request_abort(struct auth_client_request **_request)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct auth_client_request *request = *_request;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *_request = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen auth_client_send_cancel(request->conn->client, request->id);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen call_callback(request, AUTH_REQUEST_STATUS_ABORT, NULL, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenunsigned int auth_client_request_get_id(struct auth_client_request *request)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return request->id;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
cd5ee8630497fdbd853ef588a858b4ef619a5e03Timo Sirainen
cd5ee8630497fdbd853ef588a858b4ef619a5e03Timo Sirainenunsigned int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenauth_client_request_get_server_pid(struct auth_client_request *request)
7394389230750c45b105cdefb5850c81cae8cdc0Timo Sirainen{
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen return request->conn->server_pid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenconst char *auth_client_request_get_cookie(struct auth_client_request *request)
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen{
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen return request->conn->cookie;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen}
03dbd273251103f745c08966f1809c02870390ffTimo Sirainen
9887c39c5ba429169389153ca99de49e084a73f0Timo Sirainenbool auth_client_request_is_aborted(struct auth_client_request *request)
03dbd273251103f745c08966f1809c02870390ffTimo Sirainen{
03dbd273251103f745c08966f1809c02870390ffTimo Sirainen return request->callback == NULL;
03dbd273251103f745c08966f1809c02870390ffTimo Sirainen}
03dbd273251103f745c08966f1809c02870390ffTimo Sirainen
03dbd273251103f745c08966f1809c02870390ffTimo Sirainentime_t auth_client_request_get_create_time(struct auth_client_request *request)
d7095f3a4466fbb78b2d5eb3d322bc15a5b0ab1fTimo Sirainen{
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return request->created;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen}
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainenvoid auth_client_request_server_input(struct auth_client_request *request,
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen enum auth_request_status status,
d7095f3a4466fbb78b2d5eb3d322bc15a5b0ab1fTimo Sirainen const char *const *args)
e6d7d19c328e7043ad35d5a52c1617bde915a16fTimo Sirainen{
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen const char *const *tmp, *base64_data = NULL;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (request->callback == NULL) {
41bb0aa8e357876bc9a1916a37c9e3e78e5f8185Timo Sirainen /* aborted already */
41bb0aa8e357876bc9a1916a37c9e3e78e5f8185Timo Sirainen return;
41bb0aa8e357876bc9a1916a37c9e3e78e5f8185Timo Sirainen }
567e57b09a49bbb2a146b13f8617698eb56237feTimo Sirainen
567e57b09a49bbb2a146b13f8617698eb56237feTimo Sirainen switch (status) {
567e57b09a49bbb2a146b13f8617698eb56237feTimo Sirainen case AUTH_REQUEST_STATUS_OK:
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen for (tmp = args; *tmp != NULL; tmp++) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (strncmp(*tmp, "resp=", 5) == 0) {
53238473bf77147660aa6db9daa68a8a685e9381Timo Sirainen base64_data = *tmp + 5;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen break;
9315dd69233d554452df0c12bc57002d2042a8f4Timo Sirainen }
9315dd69233d554452df0c12bc57002d2042a8f4Timo Sirainen }
7889c9f65e23c83fc31cecf304cab4ab070d6aa1Timo Sirainen break;
7889c9f65e23c83fc31cecf304cab4ab070d6aa1Timo Sirainen case AUTH_REQUEST_STATUS_CONTINUE:
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen base64_data = args[0];
9315dd69233d554452df0c12bc57002d2042a8f4Timo Sirainen args = NULL;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen break;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen case AUTH_REQUEST_STATUS_FAIL:
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen case AUTH_REQUEST_STATUS_INTERNAL_FAIL:
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen case AUTH_REQUEST_STATUS_ABORT:
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen break;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen call_callback(request, status, base64_data, args);
abfcd9f73b9ad1eeef4fe6e9940383defabf68c3Timo Sirainen if (status != AUTH_REQUEST_STATUS_CONTINUE)
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen pool_unref(&request->pool);
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen}
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainenvoid auth_client_send_cancel(struct auth_client *client, unsigned int id)
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen{
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen const char *str = t_strdup_printf("CANCEL\t%u\n", id);
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen if (o_stream_send_str(client->conn->output, str) < 0)
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen i_error("Error sending request to auth server: %m");
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen}
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen