1/* $OpenBSD: svc.c,v 1.29 2015/10/05 01:23:17 deraadt Exp $ */ 2 3/* 4 * Copyright (c) 2010, Oracle America, Inc. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following 14 * disclaimer in the documentation and/or other materials 15 * provided with the distribution. 16 * * Neither the name of the "Oracle America, Inc." nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34/* 35 * svc.c, Server-side remote procedure call interface. 36 * 37 * There are two sets of procedures here. The xprt routines are 38 * for handling transport handles. The svc routines handle the 39 * list of service routines. 40 */ 41 42#include <errno.h> 43#include <stdlib.h> 44#include <string.h> 45 46#include <rpc/rpc.h> 47#include <rpc/pmap_clnt.h> 48 49static SVCXPRT **xports; 50static int xportssize; 51 52#define RQCRED_SIZE 400 /* this size is excessive */ 53 54#define max(a, b) (a > b ? a : b) 55 56/* 57 * The services list 58 * Each entry represents a set of procedures (an rpc program). 59 * The dispatch routine takes request structs and runs the 60 * appropriate procedure. 61 */ 62static struct svc_callout { 63 struct svc_callout *sc_next; 64 u_long sc_prog; 65 u_long sc_vers; 66 void (*sc_dispatch)(); 67} *svc_head; 68 69static struct svc_callout *svc_find(u_long, u_long, struct svc_callout **); 70static int svc_fd_insert(int); 71static int svc_fd_remove(int); 72 73int __svc_fdsetsize = FD_SETSIZE; 74fd_set *__svc_fdset = &svc_fdset; 75static int svc_pollfd_size; /* number of slots in svc_pollfd */ 76static int svc_used_pollfd; /* number of used slots in svc_pollfd */ 77static int *svc_pollfd_freelist; /* svc_pollfd free list */ 78static int svc_max_free; /* number of used slots in free list */ 79 80/* *************** SVCXPRT related stuff **************** */ 81 82/* 83 * Activate a transport handle. 84 */ 85void 86xprt_register(SVCXPRT *xprt) 87{ 88 /* ignore failure conditions */ 89 (void) __xprt_register(xprt); 90} 91 92/* 93 * Activate a transport handle. 94 */ 95int 96__xprt_register(SVCXPRT *xprt) 97{ 98 int sock = xprt->xp_sock; 99 100 if (xports == NULL || sock + 1 > xportssize) { 101 SVCXPRT **xp; 102 int size = FD_SETSIZE; 103 104 while (sock + 1 > size) 105 size += FD_SETSIZE; 106 xp = calloc(size, sizeof(SVCXPRT *)); 107 if (xp == NULL) 108 return (0); 109 if (xports) { 110 memcpy(xp, xports, xportssize * sizeof(SVCXPRT *)); 111 free(xports); 112 } 113 xportssize = size; 114 xports = xp; 115 } 116 117 if (!svc_fd_insert(sock)) 118 return (0); 119 xports[sock] = xprt; 120 121 return (1); 122} 123 124/* 125 * Insert a socket into svc_pollfd, svc_fdset and __svc_fdset. 126 * If we are out of space, we allocate ~128 more slots than we 127 * need now for future expansion. 128 * We try to keep svc_pollfd well packed (no holes) as possible 129 * so that poll(2) is efficient. 130 */ 131static int 132svc_fd_insert(int sock) 133{ 134 int slot; 135 136 /* 137 * Find a slot for sock in svc_pollfd; four possible cases: 138 * 1) need to allocate more space for svc_pollfd 139 * 2) there is an entry on the free list 140 * 3) the free list is empty (svc_used_pollfd is the next slot) 141 */ 142 if (svc_pollfd == NULL || svc_used_pollfd == svc_pollfd_size) { 143 struct pollfd *pfd; 144 int new_size, *new_freelist; 145 146 new_size = svc_pollfd ? svc_pollfd_size + 128 : FD_SETSIZE; 147 pfd = reallocarray(svc_pollfd, new_size, sizeof(*svc_pollfd)); 148 if (pfd == NULL) 149 return (0); /* no changes */ 150 new_freelist = realloc(svc_pollfd_freelist, new_size / 2); 151 if (new_freelist == NULL) { 152 free(pfd); 153 return (0); /* no changes */ 154 } 155 svc_pollfd = pfd; 156 svc_pollfd_size = new_size; 157 svc_pollfd_freelist = new_freelist; 158 for (slot = svc_used_pollfd; slot < svc_pollfd_size; slot++) { 159 svc_pollfd[slot].fd = -1; 160 svc_pollfd[slot].events = svc_pollfd[slot].revents = 0; 161 } 162 slot = svc_used_pollfd; 163 } else if (svc_max_free != 0) { 164 /* there is an entry on the free list, use it */ 165 slot = svc_pollfd_freelist[--svc_max_free]; 166 } else { 167 /* nothing on the free list but we have room to grow */ 168 slot = svc_used_pollfd; 169 } 170 if (sock + 1 > __svc_fdsetsize) { 171 fd_set *fds; 172 size_t bytes; 173 174 bytes = howmany(sock + 128, NFDBITS) * sizeof(fd_mask); 175 /* realloc() would be nicer but it gets tricky... */ 176 if ((fds = (fd_set *)mem_alloc(bytes)) != NULL) { 177 memset(fds, 0, bytes); 178 memcpy(fds, __svc_fdset, 179 howmany(__svc_fdsetsize, NFDBITS) * sizeof(fd_mask)); 180 if (__svc_fdset != &svc_fdset) 181 free(__svc_fdset); 182 __svc_fdset = fds; 183 __svc_fdsetsize = bytes / sizeof(fd_mask) * NFDBITS; 184 } 185 } 186 187 svc_pollfd[slot].fd = sock; 188 svc_pollfd[slot].events = POLLIN; 189 svc_used_pollfd++; 190 if (svc_max_pollfd < slot + 1) 191 svc_max_pollfd = slot + 1; 192 if (sock < FD_SETSIZE) 193 FD_SET(sock, &svc_fdset); 194 if (sock < __svc_fdsetsize && __svc_fdset != &svc_fdset) 195 FD_SET(sock, __svc_fdset); 196 svc_maxfd = max(svc_maxfd, sock); 197 198 return (1); 199} 200 201/* 202 * Remove a socket from svc_pollfd, svc_fdset and __svc_fdset. 203 * Freed slots are placed on the free list. If the free list fills 204 * up, we compact svc_pollfd (free list size == svc_pollfd_size /2). 205 */ 206static int 207svc_fd_remove(int sock) 208{ 209 int slot; 210 211 if (svc_pollfd == NULL) 212 return (0); 213 214 for (slot = 0; slot < svc_max_pollfd; slot++) { 215 if (svc_pollfd[slot].fd == sock) { 216 svc_pollfd[slot].fd = -1; 217 svc_pollfd[slot].events = svc_pollfd[slot].revents = 0; 218 svc_used_pollfd--; 219 if (sock < FD_SETSIZE) 220 FD_CLR(sock, &svc_fdset); 221 if (sock < __svc_fdsetsize && __svc_fdset != &svc_fdset) 222 FD_CLR(sock, __svc_fdset); 223 if (sock == svc_maxfd) { 224 for (svc_maxfd--; svc_maxfd >= 0; svc_maxfd--) 225 if (xports[svc_maxfd]) 226 break; 227 } 228 if (svc_max_free == svc_pollfd_size / 2) { 229 int i, j; 230 231 /* 232 * Out of space in the free list; this means 233 * that svc_pollfd is half full. Pack things 234 * such that svc_max_pollfd == svc_used_pollfd 235 * and svc_pollfd_freelist is empty. 236 */ 237 for (i = svc_used_pollfd, j = 0; 238 i < svc_max_pollfd && j < svc_max_free; i++) { 239 if (svc_pollfd[i].fd == -1) 240 continue; 241 /* be sure to use a low-numbered slot */ 242 while (svc_pollfd_freelist[j] >= 243 svc_used_pollfd) 244 j++; 245 svc_pollfd[svc_pollfd_freelist[j++]] = 246 svc_pollfd[i]; 247 svc_pollfd[i].fd = -1; 248 svc_pollfd[i].events = 249 svc_pollfd[i].revents = 0; 250 } 251 svc_max_pollfd = svc_used_pollfd; 252 svc_max_free = 0; 253 /* could realloc if svc_pollfd_size is big */ 254 } else { 255 /* trim svc_max_pollfd from the end */ 256 while (svc_max_pollfd > 0 && 257 svc_pollfd[svc_max_pollfd - 1].fd == -1) 258 svc_max_pollfd--; 259 } 260 svc_pollfd_freelist[svc_max_free++] = slot; 261 262 return (1); 263 } 264 } 265 return (0); /* not found, shouldn't happen */ 266} 267 268/* 269 * De-activate a transport handle. 270 */ 271void 272xprt_unregister(SVCXPRT *xprt) 273{ 274 int sock = xprt->xp_sock; 275 276 if (xports[sock] == xprt) { 277 xports[sock] = NULL; 278 svc_fd_remove(sock); 279 } 280} 281DEF_WEAK(xprt_unregister); 282 283 284/* ********************** CALLOUT list related stuff ************* */ 285 286/* 287 * Add a service program to the callout list. 288 * The dispatch routine will be called when a rpc request for this 289 * program number comes in. 290 */ 291bool_t 292svc_register(SVCXPRT *xprt, u_long prog, u_long vers, void (*dispatch)(), 293 int protocol) 294{ 295 struct svc_callout *prev; 296 struct svc_callout *s; 297 298 if ((s = svc_find(prog, vers, &prev)) != NULL) { 299 if (s->sc_dispatch == dispatch) 300 goto pmap_it; /* he is registering another xptr */ 301 return (FALSE); 302 } 303 s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout)); 304 if (s == NULL) { 305 return (FALSE); 306 } 307 s->sc_prog = prog; 308 s->sc_vers = vers; 309 s->sc_dispatch = dispatch; 310 s->sc_next = svc_head; 311 svc_head = s; 312pmap_it: 313 /* now register the information with the local binder service */ 314 if (protocol) { 315 return (pmap_set(prog, vers, protocol, xprt->xp_port)); 316 } 317 return (TRUE); 318} 319DEF_WEAK(svc_register); 320 321/* 322 * Remove a service program from the callout list. 323 */ 324void 325svc_unregister(u_long prog, u_long vers) 326{ 327 struct svc_callout *prev; 328 struct svc_callout *s; 329 330 if ((s = svc_find(prog, vers, &prev)) == NULL) 331 return; 332 if (prev == NULL) { 333 svc_head = s->sc_next; 334 } else { 335 prev->sc_next = s->sc_next; 336 } 337 s->sc_next = NULL; 338 mem_free((char *) s, (u_int) sizeof(struct svc_callout)); 339 /* now unregister the information with the local binder service */ 340 (void)pmap_unset(prog, vers); 341} 342 343/* 344 * Search the callout list for a program number, return the callout 345 * struct. 346 */ 347static struct svc_callout * 348svc_find(u_long prog, u_long vers, struct svc_callout **prev) 349{ 350 struct svc_callout *s, *p; 351 352 p = NULL; 353 for (s = svc_head; s != NULL; s = s->sc_next) { 354 if ((s->sc_prog == prog) && (s->sc_vers == vers)) 355 goto done; 356 p = s; 357 } 358done: 359 *prev = p; 360 return (s); 361} 362 363/* ******************* REPLY GENERATION ROUTINES ************ */ 364 365/* 366 * Send a reply to an rpc request 367 */ 368bool_t 369svc_sendreply(SVCXPRT *xprt, xdrproc_t xdr_results, caddr_t xdr_location) 370{ 371 struct rpc_msg rply; 372 373 rply.rm_direction = REPLY; 374 rply.rm_reply.rp_stat = MSG_ACCEPTED; 375 rply.acpted_rply.ar_verf = xprt->xp_verf; 376 rply.acpted_rply.ar_stat = SUCCESS; 377 rply.acpted_rply.ar_results.where = xdr_location; 378 rply.acpted_rply.ar_results.proc = xdr_results; 379 return (SVC_REPLY(xprt, &rply)); 380} 381DEF_WEAK(svc_sendreply); 382 383/* 384 * No procedure error reply 385 */ 386void 387svcerr_noproc(SVCXPRT *xprt) 388{ 389 struct rpc_msg rply; 390 391 rply.rm_direction = REPLY; 392 rply.rm_reply.rp_stat = MSG_ACCEPTED; 393 rply.acpted_rply.ar_verf = xprt->xp_verf; 394 rply.acpted_rply.ar_stat = PROC_UNAVAIL; 395 SVC_REPLY(xprt, &rply); 396} 397 398/* 399 * Can't decode args error reply 400 */ 401void 402svcerr_decode(SVCXPRT *xprt) 403{ 404 struct rpc_msg rply; 405 406 rply.rm_direction = REPLY; 407 rply.rm_reply.rp_stat = MSG_ACCEPTED; 408 rply.acpted_rply.ar_verf = xprt->xp_verf; 409 rply.acpted_rply.ar_stat = GARBAGE_ARGS; 410 SVC_REPLY(xprt, &rply); 411} 412DEF_WEAK(svcerr_decode); 413 414/* 415 * Some system error 416 */ 417void 418svcerr_systemerr(SVCXPRT *xprt) 419{ 420 struct rpc_msg rply; 421 422 rply.rm_direction = REPLY; 423 rply.rm_reply.rp_stat = MSG_ACCEPTED; 424 rply.acpted_rply.ar_verf = xprt->xp_verf; 425 rply.acpted_rply.ar_stat = SYSTEM_ERR; 426 SVC_REPLY(xprt, &rply); 427} 428 429/* 430 * Authentication error reply 431 */ 432void 433svcerr_auth(SVCXPRT *xprt, enum auth_stat why) 434{ 435 struct rpc_msg rply; 436 437 rply.rm_direction = REPLY; 438 rply.rm_reply.rp_stat = MSG_DENIED; 439 rply.rjcted_rply.rj_stat = AUTH_ERROR; 440 rply.rjcted_rply.rj_why = why; 441 SVC_REPLY(xprt, &rply); 442} 443DEF_WEAK(svcerr_auth); 444 445/* 446 * Auth too weak error reply 447 */ 448void 449svcerr_weakauth(SVCXPRT *xprt) 450{ 451 452 svcerr_auth(xprt, AUTH_TOOWEAK); 453} 454 455/* 456 * Program unavailable error reply 457 */ 458void 459svcerr_noprog(SVCXPRT *xprt) 460{ 461 struct rpc_msg rply; 462 463 rply.rm_direction = REPLY; 464 rply.rm_reply.rp_stat = MSG_ACCEPTED; 465 rply.acpted_rply.ar_verf = xprt->xp_verf; 466 rply.acpted_rply.ar_stat = PROG_UNAVAIL; 467 SVC_REPLY(xprt, &rply); 468} 469DEF_WEAK(svcerr_noprog); 470 471/* 472 * Program version mismatch error reply 473 */ 474void 475svcerr_progvers(SVCXPRT *xprt, u_long low_vers, u_long high_vers) 476{ 477 struct rpc_msg rply; 478 479 rply.rm_direction = REPLY; 480 rply.rm_reply.rp_stat = MSG_ACCEPTED; 481 rply.acpted_rply.ar_verf = xprt->xp_verf; 482 rply.acpted_rply.ar_stat = PROG_MISMATCH; 483 rply.acpted_rply.ar_vers.low = low_vers; 484 rply.acpted_rply.ar_vers.high = high_vers; 485 SVC_REPLY(xprt, &rply); 486} 487DEF_WEAK(svcerr_progvers); 488 489/* ******************* SERVER INPUT STUFF ******************* */ 490 491/* 492 * Get server side input from some transport. 493 * 494 * Statement of authentication parameters management: 495 * This function owns and manages all authentication parameters, specifically 496 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and 497 * the "cooked" credentials (rqst->rq_clntcred). 498 * However, this function does not know the structure of the cooked 499 * credentials, so it make the following assumptions: 500 * a) the structure is contiguous (no pointers), and 501 * b) the cred structure size does not exceed RQCRED_SIZE bytes. 502 * In all events, all three parameters are freed upon exit from this routine. 503 * The storage is trivially management on the call stack in userland, but 504 * is mallocated in kernel land. 505 */ 506 507void 508svc_getreq(int rdfds) 509{ 510 int bit; 511 512 for (; (bit = ffs(rdfds)); rdfds ^= (1 << (bit - 1))) 513 svc_getreq_common(bit - 1); 514} 515DEF_WEAK(svc_getreq); 516 517void 518svc_getreqset(fd_set *readfds) 519{ 520 svc_getreqset2(readfds, FD_SETSIZE); 521} 522 523void 524svc_getreqset2(fd_set *readfds, int width) 525{ 526 fd_mask mask, *maskp; 527 int bit, sock; 528 529 maskp = readfds->fds_bits; 530 for (sock = 0; sock < width; sock += NFDBITS) { 531 for (mask = *maskp++; (bit = ffs(mask)); 532 mask ^= (1 << (bit - 1))) 533 svc_getreq_common(sock + bit - 1); 534 } 535} 536DEF_WEAK(svc_getreqset2); 537 538void 539svc_getreq_poll(struct pollfd *pfd, const int nready) 540{ 541 int i, n; 542 543 for (n = nready, i = 0; n > 0; i++) { 544 if (pfd[i].fd == -1) 545 continue; 546 if (pfd[i].revents != 0) 547 n--; 548 if ((pfd[i].revents & (POLLIN | POLLHUP)) == 0) 549 continue; 550 svc_getreq_common(pfd[i].fd); 551 } 552} 553DEF_WEAK(svc_getreq_poll); 554 555void 556svc_getreq_common(int fd) 557{ 558 enum xprt_stat stat; 559 struct rpc_msg msg; 560 int prog_found; 561 u_long low_vers; 562 u_long high_vers; 563 struct svc_req r; 564 SVCXPRT *xprt; 565 char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; 566 567 msg.rm_call.cb_cred.oa_base = cred_area; 568 msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); 569 r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); 570 571 /* sock has input waiting */ 572 xprt = xports[fd]; 573 if (xprt == NULL) 574 /* But do we control the fd? */ 575 return; 576 /* now receive msgs from xprtprt (support batch calls) */ 577 do { 578 if (SVC_RECV(xprt, &msg)) { 579 /* find the exported program and call it */ 580 struct svc_callout *s; 581 enum auth_stat why; 582 583 r.rq_xprt = xprt; 584 r.rq_prog = msg.rm_call.cb_prog; 585 r.rq_vers = msg.rm_call.cb_vers; 586 r.rq_proc = msg.rm_call.cb_proc; 587 r.rq_cred = msg.rm_call.cb_cred; 588 /* first authenticate the message */ 589 if ((why= _authenticate(&r, &msg)) != AUTH_OK) { 590 svcerr_auth(xprt, why); 591 goto call_done; 592 } 593 /* now match message with a registered service*/ 594 prog_found = FALSE; 595 low_vers = (u_long) -1; 596 high_vers = 0; 597 for (s = svc_head; s != NULL; s = s->sc_next) { 598 if (s->sc_prog == r.rq_prog) { 599 if (s->sc_vers == r.rq_vers) { 600 (*s->sc_dispatch)(&r, xprt); 601 goto call_done; 602 } /* found correct version */ 603 prog_found = TRUE; 604 if (s->sc_vers < low_vers) 605 low_vers = s->sc_vers; 606 if (s->sc_vers > high_vers) 607 high_vers = s->sc_vers; 608 } /* found correct program */ 609 } 610 /* 611 * if we got here, the program or version 612 * is not served ... 613 */ 614 if (prog_found) 615 svcerr_progvers(xprt, low_vers, high_vers); 616 else 617 svcerr_noprog(xprt); 618 /* Fall through to ... */ 619 } 620 call_done: 621 if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 622 SVC_DESTROY(xprt); 623 break; 624 } 625 } while (stat == XPRT_MOREREQS); 626} 627DEF_WEAK(svc_getreq_common); 628