Index: head/usr.sbin/ypldap/ldapclient.c =================================================================== --- head/usr.sbin/ypldap/ldapclient.c (revision 309392) +++ head/usr.sbin/ypldap/ldapclient.c (revision 309393) @@ -1,692 +1,692 @@ /* $OpenBSD: ldapclient.c,v 1.31 2014/11/16 23:24:44 tedu Exp $ */ /* $FreeBSD$ */ /* * Copyright (c) 2008 Alexander Schrijver * Copyright (c) 2008 Pierre-Yves Ritschard * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "aldap.h" #include "ypldap.h" void client_sig_handler(int, short, void *); void client_dispatch_dns(int, short, void *); void client_dispatch_parent(int, short, void *); void client_shutdown(void); void client_connect(int, short, void *); void client_configure(struct env *); void client_periodic_update(int, short, void *); int client_build_req(struct idm *, struct idm_req *, struct aldap_message *, int, int); int client_search_idm(struct env *, struct idm *, struct aldap *, char **, char *, int, int, enum imsg_type); int client_try_idm(struct env *, struct idm *); int client_addr_init(struct idm *); int client_addr_free(struct idm *); struct aldap *client_aldap_open(struct ypldap_addr_list *); /* * dummy wrapper to provide aldap_init with its fd's. */ struct aldap * client_aldap_open(struct ypldap_addr_list *addr) { int fd = -1; struct ypldap_addr *p; TAILQ_FOREACH(p, addr, next) { char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; struct sockaddr *sa = (struct sockaddr *)&p->ss; if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) errx(1, "could not get numeric hostname"); if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) return NULL; if (connect(fd, sa, sa->sa_len) == 0) break; warn("connect to %s port %s (%s) failed", hbuf, sbuf, "tcp"); close(fd); } if (fd == -1) return NULL; return aldap_init(fd); } int client_addr_init(struct idm *idm) { struct sockaddr_in *sa_in; struct sockaddr_in6 *sa_in6; struct ypldap_addr *h; TAILQ_FOREACH(h, &idm->idm_addr, next) { switch (h->ss.ss_family) { case AF_INET: sa_in = (struct sockaddr_in *)&h->ss; if (ntohs(sa_in->sin_port) == 0) sa_in->sin_port = htons(LDAP_PORT); idm->idm_state = STATE_DNS_DONE; break; case AF_INET6: sa_in6 = (struct sockaddr_in6 *)&h->ss; if (ntohs(sa_in6->sin6_port) == 0) sa_in6->sin6_port = htons(LDAP_PORT); idm->idm_state = STATE_DNS_DONE; break; default: fatalx("king bula sez: wrong AF in client_addr_init"); /* not reached */ } } return (0); } int client_addr_free(struct idm *idm) { struct ypldap_addr *h; while (!TAILQ_EMPTY(&idm->idm_addr)) { h = TAILQ_FIRST(&idm->idm_addr); TAILQ_REMOVE(&idm->idm_addr, h, next); free(h); } return (0); } void client_sig_handler(int sig, short event, void *p) { switch (sig) { case SIGINT: case SIGTERM: client_shutdown(); break; default: fatalx("unexpected signal"); } } void client_dispatch_dns(int fd, short events, void *p) { struct imsg imsg; u_int16_t dlen; u_char *data; struct ypldap_addr *h; int n, wait_cnt = 0; struct idm *idm; int shut = 0; struct env *env = p; struct imsgev *iev = env->sc_iev_dns; struct imsgbuf *ibuf = &iev->ibuf; 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_dns: imsg_get error"); if (n == 0) break; switch (imsg.hdr.type) { case IMSG_HOST_DNS: TAILQ_FOREACH(idm, &env->sc_idms, idm_entry) if (idm->idm_id == imsg.hdr.peerid) break; if (idm == NULL) { log_warnx("IMSG_HOST_DNS with invalid peerID"); break; } if (!TAILQ_EMPTY(&idm->idm_addr)) { log_warnx("IMSG_HOST_DNS but addrs set!"); break; } dlen = imsg.hdr.len - IMSG_HEADER_SIZE; if (dlen == 0) { /* no data -> temp error */ idm->idm_state = STATE_DNS_TEMPFAIL; break; } data = (u_char *)imsg.data; while (dlen >= sizeof(struct sockaddr_storage)) { if ((h = calloc(1, sizeof(*h))) == NULL) fatal(NULL); memcpy(&h->ss, data, sizeof(h->ss)); TAILQ_INSERT_HEAD(&idm->idm_addr, h, next); data += sizeof(h->ss); dlen -= sizeof(h->ss); } if (dlen != 0) fatalx("IMSG_HOST_DNS: dlen != 0"); client_addr_init(idm); break; default: break; } imsg_free(&imsg); } TAILQ_FOREACH(idm, &env->sc_idms, idm_entry) { if (client_try_idm(env, idm) == -1) idm->idm_state = STATE_LDAP_FAIL; if (idm->idm_state < STATE_LDAP_DONE) wait_cnt++; } if (wait_cnt == 0) imsg_compose_event(env->sc_iev, IMSG_END_UPDATE, 0, 0, -1, NULL, 0); done: if (!shut) imsg_event_add(iev); else { /* this pipe is dead, so remove the event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void client_dispatch_parent(int fd, short events, void *p) { int n; int shut = 0; struct imsg imsg; struct env *env = p; struct imsgev *iev = env->sc_iev; struct imsgbuf *ibuf = &iev->ibuf; 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_parent: imsg_get error"); if (n == 0) break; switch (imsg.hdr.type) { case IMSG_CONF_START: { struct env params; if (env->sc_flags & F_CONFIGURING) { log_warnx("configuration already in progress"); break; } memcpy(¶ms, imsg.data, sizeof(params)); log_debug("configuration starting"); env->sc_flags |= F_CONFIGURING; purge_config(env); memcpy(&env->sc_conf_tv, ¶ms.sc_conf_tv, sizeof(env->sc_conf_tv)); env->sc_flags |= params.sc_flags; break; } case IMSG_CONF_IDM: { struct idm *idm; if (!(env->sc_flags & F_CONFIGURING)) break; if ((idm = calloc(1, sizeof(*idm))) == NULL) fatal(NULL); memcpy(idm, imsg.data, sizeof(*idm)); idm->idm_env = env; TAILQ_INSERT_TAIL(&env->sc_idms, idm, idm_entry); break; } case IMSG_CONF_END: env->sc_flags &= ~F_CONFIGURING; log_debug("applying configuration"); client_configure(env); break; default: log_debug("client_dispatch_parent: unexpect imsg %d", imsg.hdr.type); 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); } } void client_shutdown(void) { log_info("ldap client exiting"); _exit(0); } pid_t ldapclient(int pipe_main2client[2]) { pid_t pid, dns_pid; int pipe_dns[2]; struct passwd *pw; struct event ev_sigint; struct event ev_sigterm; struct env env; switch (pid = fork()) { case -1: fatal("cannot fork"); break; case 0: break; default: return (pid); } - bzero(&env, sizeof(env)); + memset(&env, 0, sizeof(env)); TAILQ_INIT(&env.sc_idms); if ((pw = getpwnam(YPLDAP_USER)) == NULL) fatal("getpwnam"); if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_dns) == -1) fatal("socketpair"); dns_pid = ypldap_dns(pipe_dns, pw); close(pipe_dns[1]); #ifndef DEBUG if (chroot(pw->pw_dir) == -1) fatal("chroot"); if (chdir("/") == -1) fatal("chdir"); #else #warning disabling chrooting in DEBUG mode #endif setproctitle("ldap client"); ypldap_process = PROC_CLIENT; #ifndef DEBUG if (setgroups(1, &pw->pw_gid) || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) fatal("cannot drop privileges"); #else #warning disabling privilege revocation in DEBUG mode #endif event_init(); signal(SIGPIPE, SIG_IGN); signal_set(&ev_sigint, SIGINT, client_sig_handler, NULL); signal_set(&ev_sigterm, SIGTERM, client_sig_handler, NULL); signal_add(&ev_sigint, NULL); signal_add(&ev_sigterm, NULL); close(pipe_main2client[0]); if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL) fatal(NULL); if ((env.sc_iev_dns = calloc(1, sizeof(*env.sc_iev_dns))) == NULL) fatal(NULL); env.sc_iev->events = EV_READ; env.sc_iev->data = &env; imsg_init(&env.sc_iev->ibuf, pipe_main2client[1]); env.sc_iev->handler = client_dispatch_parent; event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events, env.sc_iev->handler, &env); event_add(&env.sc_iev->ev, NULL); env.sc_iev_dns->events = EV_READ; env.sc_iev_dns->data = &env; imsg_init(&env.sc_iev_dns->ibuf, pipe_dns[0]); env.sc_iev_dns->handler = client_dispatch_dns; event_set(&env.sc_iev_dns->ev, env.sc_iev_dns->ibuf.fd, env.sc_iev_dns->events, env.sc_iev_dns->handler, &env); event_add(&env.sc_iev_dns->ev, NULL); event_dispatch(); client_shutdown(); return (0); } int client_build_req(struct idm *idm, struct idm_req *ir, struct aldap_message *m, int min_attr, int max_attr) { char **ldap_attrs; int i, k; - bzero(ir, sizeof(*ir)); + memset(ir, 0, sizeof(*ir)); for (i = min_attr; i < max_attr; i++) { if (idm->idm_flags & F_FIXED_ATTR(i)) { if (strlcat(ir->ir_line, idm->idm_attrs[i], sizeof(ir->ir_line)) >= sizeof(ir->ir_line)) /* * entry yields a line > 1024, trash it. */ return (-1); if (i == ATTR_UID) { ir->ir_key.ik_uid = strtonum( idm->idm_attrs[i], 0, UID_MAX, NULL); } else if (i == ATTR_GR_GID) { ir->ir_key.ik_gid = strtonum( idm->idm_attrs[i], 0, GID_MAX, NULL); } } else if (idm->idm_list & F_LIST(i)) { aldap_match_attr(m, idm->idm_attrs[i], &ldap_attrs); for (k = 0; k >= 0 && ldap_attrs && ldap_attrs[k] != NULL; k++) { /* XXX: Fail when attributes have illegal characters e.g. ',' */ if (strlcat(ir->ir_line, ldap_attrs[k], sizeof(ir->ir_line)) >= sizeof(ir->ir_line)) continue; if (ldap_attrs[k+1] != NULL) if (strlcat(ir->ir_line, ",", sizeof(ir->ir_line)) >= sizeof(ir->ir_line)) { aldap_free_attr(ldap_attrs); return (-1); } } aldap_free_attr(ldap_attrs); } else { if (aldap_match_attr(m, idm->idm_attrs[i], &ldap_attrs) == -1) return (-1); if (strlcat(ir->ir_line, ldap_attrs[0], sizeof(ir->ir_line)) >= sizeof(ir->ir_line)) { aldap_free_attr(ldap_attrs); return (-1); } if (i == ATTR_UID) { ir->ir_key.ik_uid = strtonum( ldap_attrs[0], 0, UID_MAX, NULL); } else if (i == ATTR_GR_GID) { ir->ir_key.ik_uid = strtonum( ldap_attrs[0], 0, GID_MAX, NULL); } aldap_free_attr(ldap_attrs); } if (i + 1 != max_attr) if (strlcat(ir->ir_line, ":", sizeof(ir->ir_line)) >= sizeof(ir->ir_line)) return (-1); } return (0); } int client_search_idm(struct env *env, struct idm *idm, struct aldap *al, char **attrs, char *filter, int min_attr, int max_attr, enum imsg_type type) { struct idm_req ir; struct aldap_message *m; struct aldap_page_control *pg = NULL; const char *errstr; char *dn; dn = idm->idm_basedn; if (type == IMSG_GRP_ENTRY && idm->idm_groupdn[0] != '\0') dn = idm->idm_groupdn; do { if (aldap_search(al, dn, LDAP_SCOPE_SUBTREE, filter, attrs, 0, 0, 0, pg) == -1) { aldap_get_errno(al, &errstr); log_debug("%s", errstr); return (-1); } if (pg != NULL) { aldap_freepage(pg); pg = NULL; } while ((m = aldap_parse(al)) != NULL) { if (al->msgid != m->msgid) { goto fail; } if (m->message_type == LDAP_RES_SEARCH_RESULT) { if (m->page != NULL && m->page->cookie_len != 0) pg = m->page; else pg = NULL; aldap_freemsg(m); break; } if (m->message_type != LDAP_RES_SEARCH_ENTRY) { goto fail; } if (client_build_req(idm, &ir, m, min_attr, max_attr) == 0) imsg_compose_event(env->sc_iev, type, 0, 0, -1, &ir, sizeof(ir)); aldap_freemsg(m); } } while (pg != NULL); return (0); fail: aldap_freemsg(m); if (pg != NULL) { aldap_freepage(pg); } return (-1); } int client_try_idm(struct env *env, struct idm *idm) { const char *where; char *attrs[ATTR_MAX+1]; int i, j; struct aldap_message *m; struct aldap *al; where = "connect"; if ((al = client_aldap_open(&idm->idm_addr)) == NULL) return (-1); if (idm->idm_flags & F_NEEDAUTH) { where = "binding"; if (aldap_bind(al, idm->idm_binddn, idm->idm_bindcred) == -1) goto bad; where = "parsing"; if ((m = aldap_parse(al)) == NULL) goto bad; where = "verifying msgid"; if (al->msgid != m->msgid) { aldap_freemsg(m); goto bad; } aldap_freemsg(m); } - bzero(attrs, sizeof(attrs)); + memset(attrs, 0, sizeof(attrs)); for (i = 0, j = 0; i < ATTR_MAX; i++) { if (idm->idm_flags & F_FIXED_ATTR(i)) continue; attrs[j++] = idm->idm_attrs[i]; } attrs[j] = NULL; /* * build password line. */ where = "search"; log_debug("searching password entries"); if (client_search_idm(env, idm, al, attrs, idm->idm_filters[FILTER_USER], 0, ATTR_MAX, IMSG_PW_ENTRY) == -1) goto bad; - bzero(attrs, sizeof(attrs)); + memset(attrs, 0, sizeof(attrs)); for (i = ATTR_GR_MIN, j = 0; i < ATTR_GR_MAX; i++) { if (idm->idm_flags & F_FIXED_ATTR(i)) continue; attrs[j++] = idm->idm_attrs[i]; } attrs[j] = NULL; /* * build group line. */ where = "search"; log_debug("searching group entries"); if (client_search_idm(env, idm, al, attrs, idm->idm_filters[FILTER_GROUP], ATTR_GR_MIN, ATTR_GR_MAX, IMSG_GRP_ENTRY) == -1) goto bad; aldap_close(al); idm->idm_state = STATE_LDAP_DONE; return (0); bad: aldap_close(al); log_debug("directory %s errored out in %s", idm->idm_name, where); return (-1); } void client_periodic_update(int fd, short event, void *p) { struct env *env = p; struct idm *idm; int fail_cnt = 0; /* If LDAP isn't finished, notify the master process to trash the * update. */ TAILQ_FOREACH(idm, &env->sc_idms, idm_entry) { if (idm->idm_state < STATE_LDAP_DONE) fail_cnt++; idm->idm_state = STATE_NONE; client_addr_free(idm); } if (fail_cnt > 0) { log_debug("trash the update"); imsg_compose_event(env->sc_iev, IMSG_TRASH_UPDATE, 0, 0, -1, NULL, 0); } client_configure(env); } void client_configure(struct env *env) { struct timeval tv; struct idm *idm; u_int16_t dlen; log_debug("connecting to directories"); imsg_compose_event(env->sc_iev, IMSG_START_UPDATE, 0, 0, -1, NULL, 0); /* Start the DNS lookups */ TAILQ_FOREACH(idm, &env->sc_idms, idm_entry) { dlen = strlen(idm->idm_name) + 1; imsg_compose_event(env->sc_iev_dns, IMSG_HOST_DNS, idm->idm_id, 0, -1, idm->idm_name, dlen); } tv.tv_sec = env->sc_conf_tv.tv_sec; tv.tv_usec = env->sc_conf_tv.tv_usec; evtimer_set(&env->sc_conf_ev, client_periodic_update, env); evtimer_add(&env->sc_conf_ev, &tv); } Index: head/usr.sbin/ypldap/yp.c =================================================================== --- head/usr.sbin/ypldap/yp.c (revision 309392) +++ head/usr.sbin/ypldap/yp.c (revision 309393) @@ -1,662 +1,662 @@ /* $OpenBSD: yp.c,v 1.14 2015/02/11 01:26:00 pelikan Exp $ */ /* $FreeBSD$ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ypldap.h" void yp_dispatch(struct svc_req *, SVCXPRT *); void yp_disable_events(void); void yp_fd_event(int, short, void *); int yp_check(struct svc_req *); int yp_valid_domain(char *, struct ypresp_val *); void yp_make_val(struct ypresp_val *, char *, int); void yp_make_keyval(struct ypresp_key_val *, char *, char *); static struct env *env; struct yp_event { TAILQ_ENTRY(yp_event) ye_entry; struct event ye_event; }; struct yp_data { SVCXPRT *yp_trans_udp; SVCXPRT *yp_trans_tcp; TAILQ_HEAD(, yp_event) yd_events; }; void yp_disable_events(void) { struct yp_event *ye; while ((ye = TAILQ_FIRST(&env->sc_yp->yd_events)) != NULL) { TAILQ_REMOVE(&env->sc_yp->yd_events, ye, ye_entry); event_del(&ye->ye_event); free(ye); } } void yp_enable_events(void) { int i; struct yp_event *ye; for (i = 0; i < getdtablesize(); i++) { if ((ye = calloc(1, sizeof(*ye))) == NULL) fatal(NULL); event_set(&ye->ye_event, i, EV_READ, yp_fd_event, NULL); event_add(&ye->ye_event, NULL); TAILQ_INSERT_TAIL(&env->sc_yp->yd_events, ye, ye_entry); } } void yp_fd_event(int fd, short event, void *p) { svc_getreq_common(fd); yp_disable_events(); yp_enable_events(); } void yp_init(struct env *x_env) { struct yp_data *yp; if ((yp = calloc(1, sizeof(*yp))) == NULL) fatal(NULL); TAILQ_INIT(&yp->yd_events); env = x_env; env->sc_yp = yp; (void)pmap_unset(YPPROG, YPVERS); if ((yp->yp_trans_udp = svcudp_create(RPC_ANYSOCK)) == NULL) fatal("cannot create udp service"); if ((yp->yp_trans_tcp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) fatal("cannot create tcp service"); if (!svc_register(yp->yp_trans_udp, YPPROG, YPVERS, yp_dispatch, IPPROTO_UDP)) { fatal("unable to register (YPPROG, YPVERS, udp)"); } if (!svc_register(yp->yp_trans_tcp, YPPROG, YPVERS, yp_dispatch, IPPROTO_TCP)) { fatal("unable to register (YPPROG, YPVERS, tcp)"); } } /* * lots of inspiration from ypserv by Mats O Jansson */ void yp_dispatch(struct svc_req *req, SVCXPRT *trans) { xdrproc_t xdr_argument; xdrproc_t xdr_result; char *result; char *(*cb)(char *, struct svc_req *); union { domainname ypproc_domain_2_arg; domainname ypproc_domain_nonack_2_arg; ypreq_key ypproc_match_2_arg; ypreq_nokey ypproc_first_2_arg; ypreq_key ypproc_next_2_arg; ypreq_xfr ypproc_xfr_2_arg; ypreq_nokey ypproc_all_2_arg; ypreq_nokey ypproc_master_2_arg; ypreq_nokey ypproc_order_2_arg; domainname ypproc_maplist_2_arg; } argument; xdr_argument = (xdrproc_t) xdr_void; xdr_result = (xdrproc_t) xdr_void; cb = NULL; switch (req->rq_proc) { case YPPROC_NULL: xdr_argument = (xdrproc_t) xdr_void; xdr_result = (xdrproc_t) xdr_void; if (yp_check(req) == -1) return; result = NULL; if (!svc_sendreply(trans, (xdrproc_t) xdr_void, (void *)&result)) svcerr_systemerr(trans); return; case YPPROC_DOMAIN: xdr_argument = (xdrproc_t) xdr_domainname; xdr_result = (xdrproc_t) xdr_bool; if (yp_check(req) == -1) return; cb = (void *)ypproc_domain_2_svc; break; case YPPROC_DOMAIN_NONACK: xdr_argument = (xdrproc_t) xdr_domainname; xdr_result = (xdrproc_t) xdr_bool; if (yp_check(req) == -1) return; cb = (void *)ypproc_domain_nonack_2_svc; break; case YPPROC_MATCH: xdr_argument = (xdrproc_t) xdr_ypreq_key; xdr_result = (xdrproc_t) xdr_ypresp_val; if (yp_check(req) == -1) return; cb = (void *)ypproc_match_2_svc; break; case YPPROC_FIRST: xdr_argument = (xdrproc_t) xdr_ypreq_nokey; xdr_result = (xdrproc_t) xdr_ypresp_key_val; if (yp_check(req) == -1) return; cb = (void *)ypproc_first_2_svc; break; case YPPROC_NEXT: xdr_argument = (xdrproc_t) xdr_ypreq_key; xdr_result = (xdrproc_t) xdr_ypresp_key_val; if (yp_check(req) == -1) return; cb = (void *)ypproc_next_2_svc; break; case YPPROC_XFR: if (yp_check(req) == -1) return; svcerr_noproc(trans); return; case YPPROC_CLEAR: log_debug("ypproc_clear"); if (yp_check(req) == -1) return; svcerr_noproc(trans); return; case YPPROC_ALL: log_debug("ypproc_all"); xdr_argument = (xdrproc_t) xdr_ypreq_nokey; xdr_result = (xdrproc_t) xdr_ypresp_all; if (yp_check(req) == -1) return; cb = (void *)ypproc_all_2_svc; break; case YPPROC_MASTER: log_debug("ypproc_master"); xdr_argument = (xdrproc_t) xdr_ypreq_nokey; xdr_result = (xdrproc_t) xdr_ypresp_master; if (yp_check(req) == -1) return; cb = (void *)ypproc_master_2_svc; break; case YPPROC_ORDER: log_debug("ypproc_order"); if (yp_check(req) == -1) return; svcerr_noproc(trans); return; case YPPROC_MAPLIST: log_debug("ypproc_maplist"); xdr_argument = (xdrproc_t) xdr_domainname; xdr_result = (xdrproc_t) xdr_ypresp_maplist; if (yp_check(req) == -1) return; cb = (void *)ypproc_maplist_2_svc; break; default: svcerr_noproc(trans); return; } (void)memset(&argument, 0, sizeof(argument)); if (!svc_getargs(trans, xdr_argument, (caddr_t)&argument)) { svcerr_decode(trans); return; } result = (*cb)((char *)&argument, req); if (result != NULL && !svc_sendreply(trans, xdr_result, result)) svcerr_systemerr(trans); if (!svc_freeargs(trans, xdr_argument, (caddr_t)&argument)) { /* * ypserv does it too. */ fatal("unable to free arguments"); } } int yp_check(struct svc_req *req) { struct sockaddr_in *caller; caller = svc_getcaller(req->rq_xprt); /* * We might want to know who we allow here. */ return (0); } int yp_valid_domain(char *domain, struct ypresp_val *res) { if (domain == NULL) { log_debug("NULL domain !"); return (-1); } if (strcmp(domain, env->sc_domainname) != 0) { res->stat = YP_NODOM; return (-1); } return (0); } bool_t * ypproc_domain_2_svc(domainname *arg, struct svc_req *req) { static bool_t res; res = (bool_t)1; if (strcmp(*arg, env->sc_domainname) != 0) res = (bool_t)0; return (&res); } bool_t * ypproc_domain_nonack_2_svc(domainname *arg, struct svc_req *req) { static bool_t res; if (strcmp(*arg, env->sc_domainname) != 0) return NULL; res = (bool_t)1; return (&res); } ypresp_val * ypproc_match_2_svc(ypreq_key *arg, struct svc_req *req) { struct userent ukey; struct userent *ue; struct groupent gkey; struct groupent *ge; static struct ypresp_val res; const char *estr; char *bp, *cp; char key[YPMAXRECORD+1]; log_debug("matching '%.*s' in map %s", arg->key.keydat_len, arg->key.keydat_val, arg->map); if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) return (&res); if (env->sc_user_names == NULL) { /* * tree not ready. */ return (NULL); } if (arg->key.keydat_len > YPMAXRECORD) { log_debug("argument too long"); return (NULL); } - bzero(key, sizeof(key)); + memset(key, 0, sizeof(key)); (void)strncpy(key, arg->key.keydat_val, arg->key.keydat_len); if (strcmp(arg->map, "passwd.byname") == 0 || strcmp(arg->map, "master.passwd.byname") == 0) { ukey.ue_line = key; if ((ue = RB_FIND(user_name_tree, env->sc_user_names, &ukey)) == NULL) { res.stat = YP_NOKEY; return (&res); } yp_make_val(&res, ue->ue_line, 1); return (&res); } else if (strcmp(arg->map, "passwd.byuid") == 0 || strcmp(arg->map, "master.passwd.byuid") == 0) { ukey.ue_uid = strtonum(key, 0, UID_MAX, &estr); if (estr) { res.stat = YP_BADARGS; return (&res); } if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids, &ukey)) == NULL) { res.stat = YP_NOKEY; return (&res); } yp_make_val(&res, ue->ue_line, 1); return (&res); } else if (strcmp(arg->map, "group.bygid") == 0) { gkey.ge_gid = strtonum(key, 0, GID_MAX, &estr); if (estr) { res.stat = YP_BADARGS; return (&res); } if ((ge = RB_FIND(group_gid_tree, &env->sc_group_gids, &gkey)) == NULL) { res.stat = YP_NOKEY; return (&res); } yp_make_val(&res, ge->ge_line, 1); return (&res); } else if (strcmp(arg->map, "group.byname") == 0) { gkey.ge_line = key; if ((ge = RB_FIND(group_name_tree, env->sc_group_names, &gkey)) == NULL) { res.stat = YP_NOKEY; return (&res); } yp_make_val(&res, ge->ge_line, 1); return (&res); } else if (strcmp(arg->map, "netid.byname") == 0) { bp = cp = key; if (strncmp(bp, "unix.", strlen("unix.")) != 0) { res.stat = YP_BADARGS; return (&res); } bp += strlen("unix."); if (*bp == '\0') { res.stat = YP_BADARGS; return (&res); } if (!(cp = strsep(&bp, "@"))) { res.stat = YP_BADARGS; return (&res); } if (strcmp(bp, arg->domain) != 0) { res.stat = YP_BADARGS; return (&res); } ukey.ue_uid = strtonum(cp, 0, UID_MAX, &estr); if (estr) { res.stat = YP_BADARGS; return (&res); } if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids, &ukey)) == NULL) { res.stat = YP_NOKEY; return (&res); } yp_make_val(&res, ue->ue_netid_line, 0); return (&res); } else { log_debug("unknown map %s", arg->map); res.stat = YP_NOMAP; return (&res); } } ypresp_key_val * ypproc_first_2_svc(ypreq_nokey *arg, struct svc_req *req) { static struct ypresp_key_val res; if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) return (&res); if (strcmp(arg->map, "passwd.byname") == 0 || strcmp(arg->map, "master.passwd.byname") == 0) { if (env->sc_user_lines == NULL) return (NULL); yp_make_keyval(&res, env->sc_user_lines, env->sc_user_lines); } else if (strcmp(arg->map, "group.byname") == 0) { if (env->sc_group_lines == NULL) return (NULL); yp_make_keyval(&res, env->sc_group_lines, env->sc_group_lines); } else { log_debug("unknown map %s", arg->map); res.stat = YP_NOMAP; } return (&res); } ypresp_key_val * ypproc_next_2_svc(ypreq_key *arg, struct svc_req *req) { struct userent ukey; struct userent *ue; struct groupent gkey; struct groupent *ge; char *line; static struct ypresp_key_val res; char key[YPMAXRECORD+1]; if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) return (&res); if (strcmp(arg->map, "passwd.byname") == 0 || strcmp(arg->map, "master.passwd.byname") == 0) { - bzero(key, sizeof(key)); + memset(key, 0, sizeof(key)); (void)strncpy(key, arg->key.keydat_val, arg->key.keydat_len); ukey.ue_line = key; if ((ue = RB_FIND(user_name_tree, env->sc_user_names, &ukey)) == NULL) { /* * canacar's trick: * the user might have been deleted in between calls * to next since the tree may be modified by a reload. * next should still return the next user in * lexicographical order, hence insert the search key * and look up the next field, then remove it again. */ RB_INSERT(user_name_tree, env->sc_user_names, &ukey); if ((ue = RB_NEXT(user_name_tree, &env->sc_user_names, &ukey)) == NULL) { RB_REMOVE(user_name_tree, env->sc_user_names, &ukey); res.stat = YP_NOKEY; return (&res); } RB_REMOVE(user_name_tree, env->sc_user_names, &ukey); } line = ue->ue_line + (strlen(ue->ue_line) + 1); line = line + (strlen(line) + 1); yp_make_keyval(&res, line, line); return (&res); } else if (strcmp(arg->map, "group.byname") == 0) { - bzero(key, sizeof(key)); + memset(key, 0, sizeof(key)); (void)strncpy(key, arg->key.keydat_val, arg->key.keydat_len); gkey.ge_line = key; if ((ge = RB_FIND(group_name_tree, env->sc_group_names, &gkey)) == NULL) { /* * canacar's trick reloaded. */ RB_INSERT(group_name_tree, env->sc_group_names, &gkey); if ((ge = RB_NEXT(group_name_tree, &env->sc_group_names, &gkey)) == NULL) { RB_REMOVE(group_name_tree, env->sc_group_names, &gkey); res.stat = YP_NOKEY; return (&res); } RB_REMOVE(group_name_tree, env->sc_group_names, &gkey); } line = ge->ge_line + (strlen(ge->ge_line) + 1); line = line + (strlen(line) + 1); yp_make_keyval(&res, line, line); return (&res); } else { log_debug("unknown map %s", arg->map); res.stat = YP_NOMAP; return (&res); } } ypresp_all * ypproc_all_2_svc(ypreq_nokey *arg, struct svc_req *req) { static struct ypresp_all res; if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) return (&res); svcerr_auth(req->rq_xprt, AUTH_FAILED); return (NULL); } ypresp_master * ypproc_master_2_svc(ypreq_nokey *arg, struct svc_req *req) { static struct ypresp_master res; static char master[YPMAXPEER + 1]; - bzero(&res, sizeof(res)); + memset(&res, 0, sizeof(res)); if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) return (&res); if (gethostname(master, sizeof(master)) == 0) { res.peer = (peername)master; res.stat = YP_TRUE; } else res.stat = YP_NOKEY; return (&res); } ypresp_maplist * ypproc_maplist_2_svc(domainname *arg, struct svc_req *req) { size_t i; static struct { char *name; int cond; } mapnames[] = { { "passwd.byname", YPMAP_PASSWD_BYNAME }, { "passwd.byuid", YPMAP_PASSWD_BYUID }, { "master.passwd.byname", YPMAP_MASTER_PASSWD_BYNAME }, { "master.passwd.byuid", YPMAP_MASTER_PASSWD_BYUID }, { "group.byname", YPMAP_GROUP_BYNAME }, { "group.bygid", YPMAP_GROUP_BYGID }, { "netid.byname", YPMAP_NETID_BYNAME }, }; static ypresp_maplist res; static struct ypmaplist maps[nitems(mapnames)]; if (yp_valid_domain(*arg, (struct ypresp_val *)&res) == -1) return (&res); res.stat = YP_TRUE; res.maps = NULL; for (i = 0; i < nitems(mapnames); i++) { if (!(env->sc_flags & mapnames[i].cond)) continue; maps[i].map = mapnames[i].name; maps[i].next = res.maps; res.maps = &maps[i]; } return (&res); } void yp_make_val(struct ypresp_val *res, char *line, int replacecolon) { static char buf[LINE_WIDTH]; - bzero(buf, sizeof(buf)); + memset(buf, 0, sizeof(buf)); if (replacecolon) line[strlen(line)] = ':'; (void)strlcpy(buf, line, sizeof(buf)); if (replacecolon) line[strcspn(line, ":")] = '\0'; log_debug("sending out %s", buf); res->stat = YP_TRUE; res->val.valdat_len = strlen(buf); res->val.valdat_val = buf; } void yp_make_keyval(struct ypresp_key_val *res, char *key, char *line) { static char keybuf[YPMAXRECORD+1]; static char buf[LINE_WIDTH]; - bzero(keybuf, sizeof(keybuf)); - bzero(buf, sizeof(buf)); + memset(keybuf, 0, sizeof(keybuf)); + memset(buf, 0, sizeof(buf)); (void)strlcpy(keybuf, key, sizeof(keybuf)); res->key.keydat_len = strlen(keybuf); res->key.keydat_val = keybuf; if (*line == '\0') { res->stat = YP_NOMORE; return; } res->stat = YP_TRUE; line[strlen(line)] = ':'; (void)strlcpy(buf, line, sizeof(buf)); line[strcspn(line, ":")] = '\0'; log_debug("sending out %s => %s", keybuf, buf); res->val.valdat_len = strlen(buf); res->val.valdat_val = buf; } Index: head/usr.sbin/ypldap/ypldap.c =================================================================== --- head/usr.sbin/ypldap/ypldap.c (revision 309392) +++ head/usr.sbin/ypldap/ypldap.c (revision 309393) @@ -1,650 +1,650 @@ /* $OpenBSD: ypldap.c,v 1.16 2015/11/02 10:06:06 jmatthew Exp $ */ /* $FreeBSD */ /* * Copyright (c) 2008 Pierre-Yves Ritschard * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ypldap.h" __dead2 void usage(void); int check_child(pid_t, const char *); void main_sig_handler(int, short, void *); void main_shutdown(void); void main_dispatch_client(int, short, void *); void main_configure_client(struct env *); void main_init_timer(int, short, void *); void main_start_update(struct env *); void main_trash_update(struct env *); void main_end_update(struct env *); int main_create_user_groups(struct env *); void purge_config(struct env *); void reconfigure(struct env *); int pipe_main2client[2]; pid_t client_pid = 0; char *conffile = YPLDAP_CONF_FILE; int opts = 0; void usage(void) { extern const char *__progname; fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n", __progname); exit(1); } int check_child(pid_t pid, const char *pname) { int status; if (waitpid(pid, &status, WNOHANG) > 0) { if (WIFEXITED(status)) { log_warnx("check_child: lost child %s exited", pname); return (1); } if (WIFSIGNALED(status)) { log_warnx("check_child: lost child %s terminated; " "signal %d", pname, WTERMSIG(status)); return (1); } } return (0); } /* ARGUSED */ void main_sig_handler(int sig, short event, void *p) { int die = 0; switch (sig) { case SIGTERM: case SIGINT: die = 1; /* FALLTHROUGH */ case SIGCHLD: if (check_child(client_pid, "ldap client")) { client_pid = 0; die = 1; } if (die) main_shutdown(); break; case SIGHUP: /* reconfigure */ break; default: fatalx("unexpected signal"); } } void main_shutdown(void) { _exit(0); } void main_start_update(struct env *env) { env->update_trashed = 0; log_debug("starting directory update"); env->sc_user_line_len = 0; env->sc_group_line_len = 0; if ((env->sc_user_names_t = calloc(1, sizeof(*env->sc_user_names_t))) == NULL || (env->sc_group_names_t = calloc(1, sizeof(*env->sc_group_names_t))) == NULL) fatal(NULL); RB_INIT(env->sc_user_names_t); RB_INIT(env->sc_group_names_t); } /* * XXX: Currently this function should only be called when updating is * finished. A notification should be send to ldapclient that it should stop * sending new pwd/grp entries before it can be called from different places. */ void main_trash_update(struct env *env) { struct userent *ue; struct groupent *ge; env->update_trashed = 1; while ((ue = RB_ROOT(env->sc_user_names_t)) != NULL) { RB_REMOVE(user_name_tree, env->sc_user_names_t, ue); free(ue->ue_line); free(ue->ue_netid_line); free(ue); } free(env->sc_user_names_t); env->sc_user_names_t = NULL; while ((ge = RB_ROOT(env->sc_group_names_t)) != NULL) { RB_REMOVE(group_name_tree, env->sc_group_names_t, ge); free(ge->ge_line); free(ge); } free(env->sc_group_names_t); env->sc_group_names_t = NULL; } int main_create_user_groups(struct env *env) { struct userent *ue; struct userent ukey; struct groupent *ge; gid_t pw_gid; char *bp, *cp; char *p; const char *errstr = NULL; size_t len; RB_FOREACH(ue, user_name_tree, env->sc_user_names_t) { bp = cp = ue->ue_line; /* name */ bp += strlen(bp) + 1; /* password */ bp += strcspn(bp, ":") + 1; /* uid */ bp += strcspn(bp, ":") + 1; /* gid */ bp[strcspn(bp, ":")] = '\0'; pw_gid = (gid_t)strtonum(bp, 0, GID_MAX, &errstr); if (errstr) { log_warnx("main: failed to parse gid for uid: %d\n", ue->ue_uid); return (-1); } /* bring gid column back to its proper state */ bp[strlen(bp)] = ':'; if ((ue->ue_netid_line = calloc(1, LINE_WIDTH)) == NULL) { return (-1); } if (snprintf(ue->ue_netid_line, LINE_WIDTH-1, "%d:%d", ue->ue_uid, pw_gid) >= LINE_WIDTH) { return (-1); } ue->ue_gid = pw_gid; } RB_FOREACH(ge, group_name_tree, env->sc_group_names_t) { bp = cp = ge->ge_line; /* name */ bp += strlen(bp) + 1; /* password */ bp += strcspn(bp, ":") + 1; /* gid */ bp += strcspn(bp, ":") + 1; cp = bp; if (*bp == '\0') continue; bp = cp; for (;;) { if (!(cp = strsep(&bp, ","))) break; ukey.ue_line = cp; if ((ue = RB_FIND(user_name_tree, env->sc_user_names_t, &ukey)) == NULL) { /* User not found */ log_warnx("main: unknown user %s in group %s\n", ukey.ue_line, ge->ge_line); if (bp != NULL) *(bp-1) = ','; continue; } if (bp != NULL) *(bp-1) = ','; /* Make sure the new group doesn't equal to the main gid */ if (ge->ge_gid == ue->ue_gid) continue; len = strlen(ue->ue_netid_line); p = ue->ue_netid_line + len; if ((snprintf(p, LINE_WIDTH-len-1, ",%d", ge->ge_gid)) >= (int)(LINE_WIDTH-len)) { return (-1); } } } return (0); } void main_end_update(struct env *env) { struct userent *ue; struct groupent *ge; if (env->update_trashed) return; log_debug("updates are over, cleaning up trees now"); if (main_create_user_groups(env) == -1) { main_trash_update(env); return; } if (env->sc_user_names == NULL) { env->sc_user_names = env->sc_user_names_t; env->sc_user_lines = NULL; env->sc_user_names_t = NULL; env->sc_group_names = env->sc_group_names_t; env->sc_group_lines = NULL; env->sc_group_names_t = NULL; flatten_entries(env); goto make_uids; } /* * clean previous tree. */ while ((ue = RB_ROOT(env->sc_user_names)) != NULL) { RB_REMOVE(user_name_tree, env->sc_user_names, ue); free(ue->ue_netid_line); free(ue); } free(env->sc_user_names); free(env->sc_user_lines); env->sc_user_names = env->sc_user_names_t; env->sc_user_lines = NULL; env->sc_user_names_t = NULL; while ((ge = RB_ROOT(env->sc_group_names)) != NULL) { RB_REMOVE(group_name_tree, env->sc_group_names, ge); free(ge); } free(env->sc_group_names); free(env->sc_group_lines); env->sc_group_names = env->sc_group_names_t; env->sc_group_lines = NULL; env->sc_group_names_t = NULL; flatten_entries(env); /* * trees are flat now. build up uid, gid and netid trees. */ make_uids: RB_INIT(&env->sc_user_uids); RB_INIT(&env->sc_group_gids); RB_FOREACH(ue, user_name_tree, env->sc_user_names) RB_INSERT(user_uid_tree, &env->sc_user_uids, ue); RB_FOREACH(ge, group_name_tree, env->sc_group_names) RB_INSERT(group_gid_tree, &env->sc_group_gids, ge); } void main_dispatch_client(int fd, short events, void *p) { int n; int shut = 0; struct env *env = p; struct imsgev *iev = env->sc_iev; struct imsgbuf *ibuf = &iev->ibuf; struct idm_req ir; struct imsg imsg; 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("main_dispatch_client: imsg_get error"); if (n == 0) break; switch (imsg.hdr.type) { case IMSG_START_UPDATE: main_start_update(env); break; case IMSG_PW_ENTRY: { struct userent *ue; size_t len; if (env->update_trashed) break; (void)memcpy(&ir, imsg.data, sizeof(ir)); if ((ue = calloc(1, sizeof(*ue))) == NULL || (ue->ue_line = strdup(ir.ir_line)) == NULL) { /* * should cancel tree update instead. */ fatal("out of memory"); } ue->ue_uid = ir.ir_key.ik_uid; len = strlen(ue->ue_line) + 1; ue->ue_line[strcspn(ue->ue_line, ":")] = '\0'; if (RB_INSERT(user_name_tree, env->sc_user_names_t, ue) != NULL) { /* dup */ free(ue->ue_line); free(ue); } else env->sc_user_line_len += len; break; } case IMSG_GRP_ENTRY: { struct groupent *ge; size_t len; if (env->update_trashed) break; (void)memcpy(&ir, imsg.data, sizeof(ir)); if ((ge = calloc(1, sizeof(*ge))) == NULL || (ge->ge_line = strdup(ir.ir_line)) == NULL) { /* * should cancel tree update instead. */ fatal("out of memory"); } ge->ge_gid = ir.ir_key.ik_gid; len = strlen(ge->ge_line) + 1; ge->ge_line[strcspn(ge->ge_line, ":")] = '\0'; if (RB_INSERT(group_name_tree, env->sc_group_names_t, ge) != NULL) { /* dup */ free(ge->ge_line); free(ge); } else env->sc_group_line_len += len; break; } case IMSG_TRASH_UPDATE: main_trash_update(env); break; case IMSG_END_UPDATE: { main_end_update(env); break; } default: log_debug("main_dispatch_client: unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } done: if (!shut) imsg_event_add(iev); else { log_debug("king bula sez: ran into dead pipe"); event_del(&iev->ev); event_loopexit(NULL); } } void main_configure_client(struct env *env) { struct idm *idm; struct imsgev *iev = env->sc_iev; imsg_compose_event(iev, IMSG_CONF_START, 0, 0, -1, env, sizeof(*env)); TAILQ_FOREACH(idm, &env->sc_idms, idm_entry) { imsg_compose_event(iev, IMSG_CONF_IDM, 0, 0, -1, idm, sizeof(*idm)); } imsg_compose_event(iev, IMSG_CONF_END, 0, 0, -1, NULL, 0); } void main_init_timer(int fd, short event, void *p) { struct env *env = p; main_configure_client(env); } void purge_config(struct env *env) { struct idm *idm; while ((idm = TAILQ_FIRST(&env->sc_idms)) != NULL) { TAILQ_REMOVE(&env->sc_idms, idm, idm_entry); free(idm); } } int main(int argc, char *argv[]) { int c; int debug; struct passwd *pw; struct env env; struct event ev_sigint; struct event ev_sigterm; struct event ev_sigchld; struct event ev_sighup; struct event ev_timer; struct timeval tv; debug = 0; ypldap_process = PROC_MAIN; log_init(1); while ((c = getopt(argc, argv, "dD:nf:v")) != -1) { switch (c) { case 'd': debug = 2; break; case 'D': if (cmdline_symset(optarg) < 0) log_warnx("could not parse macro definition %s", optarg); break; case 'n': debug = 2; opts |= YPLDAP_OPT_NOACTION; break; case 'f': conffile = optarg; break; case 'v': opts |= YPLDAP_OPT_VERBOSE; break; default: usage(); } } argc -= optind; argv += optind; if (argc) usage(); RB_INIT(&env.sc_user_uids); RB_INIT(&env.sc_group_gids); if (parse_config(&env, conffile, opts)) exit(1); if (opts & YPLDAP_OPT_NOACTION) { fprintf(stderr, "configuration OK\n"); exit(0); } if (geteuid()) errx(1, "need root privileges"); log_init(debug); if (!debug) { if (daemon(1, 0) == -1) err(1, "failed to daemonize"); } log_info("startup%s", (debug > 1)?" [debug mode]":""); if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, PF_UNSPEC, pipe_main2client) == -1) fatal("socketpair"); client_pid = ldapclient(pipe_main2client); setproctitle("parent"); event_init(); signal_set(&ev_sigint, SIGINT, main_sig_handler, &env); signal_set(&ev_sigterm, SIGTERM, main_sig_handler, &env); signal_set(&ev_sighup, SIGHUP, main_sig_handler, &env); signal_set(&ev_sigchld, SIGCHLD, main_sig_handler, &env); signal_add(&ev_sigint, NULL); signal_add(&ev_sigterm, NULL); signal_add(&ev_sighup, NULL); signal_add(&ev_sigchld, NULL); close(pipe_main2client[1]); if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL) fatal(NULL); imsg_init(&env.sc_iev->ibuf, pipe_main2client[0]); env.sc_iev->handler = main_dispatch_client; env.sc_iev->events = EV_READ; env.sc_iev->data = &env; event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events, env.sc_iev->handler, &env); event_add(&env.sc_iev->ev, NULL); yp_init(&env); if ((pw = getpwnam(YPLDAP_USER)) == NULL) fatal("getpwnam"); #ifndef DEBUG if (setgroups(1, &pw->pw_gid) || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) fatal("cannot drop privileges"); #else #warning disabling privilege revocation in debug mode #endif - bzero(&tv, sizeof(tv)); + memset(&tv, 0, sizeof(tv)); evtimer_set(&ev_timer, main_init_timer, &env); evtimer_add(&ev_timer, &tv); yp_enable_events(); event_dispatch(); main_shutdown(); return (0); } void imsg_event_add(struct imsgev *iev) { if (iev->handler == NULL) { imsg_flush(&iev->ibuf); return; } iev->events = EV_READ; if (iev->ibuf.w.queued) iev->events |= EV_WRITE; event_del(&iev->ev); event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data); event_add(&iev->ev, NULL); } int imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, pid_t pid, int fd, void *data, u_int16_t datalen) { int ret; if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, datalen)) != -1) imsg_event_add(iev); return (ret); } Index: head/usr.sbin/ypldap/ypldap_dns.c =================================================================== --- head/usr.sbin/ypldap/ypldap_dns.c (revision 309392) +++ head/usr.sbin/ypldap/ypldap_dns.c (revision 309393) @@ -1,251 +1,251 @@ /* $OpenBSD: ypldap_dns.c,v 1.8 2015/01/16 06:40:22 deraadt Exp $ */ /* $FreeBSD$ */ /* * Copyright (c) 2003-2008 Henning Brauer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ypldap.h" volatile sig_atomic_t quit_dns = 0; struct imsgev *iev_dns; void dns_dispatch_imsg(int, short, void *); void dns_sig_handler(int, short, void *); void dns_shutdown(void); int host_dns(const char *, struct ypldap_addr_list *); void dns_sig_handler(int sig, short event, void *p) { switch (sig) { case SIGINT: case SIGTERM: dns_shutdown(); break; default: fatalx("unexpected signal"); } } void dns_shutdown(void) { log_info("dns engine exiting"); _exit(0); } pid_t ypldap_dns(int pipe_ntp[2], struct passwd *pw) { pid_t pid; struct event ev_sigint; struct event ev_sigterm; struct event ev_sighup; struct env env; switch (pid = fork()) { case -1: fatal("cannot fork"); break; case 0: break; default: return (pid); } setproctitle("dns engine"); close(pipe_ntp[0]); if (setgroups(1, &pw->pw_gid) || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) fatal("can't drop privileges"); endservent(); event_init(); signal_set(&ev_sigint, SIGINT, dns_sig_handler, NULL); signal_set(&ev_sigterm, SIGTERM, dns_sig_handler, NULL); signal_set(&ev_sighup, SIGHUP, dns_sig_handler, NULL); signal_add(&ev_sigint, NULL); signal_add(&ev_sigterm, NULL); signal_add(&ev_sighup, NULL); if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL) fatal(NULL); env.sc_iev->events = EV_READ; env.sc_iev->data = &env; imsg_init(&env.sc_iev->ibuf, pipe_ntp[1]); env.sc_iev->handler = dns_dispatch_imsg; event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events, env.sc_iev->handler, &env); event_add(&env.sc_iev->ev, NULL); event_dispatch(); dns_shutdown(); return (0); } 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); } } int host_dns(const char *s, struct ypldap_addr_list *hn) { struct addrinfo hints, *res0, *res; int error, cnt = 0; struct sockaddr_in *sa_in; struct sockaddr_in6 *sa_in6; struct ypldap_addr *h; - bzero(&hints, sizeof(hints)); + memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; /* DUMMY */ error = getaddrinfo(s, NULL, &hints, &res0); if (error == EAI_AGAIN || error == EAI_NONAME) return (0); if (error) { log_warnx("could not parse \"%s\": %s", s, gai_strerror(error)); return (-1); } for (res = res0; res && cnt < MAX_SERVERS_DNS; res = res->ai_next) { if (res->ai_family != AF_INET && res->ai_family != AF_INET6) continue; if ((h = calloc(1, sizeof(struct ypldap_addr))) == NULL) fatal(NULL); h->ss.ss_family = res->ai_family; if (res->ai_family == AF_INET) { sa_in = (struct sockaddr_in *)&h->ss; sa_in->sin_len = sizeof(struct sockaddr_in); sa_in->sin_addr.s_addr = ((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr; } else { sa_in6 = (struct sockaddr_in6 *)&h->ss; sa_in6->sin6_len = sizeof(struct sockaddr_in6); memcpy(&sa_in6->sin6_addr, &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr, sizeof(struct in6_addr)); } TAILQ_INSERT_HEAD(hn, h, next); cnt++; } freeaddrinfo(res0); return (cnt); }