GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ypldap/yp.c Lines: 0 292 0.0 %
Date: 2017-11-13 Branches: 0 165 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: yp.c,v 1.18 2016/11/29 17:15:27 mestre Exp $ */
2
/*
3
 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
#include <sys/types.h>
19
#include <sys/queue.h>
20
#include <sys/socket.h>
21
#include <sys/select.h>
22
#include <sys/tree.h>
23
24
#include <netinet/in.h>
25
#include <arpa/inet.h>
26
27
#include <errno.h>
28
#include <event.h>
29
#include <fcntl.h>
30
#include <unistd.h>
31
#include <pwd.h>
32
#include <stdio.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <limits.h>
36
37
#include <rpc/rpc.h>
38
#include <rpc/xdr.h>
39
#include <rpc/pmap_clnt.h>
40
#include <rpc/pmap_prot.h>
41
#include <rpc/pmap_rmt.h>
42
#include <rpcsvc/yp.h>
43
#include <rpcsvc/ypclnt.h>
44
45
#include "ypldap.h"
46
47
void	yp_dispatch(struct svc_req *, SVCXPRT *);
48
void	yp_disable_events(void);
49
void	yp_fd_event(int, short, void *);
50
int	yp_check(struct svc_req *);
51
int	yp_valid_domain(char *, struct ypresp_val *);
52
void	yp_make_val(struct ypresp_val *, char *, int);
53
void	yp_make_keyval(struct ypresp_key_val *, char *, char *);
54
55
static struct env	*env;
56
57
struct yp_event {
58
	TAILQ_ENTRY(yp_event)	 ye_entry;
59
	struct event		 ye_event;
60
};
61
62
struct yp_data {
63
	SVCXPRT			*yp_trans_udp;
64
	SVCXPRT			*yp_trans_tcp;
65
	TAILQ_HEAD(, yp_event)	 yd_events;
66
};
67
68
void
69
yp_disable_events(void)
70
{
71
	struct yp_event	*ye;
72
73
	while ((ye = TAILQ_FIRST(&env->sc_yp->yd_events)) != NULL) {
74
		TAILQ_REMOVE(&env->sc_yp->yd_events, ye, ye_entry);
75
		event_del(&ye->ye_event);
76
		free(ye);
77
	}
78
}
79
80
void
81
yp_enable_events(void)
82
{
83
	int		 i;
84
	extern fd_set	*__svc_fdset;
85
	extern int	 __svc_fdsetsize;
86
	struct yp_event	*ye;
87
88
	for (i = 0; i < __svc_fdsetsize; i++) {
89
		if (FD_ISSET(i, __svc_fdset)) {
90
			if ((ye = calloc(1, sizeof(*ye))) == NULL)
91
				fatal(NULL);
92
			event_set(&ye->ye_event, i, EV_READ, yp_fd_event, NULL);
93
			event_add(&ye->ye_event, NULL);
94
			TAILQ_INSERT_TAIL(&env->sc_yp->yd_events, ye, ye_entry);
95
		}
96
	}
97
}
98
99
void
100
yp_fd_event(int fd, short event, void *p)
101
{
102
	svc_getreq_common(fd);
103
	yp_disable_events();
104
	yp_enable_events();
105
}
106
107
void
108
yp_init(struct env *x_env)
109
{
110
	struct yp_data	*yp;
111
112
	if ((yp = calloc(1, sizeof(*yp))) == NULL)
113
		fatal(NULL);
114
	TAILQ_INIT(&yp->yd_events);
115
116
	env = x_env;
117
	env->sc_yp = yp;
118
119
	(void)pmap_unset(YPPROG, YPVERS);
120
121
	if ((yp->yp_trans_udp = svcudp_create(RPC_ANYSOCK)) == NULL)
122
		fatal("cannot create udp service");
123
	if ((yp->yp_trans_tcp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL)
124
		fatal("cannot create tcp service");
125
126
	if (!svc_register(yp->yp_trans_udp, YPPROG, YPVERS,
127
	    yp_dispatch, IPPROTO_UDP)) {
128
		fatal("unable to register (YPPROG, YPVERS, udp)");
129
	}
130
	if (!svc_register(yp->yp_trans_tcp, YPPROG, YPVERS,
131
	    yp_dispatch, IPPROTO_TCP)) {
132
		fatal("unable to register (YPPROG, YPVERS, tcp)");
133
	}
134
}
135
136
/*
137
 * lots of inspiration from ypserv by Mats O Jansson
138
 */
