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