1 /* 2 * Copyright (c) 1995 3 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Bill Paul. 16 * 4. Neither the name of the author nor the names of any co-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 Bill Paul 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 Bill Paul 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 * $FreeBSD: src/usr.sbin/ypserv/yp_main.c,v 1.29 2008/02/03 17:39:37 matteo Exp $ 33 */ 34 35 /* 36 * ypserv startup function. 37 * We need out own main() since we have to do some additional work 38 * that rpcgen won't do for us. Most of this file was generated using 39 * rpcgen.new, and later modified. 40 */ 41 42 #include "yp.h" 43 #include <err.h> 44 #include <errno.h> 45 #include <memory.h> 46 #include <stdio.h> 47 #include <signal.h> 48 #include <stdlib.h> /* getenv, exit */ 49 #include <string.h> /* strcmp */ 50 #include <syslog.h> 51 #include <unistd.h> 52 #include <rpc/pmap_clnt.h> /* for pmap_unset */ 53 #ifdef __cplusplus 54 #include <sysent.h> /* getdtablesize, open */ 55 #endif /* __cplusplus */ 56 #include <sys/socket.h> 57 #include <netinet/in.h> 58 #include <sys/wait.h> 59 #include "yp_extern.h" 60 #include <rpc/rpc.h> 61 62 #ifndef SIG_PF 63 #define SIG_PF void(*)(int) 64 #endif 65 66 #define _RPCSVC_CLOSEDOWN 120 67 int _rpcpmstart; /* Started by a port monitor ? */ 68 static int _rpcfdtype; 69 /* Whether Stream or Datagram ? */ 70 /* States a server can be in wrt request */ 71 72 #define _IDLE 0 73 #define _SERVED 1 74 #define _SERVING 2 75 76 extern void ypprog_1(struct svc_req *, SVCXPRT *); 77 extern void ypprog_2(struct svc_req *, SVCXPRT *); 78 extern int _rpc_dtablesize(void); 79 extern int _rpcsvcstate; /* Set when a request is serviced */ 80 char *progname = "ypserv"; 81 const char *yp_dir = _PATH_YP; 82 int debug = 0; 83 int do_dns = 0; 84 int resfd; 85 86 struct socktype { 87 const char *st_name; 88 int st_type; 89 }; 90 static struct socktype stlist[] = { 91 { "tcp", SOCK_STREAM }, 92 { "udp", SOCK_DGRAM }, 93 { NULL, 0 } 94 }; 95 96 static void 97 _msgout(char *msg) 98 { 99 if (debug) { 100 if (_rpcpmstart) 101 syslog(LOG_ERR, "%s", msg); 102 else 103 warnx("%s", msg); 104 } else 105 syslog(LOG_ERR, "%s", msg); 106 } 107 108 pid_t yp_pid; 109 110 static void 111 yp_svc_run(void) 112 { 113 #ifdef FD_SETSIZE 114 fd_set readfds; 115 #else 116 int readfds; 117 #endif /* def FD_SETSIZE */ 118 int fd_setsize = _rpc_dtablesize(); 119 struct timeval timeout; 120 121 /* Establish the identity of the parent ypserv process. */ 122 yp_pid = getpid(); 123 124 for (;;) { 125 #ifdef FD_SETSIZE 126 readfds = svc_fdset; 127 #else 128 readfds = svc_fds; 129 #endif /* def FD_SETSIZE */ 130 131 FD_SET(resfd, &readfds); 132 133 timeout.tv_sec = RESOLVER_TIMEOUT; 134 timeout.tv_usec = 0; 135 switch (select(fd_setsize, &readfds, NULL, NULL, 136 &timeout)) { 137 case -1: 138 if (errno == EINTR) { 139 continue; 140 } 141 warn("svc_run: - select failed"); 142 return; 143 case 0: 144 if (getpid() == yp_pid) 145 yp_prune_dnsq(); 146 break; 147 default: 148 if (getpid() == yp_pid) { 149 if (FD_ISSET(resfd, &readfds)) { 150 yp_run_dnsq(); 151 FD_CLR(resfd, &readfds); 152 } 153 svc_getreqset(&readfds); 154 } 155 } 156 if (yp_pid != getpid()) 157 _exit(0); 158 } 159 } 160 161 static void 162 unregister(void) 163 { 164 pmap_unset(YPPROG, YPVERS); 165 pmap_unset(YPPROG, YPOLDVERS); 166 } 167 168 static void 169 reaper(int sig) 170 { 171 int status; 172 int saved_errno; 173 174 saved_errno = errno; 175 176 if (sig == SIGHUP) { 177 load_securenets(); 178 #ifdef DB_CACHE 179 yp_flush_all(); 180 #endif 181 errno = saved_errno; 182 return; 183 } 184 185 if (sig == SIGCHLD) { 186 while (wait3(&status, WNOHANG, NULL) > 0) 187 children--; 188 } else { 189 unregister(); 190 exit(0); 191 } 192 errno = saved_errno; 193 return; 194 } 195 196 static void 197 usage(void) 198 { 199 fprintf(stderr, "usage: ypserv [-h] [-d] [-n] [-p path] [-P port]\n"); 200 exit(1); 201 } 202 203 static void 204 closedown(int sig) 205 { 206 if (_rpcsvcstate == _IDLE) { 207 extern fd_set svc_fdset; 208 static int size; 209 int i, openfd; 210 211 if (_rpcfdtype == SOCK_DGRAM) { 212 unregister(); 213 exit(0); 214 } 215 if (size == 0) { 216 size = getdtablesize(); 217 } 218 for (i = 0, openfd = 0; i < size && openfd < 2; i++) 219 if (FD_ISSET(i, &svc_fdset)) 220 openfd++; 221 if (openfd <= 1) { 222 unregister(); 223 exit(0); 224 } 225 } 226 if (_rpcsvcstate == _SERVED) 227 _rpcsvcstate = _IDLE; 228 229 signal(SIGALRM, (SIG_PF)closedown); 230 alarm(_RPCSVC_CLOSEDOWN / 2); 231 } 232 233 int 234 main(int argc, char *argv[]) 235 { 236 SVCXPRT *transp = NULL; 237 int sock; 238 int proto = 0; 239 struct sockaddr_in saddr; 240 socklen_t asize = sizeof (saddr); 241 int ch; 242 in_port_t yp_port = 0; 243 char *errstr; 244 struct socktype *st; 245 246 while ((ch = getopt(argc, argv, "hdnp:P:")) != -1) { 247 switch (ch) { 248 case 'd': 249 debug = ypdb_debug = 1; 250 break; 251 case 'n': 252 do_dns = 1; 253 break; 254 case 'p': 255 yp_dir = optarg; 256 break; 257 case 'P': 258 yp_port = (in_port_t)strtonum(optarg, 1, 65535, 259 (const char **)&errstr); 260 if (yp_port == 0 && errstr != NULL) { 261 _msgout("invalid port number provided"); 262 exit(1); 263 } 264 break; 265 case 'h': 266 default: 267 usage(); 268 } 269 } 270 271 load_securenets(); 272 yp_init_resolver(); 273 #ifdef DB_CACHE 274 yp_init_dbs(); 275 #endif 276 if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) { 277 int ssize = sizeof (int); 278 279 if (saddr.sin_family != AF_INET) 280 exit(1); 281 if (getsockopt(0, SOL_SOCKET, SO_TYPE, 282 (char *)&_rpcfdtype, &ssize) == -1) 283 exit(1); 284 sock = 0; 285 _rpcpmstart = 1; 286 proto = 0; 287 openlog("ypserv", LOG_PID, LOG_DAEMON); 288 } else { 289 if (!debug) { 290 if (daemon(0,0)) { 291 err(1,"cannot fork"); 292 } 293 openlog("ypserv", LOG_PID, LOG_DAEMON); 294 } 295 sock = RPC_ANYSOCK; 296 pmap_unset(YPPROG, YPVERS); 297 pmap_unset(YPPROG, 1); 298 } 299 300 /* 301 * Initialize TCP/UDP sockets. 302 */ 303 memset((char *)&saddr, 0, sizeof(saddr)); 304 saddr.sin_family = AF_INET; 305 saddr.sin_addr.s_addr = htonl(INADDR_ANY); 306 saddr.sin_port = htons(yp_port); 307 for (st = stlist; st->st_name != NULL; st++) { 308 /* Do not bind the socket if the user didn't specify a port */ 309 if (yp_port == 0) 310 break; 311 312 sock = socket(AF_INET, st->st_type, 0); 313 if (sock == -1) { 314 if ((asprintf(&errstr, "cannot create a %s socket", 315 st->st_name)) == -1) 316 err(1, "unexpected failure in asprintf()"); 317 _msgout(errstr); 318 free((void *)errstr); 319 exit(1); 320 } 321 if (bind(sock, (struct sockaddr *) &saddr, sizeof(saddr)) 322 == -1) { 323 if ((asprintf(&errstr, "cannot bind %s socket", 324 st->st_name)) == -1) 325 err(1, "unexpected failure in asprintf()"); 326 _msgout(errstr); 327 free((void *)errstr); 328 exit(1); 329 } 330 errstr = NULL; 331 } 332 333 if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) { 334 transp = svcudp_create(sock); 335 if (transp == NULL) { 336 _msgout("cannot create udp service"); 337 exit(1); 338 } 339 if (!_rpcpmstart) 340 proto = IPPROTO_UDP; 341 if (!svc_register(transp, YPPROG, YPOLDVERS, ypprog_1, proto)) { 342 _msgout("unable to register (YPPROG, YPOLDVERS, udp)"); 343 exit(1); 344 } 345 if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) { 346 _msgout("unable to register (YPPROG, YPVERS, udp)"); 347 exit(1); 348 } 349 } 350 351 if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) { 352 transp = svctcp_create(sock, 0, 0); 353 if (transp == NULL) { 354 _msgout("cannot create tcp service"); 355 exit(1); 356 } 357 if (!_rpcpmstart) 358 proto = IPPROTO_TCP; 359 if (!svc_register(transp, YPPROG, YPOLDVERS, ypprog_1, proto)) { 360 _msgout("unable to register (YPPROG, YPOLDVERS, tcp)"); 361 exit(1); 362 } 363 if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) { 364 _msgout("unable to register (YPPROG, YPVERS, tcp)"); 365 exit(1); 366 } 367 } 368 369 if (transp == NULL) { 370 _msgout("could not create a handle"); 371 exit(1); 372 } 373 if (_rpcpmstart) { 374 signal(SIGALRM, (SIG_PF)closedown); 375 alarm(_RPCSVC_CLOSEDOWN / 2); 376 } 377 /* 378 * Make sure SIGPIPE doesn't blow us away while servicing TCP 379 * connections. 380 */ 381 signal(SIGPIPE, SIG_IGN); 382 signal(SIGCHLD, (SIG_PF) reaper); 383 signal(SIGTERM, (SIG_PF) reaper); 384 signal(SIGINT, (SIG_PF) reaper); 385 signal(SIGHUP, (SIG_PF) reaper); 386 yp_svc_run(); 387 _msgout("svc_run returned"); 388 exit(1); 389 /* NOTREACHED */ 390 } 391