Bug Summary

File:src/usr.sbin/portmap/portmap.c
Warning:line 151, column 7
Although the value stored to 'xprt' is used in the enclosing expression, the value is never actually read from 'xprt'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name portmap.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/portmap/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/portmap/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/portmap/portmap.c
1/* $OpenBSD: portmap.c,v 1.50 2019/06/28 13:32:49 deraadt Exp $ */
2
3/*-
4 * Copyright (c) 1996, 1997 Theo de Raadt (OpenBSD). All rights reserved.
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32/*
33 * Copyright (c) 2010, Oracle America, Inc.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions are
37 * met:
38 *
39 * * Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * * Redistributions in binary form must reproduce the above
42 * copyright notice, this list of conditions and the following
43 * disclaimer in the documentation and/or other materials
44 * provided with the distribution.
45 * * Neither the name of the "Oracle America, Inc." nor the names of its
46 * contributors may be used to endorse or promote products derived
47 * from this software without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
50 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
51 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
52 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
53 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
54 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
56 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
58 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
59 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
60 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 */
62
63/*
64 * portmap.c, Implements the program,version to port number mapping for
65 * rpc.
66 */
67
68#include <sys/types.h>
69#include <sys/socket.h>
70#include <sys/wait.h>
71#include <sys/resource.h>
72
73#include <rpcsvc/nfs_prot.h>
74#include <arpa/inet.h>
75#include <rpc/rpc.h>
76#include <rpc/pmap_prot.h>
77
78#include <signal.h>
79#include <stdio.h>
80#include <stdlib.h>
81#include <string.h>
82#include <syslog.h>
83#include <unistd.h>
84#include <netdb.h>
85#include <pwd.h>
86#include <errno(*__errno()).h>
87#include <err.h>
88
89void reg_service(struct svc_req *, SVCXPRT *);
90void reap(int);
91void callit(struct svc_req *, SVCXPRT *);
92int check_callit(struct sockaddr_in *, u_long, u_long);
93struct pmaplist *find_service(u_long, u_long, u_long);
94
95struct pmaplist *pmaplist;
96int debugging;
97
98SVCXPRT *ludpxprt, *ltcpxprt;
99
100int
101main(int argc, char *argv[])
102{
103 int sock, lsock, c, on = 1;
104 socklen_t len = sizeof(struct sockaddr_in);
105 struct sockaddr_in addr, laddr;
106 struct pmaplist *pml;
107 struct passwd *pw;
108 SVCXPRT *xprt;
109
110 while ((c = getopt(argc, argv, "d")) != -1) {
111 switch (c) {
112 case 'd':
113 debugging = 1;
114 break;
115 default:
116 (void)fprintf(stderr(&__sF[2]), "usage: %s [-d]\n", argv[0]);
117 exit(1);
118 }
119 }
120
121 if (!debugging && daemon(0, 0)) {
122 (void)fprintf(stderr(&__sF[2]), "portmap: fork: %s", strerror(errno(*__errno())));
123 exit(1);
124 }
125
126 openlog("portmap", LOG_NDELAY0x08 | (debugging ? LOG_PID0x01 | LOG_PERROR0x20 :
127 LOG_PID0x01), LOG_DAEMON(3<<3));
128
129 bzero(&addr, sizeof addr);
130 addr.sin_addr.s_addr = 0;
131 addr.sin_family = AF_INET2;
132 addr.sin_addr.s_addr = htonl(INADDR_ANY)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0x00000000))) ?
(__uint32_t)(((__uint32_t)(((u_int32_t)(0x00000000))) & 0xff
) << 24 | ((__uint32_t)(((u_int32_t)(0x00000000))) &
0xff00) << 8 | ((__uint32_t)(((u_int32_t)(0x00000000))
) & 0xff0000) >> 8 | ((__uint32_t)(((u_int32_t)(0x00000000
))) & 0xff000000) >> 24) : __swap32md(((u_int32_t)(
0x00000000))))
;
133 addr.sin_port = htons(PMAPPORT)(__uint16_t)(__builtin_constant_p(((unsigned short)111)) ? (__uint16_t
)(((__uint16_t)(((unsigned short)111)) & 0xffU) << 8
| ((__uint16_t)(((unsigned short)111)) & 0xff00U) >>
8) : __swap16md(((unsigned short)111)))
;
134
135 bzero(&laddr, sizeof laddr);
136 laddr.sin_addr.s_addr = 0;
137 laddr.sin_family = AF_INET2;
138 laddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0x7f000001))) ?
(__uint32_t)(((__uint32_t)(((u_int32_t)(0x7f000001))) & 0xff
) << 24 | ((__uint32_t)(((u_int32_t)(0x7f000001))) &
0xff00) << 8 | ((__uint32_t)(((u_int32_t)(0x7f000001))
) & 0xff0000) >> 8 | ((__uint32_t)(((u_int32_t)(0x7f000001
))) & 0xff000000) >> 24) : __swap32md(((u_int32_t)(
0x7f000001))))
;
139 laddr.sin_port = htons(PMAPPORT)(__uint16_t)(__builtin_constant_p(((unsigned short)111)) ? (__uint16_t
)(((__uint16_t)(((unsigned short)111)) & 0xffU) << 8
| ((__uint16_t)(((unsigned short)111)) & 0xff00U) >>
8) : __swap16md(((unsigned short)111)))
;
140
141 if ((sock = socket(AF_INET2, SOCK_DGRAM2, IPPROTO_UDP17)) == -1) {
142 syslog(LOG_ERR3, "cannot create udp socket: %m");
143 exit(1);
144 }
145 setsockopt(sock, SOL_SOCKET0xffff, SO_REUSEADDR0x0004, &on, sizeof on);
146 if (bind(sock, (struct sockaddr *)&addr, len) == -1) {
147 syslog(LOG_ERR3, "cannot bind udp: %m");
148 exit(1);
149 }
150
151 if ((xprt = svcudp_create(sock)) == NULL((void *)0)) {
Although the value stored to 'xprt' is used in the enclosing expression, the value is never actually read from 'xprt'
152 syslog(LOG_ERR3, "couldn't do udp_create");
153 exit(1);
154 }
155
156 if ((lsock = socket(AF_INET2, SOCK_DGRAM2, IPPROTO_UDP17)) == -1) {
157 syslog(LOG_ERR3, "cannot create udp socket: %m");
158 exit(1);
159 }
160 setsockopt(lsock, SOL_SOCKET0xffff, SO_REUSEADDR0x0004, &on, sizeof on);
161 if (bind(lsock, (struct sockaddr *)&laddr, len) == -1) {
162 syslog(LOG_ERR3, "cannot bind local udp: %m");
163 exit(1);
164 }
165
166 if ((ludpxprt = svcudp_create(lsock)) == NULL((void *)0)) {
167 syslog(LOG_ERR3, "couldn't do udp_create");
168 exit(1);
169 }
170
171 /* make an entry for ourself */
172 pml = malloc(sizeof(struct pmaplist));
173 if (pml == NULL((void *)0)) {
174 syslog(LOG_ERR3, "out of memory");
175 exit(1);
176 }
177 pml->pml_next = 0;
178 pml->pml_map.pm_prog = PMAPPROG((unsigned long)100000);
179 pml->pml_map.pm_vers = PMAPVERS((unsigned long)2);
180 pml->pml_map.pm_prot = IPPROTO_UDP17;
181 pml->pml_map.pm_port = PMAPPORT((unsigned short)111);
182 pmaplist = pml;
183
184 if ((sock = socket(AF_INET2, SOCK_STREAM1, IPPROTO_TCP6)) == -1) {
185 syslog(LOG_ERR3, "cannot create tcp socket: %m");
186 exit(1);
187 }
188 setsockopt(sock, SOL_SOCKET0xffff, SO_REUSEADDR0x0004, &on, sizeof on);
189 if (bind(sock, (struct sockaddr *)&addr, len) == -1) {
190 syslog(LOG_ERR3, "cannot bind tcp: %m");
191 exit(1);
192 }
193 if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE400, RPCSMALLMSGSIZE400)) ==
194 NULL((void *)0)) {
195 syslog(LOG_ERR3, "couldn't do tcp_create");
196 exit(1);
197 }
198
199 if ((lsock = socket(AF_INET2, SOCK_STREAM1, IPPROTO_TCP6)) == -1) {
200 syslog(LOG_ERR3, "cannot create tcp socket: %m");
201 exit(1);
202 }
203 setsockopt(lsock, SOL_SOCKET0xffff, SO_REUSEADDR0x0004, &on, sizeof on);
204 if (bind(lsock, (struct sockaddr *)&laddr, len) == -1) {
205 syslog(LOG_ERR3, "cannot bind tcp: %m");
206 exit(1);
207 }
208 if ((ltcpxprt = svctcp_create(lsock, RPCSMALLMSGSIZE400,
209 RPCSMALLMSGSIZE400)) == NULL((void *)0)) {
210 syslog(LOG_ERR3, "couldn't do tcp_create");
211 exit(1);
212 }
213
214 /* make an entry for ourself */
215 pml = malloc(sizeof(struct pmaplist));
216 if (pml == NULL((void *)0)) {
217 syslog(LOG_ERR3, "out of memory");
218 exit(1);
219 }
220 pml->pml_map.pm_prog = PMAPPROG((unsigned long)100000);
221 pml->pml_map.pm_vers = PMAPVERS((unsigned long)2);
222 pml->pml_map.pm_prot = IPPROTO_TCP6;
223 pml->pml_map.pm_port = PMAPPORT((unsigned short)111);
224 pml->pml_next = pmaplist;
225 pmaplist = pml;
226
227 if ((pw = getpwnam("_portmap")) == NULL((void *)0)) {
228 syslog(LOG_ERR3, "no such user _portmap");
229 exit(1);
230 }
231 if (chroot("/var/empty") == -1) {
232 syslog(LOG_ERR3, "cannot chroot to /var/empty.");
233 exit(1);
234 }
235 if (chdir("/") == -1) {
236 syslog(LOG_ERR3, "cannot chdir to new /.");
237 exit(1);
238 }
239
240 if (pw) {
241 if (setgroups(1, &pw->pw_gid) == -1 ||
242 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 ||
243 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) {
244 syslog(LOG_ERR3, "revoke privs: %s", strerror(errno(*__errno())));
245 exit(1);
246 }
247 }
248 endpwent();
249
250 if (pledge("stdio inet proc", NULL((void *)0)) == -1)
251 err(1, "pledge");
252
253 if (svc_register(xprt, PMAPPROG((unsigned long)100000), PMAPVERS((unsigned long)2), reg_service, FALSE(0)) == 0) {
254 syslog(LOG_ERR3, "svc_register failed.");
255 exit(1);
256 }
257
258 (void)signal(SIGCHLD20, reap);
259 svc_run();
260 syslog(LOG_ERR3, "svc_run returned unexpectedly");
261 abort();
262}
263
264struct pmaplist *
265find_service(u_long prog, u_long vers, u_long prot)
266{
267 struct pmaplist *hit = NULL((void *)0);
268 struct pmaplist *pml;
269
270 for (pml = pmaplist; pml != NULL((void *)0); pml = pml->pml_next) {
271 if ((pml->pml_map.pm_prog != prog) ||
272 (pml->pml_map.pm_prot != prot))
273 continue;
274 hit = pml;
275 if (pml->pml_map.pm_vers == vers)
276 break;
277 }
278 return (hit);
279}
280
281/*
282 * 1 OK, 0 not
283 */
284void
285reg_service(struct svc_req *rqstp, SVCXPRT *xprt)
286{
287 struct pmap reg;
288 struct pmaplist *pml, *prevpml, *fnd;
289 struct sockaddr_in *fromsin;
290 long ans = 0, port;
291 void *t;
292
293 fromsin = svc_getcaller(xprt)(&(xprt)->xp_raddr);
294
295 if (debugging)
296 (void)fprintf(stderr(&__sF[2]), "server: about to do a switch\n");
297 switch (rqstp->rq_proc) {
298 case PMAPPROC_NULL((unsigned long)0):
299 /*
300 * Null proc call
301 */
302 if (!svc_sendreply(xprt, xdr_void, NULL((void *)0)) && debugging) {
303 abort();
304 }
305 break;
306 case PMAPPROC_SET((unsigned long)1):
307 /*
308 * Set a program,version to port mapping
309 */
310 if (xprt != ltcpxprt && xprt != ludpxprt) {
311 syslog(LOG_WARNING4,
312 "non-local set attempt (might be from %s)",
313 inet_ntoa(fromsin->sin_addr));
314 svcerr_noproc(xprt);
315 return;
316 }
317 if (!svc_getargs(xprt, xdr_pmap, (caddr_t)&reg)(*(xprt)->xp_ops->xp_getargs)((xprt), (xdr_pmap), ((caddr_t
)&reg))
) {
318 svcerr_decode(xprt);
319 break;
320 }
321
322 /*
323 * check to see if already used
324 * find_service returns a hit even if
325 * the versions don't match, so check for it
326 */
327 fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
328 if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) {
329 if (fnd->pml_map.pm_port == reg.pm_port)
330 ans = 1;
331 goto done;
332 }
333
334 if (debugging)
335 printf("set: prog %lu vers %lu port %lu\n",
336 reg.pm_prog, reg.pm_vers, reg.pm_port);
337
338 if (reg.pm_port & ~0xffff)
339 goto done;
340
341 /*
342 * only permit localhost root to create
343 * mappings pointing at sensitive ports
344 */
345 if ((reg.pm_port < IPPORT_RESERVED1024 ||
346 reg.pm_port == NFS_PORT2049) &&
347 htons(fromsin->sin_port)(__uint16_t)(__builtin_constant_p(fromsin->sin_port) ? (__uint16_t
)(((__uint16_t)(fromsin->sin_port) & 0xffU) << 8
| ((__uint16_t)(fromsin->sin_port) & 0xff00U) >>
8) : __swap16md(fromsin->sin_port))
>= IPPORT_RESERVED1024) {
348 syslog(LOG_WARNING4,
349 "resvport set attempt by non-root");
350 goto done;
351 }
352
353 /*
354 * add to END of list
355 */
356 pml = malloc(sizeof(struct pmaplist));
357 if (pml == NULL((void *)0)) {
358 syslog(LOG_ERR3, "out of memory");
359 svcerr_systemerr(xprt);
360 return;
361 }
362
363 pml->pml_map = reg;
364 pml->pml_next = 0;
365 if (pmaplist == NULL((void *)0)) {
366 pmaplist = pml;
367 } else {
368 for (fnd = pmaplist; fnd->pml_next != 0;
369 fnd = fnd->pml_next)
370 ;
371 fnd->pml_next = pml;
372 }
373 ans = 1;
374done:
375 if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
376 debugging) {
377 (void)fprintf(stderr(&__sF[2]), "svc_sendreply\n");
378 abort();
379 }
380 break;
381 case PMAPPROC_UNSET((unsigned long)2):
382 /*
383 * Remove a program,version to port mapping.
384 */
385 if (xprt != ltcpxprt && xprt != ludpxprt) {
386 syslog(LOG_WARNING4,
387 "non-local unset attempt (might be from %s)",
388 inet_ntoa(fromsin->sin_addr));
389 svcerr_noproc(xprt);
390 return;
391 }
392 if (!svc_getargs(xprt, xdr_pmap, (caddr_t)&reg)(*(xprt)->xp_ops->xp_getargs)((xprt), (xdr_pmap), ((caddr_t
)&reg))
) {
393 svcerr_decode(xprt);
394 break;
395 }
396 for (prevpml = NULL((void *)0), pml = pmaplist; pml != NULL((void *)0); ) {
397 if ((pml->pml_map.pm_prog != reg.pm_prog) ||
398 (pml->pml_map.pm_vers != reg.pm_vers)) {
399 /* both pml & prevpml move forwards */
400 prevpml = pml;
401 pml = pml->pml_next;
402 continue;
403 }
404 if ((pml->pml_map.pm_port < IPPORT_RESERVED1024 ||
405 pml->pml_map.pm_port == NFS_PORT2049) &&
406 htons(fromsin->sin_port)(__uint16_t)(__builtin_constant_p(fromsin->sin_port) ? (__uint16_t
)(((__uint16_t)(fromsin->sin_port) & 0xffU) << 8
| ((__uint16_t)(fromsin->sin_port) & 0xff00U) >>
8) : __swap16md(fromsin->sin_port))
>= IPPORT_RESERVED1024) {
407 syslog(LOG_WARNING4,
408 "resvport unset attempt by non-root");
409 break;
410 }
411
412 /* found it; pml moves forward, prevpml stays */
413 ans = 1;
414 t = pml;
415 pml = pml->pml_next;
416 if (prevpml == NULL((void *)0))
417 pmaplist = pml;
418 else
419 prevpml->pml_next = pml;
420 free(t);
421 }
422 if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
423 debugging) {
424 fprintf(stderr(&__sF[2]), "svc_sendreply\n");
425 abort();
426 }
427 break;
428 case PMAPPROC_GETPORT((unsigned long)3):
429 /*
430 * Lookup the mapping for a program,version and return its port
431 */
432 if (!svc_getargs(xprt, xdr_pmap, (caddr_t)&reg)(*(xprt)->xp_ops->xp_getargs)((xprt), (xdr_pmap), ((caddr_t
)&reg))
) {
433 svcerr_decode(xprt);
434 break;
435 }
436 fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
437 if (fnd)
438 port = fnd->pml_map.pm_port;
439 else
440 port = 0;
441 if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) &&
442 debugging) {
443 fprintf(stderr(&__sF[2]), "svc_sendreply\n");
444 abort();
445 }
446 break;
447 case PMAPPROC_DUMP((unsigned long)4):
448 /*
449 * Return the current set of mapped program,version
450 */
451 if (!svc_getargs(xprt, xdr_void, NULL)(*(xprt)->xp_ops->xp_getargs)((xprt), (xdr_void), (((void
*)0)))
) {
452 svcerr_decode(xprt);
453 break;
454 }
455 if (!svc_sendreply(xprt, xdr_pmaplist, (caddr_t)&pmaplist) &&
456 debugging) {
457 fprintf(stderr(&__sF[2]), "svc_sendreply\n");
458 abort();
459 }
460 break;
461 case PMAPPROC_CALLIT((unsigned long)5):
462 /*
463 * Calls a procedure on the local machine. If the requested
464 * procedure is not registered this procedure does not return
465 * error information!!
466 * This procedure is only supported on rpc/udp and calls via
467 * rpc/udp. It passes null authentication parameters.
468 */
469 callit(rqstp, xprt);
470 break;
471 default:
472 svcerr_noproc(xprt);
473 break;
474 }
475}
476
477
478/*
479 * Stuff for the rmtcall service
480 */
481#define ARGSIZE9000 9000
482
483struct encap_parms {
484 u_int arglen;
485 char *args;
486};
487
488static bool_tint32_t
489xdr_encap_parms(XDR *xdrs, struct encap_parms *epp)
490{
491
492 return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE9000));
493}
494
495struct rmtcallargs {
496 u_long rmt_prog;
497 u_long rmt_vers;
498 u_long rmt_port;
499 u_long rmt_proc;
500 struct encap_parms rmt_args;
501};
502
503/*
504 * Version of xdr_rmtcall_args() that supports both directions
505 */
506static bool_tint32_t
507portmap_xdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap)
508{
509
510 /* does not get a port number */
511 if (xdr_u_long(xdrs, &(cap->rmt_prog)) &&
512 xdr_u_long(xdrs, &(cap->rmt_vers)) &&
513 xdr_u_long(xdrs, &(cap->rmt_proc))) {
514 return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
515 }
516 return (FALSE(0));
517}
518
519/*
520 * Version of xdr_rmtcallres() that supports both directions
521 */
522static bool_tint32_t
523portmap_xdr_rmtcallres(XDR *xdrs, struct rmtcallargs *cap)
524{
525 if (xdr_u_long(xdrs, &(cap->rmt_port)))
526 return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
527 return (FALSE(0));
528}
529
530/*
531 * only worries about the struct encap_parms part of struct rmtcallargs.
532 * The arglen must already be set!!
533 */
534static bool_tint32_t
535xdr_opaque_parms(XDR *xdrs, struct rmtcallargs *cap)
536{
537
538 return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
539}
540
541/*
542 * This routine finds and sets the length of incoming opaque paraters
543 * and then calls xdr_opaque_parms.
544 */
545static bool_tint32_t
546xdr_len_opaque_parms(XDR *xdrs, struct rmtcallargs *cap)
547{
548 u_int beginpos, lowpos, highpos, currpos, pos;
549
550 beginpos = lowpos = pos = xdr_getpos(xdrs)(*(xdrs)->x_ops->x_getpostn)(xdrs);
551 highpos = lowpos + ARGSIZE9000;
552 while (highpos >= lowpos) {
553 currpos = (lowpos + highpos) / 2;
554 if (xdr_setpos(xdrs, currpos)(*(xdrs)->x_ops->x_setpostn)(xdrs, currpos)) {
555 pos = currpos;
556 lowpos = currpos + 1;
557 } else {
558 highpos = currpos - 1;
559 }
560 }
561 xdr_setpos(xdrs, beginpos)(*(xdrs)->x_ops->x_setpostn)(xdrs, beginpos);
562 cap->rmt_args.arglen = pos - beginpos;
563 return (xdr_opaque_parms(xdrs, cap));
564}
565
566/*
567 * Call a remote procedure service
568 * This procedure is very quiet when things go wrong.
569 * The proc is written to support broadcast rpc. In the broadcast case,
570 * a machine should shut-up instead of complain, less the requestor be
571 * overrun with complaints at the expense of not hearing a valid reply ...
572 *
573 * This now forks so that the program & process that it calls can call
574 * back to the portmapper.
575 */
576void
577callit(struct svc_req *rqstp, SVCXPRT *xprt)
578{
579 struct rmtcallargs a;
580 struct pmaplist *pml;
581 u_short port;
582 struct sockaddr_in me;
583 pid_t pid;
584 int so = -1;
585 CLIENT *client;
586 struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred;
587 struct timeval timeout;
588 char buf[ARGSIZE9000];
589
590 timeout.tv_sec = 5;
591 timeout.tv_usec = 0;
592 a.rmt_args.args = buf;
593 if (!svc_getargs(xprt, portmap_xdr_rmtcall_args, (caddr_t)&a)(*(xprt)->xp_ops->xp_getargs)((xprt), (portmap_xdr_rmtcall_args
), ((caddr_t)&a))
)
594 return;
595 if (!check_callit(svc_getcaller(xprt)(&(xprt)->xp_raddr), a.rmt_prog, a.rmt_proc))
596 return;
597 if ((pml = find_service(a.rmt_prog, a.rmt_vers,
598 (u_long)IPPROTO_UDP17)) == NULL((void *)0))
599 return;
600
601 /*
602 * fork a child to do the work. Parent immediately returns.
603 * Child exits upon completion.
604 */
605 if ((pid = fork()) != 0) {
606 if (pid == -1)
607 syslog(LOG_ERR3, "CALLIT (prog %lu): fork: %m",
608 a.rmt_prog);
609 return;
610 }
611
612 if (pledge("stdio inet", NULL((void *)0)) == -1)
613 err(1, "pledge");
614
615 port = pml->pml_map.pm_port;
616 get_myaddress(&me);
617 me.sin_port = htons(port)(__uint16_t)(__builtin_constant_p(port) ? (__uint16_t)(((__uint16_t
)(port) & 0xffU) << 8 | ((__uint16_t)(port) & 0xff00U
) >> 8) : __swap16md(port))
;
618
619 /* Avoid implicit binding to reserved port by clntudp_create() */
620 so = socket(AF_INET2, SOCK_DGRAM2 | SOCK_NONBLOCK0x4000, IPPROTO_UDP17);
621 if (so == -1)
622 exit(1);
623
624 client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &so);
625 if (client != NULL((void *)0)) {
626 if (rqstp->rq_cred.oa_flavor == AUTH_UNIX1)
627 client->cl_auth = authunix_create(au->aup_machname,
628 au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids);
629 a.rmt_port = (u_long)port;
630 if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a,((*(client)->cl_ops->cl_call)(client, a.rmt_proc, xdr_opaque_parms
, (caddr_t)&a, xdr_len_opaque_parms, (caddr_t)&a, timeout
))
631 xdr_len_opaque_parms, &a, timeout)((*(client)->cl_ops->cl_call)(client, a.rmt_proc, xdr_opaque_parms
, (caddr_t)&a, xdr_len_opaque_parms, (caddr_t)&a, timeout
))
== RPC_SUCCESS)
632 svc_sendreply(xprt, portmap_xdr_rmtcallres, (caddr_t)&a);
633 AUTH_DESTROY(client->cl_auth)((*((client->cl_auth)->ah_ops->ah_destroy))(client->
cl_auth))
;
634 clnt_destroy(client)((*(client)->cl_ops->cl_destroy)(client));
635 }
636 (void)close(so);
637 exit(0);
638}
639
640/* ARGSUSED */
641void
642reap(int signo)
643{
644 int save_errno = errno(*__errno());
645
646 while (wait3(NULL((void *)0), WNOHANG1, NULL((void *)0)) > 0)
647 ;
648 errno(*__errno()) = save_errno;
649}
650
651#define NFSPROG((u_long) 100003) ((u_long) 100003)
652#define MOUNTPROG((u_long) 100005) ((u_long) 100005)
653#define YPXPROG((u_long) 100069) ((u_long) 100069)
654#define YPPROG((u_long) 100004) ((u_long) 100004)
655#define YPPROC_DOMAIN_NONACK((u_long) 2) ((u_long) 2)
656#define MOUNTPROC_MNT((u_long) 1) ((u_long) 1)
657#define XXXPROC_NOP((u_long) 0) ((u_long) 0)
658
659int
660check_callit(struct sockaddr_in *addr, u_long prog, u_long aproc)
661{
662 if ((prog == PMAPPROG((unsigned long)100000) && aproc != XXXPROC_NOP((u_long) 0)) ||
663 (prog == NFSPROG((u_long) 100003) && aproc != XXXPROC_NOP((u_long) 0)) ||
664 (prog == YPXPROG((u_long) 100069) && aproc != XXXPROC_NOP((u_long) 0)) ||
665 (prog == MOUNTPROG((u_long) 100005) && aproc == MOUNTPROC_MNT((u_long) 1)) ||
666 (prog == YPPROG((u_long) 100004) && aproc != YPPROC_DOMAIN_NONACK((u_long) 2))) {
667 syslog(LOG_WARNING4,
668 "callit prog %ld aproc %ld (might be from %s)",
669 prog, aproc, inet_ntoa(addr->sin_addr));
670 return (FALSE(0));
671 }
672 return (TRUE(1));
673}