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