示例#1
0
static void dict_mysql_quote(DICT *dict, const char *name, VSTRING *result)
{
    DICT_MYSQL *dict_mysql = (DICT_MYSQL *) dict;
    int     len = strlen(name);
    int     buflen;

    /*
     * We won't get integer overflows in 2*len + 1, because Postfix input
     * keys have reasonable size limits, better safe than sorry.
     */
    if (len > (INT_MAX - VSTRING_LEN(result) - 1) / 2)
	msg_panic("dict_mysql_quote: integer overflow in %lu+2*%d+1",
		  (unsigned long) VSTRING_LEN(result), len);
    buflen = 2 * len + 1;
    VSTRING_SPACE(result, buflen);

#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000
    if (dict_mysql->active_host)
	mysql_real_escape_string(dict_mysql->active_host->db,
				 vstring_end(result), name, len);
    else
#endif
	mysql_escape_string(vstring_end(result), name, len);

    VSTRING_SKIP(result);
}
示例#2
0
ARGV   *mail_addr_crunch(const char *string, const char *extension)
{
    VSTRING *extern_addr = vstring_alloc(100);
    VSTRING *canon_addr = vstring_alloc(100);
    ARGV   *argv = argv_alloc(1);
    TOK822 *tree;
    TOK822 **addr_list;
    TOK822 **tpp;
    char   *ratsign;
    ssize_t extlen;

    if (extension)
        extlen = strlen(extension);

#define STR(x) vstring_str(x)

    /*
     * Parse the string, rewrite each address to canonical form, and convert
     * the result to external (quoted) form. Optionally apply the extension
     * to each address found.
     *
     * XXX Workaround for the null address. This works for envelopes but
     * produces ugly results for message headers.
     */
    if (*string == 0 || strcmp(string, "<>") == 0)
        string = "\"\"";
    tree = tok822_parse(string);
    addr_list = tok822_grep(tree, TOK822_ADDR);
    for (tpp = addr_list; *tpp; tpp++) {
        tok822_externalize(extern_addr, tpp[0]->head, TOK822_STR_DEFL);
        canon_addr_external(canon_addr, STR(extern_addr));
        if (extension) {
            VSTRING_SPACE(canon_addr, extlen + 1);
            if ((ratsign = strrchr(STR(canon_addr), '@')) == 0) {
                vstring_strcat(canon_addr, extension);
            } else {
                memmove(ratsign + extlen, ratsign, strlen(ratsign) + 1);
                memcpy(ratsign, extension, extlen);
                VSTRING_SKIP(canon_addr);
            }
        }
        argv_add(argv, STR(canon_addr), ARGV_END);
    }
    argv_terminate(argv);
    myfree((char *) addr_list);
    tok822_free_tree(tree);
    vstring_free(canon_addr);
    vstring_free(extern_addr);
    return (argv);
}
示例#3
0
int     deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr)
{
    const char *myname = "deliver_resolve_tree";
    RESOLVE_REPLY reply;
    int     status;
    ssize_t ext_len;
    char   *ratsign;
    int     rcpt_delim;

    /*
     * Make verbose logging easier to understand.
     */
    state.level++;
    if (msg_verbose)
	MSG_LOG_STATE(myname, state);

    /*
     * Initialize.
     */
    resolve_clnt_init(&reply);

    /*
     * Rewrite the address to canonical form, just like the cleanup service
     * does. Then, resolve the address to (transport, nexhop, recipient),
     * just like the queue manager does. The only part missing here is the
     * virtual address substitution. Message forwarding fixes most of that.
     */
    tok822_rewrite(addr, REWRITE_CANON);
    tok822_resolve(addr, &reply);

    /*
     * First, a healthy portion of error handling.
     */
    if (reply.flags & RESOLVE_FLAG_FAIL) {
	dsb_simple(state.msg_attr.why, "4.3.0", "address resolver failure");
	status = defer_append(BOUNCE_FLAGS(state.request),
			      BOUNCE_ATTR(state.msg_attr));
    } else if (reply.flags & RESOLVE_FLAG_ERROR) {
	dsb_simple(state.msg_attr.why, "5.1.3",
		   "bad recipient address syntax: %s", STR(reply.recipient));
	status = bounce_append(BOUNCE_FLAGS(state.request),
			       BOUNCE_ATTR(state.msg_attr));
    } else {

	/*
	 * Splice in the optional unmatched address extension.
	 */
	if (state.msg_attr.unmatched) {
	    rcpt_delim = state.msg_attr.local[strlen(state.msg_attr.user)];
	    if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0) {
		VSTRING_ADDCH(reply.recipient, rcpt_delim);
		vstring_strcat(reply.recipient, state.msg_attr.unmatched);
	    } else {
		ext_len = strlen(state.msg_attr.unmatched);
		VSTRING_SPACE(reply.recipient, ext_len + 2);
		if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0)
		    msg_panic("%s: recipient @ botch", myname);
		memmove(ratsign + ext_len + 1, ratsign, strlen(ratsign) + 1);
		*ratsign = rcpt_delim;
		memcpy(ratsign + 1, state.msg_attr.unmatched, ext_len);
		VSTRING_SKIP(reply.recipient);
	    }
	}
	state.msg_attr.rcpt.address = STR(reply.recipient);

	/*
	 * Delivery to a local or non-local address. For a while there was
	 * some ugly code to force local recursive alias expansions on a host
	 * with no authority over the local domain, but that code was just
	 * too unclean.
	 */
	if (strcmp(state.msg_attr.relay, STR(reply.transport)) == 0) {
	    status = deliver_recipient(state, usr_attr);
	} else {
	    status = deliver_indirect(state);
	}
    }

    /*
     * Cleanup.
     */
    resolve_clnt_free(&reply);

    return (status);
}
示例#4
0
static void dict_pgsql_quote(DICT *dict, const char *name, VSTRING *result)
{
    DICT_PGSQL *dict_pgsql = (DICT_PGSQL *) dict;
    HOST   *active_host = dict_pgsql->active_host;
    char   *myname = "dict_pgsql_quote";
    size_t  len = strlen(name);
    size_t  buflen = 2 * len + 1;
    int     err = 1;

    if (active_host == 0)
	msg_panic("%s: bogus dict_pgsql->active_host", myname);

    /*
     * We won't get arithmetic overflows in 2*len + 1, because Postfix input
     * keys have reasonable size limits, better safe than sorry.
     */
    if (buflen <= len)
	msg_panic("%s: arithmetic overflow in 2*%lu+1",
		  myname, (unsigned long) len);

    /*
     * XXX Workaround: stop further processing when PQescapeStringConn()
     * (below) fails. A more proper fix requires invasive changes, not
     * suitable for a stable release.
     */
    if (active_host->stat == STATFAIL)
	return;

    /*
     * Escape the input string, using PQescapeStringConn(), because the older
     * PQescapeString() is not safe anymore, as stated by the documentation.
     * 
     * From current libpq (8.1.4) documentation:
     * 
     * PQescapeStringConn writes an escaped version of the from string to the to
     * buffer, escaping special characters so that they cannot cause any
     * harm, and adding a terminating zero byte.
     * 
     * ...
     * 
     * The parameter from points to the first character of the string that is to
     * be escaped, and the length parameter gives the number of bytes in this
     * string. A terminating zero byte is not required, and should not be
     * counted in length.
     * 
     * ...
     * 
     * (The parameter) to shall point to a buffer that is able to hold at least
     * one more byte than twice the value of length, otherwise the behavior
     * is undefined.
     * 
     * ...
     * 
     * If the error parameter is not NULL, then *error is set to zero on
     * success, nonzero on error ... The output string is still generated on
     * error, but it can be expected that the server will reject it as
     * malformed. On error, a suitable message is stored in the conn object,
     * whether or not error is NULL.
     */
    VSTRING_SPACE(result, buflen);
    PQescapeStringConn(active_host->db, vstring_end(result), name, len, &err);
    if (err == 0) {
	VSTRING_SKIP(result);
    } else {

	/*
	 * PQescapeStringConn() failed. According to the docs, we still have
	 * a valid, null-terminated output string, but we need not rely on
	 * this behavior.
	 */
	msg_warn("dict pgsql: (host %s) cannot escape input string: %s",
		 active_host->hostname, PQerrorMessage(active_host->db));
	active_host->stat = STATFAIL;
	VSTRING_TERMINATE(result);
    }
}
示例#5
0
const char *mail_date(time_t when)
{
    static VSTRING *vp;
    struct tm *lt;
    struct tm gmt;
    int     gmtoff;

    /*
     * As if strftime() isn't expensive enough, we're dynamically adjusting
     * the size for the result, so we won't be surprised by long names etc.
     */
    if (vp == 0)
	vp = vstring_alloc(100);
    else
	VSTRING_RESET(vp);

    /*
     * POSIX does not require that struct tm has a tm_gmtoff field, so we
     * must compute the time offset from UTC by hand.
     * 
     * Starting with the difference in hours/minutes between 24-hour clocks,
     * adjust for differences in years, in yeardays, and in (leap) seconds.
     * 
     * Assume 0..23 hours in a day, 0..59 minutes in an hour. The library spec
     * has changed: we can no longer assume that there are 0..59 seconds in a
     * minute.
     */
    gmt = *gmtime(&when);
    lt = localtime(&when);
    gmtoff = (lt->tm_hour - gmt.tm_hour) * HOUR_MIN + lt->tm_min - gmt.tm_min;
    if (lt->tm_year < gmt.tm_year)
	gmtoff -= DAY_MIN;
    else if (lt->tm_year > gmt.tm_year)
	gmtoff += DAY_MIN;
    else if (lt->tm_yday < gmt.tm_yday)
	gmtoff -= DAY_MIN;
    else if (lt->tm_yday > gmt.tm_yday)
	gmtoff += DAY_MIN;
    if (lt->tm_sec <= gmt.tm_sec - MIN_SEC)
	gmtoff -= 1;
    else if (lt->tm_sec >= gmt.tm_sec + MIN_SEC)
	gmtoff += 1;

    /*
     * First, format the date and wall-clock time. XXX The %e format (day of
     * month, leading zero replaced by blank) isn't in my POSIX book, but
     * many vendors seem to support it.
     */
#ifdef MISSING_STRFTIME_E
#define STRFTIME_FMT "%a, %d %b %Y %H:%M:%S "
#else
#define STRFTIME_FMT "%a, %e %b %Y %H:%M:%S "
#endif

    while (strftime(vstring_end(vp), vstring_avail(vp), STRFTIME_FMT, lt) == 0)
	VSTRING_SPACE(vp, 100);
    VSTRING_SKIP(vp);

    /*
     * Then, add the UTC offset.
     */
    if (gmtoff < -DAY_MIN || gmtoff > DAY_MIN)
	msg_panic("UTC time offset %d is larger than one day", gmtoff);
    vstring_sprintf_append(vp, "%+03d%02d", (int) (gmtoff / HOUR_MIN),
			   (int) (abs(gmtoff) % HOUR_MIN));

    /*
     * Finally, add the time zone name.
     */
    while (strftime(vstring_end(vp), vstring_avail(vp), " (%Z)", lt) == 0)
	VSTRING_SPACE(vp, vstring_avail(vp) + 100);
    VSTRING_SKIP(vp);

    return (vstring_str(vp));
}