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