114062Swpaul/*
214062Swpaul * Copyright (c) 1995, 1996
314062Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
414062Swpaul *
514062Swpaul * Redistribution and use in source and binary forms, with or without
614062Swpaul * modification, are permitted provided that the following conditions
714062Swpaul * are met:
814062Swpaul * 1. Redistributions of source code must retain the above copyright
914062Swpaul *    notice, this list of conditions and the following disclaimer.
1014062Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1114062Swpaul *    notice, this list of conditions and the following disclaimer in the
1214062Swpaul *    documentation and/or other materials provided with the distribution.
1314062Swpaul * 3. All advertising materials mentioning features or use of this software
1414062Swpaul *    must display the following acknowledgement:
1514062Swpaul *	This product includes software developed by Bill Paul.
1614062Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1714062Swpaul *    may be used to endorse or promote products derived from this software
1814062Swpaul *    without specific prior written permission.
1914062Swpaul *
2014062Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2114062Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2214062Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2314062Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
2414062Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2514062Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2614062Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2714062Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2814062Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2914062Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3014062Swpaul * SUCH DAMAGE.
3114062Swpaul */
3214062Swpaul
33114601Sobrien#include <sys/cdefs.h>
34114601Sobrien__FBSDID("$FreeBSD$");
3530377Scharnier
3614062Swpaul#include <sys/param.h>
3714062Swpaul#include <sys/ioctl.h>
3814062Swpaul#include <sys/stat.h>
3914062Swpaul#include <sys/socket.h>
4096222Sdes#include <sys/time.h>
4196222Sdes#include <sys/resource.h>
4214062Swpaul#include <netinet/in.h>
4396222Sdes
4414062Swpaul#include <err.h>
4514062Swpaul#include <errno.h>
4696222Sdes#include <fcntl.h>
4796222Sdes#include <memory.h>
4896222Sdes#include <signal.h>
4996222Sdes#include <stdio.h>
5096222Sdes#include <stdlib.h> /* getenv, exit */
5196222Sdes#include <string.h> /* strcmp */
5296222Sdes#include <syslog.h>
5396222Sdes#include <unistd.h>
5496222Sdes
5596222Sdes#include <rpc/rpc.h>
56109363Smbr#include <rpc/rpc_com.h>
5796222Sdes#include <rpc/pmap_clnt.h> /* for pmap_unset */
5814062Swpaul#include <rpcsvc/yp.h>
5914062Swpaul#include <rpcsvc/ypclnt.h>
6096222Sdes
6196222Sdes#include "yppasswd.h"
6214062Swpaul#include "yppasswdd_extern.h"
6327758Swpaul#include "yppasswd_private.h"
6414062Swpaul#include "ypxfr_extern.h"
6596222Sdes#include "yp_extern.h"
6614062Swpaul
6714062Swpaul#ifndef SIG_PF
6814062Swpaul#define	SIG_PF void(*)(int)
6914062Swpaul#endif
7014062Swpaul
7114062Swpaul#ifdef DEBUG
7214062Swpaul#define	RPC_SVC_FG
7314062Swpaul#endif
7414062Swpaul
7514062Swpaul#define	_RPCSVC_CLOSEDOWN 120
7614062Swpaulint _rpcpmstart = 0;		/* Started by a port monitor ? */
7714062Swpaulstatic int _rpcfdtype;
7814062Swpaul		 /* Whether Stream or Datagram ? */
7914062Swpaul	/* States a server can be in wrt request */
8014062Swpaul
8114062Swpaul#define	_IDLE 0
8214062Swpaul#define	_SERVED 1
8314062Swpaul#define	_SERVING 2
8414062Swpaul
8596222Sdesstatic char _localhost[] = "localhost";
8696222Sdesstatic char _passwd_byname[] = "passwd.byname";
8714062Swpaulextern int _rpcsvcstate;	 /* Set when a request is serviced */
8896222Sdesstatic char _progname[] = "rpc.yppasswdd";
8996222Sdeschar *progname = _progname;
9096222Sdesstatic char _yp_dir[] = _PATH_YP;
9196222Sdeschar *yp_dir = _yp_dir;
9296222Sdesstatic char _passfile_default[] = _PATH_YP "master.passwd";
9396222Sdeschar *passfile_default = _passfile_default;
9414062Swpaulchar *passfile;
9514062Swpaulchar *yppasswd_domain = NULL;
9614062Swpaulint no_chsh = 0;
9714062Swpaulint no_chfn = 0;
9814062Swpaulint allow_additions = 0;
9914062Swpaulint multidomain = 0;
10014062Swpaulint verbose = 0;
10114241Swpaulint resvport = 1;
10216134Swpaulint inplace = 0;
10396222Sdeschar sockname[] = YP_SOCKNAME;
10414062Swpaul
10590298Sdesstatic void
10696222Sdesterminate(int sig __unused)
10714062Swpaul{
10890253Salfred	rpcb_unset(YPPASSWDPROG, YPPASSWDVERS, NULL);
10990253Salfred	rpcb_unset(MASTER_YPPASSWDPROG, MASTER_YPPASSWDVERS, NULL);
11014062Swpaul	unlink(sockname);
11114062Swpaul	exit(0);
11214062Swpaul}
11314241Swpaul
11490298Sdesstatic void
11596222Sdesreload(int sig __unused)
11614241Swpaul{
11714241Swpaul	load_securenets();
11814241Swpaul}
11914241Swpaul
12014062Swpaulstatic void
12196222Sdesclosedown(int sig __unused)
12214062Swpaul{
12314062Swpaul	if (_rpcsvcstate == _IDLE) {
12414062Swpaul		extern fd_set svc_fdset;
12514062Swpaul		static int size;
12614062Swpaul		int i, openfd;
12714062Swpaul
12814062Swpaul		if (_rpcfdtype == SOCK_DGRAM) {
12914062Swpaul			unlink(sockname);
13014062Swpaul			exit(0);
13114062Swpaul		}
13214062Swpaul		if (size == 0) {
13314062Swpaul			size = getdtablesize();
13414062Swpaul		}
13514062Swpaul		for (i = 0, openfd = 0; i < size && openfd < 2; i++)
13614062Swpaul			if (FD_ISSET(i, &svc_fdset))
13714062Swpaul				openfd++;
13814062Swpaul		if (openfd <= 1) {
13914062Swpaul			unlink(sockname);
14014062Swpaul			exit(0);
14114062Swpaul		}
14214062Swpaul	}
14314062Swpaul	if (_rpcsvcstate == _SERVED)
14414062Swpaul		_rpcsvcstate = _IDLE;
14514062Swpaul
14614062Swpaul	(void) signal(SIGALRM, (SIG_PF) closedown);
14714062Swpaul	(void) alarm(_RPCSVC_CLOSEDOWN/2);
14814062Swpaul}
14914062Swpaul
15090298Sdesstatic void
15190298Sdesusage(void)
15214062Swpaul{
15330377Scharnier	fprintf(stderr, "%s\n%s\n",
15430377Scharnier"usage: rpc.yppasswdd [-t master.passwd file] [-d domain] [-p path] [-s]",
15530377Scharnier"                     [-f] [-m] [-i] [-a] [-v] [-u] [-h]");
15614062Swpaul	exit(1);
15714062Swpaul}
15814062Swpaul
15919778Speterint
16090298Sdesmain(int argc, char *argv[])
16114062Swpaul{
16296222Sdes	struct rlimit rlim;
16396222Sdes	SVCXPRT *transp = NULL;
16414062Swpaul	struct sockaddr_in saddr;
165145803Sdelphij	socklen_t asize = sizeof (saddr);
16690253Salfred	struct netconfig *nconf;
167184459Srafan	struct sigaction sa;
16890253Salfred	void *localhandle;
16914062Swpaul	int ch;
17014062Swpaul	char *mastername;
17114062Swpaul	char myname[MAXHOSTNAMELEN + 2];
172109363Smbr	int maxrec = RPC_MAXDATASIZE;
17390253Salfred
17414062Swpaul	extern int debug;
17514062Swpaul
17614062Swpaul	debug = 1;
17714062Swpaul
17824428Simp	while ((ch = getopt(argc, argv, "t:d:p:sfamuivh")) != -1) {
17990297Sdes		switch (ch) {
18014062Swpaul		case 't':
18114062Swpaul			passfile_default = optarg;
18214062Swpaul			break;
18314062Swpaul		case 'd':
18414062Swpaul			yppasswd_domain = optarg;
18514062Swpaul			break;
18614062Swpaul		case 's':
18714062Swpaul			no_chsh++;
18814062Swpaul			break;
18914062Swpaul		case 'f':
19014062Swpaul			no_chfn++;
19114062Swpaul			break;
19214062Swpaul		case 'p':
19314062Swpaul			yp_dir = optarg;
19414062Swpaul			break;
19514062Swpaul		case 'a':
19614062Swpaul			allow_additions++;
19714062Swpaul			break;
19814062Swpaul		case 'm':
19914062Swpaul			multidomain++;
20014062Swpaul			break;
20116134Swpaul		case 'i':
20216134Swpaul			inplace++;
20316134Swpaul			break;
20414062Swpaul		case 'v':
20514062Swpaul			verbose++;
20614062Swpaul			break;
20714241Swpaul		case 'u':
20814241Swpaul			resvport = 0;
20914241Swpaul			break;
21014062Swpaul		default:
21114062Swpaul		case 'h':
21214062Swpaul			usage();
21314062Swpaul			break;
21414062Swpaul		}
21514062Swpaul	}
21614062Swpaul
21714062Swpaul	if (yppasswd_domain == NULL) {
21814062Swpaul		if (yp_get_default_domain(&yppasswd_domain)) {
21914062Swpaul			yp_error("no domain specified and system domain \
22014062Swpaulname isn't set -- aborting");
22114062Swpaul		usage();
22214062Swpaul		}
22314062Swpaul	}
22414062Swpaul
22514241Swpaul	load_securenets();
22614241Swpaul
22796222Sdes	if (getrpcport(_localhost, YPPROG, YPVERS, IPPROTO_UDP) <= 0) {
22819130Swpaul		yp_error("no ypserv processes registered with local portmap");
22914062Swpaul		yp_error("this host is not an NIS server -- aborting");
23014062Swpaul		exit(1);
23114062Swpaul	}
23214062Swpaul
23396222Sdes	if ((mastername = ypxfr_get_master(yppasswd_domain,
23496222Sdes		 _passwd_byname, _localhost, 0)) == NULL) {
23519130Swpaul		yp_error("can't get name of NIS master server for domain %s",
23619130Swpaul			 				yppasswd_domain);
23714062Swpaul		exit(1);
23814062Swpaul	}
23914062Swpaul
24014062Swpaul	if (gethostname((char *)&myname, sizeof(myname)) == -1) {
24114062Swpaul		yp_error("can't get local hostname: %s", strerror(errno));
24214062Swpaul		exit(1);
24314062Swpaul	}
24414062Swpaul
24544791Sbrian	if (strncasecmp(mastername, (char *)&myname, sizeof(myname))) {
24619130Swpaul		yp_error("master of %s is %s, but we are %s",
24719130Swpaul			"passwd.byname", mastername, myname);
24819130Swpaul		yp_error("this host is not the NIS master server for \
24919130Swpaulthe %s domain -- aborting", yppasswd_domain);
25014062Swpaul		exit(1);
25114062Swpaul	}
25214062Swpaul
25314241Swpaul	debug = 0;
25414241Swpaul
25514062Swpaul	if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) {
256145803Sdelphij		socklen_t ssize = sizeof (int);
25714062Swpaul		if (saddr.sin_family != AF_INET)
25814062Swpaul			exit(1);
25914062Swpaul		if (getsockopt(0, SOL_SOCKET, SO_TYPE,
26090253Salfred		    (char *)&_rpcfdtype, &ssize) == -1)
26114062Swpaul			exit(1);
26214062Swpaul		_rpcpmstart = 1;
26314062Swpaul	}
26414062Swpaul
26590253Salfred	if (!debug && _rpcpmstart == 0) {
26690253Salfred		if (daemon(0,0)) {
26790253Salfred			err(1,"cannot fork");
26814062Swpaul		}
26914062Swpaul	}
27090253Salfred	openlog("rpc.yppasswdd", LOG_PID, LOG_DAEMON);
271184459Srafan	memset(&sa, 0, sizeof(sa));
272184459Srafan	sa.sa_flags = SA_NOCLDWAIT;
273184459Srafan	sigaction(SIGCHLD, &sa, NULL);
27414062Swpaul
27590253Salfred	rpcb_unset(YPPASSWDPROG, YPPASSWDVERS, NULL);
27690253Salfred	rpcb_unset(MASTER_YPPASSWDPROG, MASTER_YPPASSWDVERS, NULL);
27790253Salfred
278109363Smbr	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
279109363Smbr
28090253Salfred	if (svc_create(yppasswdprog_1, YPPASSWDPROG, YPPASSWDVERS, "netpath") == 0) {
28190253Salfred		yp_error("cannot create yppasswd service.");
28290253Salfred		exit(1);
28314062Swpaul	}
28490253Salfred	if (svc_create(master_yppasswdprog_1, MASTER_YPPASSWDPROG,
28590253Salfred	    MASTER_YPPASSWDVERS, "netpath") == 0) {
28690253Salfred		yp_error("cannot create master_yppasswd service.");
28790253Salfred		exit(1);
28890253Salfred	}
28914062Swpaul
29090253Salfred	nconf = NULL;
29190253Salfred	localhandle = setnetconfig();
29290253Salfred	while ((nconf = getnetconfig(localhandle)) != NULL) {
29390253Salfred		if (nconf->nc_protofmly != NULL &&
29490253Salfred		    strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
29590253Salfred			break;
29690253Salfred	}
29790253Salfred	if (nconf == NULL) {
29890253Salfred		yp_error("getnetconfigent unix: %s", nc_sperror());
29990253Salfred		exit(1);
30090253Salfred	}
30127758Swpaul	unlink(sockname);
30290253Salfred	transp = svcunix_create(RPC_ANYSOCK, 0, 0, sockname);
30327758Swpaul	if (transp == NULL) {
30427758Swpaul		yp_error("cannot create AF_LOCAL service.");
30527758Swpaul		exit(1);
30627758Swpaul	}
30790253Salfred	if (!svc_reg(transp, MASTER_YPPASSWDPROG, MASTER_YPPASSWDVERS,
30890253Salfred	    master_yppasswdprog_1, nconf)) {
30996391Salfred		yp_error("unable to register (MASTER_YPPASSWDPROG, \
31090253Salfred		    MASTER_YPPASSWDVERS, unix).");
31127758Swpaul		exit(1);
31227758Swpaul	}
31390253Salfred	endnetconfig(localhandle);
31490253Salfred
31527758Swpaul	/* Only root may connect() to the AF_UNIX link. */
31627758Swpaul	if (chmod(sockname, 0))
31727758Swpaul		err(1, "chmod of %s failed", sockname);
31827758Swpaul
31914062Swpaul	if (transp == (SVCXPRT *)NULL) {
32014062Swpaul		yp_error("could not create a handle");
32114062Swpaul		exit(1);
32214062Swpaul	}
32314062Swpaul	if (_rpcpmstart) {
32414062Swpaul		(void) signal(SIGALRM, (SIG_PF) closedown);
32514062Swpaul		(void) alarm(_RPCSVC_CLOSEDOWN/2);
32614062Swpaul	}
32714062Swpaul
32896222Sdes	/* Unlimited resource limits. */
32996222Sdes	rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
33096222Sdes	(void)setrlimit(RLIMIT_CPU, &rlim);
33196222Sdes	(void)setrlimit(RLIMIT_FSIZE, &rlim);
33296222Sdes	(void)setrlimit(RLIMIT_STACK, &rlim);
33396222Sdes	(void)setrlimit(RLIMIT_DATA, &rlim);
33496222Sdes	(void)setrlimit(RLIMIT_RSS, &rlim);
33514062Swpaul
33696222Sdes	/* Don't drop core (not really necessary, but GP's). */
33796222Sdes	rlim.rlim_cur = rlim.rlim_max = 0;
33896222Sdes	(void)setrlimit(RLIMIT_CORE, &rlim);
33914241Swpaul
34096222Sdes	/* Turn off signals. */
34196222Sdes	(void)signal(SIGALRM, SIG_IGN);
34296222Sdes	(void)signal(SIGHUP, (SIG_PF) reload);
34396222Sdes	(void)signal(SIGINT, SIG_IGN);
34496222Sdes	(void)signal(SIGPIPE, SIG_IGN);
34596222Sdes	(void)signal(SIGQUIT, SIG_IGN);
34696222Sdes	(void)signal(SIGTERM, (SIG_PF) terminate);
34796222Sdes
34827758Swpaul	svc_run();
34914062Swpaul	yp_error("svc_run returned");
35014062Swpaul	exit(1);
35114062Swpaul	/* NOTREACHED */
35214062Swpaul}
353