1 /* $OpenBSD: yp.c,v 1.19 2017/12/07 05:21:57 zhuk Exp $ */ 2 /* 3 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/queue.h> 20 #include <sys/socket.h> 21 #include <sys/select.h> 22 #include <sys/tree.h> 23 24 #include <netinet/in.h> 25 #include <arpa/inet.h> 26 27 #include <errno.h> 28 #include <event.h> 29 #include <fcntl.h> 30 #include <unistd.h> 31 #include <pwd.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <limits.h> 36 37 #include <rpc/rpc.h> 38 #include <rpc/xdr.h> 39 #include <rpc/pmap_clnt.h> 40 #include <rpc/pmap_prot.h> 41 #include <rpc/pmap_rmt.h> 42 #include <rpcsvc/yp.h> 43 #include <rpcsvc/ypclnt.h> 44 45 #include "ypldap.h" 46 47 void yp_dispatch(struct svc_req *, SVCXPRT *); 48 void yp_disable_events(void); 49 void yp_fd_event(int, short, void *); 50 int yp_check(struct svc_req *); 51 int yp_valid_domain(char *, struct ypresp_val *); 52 void yp_make_val(struct ypresp_val *, char *, int); 53 void yp_make_keyval(struct ypresp_key_val *, char *, char *); 54 55 static struct env *env; 56 57 struct yp_event { 58 TAILQ_ENTRY(yp_event) ye_entry; 59 struct event ye_event; 60 }; 61 62 struct yp_data { 63 SVCXPRT *yp_trans_udp; 64 SVCXPRT *yp_trans_tcp; 65 TAILQ_HEAD(, yp_event) yd_events; 66 }; 67 68 void 69 yp_disable_events(void) 70 { 71 struct yp_event *ye; 72 73 while ((ye = TAILQ_FIRST(&env->sc_yp->yd_events)) != NULL) { 74 TAILQ_REMOVE(&env->sc_yp->yd_events, ye, ye_entry); 75 event_del(&ye->ye_event); 76 free(ye); 77 } 78 } 79 80 void 81 yp_enable_events(void) 82 { 83 int i; 84 extern fd_set *__svc_fdset; 85 extern int __svc_fdsetsize; 86 struct yp_event *ye; 87 88 for (i = 0; i < __svc_fdsetsize; i++) { 89 if (FD_ISSET(i, __svc_fdset)) { 90 if ((ye = calloc(1, sizeof(*ye))) == NULL) 91 fatal(NULL); 92 event_set(&ye->ye_event, i, EV_READ, yp_fd_event, NULL); 93 event_add(&ye->ye_event, NULL); 94 TAILQ_INSERT_TAIL(&env->sc_yp->yd_events, ye, ye_entry); 95 } 96 } 97 } 98 99 void 100 yp_fd_event(int fd, short event, void *p) 101 { 102 svc_getreq_common(fd); 103 yp_disable_events(); 104 yp_enable_events(); 105 } 106 107 void 108 yp_init(struct env *x_env) 109 { 110 struct yp_data *yp; 111 112 if ((yp = calloc(1, sizeof(*yp))) == NULL) 113 fatal(NULL); 114 TAILQ_INIT(&yp->yd_events); 115 116 env = x_env; 117 env->sc_yp = yp; 118 119 (void)pmap_unset(YPPROG, YPVERS); 120 121 if ((yp->yp_trans_udp = svcudp_create(RPC_ANYSOCK)) == NULL) 122 fatal("cannot create udp service"); 123 if ((yp->yp_trans_tcp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) 124 fatal("cannot create tcp service"); 125 126 if (!svc_register(yp->yp_trans_udp, YPPROG, YPVERS, 127 yp_dispatch, IPPROTO_UDP)) { 128 fatal("unable to register (YPPROG, YPVERS, udp)"); 129 } 130 if (!svc_register(yp->yp_trans_tcp, YPPROG, YPVERS, 131 yp_dispatch, IPPROTO_TCP)) { 132 fatal("unable to register (YPPROG, YPVERS, tcp)"); 133 } 134 } 135 136 /* 137 * lots of inspiration from ypserv by Mats O Jansson 138 */ 139 void 140 yp_dispatch(struct svc_req *req, SVCXPRT *trans) 141 { 142 xdrproc_t xdr_argument; 143 xdrproc_t xdr_result; 144 char *result; 145 char *(*cb)(char *, struct svc_req *); 146 union { 147 domainname ypproc_domain_2_arg; 148 domainname ypproc_domain_nonack_2_arg; 149 ypreq_key ypproc_match_2_arg; 150 ypreq_nokey ypproc_first_2_arg; 151 ypreq_key ypproc_next_2_arg; 152 ypreq_xfr ypproc_xfr_2_arg; 153 ypreq_nokey ypproc_all_2_arg; 154 ypreq_nokey ypproc_master_2_arg; 155 ypreq_nokey ypproc_order_2_arg; 156 domainname ypproc_maplist_2_arg; 157 } argument; 158 159 xdr_argument = (xdrproc_t) xdr_void; 160 xdr_result = (xdrproc_t) xdr_void; 161 cb = NULL; 162 switch (req->rq_proc) { 163 case YPPROC_NULL: 164 xdr_argument = (xdrproc_t) xdr_void; 165 xdr_result = (xdrproc_t) xdr_void; 166 if (yp_check(req) == -1) 167 return; 168 result = NULL; 169 if (!svc_sendreply(trans, (xdrproc_t) xdr_void, 170 (void *)&result)) 171 svcerr_systemerr(trans); 172 return; 173 case YPPROC_DOMAIN: 174 xdr_argument = (xdrproc_t) xdr_domainname; 175 xdr_result = (xdrproc_t) xdr_bool; 176 if (yp_check(req) == -1) 177 return; 178 cb = (void *)ypproc_domain_2_svc; 179 break; 180 case YPPROC_DOMAIN_NONACK: 181 xdr_argument = (xdrproc_t) xdr_domainname; 182 xdr_result = (xdrproc_t) xdr_bool; 183 if (yp_check(req) == -1) 184 return; 185 cb = (void *)ypproc_domain_nonack_2_svc; 186 break; 187 case YPPROC_MATCH: 188 xdr_argument = (xdrproc_t) xdr_ypreq_key; 189 xdr_result = (xdrproc_t) xdr_ypresp_val; 190 if (yp_check(req) == -1) 191 return; 192 cb = (void *)ypproc_match_2_svc; 193 break; 194 case YPPROC_FIRST: 195 xdr_argument = (xdrproc_t) xdr_ypreq_nokey; 196 xdr_result = (xdrproc_t) xdr_ypresp_key_val; 197 if (yp_check(req) == -1) 198 return; 199 cb = (void *)ypproc_first_2_svc; 200 break; 201 case YPPROC_NEXT: 202 xdr_argument = (xdrproc_t) xdr_ypreq_key; 203 xdr_result = (xdrproc_t) xdr_ypresp_key_val; 204 if (yp_check(req) == -1) 205 return; 206 cb = (void *)ypproc_next_2_svc; 207 break; 208 case YPPROC_XFR: 209 if (yp_check(req) == -1) 210 return; 211 svcerr_noproc(trans); 212 return; 213 case YPPROC_CLEAR: 214 log_debug("ypproc_clear"); 215 if (yp_check(req) == -1) 216 return; 217 svcerr_noproc(trans); 218 return; 219 case YPPROC_ALL: 220 log_debug("ypproc_all"); 221 xdr_argument = (xdrproc_t) xdr_ypreq_nokey; 222 xdr_result = (xdrproc_t) xdr_ypresp_all; 223 if (yp_check(req) == -1) 224 return; 225 cb = (void *)ypproc_all_2_svc; 226 break; 227 case YPPROC_MASTER: 228 xdr_argument = (xdrproc_t) xdr_ypreq_nokey; 229 xdr_result = (xdrproc_t) xdr_ypresp_master; 230 if (yp_check(req) == -1) 231 return; 232 cb = (void *)ypproc_master_2_svc; 233 break; 234 case YPPROC_ORDER: 235 log_debug("ypproc_order"); 236 if (yp_check(req) == -1) 237 return; 238 svcerr_noproc(trans); 239 return; 240 case 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 memset(key, 0, 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 memset(key, 0, sizeof(key)); 490 (void)strncpy(key, arg->key.keydat_val, 491 arg->key.keydat_len); 492 ukey.ue_line = key; 493 if ((ue = RB_NFIND(user_name_tree, env->sc_user_names, 494 &ukey)) == NULL) { 495 res.stat = YP_NOKEY; 496 return (&res); 497 } 498 line = ue->ue_line + (strlen(ue->ue_line) + 1); 499 line = line + (strlen(line) + 1); 500 yp_make_keyval(&res, line, line); 501 return (&res); 502 503 504 } else if (strcmp(arg->map, "group.byname") == 0) { 505 memset(key, 0, sizeof(key)); 506 (void)strncpy(key, arg->key.keydat_val, 507 arg->key.keydat_len); 508 509 gkey.ge_line = key; 510 if ((ge = RB_NFIND(group_name_tree, env->sc_group_names, 511 &gkey)) == NULL) { 512 res.stat = YP_NOKEY; 513 return (&res); 514 } 515 516 line = ge->ge_line + (strlen(ge->ge_line) + 1); 517 line = line + (strlen(line) + 1); 518 yp_make_keyval(&res, line, line); 519 return (&res); 520 } else { 521 log_debug("unknown map %s", arg->map); 522 res.stat = YP_NOMAP; 523 return (&res); 524 } 525 } 526 527 ypresp_all * 528 ypproc_all_2_svc(ypreq_nokey *arg, struct svc_req *req) 529 { 530 static struct ypresp_all res; 531 532 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 533 return (&res); 534 535 svcerr_auth(req->rq_xprt, AUTH_FAILED); 536 return (NULL); 537 } 538 539 ypresp_master * 540 ypproc_master_2_svc(ypreq_nokey *arg, struct svc_req *req) 541 { 542 static struct ypresp_master res; 543 static char master[YPMAXPEER + 1]; 544 545 memset(&res, 0, sizeof(res)); 546 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1) 547 return (&res); 548 if (gethostname(master, sizeof(master)) == 0) { 549 res.peer = (peername)master; 550 res.stat = YP_TRUE; 551 } else 552 res.stat = YP_NOKEY; 553 return (&res); 554 } 555 556 ypresp_maplist * 557 ypproc_maplist_2_svc(domainname *arg, struct svc_req *req) 558 { 559 size_t i; 560 static struct { 561 char *name; 562 int cond; 563 } mapnames[] = { 564 { "passwd.byname", YPMAP_PASSWD_BYNAME }, 565 { "passwd.byuid", YPMAP_PASSWD_BYUID }, 566 { "master.passwd.byname", YPMAP_MASTER_PASSWD_BYNAME }, 567 { "master.passwd.byuid", YPMAP_MASTER_PASSWD_BYUID }, 568 { "group.byname", YPMAP_GROUP_BYNAME }, 569 { "group.bygid", YPMAP_GROUP_BYGID }, 570 { "netid.byname", YPMAP_NETID_BYNAME }, 571 }; 572 static ypresp_maplist res; 573 static struct ypmaplist maps[sizeof(mapnames) / sizeof(mapnames[0])]; 574 575 if (yp_valid_domain(*arg, (struct ypresp_val *)&res) == -1) 576 return (&res); 577 578 res.stat = YP_TRUE; 579 res.maps = NULL; 580 for (i = 0; i < sizeof(mapnames) / sizeof(mapnames[0]); i++) { 581 if (!(env->sc_flags & mapnames[i].cond)) 582 continue; 583 maps[i].map = mapnames[i].name; 584 maps[i].next = res.maps; 585 res.maps = &maps[i]; 586 } 587 588 return (&res); 589 } 590 591 void 592 yp_make_val(struct ypresp_val *res, char *line, int replacecolon) 593 { 594 static char buf[LINE_WIDTH]; 595 596 memset(buf, 0, sizeof(buf)); 597 598 if (replacecolon) 599 line[strlen(line)] = ':'; 600 (void)strlcpy(buf, line, sizeof(buf)); 601 if (replacecolon) 602 line[strcspn(line, ":")] = '\0'; 603 log_debug("sending out %s", buf); 604 605 res->stat = YP_TRUE; 606 res->val.valdat_len = strlen(buf); 607 res->val.valdat_val = buf; 608 } 609 610 void 611 yp_make_keyval(struct ypresp_key_val *res, char *key, char *line) 612 { 613 static char keybuf[YPMAXRECORD+1]; 614 static char buf[LINE_WIDTH]; 615 616 memset(keybuf, 0, sizeof(keybuf)); 617 memset(buf, 0, sizeof(buf)); 618 619 (void)strlcpy(keybuf, key, sizeof(keybuf)); 620 res->key.keydat_len = strlen(keybuf); 621 res->key.keydat_val = keybuf; 622 623 if (*line == '\0') { 624 res->stat = YP_NOMORE; 625 return; 626 } 627 res->stat = YP_TRUE; 628 line[strlen(line)] = ':'; 629 (void)strlcpy(buf, line, sizeof(buf)); 630 line[strcspn(line, ":")] = '\0'; 631 log_debug("sending out %s => %s", keybuf, buf); 632 633 res->val.valdat_len = strlen(buf); 634 res->val.valdat_val = buf; 635 } 636