Libinfo-222.4.6.tar.gz
[apple/libinfo.git] / lookup.subproj / lu_utils.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 #include <stdlib.h>
26 #include <string.h>
27 #include <mach/mach.h>
28 #include <pthread.h>
29 #ifdef DEBUG
30 #include <syslog.h>
31 #endif
32 #include "_lu_types.h"
33 #include "lookup.h"
34 #include "lu_utils.h"
35 #include "netdb_async.h"
36
37 #define MAX_LOOKUP_ATTEMPTS 10
38 #define _LU_MAXLUSTRLEN 256
39 #define QBUF_SIZE 4096
40
41 #define LU_MESSAGE_SEND_ID 4241776
42 #define LU_MESSAGE_REPLY_ID 4241876
43
44 static pthread_key_t _info_key = 0;
45 static pthread_once_t _info_key_initialized = PTHREAD_ONCE_INIT;
46
47 struct _lu_data_s
48 {
49 unsigned int icount;
50 unsigned int *ikey;
51 void **idata;
52 void (**idata_destructor)(void *);
53 };
54
55 typedef struct _lu_async_request_s
56 {
57 mach_port_t reply_port;
58 uint32_t retry;
59 uint32_t proc;
60 void *context;
61 void *callback;
62 ooline_data request_buffer;
63 mach_msg_type_number_t request_buffer_len;
64 struct _lu_async_request_s *next;
65 } _lu_async_request_t;
66
67 typedef struct
68 {
69 mach_msg_header_t head;
70 NDR_record_t NDR;
71 int proc;
72 mach_msg_type_number_t query_data_len;
73 unit query_data[QBUF_SIZE];
74 } _lu_query_msg_t;
75
76 typedef struct
77 {
78 mach_msg_header_t head;
79 mach_msg_body_t msgh_body;
80 mach_msg_ool_descriptor_t reply_data;
81 NDR_record_t NDR;
82 mach_msg_type_number_t reply_data_len;
83 mach_msg_format_0_trailer_t trailer;
84 } _lu_reply_msg_t;
85
86 static pthread_mutex_t _lu_worklist_lock = PTHREAD_MUTEX_INITIALIZER;
87 static _lu_async_request_t *_lu_worklist = NULL;
88
89 /* Send an asynchronous query message to lookupd */
90 static kern_return_t
91 _lu_async_send(_lu_async_request_t *r)
92 {
93 _lu_query_msg_t in;
94 register _lu_query_msg_t *inp = &in;
95 mach_msg_return_t status;
96 unsigned int msgh_size;
97
98 if (r == NULL) return KERN_FAILURE;
99
100 if (r->retry == 0) return MIG_SERVER_DIED;
101 r->retry--;
102
103 if (r->request_buffer_len > QBUF_SIZE) return MIG_ARRAY_TOO_LARGE;
104
105 msgh_size = (sizeof(_lu_query_msg_t) - 16384) + ((4 * r->request_buffer_len));
106 inp->head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
107 inp->head.msgh_remote_port = _lu_port;
108 inp->head.msgh_local_port = r->reply_port;
109 inp->head.msgh_id = LU_MESSAGE_SEND_ID;
110 inp->NDR = NDR_record;
111 inp->proc = r->proc;
112 inp->query_data_len = r->request_buffer_len;
113 memcpy(inp->query_data, r->request_buffer, 4 * r->request_buffer_len);
114
115 status = mach_msg(&inp->head, MACH_SEND_MSG, msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
116 if (status == MACH_MSG_SUCCESS) return KERN_SUCCESS;
117
118 if (status == MACH_SEND_INVALID_REPLY)
119 {
120 mach_port_mod_refs(mach_task_self(), r->reply_port, MACH_PORT_RIGHT_RECEIVE, -1);
121 r->reply_port = MACH_PORT_NULL;
122 }
123
124 return status;
125 }
126
127 static _lu_async_request_t *
128 _lu_worklist_remove(mach_port_t p)
129 {
130 _lu_async_request_t *r, *n;
131
132 if (p == MACH_PORT_NULL) return NULL;
133 if (_lu_worklist == NULL) return NULL;
134
135 pthread_mutex_lock(&_lu_worklist_lock);
136
137 if (_lu_worklist->reply_port == p)
138 {
139 r = _lu_worklist;
140 _lu_worklist = r->next;
141 pthread_mutex_unlock(&_lu_worklist_lock);
142 return r;
143 }
144
145 for (r = _lu_worklist; r != NULL; r = r->next)
146 {
147 n = r->next;
148 if (n == NULL) break;
149
150 if (n->reply_port == p)
151 {
152 r->next = n->next;
153 pthread_mutex_unlock(&_lu_worklist_lock);
154 return n;
155 }
156 }
157
158 pthread_mutex_unlock(&_lu_worklist_lock);
159 return NULL;
160 }
161
162 static _lu_async_request_t *
163 _lu_worklist_find(mach_port_t p)
164 {
165 _lu_async_request_t *r;
166
167 if (p == MACH_PORT_NULL) return NULL;
168 if (_lu_worklist == NULL) return NULL;
169
170 pthread_mutex_lock(&_lu_worklist_lock);
171
172 for (r = _lu_worklist; r != NULL; r = r->next)
173 {
174 if (r->reply_port == p)
175 {
176 pthread_mutex_unlock(&_lu_worklist_lock);
177 return r;
178 }
179 }
180
181 pthread_mutex_unlock(&_lu_worklist_lock);
182 return NULL;
183 }
184
185 static void
186 _lu_free_request(_lu_async_request_t *r)
187 {
188 if (r == NULL) return;
189
190 if (r->request_buffer != NULL) free(r->request_buffer);
191 r->request_buffer = NULL;
192
193 if (r->reply_port != MACH_PORT_NULL) mach_port_destroy(mach_task_self(), r->reply_port);
194 r->reply_port = MACH_PORT_NULL;
195
196 free(r);
197 }
198
199 /* Receive an asynchronous reply message from lookupd */
200 kern_return_t
201 lu_async_receive(mach_port_t p, char **buf, uint32_t *len)
202 {
203 _lu_reply_msg_t *r;
204 kern_return_t status;
205 uint32_t size;
206 _lu_async_request_t *req;
207 boolean_t msgh_simple;
208
209 size = sizeof(_lu_reply_msg_t);
210
211 r = (_lu_reply_msg_t *)calloc(1, size);
212 if (r == NULL) return KERN_RESOURCE_SHORTAGE;
213
214 r->head.msgh_local_port = p;
215 r->head.msgh_size = size;
216 status = mach_msg(&(r->head), MACH_RCV_MSG, 0, size, r->head.msgh_local_port, 0, MACH_PORT_NULL);
217 if (status != KERN_SUCCESS)
218 {
219 free(r);
220 return status;
221 }
222
223 msgh_simple = !(r->head.msgh_bits & MACH_MSGH_BITS_COMPLEX);
224
225 req = _lu_worklist_remove(r->head.msgh_local_port);
226 if (req == NULL)
227 {
228 free(r);
229 return KERN_FAILURE;
230 }
231
232 if (msgh_simple && ((mig_reply_error_t *) r)->RetCode != KERN_SUCCESS)
233 {
234 _lu_free_request(req);
235 status = ((mig_reply_error_t *) r)->RetCode;
236 free(r);
237 return status;
238 }
239
240 *buf = r->reply_data.address;
241 *len = r->reply_data.size;
242
243 free(r);
244
245 _lu_free_request(req);
246 return KERN_SUCCESS;
247 }
248
249 static void
250 _lu_worklist_append(_lu_async_request_t *r)
251 {
252 _lu_async_request_t *p;
253
254 if (r == NULL) return;
255
256 pthread_mutex_lock(&_lu_worklist_lock);
257
258 if (_lu_worklist == NULL)
259 {
260 _lu_worklist = r;
261 pthread_mutex_unlock(&_lu_worklist_lock);
262 return;
263 }
264
265 for (p = _lu_worklist; p->next != NULL; p = p->next);
266 p->next = r;
267
268 pthread_mutex_unlock(&_lu_worklist_lock);
269 }
270
271 void
272 lu_async_call_cancel(mach_port_t p)
273 {
274 _lu_async_request_t *req;
275
276 req = _lu_worklist_remove(p);
277 if (req != NULL) _lu_free_request(req);
278 else if (p != MACH_PORT_NULL) mach_port_destroy(mach_task_self(), p);
279 }
280
281 static _lu_async_request_t *
282 _lu_create_request(uint32_t proc, const char *buf, uint32_t len, void *callback, void *context)
283 {
284 _lu_async_request_t *r;
285 kern_return_t status;
286
287 if (_lu_port == MACH_PORT_NULL) return NULL;
288
289 r = (_lu_async_request_t *)calloc(1, sizeof(_lu_async_request_t));
290 if (r == NULL) return NULL;
291
292 status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &(r->reply_port));
293 if (status != KERN_SUCCESS)
294 {
295 _lu_free_request(r);
296 return NULL;
297 }
298
299 r->retry = MAX_LOOKUP_ATTEMPTS;
300
301 r->context = context;
302 r->callback = callback;
303 r->proc = proc;
304
305 r->request_buffer = malloc(len * BYTES_PER_XDR_UNIT);
306 if (r->request_buffer == NULL)
307 {
308 free(r);
309 return NULL;
310 }
311
312 memcpy(r->request_buffer, buf, len * BYTES_PER_XDR_UNIT);
313 r->request_buffer_len = len;
314
315 r->next = NULL;
316
317 return r;
318 }
319
320 kern_return_t
321 lu_async_start(mach_port_t *p, uint32_t proc, const char *buf, uint32_t len, void *callback, void *context)
322 {
323 _lu_async_request_t *r;
324 kern_return_t status;
325 uint32_t retry;
326
327 if (p == NULL) return KERN_FAILURE;
328
329 *p = MACH_PORT_NULL;
330
331 if (!_lu_running()) return KERN_FAILURE;
332
333 /* Make a request struct to keep track */
334 r = _lu_create_request(proc, buf, len, callback, context);
335 if (r == NULL) return KERN_FAILURE;
336
337 status = MIG_SERVER_DIED;
338 for (retry = 0; (status == MIG_SERVER_DIED) && (retry < MAX_LOOKUP_ATTEMPTS); retry++)
339 {
340 /* send to lookupd */
341 status = _lu_async_send(r);
342 }
343
344 if (status != KERN_SUCCESS)
345 {
346 _lu_free_request(r);
347 return status;
348 }
349
350 /* Add request to worklist */
351 _lu_worklist_append(r);
352
353 *p = r->reply_port;
354 return KERN_SUCCESS;
355 }
356
357 kern_return_t
358 lu_async_send(mach_port_t *p, uint32_t proc, const char *buf, uint32_t len)
359 {
360 return lu_async_start(p, proc, buf, len, NULL, NULL);
361 }
362
363 int
364 lu_async_handle_reply(void *msg, char **buf, uint32_t *len, void **callback, void **context)
365 {
366 _lu_reply_msg_t *r;
367 _lu_async_request_t *req;
368 kern_return_t status;
369 uint32_t retry;
370 boolean_t msgh_simple;
371
372 if (msg == NULL) return -1;
373 r = (_lu_reply_msg_t *)msg;
374
375 /* If reply status was an error, resend */
376 if (r->head.msgh_id != LU_MESSAGE_REPLY_ID)
377 {
378 if (r->head.msgh_id == MACH_NOTIFY_SEND_ONCE)
379 {
380 /* if MiG server (lookupd) died */
381 req = _lu_worklist_find(r->head.msgh_local_port);
382 if (req == NULL) return -1;
383
384 status = MIG_SERVER_DIED;
385 for (retry = 0; (status == MIG_SERVER_DIED) && (retry < MAX_LOOKUP_ATTEMPTS); retry++)
386 {
387 /* send to lookupd */
388 status = _lu_async_send(req);
389 }
390
391 if (status != KERN_SUCCESS) return -1;
392 }
393 return MIG_REPLY_MISMATCH;
394 }
395
396 msgh_simple = !(r->head.msgh_bits & MACH_MSGH_BITS_COMPLEX);
397
398 req = _lu_worklist_remove(r->head.msgh_local_port);
399 if (req == NULL) return -1;
400
401 *callback = req->callback;
402 *context = req->context;
403 _lu_free_request(req);
404
405 if (msgh_simple && ((mig_reply_error_t *) r)->RetCode != KERN_SUCCESS)
406 {
407 return ((mig_reply_error_t *) r)->RetCode;
408 }
409
410 *buf = r->reply_data.address;
411 *len = r->reply_data.size;
412
413 return 0;
414 }
415
416 ni_proplist *
417 _lookupd_xdr_dictionary(XDR *inxdr)
418 {
419 int i, nkeys, j, nvals;
420 char *key, *val;
421 ni_proplist *l;
422
423 if (!xdr_int(inxdr, &nkeys)) return NULL;
424
425 l = (ni_proplist *)malloc(sizeof(ni_proplist));
426 if (l == NULL) return NULL;
427
428 NI_INIT(l);
429
430 l->ni_proplist_len = nkeys;
431 l->ni_proplist_val = NULL;
432 if (nkeys > 0)
433 {
434 l->ni_proplist_val = (ni_property *)calloc(nkeys, sizeof(ni_property));
435 if (l->ni_proplist_val == NULL)
436 {
437 free(l);
438 return NULL;
439 }
440 }
441
442 for (i = 0; i < nkeys; i++)
443 {
444 key = NULL;
445 if (!xdr_string(inxdr, &key, -1))
446 {
447 ni_proplist_free(l);
448 return NULL;
449 }
450
451 l->ni_proplist_val[i].nip_name = key;
452
453 if (!xdr_int(inxdr, &nvals))
454 {
455 ni_proplist_free(l);
456 return NULL;
457 }
458
459 l->ni_proplist_val[i].nip_val.ni_namelist_len = nvals;
460 if (nvals > 0)
461 {
462 l->ni_proplist_val[i].nip_val.ni_namelist_val = (ni_name *)calloc(nvals, sizeof(ni_name));
463 if (l->ni_proplist_val[i].nip_val.ni_namelist_val == NULL)
464 {
465 ni_proplist_free(l);
466 return NULL;
467 }
468 }
469
470 for (j = 0; j < nvals; j++)
471 {
472 val = NULL;
473 if (!xdr_string(inxdr, &val, -1))
474 {
475 ni_proplist_free(l);
476 return NULL;
477 }
478
479 l->ni_proplist_val[i].nip_val.ni_namelist_val[j] = val;
480 }
481 }
482
483 return l;
484 }
485
486 int
487 lookupd_query(ni_proplist *l, ni_proplist ***out)
488 {
489 unsigned datalen;
490 XDR outxdr;
491 XDR inxdr;
492 int proc;
493 char *listbuf, *s;
494 char databuf[_LU_MAXLUSTRLEN * BYTES_PER_XDR_UNIT];
495 int n, i, j, na;
496 kern_return_t status;
497 ni_property *p;
498
499 if (l == NULL) return 0;
500 if (out == NULL) return 0;
501
502 if (_lu_port == MACH_PORT_NULL) return 0;
503
504 status = _lookup_link(_lu_port, "query", &proc);
505 if (status != KERN_SUCCESS) return 0;
506
507 xdrmem_create(&outxdr, databuf, sizeof(databuf), XDR_ENCODE);
508
509 na = l->ni_proplist_len;
510
511 /* Encode attribute count */
512 if (!xdr_int(&outxdr, &na))
513 {
514 xdr_destroy(&outxdr);
515 return 0;
516 }
517
518 for (i = 0; i < l->ni_proplist_len; i++)
519 {
520 p = &(l->ni_proplist_val[i]);
521 s = p->nip_name;
522 if (!xdr_string(&outxdr, &s, _LU_MAXLUSTRLEN))
523 {
524 xdr_destroy(&outxdr);
525 return 0;
526 }
527
528 if (!xdr_int(&outxdr, &(p->nip_val.ni_namelist_len)))
529 {
530 xdr_destroy(&outxdr);
531 return 0;
532 }
533
534 for (j = 0; j < p->nip_val.ni_namelist_len; j++)
535 {
536 s = p->nip_val.ni_namelist_val[j];
537 if (!xdr_string(&outxdr, &s, _LU_MAXLUSTRLEN))
538 {
539 xdr_destroy(&outxdr);
540 return 0;
541 }
542 }
543 }
544
545 listbuf = NULL;
546 datalen = 0;
547
548 n = xdr_getpos(&outxdr);
549 status = _lookup_all(_lu_port, proc, (void *)databuf, n, &listbuf, &datalen);
550 if (status != KERN_SUCCESS)
551 {
552 xdr_destroy(&outxdr);
553 return 0;
554 }
555
556 xdr_destroy(&outxdr);
557 datalen *= BYTES_PER_XDR_UNIT;
558 xdrmem_create(&inxdr, listbuf, datalen, XDR_DECODE);
559
560 if (!xdr_int(&inxdr, &n))
561 {
562 xdr_destroy(&inxdr);
563 return 0;
564 }
565
566 if (n == 0)
567 {
568 xdr_destroy(&inxdr);
569 return 0;
570 }
571
572 *out = (ni_proplist **)malloc(n * sizeof(ni_proplist *));
573 if (out == NULL)
574 {
575 xdr_destroy(&inxdr);
576 return 0;
577 }
578
579 for (i = 0; i < n; i++)
580 {
581 (*out)[i] = _lookupd_xdr_dictionary(&inxdr);
582 }
583
584 xdr_destroy(&inxdr);
585
586 vm_deallocate(mach_task_self(), (vm_address_t)listbuf, datalen);
587
588 return n;
589 }
590
591 ni_proplist *
592 lookupd_make_query(char *cat, char *fmt, ...)
593 {
594 va_list ap;
595 char *arg, *f;
596 int na, x;
597 ni_proplist *l;
598 ni_property *p;
599
600 if (fmt == NULL) return NULL;
601 if (fmt[0] != 'k') return NULL;
602
603 l = (ni_proplist *)malloc(sizeof(ni_proplist));
604 if (l == NULL) return NULL;
605
606 NI_INIT(l);
607
608 na = 0;
609 x = -1;
610
611 if (cat != NULL)
612 {
613 l->ni_proplist_val = (ni_property *)malloc(sizeof(ni_property));
614 if (l->ni_proplist_val == NULL)
615 {
616 free(l);
617 return NULL;
618 }
619
620 p = &(l->ni_proplist_val[0]);
621 arg = "_lookup_category";
622 p->nip_name = strdup(arg);
623 if (p->nip_name == NULL)
624 {
625 ni_proplist_free(l);
626 return NULL;
627 }
628
629 p->nip_val.ni_namelist_len = 1;
630 p->nip_val.ni_namelist_val = (ni_name *)malloc(sizeof(ni_name));
631 if (p->nip_val.ni_namelist_val == NULL)
632 {
633 ni_proplist_free(l);
634 return NULL;
635 }
636
637 p->nip_val.ni_namelist_val[0] = strdup(cat);
638 if (p->nip_val.ni_namelist_val[0] == NULL)
639 {
640 ni_proplist_free(l);
641 return NULL;
642 }
643
644 l->ni_proplist_len++;
645 x++;
646 }
647
648 va_start(ap, fmt);
649 for (f = fmt; (*f) != '\0'; f++)
650 {
651 arg = va_arg(ap, char *);
652 if (*f == 'k')
653 {
654 l->ni_proplist_val = (ni_property *)reallocf(l->ni_proplist_val, (l->ni_proplist_len + 1) * sizeof(ni_property));
655 if (l->ni_proplist_val == NULL)
656 {
657 ni_proplist_free(l);
658 return NULL;
659 }
660
661 p = &(l->ni_proplist_val[l->ni_proplist_len]);
662 p->nip_name = strdup(arg);
663 if (p->nip_name == NULL)
664 {
665 ni_proplist_free(l);
666 return NULL;
667 }
668
669 p->nip_val.ni_namelist_len = 0;
670 p->nip_val.ni_namelist_val = NULL;
671
672 l->ni_proplist_len++;
673 x++;
674 }
675 else
676 {
677 p = &(l->ni_proplist_val[x]);
678 if (p->nip_val.ni_namelist_len == 0)
679 {
680 p->nip_val.ni_namelist_val = (ni_name *)malloc(sizeof(ni_name));
681 }
682 else
683 {
684 p->nip_val.ni_namelist_val = (ni_name *)reallocf(p->nip_val.ni_namelist_val, (p->nip_val.ni_namelist_len + 1) * sizeof(ni_name));
685 }
686
687 if (p->nip_val.ni_namelist_val == NULL)
688 {
689 ni_proplist_free(l);
690 return NULL;
691 }
692
693 p->nip_val.ni_namelist_val[p->nip_val.ni_namelist_len] = strdup(arg);
694 if (p->nip_val.ni_namelist_val[p->nip_val.ni_namelist_len] == NULL)
695 {
696 ni_proplist_free(l);
697 return NULL;
698 }
699
700 p->nip_val.ni_namelist_len++;
701 }
702 }
703 va_end(ap);
704
705 return l;
706 }
707
708 void
709 ni_property_merge(ni_property *a, ni_property *b)
710 {
711 int i, j, addme;
712
713 if (a == NULL) return;
714 if (b == NULL) return;
715
716 for (j = 0; j < b->nip_val.ni_namelist_len; j++)
717 {
718 addme = 1;
719 for (i = 0; i < (a->nip_val.ni_namelist_len) && (addme == 1); i++)
720 {
721 if (!strcmp(a->nip_val.ni_namelist_val[i], b->nip_val.ni_namelist_val[j])) addme = 0;
722 }
723
724 if (addme == 1)
725 {
726 a->nip_val.ni_namelist_val = (ni_name *)reallocf(a->nip_val.ni_namelist_val, (a->nip_val.ni_namelist_len + 1) * sizeof(ni_name));
727 if (a->nip_val.ni_namelist_val == NULL) return;
728
729 a->nip_val.ni_namelist_val[a->nip_val.ni_namelist_len] = strdup(b->nip_val.ni_namelist_val[j]);
730 if (a->nip_val.ni_namelist_val[a->nip_val.ni_namelist_len] == NULL)
731 {
732 free(a->nip_val.ni_namelist_val);
733 a->nip_val.ni_namelist_val = NULL;
734 return;
735 }
736
737 a->nip_val.ni_namelist_len++;
738 }
739 }
740 }
741
742 void
743 ni_proplist_merge(ni_proplist *a, ni_proplist *b)
744 {
745 ni_index wa, wb;
746 int addme;
747
748 if (a == NULL) return;
749 if (b == NULL) return;
750
751 for (wb = 0; wb < b->ni_proplist_len; wb++)
752 {
753 addme = 1;
754 for (wa = 0; (wa < a->ni_proplist_len) && (addme == 1) ; wa++)
755 {
756 if (!strcmp(a->ni_proplist_val[wa].nip_name, b->ni_proplist_val[wb].nip_name)) addme = 0;
757 }
758 if (addme == 1)
759 {
760 a->ni_proplist_val = (ni_property *)reallocf(a->ni_proplist_val, (a->ni_proplist_len + 1) * sizeof(ni_property));
761 if (a->ni_proplist_val == NULL) return;
762
763 a->ni_proplist_val[a->ni_proplist_len].nip_name = strdup(b->ni_proplist_val[wb].nip_name);
764 if (a->ni_proplist_val[a->ni_proplist_len].nip_name == NULL)
765 {
766 free(a->ni_proplist_val);
767 a->ni_proplist_val = NULL;
768 return NULL;
769 }
770
771 a->ni_proplist_val[a->ni_proplist_len].nip_val.ni_namelist_len = 0;
772 a->ni_proplist_val[a->ni_proplist_len].nip_val.ni_namelist_val = NULL;
773 a->ni_proplist_len++;
774 }
775 }
776
777 for (wb = 0; wb < b->ni_proplist_len; wb++)
778 {
779 for (wa = 0; wa < a->ni_proplist_len; wa++)
780 {
781 if (!strcmp(a->ni_proplist_val[wa].nip_name, b->ni_proplist_val[wb].nip_name))
782 {
783 ni_property_merge(&(a->ni_proplist_val[wa]), &(b->ni_proplist_val[wb]));
784 }
785 }
786 }
787 }
788
789 static void
790 _lu_data_free(void *x)
791 {
792 struct _lu_data_s *t;
793 int i;
794
795 if (x == NULL) return;
796
797 t = (struct _lu_data_s *)x;
798
799 for (i = 0; i < t->icount; i++)
800 {
801 if ((t->idata[i] != NULL) && (t->idata_destructor[i] != NULL))
802 {
803 (*(t->idata_destructor[i]))(t->idata[i]);
804 }
805
806 t->idata[i] = NULL;
807 t->idata_destructor[i] = NULL;
808 }
809
810 if (t->ikey != NULL) free(t->ikey);
811 t->ikey = NULL;
812
813 if (t->idata != NULL) free(t->idata);
814 t->idata = NULL;
815
816 if (t->idata_destructor != NULL) free(t->idata_destructor);
817 t->idata_destructor = NULL;
818
819 free(t);
820 }
821
822 static void
823 _lu_data_init()
824 {
825 pthread_key_create(&_info_key, _lu_data_free);
826 return;
827 }
828
829 static struct _lu_data_s *
830 _lu_data_get()
831 {
832 struct _lu_data_s *libinfo_data;
833
834 /*
835 * Only one thread should create the _info_key
836 */
837 pthread_once(&_info_key_initialized, _lu_data_init);
838
839 /* Check if this thread already created libinfo_data */
840 libinfo_data = pthread_getspecific(_info_key);
841 if (libinfo_data != NULL) return libinfo_data;
842
843 libinfo_data = (struct _lu_data_s *)calloc(1, sizeof(struct _lu_data_s));
844 if (libinfo_data == NULL) return NULL;
845
846 pthread_setspecific(_info_key, libinfo_data);
847 return libinfo_data;
848 }
849
850 void *
851 _lu_data_create_key(unsigned int key, void (*destructor)(void *))
852 {
853 struct _lu_data_s *libinfo_data;
854 unsigned int i, n;
855
856 libinfo_data = _lu_data_get();
857 if (libinfo_data == NULL) return NULL;
858
859 for (i = 0; i < libinfo_data->icount; i++)
860 {
861 if (libinfo_data->ikey[i] == key) return libinfo_data->idata[i];
862 }
863
864 i = libinfo_data->icount;
865 n = i + 1;
866
867 if (i == 0)
868 {
869 libinfo_data->ikey = (unsigned int *)malloc(sizeof(unsigned int));
870 libinfo_data->idata = (void **)malloc(sizeof(void *));
871 libinfo_data->idata_destructor = (void (**)(void *))malloc(sizeof(void (*)(void *)));
872 }
873 else
874 {
875 libinfo_data->ikey = (unsigned int *)reallocf(libinfo_data->ikey, n * sizeof(unsigned int));
876 libinfo_data->idata = (void **)reallocf(libinfo_data->idata, n * sizeof(void *));
877 libinfo_data->idata_destructor = (void (**)(void *))reallocf(libinfo_data->idata_destructor, n * sizeof(void (*)(void *)));
878 }
879
880 if ((libinfo_data->ikey == NULL) || (libinfo_data->idata == NULL) || (libinfo_data->idata_destructor == NULL))
881 {
882 if (libinfo_data->ikey != NULL) free(libinfo_data->ikey);
883 if (libinfo_data->idata != NULL) free(libinfo_data->idata);
884 if (libinfo_data->idata_destructor != NULL) free(libinfo_data->idata_destructor);
885 return NULL;
886 }
887
888 libinfo_data->ikey[i] = key;
889 libinfo_data->idata[i] = NULL;
890 libinfo_data->idata_destructor[i] = destructor;
891 libinfo_data->icount++;
892
893 return NULL;
894 }
895
896 static unsigned int
897 _lu_data_index(unsigned int key, struct _lu_data_s *libinfo_data)
898 {
899 unsigned int i;
900
901 if (libinfo_data == NULL) return (unsigned int)-1;
902
903 for (i = 0; i < libinfo_data->icount; i++)
904 {
905 if (libinfo_data->ikey[i] == key) return i;
906 }
907
908 return (unsigned int)-1;
909 }
910
911 void
912 _lu_data_set_key(unsigned int key, void *data)
913 {
914 struct _lu_data_s *libinfo_data;
915 unsigned int i;
916
917 libinfo_data = _lu_data_get();
918 if (libinfo_data == NULL) return;
919
920 i = _lu_data_index(key, libinfo_data);
921 if (i == (unsigned int)-1) return;
922
923 libinfo_data->idata[i] = data;
924 }
925
926 void *
927 _lu_data_get_key(unsigned int key)
928 {
929 struct _lu_data_s *libinfo_data;
930 unsigned int i;
931
932 libinfo_data = _lu_data_get();
933 if (libinfo_data == NULL) return NULL;
934
935 i = _lu_data_index(key, libinfo_data);
936 if (i == (unsigned int)-1) return NULL;
937
938 return libinfo_data->idata[i];
939 }
940
941 void
942 _lu_data_free_vm_xdr(struct lu_thread_info *tdata)
943 {
944 if (tdata == NULL) return;
945
946 if (tdata->lu_vm != NULL)
947 {
948 vm_deallocate(mach_task_self(), (vm_address_t)tdata->lu_vm, tdata->lu_vm_length);
949 tdata->lu_vm = NULL;
950 }
951 tdata->lu_vm_length = 0;
952 tdata->lu_vm_cursor = 0;
953
954 if (tdata->lu_xdr != NULL)
955 {
956 xdr_destroy(tdata->lu_xdr);
957 free(tdata->lu_xdr);
958 tdata->lu_xdr = NULL;
959 }
960 }
961
962 int
963 _lu_xdr_attribute(XDR *xdr, char **key, char ***val, unsigned int *count)
964 {
965 unsigned int i, j, len;
966 char **x, *s;
967
968 if (xdr == NULL) return -1;
969 if (key == NULL) return -1;
970 if (val == NULL) return -1;
971 if (count == NULL) return -1;
972
973 *key = NULL;
974 *val = NULL;
975 *count = 0;
976
977 if (!xdr_string(xdr, key, -1)) return -1;
978
979 if (!xdr_int(xdr, &len))
980 {
981 free(*key);
982 *key = NULL;
983 return -1;
984 }
985
986 if (len == 0) return 0;
987 *count = len;
988
989 x = (char **)calloc(len + 1, sizeof(char *));
990 if (x == NULL) return -1;
991
992 *val = x;
993
994 for (i = 0; i < len; i++)
995 {
996 s = NULL;
997 if (!xdr_string(xdr, &s, -1))
998 {
999 for (j = 0; j < i; j++) free(x[j]);
1000 free(x);
1001 *val = NULL;
1002 free(*key);
1003 *key = NULL;
1004 *count = 0;
1005 return -1;
1006 }
1007 x[i] = s;
1008 }
1009
1010 x[len] = NULL;
1011
1012 return 0;
1013 }
1014
1015 kern_return_t
1016 _lookup_link(mach_port_t server, lookup_name name, int *procno)
1017 {
1018 kern_return_t status;
1019 security_token_t token;
1020 unsigned int n;
1021
1022 token.val[0] = -1;
1023 token.val[1] = -1;
1024
1025 status = MIG_SERVER_DIED;
1026 for (n = 0; (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
1027 {
1028 status = _lookup_link_secure(server, name, procno, &token);
1029 }
1030
1031 if (status != KERN_SUCCESS)
1032 {
1033 #ifdef DEBUG
1034 syslog(LOG_DEBUG, "pid %u _lookup_link %s status %u", getpid(), name, status);
1035 #endif
1036 return status;
1037 }
1038
1039 if (token.val[0] != 0)
1040 {
1041 #ifdef DEBUG
1042 syslog(LOG_DEBUG, "pid %u _lookup_link %s auth failure uid=%d", getpid(), name, token.val[0]);
1043 #endif
1044 return KERN_FAILURE;
1045 }
1046
1047 #ifdef DEBUG
1048 syslog(LOG_DEBUG, "pid %u _lookup_link %s = %d", getpid(), name, *procno);
1049 #endif
1050 return status;
1051 }
1052
1053 kern_return_t
1054 _lookup_one(mach_port_t server, int proc, inline_data indata, mach_msg_type_number_t indataCnt, inline_data outdata, mach_msg_type_number_t *outdataCnt)
1055 {
1056 kern_return_t status;
1057 security_token_t token;
1058 unsigned int n;
1059
1060 token.val[0] = -1;
1061 token.val[1] = -1;
1062
1063 status = MIG_SERVER_DIED;
1064 for (n = 0; (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
1065 {
1066 status = _lookup_one_secure(server, proc, indata, indataCnt, outdata, outdataCnt, &token);
1067 }
1068
1069 if (status != KERN_SUCCESS)
1070 {
1071 #ifdef DEBUG
1072 syslog(LOG_DEBUG, "pid %u _lookup_one %d status %u", getpid(), proc, status);
1073 #endif
1074 return status;
1075 }
1076
1077 if (token.val[0] != 0)
1078 {
1079 #ifdef DEBUG
1080 syslog(LOG_DEBUG, "pid %u _lookup_one %d auth failure uid=%d", getpid(), proc, token.val[0]);
1081 #endif
1082 return KERN_FAILURE;
1083 }
1084
1085 #ifdef DEBUG
1086 syslog(LOG_DEBUG, "pid %u _lookup_one %d", getpid(), proc);
1087 #endif
1088 return status;
1089 }
1090
1091 kern_return_t
1092 _lookup_all(mach_port_t server, int proc, inline_data indata, mach_msg_type_number_t indataCnt, ooline_data *outdata, mach_msg_type_number_t *outdataCnt)
1093 {
1094 kern_return_t status;
1095 security_token_t token;
1096 unsigned int n;
1097
1098 token.val[0] = -1;
1099 token.val[1] = -1;
1100
1101 status = MIG_SERVER_DIED;
1102 for (n = 0; (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
1103 {
1104 status = _lookup_all_secure(server, proc, indata, indataCnt, outdata, outdataCnt, &token);
1105 }
1106
1107 if (status != KERN_SUCCESS)
1108 {
1109 #ifdef DEBUG
1110 syslog(LOG_DEBUG, "pid %u _lookup_all %d status %u", getpid(), proc, status);
1111 #endif
1112 return status;
1113 }
1114
1115 if (token.val[0] != 0)
1116 {
1117 #ifdef DEBUG
1118 syslog(LOG_DEBUG, "pid %u _lookup_all %d auth failure uid=%d", getpid(), proc, token.val[0]);
1119 #endif
1120 return KERN_FAILURE;
1121 }
1122
1123 #ifdef DEBUG
1124 syslog(LOG_DEBUG, "pid %u _lookup_all %d", getpid(), proc);
1125 #endif
1126 return status;
1127 }
1128
1129 kern_return_t
1130 _lookup_ooall(mach_port_t server, int proc, ooline_data indata, mach_msg_type_number_t indataCnt, ooline_data *outdata, mach_msg_type_number_t *outdataCnt)
1131 {
1132 kern_return_t status;
1133 security_token_t token;
1134 unsigned int n;
1135
1136 token.val[0] = -1;
1137 token.val[1] = -1;
1138
1139 status = MIG_SERVER_DIED;
1140 for (n = 0; (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
1141 {
1142 status = _lookup_ooall_secure(server, proc, indata, indataCnt, outdata, outdataCnt, &token);
1143 }
1144
1145 if (status != KERN_SUCCESS)
1146 {
1147 #ifdef DEBUG
1148 syslog(LOG_DEBUG, "pid %u _lookup_ooall %d status %u", getpid(), proc, status);
1149 #endif
1150 return status;
1151 }
1152
1153 if (token.val[0] != 0)
1154 {
1155 #ifdef DEBUG
1156 syslog(LOG_DEBUG, "pid %u _lookup_ooall %d auth failure uid=%d", getpid(), proc, token.val[0]);
1157 #endif
1158 return KERN_FAILURE;
1159 }
1160
1161 #ifdef DEBUG
1162 syslog(LOG_DEBUG, "pid %u _lookup_ooall %d", getpid(), proc);
1163 #endif
1164 return status;
1165 }