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