Testsuite: tidy removed testcase files
[exim.git] / src / src / auths / get_data.c
CommitLineData
0756eb3c
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
f9ba5e22 5/* Copyright (c) University of Cambridge 1995 - 2018 */
0756eb3c
PH
6/* See the file NOTICE for conditions of use and distribution. */
7
8#include "../exim.h"
9
10
37942ad8
JH
11/****************************************************************
12* Decode and split the argument of an AUTH command *
13****************************************************************/
14
15/* If data was supplied on the AUTH command, decode it, and split it up into
16multiple items at binary zeros. The strings are put into $auth1, $auth2, etc,
17up to a maximum. To retain backwards compatibility, they are also put int $1,
18$2, etc. If the data consists of the string "=" it indicates a single, empty
19string. */
20
21int
22auth_read_input(const uschar * data)
23{
24if (Ustrcmp(data, "=") == 0)
25 {
26 auth_vars[0] = expand_nstring[++expand_nmax] = US"";
27 expand_nlength[expand_nmax] = 0;
28 }
29else
30 {
31 uschar * clear, * end;
32 int len;
33
34 if ((len = b64decode(data, &clear)) < 0) return BAD64;
35 DEBUG(D_auth) debug_printf("auth input decode:");
36 for (end = clear + len; clear < end && expand_nmax < EXPAND_MAXN; )
37 {
38 DEBUG(D_auth) debug_printf(" '%s'", clear);
39 if (expand_nmax < AUTH_VARS) auth_vars[expand_nmax] = clear;
40 expand_nstring[++expand_nmax] = clear;
41 while (*clear != 0) clear++;
42 expand_nlength[expand_nmax] = clear++ - expand_nstring[expand_nmax];
43 }
44 DEBUG(D_auth) debug_printf("\n");
45 }
46return OK;
47}
48
49
50
51
0756eb3c
PH
52/*************************************************
53* Issue a challenge and get a response *
54*************************************************/
55
56/* This function is used by authentication drivers to output a challenge
57to the SMTP client and read the response line.
58
59Arguments:
60 aptr set to point to the response (which is in big_buffer)
61 challenge the challenge text (unencoded, may be binary)
62 challen the length of the challenge text
63
64Returns: OK on success
65 BAD64 if response too large for buffer
66 CANCELLED if response is "*"
67*/
68
69int
37942ad8 70auth_get_data(uschar ** aptr, const uschar * challenge, int challen)
0756eb3c
PH
71{
72int c;
73int p = 0;
925ac8e4 74smtp_printf("334 %s\r\n", FALSE, b64encode(challenge, challen));
bd8fbe36 75while ((c = receive_getc(GETC_BUFFER_UNLIMITED)) != '\n' && c != EOF)
0756eb3c
PH
76 {
77 if (p >= big_buffer_size - 1) return BAD64;
78 big_buffer[p++] = c;
79 }
80if (p > 0 && big_buffer[p-1] == '\r') p--;
81big_buffer[p] = 0;
898d150f 82DEBUG(D_receive) debug_printf("SMTP<< %s\n", big_buffer);
0756eb3c
PH
83if (Ustrcmp(big_buffer, "*") == 0) return CANCELLED;
84*aptr = big_buffer;
85return OK;
86}
87
37942ad8
JH
88
89
90int
91auth_prompt(const uschar * challenge)
92{
93int rc, len;
94uschar * resp, * clear, * end;
95
96if ((rc = auth_get_data(&resp, challenge, Ustrlen(challenge))) != OK)
97 return rc;
98if ((len = b64decode(resp, &clear)) < 0)
99 return BAD64;
100end = clear + len;
101
102/* This loop must run at least once, in case the length is zero */
103do
104 {
105 if (expand_nmax < AUTH_VARS) auth_vars[expand_nmax] = clear;
106 expand_nstring[++expand_nmax] = clear;
107 while (*clear != 0) clear++;
108 expand_nlength[expand_nmax] = clear++ - expand_nstring[expand_nmax];
109 }
110while (clear < end && expand_nmax < EXPAND_MAXN);
111return OK;
112}
113
114
115/***********************************************
116* Send an AUTH-negotiation item *
117************************************************/
118
119/* Expand and send one client auth item and read the response.
120Include the AUTH command and method if tagged as "first". Use the given buffer
121for receiving the b6-encoded reply; decode it it return it in the string arg.
122
123Return:
124 OK success
125 FAIL_SEND error after writing a command; errno is set
126 FAIL failed after reading a response;
127 either errno is set (for timeouts, I/O failures) or
128 the buffer contains the SMTP response line
129 CANCELLED the client cancelled authentication (often "fail" in expansion)
130 the buffer may contain a message; if not, *buffer = 0
131 ERROR local problem (typically expansion error); message in buffer
132 DEFER more items expected
133*/
134
135int
136auth_client_item(void * sx, auth_instance * ablock, const uschar ** inout,
137 unsigned flags, int timeout, uschar * buffer, int buffsize)
138{
139int len, clear_len;
140uschar * ss, * clear;
141
142ss = US expand_cstring(*inout);
143if (ss == *inout) ss = string_copy(ss);
144
145/* Forced expansion failure is not an error; authentication is abandoned. On
146all but the first string, we have to abandon the authentication attempt by
147sending a line containing "*". Save the failed expansion string, because it
148is in big_buffer, and that gets used by the sending function. */
149
150if (!ss)
151 {
152 if (!(flags & AUTH_ITEM_FIRST))
153 {
154 if (smtp_write_command(sx, SCMD_FLUSH, "*\r\n") >= 0)
155 (void) smtp_read_response(sx, US buffer, buffsize, '2', timeout);
156 }
157 if (f.expand_string_forcedfail)
158 {
159 *buffer = 0; /* No message */
160 return CANCELLED;
161 }
162 string_format(buffer, buffsize, "expansion of \"%s\" failed in %s "
163 "authenticator: %s", *inout, ablock->name, expand_string_message);
164 return ERROR;
165 }
166
167len = Ustrlen(ss);
168
169/* The character ^ is used as an escape for a binary zero character, which is
170needed for the PLAIN mechanism. It must be doubled if really needed. */
171
172for (int i = 0; i < len; i++)
173 if (ss[i] == '^')
174 if (ss[i+1] != '^')
175 ss[i] = 0;
176 else
177 {
178 i++;
179 len--;
180 memmove(ss + i, ss + i + 1, len - i);
181 }
182
183/* The first string is attached to the AUTH command; others are sent
184unembellished. */
185
186if (flags & AUTH_ITEM_FIRST)
187 {
188 if (smtp_write_command(sx, SCMD_FLUSH, "AUTH %s%s%s\r\n",
189 ablock->public_name, len == 0 ? "" : " ", b64encode(CUS ss, len)) < 0)
190 return FAIL_SEND;
191 }
192else
193 if (smtp_write_command(sx, SCMD_FLUSH, "%s\r\n", b64encode(CUS ss, len)) < 0)
194 return FAIL_SEND;
195
196/* If we receive a success response from the server, authentication
197has succeeded. There may be more data to send, but is there any point
198in provoking an error here? */
199
200if (smtp_read_response(sx, US buffer, buffsize, '2', timeout))
201 {
202 *inout = NULL;
203 return OK;
204 }
205
206/* Not a success response. If errno != 0 there is some kind of transmission
207error. Otherwise, check the response code in the buffer. If it starts with
208'3', more data is expected. */
209
210if (errno != 0 || buffer[0] != '3') return FAIL;
211
212/* If there is no more data to send, we have to cancel the authentication
213exchange and return ERROR. */
214
215if (flags & AUTH_ITEM_LAST)
216 {
217 if (smtp_write_command(sx, SCMD_FLUSH, "*\r\n") >= 0)
218 (void)smtp_read_response(sx, US buffer, buffsize, '2', timeout);
219 string_format(buffer, buffsize, "Too few items in client_send in %s "
220 "authenticator", ablock->name);
221 return ERROR;
222 }
223
224/* Now that we know we'll continue, we put the received data into $auth<n>,
225if possible. First, decode it: buffer+4 skips over the SMTP status code. */
226
227clear_len = b64decode(buffer+4, &clear);
228
229/* If decoding failed, the default is to terminate the authentication, and
230return FAIL, with the SMTP response still in the buffer. However, if client_
231ignore_invalid_base64 is set, we ignore the error, and put an empty string
232into $auth<n>. */
233
234if (clear_len < 0)
235 {
236 uschar *save_bad = string_copy(buffer);
237 if (!(flags & AUTH_ITEM_IGN64))
238 {
239 if (smtp_write_command(sx, SCMD_FLUSH, "*\r\n") >= 0)
240 (void)smtp_read_response(sx, US buffer, buffsize, '2', timeout);
241 string_format(buffer, buffsize, "Invalid base64 string in server "
242 "response \"%s\"", save_bad);
243 return CANCELLED;
244 }
245 DEBUG(D_auth) debug_printf("bad b64 decode for '%s';"
246 " ignoring due to client_ignore_invalid_base64\n", save_bad);
247 clear = string_copy(US"");
248 clear_len = 0;
249 }
250
251*inout = clear;
252return DEFER;
253}
254
255
0756eb3c 256/* End of get_data.c */