head 1.57; access; symbols milter-greylist-4-3-1:1.57 milter-greylist-2-2-2:1.57 milter-greylist-4-2-2:1.57 milter-greylist-4-2-1:1.57 milter-greylist-4-2:1.57 milter-greylist-4-2-rc1:1.57 milter-greylist-4-2-beta1:1.57 milter-greylist-4-2-branch:1.57.0.2 milter-greylist-4-2-base:1.57 milter-greylist-4-2-0-base:1.57 milter-greylist-4-1-12:1.57 milter-greylist-4-1-11:1.57 milter-greylist-4-1-10:1.57 milter-greylist-4-1-9:1.57 milter-greylist-4-1-8:1.57 milter-greylist-4-1-7:1.57 milter-greylist-4-1-6:1.57 milter-greylist-4-0-1:1.55.2.1 milter-greylist-4-0-1-rc1:1.55.2.1 milter-greylist-4-1-5:1.57 milter-greylist-4-1-4:1.57 milter-greylist-4-1-3:1.57 milter-greylist-4-1-2:1.57 milter-greylist-4-1-1:1.57 milter-greylist-4-0-branch:1.55.0.2 milter-greylist-4-0-base:1.55 milter-greylist-4-0:1.55 milter-greylist-4-0-rc2:1.55 milter-greylist-4-0-rc1:1.55 milter-greylist-4-0-beta4:1.55 milter-greylist-4-0-beta3:1.55 milter-greylist-4-0-beta2:1.55 milter-greylist-4-0-beta1:1.55 milter-greylist-4-0-alpha6:1.54 milter-greylist-4-0-alpha5:1.54 milter-greylist-4-0-alpha4:1.54 milter-greylist-4-0-alpha3:1.54 milter-greylist-4-0-alpha2:1.54 milter-greylist-4-0-alpha1:1.54 milter-greylist-3-1-8:1.53 milter-greylist-3-1-7:1.53 milter-greylist-3-1-6:1.53 milter-greylist-3-1-5:1.53 milter-greylist-3-1-5-alpha1:1.53 milter-greylist-3-0-1-beta1:1.51.2.2 milter-greylist-3-1-4:1.53 milter-greylist-3-1-3:1.52 milter-greylist-3-1-2:1.52 milter-greylist-3-1-1:1.51 milter-greylist-3-0:1.51.2.1 milter-greylist-3-0-rc7:1.51.2.1 milter-greylist-3-0-rc6:1.51.2.1 milter-greylist-3-0-rc5:1.51.2.1 milter-greylist-3-0-rc4:1.51.2.1 milter-greylist-3-0-rc3:1.51.2.1 milter-greylist-3-0-rc2:1.51.2.1 milter-greylist-3-0-rc1:1.51.2.1 milter-greylist-3-0-alpha6:1.51.2.1 milter-greylist-3-0-branch:1.51.0.2 milter-greylist-3-0-base:1.51 milter-greylist-3-0-alpha5:1.51 milter-greylist-3-0-alpha4:1.50 milter-greylist-3-0-alpha3:1.50 milter-greylist-3-0-alpha2:1.49 milter-greylist-3-0-alpha1:1.46 milter-greylist-2-1-12:1.46 milter-greylist-2-1-11:1.46 milter-greylist-2-1-10:1.45 milter-greylist-2-1-9:1.45 milter-greylist-2-1-9a1:1.45 milter-greylist-2-1-8:1.45 milter-greylist-2-1-7:1.45 milter-greylist-2-1-6:1.45 milter-greylist-2-1-5:1.43 milter-greylist-2-1-4:1.43 milter-greylist-2-1-3:1.42 milter-greylist-2-1-2:1.42 milter-greylist-2-1-1:1.42 milter-greylist-2-0-2:1.41 milter-greylist-2-0-1:1.41 milter-greylist-2-0-1-b1:1.40 milter-greylist-2-0-release:1.38 milter-greylist-2-0-rc5:1.38 milter-greylist-2-0-rc4:1.38 milter-greylist-2-0-rc3:1.38 milter-grey-list-2-0-rc3:1.38 milter-grey-list-2-0-rc2:1.38 milter-grey-list-2-0-rc1:1.38 milter-greylist-2-0-beta7:1.38 milter-greylist-2-0-beta6:1.38 milter-gre-ylist-2-0-beta5:1.38 milter-greylist-2-0-beta5:1.38 milter-greylist-2-0-beta4:1.38 milter-greylist-2-0-beta3:1.38 milter-greylist-2-0-beta2:1.38 milter-greylist-2-0:1.38.0.2 milter-greylist-2-0-base:1.38 milter-greylist-2-0-beta1:1.38 milter-greylist-1-7-5:1.38 before_delayed_tempfail:1.38 milter-greylist-1-7-4:1.38 milter-greylist-1-7-3:1.38 milter-greylist-1-7-2:1.38 milter-greylist-1-6-0:1.37 milter-greylist-1-7-1:1.37 milter-greylist-1-6rc1:1.37 milter-greylist-1-6:1.37.0.2 milter-greylist-1-6-base:1.37 milter-greylist-1-5-12:1.37 milter-greylist-1-5-11:1.37 milter-greylist-1-5-10:1.37 milter-greylist-1-5-9:1.37 milter-greylist-1-5-8:1.37 milter-greylist-1-5-7:1.37 milter-greylist-1-5-6:1.36 milter-greylist-1-5-5:1.36 milter-greylist-1-5-4:1.35 milter-greylist-1-5-3:1.34 milter-greylist-1-5-2:1.34 milter-greylist-1-5-1:1.34 milter-greylist-1-4:1.32.0.2 milter-greylist-1-4-base:1.32 milter-greylist-1-3-9:1.32 milter-greylist-1-3-8:1.31 milter-greylist-1-3-7:1.31 milter-greylist-1-3-6:1.31 milter-greylist-1-3-5:1.31 milter-greylist-1-3-4:1.31 milter-greylist-1-3-3:1.30 BDB:1.26.0.2 BDB-base:1.26 before_BDB:1.22 milter-greylist-1-2-2:1.19.2.1 milter-greylist-1-3-2:1.21 milter-greylist-1-2-1:1.19 milter-greylist-1-2-0:1.19 milter-greylist-1-2:1.19.0.2 milter-greylist-1-2-base:1.19 milter-greylist-1-1-16:1.19 milter-greylist-1-1-15:1.19 milter-greylis-1-1-15:1.19 milter-greylis-1-1-16:1.19 milter-greylist-1-1-14:1.19 milter-greylist-1-1-13:1.19 milter-greylist-1-1-12:1.19 milter-greylist-1-1-11:1.19 milter-greylist-1-1-10:1.19 milter-greylist-1-10rc1:1.19 milter-greylist-1-1-9:1.19 milter-greylist-1-1-8:1.19 milter-greylist-1-1-7:1.19 milter-greylist-1-1-6:1.19 milter-greylist-1-1-5:1.19 milter-greylist-1-1-4:1.19 milter-greylist-1-1-3:1.17 milter-greylist-1-1-2:1.17 milter-greylist-1-0-2:1.15 rmilter-greylist-1-0-1:1.15 milter-greylist-1-0-1:1.15 milter-greylist-1-1-1:1.17 milter-greylist-1-0-base:1.15 milter-greylist-1-0:1.15.0.2 milter-greylist-1-0-0:1.15 milter-greylist-0-27:1.15 milter-greylist-0-26:1.15 milter-greylist-0-25:1.15 milter-greylist-0-24:1.15 milter-greylist-0-23:1.15 milter-greylist-0-22:1.11 milter-greylist-0-21:1.10 milter-greylist-0-20:1.9 milter-greylist-0-19:1.7; locks; strict; comment @ * @; 1.57 date 2007.11.22.04.25.37; author manu; state Exp; branches; next 1.56; 1.56 date 2007.11.06.11.39.33; author manu; state Exp; branches; next 1.55; 1.55 date 2007.07.08.21.02.28; author manu; state Exp; branches 1.55.2.1; next 1.54; 1.54 date 2007.03.29.03.58.51; author manu; state Exp; branches; next 1.53; 1.53 date 2007.01.22.14.08.16; author manu; state Exp; branches; next 1.52; 1.52 date 2006.11.29.21.08.54; author manu; state Exp; branches; next 1.51; 1.51 date 2006.08.30.04.57.58; author manu; state Exp; branches 1.51.2.1; next 1.50; 1.50 date 2006.08.27.20.54.40; author manu; state Exp; branches; next 1.49; 1.49 date 2006.08.20.05.53.25; author manu; state Exp; branches; next 1.48; 1.48 date 2006.08.20.05.30.39; author manu; state Exp; branches; next 1.47; 1.47 date 2006.08.08.04.21.44; author manu; state Exp; branches; next 1.46; 1.46 date 2006.08.01.14.55.20; author manu; state Exp; branches; next 1.45; 1.45 date 2006.07.24.22.49.43; author manu; state Exp; branches; next 1.44; 1.44 date 2006.05.04.19.29.45; author manu; state Exp; branches; next 1.43; 1.43 date 2006.03.03.21.54.31; author manu; state Exp; branches; next 1.42; 1.42 date 2006.01.08.00.38.24; author manu; state Exp; branches; next 1.41; 1.41 date 2005.10.04.19.15.55; author manu; state Exp; branches; next 1.40; 1.40 date 2005.09.21.13.15.22; author manu; state Exp; branches; next 1.39; 1.39 date 2005.09.16.15.23.25; author manu; state Exp; branches; next 1.38; 1.38 date 2004.12.08.22.23.09; author manu; state Exp; branches; next 1.37; 1.37 date 2004.09.13.18.41.54; author manu; state Exp; branches; next 1.36; 1.36 date 2004.08.02.12.11.48; author manu; state Exp; branches; next 1.35; 1.35 date 2004.08.01.09.27.03; author manu; state Exp; branches; next 1.34; 1.34 date 2004.06.14.20.43.21; author manu; state Exp; branches; next 1.33; 1.33 date 2004.06.12.08.41.56; author manu; state Exp; branches; next 1.32; 1.32 date 2004.06.08.14.47.47; author manu; state Exp; branches; next 1.31; 1.31 date 2004.05.26.09.14.29; author manu; state Exp; branches; next 1.30; 1.30 date 2004.05.25.08.58.48; author manu; state Exp; branches; next 1.29; 1.29 date 2004.05.25.08.37.08; author manu; state Exp; branches; next 1.28; 1.28 date 2004.05.24.22.00.38; author manu; state Exp; branches; next 1.27; 1.27 date 2004.05.24.21.22.02; author manu; state Exp; branches; next 1.26; 1.26 date 2004.05.23.19.40.45; author manu; state Exp; branches; next 1.25; 1.25 date 2004.05.23.13.03.41; author manu; state Exp; branches; next 1.24; 1.24 date 2004.05.21.10.22.08; author manu; state Exp; branches; next 1.23; 1.23 date 2004.05.15.08.41.54; author manu; state Exp; branches; next 1.22; 1.22 date 2004.05.06.13.50.54; author manu; state Exp; branches; next 1.21; 1.21 date 2004.04.22.23.27.57; author manu; state Exp; branches; next 1.20; 1.20 date 2004.04.22.23.14.23; author manu; state Exp; branches; next 1.19; 1.19 date 2004.03.31.10.07.17; author manu; state Exp; branches 1.19.2.1; next 1.18; 1.18 date 2004.03.31.09.49.16; author manu; state Exp; branches; next 1.17; 1.17 date 2004.03.29.15.21.25; author manu; state Exp; branches; next 1.16; 1.16 date 2004.03.28.14.05.42; author manu; state Exp; branches; next 1.15; 1.15 date 2004.03.22.07.12.38; author manu; state Exp; branches; next 1.14; 1.14 date 2004.03.22.07.01.53; author manu; state Exp; branches; next 1.13; 1.13 date 2004.03.21.23.57.34; author manu; state Exp; branches; next 1.12; 1.12 date 2004.03.21.23.52.40; author manu; state Exp; branches; next 1.11; 1.11 date 2004.03.20.17.22.42; author manu; state Exp; branches; next 1.10; 1.10 date 2004.03.20.07.19.03; author manu; state Exp; branches; next 1.9; 1.9 date 2004.03.19.10.16.38; author manu; state Exp; branches; next 1.8; 1.8 date 2004.03.18.22.37.21; author manu; state Exp; branches; next 1.7; 1.7 date 2004.03.18.09.55.14; author manu; state Exp; branches; next 1.6; 1.6 date 2004.03.17.22.31.05; author manu; state Exp; branches; next 1.5; 1.5 date 2004.03.17.22.28.57; author manu; state Exp; branches; next 1.4; 1.4 date 2004.03.17.22.21.36; author manu; state Exp; branches; next 1.3; 1.3 date 2004.03.17.17.33.40; author manu; state Exp; branches; next 1.2; 1.2 date 2004.03.17.15.36.19; author manu; state Exp; branches; next 1.1; 1.1 date 2004.03.16.23.16.52; author manu; state Exp; branches; next ; 1.19.2.1 date 2004.05.06.13.54.00; author manu; state Exp; branches; next ; 1.51.2.1 date 2006.09.04.22.05.58; author manu; state Exp; branches; next 1.51.2.2; 1.51.2.2 date 2006.11.29.21.08.27; author manu; state Exp; branches; next ; 1.55.2.1 date 2007.11.22.04.27.30; author manu; state Exp; branches; next ; desc @@ 1.57 log @Avoid C99 specific syntax (Greg Troxel) @ text @/* $Id: autowhite.c,v 1.56 2007/11/06 11:39:33 manu Exp $ */ /* * Copyright (c) 2004 Emmanuel Dreyfus * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Emmanuel Dreyfus * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_SYS_CDEFS_H #include #ifdef __RCSID __RCSID("$Id: autowhite.c,v 1.56 2007/11/06 11:39:33 manu Exp $"); #endif #endif #include "config.h" #ifdef HAVE_OLD_QUEUE_H #include "queue.h" #else #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "conf.h" #include "pending.h" #include "dump.h" #include "autowhite.h" #include "spf.h" #include "acl.h" #include "sync.h" #ifdef USE_DMALLOC #include #endif pthread_mutex_t autowhite_lock = PTHREAD_MUTEX_INITIALIZER; struct autowhitelist autowhite_head; struct autowhite_bucket *autowhite_buckets; void autowhite_init(void) { int i; TAILQ_INIT(&autowhite_head); if ((autowhite_buckets = calloc(AUTOWHITE_BUCKETS, sizeof(struct autowhite_bucket))) == NULL) { mg_log(LOG_ERR, "Unable to allocate autowhite list buckets: %s", strerror(errno)); exit(EX_OSERR); } for(i = 0; i < AUTOWHITE_BUCKETS; i++) { TAILQ_INIT(&autowhite_buckets[i].b_autowhite_head); } return; } /* List must be locked */ int autowhite_timeout(aw, now) struct autowhite *aw; struct timeval *now; { int dirty = 0; if (aw->a_tv.tv_sec < now->tv_sec) { char buf[IPADDRSTRLEN]; iptostring(aw->a_sa, aw->a_salen, buf, sizeof(buf)); mg_log(LOG_INFO, "(local): addr %s from %s rcpt %s: " "autowhitelisted entry expired", buf, aw->a_from, aw->a_rcpt); autowhite_put(aw); dirty = 1; } return dirty; } void autowhite_add(sa, salen, from, rcpt, date, queueid) struct sockaddr *sa; socklen_t salen; char *from; char *rcpt; time_t *date; char *queueid; { struct autowhite *aw; struct autowhite *aw_next; struct timeval now; char addr[IPADDRSTRLEN]; int h, mn, s; int dirty = 0; ipaddr *mask = NULL; struct autowhite_bucket *b; time_t autowhite; gettimeofday(&now, NULL); autowhite = *date - now.tv_sec; h = autowhite / 3600; mn = ((autowhite % 3600) / 60); s = (autowhite % 3600) % 60; if (!iptostring(sa, salen, addr, sizeof(addr))) return; switch (sa->sa_family) { case AF_INET: mask = (ipaddr *)&conf.c_match_mask; break; #ifdef AF_INET6 case AF_INET6: mask = (ipaddr *)&conf.c_match_mask6; break; #endif } AUTOWHITE_LOCK; b = &autowhite_buckets[BUCKET_HASH(sa, from, rcpt, AUTOWHITE_BUCKETS)]; for (aw = TAILQ_FIRST(&b->b_autowhite_head); aw; aw = aw_next) { aw_next = TAILQ_NEXT(aw, ab_list); if (autowhite_timeout(aw, &now)) { dirty++; continue; } /* * Look for an already existing entry */ if (ip_match(sa, aw->a_sa, mask) && ((conf.c_lazyaw == 1) || ((strcasecmp(from, aw->a_from) == 0) && (strcasecmp(rcpt, aw->a_rcpt) == 0)))) { aw->a_tv.tv_sec = *date; /* Rearrange the big queue */ TAILQ_REMOVE(&autowhite_head, aw, a_list); TAILQ_INSERT_TAIL(&autowhite_head, aw, a_list); dirty++; mg_log(LOG_INFO, "%s: addr %s from %s rcpt %s: " "autowhitelisted for more %02d:%02d:%02d", queueid, addr, from, rcpt, h, mn, s); break; } } /* * Entry not found, create it */ if (aw == NULL) { aw = autowhite_get(sa, salen, from, rcpt, *date); dirty++; mg_log(LOG_INFO, "%s: addr %s from %s rcpt %s: " "autowhitelisted for %02d:%02d:%02d", queueid, addr, from, rcpt, h, mn, s); } AUTOWHITE_UNLOCK; dump_touch(dirty); return; } int autowhite_check(sa, salen, from, rcpt, queueid, gldelay, autowhite) struct sockaddr *sa; socklen_t salen; char *from; char *rcpt; char *queueid; time_t gldelay; time_t autowhite; { struct autowhite *aw; struct autowhite *next_aw; struct pending *pending; struct timeval now, delay; char addr[IPADDRSTRLEN]; int h, mn, s; int dirty = 0; ipaddr *mask = NULL; struct autowhite_bucket *b; if (autowhite == 0) return EXF_NONE; gettimeofday(&now, NULL); delay.tv_sec = autowhite; delay.tv_usec = 0; h = autowhite / 3600; mn = ((autowhite % 3600) / 60); s = (autowhite % 3600) % 60; if (!iptostring(sa, salen, addr, sizeof(addr))) return EXF_NONE; switch (sa->sa_family) { case AF_INET: mask = (ipaddr *)&conf.c_match_mask; break; #ifdef AF_INET6 case AF_INET6: mask = (ipaddr *)&conf.c_match_mask6; break; #endif } AUTOWHITE_LOCK; b = &autowhite_buckets[BUCKET_HASH(sa, from, rcpt, AUTOWHITE_BUCKETS)]; for (aw = TAILQ_FIRST(&autowhite_head); aw; aw = next_aw) { next_aw = TAILQ_NEXT(aw, a_list); if (autowhite_timeout(aw, &now)) { dirty++; continue; } /* * Look for our record */ if (ip_match(sa, aw->a_sa, mask) && ((conf.c_lazyaw == 1) || ((strcasecmp(from, aw->a_from) == 0) && (strcasecmp(rcpt, aw->a_rcpt) == 0)))) { timeradd(&now, &delay, &aw->a_tv); /* Rearrange the big queue */ TAILQ_REMOVE(&autowhite_head, aw, a_list); TAILQ_INSERT_TAIL(&autowhite_head, aw, a_list); dirty++; break; } } AUTOWHITE_UNLOCK; dump_touch(dirty); dirty = 0; if (aw == NULL) return EXF_NONE; mg_log(LOG_INFO, "%s: addr %s from %s rcpt %s: " "autowhitelisted for more %02d:%02d:%02d", queueid, addr, from, rcpt, h, mn, s); /* * We need to tell our peers about this, we use a * fictive pending record */ PENDING_LOCK; pending = pending_get(sa, salen, from, rcpt, now.tv_sec + gldelay); if (pending != NULL) { peer_delete(pending, now.tv_sec + autowhite); pending_put(pending); ++dirty; } PENDING_UNLOCK; dump_touch(dirty); return EXF_WHITELIST | EXF_AUTO; } int autowhite_textdump(stream) FILE *stream; { struct autowhite *aw; struct autowhite *next_aw; struct timeval now; int done = 0; char textdate[DATELEN + 1]; char textaddr[IPADDRSTRLEN]; struct tm tm; time_t ti; (void)gettimeofday(&now, NULL); fprintf(stream, "\n\n#\n# Auto-whitelisted tuples\n#\n"); fprintf(stream, "# Sender IP\t%s\t%s\tExpire\n", "Sender e-mail", "Recipient e-mail"); AUTOWHITE_LOCK; for (aw = TAILQ_FIRST(&autowhite_head); aw; aw = next_aw) { next_aw = TAILQ_NEXT(aw, a_list); if (autowhite_timeout(aw, &now)) continue; iptostring(aw->a_sa, aw->a_salen, textaddr, sizeof(textaddr)); if (conf.c_dump_no_time_translation) { fprintf(stream, "%s\t%s\t%s\t%ld AUTO\n", textaddr, aw->a_from, aw->a_rcpt, (long)aw->a_tv.tv_sec); } else { ti = aw->a_tv.tv_sec; localtime_r(&ti, &tm); strftime(textdate, DATELEN, "%Y-%m-%d %T", &tm); fprintf(stream, "%s\t%s\t%s\t%ld AUTO # %s\n", textaddr, aw->a_from, aw->a_rcpt, (long)aw->a_tv.tv_sec, textdate); } done++; } AUTOWHITE_UNLOCK; return done; } /* * A new entry is inserted to the back of the queue in most cases, * but it is not true in these situations: * - The conf.c_autowhite_validity was shortened * - System clock was turned to the past * * To ensure that the queue is sorted by expiration times (a_tv), * we need to find the right position where to insert a new entry. */ struct autowhite * autowhite_get(sa, salen, from, rcpt, date) /* autowhite list must be locked */ struct sockaddr *sa; socklen_t salen; char *from; char *rcpt; time_t date; { struct autowhite *aw; if ((aw = malloc(sizeof(*aw))) == NULL) { mg_log(LOG_ERR, "malloc failed: %s", strerror(errno)); exit(EX_OSERR); } bzero((void *)aw, sizeof(*aw)); if ((aw->a_sa = malloc(salen)) == NULL || (aw->a_from = strdup(from)) == NULL || (aw->a_rcpt = strdup(rcpt)) == NULL) { mg_log(LOG_ERR, "malloc failed: %s", strerror(errno)); exit(EX_OSERR); } aw->a_tv.tv_sec = date; memcpy(aw->a_sa, sa, salen); aw->a_salen = salen; TAILQ_INSERT_TAIL(&autowhite_head, aw, a_list); TAILQ_INSERT_TAIL(&autowhite_buckets[BUCKET_HASH(aw->a_sa, from, rcpt, AUTOWHITE_BUCKETS)].b_autowhite_head, aw, ab_list); return aw; } void autowhite_put(aw) /* autowhite list must be locked */ struct autowhite *aw; { TAILQ_REMOVE(&autowhite_head, aw, a_list); TAILQ_REMOVE(&autowhite_buckets[BUCKET_HASH(aw->a_sa, aw->a_from, aw->a_rcpt, AUTOWHITE_BUCKETS)].b_autowhite_head, aw, ab_list); free(aw->a_sa); free(aw->a_from); free(aw->a_rcpt); free(aw); return; } int autowhite_del_addr(sa, salen) struct sockaddr *sa; socklen_t salen; { struct autowhite *aw; struct autowhite *next_aw; int count = 0; AUTOWHITE_LOCK; for (aw = TAILQ_FIRST(&autowhite_head); aw; aw = next_aw) { next_aw = TAILQ_NEXT(aw, a_list); if (memcmp(sa, aw->a_sa, salen) == 0) { char buf[IPADDRSTRLEN]; iptostring(aw->a_sa, aw->a_salen, buf, sizeof(buf)); mg_log(LOG_INFO, "(local): addr %s from %s rcpt %s: " "autowhitelisted entry expired", buf, aw->a_from, aw->a_rcpt); autowhite_put(aw); count++; } } AUTOWHITE_UNLOCK; dump_touch(count); return count; } @ 1.56 log @Add SPF status selection to ACL @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.55 2007/07/08 21:02:28 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.55 2007/07/08 21:02:28 manu Exp $"); d323 1 a345 2 time_t ti; @ 1.55 log @Add hooks for libdmalloc @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.54 2007/03/29 03:58:51 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.54 2007/03/29 03:58:51 manu Exp $"); d65 1 @ 1.55.2.1 log @Avoid C99 specific syntax (Greg Troxel) @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.55 2007/07/08 21:02:28 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.55 2007/07/08 21:02:28 manu Exp $"); a321 1 time_t ti; d344 2 @ 1.54 log @%% syntax in format strings (AIDA Shinra) Clarified "%Xm" and "%Xh" semantics (AIDA Shinra) Fixed a memory leak at mlfi_eom (AIDA Shinra) ix a bug where doing RCPT twice when blacklised succeed (AIDA Shinra) @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.53 2007/01/22 14:08:16 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.53 2007/01/22 14:08:16 manu Exp $"); d68 4 @ 1.53 log @Do not sort the databases, it makes startup slow and buys nothing Bump to 3.1.4 @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.52 2006/11/29 21:08:54 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.52 2006/11/29 21:08:54 manu Exp $"); d304 1 a304 1 return EXF_AUTO; @ 1.52 log @Fix timespamp on sparc64 (Gert Doering) @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.51 2006/08/30 04:57:58 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.51 2006/08/30 04:57:58 manu Exp $"); a67 2 static void autowhite_insert_to_queue(struct autowhite *); d92 1 d94 3 a96 1 autowhite_timeout(void) a97 3 struct autowhite *aw; struct autowhite *next_aw; struct timeval now; d100 2 a101 11 gettimeofday(&now, NULL); AUTOWHITE_LOCK; for (aw = TAILQ_FIRST(&autowhite_head); aw; aw = next_aw) { next_aw = TAILQ_NEXT(aw, a_list); /* * Expiration */ if (aw->a_tv.tv_sec < now.tv_sec) { char buf[IPADDRSTRLEN]; d103 4 a106 4 iptostring(aw->a_sa, aw->a_salen, buf, sizeof(buf)); mg_log(LOG_INFO, "(local): addr %s from %s rcpt %s: " "autowhitelisted entry expired", buf, aw->a_from, aw->a_rcpt); d108 3 a110 3 autowhite_put(aw); dirty++; a111 6 continue; } break; } AUTOWHITE_UNLOCK; d125 1 a154 2 dirty = autowhite_timeout(); d157 8 a164 1 TAILQ_FOREACH(aw, &b->b_autowhite_head, ab_list) { d176 1 a176 1 autowhite_insert_to_queue(aw); d217 1 a250 2 dirty = autowhite_timeout(); d253 8 a260 1 TAILQ_FOREACH(aw, &b->b_autowhite_head, ab_list) { d272 1 a272 1 autowhite_insert_to_queue(aw); d312 2 d319 2 d326 6 a331 1 TAILQ_FOREACH(aw, &autowhite_head, a_list) { a368 19 /* autowhite list must be locked */ static void autowhite_insert_to_queue(newentry) struct autowhite *newentry; { struct autowhite *aw; TAILQ_FOREACH_REVERSE(aw, &autowhite_head, autowhitelist, a_list) { if (aw->a_tv.tv_sec < newentry->a_tv.tv_sec || (aw->a_tv.tv_sec == newentry->a_tv.tv_sec && aw->a_tv.tv_usec < newentry->a_tv.tv_usec)) break; } if (aw) TAILQ_INSERT_AFTER(&autowhite_head, aw, newentry, a_list); else TAILQ_INSERT_HEAD(&autowhite_head, newentry, a_list); } d397 1 a397 1 autowhite_insert_to_queue(aw); @ 1.51 log @Fix various race conditions (AIDA Shinra) @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.50 2006/08/27 20:54:40 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.50 2006/08/27 20:54:40 manu Exp $"); d336 4 a339 1 localtime_r((time_t *)&aw->a_tv.tv_sec, &tm); @ 1.51.2.1 log @Back out race conditions fixes (too intrusive, will be back in 3.1.x) @ text @d68 3 a72 2 pthread_rwlock_t autowhite_lock; pthread_mutex_t autowhite_change_lock; d76 1 a76 1 int error, i; a85 7 if ((error = pthread_rwlock_init(&autowhite_lock, NULL)) != 0 || (error = pthread_mutex_init(&autowhite_change_lock, NULL)) != 0) { mg_log(LOG_ERR, "pthread_rwlock_init failed: %s", strerror(error)); exit(EX_OSERR); } a88 9 if ((error = pthread_mutex_init(&autowhite_buckets[i].bucket_mtx, NULL)) != 0) { mg_log(LOG_ERR, "pthread_mutex_init failed: %s", strerror(error)); exit(EX_OSERR); } d104 1 a104 1 AUTOWHITE_WRLOCK; a141 1 struct autowhite *next_aw; d173 1 a173 1 AUTOWHITE_RDLOCK; d175 1 a175 22 pthread_mutex_lock(&b->bucket_mtx); for (aw = TAILQ_FIRST(&b->b_autowhite_head); aw; aw = next_aw) { next_aw = TAILQ_NEXT(aw, ab_list); /* * Expiration (left this one in too until the list gets sorted) */ if (aw->a_tv.tv_sec < now.tv_sec) { char buf[IPADDRSTRLEN]; iptostring(aw->a_sa, aw->a_salen, buf, sizeof(buf)); mg_log(LOG_INFO, "(local): addr %s from %s rcpt %s: " "autowhitelisted entry expired", buf, aw->a_from, aw->a_rcpt); autowhite_put(aw); dirty++; continue; } d185 1 a185 2 /* Push it at the back of the big queue */ pthread_mutex_lock(&autowhite_change_lock); d187 1 a187 2 TAILQ_INSERT_TAIL(&autowhite_head, aw, a_list); pthread_mutex_unlock(&autowhite_change_lock); a209 1 pthread_mutex_unlock(&b->bucket_mtx); d212 1 a212 2 if (dirty != 0) dump_dirty += dirty; a227 1 struct autowhite *next_aw; d263 1 a263 1 AUTOWHITE_RDLOCK; d265 1 a265 26 pthread_mutex_lock(&b->bucket_mtx); for (aw = TAILQ_FIRST(&b->b_autowhite_head); aw; aw = next_aw) { next_aw = TAILQ_NEXT(aw, ab_list); /* * Do expiration first as we don't want * an outdated record to match * I've left this one too until the lists * gets sorted */ if (aw->a_tv.tv_sec < now.tv_sec) { char buf[IPADDRSTRLEN]; iptostring(aw->a_sa, aw->a_salen, buf, sizeof(buf)); mg_log(LOG_INFO, "(local): addr %s from %s rcpt %s: " "autowhitelisted entry expired", buf, aw->a_from, aw->a_rcpt); autowhite_put(aw); aw = NULL; dirty++; continue; } d275 1 a275 2 /* Push it at the back of the big queue */ pthread_mutex_lock(&autowhite_change_lock); d277 1 a277 2 TAILQ_INSERT_TAIL(&autowhite_head, aw, a_list); pthread_mutex_unlock(&autowhite_change_lock); a283 1 pthread_mutex_unlock(&b->bucket_mtx); d286 2 a287 2 if (dirty != 0) dump_dirty += dirty; d299 1 a299 1 PENDING_WRLOCK; d304 1 d307 2 d326 1 a326 2 AUTOWHITE_RDLOCK; pthread_mutex_lock(&autowhite_change_lock); a346 1 pthread_mutex_unlock(&autowhite_change_lock); d352 29 d409 1 a409 2 pthread_mutex_lock(&autowhite_change_lock); TAILQ_INSERT_TAIL(&autowhite_head, aw, a_list); a411 1 pthread_mutex_unlock(&autowhite_change_lock); d417 1 a417 1 autowhite_put(aw) /* autowhite list must be write-locked */ d420 1 a420 2 pthread_mutex_lock(&autowhite_change_lock); TAILQ_REMOVE(&autowhite_head, aw, a_list); a423 1 pthread_mutex_unlock(&autowhite_change_lock); d441 1 a441 1 AUTOWHITE_WRLOCK; a454 2 dump_dirty++; a455 1 break; d459 1 @ 1.51.2.2 log @Fix timespamp on sparc64 (Gert Doering) @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.51.2.1 2006/09/04 22:05:58 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.51.2.1 2006/09/04 22:05:58 manu Exp $"); d404 1 a404 4 time_t ti; ti = aw->a_tv.tv_sec; localtime_r(&ti, &tm); @ 1.50 log @Remove the need of LOG_PERROR, make sure no log is missed @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.49 2006/08/20 05:53:25 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.49 2006/08/20 05:53:25 manu Exp $"); d68 3 a72 2 pthread_rwlock_t autowhite_lock; pthread_mutex_t autowhite_change_lock; d76 1 a76 1 int error, i; a85 7 if ((error = pthread_rwlock_init(&autowhite_lock, NULL)) != 0 || (error = pthread_mutex_init(&autowhite_change_lock, NULL)) != 0) { mg_log(LOG_ERR, "pthread_rwlock_init failed: %s", strerror(error)); exit(EX_OSERR); } a88 9 if ((error = pthread_mutex_init(&autowhite_buckets[i].bucket_mtx, NULL)) != 0) { mg_log(LOG_ERR, "pthread_mutex_init failed: %s", strerror(error)); exit(EX_OSERR); } d104 1 a104 1 AUTOWHITE_WRLOCK; a141 1 struct autowhite *next_aw; d173 1 a173 1 AUTOWHITE_RDLOCK; d175 1 a175 22 pthread_mutex_lock(&b->bucket_mtx); for (aw = TAILQ_FIRST(&b->b_autowhite_head); aw; aw = next_aw) { next_aw = TAILQ_NEXT(aw, ab_list); /* * Expiration (left this one in too until the list gets sorted) */ if (aw->a_tv.tv_sec < now.tv_sec) { char buf[IPADDRSTRLEN]; iptostring(aw->a_sa, aw->a_salen, buf, sizeof(buf)); mg_log(LOG_INFO, "(local): addr %s from %s rcpt %s: " "autowhitelisted entry expired", buf, aw->a_from, aw->a_rcpt); autowhite_put(aw); dirty++; continue; } d185 1 a185 2 /* Push it at the back of the big queue */ pthread_mutex_lock(&autowhite_change_lock); d187 1 a187 2 TAILQ_INSERT_TAIL(&autowhite_head, aw, a_list); pthread_mutex_unlock(&autowhite_change_lock); a209 1 pthread_mutex_unlock(&b->bucket_mtx); d212 1 a212 2 if (dirty != 0) dump_dirty += dirty; a227 1 struct autowhite *next_aw; d263 1 a263 1 AUTOWHITE_RDLOCK; d265 1 a265 26 pthread_mutex_lock(&b->bucket_mtx); for (aw = TAILQ_FIRST(&b->b_autowhite_head); aw; aw = next_aw) { next_aw = TAILQ_NEXT(aw, ab_list); /* * Do expiration first as we don't want * an outdated record to match * I've left this one too until the lists * gets sorted */ if (aw->a_tv.tv_sec < now.tv_sec) { char buf[IPADDRSTRLEN]; iptostring(aw->a_sa, aw->a_salen, buf, sizeof(buf)); mg_log(LOG_INFO, "(local): addr %s from %s rcpt %s: " "autowhitelisted entry expired", buf, aw->a_from, aw->a_rcpt); autowhite_put(aw); aw = NULL; dirty++; continue; } d275 1 a275 2 /* Push it at the back of the big queue */ pthread_mutex_lock(&autowhite_change_lock); d277 1 a277 2 TAILQ_INSERT_TAIL(&autowhite_head, aw, a_list); pthread_mutex_unlock(&autowhite_change_lock); a283 1 pthread_mutex_unlock(&b->bucket_mtx); d286 2 a287 2 if (dirty != 0) dump_dirty += dirty; d299 1 a299 1 PENDING_WRLOCK; d304 1 d307 2 d326 1 a326 2 AUTOWHITE_RDLOCK; pthread_mutex_lock(&autowhite_change_lock); a346 1 pthread_mutex_unlock(&autowhite_change_lock); d352 29 d409 1 a409 2 pthread_mutex_lock(&autowhite_change_lock); TAILQ_INSERT_TAIL(&autowhite_head, aw, a_list); a411 1 pthread_mutex_unlock(&autowhite_change_lock); d417 1 a417 1 autowhite_put(aw) /* autowhite list must be write-locked */ d420 1 a420 2 pthread_mutex_lock(&autowhite_change_lock); TAILQ_REMOVE(&autowhite_head, aw, a_list); a423 1 pthread_mutex_unlock(&autowhite_change_lock); d441 1 a441 1 AUTOWHITE_WRLOCK; a454 2 dump_dirty++; a455 1 break; d459 1 @ 1.49 log @From Fabien Tassin Add more log output for blackist and flushaddr Allow rejecting by tempfail on blacklist configuration @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.48 2006/08/20 05:30:39 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.48 2006/08/20 05:30:39 manu Exp $"); d80 1 a80 1 syslog(LOG_ERR, d88 1 a88 1 syslog(LOG_ERR, "pthread_rwlock_init failed: %s", d99 1 a99 1 syslog(LOG_ERR, d130 1 a130 1 syslog(LOG_INFO, "(local): addr %s from %s rcpt %s: " d202 1 a202 1 syslog(LOG_INFO, "(local): addr %s from %s rcpt %s: " d230 1 a230 1 syslog(LOG_INFO, "%s: addr %s from %s rcpt %s: " d245 1 a245 1 syslog(LOG_INFO, "%s: addr %s from %s rcpt %s: " d321 1 a321 1 syslog(LOG_INFO, "(local): addr %s from %s rcpt %s: " d362 1 a362 1 syslog(LOG_INFO, "%s: addr %s from %s rcpt %s: " d432 1 a432 1 syslog(LOG_ERR, "malloc failed: %s", strerror(errno)); d441 1 a441 1 syslog(LOG_ERR, "malloc failed: %s", strerror(errno)); d493 1 a493 1 syslog(LOG_INFO, "(local): addr %s from %s rcpt %s: " @ 1.48 log @Fix bugs that prevented IPv6 address resolution @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.47 2006/08/08 04:21:44 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.47 2006/08/08 04:21:44 manu Exp $"); d476 1 a476 1 void d483 1 d498 1 d506 1 a506 1 return; @ 1.47 log @bugfix in IPv6 address resolution @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.46 2006/08/01 14:55:20 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.46 2006/08/01 14:55:20 manu Exp $"); d127 1 a127 1 char buf[IPADDRSTRLEN + 1]; d199 1 a199 1 char buf[IPADDRLEN + 1]; d489 1 a489 1 char buf[IPADDRLEN + 1]; @ 1.46 log @flushaddr @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.45 2006/07/24 22:49:43 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.45 2006/07/24 22:49:43 manu Exp $"); d127 1 a127 1 char buf[IPADDRLEN + 1]; @ 1.45 log @per-acl greylist and autowhitelist setting @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.44 2006/05/04 19:29:45 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.44 2006/05/04 19:29:45 manu Exp $"); d213 1 a213 1 /* d475 31 @ 1.44 log @Make log output consistent @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.43 2006/03/03 21:54:31 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.43 2006/03/03 21:54:31 manu Exp $"); d158 1 a158 1 struct timeval now, delay; a159 1 time_t autowhite_validity; d164 1 a164 3 if ((autowhite_validity = conf.c_autowhite_validity) == 0) return; d167 1 a167 2 delay.tv_sec = autowhite_validity; delay.tv_usec = 0; d169 3 a171 3 h = autowhite_validity / 3600; mn = ((autowhite_validity % 3600) / 60); s = (autowhite_validity % 3600) % 60; d220 1 a220 1 timeradd(&now, &delay, &aw->a_tv); d241 1 a241 1 aw = autowhite_get(sa, salen, from, rcpt, date); d259 1 a259 1 autowhite_check(sa, salen, from, rcpt, queueid) d265 2 a272 1 time_t autowhite_validity; d278 1 a278 1 if ((autowhite_validity = conf.c_autowhite_validity) == 0) d282 1 a282 1 delay.tv_sec = autowhite_validity; d285 3 a287 3 h = autowhite_validity / 3600; mn = ((autowhite_validity % 3600) / 60); s = (autowhite_validity % 3600) % 60; d370 1 a370 2 pending = pending_get(sa, salen, from, rcpt, (time_t)0); d372 1 a372 1 peer_delete(pending); d427 1 a427 1 time_t *date; a429 6 struct timeval now, delay; time_t autowhite_validity = conf.c_autowhite_validity; gettimeofday(&now, NULL); delay.tv_sec = autowhite_validity; delay.tv_usec = 0; d444 1 a448 5 if (date == NULL) timeradd(&now, &delay, &aw->a_tv); else aw->a_tv.tv_sec = *date; @ 1.43 log @Cosmetic changes in debug logs (Fredrik Pettai) @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.42 2006/01/08 00:38:24 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.42 2006/01/08 00:38:24 manu Exp $"); d130 1 a130 1 syslog(LOG_INFO, "(local) addr %s from %s rcpt %s: " d206 1 a206 1 syslog(LOG_INFO, "(local) addr %s from %s rcpt %s: " d324 1 a324 1 syslog(LOG_INFO, "(local) addr %s from %s rcpt %s: " @ 1.42 log @From Ranko Zivojnovic : * Bucketed search of autowhitelisted and pending entries rather than write-locked only-one-at-the-time search * Large buffer for writing the dump file * Disabled having the time comment by default next to each line in the dump (improves dump performance by order of magnitude on my Solaris). If "verbose" enabled - behavior will be as before * 'mxsync' client connection is set non-blocking, but there were no checks if fprintf actually delivers the complete sync message to the peer or just the part of it. * Also, when reading the 'mxsync' client connection, being non- blocking, fgets() can bail out with NULL and EAGAIN which is not fatal error for the connection. @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.41 2005/10/04 19:15:55 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.41 2005/10/04 19:15:55 manu Exp $"); d130 1 a130 1 syslog(LOG_INFO, "addr %s from %s rcpt %s: " d206 1 a206 1 syslog(LOG_INFO, "addr %s from %s rcpt %s: " d324 1 a324 1 syslog(LOG_INFO, "addr %s from %s rcpt %s: " @ 1.41 log @Correctly update autowhitelist when subnetmak is in use @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.40 2005/09/21 13:15:22 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.40 2005/09/21 13:15:22 manu Exp $"); d47 1 d69 1 d71 1 d75 1 a75 1 int error; d78 10 a87 1 if ((error = pthread_rwlock_init(&autowhite_lock, NULL)) != 0) { d93 13 d109 38 d164 1 d191 7 a197 3 AUTOWHITE_WRLOCK; for (aw = TAILQ_FIRST(&autowhite_head); aw; aw = next_aw) { next_aw = TAILQ_NEXT(aw, a_list); d200 1 a200 1 * Expiration d226 6 d253 1 d279 1 d306 7 a312 3 AUTOWHITE_WRLOCK; for (aw = TAILQ_FIRST(&autowhite_head); aw; aw = next_aw) { next_aw = TAILQ_NEXT(aw, a_list); d317 2 d345 6 d356 1 d398 1 a399 3 localtime_r((time_t *)&aw->a_tv.tv_sec, &tm); strftime(textdate, DATELEN, "%Y-%m-%d %T", &tm); d401 15 a415 5 fprintf(stream, "%s\t%s\t%s\t%ld AUTO # %s\n", textaddr, aw->a_from, aw->a_rcpt, (long)aw->a_tv.tv_sec, textdate); d419 1 d463 1 d465 3 d476 1 d478 4 @ 1.40 log @Patch fix for unlock location. @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.38 2004/12/08 22:23:09 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.38 2004/12/08 22:23:09 manu Exp $"); d100 1 d116 11 d152 1 a152 1 if (ip_equal(sa, aw->a_sa) && d219 11 a256 10 switch (sa->sa_family) { case AF_INET: mask = (ipaddr *)&conf.c_match_mask; break; #ifdef AF_INET6 case AF_INET6: mask = (ipaddr *)&conf.c_match_mask6; break; #endif } @ 1.39 log @Fix deadlock in autowhitelisting code (attila.bruncsak) @ text @a272 1 PENDING_UNLOCK; d277 1 @ 1.38 log @New ACL framework for whitelist and greylist (Remy Card) Tell MX peers about autowhitelist prolongation (Remy Card) @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.37 2004/09/13 18:41:54 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.37 2004/09/13 18:41:54 manu Exp $"); a251 13 syslog(LOG_INFO, "%s: addr %s from %s rcpt %s: " "autowhitelisted for more %02d:%02d:%02d", queueid, addr, from, rcpt, h, mn, s); /* * We need to tell our peers about this, we use a * fictive pending record */ pending = pending_get(sa, salen, from, rcpt, (time_t)0); if (pending != NULL) { peer_delete(pending); pending_put(pending); } d260 2 a261 2 if (aw != NULL) return EXF_AUTO; d263 16 a278 1 return EXF_NONE; @ 1.37 log @malloc e-mail addresses, avoids truncation at 32 chars, from Hajimu Umemoto @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.36 2004/08/02 12:11:48 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.36 2004/08/02 12:11:48 manu Exp $"); a60 1 #include "except.h" d64 2 d185 1 d255 10 @ 1.36 log @Changed ipaddr_t into ipaddr to fix a build problem on Solaris @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.35 2004/08/01 09:27:03 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.35 2004/08/01 09:27:03 manu Exp $"); d141 2 a142 2 ((strncasecmp(from, aw->a_from, ADDRLEN) == 0) && (strncasecmp(rcpt, aw->a_rcpt, ADDRLEN) == 0)))) { d244 2 a245 2 ((strncasecmp(from, aw->a_from, ADDRLEN) == 0) && (strncasecmp(rcpt, aw->a_rcpt, ADDRLEN) == 0)))) { d278 1 a278 1 fprintf(stream, "# Sender IP %32s %32s Expire\n", d289 1 a289 1 "%s %32s %32s %ld AUTO # %s\n", d323 3 a325 1 if ((aw->a_sa = malloc(salen)) == NULL) { a331 4 strncpy(aw->a_from, from, ADDRLEN); aw->a_from[ADDRLEN] = '\0'; strncpy(aw->a_rcpt, rcpt, ADDRLEN); aw->a_rcpt[ADDRLEN] = '\0'; d349 2 @ 1.35 log @Full blown IPv6 support, from Hajimu Umemoto Correctly clean rc-debian.sh @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.34 2004/06/14 20:43:21 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.34 2004/06/14 20:43:21 manu Exp $"); d189 1 a189 1 ipaddr_t *mask = NULL; d234 1 a234 1 mask = (ipaddr_t *)&conf.c_match_mask; d238 1 a238 1 mask = (ipaddr_t *)&conf.c_match_mask6; @ 1.34 log @syslog the expired autowhite entry correctly, from Mattieu Herrb @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.33 2004/06/12 08:41:56 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.33 2004/06/12 08:41:56 manu Exp $"); d84 3 a86 2 autowhite_add(in, from, rcpt, date, queueid) struct in_addr *in; d95 1 a95 1 char addr[IPADDRLEN + 1]; d111 2 a112 1 inet_ntop(AF_INET, in, addr, IPADDRLEN); d124 1 a124 1 inet_ntop(AF_INET, &aw->a_in, buf, IPADDRLEN); d139 1 a139 1 if ((in->s_addr == aw->a_in.s_addr) && d158 1 a158 1 aw = autowhite_get(in, from, rcpt, date); d175 3 a177 2 autowhite_check(in, from, rcpt, queueid) struct in_addr *in; d185 1 a185 1 char addr[IPADDRLEN + 1]; d189 1 d202 2 a203 1 inet_ntop(AF_INET, in, addr, IPADDRLEN); d214 1 a214 1 char buf[IPADDRLEN + 1]; d216 1 a216 1 inet_ntop(AF_INET, &aw->a_in, buf, IPADDRLEN); d232 11 a242 1 if ((IP_MATCH(in, &aw->a_in)) && d274 1 a274 1 char textaddr[IPADDRLEN + 1]; d286 1 a286 1 inet_ntop(AF_INET, &aw->a_in, textaddr, IPADDRLEN); d301 3 a303 2 autowhite_get(in, from, rcpt, date) /* autowhite list must be locked */ struct in_addr *in; d323 7 a329 1 aw->a_in.s_addr = in->s_addr; d350 1 @ 1.33 log @Minor bug fixes in queue management from Wolfgang Solfrank @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.32 2004/06/08 14:47:47 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.32 2004/06/08 14:47:47 manu Exp $"); d120 7 a130 4 syslog(LOG_INFO, "addr %s from %s rcpt %s: " "autowhitelisted entry expired", addr, from, rcpt); d209 7 a219 4 syslog(LOG_INFO, "addr %s from %s rcpt %s: " "autowhitelisted entry expired", addr, from, rcpt); @ 1.32 log @Correctly check pthread function return values @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.31 2004/05/26 09:14:29 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.31 2004/05/26 09:14:29 manu Exp $"); d91 2 a92 2 struct autowhite *aw = NULL; struct autowhite *prev_aw = NULL; d113 2 a114 2 if (!TAILQ_EMPTY(&autowhite_head)) { TAILQ_FOREACH(aw, &autowhite_head, a_list) { d116 31 a146 38 /* * Expiration */ if (aw->a_tv.tv_sec < now.tv_sec) { autowhite_put(aw); aw = NULL; dirty++; syslog(LOG_INFO, "addr %s from %s rcpt %s: " "autowhitelisted entry expired", addr, from, rcpt); if (TAILQ_EMPTY(&autowhite_head)) break; if ((aw = prev_aw) == NULL) aw = TAILQ_FIRST(&autowhite_head); continue; } prev_aw = aw; /* * Look for an already existing entry */ if ((in->s_addr == aw->a_in.s_addr) && ((conf.c_lazyaw == 1) || ((strncasecmp(from, aw->a_from, ADDRLEN) == 0) && (strncasecmp(rcpt, aw->a_rcpt, ADDRLEN) == 0)))) { timeradd(&now, &delay, &aw->a_tv); dirty++; syslog(LOG_INFO, "%s: addr %s from %s rcpt %s: " "autowhitelisted for more %02d:%02d:%02d", queueid, addr, from, rcpt, h, mn, s); break; } } d149 2 a150 2 /* * Entry not found, create it d176 2 a177 2 struct autowhite *aw = NULL; struct autowhite *prev_aw = NULL; d198 35 a232 40 if (!TAILQ_EMPTY(&autowhite_head)) { TAILQ_FOREACH(aw, &autowhite_head, a_list) { /* * Do expiration first as we don't want * an outdated record to match */ if (aw->a_tv.tv_sec < now.tv_sec) { autowhite_put(aw); aw = NULL; dirty++; syslog(LOG_INFO, "addr %s from %s rcpt %s: " "autowhitelisted entry expired", addr, from, rcpt); if (TAILQ_EMPTY(&autowhite_head)) break; if ((aw = prev_aw) == NULL) aw = TAILQ_FIRST(&autowhite_head); continue; } prev_aw = aw; /* * Look for our record */ if ((IP_MATCH(in, &aw->a_in)) && ((conf.c_lazyaw == 1) || ((strncasecmp(from, aw->a_from, ADDRLEN) == 0) && (strncasecmp(rcpt, aw->a_rcpt, ADDRLEN) == 0)))) { timeradd(&now, &delay, &aw->a_tv); dirty++; syslog(LOG_INFO, "%s: addr %s from %s rcpt %s: " "autowhitelisted for more %02d:%02d:%02d", queueid, addr, from, rcpt, h, mn, s); break; } @ 1.31 log @timeout option @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.30 2004/05/25 08:58:48 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.30 2004/05/25 08:58:48 manu Exp $"); d71 1 d74 5 a78 1 pthread_rwlock_init(&autowhite_lock, NULL); @ 1.30 log @Account autowhite fields in textdump @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.29 2004/05/25 08:37:08 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.29 2004/05/25 08:37:08 manu Exp $"); d228 3 a230 2 (strncasecmp(from, aw->a_from, ADDRLEN) == 0) && (strncasecmp(rcpt, aw->a_rcpt, ADDRLEN) == 0)) { @ 1.29 log @dumpfreq revisited @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.28 2004/05/24 22:00:38 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.28 2004/05/24 22:00:38 manu Exp $"); d277 2 @ 1.28 log @Case insensitive check for autowhitelist everywhere (was inconsistent) @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.27 2004/05/24 21:22:02 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.27 2004/05/24 21:22:02 manu Exp $"); d165 1 a165 1 if (dirty != 0) { a166 2 dump_flush(); } d243 1 a243 1 if (dirty != 0) { a244 2 dump_flush(); } @ 1.27 log @Back out Berkeley DB stuff, it will now live on the BDB branch. @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.22 2004/05/06 13:50:54 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.22 2004/05/06 13:50:54 manu Exp $"); d230 2 a231 2 (strncmp(from, aw->a_from, ADDRLEN) == 0) && (strncmp(rcpt, aw->a_rcpt, ADDRLEN) == 0)) { @ 1.26 log @remove now unused queue.h headers @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.25 2004/05/23 13:03:41 manu Exp $ */ a31 1 #include "config.h" d35 2 a36 1 __RCSID("$Id: autowhite.c,v 1.25 2004/05/23 13:03:41 manu Exp $"); d38 6 a46 1 #include a49 2 #include #include a52 1 #include a56 6 #ifdef HAVE_DB_185_H #include #else #include #endif a59 4 #ifndef O_EXLOCK #define O_EXLOCK 0 #endif d66 1 a66 1 DB *aw_db = NULL; d69 1 a69 1 int d72 1 d75 1 a75 27 if ((aw_db = dbopen(conf.c_autowhitedb, O_RDWR|O_EXLOCK|O_CREAT, 0644, DB_BTREE, NULL)) == NULL) { syslog(LOG_ERR, "dbopen \"%s\" failed: %s", conf.c_autowhitedb, strerror(errno)); exit(EX_OSERR); } /* * Create or update the option record * Check if we need to reload from the text dump */ return autowhite_db_options(AS_COLD); } void autowhite_destroy(void) { aw_db->close(aw_db); if (unlink(conf.c_autowhitedb) != 0) { syslog(LOG_ERR, "Cannot delete \"%s\": %s", conf.c_autowhitedb, strerror(errno)); exit(EX_OSERR); } autowhite_init(); return; d86 3 a88 3 struct autowhite *aw; struct autowhite awrec; time_t now; d92 1 a92 4 DBT key; DBT rec; char keystr[KEYLEN + 1]; int found; d97 3 a99 1 now = time(NULL); d107 3 a109 2 key.data = autowhite_makekey(keystr, KEYLEN, in, from, rcpt); key.size = strlen(keystr) + 1; d111 45 a155 3 AUTOWHITE_RDLOCK; found = aw_db->get(aw_db, &key, &rec, 0); AUTOWHITE_UNLOCK; d157 1 a157 14 switch(found) { case 0: /* Tuple found */ aw = (struct autowhite *)rec.data; /* * Renew the autowhitelisting expiration delay */ aw->a_expire = now + autowhite_validity; AUTOWHITE_WRLOCK; if ((aw_db->put(aw_db, &key, &rec, 0)) != 0) syslog(LOG_ERR, "db->put failed: %s", strerror(errno)); dump_dirty++; AUTOWHITE_UNLOCK; d160 1 a160 1 "autowhitelisted for more %02d:%02d:%02d", d162 2 d165 3 a167 9 break; case 1: /* Not found, create it */ autowhite_get(in, from, rcpt, date, &awrec); break; default: syslog(LOG_ERR, "db->get failed: %s", strerror(errno)); break; a169 5 /* Flush changes to disk */ AUTOWHITE_RDLOCK; aw_db->sync(aw_db, 0); AUTOWHITE_UNLOCK; d180 3 a182 2 struct autowhite *aw; time_t now; d184 1 a184 1 time_t autowhite_validity = conf.c_autowhite_validity; d186 1 a186 5 DBT key; DBT rec; char keystr[KEYLEN + 1]; int found; int retval; d188 1 a188 1 if (autowhite_validity == 0) d191 3 a193 1 now = time(NULL); d201 24 a224 2 key.data = autowhite_makekey(keystr, KEYLEN, in, from, rcpt); key.size = strlen(keystr) + 1; d226 15 a240 18 AUTOWHITE_RDLOCK; found = aw_db->get(aw_db, &key, &rec, 0); AUTOWHITE_UNLOCK; switch(found) { case 0: /* Tuple found */ aw = (struct autowhite *)rec.data; /* * Is it expired? */ if (aw->a_expire < now) { syslog(LOG_INFO, "addr %s from %s rcpt %s: " "autowhitelisted entry expired", addr, from, rcpt); autowhite_put(keystr); retval = EXF_NONE; break; a241 27 /* * Renew the autowhitelisting expiration delay */ aw->a_expire = now + autowhite_validity; AUTOWHITE_WRLOCK; if ((aw_db->put(aw_db, &key, &rec, 0)) != 0) syslog(LOG_ERR, "db->put failed: %s", strerror(errno)); dump_dirty++; aw_db->sync(aw_db, 0); /* Flush changes to disk */ AUTOWHITE_UNLOCK; syslog(LOG_INFO, "%s: addr %s from %s rcpt %s: " "autowhitelisted for more %02d:%02d:%02d", queueid, addr, from, rcpt, h, mn, s); retval = EXF_AUTO; break; case 1: /* Not found */ retval = EXF_NONE; break; default: retval = EXF_NONE; syslog(LOG_ERR, "db->get failed: %s", strerror(errno)); break; a242 45 return retval; } void autowhite_get(in, from, rcpt, date, awp) struct in_addr *in; char *from; char *rcpt; time_t *date; struct autowhite *awp; { struct autowhite aw; time_t now; time_t autowhite_validity = conf.c_autowhite_validity; DBT key; DBT rec; char keystr[KEYLEN + 1]; if (awp == NULL) awp = &aw; bzero(awp, sizeof(*awp)); now = time(NULL); awp->a_in.s_addr = in->s_addr; strncpy(awp->a_from, from, ADDRLEN); awp->a_from[ADDRLEN] = '\0'; strncpy(awp->a_rcpt, rcpt, ADDRLEN); awp->a_rcpt[ADDRLEN] = '\0'; if (date == NULL) awp->a_expire = now + autowhite_validity; else awp->a_expire = *date; key.data = autowhite_makekey(keystr, KEYLEN, in, from, rcpt); key.size = strlen(key.data) + 1; rec.data = awp; rec.size = sizeof(*awp); AUTOWHITE_WRLOCK; if (aw_db->put(aw_db, &key, &rec, 0) != 0) syslog(LOG_ERR, "db->put failed: %s", strerror(errno)); dump_dirty++; d245 3 a247 6 if (conf.c_debug) { char addr[IPADDRLEN + 1]; inet_ntop(AF_INET, in, addr, IPADDRLEN); syslog(LOG_DEBUG, "%s from %s to %s autowhitelisted for %lds", addr, awp->a_from, awp->a_rcpt, awp->a_expire - now); d250 2 a251 14 return; } void autowhite_put(keystr) char *keystr; { DBT key; if (conf.c_debug) syslog(LOG_DEBUG, "removing key \"%s\" from autowhite", keystr); key.data = keystr; key.size = strlen(keystr) + 1; d253 1 a253 44 AUTOWHITE_WRLOCK; if (aw_db->del(aw_db, &key, 0) != 0) syslog(LOG_ERR, "db->del failed: %s", strerror(errno)); dump_dirty++; aw_db->sync(aw_db, 0); /* Flush changes to disk */ AUTOWHITE_UNLOCK; return; } char * autowhite_makekey(data, len, in, from, rcpt) char *data; size_t len; struct in_addr *in; char *from; char *rcpt; { char addr[IPADDRLEN + 1]; struct in_addr masked_addr; char fromcase[ADDRLEN + 1]; char rcptcase[ADDRLEN + 1]; unsigned int i; masked_addr.s_addr = in->s_addr & conf.c_match_mask.s_addr; inet_ntop(AF_INET, &masked_addr, addr, IPADDRLEN); if (conf.c_lazyaw) { snprintf(data, len, "%s", addr); } else { for (i = 0; (i < ADDRLEN) && (from[i] != '\0'); i++) fromcase[i] = tolower(from[i]); fromcase[i] = '\0'; for (i = 0; (i < ADDRLEN) && (rcpt[i] != '\0'); i++) rcptcase[i] = tolower(rcpt[i]); rcptcase[i] = '\0'; snprintf(data, len, "A\t%s\t%s\t%s", addr, fromcase, rcptcase); } data[len] = '\0'; printf("key = \"%s\"\n", data); return data; d257 1 a257 2 autowhite_update(update, stream) /* aw_db must be write-locked */ int update; a259 4 int finished = 0; DBT key; char keystr[KEYLEN + 1]; DBT rec; d261 1 a261 7 int res; int flag = R_FIRST; struct timeval begin; time_t now; int count = 0; int deleted = 0; int dirty = dump_dirty; d263 1 a263 1 char addr[IPADDRLEN + 1]; a264 2 DB *new_db = NULL; char new_db_name[MAXPATHLEN + 1]; d266 3 a268 2 gettimeofday(&begin, NULL); now = (time_t)begin.tv_sec; d270 11 a280 11 if (update) { syslog(LOG_INFO, "Rebuilding autowhite database keys"); snprintf(new_db_name, MAXPATHLEN, "%s.new", conf.c_autowhitedb); if ((new_db = dbopen(new_db_name, O_TRUNC|O_RDWR|O_EXLOCK|O_CREAT, 0644, DB_BTREE, NULL)) == NULL) { syslog(LOG_ERR, "dbopen \"%s\" failed: %s", new_db_name, strerror(errno)); exit(EX_OSERR); } d282 1 d284 1 a284 123 if (stream != NULL) { fprintf(stream, "\n\n#\n# Auto-whitelisted tuples\n#\n"); fprintf(stream, "# Sender IP %32s %32s Expire\n", "Sender e-mail", "Recipient e-mail"); } while (!finished) { res = aw_db->seq(aw_db, &key, &rec, flag); flag = R_NEXT; printf("key.size = %d rec.size = %d\n", key.size, rec.size); switch (res) { case 0: /* Skip the DB option record */ if (strcmp(key.data, DB_OPTIONS) == 0) break; count++; aw = (struct autowhite *)rec.data; /* * Handle timeouts */ if (aw->a_expire < now) { deleted++; if (conf.c_debug) { char addr[IPADDRLEN + 1]; inet_ntop(AF_INET, &aw->a_in, addr, IPADDRLEN); syslog(LOG_DEBUG, "awdel: %s from %s to %s timed out", addr, aw->a_from, aw->a_rcpt); } if (aw_db->del(aw_db, &key, 0) != 0) syslog(LOG_ERR, "db->del failed: %s", strerror(errno)); dump_dirty++; /* * Break: we don't want to update this key * as it has just gone away */ break; } /* * Update the key by overwriting the current record. */ if (update) { key.data = autowhite_makekey(keystr, KEYLEN, &aw->a_in, aw->a_from, aw->a_rcpt); key.size = strlen(keystr) + 1; if (new_db->put(new_db, &key, &rec, R_CURSOR) != 0) syslog(LOG_ERR, "db->put failed: %s", strerror(errno)); } /* * Output the data to a text dumpfile */ if (stream == NULL) break; localtime_r(&aw->a_expire, &tm); strftime(textdate, DATELEN, "%Y-%m-%d %T", &tm); inet_ntop(AF_INET, &aw->a_in, addr, IPADDRLEN); fprintf(stream, "%s %32s %32s %ld AUTO # %s\n", addr, aw->a_from, aw->a_rcpt, (unsigned long)aw->a_expire, textdate); break; case 1: finished = 1; break; case -1: /* FALLTHROUGH */ default: syslog(LOG_ERR, "db->seq failed (%d): %s", res, strerror(errno)); finished = 1; break; } } if (update) { if (aw_db->close(aw_db) != 0) syslog(LOG_ERR, "cannot close greylist db: %s", strerror(errno)); if (rename(new_db_name, conf.c_autowhitedb) != 0) { syslog(LOG_ERR, "rename \"%s\" to \"%s\" failed: %s", new_db_name, conf.c_autowhitedb, strerror(errno)); exit(EX_OSERR); } aw_db = new_db; } if (dump_dirty != dirty) aw_db->sync(aw_db, 0); if (conf.c_debug) { struct timeval end; struct timeval duration; gettimeofday(&end, NULL); timersub(&end, &begin, &duration); syslog(LOG_DEBUG, "autowhite_update done in %ld.%06lds, deleted %d over %d", duration.tv_sec, duration.tv_usec, deleted, count); } return count; d287 6 a292 3 int autowhite_db_options(as) autowhite_startup_t as; d294 3 a296 5 DBT key; DBT rec; struct db_options *dbo; struct db_options dborec; int found; d298 3 a300 2 key.data = DB_OPTIONS; key.size = strlen(DB_OPTIONS) + 1; d302 4 a305 3 AUTOWHITE_RDLOCK; found = aw_db->get(aw_db, &key, &rec, 0); AUTOWHITE_UNLOCK; d307 1 a307 14 switch(found) { case 0: /* found */ dbo = rec.data; /* * If this is a cold reload, check for improper shutdown */ if ((as == AS_COLD) && (dbo->dbo_busy != 0)) { if (kill(dbo->dbo_busy, 0) == 0) { syslog(LOG_ERR, "milter-greylist already running (pid %d)", dbo->dbo_busy); exit(EX_USAGE); } d309 5 a313 7 /* * Bad shutdown: Cause a reload from test dump * No need to update the dbo_busy field as the * database will be destroyed and recreated. */ return -1; } d315 4 a318 21 /* * Update the dbo_busy record with our PID */ if (as == AS_COLD) { if (atexit(*autowhite_shutdown) != 0) { syslog(LOG_ERR, "atexit failed: %s", strerror(errno)); exit(EX_OSERR); } dbo->dbo_busy = getpid(); AUTOWHITE_WRLOCK; if (aw_db->put(aw_db, &key, &rec, 0) != 0) { syslog(LOG_ERR, "option record could " "not be saved: db->put failed: %s", strerror(errno)); exit(EX_OSERR); } AUTOWHITE_UNLOCK; } d320 1 a320 36 /* * If the database does not need a key fixup, get away now */ if ((dbo->dbo_match_mask.s_addr == conf.c_match_mask.s_addr) && (dbo->dbo_lazyaw == conf.c_lazyaw)) break; autowhite_update(1, NULL); /* FALLTRHOUGH */ /* * If the options changed (the case above), or if * the option record was not found (brand new database) * then we put a new option record. */ case 1: /* not found */ dborec.dbo_match_mask = conf.c_match_mask; dborec.dbo_lazyaw = conf.c_lazyaw; rec.data = &dborec; rec.size = sizeof(dborec); AUTOWHITE_WRLOCK; if (aw_db->put(aw_db, &key, &rec, 0) != 0) syslog(LOG_ERR, "option record could not be saved: " "db->put failed: %s", strerror(errno)); dump_dirty++; AUTOWHITE_UNLOCK; break; default: /* error */ syslog(LOG_ERR, "option record could not be found: " "db->get failed: %s", strerror(errno)); break; } d322 1 a322 5 AUTOWHITE_RDLOCK; aw_db->sync(aw_db, 0); AUTOWHITE_UNLOCK; return 0; d326 5 a330 45 autowhite_shutdown(void) { /* Access with no lock: exitting is monothread */ DBT key; DBT rec; struct db_options *dbo; int found; syslog(LOG_INFO, "shuting down autowhite database"); key.data = DB_OPTIONS; key.size = strlen(DB_OPTIONS) + 1; found = aw_db->get(aw_db, &key, &rec, 0); if (found != 0) { syslog(LOG_ERR, "No %s record in autowhite database", DB_OPTIONS); if (aw_db->close(aw_db) != 0) syslog(LOG_ERR, "closing autowhite database failed: %s", strerror(errno)); return; } dbo = rec.data; if (aw_db->sync(aw_db, 0) != 0) { syslog(LOG_ERR, "sync failed on autowhite database: %s", strerror(errno)); return; } dbo->dbo_busy = 0; if (aw_db->put(aw_db, &key, &rec, 0) != 0) { syslog(LOG_ERR, "put %s record failed for autowhite db: %s", DB_OPTIONS, strerror(errno)); return; } if (aw_db->close(aw_db) != 0) { syslog(LOG_ERR, "close failed on autowhite database: %s", strerror(errno)); return; } @ 1.25 log @Don't use an external lockfile, use a field in the database instead @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.24 2004/05/21 10:22:08 manu Exp $ */ d32 1 d36 1 a36 2 __RCSID("$Id: autowhite.c,v 1.24 2004/05/21 10:22:08 manu Exp $"); #endif a37 6 #include "config.h" #ifdef HAVE_OLD_QUEUE_H #include "queue.h" #else #include @ 1.24 log @Correctly rebuild the database when option change: create a brand new one and populate it with record with updated keys. This is to workaround the incapacity of Berkeley DB to update the keys while walking the database @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.23 2004/05/15 08:41:54 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.23 2004/05/15 08:41:54 manu Exp $"); d52 1 d83 1 a83 1 void d97 1 d99 2 a100 1 autowhite_db_options(); d102 13 a114 1 return; d379 1 a379 1 snprintf(data, len, "%s\t%s\t%s", addr, fromcase, rcptcase); d388 2 a389 2 autowhite_update(new_db, stream) /* aw_db must be write-locked */ DB *new_db; d407 2 d413 1 a413 1 if (new_db) d416 10 d477 1 a477 1 if (new_db) { a485 1 dump_dirty++; d519 14 d551 4 a554 2 void autowhite_db_options(void) { a559 2 DB *new_db; char new_db_name[MAXPATHLEN + 1]; a570 3 if ((dbo->dbo_match_mask.s_addr == conf.c_match_mask.s_addr) && (dbo->dbo_lazyaw == conf.c_lazyaw)) break; d573 1 a573 6 * We need to update the database keys. * * It seems Berkeley DB API limitation makes impossible * to walk the database updating the keys. We therefore * create a new database, copy the records with updated * keys in it, and replace the older database. d575 7 a581 2 snprintf(new_db_name, MAXPATHLEN, "%s.%s", conf.c_autowhitedb, "new"); d583 6 a588 6 if ((new_db = dbopen(new_db_name, O_TRUNC|O_RDWR|O_EXLOCK|O_CREAT, 0644, DB_BTREE, NULL)) == NULL) { syslog(LOG_ERR, "dbopen \"%s\" failed: %s", new_db_name, strerror(errno)); exit(EX_OSERR); d592 1 a592 4 * Remove outdated records, and save everything * else to the new database, with updated keys. * The database remain locked until we replaced * the old one. d594 6 a599 2 AUTOWHITE_WRLOCK; autowhite_update(new_db, NULL); d601 1 a601 5 /* * At that stage we don't need the older database * anymore, close it. */ aw_db->close(aw_db); d603 8 a610 7 /* * Replace the older database */ if (rename(new_db_name, conf.c_autowhitedb) != 0) { syslog(LOG_ERR, "cannot replace \"%s\" by \"%s\": %s", conf.c_autowhitedb, new_db_name, strerror(errno)); exit(EX_OSERR); d614 1 a614 1 * The newer database can now be used d616 5 a620 2 aw_db = new_db; AUTOWHITE_UNLOCK; d653 50 @ 1.23 log @First attempt with Berkeley DB. Some remaining bugs on dynamic modification of options. @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.22 2004/05/06 13:50:54 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.22 2004/05/06 13:50:54 manu Exp $"); d55 1 d373 2 a374 2 autowhite_update(update_keys, stream) int update_keys; d396 1 a396 1 if (update_keys) a404 1 AUTOWHITE_WRLOCK; a417 1 printf("rec.aw_in (1) = %s\n", inet_ntoa(*(struct in_addr *)rec.data)); d450 1 a450 2 if (update_keys) { printf("rec.aw_in = %s\n", inet_ntoa(*(struct in_addr *)rec.data)); d455 1 a455 1 if (aw_db->put(aw_db, &key, a495 2 AUTOWHITE_UNLOCK; d518 2 d535 48 a582 1 autowhite_update(1, NULL); @ 1.22 log @Ignore pthread_*_init return values as they are broken on some libpthread. The test were wrong to support those libs, and this prevented NetBSD 2.0 libpthread to work @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.21 2004/04/22 23:27:57 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.21 2004/04/22 23:27:57 manu Exp $"); d47 1 d51 1 d59 6 d68 4 d78 1 a78 1 struct autowhitelist autowhite_head; a83 1 TAILQ_INIT(&autowhite_head); d86 12 d109 3 a111 3 struct autowhite *aw = NULL; struct autowhite *prev_aw = NULL; struct timeval now, delay; d115 4 a118 1 int dirty = 0; d123 1 a123 3 gettimeofday(&now, NULL); delay.tv_sec = autowhite_validity; delay.tv_usec = 0; d131 2 a132 3 AUTOWHITE_WRLOCK; if (!TAILQ_EMPTY(&autowhite_head)) { TAILQ_FOREACH(aw, &autowhite_head, a_list) { d134 3 a136 20 /* * Expiration */ if (aw->a_tv.tv_sec < now.tv_sec) { autowhite_put(aw); aw = NULL; dirty++; syslog(LOG_INFO, "addr %s from %s rcpt %s: " "autowhitelisted entry expired", addr, from, rcpt); if (TAILQ_EMPTY(&autowhite_head)) break; if ((aw = prev_aw) == NULL) aw = TAILQ_FIRST(&autowhite_head); continue; } prev_aw = aw; d138 14 a151 18 /* * Look for an already existing entry */ if ((in->s_addr == aw->a_in.s_addr) && ((conf.c_lazyaw == 1) || ((strncasecmp(from, aw->a_from, ADDRLEN) == 0) && (strncasecmp(rcpt, aw->a_rcpt, ADDRLEN) == 0)))) { timeradd(&now, &delay, &aw->a_tv); dirty++; syslog(LOG_INFO, "%s: addr %s from %s rcpt %s: " "autowhitelisted for more %02d:%02d:%02d", queueid, addr, from, rcpt, h, mn, s); break; } } } d153 3 a155 5 /* * Entry not found, create it */ if (aw == NULL) { aw = autowhite_get(in, from, rcpt, date); d157 1 a157 1 dirty++; d159 7 a165 3 syslog(LOG_INFO, "%s: addr %s from %s rcpt %s: " "autowhitelisted for %02d:%02d:%02d", queueid, addr, from, rcpt, h, mn, s); d167 4 a172 5 if (dirty != 0) { dump_dirty += dirty; dump_flush(); } d183 2 a184 3 struct autowhite *aw = NULL; struct autowhite *prev_aw = NULL; struct timeval now, delay; d186 1 a186 1 time_t autowhite_validity; d188 5 a192 1 int dirty = 0; d194 1 a194 1 if ((autowhite_validity = conf.c_autowhite_validity) == 0) d197 1 a197 3 gettimeofday(&now, NULL); delay.tv_sec = autowhite_validity; delay.tv_usec = 0; d205 6 a210 24 AUTOWHITE_WRLOCK; if (!TAILQ_EMPTY(&autowhite_head)) { TAILQ_FOREACH(aw, &autowhite_head, a_list) { /* * Do expiration first as we don't want * an outdated record to match */ if (aw->a_tv.tv_sec < now.tv_sec) { autowhite_put(aw); aw = NULL; dirty++; syslog(LOG_INFO, "addr %s from %s rcpt %s: " "autowhitelisted entry expired", addr, from, rcpt); if (TAILQ_EMPTY(&autowhite_head)) break; if ((aw = prev_aw) == NULL) aw = TAILQ_FIRST(&autowhite_head); continue; } prev_aw = aw; d212 14 a225 15 /* * Look for our record */ if ((IP_MATCH(in, &aw->a_in)) && (strncmp(from, aw->a_from, ADDRLEN) == 0) && (strncmp(rcpt, aw->a_rcpt, ADDRLEN) == 0)) { timeradd(&now, &delay, &aw->a_tv); dirty++; syslog(LOG_INFO, "%s: addr %s from %s rcpt %s: " "autowhitelisted for more %02d:%02d:%02d", queueid, addr, from, rcpt, h, mn, s); break; } d227 27 d255 45 d302 6 a307 3 if (dirty != 0) { dump_dirty += dirty; dump_flush(); d310 1 a310 4 if (aw != NULL) return EXF_AUTO; return EXF_NONE; d313 3 a315 3 int autowhite_textdump(stream) FILE *stream; d317 4 a320 5 struct autowhite *aw; int done = 0; char textdate[DATELEN + 1]; char textaddr[IPADDRLEN + 1]; struct tm tm; d322 2 a323 3 fprintf(stream, "\n\n#\n# Auto-whitelisted tuples\n#\n"); fprintf(stream, "# Sender IP %32s %32s Expire\n", "Sender e-mail", "Recipient e-mail"); d325 5 a329 12 AUTOWHITE_RDLOCK; TAILQ_FOREACH(aw, &autowhite_head, a_list) { localtime_r((time_t *)&aw->a_tv.tv_sec, &tm); strftime(textdate, DATELEN, "%Y-%m-%d %T", &tm); inet_ntop(AF_INET, &aw->a_in, textaddr, IPADDRLEN); fprintf(stream, "%s %32s %32s %ld AUTO # %s\n", textaddr, aw->a_from, aw->a_rcpt, (long)aw->a_tv.tv_sec, textdate); } d332 1 a332 1 return done; d335 4 a338 2 struct autowhite * autowhite_get(in, from, rcpt, date) /* autowhite list must be locked */ a341 1 time_t *date; d343 37 d381 13 a393 2 struct timeval now, delay; time_t autowhite_validity = conf.c_autowhite_validity; d395 2 a396 3 gettimeofday(&now, NULL); delay.tv_sec = autowhite_validity; delay.tv_usec = 0; d398 4 a401 3 if ((aw = malloc(sizeof(*aw))) == NULL) { syslog(LOG_ERR, "malloc failed: %s", strerror(errno)); exit(EX_OSERR); d404 90 a493 1 bzero((void *)aw, sizeof(*aw)); d495 2 a496 5 aw->a_in.s_addr = in->s_addr; strncpy(aw->a_from, from, ADDRLEN); aw->a_from[ADDRLEN] = '\0'; strncpy(aw->a_rcpt, rcpt, ADDRLEN); aw->a_rcpt[ADDRLEN] = '\0'; d498 1 a498 4 if (date == NULL) timeradd(&now, &delay, &aw->a_tv); else aw->a_tv.tv_sec = *date; d500 11 a510 1 TAILQ_INSERT_TAIL(&autowhite_head, aw, a_list); d512 1 a512 1 return aw; d516 54 a569 5 autowhite_put(aw) /* autowhite list must be write-locked */ struct autowhite *aw; { TAILQ_REMOVE(&autowhite_head, aw, a_list); free(aw); @ 1.21 log @lazyaw option to get a lazy match in autowhitelist: only on the IP address. @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.20 2004/04/22 23:14:23 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.20 2004/04/22 23:14:23 manu Exp $"); d69 1 a69 1 int a70 1 int error; d73 1 d75 1 a75 4 if ((error = pthread_rwlock_init(&autowhite_lock, NULL)) == 0) return error; return 0; @ 1.20 log @Be case-insensitive when matching the auto-whitelist. @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.19 2004/03/31 10:07:17 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.19 2004/03/31 10:07:17 manu Exp $"); d139 3 a141 2 (strncasecmp(from, aw->a_from, ADDRLEN) == 0) && (strncasecmp(rcpt, aw->a_rcpt, ADDRLEN) == 0)) { @ 1.19 log @Added an option for subnet mask @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.18 2004/03/31 09:49:16 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.18 2004/03/31 09:49:16 manu Exp $"); d139 2 a140 2 (strncmp(from, aw->a_from, ADDRLEN) == 0) && (strncmp(rcpt, aw->a_rcpt, ADDRLEN) == 0)) { @ 1.19.2.1 log @pull-up bugfix to run on NetBSD-2.0: ignore pthread_*_init return values as the tests were broken to support broken libtphread @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.19 2004/03/31 10:07:17 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.19 2004/03/31 10:07:17 manu Exp $"); d69 1 a69 1 void d71 1 a73 1 pthread_rwlock_init(&autowhite_lock, NULL); d75 4 a78 1 return; @ 1.18 log @Add flag equivalents to the config file @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.17 2004/03/29 15:21:25 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.17 2004/03/29 15:21:25 manu Exp $"); d298 1 a298 1 time_t autowhite_validity; @ 1.17 log @Replace localtime by localtime_r Use +0100 (GMT+1) display instead of GMT+1 @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.16 2004/03/28 14:05:42 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.16 2004/03/28 14:05:42 manu Exp $"); d60 1 a65 2 time_t autowhite_validity = AUTOWHITE_VALIDITY; d93 1 d97 1 a97 1 if (autowhite_validity == 0) d186 1 d190 1 a190 1 if (autowhite_validity == 0) d298 1 @ 1.16 log @Add match mask (-L option) @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.15 2004/03/22 07:12:38 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.15 2004/03/22 07:12:38 manu Exp $"); d51 1 d55 1 d265 1 d273 2 a274 2 strftime(textdate, DATELEN, "%Y-%m-%d %T", localtime((time_t *)&aw->a_tv.tv_sec)); @ 1.15 log @Guard inclusion, some systems (older digitalUNIX) do not have it @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.14 2004/03/22 07:01:53 manu Exp $ */ d35 1 a35 1 __RCSID("$Id: autowhite.c,v 1.14 2004/03/22 07:01:53 manu Exp $"); d59 1 d228 1 a228 1 if ((in->s_addr == aw->a_in.s_addr) && @ 1.14 log @More casts for DigitalUNIX @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.13 2004/03/21 23:57:34 manu Exp $ */ d32 1 d35 2 a36 1 __RCSID("$Id: autowhite.c,v 1.13 2004/03/21 23:57:34 manu Exp $"); @ 1.13 log @cast for Darwin @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.12 2004/03/21 23:52:40 manu Exp $ */ d34 1 a34 1 __RCSID("$Id: autowhite.c,v 1.12 2004/03/21 23:52:40 manu Exp $"); d301 1 a301 1 bzero(aw, sizeof(*aw)); @ 1.12 log @Don't include without , as it is needed on some OS @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.11 2004/03/20 17:22:42 manu Exp $ */ d34 1 a34 1 __RCSID("$Id: autowhite.c,v 1.11 2004/03/20 17:22:42 manu Exp $"); d275 1 a275 1 aw->a_tv.tv_sec, textdate); @ 1.11 log @Locking problems in autowhite code: add one more layer of function to avoid taking the lock twice in dump_reload code path @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.10 2004/03/20 07:19:03 manu Exp $ */ d34 1 a34 1 __RCSID("$Id: autowhite.c,v 1.10 2004/03/20 07:19:03 manu Exp $"); d50 1 @ 1.10 log @Print the message Id with the logs @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.9 2004/03/19 10:16:38 manu Exp $ */ d34 1 a34 1 __RCSID("$Id: autowhite.c,v 1.9 2004/03/19 10:16:38 manu Exp $"); d112 1 a112 2 TAILQ_REMOVE(&autowhite_head, aw, a_list); free(aw); d151 1 a151 19 if ((aw = malloc(sizeof(*aw))) == NULL) { syslog(LOG_ERR, "malloc failed: %s", strerror(errno)); exit(EX_OSERR); } bzero(aw, sizeof(*aw)); aw->a_in.s_addr = in->s_addr; strncpy(aw->a_from, from, ADDRLEN); aw->a_from[ADDRLEN] = '\0'; strncpy(aw->a_rcpt, rcpt, ADDRLEN); aw->a_rcpt[ADDRLEN] = '\0'; if (date == NULL) timeradd(&now, &delay, &aw->a_tv); else aw->a_tv.tv_sec = *date; TAILQ_INSERT_TAIL(&autowhite_head, aw, a_list); d204 1 a204 2 TAILQ_REMOVE(&autowhite_head, aw, a_list); free(aw); d281 46 @ 1.9 log @Fix includes order and wrong ifdef for old queue.h @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.8 2004/03/18 22:37:21 manu Exp $ */ d34 1 a34 1 __RCSID("$Id: autowhite.c,v 1.8 2004/03/18 22:37:21 manu Exp $"); d77 1 a77 1 autowhite_add(in, from, rcpt, date) d82 1 d140 1 a140 1 syslog(LOG_INFO, "addr %s from %s rcpt %s: " d142 1 a142 1 addr, from, rcpt, h, mn, s); d174 1 a174 1 syslog(LOG_INFO, "addr %s from %s rcpt %s: " d176 1 a176 1 addr, from, rcpt, h, mn, s); d189 1 a189 1 autowhite_check(in, from, rcpt) d193 1 d251 1 a251 1 syslog(LOG_INFO, "addr %s from %s rcpt %s: " d253 1 a253 1 addr, from, rcpt, h, mn, s); @ 1.8 log @Inlude config.h before using HAVE_OLD_QUEUE_H @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.7 2004/03/18 09:55:14 manu Exp $ */ d34 8 a41 1 __RCSID("$Id: autowhite.c,v 1.7 2004/03/18 09:55:14 manu Exp $"); a53 7 #include "config.h" #ifndef HAVE_OLD_QUEUE_H #include "queue.h" #else #include #endif @ 1.7 log @Use a modern queue.h if it is missing from the system (Linux...) @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.6 2004/03/17 22:31:05 manu Exp $ */ d34 1 a34 1 __RCSID("$Id: autowhite.c,v 1.6 2004/03/17 22:31:05 manu Exp $"); d48 1 @ 1.6 log @Move the AUTO keyword at the end of the line @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.5 2004/03/17 22:28:57 manu Exp $ */ d34 1 a34 1 __RCSID("$Id: autowhite.c,v 1.5 2004/03/17 22:28:57 manu Exp $"); a42 2 #include d47 6 @ 1.5 log @When reloading the whitelist, don't change the time @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.4 2004/03/17 22:21:36 manu Exp $ */ d34 1 a34 1 __RCSID("$Id: autowhite.c,v 1.4 2004/03/17 22:21:36 manu Exp $"); d285 1 a285 1 "AUTO %s %32s %32s %ld # %s\n", @ 1.4 log @save and reload the auto-whitelist @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.3 2004/03/17 17:33:40 manu Exp $ */ d34 1 a34 1 __RCSID("$Id: autowhite.c,v 1.3 2004/03/17 17:33:40 manu Exp $"); d72 1 a72 1 autowhite_add(in, from, rcpt) d76 1 d158 6 a163 1 timeradd(&now, &delay, &aw->a_tv); @ 1.3 log @Move away the dumper thread from pending.c as it will also dump the autowhitelist now @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.2 2004/03/17 15:36:19 manu Exp $ */ d34 1 a34 1 __RCSID("$Id: autowhite.c,v 1.2 2004/03/17 15:36:19 manu Exp $"); d258 29 @ 1.2 log @Fix auto-whitelisting bugs Enable user selection of the whitelist delay @ text @d1 1 a1 1 /* $Id: autowhite.c,v 1.1 2004/03/16 23:16:52 manu Exp $ */ d34 1 a34 1 __RCSID("$Id: autowhite.c,v 1.1 2004/03/16 23:16:52 manu Exp $"); d51 1 d82 4 d109 2 d131 2 d160 2 d168 5 d187 4 d214 2 d236 2 d246 5 @ 1.1 log @Autowhitelisting. Not saved upon restarts, not user settable. @ text @d1 1 a1 1 /* $Id$ */ d34 1 a34 1 __RCSID("$Id$"); d53 2 d77 2 a78 1 struct timeval tv1, tv2, tv3; d80 1 d82 7 a88 4 gettimeofday(&tv1,NULL); tv2.tv_sec = AUTOWHITE_VALIDITY; tv2.tv_usec = 0; timeradd(&tv1, &tv2, &tv3); d95 24 d122 2 a123 1 aw->a_tv.tv_sec = tv3.tv_sec; d125 2 a126 2 "autowhitelisted for one more day", addr, from, rcpt); d129 1 a129 8 if (aw->a_tv.tv_sec < tv1.tv_sec) { TAILQ_REMOVE(&autowhite_head, aw, a_list); syslog(LOG_INFO, "addr %s from %s rcpt %s: " "autowhitelisted entry expired", addr, from, rcpt); } } d132 3 d148 1 a148 1 aw->a_tv.tv_sec = tv3.tv_sec; d152 2 a153 1 "autowhitelisted for a day", addr, from, rcpt); d167 2 a168 1 struct timeval tv1, tv2, tv3; d170 1 d172 7 a178 4 gettimeofday(&tv1,NULL); tv2.tv_sec = AUTOWHITE_VALIDITY; tv2.tv_usec = 0; timeradd(&tv1, &tv2, &tv3); d185 24 d212 1 a212 3 aw->a_tv.tv_sec = tv3.tv_sec; break; } a213 2 if (aw->a_tv.tv_sec < tv1.tv_sec) { TAILQ_REMOVE(&autowhite_head, aw, a_list); d215 3 a217 2 "autowhitelisted entry expired", addr, from, rcpt); @