Пример #1
0
int
control_init(struct privsep *ps, struct control_sock *cs)
{
	struct iked		*env = ps->ps_env;
	struct sockaddr_un	 sun;
	int			 fd;
	mode_t			 old_umask, mode;

	if (cs->cs_name == NULL)
		return (0);

	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
		log_warn("%s: socket", __func__);
		return (-1);
	}

	sun.sun_family = AF_UNIX;
	if (strlcpy(sun.sun_path, cs->cs_name,
	    sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) {
		log_warn("%s: %s name too long", __func__, cs->cs_name);
		close(fd);
		return (-1);
	}

	if (unlink(cs->cs_name) == -1)
		if (errno != ENOENT) {
			log_warn("%s: unlink %s", __func__, cs->cs_name);
			close(fd);
			return (-1);
		}

	if (cs->cs_restricted) {
		old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
		mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
	} else {
		old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
		mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP;
	}

	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
		log_warn("%s: bind: %s", __func__, cs->cs_name);
		close(fd);
		(void)umask(old_umask);
		return (-1);
	}
	(void)umask(old_umask);

	if (chmod(cs->cs_name, mode) == -1) {
		log_warn("%s: chmod", __func__);
		close(fd);
		(void)unlink(cs->cs_name);
		return (-1);
	}

	socket_set_blockmode(fd, BM_NONBLOCK);
	cs->cs_fd = fd;
	cs->cs_env = env;

	return (0);
}
Пример #2
0
void
proc_setup(struct privsep *ps)
{
	int	 i, j, sockpair[2];

	for (i = 0; i < PROC_MAX; i++)
		for (j = 0; j < PROC_MAX; j++) {
			if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC,
			    sockpair) == -1)
				fatal("sockpair");
			ps->ps_pipes[i][j] = sockpair[0];
			ps->ps_pipes[j][i] = sockpair[1];
			socket_set_blockmode(ps->ps_pipes[i][j],
			    BM_NONBLOCK);
			socket_set_blockmode(ps->ps_pipes[j][i],
			    BM_NONBLOCK);
		}
}
Пример #3
0
void
proc_open(struct privsep *ps, struct privsep_proc *p,
    struct privsep_proc *procs, size_t nproc)
{
	struct privsep_pipes	*pa, *pb;
	int			 fds[2];
	u_int			 i, j, src, proc;

	if (p == NULL)
		src = privsep_process; /* parent */
	else
		src = p->p_id;

