GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ypserv/ypxfr/ypxfr.c Lines: 0 215 0.0 %
Date: 2017-11-07 Branches: 0 105 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: ypxfr.c,v 1.39 2015/02/09 23:00:15 deraadt Exp $ */
2
3
/*
4
 * Copyright (c) 1994 Mats O Jansson <moj@stacken.kth.se>
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 */
28
29
#include <sys/types.h>
30
#include <sys/stat.h>
31
#include <sys/socket.h>
32
33
#include <netinet/in.h>
34
#include <arpa/inet.h>
35
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <unistd.h>
39
#include <fcntl.h>
40
#include <string.h>
41
#include <netdb.h>
42
43
#include <rpc/rpc.h>
44
#include <rpc/xdr.h>
45
#include <rpcsvc/yp.h>
46
#include <rpcsvc/ypclnt.h>
47
48
#include "yplib_host.h"
49
#include "yplog.h"
50
#include "ypdb.h"
51
#include "ypdef.h"
52
53
DBM	*db;
54
55
static int
56
ypxfr_foreach(u_long status, char *keystr, int keylen, char *valstr, int vallen,
57
    void *data)
58
{
59
	datum key, val;
60
61
	if (status == YP_NOMORE)
62
		return(0);
63
64
	keystr[keylen] = '\0';
65
	valstr[vallen] = '\0';
66
67
	key.dptr = keystr;
68
	key.dsize = strlen(keystr);
69
70
	val.dptr = valstr;
71
	val.dsize = strlen(valstr);
72
73
	ypdb_store(db, key, val, YPDB_INSERT);
74
	return 0;
75
}
76
77
static int
78
get_local_ordernum(char *domain, char *map, u_int32_t *lordernum)
79
{
80
	char map_path[PATH_MAX], order[MAX_LAST_LEN+1];
81
	char order_key[] = YP_LAST_KEY;
82
	struct stat finfo;
83
	datum k, v;
84
	int status;
85
	DBM *db;
86
87
	/* This routine returns YPPUSH_SUCC or YPPUSH_NODOM */
88
89
	status = YPPUSH_SUCC;
90
91
	snprintf(map_path, sizeof map_path, "%s/%s", YP_DB_PATH, domain);
92
	if (!((stat(map_path, &finfo) == 0) && S_ISDIR(finfo.st_mode))) {
93
		fprintf(stderr, "ypxfr: domain %s not found locally\n",
94
		    domain);
95
		status = YPPUSH_NODOM;
96
		goto bail;
97
	}
98
99
	snprintf(map_path, sizeof map_path, "%s/%s/%s%s",
100
	    YP_DB_PATH, domain, map, YPDB_SUFFIX);
101
	if (!(stat(map_path, &finfo) == 0)) {
102
		status = YPPUSH_NOMAP;
103
		goto bail;
104
	}
105
106
	snprintf(map_path, sizeof map_path, "%s/%s/%s",
107
	    YP_DB_PATH, domain, map);
108
	db = ypdb_open(map_path, O_RDONLY, 0444);
109
	if (db == NULL) {
110
		status = YPPUSH_DBM;
111
		goto bail;
112
	}
113
114
	k.dptr = (char *)&order_key;
115
	k.dsize = YP_LAST_LEN;
116
117
	v = ypdb_fetch(db, k);
118
119
	if (v.dptr == NULL) {
120
		*lordernum = 0;
121
	} else {
122
		strlcpy(order, v.dptr, sizeof order);
123
		*lordernum = (u_int32_t)atol(order);
124
	}
125
126
	ypdb_close(db);
127
bail:
128
	if (status == YPPUSH_NOMAP || status == YPPUSH_DBM) {
129
		*lordernum = 0;
130
		status = YPPUSH_SUCC;
131
	}
132
	return (status);
133
134
}
135
136
static int
137
get_remote_ordernum(CLIENT *client, char *domain, char *map,
138
    u_int32_t lordernum, u_int32_t *rordernum)
