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