Esempio n. 1
0
int
mproc_fork(struct mproc *p, const char *path, char *argv[])
{
	int sp[2];

	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) < 0)
		return (-1);

	io_set_nonblocking(sp[0]);
	io_set_nonblocking(sp[1]);

	if ((p->pid = fork()) == -1)
		goto err;

	if (p->pid == 0) {
		/* child process */
		dup2(sp[0], STDIN_FILENO);
		if (closefrom(STDERR_FILENO + 1) < 0)
			exit(1);

		execv(path, argv);
		err(1, "execv: %s", path);
	}

	/* parent process */
	close(sp[0]);
	mproc_init(p, sp[1]);
	return (0);

err:
	log_warn("warn: Failed to start process %s, instance of %s", argv[0], path);
	close(sp[0]);
	close(sp[1]);
	return (-1);
}
Esempio n. 2
0
int
io_connect(struct io *io, const struct sockaddr *sa, const struct sockaddr *bsa)
{
	int	sock, errno_save;

	if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) == -1)
		goto fail;

	io_set_nonblocking(sock);
	io_set_nolinger(sock);

	if (bsa && bind(sock, bsa, bsa->sa_len) == -1)
		goto fail;

	if (connect(sock, sa, sa->sa_len) == -1)
		if (errno != EINPROGRESS)
			goto fail;

	io->sock = sock;
	io_reset(io, EV_WRITE, io_dispatch_connect);

	return (sock);

    fail:
	if (sock != -1) {
		errno_save = errno;
		close(sock);
		errno = errno_save;
		io->error = strerror(errno);
	}
	return (-1);
}
Esempio n. 3
0
int
control_create_socket(void)
{
	struct sockaddr_un	s_un;
	int			fd;
	mode_t			old_umask;

	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
		fatal("control: socket");

	memset(&s_un, 0, sizeof(s_un));
	s_un.sun_family = AF_UNIX;
	if (strlcpy(s_un.sun_path, SMTPD_SOCKET,
	    sizeof(s_un.sun_path)) >= sizeof(s_un.sun_path))
		fatal("control: socket name too long");

	if (connect(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == 0)
		fatalx("control socket already listening");

	if (unlink(SMTPD_SOCKET) == -1)
		if (errno != ENOENT)
			fatal("control: cannot unlink socket");

	old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
	if (bind(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) {
		(void)umask(old_umask);
		fatal("control: bind");
	}
	(void)umask(old_umask);

	if (chmod(SMTPD_SOCKET,
		S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1) {
		(void)unlink(SMTPD_SOCKET);
		fatal("control: chmod");
	}

	io_set_nonblocking(fd);
	control_state.fd = fd;

	return fd;
}
Esempio n. 4
0
/* ARGSUSED */
static void
control_accept(int listenfd, short event, void *arg)
{
	int			 connfd;
	socklen_t		 len;
	struct sockaddr_un	 s_un;
	struct ctl_conn		*c;
	size_t			*count;
	uid_t			 euid;
	gid_t			 egid;

	if (getdtablesize() - getdtablecount() < CONTROL_FD_RESERVE)
		goto pause;

	len = sizeof(s_un);
	if ((connfd = accept(listenfd, (struct sockaddr *)&s_un, &len)) == -1) {
		if (errno == ENFILE || errno == EMFILE)
			goto pause;
		if (errno == EINTR || errno == EWOULDBLOCK ||
		    errno == ECONNABORTED)
			return;
		fatal("control_accept: accept");
	}

	io_set_nonblocking(connfd);

	if (getpeereid(connfd, &euid, &egid) == -1)
		fatal("getpeereid");

	count = tree_get(&ctl_count, euid);
	if (count == NULL) {
		count = xcalloc(1, sizeof *count, "control_accept");
		tree_xset(&ctl_count, euid, count);
	}

	if (*count == CONTROL_MAXCONN_PER_CLIENT) {
		close(connfd);
		log_warnx("warn: too many connections to control socket "
		    "from user with uid %lu", (unsigned long int)euid);
		return;
	}
	(*count)++;

	do {
		++connid;
	} while (tree_get(&ctl_conns, connid));

	c = xcalloc(1, sizeof(*c), "control_accept");
	c->euid = euid;
	c->egid = egid;
	c->id = connid;
	c->mproc.proc = PROC_CLIENT;
	c->mproc.handler = control_dispatch_ext;
	c->mproc.data = c;
	mproc_init(&c->mproc, connfd);
	mproc_enable(&c->mproc);
	tree_xset(&ctl_conns, c->id, c);

	stat_backend->increment("control.session", 1);
	return;

pause:
	log_warnx("warn: ctl client limit hit, disabling new connections");
	event_del(&control_state.ev);
}