1/*	$OpenBSD: ypserv.c,v 1.12 1997/11/04 07:40:52 deraadt Exp $ */
2
3/*
4 * Copyright (c) 1994 Mats O Jansson <moj@stacken.kth.se>
5 * All rights reserved.
6 * Portions copyright (c) 2004-2007 Apple Inc.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by Mats O Jansson
19 * 4. The name of the author may not be used to endorse or promote products
20 *    derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
26 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include <sys/cdefs.h>
36#ifndef LINT
37__unused static char rcsid[] = "$OpenBSD: ypserv.c,v 1.12 1997/11/04 07:40:52 deraadt Exp $";
38#endif
39
40#include "yp.h"
41#include "ypv1.h"
42#include <stdio.h>
43#include <stdlib.h>/* getenv, exit */
44#include <rpc/pmap_clnt.h> /* for pmap_unset */
45#include <string.h> /* strcmp */
46#include <unistd.h>
47#include <netdb.h>
48#include <signal.h>
49#include <errno.h>
50#include <sys/ttycom.h>/* TIOCNOTTY */
51#ifdef __cplusplus
52#include <sysent.h> /* getdtablesize, open */
53#endif /* __cplusplus */
54#include <memory.h>
55#include <sys/socket.h>
56#include <netinet/in.h>
57#include <syslog.h>
58#include "acl.h"
59#include "yplog.h"
60#include "ypdef.h"
61#include <sys/wait.h>
62#include <sys/ioctl.h> /* for ioctl */
63#include <sys/fcntl.h> /* for open */
64
65#ifdef __STDC__
66#define SIG_PF void(*)(int)
67#endif
68
69#ifdef DEBUG
70#define RPC_SVC_FG
71#endif
72
73#define _RPCSVC_CLOSEDOWN 120
74static int _rpcpmstart;		/* Started by a port monitor ? */
75static int _rpcfdtype;		/* Whether Stream or Datagram ? */
76static int _rpcsvcdirty;	/* Still serving ? */
77
78int	usedns = FALSE;
79char   *progname = "ypserv";
80char   *aclfile = NULL;
81
82void sig_child();
83void sig_hup();
84extern void ypdb_init(void);
85
86/* in the RPC library */
87SVCXPRT *svcfd_create(int, u_int, u_int);
88
89static
90void _msgout(char* msg)
91{
92#ifdef RPC_SVC_FG
93	if (_rpcpmstart)
94		syslog(LOG_ERR, msg);
95	else
96		(void) fprintf(stderr, "%s\n", msg);
97#else
98	syslog(LOG_ERR, "%s", msg);
99#endif
100}
101
102static void
103closedown()
104{
105	if (_rpcsvcdirty == 0) {
106		extern fd_set svc_fdset;
107		static int size;
108		int i, openfd;
109
110		if (_rpcfdtype == SOCK_DGRAM)
111			exit(0);
112		if (size == 0) {
113			size = getdtablesize();
114		}
115		for (i = 0, openfd = 0; i < size && openfd < 2; i++)
116			if (FD_ISSET(i, &svc_fdset))
117				openfd++;
118		if (openfd <= (_rpcpmstart?0:1))
119			exit(0);
120	}
121	(void) alarm(_RPCSVC_CLOSEDOWN);
122}
123
124static void
125ypprog_1(struct svc_req *rqstp, register SVCXPRT *transp)
126{
127	union {
128		domainname ypproc_domain_1_arg;
129		domainname ypproc_domain_nonack_1_arg;
130		yprequest ypproc_match_1_arg;
131		yprequest ypproc_first_1_arg;
132		yprequest ypproc_next_1_arg;
133		yprequest ypproc_poll_1_arg;
134		yprequest ypproc_push_1_arg;
135		yprequest ypproc_pull_1_arg;
136		yprequest ypproc_get_1_arg;
137	} argument;
138	char *result;
139	xdrproc_t xdr_argument, xdr_result;
140	char *(*local)(char *, struct svc_req *);
141
142	_rpcsvcdirty = 1;
143	switch (rqstp->rq_proc) {
144	case YPOLDPROC_NULL:
145		xdr_argument = (xdrproc_t) xdr_void;
146		xdr_result = (xdrproc_t) xdr_void;
147		local = (char *(*)(char *, struct svc_req *)) ypproc_null_1_svc;
148		break;
149
150	case YPOLDPROC_DOMAIN:
151		xdr_argument = (xdrproc_t) xdr_domainname;
152		xdr_result = (xdrproc_t) xdr_bool;
153		local = (char *(*)(char *, struct svc_req *)) ypproc_domain_1_svc;
154		break;
155
156	case YPOLDPROC_DOMAIN_NONACK:
157		xdr_argument = (xdrproc_t) xdr_domainname;
158		xdr_result = (xdrproc_t) xdr_bool;
159		local = (char *(*)(char *, struct svc_req *)) ypproc_domain_nonack_1_svc;
160		break;
161
162	case YPOLDPROC_MATCH:
163		xdr_argument = (xdrproc_t) xdr_yprequest;
164		xdr_result = (xdrproc_t) xdr_ypresponse;
165		local = (char *(*)(char *, struct svc_req *)) ypproc_match_1_svc;
166		break;
167
168	case YPOLDPROC_FIRST:
169		xdr_argument = (xdrproc_t) xdr_yprequest;
170		xdr_result = (xdrproc_t) xdr_ypresponse;
171		local = (char *(*)(char *, struct svc_req *)) ypproc_first_1_svc;
172		break;
173
174	case YPOLDPROC_NEXT:
175		xdr_argument = (xdrproc_t) xdr_yprequest;
176		xdr_result = (xdrproc_t) xdr_ypresponse;
177		local = (char *(*)(char *, struct svc_req *)) ypproc_next_1_svc;
178		break;
179
180	case YPOLDPROC_POLL:
181		xdr_argument = (xdrproc_t) xdr_yprequest;
182		xdr_result = (xdrproc_t) xdr_ypresponse;
183		local = (char *(*)(char *, struct svc_req *)) ypproc_poll_1_svc;
184		break;
185
186	case YPOLDPROC_PUSH:
187		xdr_argument = (xdrproc_t) xdr_yprequest;
188		xdr_result = (xdrproc_t) xdr_void;
189		local = (char *(*)(char *, struct svc_req *)) ypproc_push_1_svc;
190		break;
191
192	case YPOLDPROC_PULL:
193		xdr_argument = (xdrproc_t) xdr_yprequest;
194		xdr_result = (xdrproc_t) xdr_void;
195		local = (char *(*)(char *, struct svc_req *)) ypproc_pull_1_svc;
196		break;
197
198	case YPOLDPROC_GET:
199		xdr_argument = (xdrproc_t) xdr_yprequest;
200		xdr_result = (xdrproc_t) xdr_void;
201		local = (char *(*)(char *, struct svc_req *)) ypproc_get_1_svc;
202		break;
203
204	default:
205		svcerr_noproc(transp);
206		_rpcsvcdirty = 0;
207		return;
208	}
209	(void) memset((char *)&argument, 0, sizeof (argument));
210	if (!svc_getargs(transp, xdr_argument, (caddr_t) &argument)) {
211		svcerr_decode(transp);
212		_rpcsvcdirty = 0;
213		return;
214	}
215	result = (*local)((char *)&argument, rqstp);
216	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
217		svcerr_systemerr(transp);
218	}
219	if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) {
220		_msgout("unable to free arguments");
221		exit(1);
222	}
223	_rpcsvcdirty = 0;
224	return;
225}
226
227static void
228ypprog_2(struct svc_req *rqstp, register SVCXPRT *transp)
229{
230	union {
231		domainname ypproc_domain_2_arg;
232		domainname ypproc_domain_nonack_2_arg;
233		ypreq_key ypproc_match_2_arg;
234		ypreq_nokey ypproc_first_2_arg;
235		ypreq_key ypproc_next_2_arg;
236		ypreq_xfr ypproc_xfr_2_arg;
237		ypreq_nokey ypproc_all_2_arg;
238		ypreq_nokey ypproc_master_2_arg;
239		ypreq_nokey ypproc_order_2_arg;
240		domainname ypproc_maplist_2_arg;
241	} argument;
242	char *result;
243	xdrproc_t xdr_argument, xdr_result;
244	char *(*local)(char *, struct svc_req *);
245
246	_rpcsvcdirty = 1;
247	switch (rqstp->rq_proc) {
248	case YPPROC_NULL:
249		xdr_argument = (xdrproc_t) xdr_void;
250		xdr_result = (xdrproc_t) xdr_void;
251		local = (char *(*)(char *, struct svc_req *)) ypproc_null_2_svc;
252		break;
253
254	case YPPROC_DOMAIN:
255		xdr_argument = (xdrproc_t) xdr_domainname;
256		xdr_result = (xdrproc_t) xdr_bool;
257		local = (char *(*)(char *, struct svc_req *)) ypproc_domain_2_svc;
258		break;
259
260	case YPPROC_DOMAIN_NONACK:
261		xdr_argument = (xdrproc_t) xdr_domainname;
262		xdr_result = (xdrproc_t) xdr_bool;
263		local = (char *(*)(char *, struct svc_req *)) ypproc_domain_nonack_2_svc;
264		break;
265
266	case YPPROC_MATCH:
267		xdr_argument = (xdrproc_t) xdr_ypreq_key;
268		xdr_result = (xdrproc_t) xdr_ypresp_val;
269		local = (char *(*)(char *, struct svc_req *)) ypproc_match_2_svc;
270		break;
271
272	case YPPROC_FIRST:
273		xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
274		xdr_result = (xdrproc_t) xdr_ypresp_key_val;
275		local = (char *(*)(char *, struct svc_req *)) ypproc_first_2_svc;
276		break;
277
278	case YPPROC_NEXT:
279		xdr_argument = (xdrproc_t) xdr_ypreq_key;
280		xdr_result = (xdrproc_t) xdr_ypresp_key_val;
281		local = (char *(*)(char *, struct svc_req *)) ypproc_next_2_svc;
282		break;
283
284	case YPPROC_XFR:
285		xdr_argument = (xdrproc_t) xdr_ypreq_xfr;
286		xdr_result = (xdrproc_t) xdr_ypresp_xfr;
287		local = (char *(*)(char *, struct svc_req *)) ypproc_xfr_2_svc;
288		break;
289
290	case YPPROC_CLEAR:
291		xdr_argument = (xdrproc_t) xdr_void;
292		xdr_result = (xdrproc_t) xdr_void;
293		local = (char *(*)(char *, struct svc_req *)) ypproc_clear_2_svc;
294		break;
295
296	case YPPROC_ALL:
297		xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
298		xdr_result = (xdrproc_t) xdr_ypresp_all;
299		local = (char *(*)(char *, struct svc_req *)) ypproc_all_2_svc;
300		break;
301
302	case YPPROC_MASTER:
303		xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
304		xdr_result = (xdrproc_t) xdr_ypresp_master;
305		local = (char *(*)(char *, struct svc_req *)) ypproc_master_2_svc;
306		break;
307
308	case YPPROC_ORDER:
309		xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
310		xdr_result = (xdrproc_t) xdr_ypresp_order;
311		local = (char *(*)(char *, struct svc_req *)) ypproc_order_2_svc;
312		break;
313
314	case YPPROC_MAPLIST:
315		xdr_argument = (xdrproc_t) xdr_domainname;
316		xdr_result = (xdrproc_t) xdr_ypresp_maplist;
317		local = (char *(*)(char *, struct svc_req *)) ypproc_maplist_2_svc;
318		break;
319
320	default:
321		svcerr_noproc(transp);
322		_rpcsvcdirty = 0;
323		return;
324	}
325	(void) memset((char *)&argument, 0, sizeof (argument));
326	if (!svc_getargs(transp, xdr_argument, (caddr_t) &argument)) {
327		svcerr_decode(transp);
328		_rpcsvcdirty = 0;
329		return;
330	}
331	result = (*local)((char *)&argument, rqstp);
332	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
333		svcerr_systemerr(transp);
334	}
335	if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) {
336		_msgout("unable to free arguments");
337		exit(1);
338	}
339	_rpcsvcdirty = 0;
340	return;
341}
342
343int
344main (argc,argv)
345int argc;
346char *argv[];
347{
348	register SVCXPRT *transp = NULL;
349	int sock;
350	int proto = 0;
351	struct sockaddr_in saddr;
352	socklen_t asize = sizeof (saddr);
353	int	 usage = 0;
354	int	 xflag = 0;
355	int	 allowv1 = 0;
356	int	 ch;
357	extern	 char *optarg;
358
359	while ((ch = getopt(argc, argv, "1a:dx")) != -1)
360		switch (ch) {
361		case '1':
362			allowv1 = TRUE;
363			break;
364		case 'a':
365			aclfile = optarg;
366			break;
367		case 'd':
368			usedns = TRUE;
369			break;
370		case 'x':
371			xflag = TRUE;
372			break;
373		default:
374			usage++;
375			break;
376		}
377
378	if (usage) {
379		(void)fprintf(stderr,"usage: %s [-a aclfile] [-d] [-x]\n",progname);
380		exit(1);
381	}
382
383	if (geteuid() != 0) {
384		(void)fprintf(stderr,"%s: must be root to run.\n",progname);
385		exit(1);
386	}
387
388	if (aclfile != NULL) {
389		(void)yp_acl_init(aclfile);
390	} else {
391		(void)yp_acl_securenet(YP_SECURENET_FILE);
392	}
393	if (xflag) {
394		exit(1);
395	};
396
397	if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) {
398		socklen_t ssize = sizeof (int);
399
400		if (saddr.sin_family != AF_INET)
401			exit(1);
402		if (getsockopt(0, SOL_SOCKET, SO_TYPE,
403				(char *)&_rpcfdtype, &ssize) == -1)
404			exit(1);
405		sock = 0;
406		_rpcpmstart = 1;
407		proto = 0;
408		openlog("ypserv", LOG_PID, LOG_DAEMON);
409	} else {
410#ifndef __APPLE__
411#ifndef RPC_SVC_FG
412		int size;
413		int pid, i;
414
415		pid = fork();
416		if (pid < 0) {
417			perror("cannot fork");
418			exit(1);
419		}
420		if (pid)
421			exit(0);
422		size = getdtablesize();
423		for (i = 0; i < size; i++)
424			(void) close(i);
425		i = open("/dev/console", 2);
426		(void) dup2(i, 1);
427		(void) dup2(i, 2);
428		i = open("/dev/tty", 2);
429		if (i >= 0) {
430			(void) ioctl(i, TIOCNOTTY, (char *)NULL);
431			(void) close(i);
432		}
433		openlog("ypserv", LOG_PID, LOG_DAEMON);
434#endif
435#endif /* __APPLE__ */
436		sock = RPC_ANYSOCK;
437		(void) pmap_unset(YPPROG, YPVERS);
438		(void) pmap_unset(YPPROG, YPOLDVERS);
439	}
440
441	ypopenlog();	/* open log file */
442	ypdb_init();	/* init db stuff */
443
444	chdir("/");
445
446	(void)signal(SIGCHLD, sig_child);
447	(void)signal(SIGHUP, sig_hup);
448	{ FILE *pidfile = fopen(YPSERV_PID_PATH, "w");
449	  if (pidfile != NULL) {
450		fprintf(pidfile, "%d\n", getpid());
451		fclose(pidfile);
452	  }
453	}
454
455	if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) {
456		transp = svcudp_create(sock);
457		if (transp == NULL) {
458			_msgout("cannot create udp service.");
459			exit(1);
460		}
461		if (transp->xp_port >= IPPORT_RESERVED) {
462			_msgout("cannot allocate udp privileged port.");
463			exit(1);
464		}
465		if (!_rpcpmstart)
466			proto = IPPROTO_UDP;
467		if (allowv1) {
468			if (!svc_register(transp, YPPROG, YPOLDVERS, ypprog_1, proto)) {
469				_msgout("unable to register (YPPROG, YPOLDVERS, udp).");
470				exit(1);
471			}
472		}
473		if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) {
474			_msgout("unable to register (YPPROG, YPVERS, udp).");
475			exit(1);
476		}
477	}
478
479	if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) {
480		if (_rpcpmstart)
481			transp = svcfd_create(sock, 0, 0);
482		else
483			transp = svctcp_create(sock, 0, 0);
484		if (transp == NULL) {
485			_msgout("cannot create tcp service.");
486			exit(1);
487		}
488		if (transp->xp_port >= IPPORT_RESERVED) {
489			_msgout("cannot allocate tcp privileged port.");
490			exit(1);
491		}
492		if (!_rpcpmstart)
493			proto = IPPROTO_TCP;
494		if (allowv1) {
495			if (!svc_register(transp, YPPROG, YPOLDVERS, ypprog_1, proto)) {
496				_msgout("unable to register (YPPROG, YPOLDVERS, tcp).");
497				exit(1);
498			}
499		}
500		if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) {
501			_msgout("unable to register (YPPROG, YPVERS, tcp).");
502			exit(1);
503		}
504	}
505
506	if (transp == (SVCXPRT *)NULL) {
507		_msgout("could not create a handle");
508		exit(1);
509	}
510	if (_rpcpmstart) {
511		(void) signal(SIGALRM, (SIG_PF) closedown);
512		(void) alarm(_RPCSVC_CLOSEDOWN);
513	}
514	svc_run();
515	_msgout("svc_run returned");
516	exit(1);
517	/* NOTREACHED */
518}
519
520void
521sig_child()
522{
523	int save_errno = errno;
524
525	while (wait3((int *)NULL, WNOHANG, (struct rusage *)NULL) > 0)
526		;
527	errno = save_errno;
528}
529
530void
531sig_hup()
532{
533	yp_acl_reset();
534	if (aclfile != NULL) {
535		yplog("sig_hup: reread %s",aclfile);
536		(void)yp_acl_init(aclfile);
537	} else {
538		yplog("sig_hup: reread %s",YP_SECURENET_FILE);
539		(void)yp_acl_securenet(YP_SECURENET_FILE);
540	}
541}
542