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 /* 272 * We might want to know who we allow here. 273 */ 274 return (0); 275 } 276 277 int 278 yp_valid_domain(char *domain, struct ypresp_val *res) 279 { 280 if (domain == NULL) { 281 log_debug("NULL domain !"); 282 return (-1); 283 } 284 if (strcmp(domain, env->sc_domainname) != 0) { 285 res->stat = YP_NODOM; 286 return (-1); 287 } 288 return (0); 289 } 290 291 bool_t * 292 ypproc_domain_2_svc(domainname *arg, struct svc_req *req) 293 { 294 static bool_t res; 295 296 res = (bool_t)1; 297 if (strcmp(*arg, env->sc_domainname) != 0) 298 res = (bool_t)0; 299 return (&res); 300 } 301 302 bool_t * 303 ypproc_domain_nonack_2_svc(domainname *arg, struct svc_req *req) 304 { 305 static bool_t res; 306 307 if (strcmp(*arg, env->sc_domainname) != 0) 308 return NULL; 309 res = (bool_t)1; 310 return (&res); 311 } 312 313 ypresp_val * 314 ypproc_match_2_svc(ypreq_key *arg, struct svc_req *req) 315 { 316 struct userent ukey; 317 struct userent *ue; 318 struct groupent gkey; 319 struct groupent *ge; 320 static struct ypresp_val res; 321 const char *estr; 322 char *bp, *cp; 323 char *key; 324 325 log_debug("matching '%.*s' in map %s", arg->key.keydat_len, 326 arg->key.keydat_val, arg->map); 327 328 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 329 return (&res); 330 331 if (env->sc_user_names == NULL) { 332 /* 333 * tree not ready. 334 */ 335 return (NULL); 336 } 337 338 if (arg->key.keydat_len > YPMAXRECORD) { 339 log_debug("argument too long"); 340 return (NULL); 341 } 342 key = calloc(arg->key.keydat_len + 1, 1); 343 if (key == NULL) 344 return (NULL); 345 (void)strncpy(key, arg->key.keydat_val, arg->key.keydat_len); 346 347 if (strcmp(arg->map, "passwd.byname") == 0 || 348 strcmp(arg->map, "master.passwd.byname") == 0) { 349 ukey.ue_line = key; 350 if ((ue = RB_FIND(user_name_tree, env->sc_user_names, 351 &ukey)) == NULL) { 352 res.stat = YP_NOKEY; 353 goto out; 354 } 355 356 yp_make_val(&res, ue->ue_line, 1); 357 goto out; 358 } else if (strcmp(arg->map, "passwd.byuid") == 0 || 359 strcmp(arg->map, "master.passwd.byuid") == 0) { 360 ukey.ue_uid = strtonum(key, 0, UID_MAX, &estr); 361 if (estr) { 362 res.stat = YP_BADARGS; 363 goto out; 364 } 365 366 if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids, 367 &ukey)) == NULL) { 368 res.stat = YP_NOKEY; 369 goto out; 370 } 371 372 yp_make_val(&res, ue->ue_line, 1); 373 return (&res); 374 } else if (strcmp(arg->map, "group.bygid") == 0) { 375 gkey.ge_gid = strtonum(key, 0, GID_MAX, &estr); 376 if (estr) { 377 res.stat = YP_BADARGS; 378 goto out; 379 } 380 if ((ge = RB_FIND(group_gid_tree, &env->sc_group_gids, 381 &gkey)) == NULL) { 382 res.stat = YP_NOKEY; 383 goto out; 384 } 385 386 yp_make_val(&res, ge->ge_line, 1); 387 return (&res); 388 } else if (strcmp(arg->map, "group.byname") == 0) { 389 gkey.ge_line = key; 390 if ((ge = RB_FIND(group_name_tree, env->sc_group_names, 391 &gkey)) == NULL) { 392 res.stat = YP_NOKEY; 393 goto out; 394 } 395 396 yp_make_val(&res, ge->ge_line, 1); 397 return (&res); 398 } else if (strcmp(arg->map, "netid.byname") == 0) { 399 bp = cp = key; 400 401 if (strncmp(bp, "unix.", strlen("unix.")) != 0) { 402 res.stat = YP_BADARGS; 403 goto out; 404 } 405 406 bp += strlen("unix."); 407 408 if (*bp == '\0') { 409 res.stat = YP_BADARGS; 410 goto out; 411 } 412 413 if (!(cp = strsep(&bp, "@"))) { 414 res.stat = YP_BADARGS; 415 goto out; 416 } 417 418 if (strcmp(bp, arg->domain) != 0) { 419 res.stat = YP_BADARGS; 420 goto out; 421 } 422 423 ukey.ue_uid = strtonum(cp, 0, UID_MAX, &estr); 424 if (estr) { 425 res.stat = YP_BADARGS; 426 goto out; 427 } 428 429 if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids, 430 &ukey)) == NULL) { 431 res.stat = YP_NOKEY; 432 goto out; 433 } 434 435 yp_make_val(&res, ue->ue_netid_line, 0); 436 goto out; 437 438 } else { 439 log_debug("unknown map %s", arg->map); 440 res.stat = YP_NOMAP; 441 goto out; 442 } 443 out: 444 free(key); 445 return (&res); 446 } 447 448 ypresp_key_val * 449 ypproc_first_2_svc(ypreq_nokey *arg, struct svc_req *req) 450 { 451 static struct ypresp_key_val res; 452 453 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 454 return (&res); 455 456 if (strcmp(arg->map, "passwd.byname") == 0 || 457 strcmp(arg->map, "master.passwd.byname") == 0) { 458 if (env->sc_user_lines == NULL) 459 return (NULL); 460 461 yp_make_keyval(&res, env->sc_user_lines, env->sc_user_lines); 462 } else if (strcmp(arg->map, "group.byname") == 0) { 463 if (env->sc_group_lines == NULL) 464 return (NULL); 465 466 yp_make_keyval(&res, env->sc_group_lines, env->sc_group_lines); 467 } else { 468 log_debug("unknown map %s", arg->map); 469 res.stat = YP_NOMAP; 470 } 471 472 return (&res); 473 } 474 475 ypresp_key_val * 476 ypproc_next_2_svc(ypreq_key *arg, struct svc_req *req) 477 { 478 struct userent ukey; 479 struct userent *ue; 480 struct groupent gkey; 481 struct groupent *ge; 482 char *line; 483 static struct ypresp_key_val res; 484 char *key; 485 486 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 487 return (&res); 488 489 key = NULL; 490 if (strcmp(arg->map, "passwd.byname") == 0 || 491 strcmp(arg->map, "master.passwd.byname") == 0) { 492 key = calloc(arg->key.keydat_len + 1, 1); 493 if (key == NULL) { 494 res.stat = YP_YPERR; 495 return (&res); 496 } 497 (void)strncpy(key, arg->key.keydat_val, 498 arg->key.keydat_len); 499 ukey.ue_line = key; 500 if ((ue = RB_FIND(user_name_tree, env->sc_user_names, 501 &ukey)) == NULL) { 502 /* 503 * canacar's trick: 504 * the user might have been deleted in between calls 505 * to next since the tree may be modified by a reload. 506 * next should still return the next user in 507 * lexicographical order, hence insert the search key 508 * and look up the next field, then remove it again. 509 */ 510 RB_INSERT(user_name_tree, env->sc_user_names, &ukey); 511 if ((ue = RB_NEXT(user_name_tree, &env->sc_user_names, 512 &ukey)) == NULL) { 513 RB_REMOVE(user_name_tree, env->sc_user_names, 514 &ukey); 515 res.stat = YP_NOKEY; 516 free(key); 517 return (&res); 518 } 519 RB_REMOVE(user_name_tree, env->sc_user_names, &ukey); 520 } 521 line = ue->ue_line + (strlen(ue->ue_line) + 1); 522 line = line + (strlen(line) + 1); 523 yp_make_keyval(&res, line, line); 524 free(key); 525 return (&res); 526 527 528 } else if (strcmp(arg->map, "group.byname") == 0) { 529 key = calloc(arg->key.keydat_len + 1, 1); 530 if (key == NULL) { 531 res.stat = YP_YPERR; 532 return (&res); 533 } 534 (void)strncpy(key, arg->key.keydat_val, 535 arg->key.keydat_len); 536 537 gkey.ge_line = key; 538 if ((ge = RB_FIND(group_name_tree, env->sc_group_names, 539 &gkey)) == NULL) { 540 /* 541 * canacar's trick reloaded. 542 */ 543 RB_INSERT(group_name_tree, env->sc_group_names, &gkey); 544 if ((ge = RB_NEXT(group_name_tree, &env->sc_group_names, 545 &gkey)) == NULL) { 546 RB_REMOVE(group_name_tree, env->sc_group_names, 547 &gkey); 548 res.stat = YP_NOKEY; 549 free(key); 550 return (&res); 551 } 552 RB_REMOVE(group_name_tree, env->sc_group_names, &gkey); 553 } 554 555 line = ge->ge_line + (strlen(ge->ge_line) + 1); 556 line = line + (strlen(line) + 1); 557 yp_make_keyval(&res, line, line); 558 free(key); 559 return (&res); 560 } else { 561 log_debug("unknown map %s", arg->map); 562 res.stat = YP_NOMAP; 563 return (&res); 564 } 565 } 566 567 ypresp_all * 568 ypproc_all_2_svc(ypreq_nokey *arg, struct svc_req *req) 569 { 570 static struct ypresp_all res; 571 572 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 573 return (&res); 574 575 svcerr_auth(req->rq_xprt, AUTH_FAILED); 576 return (NULL); 577 } 578 579 ypresp_master * 580 ypproc_master_2_svc(ypreq_nokey *arg, struct svc_req *req) 581 { 582 static struct ypresp_master res; 583 static char master[YPMAXPEER + 1]; 584 585 memset(&res, 0, sizeof(res)); 586 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 587 return (&res); 588 589 if (gethostname(master, sizeof(master)) == 0) { 590 res.peer = (peername)master; 591 res.stat = YP_TRUE; 592 } else 593 res.stat = YP_NOKEY; 594 595 return (&res); 596 } 597 598 ypresp_maplist * 599 ypproc_maplist_2_svc(domainname *arg, struct svc_req *req) 600 { 601 size_t i; 602 static struct { 603 char *name; 604 int cond; 605 } mapnames[] = { 606 { "passwd.byname", YPMAP_PASSWD_BYNAME }, 607 { "passwd.byuid", YPMAP_PASSWD_BYUID }, 608 { "master.passwd.byname", YPMAP_MASTER_PASSWD_BYNAME }, 609 { "master.passwd.byuid", YPMAP_MASTER_PASSWD_BYUID }, 610 { "group.byname", YPMAP_GROUP_BYNAME }, 611 { "group.bygid", YPMAP_GROUP_BYGID }, 612 { "netid.byname", YPMAP_NETID_BYNAME }, 613 }; 614 static ypresp_maplist res; 615 static struct ypmaplist maps[nitems(mapnames)]; 616 617 if (yp_valid_domain(*arg, (struct ypresp_val *)&res) == -1) 618 return (&res); 619 620 res.stat = YP_TRUE; 621 res.maps = NULL; 622 for (i = 0; i < nitems(mapnames); i++) { 623 if (!(env->sc_flags & mapnames[i].cond)) 624 continue; 625 maps[i].map = mapnames[i].name; 626 maps[i].next = res.maps; 627 res.maps = &maps[i]; 628 } 629 630 return (&res); 631 } 632 633 void 634 yp_make_val(struct ypresp_val *res, char *line, int replacecolon) 635 { 636 static char buf[LINE_WIDTH]; 637 638 memset(buf, 0, sizeof(buf)); 639 640 if (replacecolon) 641 line[strlen(line)] = ':'; 642 (void)strlcpy(buf, line, sizeof(buf)); 643 if (replacecolon) 644 line[strcspn(line, ":")] = '\0'; 645 log_debug("sending out %s", buf); 646 647 res->stat = YP_TRUE; 648 res->val.valdat_len = strlen(buf); 649 res->val.valdat_val = buf; 650 } 651 652 void 653 yp_make_keyval(struct ypresp_key_val *res, char *key, char *line) 654 { 655 static char keybuf[YPMAXRECORD+1]; 656 static char buf[LINE_WIDTH]; 657 658 memset(keybuf, 0, sizeof(keybuf)); 659 memset(buf, 0, sizeof(buf)); 660 661 (void)strlcpy(keybuf, key, sizeof(keybuf)); 662 res->key.keydat_len = strlen(keybuf); 663 res->key.keydat_val = keybuf; 664 665 if (*line == '\0') { 666 res->stat = YP_NOMORE; 667 return; 668 } 669 res->stat = YP_TRUE; 670 line[strlen(line)] = ':'; 671 (void)strlcpy(buf, line, sizeof(buf)); 672 line[strcspn(line, ":")] = '\0'; 673 log_debug("sending out %s => %s", keybuf, buf); 674 675 res->val.valdat_len = strlen(buf); 676 res->val.valdat_val = buf; 677 } 678