	/*
	 * Open socket pairs for our peers
	 */
	for (proc = 0; proc < nproc; proc++) {
		procs[proc].p_ps = ps;
		procs[proc].p_env = ps->ps_env;

		for (i = 0; i < ps->ps_instances[src]; i++) {
			for (j = 0; j < ps->ps_instances[procs[proc].p_id];
			    j++) {
				pa = &ps->ps_pipes[src][i];
				pb = &ps->ps_pipes[procs[proc].p_id][j];

				/* Check if fds are already set by peer */
				if (pa->pp_pipes[procs[proc].p_id][j] != -1)
					continue;

				if (socketpair(AF_UNIX, SOCK_STREAM,
				    PF_UNSPEC, fds) == -1)
					fatal("socketpair");

				socket_set_blockmode(fds[0], BM_NONBLOCK);
				socket_set_blockmode(fds[1], BM_NONBLOCK);

				pa->pp_pipes[procs[proc].p_id][j] = fds[0];
				pb->pp_pipes[src][i] = fds[1];
			}
		}
	}
}
Пример #4
0
/* ARGSUSED */
void
control_accept(int listenfd, short event, void *arg)
{
	struct control_sock	*cs = arg;
	int			 connfd;
	socklen_t		 len;
	struct sockaddr_un	 sun;
	struct ctl_conn		*c;

	event_add(&cs->cs_ev, NULL);
	if ((event & EV_TIMEOUT))
		return;

	len = sizeof(sun);
	if ((connfd = accept(listenfd,
	    (struct sockaddr *)&sun, &len)) == -1) {
		/*
		 * Pause accept if we are out of file descriptors, or
		 * libevent will haunt us here too.
		 */
		if (errno == ENFILE || errno == EMFILE) {
			struct timeval evtpause = { 1, 0 };

			event_del(&cs->cs_ev);
			evtimer_add(&cs->cs_evt, &evtpause);
		} else if (errno != EWOULDBLOCK && errno != EINTR &&
		    errno != ECONNABORTED)
			log_warn("%s: accept", __func__);
		return;
	}

	socket_set_blockmode(connfd, BM_NONBLOCK);

	if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) {
		log_warn("%s", __func__);
		close(connfd);
		return;
	}

	imsg_init(&c->iev.ibuf, connfd);
	c->iev.handler = control_dispatch_imsg;
	c->iev.events = EV_READ;
	c->iev.data = cs;
	event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
	    c->iev.handler, c->iev.data);
	event_add(&c->iev.ev, NULL);

	TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
}
Пример #5
0
void
snmp_setsock(struct relayd *env, enum privsep_procid id)
{
	struct sockaddr_un	 sun;
	int			 s = -1;

	if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
		goto done;

	bzero(&sun, sizeof(sun));
	sun.sun_family = AF_UNIX;
	if (strlcpy(sun.sun_path, env->sc_snmp_path,
	    sizeof(sun.sun_path)) >= sizeof(sun.sun_path))
		fatalx("invalid socket path");

	socket_set_blockmode(s, BM_NONBLOCK);

	if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
		close(s);
		s = -1;
	}
 done:
	proc_compose_imsg(env->sc_ps, id, -1, IMSG_SNMPSOCK, s, NULL, 0);
}
Пример #6
0
int
server_fcgi(struct httpd *env, struct client *clt)
{
	struct server_fcgi_param	 param;
	struct server_config		*srv_conf = clt->clt_srv_conf;
	struct http_descriptor		*desc = clt->clt_descreq;
	struct fcgi_record_header	*h;
	struct fcgi_begin_request_body	*begin;
	char				 hbuf[HOST_NAME_MAX+1];
	size_t				 scriptlen;
	int				 pathlen;
	int				 fd = -1, ret;
	const char			*stripped, *p, *alias, *errstr = NULL;
	char				*str, *script = NULL;

	if (srv_conf->socket[0] == ':') {
		struct sockaddr_storage	 ss;
		in_port_t		 port;

		p = srv_conf->socket + 1;

		port = strtonum(p, 0, 0xffff, &errstr);
		if (errstr != NULL) {
			log_warn("%s: strtonum %s, %s", __func__, p, errstr);
			goto fail;
		}
		memset(&ss, 0, sizeof(ss));
		ss.ss_family = AF_INET;
		((struct sockaddr_in *)
		    &ss)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
		port = htons(port);

		if ((fd = server_socket_connect(&ss, port, srv_conf)) == -1)
			goto fail;
	} else {
		struct sockaddr_un	 sun;
		size_t			 len;

		if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
			goto fail;

		memset(&sun, 0, sizeof(sun));
		sun.sun_family = AF_UNIX;
		len = strlcpy(sun.sun_path,
		    srv_conf->socket, sizeof(sun.sun_path));
		if (len >= sizeof(sun.sun_path)) {
			errstr = "socket path to long";
			goto fail;
		}
		sun.sun_len = len;

		if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
			goto fail;
	}

	socket_set_blockmode(fd, BM_NONBLOCK);

	memset(hbuf, 0, sizeof(hbuf));
	clt->clt_fcgi_state = FCGI_READ_HEADER;
	clt->clt_fcgi_toread = sizeof(struct fcgi_record_header);

	if (clt->clt_srvevb != NULL)
		evbuffer_free(clt->clt_srvevb);

	clt->clt_srvevb = evbuffer_new();
	if (clt->clt_srvevb == NULL) {
		errstr = "failed to allocate evbuffer";
		goto fail;
	}

	close(clt->clt_fd);
	clt->clt_fd = fd;

	if (clt->clt_srvbev != NULL)
		bufferevent_free(clt->clt_srvbev);

	clt->clt_srvbev_throttled = 0;
	clt->clt_srvbev = bufferevent_new(fd, server_fcgi_read,
	    NULL, server_file_error, clt);
	if (clt->clt_srvbev == NULL) {
		errstr = "failed to allocate fcgi buffer event";
		goto fail;
	}

	memset(&param, 0, sizeof(param));

	h = (struct fcgi_record_header *)&param.buf;
	h->version = 1;
	h->type = FCGI_BEGIN_REQUEST;
	h->id = htons(1);
	h->content_len = htons(sizeof(struct fcgi_begin_request_body));
	h->padding_len = 0;

	begin = (struct fcgi_begin_request_body *)&param.buf[sizeof(struct
	    fcgi_record_header)];
	begin->role = htons(FCGI_RESPONDER);

	if (bufferevent_write(clt->clt_srvbev, &param.buf,
	    sizeof(struct fcgi_record_header) +
	    sizeof(struct fcgi_begin_request_body)) == -1) {
		errstr = "failed to write to evbuffer";
		goto fail;
	}

	h->type = FCGI_PARAMS;
	h->content_len = param.total_len = 0;

	alias = desc->http_path_alias != NULL
	    ? desc->http_path_alias
	    : desc->http_path;

	stripped = server_root_strip(alias, srv_conf->strip);
	if ((pathlen = asprintf(&script, "%s%s", srv_conf->root, stripped))
	    == -1) {
		errstr = "failed to get script name";
		goto fail;
	}

	scriptlen = path_info(script);
	/*
	 * no part of root should show up in PATH_INFO.
	 * therefore scriptlen should be >= strlen(root)
	 */
	if (scriptlen < strlen(srv_conf->root))
		scriptlen = strlen(srv_conf->root);
	if ((int)scriptlen < pathlen) {
		if (fcgi_add_param(&param, "PATH_INFO",
		    script + scriptlen, clt) == -1) {
			errstr = "failed to encode param";
			goto fail;
		}
		script[scriptlen] = '\0';
	} else {
		/* RFC 3875 mandates that PATH_INFO is empty if not set */
		if (fcgi_add_param(&param, "PATH_INFO", "", clt) == -1) {
			errstr = "failed to encode param";
			goto fail;
		}
	}

	/*
	 * calculate length of http SCRIPT_NAME:
	 * add length of stripped prefix,
	 * subtract length of prepended local root
	 */
	scriptlen += (stripped - alias) - strlen(srv_conf->root);
	if ((str = strndup(alias, scriptlen)) == NULL)
		goto fail;
	ret = fcgi_add_param(&param, "SCRIPT_NAME", str, clt);
	free(str);
	if (ret == -1) {
		errstr = "failed to encode param";
		goto fail;
	}
	if (fcgi_add_param(&param, "SCRIPT_FILENAME", script, clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (desc->http_query)
		if (fcgi_add_param(&param, "QUERY_STRING", desc->http_query,
		    clt) == -1) {
			errstr = "failed to encode param";
			goto fail;
		}

	if (fcgi_add_param(&param, "DOCUMENT_ROOT", srv_conf->root,
	    clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}
	if (fcgi_add_param(&param, "DOCUMENT_URI", alias,
	    clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}
	if (fcgi_add_param(&param, "GATEWAY_INTERFACE", "CGI/1.1",
	    clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (srv_conf->flags & SRVFLAG_AUTH) {
		if (fcgi_add_param(&param, "REMOTE_USER",
		    clt->clt_remote_user, clt) == -1) {
			errstr = "failed to encode param";
			goto fail;
		}
	}

	/* Add HTTP_* headers */
	if (server_headers(clt, desc, server_fcgi_writeheader, &param) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (srv_conf->flags & SRVFLAG_TLS)
		if (fcgi_add_param(&param, "HTTPS", "on", clt) == -1) {
			errstr = "failed to encode param";
			goto fail;
		}

	(void)print_host(&clt->clt_ss, hbuf, sizeof(hbuf));
	if (fcgi_add_param(&param, "REMOTE_ADDR", hbuf, clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	(void)snprintf(hbuf, sizeof(hbuf), "%d", ntohs(clt->clt_port));
	if (fcgi_add_param(&param, "REMOTE_PORT", hbuf, clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (fcgi_add_param(&param, "REQUEST_METHOD",
	    server_httpmethod_byid(desc->http_method), clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (!desc->http_query) {
		if (fcgi_add_param(&param, "REQUEST_URI", desc->http_path,
		    clt) == -1) {
			errstr = "failed to encode param";
			goto fail;
		}
	} else {
		if (asprintf(&str, "%s?%s", desc->http_path,
		    desc->http_query) == -1) {
			errstr = "failed to encode param";
			goto fail;
		}
		ret = fcgi_add_param(&param, "REQUEST_URI", str, clt);
		free(str);
		if (ret == -1) {
			errstr = "failed to encode param";
			goto fail;
		}
	}

	(void)print_host(&clt->clt_srv_ss, hbuf, sizeof(hbuf));
	if (fcgi_add_param(&param, "SERVER_ADDR", hbuf, clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	(void)snprintf(hbuf, sizeof(hbuf), "%d",
	    ntohs(server_socket_getport(&clt->clt_srv_ss)));
	if (fcgi_add_param(&param, "SERVER_PORT", hbuf, clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (fcgi_add_param(&param, "SERVER_NAME", srv_conf->name,
	    clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (fcgi_add_param(&param, "SERVER_PROTOCOL", desc->http_version,
	    clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (fcgi_add_param(&param, "SERVER_SOFTWARE", HTTPD_SERVERNAME,
	    clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (param.total_len != 0) {	/* send last params record */
		if (bufferevent_write(clt->clt_srvbev, &param.buf,
		    sizeof(struct fcgi_record_header) +
		    ntohs(h->content_len)) == -1) {
			errstr = "failed to write to client evbuffer";
			goto fail;
		}
	}

	/* send "no more params" message */
	h->content_len = 0;
	if (bufferevent_write(clt->clt_srvbev, &param.buf,
	    sizeof(struct fcgi_record_header)) == -1) {
		errstr = "failed to write to client evbuffer";
		goto fail;
	}

	bufferevent_settimeout(clt->clt_srvbev,
	    srv_conf->timeout.tv_sec, srv_conf->timeout.tv_sec);
	bufferevent_enable(clt->clt_srvbev, EV_READ|EV_WRITE);
	if (clt->clt_toread != 0) {
		server_read_httpcontent(clt->clt_bev, clt);
		bufferevent_enable(clt->clt_bev, EV_READ);
	} else {
		bufferevent_disable(clt->clt_bev, EV_READ);
		fcgi_add_stdin(clt, NULL);
	}

	if (strcmp(desc->http_version, "HTTP/1.1") == 0) {
		clt->clt_fcgi_chunked = 1;
	} else {
		/* HTTP/1.0 does not support chunked encoding */
		clt->clt_fcgi_chunked = 0;
		clt->clt_persist = 0;
	}
	clt->clt_fcgi_end = 0;
	clt->clt_done = 0;

	free(script);
	return (0);
 fail:
	free(script);
	if (errstr == NULL)
		errstr = strerror(errno);
	server_abort_http(clt, 500, errstr);
	return (-1);
}
Пример #7
0
/* async connect to configure ocsp-responder */
int
ocsp_connect(struct iked *env)
{
	struct ocsp_connect	*oc = NULL;
	struct addrinfo		 hints, *res0 = NULL, *res;
	char			*host = NULL, *port = NULL, *path = NULL;
	int			use_ssl, fd = -1, ret = -1, error;

	if (env->sc_ocsp_url == 0) {
		log_warnx("%s: no ocsp url", __func__);
		goto done;
	}
	if (!OCSP_parse_url(env->sc_ocsp_url, &host, &port, &path, &use_ssl)) {
		log_warnx("%s: error parsing OCSP-request-URL: %s", __func__,
		    env->sc_ocsp_url);
		goto done;
	}

	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		log_debug("%s: socket failed", __func__);
		goto done;
	}
	if ((oc = calloc(1, sizeof(*oc))) == NULL) {
		log_debug("%s: calloc failed", __func__);
		goto done;
	}

	bzero(&hints, sizeof(struct addrinfo));
	hints.ai_family = PF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	error = getaddrinfo(host, port, &hints, &res0);
	if (error) {
		log_debug("%s: getaddrinfo(%s, %s) failed",
		    __func__, host, port);
		goto done;
	}
	/* XXX just pick the first answer. we could loop instead */
	for (res = res0; res; res = res->ai_next)
		if (res->ai_family == AF_INET)
			break;
	if (res == NULL) {
		log_debug("%s: no addr to connect to for %s:%s",
		    __func__, host, port);
		goto done;
	}

	oc->oc_sock.sock_fd = fd;
	oc->oc_sock.sock_env = env;
	oc->oc_path = path;
	path = NULL;

	log_debug("%s: connect(%s, %s)", __func__, host, port);
	socket_set_blockmode(fd, BM_NONBLOCK);
	if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) {
		/* register callback for ansync connect */
		if (errno == EINPROGRESS) {
			event_set(&oc->oc_sock.sock_ev, fd, EV_WRITE,
			    ocsp_connect_cb, oc);
			event_add(&oc->oc_sock.sock_ev, NULL);
			ret = 0;
		} else
			log_debug("%s: error while connecting: %s", __func__,
			    strerror(errno));
	} else {
		ocsp_connect_finish(env, fd, oc);
		ret = 0;
	}
 done:
	if (res0)
		freeaddrinfo(res0);
	free(host);
	free(port);
	free(path);
	if (ret == -1) {
		ocsp_connect_finish(env, -1, oc);
		if (fd >= 0)
			close(fd);
	}
	return (ret);
}