GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/rpc/pmap_rmt.c Lines: 0 165 0.0 %
Date: 2017-11-13 Branches: 0 100 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: pmap_rmt.c,v 1.34 2015/12/28 22:08:18 mmcc Exp $ */
2
3
/*
4
 * Copyright (c) 2010, Oracle America, Inc.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions are
8
 * met:
9
 *
10
 *     * Redistributions of source code must retain the above copyright
11
 *       notice, this list of conditions and the following disclaimer.
12
 *     * Redistributions in binary form must reproduce the above
13
 *       copyright notice, this list of conditions and the following
14
 *       disclaimer in the documentation and/or other materials
15
 *       provided with the distribution.
16
 *     * Neither the name of the "Oracle America, Inc." nor the names of its
17
 *       contributors may be used to endorse or promote products derived
18
 *       from this software without specific prior written permission.
19
 *
20
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23
 *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24
 *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25
 *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
 *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27
 *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
 *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29
 *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30
 *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31
 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
 */
33
34
/*
35
 * pmap_rmt.c
36
 * Client interface to pmap rpc service.
37
 * remote call and broadcast service
38
 */
39
40
#include <rpc/rpc.h>
41
#include <rpc/pmap_prot.h>
42
#include <rpc/pmap_clnt.h>
43
#include <rpc/pmap_rmt.h>
44
#include <sys/socket.h>
45
#include <stdio.h>
46
#include <stdlib.h>
47
#include <unistd.h>
48
#include <errno.h>
49
#include <string.h>
50
#include <net/if.h>
51
#include <sys/ioctl.h>
52
#include <arpa/inet.h>
53
#include <ifaddrs.h>
54
#define MAX_BROADCAST_SIZE 1400
55
56
static struct timeval timeout = { 3, 0 };
57
58
59
/*
60
 * pmapper remote-call-service interface.
61
 * This routine is used to call the pmapper remote call service
62
 * which will look up a service program in the port maps, and then
63
 * remotely call that routine with the given parameters.  This allows
64
 * programs to do a lookup and call in one step.
65
*/
66
enum clnt_stat
67
pmap_rmtcall(struct sockaddr_in *addr, u_long prog, u_long vers, u_long proc,
68
    xdrproc_t xdrargs, caddr_t argsp, xdrproc_t xdrres, caddr_t resp,
69
    struct timeval tout, u_long *port_ptr)
70
{
71
	int sock = -1;
72
	CLIENT *client;
73
	struct rmtcallargs a;
74
	struct rmtcallres r;
75
	enum clnt_stat stat;
76
77
	addr->sin_port = htons(PMAPPORT);
78
	client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &sock);
79
	if (client != NULL) {
80
		a.prog = prog;
81
		a.vers = vers;
82
		a.proc = proc;
83
		a.args_ptr = argsp;
84
		a.xdr_args = xdrargs;
85
		r.port_ptr = port_ptr;
86
		r.results_ptr = resp;
87
		r.xdr_results = xdrres;
88
		stat = CLNT_CALL(client, PMAPPROC_CALLIT, xdr_rmtcall_args, &a,
89
		    xdr_rmtcallres, &r, tout);
90
		CLNT_DESTROY(client);
91
	} else {
92
		stat = RPC_FAILED;
93
	}
94
	addr->sin_port = 0;
95
	return (stat);
96
}
97
98
99
/*
100
 * XDR remote call arguments
101
 * written for XDR_ENCODE direction only
102
 */
103
bool_t
104
xdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap)
105
{
106
	u_int lenposition, argposition, position;
107
108
	if (xdr_u_long(xdrs, &(cap->prog)) &&
109
	    xdr_u_long(xdrs, &(cap->vers)) &&
110
	    xdr_u_long(xdrs, &(cap->proc))) {
111
		lenposition = XDR_GETPOS(xdrs);
112
		if (! xdr_u_long(xdrs, &(cap->arglen)))
113
		    return (FALSE);
114
		argposition = XDR_GETPOS(xdrs);
115
		if (! (*(cap->xdr_args))(xdrs, cap->args_ptr))
116
		    return (FALSE);
117
		position = XDR_GETPOS(xdrs);
118
		cap->arglen = (u_long)position - (u_long)argposition;
119
		XDR_SETPOS(xdrs, lenposition);
120
		if (! xdr_u_long(xdrs, &(cap->arglen)))
121
		    return (FALSE);
122
		XDR_SETPOS(xdrs, position);
123
		return (TRUE);
124
	}
125
	return (FALSE);
126
}
127
DEF_WEAK(xdr_rmtcall_args);
128
129
/*
130
 * XDR remote call results
131
 * written for XDR_DECODE direction only
132
 */
