GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/yp/yp_bind.c Lines: 0 133 0.0 %
Date: 2017-11-07 Branches: 0 88 0.0 %

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