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