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