Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/lib/rpc/pmap_rmt.c
39537 views
1
/* @(#)pmap_rmt.c 2.2 88/08/01 4.0 RPCSRC */
2
/*
3
* Copyright (c) 2010, Oracle America, Inc.
4
*
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions are met:
9
*
10
* * Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
*
13
* * Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in
15
* the documentation and/or other materials provided with the
16
* distribution.
17
*
18
* * Neither the name of the "Oracle America, Inc." nor the names of
19
* its contributors may be used to endorse or promote products
20
* derived from this software without specific prior written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
23
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
28
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
*/
34
#if !defined(lint) && defined(SCCSIDS)
35
static char sccsid[] = "@(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro";
36
#endif
37
38
/*
39
* pmap_rmt.c
40
* Client interface to pmap rpc service.
41
* remote call and broadcast service
42
*/
43
44
#include "k5-platform.h"
45
#include <unistd.h>
46
#include <gssrpc/rpc.h>
47
#include <gssrpc/pmap_prot.h>
48
#include <gssrpc/pmap_clnt.h>
49
#include <gssrpc/pmap_rmt.h>
50
#include <sys/socket.h>
51
#ifdef sun
52
#include <sys/sockio.h>
53
#endif
54
#ifdef OSF1
55
#include <net/route.h>
56
#include <sys/mbuf.h>
57
#endif
58
#include <net/if.h>
59
#include <sys/ioctl.h>
60
#include <arpa/inet.h>
61
#define MAX_BROADCAST_SIZE 1400
62
#include <port-sockets.h>
63
#include "socket-utils.h"
64
65
static struct timeval timeout = { 3, 0 };
66
67
#ifndef GETSOCKNAME_ARG3_TYPE
68
#define GETSOCKNAME_ARG3_TYPE int
69
#endif
70
71
/*
72
* pmapper remote-call-service interface.
73
* This routine is used to call the pmapper remote call service
74
* which will look up a service program in the port maps, and then
75
* remotely call that routine with the given parameters. This allows
76
* programs to do a lookup and call in one step.
77
*/
78
enum clnt_stat
79
pmap_rmtcall(
80
struct sockaddr_in *addr,
81
rpcprog_t prog,
82
rpcvers_t vers,
83
rpcproc_t proc,
84
xdrproc_t xdrargs,
85
caddr_t argsp,
86
xdrproc_t xdrres,
87
caddr_t resp,
88
struct timeval tout,
89
rpcport_t *port_ptr)
90
{
91
SOCKET sock = INVALID_SOCKET;
92
CLIENT *client;
93
struct rmtcallargs a;
94
struct rmtcallres r;
95
enum clnt_stat stat;
96
97
addr->sin_port = htons(PMAPPORT);
98
client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &sock);
99
if (client != (CLIENT *)NULL) {
100
a.prog = prog;
101
a.vers = vers;
102
a.proc = proc;
103
a.args_ptr = argsp;
104
a.xdr_args = xdrargs;
105
r.port_ptr = port_ptr;
106
r.results_ptr = resp;
107
r.xdr_results = xdrres;
108
stat = CLNT_CALL(client, PMAPPROC_CALLIT,
109
(xdrproc_t)xdr_rmtcall_args, &a,
110
(xdrproc_t)xdr_rmtcallres, &r, tout);
111
CLNT_DESTROY(client);
112
} else {
113
stat = RPC_FAILED;
114
}
115
(void)closesocket(sock);
116
addr->sin_port = 0;
117
return (stat);
118
}
119
120
121
/*
122
* XDR remote call arguments
123
* written for XDR_ENCODE direction only
124
*/
125
bool_t
126
xdr_rmtcall_args(
127
XDR *xdrs,
128
struct rmtcallargs *cap)
129
{
130
u_int lenposition, argposition, position;
131
132
if (xdr_u_int32(xdrs, &(cap->prog)) &&
133
xdr_u_int32(xdrs, &(cap->vers)) &&
134
xdr_u_int32(xdrs, &(cap->proc))) {
135
lenposition = XDR_GETPOS(xdrs);
136
if (! xdr_u_int32(xdrs, &(cap->arglen)))
137
return (FALSE);
138
argposition = XDR_GETPOS(xdrs);
139
if (! (*(cap->xdr_args))(xdrs, cap->args_ptr))
140
return (FALSE);
141
position = XDR_GETPOS(xdrs);
142
cap->arglen = (uint32_t)position - (uint32_t)argposition;
143
XDR_SETPOS(xdrs, lenposition);
144
if (! xdr_u_int32(xdrs, &(cap->arglen)))
145
return (FALSE);
146
XDR_SETPOS(xdrs, position);
147
return (TRUE);
148
}
149
return (FALSE);
150
}
151
152
/*
153
* XDR remote call results
154
* written for XDR_DECODE direction only
155
*/
156
bool_t
157
xdr_rmtcallres(
158
XDR *xdrs,
159
struct rmtcallres *crp)
160
{
161
caddr_t port_ptr;
162
163
port_ptr = (caddr_t)(void *)crp->port_ptr;
164
if (!xdr_reference(xdrs, &port_ptr, sizeof (uint32_t),
165
(xdrproc_t)xdr_u_int32))
166
return (FALSE);
167
crp->port_ptr = (uint32_t *)(void *)port_ptr;
168
if (xdr_u_int32(xdrs, &crp->resultslen))
169
return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
170
return (FALSE);
171
}
172
173
174
/*
175
* The following is kludged-up support for simple rpc broadcasts.
176
* Someday a large, complicated system will replace these trivial
177
* routines which only support udp/ip .
178
*/
179
180
#define GIFCONF_BUFSIZE (256 * sizeof (struct ifconf))
181
182
static int
183
getbroadcastnets(
184
struct in_addr *addrs,
185
int sock, /* any valid socket will do */
186
char *buf /* why allocxate more when we can use existing... */
187
)
188
{
189
struct ifconf ifc;
190
struct ifreq ifreq, *ifr;
191
int n, i;
192
193
ifc.ifc_len = GIFCONF_BUFSIZE;
194
ifc.ifc_buf = buf;
195
memset (buf, 0, GIFCONF_BUFSIZE);
196
if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
197
perror("broadcast: ioctl (get interface configuration)");
198
return (0);
199
}
200
ifr = ifc.ifc_req;
201
for (i = 0, n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) {
202
ifreq = *ifr;
203
if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
204
perror("broadcast: ioctl (get interface flags)");
205
continue;
206
}
207
if ((ifreq.ifr_flags & IFF_BROADCAST) &&
208
(ifreq.ifr_flags & IFF_UP) &&
209
ifr->ifr_addr.sa_family == AF_INET) {
210
#ifdef SIOCGIFBRDADDR /* 4.3BSD */
211
if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
212
addrs[i++].s_addr = INADDR_ANY;
213
} else {
214
addrs[i++] = sa2sin(&ifreq.ifr_addr)->sin_addr;
215
}
216
#else /* 4.2 BSD */
217
struct sockaddr_in *sockin;
218
sockin = sa2sin(&ifr->ifr_addr);
219
addrs[i++] = inet_makeaddr(inet_netof
220
(sockin->sin_addr.s_addr), INADDR_ANY);
221
#endif
222
}
223
}
224
return (i);
225
}
226
227
enum clnt_stat
228
clnt_broadcast(
229
rpcprog_t prog, /* program number */
230
rpcvers_t vers, /* version number */
231
rpcproc_t proc, /* procedure number */
232
xdrproc_t xargs, /* xdr routine for args */
233
caddr_t argsp, /* pointer to args */
234
xdrproc_t xresults, /* xdr routine for results */
235
caddr_t resultsp, /* pointer to results */
236
resultproc_t eachresult /* call with each result obtained */
237
)
238
{
239
enum clnt_stat stat;
240
AUTH *unix_auth = authunix_create_default();
241
XDR xdr_stream;
242
XDR *xdrs = &xdr_stream;
243
int outlen, nets;
244
ssize_t inlen;
245
GETSOCKNAME_ARG3_TYPE fromlen;
246
SOCKET sock;
247
int on = 1;
248
#ifdef FD_SETSIZE
249
fd_set mask;
250
fd_set readfds;
251
#else
252
int readfds;
253
int mask;
254
#endif /* def FD_SETSIZE */
255
int i;
256
bool_t done = FALSE;
257
uint32_t xid;
258
rpcport_t port;
259
struct in_addr addrs[20];
260
struct sockaddr_in baddr, raddr; /* broadcast and response addresses */
261
struct rmtcallargs a;
262
struct rmtcallres r;
263
struct rpc_msg msg;
264
struct timeval t, t2;
265
char outbuf[MAX_BROADCAST_SIZE];
266
#ifndef MAX
267
#define MAX(A,B) ((A)<(B)?(B):(A))
268
#endif
269
char inbuf[MAX (UDPMSGSIZE, GIFCONF_BUFSIZE)];
270
271
/*
272
* initialization: create a socket, a broadcast address, and
273
* preserialize the arguments into a send buffer.
274
*/
275
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
276
perror("Cannot create socket for broadcast rpc");
277
stat = RPC_CANTSEND;
278
goto done_broad;
279
}
280
set_cloexec_fd(sock);
281
#ifdef SO_BROADCAST
282
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *) &on,
283
sizeof (on)) < 0) {
284
perror("Cannot set socket option SO_BROADCAST");
285
stat = RPC_CANTSEND;
286
goto done_broad;
287
}
288
#endif /* def SO_BROADCAST */
289
#ifdef FD_SETSIZE
290
FD_ZERO(&mask);
291
FD_SET(sock, &mask);
292
#else
293
mask = (1 << sock);
294
#endif /* def FD_SETSIZE */
295
nets = getbroadcastnets(addrs, sock, inbuf);
296
memset(&baddr, 0, sizeof (baddr));
297
baddr.sin_family = AF_INET;
298
baddr.sin_port = htons(PMAPPORT);
299
baddr.sin_addr.s_addr = htonl(INADDR_ANY);
300
/* baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */
301
(void)gettimeofday(&t, (struct timezone *)0);
302
msg.rm_xid = xid = getpid() ^ t.tv_sec ^ t.tv_usec;
303
t.tv_usec = 0;
304
msg.rm_direction = CALL;
305
msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
306
msg.rm_call.cb_prog = PMAPPROG;
307
msg.rm_call.cb_vers = PMAPVERS;
308
msg.rm_call.cb_proc = PMAPPROC_CALLIT;
309
msg.rm_call.cb_cred = unix_auth->ah_cred;
310
msg.rm_call.cb_verf = unix_auth->ah_verf;
311
a.prog = prog;
312
a.vers = vers;
313
a.proc = proc;
314
a.xdr_args = xargs;
315
a.args_ptr = argsp;
316
r.port_ptr = &port;
317
r.xdr_results = xresults;
318
r.results_ptr = resultsp;
319
xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
320
if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) {
321
stat = RPC_CANTENCODEARGS;
322
goto done_broad;
323
}
324
outlen = (int)xdr_getpos(xdrs);
325
xdr_destroy(xdrs);
326
/*
327
* Basic loop: broadcast a packet and wait a while for response(s).
328
* The response timeout grows larger per iteration.
329
*/
330
for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) {
331
for (i = 0; i < nets; i++) {
332
baddr.sin_addr = addrs[i];
333
if (sendto(sock, outbuf, outlen, 0,
334
(struct sockaddr *)&baddr,
335
sizeof (struct sockaddr)) != outlen) {
336
perror("Cannot send broadcast packet");
337
stat = RPC_CANTSEND;
338
goto done_broad;
339
}
340
}
341
if (eachresult == NULL) {
342
stat = RPC_SUCCESS;
343
goto done_broad;
344
}
345
recv_again:
346
msg.acpted_rply.ar_verf = gssrpc__null_auth;
347
msg.acpted_rply.ar_results.where = (caddr_t)&r;
348
msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_rmtcallres;
349
readfds = mask;
350
t2 = t;
351
switch (select(gssrpc__rpc_dtablesize(), &readfds, (fd_set *)NULL,
352
(fd_set *)NULL, &t2)) {
353
354
case 0: /* timed out */
355
stat = RPC_TIMEDOUT;
356
continue;
357
358
case -1: /* some kind of error */
359
if (errno == EINTR)
360
goto recv_again;
361
perror("Broadcast select problem");
362
stat = RPC_CANTRECV;
363
goto done_broad;
364
365
} /* end of select results switch */
366
try_again:
367
fromlen = sizeof(struct sockaddr);
368
inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0,
369
(struct sockaddr *)&raddr, &fromlen);
370
if (inlen < 0) {
371
if (errno == EINTR)
372
goto try_again;
373
perror("Cannot receive reply to broadcast");
374
stat = RPC_CANTRECV;
375
goto done_broad;
376
}
377
if ((size_t)inlen < sizeof(uint32_t))
378
goto recv_again;
379
/*
380
* see if reply transaction id matches sent id.
381
* If so, decode the results.
382
*/
383
xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE);
384
if (xdr_replymsg(xdrs, &msg)) {
385
if ((msg.rm_xid == xid) &&
386
(msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
387
(msg.acpted_rply.ar_stat == SUCCESS)) {
388
raddr.sin_port = htons((u_short)port);
389
done = (*eachresult)(resultsp, &raddr);
390
}
391
/* otherwise, we just ignore the errors ... */
392
} else {
393
#ifdef notdef
394
/* some kind of deserialization problem ... */
395
if (msg.rm_xid == xid)
396
fprintf(stderr, "Broadcast deserialization problem");
397
/* otherwise, just random garbage */
398
#endif
399
}
400
xdrs->x_op = XDR_FREE;
401
msg.acpted_rply.ar_results.proc = xdr_void;
402
(void)xdr_replymsg(xdrs, &msg);
403
(void)(*xresults)(xdrs, resultsp);
404
xdr_destroy(xdrs);
405
if (done) {
406
stat = RPC_SUCCESS;
407
goto done_broad;
408
} else {
409
goto recv_again;
410
}
411
}
412
done_broad:
413
(void)closesocket(sock);
414
AUTH_DESTROY(unix_auth);
415
return (stat);
416
}
417
418