133
bool_t
134
xdr_rmtcallres(XDR *xdrs, struct rmtcallres *crp)
135
{
136
	caddr_t port_ptr;
137
138
	port_ptr = (caddr_t)crp->port_ptr;
139
	if (xdr_reference(xdrs, &port_ptr, sizeof (u_long),
140
	    xdr_u_long) && xdr_u_long(xdrs, &crp->resultslen)) {
141
		crp->port_ptr = (u_long *)port_ptr;
142
		return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
143
	}
144
	return (FALSE);
145
}
146
DEF_WEAK(xdr_rmtcallres);
147
148
149
/*
150
 * The following is kludged-up support for simple rpc broadcasts.
151
 * Someday a large, complicated system will replace these trivial
152
 * routines which only support udp/ip .
153
 */
154
static int
155
newgetbroadcastnets(struct in_addr **addrsp)
156
{
157
	struct ifaddrs *ifap, *ifa;
158
	struct sockaddr_in *sin;
159
	struct in_addr *addrs;
160
	int i = 0, n = 0;
161
162
	if (getifaddrs(&ifap) != 0)
163
		return 0;
164
165
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
166
		if (ifa->ifa_addr->sa_family != AF_INET)
167
			continue;
168
		if ((ifa->ifa_flags & IFF_BROADCAST) &&
169
		    (ifa->ifa_flags & IFF_UP) &&
170
		    ifa->ifa_broadaddr &&
171
		    ifa->ifa_broadaddr->sa_family == AF_INET) {
172
			n++;
173
		}
174
	}
175
176
	addrs = calloc(n, sizeof(*addrs));
177
	if (addrs == NULL) {
178
		freeifaddrs(ifap);
179
		return 0;
180
	}
181
182
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
183
		if (ifa->ifa_addr->sa_family != AF_INET)
184
			continue;
185
		if ((ifa->ifa_flags & IFF_BROADCAST) &&
186
		    (ifa->ifa_flags & IFF_UP) &&
187
		    ifa->ifa_broadaddr &&
188
		    ifa->ifa_broadaddr->sa_family == AF_INET) {
189
			sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
190
			addrs[i++] = sin->sin_addr;
191
		}
192
	}
193
194
	freeifaddrs(ifap);
195
	*addrsp = addrs;
196
	return i;
197
}
198
199
typedef bool_t (*resultproc_t)(caddr_t, struct sockaddr_in *);
200
201
enum clnt_stat
202
clnt_broadcast(u_long prog,	/* program number */
203
    u_long vers,		/* version number */
204
    u_long proc,		/* procedure number */
205
    xdrproc_t xargs,		/* xdr routine for args */
206
    caddr_t argsp,		/* pointer to args */
207
    xdrproc_t xresults,		/* xdr routine for results */
208
    caddr_t resultsp,		/* pointer to results */
209
    resultproc_t eachresult)	/* call with each result obtained */
210
{
211
	enum clnt_stat stat;
212
	AUTH *unix_auth;
213
	XDR xdr_stream;
214
	XDR *xdrs = &xdr_stream;
215
	int outlen, inlen, nets;
216
	socklen_t fromlen;
217
	int sock = -1;
218
	int on = 1;
219
	struct pollfd pfd[1];
220
	int i;
221
	int timo;
222
	bool_t done = FALSE;
223
	u_long xid;
224
	u_long port;
225
	struct in_addr *addrs = NULL;
226
	struct sockaddr_in baddr, raddr; /* broadcast and response addresses */
227
	struct rmtcallargs a;
228
	struct rmtcallres r;
229
	struct rpc_msg msg;
230
	char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE];
231
232
	if ((unix_auth = authunix_create_default()) == NULL) {
233
		stat = RPC_AUTHERROR;
234
		goto done_broad;
235
	}
236
237
	/*
238
	 * initialization: create a socket, a broadcast address, and
239
	 * preserialize the arguments into a send buffer.
240
	 */
241
	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
242
		stat = RPC_CANTSEND;
243
		goto done_broad;
244
	}
245
#ifdef SO_BROADCAST
246
	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
247
		stat = RPC_CANTSEND;
248
		goto done_broad;
249
	}
250
#endif /* def SO_BROADCAST */
251
252
	pfd[0].fd = sock;
253
	pfd[0].events = POLLIN;
254
255
	nets = newgetbroadcastnets(&addrs);
256
	if (nets == 0) {
257
		stat = RPC_CANTSEND;
258
		goto done_broad;
259
	}
260
261
	memset(&baddr, 0, sizeof (baddr));
262
	baddr.sin_len = sizeof(struct sockaddr_in);
263
	baddr.sin_family = AF_INET;
264
	baddr.sin_port = htons(PMAPPORT);
