xref: /freebsd/lib/libc/rpc/svc.c (revision 0c43d89a0d8e976ca494d4837f4c1f3734d2c300)
1 /*
2  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3  * unrestricted use provided that this legend is included on all tape
4  * media and as a part of the software program in whole or part.  Users
5  * may copy or modify Sun RPC without charge, but are not authorized
6  * to license or distribute it to anyone else except as part of a product or
7  * program developed by the user.
8  *
9  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12  *
13  * Sun RPC is provided with no support and without any obligation on the
14  * part of Sun Microsystems, Inc. to assist in its use, correction,
15  * modification or enhancement.
16  *
17  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19  * OR ANY PART THEREOF.
20  *
21  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22  * or profits or other special, indirect and consequential damages, even if
23  * Sun has been advised of the possibility of such damages.
24  *
25  * Sun Microsystems, Inc.
26  * 2550 Garcia Avenue
27  * Mountain View, California  94043
28  */
29 
30 #if defined(LIBC_SCCS) && !defined(lint)
31 /*static char *sccsid = "from: @(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";*/
32 /*static char *sccsid = "from: @(#)svc.c	2.4 88/08/11 4.0 RPCSRC";*/
33 static char *rcsid = "$Id: svc.c,v 1.1 1993/10/27 05:40:54 paul Exp $";
34 #endif
35 
36 /*
37  * svc.c, Server-side remote procedure call interface.
38  *
39  * There are two sets of procedures here.  The xprt routines are
40  * for handling transport handles.  The svc routines handle the
41  * list of service routines.
42  *
43  * Copyright (C) 1984, Sun Microsystems, Inc.
44  */
45 
46 #include <sys/errno.h>
47 #include <rpc/rpc.h>
48 #include <rpc/pmap_clnt.h>
49 
50 extern int errno;
51 
52 #ifdef FD_SETSIZE
53 static SVCXPRT **xports;
54 #else
55 #define NOFILE 32
56 
57 static SVCXPRT *xports[NOFILE];
58 #endif /* def FD_SETSIZE */
59 
60 #define NULL_SVC ((struct svc_callout *)0)
61 #define	RQCRED_SIZE	400		/* this size is excessive */
62 
63 /*
64  * The services list
65  * Each entry represents a set of procedures (an rpc program).
66  * The dispatch routine takes request structs and runs the
67  * apropriate procedure.
68  */
69 static struct svc_callout {
70 	struct svc_callout *sc_next;
71 	u_long		    sc_prog;
72 	u_long		    sc_vers;
73 	void		    (*sc_dispatch)();
74 } *svc_head;
75 
76 static struct svc_callout *svc_find();
77 
78 /* ***************  SVCXPRT related stuff **************** */
79 
80 /*
81  * Activate a transport handle.
82  */
83 void
84 xprt_register(xprt)
85 	SVCXPRT *xprt;
86 {
87 	register int sock = xprt->xp_sock;
88 
89 #ifdef FD_SETSIZE
90 	if (xports == NULL) {
91 		xports = (SVCXPRT **)
92 			mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
93 	}
94 	if (sock < _rpc_dtablesize()) {
95 		xports[sock] = xprt;
96 		FD_SET(sock, &svc_fdset);
97 	}
98 #else
99 	if (sock < NOFILE) {
100 		xports[sock] = xprt;
101 		svc_fds |= (1 << sock);
102 	}
103 #endif /* def FD_SETSIZE */
104 
105 }
106 
107 /*
108  * De-activate a transport handle.
109  */
110 void
111 xprt_unregister(xprt)
112 	SVCXPRT *xprt;
113 {
114 	register int sock = xprt->xp_sock;
115 
116 #ifdef FD_SETSIZE
117 	if ((sock < _rpc_dtablesize()) && (xports[sock] == xprt)) {
118 		xports[sock] = (SVCXPRT *)0;
119 		FD_CLR(sock, &svc_fdset);
120 	}
121 #else
122 	if ((sock < NOFILE) && (xports[sock] == xprt)) {
123 		xports[sock] = (SVCXPRT *)0;
124 		svc_fds &= ~(1 << sock);
125 	}
126 #endif /* def FD_SETSIZE */
127 }
128 
129 
130 /* ********************** CALLOUT list related stuff ************* */
131 
132 /*
133  * Add a service program to the callout list.
134  * The dispatch routine will be called when a rpc request for this
135  * program number comes in.
136  */
137 bool_t
138 svc_register(xprt, prog, vers, dispatch, protocol)
139 	SVCXPRT *xprt;
140 	u_long prog;
141 	u_long vers;
142 	void (*dispatch)();
143 	int protocol;
144 {
145 	struct svc_callout *prev;
146 	register struct svc_callout *s;
147 
148 	if ((s = svc_find(prog, vers, &prev)) != NULL_SVC) {
149 		if (s->sc_dispatch == dispatch)
150 			goto pmap_it;  /* he is registering another xptr */
151 		return (FALSE);
152 	}
153 	s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout));
154 	if (s == (struct svc_callout *)0) {
155 		return (FALSE);
156 	}
157 	s->sc_prog = prog;
158 	s->sc_vers = vers;
159 	s->sc_dispatch = dispatch;
160 	s->sc_next = svc_head;
161 	svc_head = s;
162 pmap_it:
163 	/* now register the information with the local binder service */
164 	if (protocol) {
165 		return (pmap_set(prog, vers, protocol, xprt->xp_port));
166 	}
167 	return (TRUE);
168 }
169 
170 /*
171  * Remove a service program from the callout list.
172  */
173 void
174 svc_unregister(prog, vers)
175 	u_long prog;
176 	u_long vers;
177 {
178 	struct svc_callout *prev;
179 	register struct svc_callout *s;
180 
181 	if ((s = svc_find(prog, vers, &prev)) == NULL_SVC)
182 		return;
183 	if (prev == NULL_SVC) {
184 		svc_head = s->sc_next;
185 	} else {
186 		prev->sc_next = s->sc_next;
187 	}
188 	s->sc_next = NULL_SVC;
189 	mem_free((char *) s, (u_int) sizeof(struct svc_callout));
190 	/* now unregister the information with the local binder service */
191 	(void)pmap_unset(prog, vers);
192 }
193 
194 /*
195  * Search the callout list for a program number, return the callout
196  * struct.
197  */
198 static struct svc_callout *
199 svc_find(prog, vers, prev)
200 	u_long prog;
201 	u_long vers;
202 	struct svc_callout **prev;
203 {
204 	register struct svc_callout *s, *p;
205 
206 	p = NULL_SVC;
207 	for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
208 		if ((s->sc_prog == prog) && (s->sc_vers == vers))
209 			goto done;
210 		p = s;
211 	}
212 done:
213 	*prev = p;
214 	return (s);
215 }
216 
217 /* ******************* REPLY GENERATION ROUTINES  ************ */
218 
219 /*
220  * Send a reply to an rpc request
221  */
222 bool_t
223 svc_sendreply(xprt, xdr_results, xdr_location)
224 	register SVCXPRT *xprt;
225 	xdrproc_t xdr_results;
226 	caddr_t xdr_location;
227 {
228 	struct rpc_msg rply;
229 
230 	rply.rm_direction = REPLY;
231 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
232 	rply.acpted_rply.ar_verf = xprt->xp_verf;
233 	rply.acpted_rply.ar_stat = SUCCESS;
234 	rply.acpted_rply.ar_results.where = xdr_location;
235 	rply.acpted_rply.ar_results.proc = xdr_results;
236 	return (SVC_REPLY(xprt, &rply));
237 }
238 
239 /*
240  * No procedure error reply
241  */
242 void
243 svcerr_noproc(xprt)
244 	register SVCXPRT *xprt;
245 {
246 	struct rpc_msg rply;
247 
248 	rply.rm_direction = REPLY;
249 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
250 	rply.acpted_rply.ar_verf = xprt->xp_verf;
251 	rply.acpted_rply.ar_stat = PROC_UNAVAIL;
252 	SVC_REPLY(xprt, &rply);
253 }
254 
255 /*
256  * Can't decode args error reply
257  */
258 void
259 svcerr_decode(xprt)
260 	register SVCXPRT *xprt;
261 {
262 	struct rpc_msg rply;
263 
264 	rply.rm_direction = REPLY;
265 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
266 	rply.acpted_rply.ar_verf = xprt->xp_verf;
267 	rply.acpted_rply.ar_stat = GARBAGE_ARGS;
268 	SVC_REPLY(xprt, &rply);
269 }
270 
271 /*
272  * Some system error
273  */
274 void
275 svcerr_systemerr(xprt)
276 	register SVCXPRT *xprt;
277 {
278 	struct rpc_msg rply;
279 
280 	rply.rm_direction = REPLY;
281 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
282 	rply.acpted_rply.ar_verf = xprt->xp_verf;
283 	rply.acpted_rply.ar_stat = SYSTEM_ERR;
284 	SVC_REPLY(xprt, &rply);
285 }
286 
287 /*
288  * Authentication error reply
289  */
290 void
291 svcerr_auth(xprt, why)
292 	SVCXPRT *xprt;
293 	enum auth_stat why;
294 {
295 	struct rpc_msg rply;
296 
297 	rply.rm_direction = REPLY;
298 	rply.rm_reply.rp_stat = MSG_DENIED;
299 	rply.rjcted_rply.rj_stat = AUTH_ERROR;
300 	rply.rjcted_rply.rj_why = why;
301 	SVC_REPLY(xprt, &rply);
302 }
303 
304 /*
305  * Auth too weak error reply
306  */
307 void
308 svcerr_weakauth(xprt)
309 	SVCXPRT *xprt;
310 {
311 
312 	svcerr_auth(xprt, AUTH_TOOWEAK);
313 }
314 
315 /*
316  * Program unavailable error reply
317  */
318 void
319 svcerr_noprog(xprt)
320 	register SVCXPRT *xprt;
321 {
322 	struct rpc_msg rply;
323 
324 	rply.rm_direction = REPLY;
325 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
326 	rply.acpted_rply.ar_verf = xprt->xp_verf;
327 	rply.acpted_rply.ar_stat = PROG_UNAVAIL;
328 	SVC_REPLY(xprt, &rply);
329 }
330 
331 /*
332  * Program version mismatch error reply
333  */
334 void
335 svcerr_progvers(xprt, low_vers, high_vers)
336 	register SVCXPRT *xprt;
337 	u_long low_vers;
338 	u_long high_vers;
339 {
340 	struct rpc_msg rply;
341 
342 	rply.rm_direction = REPLY;
343 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
344 	rply.acpted_rply.ar_verf = xprt->xp_verf;
345 	rply.acpted_rply.ar_stat = PROG_MISMATCH;
346 	rply.acpted_rply.ar_vers.low = low_vers;
347 	rply.acpted_rply.ar_vers.high = high_vers;
348 	SVC_REPLY(xprt, &rply);
349 }
350 
351 /* ******************* SERVER INPUT STUFF ******************* */
352 
353 /*
354  * Get server side input from some transport.
355  *
356  * Statement of authentication parameters management:
357  * This function owns and manages all authentication parameters, specifically
358  * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
359  * the "cooked" credentials (rqst->rq_clntcred).
360  * However, this function does not know the structure of the cooked
361  * credentials, so it make the following assumptions:
362  *   a) the structure is contiguous (no pointers), and
363  *   b) the cred structure size does not exceed RQCRED_SIZE bytes.
364  * In all events, all three parameters are freed upon exit from this routine.
365  * The storage is trivially management on the call stack in user land, but
366  * is mallocated in kernel land.
367  */
368 
369 void
370 svc_getreq(rdfds)
371 	int rdfds;
372 {
373 #ifdef FD_SETSIZE
374 	fd_set readfds;
375 
376 	FD_ZERO(&readfds);
377 	readfds.fds_bits[0] = rdfds;
378 	svc_getreqset(&readfds);
379 #else
380 	int readfds = rdfds & svc_fds;
381 
382 	svc_getreqset(&readfds);
383 #endif /* def FD_SETSIZE */
384 }
385 
386 void
387 svc_getreqset(readfds)
388 #ifdef FD_SETSIZE
389 	fd_set *readfds;
390 {
391 #else
392 	int *readfds;
393 {
394     int readfds_local = *readfds;
395 #endif /* def FD_SETSIZE */
396 	enum xprt_stat stat;
397 	struct rpc_msg msg;
398 	int prog_found;
399 	u_long low_vers;
400 	u_long high_vers;
401 	struct svc_req r;
402 	register SVCXPRT *xprt;
403 	register u_long mask;
404 	register int bit;
405 	register u_long *maskp;
406 	register int setsize;
407 	register int sock;
408 	char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
409 	msg.rm_call.cb_cred.oa_base = cred_area;
410 	msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
411 	r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
412 
413 
414 #ifdef FD_SETSIZE
415 	setsize = _rpc_dtablesize();
416 	maskp = (u_long *)readfds->fds_bits;
417 	for (sock = 0; sock < setsize; sock += NFDBITS) {
418 	    for (mask = *maskp++; bit = ffs(mask); mask ^= (1 << (bit - 1))) {
419 		/* sock has input waiting */
420 		xprt = xports[sock + bit - 1];
421 #else
422 	for (sock = 0; readfds_local != 0; sock++, readfds_local >>= 1) {
423 	    if ((readfds_local & 1) != 0) {
424 		/* sock has input waiting */
425 		xprt = xports[sock];
426 #endif /* def FD_SETSIZE */
427 		/* now receive msgs from xprtprt (support batch calls) */
428 		do {
429 			if (SVC_RECV(xprt, &msg)) {
430 
431 				/* now find the exported program and call it */
432 				register struct svc_callout *s;
433 				enum auth_stat why;
434 
435 				r.rq_xprt = xprt;
436 				r.rq_prog = msg.rm_call.cb_prog;
437 				r.rq_vers = msg.rm_call.cb_vers;
438 				r.rq_proc = msg.rm_call.cb_proc;
439 				r.rq_cred = msg.rm_call.cb_cred;
440 				/* first authenticate the message */
441 				if ((why= _authenticate(&r, &msg)) != AUTH_OK) {
442 					svcerr_auth(xprt, why);
443 					goto call_done;
444 				}
445 				/* now match message with a registered service*/
446 				prog_found = FALSE;
447 				low_vers = 0 - 1;
448 				high_vers = 0;
449 				for (s = svc_head; s != NULL_SVC; 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, xprt);
453 							goto call_done;
454 						}  /* found correct version */
455 						prog_found = TRUE;
456 						if (s->sc_vers < low_vers)
457 							low_vers = s->sc_vers;
458 						if (s->sc_vers > high_vers)
459 							high_vers = s->sc_vers;
460 					}   /* found correct program */
461 				}
462 				/*
463 				 * if we got here, the program or version
464 				 * is not served ...
465 				 */
466 				if (prog_found)
467 					svcerr_progvers(xprt,
468 					low_vers, high_vers);
469 				else
470 					 svcerr_noprog(xprt);
471 				/* Fall through to ... */
472 			}
473 		call_done:
474 			if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
475 				SVC_DESTROY(xprt);
476 				break;
477 			}
478 		} while (stat == XPRT_MOREREQS);
479 	    }
480 	}
481 }
482