1 /* $NetBSD: svc.c,v 1.11 1997/07/21 14:08:37 jtc 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.11 1997/07/21 14:08:37 jtc 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 #include <stdlib.h> 54 #include <string.h> 55 56 #include <sys/errno.h> 57 #include <rpc/rpc.h> 58 #include <rpc/pmap_clnt.h> 59 60 #ifdef __weak_alias 61 __weak_alias(svc_getreq,_svc_getreq); 62 __weak_alias(svc_getreqset,_svc_getreqset); 63 __weak_alias(svc_register,_svc_register); 64 __weak_alias(svc_sendreply,_svc_sendreply); 65 __weak_alias(svc_unregister,_svc_unregister); 66 __weak_alias(svcerr_auth,_svcerr_auth); 67 __weak_alias(svcerr_decode,_svcerr_decode); 68 __weak_alias(svcerr_noproc,_svcerr_noproc); 69 __weak_alias(svcerr_noprog,_svcerr_noprog); 70 __weak_alias(svcerr_progvers,_svcerr_progvers); 71 __weak_alias(svcerr_systemerr,_svcerr_systemerr); 72 __weak_alias(svcerr_weakauth,_svcerr_weakauth); 73 __weak_alias(xprt_register,_xprt_register); 74 __weak_alias(xprt_unregister,_xprt_unregister); 75 #endif 76 77 static SVCXPRT **xports; 78 79 #define NULL_SVC ((struct svc_callout *)0) 80 #define RQCRED_SIZE 400 /* this size is excessive */ 81 82 #define max(a, b) (a > b ? a : b) 83 84 /* 85 * The services list 86 * Each entry represents a set of procedures (an rpc program). 87 * The dispatch routine takes request structs and runs the 88 * apropriate procedure. 89 */ 90 static struct svc_callout { 91 struct svc_callout *sc_next; 92 u_long sc_prog; 93 u_long sc_vers; 94 void (*sc_dispatch) __P((struct svc_req *, SVCXPRT *)); 95 } *svc_head; 96 97 static struct svc_callout *svc_find __P((u_long, u_long, 98 struct svc_callout **)); 99 100 /* *************** SVCXPRT related stuff **************** */ 101 102 /* 103 * Activate a transport handle. 104 */ 105 void 106 xprt_register(xprt) 107 SVCXPRT *xprt; 108 { 109 register int sock = xprt->xp_sock; 110 111 if (xports == NULL) { 112 xports = (SVCXPRT **) 113 mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *)); 114 memset(xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *)); 115 } 116 if (sock < FD_SETSIZE) { 117 xports[sock] = xprt; 118 FD_SET(sock, &svc_fdset); 119 svc_maxfd = max(svc_maxfd, sock); 120 } 121 } 122 123 /* 124 * De-activate a transport handle. 125 */ 126 void 127 xprt_unregister(xprt) 128 SVCXPRT *xprt; 129 { 130 register int sock = xprt->xp_sock; 131 132 if ((sock < FD_SETSIZE) && (xports[sock] == xprt)) { 133 xports[sock] = (SVCXPRT *)0; 134 FD_CLR(sock, &svc_fdset); 135 if (sock == svc_maxfd) { 136 for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--) 137 if (xports[svc_maxfd]) 138 break; 139 } 140 } 141 } 142 143 144 /* ********************** CALLOUT list related stuff ************* */ 145 146 /* 147 * Add a service program to the callout list. 148 * The dispatch routine will be called when a rpc request for this 149 * program number comes in. 150 */ 151 bool_t 152 svc_register(xprt, prog, vers, dispatch, protocol) 153 SVCXPRT *xprt; 154 u_long prog; 155 u_long vers; 156 void (*dispatch) __P((struct svc_req *, SVCXPRT *)); 157 int protocol; 158 { 159 struct svc_callout *prev; 160 register struct svc_callout *s; 161 162 if ((s = svc_find(prog, vers, &prev)) != NULL_SVC) { 163 if (s->sc_dispatch == dispatch) 164 goto pmap_it; /* he is registering another xptr */ 165 return (FALSE); 166 } 167 s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout)); 168 if (s == (struct svc_callout *)0) { 169 return (FALSE); 170 } 171 s->sc_prog = prog; 172 s->sc_vers = vers; 173 s->sc_dispatch = dispatch; 174 s->sc_next = svc_head; 175 svc_head = s; 176 pmap_it: 177 /* now register the information with the local binder service */ 178 if (protocol) { 179 return (pmap_set(prog, vers, protocol, xprt->xp_port)); 180 } 181 return (TRUE); 182 } 183 184 /* 185 * Remove a service program from the callout list. 186 */ 187 void 188 svc_unregister(prog, vers) 189 u_long prog; 190 u_long vers; 191 { 192 struct svc_callout *prev; 193 register struct svc_callout *s; 194 195 if ((s = svc_find(prog, vers, &prev)) == NULL_SVC) 196 return; 197 if (prev == NULL_SVC) { 198 svc_head = s->sc_next; 199 } else { 200 prev->sc_next = s->sc_next; 201 } 202 s->sc_next = NULL_SVC; 203 mem_free((char *) s, (u_int) sizeof(struct svc_callout)); 204 /* now unregister the information with the local binder service */ 205 (void)pmap_unset(prog, vers); 206 } 207 208 /* 209 * Search the callout list for a program number, return the callout 210 * struct. 211 */ 212 static struct svc_callout * 213 svc_find(prog, vers, prev) 214 u_long prog; 215 u_long vers; 216 struct svc_callout **prev; 217 { 218 register struct svc_callout *s, *p; 219 220 p = NULL_SVC; 221 for (s = svc_head; s != NULL_SVC; s = s->sc_next) { 222 if ((s->sc_prog == prog) && (s->sc_vers == vers)) 223 goto done; 224 p = s; 225 } 226 done: 227 *prev = p; 228 return (s); 229 } 230 231 /* ******************* REPLY GENERATION ROUTINES ************ */ 232 233 /* 234 * Send a reply to an rpc request 235 */ 236 bool_t 237 svc_sendreply(xprt, xdr_results, xdr_location) 238 register SVCXPRT *xprt; 239 xdrproc_t xdr_results; 240 caddr_t xdr_location; 241 { 242 struct rpc_msg rply; 243 244 rply.rm_direction = REPLY; 245 rply.rm_reply.rp_stat = MSG_ACCEPTED; 246 rply.acpted_rply.ar_verf = xprt->xp_verf; 247 rply.acpted_rply.ar_stat = SUCCESS; 248 rply.acpted_rply.ar_results.where = xdr_location; 249 rply.acpted_rply.ar_results.proc = xdr_results; 250 return (SVC_REPLY(xprt, &rply)); 251 } 252 253 /* 254 * No procedure error reply 255 */ 256 void 257 svcerr_noproc(xprt) 258 register SVCXPRT *xprt; 259 { 260 struct rpc_msg rply; 261 262 rply.rm_direction = REPLY; 263 rply.rm_reply.rp_stat = MSG_ACCEPTED; 264 rply.acpted_rply.ar_verf = xprt->xp_verf; 265 rply.acpted_rply.ar_stat = PROC_UNAVAIL; 266 SVC_REPLY(xprt, &rply); 267 } 268 269 /* 270 * Can't decode args error reply 271 */ 272 void 273 svcerr_decode(xprt) 274 register SVCXPRT *xprt; 275 { 276 struct rpc_msg rply; 277 278 rply.rm_direction = REPLY; 279 rply.rm_reply.rp_stat = MSG_ACCEPTED; 280 rply.acpted_rply.ar_verf = xprt->xp_verf; 281 rply.acpted_rply.ar_stat = GARBAGE_ARGS; 282 SVC_REPLY(xprt, &rply); 283 } 284 285 /* 286 * Some system error 287 */ 288 void 289 svcerr_systemerr(xprt) 290 register SVCXPRT *xprt; 291 { 292 struct rpc_msg rply; 293 294 rply.rm_direction = REPLY; 295 rply.rm_reply.rp_stat = MSG_ACCEPTED; 296 rply.acpted_rply.ar_verf = xprt->xp_verf; 297 rply.acpted_rply.ar_stat = SYSTEM_ERR; 298 SVC_REPLY(xprt, &rply); 299 } 300 301 /* 302 * Authentication error reply 303 */ 304 void 305 svcerr_auth(xprt, why) 306 SVCXPRT *xprt; 307 enum auth_stat why; 308 { 309 struct rpc_msg rply; 310 311 rply.rm_direction = REPLY; 312 rply.rm_reply.rp_stat = MSG_DENIED; 313 rply.rjcted_rply.rj_stat = AUTH_ERROR; 314 rply.rjcted_rply.rj_why = why; 315 SVC_REPLY(xprt, &rply); 316 } 317 318 /* 319 * Auth too weak error reply 320 */ 321 void 322 svcerr_weakauth(xprt) 323 SVCXPRT *xprt; 324 { 325 326 svcerr_auth(xprt, AUTH_TOOWEAK); 327 } 328 329 /* 330 * Program unavailable error reply 331 */ 332 void 333 svcerr_noprog(xprt) 334 register SVCXPRT *xprt; 335 { 336 struct rpc_msg rply; 337 338 rply.rm_direction = REPLY; 339 rply.rm_reply.rp_stat = MSG_ACCEPTED; 340 rply.acpted_rply.ar_verf = xprt->xp_verf; 341 rply.acpted_rply.ar_stat = PROG_UNAVAIL; 342 SVC_REPLY(xprt, &rply); 343 } 344 345 /* 346 * Program version mismatch error reply 347 */ 348 void 349 svcerr_progvers(xprt, low_vers, high_vers) 350 register SVCXPRT *xprt; 351 u_long low_vers; 352 u_long high_vers; 353 { 354 struct rpc_msg rply; 355 356 rply.rm_direction = REPLY; 357 rply.rm_reply.rp_stat = MSG_ACCEPTED; 358 rply.acpted_rply.ar_verf = xprt->xp_verf; 359 rply.acpted_rply.ar_stat = PROG_MISMATCH; 360 rply.acpted_rply.ar_vers.low = low_vers; 361 rply.acpted_rply.ar_vers.high = high_vers; 362 SVC_REPLY(xprt, &rply); 363 } 364 365 /* ******************* SERVER INPUT STUFF ******************* */ 366 367 /* 368 * Get server side input from some transport. 369 * 370 * Statement of authentication parameters management: 371 * This function owns and manages all authentication parameters, specifically 372 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and 373 * the "cooked" credentials (rqst->rq_clntcred). 374 * However, this function does not know the structure of the cooked 375 * credentials, so it make the following assumptions: 376 * a) the structure is contiguous (no pointers), and 377 * b) the cred structure size does not exceed RQCRED_SIZE bytes. 378 * In all events, all three parameters are freed upon exit from this routine. 379 * The storage is trivially management on the call stack in user land, but 380 * is mallocated in kernel land. 381 */ 382 383 void 384 svc_getreq(rdfds) 385 int rdfds; 386 { 387 fd_set readfds; 388 389 FD_ZERO(&readfds); 390 readfds.fds_bits[0] = rdfds; 391 svc_getreqset(&readfds); 392 } 393 394 void 395 svc_getreqset(readfds) 396 fd_set *readfds; 397 { 398 enum xprt_stat stat; 399 struct rpc_msg msg; 400 int prog_found; 401 u_long low_vers; 402 u_long high_vers; 403 struct svc_req r; 404 register SVCXPRT *xprt; 405 register int bit; 406 register u_int32_t mask, *maskp; 407 register int sock; 408 char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; 409 msg.rm_call.cb_cred.oa_base = cred_area; 410 msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); 411 r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); 412 413 414 maskp = readfds->fds_bits; 415 for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) { 416 for (mask = *maskp++; (bit = ffs(mask)) != 0; 417 mask ^= (1 << (bit - 1))) { 418 /* sock has input waiting */ 419 xprt = xports[sock + bit - 1]; 420 if (xprt == NULL) 421 /* But do we control sock? */ 422 continue; 423 /* now receive msgs from xprtprt (support batch calls) */ 424 do { 425 if (SVC_RECV(xprt, &msg)) { 426 427 /* now find the exported program and call it */ 428 register struct svc_callout *s; 429 enum auth_stat why; 430 431 r.rq_xprt = xprt; 432 r.rq_prog = msg.rm_call.cb_prog; 433 r.rq_vers = msg.rm_call.cb_vers; 434 r.rq_proc = msg.rm_call.cb_proc; 435 r.rq_cred = msg.rm_call.cb_cred; 436 /* first authenticate the message */ 437 if ((why= _authenticate(&r, &msg)) != AUTH_OK) { 438 svcerr_auth(xprt, why); 439 goto call_done; 440 } 441 /* now match message with a registered service*/ 442 prog_found = FALSE; 443 low_vers = 0 - 1; 444 high_vers = 0; 445 for (s = svc_head; s != NULL_SVC; s = s->sc_next) { 446 if (s->sc_prog == r.rq_prog) { 447 if (s->sc_vers == r.rq_vers) { 448 (*s->sc_dispatch)(&r, xprt); 449 goto call_done; 450 } /* found correct version */ 451 prog_found = TRUE; 452 if (s->sc_vers < low_vers) 453 low_vers = s->sc_vers; 454 if (s->sc_vers > high_vers) 455 high_vers = s->sc_vers; 456 } /* found correct program */ 457 } 458 /* 459 * if we got here, the program or version 460 * is not served ... 461 */ 462 if (prog_found) 463 svcerr_progvers(xprt, 464 low_vers, high_vers); 465 else 466 svcerr_noprog(xprt); 467 /* Fall through to ... */ 468 } 469 call_done: 470 if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 471 SVC_DESTROY(xprt); 472 break; 473 } 474 } while (stat == XPRT_MOREREQS); 475 } 476 } 477 } 478