xref: /illumos-gate/usr/src/cmd/ypcmd/ypserv.c (revision fe4627ef755b7c263f91a0e6f07cdca5d7083501)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * Portions of this source code were derived from Berkeley 4.3 BSD
32  * under license from the Regents of the University of California.
33  */
34 
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 /*
38  * This contains the mainline code for the YP server.  Data
39  * structures which are process-global are also in this module.
40  */
41 
42 /* this is so that ypserv will compile under 5.5 */
43 #define	_SVID_GETTOD
44 #include <sys/time.h>
45 extern int gettimeofday(struct timeval *);
46 
47 #include "ypsym.h"
48 #include <sys/types.h>
49 #include <sys/wait.h>
50 #include <fcntl.h>
51 #include <rpc/rpc.h>
52 #include <netconfig.h>
53 #include <netdir.h>
54 #include <sys/select.h>
55 #include <stdlib.h>
56 #include <unistd.h>
57 #include <stdio.h>
58 #include <stdarg.h>
59 #include <signal.h>
60 #include "shim.h"
61 #include "yptol.h"
62 #include <syslog.h>
63 
64 static char register_failed[] = "ypserv:  Unable to register service for ";
65 bool silent = TRUE;
66 
67 /*
68  * client_setup_failure will be TRUE, if setup of the
69  * connection to rpc.nisd_resolv failed
70  */
71 bool client_setup_failure = FALSE;
72 
73 /* N2L options */
74 bool init_dit = FALSE;
75 bool init_containers = FALSE;
76 bool init_maps = FALSE;
77 char **ldapCLA = NULL;
78 
79 /* For DNS forwarding command line option (-d) */
80 bool dnsforward = FALSE;
81 int resolv_pid = 0;
82 CLIENT *resolv_client = NULL;
83 char *resolv_tp = "ticots";
84 
85 #ifdef MINUS_C_OPTION
86 /* For cluster support (-c) */
87 bool multiflag = FALSE;
88 #endif
89 
90 static char logfile[] = "/var/yp/ypserv.log";
91 void logprintf(char *format, ...);
92 
93 static void ypexit(void);
94 static void ypinit(int argc, char **argv);
95 static void ypdispatch(struct svc_req *rqstp, SVCXPRT *transp);
96 static void ypolddispatch(struct svc_req *rqstp, SVCXPRT *transp);
97 static void ypget_command_line_args(int argc, char **argv);
98 extern void setup_resolv(bool *fwding, int *child,
99 			CLIENT **client, char *tp_type, long prognum);
100 static void cleanup_resolv(int);
101 
102 /*
103  * This is the main line code for the yp server.
104  */
105 int
106 main(int argc, char **argv)
107 {
108 	if (geteuid() != 0) {
109 		fprintf(stderr, "must be root to run %s\n", argv[0]);
110 		exit(1);
111 	}
112 
113 	/* Set up shop */
114 	ypinit(argc, argv);
115 
116 	/* If requested set up the N2L maps. May take a while */
117 	if (init_dit)
118 		if (FAILURE == dump_maps_to_dit(init_containers)) {
119 			fprintf(stderr, "Fatal error dumping maps to DIT."
120 			" See syslog and LDAP server logs for details.\n");
121 			exit(1);
122 		}
123 
124 	if (init_maps)
125 		if (FAILURE == dump_dit_to_maps()) {
126 			fprintf(stderr, "Fatal error dumping DIT to maps."
127 			" See syslog and LDAP server logs for details.\n");
128 			exit(1);
129 		}
130 
131 	/*
132 	 * If we were asked to init the maps now exit. User will then use
133 	 * ypstart to restart ypserv and all the other NIS daemons.
134 	 */
135 	if (init_dit || init_maps) {
136 		printf("Map setup complete. Please now restart NIS daemons "
137 			"with ypstart.\n");
138 		exit(0);
139 	}
140 
141 	svc_run();
142 
143 	/*
144 	 * This is stupid, but the compiler likes to warn us about the
145 	 * absence of returns from main()
146 	 */
147 	return (0);
148 }
149 
150 typedef struct {
151 	char		*netid;
152 	int		fd;
153 	int		olddispatch;	/* Register on protocol version 1 ? */
154 	int		class;		/* Other services that must succeed */
155 	SVCXPRT		*xprt;
156 	int		ok;		/* Registered successfully ? */
157 } ypservice_t;
158 
159 ypservice_t	service[] = {
160 	{ "udp", -1, 1, 4, 0, 0 },
161 	{ "tcp", -1, 1, 4, 0, 0 },
162 	{ "udp6", -1, 0, 6, 0, 0 },
163 	{ "tcp6", -1, 0, 6, 0, 0 }
164 };
165 
166 #define	MAXSERVICES	(sizeof (service)/sizeof (service[0]))
167 
168 int		service_classes[MAXSERVICES];
169 
170 /*
171  * Does startup processing for the yp server.
172  */
173 static void
174 ypinit(int argc, char **argv)
175 {
176 	int pid;
177 	int stat, t;
178 	struct sigaction act;
179 	int ufd, tfd;
180 	SVCXPRT *utransp, *ttransp;
181 	struct netconfig *nconf;
182 	int connmaxrec = RPC_MAXDATASIZE;
183 	int i, j, services = 0;
184 
185 
186 	/*
187 	 * Init yptol flags. Will get redone by init_lock_system() but we need
188 	 * to know if we should parse yptol cmd line options.
189 	 */
190 	init_yptol_flag();
191 
192 	ypget_command_line_args(argc, argv);
193 
194 	if (silent) {
195 		pid = (int)fork();
196 
197 		if (pid == -1) {
198 		    logprintf("ypserv:  ypinit fork failure.\n");
199 		    ypexit();
200 		}
201 
202 		if (pid != 0) {
203 		    exit(0);
204 		}
205 	}
206 
207 	if (!init_lock_system(FALSE)) {
208 		ypexit();
209 	}
210 
211 	get_secure_nets(argv[0]);
212 
213 	if (silent) {
214 		closelog();
215 		closefrom(3);
216 	}
217 
218 	if (yptol_mode) {
219 		stat = parseConfig(ldapCLA, NTOL_MAP_FILE);
220 		if (stat == 1) {
221 			logprintf("NIS to LDAP mapping inactive.\n");
222 		} else if (stat != 0) {
223 			logprintf("Aborting after NIS to LDAP mapping "
224 							"error.\n");
225 			fflush(stderr);
226 			exit(-1);
227 		}
228 	}
229 
230 	if (silent) {
231 		freopen("/dev/null", "r", stdin);
232 		if (access(logfile, _IOWRT)) {
233 		    freopen("/dev/null", "w", stdout);
234 		    freopen("/dev/null", "w", stderr);
235 		} else {
236 		    freopen(logfile, "a", stdout);
237 		    freopen(logfile, "a", stderr);
238 		}
239 
240 		t = open("/dev/tty", 2);
241 
242 		setpgrp();
243 	}
244 
245 #ifdef	SYSVCONFIG
246 	sigset(SIGHUP, (void (*)())sysvconfig);
247 #else
248 	sigset(SIGHUP, SIG_IGN);
249 #endif
250 
251 	/*
252 	 * Setting disposition to SIG_IGN will not create zombies when child
253 	 * processes terminate.
254 	 */
255 	sigset(SIGCHLD, SIG_IGN);
256 
257 	act.sa_handler = cleanup_resolv;
258 	sigemptyset(&act.sa_mask);
259 	act.sa_flags = SA_RESETHAND;
260 	sigaction(SIGTERM, &act, (struct sigaction *)NULL);
261 	sigaction(SIGQUIT, &act, (struct sigaction *)NULL);
262 	sigaction(SIGABRT, &act, (struct sigaction *)NULL);
263 	sigaction(SIGBUS, &act, (struct sigaction *)NULL);
264 	sigaction(SIGSEGV, &act, (struct sigaction *)NULL);
265 
266 	/*
267 	 * Set non-blocking mode and maximum record size for
268 	 * connection oriented RPC transports.
269 	 */
270 	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
271 		logprintf("unable to set maximum RPC record size");
272 	}
273 
274 	svc_unreg(YPPROG, YPVERS);
275 	svc_unreg(YPPROG, YPVERS_ORIG);
276 
277 	for (i = 0; i < sizeof (service)/sizeof (ypservice_t); i++) {
278 
279 		service_classes[i] = -1;
280 
281 		if ((nconf = getnetconfigent(service[i].netid)) == NULL) {
282 			logprintf("getnetconfigent(\"%s\") failed\n",
283 					service[i].netid);
284 			continue;
285 		}
286 
287 		if ((service[i].fd = t_open(nconf->nc_device, O_RDWR, NULL)) <
288 			0) {
289 			logprintf("t_open failed for %s\n", service[i].netid);
290 			freenetconfigent(nconf);
291 			continue;
292 		}
293 
294 		if (netdir_options(nconf, ND_SET_RESERVEDPORT, service[i].fd,
295 			NULL) < 0) {
296 			logprintf("could not set reserved port for %s\n",
297 				service[i].netid);
298 			(void) close(service[i].fd);
299 			service[i].fd = -1;
300 			freenetconfigent(nconf);
301 			continue;
302 		}
303 
304 		if ((service[i].xprt = svc_tli_create(service[i].fd, nconf,
305 			NULL, 0, 0)) == NULL) {
306 			logprintf("svc_tli_create failed for %s\n",
307 				service[i].netid);
308 			(void) close(service[i].fd);
309 			service[i].fd = -1;
310 			freenetconfigent(nconf);
311 			continue;
312 		}
313 
314 		if (!svc_reg(service[i].xprt, YPPROG, YPVERS, ypdispatch,
315 			nconf)) {
316 			logprintf("%s %s\n", service[i].netid, register_failed);
317 			svc_destroy(service[i].xprt);
318 			service[i].xprt = 0;
319 			(void) close(service[i].fd);
320 			service[i].fd = -1;
321 			freenetconfigent(nconf);
322 			continue;
323 		}
324 
325 		if (service[i].olddispatch && !svc_reg(service[i].xprt, YPPROG,
326 					YPVERS_ORIG, ypolddispatch, nconf)) {
327 			logprintf("old %s %s\n",
328 				service[i].netid, register_failed);
329 			/* Can only unregister prognum/versnum */
330 			svc_destroy(service[i].xprt);
331 			service[i].xprt = 0;
332 			(void) close(service[i].fd);
333 			service[i].fd = -1;
334 			freenetconfigent(nconf);
335 			continue;
336 		}
337 
338 		services++;
339 		service[i].ok = 1;
340 		service_classes[i] = service[i].class;
341 
342 		freenetconfigent(nconf);
343 
344 	}
345 
346 	/*
347 	 * Check if we managed to register enough services to continue.
348 	 * It's OK if we managed to register all IPv4 services but no
349 	 * IPv6, or the other way around, but not if we (say) registered
350 	 * IPv4 UDP but not TCP.
351 	 */
352 	if (services > 0) {
353 		for (j = 0; j < MAXSERVICES; j++) {
354 			if (service_classes[j] >= 0) {
355 				/*
356 				 * Must have all services of this class
357 				 * registered.
358 				 */
359 				for (i = 0; i < MAXSERVICES; i++) {
360 					if (service[i].ok == 0 &&
361 						service[i].class ==
362 						service_classes[j]) {
363 						logprintf(
364 			"unable to register all services for class %d\n",
365 							service[i].class);
366 						ypexit();
367 					}
368 				}
369 			}
370 		}
371 	} else {
372 		logprintf("unable to register any services\n");
373 		ypexit();
374 	}
375 
376 	/* Now we setup circuit_n or yp_all() and yp_update() will not work */
377 	if (!svc_create(ypdispatch, YPPROG, YPVERS, "circuit_n")) {
378 		logprintf("circuit_n %s\n", register_failed);
379 		ypexit();
380 	}
381 
382 	if (dnsforward) {
383 		setup_resolv(&dnsforward, &resolv_pid,
384 				&resolv_client, resolv_tp, 0);
385 		if (resolv_client == NULL)
386 			client_setup_failure = TRUE;
387 	}
388 }
389 
390 void
391 cleanup_resolv(int sig)
392 {
393 	if (resolv_pid)
394 		kill(resolv_pid, sig);
395 
396 	kill(getpid(), sig);
397 }
398 
399 /*
400  * This picks up any command line args passed from the process invocation.
401  */
402 static void
403 ypget_command_line_args(int argc, char **argv)
404 {
405 	for (argv++; --argc; argv++) {
406 
407 		if ((*argv)[0] == '-') {
408 
409 			switch ((*argv)[1]) {
410 #ifdef	MINUS_C_OPTION
411 			case 'c':
412 				multiflag = TRUE;
413 				break;
414 #endif
415 			case 'd':
416 				if (access("/etc/resolv.conf", F_OK) == -1) {
417 					fprintf(stderr,
418 			"No /etc/resolv.conf file, -d option ignored\n");
419 				} else {
420 					dnsforward = TRUE;
421 				}
422 				break;
423 			case 'I':
424 				init_containers = TRUE;
425 				/* ... and also do -i stuff */
426 			case 'i':
427 				if (yptol_mode) {
428 					init_dit = TRUE;
429 				} else {
430 					fprintf(stderr, "-%c option is illegal "
431 					"if not in NIS to LDAP mode. Exiting\n",
432 						(*argv)[1]);
433 					fflush(stderr);
434 					exit(-1);
435 				}
436 
437 				/* Handle -ir */
438 				if ('r' != (*argv)[2])
439 					break;
440 
441 			case 'r':
442 				if (yptol_mode) {
443 					init_maps = TRUE;
444 				} else {
445 					fprintf(stderr, "-r option is illegal "
446 						"if not in NIS to LDAP mode. "
447 						"Exiting\n");
448 					fflush(stderr);
449 					exit(-1);
450 				}
451 				break;
452 			case 'v':
453 				silent = FALSE;
454 				break;
455 			}
456 		}
457 	}
458 
459 	/* If setting up don't run silent or demonize */
460 	if (init_dit || init_maps)
461 		silent = FALSE;
462 
463 }
464 
465 /*
466  * This dispatches to server action routines based on the input procedure
467  * number.  ypdispatch is called from the RPC function svc_run.
468  */
469 static void
470 ypdispatch(struct svc_req *rqstp, SVCXPRT *transp)
471 {
472 	sigset_t set, oset;
473 
474 
475 #ifdef	SYSVCONFIG
476 	/* prepare to answer questions about system v filesystem aliases */
477 	sysvconfig();
478 #endif
479 
480 	sigemptyset(&set);
481 	sigaddset(&set, SIGCHLD);
482 	sigprocmask(SIG_BLOCK, &set, &oset);
483 
484 	switch (rqstp->rq_proc) {
485 
486 	case YPPROC_NULL:
487 
488 		if (!svc_sendreply(transp, xdr_void, 0))
489 			logprintf("ypserv:  Can't reply to rpc call.\n");
490 		break;
491 
492 	case YPPROC_DOMAIN:
493 		ypdomain(transp, TRUE);
494 		break;
495 
496 	case YPPROC_DOMAIN_NONACK:
497 		ypdomain(transp, FALSE);
498 		break;
499 
500 	case YPPROC_MATCH:
501 		ypmatch(transp, rqstp);
502 		break;
503 
504 	case YPPROC_FIRST:
505 		ypfirst(transp);
506 		break;
507 
508 	case YPPROC_NEXT:
509 		ypnext(transp);
510 		break;
511 
512 	case YPPROC_XFR:
513 		ypxfr(transp, YPPROC_XFR);
514 		break;
515 
516 	case YPPROC_NEWXFR:
517 		ypxfr(transp, YPPROC_NEWXFR);
518 		break;
519 
520 	case YPPROC_CLEAR:
521 		ypclr_current_map();
522 
523 		if (!svc_sendreply(transp, xdr_void, 0))
524 			logprintf("ypserv:  Can't reply to rpc call.\n");
525 		break;
526 
527 	case YPPROC_ALL:
528 		ypall(transp);
529 		break;
530 
531 	case YPPROC_MASTER:
532 		ypmaster(transp);
533 		break;
534 
535 	case YPPROC_ORDER:
536 		yporder(transp);
537 		break;
538 
539 	case YPPROC_MAPLIST:
540 		ypmaplist(transp);
541 		break;
542 
543 	default:
544 		svcerr_noproc(transp);
545 		break;
546 
547 	}
548 
549 	sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL);
550 
551 }
552 
553 static void
554 ypolddispatch(struct svc_req *rqstp, SVCXPRT *transp)
555 {
556 	sigset_t set, oset;
557 
558 	sigemptyset(&set);
559 	sigaddset(&set, SIGCHLD);
560 	sigprocmask(SIG_BLOCK, &set, &oset);
561 
562 	switch (rqstp->rq_proc) {
563 
564 	case YPOLDPROC_NULL:
565 		if (!svc_sendreply(transp, xdr_void, 0))
566 			logprintf("ypserv:  Can't replay to rpc call.\n");
567 		break;
568 
569 	case YPOLDPROC_DOMAIN:
570 		ypdomain(transp, TRUE);
571 		break;
572 
573 	case YPOLDPROC_DOMAIN_NONACK:
574 		ypdomain(transp, FALSE);
575 		break;
576 
577 	case YPOLDPROC_MATCH:
578 		ypoldmatch(transp, rqstp);
579 		break;
580 
581 	case YPOLDPROC_FIRST:
582 		ypoldfirst(transp);
583 		break;
584 
585 	case YPOLDPROC_NEXT:
586 		ypoldnext(transp);
587 		break;
588 
589 	case YPOLDPROC_POLL:
590 		ypoldpoll(transp);
591 		break;
592 
593 	case YPOLDPROC_PUSH:
594 		ypoldpush(transp);
595 		break;
596 
597 	case YPOLDPROC_PULL:
598 		ypoldpull(transp);
599 		break;
600 
601 	case YPOLDPROC_GET:
602 		ypoldget(transp);
603 
604 	default:
605 		svcerr_noproc(transp);
606 		break;
607 	}
608 
609 	sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL);
610 }
611 
612 /*
613  * This flushes output to stderr, then aborts the server process to leave a
614  * core dump.
615  */
616 static void
617 ypexit(void)
618 {
619 	fflush(stderr);
620 	abort();
621 }
622 
623 /*
624  * This constructs a logging record.
625  */
626 void
627 logprintf(char *format, ...)
628 {
629 	va_list ap;
630 	struct timeval t;
631 
632 	va_start(ap, format);
633 
634 	if (silent) {
635 		gettimeofday(&t);
636 		fseek(stderr, 0, 2);
637 		fprintf(stderr, "%19.19s: ", ctime(&t.tv_sec));
638 	}
639 
640 	vfprintf(stderr, format, ap);
641 	va_end(ap);
642 	fflush(stderr);
643 }
644