svc.c revision 1.28.8.2 1 1.28.8.2 christos /* $NetBSD: svc.c,v 1.28.8.2 2008/04/25 17:44:45 christos Exp $ */
2 1.28.8.2 christos
3 1.28.8.2 christos /*
4 1.28.8.2 christos * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5 1.28.8.2 christos * unrestricted use provided that this legend is included on all tape
6 1.28.8.2 christos * media and as a part of the software program in whole or part. Users
7 1.28.8.2 christos * may copy or modify Sun RPC without charge, but are not authorized
8 1.28.8.2 christos * to license or distribute it to anyone else except as part of a product or
9 1.28.8.2 christos * program developed by the user.
10 1.28.8.2 christos *
11 1.28.8.2 christos * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12 1.28.8.2 christos * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13 1.28.8.2 christos * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14 1.28.8.2 christos *
15 1.28.8.2 christos * Sun RPC is provided with no support and without any obligation on the
16 1.28.8.2 christos * part of Sun Microsystems, Inc. to assist in its use, correction,
17 1.28.8.2 christos * modification or enhancement.
18 1.28.8.2 christos *
19 1.28.8.2 christos * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20 1.28.8.2 christos * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21 1.28.8.2 christos * OR ANY PART THEREOF.
22 1.28.8.2 christos *
23 1.28.8.2 christos * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24 1.28.8.2 christos * or profits or other special, indirect and consequential damages, even if
25 1.28.8.2 christos * Sun has been advised of the possibility of such damages.
26 1.28.8.2 christos *
27 1.28.8.2 christos * Sun Microsystems, Inc.
28 1.28.8.2 christos * 2550 Garcia Avenue
29 1.28.8.2 christos * Mountain View, California 94043
30 1.28.8.2 christos */
31 1.28.8.2 christos
32 1.28.8.2 christos #include <sys/cdefs.h>
33 1.28.8.2 christos #if defined(LIBC_SCCS) && !defined(lint)
34 1.28.8.2 christos #if 0
35 1.28.8.2 christos static char *sccsid = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";
36 1.28.8.2 christos static char *sccsid = "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC";
37 1.28.8.2 christos #else
38 1.28.8.2 christos __RCSID("$NetBSD: svc.c,v 1.28.8.2 2008/04/25 17:44:45 christos Exp $");
39 1.28.8.2 christos #endif
40 1.28.8.2 christos #endif
41 1.28.8.2 christos
42 1.28.8.2 christos /*
43 1.28.8.2 christos * svc.c, Server-side remote procedure call interface.
44 1.28.8.2 christos *
45 1.28.8.2 christos * There are two sets of procedures here. The xprt routines are
46 1.28.8.2 christos * for handling transport handles. The svc routines handle the
47 1.28.8.2 christos * list of service routines.
48 1.28.8.2 christos *
49 1.28.8.2 christos * Copyright (C) 1984, Sun Microsystems, Inc.
50 1.28.8.2 christos */
51 1.28.8.2 christos
52 1.28.8.2 christos #include "namespace.h"
53 1.28.8.2 christos #include "reentrant.h"
54 1.28.8.2 christos #include <sys/types.h>
55 1.28.8.2 christos #include <sys/poll.h>
56 1.28.8.2 christos #include <assert.h>
57 1.28.8.2 christos #include <errno.h>
58 1.28.8.2 christos #include <stdlib.h>
59 1.28.8.2 christos #include <string.h>
60 1.28.8.2 christos #include <err.h>
61 1.28.8.2 christos
62 1.28.8.2 christos #include <rpc/rpc.h>
63 1.28.8.2 christos #ifdef PORTMAP
64 1.28.8.2 christos #include <rpc/pmap_clnt.h>
65 1.28.8.2 christos #endif
66 1.28.8.2 christos
67 1.28.8.2 christos #include "rpc_internal.h"
68 1.28.8.2 christos
69 1.28.8.2 christos #ifdef __weak_alias
70 1.28.8.2 christos __weak_alias(svc_getreq,_svc_getreq)
71 1.28.8.2 christos __weak_alias(svc_getreqset,_svc_getreqset)
72 1.28.8.2 christos __weak_alias(svc_getreq_common,_svc_getreq_common)
73 1.28.8.2 christos __weak_alias(svc_register,_svc_register)
74 1.28.8.2 christos __weak_alias(svc_reg,_svc_reg)
75 1.28.8.2 christos __weak_alias(svc_unreg,_svc_unreg)
76 1.28.8.2 christos __weak_alias(svc_sendreply,_svc_sendreply)
77 1.28.8.2 christos __weak_alias(svc_unregister,_svc_unregister)
78 1.28.8.2 christos __weak_alias(svcerr_auth,_svcerr_auth)
79 1.28.8.2 christos __weak_alias(svcerr_decode,_svcerr_decode)
80 1.28.8.2 christos __weak_alias(svcerr_noproc,_svcerr_noproc)
81 1.28.8.2 christos __weak_alias(svcerr_noprog,_svcerr_noprog)
82 1.28.8.2 christos __weak_alias(svcerr_progvers,_svcerr_progvers)
83 1.28.8.2 christos __weak_alias(svcerr_systemerr,_svcerr_systemerr)
84 1.28.8.2 christos __weak_alias(svcerr_weakauth,_svcerr_weakauth)
85 1.28.8.2 christos __weak_alias(xprt_register,_xprt_register)
86 1.28.8.2 christos __weak_alias(xprt_unregister,_xprt_unregister)
87 1.28.8.2 christos __weak_alias(rpc_control,_rpc_control)
88 1.28.8.2 christos #endif
89 1.28.8.2 christos
90 1.28.8.2 christos SVCXPRT **__svc_xports;
91 1.28.8.2 christos int __svc_maxrec;
92 1.28.8.2 christos
93 1.28.8.2 christos #define RQCRED_SIZE 400 /* this size is excessive */
94 1.28.8.2 christos
95 1.28.8.2 christos #define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */
96 1.28.8.2 christos #define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
97 1.28.8.2 christos
98 1.28.8.2 christos #define max(a, b) (a > b ? a : b)
99 1.28.8.2 christos
100 1.28.8.2 christos /*
101 1.28.8.2 christos * The services list
102 1.28.8.2 christos * Each entry represents a set of procedures (an rpc program).
103 1.28.8.2 christos * The dispatch routine takes request structs and runs the
104 1.28.8.2 christos * apropriate procedure.
105 1.28.8.2 christos */
106 1.28.8.2 christos static struct svc_callout {
107 1.28.8.2 christos struct svc_callout *sc_next;
108 1.28.8.2 christos rpcprog_t sc_prog;
109 1.28.8.2 christos rpcvers_t sc_vers;
110 1.28.8.2 christos char *sc_netid;
111 1.28.8.2 christos void (*sc_dispatch) __P((struct svc_req *, SVCXPRT *));
112 1.28.8.2 christos } *svc_head;
113 1.28.8.2 christos
114 1.28.8.2 christos #ifdef _REENTRANT
115 1.28.8.2 christos extern rwlock_t svc_lock;
116 1.28.8.2 christos extern rwlock_t svc_fd_lock;
117 1.28.8.2 christos #endif
118 1.28.8.2 christos
119 1.28.8.2 christos static struct svc_callout *svc_find __P((rpcprog_t, rpcvers_t,
120 1.28.8.2 christos struct svc_callout **, char *));
121 1.28.8.2 christos static void __xprt_do_unregister __P((SVCXPRT *xprt, bool_t dolock));
122 1.28.8.2 christos
123 1.28.8.2 christos /* *************** SVCXPRT related stuff **************** */
124 1.28.8.2 christos
125 1.28.8.2 christos /*
126 1.28.8.2 christos * Activate a transport handle.
127 1.28.8.2 christos */
128 1.28.8.2 christos void
129 1.28.8.2 christos xprt_register(xprt)
130 1.28.8.2 christos SVCXPRT *xprt;
131 1.28.8.2 christos {
132 1.28.8.2 christos int sock;
133 1.28.8.2 christos
134 1.28.8.2 christos _DIAGASSERT(xprt != NULL);
135 1.28.8.2 christos
136 1.28.8.2 christos sock = xprt->xp_fd;
137 1.28.8.2 christos
138 1.28.8.2 christos rwlock_wrlock(&svc_fd_lock);
139 1.28.8.2 christos if (__svc_xports == NULL) {
140 1.28.8.2 christos __svc_xports = mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
141 1.28.8.2 christos if (__svc_xports == NULL) {
142 1.28.8.2 christos warn("xprt_register");
143 1.28.8.2 christos goto out;
144 1.28.8.2 christos }
145 1.28.8.2 christos memset(__svc_xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *));
146 1.28.8.2 christos }
147 1.28.8.2 christos if (sock < FD_SETSIZE) {
148 1.28.8.2 christos __svc_xports[sock] = xprt;
149 1.28.8.2 christos FD_SET(sock, &svc_fdset);
150 1.28.8.2 christos svc_maxfd = max(svc_maxfd, sock);
151 1.28.8.2 christos }
152 1.28.8.2 christos out:
153 1.28.8.2 christos rwlock_unlock(&svc_fd_lock);
154 1.28.8.2 christos }
155 1.28.8.2 christos
156 1.28.8.2 christos void
157 1.28.8.2 christos xprt_unregister(SVCXPRT *xprt)
158 1.28.8.2 christos {
159 1.28.8.2 christos __xprt_do_unregister(xprt, TRUE);
160 1.28.8.2 christos }
161 1.28.8.2 christos
162 1.28.8.2 christos void
163 1.28.8.2 christos __xprt_unregister_unlocked(SVCXPRT *xprt)
164 1.28.8.2 christos {
165 1.28.8.2 christos __xprt_do_unregister(xprt, FALSE);
166 1.28.8.2 christos }
167 1.28.8.2 christos
168 1.28.8.2 christos /*
169 1.28.8.2 christos * De-activate a transport handle.
170 1.28.8.2 christos */
171 1.28.8.2 christos static void
172 1.28.8.2 christos __xprt_do_unregister(xprt, dolock)
173 1.28.8.2 christos SVCXPRT *xprt;
174 1.28.8.2 christos bool_t dolock;
175 1.28.8.2 christos {
176 1.28.8.2 christos int sock;
177 1.28.8.2 christos
178 1.28.8.2 christos _DIAGASSERT(xprt != NULL);
179 1.28.8.2 christos
180 1.28.8.2 christos sock = xprt->xp_fd;
181 1.28.8.2 christos
182 1.28.8.2 christos if (dolock)
183 1.28.8.2 christos rwlock_wrlock(&svc_fd_lock);
184 1.28.8.2 christos if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) {
185 1.28.8.2 christos __svc_xports[sock] = NULL;
186 1.28.8.2 christos FD_CLR(sock, &svc_fdset);
187 1.28.8.2 christos if (sock >= svc_maxfd) {
188 1.28.8.2 christos for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--)
189 1.28.8.2 christos if (__svc_xports[svc_maxfd])
190 1.28.8.2 christos break;
191 1.28.8.2 christos }
192 1.28.8.2 christos }
193 1.28.8.2 christos if (dolock)
194 1.28.8.2 christos rwlock_unlock(&svc_fd_lock);
195 1.28.8.2 christos }
196 1.28.8.2 christos
197 1.28.8.2 christos /*
198 1.28.8.2 christos * Add a service program to the callout list.
199 1.28.8.2 christos * The dispatch routine will be called when a rpc request for this
200 1.28.8.2 christos * program number comes in.
201 1.28.8.2 christos */
202 1.28.8.2 christos bool_t
203 1.28.8.2 christos svc_reg(xprt, prog, vers, dispatch, nconf)
204 1.28.8.2 christos SVCXPRT *xprt;
205 1.28.8.2 christos const rpcprog_t prog;
206 1.28.8.2 christos const rpcvers_t vers;
207 1.28.8.2 christos void (*dispatch) __P((struct svc_req *, SVCXPRT *));
208 1.28.8.2 christos const struct netconfig *nconf;
209 1.28.8.2 christos {
210 1.28.8.2 christos bool_t dummy;
211 1.28.8.2 christos struct svc_callout *prev;
212 1.28.8.2 christos struct svc_callout *s;
213 1.28.8.2 christos struct netconfig *tnconf;
214 1.28.8.2 christos char *netid = NULL;
215 1.28.8.2 christos int flag = 0;
216 1.28.8.2 christos
217 1.28.8.2 christos _DIAGASSERT(xprt != NULL);
218 1.28.8.2 christos /* XXX: dispatch may be NULL ??? */
219 1.28.8.2 christos
220 1.28.8.2 christos /* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
221 1.28.8.2 christos
222 1.28.8.2 christos if (xprt->xp_netid) {
223 1.28.8.2 christos netid = strdup(xprt->xp_netid);
224 1.28.8.2 christos flag = 1;
225 1.28.8.2 christos } else if (nconf && nconf->nc_netid) {
226 1.28.8.2 christos netid = strdup(nconf->nc_netid);
227 1.28.8.2 christos flag = 1;
228 1.28.8.2 christos } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) {
229 1.28.8.2 christos netid = strdup(tnconf->nc_netid);
230 1.28.8.2 christos flag = 1;
231 1.28.8.2 christos freenetconfigent(tnconf);
232 1.28.8.2 christos } /* must have been created with svc_raw_create */
233 1.28.8.2 christos if ((netid == NULL) && (flag == 1)) {
234 1.28.8.2 christos return (FALSE);
235 1.28.8.2 christos }
236 1.28.8.2 christos
237 1.28.8.2 christos rwlock_wrlock(&svc_lock);
238 1.28.8.2 christos if ((s = svc_find(prog, vers, &prev, netid)) != NULL) {
239 1.28.8.2 christos if (netid)
240 1.28.8.2 christos free(netid);
241 1.28.8.2 christos if (s->sc_dispatch == dispatch)
242 1.28.8.2 christos goto rpcb_it; /* he is registering another xptr */
243 1.28.8.2 christos rwlock_unlock(&svc_lock);
244 1.28.8.2 christos return (FALSE);
245 1.28.8.2 christos }
246 1.28.8.2 christos s = mem_alloc(sizeof (struct svc_callout));
247 1.28.8.2 christos if (s == NULL) {
248 1.28.8.2 christos if (netid)
249 1.28.8.2 christos free(netid);
250 1.28.8.2 christos rwlock_unlock(&svc_lock);
251 1.28.8.2 christos return (FALSE);
252 1.28.8.2 christos }
253 1.28.8.2 christos
254 1.28.8.2 christos if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
255 1.28.8.2 christos if ((((SVCXPRT *) xprt)->xp_netid = strdup(netid)) == NULL) {
256 1.28.8.2 christos warn("svc_reg");
257 1.28.8.2 christos mem_free(s, sizeof(struct svc_callout));
258 1.28.8.2 christos rwlock_unlock(&svc_lock);
259 1.28.8.2 christos return FALSE;
260 1.28.8.2 christos }
261 1.28.8.2 christos
262 1.28.8.2 christos s->sc_prog = prog;
263 1.28.8.2 christos s->sc_vers = vers;
264 1.28.8.2 christos s->sc_dispatch = dispatch;
265 1.28.8.2 christos s->sc_netid = netid;
266 1.28.8.2 christos s->sc_next = svc_head;
267 1.28.8.2 christos svc_head = s;
268 1.28.8.2 christos
269 1.28.8.2 christos rpcb_it:
270 1.28.8.2 christos rwlock_unlock(&svc_lock);
271 1.28.8.2 christos /* now register the information with the local binder service */
272 1.28.8.2 christos if (nconf) {
273 1.28.8.2 christos dummy = rpcb_set(prog, vers, __UNCONST(nconf),
274 1.28.8.2 christos &((SVCXPRT *) xprt)->xp_ltaddr);
275 1.28.8.2 christos return (dummy);
276 1.28.8.2 christos }
277 1.28.8.2 christos return (TRUE);
278 1.28.8.2 christos }
279 1.28.8.2 christos
280 1.28.8.2 christos /*
281 1.28.8.2 christos * Remove a service program from the callout list.
282 1.28.8.2 christos */
283 1.28.8.2 christos void
284 1.28.8.2 christos svc_unreg(prog, vers)
285 1.28.8.2 christos const rpcprog_t prog;
286 1.28.8.2 christos const rpcvers_t vers;
287 1.28.8.2 christos {
288 1.28.8.2 christos struct svc_callout *prev;
289 1.28.8.2 christos struct svc_callout *s;
290 1.28.8.2 christos
291 1.28.8.2 christos /* unregister the information anyway */
292 1.28.8.2 christos (void) rpcb_unset(prog, vers, NULL);
293 1.28.8.2 christos rwlock_wrlock(&svc_lock);
294 1.28.8.2 christos while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) {
295 1.28.8.2 christos if (prev == NULL) {
296 1.28.8.2 christos svc_head = s->sc_next;
297 1.28.8.2 christos } else {
298 1.28.8.2 christos prev->sc_next = s->sc_next;
299 1.28.8.2 christos }
300 1.28.8.2 christos s->sc_next = NULL;
301 1.28.8.2 christos if (s->sc_netid)
302 1.28.8.2 christos mem_free(s->sc_netid, sizeof (s->sc_netid) + 1);
303 1.28.8.2 christos mem_free(s, sizeof (struct svc_callout));
304 1.28.8.2 christos }
305 1.28.8.2 christos rwlock_unlock(&svc_lock);
306 1.28.8.2 christos }
307 1.28.8.2 christos
308 1.28.8.2 christos /* ********************** CALLOUT list related stuff ************* */
309 1.28.8.2 christos
310 1.28.8.2 christos #ifdef PORTMAP
311 1.28.8.2 christos /*
312 1.28.8.2 christos * Add a service program to the callout list.
313 1.28.8.2 christos * The dispatch routine will be called when a rpc request for this
314 1.28.8.2 christos * program number comes in.
315 1.28.8.2 christos */
316 1.28.8.2 christos bool_t
317 1.28.8.2 christos svc_register(xprt, prog, vers, dispatch, protocol)
318 1.28.8.2 christos SVCXPRT *xprt;
319 1.28.8.2 christos u_long prog;
320 1.28.8.2 christos u_long vers;
321 1.28.8.2 christos void (*dispatch) __P((struct svc_req *, SVCXPRT *));
322 1.28.8.2 christos int protocol;
323 1.28.8.2 christos {
324 1.28.8.2 christos struct svc_callout *prev;
325 1.28.8.2 christos struct svc_callout *s;
326 1.28.8.2 christos
327 1.28.8.2 christos _DIAGASSERT(xprt != NULL);
328 1.28.8.2 christos _DIAGASSERT(dispatch != NULL);
329 1.28.8.2 christos
330 1.28.8.2 christos if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) !=
331 1.28.8.2 christos NULL) {
332 1.28.8.2 christos if (s->sc_dispatch == dispatch)
333 1.28.8.2 christos goto pmap_it; /* he is registering another xptr */
334 1.28.8.2 christos return (FALSE);
335 1.28.8.2 christos }
336 1.28.8.2 christos s = mem_alloc(sizeof(struct svc_callout));
337 1.28.8.2 christos if (s == NULL) {
338 1.28.8.2 christos return (FALSE);
339 1.28.8.2 christos }
340 1.28.8.2 christos s->sc_prog = (rpcprog_t)prog;
341 1.28.8.2 christos s->sc_vers = (rpcvers_t)vers;
342 1.28.8.2 christos s->sc_dispatch = dispatch;
343 1.28.8.2 christos s->sc_next = svc_head;
344 1.28.8.2 christos svc_head = s;
345 1.28.8.2 christos pmap_it:
346 1.28.8.2 christos /* now register the information with the local binder service */
347 1.28.8.2 christos if (protocol) {
348 1.28.8.2 christos return (pmap_set(prog, vers, protocol, xprt->xp_port));
349 1.28.8.2 christos }
350 1.28.8.2 christos return (TRUE);
351 1.28.8.2 christos }
352 1.28.8.2 christos
353 1.28.8.2 christos /*
354 1.28.8.2 christos * Remove a service program from the callout list.
355 1.28.8.2 christos */
356 1.28.8.2 christos void
357 1.28.8.2 christos svc_unregister(prog, vers)
358 1.28.8.2 christos u_long prog;
359 1.28.8.2 christos u_long vers;
360 1.28.8.2 christos {
361 1.28.8.2 christos struct svc_callout *prev;
362 1.28.8.2 christos struct svc_callout *s;
363 1.28.8.2 christos
364 1.28.8.2 christos if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) ==
365 1.28.8.2 christos NULL)
366 1.28.8.2 christos return;
367 1.28.8.2 christos if (prev == NULL) {
368 1.28.8.2 christos svc_head = s->sc_next;
369 1.28.8.2 christos } else {
370 1.28.8.2 christos prev->sc_next = s->sc_next;
371 1.28.8.2 christos }
372 1.28.8.2 christos s->sc_next = NULL;
373 1.28.8.2 christos mem_free(s, sizeof(struct svc_callout));
374 1.28.8.2 christos /* now unregister the information with the local binder service */
375 1.28.8.2 christos (void)pmap_unset(prog, vers);
376 1.28.8.2 christos }
377 1.28.8.2 christos #endif /* PORTMAP */
378 1.28.8.2 christos
379 1.28.8.2 christos /*
380 1.28.8.2 christos * Search the callout list for a program number, return the callout
381 1.28.8.2 christos * struct.
382 1.28.8.2 christos */
383 1.28.8.2 christos static struct svc_callout *
384 1.28.8.2 christos svc_find(prog, vers, prev, netid)
385 1.28.8.2 christos rpcprog_t prog;
386 1.28.8.2 christos rpcvers_t vers;
387 1.28.8.2 christos struct svc_callout **prev;
388 1.28.8.2 christos char *netid;
389 1.28.8.2 christos {
390 1.28.8.2 christos struct svc_callout *s, *p;
391 1.28.8.2 christos
392 1.28.8.2 christos _DIAGASSERT(prev != NULL);
393 1.28.8.2 christos /* netid is handled below */
394 1.28.8.2 christos
395 1.28.8.2 christos p = NULL;
396 1.28.8.2 christos for (s = svc_head; s != NULL; s = s->sc_next) {
397 1.28.8.2 christos if (((s->sc_prog == prog) && (s->sc_vers == vers)) &&
398 1.28.8.2 christos ((netid == NULL) || (s->sc_netid == NULL) ||
399 1.28.8.2 christos (strcmp(netid, s->sc_netid) == 0)))
400 1.28.8.2 christos break;
401 1.28.8.2 christos p = s;
402 1.28.8.2 christos }
403 1.28.8.2 christos *prev = p;
404 1.28.8.2 christos return (s);
405 1.28.8.2 christos }
406 1.28.8.2 christos
407 1.28.8.2 christos /* ******************* REPLY GENERATION ROUTINES ************ */
408 1.28.8.2 christos
409 1.28.8.2 christos /*
410 1.28.8.2 christos * Send a reply to an rpc request
411 1.28.8.2 christos */
412 1.28.8.2 christos bool_t
413 1.28.8.2 christos svc_sendreply(xprt, xdr_results, xdr_location)
414 1.28.8.2 christos SVCXPRT *xprt;
415 1.28.8.2 christos xdrproc_t xdr_results;
416 1.28.8.2 christos const char *xdr_location;
417 1.28.8.2 christos {
418 1.28.8.2 christos struct rpc_msg rply;
419 1.28.8.2 christos
420 1.28.8.2 christos _DIAGASSERT(xprt != NULL);
421 1.28.8.2 christos
422 1.28.8.2 christos rply.rm_direction = REPLY;
423 1.28.8.2 christos rply.rm_reply.rp_stat = MSG_ACCEPTED;
424 1.28.8.2 christos rply.acpted_rply.ar_verf = xprt->xp_verf;
425 1.28.8.2 christos rply.acpted_rply.ar_stat = SUCCESS;
426 1.28.8.2 christos rply.acpted_rply.ar_results.where = xdr_location;
427 1.28.8.2 christos rply.acpted_rply.ar_results.proc = xdr_results;
428 1.28.8.2 christos return (SVC_REPLY(xprt, &rply));
429 1.28.8.2 christos }
430 1.28.8.2 christos
431 1.28.8.2 christos /*
432 1.28.8.2 christos * No procedure error reply
433 1.28.8.2 christos */
434 1.28.8.2 christos void
435 1.28.8.2 christos svcerr_noproc(xprt)
436 1.28.8.2 christos SVCXPRT *xprt;
437 1.28.8.2 christos {
438 1.28.8.2 christos struct rpc_msg rply;
439 1.28.8.2 christos
440 1.28.8.2 christos _DIAGASSERT(xprt != NULL);
441 1.28.8.2 christos
442 1.28.8.2 christos rply.rm_direction = REPLY;
443 1.28.8.2 christos rply.rm_reply.rp_stat = MSG_ACCEPTED;
444 1.28.8.2 christos rply.acpted_rply.ar_verf = xprt->xp_verf;
445 1.28.8.2 christos rply.acpted_rply.ar_stat = PROC_UNAVAIL;
446 1.28.8.2 christos SVC_REPLY(xprt, &rply);
447 1.28.8.2 christos }
448 1.28.8.2 christos
449 1.28.8.2 christos /*
450 1.28.8.2 christos * Can't decode args error reply
451 1.28.8.2 christos */
452 1.28.8.2 christos void
453 1.28.8.2 christos svcerr_decode(xprt)
454 1.28.8.2 christos SVCXPRT *xprt;
455 1.28.8.2 christos {
456 1.28.8.2 christos struct rpc_msg rply;
457 1.28.8.2 christos
458 1.28.8.2 christos _DIAGASSERT(xprt != NULL);
459 1.28.8.2 christos
460 1.28.8.2 christos rply.rm_direction = REPLY;
461 1.28.8.2 christos rply.rm_reply.rp_stat = MSG_ACCEPTED;
462 1.28.8.2 christos rply.acpted_rply.ar_verf = xprt->xp_verf;
463 1.28.8.2 christos rply.acpted_rply.ar_stat = GARBAGE_ARGS;
464 1.28.8.2 christos SVC_REPLY(xprt, &rply);
465 1.28.8.2 christos }
466 1.28.8.2 christos
467 1.28.8.2 christos /*
468 1.28.8.2 christos * Some system error
469 1.28.8.2 christos */
470 1.28.8.2 christos void
471 1.28.8.2 christos svcerr_systemerr(xprt)
472 1.28.8.2 christos SVCXPRT *xprt;
473 1.28.8.2 christos {
474 1.28.8.2 christos struct rpc_msg rply;
475 1.28.8.2 christos
476 1.28.8.2 christos _DIAGASSERT(xprt != NULL);
477 1.28.8.2 christos
478 1.28.8.2 christos rply.rm_direction = REPLY;
479 1.28.8.2 christos rply.rm_reply.rp_stat = MSG_ACCEPTED;
480 1.28.8.2 christos rply.acpted_rply.ar_verf = xprt->xp_verf;
481 1.28.8.2 christos rply.acpted_rply.ar_stat = SYSTEM_ERR;
482 1.28.8.2 christos SVC_REPLY(xprt, &rply);
483 1.28.8.2 christos }
484 1.28.8.2 christos
485 1.28.8.2 christos #if 0
486 1.28.8.2 christos /*
487 1.28.8.2 christos * Tell RPC package to not complain about version errors to the client. This
488 1.28.8.2 christos * is useful when revving broadcast protocols that sit on a fixed address.
489 1.28.8.2 christos * There is really one (or should be only one) example of this kind of
490 1.28.8.2 christos * protocol: the portmapper (or rpc binder).
491 1.28.8.2 christos */
492 1.28.8.2 christos void
493 1.28.8.2 christos __svc_versquiet_on(xprt)
494 1.28.8.2 christos SVCXPRT *xprt;
495 1.28.8.2 christos {
496 1.28.8.2 christos u_long tmp;
497 1.28.8.2 christos
498 1.28.8.2 christos _DIAGASSERT(xprt != NULL);
499 1.28.8.2 christos
500 1.28.8.2 christos tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET;
501 1.28.8.2 christos xprt->xp_p3 = (caddr_t) tmp;
502 1.28.8.2 christos }
503 1.28.8.2 christos
504 1.28.8.2 christos void
505 1.28.8.2 christos __svc_versquiet_off(xprt)
506 1.28.8.2 christos SVCXPRT *xprt;
507 1.28.8.2 christos {
508 1.28.8.2 christos u_long tmp;
509 1.28.8.2 christos
510 1.28.8.2 christos _DIAGASSERT(xprt != NULL);
511 1.28.8.2 christos
512 1.28.8.2 christos tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET;
513 1.28.8.2 christos xprt->xp_p3 = (caddr_t) tmp;
514 1.28.8.2 christos }
515 1.28.8.2 christos
516 1.28.8.2 christos void
517 1.28.8.2 christos svc_versquiet(xprt)
518 1.28.8.2 christos SVCXPRT *xprt;
519 1.28.8.2 christos {
520 1.28.8.2 christos __svc_versquiet_on(xprt);
521 1.28.8.2 christos }
522 1.28.8.2 christos
523 1.28.8.2 christos int
524 1.28.8.2 christos __svc_versquiet_get(xprt)
525 1.28.8.2 christos SVCXPRT *xprt;
526 1.28.8.2 christos {
527 1.28.8.2 christos
528 1.28.8.2 christos _DIAGASSERT(xprt != NULL);
529 1.28.8.2 christos
530 1.28.8.2 christos return ((int) xprt->xp_p3) & SVC_VERSQUIET;
531 1.28.8.2 christos }
532 1.28.8.2 christos #endif
533 1.28.8.2 christos
534 1.28.8.2 christos /*
535 1.28.8.2 christos * Authentication error reply
536 1.28.8.2 christos */
537 1.28.8.2 christos void
538 1.28.8.2 christos svcerr_auth(xprt, why)
539 1.28.8.2 christos SVCXPRT *xprt;
540 1.28.8.2 christos enum auth_stat why;
541 1.28.8.2 christos {
542 1.28.8.2 christos struct rpc_msg rply;
543 1.28.8.2 christos
544 1.28.8.2 christos _DIAGASSERT(xprt != NULL);
545 1.28.8.2 christos
546 1.28.8.2 christos rply.rm_direction = REPLY;
547 1.28.8.2 christos rply.rm_reply.rp_stat = MSG_DENIED;
548 1.28.8.2 christos rply.rjcted_rply.rj_stat = AUTH_ERROR;
549 1.28.8.2 christos rply.rjcted_rply.rj_why = why;
550 1.28.8.2 christos SVC_REPLY(xprt, &rply);
551 1.28.8.2 christos }
552 1.28.8.2 christos
553 1.28.8.2 christos /*
554 1.28.8.2 christos * Auth too weak error reply
555 1.28.8.2 christos */
556 1.28.8.2 christos void
557 1.28.8.2 christos svcerr_weakauth(xprt)
558 1.28.8.2 christos SVCXPRT *xprt;
559 1.28.8.2 christos {
560 1.28.8.2 christos
561 1.28.8.2 christos _DIAGASSERT(xprt != NULL);
562 1.28.8.2 christos
563 1.28.8.2 christos svcerr_auth(xprt, AUTH_TOOWEAK);
564 1.28.8.2 christos }
565 1.28.8.2 christos
566 1.28.8.2 christos /*
567 1.28.8.2 christos * Program unavailable error reply
568 1.28.8.2 christos */
569 1.28.8.2 christos void
570 1.28.8.2 christos svcerr_noprog(xprt)
571 1.28.8.2 christos SVCXPRT *xprt;
572 1.28.8.2 christos {
573 1.28.8.2 christos struct rpc_msg rply;
574 1.28.8.2 christos
575 1.28.8.2 christos _DIAGASSERT(xprt != NULL);
576 1.28.8.2 christos
577 1.28.8.2 christos rply.rm_direction = REPLY;
578 1.28.8.2 christos rply.rm_reply.rp_stat = MSG_ACCEPTED;
579 1.28.8.2 christos rply.acpted_rply.ar_verf = xprt->xp_verf;
580 1.28.8.2 christos rply.acpted_rply.ar_stat = PROG_UNAVAIL;
581 1.28.8.2 christos SVC_REPLY(xprt, &rply);
582 1.28.8.2 christos }
583 1.28.8.2 christos
584 1.28.8.2 christos /*
585 1.28.8.2 christos * Program version mismatch error reply
586 1.28.8.2 christos */
587 1.28.8.2 christos void
588 1.28.8.2 christos svcerr_progvers(xprt, low_vers, high_vers)
589 1.28.8.2 christos SVCXPRT *xprt;
590 1.28.8.2 christos rpcvers_t low_vers;
591 1.28.8.2 christos rpcvers_t high_vers;
592 1.28.8.2 christos {
593 1.28.8.2 christos struct rpc_msg rply;
594 1.28.8.2 christos
595 1.28.8.2 christos _DIAGASSERT(xprt != NULL);
596 1.28.8.2 christos
597 1.28.8.2 christos rply.rm_direction = REPLY;
598 1.28.8.2 christos rply.rm_reply.rp_stat = MSG_ACCEPTED;
599 1.28.8.2 christos rply.acpted_rply.ar_verf = xprt->xp_verf;
600 1.28.8.2 christos rply.acpted_rply.ar_stat = PROG_MISMATCH;
601 1.28.8.2 christos rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers;
602 1.28.8.2 christos rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers;
603 1.28.8.2 christos SVC_REPLY(xprt, &rply);
604 1.28.8.2 christos }
605 1.28.8.2 christos
606 1.28.8.2 christos /* ******************* SERVER INPUT STUFF ******************* */
607 1.28.8.2 christos
608 1.28.8.2 christos /*
609 1.28.8.2 christos * Get server side input from some transport.
610 1.28.8.2 christos *
611 1.28.8.2 christos * Statement of authentication parameters management:
612 1.28.8.2 christos * This function owns and manages all authentication parameters, specifically
613 1.28.8.2 christos * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
614 1.28.8.2 christos * the "cooked" credentials (rqst->rq_clntcred).
615 1.28.8.2 christos * However, this function does not know the structure of the cooked
616 1.28.8.2 christos * credentials, so it make the following assumptions:
617 1.28.8.2 christos * a) the structure is contiguous (no pointers), and
618 1.28.8.2 christos * b) the cred structure size does not exceed RQCRED_SIZE bytes.
619 1.28.8.2 christos * In all events, all three parameters are freed upon exit from this routine.
620 1.28.8.2 christos * The storage is trivially management on the call stack in user land, but
621 1.28.8.2 christos * is mallocated in kernel land.
622 1.28.8.2 christos */
623 1.28.8.2 christos
624 1.28.8.2 christos void
625 1.28.8.2 christos svc_getreq(rdfds)
626 1.28.8.2 christos int rdfds;
627 1.28.8.2 christos {
628 1.28.8.2 christos fd_set readfds;
629 1.28.8.2 christos
630 1.28.8.2 christos FD_ZERO(&readfds);
631 1.28.8.2 christos readfds.fds_bits[0] = rdfds;
632 1.28.8.2 christos svc_getreqset(&readfds);
633 1.28.8.2 christos }
634 1.28.8.2 christos
635 1.28.8.2 christos void
636 1.28.8.2 christos svc_getreqset(readfds)
637 1.28.8.2 christos fd_set *readfds;
638 1.28.8.2 christos {
639 1.28.8.2 christos int bit, fd;
640 1.28.8.2 christos int32_t mask, *maskp;
641 1.28.8.2 christos int sock;
642 1.28.8.2 christos
643 1.28.8.2 christos _DIAGASSERT(readfds != NULL);
644 1.28.8.2 christos
645 1.28.8.2 christos maskp = readfds->fds_bits;
646 1.28.8.2 christos for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) {
647 1.28.8.2 christos for (mask = *maskp++; (bit = ffs(mask)) != 0;
648 1.28.8.2 christos mask ^= (1 << (bit - 1))) {
649 1.28.8.2 christos /* sock has input waiting */
650 1.28.8.2 christos fd = sock + bit - 1;
651 1.28.8.2 christos svc_getreq_common(fd);
652 1.28.8.2 christos }
653 1.28.8.2 christos }
654 1.28.8.2 christos }
655 1.28.8.2 christos
656 1.28.8.2 christos void
657 1.28.8.2 christos svc_getreq_common(fd)
658 1.28.8.2 christos int fd;
659 1.28.8.2 christos {
660 1.28.8.2 christos SVCXPRT *xprt;
661 1.28.8.2 christos struct svc_req r;
662 1.28.8.2 christos struct rpc_msg msg;
663 1.28.8.2 christos int prog_found;
664 1.28.8.2 christos rpcvers_t low_vers;
665 1.28.8.2 christos rpcvers_t high_vers;
666 1.28.8.2 christos enum xprt_stat stat;
667 1.28.8.2 christos char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
668 1.28.8.2 christos
669 1.28.8.2 christos msg.rm_call.cb_cred.oa_base = cred_area;
670 1.28.8.2 christos msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
671 1.28.8.2 christos r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
672 1.28.8.2 christos
673 1.28.8.2 christos rwlock_rdlock(&svc_fd_lock);
674 1.28.8.2 christos xprt = __svc_xports[fd];
675 1.28.8.2 christos rwlock_unlock(&svc_fd_lock);
676 1.28.8.2 christos if (xprt == NULL)
677 1.28.8.2 christos /* But do we control sock? */
678 1.28.8.2 christos return;
679 1.28.8.2 christos /* now receive msgs from xprtprt (support batch calls) */
680 1.28.8.2 christos do {
681 1.28.8.2 christos if (SVC_RECV(xprt, &msg)) {
682 1.28.8.2 christos
683 1.28.8.2 christos /* now find the exported program and call it */
684 1.28.8.2 christos struct svc_callout *s;
685 1.28.8.2 christos enum auth_stat why;
686 1.28.8.2 christos
687 1.28.8.2 christos r.rq_xprt = xprt;
688 1.28.8.2 christos r.rq_prog = msg.rm_call.cb_prog;
689 1.28.8.2 christos r.rq_vers = msg.rm_call.cb_vers;
690 1.28.8.2 christos r.rq_proc = msg.rm_call.cb_proc;
691 1.28.8.2 christos r.rq_cred = msg.rm_call.cb_cred;
692 1.28.8.2 christos /* first authenticate the message */
693 1.28.8.2 christos if ((why = _authenticate(&r, &msg)) != AUTH_OK) {
694 1.28.8.2 christos svcerr_auth(xprt, why);
695 1.28.8.2 christos goto call_done;
696 1.28.8.2 christos }
697 1.28.8.2 christos /* now match message with a registered service*/
698 1.28.8.2 christos prog_found = FALSE;
699 1.28.8.2 christos low_vers = (rpcvers_t) -1L;
700 1.28.8.2 christos high_vers = (rpcvers_t) 0L;
701 1.28.8.2 christos for (s = svc_head; s != NULL; s = s->sc_next) {
702 1.28.8.2 christos if (s->sc_prog == r.rq_prog) {
703 1.28.8.2 christos if (s->sc_vers == r.rq_vers) {
704 1.28.8.2 christos (*s->sc_dispatch)(&r, xprt);
705 1.28.8.2 christos goto call_done;
706 1.28.8.2 christos } /* found correct version */
707 1.28.8.2 christos prog_found = TRUE;
708 1.28.8.2 christos if (s->sc_vers < low_vers)
709 1.28.8.2 christos low_vers = s->sc_vers;
710 1.28.8.2 christos if (s->sc_vers > high_vers)
711 1.28.8.2 christos high_vers = s->sc_vers;
712 1.28.8.2 christos } /* found correct program */
713 1.28.8.2 christos }
714 1.28.8.2 christos /*
715 1.28.8.2 christos * if we got here, the program or version
716 1.28.8.2 christos * is not served ...
717 1.28.8.2 christos */
718 1.28.8.2 christos if (prog_found)
719 1.28.8.2 christos svcerr_progvers(xprt, low_vers, high_vers);
720 1.28.8.2 christos else
721 1.28.8.2 christos svcerr_noprog(xprt);
722 1.28.8.2 christos /* Fall through to ... */
723 1.28.8.2 christos }
724 1.28.8.2 christos /*
725 1.28.8.2 christos * Check if the xprt has been disconnected in a
726 1.28.8.2 christos * recursive call in the service dispatch routine.
727 1.28.8.2 christos * If so, then break.
728 1.28.8.2 christos */
729 1.28.8.2 christos rwlock_rdlock(&svc_fd_lock);
730 1.28.8.2 christos if (xprt != __svc_xports[fd]) {
731 1.28.8.2 christos rwlock_unlock(&svc_fd_lock);
732 1.28.8.2 christos break;
733 1.28.8.2 christos }
734 1.28.8.2 christos rwlock_unlock(&svc_fd_lock);
735 1.28.8.2 christos call_done:
736 1.28.8.2 christos if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
737 1.28.8.2 christos SVC_DESTROY(xprt);
738 1.28.8.2 christos break;
739 1.28.8.2 christos }
740 1.28.8.2 christos } while (stat == XPRT_MOREREQS);
741 1.28.8.2 christos }
742 1.28.8.2 christos
743 1.28.8.2 christos
744 1.28.8.2 christos void
745 1.28.8.2 christos svc_getreq_poll(pfdp, pollretval)
746 1.28.8.2 christos struct pollfd *pfdp;
747 1.28.8.2 christos int pollretval;
748 1.28.8.2 christos {
749 1.28.8.2 christos int i;
750 1.28.8.2 christos int fds_found;
751 1.28.8.2 christos
752 1.28.8.2 christos _DIAGASSERT(pfdp != NULL);
753 1.28.8.2 christos
754 1.28.8.2 christos for (i = fds_found = 0; fds_found < pollretval; i++) {
755 1.28.8.2 christos struct pollfd *p = &pfdp[i];
756 1.28.8.2 christos
757 1.28.8.2 christos if (p->revents) {
758 1.28.8.2 christos /* fd has input waiting */
759 1.28.8.2 christos fds_found++;
760 1.28.8.2 christos /*
761 1.28.8.2 christos * We assume that this function is only called
762 1.28.8.2 christos * via someone select()ing from svc_fdset or
763 1.28.8.2 christos * pollts()ing from svc_pollset[]. Thus it's safe
764 1.28.8.2 christos * to handle the POLLNVAL event by simply turning
765 1.28.8.2 christos * the corresponding bit off in svc_fdset. The
766 1.28.8.2 christos * svc_pollset[] array is derived from svc_fdset
767 1.28.8.2 christos * and so will also be updated eventually.
768 1.28.8.2 christos *
769 1.28.8.2 christos * XXX Should we do an xprt_unregister() instead?
770 1.28.8.2 christos */
771 1.28.8.2 christos if (p->revents & POLLNVAL) {
772 1.28.8.2 christos rwlock_wrlock(&svc_fd_lock);
773 1.28.8.2 christos FD_CLR(p->fd, &svc_fdset);
774 1.28.8.2 christos rwlock_unlock(&svc_fd_lock);
775 1.28.8.2 christos } else
776 1.28.8.2 christos svc_getreq_common(p->fd);
777 1.28.8.2 christos }
778 1.28.8.2 christos }
779 1.28.8.2 christos }
780 1.28.8.2 christos
781 1.28.8.2 christos bool_t
782 1.28.8.2 christos rpc_control(int what, void *arg)
783 1.28.8.2 christos {
784 1.28.8.2 christos int val;
785 1.28.8.2 christos
786 1.28.8.2 christos switch (what) {
787 1.28.8.2 christos case RPC_SVC_CONNMAXREC_SET:
788 1.28.8.2 christos val = *(int *)arg;
789 1.28.8.2 christos if (val <= 0)
790 1.28.8.2 christos return FALSE;
791 1.28.8.2 christos __svc_maxrec = val;
792 1.28.8.2 christos return TRUE;
793 1.28.8.2 christos case RPC_SVC_CONNMAXREC_GET:
794 1.28.8.2 christos *(int *)arg = __svc_maxrec;
795 1.28.8.2 christos return TRUE;
796 1.28.8.2 christos default:
797 1.28.8.2 christos break;
798 1.28.8.2 christos }
799 1.28.8.2 christos return FALSE;
800 1.28.8.2 christos }
801