diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2022-07-17 03:08:59 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2022-07-17 03:08:59 +0000 |
commit | 1b48033b1fcfbbdd0694a680a9b820228fbfbbb5 (patch) | |
tree | 451d245722735f7c7ab76f155b877c8e9bee9b03 | |
parent | 4baebeae7a95555101f113ff20dab1319a66e580 (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.c | 65 | ||||
-rw-r--r-- | lib/libc/yp/yp_bind.c | 232 | ||||
-rw-r--r-- | lib/libc/yp/ypinternal.h | 3 |
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; |