/* we got a connection to the ocsp responder */ int ocsp_receive_fd(struct iked *env, struct imsg *imsg) { struct iked_ocsp_entry *ioe = NULL; struct iked_ocsp *ocsp = NULL; struct iked_socket *sock; char *path = NULL; int ret = -1; log_debug("%s: received socket fd %d", __func__, imsg->fd); if ((ioe = TAILQ_FIRST(&env->sc_ocsp)) == NULL) { log_debug("%s: oops, no request for", __func__); close(imsg->fd); return (-1); } TAILQ_REMOVE(&env->sc_ocsp, ioe, ioe_entry); ocsp = ioe->ioe_ocsp; free(ioe); if ((sock = calloc(1, sizeof(*sock))) == NULL) fatal("ocsp_receive_fd: calloc sock"); /* note that sock_addr is not set */ sock->sock_fd = imsg->fd; sock->sock_env = env; ocsp->ocsp_sock = sock; /* fetch 'path' and 'fd' from imsg */ if ((path = get_string(imsg->data, IMSG_DATA_SIZE(imsg))) == NULL) goto done; BIO_set_fd(ocsp->ocsp_cbio, imsg->fd, BIO_NOCLOSE); if ((ocsp->ocsp_req_ctx = OCSP_sendreq_new(ocsp->ocsp_cbio, path, NULL, -1)) == NULL) goto done; if (!OCSP_REQ_CTX_set1_req(ocsp->ocsp_req_ctx, ocsp->ocsp_req)) goto done; event_set(&sock->sock_ev, sock->sock_fd, EV_WRITE, ocsp_callback, ocsp); event_add(&sock->sock_ev, NULL); ret = 0; done: if (ret == -1) ocsp_validate_finish(ocsp, 0); /* failed */ free(path); return (ret); }
/* ARGSUSED */ void control_dispatch_ext(int fd, short event, void *arg) { struct ctl_conn *c; struct imsg imsg; int n; uid_t euid; gid_t egid; if (getpeereid(fd, &euid, &egid) == -1) fatal("getpeereid"); if ((c = control_connbyfd(fd)) == NULL) { log_warn("control_dispatch_ext: fd %d: not found", fd); return; } if (event & EV_READ) { if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) { control_close(fd); return; } } if (event & EV_WRITE) { if (msgbuf_write(&c->iev.ibuf.w) < 0) { control_close(fd); return; } } for (;;) { if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { control_close(fd); return; } if (n == 0) break; switch (imsg.hdr.type) { case IMSG_SMTP_ENQUEUE: if (env->sc_flags & (SMTPD_SMTP_PAUSED | SMTPD_CONFIGURING | SMTPD_EXITING)) { imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); break; } imsg_compose_event(env->sc_ievs[PROC_SMTP], IMSG_SMTP_ENQUEUE, fd, 0, -1, &euid, sizeof(euid)); break; case IMSG_STATS: if (euid) goto badcred; imsg_compose_event(&c->iev, IMSG_STATS, 0, 0, -1, env->stats, sizeof(struct stats)); break; case IMSG_CTL_SHUTDOWN: /* NEEDS_FIX */ log_debug("received shutdown request"); if (euid) goto badcred; if (env->sc_flags & SMTPD_EXITING) { imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); break; } env->sc_flags |= SMTPD_EXITING; imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); break; case IMSG_CTL_VERBOSE: { int verbose; if (euid) goto badcred; if (IMSG_DATA_SIZE(&imsg) != sizeof(verbose)) goto badcred; memcpy(&verbose, imsg.data, sizeof(verbose)); log_verbose(verbose); imsg_compose_event(env->sc_ievs[PROC_PARENT], IMSG_CTL_VERBOSE, 0, 0, -1, &verbose, sizeof(verbose)); imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); break; } case IMSG_QUEUE_PAUSE_MDA: if (euid) goto badcred; if (env->sc_flags & SMTPD_MDA_PAUSED) { imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); break; } env->sc_flags |= SMTPD_MDA_PAUSED; imsg_compose_event(env->sc_ievs[PROC_QUEUE], IMSG_QUEUE_PAUSE_MDA, 0, 0, -1, NULL, 0); imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); break; case IMSG_QUEUE_PAUSE_MTA: if (euid) goto badcred; if (env->sc_flags & SMTPD_MTA_PAUSED) { imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); break; } env->sc_flags |= SMTPD_MTA_PAUSED; imsg_compose_event(env->sc_ievs[PROC_QUEUE], IMSG_QUEUE_PAUSE_MTA, 0, 0, -1, NULL, 0); imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); break; case IMSG_SMTP_PAUSE: if (euid) goto badcred; if (env->sc_flags & SMTPD_SMTP_PAUSED) { imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); break; } env->sc_flags |= SMTPD_SMTP_PAUSED; imsg_compose_event(env->sc_ievs[PROC_SMTP], IMSG_SMTP_PAUSE, 0, 0, -1, NULL, 0); imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); break; case IMSG_QUEUE_RESUME_MDA: if (euid) goto badcred; if (! (env->sc_flags & SMTPD_MDA_PAUSED)) { imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); break; } env->sc_flags &= ~SMTPD_MDA_PAUSED; imsg_compose_event(env->sc_ievs[PROC_QUEUE], IMSG_QUEUE_RESUME_MDA, 0, 0, -1, NULL, 0); imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); break; case IMSG_QUEUE_RESUME_MTA: if (euid) goto badcred; if (!(env->sc_flags & SMTPD_MTA_PAUSED)) { imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); break; } env->sc_flags &= ~SMTPD_MTA_PAUSED; imsg_compose_event(env->sc_ievs[PROC_QUEUE], IMSG_QUEUE_RESUME_MTA, 0, 0, -1, NULL, 0); imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); break; case IMSG_SMTP_RESUME: if (euid) goto badcred; if (!(env->sc_flags & SMTPD_SMTP_PAUSED)) { imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); break; } env->sc_flags &= ~SMTPD_SMTP_PAUSED; imsg_compose_event(env->sc_ievs[PROC_SMTP], IMSG_SMTP_RESUME, 0, 0, -1, NULL, 0); imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); break; case IMSG_RUNNER_SCHEDULE: { u_int64_t ullval; if (euid) goto badcred; ullval = *(u_int64_t *)imsg.data; imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_RUNNER_SCHEDULE, 0, 0, -1, &ullval, sizeof(ullval)); imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); break; } case IMSG_RUNNER_REMOVE: { u_int64_t ullval; if (euid) goto badcred; ullval = *(u_int64_t *)imsg.data; imsg_compose_event(env->sc_ievs[PROC_RUNNER], IMSG_RUNNER_REMOVE, 0, 0, -1, &ullval, sizeof(ullval)); imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); break; } default: log_debug("control_dispatch_ext: " "error handling %s imsg", imsg_to_str(imsg.hdr.type)); break; } imsg_free(&imsg); continue; badcred: imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); } imsg_event_add(&c->iev); }
int ca_getreq(struct iked *env, struct imsg *imsg) { struct ca_store *store = env->sc_priv; struct iked_sahdr sh; uint8_t type; uint8_t *ptr; size_t len; unsigned int i, n; X509 *ca = NULL, *cert = NULL; struct ibuf *buf; struct iked_static_id id; ptr = (uint8_t *)imsg->data; len = IMSG_DATA_SIZE(imsg); i = sizeof(id) + sizeof(uint8_t) + sizeof(sh); if (len < i || ((len - i) % SHA_DIGEST_LENGTH) != 0) return (-1); memcpy(&id, ptr, sizeof(id)); if (id.id_type == IKEV2_ID_NONE) return (-1); memcpy(&sh, ptr + sizeof(id), sizeof(sh)); memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(uint8_t)); switch (type) { case IKEV2_CERT_RSA_KEY: if (store->ca_pubkey.id_type != type || (buf = store->ca_pubkey.id_buf) == NULL) return (-1); log_debug("%s: using local public key of type %s", __func__, print_map(type, ikev2_cert_map)); break; case IKEV2_CERT_X509_CERT: for (n = 1; i < len; n++, i += SHA_DIGEST_LENGTH) { if ((ca = ca_by_subjectpubkey(store->ca_cas, ptr + i, SHA_DIGEST_LENGTH)) == NULL) continue; log_debug("%s: found CA %s", __func__, ca->name); if ((cert = ca_by_issuer(store->ca_certs, X509_get_subject_name(ca), &id)) != NULL) { /* XXX * should we re-validate our own cert here? */ break; } } if (ca == NULL || cert == NULL) { log_warnx("%s: no valid local certificate found", __func__); type = IKEV2_CERT_NONE; ca_setcert(env, &sh, NULL, type, NULL, 0, PROC_IKEV2); return (0); } log_debug("%s: found local certificate %s", __func__, cert->name); if ((buf = ca_x509_serialize(cert)) == NULL) return (-1); break; default: log_warnx("%s: unknown cert type requested", __func__); return (-1); } ca_setcert(env, &sh, NULL, type, ibuf_data(buf), ibuf_size(buf), PROC_IKEV2); return (0); }
int ca_getreq(struct iked *env, struct imsg *imsg) { struct ca_store *store = env->sc_priv; struct iked_sahdr sh; u_int8_t type; u_int8_t *ptr; size_t len; u_int i, n; X509 *ca = NULL, *cert = NULL; struct ibuf *buf; struct iked_static_id id; ptr = (u_int8_t *)imsg->data; len = IMSG_DATA_SIZE(imsg); i = sizeof(id) + sizeof(u_int8_t) + sizeof(sh); if (len < i || ((len - i) % SHA_DIGEST_LENGTH) != 0) return (-1); memcpy(&id, ptr, sizeof(id)); if (id.id_type == IKEV2_ID_NONE) return (-1); memcpy(&sh, ptr + sizeof(id), sizeof(sh)); memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(u_int8_t)); if (type != IKEV2_CERT_X509_CERT) return (-1); for (n = 1; i < len; n++, i += SHA_DIGEST_LENGTH) { if ((ca = ca_by_subjectpubkey(store->ca_cas, ptr + i, SHA_DIGEST_LENGTH)) == NULL) { log_debug("%s: CA %d not found", __func__, n); print_hex(ptr, i, SHA_DIGEST_LENGTH); continue; } log_debug("%s: found CA %s", __func__, ca->name); if ((cert = ca_by_issuer(store->ca_certs, X509_get_subject_name(ca), &id)) != NULL) { /* XXX should we re-validate our own cert here? */ break; } log_debug("%s: no valid certificate for this CA", __func__); } if (ca == NULL || cert == NULL) { log_warnx("%s: no valid local certificate found", __func__); type = IKEV2_CERT_NONE; ca_setcert(env, &sh, NULL, type, NULL, 0, PROC_IKEV2); return (0); } log_debug("%s: found local certificate %s", __func__, cert->name); if ((buf = ca_x509_serialize(cert)) == NULL) return (-1); type = IKEV2_CERT_X509_CERT; ca_setcert(env, &sh, NULL, type, ibuf_data(buf), ibuf_size(buf), PROC_IKEV2); return (0); }
static int show_stats_output(struct imsg *imsg) { struct stats *stats; if (imsg->hdr.type != IMSG_STATS) errx(1, "show_stats_output: bad hdr type (%d)", imsg->hdr.type); if (IMSG_DATA_SIZE(imsg) != sizeof(*stats)) errx(1, "show_stats_output: bad data size"); stats = imsg->data; stat_init(stats->counters, STATS_MAX); stat_print(STATS_CONTROL_SESSION, STAT_COUNT); stat_print(STATS_CONTROL_SESSION, STAT_ACTIVE); stat_print(STATS_CONTROL_SESSION, STAT_MAXACTIVE); stat_print(STATS_MDA_SESSION, STAT_COUNT); stat_print(STATS_MDA_SESSION, STAT_ACTIVE); stat_print(STATS_MDA_SESSION, STAT_MAXACTIVE); stat_print(STATS_MTA_SESSION, STAT_COUNT); stat_print(STATS_MTA_SESSION, STAT_ACTIVE); stat_print(STATS_MTA_SESSION, STAT_MAXACTIVE); stat_print(STATS_LKA_SESSION, STAT_COUNT); stat_print(STATS_LKA_SESSION, STAT_ACTIVE); stat_print(STATS_LKA_SESSION, STAT_MAXACTIVE); stat_print(STATS_LKA_SESSION_MX, STAT_COUNT); stat_print(STATS_LKA_SESSION_HOST, STAT_COUNT); stat_print(STATS_LKA_SESSION_CNAME, STAT_COUNT); stat_print(STATS_LKA_FAILURE, STAT_COUNT); printf("parent.uptime=%lld\n", (long long int) (time(NULL) - stats->parent.start)); stat_print(STATS_QUEUE_LOCAL, STAT_COUNT); stat_print(STATS_QUEUE_REMOTE, STAT_COUNT); stat_print(STATS_SCHEDULER, STAT_COUNT); stat_print(STATS_SCHEDULER, STAT_ACTIVE); stat_print(STATS_SCHEDULER, STAT_MAXACTIVE); stat_print(STATS_SCHEDULER_BOUNCES, STAT_COUNT); stat_print(STATS_SCHEDULER_BOUNCES, STAT_ACTIVE); stat_print(STATS_SCHEDULER_BOUNCES, STAT_MAXACTIVE); stat_print(STATS_RAMQUEUE_HOST, STAT_ACTIVE); stat_print(STATS_RAMQUEUE_BATCH, STAT_ACTIVE); stat_print(STATS_RAMQUEUE_MESSAGE, STAT_ACTIVE); stat_print(STATS_RAMQUEUE_ENVELOPE, STAT_ACTIVE); stat_print(STATS_RAMQUEUE_HOST, STAT_MAXACTIVE); stat_print(STATS_RAMQUEUE_BATCH, STAT_MAXACTIVE); stat_print(STATS_RAMQUEUE_MESSAGE, STAT_MAXACTIVE); stat_print(STATS_RAMQUEUE_ENVELOPE, STAT_MAXACTIVE); printf("smtp.errors.delays=%zd\n", stats->smtp.delays); printf("smtp.errors.linetoolong=%zd\n", stats->smtp.linetoolong); printf("smtp.errors.read_eof=%zd\n", stats->smtp.read_eof); printf("smtp.errors.read_system=%zd\n", stats->smtp.read_error); printf("smtp.errors.read_timeout=%zd\n", stats->smtp.read_timeout); printf("smtp.errors.tempfail=%zd\n", stats->smtp.tempfail); printf("smtp.errors.toofast=%zd\n", stats->smtp.toofast); printf("smtp.errors.write_eof=%zd\n", stats->smtp.write_eof); printf("smtp.errors.write_system=%zd\n", stats->smtp.write_error); printf("smtp.errors.write_timeout=%zd\n", stats->smtp.write_timeout); stat_print(STATS_SMTP_SESSION, STAT_COUNT); stat_print(STATS_SMTP_SESSION_INET4, STAT_COUNT); stat_print(STATS_SMTP_SESSION_INET6, STAT_COUNT); printf("smtp.sessions.aborted=%zd\n", stats->smtp.read_eof + stats->smtp.read_error + stats->smtp.write_eof + stats->smtp.write_error); stat_print(STATS_SMTP_SESSION, STAT_ACTIVE); stat_print(STATS_SMTP_SESSION, STAT_MAXACTIVE); printf("smtp.sessions.timeout=%zd\n", stats->smtp.read_timeout + stats->smtp.write_timeout); stat_print(STATS_SMTP_SMTPS, STAT_COUNT); stat_print(STATS_SMTP_SMTPS, STAT_ACTIVE); stat_print(STATS_SMTP_SMTPS, STAT_MAXACTIVE); stat_print(STATS_SMTP_STARTTLS, STAT_COUNT); stat_print(STATS_SMTP_STARTTLS, STAT_ACTIVE); stat_print(STATS_SMTP_STARTTLS, STAT_MAXACTIVE); return (1); }
/* ARGSUSED */ void control_dispatch_imsg(int fd, short event, void *arg) { struct ctl_conn *c = arg; struct control_sock *cs = c->cs; struct snmpd *env = cs->cs_env; struct imsg imsg; int n, v, i; if (event & EV_READ) { if (((n = imsg_read_nofd(&c->iev.ibuf)) == -1 && errno != EAGAIN) || n == 0) { control_close(c, "could not read imsg", NULL); return; } } if (event & EV_WRITE) { if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) { control_close(c, "could not write imsg", NULL); return; } } for (;;) { if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { control_close(c, "could not get imsg", NULL); return; } if (n == 0) break; if (cs->cs_restricted || (c->flags & CTL_CONN_LOCKED)) { switch (imsg.hdr.type) { case IMSG_SNMP_AGENTX: case IMSG_SNMP_ELEMENT: case IMSG_SNMP_END: case IMSG_SNMP_LOCK: break; default: control_close(c, "client requested restricted command", &imsg); return; } } control_imsg_forward(&imsg); switch (imsg.hdr.type) { case IMSG_CTL_NOTIFY: if (IMSG_DATA_SIZE(&imsg)) return control_close(c, "invalid size", &imsg); if (c->flags & CTL_CONN_NOTIFY) { log_debug("%s: " "client requested notify more than once", __func__); imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); break; } c->flags |= CTL_CONN_NOTIFY; break; case IMSG_SNMP_LOCK: if (IMSG_DATA_SIZE(&imsg)) return control_close(c, "invalid size", &imsg); /* enable restricted control mode */ c->flags |= CTL_CONN_LOCKED; break; case IMSG_SNMP_AGENTX: if (IMSG_DATA_SIZE(&imsg)) return control_close(c, "invalid size", &imsg); /* rendezvous with the client */ imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); if (imsg_flush(&c->iev.ibuf) == -1) { control_close(c, "could not rendezvous with agentx client", &imsg); return; } /* enable AgentX socket */ c->handle = snmp_agentx_alloc(c->iev.ibuf.fd); if (c->handle == NULL) { control_close(c, "could not allocate agentx socket", &imsg); return; } /* disable IMSG notifications */ c->flags &= ~CTL_CONN_NOTIFY; c->flags |= CTL_CONN_LOCKED; c->iev.handler = control_dispatch_agentx; break; case IMSG_CTL_VERBOSE: if (IMSG_DATA_SIZE(&imsg) != sizeof(v)) return control_close(c, "invalid size", &imsg); memcpy(&v, imsg.data, sizeof(v)); log_verbose(v); for (i = 0; i < PROC_MAX; i++) { if (privsep_process == PROC_CONTROL) continue; proc_forward_imsg(&env->sc_ps, &imsg, i, -1); } break; case IMSG_CTL_RELOAD: if (IMSG_DATA_SIZE(&imsg)) return control_close(c, "invalid size", &imsg); proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT, -1); break; default: control_close(c, "invalid type", &imsg); return; } imsg_free(&imsg); } imsg_event_add(&c->iev); }
int vmmaction(struct parse_result *res) { struct sockaddr_un sun; struct imsg imsg; int done = 0; int n; int ret, action; if (ctl_sock == -1) { if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0)) == -1) err(1, "socket"); bzero(&sun, sizeof(sun)); sun.sun_family = AF_UNIX; strlcpy(sun.sun_path, socket_name, sizeof(sun.sun_path)); if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) err(1, "connect: %s", socket_name); if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) err(1, "malloc"); imsg_init(ibuf, ctl_sock); } switch (res->action) { case CMD_START: /* XXX validation should be done in start_vm() */ if (res->size < 1) errx(1, "specified memory size too small"); if (res->path == NULL) errx(1, "no kernel specified"); if (res->ndisks > VMM_MAX_DISKS_PER_VM) errx(1, "too many disks"); else if (res->ndisks == 0) warnx("starting without disks"); if (res->nifs == -1) res->nifs = 0; if (res->nifs == 0) warnx("starting without network interfaces"); ret = start_vm(res->name, res->size, res->nifs, res->ndisks, res->disks, res->path); if (ret) { errno = ret; err(1, "start VM operation failed"); } break; case CMD_STOP: terminate_vm(res->id, res->name); break; case CMD_STATUS: get_info_vm(res->id, res->name, 0); break; case CMD_CONSOLE: get_info_vm(res->id, res->name, 1); break; case CMD_RELOAD: imsg_compose(ibuf, IMSG_VMDOP_RELOAD, 0, 0, -1, res->path, res->path == NULL ? 0 : strlen(res->path) + 1); done = 1; break; case CMD_LOAD: imsg_compose(ibuf, IMSG_VMDOP_LOAD, 0, 0, -1, res->path, res->path == NULL ? 0 : strlen(res->path) + 1); done = 1; break; case CMD_CREATE: case NONE: break; } action = res->action; parse_free(res); while (ibuf->w.queued) if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) err(1, "write error"); while (!done) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) errx(1, "imsg_read error"); if (n == 0) errx(1, "pipe closed"); while (!done) { if ((n = imsg_get(ibuf, &imsg)) == -1) errx(1, "imsg_get error"); if (n == 0) break; if (imsg.hdr.type == IMSG_CTL_FAIL) { if (IMSG_DATA_SIZE(&imsg) == sizeof(ret)) { memcpy(&ret, imsg.data, sizeof(ret)); errno = ret; warn("command failed"); } else { warnx("command failed"); } done = 1; break; } ret = 0; switch (action) { case CMD_START: done = start_vm_complete(&imsg, &ret, tty_autoconnect); break; case CMD_STOP: done = terminate_vm_complete(&imsg, &ret); break; case CMD_CONSOLE: case CMD_STATUS: done = add_info(&imsg, &ret); break; default: done = 1; break; } imsg_free(&imsg); } } return (0); }