1*0bd1216cSderaadt /* $OpenBSD: portmap.c,v 1.47 2015/10/09 01:37:09 deraadt 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 */ 32cb7760d1Smillert /* 33cb7760d1Smillert * Copyright (c) 2010, Oracle America, Inc. 34cb7760d1Smillert * 35cb7760d1Smillert * Redistribution and use in source and binary forms, with or without 36cb7760d1Smillert * modification, are permitted provided that the following conditions are 37cb7760d1Smillert * met: 38cb7760d1Smillert * 39cb7760d1Smillert * * Redistributions of source code must retain the above copyright 40cb7760d1Smillert * notice, this list of conditions and the following disclaimer. 41cb7760d1Smillert * * Redistributions in binary form must reproduce the above 42cb7760d1Smillert * copyright notice, this list of conditions and the following 43cb7760d1Smillert * disclaimer in the documentation and/or other materials 44cb7760d1Smillert * provided with the distribution. 45cb7760d1Smillert * * Neither the name of the "Oracle America, Inc." nor the names of its 46cb7760d1Smillert * contributors may be used to endorse or promote products derived 47cb7760d1Smillert * from this software without specific prior written permission. 48cb7760d1Smillert * 49cb7760d1Smillert * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 50cb7760d1Smillert * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 51cb7760d1Smillert * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 52cb7760d1Smillert * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 53cb7760d1Smillert * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 54cb7760d1Smillert * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 55cb7760d1Smillert * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 56cb7760d1Smillert * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 57cb7760d1Smillert * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 58cb7760d1Smillert * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 59cb7760d1Smillert * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 60cb7760d1Smillert * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 61cb7760d1Smillert */ 62df930be7Sderaadt 63df930be7Sderaadt /* 64df930be7Sderaadt * portmap.c, Implements the program,version to port number mapping for 65df930be7Sderaadt * rpc. 66df930be7Sderaadt */ 67df930be7Sderaadt 68606f45d1Smillert #include <sys/types.h> 69606f45d1Smillert #include <sys/socket.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; 95591391d8Stedu int debugging; 96df930be7Sderaadt 9777baebbfSderaadt SVCXPRT *ludpxprt, *ltcpxprt; 9877baebbfSderaadt 99d91d7659Sderaadt int 10046aa5dceSderaadt main(int argc, char *argv[]) 101df930be7Sderaadt { 102591391d8Stedu int sock, lsock, c, on = 1; 103591391d8Stedu 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 125591391d8Stedu openlog("portmap", LOG_NDELAY | (debugging ? LOG_PID | LOG_PERROR : 126591391d8Stedu LOG_PID), LOG_DAEMON); 127df930be7Sderaadt 128591391d8Stedu 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 134591391d8Stedu 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 150591391d8Stedu 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 165591391d8Stedu 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 */ 171591391d8Stedu 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 } 192591391d8Stedu if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE)) == 193591391d8Stedu 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, 208591391d8Stedu RPCSMALLMSGSIZE)) == NULL) { 20977baebbfSderaadt syslog(LOG_ERR, "couldn't do tcp_create"); 21077baebbfSderaadt exit(1); 21177baebbfSderaadt } 21277baebbfSderaadt 213df930be7Sderaadt /* make an entry for ourself */ 214591391d8Stedu 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) { 231591391d8Stedu syslog(LOG_ERR, "cannot chroot to /var/empty."); 232591391d8Stedu exit(1); 233591391d8Stedu } 234591391d8Stedu if (chdir("/") == -1) { 235591391d8Stedu 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 249*0bd1216cSderaadt if (pledge("stdio rpath inet proc", NULL) == -1) 250*0bd1216cSderaadt err(1, "pledge"); 251a828131dSderaadt 2525b63b19eSpvalchev if (svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE) == 0) { 2535b63b19eSpvalchev syslog(LOG_ERR, "svc_register failed."); 2545b63b19eSpvalchev exit(1); 2555b63b19eSpvalchev } 256df930be7Sderaadt 257606f45d1Smillert (void)signal(SIGCHLD, reap); 258df930be7Sderaadt svc_run(); 259da52f073Sderaadt syslog(LOG_ERR, "svc_run returned unexpectedly"); 260df930be7Sderaadt abort(); 261df930be7Sderaadt } 262df930be7Sderaadt 2633aef48d5Sderaadt struct pmaplist * 26446aa5dceSderaadt find_service(u_long prog, u_long vers, u_long prot) 265df930be7Sderaadt { 2660ac0d02eSmpech struct pmaplist *hit = NULL; 2670ac0d02eSmpech struct pmaplist *pml; 268df930be7Sderaadt 269df930be7Sderaadt for (pml = pmaplist; pml != NULL; pml = pml->pml_next) { 270df930be7Sderaadt if ((pml->pml_map.pm_prog != prog) || 271df930be7Sderaadt (pml->pml_map.pm_prot != prot)) 272df930be7Sderaadt continue; 273df930be7Sderaadt hit = pml; 274df930be7Sderaadt if (pml->pml_map.pm_vers == vers) 275df930be7Sderaadt break; 276df930be7Sderaadt } 277df930be7Sderaadt return (hit); 278df930be7Sderaadt } 279df930be7Sderaadt 280df930be7Sderaadt /* 281df930be7Sderaadt * 1 OK, 0 not 282df930be7Sderaadt */ 283df930be7Sderaadt void 28446aa5dceSderaadt reg_service(struct svc_req *rqstp, SVCXPRT *xprt) 285df930be7Sderaadt { 286df930be7Sderaadt struct pmap reg; 287df930be7Sderaadt struct pmaplist *pml, *prevpml, *fnd; 28877baebbfSderaadt struct sockaddr_in *fromsin; 28977baebbfSderaadt long ans = 0, port; 290591391d8Stedu void *t; 291df930be7Sderaadt 29277baebbfSderaadt fromsin = svc_getcaller(xprt); 29377baebbfSderaadt 294df930be7Sderaadt if (debugging) 295df930be7Sderaadt (void)fprintf(stderr, "server: about to do a switch\n"); 296df930be7Sderaadt switch (rqstp->rq_proc) { 297df930be7Sderaadt case PMAPPROC_NULL: 298df930be7Sderaadt /* 299df930be7Sderaadt * Null proc call 300df930be7Sderaadt */ 301591391d8Stedu if (!svc_sendreply(xprt, xdr_void, NULL) && debugging) { 302df930be7Sderaadt abort(); 303df930be7Sderaadt } 304df930be7Sderaadt break; 305df930be7Sderaadt case PMAPPROC_SET: 306df930be7Sderaadt /* 307df930be7Sderaadt * Set a program,version to port mapping 308df930be7Sderaadt */ 30977baebbfSderaadt if (xprt != ltcpxprt && xprt != ludpxprt) { 31077baebbfSderaadt syslog(LOG_WARNING, 31177baebbfSderaadt "non-local set attempt (might be from %s)", 3129430a6aeSderaadt inet_ntoa(fromsin->sin_addr)); 31377baebbfSderaadt svcerr_noproc(xprt); 31477baebbfSderaadt return; 31577baebbfSderaadt } 31660cef36bSderaadt if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®)) { 317df930be7Sderaadt svcerr_decode(xprt); 31860cef36bSderaadt break; 31960cef36bSderaadt } 3203aef48d5Sderaadt 321df930be7Sderaadt /* 322df930be7Sderaadt * check to see if already used 323df930be7Sderaadt * find_service returns a hit even if 324df930be7Sderaadt * the versions don't match, so check for it 325df930be7Sderaadt */ 326df930be7Sderaadt fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); 327df930be7Sderaadt if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) { 32877baebbfSderaadt if (fnd->pml_map.pm_port == reg.pm_port) 329df930be7Sderaadt ans = 1; 330df930be7Sderaadt goto done; 331df930be7Sderaadt } 33277baebbfSderaadt 333a982d679Sderaadt if (debugging) 33431cea007Spvalchev printf("set: prog %lu vers %lu port %lu\n", 335a982d679Sderaadt reg.pm_prog, reg.pm_vers, reg.pm_port); 336a982d679Sderaadt 337a982d679Sderaadt if (reg.pm_port & ~0xffff) 338a982d679Sderaadt goto done; 339a982d679Sderaadt 340a982d679Sderaadt /* 341a982d679Sderaadt * only permit localhost root to create 342a982d679Sderaadt * mappings pointing at sensitive ports 343a982d679Sderaadt */ 344a982d679Sderaadt if ((reg.pm_port < IPPORT_RESERVED || 345a982d679Sderaadt reg.pm_port == NFS_PORT) && 34677baebbfSderaadt htons(fromsin->sin_port) >= IPPORT_RESERVED) { 347a982d679Sderaadt syslog(LOG_WARNING, 348a982d679Sderaadt "resvport set attempt by non-root"); 349df930be7Sderaadt goto done; 350df930be7Sderaadt } 35177baebbfSderaadt 352df930be7Sderaadt /* 353df930be7Sderaadt * add to END of list 354df930be7Sderaadt */ 355591391d8Stedu pml = malloc(sizeof(struct pmaplist)); 356acfba6e6Sderaadt if (pml == NULL) { 357acfba6e6Sderaadt syslog(LOG_ERR, "out of memory"); 358acfba6e6Sderaadt svcerr_systemerr(xprt); 359acfba6e6Sderaadt return; 360acfba6e6Sderaadt } 361acfba6e6Sderaadt 362df930be7Sderaadt pml->pml_map = reg; 363df930be7Sderaadt pml->pml_next = 0; 36437ef7afbSderaadt if (pmaplist == NULL) { 365df930be7Sderaadt pmaplist = pml; 366df930be7Sderaadt } else { 367df930be7Sderaadt for (fnd = pmaplist; fnd->pml_next != 0; 36837ef7afbSderaadt fnd = fnd->pml_next) 36937ef7afbSderaadt ; 370df930be7Sderaadt fnd->pml_next = pml; 371df930be7Sderaadt } 372df930be7Sderaadt ans = 1; 373df930be7Sderaadt done: 374df930be7Sderaadt if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && 375df930be7Sderaadt debugging) { 376df930be7Sderaadt (void)fprintf(stderr, "svc_sendreply\n"); 377df930be7Sderaadt abort(); 378df930be7Sderaadt } 379df930be7Sderaadt break; 380df930be7Sderaadt case PMAPPROC_UNSET: 381df930be7Sderaadt /* 382df930be7Sderaadt * Remove a program,version to port mapping. 383df930be7Sderaadt */ 38477baebbfSderaadt if (xprt != ltcpxprt && xprt != ludpxprt) { 38577baebbfSderaadt syslog(LOG_WARNING, 38677baebbfSderaadt "non-local unset attempt (might be from %s)", 3879430a6aeSderaadt inet_ntoa(fromsin->sin_addr)); 38877baebbfSderaadt svcerr_noproc(xprt); 38977baebbfSderaadt return; 39077baebbfSderaadt } 39177baebbfSderaadt if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®)) { 392df930be7Sderaadt svcerr_decode(xprt); 39377baebbfSderaadt break; 39477baebbfSderaadt } 395df930be7Sderaadt for (prevpml = NULL, pml = pmaplist; pml != NULL; ) { 396df930be7Sderaadt if ((pml->pml_map.pm_prog != reg.pm_prog) || 397df930be7Sderaadt (pml->pml_map.pm_vers != reg.pm_vers)) { 398df930be7Sderaadt /* both pml & prevpml move forwards */ 399df930be7Sderaadt prevpml = pml; 400df930be7Sderaadt pml = pml->pml_next; 401df930be7Sderaadt continue; 402df930be7Sderaadt } 40377baebbfSderaadt if ((pml->pml_map.pm_port < IPPORT_RESERVED || 40477baebbfSderaadt pml->pml_map.pm_port == NFS_PORT) && 40577baebbfSderaadt htons(fromsin->sin_port) >= IPPORT_RESERVED) { 40677baebbfSderaadt syslog(LOG_WARNING, 40777baebbfSderaadt "resvport unset attempt by non-root"); 40877baebbfSderaadt break; 40977baebbfSderaadt } 41077baebbfSderaadt 411df930be7Sderaadt /* found it; pml moves forward, prevpml stays */ 412df930be7Sderaadt ans = 1; 413591391d8Stedu t = pml; 414df930be7Sderaadt pml = pml->pml_next; 415df930be7Sderaadt if (prevpml == NULL) 416df930be7Sderaadt pmaplist = pml; 417df930be7Sderaadt else 418df930be7Sderaadt prevpml->pml_next = pml; 419df930be7Sderaadt free(t); 420df930be7Sderaadt } 421df930be7Sderaadt if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && 422df930be7Sderaadt debugging) { 42360cef36bSderaadt fprintf(stderr, "svc_sendreply\n"); 424df930be7Sderaadt abort(); 425df930be7Sderaadt } 426df930be7Sderaadt break; 427df930be7Sderaadt case PMAPPROC_GETPORT: 428df930be7Sderaadt /* 429df930be7Sderaadt * Lookup the mapping for a program,version and return its port 430df930be7Sderaadt */ 43160cef36bSderaadt if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®)) { 432df930be7Sderaadt svcerr_decode(xprt); 43360cef36bSderaadt break; 43460cef36bSderaadt } 435df930be7Sderaadt fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); 436df930be7Sderaadt if (fnd) 437df930be7Sderaadt port = fnd->pml_map.pm_port; 438df930be7Sderaadt else 439df930be7Sderaadt port = 0; 440df930be7Sderaadt if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) && 441df930be7Sderaadt debugging) { 44260cef36bSderaadt fprintf(stderr, "svc_sendreply\n"); 443df930be7Sderaadt abort(); 444df930be7Sderaadt } 445df930be7Sderaadt break; 446df930be7Sderaadt case PMAPPROC_DUMP: 447df930be7Sderaadt /* 448df930be7Sderaadt * Return the current set of mapped program,version 449df930be7Sderaadt */ 45060cef36bSderaadt if (!svc_getargs(xprt, xdr_void, NULL)) { 451df930be7Sderaadt svcerr_decode(xprt); 45260cef36bSderaadt break; 45360cef36bSderaadt } 45460cef36bSderaadt if (!svc_sendreply(xprt, xdr_pmaplist, (caddr_t)&pmaplist) && 45560cef36bSderaadt debugging) { 45660cef36bSderaadt fprintf(stderr, "svc_sendreply\n"); 457df930be7Sderaadt abort(); 458df930be7Sderaadt } 459df930be7Sderaadt break; 460df930be7Sderaadt case PMAPPROC_CALLIT: 461df930be7Sderaadt /* 462df930be7Sderaadt * Calls a procedure on the local machine. If the requested 463df930be7Sderaadt * procedure is not registered this procedure does not return 464df930be7Sderaadt * error information!! 465df930be7Sderaadt * This procedure is only supported on rpc/udp and calls via 466df930be7Sderaadt * rpc/udp. It passes null authentication parameters. 467df930be7Sderaadt */ 468df930be7Sderaadt callit(rqstp, xprt); 469df930be7Sderaadt break; 470df930be7Sderaadt default: 471df930be7Sderaadt svcerr_noproc(xprt); 472df930be7Sderaadt break; 473df930be7Sderaadt } 474df930be7Sderaadt } 475df930be7Sderaadt 476df930be7Sderaadt 477df930be7Sderaadt /* 478df930be7Sderaadt * Stuff for the rmtcall service 479df930be7Sderaadt */ 480df930be7Sderaadt #define ARGSIZE 9000 481df930be7Sderaadt 482df930be7Sderaadt struct encap_parms { 483df930be7Sderaadt u_int arglen; 484df930be7Sderaadt char *args; 485df930be7Sderaadt }; 486df930be7Sderaadt 487df930be7Sderaadt static bool_t 48846aa5dceSderaadt xdr_encap_parms(XDR *xdrs, struct encap_parms *epp) 489df930be7Sderaadt { 490df930be7Sderaadt 491df930be7Sderaadt return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE)); 492df930be7Sderaadt } 493df930be7Sderaadt 494df930be7Sderaadt struct rmtcallargs { 495df930be7Sderaadt u_long rmt_prog; 496df930be7Sderaadt u_long rmt_vers; 497df930be7Sderaadt u_long rmt_port; 498df930be7Sderaadt u_long rmt_proc; 499df930be7Sderaadt struct encap_parms rmt_args; 500df930be7Sderaadt }; 501df930be7Sderaadt 502c1198d48Sguenther /* 503c1198d48Sguenther * Version of xdr_rmtcall_args() that supports both directions 504c1198d48Sguenther */ 505df930be7Sderaadt static bool_t 506c1198d48Sguenther portmap_xdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap) 507df930be7Sderaadt { 508df930be7Sderaadt 509df930be7Sderaadt /* does not get a port number */ 510df930be7Sderaadt if (xdr_u_long(xdrs, &(cap->rmt_prog)) && 511df930be7Sderaadt xdr_u_long(xdrs, &(cap->rmt_vers)) && 512df930be7Sderaadt xdr_u_long(xdrs, &(cap->rmt_proc))) { 513df930be7Sderaadt return (xdr_encap_parms(xdrs, &(cap->rmt_args))); 514df930be7Sderaadt } 515df930be7Sderaadt return (FALSE); 516df930be7Sderaadt } 517df930be7Sderaadt 518c1198d48Sguenther /* 519c1198d48Sguenther * Version of xdr_rmtcallres() that supports both directions 520c1198d48Sguenther */ 521df930be7Sderaadt static bool_t 522c1198d48Sguenther portmap_xdr_rmtcallres(XDR *xdrs, struct rmtcallargs *cap) 523df930be7Sderaadt { 524df930be7Sderaadt if (xdr_u_long(xdrs, &(cap->rmt_port))) 525df930be7Sderaadt return (xdr_encap_parms(xdrs, &(cap->rmt_args))); 526df930be7Sderaadt return (FALSE); 527df930be7Sderaadt } 528df930be7Sderaadt 529df930be7Sderaadt /* 530df930be7Sderaadt * only worries about the struct encap_parms part of struct rmtcallargs. 531df930be7Sderaadt * The arglen must already be set!! 532df930be7Sderaadt */ 533df930be7Sderaadt static bool_t 53446aa5dceSderaadt xdr_opaque_parms(XDR *xdrs, struct rmtcallargs *cap) 535df930be7Sderaadt { 536df930be7Sderaadt 537df930be7Sderaadt return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen)); 538df930be7Sderaadt } 539df930be7Sderaadt 540df930be7Sderaadt /* 541df930be7Sderaadt * This routine finds and sets the length of incoming opaque paraters 542df930be7Sderaadt * and then calls xdr_opaque_parms. 543df930be7Sderaadt */ 544df930be7Sderaadt static bool_t 54546aa5dceSderaadt xdr_len_opaque_parms(XDR *xdrs, struct rmtcallargs *cap) 546df930be7Sderaadt { 5470ac0d02eSmpech u_int beginpos, lowpos, highpos, currpos, pos; 548df930be7Sderaadt 549df930be7Sderaadt beginpos = lowpos = pos = xdr_getpos(xdrs); 550df930be7Sderaadt highpos = lowpos + ARGSIZE; 551591391d8Stedu while (highpos >= lowpos) { 552df930be7Sderaadt currpos = (lowpos + highpos) / 2; 553df930be7Sderaadt if (xdr_setpos(xdrs, currpos)) { 554df930be7Sderaadt pos = currpos; 555df930be7Sderaadt lowpos = currpos + 1; 556df930be7Sderaadt } else { 557df930be7Sderaadt highpos = currpos - 1; 558df930be7Sderaadt } 559df930be7Sderaadt } 560df930be7Sderaadt xdr_setpos(xdrs, beginpos); 561df930be7Sderaadt cap->rmt_args.arglen = pos - beginpos; 562df930be7Sderaadt return (xdr_opaque_parms(xdrs, cap)); 563df930be7Sderaadt } 564df930be7Sderaadt 565df930be7Sderaadt /* 566df930be7Sderaadt * Call a remote procedure service 567df930be7Sderaadt * This procedure is very quiet when things go wrong. 568df930be7Sderaadt * The proc is written to support broadcast rpc. In the broadcast case, 569df930be7Sderaadt * a machine should shut-up instead of complain, less the requestor be 570df930be7Sderaadt * overrun with complaints at the expense of not hearing a valid reply ... 571df930be7Sderaadt * 572df930be7Sderaadt * This now forks so that the program & process that it calls can call 573df930be7Sderaadt * back to the portmapper. 574df930be7Sderaadt */ 575d91d7659Sderaadt void 57646aa5dceSderaadt callit(struct svc_req *rqstp, SVCXPRT *xprt) 577df930be7Sderaadt { 578df930be7Sderaadt struct rmtcallargs a; 579df930be7Sderaadt struct pmaplist *pml; 580df930be7Sderaadt u_short port; 581df930be7Sderaadt struct sockaddr_in me; 58248822293Sderaadt pid_t pid; 5834f68b03bSguenther int so = -1; 584df930be7Sderaadt CLIENT *client; 585df930be7Sderaadt struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred; 586df930be7Sderaadt struct timeval timeout; 587df930be7Sderaadt char buf[ARGSIZE]; 588df930be7Sderaadt 589df930be7Sderaadt timeout.tv_sec = 5; 590df930be7Sderaadt timeout.tv_usec = 0; 591df930be7Sderaadt a.rmt_args.args = buf; 592c1198d48Sguenther if (!svc_getargs(xprt, portmap_xdr_rmtcall_args, (caddr_t)&a)) 593df930be7Sderaadt return; 594f99230ebSdhill if (!check_callit(svc_getcaller(xprt), a.rmt_prog, a.rmt_proc)) 595f94670b8Sderaadt return; 596df930be7Sderaadt if ((pml = find_service(a.rmt_prog, a.rmt_vers, 597df930be7Sderaadt (u_long)IPPROTO_UDP)) == NULL) 598df930be7Sderaadt return; 59977baebbfSderaadt 600df930be7Sderaadt /* 601df930be7Sderaadt * fork a child to do the work. Parent immediately returns. 602df930be7Sderaadt * Child exits upon completion. 603df930be7Sderaadt */ 604df930be7Sderaadt if ((pid = fork()) != 0) { 605df930be7Sderaadt if (pid == -1) 606df930be7Sderaadt syslog(LOG_ERR, "CALLIT (prog %lu): fork: %m", 607df930be7Sderaadt a.rmt_prog); 608df930be7Sderaadt return; 609df930be7Sderaadt } 610a828131dSderaadt 611*0bd1216cSderaadt if (pledge("stdio rpath inet", NULL) == -1) 612*0bd1216cSderaadt err(1, "pledge"); 613a828131dSderaadt 614df930be7Sderaadt port = pml->pml_map.pm_port; 615df930be7Sderaadt get_myaddress(&me); 616df930be7Sderaadt me.sin_port = htons(port); 617df930be7Sderaadt 618df930be7Sderaadt /* Avoid implicit binding to reserved port by clntudp_create() */ 6194f68b03bSguenther so = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); 620df930be7Sderaadt if (so == -1) 621df930be7Sderaadt exit(1); 622df930be7Sderaadt 623df930be7Sderaadt client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &so); 624591391d8Stedu if (client != NULL) { 62577baebbfSderaadt if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) 626df930be7Sderaadt client->cl_auth = authunix_create(au->aup_machname, 627df930be7Sderaadt au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids); 628df930be7Sderaadt a.rmt_port = (u_long)port; 629df930be7Sderaadt if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a, 63077baebbfSderaadt xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) 631c1198d48Sguenther svc_sendreply(xprt, portmap_xdr_rmtcallres, (caddr_t)&a); 632df930be7Sderaadt AUTH_DESTROY(client->cl_auth); 633df930be7Sderaadt clnt_destroy(client); 634df930be7Sderaadt } 635df930be7Sderaadt (void)close(so); 636df930be7Sderaadt exit(0); 637df930be7Sderaadt } 638df930be7Sderaadt 6399d48a621Sderaadt /* ARGSUSED */ 640df930be7Sderaadt void 64183e8fa08Sderaadt reap(int signo) 642df930be7Sderaadt { 643df930be7Sderaadt int save_errno = errno; 644df930be7Sderaadt 6457af3e1e5Sderaadt while (wait3(NULL, WNOHANG, NULL) > 0) 646df930be7Sderaadt ; 647df930be7Sderaadt errno = save_errno; 648df930be7Sderaadt } 649f94670b8Sderaadt 650f94670b8Sderaadt #define NFSPROG ((u_long) 100003) 651f94670b8Sderaadt #define MOUNTPROG ((u_long) 100005) 652f94670b8Sderaadt #define YPXPROG ((u_long) 100069) 653f94670b8Sderaadt #define YPPROG ((u_long) 100004) 654f94670b8Sderaadt #define YPPROC_DOMAIN_NONACK ((u_long) 2) 655f94670b8Sderaadt #define MOUNTPROC_MNT ((u_long) 1) 6569d791f75Sderaadt #define XXXPROC_NOP ((u_long) 0) 657f94670b8Sderaadt 658f94670b8Sderaadt int 659f99230ebSdhill check_callit(struct sockaddr_in *addr, u_long prog, u_long aproc) 660f94670b8Sderaadt { 6619d791f75Sderaadt if ((prog == PMAPPROG && aproc != XXXPROC_NOP) || 6629d791f75Sderaadt (prog == NFSPROG && aproc != XXXPROC_NOP) || 6639d791f75Sderaadt (prog == YPXPROG && aproc != XXXPROC_NOP) || 664f94670b8Sderaadt (prog == MOUNTPROG && aproc == MOUNTPROC_MNT) || 665f94670b8Sderaadt (prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) { 666f94670b8Sderaadt syslog(LOG_WARNING, 667591391d8Stedu "callit prog %ld aproc %ld (might be from %s)", 668591391d8Stedu prog, aproc, inet_ntoa(addr->sin_addr)); 669f94670b8Sderaadt return (FALSE); 670f94670b8Sderaadt } 671f94670b8Sderaadt return (TRUE); 672f94670b8Sderaadt } 673