ypserv.c revision 1.6 1 /* $NetBSD: ypserv.c,v 1.6 1997/10/08 13:45:21 lukem Exp $ */
2
3 /*
4 * Copyright (c) 1994 Mats O Jansson <moj (at) stacken.kth.se>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Mats O Jansson
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/wait.h>
37
38 #include <netinet/in.h>
39
40 #include <err.h>
41 #include <netdb.h>
42 #include <signal.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <syslog.h>
47 #include <unistd.h>
48
49 #include <rpc/rpc.h>
50 #include <rpc/xdr.h>
51 #include <rpc/pmap_clnt.h>
52
53 #include <rpcsvc/yp_prot.h>
54
55 #include "acl.h"
56 #include "yplog.h"
57 #include "ypdef.h"
58 #include "ypserv.h"
59
60 #ifdef __STDC__
61 #define SIG_PF void(*)(int)
62 #endif
63
64 #ifdef DEBUG
65 #define RPC_SVC_FG
66 #endif
67
68 #define _RPCSVC_CLOSEDOWN 120
69 static int _rpcpmstart; /* Started by a port monitor ? */
70 static int _rpcfdtype; /* Whether Stream or Datagram ? */
71 static int _rpcsvcdirty; /* Still serving ? */
72
73 int usedns;
74 char *aclfile;
75
76 extern char *__progname; /* from crt0.s */
77
78 int main __P((int, char *[]));
79 void usage __P((void));
80
81 void sighandler __P((int));
82
83 static void closedown __P((void));
84
85 static
86 void _msgout(char* msg)
87 {
88 #ifdef RPC_SVC_FG
89 if (_rpcpmstart)
90 syslog(LOG_ERR, msg);
91 else
92 warnx("%s", msg);
93 #else
94 syslog(LOG_ERR, msg);
95 #endif
96 }
97
98 static void
99 closedown()
100 {
101 if (_rpcsvcdirty == 0) {
102 extern fd_set svc_fdset;
103 static int size;
104 int i, openfd;
105
106 if (_rpcfdtype == SOCK_DGRAM)
107 exit(0);
108 if (size == 0) {
109 size = getdtablesize();
110 }
111 for (i = 0, openfd = 0; i < size && openfd < 2; i++)
112 if (FD_ISSET(i, &svc_fdset))
113 openfd++;
114 if (openfd <= (_rpcpmstart?0:1))
115 exit(0);
116 }
117 (void) alarm(_RPCSVC_CLOSEDOWN);
118 }
119
120 static void
121 ypprog_2(struct svc_req *rqstp, SVCXPRT *transp)
122 {
123 union {
124 char * ypproc_domain_2_arg;
125 char * ypproc_domain_nonack_2_arg;
126 struct ypreq_key ypproc_match_2_arg;
127 struct ypreq_nokey ypproc_first_2_arg;
128 struct ypreq_key ypproc_next_2_arg;
129 struct ypreq_xfr ypproc_xfr_2_arg;
130 struct ypreq_nokey ypproc_all_2_arg;
131 struct ypreq_nokey ypproc_master_2_arg;
132 struct ypreq_nokey ypproc_order_2_arg;
133 char * ypproc_maplist_2_arg;
134 } argument;
135 char *result;
136 xdrproc_t xdr_argument, xdr_result;
137 void *(*local) __P((void *, struct svc_req *));
138
139 _rpcsvcdirty = 1;
140 switch (rqstp->rq_proc) {
141 case YPPROC_NULL:
142 xdr_argument = xdr_void;
143 xdr_result = xdr_void;
144 local = ypproc_null_2_svc;
145 break;
146
147 case YPPROC_DOMAIN:
148 xdr_argument = xdr_ypdomain_wrap_string;
149 xdr_result = xdr_bool;
150 local = ypproc_domain_2_svc;
151 break;
152
153 case YPPROC_DOMAIN_NONACK:
154 xdr_argument = xdr_ypdomain_wrap_string;
155 xdr_result = xdr_bool;
156 local = ypproc_domain_nonack_2_svc;
157 break;
158
159 case YPPROC_MATCH:
160 xdr_argument = xdr_ypreq_key;
161 xdr_result = xdr_ypresp_val;
162 local = ypproc_match_2_svc;
163 break;
164
165 case YPPROC_FIRST:
166 xdr_argument = xdr_ypreq_nokey;
167 xdr_result = xdr_ypresp_key_val;
168 local = ypproc_first_2_svc;
169 break;
170
171 case YPPROC_NEXT:
172 xdr_argument = xdr_ypreq_key;
173 xdr_result = xdr_ypresp_key_val;
174 local = ypproc_next_2_svc;
175 break;
176
177 case YPPROC_XFR:
178 xdr_argument = xdr_ypreq_xfr;
179 xdr_result = xdr_ypresp_xfr;
180 local = ypproc_xfr_2_svc;
181 break;
182
183 case YPPROC_CLEAR:
184 xdr_argument = xdr_void;
185 xdr_result = xdr_void;
186 local = ypproc_clear_2_svc;
187 break;
188
189 case YPPROC_ALL:
190 xdr_argument = xdr_ypreq_nokey;
191 xdr_result = xdr_ypresp_all;
192 local = ypproc_all_2_svc;
193 break;
194
195 case YPPROC_MASTER:
196 xdr_argument = xdr_ypreq_nokey;
197 xdr_result = xdr_ypresp_master;
198 local = ypproc_master_2_svc;
199 break;
200
201 case YPPROC_ORDER:
202 xdr_argument = xdr_ypreq_nokey;
203 xdr_result = xdr_ypresp_order;
204 local = ypproc_order_2_svc;
205 break;
206
207 case YPPROC_MAPLIST:
208 xdr_argument = xdr_ypdomain_wrap_string;
209 xdr_result = xdr_ypresp_maplist;
210 local = ypproc_maplist_2_svc;
211 break;
212
213 default:
214 svcerr_noproc(transp);
215 _rpcsvcdirty = 0;
216 return;
217 }
218 (void) memset((char *)&argument, 0, sizeof (argument));
219 if (!svc_getargs(transp, xdr_argument, (caddr_t) &argument)) {
220 svcerr_decode(transp);
221 _rpcsvcdirty = 0;
222 return;
223 }
224 result = (*local)(&argument, rqstp);
225 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
226 svcerr_systemerr(transp);
227 }
228 if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) {
229 _msgout("unable to free arguments");
230 exit(1);
231 }
232 _rpcsvcdirty = 0;
233 return;
234 }
235
236 /*
237 * limited NIS version 1 support: the null, domain, and domain_nonack
238 * request/reply format is identical between v1 and v2. SunOS4's ypbind
239 * makes v1 domain_nonack calls.
240 */
241 static void
242 ypprog_1(struct svc_req *rqstp, SVCXPRT *transp)
243 {
244 switch (rqstp->rq_proc) {
245 case YPPROC_NULL:
246 case YPPROC_DOMAIN:
247 case YPPROC_DOMAIN_NONACK:
248 ypprog_2(rqstp, transp);
249 return;
250
251 default:
252 svcerr_noproc(transp);
253 _rpcsvcdirty = 0;
254 return;
255 }
256 }
257
258 int
259 main(argc, argv)
260 int argc;
261 char *argv[];
262 {
263 SVCXPRT *transp;
264 int sock, proto;
265 struct sigaction sa;
266 int xflag = 0;
267 int ch;
268
269 transp = NULL; /* XXX gcc -Wuninitialized */
270 proto = 0; /* XXX gcc -Wuninitialized */
271
272 while ((ch = getopt(argc, argv, "a:dx")) != -1) {
273 switch (ch) {
274 case 'a':
275 aclfile = optarg;
276 break;
277
278 case 'd':
279 usedns = 1;
280 break;
281
282 case 'x':
283 xflag = 1;
284 break;
285
286 default:
287 usage();
288 }
289 }
290
291 /* This program must be run by root. */
292 if (geteuid() != 0)
293 errx(1, "must run as root");
294
295 /* Deal with the acl file. */
296 acl_parse(aclfile);
297
298 if (xflag)
299 exit(1);
300
301 #ifndef RPC_SVC_FG
302 if (daemon(0, 0))
303 err(1, "can't detach");
304 openlog("ypserv", LOG_PID, LOG_DAEMON);
305 #endif
306
307 {
308 FILE *pidfile = fopen(YPSERV_PID_PATH, "w");
309
310 if (pidfile != NULL) {
311 fprintf(pidfile, "%d\n", getpid());
312 fclose(pidfile);
313 } else
314 err(1, "can't write PID file");
315 }
316
317 sock = RPC_ANYSOCK;
318 (void) pmap_unset(YPPROG, YPVERS);
319 (void) pmap_unset(YPPROG, YPVERS_ORIG);
320
321 ypopenlog(); /* open log file */
322 ypdb_init(); /* init db stuff */
323
324 sa.sa_handler = sighandler;
325 sa.sa_flags = 0;
326 if (sigemptyset(&sa.sa_mask))
327 err(1, "sigemptyset");
328 if (sigaction(SIGCHLD, &sa, NULL) || sigaction(SIGHUP, &sa, NULL))
329 err(1, "sigaction");
330
331 if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) {
332 transp = svcudp_create(sock);
333 if (transp == NULL) {
334 _msgout("cannot create udp service.");
335 exit(1);
336 }
337 if (transp->xp_port >= IPPORT_RESERVED) {
338 _msgout("udp service not bound to a privileged port.");
339 exit(1);
340 }
341 if (!_rpcpmstart)
342 proto = IPPROTO_UDP;
343 if (!svc_register(transp, YPPROG, YPVERS_ORIG, ypprog_1,
344 proto)) {
345 _msgout(
346 "unable to register (YPPROG, YPVERS_ORIG, udp).");
347 exit(1);
348 }
349 if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) {
350 _msgout("unable to register (YPPROG, YPVERS, udp).");
351 exit(1);
352 }
353 }
354
355 if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) {
356 if (_rpcpmstart)
357 transp = svcfd_create(sock, 0, 0);
358 else
359 transp = svctcp_create(sock, 0, 0);
360 if (transp == NULL) {
361 _msgout("cannot create tcp service.");
362 exit(1);
363 }
364 if (transp->xp_port >= IPPORT_RESERVED) {
365 _msgout("tcp service not bound to a privileged port.");
366 exit(1);
367 }
368 if (!_rpcpmstart)
369 proto = IPPROTO_TCP;
370 if (!svc_register(transp, YPPROG, YPVERS_ORIG, ypprog_1,
371 proto)) {
372 _msgout(
373 "unable to register (YPPROG, YPVERS_ORIG, tcp).");
374 exit(1);
375 }
376 if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) {
377 _msgout("unable to register (YPPROG, YPVERS, tcp).");
378 exit(1);
379 }
380 }
381
382 if (transp == (SVCXPRT *)NULL) {
383 _msgout("could not create a handle");
384 exit(1);
385 }
386 if (_rpcpmstart) {
387 (void) signal(SIGALRM, (SIG_PF) closedown);
388 (void) alarm(_RPCSVC_CLOSEDOWN);
389 }
390 svc_run();
391 _msgout("svc_run returned");
392 exit(1);
393 /* NOTREACHED */
394 }
395
396 void
397 sighandler(sig)
398 int sig;
399 {
400
401 if (sig == SIGHUP) {
402 acl_reset();
403 yplog("reread %s", aclfile ? aclfile : YP_SECURENET_FILE);
404 acl_parse(aclfile);
405 return;
406 }
407
408 /* SIGCHLD */
409 while (wait3((int *)NULL, WNOHANG, (struct rusage *)NULL) > 0);
410 }
411
412 void
413 usage()
414 {
415
416 fprintf(stderr, "usage: %s [-a aclfile] [-d] [-x]\n", __progname);
417 exit(1);
418 }
419