1*ac4529faSthib /* $OpenBSD: portmap.c,v 1.37 2009/05/20 20:37:43 thib 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 #ifndef lint 34df930be7Sderaadt char copyright[] = 35df930be7Sderaadt "@(#) Copyright (c) 1990 The Regents of the University of California.\n\ 36df930be7Sderaadt All rights reserved.\n"; 37df930be7Sderaadt #endif /* not lint */ 38df930be7Sderaadt 39df930be7Sderaadt #ifndef lint 40456a2117Smillert #if 0 41456a2117Smillert static char sccsid[] = "from: @(#)portmap.c 5.4 (Berkeley) 4/19/91"; 42456a2117Smillert #else 43*ac4529faSthib static char rcsid[] = "$OpenBSD: portmap.c,v 1.37 2009/05/20 20:37:43 thib Exp $"; 44456a2117Smillert #endif 45df930be7Sderaadt #endif /* not lint */ 46df930be7Sderaadt 47df930be7Sderaadt /* 48df930be7Sderaadt @(#)portmap.c 2.3 88/08/11 4.0 RPCSRC 49df930be7Sderaadt static char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro"; 50df930be7Sderaadt */ 51df930be7Sderaadt 52df930be7Sderaadt /* 53df930be7Sderaadt * portmap.c, Implements the program,version to port number mapping for 54df930be7Sderaadt * rpc. 55df930be7Sderaadt */ 56df930be7Sderaadt 57df930be7Sderaadt /* 58df930be7Sderaadt * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 59df930be7Sderaadt * unrestricted use provided that this legend is included on all tape 60df930be7Sderaadt * media and as a part of the software program in whole or part. Users 61df930be7Sderaadt * may copy or modify Sun RPC without charge, but are not authorized 62df930be7Sderaadt * to license or distribute it to anyone else except as part of a product or 63df930be7Sderaadt * program developed by the user. 64df930be7Sderaadt * 65df930be7Sderaadt * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 66df930be7Sderaadt * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 67df930be7Sderaadt * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 68df930be7Sderaadt * 69df930be7Sderaadt * Sun RPC is provided with no support and without any obligation on the 70df930be7Sderaadt * part of Sun Microsystems, Inc. to assist in its use, correction, 71df930be7Sderaadt * modification or enhancement. 72df930be7Sderaadt * 73df930be7Sderaadt * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 74df930be7Sderaadt * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 75df930be7Sderaadt * OR ANY PART THEREOF. 76df930be7Sderaadt * 77df930be7Sderaadt * In no event will Sun Microsystems, Inc. be liable for any lost revenue 78df930be7Sderaadt * or profits or other special, indirect and consequential damages, even if 79df930be7Sderaadt * Sun has been advised of the possibility of such damages. 80df930be7Sderaadt * 81df930be7Sderaadt * Sun Microsystems, Inc. 82df930be7Sderaadt * 2550 Garcia Avenue 83df930be7Sderaadt * Mountain View, California 94043 84df930be7Sderaadt */ 85df930be7Sderaadt 86606f45d1Smillert #include <sys/types.h> 87606f45d1Smillert #include <sys/socket.h> 88606f45d1Smillert #include <sys/ioctl.h> 89606f45d1Smillert #include <sys/wait.h> 90606f45d1Smillert #include <sys/resource.h> 91606f45d1Smillert 92606f45d1Smillert #include <rpcsvc/nfs_prot.h> 93606f45d1Smillert #include <arpa/inet.h> 94df930be7Sderaadt #include <rpc/rpc.h> 95df930be7Sderaadt #include <rpc/pmap_prot.h> 96606f45d1Smillert 97606f45d1Smillert #include <signal.h> 98df930be7Sderaadt #include <stdio.h> 99df930be7Sderaadt #include <stdlib.h> 100df930be7Sderaadt #include <string.h> 101df930be7Sderaadt #include <syslog.h> 102df930be7Sderaadt #include <unistd.h> 103df930be7Sderaadt #include <netdb.h> 10446aa5dceSderaadt #include <pwd.h> 10553a76164Stedu #include <errno.h> 106df930be7Sderaadt 107c72b5b24Smillert void reg_service(struct svc_req *, SVCXPRT *); 10883e8fa08Sderaadt void reap(int); 109c72b5b24Smillert void callit(struct svc_req *, SVCXPRT *); 110f99230ebSdhill int check_callit(struct sockaddr_in *, u_long, u_long); 111f99230ebSdhill struct pmaplist *find_service(u_long, u_long, u_long); 112df930be7Sderaadt 113df930be7Sderaadt struct pmaplist *pmaplist; 114df930be7Sderaadt int debugging = 0; 115df930be7Sderaadt 11677baebbfSderaadt SVCXPRT *ludpxprt, *ltcpxprt; 11777baebbfSderaadt 118d91d7659Sderaadt int 11946aa5dceSderaadt main(int argc, char *argv[]) 120df930be7Sderaadt { 12146aa5dceSderaadt int sock, lsock, c, on = 1, len = sizeof(struct sockaddr_in); 12277baebbfSderaadt struct sockaddr_in addr, laddr; 1230ac0d02eSmpech struct pmaplist *pml; 1240f99c42cSderaadt struct passwd *pw; 12546aa5dceSderaadt SVCXPRT *xprt; 126df930be7Sderaadt 12772799b18Smillert while ((c = getopt(argc, argv, "d")) != -1) { 128df930be7Sderaadt switch (c) { 129df930be7Sderaadt 130df930be7Sderaadt case 'd': 131df930be7Sderaadt debugging = 1; 132df930be7Sderaadt break; 133df930be7Sderaadt 134df930be7Sderaadt default: 135df930be7Sderaadt (void) fprintf(stderr, "usage: %s [-d]\n", argv[0]); 136df930be7Sderaadt exit(1); 137df930be7Sderaadt } 138df930be7Sderaadt } 139df930be7Sderaadt 140df930be7Sderaadt if (!debugging && daemon(0, 0)) { 141df930be7Sderaadt (void) fprintf(stderr, "portmap: fork: %s", strerror(errno)); 142df930be7Sderaadt exit(1); 143df930be7Sderaadt } 144df930be7Sderaadt 145b1afbf54Sderaadt openlog("portmap", LOG_NDELAY | (debugging ? LOG_PID | LOG_PERROR : LOG_PID), 146df930be7Sderaadt LOG_DAEMON); 147df930be7Sderaadt 14877baebbfSderaadt bzero((char *)&addr, sizeof addr); 14977baebbfSderaadt addr.sin_addr.s_addr = 0; 15077baebbfSderaadt addr.sin_family = AF_INET; 15177baebbfSderaadt addr.sin_addr.s_addr = htonl(INADDR_ANY); 15277baebbfSderaadt addr.sin_port = htons(PMAPPORT); 15377baebbfSderaadt 15477baebbfSderaadt bzero((char *)&laddr, sizeof laddr); 15577baebbfSderaadt laddr.sin_addr.s_addr = 0; 15677baebbfSderaadt laddr.sin_family = AF_INET; 15777baebbfSderaadt laddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 15877baebbfSderaadt laddr.sin_port = htons(PMAPPORT); 15977baebbfSderaadt 160df930be7Sderaadt if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 161df930be7Sderaadt syslog(LOG_ERR, "cannot create udp socket: %m"); 162df930be7Sderaadt exit(1); 163df930be7Sderaadt } 164afeed3b4Sderaadt setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on); 165df930be7Sderaadt if (bind(sock, (struct sockaddr *)&addr, len) != 0) { 166df930be7Sderaadt syslog(LOG_ERR, "cannot bind udp: %m"); 167df930be7Sderaadt exit(1); 168df930be7Sderaadt } 169df930be7Sderaadt 170df930be7Sderaadt if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) { 171df930be7Sderaadt syslog(LOG_ERR, "couldn't do udp_create"); 172df930be7Sderaadt exit(1); 173df930be7Sderaadt } 17477baebbfSderaadt 17577baebbfSderaadt if ((lsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 17677baebbfSderaadt syslog(LOG_ERR, "cannot create udp socket: %m"); 17777baebbfSderaadt exit(1); 17877baebbfSderaadt } 17977baebbfSderaadt setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on); 18077baebbfSderaadt if (bind(lsock, (struct sockaddr *)&laddr, len) != 0) { 1817e963911Smickey syslog(LOG_ERR, "cannot bind local udp: %m"); 18277baebbfSderaadt exit(1); 18377baebbfSderaadt } 18477baebbfSderaadt 18577baebbfSderaadt if ((ludpxprt = svcudp_create(lsock)) == (SVCXPRT *)NULL) { 18677baebbfSderaadt syslog(LOG_ERR, "couldn't do udp_create"); 18777baebbfSderaadt exit(1); 18877baebbfSderaadt } 18977baebbfSderaadt 190df930be7Sderaadt /* make an entry for ourself */ 191df930be7Sderaadt pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist)); 192acfba6e6Sderaadt if (pml == NULL) { 193acfba6e6Sderaadt syslog(LOG_ERR, "out of memory"); 194acfba6e6Sderaadt exit(1); 195acfba6e6Sderaadt } 196df930be7Sderaadt pml->pml_next = 0; 197df930be7Sderaadt pml->pml_map.pm_prog = PMAPPROG; 198df930be7Sderaadt pml->pml_map.pm_vers = PMAPVERS; 199df930be7Sderaadt pml->pml_map.pm_prot = IPPROTO_UDP; 200df930be7Sderaadt pml->pml_map.pm_port = PMAPPORT; 201df930be7Sderaadt pmaplist = pml; 202df930be7Sderaadt 203df930be7Sderaadt if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 204df930be7Sderaadt syslog(LOG_ERR, "cannot create tcp socket: %m"); 205df930be7Sderaadt exit(1); 206df930be7Sderaadt } 207afeed3b4Sderaadt setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on); 208df930be7Sderaadt if (bind(sock, (struct sockaddr *)&addr, len) != 0) { 209da52f073Sderaadt syslog(LOG_ERR, "cannot bind tcp: %m"); 210df930be7Sderaadt exit(1); 211df930be7Sderaadt } 212df930be7Sderaadt if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE)) 213df930be7Sderaadt == (SVCXPRT *)NULL) { 214df930be7Sderaadt syslog(LOG_ERR, "couldn't do tcp_create"); 215df930be7Sderaadt exit(1); 216df930be7Sderaadt } 21777baebbfSderaadt 21877baebbfSderaadt if ((lsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 21977baebbfSderaadt syslog(LOG_ERR, "cannot create tcp socket: %m"); 22077baebbfSderaadt exit(1); 22177baebbfSderaadt } 22277baebbfSderaadt setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on); 22377baebbfSderaadt if (bind(lsock, (struct sockaddr *)&laddr, len) != 0) { 224da52f073Sderaadt syslog(LOG_ERR, "cannot bind tcp: %m"); 22577baebbfSderaadt exit(1); 22677baebbfSderaadt } 22777baebbfSderaadt if ((ltcpxprt = svctcp_create(lsock, RPCSMALLMSGSIZE, 22877baebbfSderaadt RPCSMALLMSGSIZE)) == (SVCXPRT *)NULL) { 22977baebbfSderaadt syslog(LOG_ERR, "couldn't do tcp_create"); 23077baebbfSderaadt exit(1); 23177baebbfSderaadt } 23277baebbfSderaadt 233df930be7Sderaadt /* make an entry for ourself */ 234df930be7Sderaadt pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist)); 235acfba6e6Sderaadt if (pml == NULL) { 236acfba6e6Sderaadt syslog(LOG_ERR, "out of memory"); 237acfba6e6Sderaadt exit(1); 238acfba6e6Sderaadt } 239df930be7Sderaadt pml->pml_map.pm_prog = PMAPPROG; 240df930be7Sderaadt pml->pml_map.pm_vers = PMAPVERS; 241df930be7Sderaadt pml->pml_map.pm_prot = IPPROTO_TCP; 242df930be7Sderaadt pml->pml_map.pm_port = PMAPPORT; 243df930be7Sderaadt pml->pml_next = pmaplist; 244df930be7Sderaadt pmaplist = pml; 245df930be7Sderaadt 246*ac4529faSthib 247*ac4529faSthib if ((pw = getpwnam("_portmap")) == NULL) { 248*ac4529faSthib syslog(LOG_ERR, "no such user _portmap"); 249*ac4529faSthib exit(1); 250*ac4529faSthib } 2510f99c42cSderaadt if (chroot("/var/empty") == -1) { 2520f99c42cSderaadt syslog(LOG_ERR, "cannot chdir to /var/empty."); 2530f99c42cSderaadt exit(1); 2540f99c42cSderaadt } 255*ac4529faSthib 2560f99c42cSderaadt chdir("/"); 2570f99c42cSderaadt if (pw) { 2585bb60d39Sdjm if (setgroups(1, &pw->pw_gid) == -1 || 2595bb60d39Sdjm setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 || 2605bb60d39Sdjm setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) { 2615bb60d39Sdjm syslog(LOG_ERR, "revoke privs: %s", strerror(errno)); 2625bb60d39Sdjm exit(1); 2635bb60d39Sdjm } 2640f99c42cSderaadt } 265cb074343Shenning endpwent(); 2660f99c42cSderaadt 2675b63b19eSpvalchev if (svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE) == 0) { 2685b63b19eSpvalchev syslog(LOG_ERR, "svc_register failed."); 2695b63b19eSpvalchev exit(1); 2705b63b19eSpvalchev } 271df930be7Sderaadt 272606f45d1Smillert (void)signal(SIGCHLD, reap); 273df930be7Sderaadt svc_run(); 274da52f073Sderaadt syslog(LOG_ERR, "svc_run returned unexpectedly"); 275df930be7Sderaadt abort(); 276df930be7Sderaadt } 277df930be7Sderaadt 278df930be7Sderaadt #ifndef lint 279df930be7Sderaadt /* need to override perror calls in rpc library */ 280df930be7Sderaadt void 28146aa5dceSderaadt perror(const char *what) 282df930be7Sderaadt { 283df930be7Sderaadt 284df930be7Sderaadt syslog(LOG_ERR, "%s: %m", what); 285df930be7Sderaadt } 286df930be7Sderaadt #endif 287df930be7Sderaadt 2883aef48d5Sderaadt struct pmaplist * 28946aa5dceSderaadt find_service(u_long prog, u_long vers, u_long prot) 290df930be7Sderaadt { 2910ac0d02eSmpech struct pmaplist *hit = NULL; 2920ac0d02eSmpech struct pmaplist *pml; 293df930be7Sderaadt 294df930be7Sderaadt for (pml = pmaplist; pml != NULL; pml = pml->pml_next) { 295df930be7Sderaadt if ((pml->pml_map.pm_prog != prog) || 296df930be7Sderaadt (pml->pml_map.pm_prot != prot)) 297df930be7Sderaadt continue; 298df930be7Sderaadt hit = pml; 299df930be7Sderaadt if (pml->pml_map.pm_vers == vers) 300df930be7Sderaadt break; 301df930be7Sderaadt } 302df930be7Sderaadt return (hit); 303df930be7Sderaadt } 304df930be7Sderaadt 305df930be7Sderaadt /* 306df930be7Sderaadt * 1 OK, 0 not 307df930be7Sderaadt */ 308df930be7Sderaadt void 30946aa5dceSderaadt reg_service(struct svc_req *rqstp, SVCXPRT *xprt) 310df930be7Sderaadt { 311df930be7Sderaadt struct pmap reg; 312df930be7Sderaadt struct pmaplist *pml, *prevpml, *fnd; 31377baebbfSderaadt struct sockaddr_in *fromsin; 31477baebbfSderaadt long ans = 0, port; 315df930be7Sderaadt caddr_t t; 316df930be7Sderaadt 31777baebbfSderaadt fromsin = svc_getcaller(xprt); 31877baebbfSderaadt 319df930be7Sderaadt if (debugging) 320df930be7Sderaadt (void) fprintf(stderr, "server: about to do a switch\n"); 321df930be7Sderaadt switch (rqstp->rq_proc) { 322df930be7Sderaadt 323df930be7Sderaadt case PMAPPROC_NULL: 324df930be7Sderaadt /* 325df930be7Sderaadt * Null proc call 326df930be7Sderaadt */ 327df930be7Sderaadt if (!svc_sendreply(xprt, xdr_void, (caddr_t)0) && debugging) { 328df930be7Sderaadt abort(); 329df930be7Sderaadt } 330df930be7Sderaadt break; 331df930be7Sderaadt 332df930be7Sderaadt case PMAPPROC_SET: 333df930be7Sderaadt /* 334df930be7Sderaadt * Set a program,version to port mapping 335df930be7Sderaadt */ 33677baebbfSderaadt if (xprt != ltcpxprt && xprt != ludpxprt) { 33777baebbfSderaadt syslog(LOG_WARNING, 33877baebbfSderaadt "non-local set attempt (might be from %s)", 3399430a6aeSderaadt inet_ntoa(fromsin->sin_addr)); 34077baebbfSderaadt svcerr_noproc(xprt); 34177baebbfSderaadt return; 34277baebbfSderaadt } 34360cef36bSderaadt if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®)) { 344df930be7Sderaadt svcerr_decode(xprt); 34560cef36bSderaadt break; 34660cef36bSderaadt } 3473aef48d5Sderaadt 348df930be7Sderaadt /* 349df930be7Sderaadt * check to see if already used 350df930be7Sderaadt * find_service returns a hit even if 351df930be7Sderaadt * the versions don't match, so check for it 352df930be7Sderaadt */ 353df930be7Sderaadt fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); 354df930be7Sderaadt if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) { 35577baebbfSderaadt if (fnd->pml_map.pm_port == reg.pm_port) 356df930be7Sderaadt ans = 1; 357df930be7Sderaadt goto done; 358df930be7Sderaadt } 35977baebbfSderaadt 360a982d679Sderaadt if (debugging) 36131cea007Spvalchev printf("set: prog %lu vers %lu port %lu\n", 362a982d679Sderaadt reg.pm_prog, reg.pm_vers, reg.pm_port); 363a982d679Sderaadt 364a982d679Sderaadt if (reg.pm_port & ~0xffff) 365a982d679Sderaadt goto done; 366a982d679Sderaadt 367a982d679Sderaadt /* 368a982d679Sderaadt * only permit localhost root to create 369a982d679Sderaadt * mappings pointing at sensitive ports 370a982d679Sderaadt */ 371a982d679Sderaadt if ((reg.pm_port < IPPORT_RESERVED || 372a982d679Sderaadt reg.pm_port == NFS_PORT) && 37377baebbfSderaadt htons(fromsin->sin_port) >= IPPORT_RESERVED) { 374a982d679Sderaadt syslog(LOG_WARNING, 375a982d679Sderaadt "resvport set attempt by non-root"); 376df930be7Sderaadt goto done; 377df930be7Sderaadt } 37877baebbfSderaadt 379df930be7Sderaadt /* 380df930be7Sderaadt * add to END of list 381df930be7Sderaadt */ 38260cef36bSderaadt pml = (struct pmaplist *)malloc(sizeof(struct pmaplist)); 383acfba6e6Sderaadt if (pml == NULL) { 384acfba6e6Sderaadt syslog(LOG_ERR, "out of memory"); 385acfba6e6Sderaadt svcerr_systemerr(xprt); 386acfba6e6Sderaadt return; 387acfba6e6Sderaadt } 388acfba6e6Sderaadt 389df930be7Sderaadt pml->pml_map = reg; 390df930be7Sderaadt pml->pml_next = 0; 391df930be7Sderaadt if (pmaplist == 0) { 392df930be7Sderaadt pmaplist = pml; 393df930be7Sderaadt } else { 394df930be7Sderaadt for (fnd = pmaplist; fnd->pml_next != 0; 395df930be7Sderaadt fnd = fnd->pml_next); 396df930be7Sderaadt fnd->pml_next = pml; 397df930be7Sderaadt } 398df930be7Sderaadt ans = 1; 399df930be7Sderaadt done: 400df930be7Sderaadt if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && 401df930be7Sderaadt debugging) { 402df930be7Sderaadt (void) fprintf(stderr, "svc_sendreply\n"); 403df930be7Sderaadt abort(); 404df930be7Sderaadt } 405df930be7Sderaadt break; 406df930be7Sderaadt 407df930be7Sderaadt case PMAPPROC_UNSET: 408df930be7Sderaadt /* 409df930be7Sderaadt * Remove a program,version to port mapping. 410df930be7Sderaadt */ 41177baebbfSderaadt if (xprt != ltcpxprt && xprt != ludpxprt) { 41277baebbfSderaadt syslog(LOG_WARNING, 41377baebbfSderaadt "non-local unset attempt (might be from %s)", 4149430a6aeSderaadt inet_ntoa(fromsin->sin_addr)); 41577baebbfSderaadt svcerr_noproc(xprt); 41677baebbfSderaadt return; 41777baebbfSderaadt } 41877baebbfSderaadt if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®)) { 419df930be7Sderaadt svcerr_decode(xprt); 42077baebbfSderaadt break; 42177baebbfSderaadt } 422df930be7Sderaadt for (prevpml = NULL, pml = pmaplist; pml != NULL; ) { 423df930be7Sderaadt if ((pml->pml_map.pm_prog != reg.pm_prog) || 424df930be7Sderaadt (pml->pml_map.pm_vers != reg.pm_vers)) { 425df930be7Sderaadt /* both pml & prevpml move forwards */ 426df930be7Sderaadt prevpml = pml; 427df930be7Sderaadt pml = pml->pml_next; 428df930be7Sderaadt continue; 429df930be7Sderaadt } 43077baebbfSderaadt if ((pml->pml_map.pm_port < IPPORT_RESERVED || 43177baebbfSderaadt pml->pml_map.pm_port == NFS_PORT) && 43277baebbfSderaadt htons(fromsin->sin_port) >= IPPORT_RESERVED) { 43377baebbfSderaadt syslog(LOG_WARNING, 43477baebbfSderaadt "resvport unset attempt by non-root"); 43577baebbfSderaadt break; 43677baebbfSderaadt } 43777baebbfSderaadt 438df930be7Sderaadt /* found it; pml moves forward, prevpml stays */ 439df930be7Sderaadt ans = 1; 440df930be7Sderaadt t = (caddr_t)pml; 441df930be7Sderaadt pml = pml->pml_next; 442df930be7Sderaadt if (prevpml == NULL) 443df930be7Sderaadt pmaplist = pml; 444df930be7Sderaadt else 445df930be7Sderaadt prevpml->pml_next = pml; 446df930be7Sderaadt free(t); 447df930be7Sderaadt } 448df930be7Sderaadt if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && 449df930be7Sderaadt debugging) { 45060cef36bSderaadt fprintf(stderr, "svc_sendreply\n"); 451df930be7Sderaadt abort(); 452df930be7Sderaadt } 453df930be7Sderaadt break; 454df930be7Sderaadt 455df930be7Sderaadt case PMAPPROC_GETPORT: 456df930be7Sderaadt /* 457df930be7Sderaadt * Lookup the mapping for a program,version and return its port 458df930be7Sderaadt */ 45960cef36bSderaadt if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®)) { 460df930be7Sderaadt svcerr_decode(xprt); 46160cef36bSderaadt break; 46260cef36bSderaadt } 463df930be7Sderaadt fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); 464df930be7Sderaadt if (fnd) 465df930be7Sderaadt port = fnd->pml_map.pm_port; 466df930be7Sderaadt else 467df930be7Sderaadt port = 0; 468df930be7Sderaadt if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) && 469df930be7Sderaadt debugging) { 47060cef36bSderaadt fprintf(stderr, "svc_sendreply\n"); 471df930be7Sderaadt abort(); 472df930be7Sderaadt } 473df930be7Sderaadt break; 474df930be7Sderaadt 475df930be7Sderaadt case PMAPPROC_DUMP: 476df930be7Sderaadt /* 477df930be7Sderaadt * Return the current set of mapped program,version 478df930be7Sderaadt */ 47960cef36bSderaadt if (!svc_getargs(xprt, xdr_void, NULL)) { 480df930be7Sderaadt svcerr_decode(xprt); 48160cef36bSderaadt break; 48260cef36bSderaadt } 48360cef36bSderaadt if (!svc_sendreply(xprt, xdr_pmaplist, (caddr_t)&pmaplist) && 48460cef36bSderaadt debugging) { 48560cef36bSderaadt fprintf(stderr, "svc_sendreply\n"); 486df930be7Sderaadt abort(); 487df930be7Sderaadt } 488df930be7Sderaadt break; 489df930be7Sderaadt 490df930be7Sderaadt case PMAPPROC_CALLIT: 491df930be7Sderaadt /* 492df930be7Sderaadt * Calls a procedure on the local machine. If the requested 493df930be7Sderaadt * procedure is not registered this procedure does not return 494df930be7Sderaadt * error information!! 495df930be7Sderaadt * This procedure is only supported on rpc/udp and calls via 496df930be7Sderaadt * rpc/udp. It passes null authentication parameters. 497df930be7Sderaadt */ 498df930be7Sderaadt callit(rqstp, xprt); 499df930be7Sderaadt break; 500df930be7Sderaadt 501df930be7Sderaadt default: 502df930be7Sderaadt svcerr_noproc(xprt); 503df930be7Sderaadt break; 504df930be7Sderaadt } 505df930be7Sderaadt } 506df930be7Sderaadt 507df930be7Sderaadt 508df930be7Sderaadt /* 509df930be7Sderaadt * Stuff for the rmtcall service 510df930be7Sderaadt */ 511df930be7Sderaadt #define ARGSIZE 9000 512df930be7Sderaadt 513df930be7Sderaadt struct encap_parms { 514df930be7Sderaadt u_int arglen; 515df930be7Sderaadt char *args; 516df930be7Sderaadt }; 517df930be7Sderaadt 518df930be7Sderaadt static bool_t 51946aa5dceSderaadt xdr_encap_parms(XDR *xdrs, struct encap_parms *epp) 520df930be7Sderaadt { 521df930be7Sderaadt 522df930be7Sderaadt return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE)); 523df930be7Sderaadt } 524df930be7Sderaadt 525df930be7Sderaadt struct rmtcallargs { 526df930be7Sderaadt u_long rmt_prog; 527df930be7Sderaadt u_long rmt_vers; 528df930be7Sderaadt u_long rmt_port; 529df930be7Sderaadt u_long rmt_proc; 530df930be7Sderaadt struct encap_parms rmt_args; 531df930be7Sderaadt }; 532df930be7Sderaadt 533df930be7Sderaadt static bool_t 53446aa5dceSderaadt xdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap) 535df930be7Sderaadt { 536df930be7Sderaadt 537df930be7Sderaadt /* does not get a port number */ 538df930be7Sderaadt if (xdr_u_long(xdrs, &(cap->rmt_prog)) && 539df930be7Sderaadt xdr_u_long(xdrs, &(cap->rmt_vers)) && 540df930be7Sderaadt xdr_u_long(xdrs, &(cap->rmt_proc))) { 541df930be7Sderaadt return (xdr_encap_parms(xdrs, &(cap->rmt_args))); 542df930be7Sderaadt } 543df930be7Sderaadt return (FALSE); 544df930be7Sderaadt } 545df930be7Sderaadt 546df930be7Sderaadt static bool_t 54746aa5dceSderaadt xdr_rmtcall_result(XDR *xdrs, struct rmtcallargs *cap) 548df930be7Sderaadt { 549df930be7Sderaadt if (xdr_u_long(xdrs, &(cap->rmt_port))) 550df930be7Sderaadt return (xdr_encap_parms(xdrs, &(cap->rmt_args))); 551df930be7Sderaadt return (FALSE); 552df930be7Sderaadt } 553df930be7Sderaadt 554df930be7Sderaadt /* 555df930be7Sderaadt * only worries about the struct encap_parms part of struct rmtcallargs. 556df930be7Sderaadt * The arglen must already be set!! 557df930be7Sderaadt */ 558df930be7Sderaadt static bool_t 55946aa5dceSderaadt xdr_opaque_parms(XDR *xdrs, struct rmtcallargs *cap) 560df930be7Sderaadt { 561df930be7Sderaadt 562df930be7Sderaadt return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen)); 563df930be7Sderaadt } 564df930be7Sderaadt 565df930be7Sderaadt /* 566df930be7Sderaadt * This routine finds and sets the length of incoming opaque paraters 567df930be7Sderaadt * and then calls xdr_opaque_parms. 568df930be7Sderaadt */ 569df930be7Sderaadt static bool_t 57046aa5dceSderaadt xdr_len_opaque_parms(XDR *xdrs, struct rmtcallargs *cap) 571df930be7Sderaadt { 5720ac0d02eSmpech u_int beginpos, lowpos, highpos, currpos, pos; 573df930be7Sderaadt 574df930be7Sderaadt beginpos = lowpos = pos = xdr_getpos(xdrs); 575df930be7Sderaadt highpos = lowpos + ARGSIZE; 576df930be7Sderaadt while ((int)(highpos - lowpos) >= 0) { 577df930be7Sderaadt currpos = (lowpos + highpos) / 2; 578df930be7Sderaadt if (xdr_setpos(xdrs, currpos)) { 579df930be7Sderaadt pos = currpos; 580df930be7Sderaadt lowpos = currpos + 1; 581df930be7Sderaadt } else { 582df930be7Sderaadt highpos = currpos - 1; 583df930be7Sderaadt } 584df930be7Sderaadt } 585df930be7Sderaadt xdr_setpos(xdrs, beginpos); 586df930be7Sderaadt cap->rmt_args.arglen = pos - beginpos; 587df930be7Sderaadt return (xdr_opaque_parms(xdrs, cap)); 588df930be7Sderaadt } 589df930be7Sderaadt 590df930be7Sderaadt /* 591df930be7Sderaadt * Call a remote procedure service 592df930be7Sderaadt * This procedure is very quiet when things go wrong. 593df930be7Sderaadt * The proc is written to support broadcast rpc. In the broadcast case, 594df930be7Sderaadt * a machine should shut-up instead of complain, less the requestor be 595df930be7Sderaadt * overrun with complaints at the expense of not hearing a valid reply ... 596df930be7Sderaadt * 597df930be7Sderaadt * This now forks so that the program & process that it calls can call 598df930be7Sderaadt * back to the portmapper. 599df930be7Sderaadt */ 600d91d7659Sderaadt void 60146aa5dceSderaadt callit(struct svc_req *rqstp, SVCXPRT *xprt) 602df930be7Sderaadt { 603df930be7Sderaadt struct rmtcallargs a; 604df930be7Sderaadt struct pmaplist *pml; 605df930be7Sderaadt u_short port; 606df930be7Sderaadt struct sockaddr_in me; 60748822293Sderaadt pid_t pid; 60848822293Sderaadt int so = -1, dontblock = 1; 609df930be7Sderaadt CLIENT *client; 610df930be7Sderaadt struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred; 611df930be7Sderaadt struct timeval timeout; 612df930be7Sderaadt char buf[ARGSIZE]; 613df930be7Sderaadt 614df930be7Sderaadt timeout.tv_sec = 5; 615df930be7Sderaadt timeout.tv_usec = 0; 616df930be7Sderaadt a.rmt_args.args = buf; 617df930be7Sderaadt if (!svc_getargs(xprt, xdr_rmtcall_args, (caddr_t)&a)) 618df930be7Sderaadt return; 619f99230ebSdhill if (!check_callit(svc_getcaller(xprt), a.rmt_prog, a.rmt_proc)) 620f94670b8Sderaadt return; 621df930be7Sderaadt if ((pml = find_service(a.rmt_prog, a.rmt_vers, 622df930be7Sderaadt (u_long)IPPROTO_UDP)) == NULL) 623df930be7Sderaadt return; 62477baebbfSderaadt 625df930be7Sderaadt /* 626df930be7Sderaadt * fork a child to do the work. Parent immediately returns. 627df930be7Sderaadt * Child exits upon completion. 628df930be7Sderaadt */ 629df930be7Sderaadt if ((pid = fork()) != 0) { 630df930be7Sderaadt if (pid == -1) 631df930be7Sderaadt syslog(LOG_ERR, "CALLIT (prog %lu): fork: %m", 632df930be7Sderaadt a.rmt_prog); 633df930be7Sderaadt return; 634df930be7Sderaadt } 635df930be7Sderaadt port = pml->pml_map.pm_port; 636df930be7Sderaadt get_myaddress(&me); 637df930be7Sderaadt me.sin_port = htons(port); 638df930be7Sderaadt 639df930be7Sderaadt /* Avoid implicit binding to reserved port by clntudp_create() */ 640df930be7Sderaadt so = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 641df930be7Sderaadt if (so == -1) 642df930be7Sderaadt exit(1); 643df930be7Sderaadt if (ioctl(so, FIONBIO, &dontblock) == -1) 644df930be7Sderaadt exit(1); 645df930be7Sderaadt 646df930be7Sderaadt client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &so); 647df930be7Sderaadt if (client != (CLIENT *)NULL) { 64877baebbfSderaadt if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) 649df930be7Sderaadt client->cl_auth = authunix_create(au->aup_machname, 650df930be7Sderaadt au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids); 651df930be7Sderaadt a.rmt_port = (u_long)port; 652df930be7Sderaadt if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a, 65377baebbfSderaadt xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) 654df930be7Sderaadt svc_sendreply(xprt, xdr_rmtcall_result, (caddr_t)&a); 655df930be7Sderaadt AUTH_DESTROY(client->cl_auth); 656df930be7Sderaadt clnt_destroy(client); 657df930be7Sderaadt } 658df930be7Sderaadt (void)close(so); 659df930be7Sderaadt exit(0); 660df930be7Sderaadt } 661df930be7Sderaadt 6629d48a621Sderaadt /* ARGSUSED */ 663df930be7Sderaadt void 66483e8fa08Sderaadt reap(int signo) 665df930be7Sderaadt { 666df930be7Sderaadt int save_errno = errno; 667df930be7Sderaadt 6687af3e1e5Sderaadt while (wait3(NULL, WNOHANG, NULL) > 0) 669df930be7Sderaadt ; 670df930be7Sderaadt errno = save_errno; 671df930be7Sderaadt } 672f94670b8Sderaadt 673f94670b8Sderaadt #define NFSPROG ((u_long) 100003) 674f94670b8Sderaadt #define MOUNTPROG ((u_long) 100005) 675f94670b8Sderaadt #define YPXPROG ((u_long) 100069) 676f94670b8Sderaadt #define YPPROG ((u_long) 100004) 677f94670b8Sderaadt #define YPPROC_DOMAIN_NONACK ((u_long) 2) 678f94670b8Sderaadt #define MOUNTPROC_MNT ((u_long) 1) 6799d791f75Sderaadt #define XXXPROC_NOP ((u_long) 0) 680f94670b8Sderaadt 681f94670b8Sderaadt int 682f99230ebSdhill check_callit(struct sockaddr_in *addr, u_long prog, u_long aproc) 683f94670b8Sderaadt { 6849d791f75Sderaadt if ((prog == PMAPPROG && aproc != XXXPROC_NOP) || 6859d791f75Sderaadt (prog == NFSPROG && aproc != XXXPROC_NOP) || 6869d791f75Sderaadt (prog == YPXPROG && aproc != XXXPROC_NOP) || 687f94670b8Sderaadt (prog == MOUNTPROG && aproc == MOUNTPROC_MNT) || 688f94670b8Sderaadt (prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) { 689f94670b8Sderaadt syslog(LOG_WARNING, 690f94670b8Sderaadt "callit prog %d aproc %d (might be from %s)", 691d91d7659Sderaadt (int)prog, (int)aproc, inet_ntoa(addr->sin_addr)); 692f94670b8Sderaadt return (FALSE); 693f94670b8Sderaadt } 694f94670b8Sderaadt return (TRUE); 695f94670b8Sderaadt } 696