Libinfo-173.tar.gz
[apple/libinfo.git] / lookup.subproj / lu_network.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 * network lookup
27 * Copyright (C) 1989 by NeXT, Inc.
28 */
29 #include <stdlib.h>
30 #include <mach/mach.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <rpc/types.h>
34 #include <rpc/xdr.h>
35 #include <netdb.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <pthread.h>
40
41 #include "_lu_types.h"
42 #include "lookup.h"
43 #include "lu_utils.h"
44
45 static pthread_mutex_t _network_lock = PTHREAD_MUTEX_INITIALIZER;
46
47 #define N_GET_NAME 1
48 #define N_GET_ADDR 2
49 #define N_GET_ENT 3
50
51 extern struct netent *_res_getnetbyaddr();
52 extern struct netent *_res_getnetbyname();
53 extern struct netent *_old_getnetbyaddr();
54 extern struct netent *_old_getnetbyname();
55 extern struct netent *_old_getnetent();
56 extern void _old_setnetent();
57 extern void _old_endnetent();
58
59 extern mach_port_t _lu_port;
60 extern int _lu_running(void);
61
62 static void
63 free_network_data(struct netent *n)
64 {
65 char **aliases;
66
67 if (n == NULL) return;
68
69 free(n->n_name);
70
71 aliases = n->n_aliases;
72 if (aliases != NULL)
73 {
74 while (*aliases != NULL) free(*aliases++);
75 free(n->n_aliases);
76 }
77 }
78
79 static void
80 free_network(struct netent *n)
81 {
82 if (n == NULL) return;
83 free_network_data(n);
84 free(n);
85 }
86
87 static void
88 free_lu_thread_info_network(void *x)
89 {
90 struct lu_thread_info *tdata;
91
92 if (x == NULL) return;
93
94 tdata = (struct lu_thread_info *)x;
95
96 if (tdata->lu_entry != NULL)
97 {
98 free_network((struct netent *)tdata->lu_entry);
99 tdata->lu_entry = NULL;
100 }
101
102 _lu_data_free_vm_xdr(tdata);
103
104 free(tdata);
105 }
106
107 static struct netent *
108 extract_network(XDR *xdr)
109 {
110 struct netent *n;
111 int i, j, nvals, nkeys, status;
112 char *key, **vals;
113
114 if (xdr == NULL) return NULL;
115
116 if (!xdr_int(xdr, &nkeys)) return NULL;
117
118 n = (struct netent *)calloc(1, sizeof(struct netent));
119
120 n->n_addrtype = AF_INET;
121
122 for (i = 0; i < nkeys; i++)
123 {
124 key = NULL;
125 vals = NULL;
126 nvals = 0;
127
128 status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
129 if (status < 0)
130 {
131 free_network(n);
132 return NULL;
133 }
134
135 if (nvals == 0)
136 {
137 free(key);
138 continue;
139 }
140
141 j = 0;
142
143 if ((n->n_name == NULL) && (!strcmp("name", key)))
144 {
145 n->n_name = vals[0];
146 if (nvals > 1)
147 {
148 n->n_aliases = (char **)calloc(nvals, sizeof(char *));
149 for (j = 1; j < nvals; j++) n->n_aliases[j-1] = vals[j];
150 }
151 j = nvals;
152 }
153 else if (!strcmp("address", key))
154 {
155 n->n_net = inet_network(vals[0]);
156 }
157
158 free(key);
159 if (vals != NULL)
160 {
161 for (; j < nvals; j++) free(vals[j]);
162 free(vals);
163 }
164 }
165
166 if (n->n_name == NULL) n->n_name = strdup("");
167 if (n->n_aliases == NULL) n->n_aliases = (char **)calloc(1, sizeof(char *));
168
169 return n;
170 }
171
172 static struct netent *
173 copy_network(struct netent *in)
174 {
175 int i, len;
176 struct netent *n;
177
178 if (in == NULL) return NULL;
179
180 n = (struct netent *)calloc(1, sizeof(struct netent));
181
182 n->n_name = LU_COPY_STRING(in->n_name);
183
184 len = 0;
185 if (in->n_aliases != NULL)
186 {
187 for (len = 0; in->n_aliases[len] != NULL; len++);
188 }
189
190 n->n_aliases = (char **)calloc(len + 1, sizeof(char *));
191 for (i = 0; i < len; i++)
192 {
193 n->n_aliases[i] = strdup(in->n_aliases[i]);
194 }
195
196 n->n_addrtype = in->n_addrtype;
197 n->n_net = in->n_net;
198
199 return n;
200 }
201
202 static void
203 recycle_network(struct lu_thread_info *tdata, struct netent *in)
204 {
205 struct netent *n;
206
207 if (tdata == NULL) return;
208 n = (struct netent *)tdata->lu_entry;
209
210 if (in == NULL)
211 {
212 free_network(n);
213 tdata->lu_entry = NULL;
214 }
215
216 if (tdata->lu_entry == NULL)
217 {
218 tdata->lu_entry = in;
219 return;
220 }
221
222 free_network_data(n);
223
224 n->n_name = in->n_name;
225 n->n_aliases = in->n_aliases;
226 n->n_addrtype = in->n_addrtype;
227 n->n_net = in->n_net;
228
229 free(in);
230 }
231
232 static struct netent *
233 lu_getnetbyaddr(long addr, int type)
234 {
235 struct netent *n;
236 unsigned datalen;
237 XDR inxdr;
238 static int proc = -1;
239 char *lookup_buf;
240 int count;
241
242 if (type != AF_INET) return NULL;
243
244 if (proc < 0)
245 {
246 if (_lookup_link(_lu_port, "getnetbyaddr", &proc) != KERN_SUCCESS)
247 {
248 return NULL;
249 }
250 }
251
252 addr = htonl(addr);
253 datalen = 0;
254 lookup_buf = NULL;
255
256 if (_lookup_all(_lu_port, proc, (unit *)&addr, 1, &lookup_buf, &datalen) != KERN_SUCCESS)
257 {
258 return NULL;
259 }
260
261 datalen *= BYTES_PER_XDR_UNIT;
262 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
263
264 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
265
266 count = 0;
267 if (!xdr_int(&inxdr, &count))
268 {
269 xdr_destroy(&inxdr);
270 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
271 return NULL;
272 }
273
274 if (count == 0)
275 {
276 xdr_destroy(&inxdr);
277 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
278 return NULL;
279 }
280
281 n = extract_network(&inxdr);
282 xdr_destroy(&inxdr);
283 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
284
285 return n;
286 }
287
288 static struct netent *
289 lu_getnetbyname(const char *name)
290 {
291 struct netent *n;
292 unsigned datalen;
293 char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
294 XDR outxdr;
295 XDR inxdr;
296 static int proc = -1;
297 char *lookup_buf;
298 int count;
299
300 if (proc < 0)
301 {
302 if (_lookup_link(_lu_port, "getnetbyname", &proc) != KERN_SUCCESS)
303 {
304 return NULL;
305 }
306 }
307
308 xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
309 if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
310 {
311 xdr_destroy(&outxdr);
312 return NULL;
313 }
314
315 datalen = 0;
316 lookup_buf = NULL;
317
318 if (_lookup_all(_lu_port, proc, (unit *)namebuf,
319 xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen)
320 != KERN_SUCCESS)
321 {
322 xdr_destroy(&outxdr);
323 return NULL;
324 }
325
326 xdr_destroy(&outxdr);
327
328 datalen *= BYTES_PER_XDR_UNIT;
329 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
330
331 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
332
333 count = 0;
334 if (!xdr_int(&inxdr, &count))
335 {
336 xdr_destroy(&inxdr);
337 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
338 return NULL;
339 }
340
341 if (count == 0)
342 {
343 xdr_destroy(&inxdr);
344 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
345 return NULL;
346 }
347
348 n = extract_network(&inxdr);
349 xdr_destroy(&inxdr);
350 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
351
352 return n;
353 }
354
355 static void
356 lu_endnetent()
357 {
358 struct lu_thread_info *tdata;
359
360 tdata = _lu_data_create_key(_lu_data_key_network, free_lu_thread_info_network);
361 _lu_data_free_vm_xdr(tdata);
362 }
363
364 static void
365 lu_setnetent()
366 {
367 lu_endnetent();
368 }
369
370 static struct netent *
371 lu_getnetent()
372 {
373 static int proc = -1;
374 struct lu_thread_info *tdata;
375 struct netent *n;
376
377 tdata = _lu_data_create_key(_lu_data_key_network, free_lu_thread_info_network);
378 if (tdata == NULL)
379 {
380 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
381 _lu_data_set_key(_lu_data_key_network, tdata);
382 }
383
384 if (tdata->lu_vm == NULL)
385 {
386 if (proc < 0)
387 {
388 if (_lookup_link(_lu_port, "getnetent", &proc) != KERN_SUCCESS)
389 {
390 lu_endnetent();
391 return NULL;
392 }
393 }
394
395 if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
396 {
397 lu_endnetent();
398 return NULL;
399 }
400
401 /* mig stubs measure size in words (4 bytes) */
402 tdata->lu_vm_length *= 4;
403
404 if (tdata->lu_xdr != NULL)
405 {
406 xdr_destroy(tdata->lu_xdr);
407 free(tdata->lu_xdr);
408 }
409 tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
410
411 xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
412 if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
413 {
414 lu_endnetent();
415 return NULL;
416 }
417 }
418
419 if (tdata->lu_vm_cursor == 0)
420 {
421 lu_endnetent();
422 return NULL;
423 }
424
425 n = extract_network(tdata->lu_xdr);
426 if (n == NULL)
427 {
428 lu_endnetent();
429 return NULL;
430 }
431
432 tdata->lu_vm_cursor--;
433
434 return n;
435 }
436
437 static struct netent *
438 getnet(const char *name, long addr, int type, int source)
439 {
440 struct netent *res = NULL;
441 struct lu_thread_info *tdata;
442
443 tdata = _lu_data_create_key(_lu_data_key_network, free_lu_thread_info_network);
444 if (tdata == NULL)
445 {
446 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
447 _lu_data_set_key(_lu_data_key_network, tdata);
448 }
449
450 if (_lu_running())
451 {
452 switch (source)
453 {
454 case N_GET_NAME:
455 res = lu_getnetbyname(name);
456 break;
457 case N_GET_ADDR:
458 res = lu_getnetbyaddr(addr, type);
459 break;
460 case N_GET_ENT:
461 res = lu_getnetent();
462 break;
463 default: res = NULL;
464 }
465 }
466 else
467 {
468 pthread_mutex_lock(&_network_lock);
469 switch (source)
470 {
471 case N_GET_NAME:
472 res = copy_network(_old_getnetbyname(name));
473 break;
474 case N_GET_ADDR:
475 res = copy_network(_old_getnetbyaddr(addr, type));
476 break;
477 case N_GET_ENT:
478 res = copy_network(_old_getnetent());
479 break;
480 default: res = NULL;
481 }
482 pthread_mutex_unlock(&_network_lock);
483 }
484
485 recycle_network(tdata, res);
486 return (struct netent *)tdata->lu_entry;
487 }
488
489 struct netent *
490 getnetbyaddr(long addr, int type)
491 {
492 return getnet(NULL, addr, type, N_GET_ADDR);
493 }
494
495 struct netent *
496 getnetbyname(const char *name)
497 {
498 return getnet(name, 0, 0, N_GET_NAME);
499 }
500
501 struct netent *
502 getnetent(void)
503 {
504 return getnet(NULL, 0, 0, N_GET_ENT);
505 }
506
507 void
508 setnetent(int stayopen)
509 {
510 if (_lu_running()) lu_setnetent();
511 else _old_setnetent(stayopen);
512 }
513
514 void
515 endnetent(void)
516 {
517 if (_lu_running()) lu_endnetent();
518 else _old_endnetent();
519 }