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 }
213
214 static void
usage(void)215 usage(void)
216 {
217 fprintf(stderr, "usage: ypserv [-h addr] [-d] [-n] [-p path] [-P port]\n");
218 exit(1);
219 }
220
221 static void
closedown(int sig)222 closedown(int sig)
223 {
224 if (_rpcsvcstate == _IDLE) {
225 extern fd_set svc_fdset;
226 static int size;
227 int i, openfd;
228
229 if (_rpcfdtype == SOCK_DGRAM) {
230 unregister();
231 exit(0);
232 }
233 if (size == 0) {
234 size = getdtablesize();
235 }
236 for (i = 0, openfd = 0; i < size && openfd < 2; i++)
237 if (FD_ISSET(i, &svc_fdset))
238 openfd++;
239 if (openfd <= 1) {
240 unregister();
241 exit(0);
242 }
243 }
244 if (_rpcsvcstate == _SERVED)
245 _rpcsvcstate = _IDLE;
246
247 (void) signal(SIGALRM, (SIG_PF) closedown);
248 (void) alarm(_RPCSVC_CLOSEDOWN/2);
249 }
250
251 static int
create_service(const int sock,const struct netconfig * nconf,const struct __rpc_sockinfo * si)252 create_service(const int sock, const struct netconfig *nconf,
253 const struct __rpc_sockinfo *si)
254 {
255 int error;
256
257 SVCXPRT *transp;
258 struct addrinfo hints, *res, *res0;
259 struct socklistent *slep;
260 struct bindaddrlistent *blep;
261 struct netbuf svcaddr;
262
263 SLIST_INIT(&sle_head);
264 memset(&hints, 0, sizeof(hints));
265 memset(&svcaddr, 0, sizeof(svcaddr));
266
267 hints.ai_family = si->si_af;
268 hints.ai_socktype = si->si_socktype;
269 hints.ai_protocol = si->si_proto;
270
271 /*
272 * Build socketlist from bindaddrlist.
273 */
274 if (sock == RPC_ANYFD) {
275 SLIST_FOREACH(blep, &ble_head, ble_next) {
276 if (blep->ble_hostname == NULL)
277 hints.ai_flags = AI_PASSIVE;
278 else
279 hints.ai_flags = 0;
280 error = getaddrinfo(blep->ble_hostname, servname,
281 &hints, &res0);
282 if (error) {
283 _msgout("getaddrinfo(): %s",
284 gai_strerror(error));
285 return -1;
286 }
287 for (res = res0; res; res = res->ai_next) {
288 int s;
289
290 s = __rpc_nconf2fd(nconf);
291 if (s < 0) {
292 if (errno == EAFNOSUPPORT)
293 _msgout("unsupported"
294 " transport: %s",
295 nconf->nc_netid);
296 else
297 _msgout("cannot create"
298 " %s socket: %s",
299 nconf->nc_netid,
300 strerror(errno));
301 freeaddrinfo(res0);
302 return -1;
303 }
304 if (bindresvport_sa(s, res->ai_addr) == -1) {
305 if ((errno != EPERM) ||
306 (bind(s, res->ai_addr,
307 res->ai_addrlen) == -1)) {
308 _msgout("cannot bind "
309 "%s socket: %s",
310 nconf->nc_netid,
311 strerror(errno));
312 freeaddrinfo(res0);
313 close(sock);
314 return -1;
315 }
316 }
317 if (nconf->nc_semantics != NC_TPI_CLTS)
318 listen(s, SOMAXCONN);
319
320 slep = malloc(sizeof(*slep));
321 if (slep == NULL) {
322 _msgout("malloc failed: %s",
323 strerror(errno));
324 freeaddrinfo(res0);
325 close(s);
326 return -1;
327 }
328 memset(slep, 0, sizeof(*slep));
329 memcpy(&slep->sle_ss, res->ai_addr,
330 res->ai_addrlen);
331 slep->sle_sock = s;
332 SLIST_INSERT_HEAD(&sle_head, slep, sle_next);
333
334 /*
335 * If servname == "0", redefine it by using
336 * the bound socket.
337 */
338 if (strncmp("0", servname, 1) == 0) {
339 struct sockaddr *sap;
340 socklen_t slen;
341 char *sname;
342
343 sname = malloc(NI_MAXSERV);
344 if (sname == NULL) {
345 _msgout("malloc(): %s",
346 strerror(errno));
347 freeaddrinfo(res0);
348 close(s);
349 return -1;
350 }
351 memset(sname, 0, NI_MAXSERV);
352
353 sap = (struct sockaddr *)&slep->sle_ss;
354 slen = sizeof(*sap);
355 error = getsockname(s, sap, &slen);
356 if (error) {
357 _msgout("getsockname(): %s",
358 strerror(errno));
359 freeaddrinfo(res0);
360 close(s);
361 free(sname);
362 return -1;
363 }
364 error = getnameinfo(sap, slen,
365 NULL, 0,
366 sname, NI_MAXSERV,
367 NI_NUMERICHOST | NI_NUMERICSERV);
368 if (error) {
369 _msgout("getnameinfo(): %s",
370 strerror(errno));
371 freeaddrinfo(res0);
372 close(s);
373 free(sname);
374 return -1;
375 }
376 servname = sname;
377 }
378 }
379 freeaddrinfo(res0);
380 }
381 } else {
382 slep = malloc(sizeof(*slep));
383 if (slep == NULL) {
384 _msgout("malloc failed: %s", strerror(errno));
385 return -1;
386 }
387 memset(slep, 0, sizeof(*slep));
388 slep->sle_sock = sock;
389 SLIST_INSERT_HEAD(&sle_head, slep, sle_next);
390 }
391
392 /*
393 * Traverse socketlist and create rpc service handles for each socket.
394 */
395 SLIST_FOREACH(slep, &sle_head, sle_next) {
396 if (nconf->nc_semantics == NC_TPI_CLTS)
397 transp = svc_dg_create(slep->sle_sock, 0, 0);
398 else
399 transp = svc_vc_create(slep->sle_sock, RPC_MAXDATASIZE,
400 RPC_MAXDATASIZE);
401 if (transp == NULL) {
402 _msgout("unable to create service: %s",
403 nconf->nc_netid);
404 continue;
405 }
406 if (!svc_reg(transp, YPPROG, YPOLDVERS, ypprog_1, NULL)) {
407 svc_destroy(transp);
408 close(slep->sle_sock);
409 _msgout("unable to register (YPPROG, YPOLDVERS, %s):"
410 " %s", nconf->nc_netid, strerror(errno));
411 continue;
412 }
413 if (!svc_reg(transp, YPPROG, YPVERS, ypprog_2, NULL)) {
414 svc_destroy(transp);
415 close(slep->sle_sock);
416 _msgout("unable to register (YPPROG, YPVERS, %s): %s",
417 nconf->nc_netid, strerror(errno));
418 continue;
419 }
420 }
421 while(!(SLIST_EMPTY(&sle_head)))
422 SLIST_REMOVE_HEAD(&sle_head, sle_next);
423
424 /*
425 * Register RPC service to rpcbind by using AI_PASSIVE address.
426 */
427 hints.ai_flags = AI_PASSIVE;
428 error = getaddrinfo(NULL, servname, &hints, &res0);
429 if (error) {
430 _msgout("getaddrinfo(): %s", gai_strerror(error));
431 return -1;
432 }
433 svcaddr.buf = res0->ai_addr;
434 svcaddr.len = res0->ai_addrlen;
435
436 if (si->si_af == AF_INET) {
437 /* XXX: ignore error intentionally */
438 rpcb_set(YPPROG, YPOLDVERS, nconf, &svcaddr);
439 }
440 /* XXX: ignore error intentionally */
441 rpcb_set(YPPROG, YPVERS, nconf, &svcaddr);
442 freeaddrinfo(res0);
443 return 0;
444 }
445
446 int
main(int argc,char * argv[])447 main(int argc, char *argv[])
448 {
449 int ch;
450 int error;
451 int ntrans;
452
453 void *nc_handle;
454 struct netconfig *nconf;
455 struct __rpc_sockinfo si;
456 struct bindaddrlistent *blep;
457
458 memset(&si, 0, sizeof(si));
459 SLIST_INIT(&ble_head);
460
461 while ((ch = getopt(argc, argv, "dh:np:P:")) != -1) {
462 switch (ch) {
463 case 'd':
464 debug = ypdb_debug = 1;
465 break;
466 case 'h':
467 blep = malloc(sizeof(*blep));
468 if (blep == NULL)
469 err(1, "malloc() failed: -h %s", optarg);
470 blep->ble_hostname = optarg;
471 SLIST_INSERT_HEAD(&ble_head, blep, ble_next);
472 break;
473 case 'n':
474 do_dns = 1;
475 break;
476 case 'p':
477 yp_dir = optarg;
478 break;
479 case 'P':
480 servname = optarg;
481 break;
482 default:
483 usage();
484 }
485 }
486 /*
487 * Add "anyaddr" entry if no -h is specified.
488 */
489 if (SLIST_EMPTY(&ble_head)) {
490 blep = malloc(sizeof(*blep));
491 if (blep == NULL)
492 err(1, "malloc() failed");
493 memset(blep, 0, sizeof(*blep));
494 SLIST_INSERT_HEAD(&ble_head, blep, ble_next);
495 }
496
497 load_securenets();
498 yp_init_resolver();
499 #ifdef DB_CACHE
500 yp_init_dbs();
501 #endif
502 nc_handle = setnetconfig();
503 if (nc_handle == NULL)
504 err(1, "cannot read %s", NETCONFIG);
505 if (__rpc_fd2sockinfo(0, &si) != 0) {
506 /* invoked from inetd */
507 _rpcpmstart = 1;
508 _rpcfdtype = si.si_socktype;
509 _rpcaf = si.si_af;
510 _rpcfd = 0;
511 openlog("ypserv", LOG_PID, LOG_DAEMON);
512 } else {
513 /* standalone mode */
514 if (!debug) {
515 if (daemon(0,0)) {
516 err(1,"cannot fork");
517 }
518 openlog("ypserv", LOG_PID, LOG_DAEMON);
519 }
520 _rpcpmstart = 0;
521 _rpcaf = AF_INET;
522 _rpcfd = RPC_ANYFD;
523 unregister();
524 }
525
526 if (madvise(NULL, 0, MADV_PROTECT) != 0)
527 _msgout("madvise(): %s", strerror(errno));
528
529 /*
530 * Create RPC service for each transport.
531 */
532 ntrans = 0;
533 while((nconf = getnetconfig(nc_handle))) {
534 if ((nconf->nc_flag & NC_VISIBLE)) {
535 if (__rpc_nconf2sockinfo(nconf, &si) == 0) {
536 _msgout("cannot get information for %s. "
537 "Ignored.", nconf->nc_netid);
538 continue;
539 }
540 if (_rpcpmstart) {
541 if (si.si_socktype != _rpcfdtype ||
542 si.si_af != _rpcaf)
543 continue;
544 } else if (si.si_af != _rpcaf)
545 continue;
546 error = create_service(_rpcfd, nconf, &si);
547 if (error) {
548 endnetconfig(nc_handle);
549 exit(1);
550 }
551 ntrans++;
552 }
553 }
554 endnetconfig(nc_handle);
555 while(!(SLIST_EMPTY(&ble_head)))
556 SLIST_REMOVE_HEAD(&ble_head, ble_next);
557 if (ntrans == 0) {
558 _msgout("no transport is available. Aborted.");
559 exit(1);
560 }
561 if (_rpcpmstart) {
562 (void) signal(SIGALRM, (SIG_PF) closedown);
563 (void) alarm(_RPCSVC_CLOSEDOWN/2);
564 }
565 /*
566 * Make sure SIGPIPE doesn't blow us away while servicing TCP
567 * connections.
568 */
569 (void) signal(SIGPIPE, SIG_IGN);
570 (void) signal(SIGCHLD, (SIG_PF) reaper);
571 (void) signal(SIGTERM, (SIG_PF) reaper);
572 (void) signal(SIGINT, (SIG_PF) reaper);
573 (void) signal(SIGHUP, (SIG_PF) reaper);
574 yp_svc_run();
575 _msgout("svc_run returned");
576 exit(1);
577 /* NOTREACHED */
578 }
579