]> git.saurik.com Git - apple/network_cmds.git/blob - ypbind.tproj/ypbind.c
61f7b8a2ce05a17c90541e2390015f678217c512
[apple/network_cmds.git] / ypbind.tproj / ypbind.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@fsa.ca>
27 * All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by Theo de Raadt.
40 * 4. The name of the author may not be used to endorse or promote
41 * products derived from this software without specific prior written
42 * permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
45 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
46 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
48 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56
57 #ifndef LINT
58 static char rcsid[] = "$Id: ypbind.c,v 1.1.1.1 1999/05/02 03:59:00 wsanchez Exp $";
59 #endif
60 #include <sys/cdefs.h>
61
62 #include <sys/param.h>
63 #include <sys/types.h>
64 #include <sys/ioctl.h>
65 #include <sys/signal.h>
66 #include <sys/socket.h>
67 #include <sys/file.h>
68 #include <sys/fcntl.h>
69 #include <sys/uio.h>
70 #include <syslog.h>
71 #include <sys/stat.h>
72 #include <limits.h>
73 #include <stdio.h>
74 #include <stdlib.h>
75 #include <stdarg.h>
76 #include <errno.h>
77 #include <ctype.h>
78 #include <dirent.h>
79 #include <netdb.h>
80 #include <string.h>
81 #include <err.h>
82 #include <rpc/rpc.h>
83 #include <rpc/xdr.h>
84 #include <net/if.h>
85 #include <arpa/inet.h>
86 #include <rpc/pmap_clnt.h>
87 #include <rpc/pmap_prot.h>
88 #include <rpc/pmap_rmt.h>
89 #include <unistd.h>
90 #include <rpcsvc/yp.h>
91 // #include <rpcsvc/yp_prot.h>
92 // #include <rpcsvc/ypclnt.h>
93
94 #define _PATH_YPBIND_LOCK "/var/run/ypbind.lock"
95 #define YPSERVERSSUFF ".ypservers"
96 #define BINDINGDIR "/var/yp/binding"
97
98 #ifndef O_SHLOCK
99 #define O_SHLOCK 0
100 #endif
101
102 #define BUFSIZE 1400
103
104 struct _dom_binding
105 {
106 struct _dom_binding *dom_pnext;
107 char dom_domain[YPMAXDOMAIN + 1];
108 struct sockaddr_in dom_server_addr;
109 unsigned short int dom_server_port;
110 int dom_socket;
111 CLIENT *dom_client;
112 long dom_vers;
113 time_t dom_check_t;
114 time_t dom_ask_t;
115 int dom_lockfd;
116 int dom_alive;
117 u_int32_t dom_xid;
118 };
119
120 static char *dname;
121
122 static struct _dom_binding *ypbindlist;
123 static int check;
124
125 typedef enum
126 {
127 YPBIND_DIRECT,
128 YPBIND_BROADCAST,
129 YPBIND_SETLOCAL,
130 YPBIND_SETALL
131 } ypbind_mode_t;
132
133 ypbind_mode_t ypbindmode;
134
135 /*
136 * If ypbindmode is YPBIND_SETLOCAL or YPBIND_SETALL, this indicates
137 * whether or not we've been "ypset". If we haven't, we behave like
138 * YPBIND_BROADCAST. If we have, we behave like YPBIND_DIRECT.
139 */
140 int been_ypset;
141
142 static int insecure;
143 static int rpcsock, pingsock;
144 static struct rmtcallargs rmtca;
145 static struct rmtcallres rmtcr;
146 static bool_t rmtcr_outval;
147 static u_long rmtcr_port;
148 static SVCXPRT *udptransp, *tcptransp;
149
150 int main __P((int, char *[]));
151
152 static void usage __P((void));
153 static struct _dom_binding *makebinding __P((const char *));
154 static int makelock __P((struct _dom_binding *));
155 static void removelock __P((struct _dom_binding *));
156 static void checkwork __P((void));
157 static int ping __P((struct _dom_binding *));
158 static int nag_servers __P((struct _dom_binding *));
159 static enum clnt_stat handle_replies __P((void));
160 static enum clnt_stat handle_ping __P((void));
161 static void rpc_received __P((char *, struct sockaddr_in *, int));
162 static struct _dom_binding *xid2ypdb __P((u_int32_t));
163 static u_int32_t unique_xid __P((struct _dom_binding *));
164 static int broadcast __P((char *, int));
165 static int direct __P((char *, int));
166 static int direct_set __P((char *, int, struct _dom_binding *));
167
168 #define DEBUG_NONE 0
169 #define DEBUG_STDERR 1
170 #define DEBUG_SYSLOG 2
171
172 static int debug;
173 static char *msg_str = NULL;
174
175 void
176 sys_openlog(int debug, char *str, int flags, int facility)
177 {
178 if (msg_str != NULL) free(msg_str);
179 msg_str = NULL;
180 if (str != NULL)
181 {
182 msg_str = malloc(strlen(str) + 1);
183 strcpy(msg_str, str);
184 }
185
186 if (debug & DEBUG_SYSLOG) openlog(msg_str, flags, facility);
187 }
188
189 void
190 sys_msg(int debug, int priority, char *message, ...)
191 {
192 va_list ap;
193
194 va_start(ap, message);
195
196 if (debug & DEBUG_SYSLOG) vsyslog(priority, message, ap);
197
198 if (debug & DEBUG_STDERR)
199 {
200 if (msg_str != NULL) fprintf(stderr, "%s: ", msg_str);
201 vfprintf(stderr, message, ap);
202 fprintf(stderr, "\n");
203 fflush(stderr);
204 }
205
206 va_end(ap);
207 }
208
209 static void
210 usage()
211 {
212 fprintf(stderr,
213 "Usage: ypbind [-broadcast] [-insecure] [-ypset] [-ypsetme] [-d]\n");
214 exit(1);
215 }
216
217 static struct _dom_binding *
218 makebinding(const char *dm)
219 {
220 struct _dom_binding *ypdb;
221
222 ypdb = (struct _dom_binding *)malloc(sizeof *ypdb);
223 memset(ypdb, 0, sizeof *ypdb);
224 strncpy(ypdb->dom_domain, dm, sizeof ypdb->dom_domain);
225 ypdb->dom_domain[sizeof(ypdb->dom_domain) - 1] = '\0';
226
227 return ypdb;
228 }
229
230 static int
231 makelock(struct _dom_binding *ypdb)
232 {
233 int fd;
234 char path[MAXPATHLEN];
235
236 snprintf(path, sizeof(path), "%s/%s.%ld", BINDINGDIR,
237 ypdb->dom_domain, ypdb->dom_vers);
238
239 fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644);
240 if (fd == -1)
241 {
242 mkdir(BINDINGDIR, 0755);
243 fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644);
244 if (fd == -1) return -1;
245 }
246
247 #if O_SHLOCK == 0
248 flock(fd, LOCK_SH);
249 #endif
250 return fd;
251 }
252
253 static void
254 removelock(struct _dom_binding *ypdb)
255 {
256 char path[MAXPATHLEN];
257
258 snprintf(path, sizeof(path), "%s/%s.%ld",
259 BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers);
260 unlink(path);
261 }
262
263 static void *
264 svc_ypbindproc_null_2(void *argp, SVCXPRT *transp)
265 {
266 static char res;
267
268 sys_msg(debug, LOG_DEBUG, "ypbindproc_null_2");
269
270 memset(&res, 0, sizeof(res));
271 return (void *)&res;
272 }
273
274 static void *
275 svc_ypbindproc_domain_2(void *argp, SVCXPRT *transp)
276 {
277 static struct ypbind_resp res;
278 struct _dom_binding *ypdb;
279 char *arg = *(char **) argp;
280 int count;
281
282 sys_msg(debug, LOG_DEBUG, "ypbindproc_domain_2 %s", arg);
283
284 memset(&res, 0, sizeof res);
285 res.ypbind_status = YPBIND_FAIL_VAL;
286
287 for (count = 0, ypdb = ypbindlist;
288 ypdb != NULL;
289 ypdb = ypdb->dom_pnext, count++)
290 {
291 /* prevent denial of service */
292 if (count > 100) return NULL;
293 if (!strcmp(ypdb->dom_domain, arg)) break;
294 }
295
296 if (ypdb == NULL)
297 {
298 ypdb = makebinding(arg);
299 ypdb->dom_vers = YPVERS;
300 ypdb->dom_alive = 0;
301 ypdb->dom_lockfd = -1;
302 removelock(ypdb);
303 ypdb->dom_xid = unique_xid(ypdb);
304 ypdb->dom_pnext = ypbindlist;
305 ypbindlist = ypdb;
306 check++;
307 sys_msg(debug, LOG_ERR, "unknown domain %s", arg);
308 return NULL;
309 }
310
311 if (ypdb->dom_alive == 0)
312 {
313 sys_msg(debug, LOG_ERR, "dead domain %s", arg);
314 return NULL;
315 }
316
317 #ifdef HEURISTIC
318 time(&now);
319 if (now < ypdb->dom_ask_t + 5)
320 {
321 /*
322 * Hmm. More than 2 requests in 5 seconds have indicated
323 * that my binding is possibly incorrect.
324 * Ok, do an immediate poll of the server.
325 */
326 if (ypdb->dom_check_t >= now)
327 {
328 /* don't flood it */
329 ypdb->dom_check_t = 0;
330 check++;
331 }
332 }
333 ypdb->dom_ask_t = now;
334 #endif
335
336 res.ypbind_status = YPBIND_SUCC_VAL;
337 bcopy(&ypdb->dom_server_addr.sin_addr.s_addr,
338 res.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr, 4);
339 bcopy(&ypdb->dom_server_port,
340 res.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port, 2);
341
342 sys_msg(debug, LOG_DEBUG, "domain %s at %s/%d", ypdb->dom_domain,
343 inet_ntoa(ypdb->dom_server_addr.sin_addr),
344 ntohs(ypdb->dom_server_addr.sin_port));
345 return &res;
346 }
347
348 static void *
349 svc_ypbindproc_setdom_2(void *argp, SVCXPRT *transp)
350 {
351 struct ypbind_setdom *sd = argp;
352 struct sockaddr_in *fromsin, bindsin;
353 static bool_t res;
354
355 memset(&bindsin, 0, sizeof bindsin);
356 bindsin.sin_family = AF_INET;
357 bindsin.sin_len = sizeof(bindsin);
358 bcopy(&sd->ypsetdom_binding.ypbind_binding_addr,
359 &bindsin.sin_addr.s_addr, 4);
360 bcopy(&sd->ypsetdom_binding.ypbind_binding_port,
361 &bindsin.sin_port, 2);
362 fromsin = svc_getcaller(transp);
363
364 memset(&res, 0, sizeof(res));
365
366 switch (ypbindmode)
367 {
368 case YPBIND_SETLOCAL:
369 if (fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
370 {
371 sys_msg(debug, LOG_ERR, "ypset from %s denied",
372 inet_ntoa(fromsin->sin_addr));
373 return NULL;
374 }
375
376 /* FALLTHROUGH */
377
378 case YPBIND_SETALL:
379 been_ypset = 1;
380 break;
381
382 case YPBIND_DIRECT:
383 case YPBIND_BROADCAST:
384 default:
385 sys_msg(debug, LOG_ERR, "ypset denied");
386 return NULL;
387 }
388
389 if (ntohs(fromsin->sin_port) >= IPPORT_RESERVED)
390 {
391 sys_msg(debug, LOG_ERR, "ypset from unpriviledged port denied");
392 return &res;
393 }
394
395 if (sd->ypsetdom_vers != YPVERS)
396 {
397 sys_msg(debug, LOG_ERR, "ypset with wrong version denied");
398 sys_msg(debug, LOG_DEBUG, "ypsetdom_vers = %lu YPVERS = %lu",
399 sd->ypsetdom_vers, YPVERS);
400 return &res;
401 }
402
403 rpc_received(sd->ypsetdom_domain, &bindsin, 1);
404
405 sys_msg(debug, LOG_DEBUG, "ypset to %s succeeded",
406 inet_ntoa(bindsin.sin_addr));
407 res = 1;
408 return &res;
409 }
410
411 static void
412 ypbindprog_2(struct svc_req *rqstp, register SVCXPRT *transp)
413 {
414 union
415 {
416 char ypbindproc_domain_2_arg[YPMAXDOMAIN + 1];
417 struct ypbind_setdom ypbindproc_setdom_2_arg;
418 } argument;
419 struct authunix_parms *creds;
420 char *result;
421 xdrproc_t xdr_argument, xdr_result;
422 void *(*local) __P((void *, SVCXPRT *));
423
424 switch (rqstp->rq_proc)
425 {
426 case YPBINDPROC_NULL:
427 xdr_argument = xdr_void;
428 xdr_result = xdr_void;
429 local = svc_ypbindproc_null_2;
430 break;
431
432 case YPBINDPROC_DOMAIN:
433 xdr_argument = xdr_domainname;
434 xdr_result = xdr_ypbind_resp;
435 local = svc_ypbindproc_domain_2;
436 break;
437
438 case YPBINDPROC_SETDOM:
439 switch (rqstp->rq_cred.oa_flavor)
440 {
441 case AUTH_UNIX:
442 creds = (struct authunix_parms *)rqstp->rq_clntcred;
443 if (creds->aup_uid != 0)
444 {
445 svcerr_auth(transp, AUTH_BADCRED);
446 return;
447 }
448 break;
449
450 default:
451 svcerr_auth(transp, AUTH_TOOWEAK);
452 return;
453 }
454
455 xdr_argument = xdr_ypbind_setdom;
456 xdr_result = xdr_void;
457 local = svc_ypbindproc_setdom_2;
458 break;
459
460 default:
461 svcerr_noproc(transp);
462 return;
463 }
464
465 memset(&argument, 0, sizeof(argument));
466 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument))
467 {
468 svcerr_decode(transp);
469 return;
470 }
471
472 result = (*local)(&argument, transp);
473 if (result != NULL && !svc_sendreply(transp, xdr_result, result))
474 {
475 svcerr_systemerr(transp);
476 }
477
478 return;
479 }
480
481 int
482 main(int argc, char *argv[])
483 {
484 struct timeval tv;
485 fd_set fdsr;
486 int width, lockfd;
487 int evil = 0, one, i;
488 char pathname[MAXPATHLEN];
489 struct stat st;
490
491 yp_get_default_domain(&dname);
492 if (dname[0] == '\0')
493 {
494 fprintf(stderr, "Domainname not set. Aborting.\n");
495 exit(1);
496 }
497
498 debug = DEBUG_SYSLOG;
499 ypbindmode = YPBIND_DIRECT;
500 for (i = 1; i < argc; i++)
501 {
502 if (!strcmp(argv[i], "-insecure"))
503 insecure = 1;
504
505 else if (!strcmp(argv[i], "-ypset"))
506 ypbindmode = YPBIND_SETALL;
507
508 else if (!strcmp(argv[i], "-ypsetme"))
509 ypbindmode = YPBIND_SETLOCAL;
510
511 else if (!strcmp(argv[i], "-broadcast"))
512 ypbindmode = YPBIND_BROADCAST;
513
514 else if (!strcmp(argv[i], "-d"))
515 debug = DEBUG_STDERR;
516
517 else
518 usage();
519 }
520
521 sys_openlog(debug, "ypbind", LOG_NDELAY | LOG_PID, LOG_DAEMON);
522
523 /*
524 * Per traditional ypbind(8) semantics, if a ypservers
525 * file does not exist, we default to broadcast mode.
526 * If the file does exist, we default to direct mode.
527 * Note that we can still override direct mode by passing
528 * the -broadcast flag.
529 */
530 snprintf(pathname, sizeof(pathname), "%s/%s%s",
531 BINDINGDIR, dname, YPSERVERSSUFF);
532
533 if ((ypbindmode == YPBIND_DIRECT) && (stat(pathname, &st) < 0))
534 {
535 sys_msg(debug, LOG_DEBUG, "%s does not exist, defaulting to broadcast.",
536 pathname);
537 ypbindmode = YPBIND_BROADCAST;
538 }
539
540 /* blow away everything in BINDINGDIR */
541
542 lockfd = open(_PATH_YPBIND_LOCK, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644);
543 if (lockfd == -1)
544 {
545 sys_msg(debug, LOG_ERR, "Cannot create %s", _PATH_YPBIND_LOCK);
546 exit(1);
547 }
548
549 #if O_SHLOCK == 0
550 flock(lockfd, LOCK_SH);
551 #endif
552
553 pmap_unset(YPBINDPROG, YPBINDVERS);
554
555 udptransp = svcudp_create(RPC_ANYSOCK);
556 if (udptransp == NULL)
557 {
558 sys_msg(debug, LOG_ERR, "Cannot create udp service.");
559 exit(1);
560 }
561
562 if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2,
563 IPPROTO_UDP))
564 {
565 sys_msg(debug, LOG_ERR,
566 "Unable to register (YPBINDPROG, YPBINDVERS, udp).");
567 exit(1);
568 }
569
570 tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0);
571 if (tcptransp == NULL)
572 {
573 sys_msg(debug, LOG_ERR, "Cannot create tcp service.");
574 exit(1);
575 }
576
577 if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2,
578 IPPROTO_TCP))
579 {
580 sys_msg(debug, LOG_ERR,
581 "Unable to register (YPBINDPROG, YPBINDVERS, tcp).");
582 exit(1);
583 }
584
585 /* XXX use SOCK_STREAM for direct queries? */
586 rpcsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
587 if (rpcsock == -1)
588 {
589 sys_msg(debug, LOG_ERR, "rpc socket() failed.");
590 exit(1);
591 }
592
593 pingsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
594 if (pingsock == -1)
595 {
596 sys_msg(debug, LOG_ERR, "ping socket() failed.");
597 exit(1);
598 }
599
600 fcntl(rpcsock, F_SETFL, fcntl(rpcsock, F_GETFL, 0) | FNDELAY);
601 fcntl(pingsock, F_SETFL, fcntl(pingsock, F_GETFL, 0) | FNDELAY);
602
603 one = 1;
604 setsockopt(rpcsock, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one));
605 rmtca.prog = YPPROG;
606 rmtca.vers = YPVERS;
607 rmtca.proc = YPPROC_DOMAIN_NONACK;
608 rmtca.xdr_args = NULL; /* set at call time */
609 rmtca.args_ptr = NULL; /* set at call time */
610 rmtcr.port_ptr = &rmtcr_port;
611 rmtcr.xdr_results = xdr_bool;
612 rmtcr.results_ptr = (caddr_t)&rmtcr_outval;
613
614 /* build initial domain binding, make it "unsuccessful" */
615 ypbindlist = makebinding(dname);
616 ypbindlist->dom_vers = YPVERS;
617 ypbindlist->dom_alive = 0;
618 ypbindlist->dom_lockfd = -1;
619 removelock(ypbindlist);
620
621 checkwork();
622
623 // width = svc_maxfd;
624 width = FD_SETSIZE;
625 width = 32;
626 if (rpcsock > width)
627 width = rpcsock;
628 if (pingsock > width)
629 width = pingsock;
630 width++;
631
632 for (;;)
633 {
634 fdsr = svc_fdset;
635 FD_SET(rpcsock, &fdsr);
636 FD_SET(pingsock, &fdsr);
637 tv.tv_sec = 1;
638 tv.tv_usec = 0;
639
640 switch (select(width, &fdsr, NULL, NULL, &tv))
641 {
642 case 0:
643 checkwork();
644 break;
645
646 case -1:
647 sys_msg(debug, LOG_WARNING, "select: %s", strerror(errno));
648 break;
649
650 default:
651 if (FD_ISSET(rpcsock, &fdsr)) handle_replies();
652 if (FD_ISSET(pingsock, &fdsr)) handle_ping();
653 svc_getreqset(&fdsr);
654 if (check) checkwork();
655 break;
656 }
657
658 if ((evil == 0) && (ypbindlist->dom_alive != 0))
659 {
660 evil = 1;
661 if (debug == DEBUG_SYSLOG) daemon(0, 0);
662 }
663 }
664 }
665
666 /*
667 * State transition is done like this:
668 *
669 * STATE EVENT ACTION NEWSTATE TIMEOUT
670 * no binding timeout broadcast no binding 5 sec
671 * no binding answer -- binding 60 sec
672 * binding timeout ping server checking 5 sec
673 * checking timeout ping server + broadcast checking 5 sec
674 * checking answer -- binding 60 sec
675 */
676 void
677 checkwork()
678 {
679 struct _dom_binding *ypdb;
680 time_t t;
681
682 check = 0;
683
684 time(&t);
685 for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext)
686 {
687 if (ypdb->dom_check_t < t)
688 {
689 if (ypdb->dom_alive == 1) ping(ypdb);
690 else nag_servers(ypdb);
691 time(&t);
692 ypdb->dom_check_t = t + 5;
693 }
694 }
695 }
696
697 int
698 ping(struct _dom_binding *ypdb)
699 {
700 char *dom = ypdb->dom_domain;
701 struct rpc_msg msg;
702 char buf[BUFSIZE];
703 enum clnt_stat st;
704 int outlen;
705 AUTH *rpcua;
706 XDR xdr;
707
708 memset(&xdr, 0, sizeof xdr);
709 memset(&msg, 0, sizeof msg);
710
711 rpcua = authunix_create_default();
712 if (rpcua == NULL)
713 {
714 sys_msg(debug, LOG_ERR, "ping: cannot get unix auth");
715 return RPC_SYSTEMERROR;
716 }
717
718 msg.rm_direction = CALL;
719 msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
720 msg.rm_call.cb_prog = YPPROG;
721 msg.rm_call.cb_vers = YPVERS;
722 msg.rm_call.cb_proc = YPPROC_DOMAIN_NONACK;
723 msg.rm_call.cb_cred = rpcua->ah_cred;
724 msg.rm_call.cb_verf = rpcua->ah_verf;
725
726 msg.rm_xid = ypdb->dom_xid;
727 xdrmem_create(&xdr, buf, sizeof buf, XDR_ENCODE);
728 if (!xdr_callmsg(&xdr, &msg))
729 {
730 st = RPC_CANTENCODEARGS;
731 AUTH_DESTROY(rpcua);
732 return st;
733 }
734
735 if (!xdr_domainname(&xdr, (void *)&dom))
736 {
737 st = RPC_CANTENCODEARGS;
738 AUTH_DESTROY(rpcua);
739 return st;
740 }
741
742 outlen = (int)xdr_getpos(&xdr);
743 xdr_destroy(&xdr);
744 if (outlen < 1)
745 {
746 st = RPC_CANTENCODEARGS;
747 AUTH_DESTROY(rpcua);
748 return st;
749 }
750
751 AUTH_DESTROY(rpcua);
752
753 ypdb->dom_alive = 2;
754 if (sendto(pingsock, buf, outlen, 0,
755 (struct sockaddr *)&ypdb->dom_server_addr,
756 sizeof ypdb->dom_server_addr) == -1)
757 sys_msg(debug, LOG_WARNING, "ping: sendto");
758 return 0;
759
760 }
761
762 static int
763 nag_servers(struct _dom_binding *ypdb)
764 {
765 char *dom = ypdb->dom_domain;
766 struct rpc_msg msg;
767 char buf[BUFSIZE];
768 enum clnt_stat st;
769 int outlen;
770 AUTH *rpcua;
771 XDR xdr;
772
773 rmtca.xdr_args = xdr_domainname;
774 rmtca.args_ptr = (char *)&dom;
775
776 memset(&xdr, 0, sizeof xdr);
777 memset(&msg, 0, sizeof msg);
778
779 rpcua = authunix_create_default();
780 if (rpcua == NULL)
781 {
782 sys_msg(debug, LOG_ERR, "ping: cannot get unix auth");
783 return RPC_SYSTEMERROR;
784 }
785
786 msg.rm_direction = CALL;
787 msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
788 msg.rm_call.cb_prog = PMAPPROG;
789 msg.rm_call.cb_vers = PMAPVERS;
790 msg.rm_call.cb_proc = PMAPPROC_CALLIT;
791 msg.rm_call.cb_cred = rpcua->ah_cred;
792 msg.rm_call.cb_verf = rpcua->ah_verf;
793
794 msg.rm_xid = ypdb->dom_xid;
795 xdrmem_create(&xdr, buf, sizeof buf, XDR_ENCODE);
796 if (!xdr_callmsg(&xdr, &msg))
797 {
798 st = RPC_CANTENCODEARGS;
799 AUTH_DESTROY(rpcua);
800 return st;
801 }
802
803 if (!xdr_rmtcall_args(&xdr, &rmtca))
804 {
805 st = RPC_CANTENCODEARGS;
806 AUTH_DESTROY(rpcua);
807 return st;
808 }
809
810 outlen = (int)xdr_getpos(&xdr);
811 xdr_destroy(&xdr);
812 if (outlen < 1)
813 {
814 st = RPC_CANTENCODEARGS;
815 AUTH_DESTROY(rpcua);
816 return st;
817 }
818
819 AUTH_DESTROY(rpcua);
820
821 if (ypdb->dom_lockfd != -1)
822 {
823 close(ypdb->dom_lockfd);
824 ypdb->dom_lockfd = -1;
825 removelock(ypdb);
826 }
827
828 if (ypdb->dom_alive == 2)
829 {
830 /*
831 * This resolves the following situation:
832 * ypserver on other subnet was once bound,
833 * but rebooted and is now using a different port
834 */
835 struct sockaddr_in bindsin;
836
837 memset(&bindsin, 0, sizeof bindsin);
838 bindsin.sin_family = AF_INET;
839 bindsin.sin_len = sizeof(bindsin);
840 bindsin.sin_port = htons(PMAPPORT);
841 bindsin.sin_addr = ypdb->dom_server_addr.sin_addr;
842
843 if (sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bindsin,
844 sizeof bindsin) == -1)
845 sys_msg(debug, LOG_WARNING, "broadcast: sendto");
846 }
847
848 switch (ypbindmode)
849 {
850 case YPBIND_SETALL:
851 case YPBIND_SETLOCAL:
852 if (been_ypset) return direct_set(buf, outlen, ypdb);
853 /* FALLTHROUGH */
854
855 case YPBIND_BROADCAST:
856 return broadcast(buf, outlen);
857
858 case YPBIND_DIRECT:
859 return direct(buf, outlen);
860 }
861
862 return -1;
863 }
864
865 static int
866 broadcast(char *buf, int outlen)
867 {
868 struct ifconf ifc;
869 struct ifreq *ifr;
870 int offset, addrlen;
871 struct in_addr in;
872 int sock;
873 char inbuf[8192];
874 struct sockaddr_in bindsin;
875
876 /* find all networks and send the RPC packet out them all */
877 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
878 if (sock == -1)
879 {
880 sys_msg(debug, LOG_WARNING, "broadcast: socket: %s", strerror(errno));
881 return -1;
882 }
883
884 memset(&bindsin, 0, sizeof bindsin);
885 bindsin.sin_family = AF_INET;
886 bindsin.sin_len = sizeof(bindsin);
887 bindsin.sin_port = htons(PMAPPORT);
888
889 ifc.ifc_len = sizeof inbuf;
890 ifc.ifc_buf = inbuf;
891 if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
892 {
893 close(sock);
894 sys_msg(debug, LOG_WARNING, "broadcast: ioctl(SIOCGIFCONF): %s",
895 strerror(errno));
896 return -1;
897 }
898
899 addrlen = sizeof(struct ifreq) - IFNAMSIZ;
900 offset = 0;
901
902 while (offset <= ifc.ifc_len)
903 {
904 ifr = (struct ifreq *)(ifc.ifc_buf + offset);
905 offset += IFNAMSIZ;
906 if (ifr->ifr_addr.sa_len > addrlen) offset += ifr->ifr_addr.sa_len;
907 else offset += addrlen;
908
909 if (ifr->ifr_addr.sa_family != AF_INET) continue;
910 if (ioctl(sock, SIOCGIFFLAGS, ifr) < 0) continue;
911 if ((ifr->ifr_flags & IFF_UP) == 0) continue;
912
913 if (ifr->ifr_flags & IFF_BROADCAST)
914 {
915 if (ioctl(sock, SIOCGIFBRDADDR, ifr) < 0)
916 {
917 sys_msg(debug, LOG_WARNING,
918 "broadcast: ioctl(SIOCGIFBRDADDR): %s", strerror(errno));
919 continue;
920 }
921 }
922 else if (ifr->ifr_flags & IFF_LOOPBACK)
923 {
924 if (ioctl(sock, SIOCGIFADDR, ifr) < 0)
925 {
926 sys_msg(debug, LOG_WARNING,
927 "broadcast: ioctl(SIOCGIFADDR): %s", strerror(errno));
928 continue;
929 }
930 }
931 else continue;
932
933 in = ((struct sockaddr_in *)&(ifr->ifr_addr))->sin_addr;
934 bindsin.sin_addr = in;
935 if (sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bindsin,
936 sizeof bindsin) == -1)
937 sys_msg(debug, LOG_WARNING, "broadcast: sendto: %s",
938 strerror(errno));
939 }
940
941 close(sock);
942 return 0;
943 }
944
945 static int
946 direct(char *buf, int outlen)
947 {
948 static FILE *df;
949 static char ypservers_path[MAXPATHLEN];
950 char line[_POSIX2_LINE_MAX];
951 char *p;
952 struct hostent *hp;
953 struct sockaddr_in bindsin;
954 int i, count = 0;
955
956 if (df) rewind(df);
957 else {
958 snprintf(ypservers_path, sizeof(ypservers_path),
959 "%s/%s%s", BINDINGDIR, dname, YPSERVERSSUFF);
960 df = fopen(ypservers_path, "r");
961 if (df == NULL)
962 {
963 sys_msg(debug, LOG_ALERT, "Missing file %s, aborting.",
964 ypservers_path);
965 exit(1);
966 }
967 }
968
969 memset(&bindsin, 0, sizeof bindsin);
970 bindsin.sin_family = AF_INET;
971 bindsin.sin_len = sizeof(bindsin);
972 bindsin.sin_port = htons(PMAPPORT);
973
974 while(fgets(line, sizeof(line), df) != NULL)
975 {
976 /* skip lines that are too big */
977 p = strchr(line, '\n');
978 if (p == NULL)
979 {
980 int c;
981
982 while ((c = getc(df)) != '\n' && c != EOF);
983 continue;
984 }
985
986 *p = '\0';
987 p = line;
988 while (isspace(*p)) p++;
989 if (*p == '#') continue;
990 hp = gethostbyname(p);
991 if (hp == NULL)
992 {
993 sys_msg(debug, LOG_ERR, "Can't find host: %s", p);
994 continue;
995 }
996
997 /* step through all addresses in case first is unavailable */
998 for (i = 0; hp->h_addr_list[i]; i++)
999 {
1000 memmove(&bindsin.sin_addr, hp->h_addr_list[0],
1001 hp->h_length);
1002 if (sendto(rpcsock, buf, outlen, 0,
1003 (struct sockaddr *)&bindsin, sizeof bindsin) < 0)
1004 {
1005 sys_msg(debug, LOG_WARNING, "direct: sendto: %s",
1006 strerror(errno));
1007 continue;
1008 }
1009 else count++;
1010 }
1011 }
1012
1013 if (count == 0)
1014 {
1015 sys_msg(debug, LOG_ALERT,
1016 "Can't contact any servers listed in %s. Aborting", ypservers_path);
1017 exit(1);
1018 }
1019
1020 return 0;
1021 }
1022
1023 static int
1024 direct_set(char *buf, int outlen, struct _dom_binding *ypdb)
1025 {
1026 struct sockaddr_in bindsin;
1027 char path[MAXPATHLEN];
1028 struct iovec iov[2];
1029 struct ypbind_resp ybr;
1030 SVCXPRT dummy_svc;
1031 int fd, bytes;
1032
1033 /*
1034 * Gack, we lose if binding file went away. We reset
1035 * "been_set" if this happens, otherwise we'll never
1036 * bind again.
1037 */
1038 snprintf(path, sizeof(path), "%s/%s.%ld", BINDINGDIR,
1039 ypdb->dom_domain, ypdb->dom_vers);
1040
1041 if ((fd = open(path, O_SHLOCK|O_RDONLY, 0644)) == -1)
1042 {
1043 sys_msg(debug, LOG_WARNING, "Can't open file %s", path);
1044 been_ypset = 0;
1045 return -1;
1046 }
1047
1048 #if O_SHLOCK == 0
1049 flock(fd, LOCK_SH);
1050 #endif
1051
1052 /* Read the binding file... */
1053 iov[0].iov_base = (caddr_t)&(dummy_svc.xp_port);
1054 iov[0].iov_len = sizeof(dummy_svc.xp_port);
1055 iov[1].iov_base = (caddr_t)&ybr;
1056 iov[1].iov_len = sizeof(ybr);
1057 bytes = readv(fd, iov, 2);
1058 close(fd);
1059
1060 if (bytes != (iov[0].iov_len + iov[1].iov_len))
1061 {
1062 /* Binding file corrupt? */
1063 sys_msg(debug, LOG_WARNING, "Can't parse file %s", path);
1064 been_ypset = 0;
1065 return -1;
1066 }
1067
1068 bcopy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
1069 &bindsin.sin_addr, 4);
1070
1071 if (sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bindsin,
1072 sizeof(bindsin)) < 0)
1073 {
1074 sys_msg(debug, LOG_WARNING, "direct_set: sendto: %s", strerror(errno));
1075 return -1;
1076 }
1077
1078 return 0;
1079 }
1080
1081 static enum clnt_stat
1082 handle_replies()
1083 {
1084 char buf[BUFSIZE];
1085 int fromlen, inlen;
1086 struct _dom_binding *ypdb;
1087 struct sockaddr_in raddr;
1088 struct rpc_msg msg;
1089 XDR xdr;
1090
1091 recv_again:
1092 memset(&xdr, 0, sizeof(xdr));
1093 memset(&msg, 0, sizeof(msg));
1094 msg.acpted_rply.ar_verf = _null_auth;
1095 msg.acpted_rply.ar_results.where = (caddr_t)&rmtcr;
1096 msg.acpted_rply.ar_results.proc = xdr_rmtcallres;
1097
1098 try_again:
1099 fromlen = sizeof (struct sockaddr);
1100 inlen = recvfrom(rpcsock, buf, sizeof buf, 0,
1101 (struct sockaddr *)&raddr, &fromlen);
1102 if (inlen < 0)
1103 {
1104 if (errno == EINTR) goto try_again;
1105 return RPC_CANTRECV;
1106 }
1107
1108 if (inlen < sizeof(u_int32_t)) goto recv_again;
1109
1110 /*
1111 * see if reply transaction id matches sent id.
1112 * If so, decode the results.
1113 */
1114 xdrmem_create(&xdr, buf, (u_int)inlen, XDR_DECODE);
1115 if (xdr_replymsg(&xdr, &msg))
1116 {
1117 if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
1118 (msg.acpted_rply.ar_stat == SUCCESS)) {
1119 raddr.sin_port = htons((u_short)rmtcr_port);
1120 ypdb = xid2ypdb(msg.rm_xid);
1121 if (ypdb != NULL) rpc_received(ypdb->dom_domain, &raddr, 0);
1122 }
1123 }
1124
1125 xdr.x_op = XDR_FREE;
1126 msg.acpted_rply.ar_results.proc = xdr_void;
1127 xdr_destroy(&xdr);
1128
1129 return RPC_SUCCESS;
1130 }
1131
1132 static enum clnt_stat
1133 handle_ping()
1134 {
1135 char buf[BUFSIZE];
1136 int fromlen, inlen;
1137 struct _dom_binding *ypdb;
1138 struct sockaddr_in raddr;
1139 struct rpc_msg msg;
1140 XDR xdr;
1141 bool_t res;
1142
1143 recv_again:
1144 memset(&xdr, 0, sizeof(xdr));
1145 memset(&msg, 0, sizeof(msg));
1146 msg.acpted_rply.ar_verf = _null_auth;
1147 msg.acpted_rply.ar_results.where = (caddr_t)&res;
1148 msg.acpted_rply.ar_results.proc = xdr_bool;
1149
1150 try_again:
1151 fromlen = sizeof (struct sockaddr);
1152 inlen = recvfrom(pingsock, buf, sizeof buf, 0,
1153 (struct sockaddr *)&raddr, &fromlen);
1154 if (inlen < 0)
1155 {
1156 if (errno == EINTR) goto try_again;
1157 return RPC_CANTRECV;
1158 }
1159
1160 if (inlen < sizeof(u_int32_t)) goto recv_again;
1161
1162 /*
1163 * see if reply transaction id matches sent id.
1164 * If so, decode the results.
1165 */
1166 xdrmem_create(&xdr, buf, (u_int)inlen, XDR_DECODE);
1167 if (xdr_replymsg(&xdr, &msg))
1168 {
1169 if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
1170 (msg.acpted_rply.ar_stat == SUCCESS))
1171 {
1172 ypdb = xid2ypdb(msg.rm_xid);
1173 if (ypdb != NULL) rpc_received(ypdb->dom_domain, &raddr, 0);
1174 }
1175 }
1176
1177 xdr.x_op = XDR_FREE;
1178 msg.acpted_rply.ar_results.proc = xdr_void;
1179 xdr_destroy(&xdr);
1180
1181 return RPC_SUCCESS;
1182 }
1183
1184 /*
1185 * LOOPBACK IS MORE IMPORTANT: PUT IN HACK
1186 */
1187 void
1188 rpc_received(char *dom, struct sockaddr_in *raddrp, int force)
1189 {
1190 struct _dom_binding *ypdb;
1191 struct iovec iov[2];
1192 struct ypbind_resp ybr;
1193 int fd;
1194
1195 sys_msg(debug, LOG_DEBUG, "returned from %s about %s",
1196 inet_ntoa(raddrp->sin_addr), dom);
1197
1198 if (dom == NULL) return;
1199
1200 /* don't support insecure servers by default */
1201 if (!insecure && ntohs(raddrp->sin_port) >= IPPORT_RESERVED) return;
1202
1203 for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext)
1204 {
1205 if (!strcmp(ypdb->dom_domain, dom)) break;
1206 }
1207
1208 if (ypdb == NULL)
1209 {
1210 if (force == 0) return;
1211 ypdb = makebinding(dom);
1212 ypdb->dom_lockfd = -1;
1213 ypdb->dom_pnext = ypbindlist;
1214 ypbindlist = ypdb;
1215 }
1216
1217 /* soft update, alive */
1218 if (ypdb->dom_alive == 1 && force == 0)
1219 {
1220 if (!memcmp(&ypdb->dom_server_addr, raddrp,
1221 sizeof ypdb->dom_server_addr))
1222 {
1223 ypdb->dom_alive = 1;
1224 /* recheck binding in 60 sec */
1225 ypdb->dom_check_t = time(NULL) + 60;
1226 }
1227 return;
1228 }
1229
1230 memcpy(&ypdb->dom_server_addr, raddrp, sizeof ypdb->dom_server_addr);
1231 /* recheck binding in 60 seconds */
1232 ypdb->dom_check_t = time(NULL) + 60;
1233 ypdb->dom_vers = YPVERS;
1234 ypdb->dom_alive = 1;
1235
1236 if (ypdb->dom_lockfd != -1) close(ypdb->dom_lockfd);
1237
1238 if ((fd = makelock(ypdb)) == -1) return;
1239
1240 /*
1241 * ok, if BINDINGDIR exists, and we can create the binding file,
1242 * then write to it..
1243 */
1244 ypdb->dom_lockfd = fd;
1245
1246 iov[0].iov_base = (caddr_t)&(udptransp->xp_port);
1247 iov[0].iov_len = sizeof udptransp->xp_port;
1248 iov[1].iov_base = (caddr_t)&ybr;
1249 iov[1].iov_len = sizeof ybr;
1250
1251 memset(&ybr, 0, sizeof ybr);
1252 ybr.ypbind_status = YPBIND_SUCC_VAL;
1253 bcopy(&raddrp->sin_addr.s_addr,
1254 ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr, 4);
1255 bcopy(&raddrp->sin_port,
1256 ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port, 2);
1257
1258 if (writev(ypdb->dom_lockfd, iov, 2) !=
1259 iov[0].iov_len + iov[1].iov_len)
1260 {
1261 sys_msg(debug, LOG_WARNING, "writev: %s", strerror(errno));
1262 close(ypdb->dom_lockfd);
1263 removelock(ypdb);
1264 ypdb->dom_lockfd = -1;
1265 }
1266 }
1267
1268 static struct _dom_binding *
1269 xid2ypdb(u_int32_t xid)
1270 {
1271 struct _dom_binding *ypdb;
1272
1273 for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext)
1274 {
1275 if (ypdb->dom_xid == xid) break;
1276 }
1277
1278 return (ypdb);
1279 }
1280
1281 static u_int32_t
1282 unique_xid(struct _dom_binding *ypdb)
1283 {
1284 u_int32_t tmp_xid;
1285
1286 tmp_xid = (u_int32_t)(((u_long)ypdb) & 0xffffffff);
1287 while (xid2ypdb(tmp_xid) != NULL) tmp_xid++;
1288
1289 return tmp_xid;
1290 }