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