diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2022-08-02 17:00:16 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2022-08-02 17:00:16 +0000 |
commit | db34050c74cc8d0a9f9bae17843deeaf379a41d6 (patch) | |
tree | fd2a40c14b0ee2323709afaed8619042af08f69f | |
parent | 5f6a66769d783a89ff15cc995bce2af433ffefd5 (diff) |
1) The yp_bind/yp_unbind and internal _yp_dobind/_yp_unbind sequences shared
dom_binding structs between threads, which is unsafe -- example, dom_vers
signalled retry events, and structs+socket would get deallocated in _yp_unbind.
Change all yp_first (and similar) functions to understand that _yp_dobind now
provides a private dom_binding and socket, which must be released using
_yp_unbind. Use similar methods in the one-step yp_all function.
2) domainname caching in get* is not neccessary now that the domainname cannot
change relative to ypconnect(2)'s decisions.
Many fields in dom_binding struct become unused, so delete them.
ok jmatthew, also tested by miod
-rw-r--r-- | lib/libc/gen/getgrent.c | 16 | ||||
-rw-r--r-- | lib/libc/gen/getgrouplist.c | 7 | ||||
-rw-r--r-- | lib/libc/gen/getnetgrent.c | 29 | ||||
-rw-r--r-- | lib/libc/gen/getpwent.c | 26 | ||||
-rw-r--r-- | lib/libc/yp/yp_all.c | 33 | ||||
-rw-r--r-- | lib/libc/yp/yp_bind.c | 46 | ||||
-rw-r--r-- | lib/libc/yp/yp_first.c | 6 | ||||
-rw-r--r-- | lib/libc/yp/yp_get_default_domain.c | 24 | ||||
-rw-r--r-- | lib/libc/yp/yp_maplist.c | 4 | ||||
-rw-r--r-- | lib/libc/yp/yp_master.c | 4 | ||||
-rw-r--r-- | lib/libc/yp/yp_order.c | 4 | ||||
-rw-r--r-- | lib/libc/yp/ypinternal.h | 7 | ||||
-rw-r--r-- | lib/libc/yp/ypmatch_cache.c | 6 |
13 files changed, 98 insertions, 114 deletions
diff --git a/lib/libc/gen/getgrent.c b/lib/libc/gen/getgrent.c index 3b7c65bfdeb..106f6c3f9dd 100644 --- a/lib/libc/gen/getgrent.c +++ b/lib/libc/gen/getgrent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: getgrent.c,v 1.49 2022/07/17 03:10:47 deraadt Exp $ */ +/* $OpenBSD: getgrent.c,v 1.50 2022/08/02 17:00:15 deraadt Exp $ */ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -341,18 +341,8 @@ grscan(int search, gid_t gid, const char *name, struct group *p_gr, } #ifdef YP if (line[0] == '+' || line[0] == '-') { - if (__ypdomain == NULL && - yp_get_default_domain(&__ypdomain)) - goto parse; - switch (yp_bind(__ypdomain)) { - case 0: - break; - case YPERR_BADARGS: - case YPERR_YPBIND: - goto parse; - default: - return 0; - } + if (!__ypdomain) + yp_get_default_domain(&__ypdomain); } if (line[0] == '+') { switch (line[1]) { diff --git a/lib/libc/gen/getgrouplist.c b/lib/libc/gen/getgrouplist.c index b390449eef2..b23b937faf0 100644 --- a/lib/libc/gen/getgrouplist.c +++ b/lib/libc/gen/getgrouplist.c @@ -1,4 +1,4 @@ -/* $OpenBSD: getgrouplist.c,v 1.29 2022/07/17 03:10:47 deraadt Exp $ */ +/* $OpenBSD: getgrouplist.c,v 1.30 2022/08/02 17:00:15 deraadt Exp $ */ /* * Copyright (c) 2008 Ingo Schwarze <schwarze@usta.de> * Copyright (c) 1991, 1993 @@ -223,9 +223,8 @@ getgrouplist(const char *uname, gid_t agroup, gid_t *groups, int *grpcnt) } /* Only access YP when there is no static entry. */ - if (!yp_bind(__ypdomain) && - !yp_match(__ypdomain, "netid.byname", key, - (int)strlen(key), &ypdata, &ypdatalen)) + if (!yp_match(__ypdomain, "netid.byname", key, + (int)strlen(key), &ypdata, &ypdatalen)) if (_parse_netid(ypdata, pwstore.pw_uid, groups, &ngroups, maxgroups) == -1) ret = -1; diff --git a/lib/libc/gen/getnetgrent.c b/lib/libc/gen/getnetgrent.c index bd02e09bdfe..26761bde493 100644 --- a/lib/libc/gen/getnetgrent.c +++ b/lib/libc/gen/getnetgrent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: getnetgrent.c,v 1.28 2016/09/24 12:43:37 millert Exp $ */ +/* $OpenBSD: getnetgrent.c,v 1.29 2022/08/02 17:00:15 deraadt Exp $ */ /* * Copyright (c) 1994 Christos Zoulas @@ -619,7 +619,8 @@ setnetgrent(const char *ng) { struct stringlist *sl; #ifdef YP - char *line; + static char *__ypdomain; + char *line = NULL; #endif char *ng_copy, *ypdom = NULL; @@ -639,10 +640,12 @@ setnetgrent(const char *ng) * We use yp if there is a "+" in the netgroup file, or if there is * no netgroup file at all */ - if (_ng_db == NULL || lookup(NULL, "+", &line, _NG_KEYBYNAME) == 0) - yp_get_default_domain(&ypdom); - else - free(line); + if (_ng_db == NULL || lookup(NULL, "+", &line, _NG_KEYBYNAME) == 0) { + if (!__ypdomain) + yp_get_default_domain(&__ypdomain); + ypdom = __ypdomain; + } + free(line); #endif ng_copy = strdup(ng); if (ng_copy != NULL) @@ -673,9 +676,10 @@ DEF_WEAK(getnetgrent); int innetgr(const char *grp, const char *host, const char *user, const char *domain) { - char *ypdom = NULL, *grpdup; + char *ypdom = NULL, *grpdup; #ifdef YP - char *line = NULL; + static char *__ypdomain; + char *line = NULL; #endif int found; struct stringlist *sl; @@ -688,10 +692,11 @@ innetgr(const char *grp, const char *host, const char *user, const char *domain) * We use yp if there is a "+" in the netgroup file, or if there is * no netgroup file at all */ - if (_ng_db == NULL) - yp_get_default_domain(&ypdom); - else if (lookup(NULL, "+", &line, _NG_KEYBYNAME) == 0) - yp_get_default_domain(&ypdom); + if (_ng_db == NULL || lookup(NULL, "+", &line, _NG_KEYBYNAME) == 0) { + if (!__ypdomain) + yp_get_default_domain(&__ypdomain); + ypdom = __ypdomain; + } free(line); #endif diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c index 7ddbe332e4c..24ac8f96c3a 100644 --- a/lib/libc/gen/getpwent.c +++ b/lib/libc/gen/getpwent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: getpwent.c,v 1.65 2022/07/17 03:10:47 deraadt Exp $ */ +/* $OpenBSD: getpwent.c,v 1.66 2022/08/02 17:00:15 deraadt Exp $ */ /* * Copyright (c) 2008 Theo de Raadt * Copyright (c) 1988, 1993 @@ -332,12 +332,8 @@ again: int keylen, datalen, r, s; char *key, *data = NULL; - if (!__ypdomain) { - if (_yp_check(&__ypdomain) == 0) { - __ypmode = YPMODE_NONE; - goto again; - } - } + if (!__ypdomain) + yp_get_default_domain(&__ypdomain); switch (__ypmode) { case YPMODE_FULL: if (__ypcurrent) { @@ -538,14 +534,8 @@ __has_ypmaster(void) return (checked); } - if (!__ypdomain) { - if (_yp_check(&__ypdomain) == 0) { - saved_uid = uid; - saved_euid = euid; - checked = 0; - return (checked); /* No domain. */ - } - } + if (!__ypdomain) + yp_get_default_domain(&__ypdomain); if (yp_first(__ypdomain, "master.passwd.byname", &key, &keylen, &result, &resultlen)) { @@ -583,10 +573,8 @@ __yppwlookup(int lookup, char *name, uid_t uid, struct passwd *pw, break; switch (pw->pw_name[0]) { case '+': - if (!__ypdomain) { - if (_yp_check(&__ypdomain) == 0) - continue; - } + if (!__ypdomain) + yp_get_default_domain(&__ypdomain); __ypproto_set(pw, &__yppbuf, *flagsp, &yp_pw_flags); if (!map) { if (lookup == LOOKUP_BYNAME) { diff --git a/lib/libc/yp/yp_all.c b/lib/libc/yp/yp_all.c index 04a6ebe2b49..204f085ccc8 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.15 2022/07/18 02:31:19 deraadt Exp $ */ +/* $OpenBSD: yp_all.c,v 1.16 2022/08/02 16:59:29 deraadt Exp $ */ /* * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com> * All rights reserved. @@ -101,7 +101,7 @@ int yp_all(const char *dom, const char *inmap, struct ypall_callback *incallback) { struct ypreq_nokey yprnk; - struct dom_binding *ypbinding; + struct dom_binding ypbinding; struct timeval tv; int connected = 1; u_long status; @@ -118,24 +118,18 @@ again: s = ypconnect(SOCK_STREAM); if (s == -1) return YPERR_DOMAIN; /* YP not running */ + ypbinding.dom_socket = s; + ypbinding.dom_server_addr.sin_port = -1; /* don't consult portmap */ - 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); + 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); + ypbinding.dom_socket = -1; clnt_pcreateerror("clnttcp_create"); goto again; } - clnt_control(ypbinding->dom_client, CLSET_CONNECTED, &connected); + clnt_control(ypbinding.dom_client, CLSET_CONNECTED, &connected); tv.tv_sec = _yplib_timeout; tv.tv_usec = 0; @@ -143,11 +137,10 @@ again: yprnk.map = (char *)inmap; ypresp_allfn = incallback->foreach; ypresp_data = (void *) incallback->data; - (void) clnt_call(ypbinding->dom_client, YPPROC_ALL, + (void) clnt_call(ypbinding.dom_client, YPPROC_ALL, xdr_ypreq_nokey, &yprnk, _xdr_ypresp_all_seq, &status, tv); - close(ypbinding->dom_socket); - clnt_destroy(ypbinding->dom_client); - free(ypbinding); + close(ypbinding.dom_socket); + clnt_destroy(ypbinding.dom_client); if (status != YP_FALSE) r = ypprot_err(status); diff --git a/lib/libc/yp/yp_bind.c b/lib/libc/yp/yp_bind.c index 15db9ea7730..af6775e96b8 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.31 2022/07/22 05:55:05 jsg Exp $ */ +/* $OpenBSD: yp_bind.c,v 1.32 2022/08/02 16:59:29 deraadt Exp $ */ /* * Copyright (c) 1992, 1993, 1996 Theo de Raadt <deraadt@theos.com> * All rights reserved. @@ -43,13 +43,13 @@ #include <rpcsvc/ypclnt.h> #include "ypinternal.h" -static 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) { + struct dom_binding *ypbinding; struct timeval tv; int connected = 1; int s; @@ -57,19 +57,15 @@ _yp_dobind(const char *dom, struct dom_binding **ypdb) if (dom == NULL || strlen(dom) == 0) return YPERR_BADARGS; -again: - if (ypbinding && ypbinding->dom_client) - _yp_unbind(ypbinding); + ypbinding = calloc(1, sizeof (*ypbinding)); + if (ypbinding == NULL) + return YPERR_RESRC; +again: s = ypconnect(SOCK_DGRAM); - if (s == -1) + if (s == -1) { + free(ypbinding); return YPERR_YPBIND; /* YP not running */ - - free(ypbinding); - 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 */ @@ -80,14 +76,12 @@ again: YPPROG, YPVERS, tv, &ypbinding->dom_socket); if (ypbinding->dom_client == NULL) { close(ypbinding->dom_socket); - free(ypbinding); - ypbinding = NULL; + ypbinding->dom_socket = -1; clnt_pcreateerror("clntudp_create"); goto again; } clnt_control(ypbinding->dom_client, CLSET_CONNECTED, &connected); - if (ypdb) - *ypdb = ypbinding; + *ypdb = ypbinding; return 0; } @@ -95,20 +89,30 @@ void _yp_unbind(struct dom_binding *ypb) { close(ypb->dom_socket); - ypb->dom_socket = -1; - clnt_destroy(ypb->dom_client); - ypb->dom_client = NULL; + if (ypb->dom_client) + clnt_destroy(ypb->dom_client); + free(ypb); } +/* + * Check if YP is running. But do not leave it active, because we + * may not return from libc with a fd active. + */ int yp_bind(const char *dom) { - return _yp_dobind(dom, NULL); + struct dom_binding *ysd; + int r; + + r = _yp_dobind(dom, &ysd); + if (r == 0) + _yp_unbind(ysd); + return r; } DEF_WEAK(yp_bind); void yp_unbind(const char *dom) { - _yp_unbind(ypbinding); + /* do nothing */ } diff --git a/lib/libc/yp/yp_first.c b/lib/libc/yp/yp_first.c index 2f24999043f..d4978ba2a57 100644 --- a/lib/libc/yp/yp_first.c +++ b/lib/libc/yp/yp_first.c @@ -1,4 +1,4 @@ -/* $OpenBSD: yp_first.c,v 1.11 2015/09/13 20:57:28 guenther Exp $ */ +/* $OpenBSD: yp_first.c,v 1.12 2022/08/02 16:59:29 deraadt Exp $ */ /* * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com> * All rights reserved. @@ -41,7 +41,7 @@ yp_first(const char *indomain, const char *inmap, char **outkey, int *outkeylen, { struct ypresp_key_val yprkv; struct ypreq_nokey yprnk; - struct dom_binding *ysd; + struct dom_binding *ysd = NULL; struct timeval tv; int tries = 0, r; @@ -69,7 +69,7 @@ again: if (r != RPC_SUCCESS) { if (tries++) clnt_perror(ysd->dom_client, "yp_first: clnt_call"); - ysd->dom_vers = -1; + _yp_unbind(ysd); goto again; } if (!(r = ypprot_err(yprkv.stat))) { diff --git a/lib/libc/yp/yp_get_default_domain.c b/lib/libc/yp/yp_get_default_domain.c index 8cf0dc9fbd9..7eba82d81f4 100644 --- a/lib/libc/yp/yp_get_default_domain.c +++ b/lib/libc/yp/yp_get_default_domain.c @@ -1,4 +1,4 @@ -/* $OpenBSD: yp_get_default_domain.c,v 1.9 2015/09/13 20:57:28 guenther Exp $ */ +/* $OpenBSD: yp_get_default_domain.c,v 1.10 2022/08/02 16:59:30 deraadt Exp $ */ /* * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com> * All rights reserved. @@ -33,17 +33,27 @@ #include <rpcsvc/yp.h> #include <rpcsvc/ypclnt.h> #include "ypinternal.h" +#include "thread_private.h" + +_THREAD_PRIVATE_KEY(yp_get_default_domain); int yp_get_default_domain(char **domp) { + int r = 0; + + _THREAD_PRIVATE_MUTEX_LOCK(yp_get_default_domain); *domp = NULL; - if (_yp_domain[0] == '\0') - if (getdomainname(_yp_domain, sizeof _yp_domain)) - return YPERR_NODOM; + if (_yp_domain[0] == '\0') { + if (getdomainname(_yp_domain, sizeof _yp_domain) || + _yp_domain[0] == '\0') { + r = YPERR_NODOM; + goto out; + } + } *domp = _yp_domain; - if (_yp_domain[0] == '\0') - return YPERR_NODOM; - return 0; +out: + _THREAD_PRIVATE_MUTEX_UNLOCK(yp_get_default_domain); + return r; } DEF_WEAK(yp_get_default_domain); diff --git a/lib/libc/yp/yp_maplist.c b/lib/libc/yp/yp_maplist.c index 17bdefe103f..8a7afbbd32d 100644 --- a/lib/libc/yp/yp_maplist.c +++ b/lib/libc/yp/yp_maplist.c @@ -1,4 +1,4 @@ -/* $OpenBSD: yp_maplist.c,v 1.9 2015/01/16 16:48:51 deraadt Exp $ */ +/* $OpenBSD: yp_maplist.c,v 1.10 2022/08/02 16:59:30 deraadt Exp $ */ /* * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com> * All rights reserved. @@ -56,7 +56,7 @@ again: if (r != RPC_SUCCESS) { if (tries++) clnt_perror(ysd->dom_client, "yp_maplist: clnt_call"); - ysd->dom_vers = -1; + _yp_unbind(ysd); goto again; } *outmaplist = ypml.maps; diff --git a/lib/libc/yp/yp_master.c b/lib/libc/yp/yp_master.c index 0d8f6787ccc..2200d721f42 100644 --- a/lib/libc/yp/yp_master.c +++ b/lib/libc/yp/yp_master.c @@ -1,4 +1,4 @@ -/* $OpenBSD: yp_master.c,v 1.9 2015/01/16 16:48:51 deraadt Exp $ */ +/* $OpenBSD: yp_master.c,v 1.10 2022/08/02 16:59:30 deraadt Exp $ */ /* * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com> * All rights reserved. @@ -65,7 +65,7 @@ again: if (r != RPC_SUCCESS) { if (tries++) clnt_perror(ysd->dom_client, "yp_master: clnt_call"); - ysd->dom_vers = -1; + _yp_unbind(ysd); goto again; } if (!(r = ypprot_err(yprm.stat))) { diff --git a/lib/libc/yp/yp_order.c b/lib/libc/yp/yp_order.c index 696137ae0f4..522d5d7d264 100644 --- a/lib/libc/yp/yp_order.c +++ b/lib/libc/yp/yp_order.c @@ -1,4 +1,4 @@ -/* $OpenBSD: yp_order.c,v 1.10 2015/01/16 16:48:51 deraadt Exp $ */ +/* $OpenBSD: yp_order.c,v 1.11 2022/08/02 16:59:30 deraadt Exp $ */ /* * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com> * All rights reserved. @@ -72,7 +72,7 @@ again: } if (r != RPC_SUCCESS) { clnt_perror(ysd->dom_client, "yp_order: clnt_call"); - ysd->dom_vers = -1; + _yp_unbind(ysd); goto again; } *outorder = ypro.ordernum; diff --git a/lib/libc/yp/ypinternal.h b/lib/libc/yp/ypinternal.h index 7be608d812c..5b7ed4103db 100644 --- a/lib/libc/yp/ypinternal.h +++ b/lib/libc/yp/ypinternal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ypinternal.h,v 1.13 2022/07/17 03:08:58 deraadt Exp $ */ +/* $OpenBSD: ypinternal.h,v 1.14 2022/08/02 16:59:30 deraadt Exp $ */ /* * Copyright (c) 1992, 1993, 1996 Theo de Raadt <deraadt@theos.com> @@ -31,14 +31,9 @@ * yp_prot.h and yp.h. */ struct dom_binding { - struct dom_binding *dom_pnext; - char dom_domain[YPMAXDOMAIN + 1]; struct sockaddr_in dom_server_addr; - u_short dom_server_port; int dom_socket; CLIENT *dom_client; - u_short dom_local_port; - long dom_vers; }; #define BINDINGDIR "/var/yp/binding" diff --git a/lib/libc/yp/ypmatch_cache.c b/lib/libc/yp/ypmatch_cache.c index 718a1bde927..1c2af4c7c69 100644 --- a/lib/libc/yp/ypmatch_cache.c +++ b/lib/libc/yp/ypmatch_cache.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ypmatch_cache.c,v 1.17 2015/09/13 20:57:28 guenther Exp $ */ +/* $OpenBSD: ypmatch_cache.c,v 1.18 2022/08/02 16:59:30 deraadt Exp $ */ /* * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com> * All rights reserved. @@ -187,7 +187,7 @@ again: if (r != RPC_SUCCESS) { if (tries++) clnt_perror(ysd->dom_client, "yp_match: clnt_call"); - ysd->dom_vers = -1; + _yp_unbind(ysd); goto again; } if (!(r = ypprot_err(yprv.stat))) { @@ -248,7 +248,7 @@ again: if (r != RPC_SUCCESS) { if (tries++) clnt_perror(ysd->dom_client, "yp_next: clnt_call"); - ysd->dom_vers = -1; + _yp_unbind(ysd); goto again; } if (!(r = ypprot_err(yprkv.stat))) { |