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