"Fossies" - the Fresh Open Source Software Archive 
Member "zorp-7.0.4/modules/smtp/smtpdata.cc" (28 Oct 2019, 10832 Bytes) of package /linux/privat/zorp-7.0.4.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "smtpdata.cc" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
7.0.1_vs_7.0.2.
1 /***************************************************************************
2 *
3 * Copyright (c) 2000-2015 BalaBit IT Ltd, Budapest, Hungary
4 * Copyright (c) 2015-2018 BalaSys IT Ltd, Budapest, Hungary
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 *
21 ***************************************************************************/
22
23 #include "smtp.h"
24 #include <zorp/proxy/transfer2.h>
25 #include <zorpll/log.h>
26
27 #define SMTP_SR_INITIAL 0
28 #define SMTP_SR_DATA 1
29
30 #define SMTP_DW_INITIAL 0
31 #define SMTP_DW_TRANSFER 3
32 #define SMTP_DW_TRANSFER_LF 4
33 #define SMTP_DW_TRANSFER_DOT 5
34 #define SMTP_DW_REJECTED 6
35
36 /**
37 * SmtpTransfer:
38 *
39 * An SMTP specific transfer class.
40 **/
41 struct _SmtpTransfer
42 {
43 ZTransfer2 super;
44 /* destination write state */
45 gint dst_write_state;
46
47 gint src_read_state;
48
49 GString *received_line;
50 guint received_line_pos;
51
52 /* The previous line was too long, it must be concatenated with the current line */
53 gboolean previous_line_split;
54 };
55
56 extern ZClass SmtpTransfer__class;
57
58 /**
59 * smtp_transfer_src_read:
60 * @s: ZTransfer instance
61 * @stream: stream to read from
62 * @buf: buffer to read into
63 * @buf_len: size of the buffer
64 * @bytes_read: the number of read bytes is returned here
65 * @err: GLib error code
66 *
67 * Reads the incoming data stream, checks for EOF (a single '.' on its own),
68 * removes '.' escaping and handles lines longer than the buffer size of ZStreamLine.
69 *
70 **/
71 static GIOStatus
72 smtp_transfer_src_read(ZTransfer2 *s, ZStream *stream, gchar *buf, gsize buf_len, gsize *bytes_read, GError **err)
73 {
74 SmtpTransfer *self = Z_CAST(s, SmtpTransfer);
75 SmtpProxy *owner = Z_CAST(self->super.owner, SmtpProxy);
76 GIOStatus res;
77 gsize line_len = buf_len - 2; /* to make space to closing CR LF */
78
79 if (G_UNLIKELY(self->src_read_state == SMTP_SR_INITIAL))
80 {
81 if (owner->add_received_header)
82 {
83 if (self->received_line == NULL)
84 {
85 if (!smtp_generate_received(owner, &self->received_line))
86 self->src_read_state = SMTP_SR_DATA;
87 }
88
89 if (self->received_line)
90 {
91 *bytes_read = MIN(buf_len, self->received_line->len - self->received_line_pos);
92 memmove(buf, self->received_line->str + self->received_line_pos, *bytes_read);
93 self->received_line_pos += *bytes_read;
94
95 if (self->received_line_pos >= self->received_line->len)
96 {
97 self->src_read_state = SMTP_SR_DATA;
98 }
99 return G_IO_STATUS_NORMAL;
100 }
101 }
102 else
103 {
104 self->src_read_state = SMTP_SR_DATA;
105 }
106 }
107
108 if (buf_len < 2)
109 {
110 return G_IO_STATUS_AGAIN;
111 }
112
113 res = z_stream_line_get_copy(stream, buf, &line_len, err);
114 if (res == G_IO_STATUS_NORMAL)
115 {
116 if (!self->previous_line_split && line_len > 0 && buf[0] == '.')
117 {
118 if (line_len == 1)
119 {
120 return G_IO_STATUS_EOF;
121 }
122 else
123 {
124 /* strip off first dot */
125 memmove(buf, &buf[1], line_len - 1);
126 line_len = line_len - 1;
127 }
128 }
129 buf[line_len] = '\r';
130 buf[line_len+1] = '\n';
131 *bytes_read = line_len + 2;
132 self->previous_line_split = FALSE;
133 }
134 else if (res == G_IO_STATUS_AGAIN && line_len > 0)
135 {
136 /* streamline indicates that the line was too long, do not add EOL */
137 *bytes_read = line_len;
138 self->previous_line_split = TRUE;
139 res = G_IO_STATUS_NORMAL;
140 }
141 return res;
142 }
143
144 /**
145 * smtp_transfer_dst_write:
146 * @s: ZTransfer instance
147 * @stream: stream to write to
148 * @buf: buffer to read into
149 * @count: buffer size
150 * @bytes_read: number of bytes returned
151 * @err: GLib error
152 *
153 * This function handles the data stream as it comes out of the stacked
154 * proxy. It takes care about prefixing the mail body with a "DATA" command,
155 * and through complicated means also takes care about fetching the response
156 * to it. When this is successful it takes care about sending the data
157 * stream reescaping unescaped lines beginning with '.'.
158 **/
159 static GIOStatus
160 smtp_transfer_dst_write(ZTransfer2 *s, ZStream *stream, const gchar *buf, gsize count, gsize *bytes_written, GError **err)
161 {
162 SmtpTransfer *self = Z_CAST(s, SmtpTransfer);
163 GIOStatus res;
164 GError *local_error = NULL;
165 gsize bw;
166 gsize i;
167
168 *bytes_written = 0;
169 if (self->dst_write_state == SMTP_DW_INITIAL)
170 {
171 z_transfer2_suspend(s, SMTP_TRANSFER_SUSPEND_DATA);
172 self->dst_write_state = SMTP_DW_TRANSFER;
173 return G_IO_STATUS_AGAIN;
174 }
175
176 transfer_state:
177
178 if (self->dst_write_state == SMTP_DW_TRANSFER || self->dst_write_state == SMTP_DW_TRANSFER_LF)
179 {
180 for (i = *bytes_written; i < count; i++)
181 {
182 if (self->dst_write_state == SMTP_DW_TRANSFER)
183 {
184 if (buf[i] == '\n')
185 {
186 self->dst_write_state = SMTP_DW_TRANSFER_LF;
187 }
188 }
189 else if (self->dst_write_state == SMTP_DW_TRANSFER_LF)
190 {
191 if (buf[i] == '.')
192 {
193 /* we need to escape this '.' */
194
195 /* first, write buf up to this '.' */
196 res = z_stream_write(stream, buf + *bytes_written, i - *bytes_written, &bw, &local_error);
197 if (res == G_IO_STATUS_NORMAL && (i - *bytes_written) == bw)
198 {
199 *bytes_written += bw;
200 self->dst_write_state = SMTP_DW_TRANSFER_DOT;
201 break;
202 }
203 else
204 {
205 /* we wrote less bytes, go back to the original state */
206 self->dst_write_state = SMTP_DW_TRANSFER;
207 *bytes_written += bw;
208 if (local_error)
209 g_propagate_error(err, local_error);
210 return res;
211 }
212 }
213 self->dst_write_state = SMTP_DW_TRANSFER;
214 }
215 }
216 if (i == count)
217 {
218 /* no need to escape */
219 res = z_stream_write(stream, buf + *bytes_written, count - *bytes_written, &bw, err);
220 *bytes_written += bw;
221 return res;
222 }
223 }
224 if (self->dst_write_state == SMTP_DW_TRANSFER_DOT)
225 {
226 res = z_stream_write(stream, ".", 1, &bw, &local_error);
227 if (res == G_IO_STATUS_NORMAL && bw == 1)
228 {
229 self->dst_write_state = SMTP_DW_TRANSFER;
230 goto transfer_state;
231 }
232 if (local_error)
233 g_propagate_error(err, local_error);
234 return res;
235 }
236
237 /* server responded non-354 to the DATA command */
238 return G_IO_STATUS_ERROR;
239 }
240
241 /**
242 * smtp_transfer_dst_shutdown:
243 * @s: ZTransfer instance
244 * @stream: stream to shut down
245 * @shutdown_mode: shutdown mode
246 * @err: GLib error
247 *
248 * This function is called when the server side stream is to be shut down. It takes care
249 * about ending the mail body with a '.', or
250 **/
251 static GIOStatus
252 smtp_transfer_dst_shutdown(ZTransfer2 *s, ZStream *stream, GError **err)
253 {
254 gsize bytes_written;
255 GError *local_error = NULL;
256 GIOStatus res = G_IO_STATUS_NORMAL;
257 SmtpTransfer *self = Z_CAST(s, SmtpTransfer);
258
259 if (self->dst_write_state != SMTP_DW_INITIAL)
260 {
261 res = z_stream_write(stream, "\r\n.\r\n", 5, &bytes_written, &local_error);
262 }
263 if (local_error)
264 g_propagate_error(err, local_error);
265 return res;
266 }
267
268 static gboolean
269 smtp_transfer_stack_proxy(ZTransfer2 *s, ZStackedProxy **stacked)
270 {
271 SmtpProxy *owner = Z_CAST(s->owner, SmtpProxy);
272 ZPolicyObj *stacked_proxy;
273 gboolean called;
274 gboolean success = TRUE;
275
276 z_policy_lock(owner->super.thread);
277 stacked_proxy = z_policy_call(owner->super.handler,
278 "requestStack",
279 NULL,
280 &called,
281 owner->super.session_id);
282 if (!stacked_proxy)
283 success = FALSE;
284 else if (stacked_proxy != z_policy_none)
285 {
286 success = z_proxy_stack_object(&owner->super, stacked_proxy, stacked, NULL);
287 }
288
289 if (!success)
290 z_proxy_report_policy_abort(&owner->super);
291
292 z_policy_var_unref(stacked_proxy);
293 z_policy_unlock(owner->super.thread);
294 return success;
295
296 }
297
298 static gboolean
299 smtp_transfer_setup(ZTransfer2 *s)
300 {
301 z_stream_line_set_split(s->endpoints[EP_CLIENT], TRUE);
302 z_stream_line_set_truncate(s->endpoints[EP_CLIENT], FALSE);
303 return TRUE;
304 }
305
306 static gboolean
307 smtp_transfer_progress(ZTransfer2 *s)
308 {
309 SmtpTransfer *self = Z_CAST(s, SmtpTransfer);
310
311 if (self->dst_write_state == SMTP_DW_INITIAL)
312 z_transfer2_suspend(s, SMTP_TRANSFER_SUSPEND_NOOP);
313 return TRUE;
314 }
315
316 static void
317 smtp_transfer_free_method(ZObject *s)
318 {
319 SmtpTransfer *self = Z_CAST(s, SmtpTransfer);
320
321 if (self->received_line)
322 g_string_free(self->received_line, TRUE);
323 z_transfer2_free_method(s);
324 }
325
326 ZTransfer2Funcs smtp_transfer_funcs =
327 {
328 {
329 Z_FUNCS_COUNT(ZTransfer2),
330 smtp_transfer_free_method,
331 },
332 smtp_transfer_src_read,
333 smtp_transfer_dst_write,
334 NULL,
335 smtp_transfer_dst_shutdown,
336 smtp_transfer_stack_proxy,
337 /* .setup = */ smtp_transfer_setup,
338 /* .run = */ NULL,
339 /* .progress = */ smtp_transfer_progress
340 };
341
342 Z_CLASS_DEF(SmtpTransfer, ZTransfer2, smtp_transfer_funcs);
343
344 /**
345 * smtp_transfer_new:
346 * @self: SmtpProxy instance
347 *
348 * This function is an Smtp specific constructor for the ZTransfer2 class.
349 *
350 * Returns: ZTransfer2 instance
351 **/
352 ZTransfer2 *
353 smtp_transfer_new(SmtpProxy *owner)
354 {
355 SmtpTransfer *self;
356
357 self = Z_CAST(z_transfer2_new(Z_CLASS(SmtpTransfer), &owner->super, owner->poll,
358 owner->super.endpoints[EP_CLIENT], owner->super.endpoints[EP_SERVER],
359 owner->buffer_size, owner->timeout,
360 ZT2F_COMPLETE_COPY),
361 SmtpTransfer);
362 z_transfer2_set_content_format(&self->super, "email");
363 z_transfer2_enable_progress(&self->super, owner->interval_transfer_noop);
364 return &self->super;
365 }