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