1 /* $OpenBSD: yp.c,v 1.14 2015/02/11 01:26:00 pelikan Exp $ */ 2 /* $FreeBSD$ */ 3 /* 4 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/param.h> 21 #include <sys/queue.h> 22 #include <sys/socket.h> 23 #include <sys/select.h> 24 #include <sys/tree.h> 25 26 #include <netinet/in.h> 27 #include <arpa/inet.h> 28 29 #include <errno.h> 30 #include <event.h> 31 #include <fcntl.h> 32 #include <unistd.h> 33 #include <pwd.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <limits.h> 38 39 #include <rpc/rpc.h> 40 #include <rpc/xdr.h> 41 #include <rpc/pmap_clnt.h> 42 #include <rpc/pmap_prot.h> 43 #include <rpc/pmap_rmt.h> 44 #include <rpcsvc/yp.h> 45 #include <rpcsvc/ypclnt.h> 46 47 #include "ypldap.h" 48 49 void yp_dispatch(struct svc_req *, SVCXPRT *); 50 void yp_disable_events(void); 51 void yp_fd_event(int, short, void *); 52 int yp_check(struct svc_req *); 53 int yp_valid_domain(char *, struct ypresp_val *); 54 void yp_make_val(struct ypresp_val *, char *, int); 55 void yp_make_keyval(struct ypresp_key_val *, char *, char *); 56 57 static struct env *env; 58 59 struct yp_event { 60 TAILQ_ENTRY(yp_event) ye_entry; 61 struct event ye_event; 62 }; 63 64 struct yp_data { 65 SVCXPRT *yp_trans_udp; 66 SVCXPRT *yp_trans_tcp; 67 TAILQ_HEAD(, yp_event) yd_events; 68 }; 69 70 void 71 yp_disable_events(void) 72 { 73 struct yp_event *ye; 74 75 while ((ye = TAILQ_FIRST(&env->sc_yp->yd_events)) != NULL) { 76 TAILQ_REMOVE(&env->sc_yp->yd_events, ye, ye_entry); 77 event_del(&ye->ye_event); 78 free(ye); 79 } 80 } 81 82 void 83 yp_enable_events(void) 84 { 85 int i; 86 struct yp_event *ye; 87 88 for (i = 0; i < getdtablesize(); i++) { 89 if ((ye = calloc(1, sizeof(*ye))) == NULL) 90 fatal(NULL); 91 event_set(&ye->ye_event, i, EV_READ, yp_fd_event, NULL); 92 event_add(&ye->ye_event, NULL); 93 TAILQ_INSERT_TAIL(&env->sc_yp->yd_events, ye, ye_entry); 94 } 95 } 96 97 void 98 yp_fd_event(int fd, short event, void *p) 99 { 100 svc_getreq_common(fd); 101 yp_disable_events(); 102 yp_enable_events(); 103 } 104 105 void 106 yp_init(struct env *x_env) 107 { 108 struct yp_data *yp; 109 110 if ((yp = calloc(1, sizeof(*yp))) == NULL) 111 fatal(NULL); 112 TAILQ_INIT(&yp->yd_events); 113 114 env = x_env; 115 env->sc_yp = yp; 116 117 (void)pmap_unset(YPPROG, YPVERS); 118 119 if ((yp->yp_trans_udp = svcudp_create(RPC_ANYSOCK)) == NULL) 120 fatal("cannot create udp service"); 121 if ((yp->yp_trans_tcp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) 122 fatal("cannot create tcp service"); 123 124 if (!svc_register(yp->yp_trans_udp, YPPROG, YPVERS, 125 yp_dispatch, IPPROTO_UDP)) { 126 fatal("unable to register (YPPROG, YPVERS, udp)"); 127 } 128 if (!svc_register(yp->yp_trans_tcp, YPPROG, YPVERS, 129 yp_dispatch, IPPROTO_TCP)) { 130 fatal("unable to register (YPPROG, YPVERS, tcp)"); 131 } 132 } 133 134 /* 135 * lots of inspiration from ypserv by Mats O Jansson 136 */ 137 void 138 yp_dispatch(struct svc_req *req, SVCXPRT *trans) 139 { 140 xdrproc_t xdr_argument; 141 xdrproc_t xdr_result; 142 char *result; 143 char *(*cb)(char *, struct svc_req *); 144 union { 145 domainname ypproc_domain_2_arg; 146 domainname ypproc_domain_nonack_2_arg; 147 ypreq_key ypproc_match_2_arg; 148 ypreq_nokey ypproc_first_2_arg; 149 ypreq_key ypproc_next_2_arg; 150 ypreq_xfr ypproc_xfr_2_arg; 151 ypreq_nokey ypproc_all_2_arg; 152 ypreq_nokey ypproc_master_2_arg; 153 ypreq_nokey ypproc_order_2_arg; 154 domainname ypproc_maplist_2_arg; 155 } argument; 156 157 xdr_argument = (xdrproc_t) xdr_void; 158 xdr_result = (xdrproc_t) xdr_void; 159 cb = NULL; 160 switch (req->rq_proc) { 161 case YPPROC_NULL: 162 xdr_argument = (xdrproc_t) xdr_void; 163 xdr_result = (xdrproc_t) xdr_void; 164 if (yp_check(req) == -1) 165 return; 166 result = NULL; 167 if (!svc_sendreply(trans, (xdrproc_t) xdr_void, 168 (void *)&result)) 169 svcerr_systemerr(trans); 170 return; 171 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 xdr_argument = (xdrproc_t) xdr_ypreq_nokey; 220 xdr_result = (xdrproc_t) xdr_ypresp_all; 221 if (yp_check(req) == -1) 222 return; 223 cb = (void *)ypproc_all_2_svc; 224 break; 225 case YPPROC_MASTER: 226 log_debug("ypproc_master"); 227 xdr_argument = (xdrproc_t) xdr_ypreq_nokey; 228 xdr_result = (xdrproc_t) xdr_ypresp_master; 229 if (yp_check(req) == -1) 230 return; 231 cb = (void *)ypproc_master_2_svc; 232 break; 233 case YPPROC_ORDER: 234 log_debug("ypproc_order"); 235 if (yp_check(req) == -1) 236 return; 237 svcerr_noproc(trans); 238 return; 239 case YPPROC_MAPLIST: 240 log_debug("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; 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 key = calloc(arg->key.keydat_len + 1, 1); 346 if (key == NULL) 347 return (NULL); 348 (void)strncpy(key, arg->key.keydat_val, arg->key.keydat_len); 349 350 if (strcmp(arg->map, "passwd.byname") == 0 || 351 strcmp(arg->map, "master.passwd.byname") == 0) { 352 ukey.ue_line = key; 353 if ((ue = RB_FIND(user_name_tree, env->sc_user_names, 354 &ukey)) == NULL) { 355 res.stat = YP_NOKEY; 356 goto out; 357 } 358 359 yp_make_val(&res, ue->ue_line, 1); 360 goto out; 361 } else if (strcmp(arg->map, "passwd.byuid") == 0 || 362 strcmp(arg->map, "master.passwd.byuid") == 0) { 363 ukey.ue_uid = strtonum(key, 0, UID_MAX, &estr); 364 if (estr) { 365 res.stat = YP_BADARGS; 366 goto out; 367 } 368 369 if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids, 370 &ukey)) == NULL) { 371 res.stat = YP_NOKEY; 372 goto out; 373 } 374 375 yp_make_val(&res, ue->ue_line, 1); 376 return (&res); 377 } else if (strcmp(arg->map, "group.bygid") == 0) { 378 gkey.ge_gid = strtonum(key, 0, GID_MAX, &estr); 379 if (estr) { 380 res.stat = YP_BADARGS; 381 goto out; 382 } 383 if ((ge = RB_FIND(group_gid_tree, &env->sc_group_gids, 384 &gkey)) == NULL) { 385 res.stat = YP_NOKEY; 386 goto out; 387 } 388 389 yp_make_val(&res, ge->ge_line, 1); 390 return (&res); 391 } else if (strcmp(arg->map, "group.byname") == 0) { 392 gkey.ge_line = key; 393 if ((ge = RB_FIND(group_name_tree, env->sc_group_names, 394 &gkey)) == NULL) { 395 res.stat = YP_NOKEY; 396 goto out; 397 } 398 399 yp_make_val(&res, ge->ge_line, 1); 400 return (&res); 401 } else if (strcmp(arg->map, "netid.byname") == 0) { 402 bp = cp = key; 403 404 if (strncmp(bp, "unix.", strlen("unix.")) != 0) { 405 res.stat = YP_BADARGS; 406 goto out; 407 } 408 409 bp += strlen("unix."); 410 411 if (*bp == '\0') { 412 res.stat = YP_BADARGS; 413 goto out; 414 } 415 416 if (!(cp = strsep(&bp, "@"))) { 417 res.stat = YP_BADARGS; 418 goto out; 419 } 420 421 if (strcmp(bp, arg->domain) != 0) { 422 res.stat = YP_BADARGS; 423 goto out; 424 } 425 426 ukey.ue_uid = strtonum(cp, 0, UID_MAX, &estr); 427 if (estr) { 428 res.stat = YP_BADARGS; 429 goto out; 430 } 431 432 if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids, 433 &ukey)) == NULL) { 434 res.stat = YP_NOKEY; 435 goto out; 436 } 437 438 yp_make_val(&res, ue->ue_netid_line, 0); 439 goto out; 440 441 } else { 442 log_debug("unknown map %s", arg->map); 443 res.stat = YP_NOMAP; 444 goto out; 445 } 446 out: 447 free(key); 448 return (&res); 449 } 450 451 ypresp_key_val * 452 ypproc_first_2_svc(ypreq_nokey *arg, struct svc_req *req) 453 { 454 static struct ypresp_key_val res; 455 456 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 457 return (&res); 458 459 if (strcmp(arg->map, "passwd.byname") == 0 || 460 strcmp(arg->map, "master.passwd.byname") == 0) { 461 if (env->sc_user_lines == NULL) 462 return (NULL); 463 464 yp_make_keyval(&res, env->sc_user_lines, env->sc_user_lines); 465 } else if (strcmp(arg->map, "group.byname") == 0) { 466 if (env->sc_group_lines == NULL) 467 return (NULL); 468 469 yp_make_keyval(&res, env->sc_group_lines, env->sc_group_lines); 470 } else { 471 log_debug("unknown map %s", arg->map); 472 res.stat = YP_NOMAP; 473 } 474 475 return (&res); 476 } 477 478 ypresp_key_val * 479 ypproc_next_2_svc(ypreq_key *arg, struct svc_req *req) 480 { 481 struct userent ukey; 482 struct userent *ue; 483 struct groupent gkey; 484 struct groupent *ge; 485 char *line; 486 static struct ypresp_key_val res; 487 char *key; 488 489 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 490 return (&res); 491 492 key = NULL; 493 if (strcmp(arg->map, "passwd.byname") == 0 || 494 strcmp(arg->map, "master.passwd.byname") == 0) { 495 key = calloc(arg->key.keydat_len + 1, 1); 496 if (key == NULL) { 497 res.stat = YP_YPERR; 498 return (&res); 499 } 500 (void)strncpy(key, arg->key.keydat_val, 501 arg->key.keydat_len); 502 ukey.ue_line = key; 503 if ((ue = RB_FIND(user_name_tree, env->sc_user_names, 504 &ukey)) == NULL) { 505 /* 506 * canacar's trick: 507 * the user might have been deleted in between calls 508 * to next since the tree may be modified by a reload. 509 * next should still return the next user in 510 * lexicographical order, hence insert the search key 511 * and look up the next field, then remove it again. 512 */ 513 RB_INSERT(user_name_tree, env->sc_user_names, &ukey); 514 if ((ue = RB_NEXT(user_name_tree, &env->sc_user_names, 515 &ukey)) == NULL) { 516 RB_REMOVE(user_name_tree, env->sc_user_names, 517 &ukey); 518 res.stat = YP_NOKEY; 519 free(key); 520 return (&res); 521 } 522 RB_REMOVE(user_name_tree, env->sc_user_names, &ukey); 523 } 524 line = ue->ue_line + (strlen(ue->ue_line) + 1); 525 line = line + (strlen(line) + 1); 526 yp_make_keyval(&res, line, line); 527 free(key); 528 return (&res); 529 530 531 } else if (strcmp(arg->map, "group.byname") == 0) { 532 key = calloc(arg->key.keydat_len + 1, 1); 533 if (key == NULL) { 534 res.stat = YP_YPERR; 535 return (&res); 536 } 537 (void)strncpy(key, arg->key.keydat_val, 538 arg->key.keydat_len); 539 540 gkey.ge_line = key; 541 if ((ge = RB_FIND(group_name_tree, env->sc_group_names, 542 &gkey)) == NULL) { 543 /* 544 * canacar's trick reloaded. 545 */ 546 RB_INSERT(group_name_tree, env->sc_group_names, &gkey); 547 if ((ge = RB_NEXT(group_name_tree, &env->sc_group_names, 548 &gkey)) == NULL) { 549 RB_REMOVE(group_name_tree, env->sc_group_names, 550 &gkey); 551 res.stat = YP_NOKEY; 552 free(key); 553 return (&res); 554 } 555 RB_REMOVE(group_name_tree, env->sc_group_names, &gkey); 556 } 557 558 line = ge->ge_line + (strlen(ge->ge_line) + 1); 559 line = line + (strlen(line) + 1); 560 yp_make_keyval(&res, line, line); 561 free(key); 562 return (&res); 563 } else { 564 log_debug("unknown map %s", arg->map); 565 res.stat = YP_NOMAP; 566 return (&res); 567 } 568 } 569 570 ypresp_all * 571 ypproc_all_2_svc(ypreq_nokey *arg, struct svc_req *req) 572 { 573 static struct ypresp_all res; 574 575 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 576 return (&res); 577 578 svcerr_auth(req->rq_xprt, AUTH_FAILED); 579 return (NULL); 580 } 581 582 ypresp_master * 583 ypproc_master_2_svc(ypreq_nokey *arg, struct svc_req *req) 584 { 585 static struct ypresp_master res; 586 static char master[YPMAXPEER + 1]; 587 588 memset(&res, 0, sizeof(res)); 589 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 590 return (&res); 591 592 if (gethostname(master, sizeof(master)) == 0) { 593 res.peer = (peername)master; 594 res.stat = YP_TRUE; 595 } else 596 res.stat = YP_NOKEY; 597 598 return (&res); 599 } 600 601 ypresp_maplist * 602 ypproc_maplist_2_svc(domainname *arg, struct svc_req *req) 603 { 604 size_t i; 605 static struct { 606 char *name; 607 int cond; 608 } mapnames[] = { 609 { "passwd.byname", YPMAP_PASSWD_BYNAME }, 610 { "passwd.byuid", YPMAP_PASSWD_BYUID }, 611 { "master.passwd.byname", YPMAP_MASTER_PASSWD_BYNAME }, 612 { "master.passwd.byuid", YPMAP_MASTER_PASSWD_BYUID }, 613 { "group.byname", YPMAP_GROUP_BYNAME }, 614 { "group.bygid", YPMAP_GROUP_BYGID }, 615 { "netid.byname", YPMAP_NETID_BYNAME }, 616 }; 617 static ypresp_maplist res; 618 static struct ypmaplist maps[nitems(mapnames)]; 619 620 if (yp_valid_domain(*arg, (struct ypresp_val *)&res) == -1) 621 return (&res); 622 623 res.stat = YP_TRUE; 624 res.maps = NULL; 625 for (i = 0; i < nitems(mapnames); i++) { 626 if (!(env->sc_flags & mapnames[i].cond)) 627 continue; 628 maps[i].map = mapnames[i].name; 629 maps[i].next = res.maps; 630 res.maps = &maps[i]; 631 } 632 633 return (&res); 634 } 635 636 void 637 yp_make_val(struct ypresp_val *res, char *line, int replacecolon) 638 { 639 static char buf[LINE_WIDTH]; 640 641 memset(buf, 0, sizeof(buf)); 642 643 if (replacecolon) 644 line[strlen(line)] = ':'; 645 (void)strlcpy(buf, line, sizeof(buf)); 646 if (replacecolon) 647 line[strcspn(line, ":")] = '\0'; 648 log_debug("sending out %s", buf); 649 650 res->stat = YP_TRUE; 651 res->val.valdat_len = strlen(buf); 652 res->val.valdat_val = buf; 653 } 654 655 void 656 yp_make_keyval(struct ypresp_key_val *res, char *key, char *line) 657 { 658 static char keybuf[YPMAXRECORD+1]; 659 static char buf[LINE_WIDTH]; 660 661 memset(keybuf, 0, sizeof(keybuf)); 662 memset(buf, 0, sizeof(buf)); 663 664 (void)strlcpy(keybuf, key, sizeof(keybuf)); 665 res->key.keydat_len = strlen(keybuf); 666 res->key.keydat_val = keybuf; 667 668 if (*line == '\0') { 669 res->stat = YP_NOMORE; 670 return; 671 } 672 res->stat = YP_TRUE; 673 line[strlen(line)] = ':'; 674 (void)strlcpy(buf, line, sizeof(buf)); 675 line[strcspn(line, ":")] = '\0'; 676 log_debug("sending out %s => %s", keybuf, buf); 677 678 res->val.valdat_len = strlen(buf); 679 res->val.valdat_val = buf; 680 } 681