yp.c revision 296376
1139823Simp/* $OpenBSD: yp.c,v 1.14 2015/02/11 01:26:00 pelikan Exp $ */ 211819Sjulian/* $FreeBSD: head/usr.sbin/ypldap/yp.c 296376 2016-03-04 02:14:32Z araujo $ */ 311819Sjulian/* 411819Sjulian * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 511819Sjulian * 611819Sjulian * Permission to use, copy, modify, and distribute this software for any 711819Sjulian * purpose with or without fee is hereby granted, provided that the above 811819Sjulian * copyright notice and this permission notice appear in all copies. 911819Sjulian * 1011819Sjulian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1111819Sjulian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1211819Sjulian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1311819Sjulian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1411819Sjulian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1511819Sjulian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1611819Sjulian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1711819Sjulian */ 1811819Sjulian 1911819Sjulian#include <sys/types.h> 2011819Sjulian#include <sys/param.h> 2111819Sjulian#include <sys/queue.h> 2211819Sjulian#include <sys/socket.h> 2311819Sjulian#include <sys/select.h> 2411819Sjulian#include <sys/tree.h> 2511819Sjulian 2611819Sjulian#include <netinet/in.h> 2711819Sjulian#include <arpa/inet.h> 2811819Sjulian 2911819Sjulian#include <errno.h> 3011819Sjulian#include <event.h> 3111819Sjulian#include <fcntl.h> 3211819Sjulian#include <unistd.h> 3311819Sjulian#include <pwd.h> 3412057Sjulian#include <stdio.h> 3511819Sjulian#include <stdlib.h> 3611819Sjulian#include <string.h> 37116189Sobrien#include <limits.h> 38116189Sobrien 39116189Sobrien#include <rpc/rpc.h> 4032350Seivind#include <rpc/xdr.h> 4130806Sbde#include <rpc/pmap_clnt.h> 4230806Sbde#include <rpc/pmap_prot.h> 4311819Sjulian#include <rpc/pmap_rmt.h> 4411819Sjulian#include <rpcsvc/yp.h> 4511819Sjulian#include <rpcsvc/ypclnt.h> 4611819Sjulian 4711819Sjulian#include "ypldap.h" 4811819Sjulian 4911819Sjulianvoid yp_dispatch(struct svc_req *, SVCXPRT *); 5011819Sjulianvoid yp_disable_events(void); 5130806Sbdevoid yp_fd_event(int, short, void *); 5211819Sjulianint yp_check(struct svc_req *); 5311819Sjulianint yp_valid_domain(char *, struct ypresp_val *); 5411819Sjulianvoid yp_make_val(struct ypresp_val *, char *, int); 5511819Sjulianvoid yp_make_keyval(struct ypresp_key_val *, char *, char *); 5611819Sjulian 5711819Sjulianstatic struct env *env; 5815239Sbde 5925652Sjhaystruct yp_event { 6025652Sjhay TAILQ_ENTRY(yp_event) ye_entry; 6125652Sjhay struct event ye_event; 6215239Sbde}; 6315239Sbde 6411819Sjulianstruct yp_data { 6511819Sjulian SVCXPRT *yp_trans_udp; 6611819Sjulian SVCXPRT *yp_trans_tcp; 6711819Sjulian TAILQ_HEAD(, yp_event) yd_events; 6811819Sjulian}; 6911819Sjulian 7011819Sjulianvoid 7111819Sjulianyp_disable_events(void) 7211819Sjulian{ 7311819Sjulian struct yp_event *ye; 7411819Sjulian 7511819Sjulian while ((ye = TAILQ_FIRST(&env->sc_yp->yd_events)) != NULL) { 7611819Sjulian TAILQ_REMOVE(&env->sc_yp->yd_events, ye, ye_entry); 7711819Sjulian event_del(&ye->ye_event); 7811819Sjulian free(ye); 7911819Sjulian } 8011819Sjulian} 8111819Sjulian 8211819Sjulianvoid 8311819Sjulianyp_enable_events(void) 8411819Sjulian{ 8511819Sjulian int i; 8611819Sjulian struct yp_event *ye; 8725652Sjhay 8811819Sjulian for (i = 0; i < getdtablesize(); i++) { 8911819Sjulian if ((ye = calloc(1, sizeof(*ye))) == NULL) 9025652Sjhay fatal(NULL); 9125652Sjhay event_set(&ye->ye_event, i, EV_READ, yp_fd_event, NULL); 9211819Sjulian event_add(&ye->ye_event, NULL); 9311819Sjulian TAILQ_INSERT_TAIL(&env->sc_yp->yd_events, ye, ye_entry); 9425652Sjhay } 9511819Sjulian} 9611819Sjulian 9711819Sjulianvoid 9825652Sjhayyp_fd_event(int fd, short event, void *p) 9925652Sjhay{ 10025652Sjhay svc_getreq_common(fd); 10125652Sjhay yp_disable_events(); 10225652Sjhay yp_enable_events(); 10338373Sbde} 10411819Sjulian 10511819Sjulianvoid 10614093Swollmanyp_init(struct env *x_env) 10711819Sjulian{ 10811819Sjulian struct yp_data *yp; 10911819Sjulian 11011819Sjulian if ((yp = calloc(1, sizeof(*yp))) == NULL) 11111819Sjulian fatal(NULL); 11211819Sjulian TAILQ_INIT(&yp->yd_events); 11325652Sjhay 11411819Sjulian env = x_env; 11511819Sjulian env->sc_yp = yp; 11611819Sjulian 11711819Sjulian (void)pmap_unset(YPPROG, YPVERS); 11811819Sjulian 11911819Sjulian if ((yp->yp_trans_udp = svcudp_create(RPC_ANYSOCK)) == NULL) 12011819Sjulian fatal("cannot create udp service"); 12111819Sjulian if ((yp->yp_trans_tcp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) 12211819Sjulian fatal("cannot create tcp service"); 12311819Sjulian 12411819Sjulian if (!svc_register(yp->yp_trans_udp, YPPROG, YPVERS, 12511819Sjulian yp_dispatch, IPPROTO_UDP)) { 12611819Sjulian fatal("unable to register (YPPROG, YPVERS, udp)"); 12711819Sjulian } 12811819Sjulian if (!svc_register(yp->yp_trans_tcp, YPPROG, YPVERS, 12911819Sjulian yp_dispatch, IPPROTO_TCP)) { 13011819Sjulian fatal("unable to register (YPPROG, YPVERS, tcp)"); 13111819Sjulian } 13211819Sjulian} 13311819Sjulian 13411819Sjulian/* 13511819Sjulian * lots of inspiration from ypserv by Mats O Jansson 13611819Sjulian */ 13711819Sjulianvoid 13811819Sjulianyp_dispatch(struct svc_req *req, SVCXPRT *trans) 13911819Sjulian{ 14011819Sjulian xdrproc_t xdr_argument; 14111819Sjulian xdrproc_t xdr_result; 14211819Sjulian char *result; 14311819Sjulian char *(*cb)(char *, struct svc_req *); 14411819Sjulian union { 14511819Sjulian domainname ypproc_domain_2_arg; 14611819Sjulian domainname ypproc_domain_nonack_2_arg; 14725652Sjhay ypreq_key ypproc_match_2_arg; 14811819Sjulian ypreq_nokey ypproc_first_2_arg; 14911819Sjulian ypreq_key ypproc_next_2_arg; 15011819Sjulian ypreq_xfr ypproc_xfr_2_arg; 15111819Sjulian ypreq_nokey ypproc_all_2_arg; 15211819Sjulian ypreq_nokey ypproc_master_2_arg; 15311819Sjulian ypreq_nokey ypproc_order_2_arg; 15411819Sjulian domainname ypproc_maplist_2_arg; 15511819Sjulian } argument; 15611819Sjulian 15711819Sjulian xdr_argument = (xdrproc_t) xdr_void; 15811819Sjulian xdr_result = (xdrproc_t) xdr_void; 15911819Sjulian cb = NULL; 16011819Sjulian switch (req->rq_proc) { 16111819Sjulian case YPPROC_NULL: 16211819Sjulian xdr_argument = (xdrproc_t) xdr_void; 16311819Sjulian xdr_result = (xdrproc_t) xdr_void; 16411819Sjulian if (yp_check(req) == -1) 16511819Sjulian return; 16611819Sjulian result = NULL; 16711819Sjulian if (!svc_sendreply(trans, (xdrproc_t) xdr_void, 16811819Sjulian (void *)&result)) 16911819Sjulian svcerr_systemerr(trans); 17011819Sjulian return; 17111819Sjulian case YPPROC_DOMAIN: 172 xdr_argument = (xdrproc_t) xdr_domainname; 173 xdr_result = (xdrproc_t) xdr_bool; 174 if (yp_check(req) == -1) 175 return; 176 cb = (void *)ypproc_domain_2_svc; 177 break; 178 case YPPROC_DOMAIN_NONACK: 179 xdr_argument = (xdrproc_t) xdr_domainname; 180 xdr_result = (xdrproc_t) xdr_bool; 181 if (yp_check(req) == -1) 182 return; 183 cb = (void *)ypproc_domain_nonack_2_svc; 184 break; 185 case YPPROC_MATCH: 186 xdr_argument = (xdrproc_t) xdr_ypreq_key; 187 xdr_result = (xdrproc_t) xdr_ypresp_val; 188 if (yp_check(req) == -1) 189 return; 190 cb = (void *)ypproc_match_2_svc; 191 break; 192 case YPPROC_FIRST: 193 xdr_argument = (xdrproc_t) xdr_ypreq_nokey; 194 xdr_result = (xdrproc_t) xdr_ypresp_key_val; 195 if (yp_check(req) == -1) 196 return; 197 cb = (void *)ypproc_first_2_svc; 198 break; 199 case YPPROC_NEXT: 200 xdr_argument = (xdrproc_t) xdr_ypreq_key; 201 xdr_result = (xdrproc_t) xdr_ypresp_key_val; 202 if (yp_check(req) == -1) 203 return; 204 cb = (void *)ypproc_next_2_svc; 205 break; 206 case YPPROC_XFR: 207 if (yp_check(req) == -1) 208 return; 209 svcerr_noproc(trans); 210 return; 211 case YPPROC_CLEAR: 212 log_debug("ypproc_clear"); 213 if (yp_check(req) == -1) 214 return; 215 svcerr_noproc(trans); 216 return; 217 case YPPROC_ALL: 218 log_debug("ypproc_all"); 219 if (yp_check(req) == -1) 220 return; 221 cb = (void *)ypproc_all_2_svc; 222 break; 223 case YPPROC_MASTER: 224 log_debug("ypproc_master"); 225 xdr_argument = (xdrproc_t) xdr_ypreq_nokey; 226 xdr_result = (xdrproc_t) xdr_ypresp_master; 227 if (yp_check(req) == -1) 228 return; 229 cb = (void *)ypproc_master_2_svc; 230 break; 231 case YPPROC_ORDER: 232 log_debug("ypproc_order"); 233 if (yp_check(req) == -1) 234 return; 235 svcerr_noproc(trans); 236 return; 237 case YPPROC_MAPLIST: 238 log_debug("ypproc_maplist"); 239 if (yp_check(req) == -1) 240 return; 241 cb = (void *)ypproc_maplist_2_svc; 242 break; 243 default: 244 svcerr_noproc(trans); 245 return; 246 } 247 (void)memset(&argument, 0, sizeof(argument)); 248 249 if (!svc_getargs(trans, xdr_argument, (caddr_t)&argument)) { 250 svcerr_decode(trans); 251 return; 252 } 253 result = (*cb)((char *)&argument, req); 254 if (result != NULL && !svc_sendreply(trans, xdr_result, result)) 255 svcerr_systemerr(trans); 256 if (!svc_freeargs(trans, xdr_argument, (caddr_t)&argument)) { 257 /* 258 * ypserv does it too. 259 */ 260 fatal("unable to free arguments"); 261 } 262} 263 264int 265yp_check(struct svc_req *req) 266{ 267 struct sockaddr_in *caller; 268 269 caller = svc_getcaller(req->rq_xprt); 270 /* 271 * We might want to know who we allow here. 272 */ 273 return (0); 274} 275 276int 277yp_valid_domain(char *domain, struct ypresp_val *res) 278{ 279 if (domain == NULL) { 280 log_debug("NULL domain !"); 281 return (-1); 282 } 283 if (strcmp(domain, env->sc_domainname) != 0) { 284 res->stat = YP_NODOM; 285 return (-1); 286 } 287 return (0); 288} 289 290bool_t * 291ypproc_domain_2_svc(domainname *arg, struct svc_req *req) 292{ 293 static bool_t res; 294 295 res = (bool_t)1; 296 if (strcmp(*arg, env->sc_domainname) != 0) 297 res = (bool_t)0; 298 return (&res); 299} 300 301bool_t * 302ypproc_domain_nonack_2_svc(domainname *arg, struct svc_req *req) 303{ 304 static bool_t res; 305 306 if (strcmp(*arg, env->sc_domainname) != 0) 307 return NULL; 308 res = (bool_t)1; 309 return (&res); 310} 311 312ypresp_val * 313ypproc_match_2_svc(ypreq_key *arg, struct svc_req *req) 314{ 315 struct userent ukey; 316 struct userent *ue; 317 struct groupent gkey; 318 struct groupent *ge; 319 static struct ypresp_val res; 320 const char *estr; 321 char *bp, *cp; 322 char key[YPMAXRECORD+1]; 323 324 log_debug("matching '%.*s' in map %s", arg->key.keydat_len, 325 arg->key.keydat_val, arg->map); 326 327 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 328 return (&res); 329 330 if (env->sc_user_names == NULL) { 331 /* 332 * tree not ready. 333 */ 334 return (NULL); 335 } 336 337 if (arg->key.keydat_len > YPMAXRECORD) { 338 log_debug("argument too long"); 339 return (NULL); 340 } 341 bzero(key, sizeof(key)); 342 (void)strncpy(key, arg->key.keydat_val, arg->key.keydat_len); 343 344 if (strcmp(arg->map, "passwd.byname") == 0 || 345 strcmp(arg->map, "master.passwd.byname") == 0) { 346 ukey.ue_line = key; 347 if ((ue = RB_FIND(user_name_tree, env->sc_user_names, 348 &ukey)) == NULL) { 349 res.stat = YP_NOKEY; 350 return (&res); 351 } 352 353 yp_make_val(&res, ue->ue_line, 1); 354 return (&res); 355 } else if (strcmp(arg->map, "passwd.byuid") == 0 || 356 strcmp(arg->map, "master.passwd.byuid") == 0) { 357 ukey.ue_uid = strtonum(key, 0, UID_MAX, &estr); 358 if (estr) { 359 res.stat = YP_BADARGS; 360 return (&res); 361 } 362 363 if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids, 364 &ukey)) == NULL) { 365 res.stat = YP_NOKEY; 366 return (&res); 367 } 368 369 yp_make_val(&res, ue->ue_line, 1); 370 return (&res); 371 } else if (strcmp(arg->map, "group.bygid") == 0) { 372 gkey.ge_gid = strtonum(key, 0, GID_MAX, &estr); 373 if (estr) { 374 res.stat = YP_BADARGS; 375 return (&res); 376 } 377 if ((ge = RB_FIND(group_gid_tree, &env->sc_group_gids, 378 &gkey)) == NULL) { 379 res.stat = YP_NOKEY; 380 return (&res); 381 } 382 383 yp_make_val(&res, ge->ge_line, 1); 384 return (&res); 385 } else if (strcmp(arg->map, "group.byname") == 0) { 386 gkey.ge_line = key; 387 if ((ge = RB_FIND(group_name_tree, env->sc_group_names, 388 &gkey)) == NULL) { 389 res.stat = YP_NOKEY; 390 return (&res); 391 } 392 393 yp_make_val(&res, ge->ge_line, 1); 394 return (&res); 395 } else if (strcmp(arg->map, "netid.byname") == 0) { 396 bp = cp = key; 397 398 if (strncmp(bp, "unix.", strlen("unix.")) != 0) { 399 res.stat = YP_BADARGS; 400 return (&res); 401 } 402 403 bp += strlen("unix."); 404 405 if (*bp == '\0') { 406 res.stat = YP_BADARGS; 407 return (&res); 408 } 409 410 if (!(cp = strsep(&bp, "@"))) { 411 res.stat = YP_BADARGS; 412 return (&res); 413 } 414 415 if (strcmp(bp, arg->domain) != 0) { 416 res.stat = YP_BADARGS; 417 return (&res); 418 } 419 420 ukey.ue_uid = strtonum(cp, 0, UID_MAX, &estr); 421 if (estr) { 422 res.stat = YP_BADARGS; 423 return (&res); 424 } 425 426 if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids, 427 &ukey)) == NULL) { 428 res.stat = YP_NOKEY; 429 return (&res); 430 } 431 432 yp_make_val(&res, ue->ue_netid_line, 0); 433 return (&res); 434 435 } else { 436 log_debug("unknown map %s", arg->map); 437 res.stat = YP_NOMAP; 438 return (&res); 439 } 440} 441 442ypresp_key_val * 443ypproc_first_2_svc(ypreq_nokey *arg, struct svc_req *req) 444{ 445 static struct ypresp_key_val res; 446 447 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 448 return (&res); 449 450 if (strcmp(arg->map, "passwd.byname") == 0 || 451 strcmp(arg->map, "master.passwd.byname") == 0) { 452 if (env->sc_user_lines == NULL) 453 return (NULL); 454 455 yp_make_keyval(&res, env->sc_user_lines, env->sc_user_lines); 456 } else if (strcmp(arg->map, "group.byname") == 0) { 457 if (env->sc_group_lines == NULL) 458 return (NULL); 459 460 yp_make_keyval(&res, env->sc_group_lines, env->sc_group_lines); 461 } else { 462 log_debug("unknown map %s", arg->map); 463 res.stat = YP_NOMAP; 464 } 465 466 return (&res); 467} 468 469ypresp_key_val * 470ypproc_next_2_svc(ypreq_key *arg, struct svc_req *req) 471{ 472 struct userent ukey; 473 struct userent *ue; 474 struct groupent gkey; 475 struct groupent *ge; 476 char *line; 477 static struct ypresp_key_val res; 478 char key[YPMAXRECORD+1]; 479 480 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 481 return (&res); 482 483 if (strcmp(arg->map, "passwd.byname") == 0 || 484 strcmp(arg->map, "master.passwd.byname") == 0) { 485 bzero(key, sizeof(key)); 486 (void)strncpy(key, arg->key.keydat_val, 487 arg->key.keydat_len); 488 ukey.ue_line = key; 489 if ((ue = RB_FIND(user_name_tree, env->sc_user_names, 490 &ukey)) == NULL) { 491 /* 492 * canacar's trick: 493 * the user might have been deleted in between calls 494 * to next since the tree may be modified by a reload. 495 * next should still return the next user in 496 * lexicographical order, hence insert the search key 497 * and look up the next field, then remove it again. 498 */ 499 RB_INSERT(user_name_tree, env->sc_user_names, &ukey); 500 if ((ue = RB_NEXT(user_name_tree, &env->sc_user_names, 501 &ukey)) == NULL) { 502 RB_REMOVE(user_name_tree, env->sc_user_names, 503 &ukey); 504 res.stat = YP_NOKEY; 505 return (&res); 506 } 507 RB_REMOVE(user_name_tree, env->sc_user_names, &ukey); 508 } 509 line = ue->ue_line + (strlen(ue->ue_line) + 1); 510 line = line + (strlen(line) + 1); 511 yp_make_keyval(&res, line, line); 512 return (&res); 513 514 515 } else if (strcmp(arg->map, "group.byname") == 0) { 516 bzero(key, sizeof(key)); 517 (void)strncpy(key, arg->key.keydat_val, 518 arg->key.keydat_len); 519 520 gkey.ge_line = key; 521 if ((ge = RB_FIND(group_name_tree, env->sc_group_names, 522 &gkey)) == NULL) { 523 /* 524 * canacar's trick reloaded. 525 */ 526 RB_INSERT(group_name_tree, env->sc_group_names, &gkey); 527 if ((ge = RB_NEXT(group_name_tree, &env->sc_group_names, 528 &gkey)) == NULL) { 529 RB_REMOVE(group_name_tree, env->sc_group_names, 530 &gkey); 531 res.stat = YP_NOKEY; 532 return (&res); 533 } 534 RB_REMOVE(group_name_tree, env->sc_group_names, &gkey); 535 } 536 537 line = ge->ge_line + (strlen(ge->ge_line) + 1); 538 line = line + (strlen(line) + 1); 539 yp_make_keyval(&res, line, line); 540 return (&res); 541 } else { 542 log_debug("unknown map %s", arg->map); 543 res.stat = YP_NOMAP; 544 return (&res); 545 } 546} 547 548ypresp_all * 549ypproc_all_2_svc(ypreq_nokey *arg, struct svc_req *req) 550{ 551 static struct ypresp_all res; 552 553 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 554 return (&res); 555 556 svcerr_auth(req->rq_xprt, AUTH_FAILED); 557 return (NULL); 558} 559 560ypresp_master * 561ypproc_master_2_svc(ypreq_nokey *arg, struct svc_req *req) 562{ 563 static struct ypresp_master res; 564 static char master[YPMAXPEER + 1]; 565 566 bzero(&res, sizeof(res)); 567 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 568 return (&res); 569 570 if (gethostname(master, sizeof(master)) == 0) { 571 res.peer = (peername)master; 572 res.stat = YP_TRUE; 573 } else 574 res.stat = YP_NOKEY; 575 576 return (&res); 577} 578 579ypresp_maplist * 580ypproc_maplist_2_svc(domainname *arg, struct svc_req *req) 581{ 582 size_t i; 583 static struct { 584 char *name; 585 int cond; 586 } mapnames[] = { 587 { "passwd.byname", YPMAP_PASSWD_BYNAME }, 588 { "passwd.byuid", YPMAP_PASSWD_BYUID }, 589 { "master.passwd.byname", YPMAP_MASTER_PASSWD_BYNAME }, 590 { "master.passwd.byuid", YPMAP_MASTER_PASSWD_BYUID }, 591 { "group.byname", YPMAP_GROUP_BYNAME }, 592 { "group.bygid", YPMAP_GROUP_BYGID }, 593 { "netid.byname", YPMAP_NETID_BYNAME }, 594 }; 595 static ypresp_maplist res; 596 static struct ypmaplist maps[sizeof(mapnames) / sizeof(mapnames[0])]; 597 598 if (yp_valid_domain(*arg, (struct ypresp_val *)&res) == -1) 599 return (&res); 600 601 res.stat = YP_TRUE; 602 res.maps = NULL; 603 for (i = 0; i < sizeof(mapnames) / sizeof(mapnames[0]); i++) { 604 if (!(env->sc_flags & mapnames[i].cond)) 605 continue; 606 maps[i].map = mapnames[i].name; 607 maps[i].next = res.maps; 608 res.maps = &maps[i]; 609 } 610 611 return (&res); 612} 613 614void 615yp_make_val(struct ypresp_val *res, char *line, int replacecolon) 616{ 617 static char buf[LINE_WIDTH]; 618 619 bzero(buf, sizeof(buf)); 620 621 if (replacecolon) 622 line[strlen(line)] = ':'; 623 (void)strlcpy(buf, line, sizeof(buf)); 624 if (replacecolon) 625 line[strcspn(line, ":")] = '\0'; 626 log_debug("sending out %s", buf); 627 628 res->stat = YP_TRUE; 629 res->val.valdat_len = strlen(buf); 630 res->val.valdat_val = buf; 631} 632 633void 634yp_make_keyval(struct ypresp_key_val *res, char *key, char *line) 635{ 636 static char keybuf[YPMAXRECORD+1]; 637 static char buf[LINE_WIDTH]; 638 639 bzero(keybuf, sizeof(keybuf)); 640 bzero(buf, sizeof(buf)); 641 642 (void)strlcpy(keybuf, key, sizeof(keybuf)); 643 res->key.keydat_len = strlen(keybuf); 644 res->key.keydat_val = keybuf; 645 646 if (*line == '\0') { 647 res->stat = YP_NOMORE; 648 return; 649 } 650 res->stat = YP_TRUE; 651 line[strlen(line)] = ':'; 652 (void)strlcpy(buf, line, sizeof(buf)); 653 line[strcspn(line, ":")] = '\0'; 654 log_debug("sending out %s => %s", keybuf, buf); 655 656 res->val.valdat_len = strlen(buf); 657 res->val.valdat_val = buf; 658} 659