/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Portions of this source code were derived from Berkeley 4.3 BSD * under license from the Regents of the University of California. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * This contains the mainline code for the YP server. Data * structures which are process-global are also in this module. */ /* this is so that ypserv will compile under 5.5 */ #define _SVID_GETTOD #include extern int gettimeofday(struct timeval *); #include "ypsym.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "shim.h" #include "yptol.h" #include static char register_failed[] = "ypserv: Unable to register service for "; bool silent = TRUE; /* * client_setup_failure will be TRUE, if setup of the * connection to rpc.nisd_resolv failed */ bool client_setup_failure = FALSE; /* N2L options */ bool init_dit = FALSE; bool init_containers = FALSE; bool init_maps = FALSE; char **ldapCLA = NULL; /* For DNS forwarding command line option (-d) */ bool dnsforward = FALSE; int resolv_pid = 0; CLIENT *resolv_client = NULL; char *resolv_tp = "ticots"; #ifdef MINUS_C_OPTION /* For cluster support (-c) */ bool multiflag = FALSE; #endif static char logfile[] = "/var/yp/ypserv.log"; void logprintf(char *format, ...); static void ypexit(void); static void ypinit(int argc, char **argv); static void ypdispatch(struct svc_req *rqstp, SVCXPRT *transp); static void ypolddispatch(struct svc_req *rqstp, SVCXPRT *transp); static void ypget_command_line_args(int argc, char **argv); extern void setup_resolv(bool *fwding, int *child, CLIENT **client, char *tp_type, long prognum); static void cleanup_resolv(int); /* * This is the main line code for the yp server. */ int main(int argc, char **argv) { if (geteuid() != 0) { fprintf(stderr, "must be root to run %s\n", argv[0]); exit(1); } /* Set up shop */ ypinit(argc, argv); /* If requested set up the N2L maps. May take a while */ if (init_dit) if (FAILURE == dump_maps_to_dit(init_containers)) { fprintf(stderr, "Fatal error dumping maps to DIT." " See syslog and LDAP server logs for details.\n"); exit(1); } if (init_maps) if (FAILURE == dump_dit_to_maps()) { fprintf(stderr, "Fatal error dumping DIT to maps." " See syslog and LDAP server logs for details.\n"); exit(1); } /* * If we were asked to init the maps now exit. User will then use * ypstart to restart ypserv and all the other NIS daemons. */ if (init_dit || init_maps) { printf("Map setup complete. Please now restart NIS daemons " "with ypstart.\n"); exit(0); } svc_run(); /* * This is stupid, but the compiler likes to warn us about the * absence of returns from main() */ return (0); } typedef struct { char *netid; int fd; int olddispatch; /* Register on protocol version 1 ? */ int class; /* Other services that must succeed */ SVCXPRT *xprt; int ok; /* Registered successfully ? */ } ypservice_t; ypservice_t service[] = { { "udp", -1, 1, 4, 0, 0 }, { "tcp", -1, 1, 4, 0, 0 }, { "udp6", -1, 0, 6, 0, 0 }, { "tcp6", -1, 0, 6, 0, 0 } }; #define MAXSERVICES (sizeof (service)/sizeof (service[0])) int service_classes[MAXSERVICES]; /* * Does startup processing for the yp server. */ static void ypinit(int argc, char **argv) { int pid; int stat, t; struct sigaction act; int ufd, tfd; SVCXPRT *utransp, *ttransp; struct netconfig *nconf; int connmaxrec = RPC_MAXDATASIZE; int i, j, services = 0; /* * Init yptol flags. Will get redone by init_lock_system() but we need * to know if we should parse yptol cmd line options. */ init_yptol_flag(); ypget_command_line_args(argc, argv); if (silent) { pid = (int)fork(); if (pid == -1) { logprintf("ypserv: ypinit fork failure.\n"); ypexit(); } if (pid != 0) { exit(0); } } if (!init_lock_system(FALSE)) { ypexit(); } get_secure_nets(argv[0]); if (silent) { closelog(); closefrom(3); } if (yptol_mode) { stat = parseConfig(ldapCLA, NTOL_MAP_FILE); if (stat == 1) { logprintf("NIS to LDAP mapping inactive.\n"); } else if (stat != 0) { logprintf("Aborting after NIS to LDAP mapping " "error.\n"); fflush(stderr); exit(-1); } } if (silent) { freopen("/dev/null", "r", stdin); if (access(logfile, _IOWRT)) { freopen("/dev/null", "w", stdout); freopen("/dev/null", "w", stderr); } else { freopen(logfile, "a", stdout); freopen(logfile, "a", stderr); } t = open("/dev/tty", 2); setpgrp(); } #ifdef SYSVCONFIG sigset(SIGHUP, (void (*)())sysvconfig); #else sigset(SIGHUP, SIG_IGN); #endif /* * Setting disposition to SIG_IGN will not create zombies when child * processes terminate. */ sigset(SIGCHLD, SIG_IGN); act.sa_handler = cleanup_resolv; sigemptyset(&act.sa_mask); act.sa_flags = SA_RESETHAND; sigaction(SIGTERM, &act, (struct sigaction *)NULL); sigaction(SIGQUIT, &act, (struct sigaction *)NULL); sigaction(SIGABRT, &act, (struct sigaction *)NULL); sigaction(SIGBUS, &act, (struct sigaction *)NULL); sigaction(SIGSEGV, &act, (struct sigaction *)NULL); /* * Set non-blocking mode and maximum record size for * connection oriented RPC transports. */ if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) { logprintf("unable to set maximum RPC record size"); } svc_unreg(YPPROG, YPVERS); svc_unreg(YPPROG, YPVERS_ORIG); for (i = 0; i < sizeof (service)/sizeof (ypservice_t); i++) { service_classes[i] = -1; if ((nconf = getnetconfigent(service[i].netid)) == NULL) { logprintf("getnetconfigent(\"%s\") failed\n", service[i].netid); continue; } if ((service[i].fd = t_open(nconf->nc_device, O_RDWR, NULL)) < 0) { logprintf("t_open failed for %s\n", service[i].netid); freenetconfigent(nconf); continue; } if (netdir_options(nconf, ND_SET_RESERVEDPORT, service[i].fd, NULL) < 0) { logprintf("could not set reserved port for %s\n", service[i].netid); (void) close(service[i].fd); service[i].fd = -1; freenetconfigent(nconf); continue; } if ((service[i].xprt = svc_tli_create(service[i].fd, nconf, NULL, 0, 0)) == NULL) { logprintf("svc_tli_create failed for %s\n", service[i].netid); (void) close(service[i].fd); service[i].fd = -1; freenetconfigent(nconf); continue; } if (!svc_reg(service[i].xprt, YPPROG, YPVERS, ypdispatch, nconf)) { logprintf("%s %s\n", service[i].netid, register_failed); svc_destroy(service[i].xprt); service[i].xprt = 0; (void) close(service[i].fd); service[i].fd = -1; freenetconfigent(nconf); continue; } if (service[i].olddispatch && !svc_reg(service[i].xprt, YPPROG, YPVERS_ORIG, ypolddispatch, nconf)) { logprintf("old %s %s\n", service[i].netid, register_failed); /* Can only unregister prognum/versnum */ svc_destroy(service[i].xprt); service[i].xprt = 0; (void) close(service[i].fd); service[i].fd = -1; freenetconfigent(nconf); continue; } services++; service[i].ok = 1; service_classes[i] = service[i].class; freenetconfigent(nconf); } /* * Check if we managed to register enough services to continue. * It's OK if we managed to register all IPv4 services but no * IPv6, or the other way around, but not if we (say) registered * IPv4 UDP but not TCP. */ if (services > 0) { for (j = 0; j < MAXSERVICES; j++) { if (service_classes[j] >= 0) { /* * Must have all services of this class * registered. */ for (i = 0; i < MAXSERVICES; i++) { if (service[i].ok == 0 && service[i].class == service_classes[j]) { logprintf( "unable to register all services for class %d\n", service[i].class); ypexit(); } } } } } else { logprintf("unable to register any services\n"); ypexit(); } /* Now we setup circuit_n or yp_all() and yp_update() will not work */ if (!svc_create(ypdispatch, YPPROG, YPVERS, "circuit_n")) { logprintf("circuit_n %s\n", register_failed); ypexit(); } if (dnsforward) { setup_resolv(&dnsforward, &resolv_pid, &resolv_client, resolv_tp, 0); if (resolv_client == NULL) client_setup_failure = TRUE; } } void cleanup_resolv(int sig) { if (resolv_pid) kill(resolv_pid, sig); kill(getpid(), sig); } /* * This picks up any command line args passed from the process invocation. */ static void ypget_command_line_args(int argc, char **argv) { for (argv++; --argc; argv++) { if ((*argv)[0] == '-') { switch ((*argv)[1]) { #ifdef MINUS_C_OPTION case 'c': multiflag = TRUE; break; #endif case 'd': if (access("/etc/resolv.conf", F_OK) == -1) { fprintf(stderr, "No /etc/resolv.conf file, -d option ignored\n"); } else { dnsforward = TRUE; } break; case 'I': init_containers = TRUE; /* ... and also do -i stuff */ case 'i': if (yptol_mode) { init_dit = TRUE; } else { fprintf(stderr, "-%c option is illegal " "if not in NIS to LDAP mode. Exiting\n", (*argv)[1]); fflush(stderr); exit(-1); } /* Handle -ir */ if ('r' != (*argv)[2]) break; case 'r': if (yptol_mode) { init_maps = TRUE; } else { fprintf(stderr, "-r option is illegal " "if not in NIS to LDAP mode. " "Exiting\n"); fflush(stderr); exit(-1); } break; case 'v': silent = FALSE; break; } } } /* If setting up don't run silent or demonize */ if (init_dit || init_maps) silent = FALSE; } /* * This dispatches to server action routines based on the input procedure * number. ypdispatch is called from the RPC function svc_run. */ static void ypdispatch(struct svc_req *rqstp, SVCXPRT *transp) { sigset_t set, oset; #ifdef SYSVCONFIG /* prepare to answer questions about system v filesystem aliases */ sysvconfig(); #endif sigemptyset(&set); sigaddset(&set, SIGCHLD); sigprocmask(SIG_BLOCK, &set, &oset); switch (rqstp->rq_proc) { case YPPROC_NULL: if (!svc_sendreply(transp, xdr_void, 0)) logprintf("ypserv: Can't reply to rpc call.\n"); break; case YPPROC_DOMAIN: ypdomain(transp, TRUE); break; case YPPROC_DOMAIN_NONACK: ypdomain(transp, FALSE); break; case YPPROC_MATCH: ypmatch(transp, rqstp); break; case YPPROC_FIRST: ypfirst(transp); break; case YPPROC_NEXT: ypnext(transp); break; case YPPROC_XFR: ypxfr(transp, YPPROC_XFR); break; case YPPROC_NEWXFR: ypxfr(transp, YPPROC_NEWXFR); break; case YPPROC_CLEAR: ypclr_current_map(); if (!svc_sendreply(transp, xdr_void, 0)) logprintf("ypserv: Can't reply to rpc call.\n"); break; case YPPROC_ALL: ypall(transp); break; case YPPROC_MASTER: ypmaster(transp); break; case YPPROC_ORDER: yporder(transp); break; case YPPROC_MAPLIST: ypmaplist(transp); break; default: svcerr_noproc(transp); break; } sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL); } static void ypolddispatch(struct svc_req *rqstp, SVCXPRT *transp) { sigset_t set, oset; sigemptyset(&set); sigaddset(&set, SIGCHLD); sigprocmask(SIG_BLOCK, &set, &oset); switch (rqstp->rq_proc) { case YPOLDPROC_NULL: if (!svc_sendreply(transp, xdr_void, 0)) logprintf("ypserv: Can't replay to rpc call.\n"); break; case YPOLDPROC_DOMAIN: ypdomain(transp, TRUE); break; case YPOLDPROC_DOMAIN_NONACK: ypdomain(transp, FALSE); break; case YPOLDPROC_MATCH: ypoldmatch(transp, rqstp); break; case YPOLDPROC_FIRST: ypoldfirst(transp); break; case YPOLDPROC_NEXT: ypoldnext(transp); break; case YPOLDPROC_POLL: ypoldpoll(transp); break; case YPOLDPROC_PUSH: ypoldpush(transp); break; case YPOLDPROC_PULL: ypoldpull(transp); break; case YPOLDPROC_GET: ypoldget(transp); default: svcerr_noproc(transp); break; } sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL); } /* * This flushes output to stderr, then aborts the server process to leave a * core dump. */ static void ypexit(void) { fflush(stderr); abort(); } /* * This constructs a logging record. */ void logprintf(char *format, ...) { va_list ap; struct timeval t; va_start(ap, format); if (silent) { gettimeofday(&t); fseek(stderr, 0, 2); fprintf(stderr, "%19.19s: ", ctime(&t.tv_sec)); } vfprintf(stderr, format, ap); va_end(ap); fflush(stderr); }