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