1/* $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 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#if defined(LIBC_SCCS) && !defined(lint) 33static char *sccsid = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro"; 34static char *sccsid = "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC"; 35#endif 36#include <sys/cdefs.h>
| 1/* $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 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#if defined(LIBC_SCCS) && !defined(lint) 33static char *sccsid = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro"; 34static char *sccsid = "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC"; 35#endif 36#include <sys/cdefs.h>
|
37__FBSDID("$FreeBSD: head/lib/libc/rpc/svc.c 95658 2002-04-28 15:18:50Z des $");
| 37__FBSDID("$FreeBSD: head/lib/libc/rpc/svc.c 109359 2003-01-16 07:13:51Z mbr $");
|
38 39/* 40 * svc.c, Server-side remote procedure call interface. 41 * 42 * There are two sets of procedures here. The xprt routines are 43 * for handling transport handles. The svc routines handle the 44 * list of service routines. 45 * 46 * Copyright (C) 1984, Sun Microsystems, Inc. 47 */ 48 49#include "namespace.h" 50#include "reentrant.h" 51#include <sys/types.h> 52#include <sys/poll.h> 53#include <assert.h> 54#include <errno.h> 55#include <stdlib.h> 56#include <string.h> 57 58#include <rpc/rpc.h> 59#ifdef PORTMAP 60#include <rpc/pmap_clnt.h> 61#endif /* PORTMAP */ 62#include "un-namespace.h" 63 64#include "rpc_com.h" 65
| 38 39/* 40 * svc.c, Server-side remote procedure call interface. 41 * 42 * There are two sets of procedures here. The xprt routines are 43 * for handling transport handles. The svc routines handle the 44 * list of service routines. 45 * 46 * Copyright (C) 1984, Sun Microsystems, Inc. 47 */ 48 49#include "namespace.h" 50#include "reentrant.h" 51#include <sys/types.h> 52#include <sys/poll.h> 53#include <assert.h> 54#include <errno.h> 55#include <stdlib.h> 56#include <string.h> 57 58#include <rpc/rpc.h> 59#ifdef PORTMAP 60#include <rpc/pmap_clnt.h> 61#endif /* PORTMAP */ 62#include "un-namespace.h" 63 64#include "rpc_com.h" 65
|
66static SVCXPRT **xports; 67
| |
68#define RQCRED_SIZE 400 /* this size is excessive */ 69 70#define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */ 71#define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET) 72 73#define max(a, b) (a > b ? a : b) 74 75/* 76 * The services list 77 * Each entry represents a set of procedures (an rpc program). 78 * The dispatch routine takes request structs and runs the 79 * apropriate procedure. 80 */ 81static struct svc_callout { 82 struct svc_callout *sc_next; 83 rpcprog_t sc_prog; 84 rpcvers_t sc_vers; 85 char *sc_netid; 86 void (*sc_dispatch)(struct svc_req *, SVCXPRT *); 87} *svc_head; 88 89extern rwlock_t svc_lock; 90extern rwlock_t svc_fd_lock; 91 92static struct svc_callout *svc_find(rpcprog_t, rpcvers_t, 93 struct svc_callout **, char *);
| 66#define RQCRED_SIZE 400 /* this size is excessive */ 67 68#define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */ 69#define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET) 70 71#define max(a, b) (a > b ? a : b) 72 73/* 74 * The services list 75 * Each entry represents a set of procedures (an rpc program). 76 * The dispatch routine takes request structs and runs the 77 * apropriate procedure. 78 */ 79static struct svc_callout { 80 struct svc_callout *sc_next; 81 rpcprog_t sc_prog; 82 rpcvers_t sc_vers; 83 char *sc_netid; 84 void (*sc_dispatch)(struct svc_req *, SVCXPRT *); 85} *svc_head; 86 87extern rwlock_t svc_lock; 88extern rwlock_t svc_fd_lock; 89 90static struct svc_callout *svc_find(rpcprog_t, rpcvers_t, 91 struct svc_callout **, char *);
|
| 92static void __xprt_do_unregister (SVCXPRT *xprt, bool_t dolock);
|
94 95/* *************** SVCXPRT related stuff **************** */ 96 97/* 98 * Activate a transport handle. 99 */ 100void 101xprt_register(xprt) 102 SVCXPRT *xprt; 103{ 104 int sock; 105 106 assert(xprt != NULL); 107 108 sock = xprt->xp_fd; 109 110 rwlock_wrlock(&svc_fd_lock);
| 93 94/* *************** SVCXPRT related stuff **************** */ 95 96/* 97 * Activate a transport handle. 98 */ 99void 100xprt_register(xprt) 101 SVCXPRT *xprt; 102{ 103 int sock; 104 105 assert(xprt != NULL); 106 107 sock = xprt->xp_fd; 108 109 rwlock_wrlock(&svc_fd_lock);
|
111 if (xports == NULL) { 112 xports = (SVCXPRT **)
| 110 if (__svc_xports == NULL) { 111 __svc_xports = (SVCXPRT **)
|
113 mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
| 112 mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
|
114 if (xports == NULL)
| 113 if (__svc_xports == NULL)
|
115 return;
| 114 return;
|
116 memset(xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *));
| 115 memset(__svc_xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *));
|
117 } 118 if (sock < FD_SETSIZE) {
| 116 } 117 if (sock < FD_SETSIZE) {
|
119 xports[sock] = xprt;
| 118 __svc_xports[sock] = xprt;
|
120 FD_SET(sock, &svc_fdset); 121 svc_maxfd = max(svc_maxfd, sock); 122 } 123 rwlock_unlock(&svc_fd_lock); 124} 125
| 119 FD_SET(sock, &svc_fdset); 120 svc_maxfd = max(svc_maxfd, sock); 121 } 122 rwlock_unlock(&svc_fd_lock); 123} 124
|
| 125void 126xprt_unregister(SVCXPRT *xprt) 127{ 128 __xprt_do_unregister(xprt, TRUE); 129} 130 131void 132__xprt_unregister_unlocked(SVCXPRT *xprt) 133{ 134 __xprt_do_unregister(xprt, FALSE); 135} 136
|
126/* 127 * De-activate a transport handle. 128 */
| 137/* 138 * De-activate a transport handle. 139 */
|
129void 130xprt_unregister(xprt)
| 140static void 141__xprt_do_unregister(xprt, dolock)
|
131 SVCXPRT *xprt;
| 142 SVCXPRT *xprt;
|
| 143 bool_t dolock;
|
132{ 133 int sock; 134 135 assert(xprt != NULL); 136 137 sock = xprt->xp_fd; 138
| 144{ 145 int sock; 146 147 assert(xprt != NULL); 148 149 sock = xprt->xp_fd; 150
|
139 rwlock_wrlock(&svc_fd_lock); 140 if ((sock < FD_SETSIZE) && (xports[sock] == xprt)) { 141 xports[sock] = NULL;
| 151 if (dolock) 152 rwlock_wrlock(&svc_fd_lock); 153 if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) { 154 __svc_xports[sock] = NULL;
|
142 FD_CLR(sock, &svc_fdset); 143 if (sock >= svc_maxfd) { 144 for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--)
| 155 FD_CLR(sock, &svc_fdset); 156 if (sock >= svc_maxfd) { 157 for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--)
|
145 if (xports[svc_maxfd])
| 158 if (__svc_xports[svc_maxfd])
|
146 break; 147 } 148 }
| 159 break; 160 } 161 }
|
149 rwlock_unlock(&svc_fd_lock);
| 162 if (dolock) 163 rwlock_unlock(&svc_fd_lock);
|
150} 151 152/* 153 * Add a service program to the callout list. 154 * The dispatch routine will be called when a rpc request for this 155 * program number comes in. 156 */ 157bool_t 158svc_reg(xprt, prog, vers, dispatch, nconf) 159 SVCXPRT *xprt; 160 const rpcprog_t prog; 161 const rpcvers_t vers; 162 void (*dispatch)(struct svc_req *, SVCXPRT *); 163 const struct netconfig *nconf; 164{ 165 bool_t dummy; 166 struct svc_callout *prev; 167 struct svc_callout *s; 168 struct netconfig *tnconf; 169 char *netid = NULL; 170 int flag = 0; 171 172/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */ 173 174 if (xprt->xp_netid) { 175 netid = strdup(xprt->xp_netid); 176 flag = 1; 177 } else if (nconf && nconf->nc_netid) { 178 netid = strdup(nconf->nc_netid); 179 flag = 1; 180 } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) { 181 netid = strdup(tnconf->nc_netid); 182 flag = 1; 183 freenetconfigent(tnconf); 184 } /* must have been created with svc_raw_create */ 185 if ((netid == NULL) && (flag == 1)) { 186 return (FALSE); 187 } 188 189 rwlock_wrlock(&svc_lock); 190 if ((s = svc_find(prog, vers, &prev, netid)) != NULL) { 191 if (netid) 192 free(netid); 193 if (s->sc_dispatch == dispatch) 194 goto rpcb_it; /* he is registering another xptr */ 195 rwlock_unlock(&svc_lock); 196 return (FALSE); 197 } 198 s = mem_alloc(sizeof (struct svc_callout)); 199 if (s == NULL) { 200 if (netid) 201 free(netid); 202 rwlock_unlock(&svc_lock); 203 return (FALSE); 204 } 205 206 s->sc_prog = prog; 207 s->sc_vers = vers; 208 s->sc_dispatch = dispatch; 209 s->sc_netid = netid; 210 s->sc_next = svc_head; 211 svc_head = s; 212 213 if ((xprt->xp_netid == NULL) && (flag == 1) && netid) 214 ((SVCXPRT *) xprt)->xp_netid = strdup(netid); 215 216rpcb_it: 217 rwlock_unlock(&svc_lock); 218 /* now register the information with the local binder service */ 219 if (nconf) { 220 /*LINTED const castaway*/ 221 dummy = rpcb_set(prog, vers, (struct netconfig *) nconf, 222 &((SVCXPRT *) xprt)->xp_ltaddr); 223 return (dummy); 224 } 225 return (TRUE); 226} 227 228/* 229 * Remove a service program from the callout list. 230 */ 231void 232svc_unreg(prog, vers) 233 const rpcprog_t prog; 234 const rpcvers_t vers; 235{ 236 struct svc_callout *prev; 237 struct svc_callout *s; 238 239 /* unregister the information anyway */ 240 (void) rpcb_unset(prog, vers, NULL); 241 rwlock_wrlock(&svc_lock); 242 while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) { 243 if (prev == NULL) { 244 svc_head = s->sc_next; 245 } else { 246 prev->sc_next = s->sc_next; 247 } 248 s->sc_next = NULL; 249 if (s->sc_netid) 250 mem_free(s->sc_netid, sizeof (s->sc_netid) + 1); 251 mem_free(s, sizeof (struct svc_callout)); 252 } 253 rwlock_unlock(&svc_lock); 254} 255 256/* ********************** CALLOUT list related stuff ************* */ 257 258#ifdef PORTMAP 259/* 260 * Add a service program to the callout list. 261 * The dispatch routine will be called when a rpc request for this 262 * program number comes in. 263 */ 264bool_t 265svc_register(xprt, prog, vers, dispatch, protocol) 266 SVCXPRT *xprt; 267 u_long prog; 268 u_long vers; 269 void (*dispatch)(struct svc_req *, SVCXPRT *); 270 int protocol; 271{ 272 struct svc_callout *prev; 273 struct svc_callout *s; 274 275 assert(xprt != NULL); 276 assert(dispatch != NULL); 277 278 if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) != 279 NULL) { 280 if (s->sc_dispatch == dispatch) 281 goto pmap_it; /* he is registering another xptr */ 282 return (FALSE); 283 } 284 s = mem_alloc(sizeof(struct svc_callout)); 285 if (s == NULL) { 286 return (FALSE); 287 } 288 s->sc_prog = (rpcprog_t)prog; 289 s->sc_vers = (rpcvers_t)vers; 290 s->sc_dispatch = dispatch; 291 s->sc_next = svc_head; 292 svc_head = s; 293pmap_it: 294 /* now register the information with the local binder service */ 295 if (protocol) { 296 return (pmap_set(prog, vers, protocol, xprt->xp_port)); 297 } 298 return (TRUE); 299} 300 301/* 302 * Remove a service program from the callout list. 303 */ 304void 305svc_unregister(prog, vers) 306 u_long prog; 307 u_long vers; 308{ 309 struct svc_callout *prev; 310 struct svc_callout *s; 311 312 if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) == 313 NULL) 314 return; 315 if (prev == NULL) { 316 svc_head = s->sc_next; 317 } else { 318 prev->sc_next = s->sc_next; 319 } 320 s->sc_next = NULL; 321 mem_free(s, sizeof(struct svc_callout)); 322 /* now unregister the information with the local binder service */ 323 (void)pmap_unset(prog, vers); 324} 325#endif /* PORTMAP */ 326 327/* 328 * Search the callout list for a program number, return the callout 329 * struct. 330 */ 331static struct svc_callout * 332svc_find(prog, vers, prev, netid) 333 rpcprog_t prog; 334 rpcvers_t vers; 335 struct svc_callout **prev; 336 char *netid; 337{ 338 struct svc_callout *s, *p; 339 340 assert(prev != NULL); 341 342 p = NULL; 343 for (s = svc_head; s != NULL; s = s->sc_next) { 344 if (((s->sc_prog == prog) && (s->sc_vers == vers)) && 345 ((netid == NULL) || (s->sc_netid == NULL) || 346 (strcmp(netid, s->sc_netid) == 0))) 347 break; 348 p = s; 349 } 350 *prev = p; 351 return (s); 352} 353 354/* ******************* REPLY GENERATION ROUTINES ************ */ 355 356/* 357 * Send a reply to an rpc request 358 */ 359bool_t 360svc_sendreply(xprt, xdr_results, xdr_location) 361 SVCXPRT *xprt; 362 xdrproc_t xdr_results; 363 void * xdr_location; 364{ 365 struct rpc_msg rply; 366 367 assert(xprt != NULL); 368 369 rply.rm_direction = REPLY; 370 rply.rm_reply.rp_stat = MSG_ACCEPTED; 371 rply.acpted_rply.ar_verf = xprt->xp_verf; 372 rply.acpted_rply.ar_stat = SUCCESS; 373 rply.acpted_rply.ar_results.where = xdr_location; 374 rply.acpted_rply.ar_results.proc = xdr_results; 375 return (SVC_REPLY(xprt, &rply)); 376} 377 378/* 379 * No procedure error reply 380 */ 381void 382svcerr_noproc(xprt) 383 SVCXPRT *xprt; 384{ 385 struct rpc_msg rply; 386 387 assert(xprt != NULL); 388 389 rply.rm_direction = REPLY; 390 rply.rm_reply.rp_stat = MSG_ACCEPTED; 391 rply.acpted_rply.ar_verf = xprt->xp_verf; 392 rply.acpted_rply.ar_stat = PROC_UNAVAIL; 393 SVC_REPLY(xprt, &rply); 394} 395 396/* 397 * Can't decode args error reply 398 */ 399void 400svcerr_decode(xprt) 401 SVCXPRT *xprt; 402{ 403 struct rpc_msg rply; 404 405 assert(xprt != NULL); 406 407 rply.rm_direction = REPLY; 408 rply.rm_reply.rp_stat = MSG_ACCEPTED; 409 rply.acpted_rply.ar_verf = xprt->xp_verf; 410 rply.acpted_rply.ar_stat = GARBAGE_ARGS; 411 SVC_REPLY(xprt, &rply); 412} 413 414/* 415 * Some system error 416 */ 417void 418svcerr_systemerr(xprt) 419 SVCXPRT *xprt; 420{ 421 struct rpc_msg rply; 422 423 assert(xprt != NULL); 424 425 rply.rm_direction = REPLY; 426 rply.rm_reply.rp_stat = MSG_ACCEPTED; 427 rply.acpted_rply.ar_verf = xprt->xp_verf; 428 rply.acpted_rply.ar_stat = SYSTEM_ERR; 429 SVC_REPLY(xprt, &rply); 430} 431 432#if 0 433/* 434 * Tell RPC package to not complain about version errors to the client. This 435 * is useful when revving broadcast protocols that sit on a fixed address. 436 * There is really one (or should be only one) example of this kind of 437 * protocol: the portmapper (or rpc binder). 438 */ 439void 440__svc_versquiet_on(xprt) 441 SVCXPRT *xprt; 442{ 443 u_long tmp; 444 445 tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET; 446 xprt->xp_p3 = tmp; 447} 448 449void 450__svc_versquiet_off(xprt) 451 SVCXPRT *xprt; 452{ 453 u_long tmp; 454 455 tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET; 456 xprt->xp_p3 = tmp; 457} 458 459void 460svc_versquiet(xprt) 461 SVCXPRT *xprt; 462{ 463 __svc_versquiet_on(xprt); 464} 465 466int 467__svc_versquiet_get(xprt) 468 SVCXPRT *xprt; 469{ 470 return ((int) xprt->xp_p3) & SVC_VERSQUIET; 471} 472#endif 473 474/* 475 * Authentication error reply 476 */ 477void 478svcerr_auth(xprt, why) 479 SVCXPRT *xprt; 480 enum auth_stat why; 481{ 482 struct rpc_msg rply; 483 484 assert(xprt != NULL); 485 486 rply.rm_direction = REPLY; 487 rply.rm_reply.rp_stat = MSG_DENIED; 488 rply.rjcted_rply.rj_stat = AUTH_ERROR; 489 rply.rjcted_rply.rj_why = why; 490 SVC_REPLY(xprt, &rply); 491} 492 493/* 494 * Auth too weak error reply 495 */ 496void 497svcerr_weakauth(xprt) 498 SVCXPRT *xprt; 499{ 500 501 assert(xprt != NULL); 502 503 svcerr_auth(xprt, AUTH_TOOWEAK); 504} 505 506/* 507 * Program unavailable error reply 508 */ 509void 510svcerr_noprog(xprt) 511 SVCXPRT *xprt; 512{ 513 struct rpc_msg rply; 514 515 assert(xprt != NULL); 516 517 rply.rm_direction = REPLY; 518 rply.rm_reply.rp_stat = MSG_ACCEPTED; 519 rply.acpted_rply.ar_verf = xprt->xp_verf; 520 rply.acpted_rply.ar_stat = PROG_UNAVAIL; 521 SVC_REPLY(xprt, &rply); 522} 523 524/* 525 * Program version mismatch error reply 526 */ 527void 528svcerr_progvers(xprt, low_vers, high_vers) 529 SVCXPRT *xprt; 530 rpcvers_t low_vers; 531 rpcvers_t high_vers; 532{ 533 struct rpc_msg rply; 534 535 assert(xprt != NULL); 536 537 rply.rm_direction = REPLY; 538 rply.rm_reply.rp_stat = MSG_ACCEPTED; 539 rply.acpted_rply.ar_verf = xprt->xp_verf; 540 rply.acpted_rply.ar_stat = PROG_MISMATCH; 541 rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers; 542 rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers; 543 SVC_REPLY(xprt, &rply); 544} 545 546/* ******************* SERVER INPUT STUFF ******************* */ 547 548/* 549 * Get server side input from some transport. 550 * 551 * Statement of authentication parameters management: 552 * This function owns and manages all authentication parameters, specifically 553 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and 554 * the "cooked" credentials (rqst->rq_clntcred). 555 * However, this function does not know the structure of the cooked 556 * credentials, so it make the following assumptions: 557 * a) the structure is contiguous (no pointers), and 558 * b) the cred structure size does not exceed RQCRED_SIZE bytes. 559 * In all events, all three parameters are freed upon exit from this routine. 560 * The storage is trivially management on the call stack in user land, but 561 * is mallocated in kernel land. 562 */ 563 564void 565svc_getreq(rdfds) 566 int rdfds; 567{ 568 fd_set readfds; 569 570 FD_ZERO(&readfds); 571 readfds.fds_bits[0] = rdfds; 572 svc_getreqset(&readfds); 573} 574 575void 576svc_getreqset(readfds) 577 fd_set *readfds; 578{ 579 int bit, fd; 580 fd_mask mask, *maskp; 581 int sock; 582 583 assert(readfds != NULL); 584 585 maskp = readfds->fds_bits; 586 for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) { 587 for (mask = *maskp++; (bit = ffs(mask)) != 0; 588 mask ^= (1 << (bit - 1))) { 589 /* sock has input waiting */ 590 fd = sock + bit - 1; 591 svc_getreq_common(fd); 592 } 593 } 594} 595 596void 597svc_getreq_common(fd) 598 int fd; 599{ 600 SVCXPRT *xprt; 601 struct svc_req r; 602 struct rpc_msg msg; 603 int prog_found; 604 rpcvers_t low_vers; 605 rpcvers_t high_vers; 606 enum xprt_stat stat; 607 char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; 608 609 msg.rm_call.cb_cred.oa_base = cred_area; 610 msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); 611 r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); 612 613 rwlock_rdlock(&svc_fd_lock);
| 164} 165 166/* 167 * Add a service program to the callout list. 168 * The dispatch routine will be called when a rpc request for this 169 * program number comes in. 170 */ 171bool_t 172svc_reg(xprt, prog, vers, dispatch, nconf) 173 SVCXPRT *xprt; 174 const rpcprog_t prog; 175 const rpcvers_t vers; 176 void (*dispatch)(struct svc_req *, SVCXPRT *); 177 const struct netconfig *nconf; 178{ 179 bool_t dummy; 180 struct svc_callout *prev; 181 struct svc_callout *s; 182 struct netconfig *tnconf; 183 char *netid = NULL; 184 int flag = 0; 185 186/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */ 187 188 if (xprt->xp_netid) { 189 netid = strdup(xprt->xp_netid); 190 flag = 1; 191 } else if (nconf && nconf->nc_netid) { 192 netid = strdup(nconf->nc_netid); 193 flag = 1; 194 } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) { 195 netid = strdup(tnconf->nc_netid); 196 flag = 1; 197 freenetconfigent(tnconf); 198 } /* must have been created with svc_raw_create */ 199 if ((netid == NULL) && (flag == 1)) { 200 return (FALSE); 201 } 202 203 rwlock_wrlock(&svc_lock); 204 if ((s = svc_find(prog, vers, &prev, netid)) != NULL) { 205 if (netid) 206 free(netid); 207 if (s->sc_dispatch == dispatch) 208 goto rpcb_it; /* he is registering another xptr */ 209 rwlock_unlock(&svc_lock); 210 return (FALSE); 211 } 212 s = mem_alloc(sizeof (struct svc_callout)); 213 if (s == NULL) { 214 if (netid) 215 free(netid); 216 rwlock_unlock(&svc_lock); 217 return (FALSE); 218 } 219 220 s->sc_prog = prog; 221 s->sc_vers = vers; 222 s->sc_dispatch = dispatch; 223 s->sc_netid = netid; 224 s->sc_next = svc_head; 225 svc_head = s; 226 227 if ((xprt->xp_netid == NULL) && (flag == 1) && netid) 228 ((SVCXPRT *) xprt)->xp_netid = strdup(netid); 229 230rpcb_it: 231 rwlock_unlock(&svc_lock); 232 /* now register the information with the local binder service */ 233 if (nconf) { 234 /*LINTED const castaway*/ 235 dummy = rpcb_set(prog, vers, (struct netconfig *) nconf, 236 &((SVCXPRT *) xprt)->xp_ltaddr); 237 return (dummy); 238 } 239 return (TRUE); 240} 241 242/* 243 * Remove a service program from the callout list. 244 */ 245void 246svc_unreg(prog, vers) 247 const rpcprog_t prog; 248 const rpcvers_t vers; 249{ 250 struct svc_callout *prev; 251 struct svc_callout *s; 252 253 /* unregister the information anyway */ 254 (void) rpcb_unset(prog, vers, NULL); 255 rwlock_wrlock(&svc_lock); 256 while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) { 257 if (prev == NULL) { 258 svc_head = s->sc_next; 259 } else { 260 prev->sc_next = s->sc_next; 261 } 262 s->sc_next = NULL; 263 if (s->sc_netid) 264 mem_free(s->sc_netid, sizeof (s->sc_netid) + 1); 265 mem_free(s, sizeof (struct svc_callout)); 266 } 267 rwlock_unlock(&svc_lock); 268} 269 270/* ********************** CALLOUT list related stuff ************* */ 271 272#ifdef PORTMAP 273/* 274 * Add a service program to the callout list. 275 * The dispatch routine will be called when a rpc request for this 276 * program number comes in. 277 */ 278bool_t 279svc_register(xprt, prog, vers, dispatch, protocol) 280 SVCXPRT *xprt; 281 u_long prog; 282 u_long vers; 283 void (*dispatch)(struct svc_req *, SVCXPRT *); 284 int protocol; 285{ 286 struct svc_callout *prev; 287 struct svc_callout *s; 288 289 assert(xprt != NULL); 290 assert(dispatch != NULL); 291 292 if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) != 293 NULL) { 294 if (s->sc_dispatch == dispatch) 295 goto pmap_it; /* he is registering another xptr */ 296 return (FALSE); 297 } 298 s = mem_alloc(sizeof(struct svc_callout)); 299 if (s == NULL) { 300 return (FALSE); 301 } 302 s->sc_prog = (rpcprog_t)prog; 303 s->sc_vers = (rpcvers_t)vers; 304 s->sc_dispatch = dispatch; 305 s->sc_next = svc_head; 306 svc_head = s; 307pmap_it: 308 /* now register the information with the local binder service */ 309 if (protocol) { 310 return (pmap_set(prog, vers, protocol, xprt->xp_port)); 311 } 312 return (TRUE); 313} 314 315/* 316 * Remove a service program from the callout list. 317 */ 318void 319svc_unregister(prog, vers) 320 u_long prog; 321 u_long vers; 322{ 323 struct svc_callout *prev; 324 struct svc_callout *s; 325 326 if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) == 327 NULL) 328 return; 329 if (prev == NULL) { 330 svc_head = s->sc_next; 331 } else { 332 prev->sc_next = s->sc_next; 333 } 334 s->sc_next = NULL; 335 mem_free(s, sizeof(struct svc_callout)); 336 /* now unregister the information with the local binder service */ 337 (void)pmap_unset(prog, vers); 338} 339#endif /* PORTMAP */ 340 341/* 342 * Search the callout list for a program number, return the callout 343 * struct. 344 */ 345static struct svc_callout * 346svc_find(prog, vers, prev, netid) 347 rpcprog_t prog; 348 rpcvers_t vers; 349 struct svc_callout **prev; 350 char *netid; 351{ 352 struct svc_callout *s, *p; 353 354 assert(prev != NULL); 355 356 p = NULL; 357 for (s = svc_head; s != NULL; s = s->sc_next) { 358 if (((s->sc_prog == prog) && (s->sc_vers == vers)) && 359 ((netid == NULL) || (s->sc_netid == NULL) || 360 (strcmp(netid, s->sc_netid) == 0))) 361 break; 362 p = s; 363 } 364 *prev = p; 365 return (s); 366} 367 368/* ******************* REPLY GENERATION ROUTINES ************ */ 369 370/* 371 * Send a reply to an rpc request 372 */ 373bool_t 374svc_sendreply(xprt, xdr_results, xdr_location) 375 SVCXPRT *xprt; 376 xdrproc_t xdr_results; 377 void * xdr_location; 378{ 379 struct rpc_msg rply; 380 381 assert(xprt != NULL); 382 383 rply.rm_direction = REPLY; 384 rply.rm_reply.rp_stat = MSG_ACCEPTED; 385 rply.acpted_rply.ar_verf = xprt->xp_verf; 386 rply.acpted_rply.ar_stat = SUCCESS; 387 rply.acpted_rply.ar_results.where = xdr_location; 388 rply.acpted_rply.ar_results.proc = xdr_results; 389 return (SVC_REPLY(xprt, &rply)); 390} 391 392/* 393 * No procedure error reply 394 */ 395void 396svcerr_noproc(xprt) 397 SVCXPRT *xprt; 398{ 399 struct rpc_msg rply; 400 401 assert(xprt != NULL); 402 403 rply.rm_direction = REPLY; 404 rply.rm_reply.rp_stat = MSG_ACCEPTED; 405 rply.acpted_rply.ar_verf = xprt->xp_verf; 406 rply.acpted_rply.ar_stat = PROC_UNAVAIL; 407 SVC_REPLY(xprt, &rply); 408} 409 410/* 411 * Can't decode args error reply 412 */ 413void 414svcerr_decode(xprt) 415 SVCXPRT *xprt; 416{ 417 struct rpc_msg rply; 418 419 assert(xprt != NULL); 420 421 rply.rm_direction = REPLY; 422 rply.rm_reply.rp_stat = MSG_ACCEPTED; 423 rply.acpted_rply.ar_verf = xprt->xp_verf; 424 rply.acpted_rply.ar_stat = GARBAGE_ARGS; 425 SVC_REPLY(xprt, &rply); 426} 427 428/* 429 * Some system error 430 */ 431void 432svcerr_systemerr(xprt) 433 SVCXPRT *xprt; 434{ 435 struct rpc_msg rply; 436 437 assert(xprt != NULL); 438 439 rply.rm_direction = REPLY; 440 rply.rm_reply.rp_stat = MSG_ACCEPTED; 441 rply.acpted_rply.ar_verf = xprt->xp_verf; 442 rply.acpted_rply.ar_stat = SYSTEM_ERR; 443 SVC_REPLY(xprt, &rply); 444} 445 446#if 0 447/* 448 * Tell RPC package to not complain about version errors to the client. This 449 * is useful when revving broadcast protocols that sit on a fixed address. 450 * There is really one (or should be only one) example of this kind of 451 * protocol: the portmapper (or rpc binder). 452 */ 453void 454__svc_versquiet_on(xprt) 455 SVCXPRT *xprt; 456{ 457 u_long tmp; 458 459 tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET; 460 xprt->xp_p3 = tmp; 461} 462 463void 464__svc_versquiet_off(xprt) 465 SVCXPRT *xprt; 466{ 467 u_long tmp; 468 469 tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET; 470 xprt->xp_p3 = tmp; 471} 472 473void 474svc_versquiet(xprt) 475 SVCXPRT *xprt; 476{ 477 __svc_versquiet_on(xprt); 478} 479 480int 481__svc_versquiet_get(xprt) 482 SVCXPRT *xprt; 483{ 484 return ((int) xprt->xp_p3) & SVC_VERSQUIET; 485} 486#endif 487 488/* 489 * Authentication error reply 490 */ 491void 492svcerr_auth(xprt, why) 493 SVCXPRT *xprt; 494 enum auth_stat why; 495{ 496 struct rpc_msg rply; 497 498 assert(xprt != NULL); 499 500 rply.rm_direction = REPLY; 501 rply.rm_reply.rp_stat = MSG_DENIED; 502 rply.rjcted_rply.rj_stat = AUTH_ERROR; 503 rply.rjcted_rply.rj_why = why; 504 SVC_REPLY(xprt, &rply); 505} 506 507/* 508 * Auth too weak error reply 509 */ 510void 511svcerr_weakauth(xprt) 512 SVCXPRT *xprt; 513{ 514 515 assert(xprt != NULL); 516 517 svcerr_auth(xprt, AUTH_TOOWEAK); 518} 519 520/* 521 * Program unavailable error reply 522 */ 523void 524svcerr_noprog(xprt) 525 SVCXPRT *xprt; 526{ 527 struct rpc_msg rply; 528 529 assert(xprt != NULL); 530 531 rply.rm_direction = REPLY; 532 rply.rm_reply.rp_stat = MSG_ACCEPTED; 533 rply.acpted_rply.ar_verf = xprt->xp_verf; 534 rply.acpted_rply.ar_stat = PROG_UNAVAIL; 535 SVC_REPLY(xprt, &rply); 536} 537 538/* 539 * Program version mismatch error reply 540 */ 541void 542svcerr_progvers(xprt, low_vers, high_vers) 543 SVCXPRT *xprt; 544 rpcvers_t low_vers; 545 rpcvers_t high_vers; 546{ 547 struct rpc_msg rply; 548 549 assert(xprt != NULL); 550 551 rply.rm_direction = REPLY; 552 rply.rm_reply.rp_stat = MSG_ACCEPTED; 553 rply.acpted_rply.ar_verf = xprt->xp_verf; 554 rply.acpted_rply.ar_stat = PROG_MISMATCH; 555 rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers; 556 rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers; 557 SVC_REPLY(xprt, &rply); 558} 559 560/* ******************* SERVER INPUT STUFF ******************* */ 561 562/* 563 * Get server side input from some transport. 564 * 565 * Statement of authentication parameters management: 566 * This function owns and manages all authentication parameters, specifically 567 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and 568 * the "cooked" credentials (rqst->rq_clntcred). 569 * However, this function does not know the structure of the cooked 570 * credentials, so it make the following assumptions: 571 * a) the structure is contiguous (no pointers), and 572 * b) the cred structure size does not exceed RQCRED_SIZE bytes. 573 * In all events, all three parameters are freed upon exit from this routine. 574 * The storage is trivially management on the call stack in user land, but 575 * is mallocated in kernel land. 576 */ 577 578void 579svc_getreq(rdfds) 580 int rdfds; 581{ 582 fd_set readfds; 583 584 FD_ZERO(&readfds); 585 readfds.fds_bits[0] = rdfds; 586 svc_getreqset(&readfds); 587} 588 589void 590svc_getreqset(readfds) 591 fd_set *readfds; 592{ 593 int bit, fd; 594 fd_mask mask, *maskp; 595 int sock; 596 597 assert(readfds != NULL); 598 599 maskp = readfds->fds_bits; 600 for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) { 601 for (mask = *maskp++; (bit = ffs(mask)) != 0; 602 mask ^= (1 << (bit - 1))) { 603 /* sock has input waiting */ 604 fd = sock + bit - 1; 605 svc_getreq_common(fd); 606 } 607 } 608} 609 610void 611svc_getreq_common(fd) 612 int fd; 613{ 614 SVCXPRT *xprt; 615 struct svc_req r; 616 struct rpc_msg msg; 617 int prog_found; 618 rpcvers_t low_vers; 619 rpcvers_t high_vers; 620 enum xprt_stat stat; 621 char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; 622 623 msg.rm_call.cb_cred.oa_base = cred_area; 624 msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); 625 r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); 626 627 rwlock_rdlock(&svc_fd_lock);
|
614 xprt = xports[fd];
| 628 xprt = __svc_xports[fd];
|
615 rwlock_unlock(&svc_fd_lock); 616 if (xprt == NULL) 617 /* But do we control sock? */ 618 return; 619 /* now receive msgs from xprtprt (support batch calls) */ 620 do { 621 if (SVC_RECV(xprt, &msg)) { 622 623 /* now find the exported program and call it */ 624 struct svc_callout *s; 625 enum auth_stat why; 626 627 r.rq_xprt = xprt; 628 r.rq_prog = msg.rm_call.cb_prog; 629 r.rq_vers = msg.rm_call.cb_vers; 630 r.rq_proc = msg.rm_call.cb_proc; 631 r.rq_cred = msg.rm_call.cb_cred; 632 /* first authenticate the message */ 633 if ((why = _authenticate(&r, &msg)) != AUTH_OK) { 634 svcerr_auth(xprt, why); 635 goto call_done; 636 } 637 /* now match message with a registered service*/ 638 prog_found = FALSE; 639 low_vers = (rpcvers_t) -1L; 640 high_vers = (rpcvers_t) 0L; 641 for (s = svc_head; s != NULL; s = s->sc_next) { 642 if (s->sc_prog == r.rq_prog) { 643 if (s->sc_vers == r.rq_vers) { 644 (*s->sc_dispatch)(&r, xprt); 645 goto call_done; 646 } /* found correct version */ 647 prog_found = TRUE; 648 if (s->sc_vers < low_vers) 649 low_vers = s->sc_vers; 650 if (s->sc_vers > high_vers) 651 high_vers = s->sc_vers; 652 } /* found correct program */ 653 } 654 /* 655 * if we got here, the program or version 656 * is not served ... 657 */ 658 if (prog_found) 659 svcerr_progvers(xprt, low_vers, high_vers); 660 else 661 svcerr_noprog(xprt); 662 /* Fall through to ... */ 663 } 664 /* 665 * Check if the xprt has been disconnected in a 666 * recursive call in the service dispatch routine. 667 * If so, then break. 668 */ 669 rwlock_rdlock(&svc_fd_lock);
| 629 rwlock_unlock(&svc_fd_lock); 630 if (xprt == NULL) 631 /* But do we control sock? */ 632 return; 633 /* now receive msgs from xprtprt (support batch calls) */ 634 do { 635 if (SVC_RECV(xprt, &msg)) { 636 637 /* now find the exported program and call it */ 638 struct svc_callout *s; 639 enum auth_stat why; 640 641 r.rq_xprt = xprt; 642 r.rq_prog = msg.rm_call.cb_prog; 643 r.rq_vers = msg.rm_call.cb_vers; 644 r.rq_proc = msg.rm_call.cb_proc; 645 r.rq_cred = msg.rm_call.cb_cred; 646 /* first authenticate the message */ 647 if ((why = _authenticate(&r, &msg)) != AUTH_OK) { 648 svcerr_auth(xprt, why); 649 goto call_done; 650 } 651 /* now match message with a registered service*/ 652 prog_found = FALSE; 653 low_vers = (rpcvers_t) -1L; 654 high_vers = (rpcvers_t) 0L; 655 for (s = svc_head; s != NULL; s = s->sc_next) { 656 if (s->sc_prog == r.rq_prog) { 657 if (s->sc_vers == r.rq_vers) { 658 (*s->sc_dispatch)(&r, xprt); 659 goto call_done; 660 } /* found correct version */ 661 prog_found = TRUE; 662 if (s->sc_vers < low_vers) 663 low_vers = s->sc_vers; 664 if (s->sc_vers > high_vers) 665 high_vers = s->sc_vers; 666 } /* found correct program */ 667 } 668 /* 669 * if we got here, the program or version 670 * is not served ... 671 */ 672 if (prog_found) 673 svcerr_progvers(xprt, low_vers, high_vers); 674 else 675 svcerr_noprog(xprt); 676 /* Fall through to ... */ 677 } 678 /* 679 * Check if the xprt has been disconnected in a 680 * recursive call in the service dispatch routine. 681 * If so, then break. 682 */ 683 rwlock_rdlock(&svc_fd_lock);
|
670 if (xprt != xports[fd]) {
| 684 if (xprt != __svc_xports[fd]) {
|
671 rwlock_unlock(&svc_fd_lock); 672 break; 673 } 674 rwlock_unlock(&svc_fd_lock); 675call_done: 676 if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 677 SVC_DESTROY(xprt); 678 break; 679 } 680 } while (stat == XPRT_MOREREQS); 681} 682 683 684void 685svc_getreq_poll(pfdp, pollretval) 686 struct pollfd *pfdp; 687 int pollretval; 688{ 689 int i; 690 int fds_found; 691 692 for (i = fds_found = 0; fds_found < pollretval; i++) { 693 struct pollfd *p = &pfdp[i]; 694 695 if (p->revents) { 696 /* fd has input waiting */ 697 fds_found++; 698 /* 699 * We assume that this function is only called 700 * via someone _select()ing from svc_fdset or 701 * _poll()ing from svc_pollset[]. Thus it's safe 702 * to handle the POLLNVAL event by simply turning 703 * the corresponding bit off in svc_fdset. The 704 * svc_pollset[] array is derived from svc_fdset 705 * and so will also be updated eventually. 706 * 707 * XXX Should we do an xprt_unregister() instead? 708 */ 709 if (p->revents & POLLNVAL) { 710 rwlock_wrlock(&svc_fd_lock); 711 FD_CLR(p->fd, &svc_fdset); 712 rwlock_unlock(&svc_fd_lock); 713 } else 714 svc_getreq_common(p->fd); 715 } 716 } 717}
| 685 rwlock_unlock(&svc_fd_lock); 686 break; 687 } 688 rwlock_unlock(&svc_fd_lock); 689call_done: 690 if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 691 SVC_DESTROY(xprt); 692 break; 693 } 694 } while (stat == XPRT_MOREREQS); 695} 696 697 698void 699svc_getreq_poll(pfdp, pollretval) 700 struct pollfd *pfdp; 701 int pollretval; 702{ 703 int i; 704 int fds_found; 705 706 for (i = fds_found = 0; fds_found < pollretval; i++) { 707 struct pollfd *p = &pfdp[i]; 708 709 if (p->revents) { 710 /* fd has input waiting */ 711 fds_found++; 712 /* 713 * We assume that this function is only called 714 * via someone _select()ing from svc_fdset or 715 * _poll()ing from svc_pollset[]. Thus it's safe 716 * to handle the POLLNVAL event by simply turning 717 * the corresponding bit off in svc_fdset. The 718 * svc_pollset[] array is derived from svc_fdset 719 * and so will also be updated eventually. 720 * 721 * XXX Should we do an xprt_unregister() instead? 722 */ 723 if (p->revents & POLLNVAL) { 724 rwlock_wrlock(&svc_fd_lock); 725 FD_CLR(p->fd, &svc_fdset); 726 rwlock_unlock(&svc_fd_lock); 727 } else 728 svc_getreq_common(p->fd); 729 } 730 } 731}
|
| 732 733bool_t 734rpc_control(int what, void *arg) 735{ 736 int val; 737 738 switch (what) { 739 case RPC_SVC_CONNMAXREC_SET: 740 val = *(int *)arg; 741 if (val <= 0) 742 return FALSE; 743 __svc_maxrec = val; 744 return TRUE; 745 case RPC_SVC_CONNMAXREC_GET: 746 *(int *)arg = __svc_maxrec; 747 return TRUE; 748 default: 749 break; 750 } 751 return FALSE; 752}
|
| |