ypserv.c revision 1.7 1 /* $NetBSD: ypserv.c,v 1.7 1997/10/15 05:01:24 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/cdefs.h>
35 #ifndef lint
36 __RCSID("$NetBSD: ypserv.c,v 1.7 1997/10/15 05:01:24 lukem Exp $");
37 #endif
38
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/wait.h>
42
43 #include <netinet/in.h>
44
45 #include <err.h>
46 #include <netdb.h>
47 #include <signal.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <syslog.h>
52 #include <unistd.h>
53
54 #include <rpc/rpc.h>
55 #include <rpc/xdr.h>
56 #include <rpc/pmap_clnt.h>
57
58 #include <rpcsvc/yp_prot.h>
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
83 int main __P((int, char *[]));
84 void usage __P((void));
85
86 void sighandler __P((int));
87
88 static void closedown __P((void));
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, 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, 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 SVCXPRT *transp;
269 int sock, proto;
270 struct sigaction sa;
271 int xflag = 0;
272 int ch;
273
274 transp = NULL; /* XXX gcc -Wuninitialized */
275 proto = 0; /* XXX gcc -Wuninitialized */
276
277 while ((ch = getopt(argc, argv, "a:dx")) != -1) {
278 switch (ch) {
279 case 'a':
280 aclfile = optarg;
281 break;
282
283 case 'd':
284 usedns = 1;
285 break;
286
287 case 'x':
288 xflag = 1;
289 break;
290
291 default:
292 usage();
293 }
294 }
295
296 /* This program must be run by root. */
297 if (geteuid() != 0)
298 errx(1, "must run as root");
299
300 /* Deal with the acl file. */
301 acl_parse(aclfile);
302
303 if (xflag)
304 exit(1);
305
306 #ifndef RPC_SVC_FG
307 if (daemon(0, 0))
308 err(1, "can't detach");
309 openlog("ypserv", LOG_PID, LOG_DAEMON);
310 #endif
311
312 {
313 FILE *pidfile = fopen(YPSERV_PID_PATH, "w");
314
315 if (pidfile != NULL) {
316 fprintf(pidfile, "%d\n", getpid());
317 fclose(pidfile);
318 } else
319 err(1, "can't write PID file");
320 }
321
322 sock = RPC_ANYSOCK;
323 (void) pmap_unset(YPPROG, YPVERS);
324 (void) pmap_unset(YPPROG, YPVERS_ORIG);
325
326 ypopenlog(); /* open log file */
327 ypdb_init(); /* init db stuff */
328
329 sa.sa_handler = sighandler;
330 sa.sa_flags = 0;
331 if (sigemptyset(&sa.sa_mask))
332 err(1, "sigemptyset");
333 if (sigaction(SIGCHLD, &sa, NULL) || sigaction(SIGHUP, &sa, NULL))
334 err(1, "sigaction");
335
336 if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) {
337 transp = svcudp_create(sock);
338 if (transp == NULL) {
339 _msgout("cannot create udp service.");
340 exit(1);
341 }
342 if (transp->xp_port >= IPPORT_RESERVED) {
343 _msgout("udp service not bound to a privileged port.");
344 exit(1);
345 }
346 if (!_rpcpmstart)
347 proto = IPPROTO_UDP;
348 if (!svc_register(transp, YPPROG, YPVERS_ORIG, ypprog_1,
349 proto)) {
350 _msgout(
351 "unable to register (YPPROG, YPVERS_ORIG, udp).");
352 exit(1);
353 }
354 if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) {
355 _msgout("unable to register (YPPROG, YPVERS, udp).");
356 exit(1);
357 }
358 }
359
360 if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) {
361 if (_rpcpmstart)
362 transp = svcfd_create(sock, 0, 0);
363 else
364 transp = svctcp_create(sock, 0, 0);
365 if (transp == NULL) {
366 _msgout("cannot create tcp service.");
367 exit(1);
368 }
369 if (transp->xp_port >= IPPORT_RESERVED) {
370 _msgout("tcp service not bound to a privileged port.");
371 exit(1);
372 }
373 if (!_rpcpmstart)
374 proto = IPPROTO_TCP;
375 if (!svc_register(transp, YPPROG, YPVERS_ORIG, ypprog_1,
376 proto)) {
377 _msgout(
378 "unable to register (YPPROG, YPVERS_ORIG, tcp).");
379 exit(1);
380 }
381 if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) {
382 _msgout("unable to register (YPPROG, YPVERS, tcp).");
383 exit(1);
384 }
385 }
386
387 if (transp == (SVCXPRT *)NULL) {
388 _msgout("could not create a handle");
389 exit(1);
390 }
391 if (_rpcpmstart) {
392 (void) signal(SIGALRM, (SIG_PF) closedown);
393 (void) alarm(_RPCSVC_CLOSEDOWN);
394 }
395 svc_run();
396 _msgout("svc_run returned");
397 exit(1);
398 /* NOTREACHED */
399 }
400
401 void
402 sighandler(sig)
403 int sig;
404 {
405
406 if (sig == SIGHUP) {
407 acl_reset();
408 yplog("reread %s", aclfile ? aclfile : YP_SECURENET_FILE);
409 acl_parse(aclfile);
410 return;
411 }
412
413 /* SIGCHLD */
414 while (wait3((int *)NULL, WNOHANG, (struct rusage *)NULL) > 0);
415 }
416
417 void
418 usage()
419 {
420
421 fprintf(stderr, "usage: %s [-a aclfile] [-d] [-x]\n", __progname);
422 exit(1);
423 }
424
425
426 /*
427 * _yp_invalid_map: check if given map name isn't legal.
428 * returns non-zero if invalid
429 *
430 * XXX: this probably should be in libc/yp/yplib.c
431 */
432 int
433 _yp_invalid_map(map)
434 const char *map;
435 {
436 if (map == NULL || *map == '\0')
437 return 1;
438
439 if (strlen(map) > YPMAXMAP)
440 return 1;
441
442 if (strchr(map, '/') != NULL)
443 return 1;
444
445 return 0;
446 }
447