xref: /openbsd/lib/libc/yp/yp_bind.c (revision 01a83688)
1 /*
2  * Copyright (c) 1996 Theo de Raadt <deraadt@theos.com>
3  * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by Theo de Raadt.
17  * 4. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
21  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #if defined(LIBC_SCCS) && !defined(lint)
34 static char *rcsid = "$OpenBSD: yp_bind.c,v 1.10 1999/08/17 09:13:13 millert Exp $";
35 #endif /* LIBC_SCCS and not lint */
36 
37 #include <sys/param.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <sys/uio.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <rpc/rpc.h>
48 #include <rpc/xdr.h>
49 #include <rpcsvc/yp.h>
50 #include <rpcsvc/ypclnt.h>
51 #include "ypinternal.h"
52 
53 struct dom_binding *_ypbindlist;
54 char _yp_domain[MAXHOSTNAMELEN];
55 int _yplib_timeout = 10;
56 
57 int
58 _yp_dobind(dom, ypdb)
59 	const char     *dom;
60 	struct dom_binding **ypdb;
61 {
62 	static int      pid = -1;
63 	char            path[MAXPATHLEN];
64 	struct dom_binding *ysd, *ysd2;
65 	struct ypbind_resp ypbr;
66 	struct timeval  tv;
67 	struct sockaddr_in clnt_sin;
68 	struct ypbind_binding *bn;
69 	int             clnt_sock, fd, gpid;
70 	CLIENT         *client;
71 	int             new = 0, r;
72 	int             count = 0;
73 	u_short		port;
74 
75 	/*
76 	 * test if YP is running or not
77 	 */
78 	if ((fd = open(YPBINDLOCK, O_RDONLY)) == -1)
79 		return YPERR_YPBIND;
80 	if (!(flock(fd, LOCK_EX | LOCK_NB) == -1 && errno == EWOULDBLOCK)) {
81 		(void)close(fd);
82 		return YPERR_YPBIND;
83 	}
84 	(void)close(fd);
85 
86 	gpid = getpid();
87 	if (!(pid == -1 || pid == gpid)) {
88 		ysd = _ypbindlist;
89 		while (ysd) {
90 			if (ysd->dom_client)
91 				clnt_destroy(ysd->dom_client);
92 			ysd2 = ysd->dom_pnext;
93 			free(ysd);
94 			ysd = ysd2;
95 		}
96 		_ypbindlist = NULL;
97 	}
98 	pid = gpid;
99 
100 	if (ypdb != NULL)
101 		*ypdb = NULL;
102 
103 	if (dom == NULL || strlen(dom) == 0)
104 		return YPERR_BADARGS;
105 
106 	for (ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext)
107 		if (strcmp(dom, ysd->dom_domain) == 0)
108 			break;
109 	if (ysd == NULL) {
110 		if ((ysd = malloc(sizeof *ysd)) == NULL)
111 			return YPERR_YPERR;
112 		(void)memset(ysd, 0, sizeof *ysd);
113 		ysd->dom_socket = -1;
114 		ysd->dom_vers = 0;
115 		new = 1;
116 	}
117 again:
118 	if (ysd->dom_vers == 0) {
119 		(void) snprintf(path, sizeof(path), "%s/%s.%d",
120 		    BINDINGDIR, dom, 2);
121 		if ((fd = open(path, O_RDONLY)) == -1) {
122 			/*
123 			 * no binding file, YP is dead, or not yet fully
124 			 * alive.
125 			 */
126 			goto trynet;
127 		}
128 		if (flock(fd, LOCK_EX | LOCK_NB) == -1 &&
129 		    errno == EWOULDBLOCK) {
130 			struct iovec    iov[2];
131 			u_short         ypb_port;
132 
133 			/*
134 			 * we fetch the ypbind port number, but do
135 			 * nothing with it.
136 			 */
137 			iov[0].iov_base = (caddr_t) &ypb_port;
138 			iov[0].iov_len = sizeof ypb_port;
139 			iov[1].iov_base = (caddr_t) &ypbr;
140 			iov[1].iov_len = sizeof ypbr;
141 
142 			r = readv(fd, iov, 2);
143 			if (r != iov[0].iov_len + iov[1].iov_len) {
144 				(void)close(fd);
145 				ysd->dom_vers = -1;
146 				goto again;
147 			}
148 			(void)close(fd);
149 			goto gotdata;
150 		} else {
151 			/* no lock on binding file, YP is dead. */
152 			(void)close(fd);
153 			if (new)
154 				free(ysd);
155 			return YPERR_YPBIND;
156 		}
157 	}
158 trynet:
159 	if (ysd->dom_vers == -1 || ysd->dom_vers == 0) {
160 		(void)memset(&clnt_sin, 0, sizeof clnt_sin);
161 		clnt_sin.sin_len = sizeof(struct sockaddr_in);
162 		clnt_sin.sin_family = AF_INET;
163 		clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
164 
165 		clnt_sock = RPC_ANYSOCK;
166 		client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS,
167 		    &clnt_sock, 0, 0);
168 		if (client == NULL) {
169 			clnt_pcreateerror("clnttcp_create");
170 			if (new)
171 				free(ysd);
172 			return YPERR_YPBIND;
173 		}
174 		if (ntohs(clnt_sin.sin_port) >= IPPORT_RESERVED ||
175 		    ntohs(clnt_sin.sin_port) == 20) {
176 			/*
177 			 * YP was not running, but someone has registered
178 			 * ypbind with portmap -- this simply means YP is
179 			 * not running.
180 			 */
181 			clnt_destroy(client);
182 			if (new)
183 				free(ysd);
184 			return YPERR_YPBIND;
185 		}
186 		tv.tv_sec = _yplib_timeout;
187 		tv.tv_usec = 0;
188 		r = clnt_call(client, YPBINDPROC_DOMAIN, xdr_domainname,
189 		    &dom, xdr_ypbind_resp, &ypbr, tv);
190 		if (r != RPC_SUCCESS) {
191 			if (new == 0 || count)
192 				fprintf(stderr,
193 		    "YP server for domain %s not responding, still trying\n",
194 				    dom);
195 			count++;
196 			clnt_destroy(client);
197 			ysd->dom_vers = -1;
198 			goto again;
199 		}
200 		clnt_destroy(client);
201 gotdata:
202 		bn = &ypbr.ypbind_resp_u.ypbind_bindinfo;
203 		memcpy(&port, &bn->ypbind_binding_port, sizeof port);
204 		if (ntohs(port) >= IPPORT_RESERVED ||
205 		    ntohs(port) == 20) {
206 			/*
207 			 * This is bullshit -- the ypbind wants me to
208 			 * communicate to an insecure ypserv.  We are
209 			 * within rights to syslog this as an attack,
210 			 * but for now we'll simply ignore it; real YP
211 			 * is obviously not running.
212 			 */
213 			if (new)
214 				free(ysd);
215 			return YPERR_YPBIND;
216 		}
217 		(void)memset(&ysd->dom_server_addr, 0,
218 		    sizeof ysd->dom_server_addr);
219 		ysd->dom_server_addr.sin_len = sizeof(struct sockaddr_in);
220 		ysd->dom_server_addr.sin_family = AF_INET;
221 		memcpy(&ysd->dom_server_addr.sin_port,
222 		    &bn->ypbind_binding_port,
223 		    sizeof(ysd->dom_server_addr.sin_port));
224 		memcpy(&ysd->dom_server_addr.sin_addr.s_addr,
225 		    &bn->ypbind_binding_addr,
226 		    sizeof(ysd->dom_server_addr.sin_addr.s_addr));
227 		ysd->dom_server_port = ysd->dom_server_addr.sin_port;
228 		ysd->dom_vers = YPVERS;
229 		(void)strncpy(ysd->dom_domain, dom, sizeof ysd->dom_domain-1);
230 		ysd->dom_domain[sizeof ysd->dom_domain-1] = '\0';
231 	}
232 	tv.tv_sec = _yplib_timeout / 2;
233 	tv.tv_usec = 0;
234 	if (ysd->dom_client)
235 		clnt_destroy(ysd->dom_client);
236 	ysd->dom_socket = RPC_ANYSOCK;
237 	ysd->dom_client = clntudp_create(&ysd->dom_server_addr,
238 	    YPPROG, YPVERS, tv, &ysd->dom_socket);
239 	if (ysd->dom_client == NULL) {
240 		clnt_pcreateerror("clntudp_create");
241 		ysd->dom_vers = -1;
242 		goto again;
243 	}
244 	if (fcntl(ysd->dom_socket, F_SETFD, 1) == -1)
245 		perror("fcntl: F_SETFD");
246 
247 	if (new) {
248 		ysd->dom_pnext = _ypbindlist;
249 		_ypbindlist = ysd;
250 	}
251 	if (ypdb != NULL)
252 		*ypdb = ysd;
253 	return 0;
254 }
255 
256 void
257 _yp_unbind(ypb)
258 	struct dom_binding *ypb;
259 {
260 	clnt_destroy(ypb->dom_client);
261 	ypb->dom_client = NULL;
262 	ypb->dom_socket = -1;
263 }
264 
265 int
266 yp_bind(dom)
267 	const char     *dom;
268 {
269 	return _yp_dobind(dom, NULL);
270 }
271 
272 void
273 yp_unbind(dom)
274 	const char     *dom;
275 {
276 	struct dom_binding *ypb, *ypbp;
277 
278 	ypbp = NULL;
279 	for (ypb = _ypbindlist; ypb; ypb = ypb->dom_pnext) {
280 		if (strcmp(dom, ypb->dom_domain) == 0) {
281 			clnt_destroy(ypb->dom_client);
282 			if (ypbp)
283 				ypbp->dom_pnext = ypb->dom_pnext;
284 			else
285 				_ypbindlist = ypb->dom_pnext;
286 			free(ypb);
287 			return;
288 		}
289 		ypbp = ypb;
290 	}
291 }
292