xref: /titanic_41/usr/src/cmd/ypcmd/ypxfr.c (revision c2580b931007758eab8cb5ae8726ebe1588e259b)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  *
22  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /*	  All Rights Reserved   */
28 
29 /*
30  * Portions of this source code were derived from Berkeley
31  * under license from the Regents of the University of
32  * California.
33  */
34 
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 /*
38  * This is a user command which gets a NIS data base from some running
39  * server, and gets it to the local site by using the normal NIS client
40  * enumeration functions.  The map is copied to a temp name, then the real
41  * map is removed and the temp map is moved to the real name.  ypxfr then
42  * sends a "YPPROC_CLEAR" message to the local server to insure that he will
43  * not hold a removed map open, so serving an obsolete version.
44  *
45  * ypxfr [ -h <host> ] [ -d <domainname> ]
46  *		[ -s <domainname> ] [-f] [-c] [-C tid prot name] map
47  *
48  * If the host is ommitted, ypxfr will attempt to discover the master by
49  * using normal NIS services.  If it can't get the record, it will use
50  * the address of the callback, if specified. If the host is specified
51  * as an internet address, no NIS services need to be locally available.
52  *
53  * If the domain is not specified, the default domain of the local machine
54  * is used.
55  *
56  * If the -f flag is used, the transfer will be done even if the master's
57  * copy is not newer than the local copy.
58  *
59  * The -c flag suppresses the YPPROC_CLEAR request to the local ypserv.  It
60  * may be used if ypserv isn't currently running to suppress the error message.
61  *
62  * The -C flag is used to pass callback information to ypxfr when it is
63  * activated by ypserv.  The callback information is used to send a
64  * yppushresp_xfr message with transaction id "tid" to a yppush process
65  * speaking a transient protocol number "prot".  The yppush program is
66  * running on the host "name".
67  *
68  * The -s option is used to specify a source domain which may be
69  * different from the destination domain, for transfer of maps
70  * that are identical in different domains (e.g. services.byname)
71  *
72  */
73 
74 #include <ndbm.h>
75 #undef NULL
76 #define	DATUM
77 
78 #include <stdio.h>
79 #include <errno.h>
80 #include <time.h>
81 #include <ctype.h>
82 #include <netdb.h>
83 #include <netconfig.h>
84 #include <netdir.h>
85 #include <rpc/rpc.h>
86 #include <sys/file.h>
87 #include <sys/stat.h>
88 #include <dirent.h>
89 #include <rpcsvc/ypclnt.h>
90 #include <rpcsvc/yp_prot.h>
91 #include <unistd.h>
92 #include <stdlib.h>
93 #include <rpcsvc/nis.h>
94 #include "ypdefs.h"
95 #include "yp_b.h"
96 #include "shim.h"
97 #include "yptol.h"
98 
99 USE_YP_MASTER_NAME
100 USE_YP_SECURE
101 USE_YP_INTERDOMAIN
102 USE_YP_LAST_MODIFIED
103 USE_YPDBPATH
104 USE_DBM
105 
106 #define	PARANOID 1	/* make sure maps have the right # entries */
107 
108 #define	CALLINTER_TRY 10		/* Seconds between callback tries */
109 #define	CALLTIMEOUT CALLINTER_TRY*6	/* Total timeout for callback */
110 
111 DBM *db;
112 
113 /* ypxfr never uses N2L mode */
114 bool_t yptol_mode = FALSE;
115 
116 int	debug = FALSE;
117 int	treepush = FALSE;
118 #define	TREEPUSH 1
119 int	defwrite = TRUE;
120 
121 char *domain = NULL;
122 char *source = NULL;
123 char *map = NULL;
124 char *master = NULL;
125 char *pushhost = NULL;
126 /*
127  * The name of the xfer peer as specified as a
128  * -h option, -C name option or from querying the NIS
129  */
130 struct dom_binding master_server; /* To talk to above */
131 unsigned int master_prog_vers;	/* YPVERS (barfs at YPOLDVERS !) */
132 char *master_name = NULL;	/* Map's master as contained in the map */
133 unsigned *master_version = NULL; /* Order number as contained in the map */
134 char *master_ascii_version;	/* ASCII order number as contained in the map */
135 bool fake_master_version = FALSE;
136 /*
137  * TRUE only if there's no order number in
138  *  the map, and the user specified -f
139  */
140 bool force = FALSE;		/* TRUE iff user specified -f flag */
141 bool logging = FALSE;		/* TRUE iff no tty, but log file exists */
142 bool check_count = FALSE;	/* TRUE causes counts to be checked */
143 bool send_clear = TRUE;		/* FALSE iff user specified -c flag */
144 bool callback = FALSE;
145 /*
146  * TRUE iff -C flag set.  tid, proto and name
147  * will be set to point to the command line args.
148  */
149 bool secure_map = FALSE;	/* TRUE if there is yp_secure in the map */
150 bool interdomain_map = FALSE;
151 /*
152  * TRUE if there is yp_interdomain in either
153  * the local or the master version of the map
154  */
155 int interdomain_sz = 0;		/* Size of the interdomain value */
156 #define	UDPINTER_TRY 10		/* Seconds between tries for udp */
157 #define	UDPTIMEOUT UDPINTER_TRY*4	/* Total timeout for udp */
158 #define	CALLINTER_TRY 10	/* Seconds between callback tries */
159 #define	CALLTIMEOUT CALLINTER_TRY*6	/* Total timeout for callback */
160 struct timeval udp_timeout = { UDPTIMEOUT, 0};
161 struct timeval tcp_timeout = { 180, 0}; /* Timeout for map enumeration */
162 
163 char *interdomain_value; 	/* place to store the interdomain value */
164 char *tid;
165 char *proto;
166 int entry_count;		/* counts entries in the map */
167 char logfile[] = "/var/yp/ypxfr.log";
168 static char err_usage[] =
169 "Usage:\n\
170 ypxfr [-f] [ -h host ] [ -d domainname ]\n\
171 	[ -s domainname ] [-c] [-C tid prot servname ] map\n\n\
172 where\n\
173 	-f forces transfer even if the master's copy is not newer.\n\
174 	host is the server from where the map should be transfered\n\
175 	-d domainname is specified if other than the default domain\n\
176 	-s domainname is a source for the map that is same across domains\n\
177 	-c inhibits sending a \"Clear map\" message to the local ypserv.\n\
178 	-C is for use only by ypserv to pass callback information.\n";
179 char err_bad_args[] =
180 	"%s argument is bad.\n";
181 char err_cant_get_kname[] =
182 	"Can't get %s back from system call.\n";
183 char err_null_kname[] =
184 	"%s hasn't been set on this machine.\n";
185 char err_bad_hostname[] = "hostname";
186 char err_bad_mapname[] = "mapname";
187 char err_bad_domainname[] = "domainname";
188 char err_udp_failure[] =
189 	"Can't set up a udp connection to ypserv on host %s.\n";
190 char yptempname_prefix[] = "ypxfr_map.";
191 char ypbkupname_prefix[] = "ypxfr_bkup.";
192 
193 void get_command_line_args();
194 bool bind_to_server();
195 bool ping_server();
196 bool  get_private_recs();
197 bool get_order();
198 bool get_v1order();
199 bool get_v2order();
200 bool get_misc_recs();
201 bool get_master_name();
202 bool get_v1master_name();
203 bool get_v2master_name();
204 void find_map_master();
205 bool move_map();
206 unsigned get_local_version();
207 void mkfilename();
208 void mk_tmpname();
209 bool get_map();
210 bool add_private_entries();
211 bool new_mapfiles();
212 void del_mapfiles();
213 void set_output();
214 void logprintf();
215 bool send_ypclear();
216 void xfr_exit();
217 void send_callback();
218 int ypall_callback();
219 int map_yperr_to_pusherr();
220 extern CLIENT *__yp_clnt_create_rsvdport();
221 
222 bool_t is_yptol_mode();
223 
224 extern int errno;
225 
226 
227 /*
228  * This is the mainline for the ypxfr process.
229  */
230 
231 int
232 main(argc, argv)
233 	int argc;
234 	char **argv;
235 
236 {
237 
238 	static char default_domain_name[YPMAXDOMAIN];
239 	static unsigned big = 0xffffffff;
240 	int status;
241 
242 	set_output();
243 
244 	/*
245 	 * Inter-process lock synchronization structure. Since slave servers
246 	 * get their maps from another NIS server rather than LDAP they can
247 	 * never run in N2L mode. We thus do not have to init the update
248 	 * locking mechanism.
249 	 */
250 	if (init_lock_map() == FALSE) {
251 		exit(1);
252 	}
253 
254 	get_command_line_args(argc, argv);
255 
256 	if (!domain) {
257 
258 		if (!getdomainname(default_domain_name, YPMAXDOMAIN)) {
259 			domain = default_domain_name;
260 		} else {
261 			logprintf(err_cant_get_kname,
262 			    err_bad_domainname);
263 			xfr_exit(YPPUSH_RSRC);
264 		}
265 
266 		if (strlen(domain) == 0) {
267 			logprintf(err_null_kname,
268 			    err_bad_domainname);
269 			xfr_exit(YPPUSH_RSRC);
270 		}
271 	}
272 	if (!source)
273 		source = domain;
274 
275 	if (!master) {
276 		find_map_master();
277 	}
278 	/*
279 	 * if we were unable to get the master name, either from
280 	 * the -h option or from -C "name" option or from NIS,
281 	 * we are doomed !
282 	 */
283 	if (!master) {
284 		xfr_exit(YPPUSH_MADDR);
285 	}
286 
287 	if (!bind_to_server(master, &master_server,
288 	    &master_prog_vers, &status)) {
289 		xfr_exit(status);
290 	}
291 
292 	if (!get_private_recs(&status)) {
293 		xfr_exit(status);
294 	}
295 
296 	if (!master_version) {
297 
298 		if (force) {
299 			master_version = &big;
300 			fake_master_version = TRUE;
301 		} else {
302 			logprintf(
303 "Can't get order number for map %s from server at %s: use the -f flag.\n",
304 			    map, master);
305 			xfr_exit(YPPUSH_FORCE);
306 		}
307 	}
308 
309 	if (!move_map(&status)) {
310 		xfr_exit(status);
311 	}
312 
313 	if (send_clear && !send_ypclear(&status)) {
314 		xfr_exit(status);
315 	}
316 
317 	if (logging) {
318 		logprintf("Transferred map %s from %s (%d entries).\n",
319 		    map, master, entry_count);
320 	}
321 
322 	xfr_exit(YPPUSH_SUCC);
323 	return (0);
324 	/* NOTREACHED */
325 }
326 
327 /*
328  * This decides whether we're being run interactively or not, and, if not,
329  * whether we're supposed to be logging or not.  If we are logging, it sets
330  * up stderr to point to the log file, and sets the "logging"
331  * variable.  If there's no logging, the output goes in the bit bucket.
332  * Logging output differs from interactive output in the presence of a
333  * timestamp, present only in the log file.  stderr is reset, too, because it
334  * it's used by various library functions, including clnt_perror.
335  */
336 void
337 set_output()
338 {
339 	if (!isatty(1)) {
340 		if (access(logfile, W_OK)) {
341 			(void) freopen("/dev/null", "w", stderr);
342 		} else {
343 			(void) freopen(logfile, "a", stderr);
344 			logging = TRUE;
345 		}
346 	}
347 }
348 /*
349  * This constructs a logging record.
350  */
351 void
352 logprintf(arg1, arg2, arg3, arg4, arg5, arg6, arg7)
353 /*VARARGS*/
354 {
355 	struct timeval t;
356 
357 	fseek(stderr, 0, 2);
358 	if (logging) {
359 		(void) gettimeofday(&t, NULL);
360 		(void) fprintf(stderr, "%19.19s: ", ctime(&t.tv_sec));
361 	}
362 	(void) fprintf(stderr, (char *)arg1, arg2, arg3, arg4, arg5,
363 				arg6, arg7);
364 	fflush(stderr);
365 }
366 
367 /*
368  * This does the command line argument processing.
369  */
370 void
371 get_command_line_args(argc, argv)
372 	int argc;
373 	char **argv;
374 
375 {
376 	argv++;
377 
378 	if (argc < 2) {
379 		logprintf(err_usage);
380 		xfr_exit(YPPUSH_BADARGS);
381 	}
382 
383 	while (--argc) {
384 
385 		if ((*argv)[0] == '-') {
386 
387 			switch ((*argv)[1]) {
388 
389 			case 'f': {
390 				force = TRUE;
391 				argv++;
392 				break;
393 			}
394 
395 			case 'D': {
396 				debug = TRUE;
397 				argv++;
398 				break;
399 			}
400 
401 			case 'T': {
402 				treepush = TRUE;
403 				argv++;
404 				break;
405 			}
406 			case 'P': {
407 				check_count = TRUE;
408 				argv++;
409 				break;
410 			}
411 			case 'W': {
412 				defwrite = FALSE;
413 				argv++;
414 				break;
415 			}
416 			case 'c': {
417 				send_clear = FALSE;
418 				argv++;
419 				break;
420 			}
421 
422 			case 'h': {
423 
424 				if (argc > 1) {
425 					argv++;
426 					argc--;
427 					master = *argv;
428 					argv++;
429 
430 					if (strlen(master) > 256) {
431 						logprintf(
432 						    err_bad_args,
433 						    err_bad_hostname);
434 						xfr_exit(YPPUSH_BADARGS);
435 					}
436 
437 				} else {
438 					logprintf(err_usage);
439 					xfr_exit(YPPUSH_BADARGS);
440 				}
441 
442 				break;
443 			}
444 
445 			case 'd':
446 				if (argc > 1) {
447 					argv++;
448 					argc--;
449 					domain = *argv;
450 					argv++;
451 
452 					if (strlen(domain) > YPMAXDOMAIN) {
453 						logprintf(
454 						    err_bad_args,
455 						    err_bad_domainname);
456 						xfr_exit(YPPUSH_BADARGS);
457 					}
458 
459 				} else {
460 					logprintf(err_usage);
461 					xfr_exit(YPPUSH_BADARGS);
462 				}
463 				break;
464 
465 			case 's':
466 				if (argc > 1) {
467 					argv++;
468 					argc--;
469 					source = *argv;
470 					argv++;
471 
472 					if (strlen(source) > YPMAXDOMAIN) {
473 						logprintf(
474 						    err_bad_args,
475 						    err_bad_domainname);
476 						xfr_exit(YPPUSH_BADARGS);
477 					}
478 
479 				} else {
480 					logprintf(err_usage);
481 					xfr_exit(YPPUSH_BADARGS);
482 				}
483 				break;
484 
485 			case 'C':
486 			    if (argc > 3) {
487 				callback = TRUE;
488 				tid = *(++argv);
489 				proto = *(++argv);
490 				pushhost = *(++argv);
491 				if (strlen(pushhost) > 256) {
492 				    logprintf(err_bad_args, err_bad_hostname);
493 
494 				    xfr_exit(YPPUSH_BADARGS);
495 				}
496 				argc -= 3;
497 				argv++;
498 			    } else {
499 				logprintf(err_usage);
500 				xfr_exit(YPPUSH_BADARGS);
501 			    }
502 			    break;
503 
504 			case 'b': {
505 				interdomain_map = TRUE;
506 				interdomain_value = "";
507 				interdomain_sz = 0;
508 				argv++;
509 				break;
510 			}
511 
512 
513 			default: {
514 				logprintf(err_usage);
515 				xfr_exit(YPPUSH_BADARGS);
516 			}
517 
518 			}
519 
520 		} else {
521 
522 			if (!map) {
523 				map = *argv;
524 				argv++;
525 
526 				if (strlen(map) > YPMAXMAP) {
527 					logprintf(err_bad_args,
528 					err_bad_mapname);
529 					xfr_exit(YPPUSH_BADARGS);
530 				}
531 
532 			} else {
533 				logprintf(err_usage);
534 				xfr_exit(YPPUSH_BADARGS);
535 			}
536 		}
537 	}
538 
539 	if (!map) {
540 		logprintf(err_usage);
541 		xfr_exit(YPPUSH_BADARGS);
542 	}
543 }
544 
545 /*
546  * This tries to get the master name for the named map, from any
547  * server's version, using the vanilla NIS client interface.  If we get a
548  * name back, the global "master" gets pointed to it.
549  */
550 void
551 find_map_master()
552 {
553 	int err;
554 
555 	if (err = __yp_master_rsvdport(source, map, &master)) {
556 		logprintf("Can't get master of %s. Reason: %s.\n", map,
557 		    yperr_string(err));
558 	}
559 
560 	yp_unbind(source);
561 }
562 
563 #ifdef TREEPUSH
564 int
565 chk_treepush(name)
566 char *name;
567 {
568 	char inmap[256];
569 	char inkey[256];
570 	int inkeylen;
571 	char *outval;
572 	int outvallen;
573 	int err;
574 	outval = NULL;
575 	inkey[0] = 0;
576 	strcpy(inmap, "ypslaves.");
577 	strcat(inmap, name);
578 	gethostname(inkey, 256);
579 	inkeylen = strlen(inkey);
580 
581 	err = yp_match(source, inmap, inkey, inkeylen, &outval, &outvallen);
582 	yp_unbind(source);
583 	return (err);
584 }
585 #endif
586 
587 /*
588  * This sets up a udp connection to speak the correct program and version
589  * to a NIS server.  vers is set to YPVERS, doesn't give a damn about
590  * YPOLDVERS.
591  */
592 bool
593 bind_to_server(host, pdomb, vers, status)
594 	char *host;
595 	struct dom_binding *pdomb;
596 	unsigned int *vers;
597 	int *status;
598 {
599 	if (ping_server(host, pdomb, YPVERS, status)) {
600 		*vers = YPVERS;
601 		return (TRUE);
602 	} else
603 		return (FALSE);
604 }
605 
606 /*
607  * This sets up a UDP channel to a server which is assumed to speak an input
608  * version of YPPROG.  The channel is tested by pinging the server.  In all
609  * error cases except "Program Version Number Mismatch", the error is
610  * reported, and in all error cases, the client handle is destroyed and the
611  * socket associated with the channel is closed.
612  */
613 bool
614 ping_server(host, pdomb, vers, status)
615 	char *host;
616 	struct dom_binding *pdomb;
617 	unsigned int vers;
618 	int *status;
619 {
620 	enum clnt_stat rpc_stat;
621 
622 	if ((pdomb->dom_client = __yp_clnt_create_rsvdport(host, YPPROG, vers,
623 							0, 0, 0)) != 0) {
624 
625 		/*
626 		 * if we are on a c2 system, we should only accept data
627 		 * from a server which is on a reserved port.
628 		 */
629 	/*
630 	 * NUKE this for 5.0DR.
631 	 *
632 	 *	if (issecure() &&
633 	 *	    (pdomb->dom_server_addr.sin_family != AF_INET ||
634 	 *	    pdomb->dom_server_addr.sin_port >= IPPORT_RESERVED)) {
635 	 *		clnt_destroy(pdomb->dom_client);
636 	 *		close(pdomb->dom_socket);
637 	 *		(void) logprintf("bind_to_server: \
638 	 *			server is not using a privileged port\n");
639 	 *		*status = YPPUSH_YPERR;
640 	 *		return (FALSE);
641 	 *	}
642 	 */
643 
644 		rpc_stat = clnt_call(pdomb->dom_client, YPBINDPROC_NULL,
645 		    xdr_void, 0, xdr_void, 0, udp_timeout);
646 
647 		if (rpc_stat == RPC_SUCCESS) {
648 			return (TRUE);
649 		} else {
650 			clnt_destroy(pdomb->dom_client);
651 			if (rpc_stat != RPC_PROGVERSMISMATCH) {
652 				(void) clnt_perror(pdomb->dom_client,
653 				    "ypxfr: bind_to_server clnt_call error");
654 			}
655 
656 			*status = YPPUSH_RPC;
657 			return (FALSE);
658 		}
659 	} else {
660 		logprintf("bind_to_server __clnt_create_rsvd error");
661 		(void) clnt_pcreateerror("");
662 		fflush(stderr);
663 		*status = YPPUSH_RPC;
664 		return (FALSE);
665 	}
666 }
667 
668 /*
669  * This gets values for the YP_LAST_MODIFIED and YP_MASTER_NAME keys from the
670  * master server's version of the map.  Values are held in static variables
671  * here.  In the success cases, global pointer variables are set to point at
672  * the local statics.
673  */
674 bool
675 get_private_recs(pushstat)
676 	int *pushstat;
677 {
678 	static char anumber[20];
679 	static unsigned number;
680 	static char name[YPMAXPEER + 1];
681 	int status;
682 
683 	status = 0;
684 
685 	if (get_order(anumber, &number, &status)) {
686 		master_version = &number;
687 		master_ascii_version = anumber;
688 		if (debug) fprintf(stderr,
689 			"ypxfr: Master Version is %s\n", master_ascii_version);
690 	} else {
691 
692 		if (status != 0) {
693 			*pushstat = status;
694 			if (debug) fprintf(stderr,
695 		"ypxfr: Couldn't get map's master version number, \
696 		status was %d\n", status);
697 			return (FALSE);
698 		}
699 	}
700 
701 	if (get_master_name(name, &status)) {
702 		master_name = name;
703 		if (debug) fprintf(stderr,
704 			"ypxfr: Maps master is '%s'\n", master_name);
705 	} else {
706 
707 		if (status != 0) {
708 			*pushstat = status;
709 			if (debug) fprintf(stderr,
710 		"ypxfr: Couldn't get map's master name, status was %d\n",
711 			status);
712 			return (FALSE);
713 		}
714 		master_name = master;
715 	}
716 
717 	if (debug)
718 		fprintf(stderr,
719 			"ypxfr: Getting private records from master.\n");
720 	if (get_misc_recs(&status)) {
721 		if (debug)
722 			fprintf(stderr,
723 		    "ypxfr: Masters map %s secure and %s an interdomain map.\n",
724 			(secure_map) ? "is" : "is not",
725 			(interdomain_map) ? "is" : "is not");
726 	} else {
727 		if (status != 0) {
728 			*pushstat = status;
729 			if (debug)
730 				fprintf(stderr,
731 	"ypxfr: Couldn't get state of secure and interdomain flags in map.\n");
732 			return (FALSE);
733 		}
734 	}
735 
736 	return (TRUE);
737 }
738 
739 /*
740  * This gets the map's order number from the master server
741  */
742 bool
743 get_order(an, n, pushstat)
744 	char *an;
745 	unsigned *n;
746 	int *pushstat;
747 {
748 	if (master_prog_vers == YPVERS) {
749 		return (get_v2order(an, n, pushstat));
750 	} else
751 		return (FALSE);
752 }
753 
754 bool
755 get_v2order(an, n, pushstat)
756 	char *an;
757 	unsigned *n;
758 	int *pushstat;
759 {
760 	struct ypreq_nokey req;
761 	struct ypresp_order resp;
762 	int retval;
763 
764 	req.domain = source;
765 	req.map = map;
766 
767 	/*
768 	 * Get the map''s order number, null-terminate it and store it,
769 	 * and convert it to binary and store it again.
770 	 */
771 	retval = FALSE;
772 
773 	if ((enum clnt_stat) clnt_call(master_server.dom_client,
774 	    YPPROC_ORDER, (xdrproc_t)xdr_ypreq_nokey, (char *)&req,
775 	    (xdrproc_t)xdr_ypresp_order, (char *)&resp,
776 	    udp_timeout) == RPC_SUCCESS) {
777 
778 		if (resp.status == YP_TRUE) {
779 			sprintf(an, "%d", resp.ordernum);
780 			*n = resp.ordernum;
781 			retval = TRUE;
782 		} else if (resp.status != YP_BADDB) {
783 			*pushstat = ypprot_err(resp.status);
784 
785 			if (!logging) {
786 				logprintf(
787 	"(info) Can't get order number from ypserv at %s.  Reason: %s.\n",
788 				    master, yperr_string(
789 				    ypprot_err(resp.status)));
790 			}
791 		}
792 
793 		CLNT_FREERES(master_server.dom_client,
794 			(xdrproc_t)xdr_ypresp_order,
795 		    (char *)&resp);
796 	} else {
797 		*pushstat = YPPUSH_RPC;
798 		logprintf("ypxfr(get_v2order) RPC call to %s failed", master);
799 		clnt_perror(master_server.dom_client, "");
800 	}
801 
802 	return (retval);
803 }
804 
805 /*
806  * Pick up the state of the YP_SECURE and YP_INTERDOMAIN records from the
807  * master. Only works on 4.0 V2 masters that will match a YP_ private key
808  * when asked to explicitly.
809  */
810 bool
811 get_misc_recs(pushstat)
812 	int *pushstat;
813 {
814 	struct ypreq_key req;
815 	struct ypresp_val resp;
816 	int retval;
817 
818 	req.domain = source;
819 	req.map = map;
820 	req.keydat.dptr   = yp_secure;
821 	req.keydat.dsize  = yp_secure_sz;
822 
823 	resp.valdat.dptr = NULL;
824 	resp.valdat.dsize = 0;
825 
826 	/*
827 	 * Get the value of the IS_SECURE key in the map.
828 	 */
829 	retval = FALSE;
830 
831 	if (debug)
832 		fprintf(stderr, "ypxfr: Checking masters secure key.\n");
833 	if ((enum clnt_stat) clnt_call(master_server.dom_client,
834 	    YPPROC_MATCH, (xdrproc_t)xdr_ypreq_key, (char *)&req,
835 	(xdrproc_t)xdr_ypresp_val, (char *)&resp,
836 	    udp_timeout) == RPC_SUCCESS) {
837 		if (resp.status == YP_TRUE) {
838 			if (debug)
839 				fprintf(stderr, "ypxfr: SECURE\n");
840 			secure_map = TRUE;
841 			retval = TRUE;
842 		} else if ((resp.status != YP_NOKEY) &&
843 			    (resp.status != YP_VERS) &&
844 			    (resp.status != YP_NOMORE)) {
845 			*pushstat = ypprot_err(resp.status);
846 
847 			if (!logging) {
848 				logprintf(
849 	"(info) Can't get secure flag from ypserv at %s.  Reason: %s.\n",
850 				    master, yperr_string(
851 				    ypprot_err(resp.status)));
852 			}
853 		}
854 
855 		CLNT_FREERES(master_server.dom_client,
856 			(xdrproc_t)xdr_ypresp_val,
857 		    (char *)&resp);
858 	} else {
859 		*pushstat = YPPUSH_RPC;
860 		logprintf("ypxfr(get_misc_recs) RPC call to %s failed", master);
861 		clnt_perror(master_server.dom_client, "");
862 	}
863 
864 	if (debug)
865 		fprintf(stderr, "ypxfr: Checking masters INTERDOMAIN key.\n");
866 	req.keydat.dptr   = yp_interdomain;
867 	req.keydat.dsize  = yp_interdomain_sz;
868 
869 	resp.valdat.dptr = NULL;
870 	resp.valdat.dsize = 0;
871 
872 	/*
873 	 * Get the value of the INTERDOMAIN key in the map.
874 	 */
875 
876 	if ((enum clnt_stat) clnt_call(master_server.dom_client,
877 	    YPPROC_MATCH, (xdrproc_t)xdr_ypreq_key, (char *)&req,
878 	(xdrproc_t)xdr_ypresp_val, (char *)&resp,
879 	    udp_timeout) == RPC_SUCCESS) {
880 		if (resp.status == YP_TRUE) {
881 			if (debug)
882 				fprintf(stderr, "ypxfr: INTERDOMAIN\n");
883 			interdomain_map = TRUE;
884 			interdomain_value = (char *)malloc(resp.valdat.dsize+1);
885 			(void) memmove(interdomain_value, resp.valdat.dptr,
886 					resp.valdat.dsize);
887 			*(interdomain_value+resp.valdat.dsize) = '\0';
888 			interdomain_sz = resp.valdat.dsize;
889 			retval = TRUE;
890 		} else if ((resp.status != YP_NOKEY) &&
891 			    (resp.status != YP_VERS) &&
892 			    (resp.status != YP_NOMORE)) {
893 			*pushstat = ypprot_err(resp.status);
894 
895 			if (!logging) {
896 				logprintf(
897 	"(info) Can't get interdomain flag from ypserv at %s.  Reason: %s.\n",
898 				    master, yperr_string(
899 				    ypprot_err(resp.status)));
900 			}
901 		}
902 
903 		CLNT_FREERES(master_server.dom_client,
904 			(xdrproc_t)xdr_ypresp_val,
905 		    (char *)&resp);
906 	} else {
907 		*pushstat = YPPUSH_RPC;
908 		logprintf("ypxfr(get_misc_recs) RPC call to %s failed", master);
909 		clnt_perror(master_server.dom_client, "");
910 	}
911 
912 
913 	return (retval);
914 }
915 
916 /*
917  * This gets the map's master name from the master server
918  */
919 bool
920 get_master_name(name, pushstat)
921 	char *name;
922 	int *pushstat;
923 {
924 	if (master_prog_vers == YPVERS) {
925 		return (get_v2master_name(name, pushstat));
926 	} else
927 		return (FALSE);
928 }
929 
930 bool
931 get_v2master_name(name, pushstat)
932 	char *name;
933 	int *pushstat;
934 {
935 	struct ypreq_nokey req;
936 	struct ypresp_master resp;
937 	int retval;
938 
939 	req.domain = source;
940 	req.map = map;
941 	resp.master = NULL;
942 	retval = FALSE;
943 
944 	if ((enum clnt_stat) clnt_call(master_server.dom_client,
945 	    YPPROC_MASTER, (xdrproc_t)xdr_ypreq_nokey, (char *)&req,
946 	    (xdrproc_t)xdr_ypresp_master, (char *)&resp,
947 	    udp_timeout) == RPC_SUCCESS) {
948 
949 		if (resp.status == YP_TRUE) {
950 			strcpy(name, resp.master);
951 			retval = TRUE;
952 		} else if (resp.status != YP_BADDB) {
953 			*pushstat = ypprot_err(resp.status);
954 
955 			if (!logging) {
956 				logprintf(
957 "(info) Can't get master name from ypserv at %s. Reason: %s.\n",
958 				    master, yperr_string(
959 				    ypprot_err(resp.status)));
960 			}
961 		}
962 
963 		CLNT_FREERES(master_server.dom_client,
964 			(xdrproc_t)xdr_ypresp_master,
965 		    (char *)&resp);
966 	} else {
967 		*pushstat = YPPUSH_RPC;
968 		logprintf(
969 		    "ypxfr(get_v2master_name) RPC call to %s failed", master);
970 		clnt_perror(master_server.dom_client, "");
971 	}
972 
973 	return (retval);
974 }
975 
976 /*
977  * This does the work of transferring the map.
978  */
979 bool
980 move_map(pushstat)
981 	int *pushstat;
982 {
983 	unsigned local_version;
984 	char map_name[MAXNAMLEN + 1];
985 	char tmp_name[MAXNAMLEN + 1];
986 	char bkup_name[MAXNAMLEN + 1];
987 	char an[11];
988 	unsigned n;
989 	datum key;
990 	datum val;
991 	int  hgstatus;
992 
993 	mkfilename(map_name);
994 
995 	if (!force) {
996 		local_version = get_local_version(map_name);
997 		if (debug) fprintf(stderr,
998 			"ypxfr: Local version of map '%s' is %d\n",
999 			map_name, local_version);
1000 
1001 		if (local_version >= *master_version) {
1002 			logprintf(
1003 			    "Map %s at %s is not more recent than local.\n",
1004 			    map, master);
1005 			*pushstat = YPPUSH_AGE;
1006 			return (FALSE);
1007 		}
1008 	}
1009 
1010 	mk_tmpname(yptempname_prefix, tmp_name);
1011 
1012 	if (!new_mapfiles(tmp_name)) {
1013 		logprintf(
1014 		    "Can't create temp map %s.\n", tmp_name);
1015 		*pushstat = YPPUSH_FILE;
1016 		return (FALSE);
1017 	}
1018 
1019 	if ((hgstatus = ypxfrd_getdbm(tmp_name, master, source, map)) < 0)
1020 	{
1021 	logprintf(
1022 "(info) %s %s %s ypxfrd getdbm failed (reason = %d) -- using ypxfr\n",
1023 		master, domain, map, hgstatus);
1024 
1025 	    db = dbm_open(tmp_name, O_RDWR + O_CREAT + O_TRUNC, 0644);
1026 	if (db == NULL) {
1027 		logprintf(
1028 		    "Can't dbm init temp map %s.\n", tmp_name);
1029 		del_mapfiles(tmp_name);
1030 		*pushstat = YPPUSH_DBM;
1031 		return (FALSE);
1032 	}
1033 	if (defwrite) dbm_setdefwrite(db);
1034 
1035 	if (!get_map(tmp_name, pushstat)) {
1036 		del_mapfiles(tmp_name);
1037 		return (FALSE);
1038 	}
1039 
1040 	if (!add_private_entries(tmp_name)) {
1041 		del_mapfiles(tmp_name);
1042 		*pushstat = YPPUSH_DBM;
1043 		return (FALSE);
1044 	}
1045 
1046 	/*
1047 	 * Decide whether the map just transferred is a secure map.
1048 	 * If we already know the local version was secure, we do not
1049 	 * need to check this version.
1050 	 */
1051 	if (!secure_map) {
1052 		key.dptr = yp_secure;
1053 		key.dsize = yp_secure_sz;
1054 		val = dbm_fetch(db, key);
1055 		if (val.dptr != NULL) {
1056 			secure_map = TRUE;
1057 		}
1058 	}
1059 
1060 	if (dbm_close_status(db) < 0) {
1061 		logprintf(
1062 		    "Can't do dbm close operation on temp map %s.\n",
1063 		    tmp_name);
1064 		del_mapfiles(tmp_name);
1065 		*pushstat = YPPUSH_DBM;
1066 		return (FALSE);
1067 	}
1068 
1069 	if (!get_order(an, &n, pushstat)) {
1070 		return (FALSE);
1071 	}
1072 	if (n != *master_version) {
1073 		logprintf(
1074 		    "Version skew at %s while transferring map %s.\n",
1075 		    master, map);
1076 		del_mapfiles(tmp_name);
1077 		*pushstat = YPPUSH_SKEW;
1078 		return (FALSE);
1079 	}
1080 
1081 	if (check_count)
1082 	if (!count_mismatch(tmp_name, entry_count)) {
1083 		del_mapfiles(tmp_name);
1084 		*pushstat = YPPUSH_DBM;
1085 		return (FALSE);
1086 	}
1087 	} else {
1088 	/* touch up the map */
1089 	    db = dbm_open(tmp_name, 2, 0644);
1090 	if (db == NULL) {
1091 		logprintf(
1092 		    "Can't dbm init temp map %s.\n", tmp_name);
1093 		del_mapfiles(tmp_name);
1094 		*pushstat = YPPUSH_DBM;
1095 		return (FALSE);
1096 		}
1097 
1098 
1099 	if (!add_private_entries(tmp_name)) {
1100 		del_mapfiles(tmp_name);
1101 		*pushstat = YPPUSH_DBM;
1102 		return (FALSE);
1103 	}
1104 
1105 	/*
1106 	 * Decide whether the map just transferred is a secure map.
1107 	 * If we already know the local version was secure, we do not
1108 	 * need to check this version.
1109 	 */
1110 	if (!secure_map) {
1111 		key.dptr = yp_secure;
1112 		key.dsize = yp_secure_sz;
1113 		val = dbm_fetch(db, key);
1114 		if (val.dptr != NULL) {
1115 			secure_map = TRUE;
1116 		}
1117 	}
1118 
1119 	if (dbm_close_status(db) < 0) {
1120 		logprintf(
1121 		    "Can't do dbm close operation on temp map %s.\n",
1122 		    tmp_name);
1123 		del_mapfiles(tmp_name);
1124 		*pushstat = YPPUSH_DBM;
1125 		return (FALSE);
1126 	}
1127 
1128 	}
1129 
1130 	if (lock_map(map_name) == 0) {
1131 		del_mapfiles(tmp_name);
1132 		logprintf("Lock error on %s\n", map_name);
1133 		*pushstat = YPPUSH_FILE;
1134 		return (FALSE);
1135 	}
1136 	if (!check_map_existence(map_name)) {
1137 
1138 		if (!rename_map(tmp_name, map_name, secure_map)) {
1139 			del_mapfiles(tmp_name);
1140 			logprintf(
1141 			    "Rename error:  couldn't mv %s to %s.\n",
1142 			    tmp_name, map_name);
1143 			*pushstat = YPPUSH_FILE;
1144 			unlock_map(map_name);
1145 			return (FALSE);
1146 		}
1147 
1148 	} else {
1149 		mk_tmpname(ypbkupname_prefix, bkup_name);
1150 
1151 		if (!rename_map(map_name, bkup_name, secure_map)) {
1152 			(void) rename_map(bkup_name, map_name, secure_map);
1153 			logprintf(
1154 		"Rename error:  check that old %s is still intact.\n",
1155 		map_name);
1156 			del_mapfiles(tmp_name);
1157 			*pushstat = YPPUSH_FILE;
1158 			unlock_map(map_name);
1159 			return (FALSE);
1160 		}
1161 
1162 		if (rename_map(tmp_name, map_name, secure_map)) {
1163 			del_mapfiles(bkup_name);
1164 		} else {
1165 			del_mapfiles(tmp_name);
1166 			(void) rename_map(bkup_name, map_name, secure_map);
1167 				logprintf(
1168 		"Rename error:  check that old %s is still intact.\n",
1169 			    map_name);
1170 			*pushstat = YPPUSH_FILE;
1171 			unlock_map(map_name);
1172 			return (FALSE);
1173 		}
1174 	}
1175 	if (unlock_map(map_name) == 0)
1176 		return (FALSE);
1177 
1178 	return (TRUE);
1179 }
1180 
1181 /*
1182  * This tries to get the order number out of the local version of the map.
1183  * If the attempt fails for any version, the function will return "0"
1184  */
1185 unsigned
1186 get_local_version(name)
1187 	char *name;
1188 {
1189 	datum key;
1190 	datum val;
1191 	char number[11];
1192 	DBM *db;
1193 
1194 	if (!check_map_existence(name)) {
1195 		return (0);
1196 	}
1197 	if (debug) fprintf(stderr,
1198 		"ypxfr: Map does exist, checking version now.\n");
1199 
1200 	if ((db = dbm_open(name, 0, 0)) == 0) {
1201 		return (0);
1202 	}
1203 
1204 	key.dptr = yp_last_modified;
1205 	key.dsize = yp_last_modified_sz;
1206 	val = dbm_fetch(db, key);
1207 	if (!val.dptr) {	/* Check to see if dptr is NULL */
1208 		return (0);
1209 	}
1210 	if (val.dsize == 0 || val.dsize > 10) {
1211 		return (0);
1212 	}
1213 	/* Now save this value while we have it available */
1214 	(void) memmove(number, val.dptr, val.dsize);
1215 	number[val.dsize] = '\0';
1216 
1217 	/*
1218 	 * Now check to see if it is 'secure'. If we haven't already
1219 	 * determined that it is secure in get_private_recs() then we check
1220 	 * the local map here.
1221 	 */
1222 	if (!secure_map) {
1223 		key.dptr = yp_secure;
1224 		key.dsize = yp_secure_sz;
1225 		val = dbm_fetch(db, key);
1226 		secure_map = (val.dptr != NULL);
1227 	}
1228 
1229 	/*
1230 	 * Now check to see if interdomain requests are made of the local
1231 	 * map. Keep the value around if they are.
1232 	 */
1233 	if (!interdomain_map) {
1234 		key.dptr = yp_interdomain;
1235 		key.dsize = yp_interdomain_sz;
1236 		val = dbm_fetch(db, key);
1237 		if (interdomain_map = (val.dptr != NULL)) {
1238 			interdomain_value = (char *)malloc(val.dsize+1);
1239 			(void) memmove(interdomain_value, val.dptr, val.dsize);
1240 			*(interdomain_value+val.dsize) = '\0';
1241 			interdomain_sz = val.dsize;
1242 		}
1243 	}
1244 
1245 	/* finish up */
1246 	(void) dbm_close_status(db);
1247 
1248 	return ((unsigned)atoi(number));
1249 }
1250 
1251 /*
1252  * This constructs a file name for a map, minus its dbm_dir
1253  * or dbm_pag extensions
1254  */
1255 void
1256 mkfilename(ppath)
1257 	char *ppath;
1258 {
1259 	bool_t yptol_mode;
1260 	int len;
1261 
1262 	/* Work out if we are in yptol mode */
1263 	yptol_mode = is_yptol_mode();
1264 
1265 	len = strlen(domain) + strlen(map) + strlen(ypdbpath) + 3;
1266 	if (yptol_mode)
1267 		len += strlen(NTOL_PREFIX);
1268 
1269 	if (len > (MAXNAMLEN + 1)) {
1270 		logprintf("Map name string too long.\n");
1271 	}
1272 
1273 	(void) strcpy(ppath, ypdbpath);
1274 	(void) strcat(ppath, "/");
1275 	(void) strcat(ppath, domain);
1276 	(void) strcat(ppath, "/");
1277 	if (yptol_mode)
1278 		(void) strcat(ppath, NTOL_PREFIX);
1279 	(void) strcat(ppath, map);
1280 }
1281 
1282 /*
1283  * This returns a temporary name for a map transfer minus its dbm_dir or
1284  * dbm_pag extensions.
1285  */
1286 void
1287 mk_tmpname(prefix, xfr_name)
1288 	char *prefix;
1289 	char *xfr_name;
1290 {
1291 	char xfr_anumber[10];
1292 	long xfr_number;
1293 
1294 	if (!xfr_name) {
1295 		return;
1296 	}
1297 
1298 	xfr_number = getpid();
1299 	(void) sprintf(xfr_anumber, "%d", xfr_number);
1300 
1301 	(void) strcpy(xfr_name, ypdbpath);
1302 	(void) strcat(xfr_name, "/");
1303 	(void) strcat(xfr_name, domain);
1304 	(void) strcat(xfr_name, "/");
1305 	(void) strcat(xfr_name, prefix);
1306 	(void) strcat(xfr_name, map);
1307 	(void) strcat(xfr_name, ".");
1308 	(void) strcat(xfr_name, xfr_anumber);
1309 }
1310 
1311 /*
1312  * This deletes the .pag and .dir files which implement a map.
1313  *
1314  * Note:  No error checking is done here for a garbage input file name or for
1315  * failed unlink operations.
1316  */
1317 void
1318 del_mapfiles(basename)
1319 	char *basename;
1320 {
1321 	char dbfilename[MAXNAMLEN + 1];
1322 
1323 	if (!basename) {
1324 		return;
1325 	}
1326 
1327 	strcpy(dbfilename, basename);
1328 	strcat(dbfilename, dbm_pag);
1329 	unlink(dbfilename);
1330 	strcpy(dbfilename, basename);
1331 	strcat(dbfilename, dbm_dir);
1332 	unlink(dbfilename);
1333 }
1334 
1335 /*
1336  * This creates <pname>.dir and <pname>.pag
1337  */
1338 bool
1339 new_mapfiles(pname)
1340 	char *pname;
1341 {
1342 	char dbfile[MAXNAMLEN + 1];
1343 	int f;
1344 	int len;
1345 
1346 	if (!pname || ((len = strlen(pname)) == 0) ||
1347 	    (len + 5) > (MAXNAMLEN + 1)) {
1348 		return (FALSE);
1349 	}
1350 
1351 	errno = 0;
1352 	(void) strcpy(dbfile, pname);
1353 	(void) strcat(dbfile, dbm_dir);
1354 
1355 	if ((f = open(dbfile, (O_WRONLY | O_CREAT | O_TRUNC), 0600)) >= 0) {
1356 		(void) close(f);
1357 		(void) strcpy(dbfile, pname);
1358 		(void) strcat(dbfile, dbm_pag);
1359 
1360 		if ((f = open(dbfile, (O_WRONLY | O_CREAT | O_TRUNC),
1361 		    0600)) >= 0) {
1362 			(void) close(f);
1363 			return (TRUE);
1364 		} else {
1365 			return (FALSE);
1366 		}
1367 
1368 	} else {
1369 		return (FALSE);
1370 	}
1371 }
1372 
1373 int
1374 count_callback(status)
1375 	int status;
1376 {
1377 	if (status != YP_TRUE) {
1378 
1379 		if (status != YP_NOMORE) {
1380 			logprintf(
1381 			    "Error from ypserv on %s (ypall_callback) = %s.\n",
1382 			    master, yperr_string(ypprot_err(status)));
1383 		}
1384 
1385 		return (TRUE);
1386 	}
1387 
1388 	entry_count++;
1389 	return (FALSE);
1390 }
1391 
1392 /*
1393  * This counts the entries in the dbm file after the transfer to
1394  * make sure that the dbm file was built correctly.
1395  * Returns TRUE if everything is OK, FALSE if they mismatch.
1396  */
1397 int
1398 count_mismatch(pname, oldcount)
1399 	char *pname;
1400 	int oldcount;
1401 {
1402 	datum key;
1403 	DBM *db;
1404 #ifdef REALLY_PARANOID
1405 	struct ypall_callback cbinfo;
1406 	struct ypreq_nokey allreq;
1407 	enum clnt_stat s;
1408 	struct dom_binding domb;
1409 	datum value;
1410 #endif /* REALLY_PARANOID */
1411 
1412 	entry_count = 0;
1413 	db = dbm_open(pname, 0, 0);
1414 	if (db) {
1415 	    for (key = dbm_firstkey(db);
1416 				key.dptr != NULL; key = dbm_nextkey(db))
1417 		entry_count++;
1418 	    dbm_close_status(db);
1419 	}
1420 
1421 	if (oldcount != entry_count) {
1422 	logprintf(
1423 		    "*** Count mismatch in dbm file %s: old=%d, new=%d ***\n",
1424 		    map, oldcount, entry_count);
1425 	return (FALSE);
1426 	}
1427 
1428 #ifdef REALLY_PARANOID
1429 
1430 	if ((domb.dom_client = __yp_clnt_create_rsvdport(master, YPPROG,
1431 						    master_prog_vers,
1432 						    "tcp6", 0, 0)) == 0 &&
1433 		(domb.dom_client = __yp_clnt_create_rsvdport(master, YPPROG,
1434 						    master_prog_vers,
1435 						    "tcp", 0, 0)) == 0) {
1436 		clnt_pcreateerror("ypxfr (mismatch) - TCP channel "
1437 					"create failure");
1438 		return (FALSE);
1439 	}
1440 
1441 	if (master_prog_vers == YPVERS) {
1442 		int tmpstat;
1443 
1444 		allreq.domain = source;
1445 		allreq.map = map;
1446 		cbinfo.foreach = count_callback;
1447 		tmpstat = 0;
1448 		cbinfo.data = (char *)&tmpstat;
1449 
1450 		entry_count = 0;
1451 		s = clnt_call(domb.dom_client, YPPROC_ALL, xdr_ypreq_nokey,
1452 		    &allreq, xdr_ypall, &cbinfo, tcp_timeout);
1453 
1454 		if (tmpstat == 0) {
1455 			if (s == RPC_SUCCESS) {
1456 			} else {
1457 				clnt_perror(domb.dom_client,
1458 		"ypxfr (get_map/all) - RPC clnt_call (TCP) failure");
1459 		    return (FALSE);
1460 			}
1461 
1462 		} else {
1463 		    return (FALSE);
1464 		}
1465 
1466 	} else {
1467 	    logprintf("Wrong version number!\n");
1468 	    return (FALSE);
1469 	}
1470 	clnt_destroy(domb.dom_client);
1471 	close(domb.dom_socket);
1472 	entry_count += 2;			/* add in YP_entries */
1473 	if (oldcount != entry_count) {
1474 		logprintf(
1475 	"*** Count mismatch after enumerate %s: old=%d, new=%d ***\n",
1476 		    map, oldcount, entry_count);
1477 		return (FALSE);
1478 	}
1479 #endif /* REALLY_PARANOID */
1480 
1481 	return (TRUE);
1482 }
1483 
1484 /*
1485  * This sets up a TCP connection to the master server, and either gets
1486  * ypall_callback to do all the work of writing it to the local dbm file
1487  * (if the ypserv is current version), or does it itself for an old ypserv.
1488  */
1489 bool
1490 get_map(pname, pushstat)
1491 	char *pname;
1492 	int *pushstat;
1493 {
1494 	struct dom_binding domb;
1495 	enum clnt_stat s;
1496 	struct ypreq_nokey allreq;
1497 	struct ypall_callback cbinfo;
1498 	bool retval = FALSE;
1499 	int tmpstat;
1500 	int	recvsiz = 24 * 1024;
1501 	struct netconfig *nconf;
1502 	int fd;
1503 	struct netbuf *svcaddr;
1504 	char *netid[] = { "tcp6", "tcp" };
1505 	int i, lastnetid = (sizeof (netid)/sizeof (netid[0])) - 1;
1506 
1507 	svcaddr = (struct netbuf *)calloc(1, sizeof (struct netbuf));
1508 	if (! svcaddr)
1509 		return (FALSE);
1510 	svcaddr->maxlen = 32;
1511 	svcaddr->len = 32;
1512 	svcaddr->buf = (char *)malloc(32);
1513 	if (! svcaddr->buf) {
1514 		free(svcaddr);
1515 		return (FALSE);
1516 	}
1517 
1518 	for (i = 0; i <= lastnetid; i++) {
1519 		fd = RPC_ANYFD;
1520 		if ((nconf = getnetconfigent(netid[i])) == NULL) {
1521 			if (i != lastnetid)
1522 				continue;
1523 			logprintf("ypxfr: tcp transport not supported\n");
1524 			free(svcaddr->buf);
1525 			free(svcaddr);
1526 			return (FALSE);
1527 		}
1528 		if (rpcb_getaddr(YPPROG, master_prog_vers, nconf, svcaddr,
1529 				master) == FALSE) {
1530 			freenetconfigent(nconf);
1531 			if (i != lastnetid)
1532 				continue;
1533 			logprintf("ypxfr: could not get %s address\n", master);
1534 			free(svcaddr->buf);
1535 			free(svcaddr);
1536 			return (FALSE);
1537 		}
1538 		if ((domb.dom_client = __nis_clnt_create(fd, nconf, 0, svcaddr,
1539 			0, YPPROG, master_prog_vers, recvsiz, 0)) == 0) {
1540 			freenetconfigent(nconf);
1541 			if (i != lastnetid)
1542 				continue;
1543 			clnt_pcreateerror(
1544 				"ypxfr (get_map) - TCP channel create failure");
1545 			*pushstat = YPPUSH_RPC;
1546 			free(svcaddr->buf);
1547 			free(svcaddr);
1548 			return (FALSE);
1549 		}
1550 		break;
1551 	}
1552 
1553 	entry_count = 0;
1554 	if (master_prog_vers == YPVERS) {
1555 		allreq.domain = source;
1556 		allreq.map = map;
1557 		cbinfo.foreach = ypall_callback;
1558 		tmpstat = 0;
1559 		cbinfo.data = (char *)&tmpstat;
1560 
1561 		s = clnt_call(domb.dom_client, YPPROC_ALL,
1562 			(xdrproc_t)xdr_ypreq_nokey,
1563 			(char *)&allreq, (xdrproc_t)xdr_ypall, (char *)&cbinfo,
1564 			tcp_timeout);
1565 
1566 		if (tmpstat == 0) {
1567 
1568 			if (s == RPC_SUCCESS) {
1569 				retval = TRUE;
1570 			} else {
1571 				clnt_perror(domb.dom_client,
1572 			"ypxfr (get_map/all) - RPC clnt_call (TCP) failure");
1573 				*pushstat = YPPUSH_RPC;
1574 			}
1575 
1576 		} else {
1577 			*pushstat = tmpstat;
1578 		}
1579 
1580 	} else
1581 		retval = FALSE; /* barf again at YPOLDVERS */
1582 cleanup:
1583 	clnt_destroy(domb.dom_client);
1584 	return (retval);
1585 }
1586 
1587 /*
1588  * This sticks each key-value pair into the current map.  It returns FALSE as
1589  * long as it wants to keep getting called back, and TRUE on error conditions
1590  * and "No more k-v pairs".
1591  */
1592 int
1593 ypall_callback(status, key, kl, val, vl, pushstat)
1594 	int status;
1595 	char *key;
1596 	int kl;
1597 	char *val;
1598 	int vl;
1599 	int *pushstat;
1600 {
1601 	datum keydat;
1602 	datum valdat;
1603 	datum test;
1604 
1605 	if (status != YP_TRUE) {
1606 
1607 		if (status != YP_NOMORE) {
1608 			logprintf(
1609 			    "Error from ypserv on %s (ypall_callback) = %s.\n",
1610 			    master, yperr_string(ypprot_err(status)));
1611 			*pushstat = map_yperr_to_pusherr(status);
1612 		}
1613 
1614 		return (TRUE);
1615 	}
1616 
1617 	keydat.dptr = key;
1618 	keydat.dsize = kl;
1619 	valdat.dptr = val;
1620 	valdat.dsize = vl;
1621 	entry_count++;
1622 /* way too many fetches */
1623 
1624 #ifdef PARANOID
1625 	test = dbm_fetch(db, keydat);
1626 	if (test.dptr != NULL) {
1627 		logprintf("Duplicate key %s in map %s\n", key, map);
1628 		*pushstat  = YPPUSH_DBM;
1629 		return (TRUE);
1630 	}
1631 #endif /* PARANOID */
1632 	if (dbm_store(db, keydat, valdat, 0) < 0) {
1633 		logprintf(
1634 		    "Can't do dbm store into temp map %s.\n", map);
1635 		*pushstat  = YPPUSH_DBM;
1636 		return (TRUE);
1637 	}
1638 #ifdef PARANOID
1639 	test = dbm_fetch(db, keydat);
1640 	if (test.dptr == NULL) {
1641 		logprintf("Key %s was not inserted into dbm file %s\n",
1642 			key, map);
1643 		*pushstat  = YPPUSH_DBM;
1644 		return (TRUE);
1645 	}
1646 #endif /* PARANOID */
1647 
1648 	if (dbm_error(db)) {
1649 		logprintf("Key %s dbm_error raised in file %s\n",
1650 			key, map);
1651 		*pushstat  = YPPUSH_DBM;
1652 		return (TRUE);
1653 	}
1654 	return (FALSE);
1655 }
1656 
1657 /*
1658  * This maps a YP_xxxx error code into a YPPUSH_xxxx error code
1659  */
1660 int
1661 map_yperr_to_pusherr(yperr)
1662 	int yperr;
1663 {
1664 	int reason;
1665 
1666 	switch (yperr) {
1667 
1668 	case YP_NOMORE:
1669 		reason = YPPUSH_SUCC;
1670 		break;
1671 
1672 	case YP_NOMAP:
1673 		reason = YPPUSH_NOMAP;
1674 		break;
1675 
1676 	case YP_NODOM:
1677 		reason = YPPUSH_NODOM;
1678 		break;
1679 
1680 	case YP_NOKEY:
1681 		reason = YPPUSH_YPERR;
1682 		break;
1683 
1684 	case YP_BADARGS:
1685 		reason = YPPUSH_BADARGS;
1686 		break;
1687 
1688 	case YP_BADDB:
1689 		reason = YPPUSH_YPERR;
1690 		break;
1691 
1692 	default:
1693 		reason = YPPUSH_XFRERR;
1694 		break;
1695 	}
1696 
1697 	return (reason);
1698 }
1699 
1700 /*
1701  * This writes the last-modified and master entries into the new dbm file
1702  */
1703 bool
1704 add_private_entries(pname)
1705 	char *pname;
1706 {
1707 	datum key;
1708 	datum val;
1709 
1710 	if (!fake_master_version) {
1711 		key.dptr = yp_last_modified;
1712 		key.dsize = yp_last_modified_sz;
1713 		val.dptr = master_ascii_version;
1714 		val.dsize = strlen(master_ascii_version);
1715 
1716 		if (dbm_store(db, key, val, 1) < 0) {
1717 			logprintf(
1718 			    "Can't do dbm store into temp map %s.\n",
1719 			    pname);
1720 			return (FALSE);
1721 		}
1722 		entry_count++;
1723 	}
1724 
1725 	if (master_name) {
1726 		key.dptr = yp_master_name;
1727 		key.dsize = yp_master_name_sz;
1728 		val.dptr = master_name;
1729 		val.dsize = strlen(master_name);
1730 		if (dbm_store(db, key, val, 1) < 0) {
1731 			logprintf(
1732 			    "Can't do dbm store into temp map %s.\n",
1733 			    pname);
1734 			return (FALSE);
1735 		}
1736 		entry_count++;
1737 	}
1738 
1739 	if (interdomain_map) {
1740 		key.dptr = yp_interdomain;
1741 		key.dsize = yp_interdomain_sz;
1742 		val.dptr = interdomain_value;
1743 		val.dsize = interdomain_sz;
1744 		if (dbm_store(db, key, val, 1) < 0) {
1745 			logprintf(
1746 			    "Can't do dbm store into temp map %s.\n",
1747 			    pname);
1748 			return (FALSE);
1749 		}
1750 		entry_count++;
1751 	}
1752 
1753 	if (secure_map) {
1754 		key.dptr = yp_secure;
1755 		key.dsize = yp_secure_sz;
1756 		val.dptr = yp_secure;
1757 		val.dsize = yp_secure_sz;
1758 		if (dbm_store(db, key, val, 1) < 0) {
1759 			logprintf(
1760 			    "Can't do dbm store into temp map %s.\n",
1761 			    pname);
1762 			return (FALSE);
1763 		}
1764 		entry_count++;
1765 	}
1766 
1767 	return (TRUE);
1768 }
1769 
1770 
1771 /*
1772  * This sends a YPPROC_CLEAR message to the local ypserv process.
1773  */
1774 bool
1775 send_ypclear(pushstat)
1776 	int *pushstat;
1777 {
1778 	struct dom_binding domb;
1779 	char local_host_name[256];
1780 	unsigned int progvers;
1781 	int status;
1782 
1783 	if (gethostname(local_host_name, 256)) {
1784 		logprintf("Can't get local machine name.\n");
1785 		*pushstat = YPPUSH_RSRC;
1786 		return (FALSE);
1787 	}
1788 
1789 	if (!bind_to_server(local_host_name, &domb,
1790 	    &progvers, &status)) {
1791 		*pushstat = YPPUSH_CLEAR;
1792 		return (FALSE);
1793 	}
1794 
1795 	if ((enum clnt_stat) clnt_call(domb.dom_client,
1796 	    YPPROC_CLEAR, xdr_void, 0, xdr_void, 0,
1797 	    udp_timeout) != RPC_SUCCESS) {
1798 		logprintf(
1799 		"Can't send ypclear message to ypserv on the local machine.\n");
1800 		xfr_exit(YPPUSH_CLEAR);
1801 	}
1802 
1803 	return (TRUE);
1804 }
1805 
1806 /*
1807  * This decides if send_callback has to get called, and does the process exit.
1808  */
1809 void
1810 xfr_exit(status)
1811 	int status;
1812 {
1813 	if (callback) {
1814 		send_callback(&status);
1815 	}
1816 
1817 	if (status == YPPUSH_SUCC) {
1818 #ifdef TREEPUSH
1819 		if (treepush) {
1820 		if (debug)
1821 		execlp("./yppush", "yppush", "-T", map, 0);
1822 		execlp("/usr/etc/yp/yppush", "yppush", "-T", map, 0);
1823 		perror("yppush");
1824 		}
1825 #endif
1826 		exit(0);
1827 	} else {
1828 		exit(1);
1829 	}
1830 }
1831 
1832 /*
1833  * This sets up a UDP connection to the yppush process which contacted our
1834  * parent ypserv, and sends him a status on the requested transfer.
1835  */
1836 void
1837 send_callback(status)
1838 	int *status;
1839 {
1840 	struct yppushresp_xfr resp;
1841 	struct dom_binding domb;
1842 
1843 	resp.transid = (unsigned long) atoi(tid);
1844 	resp.status = (unsigned long) *status;
1845 
1846 	udp_timeout.tv_sec = CALLTIMEOUT;
1847 
1848 	if ((domb.dom_client = __yp_clnt_create_rsvdport(pushhost,
1849 						    (ulong_t)atoi(proto),
1850 						    YPPUSHVERS,
1851 						    0, 0, 0)) == NULL) {
1852 		*status = YPPUSH_RPC;
1853 		return;
1854 	}
1855 
1856 	if ((enum clnt_stat) clnt_call(domb.dom_client,
1857 	    YPPUSHPROC_XFRRESP, (xdrproc_t)xdr_yppushresp_xfr,
1858 	    (char *)&resp, xdr_void, 0,
1859 	    udp_timeout) != RPC_SUCCESS) {
1860 		*status = YPPUSH_RPC;
1861 		return;
1862 	}
1863 }
1864 
1865 /*
1866  * FUNCTION:    is_yptol_mode();
1867  *
1868  * DESCRIPTION: Determines if we should run in N2L or traditional mode based
1869  *              on the presence of the N2L mapping file.
1870  *
1871  *		This is a copy of a function from libnisdb. If more than this
1872  *		one function become required it may be worth linking the
1873  *		entire lib.
1874  *
1875  * INPUTS:      Nothing
1876  *
1877  * OUTPUTS:     TRUE = Run in N2L mode
1878  *              FALSE = Run in traditional mode.
1879  */
1880 bool_t
1881 is_yptol_mode()
1882 {
1883 	struct stat filestat;
1884 
1885 	if (stat(NTOL_MAP_FILE, &filestat) != -1)
1886 		return (TRUE);
1887 
1888 	return (FALSE);
1889 }
1890