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