Merge up from branch.
[shibboleth/cpp-sp.git] / oncrpc / pmap_rmt.c
1 /*********************************************************************
2  * RPC for the Windows NT Operating System
3  * 1993 by Martin F. Gergeleit
4  * Users may use, copy or modify Sun RPC for the Windows NT Operating 
5  * System according to the Sun copyright below.
6  *
7  * RPC for the Windows NT Operating System COMES WITH ABSOLUTELY NO 
8  * WARRANTY, NOR WILL I BE LIABLE FOR ANY DAMAGES INCURRED FROM THE 
9  * USE OF. USE ENTIRELY AT YOUR OWN RISK!!!
10  *********************************************************************/
11 /* @(#)pmap_rmt.c       2.2 88/08/01 4.0 RPCSRC */
12 /*
13  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
14  * unrestricted use provided that this legend is included on all tape
15  * media and as a part of the software program in whole or part.  Users
16  * may copy or modify Sun RPC without charge, but are not authorized
17  * to license or distribute it to anyone else except as part of a product or
18  * program developed by the user.
19  *
20  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
21  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
23  *
24  * Sun RPC is provided with no support and without any obligation on the
25  * part of Sun Microsystems, Inc. to assist in its use, correction,
26  * modification or enhancement.
27  *
28  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
29  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
30  * OR ANY PART THEREOF.
31  *
32  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
33  * or profits or other special, indirect and consequential damages, even if
34  * Sun has been advised of the possibility of such damages.
35  *
36  * Sun Microsystems, Inc.
37  * 2550 Garcia Avenue
38  * Mountain View, California  94043
39  */
40 #if !defined(lint) && defined(SCCSIDS)
41 static char sccsid[] = "@(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro";
42 #endif
43
44 /*
45  * pmap_rmt.c
46  * Client interface to pmap rpc service.
47  * remote call and broadcast service
48  *
49  * Copyright (C) 1984, Sun Microsystems, Inc.
50  */
51
52 #include <rpc/rpc.h>
53 #ifdef WIN32
54 #include <rpc/pmap_prot.h>
55 #include <rpc/pmap_clnt.h>
56 #include <rpc/pmap_rmt.h>
57 #include <stdio.h>
58 #include <errno.h>
59 #define MAX_BROADCAST_SIZE 1400
60 #else
61 #include <rpc/pmap_prot.h>
62 #include <rpc/pmap_clnt.h>
63 #include <rpc/pmap_rmt.h>
64 #include <sys/socket.h>
65 #include <stdio.h>
66 #include <errno.h>
67 #include <net/if.h>
68 #include <sys/ioctl.h>
69 #include <arpa/inet.h>
70 #define MAX_BROADCAST_SIZE 1400
71
72 #ifndef SIOCGIFCONF
73 #include <sys/sockio.h>
74 #endif
75
76 extern int errno;
77 #endif
78 static struct timeval timeout = { 3, 0 };
79
80
81 /*
82  * pmapper remote-call-service interface.
83  * This routine is used to call the pmapper remote call service
84  * which will look up a service program in the port maps, and then
85  * remotely call that routine with the given parameters.  This allows
86  * programs to do a lookup and call in one step.
87 */
88 enum clnt_stat
89 pmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_ptr)
90         struct sockaddr_in *addr;
91         u_long prog, vers, proc;
92         xdrproc_t xdrargs, xdrres;
93         caddr_t argsp, resp;
94         struct timeval tout;
95         u_long *port_ptr;
96 {
97         int socket = -1;
98         register CLIENT *client;
99         struct rmtcallargs a;
100         struct rmtcallres r;
101         enum clnt_stat stat;
102
103         addr->sin_port = htons(PMAPPORT);
104         client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &socket);
105         if (client != (CLIENT *)NULL) {
106                 a.prog = prog;
107                 a.vers = vers;
108                 a.proc = proc;
109                 a.args_ptr = argsp;
110                 a.xdr_args = xdrargs;
111                 r.port_ptr = port_ptr;
112                 r.results_ptr = resp;
113                 r.xdr_results = xdrres;
114                 stat = CLNT_CALL(client, PMAPPROC_CALLIT, xdr_rmtcall_args, &a,
115                     xdr_rmtcallres, &r, tout);
116                 CLNT_DESTROY(client);
117         } else {
118                 stat = RPC_FAILED;
119         }
120 #ifdef WIN32
121         (void)closesocket(socket);
122 #else
123         (void)close(socket);
124 #endif
125         addr->sin_port = 0;
126         return (stat);
127 }
128
129
130 /*
131  * XDR remote call arguments
132  * written for XDR_ENCODE direction only
133  */
134 bool_t
135 xdr_rmtcall_args(xdrs, cap)
136         register XDR *xdrs;
137         register struct rmtcallargs *cap;
138 {
139         u_int lenposition, argposition, position;
140
141         if (xdr_u_long(xdrs, &(cap->prog)) &&
142             xdr_u_long(xdrs, &(cap->vers)) &&
143             xdr_u_long(xdrs, &(cap->proc))) {
144                 lenposition = XDR_GETPOS(xdrs);
145                 if (! xdr_u_long(xdrs, &(cap->arglen)))
146                     return (FALSE);
147                 argposition = XDR_GETPOS(xdrs);
148                 if (! (*(cap->xdr_args))(xdrs, cap->args_ptr))
149                     return (FALSE);
150                 position = XDR_GETPOS(xdrs);
151                 cap->arglen = (u_long)position - (u_long)argposition;
152                 XDR_SETPOS(xdrs, lenposition);
153                 if (! xdr_u_long(xdrs, &(cap->arglen)))
154                     return (FALSE);
155                 XDR_SETPOS(xdrs, position);
156                 return (TRUE);
157         }
158         return (FALSE);
159 }
160
161 /*
162  * XDR remote call results
163  * written for XDR_DECODE direction only
164  */
165 bool_t
166 xdr_rmtcallres(xdrs, crp)
167         register XDR *xdrs;
168         register struct rmtcallres *crp;
169 {
170         caddr_t port_ptr;
171
172         port_ptr = (caddr_t)crp->port_ptr;
173         if (xdr_reference(xdrs, &port_ptr, sizeof (u_long),
174             xdr_u_long) && xdr_u_long(xdrs, &crp->resultslen)) {
175                 crp->port_ptr = (u_long *)port_ptr;
176                 return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
177         }
178         return (FALSE);
179 }
180
181
182 /*
183  * The following is kludged-up support for simple rpc broadcasts.
184  * Someday a large, complicated system will replace these trivial
185  * routines which only support udp/ip .
186  */
187
188 static int
189 getbroadcastnets(addrs, sock, buf)
190         struct in_addr *addrs;
191         int sock;  /* any valid socket will do */
192         char *buf;  /* why allocxate more when we can use existing... */
193 {
194 #ifdef WIN32
195         /* try to do a global broadcast, this is not a clean solution */
196         addrs[0].s_addr = INADDR_BROADCAST;
197         return 1;
198
199         /* was return 0 in version 1.04 */
200
201 #else
202         struct ifconf ifc;
203         struct ifreq ifreq, *ifr;
204         struct sockaddr_in *sin;
205         int n, i;
206
207         ifc.ifc_len = UDPMSGSIZE;
208         ifc.ifc_buf = buf;
209         if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
210                 perror("broadcast: ioctl (get interface configuration)");
211                 return (0);
212         }
213         ifr = ifc.ifc_req;
214         for (i = 0, n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) {
215                 ifreq = *ifr;
216                 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
217                         perror("broadcast: ioctl (get interface flags)");
218                         continue;
219                 }
220                 if ((ifreq.ifr_flags & IFF_BROADCAST) &&
221                     (ifreq.ifr_flags & IFF_UP) &&
222                     ifr->ifr_addr.sa_family == AF_INET) {
223                         sin = (struct sockaddr_in *)&ifr->ifr_addr;
224 #ifdef SIOCGIFBRDADDR   /* 4.3BSD */
225                         if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
226                                 addrs[i++] = inet_makeaddr(inet_netof
227                             (sin->sin_addr), INADDR_ANY);
228                         } else {
229                                 addrs[i++] = ((struct sockaddr_in*)
230                                   &ifreq.ifr_addr)->sin_addr;
231                         }
232 #else /* 4.2 BSD */
233                         addrs[i++] = inet_makeaddr(inet_netof
234                           (sin->sin_addr.s_addr), INADDR_ANY);
235 #endif
236                 }
237         }
238         return (i);
239 #endif
240 }
241
242 typedef bool_t (*resultproc_t)();
243
244 enum clnt_stat
245 clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult)
246         u_long          prog;           /* program number */
247         u_long          vers;           /* version number */
248         u_long          proc;           /* procedure number */
249         xdrproc_t       xargs;          /* xdr routine for args */
250         caddr_t         argsp;          /* pointer to args */
251         xdrproc_t       xresults;       /* xdr routine for results */
252         caddr_t         resultsp;       /* pointer to results */
253         resultproc_t    eachresult;     /* call with each result obtained */
254 {
255         enum clnt_stat stat;
256         AUTH *unix_auth = authunix_create_default();
257         XDR xdr_stream;
258         register XDR *xdrs = &xdr_stream;
259         int outlen, inlen, fromlen, nets;
260         register int sock;
261         int on = 1;
262 #ifdef FD_SETSIZE
263         fd_set mask;
264         fd_set readfds;
265 #else
266         int readfds;
267         register int mask;
268 #endif /* def FD_SETSIZE */
269         register int i;
270         bool_t done = FALSE;
271         register u_long xid;
272         u_long port;
273         struct in_addr addrs[20];
274         struct sockaddr_in baddr, raddr; /* broadcast and response addresses */
275         struct rmtcallargs a;
276         struct rmtcallres r;
277         struct rpc_msg msg;
278         struct timeval t;
279         char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE];
280
281         /*
282          * initialization: create a socket, a broadcast address, and
283          * preserialize the arguments into a send buffer.
284          */
285 #ifdef WIN32
286         if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
287 #else
288         if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
289 #endif
290                 perror("Cannot create socket for broadcast rpc");
291                 stat = RPC_CANTSEND;
292                 goto done_broad;
293         }
294 #ifdef SO_BROADCAST
295         if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
296                 perror("Cannot set socket option SO_BROADCAST");
297                 stat = RPC_CANTSEND;
298                 goto done_broad;
299         }
300 #endif /* def SO_BROADCAST */
301 #ifdef FD_SETSIZE
302         FD_ZERO(&mask);
303         FD_SET(sock, &mask);
304 #else
305         mask = (1 << sock);
306 #endif /* def FD_SETSIZE */
307         nets = getbroadcastnets(addrs, sock, inbuf);
308         bzero((char *)&baddr, sizeof (baddr));
309         baddr.sin_family = AF_INET;
310         baddr.sin_port = htons(PMAPPORT);
311         baddr.sin_addr.s_addr = htonl(INADDR_ANY);
312 /*      baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */
313         (void)gettimeofday(&t, (struct timezone *)0);
314         msg.rm_xid = xid = getpid() ^ t.tv_sec ^ t.tv_usec;
315         t.tv_usec = 0;
316         msg.rm_direction = CALL;
317         msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
318         msg.rm_call.cb_prog = PMAPPROG;
319         msg.rm_call.cb_vers = PMAPVERS;
320         msg.rm_call.cb_proc = PMAPPROC_CALLIT;
321         msg.rm_call.cb_cred = unix_auth->ah_cred;
322         msg.rm_call.cb_verf = unix_auth->ah_verf;
323         a.prog = prog;
324         a.vers = vers;
325         a.proc = proc;
326         a.xdr_args = xargs;
327         a.args_ptr = argsp;
328         r.port_ptr = &port;
329         r.xdr_results = xresults;
330         r.results_ptr = resultsp;
331         xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
332         if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) {
333                 stat = RPC_CANTENCODEARGS;
334                 goto done_broad;
335         }
336         outlen = (int)xdr_getpos(xdrs);
337         xdr_destroy(xdrs);
338         /*
339          * Basic loop: broadcast a packet and wait a while for response(s).
340          * The response timeout grows larger per iteration.
341          */
342         for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) {
343                 for (i = 0; i < nets; i++) {
344                         baddr.sin_addr = addrs[i];
345                         if (sendto(sock, outbuf, outlen, 0,
346                                 (struct sockaddr *)&baddr,
347                                 sizeof (struct sockaddr)) != outlen) {
348                                 perror("Cannot send broadcast packet");
349                                 stat = RPC_CANTSEND;
350                                 goto done_broad;
351                         }
352                 }
353                 if (eachresult == NULL) {
354                         stat = RPC_SUCCESS;
355                         goto done_broad;
356                 }
357         recv_again:
358                 msg.acpted_rply.ar_verf = _null_auth;
359                 msg.acpted_rply.ar_results.where = (caddr_t)&r;
360                 msg.acpted_rply.ar_results.proc = xdr_rmtcallres;
361                 readfds = mask;
362 #ifdef WIN32
363                 switch (select(0 /* unused in winsock */, &readfds, (int *)NULL, (int*)NULL,
364 #else
365                 switch (select(FD_SETSIZE, &readfds, NULL, NULL,
366 #endif
367                                &t)) {
368                 case 0:  /* timed out */
369                         stat = RPC_TIMEDOUT;
370                         continue;
371
372                 case -1:  /* some kind of error */
373 #ifdef WIN32
374                         if (WSAerrno == EINTR)
375 #else
376                         if (errno == EINTR)
377 #endif
378                                 goto recv_again;
379                         perror("Broadcast select problem");
380                         stat = RPC_CANTRECV;
381                         goto done_broad;
382
383                 }  /* end of select results switch */
384         try_again:
385                 fromlen = sizeof(struct sockaddr);
386                 inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0,
387                         (struct sockaddr *)&raddr, &fromlen);
388                 if (inlen < 0) {
389 #ifdef WIN32
390                         if (WSAerrno == EINTR)
391 #else
392                         if (errno == EINTR)
393 #endif
394                                 goto try_again;
395                         perror("Cannot receive reply to broadcast");
396                         stat = RPC_CANTRECV;
397                         goto done_broad;
398                 }
399                 if (inlen < sizeof(u_long))
400                         goto recv_again;
401                 /*
402                  * see if reply transaction id matches sent id.
403                  * If so, decode the results.
404                  */
405                 xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE);
406                 if (xdr_replymsg(xdrs, &msg)) {
407                         if ((msg.rm_xid == xid) &&
408                                 (msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
409                                 (msg.acpted_rply.ar_stat == SUCCESS)) {
410                                 raddr.sin_port = htons((u_short)port);
411                                 done = (*eachresult)(resultsp, &raddr);
412                         }
413                         /* otherwise, we just ignore the errors ... */
414                 } else {
415 #ifdef notdef
416                         /* some kind of deserialization problem ... */
417                         if (msg.rm_xid == xid)
418 #ifdef WIN32
419                                 nt_rpc_report("Broadcast deserialization problem");
420 #else
421                                 fprintf(stderr, "Broadcast deserialization problem");
422 #endif
423                         /* otherwise, just random garbage */
424 #endif
425                 }
426                 xdrs->x_op = XDR_FREE;
427                 msg.acpted_rply.ar_results.proc = xdr_void;
428                 (void)xdr_replymsg(xdrs, &msg);
429                 (void)(*xresults)(xdrs, resultsp);
430                 xdr_destroy(xdrs);
431                 if (done) {
432                         stat = RPC_SUCCESS;
433                         goto done_broad;
434                 } else {
435                         goto recv_again;
436                 }
437         }
438 done_broad:
439 #ifdef WIN32
440         (void)closesocket(sock);
441 #else
442         (void)close(sock);
443 #endif
444         AUTH_DESTROY(unix_auth);
445         return (stat);
446 }
447