yppasswdd_main.c revision 14241
11797Sphk/*
21797Sphk * Copyright (c) 1995, 1996
31797Sphk *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
41797Sphk *
51797Sphk * Redistribution and use in source and binary forms, with or without
61797Sphk * modification, are permitted provided that the following conditions
71797Sphk * are met:
81797Sphk * 1. Redistributions of source code must retain the above copyright
91797Sphk *    notice, this list of conditions and the following disclaimer.
101797Sphk * 2. Redistributions in binary form must reproduce the above copyright
111797Sphk *    notice, this list of conditions and the following disclaimer in the
121797Sphk *    documentation and/or other materials provided with the distribution.
131797Sphk * 3. All advertising materials mentioning features or use of this software
141797Sphk *    must display the following acknowledgement:
151797Sphk *	This product includes software developed by Bill Paul.
161797Sphk * 4. Neither the name of the author nor the names of any co-contributors
171797Sphk *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 *	$Id: yppasswdd_main.c,v 1.10 1996/02/24 21:41:15 wpaul Exp $
33 */
34
35#include "yppasswd.h"
36#include <stdio.h>
37#include <sys/types.h>
38#include <stdlib.h> /* getenv, exit */
39#include <unistd.h>
40#include <string.h>
41#include <sys/param.h>
42#include <rpc/pmap_clnt.h> /* for pmap_unset */
43#include <string.h> /* strcmp */
44#include <signal.h>
45#include <fcntl.h>
46#include <sys/ioctl.h>
47#include <sys/stat.h>
48#include <sys/ttycom.h> /* TIOCNOTTY */
49#ifdef __cplusplus
50#include <sysent.h> /* getdtablesize, open */
51#endif /* __cplusplus */
52#include <memory.h>
53#include <sys/socket.h>
54#include <netinet/in.h>
55#include <syslog.h>
56#include <err.h>
57#include <errno.h>
58#include <rpcsvc/yp.h>
59struct dom_binding {};
60#include <rpcsvc/ypclnt.h>
61#include "yppasswdd_extern.h"
62#include "yppasswd_comm.h"
63#include "ypxfr_extern.h"
64
65#ifndef SIG_PF
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
74#ifndef lint
75static const char rcsid[] = "$Id: yppasswdd_main.c,v 1.10 1996/02/24 21:41:15 wpaul Exp $";
76#endif /* not lint */
77int _rpcpmstart = 0;		/* Started by a port monitor ? */
78static int _rpcfdtype;
79		 /* Whether Stream or Datagram ? */
80	/* States a server can be in wrt request */
81
82#define	_IDLE 0
83#define	_SERVED 1
84#define	_SERVING 2
85
86extern int _rpcsvcstate;	 /* Set when a request is serviced */
87char *progname = "rpc.yppasswdd";
88char *passfile_default = "/var/yp/master.passwd";
89char *passfile;
90char *yppasswd_domain = NULL;
91int no_chsh = 0;
92int no_chfn = 0;
93int allow_additions = 0;
94int multidomain = 0;
95int verbose = 0;
96int resvport = 1;
97char *yp_dir = "/var/yp/";
98int yp_sock;
99
100
101static void
102my_svc_run()
103{
104#ifdef FD_SETSIZE
105	fd_set readfds;
106#else
107      int readfds;
108#endif /* def FD_SETSIZE */
109	extern int errno;
110
111	for (;;) {
112
113
114#ifdef FD_SETSIZE
115		readfds = svc_fdset;
116#else
117		readfds = svc_fds;
118#endif /* def FD_SETSIZE */
119		FD_SET(yp_sock, &readfds);
120
121		switch (select(_rpc_dtablesize(), &readfds, (fd_set *)0, (fd_set *)0,
122			       (struct timeval *)0)) {
123		case -1:
124			if (errno == EINTR) {
125				continue;
126			}
127			perror("svc_run: - select failed");
128			return;
129		case 0:
130			continue;
131		default:
132			if (FD_ISSET(yp_sock, &readfds)) {
133				do_master();
134				FD_CLR(yp_sock, &readfds);
135			}
136			svc_getreqset(&readfds);
137		}
138	}
139}
140
141static void terminate(sig)
142	int sig;
143{
144	svc_unregister(YPPASSWDPROG, YPPASSWDVERS);
145	close(yp_sock);
146	unlink(sockname);
147	exit(0);
148}
149
150static void reload(sig)
151	int sig;
152{
153	load_securenets();
154}
155
156static void
157closedown(int sig)
158{
159	if (_rpcsvcstate == _IDLE) {
160		extern fd_set svc_fdset;
161		static int size;
162		int i, openfd;
163
164		if (_rpcfdtype == SOCK_DGRAM) {
165			close(yp_sock);
166			unlink(sockname);
167			exit(0);
168		}
169		if (size == 0) {
170			size = getdtablesize();
171		}
172		for (i = 0, openfd = 0; i < size && openfd < 2; i++)
173			if (FD_ISSET(i, &svc_fdset))
174				openfd++;
175		if (openfd <= 1) {
176			close(yp_sock);
177			unlink(sockname);
178			exit(0);
179		}
180	}
181	if (_rpcsvcstate == _SERVED)
182		_rpcsvcstate = _IDLE;
183
184	(void) signal(SIGALRM, (SIG_PF) closedown);
185	(void) alarm(_RPCSVC_CLOSEDOWN/2);
186}
187
188static void usage()
189{
190	fprintf(stderr, "Usage: %s [-t master.passwd file] [-d domain] \
191[-p path] [-s] [-f] [-m] [-a] [-v] [-u] [-h]\n",
192		progname);
193	exit(1);
194}
195
196main(argc, argv)
197	int argc;
198	char *argv[];
199{
200	register SVCXPRT *transp = NULL;
201	int sock;
202	int proto = 0;
203	struct sockaddr_in saddr;
204	int asize = sizeof (saddr);
205	int ch;
206	int rval;
207	char *mastername;
208	char myname[MAXHOSTNAMELEN + 2];
209	extern int errno;
210	extern int debug;
211
212	debug = 1;
213
214	while ((ch = getopt(argc, argv, "t:d:p:sfamvh")) != EOF) {
215		switch(ch) {
216		case 't':
217			passfile_default = optarg;
218			break;
219		case 'd':
220			yppasswd_domain = optarg;
221			break;
222		case 's':
223			no_chsh++;
224			break;
225		case 'f':
226			no_chfn++;
227			break;
228		case 'p':
229			yp_dir = optarg;
230			break;
231		case 'a':
232			allow_additions++;
233			break;
234		case 'm':
235			multidomain++;
236			break;
237		case 'v':
238			verbose++;
239			break;
240		case 'u':
241			resvport = 0;
242			break;
243		default:
244		case 'h':
245			usage();
246			break;
247		}
248	}
249
250	if (yppasswd_domain == NULL) {
251		if (yp_get_default_domain(&yppasswd_domain)) {
252			yp_error("no domain specified and system domain \
253name isn't set -- aborting");
254		usage();
255		}
256	}
257
258	load_securenets();
259
260	if (getrpcport("localhost", YPPROG, YPVERS, IPPROTO_UDP) <= 0) {
261		yp_error("this host is not an NIS server -- aborting");
262		exit(1);
263	}
264
265	if ((mastername = ypxfr_get_master(yppasswd_domain, "passwd.byname",
266						"localhost",0)) == NULL) {
267		yp_error("can't get name of NIS master server");
268		exit(1);
269	}
270
271	if (gethostname((char *)&myname, sizeof(myname)) == -1) {
272		yp_error("can't get local hostname: %s", strerror(errno));
273		exit(1);
274	}
275
276	if (strncmp(mastername, (char *)&myname, sizeof(myname))) {
277		yp_error("this host is not an NIS master server -- aborting");
278		exit(1);
279	}
280
281	debug = 0;
282
283	if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) {
284		int ssize = sizeof (int);
285
286		if (saddr.sin_family != AF_INET)
287			exit(1);
288		if (getsockopt(0, SOL_SOCKET, SO_TYPE,
289				(char *)&_rpcfdtype, &ssize) == -1)
290			exit(1);
291		sock = 0;
292		_rpcpmstart = 1;
293		proto = 0;
294		openlog(progname, LOG_PID, LOG_DAEMON);
295	} else {
296#ifndef RPC_SVC_FG
297		int size;
298		int pid, i;
299
300		pid = fork();
301		if (pid < 0) {
302			perror("cannot fork");
303			exit(1);
304		}
305		if (pid)
306			exit(0);
307		size = getdtablesize();
308		for (i = 0; i < size; i++)
309			(void) close(i);
310		i = open("/dev/console", 2);
311		(void) dup2(i, 1);
312		(void) dup2(i, 2);
313		i = open("/dev/tty", 2);
314		if (i >= 0) {
315			(void) ioctl(i, TIOCNOTTY, (char *)NULL);
316			(void) close(i);
317		}
318		openlog(progname, LOG_PID, LOG_DAEMON);
319#endif
320		sock = RPC_ANYSOCK;
321		(void) pmap_unset(YPPASSWDPROG, YPPASSWDVERS);
322	}
323
324	if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) {
325		transp = svcudp_create(sock);
326		if (transp == NULL) {
327			yp_error("cannot create udp service.");
328			exit(1);
329		}
330		if (!_rpcpmstart)
331			proto = IPPROTO_UDP;
332		if (!svc_register(transp, YPPASSWDPROG, YPPASSWDVERS, yppasswdprog_1, proto)) {
333			yp_error("unable to register (YPPASSWDPROG, YPPASSWDVERS, udp).");
334			exit(1);
335		}
336	}
337
338	if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) {
339		transp = svctcp_create(sock, 0, 0);
340		if (transp == NULL) {
341			yp_error("cannot create tcp service.");
342			exit(1);
343		}
344		if (!_rpcpmstart)
345			proto = IPPROTO_TCP;
346		if (!svc_register(transp, YPPASSWDPROG, YPPASSWDVERS, yppasswdprog_1, proto)) {
347			yp_error("unable to register (YPPASSWDPROG, YPPASSWDVERS, tcp).");
348			exit(1);
349		}
350	}
351
352	if (transp == (SVCXPRT *)NULL) {
353		yp_error("could not create a handle");
354		exit(1);
355	}
356	if (_rpcpmstart) {
357		(void) signal(SIGALRM, (SIG_PF) closedown);
358		(void) alarm(_RPCSVC_CLOSEDOWN/2);
359	}
360	/* set up resource limits and block signals */
361	pw_init();
362
363	/* except SIGCHLD, which we need to catch */
364	install_reaper(1);
365	signal(SIGTERM, (SIG_PF) terminate);
366
367	signal(SIGHUP, (SIG_PF) reload);
368
369	unlink(sockname);
370	yp_sock = makeservsock();
371	if (chmod(sockname, 0))
372		err(1, "chmod of %s failed", sockname);
373
374	my_svc_run();
375	yp_error("svc_run returned");
376	exit(1);
377	/* NOTREACHED */
378}
379