auth-worker-client.c revision d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "common.h"
49e358eebea107aad9919dcc4bd88cee8519ba2eTimo Sirainen#include "base64.h"
49e358eebea107aad9919dcc4bd88cee8519ba2eTimo Sirainen#include "ioloop.h"
49e358eebea107aad9919dcc4bd88cee8519ba2eTimo Sirainen#include "network.h"
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#include "istream.h"
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include "ostream.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "str.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "master-service.h"
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen#include "auth-request.h"
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen#include "auth-worker-client.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
da2aa032ccfa8e7e4a4380ef738014549f4d2c2dTimo Sirainen#include <stdlib.h>
da2aa032ccfa8e7e4a4380ef738014549f4d2c2dTimo Sirainen
411d6baa37f31d90730e90c4a28c43e1974bbe58Timo Sirainen#define OUTBUF_THROTTLE_SIZE (1024*10)
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainenstruct auth_worker_client {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen int refcount;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct auth *auth;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen int fd;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen struct io *io;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen struct istream *input;
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen struct ostream *output;
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen};
09801f106cd531a28b4e03ec665e44c421264560Timo Sirainen
09801f106cd531a28b4e03ec665e44c421264560Timo Sirainenstatic void
09801f106cd531a28b4e03ec665e44c421264560Timo Sirainenauth_worker_client_check_throttle(struct auth_worker_client *client)
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (o_stream_get_buffer_used_size(client->output) >=
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen OUTBUF_THROTTLE_SIZE) {
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen /* stop reading new requests until client has read the pending
10c96a244935de4add8213ba0b894178dfb889a5Timo Sirainen replies. */
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen if (client->io != NULL)
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen io_remove(&client->io);
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen }
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen}
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainenstatic struct auth_request *
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenworker_auth_request_new(struct auth_worker_client *client, unsigned int id,
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen const char *args)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen{
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen struct auth_request *auth_request;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen const char *key, *value, *const *tmp;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen auth_request = auth_request_new_dummy(client->auth);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen client->refcount++;
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen auth_request->context = client;
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen auth_request->id = id;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (args != NULL) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen for (tmp = t_strsplit(args, "\t"); *tmp != NULL; tmp++) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen value = strchr(*tmp, '=');
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (value == NULL)
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen continue;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen key = t_strdup_until(*tmp, value);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen value++;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen (void)auth_request_import(auth_request, key, value);
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen }
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen }
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return auth_request;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void auth_worker_send_reply(struct auth_worker_client *client,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen string_t *str)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen{
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (shutdown_request)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen o_stream_send_str(client->output, "SHUTDOWN\n");
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen o_stream_send(client->output, str_data(str), str_len(str));
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen}
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainenstatic void verify_plain_callback(enum passdb_result result,
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen struct auth_request *request)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct auth_worker_client *client = request->context;
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen struct auth_stream_reply *reply;
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen string_t *str;
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen if (request->passdb_failure && result == PASSDB_RESULT_OK)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen result = PASSDB_RESULT_PASSWORD_MISMATCH;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (result == PASSDB_RESULT_OK)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen auth_stream_reply_add(reply, "OK", NULL);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen else {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen auth_stream_reply_add(reply, "FAIL", NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen auth_stream_reply_add(reply, NULL,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen t_strdup_printf("%d", result));
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (result != PASSDB_RESULT_INTERNAL_FAILURE) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen auth_stream_reply_add(reply, NULL, request->user);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen auth_stream_reply_add(reply, NULL,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen request->passdb_password == NULL ? "" :
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen request->passdb_password);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (request->extra_fields != NULL) {
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen const char *fields =
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen auth_stream_reply_export(request->extra_fields);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen auth_stream_reply_import(reply, fields);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen }
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen if (request->extra_cache_fields != NULL) {
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen const char *fields =
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen auth_stream_reply_export(request->extra_cache_fields);
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen auth_stream_reply_import(reply, fields);
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen }
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen }
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen str = auth_stream_reply_get_str(reply);
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen str_append_c(str, '\n');
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen auth_worker_send_reply(client, str);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen auth_request_unref(&request);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen auth_worker_client_check_throttle(client);
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen auth_worker_client_unref(&client);
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen}
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainenstatic void
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainenauth_worker_handle_passv(struct auth_worker_client *client,
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen unsigned int id, const char *args)
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen{
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen /* verify plaintext password */
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen struct auth_request *auth_request;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen struct auth_passdb *passdb;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen const char *password;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen unsigned int passdb_id;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen passdb_id = atoi(t_strcut(args, '\t'));
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen args = strchr(args, '\t');
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen if (args == NULL) {
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen i_error("BUG: Auth worker server sent us invalid PASSV");
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen return;
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen }
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen args++;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen password = t_strcut(args, '\t');
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen args = strchr(args, '\t');
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen if (args != NULL) args++;
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen auth_request = worker_auth_request_new(client, id, args);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen auth_request->mech_password =
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen p_strdup(auth_request->pool, password);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
699fdc186f982f70d990820796eaa0f12133e27cTimo Sirainen i_error("BUG: PASSV had missing parameters");
699fdc186f982f70d990820796eaa0f12133e27cTimo Sirainen auth_request_unref(&auth_request);
699fdc186f982f70d990820796eaa0f12133e27cTimo Sirainen return;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen }
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen passdb = auth_request->passdb;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen while (passdb != NULL && passdb->id != passdb_id)
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen passdb = passdb->next;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen if (passdb == NULL) {
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen /* could be a masterdb */
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen passdb = auth_request->auth->masterdbs;
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen while (passdb != NULL && passdb->id != passdb_id)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen passdb = passdb->next;
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen if (passdb == NULL) {
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen i_error("BUG: PASSV had invalid passdb ID");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen auth_request_unref(&auth_request);
return;
}
}
auth_request->passdb = passdb;
passdb->passdb->iface.
verify_plain(auth_request, password, verify_plain_callback);
}
static void
lookup_credentials_callback(enum passdb_result result,
const unsigned char *credentials, size_t size,
struct auth_request *request)
{
struct auth_worker_client *client = request->context;
struct auth_stream_reply *reply;
string_t *str;
if (request->passdb_failure && result == PASSDB_RESULT_OK)
result = PASSDB_RESULT_PASSWORD_MISMATCH;
reply = auth_stream_reply_init(pool_datastack_create());
auth_stream_reply_add(reply, NULL, dec2str(request->id));
if (result != PASSDB_RESULT_OK) {
auth_stream_reply_add(reply, "FAIL", NULL);
auth_stream_reply_add(reply, NULL,
t_strdup_printf("%d", result));
} else {
auth_stream_reply_add(reply, "OK", NULL);
auth_stream_reply_add(reply, NULL, request->user);
str = t_str_new(64);
str_printfa(str, "{%s.b64}", request->credentials_scheme);
base64_encode(credentials, size, str);
auth_stream_reply_add(reply, NULL, str_c(str));
if (request->extra_fields != NULL) {
const char *fields =
auth_stream_reply_export(request->extra_fields);
auth_stream_reply_import(reply, fields);
}
if (request->extra_cache_fields != NULL) {
const char *fields =
auth_stream_reply_export(request->extra_cache_fields);
auth_stream_reply_import(reply, fields);
}
}
str = auth_stream_reply_get_str(reply);
str_append_c(str, '\n');
auth_worker_send_reply(client, str);
auth_request_unref(&request);
auth_worker_client_check_throttle(client);
auth_worker_client_unref(&client);
}
static void
auth_worker_handle_passl(struct auth_worker_client *client,
unsigned int id, const char *args)
{
/* lookup credentials */
struct auth_request *auth_request;
const char *scheme;
unsigned int passdb_id;
passdb_id = atoi(t_strcut(args, '\t'));
args = strchr(args, '\t');
if (args == NULL) {
i_error("BUG: Auth worker server sent us invalid PASSL");
return;
}
args++;
scheme = t_strcut(args, '\t');
args = strchr(args, '\t');
if (args != NULL) args++;
auth_request = worker_auth_request_new(client, id, args);
auth_request->credentials_scheme = p_strdup(auth_request->pool, scheme);
if (auth_request->user == NULL || auth_request->service == NULL) {
i_error("BUG: PASSL had missing parameters");
auth_request_unref(&auth_request);
return;
}
while (auth_request->passdb->id != passdb_id) {
auth_request->passdb = auth_request->passdb->next;
if (auth_request->passdb == NULL) {
i_error("BUG: PASSL had invalid passdb ID");
auth_request_unref(&auth_request);
return;
}
}
if (auth_request->passdb->passdb->iface.lookup_credentials == NULL) {
i_error("BUG: PASSL lookup not supported by given passdb");
auth_request_unref(&auth_request);
return;
}
auth_request->prefer_plain_credentials = TRUE;
auth_request->passdb->passdb->iface.
lookup_credentials(auth_request, lookup_credentials_callback);
}
static void
set_credentials_callback(bool success, struct auth_request *request)
{
struct auth_worker_client *client = request->context;
string_t *str;
str = t_str_new(64);
str_printfa(str, "%u\t%s\n", request->id, success ? "OK" : "FAIL");
auth_worker_send_reply(client, str);
auth_request_unref(&request);
auth_worker_client_check_throttle(client);
auth_worker_client_unref(&client);
}
static void
auth_worker_handle_setcred(struct auth_worker_client *client,
unsigned int id, const char *args)
{
struct auth_request *auth_request;
unsigned int passdb_id;
const char *data;
passdb_id = atoi(t_strcut(args, '\t'));
args = strchr(args, '\t');
if (args == NULL) {
i_error("BUG: Auth worker server sent us invalid SETCRED");
return;
}
args++;
data = t_strcut(args, '\t');
args = strchr(args, '\t');
if (args != NULL) args++;
auth_request = worker_auth_request_new(client, id, args);
if (auth_request->user == NULL || auth_request->service == NULL) {
i_error("BUG: SETCRED had missing parameters");
auth_request_unref(&auth_request);
return;
}
while (auth_request->passdb->id != passdb_id) {
auth_request->passdb = auth_request->passdb->next;
if (auth_request->passdb == NULL) {
i_error("BUG: SETCRED had invalid passdb ID");
auth_request_unref(&auth_request);
return;
}
}
auth_request->passdb->passdb->iface.
set_credentials(auth_request, data, set_credentials_callback);
}
static void
lookup_user_callback(enum userdb_result result,
struct auth_request *auth_request)
{
struct auth_worker_client *client = auth_request->context;
struct auth_stream_reply *reply = auth_request->userdb_reply;
string_t *str;
if (auth_request->userdb_lookup_failed)
result = USERDB_RESULT_INTERNAL_FAILURE;
str = t_str_new(128);
str_printfa(str, "%u\t", auth_request->id);
switch (result) {
case USERDB_RESULT_INTERNAL_FAILURE:
str_append(str, "FAIL\t");
break;
case USERDB_RESULT_USER_UNKNOWN:
str_append(str, "NOTFOUND\t");
break;
case USERDB_RESULT_OK:
str_append(str, "OK\t");
str_append(str, auth_stream_reply_export(reply));
break;
}
str_append_c(str, '\n');
auth_worker_send_reply(client, str);
auth_request_unref(&auth_request);
auth_worker_client_check_throttle(client);
auth_worker_client_unref(&client);
}
static void
auth_worker_handle_user(struct auth_worker_client *client,
unsigned int id, const char *args)
{
/* lookup user */
struct auth_request *auth_request;
unsigned int num;
num = atoi(t_strcut(args, '\t'));
args = strchr(args, '\t');
if (args != NULL) args++;
auth_request = worker_auth_request_new(client, id, args);
if (auth_request->user == NULL || auth_request->service == NULL) {
i_error("BUG: USER had missing parameters");
auth_request_unref(&auth_request);
return;
}
for (; num > 0; num--) {
auth_request->userdb = auth_request->userdb->next;
if (auth_request->userdb == NULL) {
i_error("BUG: USER had invalid userdb num");
auth_request_unref(&auth_request);
return;
}
}
auth_request->userdb->userdb->iface->
lookup(auth_request, lookup_user_callback);
}
static bool
auth_worker_handle_line(struct auth_worker_client *client, const char *line)
{
const char *p;
unsigned int id;
p = strchr(line, '\t');
if (p == NULL)
return FALSE;
id = (unsigned int)strtoul(t_strdup_until(line, p), NULL, 10);
line = p + 1;
if (strncmp(line, "PASSV\t", 6) == 0)
auth_worker_handle_passv(client, id, line + 6);
else if (strncmp(line, "PASSL\t", 6) == 0)
auth_worker_handle_passl(client, id, line + 6);
else if (strncmp(line, "SETCRED\t", 8) == 0)
auth_worker_handle_setcred(client, id, line + 8);
else if (strncmp(line, "USER\t", 5) == 0)
auth_worker_handle_user(client, id, line + 5);
return TRUE;
}
static void auth_worker_input(struct auth_worker_client *client)
{
char *line;
bool ret;
switch (i_stream_read(client->input)) {
case 0:
return;
case -1:
/* disconnected */
auth_worker_client_destroy(&client);
return;
case -2:
/* buffer full */
i_error("BUG: Auth worker server sent us more than %d bytes",
(int)AUTH_WORKER_MAX_LINE_LENGTH);
auth_worker_client_destroy(&client);
return;
}
client->refcount++;
while ((line = i_stream_next_line(client->input)) != NULL) {
T_BEGIN {
ret = auth_worker_handle_line(client, line);
} T_END;
if (!ret) {
auth_worker_client_destroy(&client);
break;
}
}
auth_worker_client_unref(&client);
}
static int auth_worker_output(struct auth_worker_client *client)
{
if (o_stream_flush(client->output) < 0) {
auth_worker_client_destroy(&client);
return 1;
}
if (o_stream_get_buffer_used_size(client->output) <=
OUTBUF_THROTTLE_SIZE/3 && client->io == NULL) {
/* allow input again */
client->io = io_add(client->fd, IO_READ,
auth_worker_input, client);
}
return 1;
}
struct auth_worker_client *
auth_worker_client_create(struct auth *auth, int fd)
{
struct auth_worker_client *client;
client = i_new(struct auth_worker_client, 1);
client->refcount = 1;
client->auth = auth;
client->fd = fd;
client->input = i_stream_create_fd(fd, AUTH_WORKER_MAX_LINE_LENGTH,
FALSE);
client->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
o_stream_set_flush_callback(client->output, auth_worker_output, client);
client->io = io_add(fd, IO_READ, auth_worker_input, client);
return client;
}
void auth_worker_client_destroy(struct auth_worker_client **_client)
{
struct auth_worker_client *client = *_client;
*_client = NULL;
if (client->fd == -1)
return;
i_stream_close(client->input);
o_stream_close(client->output);
if (client->io != NULL)
io_remove(&client->io);
net_disconnect(client->fd);
client->fd = -1;
master_service_client_connection_destroyed(service);
}
void auth_worker_client_unref(struct auth_worker_client **_client)
{
struct auth_worker_client *client = *_client;
if (--client->refcount > 0) {
*_client = NULL;
return;
}
if (client->fd != -1)
auth_worker_client_destroy(_client);
i_stream_unref(&client->input);
o_stream_unref(&client->output);
i_free(client);
}