Home | History | Annotate | Line # | Download | only in ypserv
ypserv.c revision 1.5
      1 /*	$NetBSD: ypserv.c,v 1.5 1997/07/18 21:57:19 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1994 Mats O Jansson <moj (at) stacken.kth.se>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by Mats O Jansson
     18  * 4. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     22  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #include <sys/types.h>
     35 #include <sys/socket.h>
     36 #include <sys/wait.h>
     37 
     38 #include <netinet/in.h>
     39 
     40 #include <err.h>
     41 #include <netdb.h>
     42 #include <signal.h>
     43 #include <stdio.h>
     44 #include <stdlib.h>
     45 #include <string.h>
     46 #include <syslog.h>
     47 #include <unistd.h>
     48 
     49 #include <rpc/rpc.h>
     50 #include <rpc/xdr.h>
     51 #include <rpc/pmap_clnt.h>
     52 
     53 #include <rpcsvc/yp_prot.h>
     54 
     55 #include "acl.h"
     56 #include "yplog.h"
     57 #include "ypdef.h"
     58 #include "ypserv.h"
     59 
     60 #ifdef __STDC__
     61 #define SIG_PF void(*)(int)
     62 #endif
     63 
     64 #ifdef DEBUG
     65 #define RPC_SVC_FG
     66 #endif
     67 
     68 #define _RPCSVC_CLOSEDOWN 120
     69 static int _rpcpmstart;		/* Started by a port monitor ? */
     70 static int _rpcfdtype;		/* Whether Stream or Datagram ? */
     71 static int _rpcsvcdirty;	/* Still serving ? */
     72 
     73 int	usedns;
     74 char	*aclfile;
     75 
     76 extern	char *__progname;	/* from crt0.s */
     77 extern	char *optarg;
     78 extern	int optind;
     79 
     80 int	main __P((int, char *[]));
     81 void	usage __P((void));
     82 
     83 void	sighandler __P((int));
     84 
     85 static	void closedown __P((void));
     86 
     87 static
     88 void _msgout(char* msg)
     89 {
     90 #ifdef RPC_SVC_FG
     91 	if (_rpcpmstart)
     92 		syslog(LOG_ERR, msg);
     93 	else
     94 		warnx("%s", msg);
     95 #else
     96 	syslog(LOG_ERR, msg);
     97 #endif
     98 }
     99 
    100 static void
    101 closedown()
    102 {
    103 	if (_rpcsvcdirty == 0) {
    104 		extern fd_set svc_fdset;
    105 		static int size;
    106 		int i, openfd;
    107 
    108 		if (_rpcfdtype == SOCK_DGRAM)
    109 			exit(0);
    110 		if (size == 0) {
    111 			size = getdtablesize();
    112 		}
    113 		for (i = 0, openfd = 0; i < size && openfd < 2; i++)
    114 			if (FD_ISSET(i, &svc_fdset))
    115 				openfd++;
    116 		if (openfd <= (_rpcpmstart?0:1))
    117 			exit(0);
    118 	}
    119 	(void) alarm(_RPCSVC_CLOSEDOWN);
    120 }
    121 
    122 static void
    123 ypprog_2(struct svc_req *rqstp, register SVCXPRT *transp)
    124 {
    125 	union {
    126 		char * ypproc_domain_2_arg;
    127 		char * ypproc_domain_nonack_2_arg;
    128 		struct ypreq_key ypproc_match_2_arg;
    129 		struct ypreq_nokey ypproc_first_2_arg;
    130 		struct ypreq_key ypproc_next_2_arg;
    131 		struct ypreq_xfr ypproc_xfr_2_arg;
    132 		struct ypreq_nokey ypproc_all_2_arg;
    133 		struct ypreq_nokey ypproc_master_2_arg;
    134 		struct ypreq_nokey ypproc_order_2_arg;
    135 		char * ypproc_maplist_2_arg;
    136 	} argument;
    137 	char *result;
    138 	xdrproc_t xdr_argument, xdr_result;
    139 	void *(*local) __P((void *, struct svc_req *));
    140 
    141 	_rpcsvcdirty = 1;
    142 	switch (rqstp->rq_proc) {
    143 	case YPPROC_NULL:
    144 		xdr_argument = xdr_void;
    145 		xdr_result = xdr_void;
    146 		local = ypproc_null_2_svc;
    147 		break;
    148 
    149 	case YPPROC_DOMAIN:
    150 		xdr_argument = xdr_ypdomain_wrap_string;
    151 		xdr_result = xdr_bool;
    152 		local = ypproc_domain_2_svc;
    153 		break;
    154 
    155 	case YPPROC_DOMAIN_NONACK:
    156 		xdr_argument = xdr_ypdomain_wrap_string;
    157 		xdr_result = xdr_bool;
    158 		local = ypproc_domain_nonack_2_svc;
    159 		break;
    160 
    161 	case YPPROC_MATCH:
    162 		xdr_argument = xdr_ypreq_key;
    163 		xdr_result = xdr_ypresp_val;
    164 		local = ypproc_match_2_svc;
    165 		break;
    166 
    167 	case YPPROC_FIRST:
    168 		xdr_argument = xdr_ypreq_nokey;
    169 		xdr_result = xdr_ypresp_key_val;
    170 		local = ypproc_first_2_svc;
    171 		break;
    172 
    173 	case YPPROC_NEXT:
    174 		xdr_argument = xdr_ypreq_key;
    175 		xdr_result = xdr_ypresp_key_val;
    176 		local = ypproc_next_2_svc;
    177 		break;
    178 
    179 	case YPPROC_XFR:
    180 		xdr_argument = xdr_ypreq_xfr;
    181 		xdr_result = xdr_ypresp_xfr;
    182 		local = ypproc_xfr_2_svc;
    183 		break;
    184 
    185 	case YPPROC_CLEAR:
    186 		xdr_argument = xdr_void;
    187 		xdr_result = xdr_void;
    188 		local = ypproc_clear_2_svc;
    189 		break;
    190 
    191 	case YPPROC_ALL:
    192 		xdr_argument = xdr_ypreq_nokey;
    193 		xdr_result = xdr_ypresp_all;
    194 		local = ypproc_all_2_svc;
    195 		break;
    196 
    197 	case YPPROC_MASTER:
    198 		xdr_argument = xdr_ypreq_nokey;
    199 		xdr_result = xdr_ypresp_master;
    200 		local = ypproc_master_2_svc;
    201 		break;
    202 
    203 	case YPPROC_ORDER:
    204 		xdr_argument = xdr_ypreq_nokey;
    205 		xdr_result = xdr_ypresp_order;
    206 		local = ypproc_order_2_svc;
    207 		break;
    208 
    209 	case YPPROC_MAPLIST:
    210 		xdr_argument = xdr_ypdomain_wrap_string;
    211 		xdr_result = xdr_ypresp_maplist;
    212 		local = ypproc_maplist_2_svc;
    213 		break;
    214 
    215 	default:
    216 		svcerr_noproc(transp);
    217 		_rpcsvcdirty = 0;
    218 		return;
    219 	}
    220 	(void) memset((char *)&argument, 0, sizeof (argument));
    221 	if (!svc_getargs(transp, xdr_argument, (caddr_t) &argument)) {
    222 		svcerr_decode(transp);
    223 		_rpcsvcdirty = 0;
    224 		return;
    225 	}
    226 	result = (*local)(&argument, rqstp);
    227 	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
    228 		svcerr_systemerr(transp);
    229 	}
    230 	if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) {
    231 		_msgout("unable to free arguments");
    232 		exit(1);
    233 	}
    234 	_rpcsvcdirty = 0;
    235 	return;
    236 }
    237 
    238 /*
    239  * limited NIS version 1 support: the null, domain, and domain_nonack
    240  * request/reply format is identical between v1 and v2.  SunOS4's ypbind
    241  * makes v1 domain_nonack calls.
    242  */
    243 static void
    244 ypprog_1(struct svc_req *rqstp, register SVCXPRT *transp)
    245 {
    246 	switch (rqstp->rq_proc) {
    247 	case YPPROC_NULL:
    248 	case YPPROC_DOMAIN:
    249 	case YPPROC_DOMAIN_NONACK:
    250 		ypprog_2(rqstp, transp);
    251 		return;
    252 
    253 	default:
    254 		svcerr_noproc(transp);
    255 		_rpcsvcdirty = 0;
    256 		return;
    257 	}
    258 }
    259 
    260 int
    261 main(argc, argv)
    262 	int argc;
    263 	char *argv[];
    264 {
    265 	register SVCXPRT *transp;
    266 	int sock, proto;
    267 	struct sigaction sa;
    268 	int xflag = 0;
    269 	int ch;
    270 
    271 	transp = NULL;		/* XXX gcc -Wuninitialized */
    272 	proto = 0;		/* XXX gcc -Wuninitialized */
    273 
    274 	while ((ch = getopt(argc, argv, "a:dx")) != -1) {
    275 		switch (ch) {
    276 		case 'a':
    277 			aclfile = optarg;
    278 			break;
    279 
    280 		case 'd':
    281 			usedns = 1;
    282 			break;
    283 
    284 		case 'x':
    285 			xflag = 1;
    286 			break;
    287 
    288 		default:
    289 			usage();
    290 		}
    291 	}
    292 
    293 	/* This program must be run by root. */
    294 	if (geteuid() != 0)
    295 		errx(1, "must run as root");
    296 
    297 	/* Deal with the acl file. */
    298 	acl_parse(aclfile);
    299 
    300 	if (xflag)
    301 		exit(1);
    302 
    303 #ifndef RPC_SVC_FG
    304 	if (daemon(0, 0))
    305 		err(1, "can't detach");
    306 	openlog("ypserv", LOG_PID, LOG_DAEMON);
    307 #endif
    308 
    309 	{
    310 		FILE *pidfile = fopen(YPSERV_PID_PATH, "w");
    311 
    312 		if (pidfile != NULL) {
    313 			fprintf(pidfile, "%d\n", getpid());
    314 			fclose(pidfile);
    315 		} else
    316 			err(1, "can't write PID file");
    317 	}
    318 
    319 	sock = RPC_ANYSOCK;
    320 	(void) pmap_unset(YPPROG, YPVERS);
    321 	(void) pmap_unset(YPPROG, YPVERS_ORIG);
    322 
    323 	ypopenlog();	/* open log file */
    324 	ypdb_init();	/* init db stuff */
    325 
    326 	sa.sa_handler = sighandler;
    327 	sa.sa_flags = 0;
    328 	if (sigemptyset(&sa.sa_mask))
    329 		err(1, "sigemptyset");
    330 	if (sigaction(SIGCHLD, &sa, NULL) || sigaction(SIGHUP, &sa, NULL))
    331 		err(1, "sigaction");
    332 
    333 	if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) {
    334 		transp = svcudp_create(sock);
    335 		if (transp == NULL) {
    336 			_msgout("cannot create udp service.");
    337 			exit(1);
    338 		}
    339 		if (!_rpcpmstart)
    340 			proto = IPPROTO_UDP;
    341 		if (!svc_register(transp, YPPROG, YPVERS_ORIG, ypprog_1, proto)) {
    342 			_msgout("unable to register (YPPROG, YPVERS_ORIG, udp).");
    343 			exit(1);
    344 		}
    345 		if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) {
    346 			_msgout("unable to register (YPPROG, YPVERS, udp).");
    347 			exit(1);
    348 		}
    349 	}
    350 
    351 	if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) {
    352 		if (_rpcpmstart)
    353 			transp = svcfd_create(sock, 0, 0);
    354 		else
    355 			transp = svctcp_create(sock, 0, 0);
    356 		if (transp == NULL) {
    357 			_msgout("cannot create tcp service.");
    358 			exit(1);
    359 		}
    360 		if (!_rpcpmstart)
    361 			proto = IPPROTO_TCP;
    362 		if (!svc_register(transp, YPPROG, YPVERS_ORIG, ypprog_1, proto)) {
    363 			_msgout("unable to register (YPPROG, YPVERS_ORIG, tcp).");
    364 			exit(1);
    365 		}
    366 		if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) {
    367 			_msgout("unable to register (YPPROG, YPVERS, tcp).");
    368 			exit(1);
    369 		}
    370 	}
    371 
    372 	if (transp == (SVCXPRT *)NULL) {
    373 		_msgout("could not create a handle");
    374 		exit(1);
    375 	}
    376 	if (_rpcpmstart) {
    377 		(void) signal(SIGALRM, (SIG_PF) closedown);
    378 		(void) alarm(_RPCSVC_CLOSEDOWN);
    379 	}
    380 	svc_run();
    381 	_msgout("svc_run returned");
    382 	exit(1);
    383 	/* NOTREACHED */
    384 }
    385 
    386 void
    387 sighandler(sig)
    388 	int sig;
    389 {
    390 
    391 	if (sig == SIGHUP) {
    392 		acl_reset();
    393 		yplog("reread %s", aclfile ? aclfile : YP_SECURENET_FILE);
    394 		acl_parse(aclfile);
    395 		return;
    396 	}
    397 
    398 	/* SIGCHLD */
    399 	while (wait3((int *)NULL, WNOHANG, (struct rusage *)NULL) > 0);
    400 }
    401 
    402 void
    403 usage()
    404 {
    405 
    406 	fprintf(stderr, "usage: %s [-a aclfile] [-d] [-x]\n", __progname);
    407 	exit(1);
    408 }
    409