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