1 /*
2 ** Line by line reading support from sockets/pipes.
3 **
4 ** Written by Alex Kiernan <alex.kiernan@thus.net>.
5 **
6 ** This code implements an infinitely (well size_t) long single line
7 ** read routine. To protect against eating all available memory, it
8 ** actually starts discarding characters if you try to send more than
9 ** the maximum article size in a single line.
10 **
11 */
12
13 #include "portable/system.h"
14
15 #include <assert.h>
16 #ifdef HAVE_SYS_SELECT_H
17 # include <sys/select.h>
18 #endif
19
20 #include "inn/messages.h"
21 #include "nnrpd.h"
22 #include "tls.h"
23 #include <signal.h>
24
25
26 /*
27 ** Free a previously allocated line structure.
28 */
29 void
line_free(struct line * line)30 line_free(struct line *line)
31 {
32 static const struct line nullline = {0, 0, 0, 0};
33
34 if (line && line->start) {
35 free(line->start);
36 *line = nullline;
37 }
38 }
39
40 #ifdef HAVE_OPENSSL
41 /*
42 ** Alarm signal handler for client timeout.
43 */
44 static void
alarmHandler(int s UNUSED)45 alarmHandler(int s UNUSED)
46 {
47 /* Send the close_notify shutdown alert to the news reader.
48 * No need to call again SSL_shutdown() to complete the bidirectional
49 * shutdown handshake as we do not expect more data to process. Just
50 * close the underlying connection without waiting for the response.
51 * Such a unidirectional shutdown is allowed per OpenSSL documentation. */
52 SSL_shutdown(tls_conn);
53 tls_conn = NULL;
54 errno = ECONNRESET;
55 }
56 #endif
57
58 /*
59 ** Initialise a new line structure.
60 */
61 void
line_init(struct line * line)62 line_init(struct line *line)
63 {
64 assert(line);
65 line->allocated = NNTP_MAXLEN_COMMAND;
66 line->where = line->start = xmalloc(line->allocated);
67 line->remaining = 0;
68 }
69
70 /*
71 ** Reset a line structure.
72 */
73 void
line_reset(struct line * line)74 line_reset(struct line *line)
75 {
76 assert(line);
77 line->where = line->start;
78 line->remaining = 0;
79 }
80
81 /*
82 ** Timeout is used only if HAVE_OPENSSL is defined.
83 ** Returns -2 on timeout, -1 on read error, and otherwise the number of
84 ** bytes read.
85 */
86 static ssize_t
line_doread(void * p,size_t len,int timeout UNUSED)87 line_doread(void *p, size_t len, int timeout UNUSED)
88 {
89 ssize_t n;
90
91 do {
92 #if defined(HAVE_ZLIB)
93 /* Process data that may already be available in the zlib buffer. */
94 if (compression_layer_on
95 && (zstream_in->avail_in > 0 || zstream_inflate_needed)) {
96 int r;
97
98 zstream_in->next_out = p;
99 zstream_in->avail_out = len;
100
101 r = inflate(zstream_in, Z_SYNC_FLUSH);
102
103 if (!(r == Z_OK || r == Z_BUF_ERROR || r == Z_STREAM_END)) {
104 sysnotice("inflate() failed: %d; %s", r,
105 zstream_in->msg != NULL ? zstream_in->msg
106 : "no detail");
107 n = -1;
108 break;
109 }
110
111 /* Check whether inflate() has finished to process its input.
112 * If not, we need to call it again, even though avail_in is 0. */
113 zstream_inflate_needed = (r != Z_STREAM_END);
114
115 if (zstream_in->avail_out < len) {
116 /* Some data has been uncompressed. Treat it now. */
117 n = len - zstream_in->avail_out;
118 break;
119 }
120 /* If we reach here, then it means that inflate() needs more
121 * input, so we go on reading data on the wire. */
122 }
123 #endif /* HAVE_ZLIB */
124
125 #ifdef HAVE_OPENSSL
126 if (tls_conn) {
127 int err;
128 xsignal(SIGALRM, alarmHandler);
129 do {
130 alarm(timeout);
131 n = SSL_read(tls_conn, p, len);
132 alarm(0);
133 if (tls_conn == NULL) {
134 n = -2; /* timeout */
135 break;
136 }
137 err = SSL_get_error(tls_conn, n);
138 switch (err) {
139 case SSL_ERROR_ZERO_RETURN:
140 SSL_shutdown(tls_conn);
141 goto fallthrough;
142 case SSL_ERROR_SYSCALL:
143 case SSL_ERROR_SSL:
144 fallthrough:
145 /* SSL_shutdown() must not be called. */
146 tls_conn = NULL;
147 errno = ECONNRESET;
148 n = -1;
149 break;
150 }
151 } while (err == SSL_ERROR_WANT_READ);
152 xsignal(SIGALRM, SIG_DFL);
153 } else
154 #endif /* HAVE_OPENSSL */
155 do {
156 n = read(STDIN_FILENO, p, len);
157 } while (n == -1 && errno == EINTR);
158
159 if (n <= 0)
160 break; /* EOF or error. */
161
162 #if defined(HAVE_SASL)
163 if (sasl_conn != NULL && sasl_ssf > 0) {
164 /* Security layer in place, decode the data.
165 * The incoming data is always encoded in chunks of length
166 * inferior or equal to NNTP_MAXLEN_COMMAND (the maxbufsize value
167 * of SASL_SEC_PROPS passed as part of the SASL exchange).
168 * So there's enough data to read in the p buffer. */
169 const char *out;
170 unsigned outlen;
171 int r;
172
173 if ((r = sasl_decode(sasl_conn, p, n, &out, &outlen)) == SASL_OK) {
174 if (outlen > len) {
175 sysnotice("sasl_decode() returned too much output");
176 n = -1;
177 } else {
178 if (outlen > 0) {
179 memcpy(p, out, outlen);
180 }
181 n = outlen;
182 }
183 } else {
184 const char *ed = sasl_errdetail(sasl_conn);
185
186 sysnotice("sasl_decode() failed: %s; %s",
187 sasl_errstring(r, NULL, NULL),
188 ed != NULL ? ed : "no detail");
189 n = -1;
190 }
191 }
192 #endif /* HAVE_SASL */
193
194 #if defined(HAVE_ZLIB)
195 if (compression_layer_on && n > 0) {
196 size_t zconsumed;
197
198 if (zstream_in->avail_in > 0 && zstream_in->next_in != Z_NULL) {
199 zconsumed = zstream_in->next_in - zbuf_in;
200 } else {
201 zconsumed = 0;
202 zbuf_in_allocated = 0;
203 }
204
205 /* Transfer the data we have just read to zstream_in,
206 * and loop to actually process it. */
207 if ((ssize_t)(zbuf_in_size - zbuf_in_allocated) < n) {
208 size_t newsize = zbuf_in_size * 2 + n;
209
210 /* Don't grow the buffer bigger than the maximum
211 * article size we'll accept. */
212 if (PERMaccessconf->localmaxartsize > NNTP_MAXLEN_COMMAND) {
213 if (newsize > PERMaccessconf->localmaxartsize) {
214 newsize = PERMaccessconf->localmaxartsize;
215 }
216 }
217 if (newsize == zbuf_in_size) {
218 warn("%s overflowed our zstream_in buffer (%lu)",
219 Client.host, (unsigned long) newsize);
220 n = -1;
221 break;
222 }
223 zbuf_in = xrealloc(zbuf_in, newsize);
224 zbuf_in_size = newsize;
225 }
226 memcpy(zbuf_in + zbuf_in_allocated, p, n);
227 zstream_in->next_in = zbuf_in + zconsumed;
228 zstream_in->avail_in += n;
229 zbuf_in_allocated += n;
230 zstream_inflate_needed = true;
231 /* Loop to actually inflate the compressed data we received. */
232 n = 0;
233 }
234 #endif /* HAVE_ZLIB */
235 } while (n == 0); /* Split SASL blob, need to read more data. */
236
237 return n;
238 }
239
240 READTYPE
line_read(struct line * line,int timeout,const char ** p,size_t * len,size_t * stripped)241 line_read(struct line *line, int timeout, const char **p, size_t *len,
242 size_t *stripped)
243 {
244 char *where;
245 char *lf = NULL;
246 READTYPE r = RTok;
247
248 assert(line != NULL);
249 assert(line->start != NULL);
250 /* Shuffle any trailing portion not yet processed to the start of
251 * the buffer. */
252 if (line->remaining != 0) {
253 if (line->start != line->where) {
254 memmove(line->start, line->where, line->remaining);
255 }
256 lf = memchr(line->start, '\n', line->remaining);
257 }
258 where = line->start + line->remaining;
259
260 /* If we found a line terminator in the data we have, we don't need
261 * to ask for any more. */
262 if (lf == NULL) {
263 do {
264 fd_set rmask;
265 int i;
266 ssize_t count;
267
268 /* If we've filled the line buffer, double the size,
269 * reallocate the buffer and try again. */
270 if (where == line->start + line->allocated) {
271 size_t newsize = line->allocated * 2;
272
273 /* Don't grow the buffer bigger than the maximum
274 * article size we'll accept. */
275 if (PERMaccessconf->localmaxartsize > NNTP_MAXLEN_COMMAND)
276 if (newsize > PERMaccessconf->localmaxartsize)
277 newsize = PERMaccessconf->localmaxartsize;
278
279 /* If we're trying to grow from the same size, to the
280 * same size, we must have hit the localmaxartsize
281 * buffer for a second (or subsequent) time -- the user
282 * is likely trying to DOS us, so don't double the
283 * size any more, just overwrite characters until they
284 * stop, then discard the whole thing. */
285 if (newsize == line->allocated) {
286 warn("%s overflowed our line buffer (%lu), "
287 "discarding further input",
288 Client.host, PERMaccessconf->localmaxartsize);
289 where = line->start;
290 r = RTlong;
291 } else {
292 line->start = xrealloc(line->start, newsize);
293 where = line->start + line->allocated;
294 line->allocated = newsize;
295 }
296 }
297
298 #ifdef HAVE_OPENSSL
299 /* It seems that the SSL_read cannot be mixed with select()
300 * as in the current code. SSL communicates in its own data
301 * blocks and hand shaking. The do_readline using SSL_read
302 * could return, but still with a partial line in the SSL_read
303 * buffer. Then the server SSL routine would sit there waiting
304 * for completion of that data block while nnrpd sat at the
305 * select() routine waiting for more data from the server.
306 *
307 * Here, we decide to just bypass the select() wait. Unlike
308 * innd with multiple threads, the select on nnrpd is just
309 * waiting on a single file descriptor, so it is not really
310 * essential with blocked read like SSL_read. Using an alarm
311 * signal around SSL_read for non active timeout, SSL works
312 * without dead locks. However, without the select() wait,
313 * the IDLE timer stat won't be collected...
314 */
315 if (tls_conn == NULL) {
316 #endif
317 /* Wait for activity on stdin, updating timer stats as we
318 * go. */
319 do {
320 struct timeval t;
321
322 FD_ZERO(&rmask);
323 FD_SET(STDIN_FILENO, &rmask);
324 t.tv_sec = timeout;
325 t.tv_usec = 0;
326 TMRstart(TMR_IDLE);
327 i = select(STDIN_FILENO + 1, &rmask, NULL, NULL, &t);
328 TMRstop(TMR_IDLE);
329 if (i == -1 && errno != EINTR) {
330 syswarn("%s can't select", Client.host);
331 return RTtimeout;
332 }
333 } while (i == -1);
334
335 /* If stdin didn't select, we must have timed out. */
336 if (i == 0 || !FD_ISSET(STDIN_FILENO, &rmask))
337 return RTtimeout;
338 #ifdef HAVE_OPENSSL
339 }
340 #endif
341 count = line_doread(where, line->allocated - (where - line->start),
342 timeout);
343
344 /* Give timeout to both real timeouts (count == -2) and
345 * read errors (count == -1). */
346 if (count < 0) {
347 if (count == -1) {
348 sysnotice("%s can't read", Client.host);
349 }
350 return RTtimeout;
351 }
352 /* If we hit EOF, terminate the string and send it back. */
353 if (count == 0) {
354 assert((where + count) < (line->start + line->allocated));
355 where[count] = '\0';
356 return RTeof;
357 }
358 /* Search for `\n' in what we just read. If we find it, we'll
359 * drop out and return the line for processing. */
360 lf = memchr(where, '\n', count);
361 where += count;
362 } while (lf == NULL);
363 }
364
365 /* Remember where we've processed up to, so we can start off there
366 * next time. */
367 line->where = lf + 1;
368 line->remaining = where - line->where;
369
370 if (r == RTok) {
371 /* If we see a full CRLF pair, strip them both off before
372 * returning the line to our caller. If we just get an LF
373 * we'll accept that too (debugging INN can then be less annoying). */
374 if (lf > line->start && lf[-1] == '\r') {
375 --lf;
376 if (stripped != NULL)
377 (*stripped)++;
378 }
379 *lf = '\0';
380 if (stripped != NULL)
381 (*stripped)++;
382 *len = lf - line->start;
383 *p = line->start;
384 }
385 return r;
386 }
387