1331722Seadler/*
213007Swpaul * Copyright (c) 1995
313007Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
413007Swpaul *
513007Swpaul * Redistribution and use in source and binary forms, with or without
613007Swpaul * modification, are permitted provided that the following conditions
713007Swpaul * are met:
813007Swpaul * 1. Redistributions of source code must retain the above copyright
913007Swpaul *    notice, this list of conditions and the following disclaimer.
1013007Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1113007Swpaul *    notice, this list of conditions and the following disclaimer in the
1213007Swpaul *    documentation and/or other materials provided with the distribution.
1313007Swpaul * 3. All advertising materials mentioning features or use of this software
1413007Swpaul *    must display the following acknowledgement:
1513007Swpaul *	This product includes software developed by Bill Paul.
1613007Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1713007Swpaul *    may be used to endorse or promote products derived from this software
1813007Swpaul *    without specific prior written permission.
1913007Swpaul *
2013007Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2113007Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2213007Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2313007Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
2413007Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2513007Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2613007Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2713007Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2813007Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2913007Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3013007Swpaul * SUCH DAMAGE.
3113007Swpaul */
3231626Scharnier
33114626Sobrien#include <sys/cdefs.h>
34114626Sobrien__FBSDID("$FreeBSD: stable/11/libexec/ypxfr/ypxfr_main.c 359754 2020-04-09 20:38:36Z kevans $");
3531626Scharnier
3631626Scharnier#include <errno.h>
3713007Swpaul#include <stdio.h>
3813007Swpaul#include <stdlib.h>
3913007Swpaul#include <string.h>
4013007Swpaul#include <syslog.h>
4131626Scharnier#include <unistd.h>
4213007Swpaul#include <sys/types.h>
4313007Swpaul#include <sys/param.h>
4413007Swpaul#include <sys/socket.h>
4513007Swpaul#include <netinet/in.h>
4613007Swpaul#include <arpa/inet.h>
4713007Swpaul#include <rpc/rpc.h>
4813376Swpaul#include <rpc/clnt.h>
4913007Swpaul#include <rpcsvc/yp.h>
5013007Swpaul#include <rpcsvc/ypclnt.h>
5116132Swpaul#include <rpcsvc/ypxfrd.h>
5213007Swpaul#include "ypxfr_extern.h"
5313007Swpaul
54359754Skevansint debug = 1;
55359754Skevans
5613007Swpaulchar *progname = "ypxfr";
5713007Swpaulchar *yp_dir = _PATH_YP;
5813007Swpaulint _rpcpmstart = 0;
59285926Saraujostatic int ypxfr_use_yplib = 0; /* Assume the worst. */
60285926Saraujostatic int ypxfr_clear = 1;
61285926Saraujostatic int ypxfr_prognum = 0;
62285926Saraujostatic struct sockaddr_in ypxfr_callback_addr;
63285926Saraujostatic struct yppushresp_xfr ypxfr_resp;
64285926Saraujostatic DB *dbp;
6513007Swpaul
6690298Sdesstatic void
6790298Sdesypxfr_exit(ypxfrstat retval, char *temp)
6813007Swpaul{
6913007Swpaul	CLIENT *clnt;
7013007Swpaul	int sock = RPC_ANYSOCK;
7113007Swpaul	struct timeval timeout;
7213007Swpaul
7313007Swpaul	/* Clean up no matter what happened previously. */
7413007Swpaul	if (temp != NULL) {
7513276Swpaul		if (dbp != NULL)
7613276Swpaul			(void)(dbp->close)(dbp);
7713007Swpaul		if (unlink(temp) == -1) {
7813007Swpaul			yp_error("failed to unlink %s",strerror(errno));
7913007Swpaul		}
8013007Swpaul	}
8113007Swpaul
8246929Swpaul	if (ypxfr_prognum) {
8313007Swpaul		timeout.tv_sec = 20;
8413007Swpaul		timeout.tv_usec = 0;
8513007Swpaul
8613007Swpaul		if ((clnt = clntudp_create(&ypxfr_callback_addr, ypxfr_prognum,
8713007Swpaul					1, timeout, &sock)) == NULL) {
8846929Swpaul			yp_error("%s", clnt_spcreateerror("failed to "
8946929Swpaul			    "establish callback handle"));
9013007Swpaul			exit(1);
9113007Swpaul		}
9213007Swpaul
93228600Sdim		ypxfr_resp.status = (yppush_status)retval;
9413007Swpaul
9513007Swpaul		if (yppushproc_xfrresp_1(&ypxfr_resp, clnt) == NULL) {
9613007Swpaul			yp_error("%s", clnt_sperror(clnt, "callback failed"));
9713007Swpaul			clnt_destroy(clnt);
9813007Swpaul			exit(1);
9913007Swpaul		}
10013007Swpaul		clnt_destroy(clnt);
10113007Swpaul	} else {
10213007Swpaul		yp_error("Exiting: %s", ypxfrerr_string(retval));
10313007Swpaul	}
10413007Swpaul
10513007Swpaul	exit(0);
10613007Swpaul}
10713007Swpaul
10890298Sdesstatic void
10990298Sdesusage(void)
11013007Swpaul{
11113007Swpaul	if (_rpcpmstart) {
11213007Swpaul		ypxfr_exit(YPXFR_BADARGS,NULL);
11313007Swpaul	} else {
11431626Scharnier		fprintf(stderr, "%s\n%s\n%s\n",
11531626Scharnier	"usage: ypxfr [-f] [-c] [-d target domain] [-h source host]",
11631626Scharnier	"             [-s source domain] [-p path]",
11731626Scharnier	"             [-C taskid program-number ipaddr port] mapname");
11813007Swpaul		exit(1);
11913007Swpaul	}
12013007Swpaul}
12113007Swpaul
12290298Sdesint
12390298Sdesypxfr_foreach(int status, char *key, int keylen, char *val, int vallen,
12490298Sdes    char *data)
12513007Swpaul{
12613007Swpaul	DBT dbkey, dbval;
12713007Swpaul
12813007Swpaul	if (status != YP_TRUE)
12913007Swpaul		return (status);
13013007Swpaul
13130008Swpaul	/*
13230008Swpaul	 * XXX Do not attempt to write zero-length keys or
13330008Swpaul	 * data into a Berkeley DB hash database. It causes a
13430008Swpaul	 * strange failure mode where sequential searches get
13530008Swpaul	 * caught in an infinite loop.
13630008Swpaul	 */
13730008Swpaul	if (keylen) {
13830008Swpaul		dbkey.data = key;
13930008Swpaul		dbkey.size = keylen;
14030008Swpaul	} else {
14130008Swpaul		dbkey.data = "";
14230008Swpaul		dbkey.size = 1;
14330008Swpaul	}
14430008Swpaul	if (vallen) {
14530008Swpaul		dbval.data = val;
14630008Swpaul		dbval.size = vallen;
14730008Swpaul	} else {
14830008Swpaul		dbval.data = "";
14930008Swpaul		dbval.size = 1;
15030008Swpaul	}
15113007Swpaul
15216132Swpaul	if (yp_put_record(dbp, &dbkey, &dbval, 0) != YP_TRUE)
15313007Swpaul		return(yp_errno);
15413007Swpaul
15513007Swpaul	return (0);
15613007Swpaul}
15713007Swpaul
15831626Scharnierint
15990298Sdesmain(int argc, char *argv[])
16013007Swpaul{
16113007Swpaul	int ch;
16213007Swpaul	int ypxfr_force = 0;
16313007Swpaul	char *ypxfr_dest_domain = NULL;
16413007Swpaul	char *ypxfr_source_host = NULL;
16513007Swpaul	char *ypxfr_source_domain = NULL;
16613007Swpaul	char *ypxfr_local_domain = NULL;
16713007Swpaul	char *ypxfr_master = NULL;
16813007Swpaul	unsigned long ypxfr_order = -1, ypxfr_skew_check = -1;
16913007Swpaul	char *ypxfr_mapname = NULL;
17013007Swpaul	int ypxfr_args = 0;
17113007Swpaul	char ypxfr_temp_map[MAXPATHLEN + 2];
17213007Swpaul	char tempmap[MAXPATHLEN + 2];
17313007Swpaul	char buf[MAXPATHLEN + 2];
17413007Swpaul	DBT key, data;
17519065Swpaul	int remoteport;
17619181Swpaul	int interdom = 0;
17719181Swpaul	int secure = 0;
17813007Swpaul
17913007Swpaul	if (!isatty(fileno(stderr))) {
18031626Scharnier		openlog("ypxfr", LOG_PID, LOG_DAEMON);
18113007Swpaul		_rpcpmstart = 1;
18213007Swpaul	}
18313007Swpaul
18413007Swpaul	if (argc < 2)
18513007Swpaul		usage();
18613007Swpaul
18724349Simp	while ((ch = getopt(argc, argv, "fcd:h:s:p:C:")) != -1) {
18813007Swpaul		int my_optind;
18990297Sdes		switch (ch) {
19013007Swpaul		case 'f':
19113007Swpaul			ypxfr_force++;
19213007Swpaul			ypxfr_args++;
19313007Swpaul			break;
19413007Swpaul		case 'c':
19513007Swpaul			ypxfr_clear = 0;
19613007Swpaul			ypxfr_args++;
19713007Swpaul			break;
19813007Swpaul		case 'd':
19913007Swpaul			ypxfr_dest_domain = optarg;
20013007Swpaul			ypxfr_args += 2;
20113007Swpaul			break;
20213007Swpaul		case 'h':
20313007Swpaul			ypxfr_source_host = optarg;
20413007Swpaul			ypxfr_args += 2;
20513007Swpaul			break;
20613007Swpaul		case 's':
20713007Swpaul			ypxfr_source_domain = optarg;
20813007Swpaul			ypxfr_args += 2;
20913007Swpaul			break;
21013007Swpaul		case 'p':
21113007Swpaul			yp_dir = optarg;
21213007Swpaul			ypxfr_args += 2;
21313007Swpaul			break;
21413007Swpaul		case 'C':
21513007Swpaul			/*
21613007Swpaul			 * Whoever decided that the -C flag should take
21713007Swpaul			 * four arguments is a twit.
21813007Swpaul			 */
21913007Swpaul			my_optind = optind - 1;
22013007Swpaul			if (argv[my_optind] == NULL || !strlen(argv[my_optind])) {
22113007Swpaul				yp_error("transaction ID not specified");
22213007Swpaul				usage();
22313007Swpaul			}
22413007Swpaul			ypxfr_resp.transid = atol(argv[my_optind]);
22513007Swpaul			my_optind++;
22613007Swpaul			if (argv[my_optind] == NULL || !strlen(argv[my_optind])) {
22713007Swpaul				yp_error("RPC program number not specified");
22813007Swpaul				usage();
22913007Swpaul			}
23013007Swpaul			ypxfr_prognum = atol(argv[my_optind]);
23113007Swpaul			my_optind++;
23213007Swpaul			if (argv[my_optind] == NULL || !strlen(argv[my_optind])) {
23313007Swpaul				yp_error("address not specified");
23413007Swpaul				usage();
23513007Swpaul			}
23613007Swpaul			if (!inet_aton(argv[my_optind], &ypxfr_callback_addr.sin_addr)) {
23713007Swpaul				yp_error("failed to convert '%s' to IP addr",
23813007Swpaul					argv[my_optind]);
23913007Swpaul				exit(1);
24013007Swpaul			}
24113007Swpaul			my_optind++;
24213007Swpaul			if (argv[my_optind] == NULL || !strlen(argv[my_optind])) {
24313007Swpaul				yp_error("port not specified");
24413007Swpaul				usage();
24513007Swpaul			}
24613007Swpaul			ypxfr_callback_addr.sin_port = htons((u_short)atoi(argv[my_optind]));
24713007Swpaul			ypxfr_args += 5;
24813007Swpaul			break;
24913007Swpaul		default:
25013007Swpaul			usage();
25113007Swpaul			break;
25213007Swpaul		}
25313007Swpaul	}
25413007Swpaul
25513007Swpaul	ypxfr_mapname = argv[ypxfr_args + 1];
25613007Swpaul
25713007Swpaul	if (ypxfr_mapname == NULL) {
25813007Swpaul		yp_error("no map name specified");
25913007Swpaul		usage();
26013007Swpaul	}
26113007Swpaul
26213007Swpaul	/* Always the case. */
26313007Swpaul	ypxfr_callback_addr.sin_family = AF_INET;
26413007Swpaul
26513007Swpaul	/* Determine if local NIS client facilities are turned on. */
26613007Swpaul	if (!yp_get_default_domain(&ypxfr_local_domain) &&
26713007Swpaul	    _yp_check(&ypxfr_local_domain))
26813007Swpaul		ypxfr_use_yplib = 1;
26913007Swpaul
27013007Swpaul	/*
27113007Swpaul	 * If no destination domain is specified, assume that the
27213007Swpaul	 * local default domain is to be used and try to obtain it.
27313007Swpaul	 * Fails if NIS client facilities are turned off.
27413007Swpaul	 */
27513007Swpaul	if (ypxfr_dest_domain == NULL) {
27613007Swpaul		if (ypxfr_use_yplib) {
27713007Swpaul			yp_get_default_domain(&ypxfr_dest_domain);
27813007Swpaul		} else {
27913007Swpaul			yp_error("no destination domain specified and \
28013007Swpaulthe local domain name isn't set");
28113007Swpaul			ypxfr_exit(YPXFR_BADARGS,NULL);
28213007Swpaul		}
28313007Swpaul	}
28413007Swpaul
28513007Swpaul	/*
28613007Swpaul	 * If a source domain is not specified, assume it to
28713007Swpaul	 * be the same as the destination domain.
28813007Swpaul	 */
28913007Swpaul	if (ypxfr_source_domain == NULL) {
29013007Swpaul		ypxfr_source_domain = ypxfr_dest_domain;
29113007Swpaul	}
29213007Swpaul
29313007Swpaul	/*
29413007Swpaul	 * If the source host is not specified, assume it to be the
29513007Swpaul	 * master for the specified map. If local NIS client facilities
29613007Swpaul	 * are turned on, we can figure this out using yp_master().
29713007Swpaul	 * If not, we have to see if a local copy of the map exists
29813007Swpaul	 * and extract its YP_MASTER_NAME record. If _that_ fails,
29913007Swpaul	 * we are stuck and must ask the user for more information.
30013007Swpaul	 */
30113007Swpaul	if (ypxfr_source_host == NULL) {
30213007Swpaul		if (!ypxfr_use_yplib) {
30313007Swpaul		/*
30413007Swpaul		 * Double whammy: NIS isn't turned on and the user
30513007Swpaul		 * didn't specify a source host.
30613007Swpaul		 */
30713007Swpaul			char *dptr;
30813007Swpaul			key.data = "YP_MASTER_NAME";
30913007Swpaul			key.size = sizeof("YP_MASTER_NAME") - 1;
31013007Swpaul
31113007Swpaul			if (yp_get_record(ypxfr_dest_domain, ypxfr_mapname,
31213007Swpaul					 &key, &data, 1) != YP_TRUE) {
31313007Swpaul				yp_error("no source host specified");
31413007Swpaul				ypxfr_exit(YPXFR_BADARGS,NULL);
31513007Swpaul			}
31613007Swpaul			dptr = data.data;
31713007Swpaul			dptr[data.size] = '\0';
31813007Swpaul			ypxfr_master = ypxfr_source_host = strdup(dptr);
31913007Swpaul		}
32013007Swpaul	} else {
32113007Swpaul		if (ypxfr_use_yplib)
32213007Swpaul			ypxfr_use_yplib = 0;
32313007Swpaul	}
32413007Swpaul
32513007Swpaul	if (ypxfr_master == NULL) {
32613007Swpaul		if ((ypxfr_master = ypxfr_get_master(ypxfr_source_domain,
32713007Swpaul					    	 ypxfr_mapname,
32813007Swpaul					     	ypxfr_source_host,
32913007Swpaul					     	ypxfr_use_yplib)) == NULL) {
33013276Swpaul			yp_error("failed to find master of %s in domain %s: %s",
33113276Swpaul				  ypxfr_mapname, ypxfr_source_domain,
332228600Sdim				  ypxfrerr_string((ypxfrstat)yp_errno));
33313007Swpaul			ypxfr_exit(YPXFR_MADDR,NULL);
33413007Swpaul		}
33513007Swpaul	}
33613007Swpaul
33713007Swpaul	/*
33813007Swpaul	 * If we got here and ypxfr_source_host is still undefined,
33913007Swpaul	 * it means we had to resort to using yp_master() to find the
34013007Swpaul	 * master server for the map. The source host and master should
34113007Swpaul	 * be identical.
34213007Swpaul	 */
34313007Swpaul	if (ypxfr_source_host == NULL)
34413007Swpaul		ypxfr_source_host = ypxfr_master;
34513007Swpaul
34619065Swpaul	/*
34719065Swpaul	 * Don't talk to ypservs on unprivileged ports.
34819065Swpaul	 */
34919065Swpaul	remoteport = getrpcport(ypxfr_source_host, YPPROG, YPVERS, IPPROTO_UDP);
35019065Swpaul	if (remoteport >= IPPORT_RESERVED) {
35119065Swpaul		yp_error("ypserv on %s not running on reserved port",
35219065Swpaul						ypxfr_source_host);
35319065Swpaul		ypxfr_exit(YPXFR_REFUSED, NULL);
35419065Swpaul	}
35519065Swpaul
35613007Swpaul	if ((ypxfr_order = ypxfr_get_order(ypxfr_source_domain,
35713007Swpaul					     ypxfr_mapname,
35813007Swpaul					     ypxfr_master, 0)) == 0) {
35913276Swpaul		yp_error("failed to get order number of %s: %s",
360283844Srodrigc				ypxfr_mapname, yp_errno == YP_TRUE ?
361228600Sdim				"map has order 0" :
362228600Sdim				ypxfrerr_string((ypxfrstat)yp_errno));
36313007Swpaul		ypxfr_exit(YPXFR_YPERR,NULL);
36413007Swpaul	}
36513007Swpaul
36619181Swpaul	if (ypxfr_match(ypxfr_master, ypxfr_source_domain, ypxfr_mapname,
36719181Swpaul			"YP_INTERDOMAIN", sizeof("YP_INTERDOMAIN") - 1))
36819181Swpaul		interdom++;
36919181Swpaul
37019181Swpaul	if (ypxfr_match(ypxfr_master, ypxfr_source_domain, ypxfr_mapname,
37119181Swpaul			"YP_SECURE", sizeof("YP_SECURE") - 1))
37219181Swpaul		secure++;
37319181Swpaul
37413007Swpaul	key.data = "YP_LAST_MODIFIED";
37513007Swpaul	key.size = sizeof("YP_LAST_MODIFIED") - 1;
37690297Sdes
37713007Swpaul	/* The order number is immaterial when the 'force' flag is set. */
37813007Swpaul
37913007Swpaul	if (!ypxfr_force) {
38013007Swpaul		int ignore = 0;
38113007Swpaul		if (yp_get_record(ypxfr_dest_domain,ypxfr_mapname,&key,&data,1) != YP_TRUE) {
38290297Sdes			switch (yp_errno) {
38313007Swpaul			case YP_NOKEY:
38413007Swpaul				ypxfr_exit(YPXFR_FORCE,NULL);
38513007Swpaul				break;
38613007Swpaul			case YP_NOMAP:
38713007Swpaul				/*
38813007Swpaul				 * If the map doesn't exist, we're
38913007Swpaul				 * creating it. Ignore the error.
39013007Swpaul				 */
39113007Swpaul				ignore++;
39213007Swpaul				break;
39313007Swpaul			case YP_BADDB:
39413007Swpaul			default:
39513007Swpaul				ypxfr_exit(YPXFR_DBM,NULL);
39613007Swpaul				break;
39713007Swpaul			}
39813007Swpaul		}
39913007Swpaul		if (!ignore && ypxfr_order <= atoi(data.data))
40013007Swpaul			ypxfr_exit(YPXFR_AGE, NULL);
40113007Swpaul
40213007Swpaul	}
40313007Swpaul
40413007Swpaul	/* Construct a temporary map file name */
40513007Swpaul	snprintf(tempmap, sizeof(tempmap), "%s.%d",ypxfr_mapname, getpid());
40613007Swpaul	snprintf(ypxfr_temp_map, sizeof(ypxfr_temp_map), "%s/%s/%s", yp_dir,
40713007Swpaul		 ypxfr_dest_domain, tempmap);
40813007Swpaul
40919065Swpaul	if ((remoteport = getrpcport(ypxfr_source_host, YPXFRD_FREEBSD_PROG,
41019065Swpaul					YPXFRD_FREEBSD_VERS, IPPROTO_TCP))) {
41119065Swpaul
41219065Swpaul		/* Don't talk to rpc.ypxfrds on unprovileged ports. */
41319065Swpaul		if (remoteport >= IPPORT_RESERVED) {
41419065Swpaul			yp_error("rpc.ypxfrd on %s not using privileged port",
41519065Swpaul							ypxfr_source_host);
41619065Swpaul			ypxfr_exit(YPXFR_REFUSED, NULL);
41719065Swpaul		}
41819065Swpaul
41916132Swpaul		/* Try to send using ypxfrd. If it fails, use old method. */
42019065Swpaul		if (!ypxfrd_get_map(ypxfr_source_host, ypxfr_mapname,
42116132Swpaul					ypxfr_source_domain, ypxfr_temp_map))
42216132Swpaul			goto leave;
42316132Swpaul	}
42416132Swpaul
42513007Swpaul	/* Open the temporary map read/write. */
42616132Swpaul	if ((dbp = yp_open_db_rw(ypxfr_dest_domain, tempmap, 0)) == NULL) {
42713007Swpaul		yp_error("failed to open temporary map file");
42813007Swpaul		ypxfr_exit(YPXFR_DBM,NULL);
42913007Swpaul	}
43013007Swpaul
43113007Swpaul	/*
43213007Swpaul	 * Fill in the keys we already know, such as the order number,
43313007Swpaul	 * master name, input file name (we actually make up a bogus
43413007Swpaul	 * name for that) and output file name.
43513007Swpaul	 */
43638024Sbde	snprintf(buf, sizeof(buf), "%lu", ypxfr_order);
43713007Swpaul	data.data = buf;
43813007Swpaul	data.size = strlen(buf);
43913007Swpaul
44016132Swpaul	if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
44113007Swpaul		yp_error("failed to write order number to database");
44293979Sdes		ypxfr_exit(YPXFR_DBM,ypxfr_temp_map);
44313007Swpaul	}
44413007Swpaul
44513007Swpaul	key.data = "YP_MASTER_NAME";
44613007Swpaul	key.size = sizeof("YP_MASTER_NAME") - 1;
44713007Swpaul	data.data = ypxfr_master;
44813007Swpaul	data.size = strlen(ypxfr_master);
44913007Swpaul
45016132Swpaul	if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
45113007Swpaul		yp_error("failed to write master name to database");
45293979Sdes		ypxfr_exit(YPXFR_DBM,ypxfr_temp_map);
45313007Swpaul	}
45413007Swpaul
45513007Swpaul	key.data = "YP_DOMAIN_NAME";
45613007Swpaul	key.size = sizeof("YP_DOMAIN_NAME") - 1;
45713007Swpaul	data.data = ypxfr_dest_domain;
45813007Swpaul	data.size = strlen(ypxfr_dest_domain);
45913007Swpaul
46016132Swpaul	if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
46113007Swpaul		yp_error("failed to write domain name to database");
46293979Sdes		ypxfr_exit(YPXFR_DBM,ypxfr_temp_map);
46313007Swpaul	}
46413007Swpaul
46513007Swpaul	snprintf (buf, sizeof(buf), "%s:%s", ypxfr_source_host, ypxfr_mapname);
46613007Swpaul
46713007Swpaul	key.data = "YP_INPUT_NAME";
46813007Swpaul	key.size = sizeof("YP_INPUT_NAME") - 1;
46913007Swpaul	data.data = &buf;
47013007Swpaul	data.size = strlen(buf);
47113007Swpaul
47216132Swpaul	if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
47313007Swpaul		yp_error("failed to write input name to database");
47493979Sdes		ypxfr_exit(YPXFR_DBM,ypxfr_temp_map);
47513007Swpaul
47613007Swpaul	}
47713007Swpaul
47813007Swpaul	snprintf(buf, sizeof(buf), "%s/%s/%s", yp_dir, ypxfr_dest_domain,
47913007Swpaul							ypxfr_mapname);
48013007Swpaul
48113007Swpaul	key.data = "YP_OUTPUT_NAME";
48213007Swpaul	key.size = sizeof("YP_OUTPUT_NAME") - 1;
48313007Swpaul	data.data = &buf;
48413007Swpaul	data.size = strlen(buf);
48513007Swpaul
48616132Swpaul	if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
48713007Swpaul		yp_error("failed to write output name to database");
48893979Sdes		ypxfr_exit(YPXFR_DBM,ypxfr_temp_map);
48913007Swpaul	}
49013007Swpaul
49119181Swpaul	if (interdom) {
49219181Swpaul		key.data = "YP_INTERDOMAIN";
49319181Swpaul		key.size = sizeof("YP_INTERDOMAIN") - 1;
49419181Swpaul		data.data = "";
49519181Swpaul		data.size = 0;
49619181Swpaul
49719181Swpaul		if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
49819181Swpaul			yp_error("failed to add interdomain flag to database");
49993979Sdes			ypxfr_exit(YPXFR_DBM,ypxfr_temp_map);
50019181Swpaul		}
50119181Swpaul	}
50219181Swpaul
50319181Swpaul	if (secure) {
50419181Swpaul		key.data = "YP_SECURE";
50519181Swpaul		key.size = sizeof("YP_SECURE") - 1;
50619181Swpaul		data.data = "";
50719181Swpaul		data.size = 0;
50819181Swpaul
50919181Swpaul		if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
51019181Swpaul			yp_error("failed to add secure flag to database");
51193979Sdes			ypxfr_exit(YPXFR_DBM,ypxfr_temp_map);
51219181Swpaul		}
51319181Swpaul	}
51419181Swpaul
51513007Swpaul	/* Now suck over the contents of the map from the master. */
51613007Swpaul
51713007Swpaul	if (ypxfr_get_map(ypxfr_mapname,ypxfr_source_domain,
51813007Swpaul			  ypxfr_source_host, ypxfr_foreach)){
51913007Swpaul		yp_error("failed to retrieve map from source host");
52093979Sdes		ypxfr_exit(YPXFR_YPERR,ypxfr_temp_map);
52113007Swpaul	}
52213007Swpaul
52313007Swpaul	(void)(dbp->close)(dbp);
52413276Swpaul	dbp = NULL; /* <- yes, it seems this is necessary. */
52513007Swpaul
52616132Swpaulleave:
52716132Swpaul
52816132Swpaul	snprintf(buf, sizeof(buf), "%s/%s/%s", yp_dir, ypxfr_dest_domain,
52916132Swpaul							ypxfr_mapname);
53016132Swpaul
53113007Swpaul	/* Peek at the order number again and check for skew. */
53213007Swpaul	if ((ypxfr_skew_check = ypxfr_get_order(ypxfr_source_domain,
53313007Swpaul					     ypxfr_mapname,
53413007Swpaul					     ypxfr_master, 0)) == 0) {
53513276Swpaul		yp_error("failed to get order number of %s: %s",
536283844Srodrigc				ypxfr_mapname, yp_errno == YP_TRUE ?
537228600Sdim				"map has order 0" :
538228600Sdim				ypxfrerr_string((ypxfrstat)yp_errno));
53993979Sdes		ypxfr_exit(YPXFR_YPERR,ypxfr_temp_map);
54013007Swpaul	}
54113007Swpaul
54213007Swpaul	if (ypxfr_order != ypxfr_skew_check)
54393979Sdes		ypxfr_exit(YPXFR_SKEW,ypxfr_temp_map);
54413007Swpaul
54513007Swpaul	/*
54613007Swpaul	 * Send a YPPROC_CLEAR to the local ypserv.
54713007Swpaul	 */
54813376Swpaul	if (ypxfr_clear) {
54913007Swpaul		char in = 0;
55013007Swpaul		char *out = NULL;
55113376Swpaul		int stat;
55213376Swpaul		if ((stat = callrpc("localhost",YPPROG,YPVERS,YPPROC_CLEAR,
553121538Speter			(xdrproc_t)xdr_void, (void *)&in,
554121538Speter			(xdrproc_t)xdr_void, (void *)out)) != RPC_SUCCESS) {
55513376Swpaul			yp_error("failed to send 'clear' to local ypserv: %s",
55613376Swpaul				 clnt_sperrno((enum clnt_stat) stat));
55793979Sdes			ypxfr_exit(YPXFR_CLEAR, ypxfr_temp_map);
55813007Swpaul		}
55913007Swpaul	}
56013007Swpaul
56113376Swpaul	/*
56213376Swpaul	 * Put the new map in place immediately. I'm not sure if the
56313376Swpaul	 * kernel does an unlink() and rename() atomically in the event
56413376Swpaul	 * that we move a new copy of a map over the top of an existing
56513376Swpaul	 * one, but there's less chance of a race condition happening
56613376Swpaul	 * than if we were to do the unlink() ourselves.
56713376Swpaul	 */
56813007Swpaul	if (rename(ypxfr_temp_map, buf) == -1) {
56913007Swpaul		yp_error("rename(%s,%s) failed: %s", ypxfr_temp_map, buf,
57013007Swpaul							strerror(errno));
57113007Swpaul		ypxfr_exit(YPXFR_FILE,NULL);
57213007Swpaul	}
57313007Swpaul
57413007Swpaul	ypxfr_exit(YPXFR_SUCC,NULL);
57513007Swpaul
57613007Swpaul	return(1);
57713007Swpaul}
578