139
{
140
	int status;
141
142
	status = yp_order_host(client, domain, map, rordernum);
143
144
	if (status == 0) {
145
		if (*rordernum <= lordernum)
146
			status = YPPUSH_AGE;
147
		else
148
			status = YPPUSH_SUCC;
149
	}
150
	return status;
151
}
152
153
static int
154
get_map(CLIENT *client, char *domain, char *map,
155
    struct ypall_callback *incallback)
156
{
157
	int	status;
158
159
	status = yp_all_host(client, domain, map, incallback);
160
	if (status == 0 || status == YPERR_NOMORE)
161
		status = YPPUSH_SUCC;
162
	else
163
		status = YPPUSH_YPERR;
164
	return (status);
165
}
166
167
static DBM *
168
create_db(char *domain, char *map, char *temp_map)
169
{
170
	return ypdb_open_suf(temp_map, O_RDWR, 0444);
171
}
172
173
static int
174
install_db(char *domain, char *map, char *temp_map)
175
{
176
	char	db_name[PATH_MAX];
177
178
	snprintf(db_name, sizeof db_name, "%s/%s/%s%s",
179
	    YP_DB_PATH, domain, map, YPDB_SUFFIX);
180
	rename(temp_map, db_name);
181
	return YPPUSH_SUCC;
182
}
183
184
static int
185
add_order(DBM *db, u_int32_t ordernum)
186
{
187
	char	datestr[11];
188
	datum	key, val;
189
	char	keystr[] = YP_LAST_KEY;
190
	int	status;
191
192
	snprintf(datestr, sizeof datestr, "%010u", ordernum);
193
194
	key.dptr = keystr;
195
	key.dsize = strlen(keystr);
196
197
	val.dptr = datestr;
198
	val.dsize = strlen(datestr);
199
200
	status = ypdb_store(db, key, val, YPDB_INSERT);
201
	if (status >= 0)
202
		status = YPPUSH_SUCC;
203
	else
204
		status = YPPUSH_DBM;
205
	return (status);
206
}
207
208
static int
209
add_master(CLIENT *client, char *domain, char *map, DBM *db)
210
{
211
	char	keystr[] = YP_MASTER_KEY, *master = NULL;
212
	datum	key, val;
213
	int	status;
214
215
	/* Get MASTER */
216
	status = yp_master_host(client, domain, map, &master);
217
218
	if (master != NULL) {
219
		key.dptr = keystr;
220
		key.dsize = strlen(keystr);
221
222
		val.dptr = master;
223
		val.dsize = strlen(master);
224
225
		status = ypdb_store(db, key, val, YPDB_INSERT);
226
		if (status >= 0)
227
			status = YPPUSH_SUCC;
228
		else
229
			status = YPPUSH_DBM;
230
	}
231
	return (status);
232
}
233
234
static int
235
add_interdomain(CLIENT *client, char *domain, char *map, DBM *db)
236
{
237
	char	keystr[] = YP_INTERDOMAIN_KEY, *value;
238
	int	vallen, status;
239
	datum	k, v;
240
241
	/* Get INTERDOMAIN */
242
243
	k.dptr = keystr;
244
	k.dsize = strlen(keystr);
245
246
	status = yp_match_host(client, domain, map,
247
	    k.dptr, k.dsize, &value, &vallen);
248
	if (status == 0 && value) {
249
		v.dptr = value;
250
		v.dsize = vallen;
251
252
		if (v.dptr != NULL) {
253
			status = ypdb_store(db, k, v, YPDB_INSERT);
254
			if (status >= 0)
255
				status = YPPUSH_SUCC;
256
			else
257
				status = YPPUSH_DBM;
258
		}
259
	}
260
	return 1;
261
}
262
263
static int
264
add_secure(CLIENT *client, char *domain, char *map, DBM *db)
265
{
266
	char	keystr[] = YP_SECURE_KEY, *value;
267
	int	vallen, status;
268
	datum	k, v;
269
270
	/* Get SECURE */
271
272
	k.dptr = keystr;
273
	k.dsize = strlen(keystr);
274
275
	status = yp_match_host(client, domain, map,
276
	    k.dptr, k.dsize, &value, &vallen);
277
	if (status == 0 && value) {
278
		v.dptr = value;
279
		v.dsize = vallen;
280
281
		if (v.dptr != NULL) {
282
			status = ypdb_store(db, k, v, YPDB_INSERT);
283
			if (status >= 0)
284
				status = YPPUSH_SUCC;
285
			else
286
				status = YPPUSH_DBM;
287
		}
288
	}
289
	return status;
290
}
291
292
static int
293
send_clear(CLIENT *client)
294
{
295
	struct	timeval tv;
296
	int	status, r;
297
298
	status = YPPUSH_SUCC;
299
300
	tv.tv_sec = 10;
301
	tv.tv_usec = 0;
302
303
	/* Send CLEAR */
304
	r = clnt_call(client, YPPROC_CLEAR, xdr_void, 0, xdr_void, 0, tv);
305
	if (r != RPC_SUCCESS)
306
		clnt_perror(client, "yp_clear: clnt_call");
307
	return status;
308
309
}
310
311
static int
312
send_reply(CLIENT *client, u_long status, u_long tid)
313
{
314
	struct	ypresp_xfr resp;
315
	struct	timeval tv;
316
	int	r;
317
318
	tv.tv_sec = 10;
319
	tv.tv_usec = 0;
320
321
	resp.transid = tid;
322
	resp.xfrstat = status;
323
324
	/* Send CLEAR */
325
	r = clnt_call(client, 1, xdr_ypresp_xfr, &resp, xdr_void, 0, tv);
326
	if (r != RPC_SUCCESS)
327
		clnt_perror(client, "yppushresp_xdr: clnt_call");
328
	return status;
329
330
}
331
332
static void
333
usage(void)
334
{
335
	fprintf(stderr,
336
	    "usage: ypxfr [-cf] [-C tid prog ipadd port] [-d domain] "
337
	    "[-h host] [-s domain]\n"
338
	    "             mapname\n");
339
	exit(1);
340
}
341
342
int
343
main(int argc, char *argv[])
344
{
345
	int	 cflag = 0, fflag = 0, Cflag = 0;
346
	char	 *domain, *host = NULL, *srcdomain = NULL;
347
	char	 *tid = NULL, *prog = NULL, *ipadd = NULL;
348
	char	 *port = NULL, *map = NULL;
349
	int	 status, xfr_status, ch, srvport;
350
	u_int32_t ordernum, new_ordernum;
351
	struct	 ypall_callback callback;
352
	CLIENT   *client = NULL;
353
	extern	 char *optarg;
354
355
	yp_get_default_domain(&domain);
356
357
	while ((ch = getopt(argc, argv, "cd:fh:s:C:")) != -1)
358
		switch (ch) {
359
		case 'c':
360
			cflag = 1;
361
			break;
362
		case 'd':
363
			if (strchr(optarg, '/')) /* Ha ha, we are not listening */
364
				break;
365
			domain = optarg;
366
			break;
367
		case 'f':
368
			fflag = 1;
369
			break;
370
		case 'h':
371
			host = optarg;
372
			break;
373
		case 's':
374
			if (strchr(optarg, '/')) /* Ha ha, we are not listening */
375
				break;
376
			srcdomain = optarg;
377
			break;
378
		case 'C':
379
			if (optind + 3 >= argc)
380
				usage();
381
			Cflag = 1;
382
			tid = optarg;
383
			prog = argv[optind++];
384
			ipadd = argv[optind++];
385
			port = argv[optind++];
386
			break;
387
		default:
388
			usage();
389
			break;
390
		}
391
392
	status = YPPUSH_SUCC;
393
394
	if (optind + 1 != argc)
395
		usage();
396
397
	map = argv[optind];
398
399
	if (status > 0) {
400
		ypopenlog();
401
402
		yplog("ypxfr: Arguments:");
403
		yplog("YP clear to local: %s", (cflag) ? "no" : "yes");
404
		yplog("   Force transfer: %s", (fflag) ? "yes" : "no");
405
		yplog("           domain: %s", domain);
406
		yplog("             host: %s", host);
407
		yplog("    source domain: %s", srcdomain);
408
		yplog("          transid: %s", tid);
409
		yplog("             prog: %s", prog);
410
		yplog("             port: %s", port);
411
		yplog("            ipadd: %s", ipadd);
412
		yplog("              map: %s", map);
413
414
		if (fflag != 0) {
415
			ordernum = 0;
416
		} else {
417
			status = get_local_ordernum(domain, map, &ordernum);
418
		}
419
	}
420
421
	if (status > 0) {
422
		yplog("Get Master");
423
424
		if (host == NULL) {
425
			if (srcdomain == NULL) {
426
				status = yp_master(domain, map, &host);
427
			} else {
428
				status = yp_master(srcdomain, map, &host);
429
			}
430
			if (status == 0) {
431
				status = YPPUSH_SUCC;
432
			} else {
433
				status = -status;
434
			}
435
		}
436
	}
437
438
	/* XXX this is raceable if portmap has holes! */
439
	if (status > 0) {
440
		yplog("Check for reserved port on host: %s", host);
441
442
		srvport = getrpcport(host, YPPROG, YPVERS, IPPROTO_TCP);
443
		if (srvport >= IPPORT_RESERVED)
444
			status = YPPUSH_REFUSED;
445
	}
446
447
	if (status > 0) {
448
		yplog("Connect host: %s", host);
449
450
		client = yp_bind_host(host, YPPROG, YPVERS, 0, 1);
451
452
		status = get_remote_ordernum(client, domain, map,
453
		    ordernum, &new_ordernum);
454
	}
455
456
	if (status == YPPUSH_SUCC) {
457
		char	tmpmapname[PATH_MAX];
458
		int	fd;
459
460
		/* Create temporary db */
461
		snprintf(tmpmapname, sizeof tmpmapname,
462
		    "%s/%s/ypdbXXXXXXXXXX", YP_DB_PATH, domain);
463
		fd = mkstemp(tmpmapname);
464
		if (fd == -1)
465
			status = YPPUSH_DBM;
466
		else
467
			close(fd);
468
469
		if (status > 0) {
470
			db = create_db(domain, map, tmpmapname);
471
			if (db == NULL)
472
				status = YPPUSH_DBM;
473
		}
474
475
		/* Add ORDER */
476
		if (status > 0)
477
			status = add_order(db, new_ordernum);
478
479
		/* Add MASTER */
480
		if (status > 0)
481
			status = add_master(client, domain, map, db);
482
483
		/* Add INTERDOMAIN */
484
		if (status > 0)
485
			status = add_interdomain(client, domain, map, db);
486
487
		/* Add SECURE */
488
		if (status > 0)
489
			status = add_secure(client, domain, map, db);
490
491
		if (status > 0) {
492
			callback.foreach = ypxfr_foreach;
493
			status = get_map(client, domain, map, &callback);
494
		}
495
496
		/* Close db */
497
		if (db != NULL)
498
			ypdb_close(db);
499
500
		/* Rename db */
501
		if (status > 0) {
502
			status = install_db(domain, map, tmpmapname);
503
		} else {
504
			unlink(tmpmapname);
505
			status = YPPUSH_SUCC;
506
		}
507
	}
508
509
	xfr_status = status;
510
511
	if (client != NULL)
512
		clnt_destroy(client);
513
514
	/* YP_CLEAR */
515
516
	if (!cflag) {
517
		client = yp_bind_local(YPPROG, YPVERS);
518
		status = send_clear(client);
519
		clnt_destroy(client);
520
	}
521
522
	if (Cflag > 0) {
523
		/* Send Response */
524
		client = yp_bind_host(ipadd, atoi(prog), 1, atoi(port), 0);
525
		status = send_reply(client, xfr_status, atoi(tid));
526
		clnt_destroy(client);
527
	}
528
	return (0);
529
}