1*591391d8Stedu /* $OpenBSD: portmap.c,v 1.40 2010/08/22 21:28:32 tedu Exp $ */ 2456a2117Smillert 3df930be7Sderaadt /*- 49d791f75Sderaadt * Copyright (c) 1996, 1997 Theo de Raadt (OpenBSD). All rights reserved. 5df930be7Sderaadt * Copyright (c) 1990 The Regents of the University of California. 6df930be7Sderaadt * All rights reserved. 7df930be7Sderaadt * 8df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 9df930be7Sderaadt * modification, are permitted provided that the following conditions 10df930be7Sderaadt * are met: 11df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 12df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 13df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 14df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 15df930be7Sderaadt * documentation and/or other materials provided with the distribution. 1629295d1cSmillert * 3. Neither the name of the University nor the names of its contributors 17df930be7Sderaadt * may be used to endorse or promote products derived from this software 18df930be7Sderaadt * without specific prior written permission. 19df930be7Sderaadt * 20df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30df930be7Sderaadt * SUCH DAMAGE. 31df930be7Sderaadt */ 32df930be7Sderaadt 33df930be7Sderaadt /* 34df930be7Sderaadt * portmap.c, Implements the program,version to port number mapping for 35df930be7Sderaadt * rpc. 36df930be7Sderaadt */ 37df930be7Sderaadt 38df930be7Sderaadt /* 39df930be7Sderaadt * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 40df930be7Sderaadt * unrestricted use provided that this legend is included on all tape 41df930be7Sderaadt * media and as a part of the software program in whole or part. Users 42df930be7Sderaadt * may copy or modify Sun RPC without charge, but are not authorized 43df930be7Sderaadt * to license or distribute it to anyone else except as part of a product or 44df930be7Sderaadt * program developed by the user. 45df930be7Sderaadt * 46df930be7Sderaadt * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 47df930be7Sderaadt * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 48df930be7Sderaadt * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 49df930be7Sderaadt * 50df930be7Sderaadt * Sun RPC is provided with no support and without any obligation on the 51df930be7Sderaadt * part of Sun Microsystems, Inc. to assist in its use, correction, 52df930be7Sderaadt * modification or enhancement. 53df930be7Sderaadt * 54df930be7Sderaadt * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 55df930be7Sderaadt * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 56df930be7Sderaadt * OR ANY PART THEREOF. 57df930be7Sderaadt * 58df930be7Sderaadt * In no event will Sun Microsystems, Inc. be liable for any lost revenue 59df930be7Sderaadt * or profits or other special, indirect and consequential damages, even if 60df930be7Sderaadt * Sun has been advised of the possibility of such damages. 61df930be7Sderaadt * 62df930be7Sderaadt * Sun Microsystems, Inc. 63df930be7Sderaadt * 2550 Garcia Avenue 64df930be7Sderaadt * Mountain View, California 94043 65df930be7Sderaadt */ 66df930be7Sderaadt 67606f45d1Smillert #include <sys/types.h> 68606f45d1Smillert #include <sys/socket.h> 69606f45d1Smillert #include <sys/ioctl.h> 70606f45d1Smillert #include <sys/wait.h> 71606f45d1Smillert #include <sys/resource.h> 72606f45d1Smillert 73606f45d1Smillert #include <rpcsvc/nfs_prot.h> 74606f45d1Smillert #include <arpa/inet.h> 75df930be7Sderaadt #include <rpc/rpc.h> 76df930be7Sderaadt #include <rpc/pmap_prot.h> 77606f45d1Smillert 78606f45d1Smillert #include <signal.h> 79df930be7Sderaadt #include <stdio.h> 80df930be7Sderaadt #include <stdlib.h> 81df930be7Sderaadt #include <string.h> 82df930be7Sderaadt #include <syslog.h> 83df930be7Sderaadt #include <unistd.h> 84df930be7Sderaadt #include <netdb.h> 8546aa5dceSderaadt #include <pwd.h> 8653a76164Stedu #include <errno.h> 87df930be7Sderaadt 88c72b5b24Smillert void reg_service(struct svc_req *, SVCXPRT *); 8983e8fa08Sderaadt void reap(int); 90c72b5b24Smillert void callit(struct svc_req *, SVCXPRT *); 91f99230ebSdhill int check_callit(struct sockaddr_in *, u_long, u_long); 92f99230ebSdhill struct pmaplist *find_service(u_long, u_long, u_long); 93df930be7Sderaadt 94df930be7Sderaadt struct pmaplist *pmaplist; 95*591391d8Stedu int debugging; 96df930be7Sderaadt 9777baebbfSderaadt SVCXPRT *ludpxprt, *ltcpxprt; 9877baebbfSderaadt 99d91d7659Sderaadt int 10046aa5dceSderaadt main(int argc, char *argv[]) 101df930be7Sderaadt { 102*591391d8Stedu int sock, lsock, c, on = 1; 103*591391d8Stedu socklen_t len = sizeof(struct sockaddr_in); 10477baebbfSderaadt struct sockaddr_in addr, laddr; 1050ac0d02eSmpech struct pmaplist *pml; 1060f99c42cSderaadt struct passwd *pw; 10746aa5dceSderaadt SVCXPRT *xprt; 108df930be7Sderaadt 10972799b18Smillert while ((c = getopt(argc, argv, "d")) != -1) { 110df930be7Sderaadt switch (c) { 111df930be7Sderaadt case 'd': 112df930be7Sderaadt debugging = 1; 113df930be7Sderaadt break; 114df930be7Sderaadt default: 115df930be7Sderaadt (void)fprintf(stderr, "usage: %s [-d]\n", argv[0]); 116df930be7Sderaadt exit(1); 117df930be7Sderaadt } 118df930be7Sderaadt } 119df930be7Sderaadt 120df930be7Sderaadt if (!debugging && daemon(0, 0)) { 121df930be7Sderaadt (void)fprintf(stderr, "portmap: fork: %s", strerror(errno)); 122df930be7Sderaadt exit(1); 123df930be7Sderaadt } 124df930be7Sderaadt 125*591391d8Stedu openlog("portmap", LOG_NDELAY | (debugging ? LOG_PID | LOG_PERROR : 126*591391d8Stedu LOG_PID), LOG_DAEMON); 127df930be7Sderaadt 128*591391d8Stedu bzero(&addr, sizeof addr); 12977baebbfSderaadt addr.sin_addr.s_addr = 0; 13077baebbfSderaadt addr.sin_family = AF_INET; 13177baebbfSderaadt addr.sin_addr.s_addr = htonl(INADDR_ANY); 13277baebbfSderaadt addr.sin_port = htons(PMAPPORT); 13377baebbfSderaadt 134*591391d8Stedu bzero(&laddr, sizeof laddr); 13577baebbfSderaadt laddr.sin_addr.s_addr = 0; 13677baebbfSderaadt laddr.sin_family = AF_INET; 13777baebbfSderaadt laddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 13877baebbfSderaadt laddr.sin_port = htons(PMAPPORT); 13977baebbfSderaadt 140df930be7Sderaadt if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 141df930be7Sderaadt syslog(LOG_ERR, "cannot create udp socket: %m"); 142df930be7Sderaadt exit(1); 143df930be7Sderaadt } 144afeed3b4Sderaadt setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on); 145df930be7Sderaadt if (bind(sock, (struct sockaddr *)&addr, len) != 0) { 146df930be7Sderaadt syslog(LOG_ERR, "cannot bind udp: %m"); 147df930be7Sderaadt exit(1); 148df930be7Sderaadt } 149df930be7Sderaadt 150*591391d8Stedu if ((xprt = svcudp_create(sock)) == NULL) { 151df930be7Sderaadt syslog(LOG_ERR, "couldn't do udp_create"); 152df930be7Sderaadt exit(1); 153df930be7Sderaadt } 15477baebbfSderaadt 15577baebbfSderaadt if ((lsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 15677baebbfSderaadt syslog(LOG_ERR, "cannot create udp socket: %m"); 15777baebbfSderaadt exit(1); 15877baebbfSderaadt } 15977baebbfSderaadt setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on); 16077baebbfSderaadt if (bind(lsock, (struct sockaddr *)&laddr, len) != 0) { 1617e963911Smickey syslog(LOG_ERR, "cannot bind local udp: %m"); 16277baebbfSderaadt exit(1); 16377baebbfSderaadt } 16477baebbfSderaadt 165*591391d8Stedu if ((ludpxprt = svcudp_create(lsock)) == NULL) { 16677baebbfSderaadt syslog(LOG_ERR, "couldn't do udp_create"); 16777baebbfSderaadt exit(1); 16877baebbfSderaadt } 16977baebbfSderaadt 170df930be7Sderaadt /* make an entry for ourself */ 171*591391d8Stedu pml = malloc(sizeof(struct pmaplist)); 172acfba6e6Sderaadt if (pml == NULL) { 173acfba6e6Sderaadt syslog(LOG_ERR, "out of memory"); 174acfba6e6Sderaadt exit(1); 175acfba6e6Sderaadt } 176df930be7Sderaadt pml->pml_next = 0; 177df930be7Sderaadt pml->pml_map.pm_prog = PMAPPROG; 178df930be7Sderaadt pml->pml_map.pm_vers = PMAPVERS; 179df930be7Sderaadt pml->pml_map.pm_prot = IPPROTO_UDP; 180df930be7Sderaadt pml->pml_map.pm_port = PMAPPORT; 181df930be7Sderaadt pmaplist = pml; 182df930be7Sderaadt 183df930be7Sderaadt if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 184df930be7Sderaadt syslog(LOG_ERR, "cannot create tcp socket: %m"); 185df930be7Sderaadt exit(1); 186df930be7Sderaadt } 187afeed3b4Sderaadt setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on); 188df930be7Sderaadt if (bind(sock, (struct sockaddr *)&addr, len) != 0) { 189da52f073Sderaadt syslog(LOG_ERR, "cannot bind tcp: %m"); 190df930be7Sderaadt exit(1); 191df930be7Sderaadt } 192*591391d8Stedu if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE)) == 193*591391d8Stedu NULL) { 194df930be7Sderaadt syslog(LOG_ERR, "couldn't do tcp_create"); 195df930be7Sderaadt exit(1); 196df930be7Sderaadt } 19777baebbfSderaadt 19877baebbfSderaadt if ((lsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 19977baebbfSderaadt syslog(LOG_ERR, "cannot create tcp socket: %m"); 20077baebbfSderaadt exit(1); 20177baebbfSderaadt } 20277baebbfSderaadt setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on); 20377baebbfSderaadt if (bind(lsock, (struct sockaddr *)&laddr, len) != 0) { 204da52f073Sderaadt syslog(LOG_ERR, "cannot bind tcp: %m"); 20577baebbfSderaadt exit(1); 20677baebbfSderaadt } 20777baebbfSderaadt if ((ltcpxprt = svctcp_create(lsock, RPCSMALLMSGSIZE, 208*591391d8Stedu RPCSMALLMSGSIZE)) == NULL) { 20977baebbfSderaadt syslog(LOG_ERR, "couldn't do tcp_create"); 21077baebbfSderaadt exit(1); 21177baebbfSderaadt } 21277baebbfSderaadt 213df930be7Sderaadt /* make an entry for ourself */ 214*591391d8Stedu pml = malloc(sizeof(struct pmaplist)); 215acfba6e6Sderaadt if (pml == NULL) { 216acfba6e6Sderaadt syslog(LOG_ERR, "out of memory"); 217acfba6e6Sderaadt exit(1); 218acfba6e6Sderaadt } 219df930be7Sderaadt pml->pml_map.pm_prog = PMAPPROG; 220df930be7Sderaadt pml->pml_map.pm_vers = PMAPVERS; 221df930be7Sderaadt pml->pml_map.pm_prot = IPPROTO_TCP; 222df930be7Sderaadt pml->pml_map.pm_port = PMAPPORT; 223df930be7Sderaadt pml->pml_next = pmaplist; 224df930be7Sderaadt pmaplist = pml; 225df930be7Sderaadt 226ac4529faSthib if ((pw = getpwnam("_portmap")) == NULL) { 227ac4529faSthib syslog(LOG_ERR, "no such user _portmap"); 228ac4529faSthib exit(1); 229ac4529faSthib } 2300f99c42cSderaadt if (chroot("/var/empty") == -1) { 231*591391d8Stedu syslog(LOG_ERR, "cannot chroot to /var/empty."); 232*591391d8Stedu exit(1); 233*591391d8Stedu } 234*591391d8Stedu if (chdir("/") == -1) { 235*591391d8Stedu syslog(LOG_ERR, "cannot chdir to new /."); 2360f99c42cSderaadt exit(1); 2370f99c42cSderaadt } 238ac4529faSthib 2390f99c42cSderaadt if (pw) { 2405bb60d39Sdjm if (setgroups(1, &pw->pw_gid) == -1 || 2415bb60d39Sdjm setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 || 2425bb60d39Sdjm setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) { 2435bb60d39Sdjm syslog(LOG_ERR, "revoke privs: %s", strerror(errno)); 2445bb60d39Sdjm exit(1); 2455bb60d39Sdjm } 2460f99c42cSderaadt } 247cb074343Shenning endpwent(); 2480f99c42cSderaadt 2495b63b19eSpvalchev if (svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE) == 0) { 2505b63b19eSpvalchev syslog(LOG_ERR, "svc_register failed."); 2515b63b19eSpvalchev exit(1); 2525b63b19eSpvalchev } 253df930be7Sderaadt 254606f45d1Smillert (void)signal(SIGCHLD, reap); 255df930be7Sderaadt svc_run(); 256da52f073Sderaadt syslog(LOG_ERR, "svc_run returned unexpectedly"); 257df930be7Sderaadt abort(); 258df930be7Sderaadt } 259df930be7Sderaadt 260df930be7Sderaadt #ifndef lint 261df930be7Sderaadt /* need to override perror calls in rpc library */ 262df930be7Sderaadt void 26346aa5dceSderaadt perror(const char *what) 264df930be7Sderaadt { 265df930be7Sderaadt 266df930be7Sderaadt syslog(LOG_ERR, "%s: %m", what); 267df930be7Sderaadt } 268df930be7Sderaadt #endif 269df930be7Sderaadt 2703aef48d5Sderaadt struct pmaplist * 27146aa5dceSderaadt find_service(u_long prog, u_long vers, u_long prot) 272df930be7Sderaadt { 2730ac0d02eSmpech struct pmaplist *hit = NULL; 2740ac0d02eSmpech struct pmaplist *pml; 275df930be7Sderaadt 276df930be7Sderaadt for (pml = pmaplist; pml != NULL; pml = pml->pml_next) { 277df930be7Sderaadt if ((pml->pml_map.pm_prog != prog) || 278df930be7Sderaadt (pml->pml_map.pm_prot != prot)) 279df930be7Sderaadt continue; 280df930be7Sderaadt hit = pml; 281df930be7Sderaadt if (pml->pml_map.pm_vers == vers) 282df930be7Sderaadt break; 283df930be7Sderaadt } 284df930be7Sderaadt return (hit); 285df930be7Sderaadt } 286df930be7Sderaadt 287df930be7Sderaadt /* 288df930be7Sderaadt * 1 OK, 0 not 289df930be7Sderaadt */ 290df930be7Sderaadt void 29146aa5dceSderaadt reg_service(struct svc_req *rqstp, SVCXPRT *xprt) 292df930be7Sderaadt { 293df930be7Sderaadt struct pmap reg; 294df930be7Sderaadt struct pmaplist *pml, *prevpml, *fnd; 29577baebbfSderaadt struct sockaddr_in *fromsin; 29677baebbfSderaadt long ans = 0, port; 297*591391d8Stedu void *t; 298df930be7Sderaadt 29977baebbfSderaadt fromsin = svc_getcaller(xprt); 30077baebbfSderaadt 301df930be7Sderaadt if (debugging) 302df930be7Sderaadt (void)fprintf(stderr, "server: about to do a switch\n"); 303df930be7Sderaadt switch (rqstp->rq_proc) { 304df930be7Sderaadt case PMAPPROC_NULL: 305df930be7Sderaadt /* 306df930be7Sderaadt * Null proc call 307df930be7Sderaadt */ 308*591391d8Stedu if (!svc_sendreply(xprt, xdr_void, NULL) && debugging) { 309df930be7Sderaadt abort(); 310df930be7Sderaadt } 311df930be7Sderaadt break; 312df930be7Sderaadt case PMAPPROC_SET: 313df930be7Sderaadt /* 314df930be7Sderaadt * Set a program,version to port mapping 315df930be7Sderaadt */ 31677baebbfSderaadt if (xprt != ltcpxprt && xprt != ludpxprt) { 31777baebbfSderaadt syslog(LOG_WARNING, 31877baebbfSderaadt "non-local set attempt (might be from %s)", 3199430a6aeSderaadt inet_ntoa(fromsin->sin_addr)); 32077baebbfSderaadt svcerr_noproc(xprt); 32177baebbfSderaadt return; 32277baebbfSderaadt } 32360cef36bSderaadt if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®)) { 324df930be7Sderaadt svcerr_decode(xprt); 32560cef36bSderaadt break; 32660cef36bSderaadt } 3273aef48d5Sderaadt 328df930be7Sderaadt /* 329df930be7Sderaadt * check to see if already used 330df930be7Sderaadt * find_service returns a hit even if 331df930be7Sderaadt * the versions don't match, so check for it 332df930be7Sderaadt */ 333df930be7Sderaadt fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); 334df930be7Sderaadt if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) { 33577baebbfSderaadt if (fnd->pml_map.pm_port == reg.pm_port) 336df930be7Sderaadt ans = 1; 337df930be7Sderaadt goto done; 338df930be7Sderaadt } 33977baebbfSderaadt 340a982d679Sderaadt if (debugging) 34131cea007Spvalchev printf("set: prog %lu vers %lu port %lu\n", 342a982d679Sderaadt reg.pm_prog, reg.pm_vers, reg.pm_port); 343a982d679Sderaadt 344a982d679Sderaadt if (reg.pm_port & ~0xffff) 345a982d679Sderaadt goto done; 346a982d679Sderaadt 347a982d679Sderaadt /* 348a982d679Sderaadt * only permit localhost root to create 349a982d679Sderaadt * mappings pointing at sensitive ports 350a982d679Sderaadt */ 351a982d679Sderaadt if ((reg.pm_port < IPPORT_RESERVED || 352a982d679Sderaadt reg.pm_port == NFS_PORT) && 35377baebbfSderaadt htons(fromsin->sin_port) >= IPPORT_RESERVED) { 354a982d679Sderaadt syslog(LOG_WARNING, 355a982d679Sderaadt "resvport set attempt by non-root"); 356df930be7Sderaadt goto done; 357df930be7Sderaadt } 35877baebbfSderaadt 359df930be7Sderaadt /* 360df930be7Sderaadt * add to END of list 361df930be7Sderaadt */ 362*591391d8Stedu pml = malloc(sizeof(struct pmaplist)); 363acfba6e6Sderaadt if (pml == NULL) { 364acfba6e6Sderaadt syslog(LOG_ERR, "out of memory"); 365acfba6e6Sderaadt svcerr_systemerr(xprt); 366acfba6e6Sderaadt return; 367acfba6e6Sderaadt } 368acfba6e6Sderaadt 369df930be7Sderaadt pml->pml_map = reg; 370df930be7Sderaadt pml->pml_next = 0; 37137ef7afbSderaadt if (pmaplist == NULL) { 372df930be7Sderaadt pmaplist = pml; 373df930be7Sderaadt } else { 374df930be7Sderaadt for (fnd = pmaplist; fnd->pml_next != 0; 37537ef7afbSderaadt fnd = fnd->pml_next) 37637ef7afbSderaadt ; 377df930be7Sderaadt fnd->pml_next = pml; 378df930be7Sderaadt } 379df930be7Sderaadt ans = 1; 380df930be7Sderaadt done: 381df930be7Sderaadt if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && 382df930be7Sderaadt debugging) { 383df930be7Sderaadt (void)fprintf(stderr, "svc_sendreply\n"); 384df930be7Sderaadt abort(); 385df930be7Sderaadt } 386df930be7Sderaadt break; 387df930be7Sderaadt case PMAPPROC_UNSET: 388df930be7Sderaadt /* 389df930be7Sderaadt * Remove a program,version to port mapping. 390df930be7Sderaadt */ 39177baebbfSderaadt if (xprt != ltcpxprt && xprt != ludpxprt) { 39277baebbfSderaadt syslog(LOG_WARNING, 39377baebbfSderaadt "non-local unset attempt (might be from %s)", 3949430a6aeSderaadt inet_ntoa(fromsin->sin_addr)); 39577baebbfSderaadt svcerr_noproc(xprt); 39677baebbfSderaadt return; 39777baebbfSderaadt } 39877baebbfSderaadt if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®)) { 399df930be7Sderaadt svcerr_decode(xprt); 40077baebbfSderaadt break; 40177baebbfSderaadt } 402df930be7Sderaadt for (prevpml = NULL, pml = pmaplist; pml != NULL; ) { 403df930be7Sderaadt if ((pml->pml_map.pm_prog != reg.pm_prog) || 404df930be7Sderaadt (pml->pml_map.pm_vers != reg.pm_vers)) { 405df930be7Sderaadt /* both pml & prevpml move forwards */ 406df930be7Sderaadt prevpml = pml; 407df930be7Sderaadt pml = pml->pml_next; 408df930be7Sderaadt continue; 409df930be7Sderaadt } 41077baebbfSderaadt if ((pml->pml_map.pm_port < IPPORT_RESERVED || 41177baebbfSderaadt pml->pml_map.pm_port == NFS_PORT) && 41277baebbfSderaadt htons(fromsin->sin_port) >= IPPORT_RESERVED) { 41377baebbfSderaadt syslog(LOG_WARNING, 41477baebbfSderaadt "resvport unset attempt by non-root"); 41577baebbfSderaadt break; 41677baebbfSderaadt } 41777baebbfSderaadt 418df930be7Sderaadt /* found it; pml moves forward, prevpml stays */ 419df930be7Sderaadt ans = 1; 420*591391d8Stedu t = pml; 421df930be7Sderaadt pml = pml->pml_next; 422df930be7Sderaadt if (prevpml == NULL) 423df930be7Sderaadt pmaplist = pml; 424df930be7Sderaadt else 425df930be7Sderaadt prevpml->pml_next = pml; 426df930be7Sderaadt free(t); 427df930be7Sderaadt } 428df930be7Sderaadt if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && 429df930be7Sderaadt debugging) { 43060cef36bSderaadt fprintf(stderr, "svc_sendreply\n"); 431df930be7Sderaadt abort(); 432df930be7Sderaadt } 433df930be7Sderaadt break; 434df930be7Sderaadt case PMAPPROC_GETPORT: 435df930be7Sderaadt /* 436df930be7Sderaadt * Lookup the mapping for a program,version and return its port 437df930be7Sderaadt */ 43860cef36bSderaadt if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®)) { 439df930be7Sderaadt svcerr_decode(xprt); 44060cef36bSderaadt break; 44160cef36bSderaadt } 442df930be7Sderaadt fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); 443df930be7Sderaadt if (fnd) 444df930be7Sderaadt port = fnd->pml_map.pm_port; 445df930be7Sderaadt else 446df930be7Sderaadt port = 0; 447df930be7Sderaadt if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) && 448df930be7Sderaadt debugging) { 44960cef36bSderaadt fprintf(stderr, "svc_sendreply\n"); 450df930be7Sderaadt abort(); 451df930be7Sderaadt } 452df930be7Sderaadt break; 453df930be7Sderaadt case PMAPPROC_DUMP: 454df930be7Sderaadt /* 455df930be7Sderaadt * Return the current set of mapped program,version 456df930be7Sderaadt */ 45760cef36bSderaadt if (!svc_getargs(xprt, xdr_void, NULL)) { 458df930be7Sderaadt svcerr_decode(xprt); 45960cef36bSderaadt break; 46060cef36bSderaadt } 46160cef36bSderaadt if (!svc_sendreply(xprt, xdr_pmaplist, (caddr_t)&pmaplist) && 46260cef36bSderaadt debugging) { 46360cef36bSderaadt fprintf(stderr, "svc_sendreply\n"); 464df930be7Sderaadt abort(); 465df930be7Sderaadt } 466df930be7Sderaadt break; 467df930be7Sderaadt case PMAPPROC_CALLIT: 468df930be7Sderaadt /* 469df930be7Sderaadt * Calls a procedure on the local machine. If the requested 470df930be7Sderaadt * procedure is not registered this procedure does not return 471df930be7Sderaadt * error information!! 472df930be7Sderaadt * This procedure is only supported on rpc/udp and calls via 473df930be7Sderaadt * rpc/udp. It passes null authentication parameters. 474df930be7Sderaadt */ 475df930be7Sderaadt callit(rqstp, xprt); 476df930be7Sderaadt break; 477df930be7Sderaadt default: 478df930be7Sderaadt svcerr_noproc(xprt); 479df930be7Sderaadt break; 480df930be7Sderaadt } 481df930be7Sderaadt } 482df930be7Sderaadt 483df930be7Sderaadt 484df930be7Sderaadt /* 485df930be7Sderaadt * Stuff for the rmtcall service 486df930be7Sderaadt */ 487df930be7Sderaadt #define ARGSIZE 9000 488df930be7Sderaadt 489df930be7Sderaadt struct encap_parms { 490df930be7Sderaadt u_int arglen; 491df930be7Sderaadt char *args; 492df930be7Sderaadt }; 493df930be7Sderaadt 494df930be7Sderaadt static bool_t 49546aa5dceSderaadt xdr_encap_parms(XDR *xdrs, struct encap_parms *epp) 496df930be7Sderaadt { 497df930be7Sderaadt 498df930be7Sderaadt return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE)); 499df930be7Sderaadt } 500df930be7Sderaadt 501df930be7Sderaadt struct rmtcallargs { 502df930be7Sderaadt u_long rmt_prog; 503df930be7Sderaadt u_long rmt_vers; 504df930be7Sderaadt u_long rmt_port; 505df930be7Sderaadt u_long rmt_proc; 506df930be7Sderaadt struct encap_parms rmt_args; 507df930be7Sderaadt }; 508df930be7Sderaadt 509df930be7Sderaadt static bool_t 51046aa5dceSderaadt xdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap) 511df930be7Sderaadt { 512df930be7Sderaadt 513df930be7Sderaadt /* does not get a port number */ 514df930be7Sderaadt if (xdr_u_long(xdrs, &(cap->rmt_prog)) && 515df930be7Sderaadt xdr_u_long(xdrs, &(cap->rmt_vers)) && 516df930be7Sderaadt xdr_u_long(xdrs, &(cap->rmt_proc))) { 517df930be7Sderaadt return (xdr_encap_parms(xdrs, &(cap->rmt_args))); 518df930be7Sderaadt } 519df930be7Sderaadt return (FALSE); 520df930be7Sderaadt } 521df930be7Sderaadt 522df930be7Sderaadt static bool_t 52346aa5dceSderaadt xdr_rmtcall_result(XDR *xdrs, struct rmtcallargs *cap) 524df930be7Sderaadt { 525df930be7Sderaadt if (xdr_u_long(xdrs, &(cap->rmt_port))) 526df930be7Sderaadt return (xdr_encap_parms(xdrs, &(cap->rmt_args))); 527df930be7Sderaadt return (FALSE); 528df930be7Sderaadt } 529df930be7Sderaadt 530df930be7Sderaadt /* 531df930be7Sderaadt * only worries about the struct encap_parms part of struct rmtcallargs. 532df930be7Sderaadt * The arglen must already be set!! 533df930be7Sderaadt */ 534df930be7Sderaadt static bool_t 53546aa5dceSderaadt xdr_opaque_parms(XDR *xdrs, struct rmtcallargs *cap) 536df930be7Sderaadt { 537df930be7Sderaadt 538df930be7Sderaadt return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen)); 539df930be7Sderaadt } 540df930be7Sderaadt 541df930be7Sderaadt /* 542df930be7Sderaadt * This routine finds and sets the length of incoming opaque paraters 543df930be7Sderaadt * and then calls xdr_opaque_parms. 544df930be7Sderaadt */ 545df930be7Sderaadt static bool_t 54646aa5dceSderaadt xdr_len_opaque_parms(XDR *xdrs, struct rmtcallargs *cap) 547df930be7Sderaadt { 5480ac0d02eSmpech u_int beginpos, lowpos, highpos, currpos, pos; 549df930be7Sderaadt 550df930be7Sderaadt beginpos = lowpos = pos = xdr_getpos(xdrs); 551df930be7Sderaadt highpos = lowpos + ARGSIZE; 552*591391d8Stedu while (highpos >= lowpos) { 553df930be7Sderaadt currpos = (lowpos + highpos) / 2; 554df930be7Sderaadt if (xdr_setpos(xdrs, currpos)) { 555df930be7Sderaadt pos = currpos; 556df930be7Sderaadt lowpos = currpos + 1; 557df930be7Sderaadt } else { 558df930be7Sderaadt highpos = currpos - 1; 559df930be7Sderaadt } 560df930be7Sderaadt } 561df930be7Sderaadt xdr_setpos(xdrs, beginpos); 562df930be7Sderaadt cap->rmt_args.arglen = pos - beginpos; 563df930be7Sderaadt return (xdr_opaque_parms(xdrs, cap)); 564df930be7Sderaadt } 565df930be7Sderaadt 566df930be7Sderaadt /* 567df930be7Sderaadt * Call a remote procedure service 568df930be7Sderaadt * This procedure is very quiet when things go wrong. 569df930be7Sderaadt * The proc is written to support broadcast rpc. In the broadcast case, 570df930be7Sderaadt * a machine should shut-up instead of complain, less the requestor be 571df930be7Sderaadt * overrun with complaints at the expense of not hearing a valid reply ... 572df930be7Sderaadt * 573df930be7Sderaadt * This now forks so that the program & process that it calls can call 574df930be7Sderaadt * back to the portmapper. 575df930be7Sderaadt */ 576d91d7659Sderaadt void 57746aa5dceSderaadt callit(struct svc_req *rqstp, SVCXPRT *xprt) 578df930be7Sderaadt { 579df930be7Sderaadt struct rmtcallargs a; 580df930be7Sderaadt struct pmaplist *pml; 581df930be7Sderaadt u_short port; 582df930be7Sderaadt struct sockaddr_in me; 58348822293Sderaadt pid_t pid; 58448822293Sderaadt int so = -1, dontblock = 1; 585df930be7Sderaadt CLIENT *client; 586df930be7Sderaadt struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred; 587df930be7Sderaadt struct timeval timeout; 588df930be7Sderaadt char buf[ARGSIZE]; 589df930be7Sderaadt 590df930be7Sderaadt timeout.tv_sec = 5; 591df930be7Sderaadt timeout.tv_usec = 0; 592df930be7Sderaadt a.rmt_args.args = buf; 593df930be7Sderaadt if (!svc_getargs(xprt, xdr_rmtcall_args, (caddr_t)&a)) 594df930be7Sderaadt return; 595f99230ebSdhill if (!check_callit(svc_getcaller(xprt), a.rmt_prog, a.rmt_proc)) 596f94670b8Sderaadt return; 597df930be7Sderaadt if ((pml = find_service(a.rmt_prog, a.rmt_vers, 598df930be7Sderaadt (u_long)IPPROTO_UDP)) == NULL) 599df930be7Sderaadt return; 60077baebbfSderaadt 601df930be7Sderaadt /* 602df930be7Sderaadt * fork a child to do the work. Parent immediately returns. 603df930be7Sderaadt * Child exits upon completion. 604df930be7Sderaadt */ 605df930be7Sderaadt if ((pid = fork()) != 0) { 606df930be7Sderaadt if (pid == -1) 607df930be7Sderaadt syslog(LOG_ERR, "CALLIT (prog %lu): fork: %m", 608df930be7Sderaadt a.rmt_prog); 609df930be7Sderaadt return; 610df930be7Sderaadt } 611df930be7Sderaadt port = pml->pml_map.pm_port; 612df930be7Sderaadt get_myaddress(&me); 613df930be7Sderaadt me.sin_port = htons(port); 614df930be7Sderaadt 615df930be7Sderaadt /* Avoid implicit binding to reserved port by clntudp_create() */ 616df930be7Sderaadt so = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 617df930be7Sderaadt if (so == -1) 618df930be7Sderaadt exit(1); 619df930be7Sderaadt if (ioctl(so, FIONBIO, &dontblock) == -1) 620df930be7Sderaadt exit(1); 621df930be7Sderaadt 622df930be7Sderaadt client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &so); 623*591391d8Stedu if (client != NULL) { 62477baebbfSderaadt if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) 625df930be7Sderaadt client->cl_auth = authunix_create(au->aup_machname, 626df930be7Sderaadt au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids); 627df930be7Sderaadt a.rmt_port = (u_long)port; 628df930be7Sderaadt if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a, 62977baebbfSderaadt xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) 630df930be7Sderaadt svc_sendreply(xprt, xdr_rmtcall_result, (caddr_t)&a); 631df930be7Sderaadt AUTH_DESTROY(client->cl_auth); 632df930be7Sderaadt clnt_destroy(client); 633df930be7Sderaadt } 634df930be7Sderaadt (void)close(so); 635df930be7Sderaadt exit(0); 636df930be7Sderaadt } 637df930be7Sderaadt 6389d48a621Sderaadt /* ARGSUSED */ 639df930be7Sderaadt void 64083e8fa08Sderaadt reap(int signo) 641df930be7Sderaadt { 642df930be7Sderaadt int save_errno = errno; 643df930be7Sderaadt 6447af3e1e5Sderaadt while (wait3(NULL, WNOHANG, NULL) > 0) 645df930be7Sderaadt ; 646df930be7Sderaadt errno = save_errno; 647df930be7Sderaadt } 648f94670b8Sderaadt 649f94670b8Sderaadt #define NFSPROG ((u_long) 100003) 650f94670b8Sderaadt #define MOUNTPROG ((u_long) 100005) 651f94670b8Sderaadt #define YPXPROG ((u_long) 100069) 652f94670b8Sderaadt #define YPPROG ((u_long) 100004) 653f94670b8Sderaadt #define YPPROC_DOMAIN_NONACK ((u_long) 2) 654f94670b8Sderaadt #define MOUNTPROC_MNT ((u_long) 1) 6559d791f75Sderaadt #define XXXPROC_NOP ((u_long) 0) 656f94670b8Sderaadt 657f94670b8Sderaadt int 658f99230ebSdhill check_callit(struct sockaddr_in *addr, u_long prog, u_long aproc) 659f94670b8Sderaadt { 6609d791f75Sderaadt if ((prog == PMAPPROG && aproc != XXXPROC_NOP) || 6619d791f75Sderaadt (prog == NFSPROG && aproc != XXXPROC_NOP) || 6629d791f75Sderaadt (prog == YPXPROG && aproc != XXXPROC_NOP) || 663f94670b8Sderaadt (prog == MOUNTPROG && aproc == MOUNTPROC_MNT) || 664f94670b8Sderaadt (prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) { 665f94670b8Sderaadt syslog(LOG_WARNING, 666*591391d8Stedu "callit prog %ld aproc %ld (might be from %s)", 667*591391d8Stedu prog, aproc, inet_ntoa(addr->sin_addr)); 668f94670b8Sderaadt return (FALSE); 669f94670b8Sderaadt } 670f94670b8Sderaadt return (TRUE); 671f94670b8Sderaadt } 672