Libinfo-173.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 * 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 * Protocol 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 <netinet/in.h>
37
38 #include "_lu_types.h"
39 #include "lookup.h"
40 #include "lu_utils.h"
41
42 extern struct protoent *_old_getprotobynumber();
43 extern struct protoent *_old_getprotobyname();
44 extern struct protoent *_old_getprotoent();
45 extern void _old_setprotoent();
46 extern void _old_endprotoent();
47
48 #define PROTO_GET_NAME 1
49 #define PROTO_GET_NUM 2
50 #define PROTO_GET_ENT 3
51
52 static void
53 free_protocol_data(struct protoent *p)
54 {
55 char **aliases;
56
57 if (p == NULL) return;
58
59 if (p->p_name != NULL) free(p->p_name);
60 aliases = p->p_aliases;
61 if (aliases != NULL)
62 {
63 while (*aliases != NULL) free(*aliases++);
64 free(p->p_aliases);
65 }
66 }
67
68 static void
69 free_protocol(struct protoent *p)
70 {
71 if (p == NULL) return;
72 free_protocol_data(p);
73 free(p);
74 }
75
76 static void
77 free_lu_thread_info_protocol(void *x)
78 {
79 struct lu_thread_info *tdata;
80
81 if (x == NULL) return;
82
83 tdata = (struct lu_thread_info *)x;
84
85 if (tdata->lu_entry != NULL)
86 {
87 free_protocol((struct protoent *)tdata->lu_entry);
88 tdata->lu_entry = NULL;
89 }
90
91 _lu_data_free_vm_xdr(tdata);
92
93 free(tdata);
94 }
95
96 static struct protoent *
97 extract_protocol(XDR *xdr)
98 {
99 struct protoent *p;
100 int i, j, nvals, nkeys, status;
101 char *key, **vals;
102
103 if (xdr == NULL) return NULL;
104
105 if (!xdr_int(xdr, &nkeys)) return NULL;
106
107 p = (struct protoent *)calloc(1, sizeof(struct protoent));
108
109 for (i = 0; i < nkeys; i++)
110 {
111 key = NULL;
112 vals = NULL;
113 nvals = 0;
114
115 status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
116 if (status < 0)
117 {
118 free_protocol(p);
119 return NULL;
120 }
121
122 if (nvals == 0)
123 {
124 free(key);
125 continue;
126 }
127
128 j = 0;
129
130 if ((p->p_name == NULL) && (!strcmp("name", key)))
131 {
132 p->p_name = vals[0];
133 if (nvals > 1)
134 {
135 p->p_aliases = (char **)calloc(nvals, sizeof(char *));
136 for (j = 1; j < nvals; j++) p->p_aliases[j-1] = vals[j];
137 }
138 j = nvals;
139 }
140 else if (!strcmp("number", key))
141 {
142 p->p_proto = atoi(vals[0]);
143 }
144
145 free(key);
146 if (vals != NULL)
147 {
148 for (; j < nvals; j++) free(vals[j]);
149 free(vals);
150 }
151 }
152
153 if (p->p_name == NULL) p->p_name = strdup("");
154 if (p->p_aliases == NULL) p->p_aliases = (char **)calloc(1, sizeof(char *));
155
156 return p;
157 }
158
159 static struct protoent *
160 copy_protocol(struct protoent *in)
161 {
162 int i, len;
163 struct protoent *p;
164
165 if (in == NULL) return NULL;
166
167 p = (struct protoent *)calloc(1, sizeof(struct protoent));
168
169 p->p_proto = in->p_proto;
170 p->p_name = LU_COPY_STRING(in->p_name);
171
172 len = 0;
173 if (in->p_aliases != NULL)
174 {
175 for (len = 0; in->p_aliases[len] != NULL; len++);
176 }
177
178 p->p_aliases = (char **)calloc(len + 1, sizeof(char *));
179 for (i = 0; i < len; i++)
180 {
181 p->p_aliases[i] = strdup(in->p_aliases[i]);
182 }
183
184 return p;
185 }
186
187 static void
188 recycle_protocol(struct lu_thread_info *tdata, struct protoent *in)
189 {
190 struct protoent *p;
191
192 if (tdata == NULL) return;
193 p = (struct protoent *)tdata->lu_entry;
194
195 if (in == NULL)
196 {
197 free_protocol(p);
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_protocol_data(p);
208
209 p->p_proto = in->p_proto;
210 p->p_name = in->p_name;
211 p->p_aliases = in->p_aliases;
212
213 free(in);
214 }
215
216 static struct protoent *
217 lu_getprotobynumber(long number)
218 {
219 struct protoent *p;
220 unsigned int 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, "getprotobynumber", &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 p = extract_protocol(&inxdr);
265 xdr_destroy(&inxdr);
266 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
267
268 return p;
269 }
270
271 static struct protoent *
272 lu_getprotobyname(const char *name)
273 {
274 struct protoent *p;
275 unsigned int datalen;
276 char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
277 XDR outxdr;
278 XDR inxdr;
279 static int proc = -1;
280 char *lookup_buf;
281 int count;
282
283 if (proc < 0)
284 {
285 if (_lookup_link(_lu_port, "getprotobyname", &proc) != KERN_SUCCESS)
286 {
287 return NULL;
288 }
289 }
290
291 xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
292 if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
293 {
294 xdr_destroy(&outxdr);
295 return NULL;
296 }
297
298 datalen = 0;
299 lookup_buf = NULL;
300
301 if (_lookup_all(_lu_port, proc, (unit *)namebuf,
302 xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen)
303 != KERN_SUCCESS)
304 {
305 xdr_destroy(&outxdr);
306 return NULL;
307 }
308
309 xdr_destroy(&outxdr);
310
311 datalen *= BYTES_PER_XDR_UNIT;
312 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
313
314 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
315
316 count = 0;
317 if (!xdr_int(&inxdr, &count))
318 {
319 xdr_destroy(&inxdr);
320 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
321 return NULL;
322 }
323
324 if (count == 0)
325 {
326 xdr_destroy(&inxdr);
327 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
328 return NULL;
329 }
330
331 p = extract_protocol(&inxdr);
332 xdr_destroy(&inxdr);
333 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
334
335 return p;
336 }
337
338 static void
339 lu_endprotoent()
340 {
341 struct lu_thread_info *tdata;
342
343 tdata = _lu_data_create_key(_lu_data_key_protocol, free_lu_thread_info_protocol);
344 _lu_data_free_vm_xdr(tdata);
345 }
346
347 static void
348 lu_setprotoent()
349 {
350 lu_endprotoent();
351 }
352
353
354 static struct protoent *
355 lu_getprotoent()
356 {
357 struct protoent *p;
358 static int proc = -1;
359 struct lu_thread_info *tdata;
360
361 tdata = _lu_data_create_key(_lu_data_key_protocol, free_lu_thread_info_protocol);
362 if (tdata == NULL)
363 {
364 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
365 _lu_data_set_key(_lu_data_key_protocol, tdata);
366 }
367
368 if (tdata->lu_vm == NULL)
369 {
370 if (proc < 0)
371 {
372 if (_lookup_link(_lu_port, "getprotoent", &proc) != KERN_SUCCESS)
373 {
374 lu_endprotoent();
375 return NULL;
376 }
377 }
378
379 if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
380 {
381 lu_endprotoent();
382 return NULL;
383 }
384
385 /* mig stubs measure size in words (4 bytes) */
386 tdata->lu_vm_length *= 4;
387
388 if (tdata->lu_xdr != NULL)
389 {
390 xdr_destroy(tdata->lu_xdr);
391 free(tdata->lu_xdr);
392 }
393 tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
394
395 xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
396 if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
397 {
398 lu_endprotoent();
399 return NULL;
400 }
401 }
402
403 if (tdata->lu_vm_cursor == 0)
404 {
405 lu_endprotoent();
406 return NULL;
407 }
408
409 p = extract_protocol(tdata->lu_xdr);
410 if (p == NULL)
411 {
412 lu_endprotoent();
413 return NULL;
414 }
415
416 tdata->lu_vm_cursor--;
417
418 return p;
419 }
420
421 static struct protoent *
422 getproto(const char *name, int number, int source)
423 {
424 struct protoent *res = NULL;
425 struct lu_thread_info *tdata;
426
427 tdata = _lu_data_create_key(_lu_data_key_protocol, free_lu_thread_info_protocol);
428 if (tdata == NULL)
429 {
430 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
431 _lu_data_set_key(_lu_data_key_protocol, tdata);
432 }
433
434 if (_lu_running())
435 {
436 switch (source)
437 {
438 case PROTO_GET_NAME:
439 res = lu_getprotobyname(name);
440 break;
441 case PROTO_GET_NUM:
442 res = lu_getprotobynumber(number);
443 break;
444 case PROTO_GET_ENT:
445 res = lu_getprotoent();
446 break;
447 default: res = NULL;
448 }
449 }
450 else
451 {
452 switch (source)
453 {
454 case PROTO_GET_NAME:
455 res = copy_protocol(_old_getprotobyname(name));
456 break;
457 case PROTO_GET_NUM:
458 res = copy_protocol(_old_getprotobynumber(number));
459 break;
460 case PROTO_GET_ENT:
461 res = copy_protocol(_old_getprotoent());
462 break;
463 default: res = NULL;
464 }
465 }
466
467 recycle_protocol(tdata, res);
468 return (struct protoent *)tdata->lu_entry;
469 }
470
471 struct protoent *
472 getprotobyname(const char *name)
473 {
474 return getproto(name, -2, PROTO_GET_NAME);
475 }
476
477 struct protoent *
478 getprotobynumber(int number)
479 {
480 return getproto(NULL, number, PROTO_GET_NUM);
481 }
482
483 struct protoent *
484 getprotoent(void)
485 {
486 return getproto(NULL, -2, PROTO_GET_ENT);
487 }
488
489 void
490 setprotoent(int stayopen)
491 {
492 if (_lu_running()) lu_setprotoent();
493 else _old_setprotoent(stayopen);
494 }
495
496 void
497 endprotoent(void)
498 {
499 if (_lu_running()) lu_endprotoent();
500 else _old_endprotoent();
501 }