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); }
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); } }
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]; } } } }
/* 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); }
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); }
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(¶m, 0, sizeof(param)); h = (struct fcgi_record_header *)¶m.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 *)¶m.buf[sizeof(struct fcgi_record_header)]; begin->role = htons(FCGI_RESPONDER); if (bufferevent_write(clt->clt_srvbev, ¶m.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(¶m, "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(¶m, "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(¶m, "SCRIPT_NAME", str, clt); free(str); if (ret == -1) { errstr = "failed to encode param"; goto fail; } if (fcgi_add_param(¶m, "SCRIPT_FILENAME", script, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (desc->http_query) if (fcgi_add_param(¶m, "QUERY_STRING", desc->http_query, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (fcgi_add_param(¶m, "DOCUMENT_ROOT", srv_conf->root, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (fcgi_add_param(¶m, "DOCUMENT_URI", alias, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (fcgi_add_param(¶m, "GATEWAY_INTERFACE", "CGI/1.1", clt) == -1) { errstr = "failed to encode param"; goto fail; } if (srv_conf->flags & SRVFLAG_AUTH) { if (fcgi_add_param(¶m, "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, ¶m) == -1) { errstr = "failed to encode param"; goto fail; } if (srv_conf->flags & SRVFLAG_TLS) if (fcgi_add_param(¶m, "HTTPS", "on", clt) == -1) { errstr = "failed to encode param"; goto fail; } (void)print_host(&clt->clt_ss, hbuf, sizeof(hbuf)); if (fcgi_add_param(¶m, "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(¶m, "REMOTE_PORT", hbuf, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (fcgi_add_param(¶m, "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(¶m, "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(¶m, "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(¶m, "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(¶m, "SERVER_PORT", hbuf, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (fcgi_add_param(¶m, "SERVER_NAME", srv_conf->name, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (fcgi_add_param(¶m, "SERVER_PROTOCOL", desc->http_version, clt) == -1) { errstr = "failed to encode param"; goto fail; } if (fcgi_add_param(¶m, "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, ¶m.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, ¶m.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); }
/* 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); }