1 /* $OpenBSD: svc.c,v 1.25 2010/09/01 14:43:34 millert 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 49 static SVCXPRT **xports; 50 static 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 */ 62 static 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 69 static struct svc_callout *svc_find(u_long, u_long, struct svc_callout **); 70 static int svc_fd_insert(int); 71 static int svc_fd_remove(int); 72 73 int __svc_fdsetsize = FD_SETSIZE; 74 fd_set *__svc_fdset = &svc_fdset; 75 static int svc_pollfd_size; /* number of slots in svc_pollfd */ 76 static int svc_used_pollfd; /* number of used slots in svc_pollfd */ 77 static int *svc_pollfd_freelist; /* svc_pollfd free list */ 78 static int svc_max_free; /* number of used slots in free list */ 79 80 /* *************** SVCXPRT related stuff **************** */ 81 82 /* 83 * Activate a transport handle. 84 */ 85 void 86 xprt_register(SVCXPRT *xprt) 87 { 88 /* ignore failure conditions */ 89 (void) __xprt_register(xprt); 90 } 91 92 /* 93 * Activate a transport handle. 94 */ 95 int 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 = (SVCXPRT **)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 */ 131 static int 132 svc_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 = realloc(svc_pollfd, sizeof(*svc_pollfd) * new_size); 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 */ 206 static int 207 svc_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 */ 271 void 272 xprt_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 } 281 282 283 /* ********************** CALLOUT list related stuff ************* */ 284 285 /* 286 * Add a service program to the callout list. 287 * The dispatch routine will be called when a rpc request for this 288 * program number comes in. 289 */ 290 bool_t 291 svc_register(SVCXPRT *xprt, u_long prog, u_long vers, void (*dispatch)(), 292 int protocol) 293 { 294 struct svc_callout *prev; 295 struct svc_callout *s; 296 297 if ((s = svc_find(prog, vers, &prev)) != NULL) { 298 if (s->sc_dispatch == dispatch) 299 goto pmap_it; /* he is registering another xptr */ 300 return (FALSE); 301 } 302 s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout)); 303 if (s == NULL) { 304 return (FALSE); 305 } 306 s->sc_prog = prog; 307 s->sc_vers = vers; 308 s->sc_dispatch = dispatch; 309 s->sc_next = svc_head; 310 svc_head = s; 311 pmap_it: 312 /* now register the information with the local binder service */ 313 if (protocol) { 314 return (pmap_set(prog, vers, protocol, xprt->xp_port)); 315 } 316 return (TRUE); 317 } 318 319 /* 320 * Remove a service program from the callout list. 321 */ 322 void 323 svc_unregister(u_long prog, u_long vers) 324 { 325 struct svc_callout *prev; 326 struct svc_callout *s; 327 328 if ((s = svc_find(prog, vers, &prev)) == NULL) 329 return; 330 if (prev == NULL) { 331 svc_head = s->sc_next; 332 } else { 333 prev->sc_next = s->sc_next; 334 } 335 s->sc_next = NULL; 336 mem_free((char *) s, (u_int) sizeof(struct svc_callout)); 337 /* now unregister the information with the local binder service */ 338 (void)pmap_unset(prog, vers); 339 } 340 341 /* 342 * Search the callout list for a program number, return the callout 343 * struct. 344 */ 345 static struct svc_callout * 346 svc_find(u_long prog, u_long vers, struct svc_callout **prev) 347 { 348 struct svc_callout *s, *p; 349 350 p = NULL; 351 for (s = svc_head; s != NULL; s = s->sc_next) { 352 if ((s->sc_prog == prog) && (s->sc_vers == vers)) 353 goto done; 354 p = s; 355 } 356 done: 357 *prev = p; 358 return (s); 359 } 360 361 /* ******************* REPLY GENERATION ROUTINES ************ */ 362 363 /* 364 * Send a reply to an rpc request 365 */ 366 bool_t 367 svc_sendreply(SVCXPRT *xprt, xdrproc_t xdr_results, caddr_t xdr_location) 368 { 369 struct rpc_msg rply; 370 371 rply.rm_direction = REPLY; 372 rply.rm_reply.rp_stat = MSG_ACCEPTED; 373 rply.acpted_rply.ar_verf = xprt->xp_verf; 374 rply.acpted_rply.ar_stat = SUCCESS; 375 rply.acpted_rply.ar_results.where = xdr_location; 376 rply.acpted_rply.ar_results.proc = xdr_results; 377 return (SVC_REPLY(xprt, &rply)); 378 } 379 380 /* 381 * No procedure error reply 382 */ 383 void 384 svcerr_noproc(SVCXPRT *xprt) 385 { 386 struct rpc_msg rply; 387 388 rply.rm_direction = REPLY; 389 rply.rm_reply.rp_stat = MSG_ACCEPTED; 390 rply.acpted_rply.ar_verf = xprt->xp_verf; 391 rply.acpted_rply.ar_stat = PROC_UNAVAIL; 392 SVC_REPLY(xprt, &rply); 393 } 394 395 /* 396 * Can't decode args error reply 397 */ 398 void 399 svcerr_decode(SVCXPRT *xprt) 400 { 401 struct rpc_msg rply; 402 403 rply.rm_direction = REPLY; 404 rply.rm_reply.rp_stat = MSG_ACCEPTED; 405 rply.acpted_rply.ar_verf = xprt->xp_verf; 406 rply.acpted_rply.ar_stat = GARBAGE_ARGS; 407 SVC_REPLY(xprt, &rply); 408 } 409 410 /* 411 * Some system error 412 */ 413 void 414 svcerr_systemerr(SVCXPRT *xprt) 415 { 416 struct rpc_msg rply; 417 418 rply.rm_direction = REPLY; 419 rply.rm_reply.rp_stat = MSG_ACCEPTED; 420 rply.acpted_rply.ar_verf = xprt->xp_verf; 421 rply.acpted_rply.ar_stat = SYSTEM_ERR; 422 SVC_REPLY(xprt, &rply); 423 } 424 425 /* 426 * Authentication error reply 427 */ 428 void 429 svcerr_auth(SVCXPRT *xprt, enum auth_stat why) 430 { 431 struct rpc_msg rply; 432 433 rply.rm_direction = REPLY; 434 rply.rm_reply.rp_stat = MSG_DENIED; 435 rply.rjcted_rply.rj_stat = AUTH_ERROR; 436 rply.rjcted_rply.rj_why = why; 437 SVC_REPLY(xprt, &rply); 438 } 439 440 /* 441 * Auth too weak error reply 442 */ 443 void 444 svcerr_weakauth(SVCXPRT *xprt) 445 { 446 447 svcerr_auth(xprt, AUTH_TOOWEAK); 448 } 449 450 /* 451 * Program unavailable error reply 452 */ 453 void 454 svcerr_noprog(SVCXPRT *xprt) 455 { 456 struct rpc_msg rply; 457 458 rply.rm_direction = REPLY; 459 rply.rm_reply.rp_stat = MSG_ACCEPTED; 460 rply.acpted_rply.ar_verf = xprt->xp_verf; 461 rply.acpted_rply.ar_stat = PROG_UNAVAIL; 462 SVC_REPLY(xprt, &rply); 463 } 464 465 /* 466 * Program version mismatch error reply 467 */ 468 void 469 svcerr_progvers(SVCXPRT *xprt, u_long low_vers, u_long high_vers) 470 { 471 struct rpc_msg rply; 472 473 rply.rm_direction = REPLY; 474 rply.rm_reply.rp_stat = MSG_ACCEPTED; 475 rply.acpted_rply.ar_verf = xprt->xp_verf; 476 rply.acpted_rply.ar_stat = PROG_MISMATCH; 477 rply.acpted_rply.ar_vers.low = low_vers; 478 rply.acpted_rply.ar_vers.high = high_vers; 479 SVC_REPLY(xprt, &rply); 480 } 481 482 /* ******************* SERVER INPUT STUFF ******************* */ 483 484 /* 485 * Get server side input from some transport. 486 * 487 * Statement of authentication parameters management: 488 * This function owns and manages all authentication parameters, specifically 489 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and 490 * the "cooked" credentials (rqst->rq_clntcred). 491 * However, this function does not know the structure of the cooked 492 * credentials, so it make the following assumptions: 493 * a) the structure is contiguous (no pointers), and 494 * b) the cred structure size does not exceed RQCRED_SIZE bytes. 495 * In all events, all three parameters are freed upon exit from this routine. 496 * The storage is trivially management on the call stack in user land, but 497 * is mallocated in kernel land. 498 */ 499 500 void 501 svc_getreq(int rdfds) 502 { 503 int bit; 504 505 for (; (bit = ffs(rdfds)); rdfds ^= (1 << (bit - 1))) 506 svc_getreq_common(bit - 1); 507 } 508 509 void 510 svc_getreqset(fd_set *readfds) 511 { 512 svc_getreqset2(readfds, FD_SETSIZE); 513 } 514 515 void 516 svc_getreqset2(fd_set *readfds, int width) 517 { 518 fd_mask mask, *maskp; 519 int bit, sock; 520 521 maskp = readfds->fds_bits; 522 for (sock = 0; sock < width; sock += NFDBITS) { 523 for (mask = *maskp++; (bit = ffs(mask)); 524 mask ^= (1 << (bit - 1))) 525 svc_getreq_common(sock + bit - 1); 526 } 527 } 528 529 void 530 svc_getreq_poll(struct pollfd *pfd, const int nready) 531 { 532 int i, n; 533 534 for (n = nready, i = 0; n > 0; i++) { 535 if (pfd[i].fd == -1) 536 continue; 537 if (pfd[i].revents != 0) 538 n--; 539 if ((pfd[i].revents & (POLLIN | POLLHUP)) == 0) 540 continue; 541 svc_getreq_common(pfd[i].fd); 542 } 543 } 544 545 void 546 svc_getreq_common(int fd) 547 { 548 enum xprt_stat stat; 549 struct rpc_msg msg; 550 int prog_found; 551 u_long low_vers; 552 u_long high_vers; 553 struct svc_req r; 554 SVCXPRT *xprt; 555 char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; 556 557 msg.rm_call.cb_cred.oa_base = cred_area; 558 msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); 559 r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); 560 561 /* sock has input waiting */ 562 xprt = xports[fd]; 563 if (xprt == NULL) 564 /* But do we control the fd? */ 565 return; 566 /* now receive msgs from xprtprt (support batch calls) */ 567 do { 568 if (SVC_RECV(xprt, &msg)) { 569 /* find the exported program and call it */ 570 struct svc_callout *s; 571 enum auth_stat why; 572 573 r.rq_xprt = xprt; 574 r.rq_prog = msg.rm_call.cb_prog; 575 r.rq_vers = msg.rm_call.cb_vers; 576 r.rq_proc = msg.rm_call.cb_proc; 577 r.rq_cred = msg.rm_call.cb_cred; 578 /* first authenticate the message */ 579 if ((why= _authenticate(&r, &msg)) != AUTH_OK) { 580 svcerr_auth(xprt, why); 581 goto call_done; 582 } 583 /* now match message with a registered service*/ 584 prog_found = FALSE; 585 low_vers = (u_long) -1; 586 high_vers = 0; 587 for (s = svc_head; s != NULL; s = s->sc_next) { 588 if (s->sc_prog == r.rq_prog) { 589 if (s->sc_vers == r.rq_vers) { 590 (*s->sc_dispatch)(&r, xprt); 591 goto call_done; 592 } /* found correct version */ 593 prog_found = TRUE; 594 if (s->sc_vers < low_vers) 595 low_vers = s->sc_vers; 596 if (s->sc_vers > high_vers) 597 high_vers = s->sc_vers; 598 } /* found correct program */ 599 } 600 /* 601 * if we got here, the program or version 602 * is not served ... 603 */ 604 if (prog_found) 605 svcerr_progvers(xprt, low_vers, high_vers); 606 else 607 svcerr_noprog(xprt); 608 /* Fall through to ... */ 609 } 610 call_done: 611 if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 612 SVC_DESTROY(xprt); 613 break; 614 } 615 } while (stat == XPRT_MOREREQS); 616 } 617