2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * @(#) Copyright (c) 1990, 1993 The Regents of the University of California. All rights reserved.
34 * @(#)portmap.c 8.1 (Berkeley) 6/6/93
35 * $FreeBSD: src/usr.sbin/portmap/portmap.c,v 1.10.2.3 2002/05/06 18:18:21 dwmalone Exp $
36 * $DragonFly: src/usr.sbin/portmap/portmap.c,v 1.4 2004/03/30 02:58:59 cpressey Exp $
40 @(#)portmap.c 2.3 88/08/11 4.0 RPCSRC
41 static char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro";
45 * portmap.c, Implements the program,version to port number mapping for
50 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
51 * unrestricted use provided that this legend is included on all tape
52 * media and as a part of the software program in whole or part. Users
53 * may copy or modify Sun RPC without charge, but are not authorized
54 * to license or distribute it to anyone else except as part of a product or
55 * program developed by the user.
57 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
58 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
59 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
61 * Sun RPC is provided with no support and without any obligation on the
62 * part of Sun Microsystems, Inc. to assist in its use, correction,
63 * modification or enhancement.
65 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
66 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
67 * OR ANY PART THEREOF.
69 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
70 * or profits or other special, indirect and consequential damages, even if
71 * Sun has been advised of the possibility of such damages.
73 * Sun Microsystems, Inc.
75 * Mountain View, California 94043
78 #include <sys/types.h>
79 #include <sys/socket.h>
80 #include <sys/ioctl.h>
82 #include <sys/signal.h>
84 #include <sys/resource.h>
86 #include <rpc/pmap_prot.h>
97 #include "pmap_check.h"
99 static void reg_service(struct svc_req
*, SVCXPRT
*);
100 static void reap(int);
101 static void callit(struct svc_req
*, SVCXPRT
*);
102 static void usage(void);
104 struct pmaplist
*pmaplist
;
108 main(int argc
, char **argv
)
114 struct sockaddr_in addr
;
115 int len
= sizeof(struct sockaddr_in
);
116 struct pmaplist
*pml
;
118 while ((c
= getopt(argc
, argv
, "dvh:")) != -1) {
131 hosts
= realloc(hosts
, nhosts
* sizeof(char *));
132 hosts
[nhosts
- 1] = optarg
;
140 if (!debugging
&& daemon(0, 0))
143 openlog("portmap", debugging
? LOG_PID
| LOG_PERROR
: LOG_PID
,
146 bzero(&addr
, sizeof(addr
));
147 addr
.sin_family
= AF_INET
;
148 addr
.sin_port
= htons(PMAPPORT
);
151 * If no hosts were specified, just bind to INADDR_ANY. Otherwise
152 * make sure 127.0.0.1 is added to the list.
155 hosts
= realloc(hosts
, nhosts
* sizeof(char *));
157 hosts
[0] = "0.0.0.0";
159 hosts
[nhosts
- 1] = "127.0.0.1";
162 * Add UDP socket(s) - bind to specific IPs if asked to
167 if (!inet_aton(hosts
[nhosts
], &addr
.sin_addr
)) {
168 syslog(LOG_ERR
, "bad IP address: %s", hosts
[nhosts
]);
171 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) < 0) {
172 syslog(LOG_ERR
, "cannot create udp socket: %m");
176 if (bind(sock
, (struct sockaddr
*)&addr
, len
) != 0) {
177 syslog(LOG_ERR
, "cannot bind udp: %m");
181 if ((xprt
= svcudp_create(sock
)) == (SVCXPRT
*)NULL
) {
182 syslog(LOG_ERR
, "couldn't do udp_create");
186 /* make an entry for ourself */
187 pml
= (struct pmaplist
*)malloc((u_int
)sizeof(struct pmaplist
));
189 pml
->pml_map
.pm_prog
= PMAPPROG
;
190 pml
->pml_map
.pm_vers
= PMAPVERS
;
191 pml
->pml_map
.pm_prot
= IPPROTO_UDP
;
192 pml
->pml_map
.pm_port
= PMAPPORT
;
198 addr
.sin_addr
.s_addr
= 0;
199 if ((sock
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
)) < 0) {
200 syslog(LOG_ERR
, "cannot create tcp socket: %m");
203 if (bind(sock
, (struct sockaddr
*)&addr
, len
) != 0) {
204 syslog(LOG_ERR
, "cannot bind tcp: %m");
207 if ((xprt
= svctcp_create(sock
, RPCSMALLMSGSIZE
, RPCSMALLMSGSIZE
))
208 == (SVCXPRT
*)NULL
) {
209 syslog(LOG_ERR
, "couldn't do tcp_create");
212 /* make an entry for ourself */
213 pml
= (struct pmaplist
*)malloc((u_int
)sizeof(struct pmaplist
));
214 pml
->pml_map
.pm_prog
= PMAPPROG
;
215 pml
->pml_map
.pm_vers
= PMAPVERS
;
216 pml
->pml_map
.pm_prot
= IPPROTO_TCP
;
217 pml
->pml_map
.pm_port
= PMAPPORT
;
218 pml
->pml_next
= pmaplist
;
221 svc_register(xprt
, PMAPPROG
, PMAPVERS
, reg_service
, FALSE
);
223 /* additional initializations */
225 signal(SIGCHLD
, reap
);
227 syslog(LOG_ERR
, "svc_run returned unexpectedly");
234 fprintf(stderr
, "usage: portmap [-dv] [-h bindip]\n");
239 /* need to override perror calls in rpc library */
241 perror(const char *what
)
243 syslog(LOG_ERR
, "%s: %m", what
);
247 static struct pmaplist
*
248 find_service(u_long prog
, u_long vers
, u_long prot
)
250 struct pmaplist
*hit
= NULL
;
251 struct pmaplist
*pml
;
253 for (pml
= pmaplist
; pml
!= NULL
; pml
= pml
->pml_next
) {
254 if ((pml
->pml_map
.pm_prog
!= prog
) ||
255 (pml
->pml_map
.pm_prot
!= prot
))
258 if (pml
->pml_map
.pm_vers
== vers
)
268 reg_service(struct svc_req
*rqstp
, SVCXPRT
*xprt
)
271 struct pmaplist
*pml
, *prevpml
, *fnd
;
276 * Later wrappers change the logging severity on the fly. Reset to
277 * defaults before handling the next request.
279 allow_severity
= LOG_INFO
;
280 deny_severity
= LOG_WARNING
;
283 fprintf(stderr
, "server: about to do a switch\n");
284 switch (rqstp
->rq_proc
) {
290 /* remote host authorization check */
291 check_default(svc_getcaller(xprt
), rqstp
->rq_proc
, (u_long
) 0);
292 if (!svc_sendreply(xprt
, xdr_void
, (caddr_t
)0) && debugging
) {
299 * Set a program,version to port mapping
301 if (!svc_getargs(xprt
, xdr_pmap
, (caddr_t
)®
))
304 /* reject non-local requests, protect priv. ports */
305 if (!check_setunset(svc_getcaller(xprt
),
306 rqstp
->rq_proc
, reg
.pm_prog
, reg
.pm_port
)) {
311 * check to see if already used
312 * find_service returns a hit even if
313 * the versions don't match, so check for it
315 fnd
= find_service(reg
.pm_prog
, reg
.pm_vers
, reg
.pm_prot
);
316 if (fnd
&& fnd
->pml_map
.pm_vers
== reg
.pm_vers
) {
317 if (fnd
->pml_map
.pm_port
== reg
.pm_port
) {
329 pml
= (struct pmaplist
*)
330 malloc((u_int
)sizeof(struct pmaplist
));
336 for (fnd
= pmaplist
; fnd
->pml_next
!= 0;
337 fnd
= fnd
->pml_next
);
343 if ((!svc_sendreply(xprt
, xdr_long
, (caddr_t
)&ans
)) &&
345 fprintf(stderr
, "svc_sendreply\n");
353 * Remove a program,version to port mapping.
355 if (!svc_getargs(xprt
, xdr_pmap
, (caddr_t
)®
))
359 /* reject non-local requests */
360 if (!check_setunset(svc_getcaller(xprt
),
361 rqstp
->rq_proc
, reg
.pm_prog
, (u_long
) 0))
363 for (prevpml
= NULL
, pml
= pmaplist
; pml
!= NULL
; ) {
364 if ((pml
->pml_map
.pm_prog
!= reg
.pm_prog
) ||
365 (pml
->pml_map
.pm_vers
!= reg
.pm_vers
)) {
366 /* both pml & prevpml move forwards */
371 /* found it; pml moves forward, prevpml stays */
372 /* privileged port check */
373 if (!check_privileged_port(svc_getcaller(xprt
),
376 pml
->pml_map
.pm_port
)) {
386 prevpml
->pml_next
= pml
;
389 if ((!svc_sendreply(xprt
, xdr_long
, (caddr_t
)&ans
)) &&
391 fprintf(stderr
, "svc_sendreply\n");
397 case PMAPPROC_GETPORT
:
399 * Lookup the mapping for a program,version and return its port
401 if (!svc_getargs(xprt
, xdr_pmap
, (caddr_t
)®
))
404 /* remote host authorization check */
405 if (!check_default(svc_getcaller(xprt
),
411 fnd
= find_service(reg
.pm_prog
, reg
.pm_vers
, reg
.pm_prot
);
413 port
= fnd
->pml_map
.pm_port
;
416 if ((!svc_sendreply(xprt
, xdr_long
, (caddr_t
)&port
)) &&
418 fprintf(stderr
, "svc_sendreply\n");
426 * Return the current set of mapped program,version
428 if (!svc_getargs(xprt
, xdr_void
, NULL
))
431 /* remote host authorization check */
433 if (!check_default(svc_getcaller(xprt
),
434 rqstp
->rq_proc
, (u_long
) 0)) {
435 p
= 0; /* send empty list */
439 if ((!svc_sendreply(xprt
, xdr_pmaplist
,
440 (caddr_t
)&p
)) && debugging
) {
441 fprintf(stderr
, "svc_sendreply\n");
447 case PMAPPROC_CALLIT
:
449 * Calls a procedure on the local machine. If the requested
450 * procedure is not registered this procedure does not return
451 * error information!!
452 * This procedure is only supported on rpc/udp and calls via
453 * rpc/udp. It passes null authentication parameters.
459 /* remote host authorization check */
460 check_default(svc_getcaller(xprt
), rqstp
->rq_proc
, (u_long
) 0);
468 * Stuff for the rmtcall service
478 xdr_encap_parms(XDR
*xdrs
, struct encap_parms
*epp
)
480 return (xdr_bytes(xdrs
, &(epp
->args
), &(epp
->arglen
), ARGSIZE
));
488 struct encap_parms rmt_args
;
492 xdr_rmtcall_args(XDR
*xdrs
, struct rmtcallargs
*cap
)
494 /* does not get a port number */
495 if (xdr_u_long(xdrs
, &(cap
->rmt_prog
)) &&
496 xdr_u_long(xdrs
, &(cap
->rmt_vers
)) &&
497 xdr_u_long(xdrs
, &(cap
->rmt_proc
))) {
498 return (xdr_encap_parms(xdrs
, &(cap
->rmt_args
)));
504 xdr_rmtcall_result(XDR
*xdrs
, struct rmtcallargs
*cap
)
506 if (xdr_u_long(xdrs
, &(cap
->rmt_port
)))
507 return (xdr_encap_parms(xdrs
, &(cap
->rmt_args
)));
512 * only worries about the struct encap_parms part of struct rmtcallargs.
513 * The arglen must already be set!!
516 xdr_opaque_parms(XDR
*xdrs
, struct rmtcallargs
*cap
)
518 return (xdr_opaque(xdrs
, cap
->rmt_args
.args
, cap
->rmt_args
.arglen
));
522 * This routine finds and sets the length of incoming opaque paraters
523 * and then calls xdr_opaque_parms.
526 xdr_len_opaque_parms(XDR
*xdrs
, struct rmtcallargs
*cap
)
528 u_int beginpos
, lowpos
, highpos
, currpos
, pos
;
530 beginpos
= lowpos
= pos
= xdr_getpos(xdrs
);
531 highpos
= lowpos
+ ARGSIZE
;
532 while ((int)(highpos
- lowpos
) >= 0) {
533 currpos
= (lowpos
+ highpos
) / 2;
534 if (xdr_setpos(xdrs
, currpos
)) {
536 lowpos
= currpos
+ 1;
538 highpos
= currpos
- 1;
541 xdr_setpos(xdrs
, beginpos
);
542 cap
->rmt_args
.arglen
= pos
- beginpos
;
543 return (xdr_opaque_parms(xdrs
, cap
));
547 * Call a remote procedure service
548 * This procedure is very quiet when things go wrong.
549 * The proc is written to support broadcast rpc. In the broadcast case,
550 * a machine should shut-up instead of complain, less the requestor be
551 * overrun with complaints at the expense of not hearing a valid reply ...
553 * This now forks so that the program & process that it calls can call
554 * back to the portmapper.
557 callit(struct svc_req
*rqstp
, SVCXPRT
*xprt
)
559 struct rmtcallargs a
;
560 struct pmaplist
*pml
;
562 struct sockaddr_in me
;
565 struct authunix_parms
*au
= (struct authunix_parms
*)rqstp
->rq_clntcred
;
566 struct timeval timeout
;
571 a
.rmt_args
.args
= buf
;
572 if (!svc_getargs(xprt
, xdr_rmtcall_args
, (caddr_t
)&a
))
574 /* host and service access control */
575 if (!check_callit(svc_getcaller(xprt
),
576 rqstp
->rq_proc
, a
.rmt_prog
, a
.rmt_proc
))
578 if ((pml
= find_service(a
.rmt_prog
, a
.rmt_vers
,
579 (u_long
)IPPROTO_UDP
)) == NULL
)
582 * fork a child to do the work. Parent immediately returns.
583 * Child exits upon completion.
585 if ((pid
= fork()) != 0) {
587 syslog(LOG_ERR
, "CALLIT (prog %lu): fork: %m",
591 port
= pml
->pml_map
.pm_port
;
593 me
.sin_port
= htons(port
);
594 client
= clntudp_create(&me
, a
.rmt_prog
, a
.rmt_vers
, timeout
, &so
);
595 if (client
!= (CLIENT
*)NULL
) {
596 if (rqstp
->rq_cred
.oa_flavor
== AUTH_UNIX
) {
597 client
->cl_auth
= authunix_create(au
->aup_machname
,
598 au
->aup_uid
, au
->aup_gid
, au
->aup_len
, au
->aup_gids
);
600 a
.rmt_port
= (u_long
)port
;
601 if (clnt_call(client
, a
.rmt_proc
, xdr_opaque_parms
, &a
,
602 xdr_len_opaque_parms
, &a
, timeout
) == RPC_SUCCESS
) {
603 svc_sendreply(xprt
, xdr_rmtcall_result
, (caddr_t
)&a
);
605 AUTH_DESTROY(client
->cl_auth
);
606 clnt_destroy(client
);
618 while (wait3((int *)NULL
, WNOHANG
, (struct rusage
*)NULL
) > 0);