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