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