xref: /freebsd/usr.sbin/rpc.yppasswdd/yppasswdd_main.c (revision ef5d438ed4bc17ad7ece3e40fe4d1f9baf3aadf7)
1 /*
2  * Copyright (c) 1995, 1996
3  *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by Bill Paul.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    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>
59 struct 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
75 static const char rcsid[] = "$Id: yppasswdd_main.c,v 1.10 1996/02/24 21:41:15 wpaul Exp $";
76 #endif /* not lint */
77 int _rpcpmstart = 0;		/* Started by a port monitor ? */
78 static 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 
86 extern int _rpcsvcstate;	 /* Set when a request is serviced */
87 char *progname = "rpc.yppasswdd";
88 char *passfile_default = "/var/yp/master.passwd";
89 char *passfile;
90 char *yppasswd_domain = NULL;
91 int no_chsh = 0;
92 int no_chfn = 0;
93 int allow_additions = 0;
94 int multidomain = 0;
95 int verbose = 0;
96 int resvport = 1;
97 char *yp_dir = "/var/yp/";
98 int yp_sock;
99 
100 
101 static void
102 my_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 
141 static void terminate(sig)
142 	int sig;
143 {
144 	svc_unregister(YPPASSWDPROG, YPPASSWDVERS);
145 	close(yp_sock);
146 	unlink(sockname);
147 	exit(0);
148 }
149 
150 static void reload(sig)
151 	int sig;
152 {
153 	load_securenets();
154 }
155 
156 static void
157 closedown(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 
188 static 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 
196 main(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 \
253 name 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