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