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