1 /* @(#)svc.c 2.4 88/08/11 4.0 RPCSRC; from 1.44 88/02/08 SMI */
3 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
4 * unrestricted use provided that this legend is included on all tape
5 * media and as a part of the software program in whole or part. Users
6 * may copy or modify Sun RPC without charge, but are not authorized
7 * to license or distribute it to anyone else except as part of a product or
8 * program developed by the user.
10 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
11 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
12 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14 * Sun RPC is provided with no support and without any obligation on the
15 * part of Sun Microsystems, Inc. to assist in its use, correction,
16 * modification or enhancement.
18 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
19 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
20 * OR ANY PART THEREOF.
22 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
23 * or profits or other special, indirect and consequential damages, even if
24 * Sun has been advised of the possibility of such damages.
26 * Sun Microsystems, Inc.
28 * Mountain View, California 94043
30 #if !defined(lint) && defined(SCCSIDS)
31 static char sccsid
[] = "@(#)svc.c 1.41 87/10/13 Copyr 1984 Sun Micro";
35 * svc.c, Server-side remote procedure call interface.
37 * There are two sets of procedures here. The xprt routines are
38 * for handling transport handles. The svc routines handle the
39 * list of service routines.
41 * Copyright (C) 1984, Sun Microsystems, Inc.
44 #include <sys/errno.h>
46 #include <rpc/pmap_clnt.h>
51 static SVCXPRT
**xports
;
55 static SVCXPRT
*xports
[NOFILE
];
56 #endif /* def FD_SETSIZE */
58 #define NULL_SVC ((struct svc_callout *)0)
59 #define RQCRED_SIZE 400 /* this size is excessive */
63 * Each entry represents a set of procedures (an rpc program).
64 * The dispatch routine takes request structs and runs the
65 * apropriate procedure.
67 static struct svc_callout
{
68 struct svc_callout
*sc_next
;
71 void (*sc_dispatch
)();
74 static struct svc_callout
*svc_find();
76 /* *************** SVCXPRT related stuff **************** */
79 * Activate a transport handle.
85 register int sock
= xprt
->xp_sock
;
90 mem_alloc(FD_SETSIZE
* sizeof(SVCXPRT
*));
92 if (sock
< _rpc_dtablesize()) {
94 FD_SET(sock
, &svc_fdset
);
99 svc_fds
|= (1 << sock
);
101 #endif /* def FD_SETSIZE */
106 * De-activate a transport handle.
109 xprt_unregister(xprt
)
112 register int sock
= xprt
->xp_sock
;
115 if ((sock
< _rpc_dtablesize()) && (xports
[sock
] == xprt
)) {
116 xports
[sock
] = (SVCXPRT
*)0;
117 FD_CLR(sock
, &svc_fdset
);
120 if ((sock
< NOFILE
) && (xports
[sock
] == xprt
)) {
121 xports
[sock
] = (SVCXPRT
*)0;
122 svc_fds
&= ~(1 << sock
);
124 #endif /* def FD_SETSIZE */
128 /* ********************** CALLOUT list related stuff ************* */
131 * Add a service program to the callout list.
132 * The dispatch routine will be called when a rpc request for this
133 * program number comes in.
136 svc_register(xprt
, prog
, vers
, dispatch
, protocol
)
143 struct svc_callout
*prev
;
144 register struct svc_callout
*s
;
146 if ((s
= svc_find(prog
, vers
, &prev
)) != NULL_SVC
) {
147 if (s
->sc_dispatch
== dispatch
)
148 goto pmap_it
; /* he is registering another xptr */
151 s
= (struct svc_callout
*)mem_alloc(sizeof(struct svc_callout
));
152 if (s
== (struct svc_callout
*)0) {
157 s
->sc_dispatch
= dispatch
;
158 s
->sc_next
= svc_head
;
161 /* now register the information with the local binder service */
163 return (pmap_set(prog
, vers
, protocol
, xprt
->xp_port
));
169 * Remove a service program from the callout list.
172 svc_unregister(prog
, vers
)
176 struct svc_callout
*prev
;
177 register struct svc_callout
*s
;
179 if ((s
= svc_find(prog
, vers
, &prev
)) == NULL_SVC
)
181 if (prev
== NULL_SVC
) {
182 svc_head
= s
->sc_next
;
184 prev
->sc_next
= s
->sc_next
;
186 s
->sc_next
= NULL_SVC
;
187 mem_free((char *) s
, (u_int
) sizeof(struct svc_callout
));
188 /* now unregister the information with the local binder service */
189 (void)pmap_unset(prog
, vers
);
193 * Search the callout list for a program number, return the callout
196 static struct svc_callout
*
197 svc_find(prog
, vers
, prev
)
200 struct svc_callout
**prev
;
202 register struct svc_callout
*s
, *p
;
205 for (s
= svc_head
; s
!= NULL_SVC
; s
= s
->sc_next
) {
206 if ((s
->sc_prog
== prog
) && (s
->sc_vers
== vers
))
215 /* ******************* REPLY GENERATION ROUTINES ************ */
218 * Send a reply to an rpc request
221 svc_sendreply(xprt
, xdr_results
, xdr_location
)
222 register SVCXPRT
*xprt
;
223 xdrproc_t xdr_results
;
224 caddr_t xdr_location
;
228 rply
.rm_direction
= REPLY
;
229 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
230 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
231 rply
.acpted_rply
.ar_stat
= SUCCESS
;
232 rply
.acpted_rply
.ar_results
.where
= xdr_location
;
233 rply
.acpted_rply
.ar_results
.proc
= xdr_results
;
234 return (SVC_REPLY(xprt
, &rply
));
238 * No procedure error reply
242 register SVCXPRT
*xprt
;
246 rply
.rm_direction
= REPLY
;
247 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
248 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
249 rply
.acpted_rply
.ar_stat
= PROC_UNAVAIL
;
250 SVC_REPLY(xprt
, &rply
);
254 * Can't decode args error reply
258 register SVCXPRT
*xprt
;
262 rply
.rm_direction
= REPLY
;
263 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
264 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
265 rply
.acpted_rply
.ar_stat
= GARBAGE_ARGS
;
266 SVC_REPLY(xprt
, &rply
);
273 svcerr_systemerr(xprt
)
274 register SVCXPRT
*xprt
;
278 rply
.rm_direction
= REPLY
;
279 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
280 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
281 rply
.acpted_rply
.ar_stat
= SYSTEM_ERR
;
282 SVC_REPLY(xprt
, &rply
);
286 * Authentication error reply
289 svcerr_auth(xprt
, why
)
295 rply
.rm_direction
= REPLY
;
296 rply
.rm_reply
.rp_stat
= MSG_DENIED
;
297 rply
.rjcted_rply
.rj_stat
= AUTH_ERROR
;
298 rply
.rjcted_rply
.rj_why
= why
;
299 SVC_REPLY(xprt
, &rply
);
303 * Auth too weak error reply
306 svcerr_weakauth(xprt
)
310 svcerr_auth(xprt
, AUTH_TOOWEAK
);
314 * Program unavailable error reply
318 register SVCXPRT
*xprt
;
322 rply
.rm_direction
= REPLY
;
323 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
324 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
325 rply
.acpted_rply
.ar_stat
= PROG_UNAVAIL
;
326 SVC_REPLY(xprt
, &rply
);
330 * Program version mismatch error reply
333 svcerr_progvers(xprt
, low_vers
, high_vers
)
334 register SVCXPRT
*xprt
;
340 rply
.rm_direction
= REPLY
;
341 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
342 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
343 rply
.acpted_rply
.ar_stat
= PROG_MISMATCH
;
344 rply
.acpted_rply
.ar_vers
.low
= low_vers
;
345 rply
.acpted_rply
.ar_vers
.high
= high_vers
;
346 SVC_REPLY(xprt
, &rply
);
349 /* ******************* SERVER INPUT STUFF ******************* */
352 * Get server side input from some transport.
354 * Statement of authentication parameters management:
355 * This function owns and manages all authentication parameters, specifically
356 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
357 * the "cooked" credentials (rqst->rq_clntcred).
358 * However, this function does not know the structure of the cooked
359 * credentials, so it make the following assumptions:
360 * a) the structure is contiguous (no pointers), and
361 * b) the cred structure size does not exceed RQCRED_SIZE bytes.
362 * In all events, all three parameters are freed upon exit from this routine.
363 * The storage is trivially management on the call stack in user land, but
364 * is mallocated in kernel land.
375 readfds
.fds_bits
[0] = rdfds
;
376 svc_getreqset(&readfds
);
378 int readfds
= rdfds
& svc_fds
;
380 svc_getreqset(&readfds
);
381 #endif /* def FD_SETSIZE */
385 svc_getreqset(readfds
)
392 int readfds_local
= *readfds
;
393 #endif /* def FD_SETSIZE */
400 register SVCXPRT
*xprt
;
401 register u_long mask
;
403 register u_int32_t
*maskp
;
404 register int setsize
;
406 char cred_area
[2*MAX_AUTH_BYTES
+ RQCRED_SIZE
];
407 msg
.rm_call
.cb_cred
.oa_base
= cred_area
;
408 msg
.rm_call
.cb_verf
.oa_base
= &(cred_area
[MAX_AUTH_BYTES
]);
409 r
.rq_clntcred
= &(cred_area
[2*MAX_AUTH_BYTES
]);
413 setsize
= _rpc_dtablesize();
414 maskp
= (u_int32_t
*)readfds
->fds_bits
;
415 for (sock
= 0; sock
< setsize
; sock
+= NFDBITS
) {
416 for (mask
= *maskp
++; bit
= ffs(mask
); mask
^= (1 << (bit
- 1))) {
417 /* sock has input waiting */
418 xprt
= xports
[sock
+ bit
- 1];
420 for (sock
= 0; readfds_local
!= 0; sock
++, readfds_local
>>= 1) {
421 if ((readfds_local
& 1) != 0) {
422 /* sock has input waiting */
424 #endif /* def FD_SETSIZE */
425 /* now receive msgs from xprtprt (support batch calls) */
427 if (SVC_RECV(xprt
, &msg
)) {
429 /* now find the exported program and call it */
430 register struct svc_callout
*s
;
434 r
.rq_prog
= msg
.rm_call
.cb_prog
;
435 r
.rq_vers
= msg
.rm_call
.cb_vers
;
436 r
.rq_proc
= msg
.rm_call
.cb_proc
;
437 r
.rq_cred
= msg
.rm_call
.cb_cred
;
438 /* first authenticate the message */
439 if ((why
= _authenticate(&r
, &msg
)) != AUTH_OK
) {
440 svcerr_auth(xprt
, why
);
443 /* now match message with a registered service*/
447 for (s
= svc_head
; s
!= NULL_SVC
; s
= s
->sc_next
) {
448 if (s
->sc_prog
== r
.rq_prog
) {
449 if (s
->sc_vers
== r
.rq_vers
) {
450 (*s
->sc_dispatch
)(&r
, xprt
);
452 } /* found correct version */
454 if (s
->sc_vers
< low_vers
)
455 low_vers
= s
->sc_vers
;
456 if (s
->sc_vers
> high_vers
)
457 high_vers
= s
->sc_vers
;
458 } /* found correct program */
461 * if we got here, the program or version
465 svcerr_progvers(xprt
,
466 low_vers
, high_vers
);
469 /* Fall through to ... */
472 if ((stat
= SVC_STAT(xprt
)) == XPRT_DIED
){
476 } while (stat
== XPRT_MOREREQS
);