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