Home | History | Annotate | Line # | Download | only in ypserv
ypserv.c revision 1.6
      1 /*	$NetBSD: ypserv.c,v 1.6 1997/10/08 13:45:21 lukem 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 
     78 int	main __P((int, char *[]));
     79 void	usage __P((void));
     80 
     81 void	sighandler __P((int));
     82 
     83 static	void closedown __P((void));
     84 
     85 static
     86 void _msgout(char* msg)
     87 {
     88 #ifdef RPC_SVC_FG
     89 	if (_rpcpmstart)
     90 		syslog(LOG_ERR, msg);
     91 	else
     92 		warnx("%s", msg);
     93 #else
     94 	syslog(LOG_ERR, msg);
     95 #endif
     96 }
     97 
     98 static void
     99 closedown()
    100 {
    101 	if (_rpcsvcdirty == 0) {
    102 		extern fd_set svc_fdset;
    103 		static int size;
    104 		int i, openfd;
    105 
    106 		if (_rpcfdtype == SOCK_DGRAM)
    107 			exit(0);
    108 		if (size == 0) {
    109 			size = getdtablesize();
    110 		}
    111 		for (i = 0, openfd = 0; i < size && openfd < 2; i++)
    112 			if (FD_ISSET(i, &svc_fdset))
    113 				openfd++;
    114 		if (openfd <= (_rpcpmstart?0:1))
    115 			exit(0);
    116 	}
    117 	(void) alarm(_RPCSVC_CLOSEDOWN);
    118 }
    119 
    120 static void
    121 ypprog_2(struct svc_req *rqstp, SVCXPRT *transp)
    122 {
    123 	union {
    124 		char * ypproc_domain_2_arg;
    125 		char * ypproc_domain_nonack_2_arg;
    126 		struct ypreq_key ypproc_match_2_arg;
    127 		struct ypreq_nokey ypproc_first_2_arg;
    128 		struct ypreq_key ypproc_next_2_arg;
    129 		struct ypreq_xfr ypproc_xfr_2_arg;
    130 		struct ypreq_nokey ypproc_all_2_arg;
    131 		struct ypreq_nokey ypproc_master_2_arg;
    132 		struct ypreq_nokey ypproc_order_2_arg;
    133 		char * ypproc_maplist_2_arg;
    134 	} argument;
    135 	char *result;
    136 	xdrproc_t xdr_argument, xdr_result;
    137 	void *(*local) __P((void *, struct svc_req *));
    138 
    139 	_rpcsvcdirty = 1;
    140 	switch (rqstp->rq_proc) {
    141 	case YPPROC_NULL:
    142 		xdr_argument = xdr_void;
    143 		xdr_result = xdr_void;
    144 		local = ypproc_null_2_svc;
    145 		break;
    146 
    147 	case YPPROC_DOMAIN:
    148 		xdr_argument = xdr_ypdomain_wrap_string;
    149 		xdr_result = xdr_bool;
    150 		local = ypproc_domain_2_svc;
    151 		break;
    152 
    153 	case YPPROC_DOMAIN_NONACK:
    154 		xdr_argument = xdr_ypdomain_wrap_string;
    155 		xdr_result = xdr_bool;
    156 		local = ypproc_domain_nonack_2_svc;
    157 		break;
    158 
    159 	case YPPROC_MATCH:
    160 		xdr_argument = xdr_ypreq_key;
    161 		xdr_result = xdr_ypresp_val;
    162 		local = ypproc_match_2_svc;
    163 		break;
    164 
    165 	case YPPROC_FIRST:
    166 		xdr_argument = xdr_ypreq_nokey;
    167 		xdr_result = xdr_ypresp_key_val;
    168 		local = ypproc_first_2_svc;
    169 		break;
    170 
    171 	case YPPROC_NEXT:
    172 		xdr_argument = xdr_ypreq_key;
    173 		xdr_result = xdr_ypresp_key_val;
    174 		local = ypproc_next_2_svc;
    175 		break;
    176 
    177 	case YPPROC_XFR:
    178 		xdr_argument = xdr_ypreq_xfr;
    179 		xdr_result = xdr_ypresp_xfr;
    180 		local = ypproc_xfr_2_svc;
    181 		break;
    182 
    183 	case YPPROC_CLEAR:
    184 		xdr_argument = xdr_void;
    185 		xdr_result = xdr_void;
    186 		local = ypproc_clear_2_svc;
    187 		break;
    188 
    189 	case YPPROC_ALL:
    190 		xdr_argument = xdr_ypreq_nokey;
    191 		xdr_result = xdr_ypresp_all;
    192 		local = ypproc_all_2_svc;
    193 		break;
    194 
    195 	case YPPROC_MASTER:
    196 		xdr_argument = xdr_ypreq_nokey;
    197 		xdr_result = xdr_ypresp_master;
    198 		local = ypproc_master_2_svc;
    199 		break;
    200 
    201 	case YPPROC_ORDER:
    202 		xdr_argument = xdr_ypreq_nokey;
    203 		xdr_result = xdr_ypresp_order;
    204 		local = ypproc_order_2_svc;
    205 		break;
    206 
    207 	case YPPROC_MAPLIST:
    208 		xdr_argument = xdr_ypdomain_wrap_string;
    209 		xdr_result = xdr_ypresp_maplist;
    210 		local = ypproc_maplist_2_svc;
    211 		break;
    212 
    213 	default:
    214 		svcerr_noproc(transp);
    215 		_rpcsvcdirty = 0;
    216 		return;
    217 	}
    218 	(void) memset((char *)&argument, 0, sizeof (argument));
    219 	if (!svc_getargs(transp, xdr_argument, (caddr_t) &argument)) {
    220 		svcerr_decode(transp);
    221 		_rpcsvcdirty = 0;
    222 		return;
    223 	}
    224 	result = (*local)(&argument, rqstp);
    225 	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
    226 		svcerr_systemerr(transp);
    227 	}
    228 	if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) {
    229 		_msgout("unable to free arguments");
    230 		exit(1);
    231 	}
    232 	_rpcsvcdirty = 0;
    233 	return;
    234 }
    235 
    236 /*
    237  * limited NIS version 1 support: the null, domain, and domain_nonack
    238  * request/reply format is identical between v1 and v2.  SunOS4's ypbind
    239  * makes v1 domain_nonack calls.
    240  */
    241 static void
    242 ypprog_1(struct svc_req *rqstp, SVCXPRT *transp)
    243 {
    244 	switch (rqstp->rq_proc) {
    245 	case YPPROC_NULL:
    246 	case YPPROC_DOMAIN:
    247 	case YPPROC_DOMAIN_NONACK:
    248 		ypprog_2(rqstp, transp);
    249 		return;
    250 
    251 	default:
    252 		svcerr_noproc(transp);
    253 		_rpcsvcdirty = 0;
    254 		return;
    255 	}
    256 }
    257 
    258 int
    259 main(argc, argv)
    260 	int argc;
    261 	char *argv[];
    262 {
    263 	SVCXPRT *transp;
    264 	int sock, proto;
    265 	struct sigaction sa;
    266 	int xflag = 0;
    267 	int ch;
    268 
    269 	transp = NULL;		/* XXX gcc -Wuninitialized */
    270 	proto = 0;		/* XXX gcc -Wuninitialized */
    271 
    272 	while ((ch = getopt(argc, argv, "a:dx")) != -1) {
    273 		switch (ch) {
    274 		case 'a':
    275 			aclfile = optarg;
    276 			break;
    277 
    278 		case 'd':
    279 			usedns = 1;
    280 			break;
    281 
    282 		case 'x':
    283 			xflag = 1;
    284 			break;
    285 
    286 		default:
    287 			usage();
    288 		}
    289 	}
    290 
    291 	/* This program must be run by root. */
    292 	if (geteuid() != 0)
    293 		errx(1, "must run as root");
    294 
    295 	/* Deal with the acl file. */
    296 	acl_parse(aclfile);
    297 
    298 	if (xflag)
    299 		exit(1);
    300 
    301 #ifndef RPC_SVC_FG
    302 	if (daemon(0, 0))
    303 		err(1, "can't detach");
    304 	openlog("ypserv", LOG_PID, LOG_DAEMON);
    305 #endif
    306 
    307 	{
    308 		FILE *pidfile = fopen(YPSERV_PID_PATH, "w");
    309 
    310 		if (pidfile != NULL) {
    311 			fprintf(pidfile, "%d\n", getpid());
    312 			fclose(pidfile);
    313 		} else
    314 			err(1, "can't write PID file");
    315 	}
    316 
    317 	sock = RPC_ANYSOCK;
    318 	(void) pmap_unset(YPPROG, YPVERS);
    319 	(void) pmap_unset(YPPROG, YPVERS_ORIG);
    320 
    321 	ypopenlog();	/* open log file */
    322 	ypdb_init();	/* init db stuff */
    323 
    324 	sa.sa_handler = sighandler;
    325 	sa.sa_flags = 0;
    326 	if (sigemptyset(&sa.sa_mask))
    327 		err(1, "sigemptyset");
    328 	if (sigaction(SIGCHLD, &sa, NULL) || sigaction(SIGHUP, &sa, NULL))
    329 		err(1, "sigaction");
    330 
    331 	if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) {
    332 		transp = svcudp_create(sock);
    333 		if (transp == NULL) {
    334 			_msgout("cannot create udp service.");
    335 			exit(1);
    336 		}
    337 		if (transp->xp_port >= IPPORT_RESERVED) {
    338 			_msgout("udp service not bound to a privileged port.");
    339 			exit(1);
    340 		}
    341 		if (!_rpcpmstart)
    342 			proto = IPPROTO_UDP;
    343 		if (!svc_register(transp, YPPROG, YPVERS_ORIG, ypprog_1,
    344 		    proto)) {
    345 			_msgout(
    346 			    "unable to register (YPPROG, YPVERS_ORIG, udp).");
    347 			exit(1);
    348 		}
    349 		if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) {
    350 			_msgout("unable to register (YPPROG, YPVERS, udp).");
    351 			exit(1);
    352 		}
    353 	}
    354 
    355 	if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) {
    356 		if (_rpcpmstart)
    357 			transp = svcfd_create(sock, 0, 0);
    358 		else
    359 			transp = svctcp_create(sock, 0, 0);
    360 		if (transp == NULL) {
    361 			_msgout("cannot create tcp service.");
    362 			exit(1);
    363 		}
    364 		if (transp->xp_port >= IPPORT_RESERVED) {
    365 			_msgout("tcp service not bound to a privileged port.");
    366 			exit(1);
    367 		}
    368 		if (!_rpcpmstart)
    369 			proto = IPPROTO_TCP;
    370 		if (!svc_register(transp, YPPROG, YPVERS_ORIG, ypprog_1,
    371 		    proto)) {
    372 			_msgout(
    373 			    "unable to register (YPPROG, YPVERS_ORIG, tcp).");
    374 			exit(1);
    375 		}
    376 		if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) {
    377 			_msgout("unable to register (YPPROG, YPVERS, tcp).");
    378 			exit(1);
    379 		}
    380 	}
    381 
    382 	if (transp == (SVCXPRT *)NULL) {
    383 		_msgout("could not create a handle");
    384 		exit(1);
    385 	}
    386 	if (_rpcpmstart) {
    387 		(void) signal(SIGALRM, (SIG_PF) closedown);
    388 		(void) alarm(_RPCSVC_CLOSEDOWN);
    389 	}
    390 	svc_run();
    391 	_msgout("svc_run returned");
    392 	exit(1);
    393 	/* NOTREACHED */
    394 }
    395 
    396 void
    397 sighandler(sig)
    398 	int sig;
    399 {
    400 
    401 	if (sig == SIGHUP) {
    402 		acl_reset();
    403 		yplog("reread %s", aclfile ? aclfile : YP_SECURENET_FILE);
    404 		acl_parse(aclfile);
    405 		return;
    406 	}
    407 
    408 	/* SIGCHLD */
    409 	while (wait3((int *)NULL, WNOHANG, (struct rusage *)NULL) > 0);
    410 }
    411 
    412 void
    413 usage()
    414 {
    415 
    416 	fprintf(stderr, "usage: %s [-a aclfile] [-d] [-x]\n", __progname);
    417 	exit(1);
    418 }
    419