Rather than opening the binding file, checking for advisory lock, reading a
authorderaadt <deraadt@openbsd.org>
Sun, 17 Jul 2022 03:08:58 +0000 (03:08 +0000)
committerderaadt <deraadt@openbsd.org>
Sun, 17 Jul 2022 03:08:58 +0000 (03:08 +0000)
piece of it for the address, opening a socket, and providing the address to
the RPC clnt layer.. do all these steps with the magic system call ypconnect(2)
which performs these steps without other system calls, and provides a socket
which is not readily abuseable for other purposes.
ok jmatthew, miod

lib/libc/yp/yp_all.c
lib/libc/yp/yp_bind.c
lib/libc/yp/ypinternal.h

index 014cc51..78dd259 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: yp_all.c,v 1.13 2015/09/28 14:51:04 deraadt Exp $ */
+/*     $OpenBSD: yp_all.c,v 1.14 2022/07/17 03:08:58 deraadt Exp $ */
 /*
  * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com>
  * All rights reserved.
  */
 
 #include <sys/types.h>
+#include <sys/socket.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <limits.h>
+#include <unistd.h>
 #include <rpc/rpc.h>
 #include <rpc/xdr.h>
 #include <rpcsvc/yp.h>
@@ -96,47 +98,58 @@ fail:
 }
 
 int
