/* ARGSUSED */ void client_callback(unused int fd, short events, unused void *data) { ssize_t n; if (events & EV_READ) { if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) goto lost_server; if (client_dispatch() != 0) { event_loopexit(NULL); return; } } if (events & EV_WRITE) { if (msgbuf_write(&client_ibuf.w) < 0) goto lost_server; } client_update_event(); return; lost_server: client_exitmsg = "lost server"; client_exitval = 1; event_loopexit(NULL); }
int imsg_flush(struct imsgbuf *ibuf) { while (ibuf->w.queued) if (msgbuf_write(&ibuf->w) <= 0) return (-1); return (0); }
void imsgev_dispatch(int fd, short ev, void *humppa) { struct imsgev *iev = humppa; struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; ssize_t n; iev->events = 0; if (ev & EV_READ) { if ((n = imsg_read(ibuf)) == -1) { imsgev_disconnect(iev, IMSGEV_EREAD); return; } if (n == 0) { /* * Connection is closed for reading, and we assume * it is also closed for writing, so we error out * if write data is pending. */ imsgev_disconnect(iev, (iev->ibuf.w.queued) ? IMSGEV_EWRITE : IMSGEV_DONE); return; } } if (ev & EV_WRITE) { /* * We wanted to write data out but the connection is either * closed, or some error occured. Both case are not recoverable * from the imsg perspective, so we treat it as a WRITE error. */ if ((n = msgbuf_write(&ibuf->w)) != 0) { imsgev_disconnect(iev, IMSGEV_EWRITE); return; } } while (iev->terminate == 0) { if ((n = imsg_get(ibuf, &imsg)) == -1) { imsgev_disconnect(iev, IMSGEV_EIMSG); return; } if (n == 0) break; iev->callback(iev, IMSGEV_IMSG, &imsg); imsg_free(&imsg); } if (iev->terminate && iev->ibuf.w.queued == 0) { imsgev_disconnect(iev, IMSGEV_DONE); return; } imsgev_add(iev); }
static void proc_event_cb(unused int fd, short events, void *arg) { struct tmuxpeer *peer = arg; ssize_t n; struct imsg imsg; int v; if (!(peer->flags & PEER_BAD) && (events & EV_READ)) { if ((n = imsg_read(&peer->ibuf)) == -1 || n == 0) { peer->dispatchcb(NULL, peer->arg); return; } for (;;) { if ((n = imsg_get(&peer->ibuf, &imsg)) == -1) { peer->dispatchcb(NULL, peer->arg); return; } if (n == 0) break; log_debug("peer %p message %d", peer, imsg.hdr.type); v = imsg.hdr.peerid; if (imsg.hdr.type != MSG_VERSION && v != PROTOCOL_VERSION) { log_debug("peer %p bad version %d", peer, v); proc_send(peer, MSG_VERSION, -1, NULL, 0); peer->flags |= PEER_BAD; if (imsg.fd != -1) close(imsg.fd); imsg_free(&imsg); break; } peer->dispatchcb(&imsg, peer->arg); imsg_free(&imsg); } } if (events & EV_WRITE) { if (msgbuf_write(&peer->ibuf.w) <= 0 && errno != EAGAIN) { peer->dispatchcb(NULL, peer->arg); return; } } if ((peer->flags & PEER_BAD) && peer->ibuf.w.queued == 0) { peer->dispatchcb(NULL, peer->arg); return; } proc_update_event(peer); }
static void proc_event_cb(__unused int fd, short events, void *arg) { struct tmuxpeer *peer = arg; ssize_t n; struct imsg imsg; if (!(peer->flags & PEER_BAD) && (events & EV_READ)) { if (((n = imsg_read(&peer->ibuf)) == -1 && errno != EAGAIN) || n == 0) { peer->dispatchcb(NULL, peer->arg); return; } for (;;) { if ((n = imsg_get(&peer->ibuf, &imsg)) == -1) { peer->dispatchcb(NULL, peer->arg); return; } if (n == 0) break; log_debug("peer %p message %d", peer, imsg.hdr.type); if (peer_check_version(peer, &imsg) != 0) { if (imsg.fd != -1) close(imsg.fd); imsg_free(&imsg); break; } peer->dispatchcb(&imsg, peer->arg); imsg_free(&imsg); } } if (events & EV_WRITE) { if (msgbuf_write(&peer->ibuf.w) <= 0 && errno != EAGAIN) { peer->dispatchcb(NULL, peer->arg); return; } } if ((peer->flags & PEER_BAD) && peer->ibuf.w.queued == 0) { peer->dispatchcb(NULL, peer->arg); return; } proc_update_event(peer); }
static void tnt_imsg_callback(evutil_socket_t fd, short events, void *args) { (void)fd; struct imsg_data *data = args; struct imsgbuf *ibuf = data->ibuf; if (events & EV_READ || data->is_ready_read == 1) { data->is_ready_read = 1; if (tnt_dispatch_imsg(data) == -1) data->is_ready_read = 0; } if (events & EV_WRITE || data->is_ready_write == 1) { data->is_ready_write = 1; if (ibuf->w.queued > 0) { if (msgbuf_write(&ibuf->w) == -1) data->is_ready_write = 0; } } }
static int open_connection(void) { struct imsg imsg; int fd; int n; imsg_compose(ibuf, IMSG_SMTP_ENQUEUE, 0, 0, -1, NULL, 0); while (ibuf->w.queued) if (msgbuf_write(&ibuf->w) < 0) err(1, "write error"); while (1) { if ((n = imsg_read(ibuf)) == -1) errx(1, "imsg_read error"); if (n == 0) errx(1, "pipe closed"); if ((n = imsg_get(ibuf, &imsg)) == -1) errx(1, "imsg_get error"); if (n == 0) continue; switch (imsg.hdr.type) { case IMSG_CTL_OK: break; case IMSG_CTL_FAIL: errx(1, "server disallowed submission request"); default: errx(1, "unexpected imsg reply type"); } fd = imsg.fd; imsg_free(&imsg); break; } return fd; }
/* * Loop waiting for packets, timeouts or routing messages. */ void dispatch(void) { int count, to_msec; struct pollfd fds[3]; time_t cur_time, howlong; void (*func)(void); while (quit == 0) { /* * Call expired timeout, and then if there's still * a timeout registered, time out the select call then. */ another: if (!ifi) { warning("No interfaces available"); quit = INTERNALSIG; continue; } if (ifi->rdomain != get_rdomain(ifi->name)) { warning("Interface %s:" " rdomain changed out from under us", ifi->name); quit = INTERNALSIG; continue; } if (timeout.func) { time(&cur_time); if (timeout.when <= cur_time) { func = timeout.func; cancel_timeout(); (*(func))(); goto another; } /* * Figure timeout in milliseconds, and check for * potential overflow, so we can cram into an * int for poll, while not polling with a * negative timeout and blocking indefinitely. */ howlong = timeout.when - cur_time; if (howlong > INT_MAX / 1000) howlong = INT_MAX / 1000; to_msec = howlong * 1000; } else to_msec = -1; /* Set up the descriptors to be polled. */ if (!ifi || ifi->rfdesc == -1) { warning("No live interface to poll on"); quit = INTERNALSIG; continue; } fds[0].fd = ifi->rfdesc; fds[1].fd = routefd; /* Could be -1, which will be ignored. */ fds[2].fd = unpriv_ibuf->fd; fds[0].events = fds[1].events = fds[2].events = POLLIN; if (unpriv_ibuf->w.queued) fds[2].events |= POLLOUT; /* Wait for a packet or a timeout or unpriv_ibuf->fd. XXX */ count = poll(fds, 3, to_msec); /* Not likely to be transitory. */ if (count == -1) { if (errno == EAGAIN || errno == EINTR) { continue; } else { warning("poll: %s", strerror(errno)); quit = INTERNALSIG; continue; } } if ((fds[0].revents & (POLLIN | POLLHUP))) { if (ifi && ifi->linkstat && ifi->rfdesc != -1) got_one(); } if ((fds[1].revents & (POLLIN | POLLHUP))) { if (ifi) routehandler(); } if (fds[2].revents & POLLOUT) { if (msgbuf_write(&unpriv_ibuf->w) <= 0 && errno != EAGAIN) { warning("pipe write error to [priv]"); quit = INTERNALSIG; continue; } } if ((fds[2].revents & (POLLIN | POLLHUP))) { /* Pipe to [priv] closed. Assume it emitted error. */ quit = INTERNALSIG; continue; } } if (quit == SIGHUP) { /* Tell [priv] process that HUP has occurred. */ sendhup(client->active); warning("%s; restarting", strsignal(quit)); exit (0); } else if (quit != INTERNALSIG) { warning("%s; exiting", strsignal(quit)); exit(1); } }
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); }
int main(int argc, char *argv[]) { struct sockaddr_un sun; struct parse_result *res; struct imsg imsg; int ctl_sock; int done = 0; int n, verbose = 0; /* parse options */ if ((res = parse(argc - 1, argv + 1)) == NULL) exit(1); /* connect to relayd control socket */ if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err(1, "socket"); bzero(&sun, sizeof(sun)); sun.sun_family = AF_UNIX; strlcpy(sun.sun_path, RELAYD_SOCKET, sizeof(sun.sun_path)); reconnect: if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) { /* Keep retrying if running in monitor mode */ if (res->action == MONITOR && (errno == ENOENT || errno == ECONNREFUSED)) { usleep(100); goto reconnect; } err(1, "connect: %s", RELAYD_SOCKET); } if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) err(1, NULL); imsg_init(ibuf, ctl_sock); done = 0; /* process user request */ switch (res->action) { case NONE: usage(); /* not reached */ case SHOW_SUM: case SHOW_HOSTS: case SHOW_RDRS: case SHOW_RELAYS: case SHOW_ROUTERS: imsg_compose(ibuf, IMSG_CTL_SHOW_SUM, 0, 0, -1, NULL, 0); printf("%-4s\t%-8s\t%-24s\t%-7s\tStatus\n", "Id", "Type", "Name", "Avlblty"); break; case SHOW_SESSIONS: imsg_compose(ibuf, IMSG_CTL_SESSION, 0, 0, -1, NULL, 0); break; case RDR_ENABLE: imsg_compose(ibuf, IMSG_CTL_RDR_ENABLE, 0, 0, -1, &res->id, sizeof(res->id)); break; case RDR_DISABLE: imsg_compose(ibuf, IMSG_CTL_RDR_DISABLE, 0, 0, -1, &res->id, sizeof(res->id)); break; case TABLE_ENABLE: imsg_compose(ibuf, IMSG_CTL_TABLE_ENABLE, 0, 0, -1, &res->id, sizeof(res->id)); break; case TABLE_DISABLE: imsg_compose(ibuf, IMSG_CTL_TABLE_DISABLE, 0, 0, -1, &res->id, sizeof(res->id)); break; case HOST_ENABLE: imsg_compose(ibuf, IMSG_CTL_HOST_ENABLE, 0, 0, -1, &res->id, sizeof(res->id)); break; case HOST_DISABLE: imsg_compose(ibuf, IMSG_CTL_HOST_DISABLE, 0, 0, -1, &res->id, sizeof(res->id)); break; case SHUTDOWN: imsg_compose(ibuf, IMSG_CTL_SHUTDOWN, 0, 0, -1, NULL, 0); break; case POLL: imsg_compose(ibuf, IMSG_CTL_POLL, 0, 0, -1, NULL, 0); break; case LOAD: imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, res->path, strlen(res->path)); done = 1; break; case RELOAD: imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); done = 1; break; case MONITOR: imsg_compose(ibuf, IMSG_CTL_NOTIFY, 0, 0, -1, NULL, 0); break; case LOG_VERBOSE: verbose = 2; /* FALLTHROUGH */ case LOG_BRIEF: imsg_compose(ibuf, IMSG_CTL_VERBOSE, 0, 0, -1, &verbose, sizeof(verbose)); printf("logging request sent.\n"); done = 1; break; } while (ibuf->w.queued) if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) err(1, "write error"); while (!done) { if ((n = imsg_read(ibuf)) == -1) 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; switch (res->action) { case SHOW_SUM: case SHOW_HOSTS: case SHOW_RDRS: case SHOW_RELAYS: case SHOW_ROUTERS: done = show_summary_msg(&imsg, res->action); break; case SHOW_SESSIONS: done = show_session_msg(&imsg); break; case RDR_DISABLE: case RDR_ENABLE: case TABLE_DISABLE: case TABLE_ENABLE: case HOST_DISABLE: case HOST_ENABLE: case POLL: case SHUTDOWN: done = show_command_output(&imsg); break; case NONE: case LOG_VERBOSE: case LOG_BRIEF: case RELOAD: case LOAD: break; case MONITOR: done = monitor(&imsg); break; } imsg_free(&imsg); } } close(ctl_sock); free(ibuf); return (error ? 1 : 0); }
int main(int argc, char *argv[]) { struct sockaddr_un sun; struct parse_result *res; struct imsg imsg; int ctl_sock; int done = 1; int n; int ch; int v = 0; int quiet = 0; const char *sock = IKED_SOCKET; while ((ch = getopt(argc, argv, "qs:")) != -1) { switch (ch) { case 'q': quiet = 1; break; case 's': sock = optarg; break; default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; /* parse options */ if ((res = parse(argc, argv)) == NULL) exit(1); res->quiet = quiet; switch (res->action) { case CA_CREATE: case CA_DELETE: case CA_INSTALL: case CA_EXPORT: case CA_CERT_CREATE: case CA_CLIENT: case CA_SERVER: case CA_OCSP: case CA_CERT_DELETE: case CA_CERT_INSTALL: case CA_CERT_EXPORT: case CA_CERT_REVOKE: case SHOW_CA: case SHOW_CA_CERTIFICATES: case CA_KEY_CREATE: case CA_KEY_DELETE: case CA_KEY_INSTALL: case CA_KEY_IMPORT: case CA_SUBCA_CREATE: case CA_SUBCA_REVOKE: if (pledge("stdio proc exec rpath wpath cpath fattr tty", NULL) == -1) err(1, "pledge"); ca_opt(res); break; case NONE: usage(); break; default: goto connect; } return (0); connect: /* connect to iked control socket */ if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err(1, "socket"); bzero(&sun, sizeof(sun)); sun.sun_family = AF_UNIX; strlcpy(sun.sun_path, sock, sizeof(sun.sun_path)); reconnect: if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) { /* Keep retrying if running in monitor mode */ if (res->action == MONITOR && (errno == ENOENT || errno == ECONNREFUSED)) { usleep(100); goto reconnect; } err(1, "connect: %s", sock); } if (pledge("stdio", NULL) == -1) err(1, "pledge"); if (res->ibuf != NULL) ibuf = res->ibuf; else if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) err(1, "malloc"); imsg_init(ibuf, ctl_sock); /* process user request */ switch (res->action) { case RESETALL: v = RESET_ALL; break; case RESETCA: v = RESET_CA; break; case RESETPOLICY: v = RESET_POLICY; break; case RESETSA: v = RESET_SA; break; case RESETUSER: v = RESET_USER; break; case LOG_VERBOSE: v = 2; break; case LOG_BRIEF: default: v = 0; break; } switch (res->action) { case NONE: usage(); /* NOTREACHED */ break; case RESETALL: case RESETCA: case RESETPOLICY: case RESETSA: case RESETUSER: imsg_compose(ibuf, IMSG_CTL_RESET, 0, 0, -1, &v, sizeof(v)); printf("reset request sent.\n"); break; case LOAD: imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, res->path, strlen(res->path)); break; case RELOAD: imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); break; case MONITOR: imsg_compose(ibuf, IMSG_CTL_NOTIFY, 0, 0, -1, NULL, 0); done = 0; break; case COUPLE: imsg_compose(ibuf, IMSG_CTL_COUPLE, 0, 0, -1, NULL, 0); break; case DECOUPLE: imsg_compose(ibuf, IMSG_CTL_DECOUPLE, 0, 0, -1, NULL, 0); break; case ACTIVE: imsg_compose(ibuf, IMSG_CTL_ACTIVE, 0, 0, -1, NULL, 0); break; case PASSIVE: imsg_compose(ibuf, IMSG_CTL_PASSIVE, 0, 0, -1, NULL, 0); break; case LOG_VERBOSE: case LOG_BRIEF: imsg_compose(ibuf, IMSG_CTL_VERBOSE, 0, 0, -1, &v, sizeof(v)); printf("logging request sent.\n"); break; default: break; } 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; switch (res->action) { case MONITOR: done = monitor(&imsg); break; default: break; } imsg_free(&imsg); } } close(ctl_sock); free(ibuf); return (0); }
/* ARGSUSED */ void rde_dispatch_parent(int fd, short event, void *bula) { struct imsg imsg; struct rt_node *rt; struct kroute kr; struct imsgev *iev = bula; struct imsgbuf *ibuf = &iev->ibuf; ssize_t n; int shut = 0; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1) fatal("imsg_read error"); if (n == 0) /* connection closed */ shut = 1; } if (event & EV_WRITE) { if (msgbuf_write(&ibuf->w) == -1 && errno != EAGAIN) fatal("msgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("rde_dispatch_parent: imsg_read error"); if (n == 0) break; switch (imsg.hdr.type) { case IMSG_NETWORK_ADD: if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(kr)) { log_warnx("rde_dispatch: wrong imsg len"); break; } memcpy(&kr, imsg.data, sizeof(kr)); rt = rt_new_kr(&kr); rt_insert(rt); break; case IMSG_NETWORK_DEL: if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(kr)) { log_warnx("rde_dispatch: wrong imsg len"); break; } memcpy(&kr, imsg.data, sizeof(kr)); if ((rt = rt_find(kr.prefix.s_addr, kr.netmask.s_addr)) != NULL) rt_remove(rt); break; default: log_debug("rde_dispatch_parent: unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* this pipe is dead, so remove the event handler */ event_del(&iev->ev); event_loopexit(NULL); } }
int tnt_fork(int imsg_fds[2]) { pid_t pid; struct imsgbuf ibuf; struct imsg_data data; struct passwd *pw; struct event_base *evbase = NULL; struct event *sigterm = NULL; struct event *sigint = NULL; struct event *imsg_event = NULL; struct server server; struct event_config *evcfg; switch ((pid = fork())) { case -1: log_err(TNT_OSERR, "fork"); break; case 0: tnt_setproctitle("[unpriv]"); log_set_prefix("unpriv"); break; default: tnt_setproctitle("[priv]"); log_set_prefix("priv"); return pid; } if ((pw = getpwnam(TNETACLE_USER)) == NULL) { log_errx(1, "unknown user " TNETACLE_USER); return TNT_NOUSER; } /*Allocate the event config*/ evcfg = event_config_new(); /* Initialize the OpenSSL library */ SSL_library_init(); SSL_load_error_strings(); /* We MUST have entropy, or else there's no point to crypto. */ if (!RAND_poll()) { log_errx(TNT_SOFTWARE, "[INIT] failed to find an entropy source"); /* never returns */ } if (serv_opts.encryption) server.server_ctx = evssl_init(); else server.server_ctx = NULL; tnt_priv_drop(pw); #if defined(Darwin) /* It's sad isn't it ?*/ event_config_avoid_method(evcfg, "kqueue"); event_config_avoid_method(evcfg, "poll"); event_config_avoid_method(evcfg, "devpoll"); if ((evbase = event_base_new_with_config(evcfg)) == NULL) { log_err(1, "libevent"); } #else if ((evbase = event_base_new_with_config(evcfg)) == NULL) { log_err(1, "libevent"); } #endif sigterm = event_new(evbase, SIGTERM, EV_SIGNAL, &chld_sighdlr, evbase); sigint = event_new(evbase, SIGINT, EV_SIGNAL, &chld_sighdlr, evbase); signal(SIGPIPE, SIG_IGN); signal(SIGHUP, SIG_IGN); signal(SIGCHLD, SIG_DFL); if (server_init(&server, evbase) == -1) log_errx(1, "failed to init the server socket"); data.ibuf = &ibuf; data.evbase = evbase; data.server = &server; imsg_event = init_pipe_endpoint(imsg_fds, &data); event_add(sigterm, NULL); event_add(sigint, NULL); event_add(imsg_event, NULL); log_info("tnetacle ready"); /* Immediately request the creation of a tun interface */ imsg_compose(&ibuf, IMSG_CREATE_DEV, 0, 0, -1, NULL, 0); log_info("starting event loop"); event_base_dispatch(evbase); /* cleanely exit */ msgbuf_write(&ibuf.w); msgbuf_clear(&ibuf.w); /* Shutdown the server */ server_delete(&server); /* * It may look like we freed this one twice, * once here and once in tnetacled.c but this is not the case. * Please don't erase this ! */ event_free(sigterm); event_free(sigint); close(event_get_fd(imsg_event)); event_free(imsg_event); event_base_free(evbase); event_config_free(evcfg); log_info("tnetacle exiting"); exit(TNT_OK); }
/* ARGSUSED */ void control_dispatch_imsg(int fd, short event, void *bula) { struct ctl_conn *c; struct imsg imsg; ssize_t n; unsigned int ifidx; int verbose; if ((c = control_connbyfd(fd)) == NULL) { log_warn("control_dispatch_imsg: 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) == -1) { 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_CTL_FIB_COUPLE: case IMSG_CTL_FIB_DECOUPLE: ospfe_fib_update(imsg.hdr.type); /* FALLTHROUGH */ case IMSG_CTL_FIB_RELOAD: case IMSG_CTL_RELOAD: c->iev.ibuf.pid = imsg.hdr.pid; ospfe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0); break; case IMSG_CTL_KROUTE: case IMSG_CTL_KROUTE_ADDR: case IMSG_CTL_IFINFO: c->iev.ibuf.pid = imsg.hdr.pid; ospfe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); break; case IMSG_CTL_SHOW_INTERFACE: if (imsg.hdr.len == IMSG_HEADER_SIZE + sizeof(ifidx)) { memcpy(&ifidx, imsg.data, sizeof(ifidx)); ospfe_iface_ctl(c, ifidx); imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); } break; case IMSG_CTL_SHOW_DATABASE: case IMSG_CTL_SHOW_DB_EXT: case IMSG_CTL_SHOW_DB_NET: case IMSG_CTL_SHOW_DB_RTR: case IMSG_CTL_SHOW_DB_SELF: case IMSG_CTL_SHOW_DB_SUM: case IMSG_CTL_SHOW_DB_ASBR: case IMSG_CTL_SHOW_DB_OPAQ: case IMSG_CTL_SHOW_RIB: case IMSG_CTL_SHOW_SUM: c->iev.ibuf.pid = imsg.hdr.pid; ospfe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid, imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); break; case IMSG_CTL_SHOW_NBR: ospfe_nbr_ctl(c); break; case IMSG_CTL_LOG_VERBOSE: if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(verbose)) break; /* forward to other processes */ ospfe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); ospfe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid, imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); memcpy(&verbose, imsg.data, sizeof(verbose)); log_verbose(verbose); break; default: log_debug("control_dispatch_imsg: " "error handling imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } imsg_event_add(&c->iev); }
void dns_dispatch_imsg(int fd, short events, void *p) { struct imsg imsg; int n, cnt; char *name; struct ypldap_addr_list hn = TAILQ_HEAD_INITIALIZER(hn); struct ypldap_addr *h; struct ibuf *buf; struct env *env = p; struct imsgev *iev = env->sc_iev; struct imsgbuf *ibuf = &iev->ibuf; int shut = 0; if ((events & (EV_READ | EV_WRITE)) == 0) fatalx("unknown event"); if (events & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) shut = 1; } if (events & EV_WRITE) { if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) shut = 1; goto done; } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("client_dispatch_imsg: imsg_get error"); if (n == 0) break; switch (imsg.hdr.type) { case IMSG_HOST_DNS: name = imsg.data; if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE) fatalx("invalid IMSG_HOST_DNS received"); imsg.hdr.len -= 1 + IMSG_HEADER_SIZE; if (name[imsg.hdr.len] != '\0' || strlen(name) != imsg.hdr.len) fatalx("invalid IMSG_HOST_DNS received"); if ((cnt = host_dns(name, &hn)) == -1) break; buf = imsg_create(ibuf, IMSG_HOST_DNS, imsg.hdr.peerid, 0, cnt * sizeof(struct sockaddr_storage)); if (buf == NULL) break; if (cnt > 0) { while(!TAILQ_EMPTY(&hn)) { h = TAILQ_FIRST(&hn); TAILQ_REMOVE(&hn, h, next); imsg_add(buf, &h->ss, sizeof(h->ss)); free(h); } } imsg_close(ibuf, buf); break; default: break; } imsg_free(&imsg); } done: if (!shut) imsg_event_add(iev); else { /* this pipe is dead, so remove the event handler */ event_del(&iev->ev); event_loopexit(NULL); } }
static void filter_handler(int fd, short event, void *p) { struct imsg imsg; ssize_t n; short evflags = EV_READ; enum filter_status ret; struct filter_msg fm; if (event & EV_READ) { n = imsg_read(&fi.ibuf); if (n == -1) err(1, "imsg_read"); if (n == 0) { event_del(&fi.ev); event_loopexit(NULL); return; } } if (event & EV_WRITE) { if (msgbuf_write(&fi.ibuf.w) == -1) err(1, "msgbuf_write"); if (fi.ibuf.w.queued) evflags |= EV_WRITE; } for (;;) { n = imsg_get(&fi.ibuf, &imsg); if (n == -1) errx(1, "imsg_get"); if (n == 0) break; if ((imsg.hdr.len - IMSG_HEADER_SIZE) != sizeof(fm)) errx(1, "corrupted imsg"); memcpy(&fm, imsg.data, sizeof (fm)); if (fm.version != FILTER_API_VERSION) errx(1, "API version mismatch"); switch (imsg.hdr.type) { case FILTER_CONNECT: if (fi.connect_cb == NULL) goto ignore; ret = fi.connect_cb(fm.cl_id, &fm.u.connect, fi.connect_cb_arg); break; case FILTER_HELO: if (fi.helo_cb == NULL) goto ignore; ret = fi.helo_cb(fm.cl_id, &fm.u.helo, fi.helo_cb_arg); break; case FILTER_EHLO: if (fi.ehlo_cb == NULL) goto ignore; ret = fi.ehlo_cb(fm.cl_id, &fm.u.helo, fi.ehlo_cb_arg); break; case FILTER_MAIL: if (fi.mail_cb == NULL) goto ignore; ret = fi.mail_cb(fm.cl_id, &fm.u.mail, fi.mail_cb_arg); break; case FILTER_RCPT: if (fi.rcpt_cb == NULL) goto ignore; ret = fi.rcpt_cb(fm.cl_id, &fm.u.rcpt, fi.rcpt_cb_arg); break; case FILTER_DATALINE: if (fi.dataline_cb == NULL) goto ignore; ret = fi.dataline_cb(fm.cl_id, &fm.u.dataline, fi.dataline_cb_arg); break; case FILTER_QUIT: if (fi.quit_cb == NULL) goto ignore; ret = fi.quit_cb(fm.cl_id, fi.quit_cb_arg); break; case FILTER_CLOSE: if (fi.close_cb == NULL) goto ignore; ret = fi.close_cb(fm.cl_id, fi.close_cb_arg); break; case FILTER_RSET: if (fi.rset_cb == NULL) goto ignore; ret = fi.rset_cb(fm.cl_id, fi.rset_cb_arg); break; default: errx(1, "unsupported imsg"); } switch (ret) { case STATUS_ACCEPT: case STATUS_REJECT: fm.code = ret; imsg_compose(&fi.ibuf, imsg.hdr.type, 0, 0, -1, &fm, sizeof fm); evflags |= EV_WRITE; break; case STATUS_WAITING: /* waiting for asynchronous call ... */ break; } imsg_free(&imsg); } event_set(&fi.ev, 0, evflags, filter_handler, &fi); event_add(&fi.ev, NULL); return; ignore: imsg_free(&imsg); fm.code = STATUS_IGNORE; imsg_compose(&fi.ibuf, imsg.hdr.type, 0, 0, -1, &fm, sizeof fm); evflags |= EV_WRITE; event_set(&fi.ev, 0, evflags, filter_handler, &fi); event_add(&fi.ev, NULL); }
int main(int argc, char *argv[]) { struct sockaddr_un sun; struct parse_result *res; struct imsg imsg; unsigned int ifidx = 0; int ctl_sock; int done = 0, verbose = 0; int n; int ch; char *sockname; sockname = OSPF6D_SOCKET; while ((ch = getopt(argc, argv, "s:")) != -1) { switch (ch) { case 's': sockname = optarg; break; default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; /* parse options */ if ((res = parse(argc, argv)) == NULL) exit(1); /* connect to ospf6d control socket */ if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err(1, "socket"); bzero(&sun, sizeof(sun)); sun.sun_family = AF_UNIX; strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)); if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) err(1, "connect: %s", sockname); if (pledge("stdio", NULL) == -1) err(1, "pledge"); if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) err(1, NULL); imsg_init(ibuf, ctl_sock); done = 0; /* process user request */ switch (res->action) { case NONE: usage(); /* not reached */ case SHOW: case SHOW_SUM: imsg_compose(ibuf, IMSG_CTL_SHOW_SUM, 0, 0, -1, NULL, 0); break; case SHOW_IFACE: printf("%-11s %-29s %-6s %-10s %-10s %-8s\n", "Interface", "Address", "State", "HelloTimer", "Linkstate", "Uptime"); /*FALLTHROUGH*/ case SHOW_IFACE_DTAIL: if (*res->ifname) { ifidx = if_nametoindex(res->ifname); if (ifidx == 0) errx(1, "no such interface %s", res->ifname); } imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, &ifidx, sizeof(ifidx)); break; case SHOW_NBR: printf("%-15s %-3s %-12s %-9s %-11s %s\n", "ID", "Pri", "State", "DeadTime", "Iface","Uptime"); /*FALLTHROUGH*/ case SHOW_NBR_DTAIL: imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0); break; case SHOW_DB: imsg_compose(ibuf, IMSG_CTL_SHOW_DATABASE, 0, 0, -1, NULL, 0); break; case SHOW_DBBYAREA: imsg_compose(ibuf, IMSG_CTL_SHOW_DATABASE, 0, 0, -1, &res->addr, sizeof(res->addr)); break; case SHOW_DBEXT: imsg_compose(ibuf, IMSG_CTL_SHOW_DB_EXT, 0, 0, -1, NULL, 0); break; case SHOW_DBLINK: imsg_compose(ibuf, IMSG_CTL_SHOW_DB_LINK, 0, 0, -1, NULL, 0); break; case SHOW_DBNET: imsg_compose(ibuf, IMSG_CTL_SHOW_DB_NET, 0, 0, -1, NULL, 0); break; case SHOW_DBRTR: imsg_compose(ibuf, IMSG_CTL_SHOW_DB_RTR, 0, 0, -1, NULL, 0); break; case SHOW_DBINTRA: imsg_compose(ibuf, IMSG_CTL_SHOW_DB_INTRA, 0, 0, -1, NULL, 0); break; case SHOW_DBSELF: imsg_compose(ibuf, IMSG_CTL_SHOW_DB_SELF, 0, 0, -1, NULL, 0); break; case SHOW_DBSUM: imsg_compose(ibuf, IMSG_CTL_SHOW_DB_SUM, 0, 0, -1, NULL, 0); break; case SHOW_DBASBR: imsg_compose(ibuf, IMSG_CTL_SHOW_DB_ASBR, 0, 0, -1, NULL, 0); break; case SHOW_RIB: printf("%-20s %-17s %-12s %-9s %-7s %-8s\n", "Destination", "Nexthop", "Path Type", "Type", "Cost", "Uptime"); /*FALLTHROUGH*/ case SHOW_RIB_DTAIL: imsg_compose(ibuf, IMSG_CTL_SHOW_RIB, 0, 0, -1, NULL, 0); break; case SHOW_FIB: if (IN6_IS_ADDR_UNSPECIFIED(&res->addr)) imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1, &res->flags, sizeof(res->flags)); else imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1, &res->addr, sizeof(res->addr)); show_fib_head(); break; case FIB: errx(1, "fib couple|decouple"); break; case FIB_COUPLE: imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0); printf("couple request sent.\n"); done = 1; break; case FIB_DECOUPLE: imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0); printf("decouple request sent.\n"); done = 1; break; case LOG_VERBOSE: verbose = 1; /* FALLTHROUGH */ case LOG_BRIEF: imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, &verbose, sizeof(verbose)); printf("logging request sent.\n"); done = 1; break; case RELOAD: imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); printf("reload request sent.\n"); done = 1; break; } 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; switch (res->action) { case SHOW: case SHOW_SUM: done = show_summary_msg(&imsg); break; case SHOW_IFACE: done = show_interface_msg(&imsg); break; case SHOW_IFACE_DTAIL: done = show_interface_detail_msg(&imsg); break; case SHOW_NBR: done = show_nbr_msg(&imsg); break; case SHOW_NBR_DTAIL: done = show_nbr_detail_msg(&imsg); break; case SHOW_DB: case SHOW_DBBYAREA: case SHOW_DBSELF: done = show_database_msg(&imsg); break; case SHOW_DBEXT: case SHOW_DBLINK: case SHOW_DBNET: case SHOW_DBRTR: case SHOW_DBINTRA: case SHOW_DBSUM: case SHOW_DBASBR: done = show_db_msg_detail(&imsg); break; case SHOW_RIB: done = show_rib_msg(&imsg); break; case SHOW_RIB_DTAIL: done = show_rib_detail_msg(&imsg); break; case SHOW_FIB: done = show_fib_msg(&imsg); break; case NONE: case FIB: case FIB_COUPLE: case FIB_DECOUPLE: case LOG_VERBOSE: case LOG_BRIEF: case RELOAD: break; } imsg_free(&imsg); } } close(ctl_sock); free(ibuf); return (0); }
int main(int argc, char *argv[]) { struct sockaddr_un sun; struct parse_result *res = NULL; struct imsg imsg; struct smtpd smtpd; int ctl_sock; int done = 0; int n, verbose = 0; /* parse options */ if (strcmp(__progname, "sendmail") == 0 || strcmp(__progname, "send-mail") == 0) sendmail = 1; else if (strcmp(__progname, "mailq") == 0) { if (geteuid()) errx(1, "need root privileges"); setup_env(&smtpd); show_queue(0); return 0; } else if (strcmp(__progname, "smtpctl") == 0) { /* check for root privileges */ if (geteuid()) errx(1, "need root privileges"); setup_env(&smtpd); if ((res = parse(argc - 1, argv + 1)) == NULL) exit(1); /* handle "disconnected" commands */ switch (res->action) { case SHOW_QUEUE: show_queue(0); break; case SHOW_RUNQUEUE: break; default: goto connected; } return 0; } else errx(1, "unsupported mode"); connected: /* connect to smtpd control socket */ if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err(1, "socket"); bzero(&sun, sizeof(sun)); sun.sun_family = AF_UNIX; strlcpy(sun.sun_path, SMTPD_SOCKET, sizeof(sun.sun_path)); if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) { if (sendmail) return enqueue_offline(argc, argv); err(1, "connect: %s", SMTPD_SOCKET); } if ((ibuf = calloc(1, sizeof(struct imsgbuf))) == NULL) err(1, NULL); imsg_init(ibuf, ctl_sock); if (sendmail) return enqueue(argc, argv); /* process user request */ switch (res->action) { case NONE: usage(); /* not reached */ case SCHEDULE: case REMOVE: { u_int64_t ulval; char *ep; errno = 0; ulval = strtoull(res->data, &ep, 16); if (res->data[0] == '\0' || *ep != '\0') errx(1, "invalid msgid/evpid"); if (errno == ERANGE && ulval == ULLONG_MAX) errx(1, "invalid msgid/evpid"); if (ulval == 0) errx(1, "invalid msgid/evpid"); if (res->action == SCHEDULE) imsg_compose(ibuf, IMSG_SCHEDULER_SCHEDULE, 0, 0, -1, &ulval, sizeof(ulval)); if (res->action == REMOVE) imsg_compose(ibuf, IMSG_SCHEDULER_REMOVE, 0, 0, -1, &ulval, sizeof(ulval)); break; } case SCHEDULE_ALL: { u_int64_t ulval = 0; imsg_compose(ibuf, IMSG_SCHEDULER_SCHEDULE, 0, 0, -1, &ulval, sizeof(ulval)); break; } case SHUTDOWN: imsg_compose(ibuf, IMSG_CTL_SHUTDOWN, 0, 0, -1, NULL, 0); break; case PAUSE_MDA: imsg_compose(ibuf, IMSG_QUEUE_PAUSE_MDA, 0, 0, -1, NULL, 0); break; case PAUSE_MTA: imsg_compose(ibuf, IMSG_QUEUE_PAUSE_MTA, 0, 0, -1, NULL, 0); break; case PAUSE_SMTP: imsg_compose(ibuf, IMSG_SMTP_PAUSE, 0, 0, -1, NULL, 0); break; case RESUME_MDA: imsg_compose(ibuf, IMSG_QUEUE_RESUME_MDA, 0, 0, -1, NULL, 0); break; case RESUME_MTA: imsg_compose(ibuf, IMSG_QUEUE_RESUME_MTA, 0, 0, -1, NULL, 0); break; case RESUME_SMTP: imsg_compose(ibuf, IMSG_SMTP_RESUME, 0, 0, -1, NULL, 0); break; case SHOW_STATS: imsg_compose(ibuf, IMSG_STATS, 0, 0, -1, NULL, 0); break; case MONITOR: /* XXX */ break; case LOG_VERBOSE: verbose = 1; /* FALLTHROUGH */ case LOG_BRIEF: imsg_compose(ibuf, IMSG_CTL_VERBOSE, 0, 0, -1, &verbose, sizeof(verbose)); printf("logging request sent.\n"); done = 1; break; default: errx(1, "unknown request (%d)", res->action); } while (ibuf->w.queued) if (msgbuf_write(&ibuf->w) < 0) err(1, "write error"); while (!done) { if ((n = imsg_read(ibuf)) == -1) 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; switch(res->action) { case REMOVE: case SCHEDULE: case SCHEDULE_ALL: case SHUTDOWN: case PAUSE_MDA: case PAUSE_MTA: case PAUSE_SMTP: case RESUME_MDA: case RESUME_MTA: case RESUME_SMTP: case LOG_VERBOSE: case LOG_BRIEF: done = show_command_output(&imsg); break; case SHOW_STATS: done = show_stats_output(&imsg); break; case NONE: break; case MONITOR: break; default: err(1, "unexpected reply (%d)", res->action); } /* insert imsg replies switch here */ imsg_free(&imsg); } } close(ctl_sock); free(ibuf); return (0); }
/* ARGSUSED */ void control_dispatch_imsg(int fd, short event, void *arg) { struct control_sock *cs = (struct control_sock *)arg; struct ctl_conn *c; struct imsg imsg; int n, retval; if ((c = control_connbyfd(fd)) == NULL) { log_warn("control_dispatch_imsg: fd %d: not found", fd); return; } if (event & EV_WRITE) { if (msgbuf_write(&c->iev.ibuf.w) < 0) { control_close(fd, cs); return; } if (!c->iev.ibuf.w.queued) npppd_ctl_imsg_compose(c->ctx, &c->iev.ibuf); imsg_event_add(&c->iev); if (!(event & EV_READ)) return; } if (event & EV_READ) { if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) { control_close(fd, cs); return; } } else fatalx("unknown event"); for (;;) { if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { control_close(fd, cs); return; } if (n == 0) break; if (cs->cs_restricted || (c->flags & CTL_CONN_LOCKED)) { switch (imsg.hdr.type) { default: log_debug("control_dispatch_imsg: " "client requested restricted command"); imsg_free(&imsg); control_close(fd, cs); return; } } switch (imsg.hdr.type) { case IMSG_CTL_NOP: imsg_compose(&c->iev.ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0); break; case IMSG_CTL_WHO: case IMSG_CTL_MONITOR: case IMSG_CTL_WHO_AND_MONITOR: if (imsg.hdr.type == IMSG_CTL_WHO) retval = npppd_ctl_who(c->ctx); else if (imsg.hdr.type == IMSG_CTL_MONITOR) retval = npppd_ctl_monitor(c->ctx); else retval = npppd_ctl_who_and_monitor(c->ctx); imsg_compose(&c->iev.ibuf, (retval == 0)? IMSG_CTL_OK : IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); break; case IMSG_CTL_DISCONNECT: { struct npppd_disconnect_request *req; struct npppd_disconnect_response res; req = (struct npppd_disconnect_request *)imsg.data; retval = npppd_ctl_disconnect(c->ctx, req->ppp_id, req->count); res.count = retval; imsg_compose(&c->iev.ibuf, IMSG_CTL_OK, 0, 0, -1, &res, sizeof(res)); break; } default: imsg_compose(&c->iev.ibuf, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); break; } imsg_free(&imsg); } if (!c->iev.ibuf.w.queued) npppd_ctl_imsg_compose(c->ctx, &c->iev.ibuf); imsg_event_add(&c->iev); }
/* ARGSUSED */ void control_dispatch_imsg(int fd, short event, void *bula) { struct ctl_conn *c; struct imsg imsg; int n; unsigned int ifidx; int verbose; if ((c = control_connbyfd(fd)) == NULL) { log_warn("control_dispatch_imsg: 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) == -1 && errno != EAGAIN) { 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_CTL_MFC_COUPLE: case IMSG_CTL_MFC_DECOUPLE: case IMSG_CTL_RELOAD: dvmrpe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0); break; case IMSG_CTL_SHOW_IFACE: if (imsg.hdr.len == IMSG_HEADER_SIZE + sizeof(ifidx)) { memcpy(&ifidx, imsg.data, sizeof(ifidx)); dvmrpe_iface_ctl(c, ifidx); imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); } break; case IMSG_CTL_SHOW_IGMP: if (imsg.hdr.len == IMSG_HEADER_SIZE + sizeof(ifidx)) { memcpy(&ifidx, imsg.data, sizeof(ifidx)); dvmrpe_iface_igmp_ctl(c, ifidx); imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); } break; case IMSG_CTL_SHOW_NBR: dvmrpe_nbr_ctl(c); break; case IMSG_CTL_SHOW_RIB: case IMSG_CTL_SHOW_MFC: case IMSG_CTL_SHOW_SUM: c->iev.ibuf.pid = imsg.hdr.pid; dvmrpe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid, imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); break; case IMSG_CTL_LOG_VERBOSE: if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(verbose)) break; /* forward to other processes */ dvmrpe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); dvmrpe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid, imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); memcpy(&verbose, imsg.data, sizeof(verbose)); log_verbose(verbose); break; default: log_debug("control_dispatch_imsg: " "error handling imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } imsg_event_add(&c->iev); }
/* ARGSUSED */ void rde_dispatch_imsg(int fd, short event, void *bula) { struct imsgev *iev = bula; struct imsgbuf *ibuf = &iev->ibuf; struct rip_route rr; struct imsg imsg; ssize_t n; int shut = 0, verbose; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1) fatal("imsg_read error"); if (n == 0) /* connection closed */ shut = 1; } if (event & EV_WRITE) { if (msgbuf_write(&ibuf->w) == -1 && errno != EAGAIN) fatal("msgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("rde_dispatch_imsg: imsg_read error"); if (n == 0) break; switch (imsg.hdr.type) { case IMSG_ROUTE_FEED: if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(rr)) fatalx("invalid size of RDE request"); memcpy(&rr, imsg.data, sizeof(rr)); if (rde_check_route(&rr) == -1) log_debug("rde_dispatch_imsg: " "packet malformed\n"); break; case IMSG_FULL_REQUEST: bzero(&rr, sizeof(rr)); /* * AFI == 0 && metric == INFINITY request the * whole routing table */ rr.metric = INFINITY; rde_imsg_compose_ripe(IMSG_REQUEST_ADD, 0, 0, &rr, sizeof(rr)); rde_imsg_compose_ripe(IMSG_SEND_REQUEST, 0, 0, NULL, 0); break; case IMSG_FULL_RESPONSE: rt_snap(imsg.hdr.peerid); rde_imsg_compose_ripe(IMSG_SEND_RESPONSE, imsg.hdr.peerid, 0, NULL, 0); break; case IMSG_ROUTE_REQUEST: if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(rr)) fatalx("invalid size of RDE request"); memcpy(&rr, imsg.data, sizeof(rr)); rt_complete(&rr); rde_imsg_compose_ripe(IMSG_RESPONSE_ADD, imsg.hdr.peerid, 0, &rr, sizeof(rr)); break; case IMSG_ROUTE_REQUEST_END: rde_imsg_compose_ripe(IMSG_SEND_RESPONSE, imsg.hdr.peerid, 0, NULL, 0); break; case IMSG_CTL_SHOW_RIB: rt_dump(imsg.hdr.pid); imsg_compose_event(iev_ripe, IMSG_CTL_END, 0, imsg.hdr.pid, -1, NULL, 0); break; case IMSG_CTL_LOG_VERBOSE: /* already checked by ripe */ memcpy(&verbose, imsg.data, sizeof(verbose)); log_verbose(verbose); break; default: log_debug("rde_dispatch_msg: unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* this pipe is dead, so remove the event handler */ event_del(&iev->ev); event_loopexit(NULL); } }
int client_main(struct client_ctx *cctx) { struct pollfd pfd; int n, nfds; siginit(); logfile("client"); /* * imsg_read in the first client poll loop (before the terminal has * been initialiased) may have read messages into the buffer after the * MSG_READY switched to here. Process anything outstanding now so poll * doesn't hang waiting for messages that have already arrived. */ if (client_msg_dispatch(cctx) != 0) goto out; for (;;) { if (sigterm) client_write_server(cctx, MSG_EXITING, NULL, 0); if (sigchld) { waitpid(WAIT_ANY, NULL, WNOHANG); sigchld = 0; } if (sigwinch) client_handle_winch(cctx); if (sigcont) { siginit(); client_write_server(cctx, MSG_WAKEUP, NULL, 0); sigcont = 0; } pfd.fd = cctx->ibuf.fd; pfd.events = POLLIN; if (cctx->ibuf.w.queued > 0) pfd.events |= POLLOUT; if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { if (errno == EAGAIN || errno == EINTR) continue; fatal("poll failed"); } if (nfds == 0) continue; if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL)) fatalx("socket error"); if (pfd.revents & POLLIN) { if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) { cctx->exittype = CCTX_DIED; break; } if (client_msg_dispatch(cctx) != 0) break; } if (pfd.revents & POLLOUT) { if (msgbuf_write(&cctx->ibuf.w) < 0) { cctx->exittype = CCTX_DIED; break; } } } out: if (sigterm) { printf("[terminated]\n"); return (1); } switch (cctx->exittype) { case CCTX_DIED: printf("[lost server]\n"); return (0); case CCTX_SHUTDOWN: printf("[server exited]\n"); return (0); case CCTX_EXIT: if (cctx->errstr != NULL) { printf("[error: %s]\n", cctx->errstr); return (1); } printf("[exited]\n"); return (0); case CCTX_DETACH: printf("[detached]\n"); return (0); default: printf("[unknown error]\n"); return (1); } }
void ctl_main(int argc, char *argv[]) { struct sockaddr_un sa; struct imsg imsg; struct imsgbuf *ibuf_ctl; int fd, n, done, ch, action; char *sockname; sockname = CTLSOCKET; if (argc < 2) { usage(); /* NOTREACHED */ } while ((ch = getopt(argc, argv, "s:")) != -1) { switch (ch) { case 's': showopt = ctl_lookup_option(optarg, ctl_showopt_list); if (showopt == NULL) { warnx("Unknown show modifier '%s'", optarg); usage(); } break; default: usage(); /* NOTREACHED */ } } action = -1; if (showopt != NULL) { switch (*showopt) { case 'p': action = CTL_SHOW_PEERS; break; case 's': action = CTL_SHOW_STATUS; break; case 'S': action = CTL_SHOW_SENSORS; break; case 'a': action = CTL_SHOW_ALL; break; } } if (action == -1) usage(); /* NOTREACHED */ if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err(1, "ntpctl: socket"); bzero(&sa, sizeof(sa)); sa.sun_family = AF_UNIX; if (strlcpy(sa.sun_path, sockname, sizeof(sa.sun_path)) >= sizeof(sa.sun_path)) errx(1, "ctl socket name too long"); if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) err(1, "connect: %s", sockname); if ((ibuf_ctl = malloc(sizeof(struct imsgbuf))) == NULL) err(1, NULL); imsg_init(ibuf_ctl, fd); switch (action) { case CTL_SHOW_STATUS: imsg_compose(ibuf_ctl, IMSG_CTL_SHOW_STATUS, 0, 0, -1, NULL, 0); break; case CTL_SHOW_PEERS: imsg_compose(ibuf_ctl, IMSG_CTL_SHOW_PEERS, 0, 0, -1, NULL, 0); break; case CTL_SHOW_SENSORS: imsg_compose(ibuf_ctl, IMSG_CTL_SHOW_SENSORS, 0, 0, -1, NULL, 0); break; case CTL_SHOW_ALL: imsg_compose(ibuf_ctl, IMSG_CTL_SHOW_ALL, 0, 0, -1, NULL, 0); break; default: errx(1, "invalid action"); break; /* NOTREACHED */ } while (ibuf_ctl->w.queued) if (msgbuf_write(&ibuf_ctl->w) <= 0 && errno != EAGAIN) err(1, "ibuf_ctl: msgbuf_write error"); done = 0; while (!done) { if ((n = imsg_read(ibuf_ctl)) == -1) err(1, "ibuf_ctl: imsg_read error"); if (n == 0) errx(1, "ntpctl: pipe closed"); while (!done) { if ((n = imsg_get(ibuf_ctl, &imsg)) == -1) err(1, "ibuf_ctl: imsg_get error"); if (n == 0) break; switch (action) { case CTL_SHOW_STATUS: show_status_msg(&imsg); done = 1; break; case CTL_SHOW_PEERS: show_peer_msg(&imsg, 0); if (imsg.hdr.type == IMSG_CTL_SHOW_PEERS_END) done = 1; break; case CTL_SHOW_SENSORS: show_sensor_msg(&imsg, 0); if (imsg.hdr.type == IMSG_CTL_SHOW_SENSORS_END) done = 1; break; case CTL_SHOW_ALL: switch (imsg.hdr.type) { case IMSG_CTL_SHOW_STATUS: show_status_msg(&imsg); break; case IMSG_CTL_SHOW_PEERS: show_peer_msg(&imsg, 1); break; case IMSG_CTL_SHOW_SENSORS: show_sensor_msg(&imsg, 1); break; case IMSG_CTL_SHOW_PEERS_END: case IMSG_CTL_SHOW_SENSORS_END: /* do nothing */ break; case IMSG_CTL_SHOW_ALL_END: done=1; break; default: /* no action taken */ break; } default: /* no action taken */ break; } imsg_free(&imsg); } } close(fd); free(ibuf_ctl); exit(0); }
/* 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); }
void proc_dispatch(int fd, short event, void *arg) { struct privsep_proc *p = (struct privsep_proc *)arg; struct privsep *ps = p->p_ps; struct imsgev *iev; struct imsgbuf *ibuf; struct imsg imsg; ssize_t n; int verbose; const char *title; title = ps->ps_title[privsep_process]; iev = &ps->ps_ievs[p->p_id]; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1) fatal(title); if (n == 0) { /* this pipe is dead, so remove the event handler */ event_del(&iev->ev); event_loopexit(NULL); return; } } if (event & EV_WRITE) { if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) fatal(title); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal(title); if (n == 0) break; /* * Check the message with the program callback */ if ((p->p_cb)(fd, p, &imsg) == 0) { /* Message was handled by the callback, continue */ imsg_free(&imsg); continue; } /* * Generic message handling */ switch (imsg.hdr.type) { case IMSG_CTL_VERBOSE: IMSG_SIZE_CHECK(&imsg, &verbose); memcpy(&verbose, imsg.data, sizeof(verbose)); log_verbose(verbose); break; default: log_warnx("%s: %s got imsg %d", __func__, p->p_title, imsg.hdr.type); fatalx(title); } imsg_free(&imsg); } imsg_event_add(iev); }
/* ARGSUSED */ void control_dispatch_imsg(int fd, short event, void *arg) { struct control_sock *cs = arg; struct iked *env = cs->cs_env; struct ctl_conn *c; struct imsg imsg; int n, v; if ((c = control_connbyfd(fd)) == NULL) { log_warn("%s: fd %d: not found", __func__, fd); return; } if (event & EV_READ) { if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) { control_close(fd, cs); return; } } if (event & EV_WRITE) { if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) { control_close(fd, cs); return; } } for (;;) { if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { control_close(fd, cs); return; } if (n == 0) break; control_imsg_forward(&imsg); switch (imsg.hdr.type) { case IMSG_CTL_NOTIFY: 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_CTL_VERBOSE: IMSG_SIZE_CHECK(&imsg, &v); memcpy(&v, imsg.data, sizeof(v)); log_verbose(v); proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT, -1); proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV2, -1); proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV1, -1); break; case IMSG_CTL_RELOAD: case IMSG_CTL_RESET: case IMSG_CTL_COUPLE: case IMSG_CTL_DECOUPLE: case IMSG_CTL_ACTIVE: case IMSG_CTL_PASSIVE: proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT, -1); break; default: log_debug("%s: error handling imsg %d", __func__, imsg.hdr.type); break; } imsg_free(&imsg); } imsg_event_add(&c->iev); }
/* ARGSUSED */ static void control_dispatch_ext(int fd, short event, void *arg) { struct ctl_conn *c; struct imsg imsg; int n, verbose; uid_t euid; gid_t egid; uint64_t id; struct stat_kv *kvp; char *key; struct stat_value val; size_t len; 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(c); return; } } if (event & EV_WRITE) { if (msgbuf_write(&c->iev.ibuf.w) < 0) { control_close(c); return; } } for (;;) { if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { control_close(c); 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, NULL, 0); break; case IMSG_STATS_GET: if (euid) goto badcred; kvp = imsg.data; if (! stat_backend->iter(&kvp->iter, &key, &val)) kvp->iter = NULL; else { strlcpy(kvp->key, key, sizeof kvp->key); kvp->val = val; } imsg_compose_event(&c->iev, IMSG_STATS_GET, 0, 0, -1, kvp, sizeof *kvp); 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); imsg_compose_event(env->sc_ievs[PROC_PARENT], IMSG_CTL_SHUTDOWN, 0, 0, -1, NULL, 0); break; case IMSG_CTL_VERBOSE: if (euid) goto badcred; if (imsg.hdr.len - IMSG_HEADER_SIZE != 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; } log_info("mda paused"); 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; } log_info("mta paused"); 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; } log_info("smtp paused"); 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; } log_info("mda resumed"); 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; } log_info("mta resumed"); 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; } log_info("smtp resumed"); 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_SCHEDULER_SCHEDULE: if (euid) goto badcred; id = *(uint64_t *)imsg.data; imsg_compose_event(env->sc_ievs[PROC_SCHEDULER], IMSG_SCHEDULER_SCHEDULE, 0, 0, -1, &id, sizeof id); imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); break; case IMSG_SCHEDULER_REMOVE: if (euid) goto badcred; id = *(uint64_t *)imsg.data; imsg_compose_event(env->sc_ievs[PROC_SCHEDULER], IMSG_SCHEDULER_REMOVE, 0, 0, -1, &id, sizeof id); imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0); break; case IMSG_LKA_UPDATE_MAP: if (euid) goto badcred; /* map name too long */ len = strlen(imsg.data); if (len >= MAX_LINE_SIZE) goto invalid; imsg_compose_event(env->sc_ievs[PROC_LKA], IMSG_LKA_UPDATE_MAP, 0, 0, -1, imsg.data, len + 1); break; default: log_debug("control_dispatch_ext: " "error handling %s imsg", imsg_to_str(imsg.hdr.type)); break; } imsg_free(&imsg); continue; badcred: invalid: imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); } imsg_event_add(&c->iev); }
int main(int argc, char *argv[]) { struct sockaddr_un sun; struct parse_result *res; struct imsg imsg; int ctl_sock; int done = 0; int n; int ch; const char *sock = SNMPD_SOCKET; if ((env = calloc(1, sizeof(struct snmpd))) == NULL) err(1, "calloc"); gettimeofday(&env->sc_starttime, NULL); while ((ch = getopt(argc, argv, "ns:")) != -1) { switch (ch) { case 'n': env->sc_flags |= SNMPD_F_NONAMES; break; case 's': sock = optarg; break; default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; smi_init(); /* parse options */ if ((res = parse(argc, argv)) == NULL) exit(1); switch (res->action) { case NONE: usage(); break; case SHOW_MIB: show_mib(); break; case WALK: case GET: case BULKWALK: snmpclient(res); break; default: goto connect; } free(env); return (0); connect: /* connect to snmpd control socket */ if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err(1, "socket"); bzero(&sun, sizeof(sun)); sun.sun_family = AF_UNIX; strlcpy(sun.sun_path, sock, sizeof(sun.sun_path)); reconnect: if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) { /* Keep retrying if running in monitor mode */ if (res->action == MONITOR && (errno == ENOENT || errno == ECONNREFUSED)) { usleep(100); goto reconnect; } err(1, "connect: %s", sock); } imsg_init(&ibuf, ctl_sock); done = 0; /* process user request */ switch (res->action) { case MONITOR: imsg_compose(&ibuf, IMSG_CTL_NOTIFY, 0, 0, -1, NULL, 0); break; case NONE: case SHOW_MIB: case WALK: case GET: case BULKWALK: break; case TRAP: /* explicitly downgrade the socket */ imsg_compose(&ibuf, IMSG_SNMP_AGENTX, 0, 0, -1, NULL, 0); break; } while (ibuf.w.queued) if (msgbuf_write(&ibuf.w) <= 0 && errno != EAGAIN) err(1, "write error"); while (!done) { if ((n = imsg_read(&ibuf)) == -1) 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; switch (res->action) { case MONITOR: done = monitor(&imsg); break; case TRAP: if (imsg.hdr.type == IMSG_CTL_OK) { snmpctl_trap(ctl_sock, res); done = 1; } else errx(1, "snmpd refused connection"); break; case NONE: case SHOW_MIB: case WALK: case GET: case BULKWALK: break; } imsg_free(&imsg); } } close(ctl_sock); return (0); }
int main(int argc, char *argv[]) { struct ntpd_conf lconf; struct pollfd pfd[POLL_MAX]; pid_t chld_pid = 0, pid; const char *conffile; int fd_ctl, ch, nfds; int pipe_chld[2]; struct passwd *pw; extern char *__progname; if (strcmp(__progname, "ntpctl") == 0) { ctl_main(argc, argv); /* NOTREACHED */ } conffile = CONFFILE; bzero(&lconf, sizeof(lconf)); log_init(1); /* log to stderr until daemonized */ while ((ch = getopt(argc, argv, "df:nsSv")) != -1) { switch (ch) { case 'd': lconf.debug = 1; log_verbose(1); break; case 'f': conffile = optarg; break; case 'n': lconf.noaction = 1; break; case 's': lconf.settime = 1; break; case 'S': lconf.settime = 0; break; case 'v': log_verbose(1); break; default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc > 0) usage(); if (parse_config(conffile, &lconf)) exit(1); if (lconf.noaction) { fprintf(stderr, "configuration OK\n"); exit(0); } if (geteuid()) errx(1, "need root privileges"); if ((pw = getpwnam(NTPD_USER)) == NULL) errx(1, "unknown user %s", NTPD_USER); if (setpriority(PRIO_PROCESS, 0, -20) == -1) warn("can't set priority"); reset_adjtime(); if (!lconf.settime) { log_init(lconf.debug); if (!lconf.debug) if (daemon(1, 0)) fatal("daemon"); } else timeout = SETTIME_TIMEOUT * 1000; if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_chld) == -1) fatal("socketpair"); if ((fd_ctl = control_init(CTLSOCKET)) == -1) fatalx("control socket init failed"); if (control_listen(fd_ctl) == -1) fatalx("control socket listen failed"); signal(SIGCHLD, sighdlr); /* fork child process */ chld_pid = ntp_main(pipe_chld, fd_ctl, &lconf, pw); setproctitle("[priv]"); readfreq(); signal(SIGTERM, sighdlr); signal(SIGINT, sighdlr); signal(SIGHUP, sighdlr); close(pipe_chld[1]); if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) fatal(NULL); imsg_init(ibuf, pipe_chld[0]); while (quit == 0) { pfd[PFD_PIPE].fd = ibuf->fd; pfd[PFD_PIPE].events = POLLIN; if (ibuf->w.queued) pfd[PFD_PIPE].events |= POLLOUT; if ((nfds = poll(pfd, 1, timeout)) == -1) if (errno != EINTR) { log_warn("poll error"); quit = 1; } if (nfds == 0 && lconf.settime) { lconf.settime = 0; timeout = INFTIM; log_init(lconf.debug); log_warnx("no reply received in time, skipping initial " "time setting"); if (!lconf.debug) if (daemon(1, 0)) fatal("daemon"); } if (nfds > 0 && (pfd[PFD_PIPE].revents & POLLOUT)) if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) { log_warn("pipe write error (to child)"); quit = 1; } if (nfds > 0 && pfd[PFD_PIPE].revents & POLLIN) { nfds--; if (dispatch_imsg(&lconf) == -1) quit = 1; } if (sigchld) { if (check_child(chld_pid, "child")) { quit = 1; chld_pid = 0; } sigchld = 0; } } signal(SIGCHLD, SIG_DFL); if (chld_pid) kill(chld_pid, SIGTERM); do { if ((pid = wait(NULL)) == -1 && errno != EINTR && errno != ECHILD) fatal("wait"); } while (pid != -1 || (pid == -1 && errno == EINTR)); msgbuf_clear(&ibuf->w); free(ibuf); log_info("Terminating"); return (0); }