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 *sccsid = "from: @(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";*/ 32 /*static char *sccsid = "from: @(#)svc.c 2.4 88/08/11 4.0 RPCSRC";*/ 33 static char *rcsid = "$Id: svc.c,v 1.3 1994/08/23 18:42:11 deraadt Exp $"; 34 #endif 35 36 /* 37 * svc.c, Server-side remote procedure call interface. 38 * 39 * There are two sets of procedures here. The xprt routines are 40 * for handling transport handles. The svc routines handle the 41 * list of service routines. 42 * 43 * Copyright (C) 1984, Sun Microsystems, Inc. 44 */ 45 46 #include <sys/errno.h> 47 #include <rpc/rpc.h> 48 #include <rpc/pmap_clnt.h> 49 50 extern int errno; 51 52 static SVCXPRT **xports; 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 /* *************** SVCXPRT related stuff **************** */ 75 76 extern int svc_maxfd; 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 u_long mask; 381 register int bit; 382 register u_long *maskp; 383 register int sock; 384 char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; 385 msg.rm_call.cb_cred.oa_base = cred_area; 386 msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); 387 r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); 388 389 390 maskp = (u_long *)readfds->fds_bits; 391 for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) { 392 for (mask = *maskp++; bit = ffs(mask); mask ^= (1 << (bit - 1))) { 393 /* sock has input waiting */ 394 xprt = xports[sock + bit - 1]; 395 /* now receive msgs from xprtprt (support batch calls) */ 396 do { 397 if (SVC_RECV(xprt, &msg)) { 398 399 /* now find the exported program and call it */ 400 register struct svc_callout *s; 401 enum auth_stat why; 402 403 r.rq_xprt = xprt; 404 r.rq_prog = msg.rm_call.cb_prog; 405 r.rq_vers = msg.rm_call.cb_vers; 406 r.rq_proc = msg.rm_call.cb_proc; 407 r.rq_cred = msg.rm_call.cb_cred; 408 /* first authenticate the message */ 409 if ((why= _authenticate(&r, &msg)) != AUTH_OK) { 410 svcerr_auth(xprt, why); 411 goto call_done; 412 } 413 /* now match message with a registered service*/ 414 prog_found = FALSE; 415 low_vers = 0 - 1; 416 high_vers = 0; 417 for (s = svc_head; s != NULL_SVC; s = s->sc_next) { 418 if (s->sc_prog == r.rq_prog) { 419 if (s->sc_vers == r.rq_vers) { 420 (*s->sc_dispatch)(&r, xprt); 421 goto call_done; 422 } /* found correct version */ 423 prog_found = TRUE; 424 if (s->sc_vers < low_vers) 425 low_vers = s->sc_vers; 426 if (s->sc_vers > high_vers) 427 high_vers = s->sc_vers; 428 } /* found correct program */ 429 } 430 /* 431 * if we got here, the program or version 432 * is not served ... 433 */ 434 if (prog_found) 435 svcerr_progvers(xprt, 436 low_vers, high_vers); 437 else 438 svcerr_noprog(xprt); 439 /* Fall through to ... */ 440 } 441 call_done: 442 if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 443 SVC_DESTROY(xprt); 444 break; 445 } 446 } while (stat == XPRT_MOREREQS); 447 } 448 } 449 } 450