Example #1
0
static void anvil_service_done(VSTREAM *client_stream, char *unused_service,
			               char **unused_argv)
{
    ANVIL_LOCAL *anvil_local;
    const char *myname = "anvil_service_done";

    if (msg_verbose)
	msg_info("%s fd=%d stream=0x%lx",
		 myname, vstream_fileno(client_stream),
		 (unsigned long) client_stream);

    /*
     * Look up the local server, and get rid of any remote connection state
     * that we still have for this local server. Do not destroy remote client
     * status information before it expires.
     */
    if ((anvil_local = (ANVIL_LOCAL *) vstream_context(client_stream)) != 0) {
	if (msg_verbose)
	    msg_info("%s: anvil_local 0x%lx",
		     myname, (unsigned long) anvil_local);
	ANVIL_LOCAL_DROP_ALL(client_stream, anvil_local);
	myfree((char *) anvil_local);
    } else if (msg_verbose)
	msg_info("client socket not found for fd=%d",
		 vstream_fileno(client_stream));
}
Example #2
0
static void multi_server_execute(int unused_event, char *context)
{
    VSTREAM *stream = (VSTREAM *) context;
    HTABLE *attr = (vstream_flags(stream) == multi_server_saved_flags ?
		    (HTABLE *) vstream_context(stream) : 0);

    if (multi_server_lock != 0
	&& myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK,
		   MYFLOCK_OP_NONE) < 0)
	msg_fatal("select unlock: %m");

    /*
     * Do not bother the application when the client disconnected. Don't drop
     * the already accepted client request after "postfix reload"; that would
     * be rude.
     */
    if (peekfd(vstream_fileno(stream)) > 0) {
	if (master_notify(var_pid, multi_server_generation, MASTER_STAT_TAKEN) < 0)
	     /* void */ ;
	multi_server_service(stream, multi_server_name, multi_server_argv);
	if (master_notify(var_pid, multi_server_generation, MASTER_STAT_AVAIL) < 0)
	    multi_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
    } else {
	multi_server_disconnect(stream);
    }
    if (attr)
	htable_free(attr, myfree);
}
Example #3
0
static void anvil_remote_disconnect(VSTREAM *client_stream, const char *ident)
{
    ANVIL_REMOTE *anvil_remote;
    ANVIL_LOCAL *anvil_local;
    const char *myname = "anvil_remote_disconnect";

    if (msg_verbose)
	msg_info("%s fd=%d stream=0x%lx ident=%s",
		 myname, vstream_fileno(client_stream),
		 (unsigned long) client_stream, ident);

    /*
     * Update local and remote info if this remote connection is listed for
     * this local server.
     */
    if ((anvil_local = (ANVIL_LOCAL *) vstream_context(client_stream)) != 0
	&& (anvil_remote =
	    (ANVIL_REMOTE *) htable_find(anvil_remote_map, ident)) != 0
	&& ANVIL_LOCAL_REMOTE_LINKED(anvil_local, anvil_remote)) {
	ANVIL_REMOTE_DROP_ONE(anvil_remote);
	ANVIL_LOCAL_DROP_ONE(anvil_local, anvil_remote);
    }
    if (msg_verbose)
	msg_info("%s: anvil_local 0x%lx",
		 myname, (unsigned long) anvil_local);

    /*
     * Respond to the local server.
     */
    attr_print_plain(client_stream, ATTR_FLAG_NONE,
		     ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
		     ATTR_TYPE_END);
}
Example #4
0
void    smtpd_peer_init(SMTPD_STATE *state)
{

    /*
     * Initialize.
     */
    if (proto_info == 0)
	proto_info = inet_proto_info();

    /*
     * Prepare for partial initialization after error.
     */
    memset((void *) &(state->sockaddr), 0, sizeof(state->sockaddr));
    state->sockaddr_len = 0;
    state->name = 0;
    state->reverse_name = 0;
    state->addr = 0;
    state->namaddr = 0;
    state->rfc_addr = 0;
    state->port = 0;
    state->dest_addr = 0;
    state->dest_port = 0;

    /*
     * Determine the remote SMTP client address and port.
     * 
     * XXX In stand-alone mode, don't assume that the peer will be a local
     * process. That could introduce a gaping hole when the SMTP daemon is
     * hooked up to the network via inetd or some other super-server.
     */
    if (vstream_context(state->client) != 0) {
	smtpd_peer_from_pass_attr(state);
	if (*var_smtpd_uproxy_proto != 0)
	    msg_warn("ignoring non-empty %s setting behind postscreen",
		     VAR_SMTPD_UPROXY_PROTO);
    } else if (SMTPD_STAND_ALONE(state) || *var_smtpd_uproxy_proto == 0) {
	smtpd_peer_from_default(state);
    } else {
	smtpd_peer_from_proxy(state);
    }

    /*
     * Determine the remote SMTP client hostname. Note: some of the handlers
     * above provide surrogate endpoint information in case of error. In that
     * case, leave the surrogate information alone.
     */
    if (state->name == 0)
	smtpd_peer_sockaddr_to_hostname(state);

    /*
     * Do the name[addr]:port formatting for pretty reports.
     */
    state->namaddr = SMTPD_BUILD_NAMADDRPORT(state->name, state->addr,
					     state->port);
}
Example #5
0
static void smtpd_peer_from_pass_attr(SMTPD_STATE *state)
{
    HTABLE *attr = (HTABLE *) vstream_context(state->client);
    const char *cp;

    /*
     * Extract the client endpoint information from the attribute hash.
     */
    if ((cp = htable_find(attr, MAIL_ATTR_ACT_CLIENT_ADDR)) == 0)
	msg_fatal("missing client address from proxy");
    if (strrchr(cp, ':') != 0) {
	if (valid_ipv6_hostaddr(cp, DO_GRIPE) == 0)
	    msg_fatal("bad IPv6 client address syntax from proxy: %s", cp);
	state->addr = mystrdup(cp);
	state->rfc_addr = concatenate(IPV6_COL, cp, (char *) 0);
	state->addr_family = AF_INET6;
    } else {
	if (valid_ipv4_hostaddr(cp, DO_GRIPE) == 0)
	    msg_fatal("bad IPv4 client address syntax from proxy: %s", cp);
	state->addr = mystrdup(cp);
	state->rfc_addr = mystrdup(cp);
	state->addr_family = AF_INET;
    }
    if ((cp = htable_find(attr, MAIL_ATTR_ACT_CLIENT_PORT)) == 0)
	msg_fatal("missing client port from proxy");
    if (valid_hostport(cp, DO_GRIPE) == 0)
	msg_fatal("bad TCP client port number syntax from proxy: %s", cp);
    state->port = mystrdup(cp);

    /*
     * The Dovecot authentication server needs the server IP address.
     */
    if ((cp = htable_find(attr, MAIL_ATTR_ACT_SERVER_ADDR)) == 0)
	msg_fatal("missing server address from proxy");
    if (valid_hostaddr(cp, DO_GRIPE) == 0)
	msg_fatal("bad IPv6 server address syntax from proxy: %s", cp);
    state->dest_addr = mystrdup(cp);

    if ((cp = htable_find(attr, MAIL_ATTR_ACT_SERVER_PORT)) == 0)
	msg_fatal("missing server port from proxy");
    if (valid_hostport(cp, DO_GRIPE) == 0)
	msg_fatal("bad TCP server port number syntax from proxy: %s", cp);
    state->dest_port = mystrdup(cp);

    /*
     * Convert the client address from string to binary form.
     */
    smtpd_peer_hostaddr_to_sockaddr(state);
}
Example #6
0
static ANVIL_REMOTE *anvil_remote_conn_update(VSTREAM *client_stream, const char *ident)
{
    ANVIL_REMOTE *anvil_remote;
    ANVIL_LOCAL *anvil_local;
    const char *myname = "anvil_remote_conn_update";

    if (msg_verbose)
	msg_info("%s fd=%d stream=0x%lx ident=%s",
		 myname, vstream_fileno(client_stream),
		 (unsigned long) client_stream, ident);

    /*
     * Look up remote connection count information. Update remote connection
     * rate information. Simply reset the counter every var_anvil_time_unit
     * seconds. This is easier than maintaining a moving average and it gives
     * a quicker response to tresspassers.
     */
    if ((anvil_remote =
	 (ANVIL_REMOTE *) htable_find(anvil_remote_map, ident)) == 0) {
	anvil_remote = (ANVIL_REMOTE *) mymalloc(sizeof(*anvil_remote));
	ANVIL_REMOTE_FIRST_CONN(anvil_remote, ident);
	htable_enter(anvil_remote_map, ident, (char *) anvil_remote);
	if (max_cache_size < anvil_remote_map->used) {
	    max_cache_size = anvil_remote_map->used;
	    max_cache_time = event_time();
	}
    } else {
	ANVIL_REMOTE_NEXT_CONN(anvil_remote);
    }

    /*
     * Record this connection under the local server information, so that we
     * can clean up all its connection state when the local server goes away.
     */
    if ((anvil_local = (ANVIL_LOCAL *) vstream_context(client_stream)) == 0) {
	anvil_local = (ANVIL_LOCAL *) mymalloc(sizeof(*anvil_local));
	ANVIL_LOCAL_INIT(anvil_local);
	vstream_control(client_stream,
			VSTREAM_CTL_CONTEXT, (void *) anvil_local,
			VSTREAM_CTL_END);
    }
    ANVIL_LOCAL_ADD_ONE(anvil_local, anvil_remote);
    if (msg_verbose)
	msg_info("%s: anvil_local 0x%lx",
		 myname, (unsigned long) anvil_local);

    return (anvil_remote);
}
Example #7
0
static void psc_dnsbl_receive(int event, void *context)
{
    const char *myname = "psc_dnsbl_receive";
    VSTREAM *stream = (VSTREAM *) context;
    PSC_DNSBL_SCORE *score;
    PSC_DNSBL_HEAD *head;
    PSC_DNSBL_SITE *site;
    ARGV   *reply_argv;
    int     request_id;
    int     dnsbl_ttl;

    PSC_CLEAR_EVENT_REQUEST(vstream_fileno(stream), psc_dnsbl_receive, context);

    /*
     * Receive the DNSBL lookup result.
     * 
     * This is preliminary code to explore the field. Later, DNSBL lookup will
     * be handled by an UDP-based DNS client that is built directly into some
     * Postfix daemon.
     * 
     * Don't bother looking up the blocklist score when the client IP address is
     * not listed at the DNSBL.
     * 
     * Don't panic when the blocklist score no longer exists. It may be deleted
     * when the client triggers a "drop" action after pregreet, when the
     * client does not pregreet and the DNSBL reply arrives late, or when the
     * client triggers a "drop" action after hanging up.
     */
    if (event == EVENT_READ
	&& attr_scan(stream,
		     ATTR_FLAG_STRICT,
		     RECV_ATTR_STR(MAIL_ATTR_RBL_DOMAIN, reply_dnsbl),
		     RECV_ATTR_STR(MAIL_ATTR_ACT_CLIENT_ADDR, reply_client),
		     RECV_ATTR_INT(MAIL_ATTR_LABEL, &request_id),
		     RECV_ATTR_STR(MAIL_ATTR_RBL_ADDR, reply_addr),
		     RECV_ATTR_INT(MAIL_ATTR_TTL, &dnsbl_ttl),
		     ATTR_TYPE_END) == 5
	&& (score = (PSC_DNSBL_SCORE *)
	    htable_find(dnsbl_score_cache, STR(reply_client))) != 0
	&& score->request_id == request_id) {

	/*
	 * Run this response past all applicable DNSBL filters and update the
	 * blocklist score for this client IP address.
	 * 
	 * Don't panic when the DNSBL domain name is not found. The DNSBLOG
	 * server may be messed up.
	 */
	if (msg_verbose > 1)
	    msg_info("%s: client=\"%s\" score=%d domain=\"%s\" reply=\"%d %s\"",
		     myname, STR(reply_client), score->total,
		     STR(reply_dnsbl), dnsbl_ttl, STR(reply_addr));
	head = (PSC_DNSBL_HEAD *)
	    htable_find(dnsbl_site_cache, STR(reply_dnsbl));
	if (head == 0) {
	    /* Bogus domain. Do nothing. */
	} else if (*STR(reply_addr) != 0) {
	    /* DNS reputation record(s) found. */
	    reply_argv = 0;
	    for (site = head->first; site != 0; site = site->next) {
		if (site->byte_codes == 0
		    || psc_dnsbl_match(site->byte_codes, reply_argv ? reply_argv :
			 (reply_argv = argv_split(STR(reply_addr), " ")))) {
		    if (score->dnsbl_name == 0
			|| score->dnsbl_weight < site->weight) {
			score->dnsbl_name = head->safe_dnsbl;
			score->dnsbl_weight = site->weight;
		    }
		    score->total += site->weight;
		    if (msg_verbose > 1)
			msg_info("%s: filter=\"%s\" weight=%d score=%d",
			       myname, site->filter ? site->filter : "null",
				 site->weight, score->total);
		}
		/* As with dnsblog(8), a value < 0 means no reply TTL. */
		if (site->weight > 0) {
		    if (score->fail_ttl < 0 || score->fail_ttl > dnsbl_ttl)
			score->fail_ttl = dnsbl_ttl;
		} else {
		    if (score->pass_ttl < 0 || score->pass_ttl > dnsbl_ttl)
			score->pass_ttl = dnsbl_ttl;
		}
	    }
	    if (reply_argv != 0)
		argv_free(reply_argv);
	} else {
	    /* No DNS reputation record found. */
	    for (site = head->first; site != 0; site = site->next) {
		/* As with dnsblog(8), a value < 0 means no reply TTL. */
		if (site->weight > 0) {
		    if (score->pass_ttl < 0 || score->pass_ttl > dnsbl_ttl)
			score->pass_ttl = dnsbl_ttl;
		} else {
		    if (score->fail_ttl < 0 || score->fail_ttl > dnsbl_ttl)
			score->fail_ttl = dnsbl_ttl;
		}
	    }
	}

	/*
	 * Notify the requestor(s) that the result is ready to be picked up.
	 * If this call isn't made, clients have to sit out the entire
	 * pre-handshake delay.
	 */
	score->pending_lookups -= 1;
	if (score->pending_lookups == 0)
	    PSC_CALL_BACK_NOTIFY(score, PSC_NULL_EVENT);
    } else if (event == EVENT_TIME) {
	msg_warn("dnsblog reply timeout %ds for %s",
		 var_psc_dnsbl_tmout, (char *) vstream_context(stream));
    }
    /* Here, score may be a null pointer. */
    vstream_fclose(stream);
}