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