Libinfo-129.tar.gz
[apple/libinfo.git] / lookup.subproj / lu_protocol.c
1 /*
2 * Copyright (c) 1999 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 * Protocol 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 <netinet/in.h>
36
37 #include "_lu_types.h"
38 #include "lookup.h"
39 #include "lu_utils.h"
40
41 extern struct protoent *_old_getprotobynumber();
42 extern struct protoent *_old_getprotobyname();
43 extern struct protoent *_old_getprotoent();
44 extern void _old_setprotoent();
45 extern void _old_endprotoent();
46
47 #define PROTO_GET_NAME 1
48 #define PROTO_GET_NUM 2
49 #define PROTO_GET_ENT 3
50
51 static void
52 free_protocol_data(struct protoent *p)
53 {
54 char **aliases;
55
56 if (p == NULL) return;
57
58 if (p->p_name != NULL) free(p->p_name);
59 aliases = p->p_aliases;
60 if (aliases != NULL)
61 {
62 while (*aliases != NULL) free(*aliases++);
63 free(p->p_aliases);
64 }
65 }
66
67 static void
68 free_protocol(struct protoent *p)
69 {
70 if (p == NULL) return;
71 free_protocol_data(p);
72 free(p);
73 }
74
75 static void
76 free_lu_thread_info_protocol(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_protocol((struct protoent *)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 protoent *
96 extract_protocol(XDR *xdr)
97 {
98 struct protoent *p;
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 p = (struct protoent *)calloc(1, sizeof(struct protoent));
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_protocol(p);
118 return NULL;
119 }
120
121 if (nvals == 0)
122 {
123 free(key);
124 continue;
125 }
126
127 j = 0;
128
129 if ((p->p_name == NULL) && (!strcmp("name", key)))
130 {
131 p->p_name = vals[0];
132 if (nvals > 1)
133 {
134 p->p_aliases = (char **)calloc(nvals, sizeof(char *));
135 for (j = 1; j < nvals; j++) p->p_aliases[j-1] = vals[j];
136 }
137 j = nvals;
138 }
139 else if (!strcmp("number", key))
140 {
141 p->p_proto = 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 (p->p_name == NULL) p->p_name = strdup("");
153 if (p->p_aliases == NULL) p->p_aliases = (char **)calloc(1, sizeof(char *));
154
155 return p;
156 }
157
158 static struct protoent *
159 copy_protocol(struct protoent *in)
160 {
161 int i, len;
162 struct protoent *p;
163
164 if (in == NULL) return NULL;
165
166 p = (struct protoent *)calloc(1, sizeof(struct protoent));
167
168 p->p_proto = in->p_proto;
169 p->p_name = LU_COPY_STRING(in->p_name);
170
171 len = 0;
172 if (in->p_aliases != NULL)
173 {
174 for (len = 0; in->p_aliases[len] != NULL; len++);
175 }
176
177 p->p_aliases = (char **)calloc(len + 1, sizeof(char *));
178 for (i = 0; i < len; i++)
179 {
180 p->p_aliases[i] = strdup(in->p_aliases[i]);
181 }
182
183 return p;
184 }
185
186 static void
187 recycle_protocol(struct lu_thread_info *tdata, struct protoent *in)
188 {
189 struct protoent *p;
190
191 if (tdata == NULL) return;
192 p = (struct protoent *)tdata->lu_entry;
193
194 if (in == NULL)
195 {
196 free_protocol(p);
197 tdata->lu_entry = NULL;
198 }
199
200 if (tdata->lu_entry == NULL)
201 {
202 tdata->lu_entry = in;
203 return;
204 }
205
206 free_protocol_data(p);
207
208 p->p_proto = in->p_proto;
209 p->p_name = in->p_name;
210 p->p_aliases = in->p_aliases;
211
212 free(in);
213 }
214
215 static struct protoent *
216 lu_getprotobynumber(long number)
217 {
218 struct protoent *p;
219 unsigned int datalen;
220 XDR inxdr;
221 static int proc = -1;
222 char *lookup_buf;
223 int count;
224
225 if (proc < 0)
226 {
227 if (_lookup_link(_lu_port, "getprotobynumber", &proc) != KERN_SUCCESS)
228 {
229 return NULL;
230 }
231 }
232
233 number = htonl(number);
234 datalen = 0;
235 lookup_buf = NULL;
236
237 if (_lookup_all(_lu_port, proc, (unit *)&number, 1, &lookup_buf, &datalen)
238 != KERN_SUCCESS)
239 {
240 return NULL;
241 }
242
243 datalen *= BYTES_PER_XDR_UNIT;
244 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
245
246 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
247
248 count = 0;
249 if (!xdr_int(&inxdr, &count))
250 {
251 xdr_destroy(&inxdr);
252 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
253 return NULL;
254 }
255
256 if (count == 0)
257 {
258 xdr_destroy(&inxdr);
259 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
260 return NULL;
261 }
262
263 p = extract_protocol(&inxdr);
264 xdr_destroy(&inxdr);
265 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
266
267 return p;
268 }
269
270 static struct protoent *
271 lu_getprotobyname(const char *name)
272 {
273 struct protoent *p;
274 unsigned int datalen;
275 char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
276 XDR outxdr;
277 XDR 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, "getprotobyname", &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 p = extract_protocol(&inxdr);
331 xdr_destroy(&inxdr);
332 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
333
334 return p;
335 }
336
337 static void
338 lu_endprotoent()
339 {
340 struct lu_thread_info *tdata;
341
342 tdata = _lu_data_create_key(_lu_data_key_service, free_lu_thread_info_protocol);
343 _lu_data_free_vm_xdr(tdata);
344 }
345
346 static void
347 lu_setprotoent()
348 {
349 lu_endprotoent();
350 }
351
352
353 static struct protoent *
354 lu_getprotoent()
355 {
356 struct protoent *p;
357 static int proc = -1;
358 struct lu_thread_info *tdata;
359
360 tdata = _lu_data_create_key(_lu_data_key_protocol, free_lu_thread_info_protocol);
361 if (tdata == NULL)
362 {
363 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
364 _lu_data_set_key(_lu_data_key_protocol, tdata);
365 }
366
367 if (tdata->lu_vm == NULL)
368 {
369 if (proc < 0)
370 {
371 if (_lookup_link(_lu_port, "getprotoent", &proc) != KERN_SUCCESS)
372 {
373 lu_endprotoent();
374 return NULL;
375 }
376 }
377
378 if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
379 {
380 lu_endprotoent();
381 return NULL;
382 }
383
384 /* mig stubs measure size in words (4 bytes) */
385 tdata->lu_vm_length *= 4;
386
387 if (tdata->lu_xdr != NULL)
388 {
389 xdr_destroy(tdata->lu_xdr);
390 free(tdata->lu_xdr);
391 }
392 tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
393
394 xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
395 if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
396 {
397 lu_endprotoent();
398 return NULL;
399 }
400 }
401
402 if (tdata->lu_vm_cursor == 0)
403 {
404 lu_endprotoent();
405 return NULL;
406 }
407
408 p = extract_protocol(tdata->lu_xdr);
409 if (p == NULL)
410 {
411 lu_endprotoent();
412 return NULL;
413 }
414
415 tdata->lu_vm_cursor--;
416
417 return p;
418 }
419
420 static struct protoent *
421 getproto(const char *name, int number, int source)
422 {
423 struct protoent *res = NULL;
424 struct lu_thread_info *tdata;
425
426 tdata = _lu_data_create_key(_lu_data_key_protocol, free_lu_thread_info_protocol);
427 if (tdata == NULL)
428 {
429 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
430 _lu_data_set_key(_lu_data_key_protocol, tdata);
431 }
432
433 if (_lu_running())
434 {
435 switch (source)
436 {
437 case PROTO_GET_NAME:
438 res = lu_getprotobyname(name);
439 break;
440 case PROTO_GET_NUM:
441 res = lu_getprotobynumber(number);
442 break;
443 case PROTO_GET_ENT:
444 res = lu_getprotoent();
445 break;
446 default: res = NULL;
447 }
448 }
449 else
450 {
451 switch (source)
452 {
453 case PROTO_GET_NAME:
454 res = copy_protocol(_old_getprotobyname(name));
455 break;
456 case PROTO_GET_NUM:
457 res = copy_protocol(_old_getprotobynumber(number));
458 break;
459 case PROTO_GET_ENT:
460 res = copy_protocol(_old_getprotoent());
461 break;
462 default: res = NULL;
463 }
464 }
465
466 recycle_protocol(tdata, res);
467 return (struct protoent *)tdata->lu_entry;
468 }
469
470 struct protoent *
471 getprotobyname(const char *name)
472 {
473 return getproto(name, -2, PROTO_GET_NAME);
474 }
475
476 struct protoent *
477 getprotobynumber(int number)
478 {
479 return getproto(NULL, number, PROTO_GET_NUM);
480 }
481
482 struct protoent *
483 getprotoent(void)
484 {
485 return getproto(NULL, -2, PROTO_GET_ENT);
486 }
487
488 void
489 setprotoent(int stayopen)
490 {
491 if (_lu_running()) lu_setprotoent();
492 else _old_setprotoent(stayopen);
493 }
494
495 void
496 endprotoent(void)
497 {
498 if (_lu_running()) lu_endprotoent();
499 else _old_endprotoent();
500 }