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