ypserv.c revision 1.4 1 /* $NetBSD: ypserv.c,v 1.4 1997/04/17 17:46:17 christos 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 <memory.h>
41 #include <netdb.h>
42 #include <signal.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46
47 #include <rpc/rpc.h>
48 #include <rpc/xdr.h>
49 #include <rpc/pmap_clnt.h>
50
51 #include <rpcsvc/yp_prot.h>
52
53 #ifdef SYSLOG
54 #include <syslog.h>
55 #else
56 #define LOG_ERR 1
57 #define openlog(a, b, c)
58 #endif
59
60 #include "acl.h"
61 #include "yplog.h"
62 #include "ypdef.h"
63 #include "ypserv.h"
64
65 #ifdef __STDC__
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 static int _rpcpmstart; /* Started by a port monitor ? */
75 static int _rpcfdtype; /* Whether Stream or Datagram ? */
76 static int _rpcsvcdirty; /* Still serving ? */
77
78 int usedns;
79 char *aclfile;
80
81 extern char *__progname; /* from crt0.s */
82 extern char *optarg;
83 extern int optind;
84
85 void usage __P((void));
86
87 void sig_child();
88 void sig_hup();
89
90 static
91 void _msgout(char* msg)
92 {
93 #ifdef RPC_SVC_FG
94 if (_rpcpmstart)
95 syslog(LOG_ERR, msg);
96 else
97 warnx("%s", msg);
98 #else
99 syslog(LOG_ERR, msg);
100 #endif
101 }
102
103 static void
104 closedown()
105 {
106 if (_rpcsvcdirty == 0) {
107 extern fd_set svc_fdset;
108 static int size;
109 int i, openfd;
110
111 if (_rpcfdtype == SOCK_DGRAM)
112 exit(0);
113 if (size == 0) {
114 size = getdtablesize();
115 }
116 for (i = 0, openfd = 0; i < size && openfd < 2; i++)
117 if (FD_ISSET(i, &svc_fdset))
118 openfd++;
119 if (openfd <= (_rpcpmstart?0:1))
120 exit(0);
121 }
122 (void) alarm(_RPCSVC_CLOSEDOWN);
123 }
124
125 static void
126 ypprog_2(struct svc_req *rqstp, register SVCXPRT *transp)
127 {
128 union {
129 char * ypproc_domain_2_arg;
130 char * ypproc_domain_nonack_2_arg;
131 struct ypreq_key ypproc_match_2_arg;
132 struct ypreq_nokey ypproc_first_2_arg;
133 struct ypreq_key ypproc_next_2_arg;
134 struct ypreq_xfr ypproc_xfr_2_arg;
135 struct ypreq_nokey ypproc_all_2_arg;
136 struct ypreq_nokey ypproc_master_2_arg;
137 struct ypreq_nokey ypproc_order_2_arg;
138 char * ypproc_maplist_2_arg;
139 } argument;
140 char *result;
141 xdrproc_t xdr_argument, xdr_result;
142 void *(*local) __P((void *, struct svc_req *));
143
144 _rpcsvcdirty = 1;
145 switch (rqstp->rq_proc) {
146 case YPPROC_NULL:
147 xdr_argument = xdr_void;
148 xdr_result = xdr_void;
149 local = ypproc_null_2_svc;
150 break;
151
152 case YPPROC_DOMAIN:
153 xdr_argument = xdr_ypdomain_wrap_string;
154 xdr_result = xdr_bool;
155 local = ypproc_domain_2_svc;
156 break;
157
158 case YPPROC_DOMAIN_NONACK:
159 xdr_argument = xdr_ypdomain_wrap_string;
160 xdr_result = xdr_bool;
161 local = ypproc_domain_nonack_2_svc;
162 break;
163
164 case YPPROC_MATCH:
165 xdr_argument = xdr_ypreq_key;
166 xdr_result = xdr_ypresp_val;
167 local = ypproc_match_2_svc;
168 break;
169
170 case YPPROC_FIRST:
171 xdr_argument = xdr_ypreq_nokey;
172 xdr_result = xdr_ypresp_key_val;
173 local = ypproc_first_2_svc;
174 break;
175
176 case YPPROC_NEXT:
177 xdr_argument = xdr_ypreq_key;
178 xdr_result = xdr_ypresp_key_val;
179 local = ypproc_next_2_svc;
180 break;
181
182 case YPPROC_XFR:
183 xdr_argument = xdr_ypreq_xfr;
184 xdr_result = xdr_ypresp_xfr;
185 local = ypproc_xfr_2_svc;
186 break;
187
188 case YPPROC_CLEAR:
189 xdr_argument = xdr_void;
190 xdr_result = xdr_void;
191 local = ypproc_clear_2_svc;
192 break;
193
194 case YPPROC_ALL:
195 xdr_argument = xdr_ypreq_nokey;
196 xdr_result = xdr_ypresp_all;
197 local = ypproc_all_2_svc;
198 break;
199
200 case YPPROC_MASTER:
201 xdr_argument = xdr_ypreq_nokey;
202 xdr_result = xdr_ypresp_master;
203 local = ypproc_master_2_svc;
204 break;
205
206 case YPPROC_ORDER:
207 xdr_argument = xdr_ypreq_nokey;
208 xdr_result = xdr_ypresp_order;
209 local = ypproc_order_2_svc;
210 break;
211
212 case YPPROC_MAPLIST:
213 xdr_argument = xdr_ypdomain_wrap_string;
214 xdr_result = xdr_ypresp_maplist;
215 local = ypproc_maplist_2_svc;
216 break;
217
218 default:
219 svcerr_noproc(transp);
220 _rpcsvcdirty = 0;
221 return;
222 }
223 (void) memset((char *)&argument, 0, sizeof (argument));
224 if (!svc_getargs(transp, xdr_argument, (caddr_t) &argument)) {
225 svcerr_decode(transp);
226 _rpcsvcdirty = 0;
227 return;
228 }
229 result = (*local)(&argument, rqstp);
230 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
231 svcerr_systemerr(transp);
232 }
233 if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) {
234 _msgout("unable to free arguments");
235 exit(1);
236 }
237 _rpcsvcdirty = 0;
238 return;
239 }
240
241 /*
242 * limited NIS version 1 support: the null, domain, and domain_nonack
243 * request/reply format is identical between v1 and v2. SunOS4's ypbind
244 * makes v1 domain_nonack calls.
245 */
246 static void
247 ypprog_1(struct svc_req *rqstp, register SVCXPRT *transp)
248 {
249 switch (rqstp->rq_proc) {
250 case YPPROC_NULL:
251 case YPPROC_DOMAIN:
252 case YPPROC_DOMAIN_NONACK:
253 ypprog_2(rqstp, transp);
254 return;
255
256 default:
257 svcerr_noproc(transp);
258 _rpcsvcdirty = 0;
259 return;
260 }
261 }
262
263 int
264 main(argc, argv)
265 int argc;
266 char **argv;
267 {
268 register SVCXPRT *transp;
269 int sock, proto;
270 struct sockaddr_in saddr;
271 int asize = sizeof(saddr);
272 int xflag = 0;
273 int ch;
274
275 while ((ch = getopt(argc, argv, "a:dx")) != -1) {
276 switch (ch) {
277 case 'a':
278 aclfile = optarg;
279 break;
280
281 case 'd':
282 usedns = 1;
283 break;
284
285 case 'x':
286 xflag = 1;
287 break;
288
289 default:
290 usage();
291 }
292 }
293
294 /* This program must be run by root. */
295 if (geteuid() != 0)
296 errx(1, "must run as root");
297
298 /* Deal with the acl file. */
299 acl_parse(aclfile);
300
301 if (xflag)
302 exit(1);
303
304 #ifndef RPC_SVC_FG
305 if (daemon(0, 0))
306 err(1, "can't detach");
307 openlog("ypserv", LOG_PID, LOG_DAEMON);
308 #endif
309
310 {
311 FILE *pidfile = fopen(YPSERV_PID_PATH, "w");
312
313 if (pidfile != NULL) {
314 fprintf(pidfile, "%d\n", getpid());
315 fclose(pidfile);
316 } else
317 err(1, "can't write PID file");
318 }
319
320 sock = RPC_ANYSOCK;
321 (void) pmap_unset(YPPROG, YPVERS);
322 (void) pmap_unset(YPPROG, YPVERS_ORIG);
323
324 ypopenlog(); /* open log file */
325 ypdb_init(); /* init db stuff */
326
327 (void)signal(SIGCHLD, sig_child);
328 (void)signal(SIGHUP, sig_hup);
329
330 if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) {
331 transp = svcudp_create(sock);
332 if (transp == NULL) {
333 _msgout("cannot create udp service.");
334 exit(1);
335 }
336 if (!_rpcpmstart)
337 proto = IPPROTO_UDP;
338 if (!svc_register(transp, YPPROG, YPVERS_ORIG, ypprog_1, proto)) {
339 _msgout("unable to register (YPPROG, YPVERS_ORIG, udp).");
340 exit(1);
341 }
342 if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) {
343 _msgout("unable to register (YPPROG, YPVERS, udp).");
344 exit(1);
345 }
346 }
347
348 if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) {
349 if (_rpcpmstart)
350 transp = svcfd_create(sock, 0, 0);
351 else
352 transp = svctcp_create(sock, 0, 0);
353 if (transp == NULL) {
354 _msgout("cannot create tcp service.");
355 exit(1);
356 }
357 if (!_rpcpmstart)
358 proto = IPPROTO_TCP;
359 if (!svc_register(transp, YPPROG, YPVERS_ORIG, ypprog_1, proto)) {
360 _msgout("unable to register (YPPROG, YPVERS_ORIG, tcp).");
361 exit(1);
362 }
363 if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) {
364 _msgout("unable to register (YPPROG, YPVERS, tcp).");
365 exit(1);
366 }
367 }
368
369 if (transp == (SVCXPRT *)NULL) {
370 _msgout("could not create a handle");
371 exit(1);
372 }
373 if (_rpcpmstart) {
374 (void) signal(SIGALRM, (SIG_PF) closedown);
375 (void) alarm(_RPCSVC_CLOSEDOWN);
376 }
377 svc_run();
378 _msgout("svc_run returned");
379 exit(1);
380 /* NOTREACHED */
381 }
382
383 void
384 sig_child()
385 {
386
387 while (wait3((int *)NULL, WNOHANG, (struct rusage *)NULL) > 0);
388 }
389
390 void
391 sig_hup()
392 {
393
394 acl_reset();
395 yplog("sig_hup: reread %s", aclfile ? aclfile : YP_SECURENET_FILE);
396 acl_parse(aclfile);
397 }
398
399 void
400 usage()
401 {
402
403 fprintf(stderr, "usage: %s [-a aclfile] [-d] [-x]\n", __progname);
404 exit(1);
405 }
406