ypserv.c revision 1.16 1 /* $NetBSD: ypserv.c,v 1.16 2002/07/06 00:18:48 wiz 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.16 2002/07/06 00:18:48 wiz Exp $");
37 #endif
38
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/wait.h>
42
43 #include <err.h>
44 #include <netdb.h>
45 #include <signal.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <syslog.h>
50 #include <unistd.h>
51 #include <util.h>
52
53 #include <rpc/rpc.h>
54 #include <rpc/xdr.h>
55 #include <rpc/pmap_clnt.h>
56
57 #include <rpcsvc/yp_prot.h>
58
59 #include "ypdef.h"
60 #include "ypserv.h"
61
62 #ifdef LIBWRAP
63 #include <tcpd.h>
64
65 int allow_severity = LOG_DAEMON | LOG_INFO;
66 int deny_severity = LOG_DAEMON | LOG_WARNING;
67
68 /* XXX For ypserv_proc.c -- NOT THREAD SAFE! (like any of this code is) */
69 const char *clientstr;
70 const char *svcname;
71 #endif /* LIBWRAP */
72
73 #define SIG_PF void(*)(int)
74
75 int usedns;
76 #ifdef DEBUG
77 int foreground = 1;
78 #else
79 int foreground;
80 #endif
81
82 #ifdef LIBWRAP
83 int lflag;
84 #endif
85
86 int main(int, char *[]);
87 void usage(void);
88
89 void sighandler(int);
90
91
92 static
93 void _msgout(int level, const char *msg)
94 {
95 if (foreground)
96 warnx("%s", msg);
97 else
98 syslog(level, "%s", msg);
99 }
100
101 static void
102 ypprog_2(struct svc_req *rqstp, SVCXPRT *transp)
103 {
104 union {
105 char * ypproc_domain_2_arg;
106 char * ypproc_domain_nonack_2_arg;
107 struct ypreq_key ypproc_match_2_arg;
108 struct ypreq_nokey ypproc_first_2_arg;
109 struct ypreq_key ypproc_next_2_arg;
110 struct ypreq_xfr ypproc_xfr_2_arg;
111 struct ypreq_nokey ypproc_all_2_arg;
112 struct ypreq_nokey ypproc_master_2_arg;
113 struct ypreq_nokey ypproc_order_2_arg;
114 char * ypproc_maplist_2_arg;
115 } argument;
116 char *result;
117 xdrproc_t xdr_argument, xdr_result;
118 void *(*local)(void *, struct svc_req *);
119 #ifdef LIBWRAP
120 struct request_info req;
121 struct sockaddr *caller;
122 #define SVCNAME(x) svcname = x
123 #else
124 #define SVCNAME(x) /* nothing */
125 #endif
126
127 #ifdef LIBWRAP
128 caller = svc_getrpccaller(transp)->buf;
129 request_init(&req, RQ_DAEMON, getprogname(), RQ_CLIENT_SIN, caller,
130 NULL);
131 sock_methods(&req);
132 #endif
133
134 switch (rqstp->rq_proc) {
135 case YPPROC_NULL:
136 xdr_argument = xdr_void;
137 xdr_result = xdr_void;
138 local = ypproc_null_2_svc;
139 SVCNAME("null_2");
140 break;
141
142 case YPPROC_DOMAIN:
143 xdr_argument = xdr_ypdomain_wrap_string;
144 xdr_result = xdr_bool;
145 local = ypproc_domain_2_svc;
146 SVCNAME("domain_2");
147 break;
148
149 case YPPROC_DOMAIN_NONACK:
150 xdr_argument = xdr_ypdomain_wrap_string;
151 xdr_result = xdr_bool;
152 local = ypproc_domain_nonack_2_svc;
153 SVCNAME("domain_nonack_2");
154 break;
155
156 case YPPROC_MATCH:
157 xdr_argument = xdr_ypreq_key;
158 xdr_result = xdr_ypresp_val;
159 local = ypproc_match_2_svc;
160 SVCNAME("match_2");
161 break;
162
163 case YPPROC_FIRST:
164 xdr_argument = xdr_ypreq_nokey;
165 xdr_result = xdr_ypresp_key_val;
166 local = ypproc_first_2_svc;
167 SVCNAME("first_2");
168 break;
169
170 case YPPROC_NEXT:
171 xdr_argument = xdr_ypreq_key;
172 xdr_result = xdr_ypresp_key_val;
173 local = ypproc_next_2_svc;
174 SVCNAME("next_2");
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 SVCNAME("xfer_2");
182 break;
183
184 case YPPROC_CLEAR:
185 xdr_argument = xdr_void;
186 xdr_result = xdr_void;
187 local = ypproc_clear_2_svc;
188 SVCNAME("clear_2");
189 break;
190
191 case YPPROC_ALL:
192 xdr_argument = xdr_ypreq_nokey;
193 xdr_result = xdr_ypresp_all;
194 local = ypproc_all_2_svc;
195 SVCNAME("all_2");
196 break;
197
198 case YPPROC_MASTER:
199 xdr_argument = xdr_ypreq_nokey;
200 xdr_result = xdr_ypresp_master;
201 local = ypproc_master_2_svc;
202 SVCNAME("master_2");
203 break;
204
205 case YPPROC_ORDER:
206 xdr_argument = xdr_ypreq_nokey;
207 xdr_result = xdr_ypresp_order;
208 local = ypproc_order_2_svc;
209 SVCNAME("order_2");
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 SVCNAME("maplist_2");
217 break;
218
219 default:
220 svcerr_noproc(transp);
221 return;
222 }
223
224 #ifdef LIBWRAP
225 clientstr = eval_client(&req);
226
227 if (hosts_access(&req) == 0) {
228 syslog(deny_severity,
229 "%s: refused request from %.500s", svcname, clientstr);
230 svcerr_auth(transp, AUTH_FAILED);
231 return;
232 }
233 #endif
234
235 (void) memset((char *)&argument, 0, sizeof (argument));
236 if (!svc_getargs(transp, xdr_argument, (caddr_t) &argument)) {
237 svcerr_decode(transp);
238 return;
239 }
240 result = (*local)(&argument, rqstp);
241 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
242 svcerr_systemerr(transp);
243 }
244 if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) {
245 _msgout(LOG_ERR, "unable to free arguments");
246 exit(1);
247 }
248 return;
249 }
250
251 /*
252 * limited NIS version 1 support: the null, domain, and domain_nonack
253 * request/reply format is identical between v1 and v2. SunOS4's ypbind
254 * makes v1 domain_nonack calls.
255 */
256 static void
257 ypprog_1(struct svc_req *rqstp, SVCXPRT *transp)
258 {
259 switch (rqstp->rq_proc) {
260 case YPPROC_NULL:
261 case YPPROC_DOMAIN:
262 case YPPROC_DOMAIN_NONACK:
263 ypprog_2(rqstp, transp);
264 return;
265
266 default:
267 svcerr_noproc(transp);
268 return;
269 }
270 }
271
272 int
273 main(argc, argv)
274 int argc;
275 char *argv[];
276 {
277 SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp;
278 struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf;
279 int udpsock, tcpsock, udp6sock, tcp6sock;
280 struct sigaction sa;
281 int ch, xcreated = 0, one = 1;
282
283 #ifdef LIBWRAP
284 #define GETOPTSTR "dfl"
285 #else
286 #define GETOPTSTR "df"
287 #endif
288
289 while ((ch = getopt(argc, argv, GETOPTSTR)) != -1) {
290 switch (ch) {
291 case 'd':
292 usedns = 1;
293 break;
294 case 'f':
295 foreground = 1;
296 break;
297
298 #ifdef LIBWRAP
299 case 'l':
300 lflag = 1;
301 break;
302 #endif
303 default:
304 usage();
305 }
306 }
307
308 #undef GETOPTSTR
309
310 /* This program must be run by root. */
311 if (geteuid() != 0)
312 errx(1, "must run as root");
313
314 if (foreground == 0 && daemon(0, 0))
315 err(1, "can't detach");
316
317 openlog("ypserv", LOG_PID, LOG_DAEMON);
318 syslog(LOG_INFO, "starting");
319 pidfile(NULL);
320
321 (void) rpcb_unset(YPPROG, YPVERS, NULL);
322 (void) rpcb_unset(YPPROG, YPVERS_ORIG, NULL);
323
324 udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
325 tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
326 udp6sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
327 tcp6sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
328
329 /*
330 * We're doing host-based access checks here, so don't allow
331 * v4-in-v6 to confuse things.
332 */
333 if (udp6sock != -1 && setsockopt(udp6sock, IPPROTO_IPV6,
334 IPV6_V6ONLY, &one, sizeof(one)) < 0) {
335 _msgout(LOG_ERR, "can't disable v4-in-v6 on UDP socket");
336 exit(1);
337 }
338 if (tcp6sock != -1 && setsockopt(tcp6sock, IPPROTO_IPV6,
339 IPV6_V6ONLY, &one, sizeof(one)) < 0) {
340 _msgout(LOG_ERR, "can't disable v4-in-v6 on TCP socket");
341 exit(1);
342 }
343
344 ypdb_init(); /* init db stuff */
345
346 sa.sa_handler = sighandler;
347 sa.sa_flags = 0;
348 if (sigemptyset(&sa.sa_mask)) {
349 _msgout(LOG_ERR, "sigemptyset: %m");
350 exit(1);
351 }
352 if (sigaction(SIGCHLD, &sa, NULL)) {
353 _msgout(LOG_ERR, "sigaction: %m");
354 exit(1);
355 }
356
357 udpconf = getnetconfigent("udp");
358 tcpconf = getnetconfigent("tcp");
359 udp6conf = getnetconfigent("udp6");
360 tcp6conf = getnetconfigent("tcp6");
361
362 if (udpsock != -1 && udpconf != NULL) {
363 if (bindresvport(udpsock, NULL) == 0) {
364 udptransp = svc_dg_create(udpsock, 0, 0);
365 if (udptransp != NULL) {
366 if (svc_reg(udptransp, YPPROG, YPVERS_ORIG,
367 ypprog_1, udpconf) == 0 ||
368 svc_reg(udptransp, YPPROG, YPVERS,
369 ypprog_2, udpconf) == 0)
370 _msgout(LOG_WARNING,
371 "unable to register UDP service");
372 else
373 xcreated++;
374 } else
375 _msgout(LOG_WARNING,
376 "unable to create UDP service");
377 } else
378 _msgout(LOG_ERR, "unable to bind reserved UDP port");
379 freenetconfigent(udpconf);
380 }
381
382 if (tcpsock != -1 && tcpconf != NULL) {
383 if (bindresvport(tcpsock, NULL) == 0) {
384 listen(tcpsock, SOMAXCONN);
385 tcptransp = svc_vc_create(tcpsock, 0, 0);
386 if (tcptransp != NULL) {
387 if (svc_reg(tcptransp, YPPROG, YPVERS_ORIG,
388 ypprog_1, tcpconf) == 0 ||
389 svc_reg(tcptransp, YPPROG, YPVERS,
390 ypprog_2, tcpconf) == 0)
391 _msgout(LOG_WARNING,
392 "unable to register TCP service");
393 else
394 xcreated++;
395 } else
396 _msgout(LOG_WARNING,
397 "unable to create TCP service");
398 } else
399 _msgout(LOG_ERR, "unable to bind reserved TCP port");
400 freenetconfigent(tcpconf);
401 }
402
403 if (udp6sock != -1 && udp6conf != NULL) {
404 if (bindresvport(udp6sock, NULL) == 0) {
405 udp6transp = svc_dg_create(udp6sock, 0, 0);
406 if (udp6transp != NULL) {
407 if (svc_reg(udp6transp, YPPROG, YPVERS_ORIG,
408 ypprog_1, udp6conf) == 0 ||
409 svc_reg(udp6transp, YPPROG, YPVERS,
410 ypprog_2, udp6conf) == 0)
411 _msgout(LOG_WARNING,
412 "unable to register UDP6 service");
413 else
414 xcreated++;
415 } else
416 _msgout(LOG_WARNING,
417 "unable to create UDP6 service");
418 } else
419 _msgout(LOG_ERR, "unable to bind reserved UDP6 port");
420 freenetconfigent(udp6conf);
421 }
422
423 if (tcp6sock != -1 && tcp6conf != NULL) {
424 if (bindresvport(tcp6sock, NULL) == 0) {
425 listen(tcp6sock, SOMAXCONN);
426 tcp6transp = svc_vc_create(tcp6sock, 0, 0);
427 if (tcp6transp != NULL) {
428 if (svc_reg(tcp6transp, YPPROG, YPVERS_ORIG,
429 ypprog_1, tcp6conf) == 0 ||
430 svc_reg(tcp6transp, YPPROG, YPVERS,
431 ypprog_2, tcp6conf) == 0)
432 _msgout(LOG_WARNING,
433 "unable to register TCP6 service");
434 else
435 xcreated++;
436 } else
437 _msgout(LOG_WARNING,
438 "unable to create TCP6 service");
439 } else
440 _msgout(LOG_ERR, "unable to bind reserved TCP6 port");
441 freenetconfigent(tcp6conf);
442 }
443
444 if (xcreated == 0) {
445 _msgout(LOG_ERR, "unable to create any services");
446 exit(1);
447 }
448
449 svc_run();
450 _msgout(LOG_ERR, "svc_run returned");
451 exit(1);
452 /* NOTREACHED */
453 }
454
455 void
456 sighandler(sig)
457 int sig;
458 {
459
460 /* SIGCHLD */
461 while (wait3((int *)NULL, WNOHANG, (struct rusage *)NULL) > 0);
462 }
463
464 void
465 usage()
466 {
467
468 #ifdef LIBWRAP
469 #define USAGESTR "usage: %s [-d] [-l]\n"
470 #else
471 #define USAGESTR "usage: %s [-d]\n"
472 #endif
473
474 fprintf(stderr, USAGESTR, getprogname());
475 exit(1);
476
477 #undef USAGESTR
478 }
479
480 /*
481 * _yp_invalid_map: check if given map name isn't legal.
482 * returns non-zero if invalid
483 *
484 * XXX: this probably should be in libc/yp/yplib.c
485 */
486 int
487 _yp_invalid_map(map)
488 const char *map;
489 {
490 if (map == NULL || *map == '\0')
491 return 1;
492
493 if (strlen(map) > YPMAXMAP)
494 return 1;
495
496 if (strchr(map, '/') != NULL)
497 return 1;
498
499 return 0;
500 }
501