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