static void mproc_dispatch(int fd, short event, void *arg) { struct mproc *p = arg; struct imsg imsg; ssize_t n; p->events = 0; if (event & EV_READ) { if (p->proc == PROC_CLIENT) n = imsg_read_nofd(&p->imsgbuf); else n = imsg_read(&p->imsgbuf); switch (n) { case -1: if (errno == EAGAIN) break; log_warn("warn: %s -> %s: imsg_read", proc_name(smtpd_process), p->name); fatal("exiting"); /* NOTREACHED */ case 0: /* this pipe is dead, so remove the event handler */ log_debug("debug: %s -> %s: pipe closed", proc_name(smtpd_process), p->name); p->handler(p, NULL); return; default: break; } } if (event & EV_WRITE) { n = msgbuf_write(&p->imsgbuf.w); if (n == 0 || (n == -1 && errno != EAGAIN)) { /* this pipe is dead, so remove the event handler */ log_debug("debug: %s -> %s: pipe closed", proc_name(smtpd_process), p->name); p->handler(p, NULL); return; } } for (;;) { if ((n = imsg_get(&p->imsgbuf, &imsg)) == -1) { if (smtpd_process == PROC_CONTROL && p->proc == PROC_CLIENT) { log_warnx("warn: client sent invalid imsg " "over control socket"); p->handler(p, NULL); return; } log_warn("fatal: %s: error in imsg_get for %s", proc_name(smtpd_process), p->name); fatalx(NULL); } if (n == 0) break; p->handler(p, &imsg); imsg_free(&imsg); } mproc_event_add(p); }
/* 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); }