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