示例#1
0
void    master_listen_init(MASTER_SERV *serv)
{
    const char *myname = "master_listen_init";
    char   *end_point;
    int     n;
    MAI_HOSTADDR_STR hostaddr;
    struct sockaddr *sa;

    /*
     * Find out what transport we should use, then create one or more
     * listener sockets. Make the listener sockets non-blocking, so that
     * child processes don't block in accept() when multiple processes are
     * selecting on the same socket and only one of them gets the connection.
     */
    switch (serv->type) {

	/*
	 * UNIX-domain or stream listener endpoints always come as singlets.
	 */
    case MASTER_SERV_TYPE_UNIX:
	set_eugid(var_owner_uid, var_owner_gid);
	serv->listen_fd[0] =
	    LOCAL_LISTEN(serv->name, serv->max_proc > var_proc_limit ?
			 serv->max_proc : var_proc_limit, NON_BLOCKING);
	close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC);
	set_ugid(getuid(), getgid());
	break;

	/*
	 * FIFO listener endpoints always come as singlets.
	 */
    case MASTER_SERV_TYPE_FIFO:
	set_eugid(var_owner_uid, var_owner_gid);
	serv->listen_fd[0] = fifo_listen(serv->name, 0622, NON_BLOCKING);
	close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC);
	set_ugid(getuid(), getgid());
	break;

	/*
	 * INET-domain listener endpoints can be wildcarded (the default) or
	 * bound to specific interface addresses.
	 * 
	 * With dual-stack IPv4/6 systems it does not matter, we have to specify
	 * the addresses anyway, either explicit or wild-card.
	 */
    case MASTER_SERV_TYPE_INET:
	for (n = 0; n < serv->listen_fd_count; n++) {
	    sa = SOCK_ADDR_PTR(MASTER_INET_ADDRLIST(serv)->addrs + n);
	    SOCKADDR_TO_HOSTADDR(sa, SOCK_ADDR_LEN(sa), &hostaddr,
				 (MAI_SERVPORT_STR *) 0, 0);
	    end_point = concatenate(hostaddr.buf,
				    ":", MASTER_INET_PORT(serv), (char *) 0);
	    serv->listen_fd[n]
		= inet_listen(end_point, serv->max_proc > var_proc_limit ?
			      serv->max_proc : var_proc_limit, NON_BLOCKING);
	    close_on_exec(serv->listen_fd[n], CLOSE_ON_EXEC);
	    myfree(end_point);
	}
	break;

	/*
	 * Descriptor passing endpoints always come as singlets.
	 */
#ifdef MASTER_SERV_TYPE_PASS
    case MASTER_SERV_TYPE_PASS:
	set_eugid(var_owner_uid, var_owner_gid);
	serv->listen_fd[0] =
	    PASS_LISTEN(serv->name, serv->max_proc > var_proc_limit ?
			serv->max_proc : var_proc_limit, NON_BLOCKING);
	close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC);
	set_ugid(getuid(), getgid());
	break;