-yp_all(const char *indomain, const char *inmap, struct ypall_callback *incallback)
+yp_all(const char *dom, const char *inmap, struct ypall_callback *incallback)
 {
        struct ypreq_nokey yprnk;
-       struct dom_binding *ysd;
+       struct dom_binding *ypbinding;
        struct timeval  tv;
-       struct sockaddr_in clnt_sin;
-       CLIENT         *clnt;
+       int connected = 1;
        u_long          status;
-       int             clnt_sock;
-       int             r = 0;
+       int             r = 0, s;
 
-       if (indomain == NULL || *indomain == '\0' ||
-           strlen(indomain) > YPMAXDOMAIN || inmap == NULL ||
+       if (dom == NULL || strlen(dom) == 0)
+               return YPERR_BADARGS;
+
+       if (strlen(dom) > YPMAXDOMAIN || inmap == NULL ||
            *inmap == '\0' || strlen(inmap) > YPMAXMAP || incallback == NULL)
                return YPERR_BADARGS;
 
-       if (_yp_dobind(indomain, &ysd) != 0)
-               return YPERR_DOMAIN;
+again:
+       s = ypconnect(SOCK_STREAM);
+       if (s == -1)
+               return YPERR_DOMAIN;    /* YP not running */
 
-       tv.tv_sec = _yplib_timeout;
-       tv.tv_usec = 0;
-       clnt_sock = RPC_ANYSOCK;
-       clnt_sin = ysd->dom_server_addr;
-       clnt_sin.sin_port = 0;
-       clnt = clnttcp_create(&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
-       if (clnt == NULL) {
+       ypbinding = calloc(1, sizeof *ypbinding);
+       if (ypbinding == NULL) {
+               close(s);
+               return YPERR_RESRC;
+       }
+       ypbinding->dom_socket = s;
+       ypbinding->dom_server_addr.sin_port = -1; /* don't consult portmap */
+
+       ypbinding->dom_client = clnttcp_create(&ypbinding->dom_server_addr,
+           YPPROG, YPVERS, &ypbinding->dom_socket, 0, 0);
+       if (ypbinding->dom_client == NULL) {
+               close(ypbinding->dom_socket);
+               free(ypbinding);
                printf("clnttcp_create failed\n");
-               r = YPERR_PMAP;
-               goto out;
+               goto again;
        }
-       yprnk.domain = (char *)indomain;
+       clnt_control(ypbinding->dom_client, CLSET_CONNECTED, &connected);
+
+       tv.tv_sec = _yplib_timeout;
+       tv.tv_usec = 0;
+       yprnk.domain = (char *)dom;
        yprnk.map = (char *)inmap;
        ypresp_allfn = incallback->foreach;
        ypresp_data = (void *) incallback->data;
-
-       (void) clnt_call(clnt, YPPROC_ALL,
+       (void) clnt_call(ypbinding->dom_client, YPPROC_ALL,
            xdr_ypreq_nokey, &yprnk, _xdr_ypresp_all_seq, &status, tv);
-       clnt_destroy(clnt);
+       close(ypbinding->dom_socket);
+       clnt_destroy(ypbinding->dom_client);
+       free(ypbinding);
+
        if (status != YP_FALSE)
                r = ypprot_err(status);
-out:
-       _yp_unbind(ysd);
        return r;
 }
index 9208fd5..411726c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: yp_bind.c,v 1.28 2016/05/30 02:53:29 guenther Exp $ */
+/*     $OpenBSD: yp_bind.c,v 1.29 2022/07/17 03:08:58 deraadt Exp $ */
 /*
  * Copyright (c) 1992, 1993, 1996 Theo de Raadt <deraadt@theos.com>
  * All rights reserved.
 #include <rpcsvc/ypclnt.h>
 #include "ypinternal.h"
 
-struct dom_binding *_ypbindlist;
+struct dom_binding *ypbinding;
 char _yp_domain[HOST_NAME_MAX+1];
 int _yplib_timeout = 10;
 
 int
 _yp_dobind(const char *dom, struct dom_binding **ypdb)
 {
-       static pid_t    pid = -1;
-       char            path[PATH_MAX];
-       struct dom_binding *ysd, *ysd2;
-       struct ypbind_resp ypbr;
-       struct timeval  tv;
-       struct sockaddr_in clnt_sin;
-       struct ypbind_binding *bn;
-       int             clnt_sock, fd;
-       pid_t           gpid;
-       CLIENT         *client;
-       int             new = 0, r;
-       u_short         port;
-
-       /*
-        * test if YP is running or not
-        */
-       if ((fd = open(YPBINDLOCK, O_RDONLY)) == -1)
-               return YPERR_YPBIND;
-       if (!(flock(fd, LOCK_EX | LOCK_NB) == -1 && errno == EWOULDBLOCK)) {
-               (void)close(fd);
-               return YPERR_YPBIND;
-       }
-       (void)close(fd);
-
-       gpid = getpid();
-       if (!(pid == -1 || pid == gpid)) {
-               ysd = _ypbindlist;
-               while (ysd) {
-                       if (ysd->dom_client)
-                               clnt_destroy(ysd->dom_client);
-                       ysd2 = ysd->dom_pnext;
-                       free(ysd);
-                       ysd = ysd2;
-               }
-               _ypbindlist = NULL;
-       }
-       pid = gpid;
-
-       if (ypdb != NULL)
-               *ypdb = NULL;
+       struct timeval tv;
+       int connected = 1;
+       int s;
 
        if (dom == NULL || strlen(dom) == 0)
                return YPERR_BADARGS;
 
-       for (ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext)
-               if (strcmp(dom, ysd->dom_domain) == 0)
-                       break;
-       if (ysd == NULL) {
-               if ((ysd = calloc(1, sizeof *ysd)) == NULL)
-                       return YPERR_RESRC;
-               ysd->dom_socket = -1;
-               ysd->dom_vers = 0;
-               new = 1;
-       }
 again:
-       if (ysd->dom_vers == 0) {
-               r = snprintf(path, sizeof(path), "%s/%s.%d",
-                   BINDINGDIR, dom, 2);
-               if (r < 0 || r >= sizeof(path)) {
-                       if (new)
-                               free(ysd);
-                       return YPERR_BADARGS;
-               }
-               if ((fd = open(path, O_RDONLY)) == -1) {
-                       /*
-                        * no binding file, YP is dead, or not yet fully
-                        * alive.
-                        */
-                       goto trynet;
-               }
-               if (flock(fd, LOCK_EX | LOCK_NB) == -1 &&
-                   errno == EWOULDBLOCK) {
-                       struct iovec    iov[2];
-                       u_short         ypb_port;
-
-                       /*
-                        * we fetch the ypbind port number, but do
-                        * nothing with it.
-                        */
-                       iov[0].iov_base = (caddr_t) &ypb_port;
-                       iov[0].iov_len = sizeof ypb_port;
-                       iov[1].iov_base = (caddr_t) &ypbr;
-                       iov[1].iov_len = sizeof ypbr;
-
-                       r = readv(fd, iov, 2);
-                       if (r != iov[0].iov_len + iov[1].iov_len) {
-                               (void)close(fd);
-                               ysd->dom_vers = -1;
-                               goto again;
-                       }
-                       (void)close(fd);
-                       goto gotdata;
-               } else {
-                       /* no lock on binding file, YP is dead. */
-                       (void)close(fd);
-                       if (new)
-                               free(ysd);
-                       return YPERR_YPBIND;
-               }
+       if (ypbinding && ypbinding->dom_client)
+               _yp_unbind(ypbinding);
+
+       s = ypconnect(SOCK_DGRAM);
+       if (s == -1)
+               return YPERR_YPBIND;    /* YP not running */
+
+       free(ypbinding);
+       ypbinding = calloc(1, sizeof *ypbinding);
+       if (ypbinding == NULL) {
+               close(s);
+               return YPERR_RESRC;
        }
-trynet:
-       if (ysd->dom_vers == -1 || ysd->dom_vers == 0) {
-               (void)memset(&clnt_sin, 0, sizeof clnt_sin);
-               clnt_sin.sin_len = sizeof(struct sockaddr_in);
-               clnt_sin.sin_family = AF_INET;
-               clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       ypbinding->dom_socket = s;
+       ypbinding->dom_server_addr.sin_port = -1; /* don't consult portmap */
 
-               clnt_sock = RPC_ANYSOCK;
-               client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS,
-                   &clnt_sock, 0, 0);
-               if (client == NULL) {
-                       clnt_pcreateerror("clnttcp_create");
-                       if (new)
-                               free(ysd);
-                       switch (rpc_createerr.cf_error.re_errno) {
-                       case ECONNREFUSED:
-                               return YPERR_YPBIND;
-                       case ENOMEM:
-                               return YPERR_RESRC;
-                       default:
-                               return YPERR_YPERR;
-                       }
-               }
-               if (ntohs(clnt_sin.sin_port) >= IPPORT_RESERVED ||
-                   ntohs(clnt_sin.sin_port) == 20) {
-                       /*
-                        * YP was not running, but someone has registered
-                        * ypbind with portmap -- this simply means YP is
-                        * not running.
-                        */
-                       clnt_destroy(client);
-                       if (new)
-                               free(ysd);
-                       return YPERR_YPBIND;
-               }
-               tv.tv_sec = _yplib_timeout;
-               tv.tv_usec = 0;
-               r = clnt_call(client, YPBINDPROC_DOMAIN, xdr_domainname,
-                   &dom, xdr_ypbind_resp, &ypbr, tv);
-               if (r != RPC_SUCCESS) {
-                       clnt_destroy(client);
-                       ysd->dom_vers = -1;
-                       goto again;
-               }
-               clnt_destroy(client);
-gotdata:
-               bn = &ypbr.ypbind_resp_u.ypbind_bindinfo;
-               memcpy(&port, &bn->ypbind_binding_port, sizeof port);
-               if (ntohs(port) >= IPPORT_RESERVED ||
-                   ntohs(port) == 20) {
-                       /*
-                        * This is bullshit -- the ypbind wants me to
-                        * communicate to an insecure ypserv.  We are
-                        * within rights to syslog this as an attack,
-                        * but for now we'll simply ignore it; real YP
-                        * is obviously not running.
-                        */
-                       if (new)
-                               free(ysd);
-                       return YPERR_YPBIND;
-               }
-               (void)memset(&ysd->dom_server_addr, 0,
-                   sizeof ysd->dom_server_addr);
-               ysd->dom_server_addr.sin_len = sizeof(struct sockaddr_in);
-               ysd->dom_server_addr.sin_family = AF_INET;
-               memcpy(&ysd->dom_server_addr.sin_port,
-                   &bn->ypbind_binding_port,
-                   sizeof(ysd->dom_server_addr.sin_port));
-               memcpy(&ysd->dom_server_addr.sin_addr.s_addr,
-                   &bn->ypbind_binding_addr,
-                   sizeof(ysd->dom_server_addr.sin_addr.s_addr));
-               ysd->dom_server_port = ysd->dom_server_addr.sin_port;
-               ysd->dom_vers = YPVERS;
-               strlcpy(ysd->dom_domain, dom, sizeof ysd->dom_domain);
-       }
        tv.tv_sec = _yplib_timeout / 2;
        tv.tv_usec = 0;
-       if (ysd->dom_client)
-               clnt_destroy(ysd->dom_client);
-       ysd->dom_socket = RPC_ANYSOCK;
-       ysd->dom_client = clntudp_create(&ysd->dom_server_addr,
-           YPPROG, YPVERS, tv, &ysd->dom_socket);
-       if (ysd->dom_client == NULL) {
+       ypbinding->dom_client = clntudp_create(&ypbinding->dom_server_addr,
+           YPPROG, YPVERS, tv, &ypbinding->dom_socket);
+       if (ypbinding->dom_client == NULL) {
+               close(ypbinding->dom_socket);
+               free(ypbinding);
                clnt_pcreateerror("clntudp_create");
-               ysd->dom_vers = -1;
                goto again;
        }
-       if (fcntl(ysd->dom_socket, F_SETFD, FD_CLOEXEC) == -1)
-               perror("fcntl: F_SETFD");
-
-       if (new) {
-               ysd->dom_pnext = _ypbindlist;
-               _ypbindlist = ysd;
-       }
-       if (ypdb != NULL)
-               *ypdb = ysd;
+       clnt_control(ypbinding->dom_client, CLSET_CONNECTED, &connected);
+       if (ypdb)
+               *ypdb = ypbinding;
        return 0;
 }
 
 void
 _yp_unbind(struct dom_binding *ypb)
 {
+       close(ypb->dom_socket);
+       ypb->dom_socket = -1;
        clnt_destroy(ypb->dom_client);
        ypb->dom_client = NULL;
-       ypb->dom_socket = -1;
 }
 
 int
@@ -267,19 +109,5 @@ DEF_WEAK(yp_bind);
 void
 yp_unbind(const char *dom)
 {
-       struct dom_binding *ypb, *ypbp;
-
-       ypbp = NULL;
-       for (ypb = _ypbindlist; ypb; ypb = ypb->dom_pnext) {
-               if (strcmp(dom, ypb->dom_domain) == 0) {
-                       clnt_destroy(ypb->dom_client);
-                       if (ypbp)
-                               ypbp->dom_pnext = ypb->dom_pnext;
-                       else
-                               _ypbindlist = ypb->dom_pnext;
-                       free(ypb);
-                       return;
-               }
-               ypbp = ypb;
-       }
+       _yp_unbind(ypbinding);
 }
index 0b4e464..7be608d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ypinternal.h,v 1.12 2022/07/17 03:04:27 deraadt Exp $  */
+/*     $OpenBSD: ypinternal.h,v 1.13 2022/07/17 03:08:58 deraadt Exp $  */
 
 /*
  * Copyright (c) 1992, 1993, 1996 Theo de Raadt <deraadt@theos.com>
@@ -42,7 +42,6 @@ struct dom_binding {
 };
 
 #define BINDINGDIR     "/var/yp/binding"
-#define YPBINDLOCK     "/var/run/ypbind.lock"
 
 __BEGIN_HIDDEN_DECLS
 extern struct dom_binding *_ypbindlist;