1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "login-common.h"
#include "str.h"
#include "strescape.h"
#include "base64.h"
#include "net.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "master-service.h"
#include "auth-client.h"
#include "client-common.h"
#include "imap-urlauth-login-settings.h"
#define IMAP_URLAUTH_PROTOCOL_MAJOR_VERSION 2
#define IMAP_URLAUTH_PROTOCOL_MINOR_VERSION 0
struct imap_urlauth_client {
struct client common;
const struct imap_urlauth_login_settings *set;
bool version_received:1;
};
static void
imap_urlauth_client_auth_result(struct client *client,
enum client_auth_result result,
const struct client_auth_reply *reply ATTR_UNUSED,
const char *text ATTR_UNUSED)
{
if (result != CLIENT_AUTH_RESULT_SUCCESS) {
/* failed or otherwise invalid status */
client_send_raw(client, "FAILED\n");
client_destroy(client, "Authentication failed");
} else {
/* authentication succeeded */
}
}
static void imap_urlauth_client_handle_input(struct client *client)
{
#define AUTH_ARG_COUNT 6
struct imap_urlauth_client *uauth_client =
(struct imap_urlauth_client *)client;
struct net_unix_cred cred;
const char *line;
const char *const *args;
pid_t pid;
if (!uauth_client->version_received) {
if ((line = i_stream_next_line(client->input)) == NULL)
return;
if (!version_string_verify(line, "imap-urlauth",
IMAP_URLAUTH_PROTOCOL_MAJOR_VERSION)) {
e_error(client->event,
"IMAP URLAUTH client not compatible with this server "
"(mixed old and new binaries?) %s", line);
client_destroy(client, "Version mismatch");
return;
}
uauth_client->version_received = TRUE;
}
if ((line = i_stream_next_line(client->input)) == NULL)
return;
/* read authentication info from input;
"AUTH"\t<service>\t<session-pid>\t<auth-username>\t<session_id>\t<token> */
args = t_strsplit_tabescaped(line);
if (str_array_length(args) < AUTH_ARG_COUNT ||
strcmp(args[0], "AUTH") != 0 || str_to_pid(args[2], &pid) < 0) {
e_error(client->event,
"IMAP URLAUTH client sent unexpected AUTH input: %s", line);
client_destroy(client, "Unexpected input");
return;
}
/* only imap and submission have direct access to urlauth service */
if (strcmp(args[1], "imap") != 0 && strcmp(args[1], "submission") != 0) {
e_error(client->event,
"IMAP URLAUTH accessed from inappropriate service: %s", args[1]);
client_destroy(client, "Unexpected input");
return;
}
/* verify session pid if possible */
if (net_getunixcred(client->fd, &cred) == 0 &&
cred.pid != (pid_t)-1 && pid != cred.pid) {
e_error(client->event,
"IMAP URLAUTH client sent invalid session pid %ld in AUTH request: "
"it did not match peer credentials (pid=%ld, uid=%ld)",
(long)pid, (long)cred.pid, (long)cred.uid);
client_destroy(client, "Invalid AUTH request");
return;
}
T_BEGIN {
string_t *auth_data = t_str_new(128);
string_t *init_resp;
unsigned int i;
str_append(auth_data, args[1]);
for (i = 2; i < AUTH_ARG_COUNT; i++) {
str_append_c(auth_data, '\0');
str_append(auth_data, args[i]);
}
init_resp = t_str_new(256);
base64_encode(str_data(auth_data),
str_len(auth_data), init_resp);
(void)client_auth_begin_private(client, "DOVECOT-TOKEN",
str_c(init_resp));
} T_END;
}
static void imap_urlauth_client_input(struct client *client)
{
if (!client_read(client))
return;
client_ref(client);
o_stream_cork(client->output);
if (!auth_client_is_connected(auth_client)) {
/* we're not currently connected to auth process -
don't allow any commands */
timeout_remove(&client->to_auth_waiting);
client->input_blocked = TRUE;
} else {
imap_urlauth_client_handle_input(client);
}
o_stream_uncork(client->output);
client_unref(&client);
}
static struct client *imap_urlauth_client_alloc(pool_t pool)
{
struct imap_urlauth_client *uauth_client;
uauth_client = p_new(pool, struct imap_urlauth_client, 1);
return &uauth_client->common;
}
static void imap_urlauth_client_create
(struct client *client, void **other_sets)
{
struct imap_urlauth_client *uauth_client =
(struct imap_urlauth_client *)client;
uauth_client->set = other_sets[0];
client->io = io_add_istream(client->input, client_input, client);
}
static void imap_urlauth_login_preinit(void)
{
login_set_roots = imap_urlauth_login_setting_roots;
}
static void imap_urlauth_login_init(void)
{
}
static void imap_urlauth_login_deinit(void)
{
clients_destroy_all();
}
static struct client_vfuncs imap_urlauth_vfuncs = {
.alloc = imap_urlauth_client_alloc,
.create = imap_urlauth_client_create,
.input = imap_urlauth_client_input,
.auth_result = imap_urlauth_client_auth_result,
.send_raw_data = client_common_send_raw_data,
.free = client_common_default_free,
};
static struct login_binary imap_urlauth_login_binary = {
.protocol = "imap-urlauth",
.process_name = "imap-urlauth-login",
.default_login_socket = LOGIN_TOKEN_DEFAULT_SOCKET,
.event_category = {
.name = "imap",
},
.client_vfuncs = &imap_urlauth_vfuncs,
.preinit = imap_urlauth_login_preinit,
.init = imap_urlauth_login_init,
.deinit = imap_urlauth_login_deinit,
.anonymous_login_acceptable = TRUE,
};
int main(int argc, char *argv[])
{
return login_binary_run(&imap_urlauth_login_binary, argc, argv);
}
|