139
void
140
yp_dispatch(struct svc_req *req, SVCXPRT *trans)
141
{
142
	xdrproc_t		 xdr_argument;
143
	xdrproc_t		 xdr_result;
144
	char			*result;
145
	char			*(*cb)(char *, struct svc_req *);
146
        union {
147
		domainname	 ypproc_domain_2_arg;
148
		domainname	 ypproc_domain_nonack_2_arg;
149
		ypreq_key	 ypproc_match_2_arg;
150
		ypreq_nokey	 ypproc_first_2_arg;
151
		ypreq_key	 ypproc_next_2_arg;
152
		ypreq_xfr	 ypproc_xfr_2_arg;
153
		ypreq_nokey	 ypproc_all_2_arg;
154
		ypreq_nokey	 ypproc_master_2_arg;
155
		ypreq_nokey	 ypproc_order_2_arg;
156
		domainname	 ypproc_maplist_2_arg;
157
	} argument;
158
159
	xdr_argument = (xdrproc_t) xdr_void;
160
	xdr_result = (xdrproc_t) xdr_void;
161
	cb = NULL;
162
	switch (req->rq_proc) {
163
	case YPPROC_NULL:
164
		xdr_argument = (xdrproc_t) xdr_void;
165
		xdr_result = (xdrproc_t) xdr_void;
166
		if (yp_check(req) == -1)
167
			return;
168
		result = NULL;
169
		if (!svc_sendreply(trans, (xdrproc_t) xdr_void,
170
		    (void *)&result))
171
			svcerr_systemerr(trans);
172
		return;
173
	case YPPROC_DOMAIN:
174
		xdr_argument = (xdrproc_t) xdr_domainname;
175
		xdr_result = (xdrproc_t) xdr_bool;
176
		if (yp_check(req) == -1)
177
			return;
178
		cb = (void *)ypproc_domain_2_svc;
179
		break;
180
	case YPPROC_DOMAIN_NONACK:
181
		xdr_argument = (xdrproc_t) xdr_domainname;
182
		xdr_result = (xdrproc_t) xdr_bool;
183
		if (yp_check(req) == -1)
184
			return;
185
		cb = (void *)ypproc_domain_nonack_2_svc;
186
		break;
187
	case YPPROC_MATCH:
188
		xdr_argument = (xdrproc_t) xdr_ypreq_key;
189
		xdr_result = (xdrproc_t) xdr_ypresp_val;
190
		if (yp_check(req) == -1)
191
			return;
192
		cb = (void *)ypproc_match_2_svc;
193
		break;
194
	case YPPROC_FIRST:
195
		xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
196
		xdr_result = (xdrproc_t) xdr_ypresp_key_val;
197
		if (yp_check(req) == -1)
198
			return;
199
		cb = (void *)ypproc_first_2_svc;
200
		break;
201
	case YPPROC_NEXT:
202
		xdr_argument = (xdrproc_t) xdr_ypreq_key;
203
		xdr_result = (xdrproc_t) xdr_ypresp_key_val;
204
		if (yp_check(req) == -1)
205
			return;
206
		cb = (void *)ypproc_next_2_svc;
207
		break;
208
	case YPPROC_XFR:
209
		if (yp_check(req) == -1)
210
			return;
211
		svcerr_noproc(trans);
212
		return;
213
	case YPPROC_CLEAR:
214
		log_debug("ypproc_clear");
215
		if (yp_check(req) == -1)
216
			return;
217
		svcerr_noproc(trans);
218
		return;
219
	case YPPROC_ALL:
220
		log_debug("ypproc_all");
221
		xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
222
		xdr_result = (xdrproc_t) xdr_ypresp_all;
223
		if (yp_check(req) == -1)
224
			return;
225
		cb = (void *)ypproc_all_2_svc;
226
		break;
227
	case YPPROC_MASTER:
228
		xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
229
		xdr_result = (xdrproc_t) xdr_ypresp_master;
230
		if (yp_check(req) == -1)
231
			return;
232
		cb = (void *)ypproc_master_2_svc;
233
		break;
234
	case YPPROC_ORDER:
235
		log_debug("ypproc_order");
236
		if (yp_check(req) == -1)
237
			return;
238
		svcerr_noproc(trans);
239
		return;
240
	case YPPROC_MAPLIST:
241
		xdr_argument = (xdrproc_t) xdr_domainname;
242
		xdr_result = (xdrproc_t) xdr_ypresp_maplist;
243
		if (yp_check(req) == -1)
244
			return;
245
		cb = (void *)ypproc_maplist_2_svc;
246
		break;
247
	default:
248
		svcerr_noproc(trans);
249
		return;
250
	}
251
	(void)memset(&argument, 0, sizeof(argument));
252
253
	if (!svc_getargs(trans, xdr_argument, (caddr_t)&argument)) {
254
		svcerr_decode(trans);
255
		return;
256
	}
257
	result = (*cb)((char *)&argument, req);
258
	if (result != NULL && !svc_sendreply(trans, xdr_result, result))
259
		svcerr_systemerr(trans);
260
	if (!svc_freeargs(trans, xdr_argument, (caddr_t)&argument)) {
261
		/*
262
		 * ypserv does it too.
263
		 */
264
		fatal("unable to free arguments");
265
	}
266
}
267
268
int
269
yp_check(struct svc_req *req)
270
{
271
	struct sockaddr_in	*caller;
272
273
	caller = svc_getcaller(req->rq_xprt);
274
	/*
275
	 * We might want to know who we allow here.
276
	 */
277
	return (0);
278
}
279
280
int
281
yp_valid_domain(char *domain, struct ypresp_val *res)
282
{
283
	if (domain == NULL) {
284
		log_debug("NULL domain !");
285
		return (-1);
286
	}
287
	if (strcmp(domain, env->sc_domainname) != 0) {
288
		res->stat = YP_NODOM;
289
		return (-1);
290
	}
291
	return (0);
292
}
293
294
bool_t *
295
ypproc_domain_2_svc(domainname *arg, struct svc_req *req)
296
{
297
	static bool_t	res;
298
299
	res = (bool_t)1;
300
	if (strcmp(*arg, env->sc_domainname) != 0)
301
		res = (bool_t)0;
302
	return (&res);
303
}
304
305
bool_t *
306
ypproc_domain_nonack_2_svc(domainname *arg, struct svc_req *req)
307
{
308
	static bool_t	res;
309
310
	if (strcmp(*arg, env->sc_domainname) != 0)
311
		return NULL;
312
	res = (bool_t)1;
313
	return (&res);
314
}
315
316
ypresp_val *
317
ypproc_match_2_svc(ypreq_key *arg, struct svc_req *req)
318
{
319
	struct userent		 ukey;
320
	struct userent		*ue;
321
	struct groupent		 gkey;
322
	struct groupent		*ge;
323
	static struct ypresp_val res;
324
	const char		*estr;
325
	char			*bp, *cp;
326
	char			 key[YPMAXRECORD+1];
327
328
	log_debug("matching '%.*s' in map %s", arg->key.keydat_len,
329
	   arg->key.keydat_val, arg->map);
330
331
	if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
332
		return (&res);
333
334
	if (env->sc_user_names == NULL) {
335
		/*
336
		 * tree not ready.
337
		 */
338
		return (NULL);
339
	}
340
341
	if (arg->key.keydat_len > YPMAXRECORD) {
342
		log_debug("argument too long");
343
		return (NULL);
344
	}
345
	memset(key, 0, sizeof(key));
346
	(void)strncpy(key, arg->key.keydat_val, arg->key.keydat_len);
347
348
	if (strcmp(arg->map, "passwd.byname") == 0 ||
349
	    strcmp(arg->map, "master.passwd.byname") == 0) {
350
		ukey.ue_line = key;
351
		if ((ue = RB_FIND(user_name_tree, env->sc_user_names,
352
		    &ukey)) == NULL) {
353
			res.stat = YP_NOKEY;
354
			return (&res);
355
		}
356
357
		yp_make_val(&res, ue->ue_line, 1);
358
		return (&res);
359
	} else if (strcmp(arg->map, "passwd.byuid") == 0 ||
360
		   strcmp(arg->map, "master.passwd.byuid") == 0) {
361
		ukey.ue_uid = strtonum(key, 0, UID_MAX, &estr);
362
		if (estr) {
363
			res.stat = YP_BADARGS;
364
			return (&res);
365
		}
366
367
		if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids,
368
		    &ukey)) == NULL) {
369
			res.stat = YP_NOKEY;
370
			return (&res);
371
		}
