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