xref: /freebsd/usr.sbin/rpc.yppasswdd/yppasswdd_main.c (revision 8e537d168674d6b65869f73c20813001af875738)
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.13 1996/06/23 22:24:42 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.13 1996/06/23 22:24:42 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 *yp_dir = _PATH_YP;
89 char *passfile_default = _PATH_YP "master.passwd";
90 char *passfile;
91 char *yppasswd_domain = NULL;
92 int no_chsh = 0;
93 int no_chfn = 0;
94 int allow_additions = 0;
95 int multidomain = 0;
96 int verbose = 0;
97 int resvport = 1;
98 int inplace = 0;
99 int yp_sock;
100 
101 
102 static void
103 my_svc_run()
104 {
105 #ifdef FD_SETSIZE
106 	fd_set readfds;
107 #else
108       int readfds;
109 #endif /* def FD_SETSIZE */
110 	extern int errno;
111 
112 	for (;;) {
113 
114 
115 #ifdef FD_SETSIZE
116 		readfds = svc_fdset;
117 #else
118 		readfds = svc_fds;
119 #endif /* def FD_SETSIZE */
120 		FD_SET(yp_sock, &readfds);
121 
122 		switch (select(_rpc_dtablesize(), &readfds, (fd_set *)0, (fd_set *)0,
123 			       (struct timeval *)0)) {
124 		case -1:
125 			if (errno == EINTR) {
126 				continue;
127 			}
128 			perror("svc_run: - select failed");
129 			return;
130 		case 0:
131 			continue;
132 		default:
133 			if (FD_ISSET(yp_sock, &readfds)) {
134 				do_master();
135 				FD_CLR(yp_sock, &readfds);
136 			}
137 			svc_getreqset(&readfds);
138 		}
139 	}
140 }
141 
142 static void terminate(sig)
143 	int sig;
144 {
145 	svc_unregister(YPPASSWDPROG, YPPASSWDVERS);
146 	close(yp_sock);
147 	unlink(sockname);
148 	exit(0);
149 }
150 
151 static void reload(sig)
152 	int sig;
153 {
154 	load_securenets();
155 }
156 
157 static void
158 closedown(int sig)
159 {
160 	if (_rpcsvcstate == _IDLE) {
161 		extern fd_set svc_fdset;
162 		static int size;
163 		int i, openfd;
164 
165 		if (_rpcfdtype == SOCK_DGRAM) {
166 			close(yp_sock);
167 			unlink(sockname);
168 			exit(0);
169 		}
170 		if (size == 0) {
171 			size = getdtablesize();
172 		}
173 		for (i = 0, openfd = 0; i < size && openfd < 2; i++)
174 			if (FD_ISSET(i, &svc_fdset))
175 				openfd++;
176 		if (openfd <= 1) {
177 			close(yp_sock);
178 			unlink(sockname);
179 			exit(0);
180 		}
181 	}
182 	if (_rpcsvcstate == _SERVED)
183 		_rpcsvcstate = _IDLE;
184 
185 	(void) signal(SIGALRM, (SIG_PF) closedown);
186 	(void) alarm(_RPCSVC_CLOSEDOWN/2);
187 }
188 
189 static void usage()
190 {
191 	fprintf(stderr, "Usage: %s [-t master.passwd file] [-d domain] \
192 [-p path] [-s] [-f] [-m] [-i] [-a] [-v] [-u] [-h]\n",
193 		progname);
194 	exit(1);
195 }
196 
197 main(argc, argv)
198 	int argc;
199 	char *argv[];
200 {
201 	register SVCXPRT *transp = NULL;
202 	int sock;
203 	int proto = 0;
204 	struct sockaddr_in saddr;
205 	int asize = sizeof (saddr);
206 	int ch;
207 	int rval;
208 	char *mastername;
209 	char myname[MAXHOSTNAMELEN + 2];
210 	extern int errno;
211 	extern int debug;
212 
213 	debug = 1;
214 
215 	while ((ch = getopt(argc, argv, "t:d:p:sfamivh")) != EOF) {
216 		switch(ch) {
217 		case 't':
218 			passfile_default = optarg;
219 			break;
220 		case 'd':
221 			yppasswd_domain = optarg;
222 			break;
223 		case 's':
224 			no_chsh++;
225 			break;
226 		case 'f':
227 			no_chfn++;
228 			break;
229 		case 'p':
230 			yp_dir = optarg;
231 			break;
232 		case 'a':
233 			allow_additions++;
234 			break;
235 		case 'm':
236 			multidomain++;
237 			break;
238 		case 'i':
239 			inplace++;
240 			break;
241 		case 'v':
242 			verbose++;
243 			break;
244 		case 'u':
245 			resvport = 0;
246 			break;
247 		default:
248 		case 'h':
249 			usage();
250 			break;
251 		}
252 	}
253 
254 	if (yppasswd_domain == NULL) {
255 		if (yp_get_default_domain(&yppasswd_domain)) {
256 			yp_error("no domain specified and system domain \
257 name isn't set -- aborting");
258 		usage();
259 		}
260 	}
261 
262 	load_securenets();
263 
264 	if (getrpcport("localhost", YPPROG, YPVERS, IPPROTO_UDP) <= 0) {
265 		yp_error("this host is not an NIS server -- aborting");
266 		exit(1);
267 	}
268 
269 	if ((mastername = ypxfr_get_master(yppasswd_domain, "passwd.byname",
270 						"localhost",0)) == NULL) {
271 		yp_error("can't get name of NIS master server");
272 		exit(1);
273 	}
274 
275 	if (gethostname((char *)&myname, sizeof(myname)) == -1) {
276 		yp_error("can't get local hostname: %s", strerror(errno));
277 		exit(1);
278 	}
279 
280 	if (strncmp(mastername, (char *)&myname, sizeof(myname))) {
281 		yp_error("this host is not an NIS master server -- aborting");
282 		exit(1);
283 	}
284 
285 	debug = 0;
286 
287 	if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) {
288 		int ssize = sizeof (int);
289 
290 		if (saddr.sin_family != AF_INET)
291 			exit(1);
292 		if (getsockopt(0, SOL_SOCKET, SO_TYPE,
293 				(char *)&_rpcfdtype, &ssize) == -1)
294 			exit(1);
295 		sock = 0;
296 		_rpcpmstart = 1;
297 		proto = 0;
298 		openlog(progname, LOG_PID, LOG_DAEMON);
299 	} else {
300 #ifndef RPC_SVC_FG
301 		int size;
302 		int pid, i;
303 
304 		pid = fork();
305 		if (pid < 0) {
306 			perror("cannot fork");
307 			exit(1);
308 		}
309 		if (pid)
310 			exit(0);
311 		size = getdtablesize();
312 		for (i = 0; i < size; i++)
313 			(void) close(i);
314 		i = open("/dev/console", 2);
315 		(void) dup2(i, 1);
316 		(void) dup2(i, 2);
317 		i = open("/dev/tty", 2);
318 		if (i >= 0) {
319 			(void) ioctl(i, TIOCNOTTY, (char *)NULL);
320 			(void) close(i);
321 		}
322 		openlog(progname, LOG_PID, LOG_DAEMON);
323 #endif
324 		sock = RPC_ANYSOCK;
325 		(void) pmap_unset(YPPASSWDPROG, YPPASSWDVERS);
326 	}
327 
328 	if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) {
329 		transp = svcudp_create(sock);
330 		if (transp == NULL) {
331 			yp_error("cannot create udp service.");
332 			exit(1);
333 		}
334 		if (!_rpcpmstart)
335 			proto = IPPROTO_UDP;
336 		if (!svc_register(transp, YPPASSWDPROG, YPPASSWDVERS, yppasswdprog_1, proto)) {
337 			yp_error("unable to register (YPPASSWDPROG, YPPASSWDVERS, udp).");
338 			exit(1);
339 		}
340 	}
341 
342 	if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) {
343 		transp = svctcp_create(sock, 0, 0);
344 		if (transp == NULL) {
345 			yp_error("cannot create tcp service.");
346 			exit(1);
347 		}
348 		if (!_rpcpmstart)
349 			proto = IPPROTO_TCP;
350 		if (!svc_register(transp, YPPASSWDPROG, YPPASSWDVERS, yppasswdprog_1, proto)) {
351 			yp_error("unable to register (YPPASSWDPROG, YPPASSWDVERS, tcp).");
352 			exit(1);
353 		}
354 	}
355 
356 	if (transp == (SVCXPRT *)NULL) {
357 		yp_error("could not create a handle");
358 		exit(1);
359 	}
360 	if (_rpcpmstart) {
361 		(void) signal(SIGALRM, (SIG_PF) closedown);
362 		(void) alarm(_RPCSVC_CLOSEDOWN/2);
363 	}
364 	/* set up resource limits and block signals */
365 	pw_init();
366 
367 	/* except SIGCHLD, which we need to catch */
368 	install_reaper(1);
369 	signal(SIGTERM, (SIG_PF) terminate);
370 
371 	signal(SIGHUP, (SIG_PF) reload);
372 
373 	unlink(sockname);
374 	yp_sock = makeservsock();
375 	if (chmod(sockname, 0))
376 		err(1, "chmod of %s failed", sockname);
377 
378 	my_svc_run();
379 	yp_error("svc_run returned");
380 	exit(1);
381 	/* NOTREACHED */
382 }
383