xref: /openbsd-src/lib/libc/rpc/svc.c (revision 43003dfe3ad45d1698bed8a37f2b0f5b14f20d4f)
1 /*	$OpenBSD: svc.c,v 1.22 2009/06/05 20:23:38 deraadt Exp $ */
2 /*
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.
9  *
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.
13  *
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.
17  *
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.
21  *
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.
25  *
26  * Sun Microsystems, Inc.
27  * 2550 Garcia Avenue
28  * Mountain View, California  94043
29  */
30 
31 /*
32  * svc.c, Server-side remote procedure call interface.
33  *
34  * There are two sets of procedures here.  The xprt routines are
35  * for handling transport handles.  The svc routines handle the
36  * list of service routines.
37  *
38  * Copyright (C) 1984, Sun Microsystems, Inc.
39  */
40 
41 #include <errno.h>
42 #include <stdlib.h>
43 #include <string.h>
44 
45 #include <rpc/rpc.h>
46 #include <rpc/pmap_clnt.h>
47 
48 static SVCXPRT **xports;
49 static int xportssize;
50 
51 #define	RQCRED_SIZE	400		/* this size is excessive */
52 
53 #define max(a, b) (a > b ? a : b)
54 
55 /*
56  * The services list
57  * Each entry represents a set of procedures (an rpc program).
58  * The dispatch routine takes request structs and runs the
59  * appropriate procedure.
60  */
61 static struct svc_callout {
62 	struct svc_callout *sc_next;
63 	u_long		    sc_prog;
64 	u_long		    sc_vers;
65 	void		    (*sc_dispatch)();
66 } *svc_head;
67 
68 static struct svc_callout *svc_find(u_long, u_long, struct svc_callout **);
69 static int svc_fd_insert(int);
70 static int svc_fd_remove(int);
71 
72 int __svc_fdsetsize = FD_SETSIZE;
73 fd_set *__svc_fdset = &svc_fdset;
74 static int svc_pollfd_size;		/* number of slots in svc_pollfd */
75 static int svc_used_pollfd;		/* number of used slots in svc_pollfd */
76 static int *svc_pollfd_freelist;	/* svc_pollfd free list */
77 static int svc_max_free;		/* number of used slots in free list */
78 
79 /* ***************  SVCXPRT related stuff **************** */
80 
81 /*
82  * Activate a transport handle.
83  */
84 void
85 xprt_register(SVCXPRT *xprt)
86 {
87 	/* ignore failure conditions */
88 	(void) __xprt_register(xprt);
89 }
90 
91 /*
92  * Activate a transport handle.
93  */
94 int
95 __xprt_register(SVCXPRT *xprt)
96 {
97 	int sock = xprt->xp_sock;
98 
99 	if (xports == NULL || sock + 1 > xportssize) {
100 		SVCXPRT **xp;
101 		int size = FD_SETSIZE;
102 
103 		while (sock + 1 > size)
104 			size += FD_SETSIZE;
105 		xp = (SVCXPRT **)calloc(size, sizeof(SVCXPRT *));
106 		if (xp == NULL)
107 			return (0);
108 		if (xports) {
109 			memcpy(xp, xports, xportssize * sizeof(SVCXPRT *));
110 			free(xports);
111 		}
112 		xportssize = size;
113 		xports = xp;
114 	}
115 
116 	if (!svc_fd_insert(sock))
117 		return (0);
118 	xports[sock] = xprt;
119 
120 	return (1);
121 }
122 
123 /*
124  * Insert a socket into svc_pollfd, svc_fdset and __svc_fdset.
125  * If we are out of space, we allocate ~128 more slots than we
126  * need now for future expansion.
127  * We try to keep svc_pollfd well packed (no holes) as possible
128  * so that poll(2) is efficient.
129  */
130 static int
131 svc_fd_insert(int sock)
132 {
133 	int slot;
134 
135 	/*
136 	 * Find a slot for sock in svc_pollfd; four possible cases:
137 	 *  1) need to allocate more space for svc_pollfd
138 	 *  2) there is an entry on the free list
139 	 *  3) the free list is empty (svc_used_pollfd is the next slot)
140 	 */
141 	if (svc_pollfd == NULL || svc_used_pollfd == svc_pollfd_size) {
142 		struct pollfd *pfd;
143 		int new_size, *new_freelist;
144 
145 		new_size = svc_pollfd ? svc_pollfd_size + 128 : FD_SETSIZE;
146 		pfd = realloc(svc_pollfd, sizeof(*svc_pollfd) * new_size);
147 		if (pfd == NULL)
148 			return (0);			/* no changes */
149 		new_freelist = realloc(svc_pollfd_freelist, new_size / 2);
150 		if (new_freelist == NULL) {
151 			free(pfd);
152 			return (0);			/* no changes */
153 		}
154 		svc_pollfd = pfd;
155 		svc_pollfd_size = new_size;
156 		svc_pollfd_freelist = new_freelist;
157 		for (slot = svc_used_pollfd; slot < svc_pollfd_size; slot++) {
158 			svc_pollfd[slot].fd = -1;
159 			svc_pollfd[slot].events = svc_pollfd[slot].revents = 0;
160 		}
161 		slot = svc_used_pollfd;
162 	} else if (svc_max_free != 0) {
163 		/* there is an entry on the free list, use it */
164 		slot = svc_pollfd_freelist[--svc_max_free];
165 	} else {
166 		/* nothing on the free list but we have room to grow */
167 		slot = svc_used_pollfd;
168 	}
169 	if (sock + 1 > __svc_fdsetsize) {
170 		fd_set *fds;
171 		size_t bytes;
172 
173 		bytes = howmany(sock + 128, NFDBITS) * sizeof(fd_mask);
174 		/* realloc() would be nicer but it gets tricky... */
175 		if ((fds = (fd_set *)mem_alloc(bytes)) != NULL) {
176 			memset(fds, 0, bytes);
177 			memcpy(fds, __svc_fdset,
178 			    howmany(__svc_fdsetsize, NFDBITS) * sizeof(fd_mask));
179 			if (__svc_fdset != &svc_fdset)
180 				free(__svc_fdset);
181 			__svc_fdset = fds;
182 			__svc_fdsetsize = bytes / sizeof(fd_mask);
183 		}
184 	}
185 
186 	svc_pollfd[slot].fd = sock;
187 	svc_pollfd[slot].events = POLLIN;
188 	svc_used_pollfd++;
189 	if (svc_max_pollfd < slot + 1)
190 		svc_max_pollfd = slot + 1;
191 	if (sock < FD_SETSIZE)
192 		FD_SET(sock, &svc_fdset);
193 	else if (sock < __svc_fdsetsize)
194 		FD_SET(sock, __svc_fdset);
195 	svc_maxfd = max(svc_maxfd, sock);
196 
197 	return (1);
198 }
199 
200 /*
201  * Remove a socket from svc_pollfd, svc_fdset and __svc_fdset.
202  * Freed slots are placed on the free list.  If the free list fills
203  * up, we compact svc_pollfd (free list size == svc_pollfd_size /2).
204  */
205 static int
206 svc_fd_remove(int sock)
207 {
208 	int slot;
209 
210 	if (svc_pollfd == NULL)
211 		return (0);
212 
213 	for (slot = 0; slot < svc_max_pollfd; slot++) {
214 		if (svc_pollfd[slot].fd == sock) {
215 			svc_pollfd[slot].fd = -1;
216 			svc_pollfd[slot].events = svc_pollfd[slot].revents = 0;
217 			svc_used_pollfd--;
218 			if (sock < FD_SETSIZE)
219 				FD_CLR(sock, &svc_fdset);
220 			else if (sock < __svc_fdsetsize)
221 				FD_CLR(sock, __svc_fdset);
222 			if (sock == svc_maxfd) {
223 				for (svc_maxfd--; svc_maxfd >= 0; svc_maxfd--)
224 					if (xports[svc_maxfd])
225 						break;
226 			}
227 			if (svc_max_free == svc_pollfd_size / 2) {
228 				int i, j;
229 
230 				/*
231 				 * Out of space in the free list; this means
232 				 * that svc_pollfd is half full.  Pack things
233 				 * such that svc_max_pollfd == svc_used_pollfd
234 				 * and svc_pollfd_freelist is empty.
235 				 */
236 				for (i = svc_used_pollfd, j = 0;
237 				    i < svc_max_pollfd && j < svc_max_free; i++) {
238 					if (svc_pollfd[i].fd == -1)
239 						continue;
240 					/* be sure to use a low-numbered slot */
241 					while (svc_pollfd_freelist[j] >=
242 					    svc_used_pollfd)
243 						j++;
244 					svc_pollfd[svc_pollfd_freelist[j++]] =
245 					    svc_pollfd[i];
246 					svc_pollfd[i].fd = -1;
247 					svc_pollfd[i].events =
248 					    svc_pollfd[i].revents = 0;
249 				}
250 				svc_max_pollfd = svc_used_pollfd;
251 				svc_max_free = 0;
252 				/* could realloc if svc_pollfd_size is big */
253 			} else {
254 				/* trim svc_max_pollfd from the end */
255 				while (svc_max_pollfd > 0 &&
256 				    svc_pollfd[svc_max_pollfd - 1].fd == -1)
257 					svc_max_pollfd--;
258 			}
259 			svc_pollfd_freelist[svc_max_free++] = slot;
260 
261 			return (1);
262 		}
263 	}
264 	return (0);		/* not found, shouldn't happen */
265 }
266 
267 /*
268  * De-activate a transport handle.
269  */
270 void
271 xprt_unregister(SVCXPRT *xprt)
272 {
273 	int sock = xprt->xp_sock;
274 
275 	if (xports[sock] == xprt) {
276 		xports[sock] = NULL;
277 		svc_fd_remove(sock);
278 	}
279 }
280 
281 
282 /* ********************** CALLOUT list related stuff ************* */
283 
284 /*
285  * Add a service program to the callout list.
286  * The dispatch routine will be called when a rpc request for this
287  * program number comes in.
288  */
289 bool_t
290 svc_register(SVCXPRT *xprt, u_long prog, u_long vers, void (*dispatch)(),
291     int protocol)
292 {
293 	struct svc_callout *prev;
294 	struct svc_callout *s;
295 
296 	if ((s = svc_find(prog, vers, &prev)) != NULL) {
297 		if (s->sc_dispatch == dispatch)
298 			goto pmap_it;  /* he is registering another xptr */
299 		return (FALSE);
300 	}
301 	s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout));
302 	if (s == NULL) {
303 		return (FALSE);
304 	}
305 	s->sc_prog = prog;
306 	s->sc_vers = vers;
307 	s->sc_dispatch = dispatch;
308 	s->sc_next = svc_head;
309 	svc_head = s;
310 pmap_it:
311 	/* now register the information with the local binder service */
312 	if (protocol) {
313 		return (pmap_set(prog, vers, protocol, xprt->xp_port));
314 	}
315 	return (TRUE);
316 }
317 
318 /*
319  * Remove a service program from the callout list.
320  */
321 void
322 svc_unregister(u_long prog, u_long vers)
323 {
324 	struct svc_callout *prev;
325 	struct svc_callout *s;
326 
327 	if ((s = svc_find(prog, vers, &prev)) == NULL)
328 		return;
329 	if (prev == NULL) {
330 		svc_head = s->sc_next;
331 	} else {
332 		prev->sc_next = s->sc_next;
333 	}
334 	s->sc_next = NULL;
335 	mem_free((char *) s, (u_int) sizeof(struct svc_callout));
336 	/* now unregister the information with the local binder service */
337 	(void)pmap_unset(prog, vers);
338 }
339 
340 /*
341  * Search the callout list for a program number, return the callout
342  * struct.
343  */
344 static struct svc_callout *
345 svc_find(u_long prog, u_long vers, struct svc_callout **prev)
346 {
347 	struct svc_callout *s, *p;
348 
349 	p = NULL;
350 	for (s = svc_head; s != NULL; s = s->sc_next) {
351 		if ((s->sc_prog == prog) && (s->sc_vers == vers))
352 			goto done;
353 		p = s;
354 	}
355 done:
356 	*prev = p;
357 	return (s);
358 }
359 
360 /* ******************* REPLY GENERATION ROUTINES  ************ */
361 
362 /*
363  * Send a reply to an rpc request
364  */
365 bool_t
366 svc_sendreply(SVCXPRT *xprt, xdrproc_t xdr_results, caddr_t xdr_location)
367 {
368 	struct rpc_msg rply;
369 
370 	rply.rm_direction = REPLY;
371 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
372 	rply.acpted_rply.ar_verf = xprt->xp_verf;
373 	rply.acpted_rply.ar_stat = SUCCESS;
374 	rply.acpted_rply.ar_results.where = xdr_location;
375 	rply.acpted_rply.ar_results.proc = xdr_results;
376 	return (SVC_REPLY(xprt, &rply));
377 }
378 
379 /*
380  * No procedure error reply
381  */
382 void
383 svcerr_noproc(SVCXPRT *xprt)
384 {
385 	struct rpc_msg rply;
386 
387 	rply.rm_direction = REPLY;
388 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
389 	rply.acpted_rply.ar_verf = xprt->xp_verf;
390 	rply.acpted_rply.ar_stat = PROC_UNAVAIL;
391 	SVC_REPLY(xprt, &rply);
392 }
393 
394 /*
395  * Can't decode args error reply
396  */
397 void
398 svcerr_decode(SVCXPRT *xprt)
399 {
400 	struct rpc_msg rply;
401 
402 	rply.rm_direction = REPLY;
403 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
404 	rply.acpted_rply.ar_verf = xprt->xp_verf;
405 	rply.acpted_rply.ar_stat = GARBAGE_ARGS;
406 	SVC_REPLY(xprt, &rply);
407 }
408 
409 /*
410  * Some system error
411  */
412 void
413 svcerr_systemerr(SVCXPRT *xprt)
414 {
415 	struct rpc_msg rply;
416 
417 	rply.rm_direction = REPLY;
418 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
419 	rply.acpted_rply.ar_verf = xprt->xp_verf;
420 	rply.acpted_rply.ar_stat = SYSTEM_ERR;
421 	SVC_REPLY(xprt, &rply);
422 }
423 
424 /*
425  * Authentication error reply
426  */
427 void
428 svcerr_auth(SVCXPRT *xprt, enum auth_stat why)
429 {
430 	struct rpc_msg rply;
431 
432 	rply.rm_direction = REPLY;
433 	rply.rm_reply.rp_stat = MSG_DENIED;
434 	rply.rjcted_rply.rj_stat = AUTH_ERROR;
435 	rply.rjcted_rply.rj_why = why;
436 	SVC_REPLY(xprt, &rply);
437 }
438 
439 /*
440  * Auth too weak error reply
441  */
442 void
443 svcerr_weakauth(SVCXPRT *xprt)
444 {
445 
446 	svcerr_auth(xprt, AUTH_TOOWEAK);
447 }
448 
449 /*
450  * Program unavailable error reply
451  */
452 void
453 svcerr_noprog(SVCXPRT *xprt)
454 {
455 	struct rpc_msg rply;
456 
457 	rply.rm_direction = REPLY;
458 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
459 	rply.acpted_rply.ar_verf = xprt->xp_verf;
460 	rply.acpted_rply.ar_stat = PROG_UNAVAIL;
461 	SVC_REPLY(xprt, &rply);
462 }
463 
464 /*
465  * Program version mismatch error reply
466  */
467 void
468 svcerr_progvers(SVCXPRT *xprt, u_long low_vers, u_long high_vers)
469 {
470 	struct rpc_msg rply;
471 
472 	rply.rm_direction = REPLY;
473 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
474 	rply.acpted_rply.ar_verf = xprt->xp_verf;
475 	rply.acpted_rply.ar_stat = PROG_MISMATCH;
476 	rply.acpted_rply.ar_vers.low = low_vers;
477 	rply.acpted_rply.ar_vers.high = high_vers;
478 	SVC_REPLY(xprt, &rply);
479 }
480 
481 /* ******************* SERVER INPUT STUFF ******************* */
482 
483 /*
484  * Get server side input from some transport.
485  *
486  * Statement of authentication parameters management:
487  * This function owns and manages all authentication parameters, specifically
488  * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
489  * the "cooked" credentials (rqst->rq_clntcred).
490  * However, this function does not know the structure of the cooked
491  * credentials, so it make the following assumptions:
492  *   a) the structure is contiguous (no pointers), and
493  *   b) the cred structure size does not exceed RQCRED_SIZE bytes.
494  * In all events, all three parameters are freed upon exit from this routine.
495  * The storage is trivially management on the call stack in user land, but
496  * is mallocated in kernel land.
497  */
498 
499 void
500 svc_getreq(int rdfds)
501 {
502 	int bit;
503 
504 	for (; (bit = ffs(rdfds)); rdfds ^= (1 << (bit - 1)))
505 		svc_getreq_common(bit - 1);
506 }
507 
508 void
509 svc_getreqset(fd_set *readfds)
510 {
511 	svc_getreqset2(readfds, FD_SETSIZE);
512 }
513 
514 void
515 svc_getreqset2(fd_set *readfds, int width)
516 {
517 	fd_mask mask, *maskp;
518 	int bit, sock;
519 
520 	maskp = readfds->fds_bits;
521 	for (sock = 0; sock < width; sock += NFDBITS) {
522 		for (mask = *maskp++; (bit = ffs(mask));
523 		    mask ^= (1 << (bit - 1)))
524 			svc_getreq_common(sock + bit - 1);
525 	}
526 }
527 
528 void
529 svc_getreq_poll(struct pollfd *pfd, const int nready)
530 {
531 	int i, n;
532 
533 	for (n = nready, i = 0; n > 0; i++) {
534 		if (pfd[i].fd == -1)
535 			continue;
536 		if (pfd[i].revents != 0)
537 			n--;
538 		if ((pfd[i].revents & (POLLIN | POLLHUP)) == 0)
539 			continue;
540 		svc_getreq_common(pfd[i].fd);
541 	}
542 }
543 
544 void
545 svc_getreq_common(int fd)
546 {
547 	enum xprt_stat stat;
548 	struct rpc_msg msg;
549 	int prog_found;
550 	u_long low_vers;
551 	u_long high_vers;
552 	struct svc_req r;
553 	SVCXPRT *xprt;
554 	char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
555 
556 	msg.rm_call.cb_cred.oa_base = cred_area;
557 	msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
558 	r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
559 
560 	/* sock has input waiting */
561 	xprt = xports[fd];
562 	if (xprt == NULL)
563 		/* But do we control the fd? */
564 		return;
565 	/* now receive msgs from xprtprt (support batch calls) */
566 	do {
567 		if (SVC_RECV(xprt, &msg)) {
568 			/* find the exported program and call it */
569 			struct svc_callout *s;
570 			enum auth_stat why;
571 
572 			r.rq_xprt = xprt;
573 			r.rq_prog = msg.rm_call.cb_prog;
574 			r.rq_vers = msg.rm_call.cb_vers;
575 			r.rq_proc = msg.rm_call.cb_proc;
576 			r.rq_cred = msg.rm_call.cb_cred;
577 			/* first authenticate the message */
578 			if ((why= _authenticate(&r, &msg)) != AUTH_OK) {
579 				svcerr_auth(xprt, why);
580 				goto call_done;
581 			}
582 			/* now match message with a registered service*/
583 			prog_found = FALSE;
584 			low_vers = (u_long) -1;
585 			high_vers = 0;
586 			for (s = svc_head; s != NULL; s = s->sc_next) {
587 				if (s->sc_prog == r.rq_prog) {
588 					if (s->sc_vers == r.rq_vers) {
589 						(*s->sc_dispatch)(&r, xprt);
590 						goto call_done;
591 					}  /* found correct version */
592 					prog_found = TRUE;
593 					if (s->sc_vers < low_vers)
594 						low_vers = s->sc_vers;
595 					if (s->sc_vers > high_vers)
596 						high_vers = s->sc_vers;
597 				}   /* found correct program */
598 			}
599 			/*
600 			 * if we got here, the program or version
601 			 * is not served ...
602 			 */
603 			if (prog_found)
604 				svcerr_progvers(xprt, low_vers, high_vers);
605 			else
606 				 svcerr_noprog(xprt);
607 			/* Fall through to ... */
608 		}
609 	call_done:
610 		if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
611 			SVC_DESTROY(xprt);
612 			break;
613 		}
614 	} while (stat == XPRT_MOREREQS);
615 }
616