1 /* 2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 3 * unrestricted use provided that this legend is included on all tape 4 * media and as a part of the software program in whole or part. Users 5 * may copy or modify Sun RPC without charge, but are not authorized 6 * to license or distribute it to anyone else except as part of a product or 7 * program developed by the user. 8 * 9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 12 * 13 * Sun RPC is provided with no support and without any obligation on the 14 * part of Sun Microsystems, Inc. to assist in its use, correction, 15 * modification or enhancement. 16 * 17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 19 * OR ANY PART THEREOF. 20 * 21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 22 * or profits or other special, indirect and consequential damages, even if 23 * Sun has been advised of the possibility of such damages. 24 * 25 * Sun Microsystems, Inc. 26 * 2550 Garcia Avenue 27 * Mountain View, California 94043 28 * 29 * @(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro 30 * @(#)svc.c 2.4 88/08/11 4.0 RPCSRC 31 * $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $ 32 * $FreeBSD: src/lib/libc/rpc/svc.c,v 1.24 2006/02/27 22:10:59 deischen Exp $ 33 * $DragonFly: src/lib/libc/rpc/svc.c,v 1.4 2005/11/13 12:27:04 swildner Exp $ 34 */ 35 36 /* 37 * svc.c, Server-side remote procedure call interface. 38 * 39 * There are two sets of procedures here. The xprt routines are 40 * for handling transport handles. The svc routines handle the 41 * list of service routines. 42 * 43 * Copyright (C) 1984, Sun Microsystems, Inc. 44 */ 45 46 #include "namespace.h" 47 #include "reentrant.h" 48 #include <sys/types.h> 49 #include <sys/poll.h> 50 #include <assert.h> 51 #include <errno.h> 52 #include <stdlib.h> 53 #include <string.h> 54 55 #include <rpc/rpc.h> 56 #ifdef PORTMAP 57 #include <rpc/pmap_clnt.h> 58 #endif /* PORTMAP */ 59 #include "un-namespace.h" 60 61 #include "rpc_com.h" 62 #include "mt_misc.h" 63 64 #define RQCRED_SIZE 400 /* this size is excessive */ 65 66 #define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */ 67 #define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET) 68 69 #define max(a, b) (a > b ? a : b) 70 71 /* 72 * The services list 73 * Each entry represents a set of procedures (an rpc program). 74 * The dispatch routine takes request structs and runs the 75 * apropriate procedure. 76 */ 77 static struct svc_callout { 78 struct svc_callout *sc_next; 79 rpcprog_t sc_prog; 80 rpcvers_t sc_vers; 81 char *sc_netid; 82 void (*sc_dispatch)(struct svc_req *, SVCXPRT *); 83 } *svc_head; 84 85 static struct svc_callout *svc_find(rpcprog_t, rpcvers_t, 86 struct svc_callout **, char *); 87 static void __xprt_do_unregister (SVCXPRT *xprt, bool_t dolock); 88 89 /* *************** SVCXPRT related stuff **************** */ 90 91 /* 92 * Activate a transport handle. 93 */ 94 void 95 xprt_register(SVCXPRT *xprt) 96 { 97 int sock; 98 99 assert(xprt != NULL); 100 101 sock = xprt->xp_fd; 102 103 rwlock_wrlock(&svc_fd_lock); 104 if (__svc_xports == NULL) { 105 __svc_xports = (SVCXPRT **) 106 mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *)); 107 if (__svc_xports == NULL) 108 return; 109 memset(__svc_xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *)); 110 } 111 if (sock < FD_SETSIZE) { 112 __svc_xports[sock] = xprt; 113 FD_SET(sock, &svc_fdset); 114 svc_maxfd = max(svc_maxfd, sock); 115 } 116 rwlock_unlock(&svc_fd_lock); 117 } 118 119 void 120 xprt_unregister(SVCXPRT *xprt) 121 { 122 __xprt_do_unregister(xprt, TRUE); 123 } 124 125 void 126 __xprt_unregister_unlocked(SVCXPRT *xprt) 127 { 128 __xprt_do_unregister(xprt, FALSE); 129 } 130 131 /* 132 * De-activate a transport handle. 133 */ 134 static void 135 __xprt_do_unregister(SVCXPRT *xprt, bool_t dolock) 136 { 137 int sock; 138 139 assert(xprt != NULL); 140 141 sock = xprt->xp_fd; 142 143 if (dolock) 144 rwlock_wrlock(&svc_fd_lock); 145 if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) { 146 __svc_xports[sock] = NULL; 147 FD_CLR(sock, &svc_fdset); 148 if (sock >= svc_maxfd) { 149 for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--) 150 if (__svc_xports[svc_maxfd]) 151 break; 152 } 153 } 154 if (dolock) 155 rwlock_unlock(&svc_fd_lock); 156 } 157 158 /* 159 * Add a service program to the callout list. 160 * The dispatch routine will be called when a rpc request for this 161 * program number comes in. 162 */ 163 bool_t 164 svc_reg(SVCXPRT *xprt, const rpcprog_t prog, const rpcvers_t vers, 165 void (*dispatch)(struct svc_req *, SVCXPRT *), 166 const struct netconfig *nconf) 167 { 168 bool_t dummy; 169 struct svc_callout *prev; 170 struct svc_callout *s; 171 struct netconfig *tnconf; 172 char *netid = NULL; 173 int flag = 0; 174 175 /* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */ 176 177 if (xprt->xp_netid) { 178 netid = strdup(xprt->xp_netid); 179 flag = 1; 180 } else if (nconf && nconf->nc_netid) { 181 netid = strdup(nconf->nc_netid); 182 flag = 1; 183 } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) { 184 netid = strdup(tnconf->nc_netid); 185 flag = 1; 186 freenetconfigent(tnconf); 187 } /* must have been created with svc_raw_create */ 188 if ((netid == NULL) && (flag == 1)) { 189 return (FALSE); 190 } 191 192 rwlock_wrlock(&svc_lock); 193 if ((s = svc_find(prog, vers, &prev, netid)) != NULL) { 194 if (netid) 195 free(netid); 196 if (s->sc_dispatch == dispatch) 197 goto rpcb_it; /* he is registering another xptr */ 198 rwlock_unlock(&svc_lock); 199 return (FALSE); 200 } 201 s = mem_alloc(sizeof (struct svc_callout)); 202 if (s == NULL) { 203 if (netid) 204 free(netid); 205 rwlock_unlock(&svc_lock); 206 return (FALSE); 207 } 208 209 s->sc_prog = prog; 210 s->sc_vers = vers; 211 s->sc_dispatch = dispatch; 212 s->sc_netid = netid; 213 s->sc_next = svc_head; 214 svc_head = s; 215 216 if ((xprt->xp_netid == NULL) && (flag == 1) && netid) 217 ((SVCXPRT *) xprt)->xp_netid = strdup(netid); 218 219 rpcb_it: 220 rwlock_unlock(&svc_lock); 221 /* now register the information with the local binder service */ 222 if (nconf) { 223 /*LINTED const castaway*/ 224 dummy = rpcb_set(prog, vers, (struct netconfig *) nconf, 225 &((SVCXPRT *) xprt)->xp_ltaddr); 226 return (dummy); 227 } 228 return (TRUE); 229 } 230 231 /* 232 * Remove a service program from the callout list. 233 */ 234 void 235 svc_unreg(const rpcprog_t prog, const rpcvers_t vers) 236 { 237 struct svc_callout *prev; 238 struct svc_callout *s; 239 240 /* unregister the information anyway */ 241 rpcb_unset(prog, vers, NULL); 242 rwlock_wrlock(&svc_lock); 243 while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) { 244 if (prev == NULL) { 245 svc_head = s->sc_next; 246 } else { 247 prev->sc_next = s->sc_next; 248 } 249 s->sc_next = NULL; 250 if (s->sc_netid) 251 mem_free(s->sc_netid, sizeof (s->sc_netid) + 1); 252 mem_free(s, sizeof (struct svc_callout)); 253 } 254 rwlock_unlock(&svc_lock); 255 } 256 257 /* ********************** CALLOUT list related stuff ************* */ 258 259 #ifdef PORTMAP 260 /* 261 * Add a service program to the callout list. 262 * The dispatch routine will be called when a rpc request for this 263 * program number comes in. 264 */ 265 bool_t 266 svc_register(SVCXPRT *xprt, u_long prog, u_long vers, 267 void (*dispatch)(struct svc_req *, SVCXPRT *), int protocol) 268 { 269 struct svc_callout *prev; 270 struct svc_callout *s; 271 272 assert(xprt != NULL); 273 assert(dispatch != NULL); 274 275 if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) != 276 NULL) { 277 if (s->sc_dispatch == dispatch) 278 goto pmap_it; /* he is registering another xptr */ 279 return (FALSE); 280 } 281 s = mem_alloc(sizeof(struct svc_callout)); 282 if (s == NULL) { 283 return (FALSE); 284 } 285 s->sc_prog = (rpcprog_t)prog; 286 s->sc_vers = (rpcvers_t)vers; 287 s->sc_dispatch = dispatch; 288 s->sc_next = svc_head; 289 svc_head = s; 290 pmap_it: 291 /* now register the information with the local binder service */ 292 if (protocol) { 293 return (pmap_set(prog, vers, protocol, xprt->xp_port)); 294 } 295 return (TRUE); 296 } 297 298 /* 299 * Remove a service program from the callout list. 300 */ 301 void 302 svc_unregister(u_long prog, u_long vers) 303 { 304 struct svc_callout *prev; 305 struct svc_callout *s; 306 307 if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) == 308 NULL) 309 return; 310 if (prev == NULL) { 311 svc_head = s->sc_next; 312 } else { 313 prev->sc_next = s->sc_next; 314 } 315 s->sc_next = NULL; 316 mem_free(s, sizeof(struct svc_callout)); 317 /* now unregister the information with the local binder service */ 318 pmap_unset(prog, vers); 319 } 320 #endif /* PORTMAP */ 321 322 /* 323 * Search the callout list for a program number, return the callout 324 * struct. 325 */ 326 static struct svc_callout * 327 svc_find(rpcprog_t prog, rpcvers_t vers, struct svc_callout **prev, char *netid) 328 { 329 struct svc_callout *s, *p; 330 331 assert(prev != NULL); 332 333 p = NULL; 334 for (s = svc_head; s != NULL; s = s->sc_next) { 335 if (((s->sc_prog == prog) && (s->sc_vers == vers)) && 336 ((netid == NULL) || (s->sc_netid == NULL) || 337 (strcmp(netid, s->sc_netid) == 0))) 338 break; 339 p = s; 340 } 341 *prev = p; 342 return (s); 343 } 344 345 /* ******************* REPLY GENERATION ROUTINES ************ */ 346 347 /* 348 * Send a reply to an rpc request 349 */ 350 bool_t 351 svc_sendreply(SVCXPRT *xprt, xdrproc_t xdr_results, void *xdr_location) 352 { 353 struct rpc_msg rply; 354 355 assert(xprt != NULL); 356 357 rply.rm_direction = REPLY; 358 rply.rm_reply.rp_stat = MSG_ACCEPTED; 359 rply.acpted_rply.ar_verf = xprt->xp_verf; 360 rply.acpted_rply.ar_stat = SUCCESS; 361 rply.acpted_rply.ar_results.where = xdr_location; 362 rply.acpted_rply.ar_results.proc = xdr_results; 363 return (SVC_REPLY(xprt, &rply)); 364 } 365 366 /* 367 * No procedure error reply 368 */ 369 void 370 svcerr_noproc(SVCXPRT *xprt) 371 { 372 struct rpc_msg rply; 373 374 assert(xprt != NULL); 375 376 rply.rm_direction = REPLY; 377 rply.rm_reply.rp_stat = MSG_ACCEPTED; 378 rply.acpted_rply.ar_verf = xprt->xp_verf; 379 rply.acpted_rply.ar_stat = PROC_UNAVAIL; 380 SVC_REPLY(xprt, &rply); 381 } 382 383 /* 384 * Can't decode args error reply 385 */ 386 void 387 svcerr_decode(SVCXPRT *xprt) 388 { 389 struct rpc_msg rply; 390 391 assert(xprt != NULL); 392 393 rply.rm_direction = REPLY; 394 rply.rm_reply.rp_stat = MSG_ACCEPTED; 395 rply.acpted_rply.ar_verf = xprt->xp_verf; 396 rply.acpted_rply.ar_stat = GARBAGE_ARGS; 397 SVC_REPLY(xprt, &rply); 398 } 399 400 /* 401 * Some system error 402 */ 403 void 404 svcerr_systemerr(SVCXPRT *xprt) 405 { 406 struct rpc_msg rply; 407 408 assert(xprt != NULL); 409 410 rply.rm_direction = REPLY; 411 rply.rm_reply.rp_stat = MSG_ACCEPTED; 412 rply.acpted_rply.ar_verf = xprt->xp_verf; 413 rply.acpted_rply.ar_stat = SYSTEM_ERR; 414 SVC_REPLY(xprt, &rply); 415 } 416 417 /* 418 * Authentication error reply 419 */ 420 void 421 svcerr_auth(SVCXPRT *xprt, enum auth_stat why) 422 { 423 struct rpc_msg rply; 424 425 assert(xprt != NULL); 426 427 rply.rm_direction = REPLY; 428 rply.rm_reply.rp_stat = MSG_DENIED; 429 rply.rjcted_rply.rj_stat = AUTH_ERROR; 430 rply.rjcted_rply.rj_why = why; 431 SVC_REPLY(xprt, &rply); 432 } 433 434 /* 435 * Auth too weak error reply 436 */ 437 void 438 svcerr_weakauth(SVCXPRT *xprt) 439 { 440 441 assert(xprt != NULL); 442 443 svcerr_auth(xprt, AUTH_TOOWEAK); 444 } 445 446 /* 447 * Program unavailable error reply 448 */ 449 void 450 svcerr_noprog(SVCXPRT *xprt) 451 { 452 struct rpc_msg rply; 453 454 assert(xprt != NULL); 455 456 rply.rm_direction = REPLY; 457 rply.rm_reply.rp_stat = MSG_ACCEPTED; 458 rply.acpted_rply.ar_verf = xprt->xp_verf; 459 rply.acpted_rply.ar_stat = PROG_UNAVAIL; 460 SVC_REPLY(xprt, &rply); 461 } 462 463 /* 464 * Program version mismatch error reply 465 */ 466 void 467 svcerr_progvers(SVCXPRT *xprt, rpcvers_t low_vers, rpcvers_t high_vers) 468 { 469 struct rpc_msg rply; 470 471 assert(xprt != NULL); 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 = (u_int32_t)low_vers; 478 rply.acpted_rply.ar_vers.high = (u_int32_t)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 fd_set readfds; 504 505 FD_ZERO(&readfds); 506 readfds.fds_bits[0] = rdfds; 507 svc_getreqset(&readfds); 508 } 509 510 void 511 svc_getreqset(fd_set *readfds) 512 { 513 int bit, fd; 514 fd_mask mask, *maskp; 515 int sock; 516 517 assert(readfds != NULL); 518 519 maskp = readfds->fds_bits; 520 for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) { 521 for (mask = *maskp++; (bit = ffs(mask)) != 0; 522 mask ^= (1 << (bit - 1))) { 523 /* sock has input waiting */ 524 fd = sock + bit - 1; 525 svc_getreq_common(fd); 526 } 527 } 528 } 529 530 void 531 svc_getreq_common(int fd) 532 { 533 SVCXPRT *xprt; 534 struct svc_req r; 535 struct rpc_msg msg; 536 int prog_found; 537 rpcvers_t low_vers; 538 rpcvers_t high_vers; 539 enum xprt_stat stat; 540 char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; 541 542 msg.rm_call.cb_cred.oa_base = cred_area; 543 msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); 544 r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); 545 546 rwlock_rdlock(&svc_fd_lock); 547 xprt = __svc_xports[fd]; 548 rwlock_unlock(&svc_fd_lock); 549 if (xprt == NULL) 550 /* But do we control sock? */ 551 return; 552 /* now receive msgs from xprtprt (support batch calls) */ 553 do { 554 if (SVC_RECV(xprt, &msg)) { 555 556 /* now find the exported program and call it */ 557 struct svc_callout *s; 558 enum auth_stat why; 559 560 r.rq_xprt = xprt; 561 r.rq_prog = msg.rm_call.cb_prog; 562 r.rq_vers = msg.rm_call.cb_vers; 563 r.rq_proc = msg.rm_call.cb_proc; 564 r.rq_cred = msg.rm_call.cb_cred; 565 /* first authenticate the message */ 566 if ((why = _authenticate(&r, &msg)) != AUTH_OK) { 567 svcerr_auth(xprt, why); 568 goto call_done; 569 } 570 /* now match message with a registered service*/ 571 prog_found = FALSE; 572 low_vers = (rpcvers_t) -1L; 573 high_vers = (rpcvers_t) 0L; 574 for (s = svc_head; s != NULL; s = s->sc_next) { 575 if (s->sc_prog == r.rq_prog) { 576 if (s->sc_vers == r.rq_vers) { 577 (*s->sc_dispatch)(&r, xprt); 578 goto call_done; 579 } /* found correct version */ 580 prog_found = TRUE; 581 if (s->sc_vers < low_vers) 582 low_vers = s->sc_vers; 583 if (s->sc_vers > high_vers) 584 high_vers = s->sc_vers; 585 } /* found correct program */ 586 } 587 /* 588 * if we got here, the program or version 589 * is not served ... 590 */ 591 if (prog_found) 592 svcerr_progvers(xprt, low_vers, high_vers); 593 else 594 svcerr_noprog(xprt); 595 /* Fall through to ... */ 596 } 597 /* 598 * Check if the xprt has been disconnected in a 599 * recursive call in the service dispatch routine. 600 * If so, then break. 601 */ 602 rwlock_rdlock(&svc_fd_lock); 603 if (xprt != __svc_xports[fd]) { 604 rwlock_unlock(&svc_fd_lock); 605 break; 606 } 607 rwlock_unlock(&svc_fd_lock); 608 call_done: 609 if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 610 SVC_DESTROY(xprt); 611 break; 612 } 613 } while (stat == XPRT_MOREREQS); 614 } 615 616 617 void 618 svc_getreq_poll(struct pollfd *pfdp, int pollretval) 619 { 620 int i; 621 int fds_found; 622 623 for (i = fds_found = 0; fds_found < pollretval; i++) { 624 struct pollfd *p = &pfdp[i]; 625 626 if (p->revents) { 627 /* fd has input waiting */ 628 fds_found++; 629 /* 630 * We assume that this function is only called 631 * via someone _select()ing from svc_fdset or 632 * _poll()ing from svc_pollset[]. Thus it's safe 633 * to handle the POLLNVAL event by simply turning 634 * the corresponding bit off in svc_fdset. The 635 * svc_pollset[] array is derived from svc_fdset 636 * and so will also be updated eventually. 637 * 638 * XXX Should we do an xprt_unregister() instead? 639 */ 640 if (p->revents & POLLNVAL) { 641 rwlock_wrlock(&svc_fd_lock); 642 FD_CLR(p->fd, &svc_fdset); 643 rwlock_unlock(&svc_fd_lock); 644 } else 645 svc_getreq_common(p->fd); 646 } 647 } 648 } 649 650 bool_t 651 rpc_control(int what, void *arg) 652 { 653 int val; 654 655 switch (what) { 656 case RPC_SVC_CONNMAXREC_SET: 657 val = *(int *)arg; 658 if (val <= 0) 659 return FALSE; 660 __svc_maxrec = val; 661 return TRUE; 662 case RPC_SVC_CONNMAXREC_GET: 663 *(int *)arg = __svc_maxrec; 664 return TRUE; 665 default: 666 break; 667 } 668 return FALSE; 669 } 670