ypxfr_main.c revision 90298
113007Swpaul/*
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
3331626Scharnier#ifndef lint
3431626Scharnierstatic const char rcsid[] =
3550476Speter  "$FreeBSD: head/libexec/ypxfr/ypxfr_main.c 90298 2002-02-06 15:26:07Z des $";
3631626Scharnier#endif /* not lint */
3731626Scharnier
3831626Scharnier#include <errno.h>
3913007Swpaul#include <stdio.h>
4013007Swpaul#include <stdlib.h>
4113007Swpaul#include <string.h>
4213007Swpaul#include <syslog.h>
4331626Scharnier#include <unistd.h>
4413007Swpaul#include <sys/types.h>
4513007Swpaul#include <sys/param.h>
4613007Swpaul#include <sys/socket.h>
4713007Swpaul#include <netinet/in.h>
4813007Swpaul#include <arpa/inet.h>
4913007Swpaul#include <rpc/rpc.h>
5013376Swpaul#include <rpc/clnt.h>
5113007Swpaul#include <rpcsvc/yp.h>
5213007Swpaulstruct dom_binding {};
5313007Swpaul#include <rpcsvc/ypclnt.h>
5416132Swpaul#include <rpcsvc/ypxfrd.h>
5513007Swpaul#include "ypxfr_extern.h"
5613007Swpaul
5713007Swpaulchar *progname = "ypxfr";
5813007Swpaulchar *yp_dir = _PATH_YP;
5913007Swpaulint _rpcpmstart = 0;
6013007Swpaulint ypxfr_use_yplib = 0; /* Assume the worst. */
6113007Swpaulint ypxfr_clear = 1;
6213007Swpaulint ypxfr_prognum = 0;
6313007Swpaulstruct sockaddr_in ypxfr_callback_addr;
6413007Swpaulstruct yppushresp_xfr ypxfr_resp;
6513007SwpaulDB *dbp;
6613007Swpaul
6790298Sdesstatic void
6890298Sdesypxfr_exit(ypxfrstat retval, char *temp)
6913007Swpaul{
7013007Swpaul	CLIENT *clnt;
7113007Swpaul	int sock = RPC_ANYSOCK;
7213007Swpaul	struct timeval timeout;
7313007Swpaul
7413007Swpaul	/* Clean up no matter what happened previously. */
7513007Swpaul	if (temp != NULL) {
7613276Swpaul		if (dbp != NULL)
7713276Swpaul			(void)(dbp->close)(dbp);
7813007Swpaul		if (unlink(temp) == -1) {
7913007Swpaul			yp_error("failed to unlink %s",strerror(errno));
8013007Swpaul		}
8113007Swpaul	}
8213007Swpaul
8346929Swpaul	if (ypxfr_prognum) {
8413007Swpaul		timeout.tv_sec = 20;
8513007Swpaul		timeout.tv_usec = 0;
8613007Swpaul
8713007Swpaul		if ((clnt = clntudp_create(&ypxfr_callback_addr, ypxfr_prognum,
8813007Swpaul					1, timeout, &sock)) == NULL) {
8946929Swpaul			yp_error("%s", clnt_spcreateerror("failed to "
9046929Swpaul			    "establish callback handle"));
9113007Swpaul			exit(1);
9213007Swpaul		}
9313007Swpaul
9413007Swpaul		ypxfr_resp.status = retval;
9513007Swpaul
9613007Swpaul		if (yppushproc_xfrresp_1(&ypxfr_resp, clnt) == NULL) {
9713007Swpaul			yp_error("%s", clnt_sperror(clnt, "callback failed"));
9813007Swpaul			clnt_destroy(clnt);
9913007Swpaul			exit(1);
10013007Swpaul		}
10113007Swpaul		clnt_destroy(clnt);
10213007Swpaul	} else {
10313007Swpaul		yp_error("Exiting: %s", ypxfrerr_string(retval));
10413007Swpaul	}
10513007Swpaul
10613007Swpaul	exit(0);
10713007Swpaul}
10813007Swpaul
10990298Sdesstatic void
11090298Sdesusage(void)
11113007Swpaul{
11213007Swpaul	if (_rpcpmstart) {
11313007Swpaul		ypxfr_exit(YPXFR_BADARGS,NULL);
11413007Swpaul	} else {
11531626Scharnier		fprintf(stderr, "%s\n%s\n%s\n",
11631626Scharnier	"usage: ypxfr [-f] [-c] [-d target domain] [-h source host]",
11731626Scharnier	"             [-s source domain] [-p path]",
11831626Scharnier	"             [-C taskid program-number ipaddr port] mapname");
11913007Swpaul		exit(1);
12013007Swpaul	}
12113007Swpaul}
12213007Swpaul
12390298Sdesint
12490298Sdesypxfr_foreach(int status, char *key, int keylen, char *val, int vallen,
12590298Sdes    char *data)
12613007Swpaul{
12713007Swpaul	DBT dbkey, dbval;
12813007Swpaul
12913007Swpaul	if (status != YP_TRUE)
13013007Swpaul		return (status);
13113007Swpaul
13230008Swpaul	/*
13330008Swpaul	 * XXX Do not attempt to write zero-length keys or
13430008Swpaul	 * data into a Berkeley DB hash database. It causes a
13530008Swpaul	 * strange failure mode where sequential searches get
13630008Swpaul	 * caught in an infinite loop.
13730008Swpaul	 */
13830008Swpaul	if (keylen) {
13930008Swpaul		dbkey.data = key;
14030008Swpaul		dbkey.size = keylen;
14130008Swpaul	} else {
14230008Swpaul		dbkey.data = "";
14330008Swpaul		dbkey.size = 1;
14430008Swpaul	}
14530008Swpaul	if (vallen) {
14630008Swpaul		dbval.data = val;
14730008Swpaul		dbval.size = vallen;
14830008Swpaul	} else {
14930008Swpaul		dbval.data = "";
15030008Swpaul		dbval.size = 1;
15130008Swpaul	}
15213007Swpaul
15316132Swpaul	if (yp_put_record(dbp, &dbkey, &dbval, 0) != YP_TRUE)
15413007Swpaul		return(yp_errno);
15513007Swpaul
15613007Swpaul	return (0);
15713007Swpaul}
15813007Swpaul
15931626Scharnierint
16090298Sdesmain(int argc, char *argv[])
16113007Swpaul{
16213007Swpaul	int ch;
16313007Swpaul	int ypxfr_force = 0;
16413007Swpaul	char *ypxfr_dest_domain = NULL;
16513007Swpaul	char *ypxfr_source_host = NULL;
16613007Swpaul	char *ypxfr_source_domain = NULL;
16713007Swpaul	char *ypxfr_local_domain = NULL;
16813007Swpaul	char *ypxfr_master = NULL;
16913007Swpaul	unsigned long ypxfr_order = -1, ypxfr_skew_check = -1;
17013007Swpaul	char *ypxfr_mapname = NULL;
17113007Swpaul	int ypxfr_args = 0;
17213007Swpaul	char ypxfr_temp_map[MAXPATHLEN + 2];
17313007Swpaul	char tempmap[MAXPATHLEN + 2];
17413007Swpaul	char buf[MAXPATHLEN + 2];
17513007Swpaul	DBT key, data;
17619065Swpaul	int remoteport;
17719181Swpaul	int interdom = 0;
17819181Swpaul	int secure = 0;
17913007Swpaul
18013007Swpaul	debug = 1;
18113007Swpaul
18213007Swpaul	if (!isatty(fileno(stderr))) {
18331626Scharnier		openlog("ypxfr", LOG_PID, LOG_DAEMON);
18413007Swpaul		_rpcpmstart = 1;
18513007Swpaul	}
18613007Swpaul
18713007Swpaul	if (argc < 2)
18813007Swpaul		usage();
18913007Swpaul
19024349Simp	while ((ch = getopt(argc, argv, "fcd:h:s:p:C:")) != -1) {
19113007Swpaul		int my_optind;
19290297Sdes		switch (ch) {
19313007Swpaul		case 'f':
19413007Swpaul			ypxfr_force++;
19513007Swpaul			ypxfr_args++;
19613007Swpaul			break;
19713007Swpaul		case 'c':
19813007Swpaul			ypxfr_clear = 0;
19913007Swpaul			ypxfr_args++;
20013007Swpaul			break;
20113007Swpaul		case 'd':
20213007Swpaul			ypxfr_dest_domain = optarg;
20313007Swpaul			ypxfr_args += 2;
20413007Swpaul			break;
20513007Swpaul		case 'h':
20613007Swpaul			ypxfr_source_host = optarg;
20713007Swpaul			ypxfr_args += 2;
20813007Swpaul			break;
20913007Swpaul		case 's':
21013007Swpaul			ypxfr_source_domain = optarg;
21113007Swpaul			ypxfr_args += 2;
21213007Swpaul			break;
21313007Swpaul		case 'p':
21413007Swpaul			yp_dir = optarg;
21513007Swpaul			ypxfr_args += 2;
21613007Swpaul			break;
21713007Swpaul		case 'C':
21813007Swpaul			/*
21913007Swpaul			 * Whoever decided that the -C flag should take
22013007Swpaul			 * four arguments is a twit.
22113007Swpaul			 */
22213007Swpaul			my_optind = optind - 1;
22313007Swpaul			if (argv[my_optind] == NULL || !strlen(argv[my_optind])) {
22413007Swpaul				yp_error("transaction ID not specified");
22513007Swpaul				usage();
22613007Swpaul			}
22713007Swpaul			ypxfr_resp.transid = atol(argv[my_optind]);
22813007Swpaul			my_optind++;
22913007Swpaul			if (argv[my_optind] == NULL || !strlen(argv[my_optind])) {
23013007Swpaul				yp_error("RPC program number not specified");
23113007Swpaul				usage();
23213007Swpaul			}
23313007Swpaul			ypxfr_prognum = atol(argv[my_optind]);
23413007Swpaul			my_optind++;
23513007Swpaul			if (argv[my_optind] == NULL || !strlen(argv[my_optind])) {
23613007Swpaul				yp_error("address not specified");
23713007Swpaul				usage();
23813007Swpaul			}
23913007Swpaul			if (!inet_aton(argv[my_optind], &ypxfr_callback_addr.sin_addr)) {
24013007Swpaul				yp_error("failed to convert '%s' to IP addr",
24113007Swpaul					argv[my_optind]);
24213007Swpaul				exit(1);
24313007Swpaul			}
24413007Swpaul			my_optind++;
24513007Swpaul			if (argv[my_optind] == NULL || !strlen(argv[my_optind])) {
24613007Swpaul				yp_error("port not specified");
24713007Swpaul				usage();
24813007Swpaul			}
24913007Swpaul			ypxfr_callback_addr.sin_port = htons((u_short)atoi(argv[my_optind]));
25013007Swpaul			ypxfr_args += 5;
25113007Swpaul			break;
25213007Swpaul		default:
25313007Swpaul			usage();
25413007Swpaul			break;
25513007Swpaul		}
25613007Swpaul	}
25713007Swpaul
25813007Swpaul	ypxfr_mapname = argv[ypxfr_args + 1];
25913007Swpaul
26013007Swpaul	if (ypxfr_mapname == NULL) {
26113007Swpaul		yp_error("no map name specified");
26213007Swpaul		usage();
26313007Swpaul	}
26413007Swpaul
26513007Swpaul	/* Always the case. */
26613007Swpaul	ypxfr_callback_addr.sin_family = AF_INET;
26713007Swpaul
26813007Swpaul	/* Determine if local NIS client facilities are turned on. */
26913007Swpaul	if (!yp_get_default_domain(&ypxfr_local_domain) &&
27013007Swpaul	    _yp_check(&ypxfr_local_domain))
27113007Swpaul		ypxfr_use_yplib = 1;
27213007Swpaul
27313007Swpaul	/*
27413007Swpaul	 * If no destination domain is specified, assume that the
27513007Swpaul	 * local default domain is to be used and try to obtain it.
27613007Swpaul	 * Fails if NIS client facilities are turned off.
27713007Swpaul	 */
27813007Swpaul	if (ypxfr_dest_domain == NULL) {
27913007Swpaul		if (ypxfr_use_yplib) {
28013007Swpaul			yp_get_default_domain(&ypxfr_dest_domain);
28113007Swpaul		} else {
28213007Swpaul			yp_error("no destination domain specified and \
28313007Swpaulthe local domain name isn't set");
28413007Swpaul			ypxfr_exit(YPXFR_BADARGS,NULL);
28513007Swpaul		}
28613007Swpaul	}
28713007Swpaul
28813007Swpaul	/*
28913007Swpaul	 * If a source domain is not specified, assume it to
29013007Swpaul	 * be the same as the destination domain.
29113007Swpaul	 */
29213007Swpaul	if (ypxfr_source_domain == NULL) {
29313007Swpaul		ypxfr_source_domain = ypxfr_dest_domain;
29413007Swpaul	}
29513007Swpaul
29613007Swpaul	/*
29713007Swpaul	 * If the source host is not specified, assume it to be the
29813007Swpaul	 * master for the specified map. If local NIS client facilities
29913007Swpaul	 * are turned on, we can figure this out using yp_master().
30013007Swpaul	 * If not, we have to see if a local copy of the map exists
30113007Swpaul	 * and extract its YP_MASTER_NAME record. If _that_ fails,
30213007Swpaul	 * we are stuck and must ask the user for more information.
30313007Swpaul	 */
30413007Swpaul	if (ypxfr_source_host == NULL) {
30513007Swpaul		if (!ypxfr_use_yplib) {
30613007Swpaul		/*
30713007Swpaul		 * Double whammy: NIS isn't turned on and the user
30813007Swpaul		 * didn't specify a source host.
30913007Swpaul		 */
31013007Swpaul			char *dptr;
31113007Swpaul			key.data = "YP_MASTER_NAME";
31213007Swpaul			key.size = sizeof("YP_MASTER_NAME") - 1;
31313007Swpaul
31413007Swpaul			if (yp_get_record(ypxfr_dest_domain, ypxfr_mapname,
31513007Swpaul					 &key, &data, 1) != YP_TRUE) {
31613007Swpaul				yp_error("no source host specified");
31713007Swpaul				ypxfr_exit(YPXFR_BADARGS,NULL);
31813007Swpaul			}
31913007Swpaul			dptr = data.data;
32013007Swpaul			dptr[data.size] = '\0';
32113007Swpaul			ypxfr_master = ypxfr_source_host = strdup(dptr);
32213007Swpaul		}
32313007Swpaul	} else {
32413007Swpaul		if (ypxfr_use_yplib)
32513007Swpaul			ypxfr_use_yplib = 0;
32613007Swpaul	}
32713007Swpaul
32813007Swpaul	if (ypxfr_master == NULL) {
32913007Swpaul		if ((ypxfr_master = ypxfr_get_master(ypxfr_source_domain,
33013007Swpaul					    	 ypxfr_mapname,
33113007Swpaul					     	ypxfr_source_host,
33213007Swpaul					     	ypxfr_use_yplib)) == NULL) {
33313276Swpaul			yp_error("failed to find master of %s in domain %s: %s",
33413276Swpaul				  ypxfr_mapname, ypxfr_source_domain,
33513276Swpaul				  ypxfrerr_string(yp_errno));
33613007Swpaul			ypxfr_exit(YPXFR_MADDR,NULL);
33713007Swpaul		}
33813007Swpaul	}
33913007Swpaul
34013007Swpaul	/*
34113007Swpaul	 * If we got here and ypxfr_source_host is still undefined,
34213007Swpaul	 * it means we had to resort to using yp_master() to find the
34313007Swpaul	 * master server for the map. The source host and master should
34413007Swpaul	 * be identical.
34513007Swpaul	 */
34613007Swpaul	if (ypxfr_source_host == NULL)
34713007Swpaul		ypxfr_source_host = ypxfr_master;
34813007Swpaul
34919065Swpaul	/*
35019065Swpaul	 * Don't talk to ypservs on unprivileged ports.
35119065Swpaul	 */
35219065Swpaul	remoteport = getrpcport(ypxfr_source_host, YPPROG, YPVERS, IPPROTO_UDP);
35319065Swpaul	if (remoteport >= IPPORT_RESERVED) {
35419065Swpaul		yp_error("ypserv on %s not running on reserved port",
35519065Swpaul						ypxfr_source_host);
35619065Swpaul		ypxfr_exit(YPXFR_REFUSED, NULL);
35719065Swpaul	}
35819065Swpaul
35913007Swpaul	if ((ypxfr_order = ypxfr_get_order(ypxfr_source_domain,
36013007Swpaul					     ypxfr_mapname,
36113007Swpaul					     ypxfr_master, 0)) == 0) {
36213276Swpaul		yp_error("failed to get order number of %s: %s",
36313376Swpaul				ypxfr_mapname, yp_errno == YPXFR_SUCC ?
36413376Swpaul				"map has order 0" : ypxfrerr_string(yp_errno));
36513007Swpaul		ypxfr_exit(YPXFR_YPERR,NULL);
36613007Swpaul	}
36713007Swpaul
36819181Swpaul	if (ypxfr_match(ypxfr_master, ypxfr_source_domain, ypxfr_mapname,
36919181Swpaul			"YP_INTERDOMAIN", sizeof("YP_INTERDOMAIN") - 1))
37019181Swpaul		interdom++;
37119181Swpaul
37219181Swpaul	if (ypxfr_match(ypxfr_master, ypxfr_source_domain, ypxfr_mapname,
37319181Swpaul			"YP_SECURE", sizeof("YP_SECURE") - 1))
37419181Swpaul		secure++;
37519181Swpaul
37613007Swpaul	key.data = "YP_LAST_MODIFIED";
37713007Swpaul	key.size = sizeof("YP_LAST_MODIFIED") - 1;
37890297Sdes
37913007Swpaul	/* The order number is immaterial when the 'force' flag is set. */
38013007Swpaul
38113007Swpaul	if (!ypxfr_force) {
38213007Swpaul		int ignore = 0;
38313007Swpaul		if (yp_get_record(ypxfr_dest_domain,ypxfr_mapname,&key,&data,1) != YP_TRUE) {
38490297Sdes			switch (yp_errno) {
38513007Swpaul			case YP_NOKEY:
38613007Swpaul				ypxfr_exit(YPXFR_FORCE,NULL);
38713007Swpaul				break;
38813007Swpaul			case YP_NOMAP:
38913007Swpaul				/*
39013007Swpaul				 * If the map doesn't exist, we're
39113007Swpaul				 * creating it. Ignore the error.
39213007Swpaul				 */
39313007Swpaul				ignore++;
39413007Swpaul				break;
39513007Swpaul			case YP_BADDB:
39613007Swpaul			default:
39713007Swpaul				ypxfr_exit(YPXFR_DBM,NULL);
39813007Swpaul				break;
39913007Swpaul			}
40013007Swpaul		}
40113007Swpaul		if (!ignore && ypxfr_order <= atoi(data.data))
40213007Swpaul			ypxfr_exit(YPXFR_AGE, NULL);
40313007Swpaul
40413007Swpaul	}
40513007Swpaul
40613007Swpaul	/* Construct a temporary map file name */
40713007Swpaul	snprintf(tempmap, sizeof(tempmap), "%s.%d",ypxfr_mapname, getpid());
40813007Swpaul	snprintf(ypxfr_temp_map, sizeof(ypxfr_temp_map), "%s/%s/%s", yp_dir,
40913007Swpaul		 ypxfr_dest_domain, tempmap);
41013007Swpaul
41119065Swpaul	if ((remoteport = getrpcport(ypxfr_source_host, YPXFRD_FREEBSD_PROG,
41219065Swpaul					YPXFRD_FREEBSD_VERS, IPPROTO_TCP))) {
41319065Swpaul
41419065Swpaul		/* Don't talk to rpc.ypxfrds on unprovileged ports. */
41519065Swpaul		if (remoteport >= IPPORT_RESERVED) {
41619065Swpaul			yp_error("rpc.ypxfrd on %s not using privileged port",
41719065Swpaul							ypxfr_source_host);
41819065Swpaul			ypxfr_exit(YPXFR_REFUSED, NULL);
41919065Swpaul		}
42019065Swpaul
42116132Swpaul		/* Try to send using ypxfrd. If it fails, use old method. */
42219065Swpaul		if (!ypxfrd_get_map(ypxfr_source_host, ypxfr_mapname,
42316132Swpaul					ypxfr_source_domain, ypxfr_temp_map))
42416132Swpaul			goto leave;
42516132Swpaul	}
42616132Swpaul
42713007Swpaul	/* Open the temporary map read/write. */
42816132Swpaul	if ((dbp = yp_open_db_rw(ypxfr_dest_domain, tempmap, 0)) == NULL) {
42913007Swpaul		yp_error("failed to open temporary map file");
43013007Swpaul		ypxfr_exit(YPXFR_DBM,NULL);
43113007Swpaul	}
43213007Swpaul
43313007Swpaul	/*
43413007Swpaul	 * Fill in the keys we already know, such as the order number,
43513007Swpaul	 * master name, input file name (we actually make up a bogus
43613007Swpaul	 * name for that) and output file name.
43713007Swpaul	 */
43838024Sbde	snprintf(buf, sizeof(buf), "%lu", ypxfr_order);
43913007Swpaul	data.data = buf;
44013007Swpaul	data.size = strlen(buf);
44113007Swpaul
44216132Swpaul	if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
44313007Swpaul		yp_error("failed to write order number to database");
44413007Swpaul		ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
44513007Swpaul	}
44613007Swpaul
44713007Swpaul	key.data = "YP_MASTER_NAME";
44813007Swpaul	key.size = sizeof("YP_MASTER_NAME") - 1;
44913007Swpaul	data.data = ypxfr_master;
45013007Swpaul	data.size = strlen(ypxfr_master);
45113007Swpaul
45216132Swpaul	if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
45313007Swpaul		yp_error("failed to write master name to database");
45413007Swpaul		ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
45513007Swpaul	}
45613007Swpaul
45713007Swpaul	key.data = "YP_DOMAIN_NAME";
45813007Swpaul	key.size = sizeof("YP_DOMAIN_NAME") - 1;
45913007Swpaul	data.data = ypxfr_dest_domain;
46013007Swpaul	data.size = strlen(ypxfr_dest_domain);
46113007Swpaul
46216132Swpaul	if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
46313007Swpaul		yp_error("failed to write domain name to database");
46413007Swpaul		ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
46513007Swpaul	}
46613007Swpaul
46713007Swpaul	snprintf (buf, sizeof(buf), "%s:%s", ypxfr_source_host, ypxfr_mapname);
46813007Swpaul
46913007Swpaul	key.data = "YP_INPUT_NAME";
47013007Swpaul	key.size = sizeof("YP_INPUT_NAME") - 1;
47113007Swpaul	data.data = &buf;
47213007Swpaul	data.size = strlen(buf);
47313007Swpaul
47416132Swpaul	if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
47513007Swpaul		yp_error("failed to write input name to database");
47613007Swpaul		ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
47713007Swpaul
47813007Swpaul	}
47913007Swpaul
48013007Swpaul	snprintf(buf, sizeof(buf), "%s/%s/%s", yp_dir, ypxfr_dest_domain,
48113007Swpaul							ypxfr_mapname);
48213007Swpaul
48313007Swpaul	key.data = "YP_OUTPUT_NAME";
48413007Swpaul	key.size = sizeof("YP_OUTPUT_NAME") - 1;
48513007Swpaul	data.data = &buf;
48613007Swpaul	data.size = strlen(buf);
48713007Swpaul
48816132Swpaul	if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
48913007Swpaul		yp_error("failed to write output name to database");
49013007Swpaul		ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
49113007Swpaul	}
49213007Swpaul
49319181Swpaul	if (interdom) {
49419181Swpaul		key.data = "YP_INTERDOMAIN";
49519181Swpaul		key.size = sizeof("YP_INTERDOMAIN") - 1;
49619181Swpaul		data.data = "";
49719181Swpaul		data.size = 0;
49819181Swpaul
49919181Swpaul		if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
50019181Swpaul			yp_error("failed to add interdomain flag to database");
50119181Swpaul			ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
50219181Swpaul		}
50319181Swpaul	}
50419181Swpaul
50519181Swpaul	if (secure) {
50619181Swpaul		key.data = "YP_SECURE";
50719181Swpaul		key.size = sizeof("YP_SECURE") - 1;
50819181Swpaul		data.data = "";
50919181Swpaul		data.size = 0;
51019181Swpaul
51119181Swpaul		if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
51219181Swpaul			yp_error("failed to add secure flag to database");
51319181Swpaul			ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
51419181Swpaul		}
51519181Swpaul	}
51619181Swpaul
51713007Swpaul	/* Now suck over the contents of the map from the master. */
51813007Swpaul
51913007Swpaul	if (ypxfr_get_map(ypxfr_mapname,ypxfr_source_domain,
52013007Swpaul			  ypxfr_source_host, ypxfr_foreach)){
52113007Swpaul		yp_error("failed to retrieve map from source host");
52213007Swpaul		ypxfr_exit(YPXFR_YPERR,&ypxfr_temp_map);
52313007Swpaul	}
52413007Swpaul
52513007Swpaul	(void)(dbp->close)(dbp);
52613276Swpaul	dbp = NULL; /* <- yes, it seems this is necessary. */
52713007Swpaul
52816132Swpaulleave:
52916132Swpaul
53016132Swpaul	snprintf(buf, sizeof(buf), "%s/%s/%s", yp_dir, ypxfr_dest_domain,
53116132Swpaul							ypxfr_mapname);
53216132Swpaul
53313007Swpaul	/* Peek at the order number again and check for skew. */
53413007Swpaul	if ((ypxfr_skew_check = ypxfr_get_order(ypxfr_source_domain,
53513007Swpaul					     ypxfr_mapname,
53613007Swpaul					     ypxfr_master, 0)) == 0) {
53713276Swpaul		yp_error("failed to get order number of %s: %s",
53813376Swpaul				ypxfr_mapname, yp_errno == YPXFR_SUCC ?
53913376Swpaul				"map has order 0" : ypxfrerr_string(yp_errno));
54013007Swpaul		ypxfr_exit(YPXFR_YPERR,&ypxfr_temp_map);
54113007Swpaul	}
54213007Swpaul
54313007Swpaul	if (ypxfr_order != ypxfr_skew_check)
54413007Swpaul		ypxfr_exit(YPXFR_SKEW,&ypxfr_temp_map);
54513007Swpaul
54613007Swpaul	/*
54713007Swpaul	 * Send a YPPROC_CLEAR to the local ypserv.
54813007Swpaul	 */
54913376Swpaul	if (ypxfr_clear) {
55013007Swpaul		char in = 0;
55113007Swpaul		char *out = NULL;
55213376Swpaul		int stat;
55313376Swpaul		if ((stat = callrpc("localhost",YPPROG,YPVERS,YPPROC_CLEAR,
55413376Swpaul			xdr_void, (void *)&in,
55513376Swpaul			xdr_void, (void *)out)) != RPC_SUCCESS) {
55613376Swpaul			yp_error("failed to send 'clear' to local ypserv: %s",
55713376Swpaul				 clnt_sperrno((enum clnt_stat) stat));
55813376Swpaul			ypxfr_exit(YPXFR_CLEAR, &ypxfr_temp_map);
55913007Swpaul		}
56013007Swpaul	}
56113007Swpaul
56213376Swpaul	/*
56313376Swpaul	 * Put the new map in place immediately. I'm not sure if the
56413376Swpaul	 * kernel does an unlink() and rename() atomically in the event
56513376Swpaul	 * that we move a new copy of a map over the top of an existing
56613376Swpaul	 * one, but there's less chance of a race condition happening
56713376Swpaul	 * than if we were to do the unlink() ourselves.
56813376Swpaul	 */
56913007Swpaul	if (rename(ypxfr_temp_map, buf) == -1) {
57013007Swpaul		yp_error("rename(%s,%s) failed: %s", ypxfr_temp_map, buf,
57113007Swpaul							strerror(errno));
57213007Swpaul		ypxfr_exit(YPXFR_FILE,NULL);
57313007Swpaul	}
57413007Swpaul
57513007Swpaul	ypxfr_exit(YPXFR_SUCC,NULL);
57613007Swpaul
57713007Swpaul	return(1);
57813007Swpaul}
579