From 56f45a56c4c4c99dd61a67b1122522da0f03c0cc Mon Sep 17 00:00:00 2001 From: jmatthew Date: Fri, 19 Aug 2022 03:50:32 +0000 Subject: [PATCH] Add local bind mode, where ypldap manages the YP binding file itself rather than relying on ypbind to do it, which also means you don't need portmap running. In this mode, ypldap binds its rpc sockets to loopback, so YP services are only available to the host it's running on. The previous behaviour, now called portmap bind mode, is still the default. encouragement from deraadt@ and dlg@ --- usr.sbin/ypldap/parse.y | 15 +++- usr.sbin/ypldap/yp.c | 133 ++++++++++++++++++++++++++++++---- usr.sbin/ypldap/ypldap.conf.5 | 31 +++++++- usr.sbin/ypldap/ypldap.h | 8 +- 4 files changed, 169 insertions(+), 18 deletions(-) diff --git a/usr.sbin/ypldap/parse.y b/usr.sbin/ypldap/parse.y index 32ca3da3e97..9bf8b4127d3 100644 --- a/usr.sbin/ypldap/parse.y +++ b/usr.sbin/ypldap/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.34 2021/10/15 15:01:29 naddy Exp $ */ +/* $OpenBSD: parse.y,v 1.35 2022/08/19 03:50:32 jmatthew Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard @@ -108,6 +108,7 @@ typedef struct { %token USER GROUP TO EXPIRE HOME SHELL GECOS UID GID INTERVAL %token PASSWD NAME FIXED LIST GROUPNAME GROUPPASSWD GROUPGID MAP %token INCLUDE DIRECTORY CLASS PORT ERROR GROUPMEMBERS LDAPS TLS CAFILE +%token BIND LOCAL PORTMAP %token STRING %token NUMBER %type opcode attribute @@ -407,7 +408,13 @@ main : INTERVAL NUMBER { | CAFILE STRING { free(conf->sc_cafile); conf->sc_cafile = $2; - } + } + | BIND LOCAL { + conf->sc_bind_mode = BIND_MODE_LOCAL; + } + | BIND PORTMAP { + conf->sc_bind_mode = BIND_MODE_PORTMAP; + } ; diropts : diropts diropt nl @@ -450,6 +457,7 @@ lookup(char *s) static const struct keywords keywords[] = { { "attribute", ATTRIBUTE }, { "basedn", BASEDN }, + { "bind", BIND }, { "bindcred", BINDCRED }, { "binddn", BINDDN }, { "cafile", CAFILE }, @@ -473,11 +481,13 @@ lookup(char *s) { "interval", INTERVAL }, { "ldaps", LDAPS }, { "list", LIST }, + { "local", LOCAL }, { "map", MAP }, { "maps", MAPS }, { "name", NAME }, { "passwd", PASSWD }, { "port", PORT }, + { "portmap", PORTMAP }, { "provide", PROVIDE }, { "server", SERVER }, { "shell", SHELL }, @@ -850,6 +860,7 @@ parse_config(struct env *x_conf, const char *filename, int opts) log_warn("%s", __func__); return (-1); } + conf->sc_bind_mode = BIND_MODE_PORTMAP; errors = 0; diff --git a/usr.sbin/ypldap/yp.c b/usr.sbin/ypldap/yp.c index 1cca2a1352a..98ed3f7ebb2 100644 --- a/usr.sbin/ypldap/yp.c +++ b/usr.sbin/ypldap/yp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: yp.c,v 1.20 2022/02/05 22:59:58 naddy Exp $ */ +/* $OpenBSD: yp.c,v 1.21 2022/08/19 03:50:32 jmatthew Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard * @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,8 @@ #include "ypldap.h" +#define BINDINGDIR "/var/yp/binding" + void yp_dispatch(struct svc_req *, SVCXPRT *); void yp_disable_events(void); void yp_fd_event(int, short, void *); @@ -51,6 +54,7 @@ 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 *); +int yp_write_binding(int, int); static struct env *env; @@ -107,7 +111,9 @@ yp_fd_event(int fd, short event, void *p) void yp_init(struct env *x_env) { - struct yp_data *yp; + struct sockaddr_in addr; + struct yp_data *yp; + int s, udpport, tcpport; if ((yp = calloc(1, sizeof(*yp))) == NULL) fatal(NULL); @@ -116,21 +122,122 @@ yp_init(struct env *x_env) env = x_env; env->sc_yp = yp; - (void)pmap_unset(YPPROG, YPVERS); + switch (env->sc_bind_mode) { + case BIND_MODE_LOCAL: + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr.sin_len = sizeof(struct sockaddr_in); + addr.sin_family = AF_INET; + + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (s == -1) + fatal("cannot create udp socket"); + addr.sin_port = 0; + if (bindresvport(s, &addr)) + fatal("cannot bind udp socket"); + if ((yp->yp_trans_udp = svcudp_create(s)) == NULL) + fatal("cannot create udp service"); + udpport = ntohs(addr.sin_port); + + s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (s == -1) + fatal("cannot create tcp socket"); + addr.sin_port = 0; + if (bindresvport(s, &addr)) + fatal("cannot bind tcp socket"); + if ((yp->yp_trans_tcp = svctcp_create(s, 0, 0)) == NULL) + fatal("cannot create tcp service"); + tcpport = ntohs(addr.sin_port); + + /* protocol 0 means don't register with portmap */ + if (!svc_register(yp->yp_trans_udp, YPPROG, YPVERS, + yp_dispatch, 0)) { + fatal("unable to register (YPPROG, YPVERS, udp)"); + } + if (!svc_register(yp->yp_trans_tcp, YPPROG, YPVERS, + yp_dispatch, 0)) { + fatal("unable to register (YPPROG, YPVERS, tcp)"); + } - 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 (yp_write_binding(udpport, tcpport)) + fatal("cannot write yp binding file"); + + break; + + case BIND_MODE_PORTMAP: + (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)"); + } + break; + } +} - if (!svc_register(yp->yp_trans_udp, YPPROG, YPVERS, - yp_dispatch, IPPROTO_UDP)) { - fatal("unable to register (YPPROG, YPVERS, udp)"); +int +yp_write_binding(int udpport, int tcpport) +{ + char path[PATH_MAX]; + struct ypbind_resp ybr; + struct iovec iov[3]; + struct in_addr bindaddr; + u_short ypbind, ypserv_tcp, ypserv_udp; + ssize_t total; + int fd; + + snprintf(path, sizeof path, "%s/%s.%ld", BINDINGDIR, env->sc_domainname, + YPVERS); + fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644); + if (fd == -1) { + (void)mkdir(BINDINGDIR, 0755); + fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, + 0644); + if (fd == -1) + return -1; } - if (!svc_register(yp->yp_trans_tcp, YPPROG, YPVERS, - yp_dispatch, IPPROTO_TCP)) { - fatal("unable to register (YPPROG, YPVERS, tcp)"); + + if (fchmod(fd, 0644) == -1) + return -1; + + iov[0].iov_base = (caddr_t)&ypbind; + iov[0].iov_len = sizeof ypbind; + iov[1].iov_base = (caddr_t)&ybr; + iov[1].iov_len = sizeof ybr; + iov[2].iov_base = (caddr_t)&ypserv_tcp; + iov[2].iov_len = sizeof ypserv_tcp; + + bindaddr.s_addr = htonl(INADDR_LOOPBACK); + ypserv_tcp = htons(tcpport); + ypserv_udp = htons(udpport); + ypbind = 0; + memset(&ybr, 0, sizeof ybr); + ybr.ypbind_status = YPBIND_SUCC_VAL; + memmove(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr, + &bindaddr, + sizeof(ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr)); + memmove(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port, + &ypserv_udp, + sizeof(ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port)); + + total = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len; + if (writev(fd, iov, sizeof(iov)/sizeof(iov[0])) != + total) { + close(fd); + unlink(path); + return -1; } + + return 0; } /* diff --git a/usr.sbin/ypldap/ypldap.conf.5 b/usr.sbin/ypldap/ypldap.conf.5 index 9b6ec7d036a..2e109f1e91c 100644 --- a/usr.sbin/ypldap/ypldap.conf.5 +++ b/usr.sbin/ypldap/ypldap.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ypldap.conf.5,v 1.24 2020/05/16 16:58:12 jmc Exp $ +.\" $OpenBSD: ypldap.conf.5,v 1.25 2022/08/19 03:50:32 jmatthew Exp $ .\" .\" Copyright (c) 2008 Pierre-Yves Ritschard .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: May 16 2020 $ +.Dd $Mdocdate: August 19 2022 $ .Dt YPLDAP.CONF 5 .Os .Sh NAME @@ -76,6 +76,33 @@ group.byname, group.bygid. Load CA certificates from the specified file to validate the server certificate. If not specified, CA certificates will be loaded from .Pa /etc/ssl/cert.pem . +.It Ic bind Ar mode +Specify how the domain is made available for binding. +Valid options are: +.Bl -tag -width portmap +.It Ic portmap +Register with +.Xr portmap 8 +and allow +.Xr ypbind 8 +discovery. +This is the default mode. +.It Ic local +Create a YP binding file in +.Pa /var/yp/binding +to enable YP support in the +.Xr passwd 5 +and +.Xr group 5 +databases. +In this mode it is not neccessary to run +.Xr portmap 8 , +and +.Xr ypbind 8 +must not be running. +YP services are only available to the host running +.Xr ypldap 8 . +.El .El .Sh DIRECTORIES Directories are used to describe the LDAP schema and help diff --git a/usr.sbin/ypldap/ypldap.h b/usr.sbin/ypldap/ypldap.h index 08359a76de4..957befc3ebb 100644 --- a/usr.sbin/ypldap/ypldap.h +++ b/usr.sbin/ypldap/ypldap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ypldap.h,v 1.21 2021/01/27 07:21:55 deraadt Exp $ */ +/* $OpenBSD: ypldap.h,v 1.22 2022/08/19 03:50:32 jmatthew Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard @@ -146,6 +146,11 @@ struct imsgev { short events; }; +enum bind_mode { + BIND_MODE_PORTMAP, + BIND_MODE_LOCAL +}; + struct env { #define YPLDAP_OPT_VERBOSE 0x01 #define YPLDAP_OPT_NOACTION 0x02 @@ -162,6 +167,7 @@ struct env { u_int32_t sc_maxid; char sc_domainname[HOST_NAME_MAX+1]; + enum bind_mode sc_bind_mode; struct timeval sc_conf_tv; struct event sc_conf_ev; char *sc_cafile; -- 2.20.1