Пример #1
0
static HOST *host_init(const char *hostname)
{
    const char *myname = "pgsql host_init";
    HOST   *host = (HOST *) mymalloc(sizeof(HOST));
    const char *d = hostname;

    host->db = 0;
    host->hostname = mystrdup(hostname);
    host->stat = STATUNTRIED;
    host->ts = 0;

    /*
     * Ad-hoc parsing code. Expect "unix:pathname" or "inet:host:port", where
     * both "inet:" and ":port" are optional.
     */
    if (strncmp(d, "unix:", 5) == 0 || strncmp(d, "inet:", 5) == 0)
	d += 5;
    host->name = mystrdup(d);
    host->port = split_at_right(host->name, ':');

    /* This is how PgSQL distinguishes between UNIX and INET: */
    if (host->name[0] && host->name[0] != '/')
	host->type = TYPEINET;
    else
	host->type = TYPEUNIX;

    if (msg_verbose > 1)
	msg_info("%s: host=%s, port=%s, type=%s", myname, host->name,
		 host->port ? host->port : "",
		 host->type == TYPEUNIX ? "unix" : "inet");
    return host;
}
Пример #2
0
const char *host_port(char *buf, char **host, char *def_host,
		              char **port, char *def_service)
{
    char   *cp = buf;

    /*
     * [host]:port, [host]:, [host].
     */
    if (*cp == '[') {
	*host = ++cp;
	if ((cp = split_at(cp, ']')) == 0)
	    return ("missing \"]\"");
	if (*cp && *cp++ != ':')
	    return ("garbage after \"]\"");
	*port = *cp ? cp : def_service;
    }

    /*
     * host:port, host:, host, :port, port.
     */
    else {
	if ((cp = split_at_right(buf, ':')) != 0) {
	    *host = *buf ? buf : def_host;
	    *port = *cp ? cp : def_service;
	} else {
	    *host = def_host ? def_host : (*buf ? buf : 0);
	    *port = def_service ? def_service : (*buf ? buf : 0);
	}
    }
    if (*host == 0)
	return ("missing host information");
    if (*port == 0)
	return ("missing service information");

    /*
     * Final sanity checks. We're still sloppy, allowing bare numerical
     * network addresses instead of requiring proper [ipaddress] forms.
     */
    if (*host != def_host && !valid_hostname(*host, DONT_GRIPE)
	&& !valid_hostaddr(*host, DONT_GRIPE))
	return ("valid hostname or network address required");
    if (*port != def_service && ISDIGIT(**port) && !alldig(*port))
	return ("garbage after numerical service");
    return (0);
}
Пример #3
0
/* host_init - initialize HOST structure */
static HOST *host_init(const char *hostname)
{
    const char *myname = "mysql host_init";
    HOST   *host = (HOST *) mymalloc(sizeof(HOST));
    const char *d = hostname;
    char   *s;

    host->db = 0;
    host->hostname = mystrdup(hostname);
    host->port = 0;
    host->stat = STATUNTRIED;
    host->ts = 0;

    /*
     * Ad-hoc parsing code. Expect "unix:pathname" or "inet:host:port", where
     * both "inet:" and ":port" are optional.
     */
    if (strncmp(d, "unix:", 5) == 0) {
        d += 5;
        host->type = TYPEUNIX;
    } else {
        if (strncmp(d, "inet:", 5) == 0)
            d += 5;
        host->type = TYPEINET;
    }
    host->name = mystrdup(d);
    if ((s = split_at_right(host->name, ':')) != 0)
        host->port = ntohs(find_inet_port(s, "tcp"));
    if (strcasecmp(host->name, "localhost") == 0) {
        /* The MySQL way: this will actually connect over the UNIX socket */
        myfree(host->name);
        host->name = 0;
        host->type = TYPEUNIX;
    }

    if (msg_verbose > 1)
        msg_info("%s: host=%s, port=%d, type=%s", myname,
                 host->name ? host->name : "localhost",
                 host->port, host->type == TYPEUNIX ? "unix" : "inet");
    return host;
}
Пример #4
0
int     deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
{
    const char *myname = "deliver_recipient";
    int     rcpt_stat;

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

    /*
     * Duplicate filter.
     */
    if (been_here(state.dup_filter, "recipient %d %s",
		  state.level, state.msg_attr.rcpt.address))
	return (0);

    /*
     * With each level of recursion, detect and break external message
     * forwarding loops.
     * 
     * If the looping recipient address has an owner- alias, send the error
     * report there instead.
     * 
     * XXX A delivery agent cannot change the envelope sender address for
     * bouncing. As a workaround we use a one-recipient bounce procedure.
     * 
     * The proper fix would be to record in the bounce logfile an error return
     * address for each individual recipient. This would also eliminate the
     * need for VERP specific bouncing code, at the cost of complicating the
     * normal bounce sending procedure, but would simplify the code below.
     */
    if (delivered_hdr_find(state.loop_info, state.msg_attr.rcpt.address)) {
	dsb_simple(state.msg_attr.why, "5.4.6", "mail forwarding loop for %s",
		   state.msg_attr.rcpt.address);
	/* Account for possible owner- sender address override. */
	return (bounce_workaround(state));
    }

    /*
     * Set up the recipient-specific attributes. If this is forwarded mail,
     * leave the delivered attribute alone, so that the forwarded message
     * will show the correct forwarding recipient.
     */
    if (state.msg_attr.delivered == 0)
	state.msg_attr.delivered = state.msg_attr.rcpt.address;
    state.msg_attr.local = mystrdup(state.msg_attr.rcpt.address);
    lowercase(state.msg_attr.local);
    if ((state.msg_attr.domain = split_at_right(state.msg_attr.local, '@')) == 0)
	msg_warn("no @ in recipient address: %s", state.msg_attr.local);

    /*
     * Address extension management.
     */
    state.msg_attr.user = mystrdup(state.msg_attr.local);
    if (*var_rcpt_delim) {
	state.msg_attr.extension =
	    split_addr(state.msg_attr.user, *var_rcpt_delim);
	if (state.msg_attr.extension && strchr(state.msg_attr.extension, '/')) {
	    msg_warn("%s: address with illegal extension: %s",
		     state.msg_attr.queue_id, state.msg_attr.local);
	    state.msg_attr.extension = 0;
	}
    } else
	state.msg_attr.extension = 0;
    state.msg_attr.unmatched = state.msg_attr.extension;

    /*
     * Do not allow null usernames.
     */
    if (state.msg_attr.user[0] == 0) {
	dsb_simple(state.msg_attr.why, "5.1.3",
		   "null username in \"%s\"", state.msg_attr.rcpt.address);
	return (bounce_append(BOUNCE_FLAGS(state.request),
			      BOUNCE_ATTR(state.msg_attr)));
    }

    /*
     * Run the recipient through the delivery switch.
     */
    if (msg_verbose)
	deliver_attr_dump(&state.msg_attr);
    rcpt_stat = deliver_switch(state, usr_attr);

    /*
     * Clean up.
     */
    myfree(state.msg_attr.local);
    myfree(state.msg_attr.user);

    return (rcpt_stat);
}
Пример #5
0
DICT   *dict_sockmap_open(const char *mapname, int open_flags, int dict_flags)
{
    DICT_SOCKMAP *dp;
    char   *saved_name = 0;
    char   *sockmap;
    DICT_SOCKMAP_REFC_HANDLE *ref_handle;
    HTABLE_INFO *client_info;

    /*
     * Let the optimizer worry about eliminating redundant code.
     */
#define DICT_SOCKMAP_OPEN_RETURN(d) { \
	DICT *__d = (d); \
	if (saved_name != 0) \
	    myfree(saved_name); \
	return (__d); \
    } while (0)

    /*
     * Sanity checks.
     */
    if (open_flags != O_RDONLY)
	DICT_SOCKMAP_OPEN_RETURN(dict_surrogate(DICT_TYPE_SOCKMAP, mapname,
					   open_flags, dict_flags,
				  "%s:%s map requires O_RDONLY access mode",
					   DICT_TYPE_SOCKMAP, mapname));
    if (dict_flags & DICT_FLAG_NO_UNAUTH)
	DICT_SOCKMAP_OPEN_RETURN(dict_surrogate(DICT_TYPE_SOCKMAP, mapname,
					   open_flags, dict_flags,
		     "%s:%s map is not allowed for security-sensitive data",
					   DICT_TYPE_SOCKMAP, mapname));

    /*
     * Separate the socketmap name from the socketmap server name.
     */
    saved_name = mystrdup(mapname);
    if ((sockmap = split_at_right(saved_name, ':')) == 0)
	DICT_SOCKMAP_OPEN_RETURN(dict_surrogate(DICT_TYPE_SOCKMAP, mapname,
					   open_flags, dict_flags,
				    "%s requires server:socketmap argument",
					   DICT_TYPE_SOCKMAP));

    /*
     * Use one reference-counted client handle for all socketmaps with the
     * same inet:host:port or unix:pathname information.
     * 
     * XXX Todo: graceful degradation after endpoint syntax error.
     */
    if (dict_sockmap_handles == 0)
	dict_sockmap_handles = htable_create(1);
    if ((client_info = htable_locate(dict_sockmap_handles, saved_name)) == 0) {
	ref_handle = (DICT_SOCKMAP_REFC_HANDLE *) mymalloc(sizeof(*ref_handle));
	client_info = htable_enter(dict_sockmap_handles,
				   saved_name, (char *) ref_handle);
	/* XXX Late initialization, so we can reuse macros for consistency. */
	DICT_SOCKMAP_RH_REFCOUNT(client_info) = 1;
	DICT_SOCKMAP_RH_HANDLE(client_info) =
	    auto_clnt_create(saved_name, dict_sockmap_timeout,
			     dict_sockmap_max_idle, dict_sockmap_max_ttl);
    } else
	DICT_SOCKMAP_RH_REFCOUNT(client_info) += 1;

    /*
     * Instantiate a socket map handle.
     */
    dp = (DICT_SOCKMAP *) dict_alloc(DICT_TYPE_SOCKMAP, mapname, sizeof(*dp));
    dp->rdwr_buf = vstring_alloc(100);
    dp->sockmap_name = mystrdup(sockmap);
    dp->client_info = client_info;
    dp->dict.lookup = dict_sockmap_lookup;
    dp->dict.close = dict_sockmap_close;
    /* Don't look up parent domains or network superblocks. */
    dp->dict.flags = dict_flags | DICT_FLAG_PATTERN;

    DICT_SOCKMAP_OPEN_RETURN(DICT_DEBUG (&dp->dict));
}
Пример #6
0
static ARGV *expand_argv(const char *service, char **argv,
			         RECIPIENT_LIST *rcpt_list, int flags)
{
    VSTRING *buf = vstring_alloc(100);
    ARGV   *result;
    char  **cpp;
    PIPE_STATE state;
    int     i;
    char   *ext;
    char   *dom;

    /*
     * This appears to be simple operation (replace $name by its expansion).
     * However, it becomes complex because a command-line argument that
     * references $recipient must expand to as many command-line arguments as
     * there are recipients (that's wat programs called by sendmail expect).
     * So we parse each command-line argument, and depending on what we find,
     * we either expand the argument just once, or we expand it once for each
     * recipient. In either case we end up parsing the command-line argument
     * twice. The amount of CPU time wasted will be negligible.
     * 
     * Note: we can't use recursive macro expansion here, because recursion
     * would screw up mail addresses that contain $ characters.
     */
#define NO	0
#define EARLY_RETURN(x) { argv_free(result); vstring_free(buf); return (x); }

    result = argv_alloc(1);
    for (cpp = argv; *cpp; cpp++) {
	state.service = service;
	state.expand_flag = 0;
	if (mac_parse(*cpp, parse_callback, (char *) &state) & MAC_PARSE_ERROR)
	    EARLY_RETURN(0);
	if (state.expand_flag == 0) {		/* no $recipient etc. */
	    argv_add(result, dict_eval(PIPE_DICT_TABLE, *cpp, NO), ARGV_END);
	} else {				/* contains $recipient etc. */
	    for (i = 0; i < rcpt_list->len; i++) {

		/*
		 * This argument contains $recipient.
		 */
		if (state.expand_flag & PIPE_FLAG_RCPT) {
		    morph_recipient(buf, rcpt_list->info[i].address, flags);
		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_RCPT, STR(buf));
		}

		/*
		 * This argument contains $original_recipient.
		 */
		if (state.expand_flag & PIPE_FLAG_ORIG_RCPT) {
		    morph_recipient(buf, rcpt_list->info[i].orig_addr, flags);
		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_ORIG_RCPT, STR(buf));
		}

		/*
		 * This argument contains $user. Extract the plain user name.
		 * Either anything to the left of the extension delimiter or,
		 * in absence of the latter, anything to the left of the
		 * rightmost @.
		 * 
		 * Beware: if the user name is blank (e.g. +user@host), the
		 * argument is suppressed. This is necessary to allow for
		 * cyrus bulletin-board (global mailbox) delivery. XXX But,
		 * skipping empty user parts will also prevent other
		 * expansions of this specific command-line argument.
		 */
		if (state.expand_flag & PIPE_FLAG_USER) {
		    morph_recipient(buf, rcpt_list->info[i].address,
				    flags & PIPE_OPT_FOLD_ALL);
		    if (split_at_right(STR(buf), '@') == 0)
			msg_warn("no @ in recipient address: %s",
				 rcpt_list->info[i].address);
		    if (*var_rcpt_delim)
			split_addr(STR(buf), var_rcpt_delim);
		    if (*STR(buf) == 0)
			continue;
		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_USER, STR(buf));
		}

		/*
		 * This argument contains $extension. Extract the recipient
		 * extension: anything between the leftmost extension
		 * delimiter and the rightmost @. The extension may be blank.
		 */
		if (state.expand_flag & PIPE_FLAG_EXTENSION) {
		    morph_recipient(buf, rcpt_list->info[i].address,
				    flags & PIPE_OPT_FOLD_ALL);
		    if (split_at_right(STR(buf), '@') == 0)
			msg_warn("no @ in recipient address: %s",
				 rcpt_list->info[i].address);
		    if (*var_rcpt_delim == 0
			|| (ext = split_addr(STR(buf), var_rcpt_delim)) == 0)
			ext = "";		/* insert null arg */
		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_EXTENSION, ext);
		}

		/*
		 * This argument contains $mailbox. Extract the mailbox name:
		 * anything to the left of the rightmost @.
		 */
		if (state.expand_flag & PIPE_FLAG_MAILBOX) {
		    morph_recipient(buf, rcpt_list->info[i].address,
				    flags & PIPE_OPT_FOLD_ALL);
		    if (split_at_right(STR(buf), '@') == 0)
			msg_warn("no @ in recipient address: %s",
				 rcpt_list->info[i].address);
		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_MAILBOX, STR(buf));
		}

		/*
		 * This argument contains $domain. Extract the domain name:
		 * anything to the right of the rightmost @.
		 */
		if (state.expand_flag & PIPE_FLAG_DOMAIN) {
		    morph_recipient(buf, rcpt_list->info[i].address,
				    flags & PIPE_OPT_FOLD_ALL);
		    dom = split_at_right(STR(buf), '@');
		    if (dom == 0) {
			msg_warn("no @ in recipient address: %s",
				 rcpt_list->info[i].address);
			dom = "";		/* insert null arg */
		    }
		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_DOMAIN, dom);
		}

		/*
		 * Done.
		 */
		argv_add(result, dict_eval(PIPE_DICT_TABLE, *cpp, NO), ARGV_END);
	    }
	}
    }
    argv_terminate(result);
    vstring_free(buf);
    return (result);
}