1/* $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $ */ 2 3/*- 4 * Copyright (c) 2009, Sun Microsystems, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * - Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * - Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * - Neither the name of Sun Microsystems, Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#if defined(LIBC_SCCS) && !defined(lint) 32static char *sccsid2 = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro"; 33static char *sccsid = "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC"; 34#endif 35#include <sys/cdefs.h>
| 1/* $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $ */ 2 3/*- 4 * Copyright (c) 2009, Sun Microsystems, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * - Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * - Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * - Neither the name of Sun Microsystems, Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#if defined(LIBC_SCCS) && !defined(lint) 32static char *sccsid2 = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro"; 33static char *sccsid = "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC"; 34#endif 35#include <sys/cdefs.h>
|
87static struct svc_callout *svc_find(rpcprog_t, rpcvers_t, 88 struct svc_callout **, char *); 89static void __xprt_do_unregister (SVCXPRT *xprt, bool_t dolock); 90 91/* *************** SVCXPRT related stuff **************** */ 92 93/* 94 * Activate a transport handle. 95 */ 96void 97xprt_register(xprt) 98 SVCXPRT *xprt; 99{ 100 int sock; 101 102 assert(xprt != NULL); 103 104 sock = xprt->xp_fd; 105 106 rwlock_wrlock(&svc_fd_lock); 107 if (__svc_xports == NULL) { 108 __svc_xports = (SVCXPRT **) 109 mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *)); 110 if (__svc_xports == NULL) { 111 rwlock_unlock(&svc_fd_lock); 112 return; 113 } 114 memset(__svc_xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *)); 115 } 116 if (sock < FD_SETSIZE) { 117 __svc_xports[sock] = xprt; 118 FD_SET(sock, &svc_fdset); 119 svc_maxfd = max(svc_maxfd, sock); 120 } 121 rwlock_unlock(&svc_fd_lock); 122} 123 124void 125xprt_unregister(SVCXPRT *xprt) 126{ 127 __xprt_do_unregister(xprt, TRUE); 128} 129 130void 131__xprt_unregister_unlocked(SVCXPRT *xprt) 132{ 133 __xprt_do_unregister(xprt, FALSE); 134} 135 136/* 137 * De-activate a transport handle. 138 */ 139static void 140__xprt_do_unregister(xprt, dolock) 141 SVCXPRT *xprt; 142 bool_t dolock; 143{ 144 int sock; 145 146 assert(xprt != NULL); 147 148 sock = xprt->xp_fd; 149 150 if (dolock) 151 rwlock_wrlock(&svc_fd_lock); 152 if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) { 153 __svc_xports[sock] = NULL; 154 FD_CLR(sock, &svc_fdset); 155 if (sock >= svc_maxfd) { 156 for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--) 157 if (__svc_xports[svc_maxfd]) 158 break; 159 } 160 } 161 if (dolock) 162 rwlock_unlock(&svc_fd_lock); 163} 164 165/* 166 * Add a service program to the callout list. 167 * The dispatch routine will be called when a rpc request for this 168 * program number comes in. 169 */ 170bool_t 171svc_reg(xprt, prog, vers, dispatch, nconf) 172 SVCXPRT *xprt; 173 const rpcprog_t prog; 174 const rpcvers_t vers; 175 void (*dispatch)(struct svc_req *, SVCXPRT *); 176 const struct netconfig *nconf; 177{ 178 bool_t dummy; 179 struct svc_callout *prev; 180 struct svc_callout *s; 181 struct netconfig *tnconf; 182 char *netid = NULL; 183 int flag = 0; 184 185/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */ 186 187 if (xprt->xp_netid) { 188 netid = strdup(xprt->xp_netid); 189 flag = 1; 190 } else if (nconf && nconf->nc_netid) { 191 netid = strdup(nconf->nc_netid); 192 flag = 1; 193 } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) { 194 netid = strdup(tnconf->nc_netid); 195 flag = 1; 196 freenetconfigent(tnconf); 197 } /* must have been created with svc_raw_create */ 198 if ((netid == NULL) && (flag == 1)) { 199 return (FALSE); 200 } 201 202 rwlock_wrlock(&svc_lock); 203 if ((s = svc_find(prog, vers, &prev, netid)) != NULL) { 204 if (netid) 205 free(netid); 206 if (s->sc_dispatch == dispatch) 207 goto rpcb_it; /* he is registering another xptr */ 208 rwlock_unlock(&svc_lock); 209 return (FALSE); 210 } 211 s = mem_alloc(sizeof (struct svc_callout)); 212 if (s == NULL) { 213 if (netid) 214 free(netid); 215 rwlock_unlock(&svc_lock); 216 return (FALSE); 217 } 218 219 s->sc_prog = prog; 220 s->sc_vers = vers; 221 s->sc_dispatch = dispatch; 222 s->sc_netid = netid; 223 s->sc_next = svc_head; 224 svc_head = s; 225 226 if ((xprt->xp_netid == NULL) && (flag == 1) && netid) 227 ((SVCXPRT *) xprt)->xp_netid = strdup(netid); 228 229rpcb_it: 230 rwlock_unlock(&svc_lock); 231 /* now register the information with the local binder service */ 232 if (nconf) { 233 /*LINTED const castaway*/ 234 dummy = rpcb_set(prog, vers, (struct netconfig *) nconf, 235 &((SVCXPRT *) xprt)->xp_ltaddr); 236 return (dummy); 237 } 238 return (TRUE); 239} 240 241/* 242 * Remove a service program from the callout list. 243 */ 244void 245svc_unreg(prog, vers) 246 const rpcprog_t prog; 247 const rpcvers_t vers; 248{ 249 struct svc_callout *prev; 250 struct svc_callout *s; 251 252 /* unregister the information anyway */ 253 (void) rpcb_unset(prog, vers, NULL); 254 rwlock_wrlock(&svc_lock); 255 while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) { 256 if (prev == NULL) { 257 svc_head = s->sc_next; 258 } else { 259 prev->sc_next = s->sc_next; 260 } 261 s->sc_next = NULL; 262 if (s->sc_netid) 263 mem_free(s->sc_netid, sizeof (s->sc_netid) + 1); 264 mem_free(s, sizeof (struct svc_callout)); 265 } 266 rwlock_unlock(&svc_lock); 267} 268 269/* ********************** CALLOUT list related stuff ************* */ 270 271#ifdef PORTMAP 272/* 273 * Add a service program to the callout list. 274 * The dispatch routine will be called when a rpc request for this 275 * program number comes in. 276 */ 277bool_t 278svc_register(xprt, prog, vers, dispatch, protocol) 279 SVCXPRT *xprt; 280 u_long prog; 281 u_long vers; 282 void (*dispatch)(struct svc_req *, SVCXPRT *); 283 int protocol; 284{ 285 struct svc_callout *prev; 286 struct svc_callout *s; 287 288 assert(xprt != NULL); 289 assert(dispatch != NULL); 290 291 if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) != 292 NULL) { 293 if (s->sc_dispatch == dispatch) 294 goto pmap_it; /* he is registering another xptr */ 295 return (FALSE); 296 } 297 s = mem_alloc(sizeof(struct svc_callout)); 298 if (s == NULL) { 299 return (FALSE); 300 } 301 s->sc_prog = (rpcprog_t)prog; 302 s->sc_vers = (rpcvers_t)vers; 303 s->sc_dispatch = dispatch; 304 s->sc_next = svc_head; 305 svc_head = s; 306pmap_it: 307 /* now register the information with the local binder service */ 308 if (protocol) { 309 return (pmap_set(prog, vers, protocol, xprt->xp_port)); 310 } 311 return (TRUE); 312} 313 314/* 315 * Remove a service program from the callout list. 316 */ 317void 318svc_unregister(prog, vers) 319 u_long prog; 320 u_long vers; 321{ 322 struct svc_callout *prev; 323 struct svc_callout *s; 324 325 if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) == 326 NULL) 327 return; 328 if (prev == NULL) { 329 svc_head = s->sc_next; 330 } else { 331 prev->sc_next = s->sc_next; 332 } 333 s->sc_next = NULL; 334 mem_free(s, sizeof(struct svc_callout)); 335 /* now unregister the information with the local binder service */ 336 (void)pmap_unset(prog, vers); 337} 338#endif /* PORTMAP */ 339 340/* 341 * Search the callout list for a program number, return the callout 342 * struct. 343 */ 344static struct svc_callout * 345svc_find(prog, vers, prev, netid) 346 rpcprog_t prog; 347 rpcvers_t vers; 348 struct svc_callout **prev; 349 char *netid; 350{ 351 struct svc_callout *s, *p; 352 353 assert(prev != NULL); 354 355 p = NULL; 356 for (s = svc_head; s != NULL; s = s->sc_next) { 357 if (((s->sc_prog == prog) && (s->sc_vers == vers)) && 358 ((netid == NULL) || (s->sc_netid == NULL) || 359 (strcmp(netid, s->sc_netid) == 0))) 360 break; 361 p = s; 362 } 363 *prev = p; 364 return (s); 365} 366 367/* ******************* REPLY GENERATION ROUTINES ************ */ 368 369/* 370 * Send a reply to an rpc request 371 */ 372bool_t 373svc_sendreply(xprt, xdr_results, xdr_location) 374 SVCXPRT *xprt; 375 xdrproc_t xdr_results; 376 void * xdr_location; 377{ 378 struct rpc_msg rply; 379 380 assert(xprt != NULL); 381 382 rply.rm_direction = REPLY; 383 rply.rm_reply.rp_stat = MSG_ACCEPTED; 384 rply.acpted_rply.ar_verf = xprt->xp_verf; 385 rply.acpted_rply.ar_stat = SUCCESS; 386 rply.acpted_rply.ar_results.where = xdr_location; 387 rply.acpted_rply.ar_results.proc = xdr_results; 388 return (SVC_REPLY(xprt, &rply)); 389} 390 391/* 392 * No procedure error reply 393 */ 394void 395svcerr_noproc(xprt) 396 SVCXPRT *xprt; 397{ 398 struct rpc_msg rply; 399 400 assert(xprt != NULL); 401 402 rply.rm_direction = REPLY; 403 rply.rm_reply.rp_stat = MSG_ACCEPTED; 404 rply.acpted_rply.ar_verf = xprt->xp_verf; 405 rply.acpted_rply.ar_stat = PROC_UNAVAIL; 406 SVC_REPLY(xprt, &rply); 407} 408 409/* 410 * Can't decode args error reply 411 */ 412void 413svcerr_decode(xprt) 414 SVCXPRT *xprt; 415{ 416 struct rpc_msg rply; 417 418 assert(xprt != NULL); 419 420 rply.rm_direction = REPLY; 421 rply.rm_reply.rp_stat = MSG_ACCEPTED; 422 rply.acpted_rply.ar_verf = xprt->xp_verf; 423 rply.acpted_rply.ar_stat = GARBAGE_ARGS; 424 SVC_REPLY(xprt, &rply); 425} 426 427/* 428 * Some system error 429 */ 430void 431svcerr_systemerr(xprt) 432 SVCXPRT *xprt; 433{ 434 struct rpc_msg rply; 435 436 assert(xprt != NULL); 437 438 rply.rm_direction = REPLY; 439 rply.rm_reply.rp_stat = MSG_ACCEPTED; 440 rply.acpted_rply.ar_verf = xprt->xp_verf; 441 rply.acpted_rply.ar_stat = SYSTEM_ERR; 442 SVC_REPLY(xprt, &rply); 443} 444 445#if 0 446/* 447 * Tell RPC package to not complain about version errors to the client. This 448 * is useful when revving broadcast protocols that sit on a fixed address. 449 * There is really one (or should be only one) example of this kind of 450 * protocol: the portmapper (or rpc binder). 451 */ 452void 453__svc_versquiet_on(xprt) 454 SVCXPRT *xprt; 455{ 456 457 SVC_EXT(xprt)->xp_flags |= SVC_VERSQUIET; 458} 459 460void 461__svc_versquiet_off(xprt) 462 SVCXPRT *xprt; 463{ 464 465 SVC_EXT(xprt)->xp_flags &= ~SVC_VERSQUIET; 466} 467 468void 469svc_versquiet(xprt) 470 SVCXPRT *xprt; 471{ 472 __svc_versquiet_on(xprt); 473} 474 475int 476__svc_versquiet_get(xprt) 477 SVCXPRT *xprt; 478{ 479 480 return (SVC_EXT(xprt)->xp_flags & SVC_VERSQUIET); 481} 482#endif 483 484/* 485 * Authentication error reply 486 */ 487void 488svcerr_auth(xprt, why) 489 SVCXPRT *xprt; 490 enum auth_stat why; 491{ 492 struct rpc_msg rply; 493 494 assert(xprt != NULL); 495 496 rply.rm_direction = REPLY; 497 rply.rm_reply.rp_stat = MSG_DENIED; 498 rply.rjcted_rply.rj_stat = AUTH_ERROR; 499 rply.rjcted_rply.rj_why = why; 500 SVC_REPLY(xprt, &rply); 501} 502 503/* 504 * Auth too weak error reply 505 */ 506void 507svcerr_weakauth(xprt) 508 SVCXPRT *xprt; 509{ 510 511 assert(xprt != NULL); 512 513 svcerr_auth(xprt, AUTH_TOOWEAK); 514} 515 516/* 517 * Program unavailable error reply 518 */ 519void 520svcerr_noprog(xprt) 521 SVCXPRT *xprt; 522{ 523 struct rpc_msg rply; 524 525 assert(xprt != NULL); 526 527 rply.rm_direction = REPLY; 528 rply.rm_reply.rp_stat = MSG_ACCEPTED; 529 rply.acpted_rply.ar_verf = xprt->xp_verf; 530 rply.acpted_rply.ar_stat = PROG_UNAVAIL; 531 SVC_REPLY(xprt, &rply); 532} 533 534/* 535 * Program version mismatch error reply 536 */ 537void 538svcerr_progvers(xprt, low_vers, high_vers) 539 SVCXPRT *xprt; 540 rpcvers_t low_vers; 541 rpcvers_t high_vers; 542{ 543 struct rpc_msg rply; 544 545 assert(xprt != NULL); 546 547 rply.rm_direction = REPLY; 548 rply.rm_reply.rp_stat = MSG_ACCEPTED; 549 rply.acpted_rply.ar_verf = xprt->xp_verf; 550 rply.acpted_rply.ar_stat = PROG_MISMATCH; 551 rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers; 552 rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers; 553 SVC_REPLY(xprt, &rply); 554} 555 556/* 557 * Allocate a new server transport structure. All fields are 558 * initialized to zero and xp_p3 is initialized to point at an 559 * extension structure to hold various flags and authentication 560 * parameters. 561 */ 562SVCXPRT * 563svc_xprt_alloc() 564{ 565 SVCXPRT *xprt; 566 SVCXPRT_EXT *ext; 567 568 xprt = mem_alloc(sizeof(SVCXPRT)); 569 if (xprt == NULL) 570 return (NULL); 571 memset(xprt, 0, sizeof(SVCXPRT)); 572 ext = mem_alloc(sizeof(SVCXPRT_EXT)); 573 if (ext == NULL) { 574 mem_free(xprt, sizeof(SVCXPRT)); 575 return (NULL); 576 } 577 memset(ext, 0, sizeof(SVCXPRT_EXT)); 578 xprt->xp_p3 = ext; 579 ext->xp_auth.svc_ah_ops = &svc_auth_null_ops; 580 581 return (xprt); 582} 583 584/* 585 * Free a server transport structure. 586 */ 587void 588svc_xprt_free(xprt) 589 SVCXPRT *xprt; 590{ 591 592 mem_free(xprt->xp_p3, sizeof(SVCXPRT_EXT)); 593 mem_free(xprt, sizeof(SVCXPRT)); 594} 595 596/* ******************* SERVER INPUT STUFF ******************* */ 597 598/* 599 * Get server side input from some transport. 600 * 601 * Statement of authentication parameters management: 602 * This function owns and manages all authentication parameters, specifically 603 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and 604 * the "cooked" credentials (rqst->rq_clntcred). 605 * However, this function does not know the structure of the cooked 606 * credentials, so it make the following assumptions: 607 * a) the structure is contiguous (no pointers), and 608 * b) the cred structure size does not exceed RQCRED_SIZE bytes. 609 * In all events, all three parameters are freed upon exit from this routine. 610 * The storage is trivially management on the call stack in user land, but 611 * is mallocated in kernel land. 612 */ 613 614void 615svc_getreq(rdfds) 616 int rdfds; 617{ 618 fd_set readfds; 619 620 FD_ZERO(&readfds); 621 readfds.fds_bits[0] = rdfds; 622 svc_getreqset(&readfds); 623} 624 625void 626svc_getreqset(readfds) 627 fd_set *readfds; 628{ 629 int bit, fd; 630 fd_mask mask, *maskp; 631 int sock; 632 633 assert(readfds != NULL); 634 635 maskp = readfds->fds_bits; 636 for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) { 637 for (mask = *maskp++; (bit = ffsl(mask)) != 0; 638 mask ^= (1ul << (bit - 1))) { 639 /* sock has input waiting */ 640 fd = sock + bit - 1; 641 svc_getreq_common(fd); 642 } 643 } 644} 645 646void 647svc_getreq_common(fd) 648 int fd; 649{ 650 SVCXPRT *xprt; 651 struct svc_req r; 652 struct rpc_msg msg; 653 int prog_found; 654 rpcvers_t low_vers; 655 rpcvers_t high_vers; 656 enum xprt_stat stat; 657 char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; 658 659 msg.rm_call.cb_cred.oa_base = cred_area; 660 msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); 661 r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); 662 663 rwlock_rdlock(&svc_fd_lock); 664 xprt = __svc_xports[fd]; 665 rwlock_unlock(&svc_fd_lock); 666 if (xprt == NULL) 667 /* But do we control sock? */ 668 return; 669 /* now receive msgs from xprtprt (support batch calls) */ 670 do { 671 if (SVC_RECV(xprt, &msg)) { 672 673 /* now find the exported program and call it */ 674 struct svc_callout *s; 675 enum auth_stat why; 676 677 r.rq_xprt = xprt; 678 r.rq_prog = msg.rm_call.cb_prog; 679 r.rq_vers = msg.rm_call.cb_vers; 680 r.rq_proc = msg.rm_call.cb_proc; 681 r.rq_cred = msg.rm_call.cb_cred; 682 /* first authenticate the message */ 683 if ((why = _authenticate(&r, &msg)) != AUTH_OK) { 684 /* 685 * RPCSEC_GSS uses this return code 686 * for requests that form part of its 687 * context establishment protocol and 688 * should not be dispatched to the 689 * application. 690 */ 691 if (why != RPCSEC_GSS_NODISPATCH) 692 svcerr_auth(xprt, why); 693 goto call_done; 694 } 695 /* now match message with a registered service*/ 696 prog_found = FALSE; 697 low_vers = (rpcvers_t) -1L; 698 high_vers = (rpcvers_t) 0L; 699 for (s = svc_head; s != NULL; s = s->sc_next) { 700 if (s->sc_prog == r.rq_prog) { 701 if (s->sc_vers == r.rq_vers) { 702 (*s->sc_dispatch)(&r, xprt); 703 goto call_done; 704 } /* found correct version */ 705 prog_found = TRUE; 706 if (s->sc_vers < low_vers) 707 low_vers = s->sc_vers; 708 if (s->sc_vers > high_vers) 709 high_vers = s->sc_vers; 710 } /* found correct program */ 711 } 712 /* 713 * if we got here, the program or version 714 * is not served ... 715 */ 716 if (prog_found) 717 svcerr_progvers(xprt, low_vers, high_vers); 718 else 719 svcerr_noprog(xprt); 720 /* Fall through to ... */ 721 } 722 /* 723 * Check if the xprt has been disconnected in a 724 * recursive call in the service dispatch routine. 725 * If so, then break. 726 */ 727 rwlock_rdlock(&svc_fd_lock); 728 if (xprt != __svc_xports[fd]) { 729 rwlock_unlock(&svc_fd_lock); 730 break; 731 } 732 rwlock_unlock(&svc_fd_lock); 733call_done: 734 if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 735 SVC_DESTROY(xprt); 736 break; 737 } 738 } while (stat == XPRT_MOREREQS); 739} 740 741 742void 743svc_getreq_poll(pfdp, pollretval) 744 struct pollfd *pfdp; 745 int pollretval; 746{ 747 int i; 748 int fds_found; 749 750 for (i = fds_found = 0; fds_found < pollretval; i++) { 751 struct pollfd *p = &pfdp[i]; 752 753 if (p->revents) { 754 /* fd has input waiting */ 755 fds_found++; 756 /* 757 * We assume that this function is only called 758 * via someone _select()ing from svc_fdset or 759 * _poll()ing from svc_pollset[]. Thus it's safe 760 * to handle the POLLNVAL event by simply turning 761 * the corresponding bit off in svc_fdset. The 762 * svc_pollset[] array is derived from svc_fdset 763 * and so will also be updated eventually. 764 * 765 * XXX Should we do an xprt_unregister() instead? 766 */ 767 if (p->revents & POLLNVAL) { 768 rwlock_wrlock(&svc_fd_lock); 769 FD_CLR(p->fd, &svc_fdset); 770 rwlock_unlock(&svc_fd_lock); 771 } else 772 svc_getreq_common(p->fd); 773 } 774 } 775} 776 777bool_t 778rpc_control(int what, void *arg) 779{ 780 int val; 781 782 switch (what) { 783 case RPC_SVC_CONNMAXREC_SET: 784 val = *(int *)arg; 785 if (val <= 0) 786 return FALSE; 787 __svc_maxrec = val; 788 return TRUE; 789 case RPC_SVC_CONNMAXREC_GET: 790 *(int *)arg = __svc_maxrec; 791 return TRUE; 792 default: 793 break; 794 } 795 return FALSE; 796}
| 90static struct svc_callout *svc_find(rpcprog_t, rpcvers_t, 91 struct svc_callout **, char *); 92static void __xprt_do_unregister (SVCXPRT *xprt, bool_t dolock); 93 94/* *************** SVCXPRT related stuff **************** */ 95 96/* 97 * Activate a transport handle. 98 */ 99void 100xprt_register(xprt) 101 SVCXPRT *xprt; 102{ 103 int sock; 104 105 assert(xprt != NULL); 106 107 sock = xprt->xp_fd; 108 109 rwlock_wrlock(&svc_fd_lock); 110 if (__svc_xports == NULL) { 111 __svc_xports = (SVCXPRT **) 112 mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *)); 113 if (__svc_xports == NULL) { 114 rwlock_unlock(&svc_fd_lock); 115 return; 116 } 117 memset(__svc_xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *)); 118 } 119 if (sock < FD_SETSIZE) { 120 __svc_xports[sock] = xprt; 121 FD_SET(sock, &svc_fdset); 122 svc_maxfd = max(svc_maxfd, sock); 123 } 124 rwlock_unlock(&svc_fd_lock); 125} 126 127void 128xprt_unregister(SVCXPRT *xprt) 129{ 130 __xprt_do_unregister(xprt, TRUE); 131} 132 133void 134__xprt_unregister_unlocked(SVCXPRT *xprt) 135{ 136 __xprt_do_unregister(xprt, FALSE); 137} 138 139/* 140 * De-activate a transport handle. 141 */ 142static void 143__xprt_do_unregister(xprt, dolock) 144 SVCXPRT *xprt; 145 bool_t dolock; 146{ 147 int sock; 148 149 assert(xprt != NULL); 150 151 sock = xprt->xp_fd; 152 153 if (dolock) 154 rwlock_wrlock(&svc_fd_lock); 155 if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) { 156 __svc_xports[sock] = NULL; 157 FD_CLR(sock, &svc_fdset); 158 if (sock >= svc_maxfd) { 159 for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--) 160 if (__svc_xports[svc_maxfd]) 161 break; 162 } 163 } 164 if (dolock) 165 rwlock_unlock(&svc_fd_lock); 166} 167 168/* 169 * Add a service program to the callout list. 170 * The dispatch routine will be called when a rpc request for this 171 * program number comes in. 172 */ 173bool_t 174svc_reg(xprt, prog, vers, dispatch, nconf) 175 SVCXPRT *xprt; 176 const rpcprog_t prog; 177 const rpcvers_t vers; 178 void (*dispatch)(struct svc_req *, SVCXPRT *); 179 const struct netconfig *nconf; 180{ 181 bool_t dummy; 182 struct svc_callout *prev; 183 struct svc_callout *s; 184 struct netconfig *tnconf; 185 char *netid = NULL; 186 int flag = 0; 187 188/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */ 189 190 if (xprt->xp_netid) { 191 netid = strdup(xprt->xp_netid); 192 flag = 1; 193 } else if (nconf && nconf->nc_netid) { 194 netid = strdup(nconf->nc_netid); 195 flag = 1; 196 } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) { 197 netid = strdup(tnconf->nc_netid); 198 flag = 1; 199 freenetconfigent(tnconf); 200 } /* must have been created with svc_raw_create */ 201 if ((netid == NULL) && (flag == 1)) { 202 return (FALSE); 203 } 204 205 rwlock_wrlock(&svc_lock); 206 if ((s = svc_find(prog, vers, &prev, netid)) != NULL) { 207 if (netid) 208 free(netid); 209 if (s->sc_dispatch == dispatch) 210 goto rpcb_it; /* he is registering another xptr */ 211 rwlock_unlock(&svc_lock); 212 return (FALSE); 213 } 214 s = mem_alloc(sizeof (struct svc_callout)); 215 if (s == NULL) { 216 if (netid) 217 free(netid); 218 rwlock_unlock(&svc_lock); 219 return (FALSE); 220 } 221 222 s->sc_prog = prog; 223 s->sc_vers = vers; 224 s->sc_dispatch = dispatch; 225 s->sc_netid = netid; 226 s->sc_next = svc_head; 227 svc_head = s; 228 229 if ((xprt->xp_netid == NULL) && (flag == 1) && netid) 230 ((SVCXPRT *) xprt)->xp_netid = strdup(netid); 231 232rpcb_it: 233 rwlock_unlock(&svc_lock); 234 /* now register the information with the local binder service */ 235 if (nconf) { 236 /*LINTED const castaway*/ 237 dummy = rpcb_set(prog, vers, (struct netconfig *) nconf, 238 &((SVCXPRT *) xprt)->xp_ltaddr); 239 return (dummy); 240 } 241 return (TRUE); 242} 243 244/* 245 * Remove a service program from the callout list. 246 */ 247void 248svc_unreg(prog, vers) 249 const rpcprog_t prog; 250 const rpcvers_t vers; 251{ 252 struct svc_callout *prev; 253 struct svc_callout *s; 254 255 /* unregister the information anyway */ 256 (void) rpcb_unset(prog, vers, NULL); 257 rwlock_wrlock(&svc_lock); 258 while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) { 259 if (prev == NULL) { 260 svc_head = s->sc_next; 261 } else { 262 prev->sc_next = s->sc_next; 263 } 264 s->sc_next = NULL; 265 if (s->sc_netid) 266 mem_free(s->sc_netid, sizeof (s->sc_netid) + 1); 267 mem_free(s, sizeof (struct svc_callout)); 268 } 269 rwlock_unlock(&svc_lock); 270} 271 272/* ********************** CALLOUT list related stuff ************* */ 273 274#ifdef PORTMAP 275/* 276 * Add a service program to the callout list. 277 * The dispatch routine will be called when a rpc request for this 278 * program number comes in. 279 */ 280bool_t 281svc_register(xprt, prog, vers, dispatch, protocol) 282 SVCXPRT *xprt; 283 u_long prog; 284 u_long vers; 285 void (*dispatch)(struct svc_req *, SVCXPRT *); 286 int protocol; 287{ 288 struct svc_callout *prev; 289 struct svc_callout *s; 290 291 assert(xprt != NULL); 292 assert(dispatch != NULL); 293 294 if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) != 295 NULL) { 296 if (s->sc_dispatch == dispatch) 297 goto pmap_it; /* he is registering another xptr */ 298 return (FALSE); 299 } 300 s = mem_alloc(sizeof(struct svc_callout)); 301 if (s == NULL) { 302 return (FALSE); 303 } 304 s->sc_prog = (rpcprog_t)prog; 305 s->sc_vers = (rpcvers_t)vers; 306 s->sc_dispatch = dispatch; 307 s->sc_next = svc_head; 308 svc_head = s; 309pmap_it: 310 /* now register the information with the local binder service */ 311 if (protocol) { 312 return (pmap_set(prog, vers, protocol, xprt->xp_port)); 313 } 314 return (TRUE); 315} 316 317/* 318 * Remove a service program from the callout list. 319 */ 320void 321svc_unregister(prog, vers) 322 u_long prog; 323 u_long vers; 324{ 325 struct svc_callout *prev; 326 struct svc_callout *s; 327 328 if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) == 329 NULL) 330 return; 331 if (prev == NULL) { 332 svc_head = s->sc_next; 333 } else { 334 prev->sc_next = s->sc_next; 335 } 336 s->sc_next = NULL; 337 mem_free(s, sizeof(struct svc_callout)); 338 /* now unregister the information with the local binder service */ 339 (void)pmap_unset(prog, vers); 340} 341#endif /* PORTMAP */ 342 343/* 344 * Search the callout list for a program number, return the callout 345 * struct. 346 */ 347static struct svc_callout * 348svc_find(prog, vers, prev, netid) 349 rpcprog_t prog; 350 rpcvers_t vers; 351 struct svc_callout **prev; 352 char *netid; 353{ 354 struct svc_callout *s, *p; 355 356 assert(prev != NULL); 357 358 p = NULL; 359 for (s = svc_head; s != NULL; s = s->sc_next) { 360 if (((s->sc_prog == prog) && (s->sc_vers == vers)) && 361 ((netid == NULL) || (s->sc_netid == NULL) || 362 (strcmp(netid, s->sc_netid) == 0))) 363 break; 364 p = s; 365 } 366 *prev = p; 367 return (s); 368} 369 370/* ******************* REPLY GENERATION ROUTINES ************ */ 371 372/* 373 * Send a reply to an rpc request 374 */ 375bool_t 376svc_sendreply(xprt, xdr_results, xdr_location) 377 SVCXPRT *xprt; 378 xdrproc_t xdr_results; 379 void * xdr_location; 380{ 381 struct rpc_msg rply; 382 383 assert(xprt != NULL); 384 385 rply.rm_direction = REPLY; 386 rply.rm_reply.rp_stat = MSG_ACCEPTED; 387 rply.acpted_rply.ar_verf = xprt->xp_verf; 388 rply.acpted_rply.ar_stat = SUCCESS; 389 rply.acpted_rply.ar_results.where = xdr_location; 390 rply.acpted_rply.ar_results.proc = xdr_results; 391 return (SVC_REPLY(xprt, &rply)); 392} 393 394/* 395 * No procedure error reply 396 */ 397void 398svcerr_noproc(xprt) 399 SVCXPRT *xprt; 400{ 401 struct rpc_msg rply; 402 403 assert(xprt != NULL); 404 405 rply.rm_direction = REPLY; 406 rply.rm_reply.rp_stat = MSG_ACCEPTED; 407 rply.acpted_rply.ar_verf = xprt->xp_verf; 408 rply.acpted_rply.ar_stat = PROC_UNAVAIL; 409 SVC_REPLY(xprt, &rply); 410} 411 412/* 413 * Can't decode args error reply 414 */ 415void 416svcerr_decode(xprt) 417 SVCXPRT *xprt; 418{ 419 struct rpc_msg rply; 420 421 assert(xprt != NULL); 422 423 rply.rm_direction = REPLY; 424 rply.rm_reply.rp_stat = MSG_ACCEPTED; 425 rply.acpted_rply.ar_verf = xprt->xp_verf; 426 rply.acpted_rply.ar_stat = GARBAGE_ARGS; 427 SVC_REPLY(xprt, &rply); 428} 429 430/* 431 * Some system error 432 */ 433void 434svcerr_systemerr(xprt) 435 SVCXPRT *xprt; 436{ 437 struct rpc_msg rply; 438 439 assert(xprt != NULL); 440 441 rply.rm_direction = REPLY; 442 rply.rm_reply.rp_stat = MSG_ACCEPTED; 443 rply.acpted_rply.ar_verf = xprt->xp_verf; 444 rply.acpted_rply.ar_stat = SYSTEM_ERR; 445 SVC_REPLY(xprt, &rply); 446} 447 448#if 0 449/* 450 * Tell RPC package to not complain about version errors to the client. This 451 * is useful when revving broadcast protocols that sit on a fixed address. 452 * There is really one (or should be only one) example of this kind of 453 * protocol: the portmapper (or rpc binder). 454 */ 455void 456__svc_versquiet_on(xprt) 457 SVCXPRT *xprt; 458{ 459 460 SVC_EXT(xprt)->xp_flags |= SVC_VERSQUIET; 461} 462 463void 464__svc_versquiet_off(xprt) 465 SVCXPRT *xprt; 466{ 467 468 SVC_EXT(xprt)->xp_flags &= ~SVC_VERSQUIET; 469} 470 471void 472svc_versquiet(xprt) 473 SVCXPRT *xprt; 474{ 475 __svc_versquiet_on(xprt); 476} 477 478int 479__svc_versquiet_get(xprt) 480 SVCXPRT *xprt; 481{ 482 483 return (SVC_EXT(xprt)->xp_flags & SVC_VERSQUIET); 484} 485#endif 486 487/* 488 * Authentication error reply 489 */ 490void 491svcerr_auth(xprt, why) 492 SVCXPRT *xprt; 493 enum auth_stat why; 494{ 495 struct rpc_msg rply; 496 497 assert(xprt != NULL); 498 499 rply.rm_direction = REPLY; 500 rply.rm_reply.rp_stat = MSG_DENIED; 501 rply.rjcted_rply.rj_stat = AUTH_ERROR; 502 rply.rjcted_rply.rj_why = why; 503 SVC_REPLY(xprt, &rply); 504} 505 506/* 507 * Auth too weak error reply 508 */ 509void 510svcerr_weakauth(xprt) 511 SVCXPRT *xprt; 512{ 513 514 assert(xprt != NULL); 515 516 svcerr_auth(xprt, AUTH_TOOWEAK); 517} 518 519/* 520 * Program unavailable error reply 521 */ 522void 523svcerr_noprog(xprt) 524 SVCXPRT *xprt; 525{ 526 struct rpc_msg rply; 527 528 assert(xprt != NULL); 529 530 rply.rm_direction = REPLY; 531 rply.rm_reply.rp_stat = MSG_ACCEPTED; 532 rply.acpted_rply.ar_verf = xprt->xp_verf; 533 rply.acpted_rply.ar_stat = PROG_UNAVAIL; 534 SVC_REPLY(xprt, &rply); 535} 536 537/* 538 * Program version mismatch error reply 539 */ 540void 541svcerr_progvers(xprt, low_vers, high_vers) 542 SVCXPRT *xprt; 543 rpcvers_t low_vers; 544 rpcvers_t high_vers; 545{ 546 struct rpc_msg rply; 547 548 assert(xprt != NULL); 549 550 rply.rm_direction = REPLY; 551 rply.rm_reply.rp_stat = MSG_ACCEPTED; 552 rply.acpted_rply.ar_verf = xprt->xp_verf; 553 rply.acpted_rply.ar_stat = PROG_MISMATCH; 554 rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers; 555 rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers; 556 SVC_REPLY(xprt, &rply); 557} 558 559/* 560 * Allocate a new server transport structure. All fields are 561 * initialized to zero and xp_p3 is initialized to point at an 562 * extension structure to hold various flags and authentication 563 * parameters. 564 */ 565SVCXPRT * 566svc_xprt_alloc() 567{ 568 SVCXPRT *xprt; 569 SVCXPRT_EXT *ext; 570 571 xprt = mem_alloc(sizeof(SVCXPRT)); 572 if (xprt == NULL) 573 return (NULL); 574 memset(xprt, 0, sizeof(SVCXPRT)); 575 ext = mem_alloc(sizeof(SVCXPRT_EXT)); 576 if (ext == NULL) { 577 mem_free(xprt, sizeof(SVCXPRT)); 578 return (NULL); 579 } 580 memset(ext, 0, sizeof(SVCXPRT_EXT)); 581 xprt->xp_p3 = ext; 582 ext->xp_auth.svc_ah_ops = &svc_auth_null_ops; 583 584 return (xprt); 585} 586 587/* 588 * Free a server transport structure. 589 */ 590void 591svc_xprt_free(xprt) 592 SVCXPRT *xprt; 593{ 594 595 mem_free(xprt->xp_p3, sizeof(SVCXPRT_EXT)); 596 mem_free(xprt, sizeof(SVCXPRT)); 597} 598 599/* ******************* SERVER INPUT STUFF ******************* */ 600 601/* 602 * Get server side input from some transport. 603 * 604 * Statement of authentication parameters management: 605 * This function owns and manages all authentication parameters, specifically 606 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and 607 * the "cooked" credentials (rqst->rq_clntcred). 608 * However, this function does not know the structure of the cooked 609 * credentials, so it make the following assumptions: 610 * a) the structure is contiguous (no pointers), and 611 * b) the cred structure size does not exceed RQCRED_SIZE bytes. 612 * In all events, all three parameters are freed upon exit from this routine. 613 * The storage is trivially management on the call stack in user land, but 614 * is mallocated in kernel land. 615 */ 616 617void 618svc_getreq(rdfds) 619 int rdfds; 620{ 621 fd_set readfds; 622 623 FD_ZERO(&readfds); 624 readfds.fds_bits[0] = rdfds; 625 svc_getreqset(&readfds); 626} 627 628void 629svc_getreqset(readfds) 630 fd_set *readfds; 631{ 632 int bit, fd; 633 fd_mask mask, *maskp; 634 int sock; 635 636 assert(readfds != NULL); 637 638 maskp = readfds->fds_bits; 639 for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) { 640 for (mask = *maskp++; (bit = ffsl(mask)) != 0; 641 mask ^= (1ul << (bit - 1))) { 642 /* sock has input waiting */ 643 fd = sock + bit - 1; 644 svc_getreq_common(fd); 645 } 646 } 647} 648 649void 650svc_getreq_common(fd) 651 int fd; 652{ 653 SVCXPRT *xprt; 654 struct svc_req r; 655 struct rpc_msg msg; 656 int prog_found; 657 rpcvers_t low_vers; 658 rpcvers_t high_vers; 659 enum xprt_stat stat; 660 char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; 661 662 msg.rm_call.cb_cred.oa_base = cred_area; 663 msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); 664 r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); 665 666 rwlock_rdlock(&svc_fd_lock); 667 xprt = __svc_xports[fd]; 668 rwlock_unlock(&svc_fd_lock); 669 if (xprt == NULL) 670 /* But do we control sock? */ 671 return; 672 /* now receive msgs from xprtprt (support batch calls) */ 673 do { 674 if (SVC_RECV(xprt, &msg)) { 675 676 /* now find the exported program and call it */ 677 struct svc_callout *s; 678 enum auth_stat why; 679 680 r.rq_xprt = xprt; 681 r.rq_prog = msg.rm_call.cb_prog; 682 r.rq_vers = msg.rm_call.cb_vers; 683 r.rq_proc = msg.rm_call.cb_proc; 684 r.rq_cred = msg.rm_call.cb_cred; 685 /* first authenticate the message */ 686 if ((why = _authenticate(&r, &msg)) != AUTH_OK) { 687 /* 688 * RPCSEC_GSS uses this return code 689 * for requests that form part of its 690 * context establishment protocol and 691 * should not be dispatched to the 692 * application. 693 */ 694 if (why != RPCSEC_GSS_NODISPATCH) 695 svcerr_auth(xprt, why); 696 goto call_done; 697 } 698 /* now match message with a registered service*/ 699 prog_found = FALSE; 700 low_vers = (rpcvers_t) -1L; 701 high_vers = (rpcvers_t) 0L; 702 for (s = svc_head; s != NULL; s = s->sc_next) { 703 if (s->sc_prog == r.rq_prog) { 704 if (s->sc_vers == r.rq_vers) { 705 (*s->sc_dispatch)(&r, xprt); 706 goto call_done; 707 } /* found correct version */ 708 prog_found = TRUE; 709 if (s->sc_vers < low_vers) 710 low_vers = s->sc_vers; 711 if (s->sc_vers > high_vers) 712 high_vers = s->sc_vers; 713 } /* found correct program */ 714 } 715 /* 716 * if we got here, the program or version 717 * is not served ... 718 */ 719 if (prog_found) 720 svcerr_progvers(xprt, low_vers, high_vers); 721 else 722 svcerr_noprog(xprt); 723 /* Fall through to ... */ 724 } 725 /* 726 * Check if the xprt has been disconnected in a 727 * recursive call in the service dispatch routine. 728 * If so, then break. 729 */ 730 rwlock_rdlock(&svc_fd_lock); 731 if (xprt != __svc_xports[fd]) { 732 rwlock_unlock(&svc_fd_lock); 733 break; 734 } 735 rwlock_unlock(&svc_fd_lock); 736call_done: 737 if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 738 SVC_DESTROY(xprt); 739 break; 740 } 741 } while (stat == XPRT_MOREREQS); 742} 743 744 745void 746svc_getreq_poll(pfdp, pollretval) 747 struct pollfd *pfdp; 748 int pollretval; 749{ 750 int i; 751 int fds_found; 752 753 for (i = fds_found = 0; fds_found < pollretval; i++) { 754 struct pollfd *p = &pfdp[i]; 755 756 if (p->revents) { 757 /* fd has input waiting */ 758 fds_found++; 759 /* 760 * We assume that this function is only called 761 * via someone _select()ing from svc_fdset or 762 * _poll()ing from svc_pollset[]. Thus it's safe 763 * to handle the POLLNVAL event by simply turning 764 * the corresponding bit off in svc_fdset. The 765 * svc_pollset[] array is derived from svc_fdset 766 * and so will also be updated eventually. 767 * 768 * XXX Should we do an xprt_unregister() instead? 769 */ 770 if (p->revents & POLLNVAL) { 771 rwlock_wrlock(&svc_fd_lock); 772 FD_CLR(p->fd, &svc_fdset); 773 rwlock_unlock(&svc_fd_lock); 774 } else 775 svc_getreq_common(p->fd); 776 } 777 } 778} 779 780bool_t 781rpc_control(int what, void *arg) 782{ 783 int val; 784 785 switch (what) { 786 case RPC_SVC_CONNMAXREC_SET: 787 val = *(int *)arg; 788 if (val <= 0) 789 return FALSE; 790 __svc_maxrec = val; 791 return TRUE; 792 case RPC_SVC_CONNMAXREC_GET: 793 *(int *)arg = __svc_maxrec; 794 return TRUE; 795 default: 796 break; 797 } 798 return FALSE; 799}
|