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