1 /* @(#)svc.c 2.4 88/08/11 4.0 RPCSRC; from 1.44 88/02/08 SMI */ 2 /* 3 * Copyright (c) 2010, Oracle America, Inc. 4 * 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 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 18 * * Neither the name of the "Oracle America, Inc." nor the names of 19 * its contributors may be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 23 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 25 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 28 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 29 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 #if !defined(lint) && defined(SCCSIDS) 35 static char sccsid[] = "@(#)svc.c 1.41 87/10/13 Copyr 1984 Sun Micro"; 36 #endif 37 38 /* 39 * svc.c, Server-side remote procedure call interface. 40 * 41 * There are two sets of procedures here. The xprt routines are 42 * for handling transport handles. The svc routines handle the 43 * list of service routines. 44 */ 45 46 #include "autoconf.h" 47 #if HAVE_SYS_PARAM_H 48 #include <sys/param.h> 49 #endif 50 #include <gssrpc/rpc.h> 51 #include <gssrpc/pmap_clnt.h> 52 #include <stdio.h> 53 #include <string.h> 54 #include <errno.h> 55 56 #ifdef FD_SETSIZE 57 static SVCXPRT **xports; 58 extern int gssrpc_svc_fdset_init; 59 #else 60 61 #ifdef NBBY 62 #define NOFILE (sizeof(int) * NBBY) 63 #else 64 #define NOFILE (sizeof(int) * 8) 65 #endif 66 67 static SVCXPRT *xports[NOFILE]; 68 #endif /* def FD_SETSIZE */ 69 70 #define NULL_SVC ((struct svc_callout *)0) 71 #define RQCRED_SIZE 1024 /* this size is excessive */ 72 73 /* 74 * The services list 75 * Each entry represents a set of procedures (an rpc program). 76 * The dispatch routine takes request structs and runs the 77 * appropriate procedure. 78 */ 79 static struct svc_callout { 80 struct svc_callout *sc_next; 81 rpcprog_t sc_prog; 82 rpcprog_t sc_vers; 83 void (*sc_dispatch)(); 84 } *svc_head; 85 86 static struct svc_callout *svc_find(rpcprog_t, rpcvers_t, 87 struct svc_callout **); 88 89 static void svc_do_xprt(SVCXPRT *xprt); 90 91 /* *************** SVCXPRT related stuff **************** */ 92 93 /* 94 * Activate a transport handle. 95 */ 96 void 97 xprt_register(SVCXPRT *xprt) 98 { 99 int sock = xprt->xp_sock; 100 101 #ifdef FD_SETSIZE 102 if (gssrpc_svc_fdset_init == 0) { 103 FD_ZERO(&svc_fdset); 104 gssrpc_svc_fdset_init++; 105 } 106 if (xports == NULL) { 107 xports = (SVCXPRT **) 108 mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *)); 109 memset(xports, 0, FD_SETSIZE * sizeof(SVCXPRT *)); 110 } 111 if (sock < FD_SETSIZE) { 112 xports[sock] = xprt; 113 FD_SET(sock, &svc_fdset); 114 if (sock > svc_maxfd) 115 svc_maxfd = sock; 116 } 117 #else 118 if (sock < NOFILE) { 119 xports[sock] = xprt; 120 svc_fds |= (1 << sock); 121 if (sock > svc_maxfd) 122 svc_maxfd = sock; 123 } 124 #endif /* def FD_SETSIZE */ 125 } 126 127 /* 128 * De-activate a transport handle. 129 */ 130 void 131 xprt_unregister(SVCXPRT *xprt) 132 { 133 int sock = xprt->xp_sock; 134 135 #ifdef FD_SETSIZE 136 if ((sock < FD_SETSIZE) && (xports[sock] == xprt)) { 137 xports[sock] = (SVCXPRT *)0; 138 FD_CLR(sock, &svc_fdset); 139 } 140 #else 141 if ((sock < NOFILE) && (xports[sock] == xprt)) { 142 xports[sock] = (SVCXPRT *)0; 143 svc_fds &= ~(1 << sock); 144 } 145 #endif /* def FD_SETSIZE */ 146 if (svc_maxfd <= sock) { 147 while ((svc_maxfd > 0) && xports[svc_maxfd] == 0) 148 svc_maxfd--; 149 } 150 } 151 152 153 /* ********************** CALLOUT list related stuff ************* */ 154 155 /* 156 * Add a service program to the callout list. 157 * The dispatch routine will be called when a rpc request for this 158 * program number comes in. 159 */ 160 bool_t 161 svc_register( 162 SVCXPRT *xprt, 163 rpcprog_t prog, 164 rpcvers_t vers, 165 void (*dispatch)(), 166 int protocol) 167 { 168 struct svc_callout *prev; 169 struct svc_callout *s; 170 171 if ((s = svc_find(prog, vers, &prev)) != NULL_SVC) { 172 if (s->sc_dispatch == dispatch) 173 goto pmap_it; /* he is registering another xptr */ 174 return (FALSE); 175 } 176 s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout)); 177 if (s == (struct svc_callout *)0) { 178 return (FALSE); 179 } 180 s->sc_prog = prog; 181 s->sc_vers = vers; 182 s->sc_dispatch = dispatch; 183 s->sc_next = svc_head; 184 svc_head = s; 185 pmap_it: 186 /* now register the information with the local binder service */ 187 if (protocol) { 188 return (pmap_set(prog, vers, protocol, xprt->xp_port)); 189 } 190 return (TRUE); 191 } 192 193 /* 194 * Remove a service program from the callout list. 195 */ 196 void 197 svc_unregister( 198 rpcprog_t prog, 199 rpcvers_t vers) 200 { 201 struct svc_callout *prev; 202 struct svc_callout *s; 203 204 if ((s = svc_find(prog, vers, &prev)) == NULL_SVC) 205 return; 206 if (prev == NULL_SVC) { 207 svc_head = s->sc_next; 208 } else { 209 prev->sc_next = s->sc_next; 210 } 211 s->sc_next = NULL_SVC; 212 mem_free((char *) s, (u_int) sizeof(struct svc_callout)); 213 /* now unregister the information with the local binder service */ 214 (void)pmap_unset(prog, vers); 215 } 216 217 /* 218 * Search the callout list for a program number, return the callout 219 * struct. 220 */ 221 static struct svc_callout * 222 svc_find( 223 rpcprog_t prog, 224 rpcvers_t vers, 225 struct svc_callout **prev) 226 { 227 struct svc_callout *s, *p; 228 229 p = NULL_SVC; 230 for (s = svc_head; s != NULL_SVC; s = s->sc_next) { 231 if ((s->sc_prog == prog) && (s->sc_vers == vers)) 232 goto done; 233 p = s; 234 } 235 done: 236 *prev = p; 237 return (s); 238 } 239 240 /* ******************* REPLY GENERATION ROUTINES ************ */ 241 242 /* 243 * Send a reply to an rpc request 244 */ 245 bool_t 246 svc_sendreply( 247 SVCXPRT *xprt, 248 xdrproc_t xdr_results, 249 caddr_t xdr_location) 250 { 251 struct rpc_msg rply; 252 253 rply.rm_direction = REPLY; 254 rply.rm_reply.rp_stat = MSG_ACCEPTED; 255 rply.acpted_rply.ar_verf = xprt->xp_verf; 256 rply.acpted_rply.ar_stat = SUCCESS; 257 rply.acpted_rply.ar_results.where = xdr_location; 258 rply.acpted_rply.ar_results.proc = xdr_results; 259 return (SVC_REPLY(xprt, &rply)); 260 } 261 262 /* 263 * No procedure error reply 264 */ 265 void 266 svcerr_noproc(SVCXPRT *xprt) 267 { 268 struct rpc_msg rply; 269 270 rply.rm_direction = REPLY; 271 rply.rm_reply.rp_stat = MSG_ACCEPTED; 272 rply.acpted_rply.ar_verf = xprt->xp_verf; 273 rply.acpted_rply.ar_stat = PROC_UNAVAIL; 274 SVC_REPLY(xprt, &rply); 275 } 276 277 /* 278 * Can't decode args error reply 279 */ 280 void 281 svcerr_decode(SVCXPRT *xprt) 282 { 283 struct rpc_msg rply; 284 285 rply.rm_direction = REPLY; 286 rply.rm_reply.rp_stat = MSG_ACCEPTED; 287 rply.acpted_rply.ar_verf = xprt->xp_verf; 288 rply.acpted_rply.ar_stat = GARBAGE_ARGS; 289 SVC_REPLY(xprt, &rply); 290 } 291 292 /* 293 * Some system error 294 */ 295 void 296 svcerr_systemerr(SVCXPRT *xprt) 297 { 298 struct rpc_msg rply; 299 300 rply.rm_direction = REPLY; 301 rply.rm_reply.rp_stat = MSG_ACCEPTED; 302 rply.acpted_rply.ar_verf = xprt->xp_verf; 303 rply.acpted_rply.ar_stat = SYSTEM_ERR; 304 SVC_REPLY(xprt, &rply); 305 } 306 307 /* 308 * Authentication error reply 309 */ 310 void 311 svcerr_auth( 312 SVCXPRT *xprt, 313 enum auth_stat why) 314 { 315 struct rpc_msg rply; 316 317 rply.rm_direction = REPLY; 318 rply.rm_reply.rp_stat = MSG_DENIED; 319 rply.rjcted_rply.rj_stat = AUTH_ERROR; 320 rply.rjcted_rply.rj_why = why; 321 SVC_REPLY(xprt, &rply); 322 } 323 324 /* 325 * Auth too weak error reply 326 */ 327 void 328 svcerr_weakauth(SVCXPRT *xprt) 329 { 330 331 svcerr_auth(xprt, AUTH_TOOWEAK); 332 } 333 334 /* 335 * Program unavailable error reply 336 */ 337 void 338 svcerr_noprog(SVCXPRT *xprt) 339 { 340 struct rpc_msg rply; 341 342 rply.rm_direction = REPLY; 343 rply.rm_reply.rp_stat = MSG_ACCEPTED; 344 rply.acpted_rply.ar_verf = xprt->xp_verf; 345 rply.acpted_rply.ar_stat = PROG_UNAVAIL; 346 SVC_REPLY(xprt, &rply); 347 } 348 349 /* 350 * Program version mismatch error reply 351 */ 352 void 353 svcerr_progvers( 354 SVCXPRT *xprt, 355 rpcvers_t low_vers, 356 rpcvers_t high_vers) 357 { 358 struct rpc_msg rply; 359 360 rply.rm_direction = REPLY; 361 rply.rm_reply.rp_stat = MSG_ACCEPTED; 362 rply.acpted_rply.ar_verf = xprt->xp_verf; 363 rply.acpted_rply.ar_stat = PROG_MISMATCH; 364 rply.acpted_rply.ar_vers.low = low_vers; 365 rply.acpted_rply.ar_vers.high = high_vers; 366 SVC_REPLY(xprt, &rply); 367 } 368 369 /* ******************* SERVER INPUT STUFF ******************* */ 370 371 /* 372 * Get server side input from some transport. 373 * 374 * Statement of authentication parameters management: 375 * This function owns and manages all authentication parameters, specifically 376 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and 377 * the "cooked" credentials (rqst->rq_clntcred). 378 * However, this function does not know the structure of the cooked 379 * credentials, so it make the following assumptions: 380 * a) the structure is contiguous (no pointers), and 381 * b) the cred structure size does not exceed RQCRED_SIZE bytes. 382 * In all events, all three parameters are freed upon exit from this routine. 383 * The storage is trivially management on the call stack in user land, but 384 * is mallocated in kernel land. 385 */ 386 387 void 388 svc_getreq(int rdfds) 389 { 390 #ifdef FD_SETSIZE 391 fd_set readfds; 392 int i, mask; 393 394 FD_ZERO(&readfds); 395 for (i=0, mask=1; rdfds; i++, mask <<=1) { 396 if (rdfds & mask) 397 FD_SET(i, &readfds); 398 rdfds &= ~mask; 399 } 400 svc_getreqset(&readfds); 401 #else 402 int readfds = rdfds & svc_fds; 403 404 svc_getreqset(&readfds); 405 #endif /* def FD_SETSIZE */ 406 } 407 408 #ifdef FD_SETSIZE 409 #define FDSET_TYPE fd_set 410 #else 411 #define FDSET_TYPE int 412 #endif 413 414 void 415 svc_getreqset(FDSET_TYPE *readfds) 416 { 417 #ifndef FD_SETSIZE 418 int readfds_local = *readfds; 419 #endif 420 SVCXPRT *xprt; 421 int sock; 422 423 #ifdef FD_SETSIZE 424 for (sock = 0; sock <= svc_maxfd; sock++) { 425 if (!FD_ISSET(sock, readfds)) 426 continue; 427 /* sock has input waiting */ 428 xprt = xports[sock]; 429 /* now receive msgs from xprtprt (support batch calls) */ 430 svc_do_xprt(xprt); 431 } 432 #else 433 for (sock = 0; readfds_local != 0; sock++, readfds_local >>= 1) { 434 if ((readfds_local & 1) == 0) 435 continue; 436 /* sock has input waiting */ 437 xprt = xports[sock]; 438 /* now receive msgs from xprtprt (support batch calls) */ 439 svc_do_xprt(xprt); 440 } 441 #endif 442 } 443 444 extern struct svc_auth_ops svc_auth_gss_ops; 445 446 static void 447 svc_do_xprt(SVCXPRT *xprt) 448 { 449 caddr_t rawcred, rawverf, cookedcred; 450 struct rpc_msg msg; 451 struct svc_req r; 452 bool_t no_dispatch; 453 int prog_found; 454 rpcvers_t low_vers; 455 rpcvers_t high_vers; 456 enum xprt_stat stat; 457 458 rawcred = mem_alloc(MAX_AUTH_BYTES); 459 rawverf = mem_alloc(MAX_AUTH_BYTES); 460 cookedcred = mem_alloc(RQCRED_SIZE); 461 462 if (rawcred == NULL || rawverf == NULL || cookedcred == NULL) 463 return; 464 465 msg.rm_call.cb_cred.oa_base = rawcred; 466 msg.rm_call.cb_verf.oa_base = rawverf; 467 r.rq_clntcred = cookedcred; 468 469 do { 470 struct svc_callout *s; 471 enum auth_stat why; 472 473 if (!SVC_RECV(xprt, &msg)) 474 goto call_done; 475 476 /* now find the exported program and call it */ 477 478 r.rq_xprt = xprt; 479 r.rq_prog = msg.rm_call.cb_prog; 480 r.rq_vers = msg.rm_call.cb_vers; 481 r.rq_proc = msg.rm_call.cb_proc; 482 r.rq_cred = msg.rm_call.cb_cred; 483 484 no_dispatch = FALSE; 485 486 /* first authenticate the message */ 487 why = gssrpc__authenticate(&r, &msg, &no_dispatch); 488 if (why != AUTH_OK) { 489 svcerr_auth(xprt, why); 490 goto call_done; 491 } else if (no_dispatch) { 492 goto call_done; 493 } 494 495 /* now match message with a registered service*/ 496 prog_found = FALSE; 497 low_vers = (rpcvers_t) -1L; 498 high_vers = 0; 499 for (s = svc_head; s != NULL_SVC; s = s->sc_next) { 500 if (s->sc_prog == r.rq_prog) { 501 if (s->sc_vers == r.rq_vers) { 502 (*s->sc_dispatch)(&r, xprt); 503 goto call_done; 504 } /* found correct version */ 505 prog_found = TRUE; 506 if (s->sc_vers < low_vers) 507 low_vers = s->sc_vers; 508 if (s->sc_vers > high_vers) 509 high_vers = s->sc_vers; 510 } /* found correct program */ 511 } 512 /* 513 * if we got here, the program or version 514 * is not served ... 515 */ 516 if (prog_found) 517 svcerr_progvers(xprt, 518 low_vers, high_vers); 519 else 520 svcerr_noprog(xprt); 521 /* Fall through to ... */ 522 523 call_done: 524 if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 525 SVC_DESTROY(xprt); 526 break; 527 } else if ((xprt->xp_auth != NULL) && 528 (xprt->xp_auth->svc_ah_ops != &svc_auth_gss_ops)) { 529 xprt->xp_auth = NULL; 530 } 531 } while (stat == XPRT_MOREREQS); 532 533 mem_free(rawcred, MAX_AUTH_BYTES); 534 mem_free(rawverf, MAX_AUTH_BYTES); 535 mem_free(cookedcred, RQCRED_SIZE); 536 } 537