#endif
    default:
	msg_panic("%s: unknown service type: %d", myname, serv->type);
    }
}
示例#2
0
文件: master_ent.c 项目: tmtm/postfix
MASTER_SERV *get_master_ent()
{
    VSTRING *buf = vstring_alloc(100);
    VSTRING *junk = vstring_alloc(100);
    MASTER_SERV *serv;
    char   *cp;
    char   *name;
    char   *host = 0;
    char   *port = 0;
    char   *transport;
    int     private;
    int     unprivileged;		/* passed on to child */
    int     chroot;			/* passed on to child */
    char   *command;
    int     n;
    char   *bufp;
    char   *atmp;
    const char *parse_err;
    static char *saved_interfaces = 0;
    char   *err;

    if (master_fp == 0)
	msg_panic("get_master_ent: config file not open");
    if (master_disable == 0)
	msg_panic("get_master_ent: no service disable list");

    /*
     * XXX We cannot change the inet_interfaces setting for a running master
     * process. Listening sockets are inherited by child processes so that
     * closing and reopening those sockets in the master does not work.
     * 
     * Another problem is that library routines still cache results that are
     * based on the old inet_interfaces setting. It is too much trouble to
     * recompute everything.
     * 
     * In order to keep our data structures consistent we ignore changes in
     * inet_interfaces settings, and issue a warning instead.
     */
    if (saved_interfaces == 0)
	saved_interfaces = mystrdup(var_inet_interfaces);

    /*
     * Skip blank lines and comment lines.
     */
    for (;;) {
	if (readllines(buf, master_fp, &master_line_last, &master_line) == 0) {
	    vstring_free(buf);
	    vstring_free(junk);
	    return (0);
	}
	bufp = vstring_str(buf);
	if ((cp = mystrtok(&bufp, master_blanks)) == 0)
	    continue;
	name = cp;
	transport = get_str_ent(&bufp, "transport type", (char *) 0);
	vstring_sprintf(junk, "%s/%s", name, transport);
	if (match_service_match(master_disable, vstring_str(junk)) == 0)
	    break;
    }

    /*
     * Parse one logical line from the configuration file. Initialize service
     * structure members in order.
     */
    serv = (MASTER_SERV *) mymalloc(sizeof(MASTER_SERV));
    serv->next = 0;

    /*
     * Flags member.
     */
    serv->flags = 0;

    /*
     * All servers busy warning timer.
     */
    serv->busy_warn_time = 0;

    /*
     * Service name. Syntax is transport-specific.
     */
    serv->ext_name = mystrdup(name);

    /*
     * Transport type: inet (wild-card listen or virtual) or unix.
     */
#define STR_SAME	!strcmp

    if (STR_SAME(transport, MASTER_XPORT_NAME_INET)) {
	if (!STR_SAME(saved_interfaces, var_inet_interfaces)) {
	    msg_warn("service %s: ignoring %s change",
		     serv->ext_name, VAR_INET_INTERFACES);
	    msg_warn("to change %s, stop and start Postfix",
		     VAR_INET_INTERFACES);
	}
	serv->type = MASTER_SERV_TYPE_INET;
	atmp = mystrdup(name);
	if ((parse_err = host_port(atmp, &host, "", &port, (char *) 0)) != 0)
	    fatal_with_context("%s in \"%s\"", parse_err, name);
	if (*host) {
	    serv->flags |= MASTER_FLAG_INETHOST;/* host:port */
	    MASTER_INET_ADDRLIST(serv) = (INET_ADDR_LIST *)
		mymalloc(sizeof(*MASTER_INET_ADDRLIST(serv)));
	    inet_addr_list_init(MASTER_INET_ADDRLIST(serv));
	    if (inet_addr_host(MASTER_INET_ADDRLIST(serv), host) == 0)
		fatal_with_context("bad hostname or network address: %s", name);
	    inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv));
	    serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used;
	} else {
	    MASTER_INET_ADDRLIST(serv) =
		strcasecmp(saved_interfaces, INET_INTERFACES_ALL) ?
		own_inet_addr_list() :		/* virtual */
		wildcard_inet_addr_list();	/* wild-card */
	    inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv));
	    serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used;
	}
	MASTER_INET_PORT(serv) = mystrdup(port);
	for (n = 0; /* see below */ ; n++) {
	    if (n >= MASTER_INET_ADDRLIST(serv)->used) {
		serv->flags |= MASTER_FLAG_LOCAL_ONLY;
		break;
	    }
	    if (!sock_addr_in_loopback(SOCK_ADDR_PTR(MASTER_INET_ADDRLIST(serv)->addrs + n)))
		break;
	}
    } else if (STR_SAME(transport, MASTER_XPORT_NAME_UNIX)) {
	serv->type = MASTER_SERV_TYPE_UNIX;
	serv->listen_fd_count = 1;
	serv->flags |= MASTER_FLAG_LOCAL_ONLY;
    } else if (STR_SAME(transport, MASTER_XPORT_NAME_UXDG)) {
	serv->type = MASTER_SERV_TYPE_UXDG;
	serv->listen_fd_count = 1;
	serv->flags |= MASTER_FLAG_LOCAL_ONLY;
    } else if (STR_SAME(transport, MASTER_XPORT_NAME_FIFO)) {
	serv->type = MASTER_SERV_TYPE_FIFO;
	serv->listen_fd_count = 1;
	serv->flags |= MASTER_FLAG_LOCAL_ONLY;
#ifdef MASTER_SERV_TYPE_PASS
    } else if (STR_SAME(transport, MASTER_XPORT_NAME_PASS)) {
	serv->type = MASTER_SERV_TYPE_PASS;
	serv->listen_fd_count = 1;
	/* If this is a connection screener, remote clients are likely. */
#endif
    } else {
	fatal_with_context("bad transport type: %s", transport);
    }

    /*
     * Service class: public or private.
     */
    private = get_bool_ent(&bufp, "private", "y");