Add local bind mode, where ypldap manages the YP binding file itself
authorjmatthew <jmatthew@openbsd.org>
Fri, 19 Aug 2022 03:50:32 +0000 (03:50 +0000)
committerjmatthew <jmatthew@openbsd.org>
Fri, 19 Aug 2022 03:50:32 +0000 (03:50 +0000)
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
usr.sbin/ypldap/yp.c
usr.sbin/ypldap/ypldap.conf.5
usr.sbin/ypldap/ypldap.h

index 32ca3da..9bf8b41 100644 (file)
@@ -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 <pyr@openbsd.org>
@@ -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 <v.string>      STRING
 %token  <v.number>     NUMBER
 %type  <v.number>      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;
 
index 1cca2a1..98ed3f7 100644 (file)
@@ -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 <pyr@openbsd.org>
  *
@@ -20,6 +20,7 @@
 #include <sys/socket.h>
 #include <sys/select.h>
 #include <sys/tree.h>
+#include <sys/stat.h>
 
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -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;
 }
 
 /*
index 9b6ec7d..2e109f1 100644 (file)
@@ -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 <pyr@openbsd.org>
 .\"
@@ -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
index 08359a7..957befc 100644 (file)
@@ -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 <pyr@openbsd.org>
@@ -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;