265
	baddr.sin_addr.s_addr = htonl(INADDR_ANY);
266
	msg.rm_xid = xid = arc4random();
267
	msg.rm_direction = CALL;
268
	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
269
	msg.rm_call.cb_prog = PMAPPROG;
270
	msg.rm_call.cb_vers = PMAPVERS;
271
	msg.rm_call.cb_proc = PMAPPROC_CALLIT;
272
	msg.rm_call.cb_cred = unix_auth->ah_cred;
273
	msg.rm_call.cb_verf = unix_auth->ah_verf;
274
	a.prog = prog;
275
	a.vers = vers;
276
	a.proc = proc;
277
	a.xdr_args = xargs;
278
	a.args_ptr = argsp;
279
	r.port_ptr = &port;
280
	r.xdr_results = xresults;
281
	r.results_ptr = resultsp;
282
	xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
283
	if (!xdr_callmsg(xdrs, &msg) || !xdr_rmtcall_args(xdrs, &a)) {
284
		stat = RPC_CANTENCODEARGS;
285
		goto done_broad;
286
	}
287
	outlen = (int)xdr_getpos(xdrs);
288
	xdr_destroy(xdrs);
289
290
	/*
291
	 * Basic loop: broadcast a packet and wait a while for response(s).
292
	 * The response timeout grows larger per iteration.
293
	 *
294
	 * XXX This will loop about 5 times the stop. If there are
295
	 * lots of signals being received by the process it will quit
296
	 * send them all in one quick burst, not paying attention to
297
	 * the intended function of sending them slowly over half a
298
	 * minute or so
299
	 */
300
	for (timo = 4000; timo <= 14000; timo += 2000) {
301
		for (i = 0; i < nets; i++) {
302
			baddr.sin_addr = addrs[i];
303
			if (sendto(sock, outbuf, outlen, 0,
304
			    (struct sockaddr *)&baddr,
305
			    sizeof (struct sockaddr)) != outlen) {
306
				stat = RPC_CANTSEND;
307
				goto done_broad;
308
			}
309
		}
310
		if (eachresult == NULL) {
311
			stat = RPC_SUCCESS;
312
			goto done_broad;
313
		}
314
	recv_again:
315
		msg.acpted_rply.ar_verf = _null_auth;
316
		msg.acpted_rply.ar_results.where = (caddr_t)&r;
317
		msg.acpted_rply.ar_results.proc = xdr_rmtcallres;
318
319
		switch (poll(pfd, 1, timo)) {
320
		case 0:  /* timed out */
321
			stat = RPC_TIMEDOUT;
322
			continue;
323
		case 1:
324
			if (pfd[0].revents & POLLNVAL)
325
				errno = EBADF;
326
			else if (pfd[0].revents & POLLERR)
327
				errno = EIO;
328
			else
329
				break;
330
			/* FALLTHROUGH */
331
		case -1:  /* some kind of error */
332
			if (errno == EINTR)
333
				goto recv_again;
334
			stat = RPC_CANTRECV;
335
			goto done_broad;
336
		}
337
	try_again:
338
		fromlen = sizeof(struct sockaddr);
339
		inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0,
340
		    (struct sockaddr *)&raddr, &fromlen);
341
		if (inlen < 0) {
342
			if (errno == EINTR)
343
				goto try_again;
344
			stat = RPC_CANTRECV;
345
			goto done_broad;
346
		}
347
		if (inlen < sizeof(u_int32_t))
348
			goto recv_again;
349
		/*
350
		 * see if reply transaction id matches sent id.
351
		 * If so, decode the results.
352
		 */
353
		xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE);
354
		if (xdr_replymsg(xdrs, &msg)) {
355
			if ((msg.rm_xid == xid) &&
356
			    (msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
357
			    (msg.acpted_rply.ar_stat == SUCCESS)) {
358
				raddr.sin_port = htons((u_short)port);
359
				done = (*eachresult)(resultsp, &raddr);
360
			}
361
			/* otherwise, we just ignore the errors ... */
362
		}
363
		xdrs->x_op = XDR_FREE;
364
		msg.acpted_rply.ar_results.proc = xdr_void;
365
		(void)xdr_replymsg(xdrs, &msg);
366
		(void)(*xresults)(xdrs, resultsp);
367
		xdr_destroy(xdrs);
368
		if (done) {
369
			stat = RPC_SUCCESS;
370
			goto done_broad;
371
		} else {
372
			goto recv_again;
373
		}
374
	}
375
done_broad:
376
	free(addrs);
377
	if (sock >= 0)
378
		(void)close(sock);
379
	if (unix_auth != NULL)
380
		AUTH_DESTROY(unix_auth);
381
	return (stat);
382
}