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