1 /* @(#)portmap.c 2.3 88/08/11 4.0 RPCSRC */
3 static char sccsid
[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro";
7 * Copyright (c) 1984 by Sun Microsystems, Inc.
11 * portmap.c, Implements the program,version to port number mapping for
16 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
17 * unrestricted use provided that this legend is included on all tape
18 * media and as a part of the software program in whole or part. Users
19 * may copy or modify Sun RPC without charge, but are not authorized
20 * to license or distribute it to anyone else except as part of a product or
21 * program developed by the user.
23 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
24 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
27 * Sun RPC is provided with no support and without any obligation on the
28 * part of Sun Microsystems, Inc. to assist in its use, correction,
29 * modification or enhancement.
31 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
32 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
33 * OR ANY PART THEREOF.
35 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
36 * or profits or other special, indirect and consequential damages, even if
37 * Sun has been advised of the possibility of such damages.
39 * Sun Microsystems, Inc.
41 * Mountain View, California 94043
45 #include <rpc/pmap_prot.h>
48 #include <sys/socket.h>
49 #include <sys/ioctl.h>
51 #include <sys/signal.h>
56 struct pmaplist
*pmaplist
;
57 static int debugging
= 0;
63 struct sockaddr_in addr
;
64 int len
= sizeof(struct sockaddr_in
);
65 register struct pmaplist
*pml
;
70 perror("portmap: fork");
75 for (t
= 0; t
< 20; t
++)
80 t
= open("/dev/tty", 2);
82 ioctl(t
, TIOCNOTTY
, (char *)0);
86 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) < 0) {
87 perror("portmap cannot create socket");
91 addr
.sin_addr
.s_addr
= 0;
92 addr
.sin_family
= AF_INET
;
93 addr
.sin_port
= htons(PMAPPORT
);
94 if (bind(sock
, (struct sockaddr
*)&addr
, len
) != 0) {
95 perror("portmap cannot bind");
99 if ((xprt
= svcudp_create(sock
)) == (SVCXPRT
*)NULL
) {
100 fprintf(stderr
, "couldn't do udp_create\n");
103 /* make an entry for ourself */
104 pml
= (struct pmaplist
*)malloc((u_int
)sizeof(struct pmaplist
));
106 pml
->pml_map
.pm_prog
= PMAPPROG
;
107 pml
->pml_map
.pm_vers
= PMAPVERS
;
108 pml
->pml_map
.pm_prot
= IPPROTO_UDP
;
109 pml
->pml_map
.pm_port
= PMAPPORT
;
112 if ((sock
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
)) < 0) {
113 perror("portmap cannot create socket");
116 if (bind(sock
, (struct sockaddr
*)&addr
, len
) != 0) {
117 perror("portmap cannot bind");
120 if ((xprt
= svctcp_create(sock
, RPCSMALLMSGSIZE
, RPCSMALLMSGSIZE
))
121 == (SVCXPRT
*)NULL
) {
122 fprintf(stderr
, "couldn't do tcp_create\n");
125 /* make an entry for ourself */
126 pml
= (struct pmaplist
*)malloc((u_int
)sizeof(struct pmaplist
));
127 pml
->pml_map
.pm_prog
= PMAPPROG
;
128 pml
->pml_map
.pm_vers
= PMAPVERS
;
129 pml
->pml_map
.pm_prot
= IPPROTO_TCP
;
130 pml
->pml_map
.pm_port
= PMAPPORT
;
131 pml
->pml_next
= pmaplist
;
134 (void)svc_register(xprt
, PMAPPROG
, PMAPVERS
, reg_service
, FALSE
);
136 (void)signal(SIGCHLD
, reap
);
138 fprintf(stderr
, "run_svc returned unexpectedly\n");
142 static struct pmaplist
*
143 find_service(prog
, vers
, prot
)
147 register struct pmaplist
*hit
= NULL
;
148 register struct pmaplist
*pml
;
150 for (pml
= pmaplist
; pml
!= NULL
; pml
= pml
->pml_next
) {
151 if ((pml
->pml_map
.pm_prog
!= prog
) ||
152 (pml
->pml_map
.pm_prot
!= prot
))
155 if (pml
->pml_map
.pm_vers
== vers
)
164 reg_service(rqstp
, xprt
)
165 struct svc_req
*rqstp
;
169 struct pmaplist
*pml
, *prevpml
, *fnd
;
174 fprintf(stderr
, "server: about do a switch\n");
176 switch (rqstp
->rq_proc
) {
182 if ((!svc_sendreply(xprt
, xdr_void
, NULL
)) && debugging
) {
189 * Set a program,version to port mapping
191 if (!svc_getargs(xprt
, xdr_pmap
, ®
))
195 * check to see if already used
196 * find_service returns a hit even if
197 * the versions don't match, so check for it
199 fnd
= find_service(reg
.pm_prog
, reg
.pm_vers
, reg
.pm_prot
);
200 if (fnd
&& fnd
->pml_map
.pm_vers
== reg
.pm_vers
) {
201 if (fnd
->pml_map
.pm_port
== reg
.pm_port
) {
213 pml
= (struct pmaplist
*)
214 malloc((u_int
)sizeof(struct pmaplist
));
220 for (fnd
= pmaplist
; fnd
->pml_next
!= 0;
221 fnd
= fnd
->pml_next
);
227 if ((!svc_sendreply(xprt
, xdr_long
, (caddr_t
)&ans
)) &&
229 fprintf(stderr
, "svc_sendreply\n");
237 * Remove a program,version to port mapping.
239 if (!svc_getargs(xprt
, xdr_pmap
, ®
))
243 for (prevpml
= NULL
, pml
= pmaplist
; pml
!= NULL
; ) {
244 if ((pml
->pml_map
.pm_prog
!= reg
.pm_prog
) ||
245 (pml
->pml_map
.pm_vers
!= reg
.pm_vers
)) {
246 /* both pml & prevpml move forwards */
251 /* found it; pml moves forward, prevpml stays */
258 prevpml
->pml_next
= pml
;
261 if ((!svc_sendreply(xprt
, xdr_long
, (caddr_t
)&ans
)) &&
263 fprintf(stderr
, "svc_sendreply\n");
269 case PMAPPROC_GETPORT
:
271 * Lookup the mapping for a program,version and return its port
273 if (!svc_getargs(xprt
, xdr_pmap
, ®
))
276 fnd
= find_service(reg
.pm_prog
, reg
.pm_vers
, reg
.pm_prot
);
278 port
= fnd
->pml_map
.pm_port
;
281 if ((!svc_sendreply(xprt
, xdr_long
, (caddr_t
)&port
)) &&
283 fprintf(stderr
, "svc_sendreply\n");
291 * Return the current set of mapped program,version
293 if (!svc_getargs(xprt
, xdr_void
, NULL
))
296 if ((!svc_sendreply(xprt
, xdr_pmaplist
,
297 (caddr_t
)&pmaplist
)) && debugging
) {
298 fprintf(stderr
, "svc_sendreply\n");
304 case PMAPPROC_CALLIT
:
306 * Calls a procedure on the local machine. If the requested
307 * procedure is not registered this procedure does not return
308 * error information!!
309 * This procedure is only supported on rpc/udp and calls via
310 * rpc/udp. It passes null authentication parameters.
323 * Stuff for the rmtcall service
327 typedef struct encap_parms
{
333 xdr_encap_parms(xdrs
, epp
)
335 struct encap_parms
*epp
;
338 return (xdr_bytes(xdrs
, &(epp
->args
), &(epp
->arglen
), ARGSIZE
));
341 typedef struct rmtcallargs
{
346 struct encap_parms rmt_args
;
350 xdr_rmtcall_args(xdrs
, cap
)
352 register struct rmtcallargs
*cap
;
355 /* does not get a port number */
356 if (xdr_u_long(xdrs
, &(cap
->rmt_prog
)) &&
357 xdr_u_long(xdrs
, &(cap
->rmt_vers
)) &&
358 xdr_u_long(xdrs
, &(cap
->rmt_proc
))) {
359 return (xdr_encap_parms(xdrs
, &(cap
->rmt_args
)));
365 xdr_rmtcall_result(xdrs
, cap
)
367 register struct rmtcallargs
*cap
;
369 if (xdr_u_long(xdrs
, &(cap
->rmt_port
)))
370 return (xdr_encap_parms(xdrs
, &(cap
->rmt_args
)));
375 * only worries about the struct encap_parms part of struct rmtcallargs.
376 * The arglen must already be set!!
379 xdr_opaque_parms(xdrs
, cap
)
381 struct rmtcallargs
*cap
;
384 return (xdr_opaque(xdrs
, cap
->rmt_args
.args
, cap
->rmt_args
.arglen
));
388 * This routine finds and sets the length of incoming opaque paraters
389 * and then calls xdr_opaque_parms.
392 xdr_len_opaque_parms(xdrs
, cap
)
394 struct rmtcallargs
*cap
;
396 register u_int beginpos
, lowpos
, highpos
, currpos
, pos
;
398 beginpos
= lowpos
= pos
= xdr_getpos(xdrs
);
399 highpos
= lowpos
+ ARGSIZE
;
400 while ((int)(highpos
- lowpos
) >= 0) {
401 currpos
= (lowpos
+ highpos
) / 2;
402 if (xdr_setpos(xdrs
, currpos
)) {
404 lowpos
= currpos
+ 1;
406 highpos
= currpos
- 1;
409 xdr_setpos(xdrs
, beginpos
);
410 cap
->rmt_args
.arglen
= pos
- beginpos
;
411 return (xdr_opaque_parms(xdrs
, cap
));
415 * Call a remote procedure service
416 * This procedure is very quiet when things go wrong.
417 * The proc is written to support broadcast rpc. In the broadcast case,
418 * a machine should shut-up instead of complain, less the requestor be
419 * overrun with complaints at the expense of not hearing a valid reply ...
421 * This now forks so that the program & process that it calls can call
422 * back to the portmapper.
426 struct svc_req
*rqstp
;
429 struct rmtcallargs a
;
430 struct pmaplist
*pml
;
432 struct sockaddr_in me
;
433 int pid
, socket
= -1;
435 struct authunix_parms
*au
= (struct authunix_parms
*)rqstp
->rq_clntcred
;
436 struct timeval timeout
;
441 a
.rmt_args
.args
= buf
;
442 if (!svc_getargs(xprt
, xdr_rmtcall_args
, &a
))
444 if ((pml
= find_service(a
.rmt_prog
, a
.rmt_vers
, IPPROTO_UDP
)) == NULL
)
447 * fork a child to do the work. Parent immediately returns.
448 * Child exits upon completion.
450 if ((pid
= fork()) != 0) {
451 if (debugging
&& (pid
< 0)) {
452 fprintf(stderr
, "portmap CALLIT: cannot fork.\n");
456 port
= pml
->pml_map
.pm_port
;
458 me
.sin_port
= htons(port
);
459 client
= clntudp_create(&me
, a
.rmt_prog
, a
.rmt_vers
, timeout
, &socket
);
460 if (client
!= (CLIENT
*)NULL
) {
461 if (rqstp
->rq_cred
.oa_flavor
== AUTH_UNIX
) {
462 client
->cl_auth
= authunix_create(au
->aup_machname
,
463 au
->aup_uid
, au
->aup_gid
, au
->aup_len
, au
->aup_gids
);
465 a
.rmt_port
= (u_long
)port
;
466 if (clnt_call(client
, a
.rmt_proc
, xdr_opaque_parms
, &a
,
467 xdr_len_opaque_parms
, &a
, timeout
) == RPC_SUCCESS
) {
468 svc_sendreply(xprt
, xdr_rmtcall_result
, &a
);
470 AUTH_DESTROY(client
->cl_auth
);
471 clnt_destroy(client
);
480 while (wait3(NULL
, WNOHANG
, NULL
) > 0);