|
tss@2733
|
1 |
/* Copyright (C) 2002-2004 Timo Sirainen */
|
|
tss@2733
|
2 |
|
|
tss@2733
|
3 |
#include "common.h"
|
|
tss@2733
|
4 |
#include "base64.h"
|
|
tss@2733
|
5 |
#include "buffer.h"
|
|
tss@2733
|
6 |
#include "str-sanitize.h"
|
|
tss@2733
|
7 |
#include "auth-client.h"
|
|
tss@2733
|
8 |
#include "ssl-proxy.h"
|
|
tss@2733
|
9 |
#include "client-common.h"
|
|
tss@2733
|
10 |
#include "master.h"
|
|
tss@2733
|
11 |
|
|
tss@2736
|
12 |
static enum auth_request_flags
|
|
tss@2733
|
13 |
client_get_auth_flags(struct client *client)
|
|
tss@2733
|
14 |
{
|
|
tss@2736
|
15 |
enum auth_request_flags auth_flags = 0;
|
|
tss@2733
|
16 |
|
|
tss@2733
|
17 |
if (client->proxy != NULL &&
|
|
tss@2733
|
18 |
ssl_proxy_has_valid_client_cert(client->proxy))
|
|
tss@2736
|
19 |
auth_flags |= AUTH_REQUEST_FLAG_VALID_CLIENT_CERT;
|
|
tss@2736
|
20 |
if (client->secured)
|
|
tss@2736
|
21 |
auth_flags |= AUTH_REQUEST_FLAG_SECURED;
|
|
tss@2733
|
22 |
return auth_flags;
|
|
tss@2733
|
23 |
}
|
|
tss@2733
|
24 |
|
|
tss@5070
|
25 |
static void
|
|
tss@5070
|
26 |
call_client_callback(struct client *client, enum sasl_server_reply reply,
|
|
tss@5070
|
27 |
const char *data, const char *const *args)
|
|
tss@5070
|
28 |
{
|
|
tss@5070
|
29 |
sasl_server_callback_t *sasl_callback;
|
|
tss@5070
|
30 |
|
|
tss@5070
|
31 |
i_assert(reply != SASL_SERVER_REPLY_CONTINUE);
|
|
tss@5070
|
32 |
|
|
tss@5070
|
33 |
sasl_callback = client->sasl_callback;
|
|
tss@5070
|
34 |
client->sasl_callback = NULL;
|
|
tss@5070
|
35 |
|
|
tss@5070
|
36 |
sasl_callback(client, reply, data, args);
|
|
tss@5070
|
37 |
/* NOTE: client may be destroyed now */
|
|
tss@5070
|
38 |
}
|
|
tss@5070
|
39 |
|
|
tss@3863
|
40 |
static void master_callback(struct client *client, bool success)
|
|
tss@2733
|
41 |
{
|
|
tss@2733
|
42 |
client->authenticating = FALSE;
|
|
tss@5070
|
43 |
call_client_callback(client, success ? SASL_SERVER_REPLY_SUCCESS :
|
|
tss@5070
|
44 |
SASL_SERVER_REPLY_MASTER_FAILED, NULL, NULL);
|
|
tss@2733
|
45 |
}
|
|
tss@2733
|
46 |
|
|
tss@2736
|
47 |
static void authenticate_callback(struct auth_request *request, int status,
|
|
tss@2736
|
48 |
const char *data_base64,
|
|
tss@2736
|
49 |
const char *const *args, void *context)
|
|
tss@2733
|
50 |
{
|
|
tss@2733
|
51 |
struct client *client = context;
|
|
tss@2766
|
52 |
unsigned int i;
|
|
tss@3863
|
53 |
bool nologin;
|
|
tss@2733
|
54 |
|
|
tss@2733
|
55 |
if (!client->authenticating) {
|
|
tss@2733
|
56 |
/* client aborted */
|
|
tss@2736
|
57 |
i_assert(status < 0);
|
|
tss@2733
|
58 |
return;
|
|
tss@2733
|
59 |
}
|
|
tss@2733
|
60 |
|
|
tss@4952
|
61 |
i_assert(client->auth_request == request);
|
|
tss@5216
|
62 |
client->waiting_auth_reply = FALSE;
|
|
tss@5216
|
63 |
|
|
tss@2736
|
64 |
switch (status) {
|
|
tss@2736
|
65 |
case 0:
|
|
tss@2736
|
66 |
/* continue */
|
|
tss@2733
|
67 |
client->sasl_callback(client, SASL_SERVER_REPLY_CONTINUE,
|
|
tss@2766
|
68 |
data_base64, NULL);
|
|
tss@2733
|
69 |
break;
|
|
tss@2736
|
70 |
case 1:
|
|
tss@2733
|
71 |
client->auth_request = NULL;
|
|
tss@2733
|
72 |
|
|
tss@2766
|
73 |
nologin = FALSE;
|
|
tss@2766
|
74 |
for (i = 0; args[i] != NULL; i++) {
|
|
tss@2766
|
75 |
if (strncmp(args[i], "user=", 5) == 0) {
|
|
tss@2736
|
76 |
i_free(client->virtual_user);
|
|
tss@2766
|
77 |
client->virtual_user = i_strdup(args[i] + 5);
|
|
tss@2766
|
78 |
}
|
|
tss@4783
|
79 |
if (strcmp(args[i], "nologin") == 0 ||
|
|
tss@4783
|
80 |
strcmp(args[i], "proxy") == 0) {
|
|
tss@2766
|
81 |
/* user can't login */
|
|
tss@2766
|
82 |
nologin = TRUE;
|
|
tss@2736
|
83 |
}
|
|
tss@2736
|
84 |
}
|
|
tss@2733
|
85 |
|
|
tss@2766
|
86 |
if (nologin) {
|
|
tss@2766
|
87 |
client->authenticating = FALSE;
|
|
tss@5070
|
88 |
call_client_callback(client, SASL_SERVER_REPLY_SUCCESS,
|
|
tss@5070
|
89 |
NULL, args);
|
|
tss@2766
|
90 |
} else {
|
|
tss@2766
|
91 |
master_request_login(client, master_callback,
|
|
tss@2733
|
92 |
auth_client_request_get_server_pid(request),
|
|
tss@2733
|
93 |
auth_client_request_get_id(request));
|
|
tss@2766
|
94 |
}
|
|
tss@2733
|
95 |
break;
|
|
tss@2736
|
96 |
case -1:
|
|
tss@2733
|
97 |
client->auth_request = NULL;
|
|
tss@2733
|
98 |
|
|
tss@2768
|
99 |
if (args != NULL) {
|
|
tss@2772
|
100 |
/* parse our username if it's there */
|
|
tss@2768
|
101 |
for (i = 0; args[i] != NULL; i++) {
|
|
tss@2768
|
102 |
if (strncmp(args[i], "user=", 5) == 0) {
|
|
tss@2768
|
103 |
i_free(client->virtual_user);
|
|
tss@2768
|
104 |
client->virtual_user =
|
|
tss@2768
|
105 |
i_strdup(args[i] + 5);
|
|
tss@2768
|
106 |
}
|
|
tss@2768
|
107 |
}
|
|
tss@2768
|
108 |
}
|
|
tss@2768
|
109 |
|
|
tss@2766
|
110 |
client->authenticating = FALSE;
|
|
tss@5070
|
111 |
call_client_callback(client, SASL_SERVER_REPLY_AUTH_FAILED,
|
|
tss@5070
|
112 |
NULL, args);
|
|
tss@2733
|
113 |
break;
|
|
tss@2733
|
114 |
}
|
|
tss@2733
|
115 |
}
|
|
tss@2733
|
116 |
|
|
tss@2733
|
117 |
void sasl_server_auth_begin(struct client *client,
|
|
tss@2781
|
118 |
const char *service, const char *mech_name,
|
|
tss@2736
|
119 |
const char *initial_resp_base64,
|
|
tss@2733
|
120 |
sasl_server_callback_t *callback)
|
|
tss@2733
|
121 |
{
|
|
tss@2733
|
122 |
struct auth_request_info info;
|
|
tss@2733
|
123 |
const struct auth_mech_desc *mech;
|
|
tss@2733
|
124 |
const char *error;
|
|
tss@2733
|
125 |
|
|
tss@2733
|
126 |
client->authenticating = TRUE;
|
|
tss@2766
|
127 |
i_free(client->auth_mech_name);
|
|
tss@4768
|
128 |
client->auth_mech_name = str_ucase(i_strdup(mech_name));
|
|
tss@2733
|
129 |
client->sasl_callback = callback;
|
|
tss@2733
|
130 |
|
|
tss@2733
|
131 |
mech = auth_client_find_mech(auth_client, mech_name);
|
|
tss@2733
|
132 |
if (mech == NULL) {
|
|
tss@5449
|
133 |
sasl_server_auth_failed(client,
|
|
tss@2733
|
134 |
"Unsupported authentication mechanism.");
|
|
tss@2733
|
135 |
return;
|
|
tss@2733
|
136 |
}
|
|
tss@2733
|
137 |
|
|
tss@2736
|
138 |
if (!client->secured && disable_plaintext_auth &&
|
|
tss@2736
|
139 |
(mech->flags & MECH_SEC_PLAINTEXT) != 0) {
|
|
tss@5449
|
140 |
sasl_server_auth_failed(client,
|
|
tss@4311
|
141 |
"Plaintext authentication disabled.");
|
|
tss@2733
|
142 |
return;
|
|
tss@2733
|
143 |
}
|
|
tss@2733
|
144 |
|
|
tss@2733
|
145 |
memset(&info, 0, sizeof(info));
|
|
tss@2733
|
146 |
info.mech = mech->name;
|
|
tss@2781
|
147 |
info.service = service;
|
|
tss@3635
|
148 |
info.cert_username = client->proxy == NULL ? NULL :
|
|
tss@3635
|
149 |
ssl_proxy_get_peer_name(client->proxy);
|
|
tss@2733
|
150 |
info.flags = client_get_auth_flags(client);
|
|
tss@2733
|
151 |
info.local_ip = client->local_ip;
|
|
tss@2733
|
152 |
info.remote_ip = client->ip;
|
|
tss@2736
|
153 |
info.initial_resp_base64 = initial_resp_base64;
|
|
tss@2733
|
154 |
|
|
tss@2733
|
155 |
client->auth_request =
|
|
tss@2733
|
156 |
auth_client_request_new(auth_client, NULL, &info,
|
|
tss@2733
|
157 |
authenticate_callback, client, &error);
|
|
tss@2733
|
158 |
if (client->auth_request == NULL) {
|
|
tss@4311
|
159 |
sasl_server_auth_failed(client,
|
|
tss@2733
|
160 |
t_strconcat("Authentication failed: ", error, NULL));
|
|
tss@2733
|
161 |
}
|
|
tss@2733
|
162 |
}
|
|
tss@2733
|
163 |
|
|
tss@4311
|
164 |
static void sasl_server_auth_cancel(struct client *client, const char *reason,
|
|
tss@4311
|
165 |
enum sasl_server_reply reply)
|
|
tss@2733
|
166 |
{
|
|
tss@4991
|
167 |
i_assert(client->authenticating);
|
|
tss@4991
|
168 |
|
|
tss@2733
|
169 |
if (verbose_auth && reason != NULL) {
|
|
tss@3384
|
170 |
const char *auth_name =
|
|
tss@3384
|
171 |
str_sanitize(client->auth_mech_name, MAX_MECH_NAME);
|
|
tss@3384
|
172 |
client_syslog(client,
|
|
tss@3384
|
173 |
t_strdup_printf("Authenticate %s failed: %s",
|
|
tss@3384
|
174 |
auth_name, reason));
|
|
tss@2733
|
175 |
}
|
|
tss@2733
|
176 |
|
|
tss@2733
|
177 |
client->authenticating = FALSE;
|
|
tss@5217
|
178 |
client->waiting_auth_reply = FALSE;
|
|
tss@2733
|
179 |
|
|
tss@2733
|
180 |
if (client->auth_request != NULL) {
|
|
tss@2733
|
181 |
auth_client_request_abort(client->auth_request);
|
|
tss@2733
|
182 |
client->auth_request = NULL;
|
|
tss@2733
|
183 |
}
|
|
tss@2733
|
184 |
|
|
tss@5070
|
185 |
call_client_callback(client, reply, reason, NULL);
|
|
tss@2733
|
186 |
}
|
|
tss@4311
|
187 |
|
|
tss@4311
|
188 |
void sasl_server_auth_failed(struct client *client, const char *reason)
|
|
tss@4311
|
189 |
{
|
|
tss@4311
|
190 |
sasl_server_auth_cancel(client, reason, SASL_SERVER_REPLY_AUTH_FAILED);
|
|
tss@4311
|
191 |
}
|
|
tss@4311
|
192 |
|
|
tss@4311
|
193 |
void sasl_server_auth_client_error(struct client *client, const char *reason)
|
|
tss@4311
|
194 |
{
|
|
tss@4311
|
195 |
sasl_server_auth_cancel(client, reason, SASL_SERVER_REPLY_CLIENT_ERROR);
|
|
tss@4311
|
196 |
}
|