1 /* $NetBSD: svc.c,v 1.18 1999/09/20 04:39:24 lukem Exp $ */ 2 3 /* 4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5 * unrestricted use provided that this legend is included on all tape 6 * media and as a part of the software program in whole or part. Users 7 * may copy or modify Sun RPC without charge, but are not authorized 8 * to license or distribute it to anyone else except as part of a product or 9 * program developed by the user. 10 * 11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 14 * 15 * Sun RPC is provided with no support and without any obligation on the 16 * part of Sun Microsystems, Inc. to assist in its use, correction, 17 * modification or enhancement. 18 * 19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 21 * OR ANY PART THEREOF. 22 * 23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24 * or profits or other special, indirect and consequential damages, even if 25 * Sun has been advised of the possibility of such damages. 26 * 27 * Sun Microsystems, Inc. 28 * 2550 Garcia Avenue 29 * Mountain View, California 94043 30 */ 31 32 #include <sys/cdefs.h> 33 #if defined(LIBC_SCCS) && !defined(lint) 34 #if 0 35 static char *sccsid = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro"; 36 static char *sccsid = "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC"; 37 #else 38 __RCSID("$NetBSD: svc.c,v 1.18 1999/09/20 04:39:24 lukem Exp $"); 39 #endif 40 #endif 41 42 /* 43 * svc.c, Server-side remote procedure call interface. 44 * 45 * There are two sets of procedures here. The xprt routines are 46 * for handling transport handles. The svc routines handle the 47 * list of service routines. 48 * 49 * Copyright (C) 1984, Sun Microsystems, Inc. 50 */ 51 52 #include "namespace.h" 53 54 #include <assert.h> 55 #include <errno.h> 56 #include <stdlib.h> 57 #include <string.h> 58 59 #include <rpc/rpc.h> 60 #include <rpc/pmap_clnt.h> 61 62 #ifdef __weak_alias 63 __weak_alias(svc_getreq,_svc_getreq); 64 __weak_alias(svc_getreqset,_svc_getreqset); 65 __weak_alias(svc_register,_svc_register); 66 __weak_alias(svc_sendreply,_svc_sendreply); 67 __weak_alias(svc_unregister,_svc_unregister); 68 __weak_alias(svcerr_auth,_svcerr_auth); 69 __weak_alias(svcerr_decode,_svcerr_decode); 70 __weak_alias(svcerr_noproc,_svcerr_noproc); 71 __weak_alias(svcerr_noprog,_svcerr_noprog); 72 __weak_alias(svcerr_progvers,_svcerr_progvers); 73 __weak_alias(svcerr_systemerr,_svcerr_systemerr); 74 __weak_alias(svcerr_weakauth,_svcerr_weakauth); 75 __weak_alias(xprt_register,_xprt_register); 76 __weak_alias(xprt_unregister,_xprt_unregister); 77 #endif 78 79 static SVCXPRT **xports; 80 81 #define NULL_SVC ((struct svc_callout *)0) 82 #define RQCRED_SIZE 400 /* this size is excessive */ 83 84 #define max(a, b) (a > b ? a : b) 85 86 /* 87 * The services list 88 * Each entry represents a set of procedures (an rpc program). 89 * The dispatch routine takes request structs and runs the 90 * apropriate procedure. 91 */ 92 static struct svc_callout { 93 struct svc_callout *sc_next; 94 u_long sc_prog; 95 u_long sc_vers; 96 void (*sc_dispatch) __P((struct svc_req *, SVCXPRT *)); 97 } *svc_head; 98 99 static struct svc_callout *svc_find __P((u_long, u_long, 100 struct svc_callout **)); 101 102 /* *************** SVCXPRT related stuff **************** */ 103 104 /* 105 * Activate a transport handle. 106 */ 107 void 108 xprt_register(xprt) 109 SVCXPRT *xprt; 110 { 111 int sock; 112 113 _DIAGASSERT(xprt != NULL); 114 115 sock = xprt->xp_sock; 116 117 if (xports == NULL) { 118 xports = (SVCXPRT **) 119 mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *)); 120 if (xports == NULL) 121 return; 122 memset(xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *)); 123 } 124 if (sock < FD_SETSIZE) { 125 xports[sock] = xprt; 126 FD_SET(sock, &svc_fdset); 127 svc_maxfd = max(svc_maxfd, sock); 128 } 129 } 130 131 /* 132 * De-activate a transport handle. 133 */ 134 void 135 xprt_unregister(xprt) 136 SVCXPRT *xprt; 137 { 138 int sock; 139 140 _DIAGASSERT(xprt != NULL); 141 142 sock = xprt->xp_sock; 143 144 if ((sock < FD_SETSIZE) && (xports[sock] == xprt)) { 145 xports[sock] = (SVCXPRT *)0; 146 FD_CLR(sock, &svc_fdset); 147 if (sock == svc_maxfd) { 148 for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--) 149 if (xports[svc_maxfd]) 150 break; 151 } 152 } 153 } 154 155 156 /* ********************** CALLOUT list related stuff ************* */ 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_register(xprt, prog, vers, dispatch, protocol) 165 SVCXPRT *xprt; 166 u_long prog; 167 u_long vers; 168 void (*dispatch) __P((struct svc_req *, SVCXPRT *)); 169 int protocol; 170 { 171 struct svc_callout *prev; 172 struct svc_callout *s; 173 174 _DIAGASSERT(xprt != NULL); 175 _DIAGASSERT(dispatch != NULL); 176 177 if ((s = svc_find(prog, vers, &prev)) != NULL_SVC) { 178 if (s->sc_dispatch == dispatch) 179 goto pmap_it; /* he is registering another xptr */ 180 return (FALSE); 181 } 182 s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout)); 183 if (s == (struct svc_callout *)0) { 184 return (FALSE); 185 } 186 s->sc_prog = prog; 187 s->sc_vers = vers; 188 s->sc_dispatch = dispatch; 189 s->sc_next = svc_head; 190 svc_head = s; 191 pmap_it: 192 /* now register the information with the local binder service */ 193 if (protocol) { 194 return (pmap_set(prog, vers, protocol, xprt->xp_port)); 195 } 196 return (TRUE); 197 } 198 199 /* 200 * Remove a service program from the callout list. 201 */ 202 void 203 svc_unregister(prog, vers) 204 u_long prog; 205 u_long vers; 206 { 207 struct svc_callout *prev; 208 struct svc_callout *s; 209 210 if ((s = svc_find(prog, vers, &prev)) == NULL_SVC) 211 return; 212 if (prev == NULL_SVC) { 213 svc_head = s->sc_next; 214 } else { 215 prev->sc_next = s->sc_next; 216 } 217 s->sc_next = NULL_SVC; 218 mem_free(s, sizeof(struct svc_callout)); 219 /* now unregister the information with the local binder service */ 220 (void)pmap_unset(prog, vers); 221 } 222 223 /* 224 * Search the callout list for a program number, return the callout 225 * struct. 226 */ 227 static struct svc_callout * 228 svc_find(prog, vers, prev) 229 u_long prog; 230 u_long vers; 231 struct svc_callout **prev; 232 { 233 struct svc_callout *s, *p; 234 235 _DIAGASSERT(prev != NULL); 236 237 p = NULL_SVC; 238 for (s = svc_head; s != NULL_SVC; s = s->sc_next) { 239 if ((s->sc_prog == prog) && (s->sc_vers == vers)) 240 goto done; 241 p = s; 242 } 243 done: 244 *prev = p; 245 return (s); 246 } 247 248 /* ******************* REPLY GENERATION ROUTINES ************ */ 249 250 /* 251 * Send a reply to an rpc request 252 */ 253 bool_t 254 svc_sendreply(xprt, xdr_results, xdr_location) 255 SVCXPRT *xprt; 256 xdrproc_t xdr_results; 257 caddr_t xdr_location; 258 { 259 struct rpc_msg rply; 260 261 _DIAGASSERT(xprt != NULL); 262 263 rply.rm_direction = REPLY; 264 rply.rm_reply.rp_stat = MSG_ACCEPTED; 265 rply.acpted_rply.ar_verf = xprt->xp_verf; 266 rply.acpted_rply.ar_stat = SUCCESS; 267 rply.acpted_rply.ar_results.where = xdr_location; 268 rply.acpted_rply.ar_results.proc = xdr_results; 269 return (SVC_REPLY(xprt, &rply)); 270 } 271 272 /* 273 * No procedure error reply 274 */ 275 void 276 svcerr_noproc(xprt) 277 SVCXPRT *xprt; 278 { 279 struct rpc_msg rply; 280 281 _DIAGASSERT(xprt != NULL); 282 283 rply.rm_direction = REPLY; 284 rply.rm_reply.rp_stat = MSG_ACCEPTED; 285 rply.acpted_rply.ar_verf = xprt->xp_verf; 286 rply.acpted_rply.ar_stat = PROC_UNAVAIL; 287 SVC_REPLY(xprt, &rply); 288 } 289 290 /* 291 * Can't decode args error reply 292 */ 293 void 294 svcerr_decode(xprt) 295 SVCXPRT *xprt; 296 { 297 struct rpc_msg rply; 298 299 _DIAGASSERT(xprt != NULL); 300 301 rply.rm_direction = REPLY; 302 rply.rm_reply.rp_stat = MSG_ACCEPTED; 303 rply.acpted_rply.ar_verf = xprt->xp_verf; 304 rply.acpted_rply.ar_stat = GARBAGE_ARGS; 305 SVC_REPLY(xprt, &rply); 306 } 307 308 /* 309 * Some system error 310 */ 311 void 312 svcerr_systemerr(xprt) 313 SVCXPRT *xprt; 314 { 315 struct rpc_msg rply; 316 317 _DIAGASSERT(xprt != NULL); 318 319 rply.rm_direction = REPLY; 320 rply.rm_reply.rp_stat = MSG_ACCEPTED; 321 rply.acpted_rply.ar_verf = xprt->xp_verf; 322 rply.acpted_rply.ar_stat = SYSTEM_ERR; 323 SVC_REPLY(xprt, &rply); 324 } 325 326 /* 327 * Authentication error reply 328 */ 329 void 330 svcerr_auth(xprt, why) 331 SVCXPRT *xprt; 332 enum auth_stat why; 333 { 334 struct rpc_msg rply; 335 336 _DIAGASSERT(xprt != NULL); 337 338 rply.rm_direction = REPLY; 339 rply.rm_reply.rp_stat = MSG_DENIED; 340 rply.rjcted_rply.rj_stat = AUTH_ERROR; 341 rply.rjcted_rply.rj_why = why; 342 SVC_REPLY(xprt, &rply); 343 } 344 345 /* 346 * Auth too weak error reply 347 */ 348 void 349 svcerr_weakauth(xprt) 350 SVCXPRT *xprt; 351 { 352 353 _DIAGASSERT(xprt != NULL); 354 355 svcerr_auth(xprt, AUTH_TOOWEAK); 356 } 357 358 /* 359 * Program unavailable error reply 360 */ 361 void 362 svcerr_noprog(xprt) 363 SVCXPRT *xprt; 364 { 365 struct rpc_msg rply; 366 367 _DIAGASSERT(xprt != NULL); 368 369 rply.rm_direction = REPLY; 370 rply.rm_reply.rp_stat = MSG_ACCEPTED; 371 rply.acpted_rply.ar_verf = xprt->xp_verf; 372 rply.acpted_rply.ar_stat = PROG_UNAVAIL; 373 SVC_REPLY(xprt, &rply); 374 } 375 376 /* 377 * Program version mismatch error reply 378 */ 379 void 380 svcerr_progvers(xprt, low_vers, high_vers) 381 SVCXPRT *xprt; 382 u_long low_vers; 383 u_long high_vers; 384 { 385 struct rpc_msg rply; 386 387 _DIAGASSERT(xprt != NULL); 388 389 rply.rm_direction = REPLY; 390 rply.rm_reply.rp_stat = MSG_ACCEPTED; 391 rply.acpted_rply.ar_verf = xprt->xp_verf; 392 rply.acpted_rply.ar_stat = PROG_MISMATCH; 393 rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers; 394 rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers; 395 SVC_REPLY(xprt, &rply); 396 } 397 398 /* ******************* SERVER INPUT STUFF ******************* */ 399 400 /* 401 * Get server side input from some transport. 402 * 403 * Statement of authentication parameters management: 404 * This function owns and manages all authentication parameters, specifically 405 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and 406 * the "cooked" credentials (rqst->rq_clntcred). 407 * However, this function does not know the structure of the cooked 408 * credentials, so it make the following assumptions: 409 * a) the structure is contiguous (no pointers), and 410 * b) the cred structure size does not exceed RQCRED_SIZE bytes. 411 * In all events, all three parameters are freed upon exit from this routine. 412 * The storage is trivially management on the call stack in user land, but 413 * is mallocated in kernel land. 414 */ 415 416 void 417 svc_getreq(rdfds) 418 int rdfds; 419 { 420 fd_set readfds; 421 422 FD_ZERO(&readfds); 423 readfds.fds_bits[0] = rdfds; 424 svc_getreqset(&readfds); 425 } 426 427 void 428 svc_getreqset(readfds) 429 fd_set *readfds; 430 { 431 enum xprt_stat stat; 432 struct rpc_msg msg; 433 int prog_found; 434 u_long low_vers; 435 u_long high_vers; 436 struct svc_req r; 437 SVCXPRT *xprt; 438 int bit; 439 int32_t mask, *maskp; 440 int sock; 441 char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; 442 msg.rm_call.cb_cred.oa_base = cred_area; 443 msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); 444 r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); 445 446 _DIAGASSERT(readfds != NULL); 447 448 maskp = readfds->fds_bits; 449 for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) { 450 for (mask = *maskp++; (bit = ffs(mask)) != 0; 451 mask ^= (1 << (bit - 1))) { 452 /* sock has input waiting */ 453 xprt = xports[sock + bit - 1]; 454 if (xprt == NULL) 455 /* But do we control sock? */ 456 continue; 457 /* now receive msgs from xprtprt (support batch calls) */ 458 do { 459 if (SVC_RECV(xprt, &msg)) { 460 461 /* now find the exported program and call it */ 462 struct svc_callout *s; 463 enum auth_stat why; 464 465 r.rq_xprt = xprt; 466 r.rq_prog = msg.rm_call.cb_prog; 467 r.rq_vers = msg.rm_call.cb_vers; 468 r.rq_proc = msg.rm_call.cb_proc; 469 r.rq_cred = msg.rm_call.cb_cred; 470 /* first authenticate the message */ 471 if ((why= _authenticate(&r, &msg)) != AUTH_OK) { 472 svcerr_auth(xprt, why); 473 goto call_done; 474 } 475 /* now match message with a registered service*/ 476 prog_found = FALSE; 477 low_vers = (u_long) -1L; 478 high_vers = (u_long) 0L; 479 for (s = svc_head; s != NULL_SVC; 480 s = s->sc_next) { 481 if (s->sc_prog == r.rq_prog) { 482 if (s->sc_vers == r.rq_vers) { 483 (*s->sc_dispatch)(&r, 484 xprt); 485 goto call_done; 486 } /* found correct version */ 487 prog_found = TRUE; 488 if (s->sc_vers < low_vers) 489 low_vers = s->sc_vers; 490 if (s->sc_vers > high_vers) 491 high_vers = s->sc_vers; 492 } /* found correct program */ 493 } 494 /* 495 * if we got here, the program or version 496 * is not served ... 497 */ 498 if (prog_found) 499 svcerr_progvers(xprt, 500 low_vers, high_vers); 501 else 502 svcerr_noprog(xprt); 503 /* Fall through to ... */ 504 } 505 call_done: 506 if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 507 SVC_DESTROY(xprt); 508 break; 509 } 510 } while (stat == XPRT_MOREREQS); 511 } 512 } 513 } 514