예제 #1
0
파일: mproc.c 프로젝트: OpenSMTPD/OpenSMTPD
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);
}
예제 #2
0
/* 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);
}