Libinfo-173.tar.gz
[apple/libinfo.git] / lookup.subproj / lu_rpc.c
1 /*
2 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * RPC lookup
27 * Copyright (C) 1989 by NeXT, Inc.
28 */
29
30 #include <rpc/rpc.h>
31 #include <netdb.h>
32 #include <stdlib.h>
33 #include <mach/mach.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <netinet/in.h>
37 #include <pthread.h>
38
39 #include "_lu_types.h"
40 #include "lookup.h"
41 #include "lu_utils.h"
42 #include "lu_overrides.h"
43
44 static pthread_mutex_t _rpc_lock = PTHREAD_MUTEX_INITIALIZER;
45
46 #define RPC_GET_NAME 1
47 #define RPC_GET_NUM 2
48 #define RPC_GET_ENT 3
49
50 static void
51 free_rpc_data(struct rpcent *r)
52 {
53 char **aliases;
54
55 if (r == NULL) return;
56
57 if (r->r_name != NULL) free(r->r_name);
58
59 aliases = r->r_aliases;
60 if (aliases != NULL)
61 {
62 while (*aliases != NULL) free(*aliases++);
63 free(r->r_aliases);
64 }
65 }
66
67 static void
68 free_rpc(struct rpcent *r)
69 {
70 if (r == NULL) return;
71 free_rpc_data(r);
72 free(r);
73 }
74
75 static void
76 free_lu_thread_info_rpc(void *x)
77 {
78 struct lu_thread_info *tdata;
79
80 if (x == NULL) return;
81
82 tdata = (struct lu_thread_info *)x;
83
84 if (tdata->lu_entry != NULL)
85 {
86 free_rpc((struct rpcent *)tdata->lu_entry);
87 tdata->lu_entry = NULL;
88 }
89
90 _lu_data_free_vm_xdr(tdata);
91
92 free(tdata);
93 }
94
95 static struct rpcent *
96 extract_rpc(XDR *xdr)
97 {
98 struct rpcent *r;
99 int i, j, nvals, nkeys, status;
100 char *key, **vals;
101
102 if (xdr == NULL) return NULL;
103
104 if (!xdr_int(xdr, &nkeys)) return NULL;
105
106 r = (struct rpcent *)calloc(1, sizeof(struct rpcent));
107
108 for (i = 0; i < nkeys; i++)
109 {
110 key = NULL;
111 vals = NULL;
112 nvals = 0;
113
114 status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
115 if (status < 0)
116 {
117 free_rpc(r);
118 return NULL;
119 }
120
121 if (nvals == 0)
122 {
123 free(key);
124 continue;
125 }
126
127 j = 0;
128
129 if ((r->r_name == NULL) && (!strcmp("name", key)))
130 {
131 r->r_name = vals[0];
132 if (nvals > 1)
133 {
134 r->r_aliases = (char **)calloc(nvals, sizeof(char *));
135 for (j = 1; j < nvals; j++) r->r_aliases[j-1] = vals[j];
136 }
137 j = nvals;
138 }
139 else if (!strcmp("number", key))
140 {
141 r->r_number= atoi(vals[0]);
142 }
143
144 free(key);
145 if (vals != NULL)
146 {
147 for (; j < nvals; j++) free(vals[j]);
148 free(vals);
149 }
150 }
151
152 if (r->r_name == NULL) r->r_name = strdup("");
153 if (r->r_aliases == NULL) r->r_aliases = (char **)calloc(1, sizeof(char *));
154
155 return r;
156 }
157
158 static struct rpcent *
159 copy_rpc(struct rpcent *in)
160 {
161 int i, len;
162 struct rpcent *r;
163
164 if (in == NULL) return NULL;
165
166 r = (struct rpcent *)calloc(1, sizeof(struct rpcent));
167
168 r->r_name = LU_COPY_STRING(in->r_name);
169
170 len = 0;
171 if (in->r_aliases != NULL)
172 {
173 for (len = 0; in->r_aliases[len] != NULL; len++);
174 }
175
176 r->r_aliases = (char **)calloc(len + 1, sizeof(char *));
177 for (i = 0; i < len; i++)
178 {
179 r->r_aliases[i] = strdup(in->r_aliases[i]);
180 }
181
182 r->r_number = in->r_number;
183
184 return r;
185 }
186
187 static void
188 recycle_rpc(struct lu_thread_info *tdata, struct rpcent *in)
189 {
190 struct rpcent *r;
191
192 if (tdata == NULL) return;
193 r = (struct rpcent *)tdata->lu_entry;
194
195 if (in == NULL)
196 {
197 free_rpc(r);
198 tdata->lu_entry = NULL;
199 }
200
201 if (tdata->lu_entry == NULL)
202 {
203 tdata->lu_entry = in;
204 return;
205 }
206
207 free_rpc_data(r);
208
209 r->r_name = in->r_name;
210 r->r_aliases = in->r_aliases;
211 r->r_number = in->r_number;
212
213 free(in);
214 }
215
216 static struct rpcent *
217 lu_getrpcbynumber(long number)
218 {
219 struct rpcent *r;
220 unsigned datalen;
221 XDR inxdr;
222 static int proc = -1;
223 char *lookup_buf;
224 int count;
225
226 if (proc < 0)
227 {
228 if (_lookup_link(_lu_port, "getrpcbynumber", &proc) != KERN_SUCCESS)
229 {
230 return NULL;
231 }
232 }
233
234 number = htonl(number);
235 datalen = 0;
236 lookup_buf = NULL;
237
238 if (_lookup_all(_lu_port, proc, (unit *)&number, 1, &lookup_buf, &datalen)
239 != KERN_SUCCESS)
240 {
241 return NULL;
242 }
243
244 datalen *= BYTES_PER_XDR_UNIT;
245 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
246
247 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
248
249 count = 0;
250 if (!xdr_int(&inxdr, &count))
251 {
252 xdr_destroy(&inxdr);
253 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
254 return NULL;
255 }
256
257 if (count == 0)
258 {
259 xdr_destroy(&inxdr);
260 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
261 return NULL;
262 }
263
264 r = extract_rpc(&inxdr);
265 xdr_destroy(&inxdr);
266 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
267
268 return r;
269 }
270
271 static struct rpcent *
272 lu_getrpcbyname(const char *name)
273 {
274 struct rpcent *r;
275 unsigned datalen;
276 char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
277 XDR outxdr, inxdr;
278 static int proc = -1;
279 char *lookup_buf;
280 int count;
281
282 if (proc < 0)
283 {
284 if (_lookup_link(_lu_port, "getrpcbyname", &proc) != KERN_SUCCESS)
285 {
286 return NULL;
287 }
288 }
289
290 xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
291 if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
292 {
293 xdr_destroy(&outxdr);
294 return NULL;
295 }
296
297 datalen = 0;
298 lookup_buf = NULL;
299
300 if (_lookup_all(_lu_port, proc, (unit *)namebuf,
301 xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen)
302 != KERN_SUCCESS)
303 {
304 xdr_destroy(&outxdr);
305 return NULL;
306 }
307
308 xdr_destroy(&outxdr);
309
310 datalen *= BYTES_PER_XDR_UNIT;
311 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
312
313 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
314
315 count = 0;
316 if (!xdr_int(&inxdr, &count))
317 {
318 xdr_destroy(&inxdr);
319 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
320 return NULL;
321 }
322
323 if (count == 0)
324 {
325 xdr_destroy(&inxdr);
326 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
327 return NULL;
328 }
329
330 r = extract_rpc(&inxdr);
331 xdr_destroy(&inxdr);
332 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
333
334 return r;
335 }
336
337 static void
338 lu_endrpcent(void)
339 {
340 struct lu_thread_info *tdata;
341
342 tdata = _lu_data_create_key(_lu_data_key_rpc, free_lu_thread_info_rpc);
343 _lu_data_free_vm_xdr(tdata);
344 }
345
346 static void
347 lu_setrpcent()
348 {
349 lu_endrpcent();
350 }
351
352 static struct rpcent *
353 lu_getrpcent()
354 {
355 struct rpcent *r;
356 static int proc = -1;
357 struct lu_thread_info *tdata;
358
359 tdata = _lu_data_create_key(_lu_data_key_rpc, free_lu_thread_info_rpc);
360 if (tdata == NULL)
361 {
362 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
363 _lu_data_set_key(_lu_data_key_rpc, tdata);
364 }
365
366 if (tdata->lu_vm == NULL)
367 {
368 if (proc < 0)
369 {
370 if (_lookup_link(_lu_port, "getrpcent", &proc) != KERN_SUCCESS)
371 {
372 lu_endrpcent();
373 return NULL;
374 }
375 }
376
377 if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
378 {
379 lu_endrpcent();
380 return NULL;
381 }
382
383 /* mig stubs measure size in words (4 bytes) */
384 tdata->lu_vm_length *= 4;
385
386 if (tdata->lu_xdr != NULL)
387 {
388 xdr_destroy(tdata->lu_xdr);
389 free(tdata->lu_xdr);
390 }
391 tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
392
393 xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
394 if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
395 {
396 lu_endrpcent();
397 return NULL;
398 }
399 }
400
401 if (tdata->lu_vm_cursor == 0)
402 {
403 lu_endrpcent();
404 return NULL;
405 }
406
407 r = extract_rpc(tdata->lu_xdr);
408 if (r == NULL)
409 {
410 lu_endrpcent();
411 return NULL;
412 }
413
414 tdata->lu_vm_cursor--;
415
416 return r;
417 }
418
419 static struct rpcent *
420 getrpc(const char *name, long number, int source)
421 {
422 struct rpcent *res = NULL;
423 struct lu_thread_info *tdata;
424
425 tdata = _lu_data_create_key(_lu_data_key_rpc, free_lu_thread_info_rpc);
426 if (tdata == NULL)
427 {
428 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
429 _lu_data_set_key(_lu_data_key_rpc, tdata);
430 }
431
432 if (_lu_running())
433 {
434 switch (source)
435 {
436 case RPC_GET_NAME:
437 res = lu_getrpcbyname(name);
438 break;
439 case RPC_GET_NUM:
440 res = lu_getrpcbynumber(number);
441 break;
442 case RPC_GET_ENT:
443 res = lu_getrpcent();
444 break;
445 default: res = NULL;
446 }
447 }
448 else
449 {
450 pthread_mutex_lock(&_rpc_lock);
451 switch (source)
452 {
453 case RPC_GET_NAME:
454 res = copy_rpc(_old_getrpcbyname(name));
455 break;
456 case RPC_GET_NUM:
457 res = copy_rpc(_old_getrpcbynumber(number));
458 break;
459 case RPC_GET_ENT:
460 res = copy_rpc(_old_getrpcent());
461 break;
462 default: res = NULL;
463 }
464 pthread_mutex_unlock(&_rpc_lock);
465 }
466
467 recycle_rpc(tdata, res);
468 return (struct rpcent *)tdata->lu_entry;
469 }
470
471 struct rpcent *
472 getrpcbyname(const char *name)
473 {
474 return getrpc(name, -2, RPC_GET_NAME);
475 }
476
477 struct rpcent *
478 getrpcbynumber(long number)
479 {
480 return getrpc(NULL, number, RPC_GET_NUM);
481 }
482
483 struct rpcent *
484 getrpcent(void)
485 {
486 return getrpc(NULL, -2, RPC_GET_ENT);
487 }
488
489 void
490 setrpcent(int stayopen)
491 {
492 if (_lu_running()) lu_setrpcent();
493 else _old_setrpcent(stayopen);
494 }
495
496 void
497 endrpcent(void)
498 {
499 if (_lu_running()) lu_endrpcent();
500 else _old_endrpcent();
501 }