372
373
		yp_make_val(&res, ue->ue_line, 1);
374
		return (&res);
375
	} else if (strcmp(arg->map, "group.bygid") == 0) {
376
		gkey.ge_gid = strtonum(key, 0, GID_MAX, &estr);
377
		if (estr) {
378
			res.stat = YP_BADARGS;
379
			return (&res);
380
		}
381
		if ((ge = RB_FIND(group_gid_tree, &env->sc_group_gids,
382
		    &gkey)) == NULL) {
383
			res.stat = YP_NOKEY;
384
			return (&res);
385
		}
386
387
		yp_make_val(&res, ge->ge_line, 1);
388
		return (&res);
389
	} else if (strcmp(arg->map, "group.byname") == 0) {
390
		gkey.ge_line = key;
391
		if ((ge = RB_FIND(group_name_tree, env->sc_group_names,
392
		    &gkey)) == NULL) {
393
			res.stat = YP_NOKEY;
394
			return (&res);
395
		}
396
397
		yp_make_val(&res, ge->ge_line, 1);
398
		return (&res);
399
	} else if (strcmp(arg->map, "netid.byname") == 0) {
400
		bp = cp = key;
401
402
		if (strncmp(bp, "unix.", strlen("unix.")) != 0) {
403
			res.stat = YP_BADARGS;
404
			return (&res);
405
		}
406
407
		bp += strlen("unix.");
408
409
		if (*bp == '\0') {
410
			res.stat = YP_BADARGS;
411
			return (&res);
412
		}
413
414
		if (!(cp = strsep(&bp, "@"))) {
415
			res.stat = YP_BADARGS;
416
			return (&res);
417
		}
418
419
		if (strcmp(bp, arg->domain) != 0) {
420
			res.stat = YP_BADARGS;
421
			return (&res);
422
		}
423
424
		ukey.ue_uid = strtonum(cp, 0, UID_MAX, &estr);
425
		if (estr) {
426
			res.stat = YP_BADARGS;
427
			return (&res);
428
		}
429
430
		if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids,
431
		    &ukey)) == NULL) {
432
			res.stat = YP_NOKEY;
433
			return (&res);
434
		}
