1 /*-
2 * SPDX-License-Identifier: BSD-4-Clause
3 *
4 * Copyright (c) 1995
5 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Bill Paul.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 /*
37 * ypserv startup function.
38 * We need out own main() since we have to do some additional work
39 * that rpcgen won't do for us. Most of this file was generated using
40 * rpcgen.new, and later modified.
41 */
42
43 #include <sys/types.h>
44 #include <sys/mman.h>
45 #include <sys/queue.h>
46 #include <sys/socket.h>
47 #include <sys/wait.h>
48 #include "yp.h"
49 #include <err.h>
50 #include <errno.h>
51 #include <memory.h>
52 #include <stdio.h>
53 #include <signal.h>
54 #include <stdarg.h>
55 #include <stdlib.h> /* getenv, exit */
56 #include <string.h> /* strcmp */
57 #include <syslog.h>
58 #include <unistd.h>
59 #ifdef __cplusplus
60 #include <sysent.h> /* getdtablesize, open */
61 #endif /* __cplusplus */
62 #include <netinet/in.h>
63 #include <netdb.h>
64 #include "yp_extern.h"
65 #include <netconfig.h>
66 #include <rpc/rpc.h>
67 #include <rpc/rpc_com.h>
68
69 #ifndef SIG_PF
70 #define SIG_PF void(*)(int)
71 #endif
72
73 #define _RPCSVC_CLOSEDOWN 120
74 int _rpcpmstart; /* Started by a port monitor ? */
75 static int _rpcfdtype; /* Whether Stream or Datagram? */
76 static int _rpcaf;
77 static int _rpcfd;
78
79 /* States a server can be in wrt request */
80 #define _IDLE 0
81 #define _SERVED 1
82 #define _SERVING 2
83
84 extern void ypprog_1(struct svc_req *, SVCXPRT *);
85 extern void ypprog_2(struct svc_req *, SVCXPRT *);
86 extern int _rpc_dtablesize(void);
87 extern int _rpcsvcstate; /* Set when a request is serviced */
88 char *progname = "ypserv";
89 char *yp_dir = _PATH_YP;
90 int debug;
91 int do_dns = 0;
92 int resfd;
93
94 struct socklistent {
95 int sle_sock;
96 struct sockaddr_storage sle_ss;
97 SLIST_ENTRY(socklistent) sle_next;
98 };
99 static SLIST_HEAD(, socklistent) sle_head =
100 SLIST_HEAD_INITIALIZER(sle_head);
101
102 struct bindaddrlistent {
103 const char *ble_hostname;
104 SLIST_ENTRY(bindaddrlistent) ble_next;
105 };
106 static SLIST_HEAD(, bindaddrlistent) ble_head =
107 SLIST_HEAD_INITIALIZER(ble_head);
108
109 static char *servname = "0";
110
111 static
_msgout(char * msg,...)112 void _msgout(char* msg, ...)
113 {
114 va_list ap;
115
116 va_start(ap, msg);
117 if (debug) {
118 if (_rpcpmstart)
119 vsyslog(LOG_ERR, msg, ap);
120 else
121 vwarnx(msg, ap);
122 } else
123 vsyslog(LOG_ERR, msg, ap);
124 va_end(ap);
125 }
126
127 pid_t yp_pid;
128
129 static void
yp_svc_run(void)130 yp_svc_run(void)
131 {
132 #ifdef FD_SETSIZE
133 fd_set readfds;
134 #else
135 int readfds;
136 #endif /* def FD_SETSIZE */
137 int fd_setsize = _rpc_dtablesize();
138 struct timeval timeout;
139
140 /* Establish the identity of the parent ypserv process. */
141 yp_pid = getpid();
142
143 for (;;) {
144 #ifdef FD_SETSIZE
145 readfds = svc_fdset;
146 #else
147 readfds = svc_fds;
148 #endif /* def FD_SETSIZE */
149
150 FD_SET(resfd, &readfds);
151
152 timeout.tv_sec = RESOLVER_TIMEOUT;
153 timeout.tv_usec = 0;
154 switch (select(fd_setsize, &readfds, NULL, NULL,
155 &timeout)) {
156 case -1:
157 if (errno == EINTR) {
158 continue;
159 }
160 warn("svc_run: - select failed");
161 return;
162 case 0:
163 if (getpid() == yp_pid)
164 yp_prune_dnsq();
165 break;
166 default:
167 if (getpid() == yp_pid) {
168 if (FD_ISSET(resfd, &readfds)) {
169 yp_run_dnsq();
170 FD_CLR(resfd, &readfds);
171 }
172 svc_getreqset(&readfds);
173 }
174 }
175 if (yp_pid != getpid())
176 _exit(0);
177 }
178 }
179
180 static void
unregister(void)181 unregister(void)
182 {
183 (void)svc_unreg(YPPROG, YPVERS);
184 (void)svc_unreg(YPPROG, YPOLDVERS);
185 }
186
187 static void
reaper(int sig)188 reaper(int sig)
189 {
190 int status;
191 int saved_errno;
192
193 saved_errno = errno;
194
195 if (sig == SIGHUP) {
196 load_securenets();
197 #ifdef DB_CACHE
198 yp_flush_all();
199 #endif
200 errno = saved_errno;
201 return;
202 }
203
204 if (sig == SIGCHLD) {
205 while (wait3(&status, WNOHANG, NULL) > 0)
206 children--;
207 } else {
208 unregister();
209 exit(0);
210 }
211 errno = saved_errno;
212 return;
213 }
214
215 static void
usage(void)216 usage(void)
217 {
218 fprintf(stderr, "usage: ypserv [-h addr] [-d] [-n] [-p path] [-P port]\n");
219 exit(1);
220 }
221
222 static void
closedown(int sig)223 closedown(int sig)
224 {
225 if (_rpcsvcstate == _IDLE) {
226 extern fd_set svc_fdset;
227 static int size;
228 int i, openfd;
229
230 if (_rpcfdtype == SOCK_DGRAM) {
231 unregister();
232 exit(0);
233 }
234 if (size == 0) {
235 size = getdtablesize();
236 }
237 for (i = 0, openfd = 0; i < size && openfd < 2; i++)
238 if (FD_ISSET(i, &svc_fdset))
239 openfd++;
240 if (openfd <= 1) {
241 unregister();
242 exit(0);
243 }
244 }
245 if (_rpcsvcstate == _SERVED)
246 _rpcsvcstate = _IDLE;
247
248 (void) signal(SIGALRM, (SIG_PF) closedown);
249 (void) alarm(_RPCSVC_CLOSEDOWN/2);
250 }
251
252 static int
create_service(const int sock,const struct netconfig * nconf,const struct __rpc_sockinfo * si)253 create_service(const int sock, const struct netconfig *nconf,
254 const struct __rpc_sockinfo *si)
255 {
256 int error;
257
258 SVCXPRT *transp;
259 struct addrinfo hints, *res, *res0;
260 struct socklistent *slep;
261 struct bindaddrlistent *blep;
262 struct netbuf svcaddr;
263
264 SLIST_INIT(&sle_head);
265 memset(&hints, 0, sizeof(hints));
266 memset(&svcaddr, 0, sizeof(svcaddr));
267
268 hints.ai_family = si->si_af;
269 hints.ai_socktype = si->si_socktype;
270 hints.ai_protocol = si->si_proto;
271
272 /*
273 * Build socketlist from bindaddrlist.
274 */
275 if (sock == RPC_ANYFD) {
276 SLIST_FOREACH(blep, &ble_head, ble_next) {
277 if (blep->ble_hostname == NULL)
278 hints.ai_flags = AI_PASSIVE;
279 else
280 hints.ai_flags = 0;
281 error = getaddrinfo(blep->ble_hostname, servname,
282 &hints, &res0);
283 if (error) {
284 _msgout("getaddrinfo(): %s",
285 gai_strerror(error));
286 return -1;
287 }
288 for (res = res0; res; res = res->ai_next) {
289 int s;
290
291 s = __rpc_nconf2fd(nconf);
292 if (s < 0) {
293 if (errno == EAFNOSUPPORT)
294 _msgout("unsupported"
295 " transport: %s",
296 nconf->nc_netid);
297 else
298 _msgout("cannot create"
299 " %s socket: %s",
300 nconf->nc_netid,
301 strerror(errno));
302 freeaddrinfo(res0);
303 return -1;
304 }
305 if (bindresvport_sa(s, res->ai_addr) == -1) {
306 if ((errno != EPERM) ||
307 (bind(s, res->ai_addr,
308 res->ai_addrlen) == -1)) {
309 _msgout("cannot bind "
310 "%s socket: %s",
311 nconf->nc_netid,
312 strerror(errno));
313 freeaddrinfo(res0);
314 close(sock);
315 return -1;
316 }
317 }
318 if (nconf->nc_semantics != NC_TPI_CLTS)
319 listen(s, SOMAXCONN);
320
321 slep = malloc(sizeof(*slep));
322 if (slep == NULL) {
323 _msgout("malloc failed: %s",
324 strerror(errno));
325 freeaddrinfo(res0);
326 close(s);
327 return -1;
328 }
329 memset(slep, 0, sizeof(*slep));
330 memcpy(&slep->sle_ss, res->ai_addr,
331 res->ai_addrlen);
332 slep->sle_sock = s;
333 SLIST_INSERT_HEAD(&sle_head, slep, sle_next);
334
335 /*
336 * If servname == "0", redefine it by using
337 * the bound socket.
338 */
339 if (strncmp("0", servname, 1) == 0) {
340 struct sockaddr *sap;
341 socklen_t slen;
342 char *sname;
343
344 sname = malloc(NI_MAXSERV);
345 if (sname == NULL) {
346 _msgout("malloc(): %s",
347 strerror(errno));
348 freeaddrinfo(res0);
349 close(s);
350 return -1;
351 }
352 memset(sname, 0, NI_MAXSERV);
353
354 sap = (struct sockaddr *)&slep->sle_ss;
355 slen = sizeof(*sap);
356 error = getsockname(s, sap, &slen);
357 if (error) {
358 _msgout("getsockname(): %s",
359 strerror(errno));
360 freeaddrinfo(res0);
361 close(s);
362 free(sname);
363 return -1;
364 }
365 error = getnameinfo(sap, slen,
366 NULL, 0,
367 sname, NI_MAXSERV,
368 NI_NUMERICHOST | NI_NUMERICSERV);
369 if (error) {
370 _msgout("getnameinfo(): %s",
371 strerror(errno));
372 freeaddrinfo(res0);
373 close(s);
374 free(sname);
375 return -1;
376 }
377 servname = sname;
378 }
379 }
380 freeaddrinfo(res0);
381 }
382 } else {
383 slep = malloc(sizeof(*slep));
384 if (slep == NULL) {
385 _msgout("malloc failed: %s", strerror(errno));
386 return -1;
387 }
388 memset(slep, 0, sizeof(*slep));
389 slep->sle_sock = sock;
390 SLIST_INSERT_HEAD(&sle_head, slep, sle_next);
391 }
392
393 /*
394 * Traverse socketlist and create rpc service handles for each socket.
395 */
396 SLIST_FOREACH(slep, &sle_head, sle_next) {
397 if (nconf->nc_semantics == NC_TPI_CLTS)
398 transp = svc_dg_create(slep->sle_sock, 0, 0);
399 else
400 transp = svc_vc_create(slep->sle_sock, RPC_MAXDATASIZE,
401 RPC_MAXDATASIZE);
402 if (transp == NULL) {
403 _msgout("unable to create service: %s",
404 nconf->nc_netid);
405 continue;
406 }
407 if (!svc_reg(transp, YPPROG, YPOLDVERS, ypprog_1, NULL)) {
408 svc_destroy(transp);
409 close(slep->sle_sock);
410 _msgout("unable to register (YPPROG, YPOLDVERS, %s):"
411 " %s", nconf->nc_netid, strerror(errno));
412 continue;
413 }
414 if (!svc_reg(transp, YPPROG, YPVERS, ypprog_2, NULL)) {
415 svc_destroy(transp);
416 close(slep->sle_sock);
417 _msgout("unable to register (YPPROG, YPVERS, %s): %s",
418 nconf->nc_netid, strerror(errno));
419 continue;
420 }
421 }
422 while(!(SLIST_EMPTY(&sle_head)))
423 SLIST_REMOVE_HEAD(&sle_head, sle_next);
424
425 /*
426 * Register RPC service to rpcbind by using AI_PASSIVE address.
427 */
428 hints.ai_flags = AI_PASSIVE;
429 error = getaddrinfo(NULL, servname, &hints, &res0);
430 if (error) {
431 _msgout("getaddrinfo(): %s", gai_strerror(error));
432 return -1;
433 }
434 svcaddr.buf = res0->ai_addr;
435 svcaddr.len = res0->ai_addrlen;
436
437 if (si->si_af == AF_INET) {
438 /* XXX: ignore error intentionally */
439 rpcb_set(YPPROG, YPOLDVERS, nconf, &svcaddr);
440 }
441 /* XXX: ignore error intentionally */
442 rpcb_set(YPPROG, YPVERS, nconf, &svcaddr);
443 freeaddrinfo(res0);
444 return 0;
445 }
446
447 int
main(int argc,char * argv[])448 main(int argc, char *argv[])
449 {
450 int ch;
451 int error;
452 int ntrans;
453
454 void *nc_handle;
455 struct netconfig *nconf;
456 struct __rpc_sockinfo si;
457 struct bindaddrlistent *blep;
458
459 memset(&si, 0, sizeof(si));
460 SLIST_INIT(&ble_head);
461
462 while ((ch = getopt(argc, argv, "dh:np:P:")) != -1) {
463 switch (ch) {
464 case 'd':
465 debug = ypdb_debug = 1;
466 break;
467 case 'h':
468 blep = malloc(sizeof(*blep));
469 if (blep == NULL)
470 err(1, "malloc() failed: -h %s", optarg);
471 blep->ble_hostname = optarg;
472 SLIST_INSERT_HEAD(&ble_head, blep, ble_next);
473 break;
474 case 'n':
475 do_dns = 1;
476 break;
477 case 'p':
478 yp_dir = optarg;
479 break;
480 case 'P':
481 servname = optarg;
482 break;
483 default:
484 usage();
485 }
486 }
487 /*
488 * Add "anyaddr" entry if no -h is specified.
489 */
490 if (SLIST_EMPTY(&ble_head)) {
491 blep = malloc(sizeof(*blep));
492 if (blep == NULL)
493 err(1, "malloc() failed");
494 memset(blep, 0, sizeof(*blep));
495 SLIST_INSERT_HEAD(&ble_head, blep, ble_next);
496 }
497
498 load_securenets();
499 yp_init_resolver();
500 #ifdef DB_CACHE
501 yp_init_dbs();
502 #endif
503 nc_handle = setnetconfig();
504 if (nc_handle == NULL)
505 err(1, "cannot read %s", NETCONFIG);
506 if (__rpc_fd2sockinfo(0, &si) != 0) {
507 /* invoked from inetd */
508 _rpcpmstart = 1;
509 _rpcfdtype = si.si_socktype;
510 _rpcaf = si.si_af;
511 _rpcfd = 0;
512 openlog("ypserv", LOG_PID, LOG_DAEMON);
513 } else {
514 /* standalone mode */
515 if (!debug) {
516 if (daemon(0,0)) {
517 err(1,"cannot fork");
518 }
519 openlog("ypserv", LOG_PID, LOG_DAEMON);
520 }
521 _rpcpmstart = 0;
522 _rpcaf = AF_INET;
523 _rpcfd = RPC_ANYFD;
524 unregister();
525 }
526
527 if (madvise(NULL, 0, MADV_PROTECT) != 0)
528 _msgout("madvise(): %s", strerror(errno));
529
530 /*
531 * Create RPC service for each transport.
532 */
533 ntrans = 0;
534 while((nconf = getnetconfig(nc_handle))) {
535 if ((nconf->nc_flag & NC_VISIBLE)) {
536 if (__rpc_nconf2sockinfo(nconf, &si) == 0) {
537 _msgout("cannot get information for %s. "
538 "Ignored.", nconf->nc_netid);
539 continue;
540 }
541 if (_rpcpmstart) {
542 if (si.si_socktype != _rpcfdtype ||
543 si.si_af != _rpcaf)
544 continue;
545 } else if (si.si_af != _rpcaf)
546 continue;
547 error = create_service(_rpcfd, nconf, &si);
548 if (error) {
549 endnetconfig(nc_handle);
550 exit(1);
551 }
552 ntrans++;
553 }
554 }
555 endnetconfig(nc_handle);
556 while(!(SLIST_EMPTY(&ble_head)))
557 SLIST_REMOVE_HEAD(&ble_head, ble_next);
558 if (ntrans == 0) {
559 _msgout("no transport is available. Aborted.");
560 exit(1);
561 }
562 if (_rpcpmstart) {
563 (void) signal(SIGALRM, (SIG_PF) closedown);
564 (void) alarm(_RPCSVC_CLOSEDOWN/2);
565 }
566 /*
567 * Make sure SIGPIPE doesn't blow us away while servicing TCP
568 * connections.
569 */
570 (void) signal(SIGPIPE, SIG_IGN);
571 (void) signal(SIGCHLD, (SIG_PF) reaper);
572 (void) signal(SIGTERM, (SIG_PF) reaper);
573 (void) signal(SIGINT, (SIG_PF) reaper);
574 (void) signal(SIGHUP, (SIG_PF) reaper);
575 yp_svc_run();
576 _msgout("svc_run returned");
577 exit(1);
578 /* NOTREACHED */
579 }
580