auth-worker-client.c revision 3c9828bc22054744d740925fc9519d02ecb89184
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned int id;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic void auth_worker_input(struct auth_worker_client *client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic int auth_worker_output(struct auth_worker_client *client);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainenauth_worker_client_check_throttle(struct auth_worker_client *client)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (o_stream_get_buffer_used_size(client->output) >=
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* stop reading new requests until client has read the pending
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenworker_auth_request_new(struct auth_worker_client *client, unsigned int id,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen const char *const *args)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen (void)auth_request_import(auth_request, key, value);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic void auth_worker_send_reply(struct auth_worker_client *client,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen o_stream_send_str(client->output, "SHUTDOWN\n");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen o_stream_send(client->output, str_data(str), str_len(str));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic void verify_plain_callback(enum passdb_result result,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct auth_worker_client *client = request->context;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (request->passdb_failure && result == PASSDB_RESULT_OK)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
1f85b15e9bfabc5ee390d2cddcfa347a33af8689Timo Sirainen if (result != PASSDB_RESULT_INTERNAL_FAILURE) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_stream_reply_add(reply, NULL, request->user);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen const char *fields =
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen auth_stream_reply_export(request->extra_fields);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const char *fields =
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_stream_reply_export(request->extra_cache_fields);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenauth_worker_handle_passv(struct auth_worker_client *client,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* verify plaintext password */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* <passdb id> <password> [<args>] */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (str_to_uint(args[0], &passdb_id) < 0 || args[1] == NULL) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_error("BUG: Auth worker server sent us invalid PASSV");
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen auth_request = worker_auth_request_new(client, id, args + 2);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen while (passdb != NULL && passdb->passdb->id != passdb_id)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* could be a masterdb */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen passdb = auth_request_get_auth(auth_request)->masterdbs;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen while (passdb != NULL && passdb->passdb->id != passdb_id)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen verify_plain(auth_request, password, verify_plain_callback);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenlookup_credentials_callback(enum passdb_result result,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen const unsigned char *credentials, size_t size,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_worker_client *client = request->context;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (request->passdb_failure && result == PASSDB_RESULT_OK)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_stream_reply_add(reply, NULL, request->user);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_printfa(str, "{%s.b64}", request->credentials_scheme);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_stream_reply_add(reply, NULL, str_c(str));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen const char *fields =
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_stream_reply_export(request->extra_fields);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen const char *fields =
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_stream_reply_export(request->extra_cache_fields);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainenauth_worker_handle_passl(struct auth_worker_client *client,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* lookup credentials */
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen /* <passdb id> <scheme> [<args>] */
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (str_to_uint(args[0], &passdb_id) < 0 || args[1] == NULL) {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen i_error("BUG: Auth worker server sent us invalid PASSL");
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen auth_request = worker_auth_request_new(client, id, args + 2);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen auth_request->credentials_scheme = p_strdup(auth_request->pool, scheme);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen while (auth_request->passdb->passdb->id != passdb_id) {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen auth_request->passdb = auth_request->passdb->next;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (auth_request->passdb->passdb->iface.lookup_credentials == NULL) {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen i_error("BUG: PASSL lookup not supported by given passdb");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_request->prefer_plain_credentials = TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen lookup_credentials(auth_request, lookup_credentials_callback);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenset_credentials_callback(bool success, struct auth_request *request)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct auth_worker_client *client = request->context;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen str_printfa(str, "%u\t%s\n", request->id, success ? "OK" : "FAIL");
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainenauth_worker_handle_setcred(struct auth_worker_client *client,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* <passdb id> <credentials> [<args>] */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (str_to_uint(args[0], &passdb_id) < 0 || args[1] == NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("BUG: Auth worker server sent us invalid SETCRED");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_request = worker_auth_request_new(client, id, args + 2);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("BUG: SETCRED had missing parameters");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen while (auth_request->passdb->passdb->id != passdb_id) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_request->passdb = auth_request->passdb->next;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("BUG: SETCRED had invalid passdb ID");
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen set_credentials(auth_request, creds, set_credentials_callback);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenlookup_user_callback(enum userdb_result result,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_worker_client *client = auth_request->context;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct auth_stream_reply *reply = auth_request->userdb_reply;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen value = auth_stream_reply_find(reply, "reason");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_append(str, auth_stream_reply_export(reply));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic struct auth_userdb *
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainenauth_userdb_find_by_id(struct auth_userdb *userdbs, unsigned int id)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen for (db = userdbs; db != NULL; db = db->next) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenauth_worker_handle_user(struct auth_worker_client *client,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* lookup user */
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen /* <userdb id> [<args>] */
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen i_error("BUG: Auth worker server sent us invalid USER");
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen auth_request = worker_auth_request_new(client, id, args + 1);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen auth_userdb_find_by_id(auth_request->userdb, userdb_id);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainenstatic void list_iter_deinit(struct auth_worker_list_context *ctx)
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen struct auth_worker_client *client = ctx->client;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (ctx->userdb->iface->iterate_deinit(ctx->iter) < 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen client->io = io_add(client->fd, IO_READ, auth_worker_input, client);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen o_stream_set_flush_callback(client->output, auth_worker_output, client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic void list_iter_callback(const char *user, void *context)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_worker_list_context *ctx = context;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_printfa(str, "%u\t*\t%s\n", ctx->id, user);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen o_stream_send(ctx->client->output, str_data(str), str_len(str));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* avoid recursively looping to this same function */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen o_stream_get_buffer_used_size(ctx->client->output) == 0);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic int auth_worker_list_output(struct auth_worker_list_context *ctx)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if ((ret = o_stream_flush(ctx->client->output)) < 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenauth_worker_handle_list(struct auth_worker_client *client,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("BUG: Auth worker server sent us invalid LIST");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen userdb = auth_userdb_find_by_id(client->auth->userdbs, userdb_id);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx = i_new(struct auth_worker_list_context, 1);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen o_stream_set_flush_callback(ctx->client->output,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen iterate_init(userdb->userdb, list_iter_callback, ctx);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenauth_worker_handle_line(struct auth_worker_client *client, const char *line)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen const char *const *args;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned int id;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (args[0] == NULL || args[1] == NULL || args[2] == NULL ||
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = auth_worker_handle_passv(client, id, args + 2);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = auth_worker_handle_passl(client, id, args + 2);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = auth_worker_handle_setcred(client, id, args + 2);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = auth_worker_handle_user(client, id, args + 2);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = auth_worker_handle_list(client, id, args + 2);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("BUG: Auth-worker received unknown command: %s",
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic bool auth_worker_verify_db_hash(const char *line)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen binary_to_hex_append(str, passdb_md5, sizeof(passdb_md5));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen binary_to_hex_append(str, userdb_md5, sizeof(userdb_md5));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic void auth_worker_input(struct auth_worker_client *client)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* disconnected */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* buffer full */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("BUG: Auth worker server sent us more than %d bytes",
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (strncmp(line, "VERSION\tauth-worker\t", 20) != 0 ||
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("Auth worker not compatible with this server "
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "(mixed old and new binaries?)");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("Auth worker sees different passdbs/userdbs "
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "than auth server. Maybe config just changed "
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "and this goes away automatically?");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen while ((line = i_stream_next_line(client->input)) != NULL) {
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainenstatic int auth_worker_output(struct auth_worker_client *client)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (o_stream_get_buffer_used_size(client->output) <=
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen OUTBUF_THROTTLE_SIZE/3 && client->io == NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* allow input again */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenauth_worker_client_create(struct auth *auth, int fd)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen client->input = i_stream_create_fd(fd, AUTH_WORKER_MAX_LINE_LENGTH,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen client->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen o_stream_set_flush_callback(client->output, auth_worker_output, client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen client->io = io_add(fd, IO_READ, auth_worker_input, client);