435
436
		yp_make_val(&res, ue->ue_netid_line, 0);
437
		return (&res);
438
439
	} else {
440
		log_debug("unknown map %s", arg->map);
441
		res.stat = YP_NOMAP;
442
		return (&res);
443
	}
444
}
445
446
ypresp_key_val *
447
ypproc_first_2_svc(ypreq_nokey *arg, struct svc_req *req)
448
{
449
	static struct ypresp_key_val	res;
450
451
	if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
452
		return (&res);
453
454
	if (strcmp(arg->map, "passwd.byname") == 0 ||
455
	    strcmp(arg->map, "master.passwd.byname") == 0) {
456
		if (env->sc_user_lines == NULL)
457
			return (NULL);
458
459
		yp_make_keyval(&res, env->sc_user_lines, env->sc_user_lines);
460
	} else if (strcmp(arg->map, "group.byname") == 0) {
461
		if (env->sc_group_lines == NULL)
462
			return (NULL);
463
464
		yp_make_keyval(&res, env->sc_group_lines, env->sc_group_lines);
465
	} else {
466
		log_debug("unknown map %s", arg->map);
467
		res.stat = YP_NOMAP;
468
	}
469
470
	return (&res);
471
}
472
473
ypresp_key_val *
474
ypproc_next_2_svc(ypreq_key *arg, struct svc_req *req)
475
{
476
	struct userent			 ukey;
477
	struct userent			*ue;
478
	struct groupent			 gkey;
479
	struct groupent			*ge;
480
	char				*line;
481
	static struct ypresp_key_val	 res;
482
	char				 key[YPMAXRECORD+1];
483
484
	if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
485
		return (&res);
486
487
	if (strcmp(arg->map, "passwd.byname") == 0 ||
488
	    strcmp(arg->map, "master.passwd.byname") == 0) {
489
		memset(key, 0, sizeof(key));
490
		(void)strncpy(key, arg->key.keydat_val,
491
		    arg->key.keydat_len);
492
		ukey.ue_line = key;
493
		if ((ue = RB_FIND(user_name_tree, env->sc_user_names,
494
		    &ukey)) == NULL) {
495
			/*
496
			 * canacar's trick:
497
			 * the user might have been deleted in between calls
498
			 * to next since the tree may be modified by a reload.
499
			 * next should still return the next user in
500
			 * lexicographical order, hence insert the search key
501
			 * and look up the next field, then remove it again.
502
			 */
503
			RB_INSERT(user_name_tree, env->sc_user_names, &ukey);
504
			if ((ue = RB_NEXT(user_name_tree, &env->sc_user_names,
505
			    &ukey)) == NULL) {
506
				RB_REMOVE(user_name_tree, env->sc_user_names,
507
				    &ukey);
508
				res.stat = YP_NOKEY;
509
				return (&res);
510
			}
511
			RB_REMOVE(user_name_tree, env->sc_user_names, &ukey);
512
		}
513
		line = ue->ue_line + (strlen(ue->ue_line) + 1);
514
		line = line + (strlen(line) + 1);
515
		yp_make_keyval(&res, line, line);
516
		return (&res);
517
518
519
	} else if (strcmp(arg->map, "group.byname") == 0) {
520
		memset(key, 0, sizeof(key));
521
		(void)strncpy(key, arg->key.keydat_val,
522
		    arg->key.keydat_len);
523
524
		gkey.ge_line = key;
525
		if ((ge = RB_FIND(group_name_tree, env->sc_group_names,
526
		    &gkey)) == NULL) {
527
			/*
528
			 * canacar's trick reloaded.
529
			 */
530
			RB_INSERT(group_name_tree, env->sc_group_names, &gkey);
531
			if ((ge = RB_NEXT(group_name_tree, &env->sc_group_names,
532
			    &gkey)) == NULL) {
533
				RB_REMOVE(group_name_tree, env->sc_group_names,
534
				    &gkey);
535
				res.stat = YP_NOKEY;
536
				return (&res);
537
			}
538
			RB_REMOVE(group_name_tree, env->sc_group_names, &gkey);
539
		}
540
541
		line = ge->ge_line + (strlen(ge->ge_line) + 1);
542
		line = line + (strlen(line) + 1);
543
		yp_make_keyval(&res, line, line);
544
		return (&res);
545
	} else {
546
		log_debug("unknown map %s", arg->map);
547
		res.stat = YP_NOMAP;
548
		return (&res);
549
	}
550
}
551
552
ypresp_all *
553
ypproc_all_2_svc(ypreq_nokey *arg, struct svc_req *req)
554
{
555
	static struct ypresp_all	res;
556
557
	if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
558
		return (&res);
559
560
	svcerr_auth(req->rq_xprt, AUTH_FAILED);
561
	return (NULL);
562
}
563
564
ypresp_master *
565
ypproc_master_2_svc(ypreq_nokey *arg, struct svc_req *req)
566
{
567
	static struct ypresp_master	 res;
568
	static char master[YPMAXPEER + 1];
569
570
	memset(&res, 0, sizeof(res));
571
	if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
572
		return (&res);
573
	if (gethostname(master, sizeof(master)) == 0) {
574
		res.peer = (peername)master;
575
		res.stat = YP_TRUE;
576
	} else
577
		res.stat = YP_NOKEY;
578
	return (&res);
579
}
580
581
ypresp_maplist *
582
ypproc_maplist_2_svc(domainname *arg, struct svc_req *req)
583
{
584
	size_t			 i;
585
	static struct {
586
		char		*name;
587
		int		 cond;
588
	}			 mapnames[] = {
589
		{ "passwd.byname",		YPMAP_PASSWD_BYNAME },
590
		{ "passwd.byuid",		YPMAP_PASSWD_BYUID },
591
		{ "master.passwd.byname",	YPMAP_MASTER_PASSWD_BYNAME },
592
		{ "master.passwd.byuid",	YPMAP_MASTER_PASSWD_BYUID },
593
		{ "group.byname",		YPMAP_GROUP_BYNAME },
594
		{ "group.bygid",		YPMAP_GROUP_BYGID },
595
		{ "netid.byname",		YPMAP_NETID_BYNAME },
596
	};
597
	static ypresp_maplist	 res;
598
	static struct ypmaplist	 maps[sizeof(mapnames) / sizeof(mapnames[0])];
599
600
	if (yp_valid_domain(*arg, (struct ypresp_val *)&res) == -1)
601
		return (&res);
602
603
	res.stat = YP_TRUE;
604
	res.maps = NULL;
605
	for (i = 0; i < sizeof(mapnames) / sizeof(mapnames[0]); i++) {
606
		if (!(env->sc_flags & mapnames[i].cond))
607
			continue;
608
		maps[i].map = mapnames[i].name;
609
		maps[i].next = res.maps;
610
		res.maps = &maps[i];
611
	}
612
613
	return (&res);
614
}
615
616
void
617
yp_make_val(struct ypresp_val *res, char *line, int replacecolon)
618
{
619
	static char		 buf[LINE_WIDTH];
620
621
	memset(buf, 0, sizeof(buf));
622
623
	if (replacecolon)
624
		line[strlen(line)] = ':';
625
	(void)strlcpy(buf, line, sizeof(buf));
626
	if (replacecolon)
627
		line[strcspn(line, ":")] = '\0';
628
	log_debug("sending out %s", buf);
629
630
	res->stat = YP_TRUE;
631
	res->val.valdat_len = strlen(buf);
632
	res->val.valdat_val = buf;
633
}
634
635
void
636
yp_make_keyval(struct ypresp_key_val *res, char *key, char *line)
637
{
638
	static char	keybuf[YPMAXRECORD+1];
639
	static char	buf[LINE_WIDTH];
640
641
	memset(keybuf, 0, sizeof(keybuf));
642
	memset(buf, 0, sizeof(buf));
643
644
	(void)strlcpy(keybuf, key, sizeof(keybuf));
645
	res->key.keydat_len = strlen(keybuf);
646
	res->key.keydat_val = keybuf;
647
648
	if (*line == '\0') {
649
		res->stat = YP_NOMORE;
650
		return;
651
	}
652
	res->stat = YP_TRUE;
653
	line[strlen(line)] = ':';
654
	(void)strlcpy(buf, line, sizeof(buf));
655
	line[strcspn(line, ":")] = '\0';
656
	log_debug("sending out %s => %s", keybuf, buf);
657
658
	res->val.valdat_len = strlen(buf);
659
	res->val.valdat_val = buf;
660
}