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