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[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 bzero(key, 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 bzero(key, 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 bzero(key, 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 bzero(&res, sizeof(res)); 571 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 572 return (&res); 573 574 if (gethostname(master, sizeof(master)) == 0) { 575 res.peer = (peername)master; 576 res.stat = YP_TRUE; 577 } else 578 res.stat = YP_NOKEY; 579 580 return (&res); 581 } 582 583 ypresp_maplist * 584 ypproc_maplist_2_svc(domainname *arg, struct svc_req *req) 585 { 586 size_t i; 587 static struct { 588 char *name; 589 int cond; 590 } mapnames[] = { 591 { "passwd.byname", YPMAP_PASSWD_BYNAME }, 592 { "passwd.byuid", YPMAP_PASSWD_BYUID }, 593 { "master.passwd.byname", YPMAP_MASTER_PASSWD_BYNAME }, 594 { "master.passwd.byuid", YPMAP_MASTER_PASSWD_BYUID }, 595 { "group.byname", YPMAP_GROUP_BYNAME }, 596 { "group.bygid", YPMAP_GROUP_BYGID }, 597 { "netid.byname", YPMAP_NETID_BYNAME }, 598 }; 599 static ypresp_maplist res; 600 static struct ypmaplist maps[nitems(mapnames)]; 601 602 if (yp_valid_domain(*arg, (struct ypresp_val *)&res) == -1) 603 return (&res); 604 605 res.stat = YP_TRUE; 606 res.maps = NULL; 607 for (i = 0; i < nitems(mapnames); i++) { 608 if (!(env->sc_flags & mapnames[i].cond)) 609 continue; 610 maps[i].map = mapnames[i].name; 611 maps[i].next = res.maps; 612 res.maps = &maps[i]; 613 } 614 615 return (&res); 616 } 617 618 void 619 yp_make_val(struct ypresp_val *res, char *line, int replacecolon) 620 { 621 static char buf[LINE_WIDTH]; 622 623 bzero(buf, sizeof(buf)); 624 625 if (replacecolon) 626 line[strlen(line)] = ':'; 627 (void)strlcpy(buf, line, sizeof(buf)); 628 if (replacecolon) 629 line[strcspn(line, ":")] = '\0'; 630 log_debug("sending out %s", buf); 631 632 res->stat = YP_TRUE; 633 res->val.valdat_len = strlen(buf); 634 res->val.valdat_val = buf; 635 } 636 637 void 638 yp_make_keyval(struct ypresp_key_val *res, char *key, char *line) 639 { 640 static char keybuf[YPMAXRECORD+1]; 641 static char buf[LINE_WIDTH]; 642 643 bzero(keybuf, sizeof(keybuf)); 644 bzero(buf, sizeof(buf)); 645 646 (void)strlcpy(keybuf, key, sizeof(keybuf)); 647 res->key.keydat_len = strlen(keybuf); 648 res->key.keydat_val = keybuf; 649 650 if (*line == '\0') { 651 res->stat = YP_NOMORE; 652 return; 653 } 654 res->stat = YP_TRUE; 655 line[strlen(line)] = ':'; 656 (void)strlcpy(buf, line, sizeof(buf)); 657 line[strcspn(line, ":")] = '\0'; 658 log_debug("sending out %s => %s", keybuf, buf); 659 660 res->val.valdat_len = strlen(buf); 661 res->val.valdat_val = buf; 662 } 663