summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2022-07-17 03:08:59 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2022-07-17 03:08:59 +0000
commit1b48033b1fcfbbdd0694a680a9b820228fbfbbb5 (patch)
tree451d245722735f7c7ab76f155b877c8e9bee9b03
parent4baebeae7a95555101f113ff20dab1319a66e580 (diff)
Rather than opening the binding file, checking for advisory lock, reading a
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
-rw-r--r--lib/libc/yp/yp_all.c65
-rw-r--r--lib/libc/yp/yp_bind.c232
-rw-r--r--lib/libc/yp/ypinternal.h3
3 files changed, 70 insertions, 230 deletions
diff --git a/lib/libc/yp/yp_all.c b/lib/libc/yp/yp_all.c
index 014cc51568e..78dd259d496 100644
--- a/lib/libc/yp/yp_all.c
+++ b/lib/libc/yp/yp_all.c
@@ -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.
@@ -26,10 +26,12 @@
*/
#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;
}
diff --git a/lib/libc/yp/yp_bind.c b/lib/libc/yp/yp_bind.c
index 9208fd5225b..411726cd29b 100644
--- a/lib/libc/yp/yp_bind.c
+++ b/lib/libc/yp/yp_bind.c
@@ -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.
@@ -43,218 +43,60 @@
#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);
}
diff --git a/lib/libc/yp/ypinternal.h b/lib/libc/yp/ypinternal.h
index 0b4e46461c4..7be608d812c 100644
--- a/lib/libc/yp/ypinternal.h
+++ b/lib/libc/yp/ypinternal.h
@@ -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;