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
main(int argc,char ** argv)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
ypinit(int argc,char ** argv)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
cleanup_resolv(int sig)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
ypget_command_line_args(int argc,char ** argv)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
ypdispatch(struct svc_req * rqstp,SVCXPRT * transp)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
ypolddispatch(struct svc_req * rqstp,SVCXPRT * transp)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
ypexit(void)617 ypexit(void)
618 {
619 fflush(stderr);
620 abort();
621 }
622
623 /*
624 * This constructs a logging record.
625 */
626 void
logprintf(char * format,...)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