1*9a513d96Schristos /* $NetBSD: yplib.c,v 1.46 2014/09/18 13:58:20 christos Exp $ */
2693e99f7Scgd
377c037edSderaadt /*
43bf2b62fSderaadt * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@fsa.ca>
577c037edSderaadt * All rights reserved.
677c037edSderaadt *
777c037edSderaadt * Redistribution and use in source and binary forms, with or without
877c037edSderaadt * modification, are permitted provided that the following conditions
977c037edSderaadt * are met:
1077c037edSderaadt * 1. Redistributions of source code must retain the above copyright
1177c037edSderaadt * notice, this list of conditions and the following disclaimer.
1277c037edSderaadt * 2. Redistributions in binary form must reproduce the above copyright
1377c037edSderaadt * notice, this list of conditions and the following disclaimer in the
1477c037edSderaadt * documentation and/or other materials provided with the distribution.
1577c037edSderaadt *
1677c037edSderaadt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
1777c037edSderaadt * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1877c037edSderaadt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1977c037edSderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
2077c037edSderaadt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2177c037edSderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2277c037edSderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2377c037edSderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2477c037edSderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2577c037edSderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2677c037edSderaadt * SUCH DAMAGE.
2777c037edSderaadt */
2877c037edSderaadt
29e7cc5503Schristos #include <sys/cdefs.h>
306bb5d0a0Sjtc #if defined(LIBC_SCCS) && !defined(lint)
31*9a513d96Schristos __RCSID("$NetBSD: yplib.c,v 1.46 2014/09/18 13:58:20 christos Exp $");
3277c037edSderaadt #endif
3377c037edSderaadt
3443fa6fe3Sjtc #include "namespace.h"
35c49e8087Slukem #include "reentrant.h"
36c49e8087Slukem
3742d384baSderaadt #include <sys/param.h>
3842d384baSderaadt #include <sys/socket.h>
3942d384baSderaadt #include <sys/file.h>
4066cf56adSderaadt #include <sys/uio.h>
41b48252f3Slukem
4242736edbSlukem #include <arpa/nameser.h>
43b48252f3Slukem
44b48252f3Slukem #include <assert.h>
4542d384baSderaadt #include <errno.h>
4642d384baSderaadt #include <stdio.h>
47fac4c46fSjtc #include <stdlib.h>
4842d384baSderaadt #include <string.h>
49fac4c46fSjtc #include <unistd.h>
50b48252f3Slukem
5142d384baSderaadt #include <rpc/rpc.h>
5242d384baSderaadt #include <rpc/xdr.h>
5342d384baSderaadt #include <rpcsvc/yp_prot.h>
5442d384baSderaadt #include <rpcsvc/ypclnt.h>
55e7cc5503Schristos #include "local.h"
5642d384baSderaadt
5742d384baSderaadt #define BINDINGDIR "/var/yp/binding"
58d87a87c7Sderaadt #define YPBINDLOCK "/var/run/ypbind.lock"
5942d384baSderaadt
6042d384baSderaadt struct dom_binding *_ypbindlist;
615d8adb68Sjtc char _yp_domain[MAXHOSTNAMELEN];
6242d384baSderaadt
63ac6352fdSthorpej #define YPLIB_TIMEOUT 10
64ac6352fdSthorpej #define YPLIB_RPC_RETRIES 4
65ac6352fdSthorpej
66ac6352fdSthorpej struct timeval _yplib_timeout = { YPLIB_TIMEOUT, 0 };
67ac6352fdSthorpej struct timeval _yplib_rpc_timeout = { YPLIB_TIMEOUT / YPLIB_RPC_RETRIES,
68ac6352fdSthorpej 1000000 * (YPLIB_TIMEOUT % YPLIB_RPC_RETRIES) / YPLIB_RPC_RETRIES };
69409a9590Schristos int _yplib_nerrs = 5;
702b01a8adSchristos int _yplib_bindtries = 0;
7176bf46a3Sjtc
7243fa6fe3Sjtc #ifdef __weak_alias
7360549036Smycroft __weak_alias(yp_bind, _yp_bind)
7460549036Smycroft __weak_alias(yp_unbind, _yp_unbind)
7560549036Smycroft __weak_alias(yp_get_default_domain, _yp_get_default_domain)
762b01a8adSchristos __weak_alias(yp_setbindtries, _yp_setbindtries)
7743fa6fe3Sjtc #endif
7843fa6fe3Sjtc
7904562cacSchristos #ifdef _REENTRANT
8004562cacSchristos static mutex_t _ypmutex = MUTEX_INITIALIZER;
8104562cacSchristos #define YPLOCK() mutex_lock(&_ypmutex)
8204562cacSchristos #define YPUNLOCK() mutex_unlock(&_ypmutex)
8304562cacSchristos #else
8404562cacSchristos #define YPLOCK()
8504562cacSchristos #define YPUNLOCK()
8604562cacSchristos #endif
8704562cacSchristos
8842d384baSderaadt int
yp_setbindtries(int ntries)898147d218Smatt yp_setbindtries(int ntries)
908147d218Smatt {
912b01a8adSchristos int old_val = _yplib_bindtries;
922b01a8adSchristos
932b01a8adSchristos if (ntries >= 0)
942b01a8adSchristos _yplib_bindtries = ntries;
952b01a8adSchristos return old_val;
962b01a8adSchristos }
972b01a8adSchristos
982b01a8adSchristos int
_yp_dobind(const char * dom,struct dom_binding ** ypdb)998147d218Smatt _yp_dobind(const char *dom, struct dom_binding **ypdb)
10042d384baSderaadt {
10142d384baSderaadt static int pid = -1;
10242d384baSderaadt char path[MAXPATHLEN];
10342d384baSderaadt struct dom_binding *ysd, *ysd2;
10442d384baSderaadt struct ypbind_resp ypbr;
10542d384baSderaadt struct sockaddr_in clnt_sin;
10642d384baSderaadt int clnt_sock, fd, gpid;
10742d384baSderaadt CLIENT *client;
108ff64706cSthorpej int new = 0;
109772697e2Schristos int nerrs = 0;
110ff64706cSthorpej ssize_t r;
11142d384baSderaadt
11242736edbSlukem if (dom == NULL || *dom == '\0')
11376bf46a3Sjtc return YPERR_BADARGS;
11476bf46a3Sjtc
115d87a87c7Sderaadt /*
116d87a87c7Sderaadt * test if YP is running or not
117d87a87c7Sderaadt */
118*9a513d96Schristos if ((fd = open(YPBINDLOCK, O_RDONLY | O_CLOEXEC)) == -1)
119d87a87c7Sderaadt return YPERR_YPBIND;
120d87a87c7Sderaadt if (!(flock(fd, LOCK_EX | LOCK_NB) == -1 && errno == EWOULDBLOCK)) {
121a667b8f7Schristos (void)close(fd);
122d87a87c7Sderaadt return YPERR_YPBIND;
123d87a87c7Sderaadt }
124a667b8f7Schristos (void)close(fd);
125d87a87c7Sderaadt
12642d384baSderaadt gpid = getpid();
12742d384baSderaadt if (!(pid == -1 || pid == gpid)) {
12842d384baSderaadt ysd = _ypbindlist;
12942d384baSderaadt while (ysd) {
13042d384baSderaadt if (ysd->dom_client)
13142d384baSderaadt clnt_destroy(ysd->dom_client);
13242d384baSderaadt ysd2 = ysd->dom_pnext;
13342d384baSderaadt free(ysd);
13442d384baSderaadt ysd = ysd2;
13542d384baSderaadt }
13642d384baSderaadt _ypbindlist = NULL;
13742d384baSderaadt }
13842d384baSderaadt pid = gpid;
13942d384baSderaadt
14042d384baSderaadt if (ypdb != NULL)
14142d384baSderaadt *ypdb = NULL;
14242d384baSderaadt
14342d384baSderaadt for (ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext)
14442d384baSderaadt if (strcmp(dom, ysd->dom_domain) == 0)
14542d384baSderaadt break;
14642d384baSderaadt if (ysd == NULL) {
147a667b8f7Schristos if ((ysd = malloc(sizeof *ysd)) == NULL)
148a667b8f7Schristos return YPERR_YPERR;
149a667b8f7Schristos (void)memset(ysd, 0, sizeof *ysd);
15042d384baSderaadt ysd->dom_socket = -1;
15142d384baSderaadt ysd->dom_vers = 0;
15242d384baSderaadt new = 1;
15342d384baSderaadt }
15442d384baSderaadt again:
15542d384baSderaadt if (ysd->dom_vers == 0) {
156a667b8f7Schristos (void) snprintf(path, sizeof(path), "%s/%s.%d",
157a667b8f7Schristos BINDINGDIR, dom, 2);
158*9a513d96Schristos if ((fd = open(path, O_RDONLY | O_CLOEXEC)) == -1) {
159a667b8f7Schristos /*
160a667b8f7Schristos * no binding file, YP is dead, or not yet fully
161a667b8f7Schristos * alive.
162a667b8f7Schristos */
1639de7a8a1Sderaadt goto trynet;
16442d384baSderaadt }
165a667b8f7Schristos if (flock(fd, LOCK_EX | LOCK_NB) == -1 &&
166a667b8f7Schristos errno == EWOULDBLOCK) {
16766cf56adSderaadt struct iovec iov[2];
16866cf56adSderaadt struct ypbind_resp ybr;
16966cf56adSderaadt u_short ypb_port;
170a667b8f7Schristos struct ypbind_binding *bn;
17166cf56adSderaadt
172780ffacdSmycroft iov[0].iov_base = &ypb_port;
17366cf56adSderaadt iov[0].iov_len = sizeof ypb_port;
174780ffacdSmycroft iov[1].iov_base = &ybr;
17566cf56adSderaadt iov[1].iov_len = sizeof ybr;
17666cf56adSderaadt
17766cf56adSderaadt r = readv(fd, iov, 2);
178ff64706cSthorpej if (r != (ssize_t)(iov[0].iov_len + iov[1].iov_len)) {
179a667b8f7Schristos (void)close(fd);
18042d384baSderaadt ysd->dom_vers = -1;
18142d384baSderaadt goto again;
18242d384baSderaadt }
183a667b8f7Schristos (void)memset(&ysd->dom_server_addr, 0,
184a667b8f7Schristos sizeof ysd->dom_server_addr);
185a667b8f7Schristos ysd->dom_server_addr.sin_len =
186a667b8f7Schristos sizeof(struct sockaddr_in);
1875860921eSmycroft ysd->dom_server_addr.sin_family = AF_INET;
188a667b8f7Schristos bn = &ybr.ypbind_respbody.ypbind_bindinfo;
18966cf56adSderaadt ysd->dom_server_addr.sin_port =
190a667b8f7Schristos bn->ypbind_binding_port;
191a667b8f7Schristos
1925860921eSmycroft ysd->dom_server_addr.sin_addr =
193a667b8f7Schristos bn->ypbind_binding_addr;
19466cf56adSderaadt
19542d384baSderaadt ysd->dom_server_port = ysd->dom_server_addr.sin_port;
196a667b8f7Schristos (void)close(fd);
19742d384baSderaadt goto gotit;
19842d384baSderaadt } else {
19942d384baSderaadt /* no lock on binding file, YP is dead. */
200a667b8f7Schristos (void)close(fd);
20142d384baSderaadt if (new)
20242d384baSderaadt free(ysd);
20342d384baSderaadt return YPERR_YPBIND;
20442d384baSderaadt }
20542d384baSderaadt }
2069de7a8a1Sderaadt trynet:
20742d384baSderaadt if (ysd->dom_vers == -1 || ysd->dom_vers == 0) {
208a667b8f7Schristos struct ypbind_binding *bn;
209a667b8f7Schristos (void)memset(&clnt_sin, 0, sizeof clnt_sin);
2105860921eSmycroft clnt_sin.sin_len = sizeof(struct sockaddr_in);
21142d384baSderaadt clnt_sin.sin_family = AF_INET;
21242d384baSderaadt clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
21342d384baSderaadt
21442d384baSderaadt clnt_sock = RPC_ANYSOCK;
215a667b8f7Schristos client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS,
216a667b8f7Schristos &clnt_sock, 0, 0);
21742d384baSderaadt if (client == NULL) {
21842d384baSderaadt clnt_pcreateerror("clnttcp_create");
21942d384baSderaadt if (new)
22042d384baSderaadt free(ysd);
22142d384baSderaadt return YPERR_YPBIND;
22242d384baSderaadt }
223473ea2c4Schristos r = clnt_call(client, (rpcproc_t)YPBINDPROC_DOMAIN,
224b2a14ab2Schristos (xdrproc_t)xdr_ypdomain_wrap_string, &dom,
225b2a14ab2Schristos (xdrproc_t)xdr_ypbind_resp, &ypbr, _yplib_timeout);
22642d384baSderaadt if (r != RPC_SUCCESS) {
2272b01a8adSchristos if (_yplib_bindtries <= 0 && new == 0 &&
2282b01a8adSchristos ++nerrs == _yplib_nerrs) {
229772697e2Schristos nerrs = 0;
23042d384baSderaadt fprintf(stderr,
231432a32dcSderaadt "YP server for domain %s not responding, still trying\n",
232432a32dcSderaadt dom);
233772697e2Schristos }
2342b01a8adSchristos else if (_yplib_bindtries > 0 &&
2352b01a8adSchristos ++nerrs == _yplib_bindtries) {
2362b01a8adSchristos free(ysd);
2372b01a8adSchristos return YPERR_YPBIND;
2382b01a8adSchristos }
23942d384baSderaadt clnt_destroy(client);
24042d384baSderaadt ysd->dom_vers = -1;
24142d384baSderaadt goto again;
24242d384baSderaadt }
24342d384baSderaadt clnt_destroy(client);
24442d384baSderaadt
245a667b8f7Schristos (void)memset(&ysd->dom_server_addr, 0,
246a667b8f7Schristos sizeof ysd->dom_server_addr);
2475860921eSmycroft ysd->dom_server_addr.sin_len = sizeof(struct sockaddr_in);
24842d384baSderaadt ysd->dom_server_addr.sin_family = AF_INET;
249a667b8f7Schristos bn = &ypbr.ypbind_respbody.ypbind_bindinfo;
25042d384baSderaadt ysd->dom_server_addr.sin_port =
251a667b8f7Schristos bn->ypbind_binding_port;
25242d384baSderaadt ysd->dom_server_addr.sin_addr.s_addr =
253a667b8f7Schristos bn->ypbind_binding_addr.s_addr;
25442d384baSderaadt ysd->dom_server_port =
255a667b8f7Schristos bn->ypbind_binding_port;
25642d384baSderaadt gotit:
25742d384baSderaadt ysd->dom_vers = YPVERS;
2589134efabSitojun (void)strlcpy(ysd->dom_domain, dom, sizeof(ysd->dom_domain));
25942d384baSderaadt }
26042d384baSderaadt if (ysd->dom_client)
26142d384baSderaadt clnt_destroy(ysd->dom_client);
26242d384baSderaadt ysd->dom_socket = RPC_ANYSOCK;
26342d384baSderaadt ysd->dom_client = clntudp_create(&ysd->dom_server_addr,
264ac6352fdSthorpej YPPROG, YPVERS, _yplib_rpc_timeout, &ysd->dom_socket);
26542d384baSderaadt if (ysd->dom_client == NULL) {
26642d384baSderaadt clnt_pcreateerror("clntudp_create");
26742d384baSderaadt ysd->dom_vers = -1;
26842d384baSderaadt goto again;
26942d384baSderaadt }
27095c7627cSchristos if (fcntl(ysd->dom_socket, F_SETFD, FD_CLOEXEC) == -1)
27142d384baSderaadt perror("fcntl: F_SETFD");
27242d384baSderaadt
27342d384baSderaadt if (new) {
27442d384baSderaadt ysd->dom_pnext = _ypbindlist;
27542d384baSderaadt _ypbindlist = ysd;
27642d384baSderaadt }
27742d384baSderaadt if (ypdb != NULL)
27842d384baSderaadt *ypdb = ysd;
27942d384baSderaadt return 0;
28042d384baSderaadt }
28142d384baSderaadt
2827808771dSjtc void
__yp_unbind(struct dom_binding * ypb)2838147d218Smatt __yp_unbind(struct dom_binding *ypb)
28442d384baSderaadt {
285b48252f3Slukem
286b48252f3Slukem _DIAGASSERT(ypb != NULL);
287b48252f3Slukem
28842d384baSderaadt clnt_destroy(ypb->dom_client);
28942d384baSderaadt ypb->dom_client = NULL;
29042d384baSderaadt ypb->dom_socket = -1;
29142d384baSderaadt }
29242d384baSderaadt
29342d384baSderaadt int
yp_bind(const char * dom)2948147d218Smatt yp_bind(const char *dom)
29542d384baSderaadt {
29642736edbSlukem if (_yp_invalid_domain(dom))
29742736edbSlukem return YPERR_BADARGS;
29842736edbSlukem
29942d384baSderaadt return _yp_dobind(dom, NULL);
30042d384baSderaadt }
30142d384baSderaadt
30242d384baSderaadt void
yp_unbind(const char * dom)3038147d218Smatt yp_unbind(const char *dom)
30442d384baSderaadt {
30542d384baSderaadt struct dom_binding *ypb, *ypbp;
30642d384baSderaadt
30742736edbSlukem if (_yp_invalid_domain(dom))
30842736edbSlukem return;
30942736edbSlukem
31042d384baSderaadt ypbp = NULL;
31142d384baSderaadt for (ypb = _ypbindlist; ypb; ypb = ypb->dom_pnext) {
31242d384baSderaadt if (strcmp(dom, ypb->dom_domain) == 0) {
31342d384baSderaadt clnt_destroy(ypb->dom_client);
31442d384baSderaadt if (ypbp)
31542d384baSderaadt ypbp->dom_pnext = ypb->dom_pnext;
31642d384baSderaadt else
31742d384baSderaadt _ypbindlist = ypb->dom_pnext;
31842d384baSderaadt free(ypb);
31942d384baSderaadt return;
32042d384baSderaadt }
32142d384baSderaadt ypbp = ypb;
32242d384baSderaadt }
32342d384baSderaadt return;
32442d384baSderaadt }
32542d384baSderaadt
32642d384baSderaadt int
yp_get_default_domain(char ** domp)3278147d218Smatt yp_get_default_domain(char **domp)
32842d384baSderaadt {
329b48252f3Slukem if (domp == NULL)
330b48252f3Slukem return YPERR_BADARGS;
33142d384baSderaadt *domp = NULL;
33242d384baSderaadt if (_yp_domain[0] == '\0')
33342d384baSderaadt if (getdomainname(_yp_domain, sizeof _yp_domain))
33442d384baSderaadt return YPERR_NODOM;
33542d384baSderaadt *domp = _yp_domain;
33642d384baSderaadt return 0;
33742d384baSderaadt }
33842d384baSderaadt
33942d384baSderaadt int
_yp_check(char ** dom)3408147d218Smatt _yp_check(char **dom)
34142d384baSderaadt {
34242d384baSderaadt char *unused;
34304562cacSchristos int good;
34404562cacSchristos
34504562cacSchristos YPLOCK();
34642d384baSderaadt
34742d384baSderaadt if (_yp_domain[0] == '\0')
34804562cacSchristos if (yp_get_default_domain(&unused)) {
34904562cacSchristos good = 0;
35004562cacSchristos goto done;
35104562cacSchristos }
35242d384baSderaadt if (dom)
35342d384baSderaadt *dom = _yp_domain;
35442d384baSderaadt
35504562cacSchristos good = yp_bind(_yp_domain) == 0;
35604562cacSchristos done:
35704562cacSchristos YPUNLOCK();
35804562cacSchristos return good;
35942d384baSderaadt }
36042736edbSlukem
36142736edbSlukem /*
36223d6c4faSlukem * _yp_invalid_domain: check if given domainname isn't legal.
36342736edbSlukem * returns non-zero if invalid
36442736edbSlukem */
36542736edbSlukem int
_yp_invalid_domain(const char * dom)3668147d218Smatt _yp_invalid_domain(const char *dom)
36742736edbSlukem {
36842736edbSlukem if (dom == NULL || *dom == '\0')
36942736edbSlukem return 1;
37042736edbSlukem
37123d6c4faSlukem if (strlen(dom) > YPMAXDOMAIN)
37223d6c4faSlukem return 1;
37342736edbSlukem
37423d6c4faSlukem if (strchr(dom, '/') != NULL)
37542736edbSlukem return 1;
37623d6c4faSlukem
37742736edbSlukem return 0;
37842736edbSlukem }
379