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