pop3-proxy.c revision 0745a5190c95a5ca80f7ff32e4db8e429dc2a03f
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (C) 2004 Timo Sirainen */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "common.h"
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen#include "ioloop.h"
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen#include "istream.h"
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen#include "ostream.h"
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen#include "base64.h"
105addcb709523868418cc3e3baad7ad3453a91eTimo Sirainen#include "safe-memset.h"
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen#include "str.h"
105addcb709523868418cc3e3baad7ad3453a91eTimo Sirainen#include "client.h"
105addcb709523868418cc3e3baad7ad3453a91eTimo Sirainen#include "pop3-proxy.h"
e0f4fbf127b192667c62af7875c4f2ca294b6c7aTimo Sirainen
e0f4fbf127b192667c62af7875c4f2ca294b6c7aTimo Sirainenstatic void proxy_input(struct istream *input, struct ostream *output,
e0f4fbf127b192667c62af7875c4f2ca294b6c7aTimo Sirainen void *context)
e0f4fbf127b192667c62af7875c4f2ca294b6c7aTimo Sirainen{
e0f4fbf127b192667c62af7875c4f2ca294b6c7aTimo Sirainen struct pop3_client *client = context;
e0f4fbf127b192667c62af7875c4f2ca294b6c7aTimo Sirainen string_t *str;
e0f4fbf127b192667c62af7875c4f2ca294b6c7aTimo Sirainen const char *line;
e0f4fbf127b192667c62af7875c4f2ca294b6c7aTimo Sirainen
e0f4fbf127b192667c62af7875c4f2ca294b6c7aTimo Sirainen if (input == NULL) {
e0f4fbf127b192667c62af7875c4f2ca294b6c7aTimo Sirainen if (client->io != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* remote authentication failed, we're just
105addcb709523868418cc3e3baad7ad3453a91eTimo Sirainen freeing the proxy */
105addcb709523868418cc3e3baad7ad3453a91eTimo Sirainen return;
105addcb709523868418cc3e3baad7ad3453a91eTimo Sirainen }
105addcb709523868418cc3e3baad7ad3453a91eTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* failed for some reason */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_destroy_internal_failure(client);
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen return;
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen }
105addcb709523868418cc3e3baad7ad3453a91eTimo Sirainen
49d4afbb76f47c8904537d087bc81e43f1c0aa25Timo Sirainen switch (i_stream_read(input)) {
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen case -2:
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen /* buffer full */
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen i_error("pop-proxy(%s): Remote input buffer full",
b44faf865da16ac4d18eecd85a55b3fab6b9e63aTimo Sirainen client->common.virtual_user);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_destroy_internal_failure(client);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case -1:
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen /* disconnected */
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen client_destroy(client, "Proxy: Remote disconnected");
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen return;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen line = i_stream_next_line(input);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (line == NULL)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen return;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if (client->proxy_user != NULL) {
c5794838af9995f50bfecb06a3cd4f9a0ac77858Timo Sirainen /* this is a banner */
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (strncmp(line, "+OK", 3) != 0) {
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen i_error("pop3-proxy(%s): "
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen "Remote returned invalid banner: %s",
651fc0f1e43fef3e02e0e7b5f498973b05f641d7Timo Sirainen client->common.virtual_user, line);
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen client_destroy_internal_failure(client);
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen return;
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen /* send USER command */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str = t_str_new(128);
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen str_append(str, "USER ");
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen str_append(str, client->proxy_user);
041d312b44f8d41f0c9a5762c23e4d146ef7302bTimo Sirainen str_append(str, "\r\n");
041d312b44f8d41f0c9a5762c23e4d146ef7302bTimo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(client->proxy_user);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->proxy_user = NULL;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen } else if (strncmp(line, "+OK", 3) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (client->proxy_password != NULL) {
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen /* USER successful, send PASS */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str = t_str_new(128);
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen str_append(str, "PASS ");
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen str_append(str, client->proxy_password);
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen str_append(str, "\r\n");
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen (void)o_stream_send(output, str_data(str),
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen str_len(str));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen safe_memset(client->proxy_password, 0,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen strlen(client->proxy_password));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(client->proxy_password);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->proxy_password = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Login successful. Send this line to client. */
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen (void)o_stream_send_str(client->output, line);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen (void)o_stream_send(client->output, "\r\n", 2);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen login_proxy_detach(client->proxy, client->input,
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen client->output);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen client->proxy = NULL;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen client->input = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->output = NULL;
659fe5d24825b160cae512538088020d97a60239Timo Sirainen client->common.fd = -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_destroy(client,
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen t_strdup_printf("proxy(%s): started",
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen client->common.virtual_user));
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen }
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Login failed. Send our own failure reply so client can't
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen figure out if user exists or not just by looking at the
659fe5d24825b160cae512538088020d97a60239Timo Sirainen reply string. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_send_line(client, "-ERR "AUTH_FAILED_MSG);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen /* allow client input again */
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen i_assert(client->io == NULL);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen client->io = io_add(client->common.fd, IO_READ,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen client_input, client);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen login_proxy_free(client->proxy);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen client->proxy = NULL;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen }
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenint pop3_proxy_new(struct pop3_client *client, const char *host,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int port, const char *user, const char *password)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen i_assert(user != NULL);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if (password == NULL) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen i_error("proxy(%s): password not given",
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen client->common.virtual_user);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen return -1;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen }
a928e7efabb1672b1476e597106d4b4b81ac6f3cTimo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen client->proxy = login_proxy_new(&client->common, host, port,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen proxy_input, client);
838f56174b963779a88083a0d0e85b30d2d846e7Timo Sirainen if (client->proxy == NULL)
894987bf45718f8849cc3898afdfb1ac3cfa2445Timo Sirainen return -1;
894987bf45718f8849cc3898afdfb1ac3cfa2445Timo Sirainen
894987bf45718f8849cc3898afdfb1ac3cfa2445Timo Sirainen client->proxy_user = i_strdup(user);
838f56174b963779a88083a0d0e85b30d2d846e7Timo Sirainen client->proxy_password = i_strdup(password);
838f56174b963779a88083a0d0e85b30d2d846e7Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen /* disable input until authentication is finished */
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen if (client->io != NULL) {
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen io_remove(client->io);
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen client->io = NULL;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return 0;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen}
838f56174b963779a88083a0d0e85b30d2d846e7Timo Sirainen