#define _SVID_GETTOD
#include <sys/time.h>
extern int gettimeofday(struct timeval *);
#include "ypsym.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <rpc/rpc.h>
#include <netconfig.h>
#include <netdir.h>
#include <sys/select.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <stdarg.h>
#include <signal.h>
#include "shim.h"
#include "yptol.h"
#include <syslog.h>
static char register_failed[] = "ypserv: Unable to register service for ";
bool silent = TRUE;
bool client_setup_failure = FALSE;
bool init_dit = FALSE;
bool init_containers = FALSE;
bool init_maps = FALSE;
char **ldapCLA = NULL;
bool dnsforward = FALSE;
int resolv_pid = 0;
CLIENT *resolv_client = NULL;
char *resolv_tp = "ticots";
#ifdef MINUS_C_OPTION
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);
int
main(int argc, char **argv)
{
if (geteuid() != 0) {
fprintf(stderr, "must be root to run %s\n", argv[0]);
exit(1);
}
ypinit(argc, argv);
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 (init_dit || init_maps) {
printf("Map setup complete. Please now restart NIS daemons "
"with ypstart.\n");
exit(0);
}
svc_run();
return (0);
}
typedef struct {
char *netid;
int fd;
int olddispatch;
int class;
SVCXPRT *xprt;
int ok;
} 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];
static void
ypinit(int argc, char **argv)
{
int pid;
int stat;
struct sigaction act;
int ufd, tfd;
SVCXPRT *utransp, *ttransp;
struct netconfig *nconf;
int connmaxrec = RPC_MAXDATASIZE;
int i, j, services = 0;
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);
}
(void) open("/dev/tty", 2);
setpgrp();
}
#ifdef SYSVCONFIG
sigset(SIGHUP, (void (*)())sysvconfig);
#else
sigset(SIGHUP, SIG_IGN);
#endif
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);
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);
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);
}
if (services > 0) {
for (j = 0; j < MAXSERVICES; j++) {
if (service_classes[j] >= 0) {
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();
}
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);
}
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;
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);
}
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 (init_dit || init_maps)
silent = FALSE;
}
static void
ypdispatch(struct svc_req *rqstp, SVCXPRT *transp)
{
sigset_t set, oset;
#ifdef SYSVCONFIG
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);
}
static void
ypexit(void)
{
fflush(stderr);
abort();
}
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);
}