1 /* Copyright (c) 2013, Vsevolod Stakhov
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *       * Redistributions of source code must retain the above copyright
7  *         notice, this list of conditions and the following disclaimer.
8  *       * Redistributions in binary form must reproduce the above copyright
9  *         notice, this list of conditions and the following disclaimer in the
10  *         documentation and/or other materials provided with the distribution.
11  *
12  * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15  * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22  */
23 
24 #include "config.h"
25 #include "util.h"
26 #include "rmilter.h"
27 #include <assert.h>
28 #include <stdbool.h>
29 
30 
31 extern const char *_rmilter_progname;
32 
33 size_t
rmilter_strlcpy(char * dst,const char * src,size_t siz)34 rmilter_strlcpy(char *dst, const char *src, size_t siz)
35 {
36 	char *d = dst;
37 	const char *s = src;
38 	size_t n = siz;
39 
40 	/* Copy as many bytes as will fit */
41 	if (n != 0) {
42 		while (--n != 0) {
43 			if ((*d++ = *s++) == '\0') {
44 				break;
45 			}
46 		}
47 	}
48 
49 	if (n == 0 && siz != 0) {
50 		*d = '\0';
51 	}
52 
53 	return (s - src - 1); /* count does not include NUL */
54 }
55 
56 bool
rmilter_file_lock(int fd,bool async)57 rmilter_file_lock(int fd, bool async)
58 {
59 	int flags;
60 
61 	if (async) {
62 		flags = LOCK_EX | LOCK_NB;
63 	}
64 	else {
65 		flags = LOCK_EX;
66 	}
67 
68 	if (flock (fd, flags) == -1) {
69 		if (async && errno == EAGAIN) {
70 			return false;
71 		}
72 
73 		return false;
74 	}
75 
76 	return true;
77 }
78 
79 bool
rmilter_file_unlock(int fd,bool async)80 rmilter_file_unlock(int fd, bool async)
81 {
82 	int flags;
83 
84 	if (async) {
85 		flags = LOCK_UN | LOCK_NB;
86 	}
87 	else {
88 		flags = LOCK_UN;
89 	}
90 
91 	if (flock (fd, flags) == -1) {
92 		if (async && errno == EAGAIN) {
93 			return false;
94 		}
95 
96 		return false;
97 	}
98 
99 	return true;
100 
101 }
102 
103 static int _rmilter_pidfile_remove(rmilter_pidfh_t *pfh, int freeit);
104 
105 static int
rmilter_pidfile_verify(rmilter_pidfh_t * pfh)106 rmilter_pidfile_verify(rmilter_pidfh_t *pfh)
107 {
108 	struct stat sb;
109 
110 	if (pfh == NULL || pfh->pf_fd == -1)
111 		return (-1);
112 	/*
113 	 * Check remembered descriptor.
114 	 */
115 	if (fstat (pfh->pf_fd, &sb) == -1)
116 		return (errno);
117 	if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino)
118 		return -1;
119 	return 0;
120 }
121 
122 static int
rmilter_pidfile_read(const char * path,pid_t * pidptr)123 rmilter_pidfile_read(const char *path, pid_t * pidptr)
124 {
125 	char buf[16], *endptr;
126 	int error, fd, i;
127 
128 	fd = open (path, O_RDONLY);
129 	if (fd == -1)
130 		return (errno);
131 
132 	i = read (fd, buf, sizeof(buf) - 1);
133 	error = errno; /* Remember errno in case close() wants to change it. */
134 	close (fd);
135 	if (i == -1)
136 		return error;
137 	else if (i == 0)
138 		return EAGAIN;
139 	buf[i] = '\0';
140 
141 	*pidptr = strtol (buf, &endptr, 10);
142 	if (endptr != &buf[i])
143 		return EINVAL;
144 
145 	return 0;
146 }
147 
148 rmilter_pidfh_t *
rmilter_pidfile_open(const char * path,mode_t mode,pid_t * pidptr)149 rmilter_pidfile_open(const char *path, mode_t mode, pid_t * pidptr)
150 {
151 	rmilter_pidfh_t *pfh;
152 	struct stat sb;
153 	int error, fd, len, count;
154 	struct timespec rqtp;
155 
156 	pfh = malloc (sizeof(*pfh));
157 	if (pfh == NULL)
158 		return NULL;
159 
160 	if (path == NULL)
161 		len = snprintf(pfh->pf_path, sizeof(pfh->pf_path), "/var/run/%s.pid",
162 				_rmilter_progname);
163 	else
164 		len = snprintf(pfh->pf_path, sizeof(pfh->pf_path), "%s", path);
165 	if (len >= (int) sizeof(pfh->pf_path)) {
166 		free (pfh);
167 		errno = ENAMETOOLONG;
168 		return NULL;
169 	}
170 
171 	/*
172 	 * Open the PID file and obtain exclusive lock.
173 	 * We truncate PID file here only to remove old PID immediatelly,
174 	 * PID file will be truncated again in pidfile_write(), so
175 	 * pidfile_write() can be called multiple times.
176 	 */
177 	fd = open (pfh->pf_path, O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, mode);
178 	rmilter_file_lock (fd, true);
179 	if (fd == -1) {
180 		count = 0;
181 		rqtp.tv_sec = 0;
182 		rqtp.tv_nsec = 5000000;
183 		if (errno == EWOULDBLOCK && pidptr != NULL) {
184 			again:
185 			errno = rmilter_pidfile_read (pfh->pf_path, pidptr);
186 			if (errno == 0)
187 				errno = EEXIST;
188 			else if (errno == EAGAIN) {
189 				if (++count <= 3) {
190 					nanosleep (&rqtp, 0);
191 					goto again;
192 				}
193 			}
194 		}
195 		free (pfh);
196 		return NULL;
197 	}
198 	/*
199 	 * Remember file information, so in pidfile_write() we are sure we write
200 	 * to the proper descriptor.
201 	 */
202 	if (fstat (fd, &sb) == -1) {
203 		error = errno;
204 		unlink (pfh->pf_path);
205 		close (fd);
206 		free (pfh);
207 		errno = error;
208 		return NULL;
209 	}
210 
211 	pfh->pf_fd = fd;
212 	pfh->pf_dev = sb.st_dev;
213 	pfh->pf_ino = sb.st_ino;
214 
215 	return pfh;
216 }
217 
218 int
rmilter_pidfile_write(rmilter_pidfh_t * pfh)219 rmilter_pidfile_write(rmilter_pidfh_t *pfh)
220 {
221 	char pidstr[16];
222 	int error, fd;
223 
224 	/*
225 	 * Check remembered descriptor, so we don't overwrite some other
226 	 * file if pidfile was closed and descriptor reused.
227 	 */
228 	errno = rmilter_pidfile_verify (pfh);
229 	if (errno != 0) {
230 		/*
231 		 * Don't close descriptor, because we are not sure if it's ours.
232 		 */
233 		return -1;
234 	}
235 	fd = pfh->pf_fd;
236 
237 	/*
238 	 * Truncate PID file, so multiple calls of pidfile_write() are allowed.
239 	 */
240 	if (ftruncate (fd, 0) == -1) {
241 		error = errno;
242 		_rmilter_pidfile_remove (pfh, 0);
243 		errno = error;
244 		return -1;
245 	}
246 
247 	snprintf (pidstr, sizeof(pidstr), "%ld", (long)getpid ());
248 	if (pwrite (fd, pidstr, strlen (pidstr), 0) != (ssize_t) strlen (pidstr)) {
249 		error = errno;
250 		_rmilter_pidfile_remove (pfh, 0);
251 		errno = error;
252 		return -1;
253 	}
254 
255 	return 0;
256 }
257 
258 int
rmilter_pidfile_close(rmilter_pidfh_t * pfh)259 rmilter_pidfile_close(rmilter_pidfh_t *pfh)
260 {
261 	int error;
262 
263 	error = rmilter_pidfile_verify (pfh);
264 	if (error != 0) {
265 		errno = error;
266 		return -1;
267 	}
268 
269 	if (close (pfh->pf_fd) == -1)
270 		error = errno;
271 	free (pfh);
272 	if (error != 0) {
273 		errno = error;
274 		return -1;
275 	}
276 	return 0;
277 }
278 
279 static int
_rmilter_pidfile_remove(rmilter_pidfh_t * pfh,int freeit)280 _rmilter_pidfile_remove(rmilter_pidfh_t *pfh, int freeit)
281 {
282 	int error;
283 
284 	error = rmilter_pidfile_verify (pfh);
285 	if (error != 0) {
286 		errno = error;
287 		return -1;
288 	}
289 
290 	if (unlink (pfh->pf_path) == -1)
291 		error = errno;
292 	if (!rmilter_file_unlock (pfh->pf_fd, false)) {
293 		if (error == 0)
294 			error = errno;
295 	}
296 	if (close (pfh->pf_fd) == -1) {
297 		if (error == 0)
298 			error = errno;
299 	}
300 	if (freeit)
301 		free (pfh);
302 	else
303 		pfh->pf_fd = -1;
304 	if (error != 0) {
305 		errno = error;
306 		return -1;
307 	}
308 	return 0;
309 }
310 
311 int
rmilter_pidfile_remove(rmilter_pidfh_t * pfh)312 rmilter_pidfile_remove(rmilter_pidfh_t *pfh)
313 {
314 
315 	return (_rmilter_pidfile_remove (pfh, 1));
316 }
317 
318 /*
319  * Written by Manuel Bouyer <bouyer@NetBSD.org>.
320  * Public domain.
321  */
322 #ifndef bswap32
323 	static uint32_t
bswap32(uint32_t x)324 	bswap32 (uint32_t x)
325 	{
326 		return ((x << 24) & 0xff000000) |
327 				((x << 8) & 0x00ff0000) |
328 				((x >> 8) & 0x0000ff00) |
329 				((x >> 24) & 0x000000ff);
330 	}
331 #endif
332 
333 #ifndef bswap64
334 	static uint64_t
bswap64(uint64_t x)335 	bswap64 (uint64_t x)
336 	{
337 	#ifdef _LP64
338 		/*
339 		 * Assume we have wide enough registers to do it without touching
340 		 * memory.
341 		 */
342 		return ((x << 56) & 0xff00000000000000UL) |
343 				((x << 40) & 0x00ff000000000000UL) |
344 				((x << 24) & 0x0000ff0000000000UL) |
345 				((x << 8) & 0x000000ff00000000UL) |
346 				((x >> 8) & 0x00000000ff000000UL) |
347 				((x >> 24) & 0x0000000000ff0000UL) |
348 				((x >> 40) & 0x000000000000ff00UL) |
349 				((x >> 56) & 0x00000000000000ffUL);
350 	#else
351 		/*
352 		 * Split the operation in two 32bit steps.
353 		 */
354 		uint32_t tl, th;
355 
356 		th = bswap32((uint32_t)(x & 0x00000000ffffffffULL));
357 		tl = bswap32((uint32_t)((x >> 32) & 0x00000000ffffffffULL));
358 		return ((uint64_t)th << 32) | tl;
359 	#endif
360 	}
361 #endif
362 
363 static char *
rmilter_encode_base64_common(const u_char * in,size_t inlen,int str_len,size_t * outlen,int fold)364 rmilter_encode_base64_common (const u_char *in, size_t inlen, int str_len,
365 		size_t *outlen, int fold)
366 {
367 #define CHECK_SPLIT \
368     do { if (str_len > 0 && cols >= str_len) { \
369                 *o++ = '\r'; \
370                 *o++ = '\n'; \
371                 if (fold) *o++ = '\t'; \
372                 cols = 0; \
373     } } \
374 while (0)
375 
376 	size_t allocated_len = (inlen / 3) * 4 + 5;
377 	char *out, *o;
378 	uint64_t n;
379 	uint32_t rem, t, carry;
380 	int cols, shift;
381 	static const char b64_enc[] =
382 			"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
383 					"abcdefghijklmnopqrstuvwxyz"
384 					"0123456789+/";
385 
386 	if (str_len > 0) {
387 		assert (str_len > 8);
388 		allocated_len += (allocated_len / str_len + 1) * (fold ? 3 : 2) + 1;
389 	}
390 
391 	out = malloc (allocated_len);
392 	o = out;
393 	cols = 0;
394 
395 	while (inlen > 6) {
396 		n = *(uint64_t *) in;
397 #if BYTE_ORDER == LITTLE_ENDIAN
398 		n = bswap64 (n);
399 #endif
400 		if (str_len <= 0 || cols <= str_len - 8) {
401 			*o++ = b64_enc[(n >> 58) & 0x3F];
402 			*o++ = b64_enc[(n >> 52) & 0x3F];
403 			*o++ = b64_enc[(n >> 46) & 0x3F];
404 			*o++ = b64_enc[(n >> 40) & 0x3F];
405 			*o++ = b64_enc[(n >> 34) & 0x3F];
406 			*o++ = b64_enc[(n >> 28) & 0x3F];
407 			*o++ = b64_enc[(n >> 22) & 0x3F];
408 			*o++ = b64_enc[(n >> 16) & 0x3F];
409 			cols += 8;
410 		}
411 		else {
412 			cols = str_len - cols;
413 			shift = 58;
414 			while (cols) {
415 				*o++ = b64_enc[(n >> shift) & 0x3F];
416 				shift -= 6;
417 				cols--;
418 			}
419 
420 			*o++ = '\r';
421 			*o++ = '\n';
422 			if (fold) {
423 				*o++ = '\t';
424 			}
425 
426 			/* Remaining bytes */
427 			while (shift >= 16) {
428 				*o++ = b64_enc[(n >> shift) & 0x3F];
429 				shift -= 6;
430 				cols++;
431 			}
432 		}
433 
434 		in += 6;
435 		inlen -= 6;
436 	}
437 
438 	CHECK_SPLIT;
439 
440 	rem = 0;
441 	carry = 0;
442 
443 	for (; ;) {
444 		/* Padding + remaining data (0 - 2 bytes) */
445 		switch (rem) {
446 		case 0:
447 			if (inlen-- == 0) {
448 				goto end;
449 			}
450 			t = *in++;
451 			*o++ = b64_enc[t >> 2];
452 			carry = (t << 4) & 0x30;
453 			rem = 1;
454 			cols++;
455 		case 1:
456 			if (inlen-- == 0) {
457 				goto end;
458 			}
459 			CHECK_SPLIT;
460 			t = *in++;
461 			*o++ = b64_enc[carry | (t >> 4)];
462 			carry = (t << 2) & 0x3C;
463 			rem = 2;
464 			cols++;
465 		default:
466 			if (inlen-- == 0) {
467 				goto end;
468 			}
469 			CHECK_SPLIT;
470 			t = *in++;
471 			*o++ = b64_enc[carry | (t >> 6)];
472 			cols++;
473 			CHECK_SPLIT;
474 			*o++ = b64_enc[t & 0x3F];
475 			cols++;
476 			CHECK_SPLIT;
477 			rem = 0;
478 		}
479 	}
480 
481 	end:
482 	if (rem == 1) {
483 		*o++ = b64_enc[carry];
484 		cols++;
485 		CHECK_SPLIT;
486 		*o++ = '=';
487 		cols++;
488 		CHECK_SPLIT;
489 		*o++ = '=';
490 		cols++;
491 		CHECK_SPLIT;
492 	}
493 	else if (rem == 2) {
494 		*o++ = b64_enc[carry];
495 		cols++;
496 		CHECK_SPLIT;
497 		*o++ = '=';
498 		cols++;
499 	}
500 
501 	CHECK_SPLIT;
502 
503 	*o = '\0';
504 
505 	if (outlen != NULL) {
506 		*outlen = o - out;
507 	}
508 
509 	return out;
510 }
511 
512 char *
rmilter_encode_base64(const u_char * in,size_t inlen,int str_len,size_t * outlen)513 rmilter_encode_base64 (const u_char *in, size_t inlen, int str_len,
514 		size_t *outlen)
515 {
516 	return rmilter_encode_base64_common (in, inlen, str_len, outlen, 0);
517 }
518 
519 int
rmilter_connect_addr(const char * addr,int port,int msec,const struct mlfi_priv * priv)520 rmilter_connect_addr (const char *addr, int port, int msec,
521 		const struct mlfi_priv *priv)
522 {
523 	struct sockaddr_un su;
524 	int ofl, r;
525 	struct addrinfo hints, *res, *res0;
526 	int error;
527 	int s;
528 	const char *cause = NULL;
529 	char portbuf[32];
530 	socklen_t slen;
531 
532 	if (addr[0] == '/' || addr[0] == '.') {
533 		/* Unix socket */
534 		su.sun_family = AF_UNIX;
535 		rmilter_strlcpy (su.sun_path, addr, sizeof (su.sun_path));
536 #if defined(FREEBSD) || defined(__APPLE__)
537 		su.sun_len = SUN_LEN (&su);
538 #endif
539 		s = socket (AF_UNIX, SOCK_STREAM, 0);
540 		if (s < 0) {
541 			cause = "socket";
542 			error = errno;
543 		}
544 
545 		ofl = fcntl (s, F_GETFL, 0);
546 		fcntl (s, F_SETFL, ofl | O_NONBLOCK);
547 #ifdef SUN_LEN
548 		slen = SUN_LEN (&su);
549 #else
550 		slen = sizeof (su);
551 #endif
552 
553 		if (connect (s, (struct sockaddr *)&su, slen) < 0) {
554 			if (errno != EINPROGRESS && errno != EAGAIN) {
555 				cause = "connect";
556 				error = errno;
557 				close (s);
558 				s = -1;
559 			}
560 		}
561 	}
562 	else {
563 		memset(&hints, 0, sizeof(hints));
564 		snprintf(portbuf, sizeof(portbuf), "%d", port);
565 		hints.ai_family = PF_UNSPEC;
566 		hints.ai_socktype = SOCK_STREAM;
567 		hints.ai_flags = AI_NUMERICSERV;
568 		error = getaddrinfo (addr, portbuf, &hints, &res0);
569 
570 		if (error) {
571 			msg_err ("<%s>; rmilter_connect_addr: getaddrinfo failed for %s:%d: %s",
572 					priv->mlfi_id, addr, port, gai_strerror (error));
573 			return -1;
574 		}
575 
576 		s = -1;
577 		for (res = res0; res; res = res->ai_next) {
578 			s = socket (res->ai_family, res->ai_socktype, res->ai_protocol);
579 			if (s < 0) {
580 				cause = "socket";
581 				error = errno;
582 				continue;
583 			}
584 
585 			ofl = fcntl (s, F_GETFL, 0);
586 			fcntl (s, F_SETFL, ofl | O_NONBLOCK);
587 
588 			if (connect (s, res->ai_addr, res->ai_addrlen) < 0) {
589 				if (errno == EINPROGRESS || errno == EAGAIN) {
590 					break;
591 				}
592 
593 				cause = "connect";
594 				error = errno;
595 				close (s);
596 				s = -1;
597 				continue;
598 			}
599 
600 			break; /* okay we got one */
601 		}
602 
603 		freeaddrinfo (res0);
604 	}
605 
606 	if (s < 0) {
607 		if (s == 0) {
608 			errno = ETIMEDOUT;
609 		}
610 
611 		msg_err ("<%s>; rmilter_connect_addr: connect failed: %s: %s",
612 				priv->mlfi_id, cause, strerror (error));
613 		return -1;
614 	}
615 
616 	/* Get write readiness */
617 	if (rmilter_poll_fd (s, msec, POLLOUT) == 1) {
618 		return s;
619 	}
620 	else {
621 		msg_err ("<%s>; rmilter_connect_addr: connect failed: timeout", priv->mlfi_id);
622 		close (s);
623 	}
624 
625 	return -1;
626 }
627 
628 int
rmilter_poll_fd(int fd,int timeout,short events)629 rmilter_poll_fd (int fd, int timeout, short events)
630 {
631 	int r;
632 	struct pollfd fds[1];
633 
634 	fds->fd = fd;
635 	fds->events = events;
636 	fds->revents = 0;
637 	while ((r = poll (fds, 1, timeout)) < 0) {
638 		if (errno != EINTR)
639 			break;
640 	}
641 
642 
643 	return r;
644 }
645 
646 static const unsigned char lc_map[256] = {
647 		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
648 		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
649 		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
650 		0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
651 		0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
652 		0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
653 		0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
654 		0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
655 		0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
656 		0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
657 		0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
658 		0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
659 		0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
660 		0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
661 		0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
662 		0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
663 		0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
664 		0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
665 		0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
666 		0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
667 		0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
668 		0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
669 		0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
670 		0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
671 		0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
672 		0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
673 		0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
674 		0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
675 		0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
676 		0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
677 		0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
678 		0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
679 };
680 
681 void
rmilter_str_lc(char * str,unsigned int size)682 rmilter_str_lc (char *str, unsigned int size)
683 {
684 	unsigned int leftover = size % 4;
685 	unsigned int fp, i;
686 	const uint8_t* s = (const uint8_t*) str;
687 	char *dest = str;
688 	unsigned char c1, c2, c3, c4;
689 
690 	fp = size - leftover;
691 
692 	for (i = 0; i != fp; i += 4) {
693 		c1 = s[i], c2 = s[i + 1], c3 = s[i + 2], c4 = s[i + 3];
694 		dest[0] = lc_map[c1];
695 		dest[1] = lc_map[c2];
696 		dest[2] = lc_map[c3];
697 		dest[3] = lc_map[c4];
698 		dest += 4;
699 	}
700 
701 	switch (leftover) {
702 	case 3:
703 		*dest++ = lc_map[(unsigned char)str[i++]];
704 	case 2:
705 		*dest++ = lc_map[(unsigned char)str[i++]];
706 	case 1:
707 		*dest++ = lc_map[(unsigned char)str[i]];
708 	}
709 
710 }
711 
712 ssize_t
rmilter_atomic_write(int fd,const void * buf,size_t len)713 rmilter_atomic_write (int fd, const void *buf, size_t len)
714 {
715 	const char *s = buf;
716 	size_t pos = 0;
717 	ssize_t res;
718 
719 	while (len > pos) {
720 		res = write (fd, s + pos, len - pos);
721 
722 		switch (res) {
723 		case -1:
724 			if (errno == EINTR || errno == EAGAIN) {
725 				continue;
726 			}
727 
728 			return -1;
729 		case 0:
730 			errno = EPIPE;
731 			return -1;
732 		default:
733 			pos += res;
734 		}
735 	}
736 
737 	return pos;
738 }
739 
740 int
rmilter_file_xopen(const char * fname,int oflags,unsigned int mode)741 rmilter_file_xopen (const char *fname, int oflags, unsigned int mode)
742 {
743 	struct stat sb;
744 	int fd;
745 
746 	if (lstat (fname, &sb) == -1) {
747 
748 		if (errno != ENOENT) {
749 			return (-1);
750 		}
751 	}
752 	else if (!S_ISREG (sb.st_mode)) {
753 		return -1;
754 	}
755 
756 #ifdef HAVE_ONOFOLLOW
757 	fd = open (fname, oflags | O_NOFOLLOW, mode);
758 #else
759 	fd = open (fname, oflags, mode);
760 #endif
761 
762 	return (fd);
763 }
764 
765 void *
rmilter_file_xmap(const char * fname,unsigned int mode,size_t * size)766 rmilter_file_xmap (const char *fname, unsigned int mode,
767 		size_t *size)
768 {
769 	int fd;
770 	struct stat sb;
771 	void *map;
772 
773 	assert (fname != NULL);
774 	assert (size != NULL);
775 
776 	if (mode & PROT_WRITE) {
777 		fd = rmilter_file_xopen (fname, O_RDWR, 0);
778 	}
779 	else {
780 		fd = rmilter_file_xopen (fname, O_RDONLY, 0);
781 	}
782 
783 	if (fd == -1) {
784 		return NULL;
785 	}
786 
787 	if (fstat (fd, &sb) == -1 || !S_ISREG (sb.st_mode)) {
788 		close (fd);
789 
790 		return NULL;
791 	}
792 
793 	map = mmap (NULL, sb.st_size, mode, MAP_SHARED, fd, 0);
794 	close (fd);
795 
796 	if (map == MAP_FAILED) {
797 		return NULL;
798 	}
799 
800 	*size = sb.st_size;
801 
802 	return map;
803 }
804 
805 GString *
rmilter_header_value_fold(const gchar * name,const gchar * value,guint fold_max)806 rmilter_header_value_fold (const gchar *name,
807 		const gchar *value,
808 		guint fold_max)
809 {
810 	GString *res;
811 	const guint default_fold_max = 76;
812 	guint cur_len;
813 	const gchar *p, *c;
814 	gboolean first_token = TRUE;
815 	enum {
816 		fold_before = 0,
817 		fold_after
818 	} fold_type = fold_before;
819 	enum {
820 		read_token = 0,
821 		read_quoted,
822 		after_quote,
823 		fold_token,
824 	} state = read_token, next_state = read_token;
825 
826 	g_assert (name != NULL);
827 	g_assert (value != NULL);
828 
829 	/* Filter insane values */
830 	if (fold_max < 20) {
831 		fold_max = default_fold_max;
832 	}
833 
834 	res = g_string_sized_new (strlen (value));
835 
836 	c = value;
837 	p = c;
838 	/* name:<WSP> */
839 	cur_len = strlen (name) + 2;
840 
841 	while (*p) {
842 		switch (state) {
843 		case read_token:
844 			if (*p == ',' || *p == ';') {
845 				/* We have something similar to the token's end, so check len */
846 				if (cur_len > fold_max * 0.8 && cur_len < fold_max) {
847 					/* We want fold */
848 					fold_type = fold_after;
849 					state = fold_token;
850 					next_state = read_token;
851 				}
852 				else if (cur_len > fold_max && !first_token) {
853 					fold_type = fold_before;
854 					state = fold_token;
855 					next_state = read_token;
856 				}
857 				else {
858 					g_string_append_len (res, c, p - c);
859 					c = p;
860 					first_token = FALSE;
861 				}
862 				p ++;
863 			}
864 			else if (*p == '"') {
865 				/* Fold before quoted tokens */
866 				g_string_append_len (res, c, p - c);
867 				c = p;
868 				state = read_quoted;
869 			}
870 			else if (*p == '\r') {
871 				/* Reset line length */
872 				cur_len = 0;
873 
874 				while (g_ascii_isspace (*p)) {
875 					p ++;
876 				}
877 
878 				g_string_append_len (res, c, p - c);
879 				c = p;
880 			}
881 			else if (g_ascii_isspace (*p)) {
882 				if (cur_len > fold_max * 0.8 && cur_len < fold_max) {
883 					/* We want fold */
884 					fold_type = fold_after;
885 					state = fold_token;
886 					next_state = read_token;
887 				}
888 				else if (cur_len > fold_max && !first_token) {
889 					fold_type = fold_before;
890 					state = fold_token;
891 					next_state = read_token;
892 				}
893 				else {
894 					g_string_append_len (res, c, p - c);
895 					c = p;
896 					first_token = FALSE;
897 					p ++;
898 				}
899 			}
900 			else {
901 				p ++;
902 				cur_len ++;
903 			}
904 			break;
905 		case fold_token:
906 			/* Here, we have token start at 'c' and token end at 'p' */
907 			if (fold_type == fold_after) {
908 				g_string_append_len (res, c, p - c);
909 				g_string_append_len (res, "\r\n\t", 3);
910 
911 				/* Skip space if needed */
912 				if (g_ascii_isspace (*p)) {
913 					p ++;
914 				}
915 			}
916 			else {
917 				/* Skip space if needed */
918 				if (g_ascii_isspace (*c)) {
919 					c ++;
920 				}
921 
922 				g_string_append_len (res, "\r\n\t", 3);
923 				g_string_append_len (res, c, p - c);
924 			}
925 
926 			c = p;
927 			state = next_state;
928 			cur_len = 0;
929 			first_token = TRUE;
930 			break;
931 
932 		case read_quoted:
933 			if (p != c && *p == '"') {
934 				state = after_quote;
935 			}
936 			p ++;
937 			cur_len ++;
938 			break;
939 
940 		case after_quote:
941 			state = read_token;
942 			/* Skip one more character after the quote */
943 			p ++;
944 			cur_len ++;
945 			g_string_append_len (res, c, p - c);
946 			c = p;
947 			first_token = TRUE;
948 			break;
949 		}
950 	}
951 
952 	/* Last token */
953 	switch (state) {
954 	case read_token:
955 		if (cur_len > fold_max && !first_token) {
956 			g_string_append_len (res, "\r\n\t", 3);
957 			g_string_append_len (res, c, p - c);
958 		}
959 		else {
960 			g_string_append_len (res, c, p - c);
961 		}
962 		break;
963 	case read_quoted:
964 	case after_quote:
965 		g_string_append_len (res, c, p - c);
966 		break;
967 
968 	default:
969 		g_assert (p == c);
970 		break;
971 	}
972 
973 	return res;
974 }
975