Libinfo-129.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
36 #define MAX_LOOKUP_ATTEMPTS 10
37
38 static pthread_key_t _info_key = NULL;
39 static pthread_once_t _info_key_initialized = PTHREAD_ONCE_INIT;
40
41 struct _lu_data_s
42 {
43 unsigned int icount;
44 unsigned int *ikey;
45 void **idata;
46 void (**idata_destructor)(void *);
47 };
48
49 #define _LU_MAXLUSTRLEN 256
50
51 ni_proplist *
52 _lookupd_xdr_dictionary(XDR *inxdr)
53 {
54 int i, nkeys, j, nvals;
55 char *key, *val;
56 ni_proplist *l;
57
58 if (!xdr_int(inxdr, &nkeys)) return NULL;
59
60 l = (ni_proplist *)malloc(sizeof(ni_proplist));
61 NI_INIT(l);
62
63 l->ni_proplist_len = nkeys;
64 l->ni_proplist_val = NULL;
65 if (nkeys > 0)
66 {
67 i = nkeys * sizeof(ni_property);
68 l->ni_proplist_val = (ni_property *)calloc(1, i);
69 }
70
71 for (i = 0; i < nkeys; i++)
72 {
73 key = NULL;
74 if (!xdr_string(inxdr, &key, -1))
75 {
76 ni_proplist_free(l);
77 return NULL;
78 }
79
80 l->ni_proplist_val[i].nip_name = key;
81
82 if (!xdr_int(inxdr, &nvals))
83 {
84 ni_proplist_free(l);
85 return NULL;
86 }
87
88 l->ni_proplist_val[i].nip_val.ni_namelist_len = nvals;
89 if (nvals > 0)
90 {
91 j = nvals * sizeof(ni_name);
92 l->ni_proplist_val[i].nip_val.ni_namelist_val = (ni_name *)calloc(1, j);
93 }
94
95 for (j = 0; j < nvals; j++)
96 {
97 val = NULL;
98 if (!xdr_string(inxdr, &val, -1))
99 {
100 ni_proplist_free(l);
101 return NULL;
102 }
103
104 l->ni_proplist_val[i].nip_val.ni_namelist_val[j] = val;
105 }
106 }
107
108 return l;
109 }
110
111 int
112 lookupd_query(ni_proplist *l, ni_proplist ***out)
113 {
114 unsigned datalen;
115 XDR outxdr;
116 XDR inxdr;
117 int proc;
118 char *listbuf, *s;
119 char databuf[_LU_MAXLUSTRLEN * BYTES_PER_XDR_UNIT];
120 int n, i, j, na;
121 kern_return_t status;
122 ni_property *p;
123
124 if (l == NULL) return 0;
125 if (out == NULL) return 0;
126
127 if (_lu_port == NULL) return 0;
128
129 status = _lookup_link(_lu_port, "query", &proc);
130 if (status != KERN_SUCCESS) return 0;
131
132 xdrmem_create(&outxdr, databuf, sizeof(databuf), XDR_ENCODE);
133
134 na = l->ni_proplist_len;
135
136 /* Encode attribute count */
137 if (!xdr_int(&outxdr, &na))
138 {
139 xdr_destroy(&outxdr);
140 return 0;
141 }
142
143 for (i = 0; i < l->ni_proplist_len; i++)
144 {
145 p = &(l->ni_proplist_val[i]);
146 s = NULL;
147 if (!xdr_string(&outxdr, &s, _LU_MAXLUSTRLEN))
148 {
149 xdr_destroy(&outxdr);
150 return 0;
151 }
152 p->nip_name = s;
153
154 if (!xdr_int(&outxdr, &(p->nip_val.ni_namelist_len)))
155 {
156 xdr_destroy(&outxdr);
157 return 0;
158 }
159
160 for (j = 0; j < p->nip_val.ni_namelist_len; j++)
161 {
162 s = NULL;
163 if (!xdr_string(&outxdr, &s, _LU_MAXLUSTRLEN))
164 {
165 xdr_destroy(&outxdr);
166 return 0;
167 }
168 p->nip_val.ni_namelist_val[j] = s;
169 }
170 }
171
172 listbuf = NULL;
173 datalen = 0;
174
175 n = xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT;
176 status = _lookup_all(_lu_port, proc, (unit *)databuf, n, &listbuf, &datalen);
177 if (status != KERN_SUCCESS)
178 {
179 xdr_destroy(&outxdr);
180 return 0;
181 }
182
183 xdr_destroy(&outxdr);
184
185 #ifdef NOTDEF
186 /* NOTDEF because OOL buffers are counted in bytes with untyped IPC */
187 datalen *= BYTES_PER_XDR_UNIT;
188 #endif
189
190 xdrmem_create(&inxdr, listbuf, datalen, XDR_DECODE);
191
192 if (!xdr_int(&inxdr, &n))
193 {
194 xdr_destroy(&inxdr);
195 return 0;
196 }
197
198 if (n == 0)
199 {
200 xdr_destroy(&inxdr);
201 return 0;
202 }
203
204 *out = (ni_proplist **)malloc(n * sizeof(ni_proplist *));
205
206 for (i = 0; i < n; i++)
207 {
208 (*out)[i] = _lookupd_xdr_dictionary(&inxdr);
209 }
210
211 xdr_destroy(&inxdr);
212
213 vm_deallocate(mach_task_self(), (vm_address_t)listbuf, datalen);
214
215 return n;
216 }
217
218 ni_proplist *
219 lookupd_make_query(char *cat, char *fmt, ...)
220 {
221 va_list ap;
222 char *arg, *f;
223 int na, x;
224 ni_proplist *l;
225 ni_property *p;
226
227 if (fmt == NULL) return NULL;
228 if (fmt[0] != 'k') return NULL;
229
230 l = (ni_proplist *)malloc(sizeof(ni_proplist));
231 NI_INIT(l);
232
233 na = 0;
234 x = -1;
235
236 if (cat != NULL)
237 {
238 l->ni_proplist_val = (ni_property *)malloc(sizeof(ni_property));
239 p = &(l->ni_proplist_val[0]);
240 arg = "_lookup_category";
241 p->nip_name = strdup(arg);
242 p->nip_val.ni_namelist_len = 1;
243 p->nip_val.ni_namelist_val = (ni_name *)malloc(sizeof(ni_name));
244 p->nip_val.ni_namelist_val[0] = strdup(cat);
245
246 l->ni_proplist_len++;
247 x++;
248 }
249
250 va_start(ap, fmt);
251 for (f = fmt; *f != NULL; f++)
252 {
253 arg = va_arg(ap, char *);
254 if (*f == 'k')
255 {
256 l->ni_proplist_val = (ni_property *)realloc(l->ni_proplist_val, (l->ni_proplist_len + 1) * sizeof(ni_property));
257
258 p = &(l->ni_proplist_val[l->ni_proplist_len]);
259 p->nip_name = strdup(arg);
260 p->nip_val.ni_namelist_len = 0;
261 p->nip_val.ni_namelist_val = NULL;
262
263 l->ni_proplist_len++;
264 x++;
265 }
266 else
267 {
268 p = &(l->ni_proplist_val[x]);
269 if (p->nip_val.ni_namelist_len == 0)
270 {
271 p->nip_val.ni_namelist_val = (ni_name *)malloc(sizeof(ni_name));
272 }
273 else
274 {
275 p->nip_val.ni_namelist_val = (ni_name *)realloc(p->nip_val.ni_namelist_val, (p->nip_val.ni_namelist_len + 1) * sizeof(ni_name));
276 }
277 p->nip_val.ni_namelist_val[p->nip_val.ni_namelist_len] = strdup(arg);
278 p->nip_val.ni_namelist_len++;
279 }
280 }
281 va_end(ap);
282
283 return l;
284 }
285
286 void
287 ni_property_merge(ni_property *a, ni_property *b)
288 {
289 int i, j, addme;
290
291 if (a == NULL) return;
292 if (b == NULL) return;
293
294 for (j = 0; j < b->nip_val.ni_namelist_len; j++)
295 {
296 addme = 1;
297 for (i = 0; i < (a->nip_val.ni_namelist_len) && (addme == 1); i++)
298 {
299 if (!strcmp(a->nip_val.ni_namelist_val[i], b->nip_val.ni_namelist_val[j])) addme = 0;
300 }
301
302 if (addme == 1)
303 {
304 a->nip_val.ni_namelist_val = (ni_name *)realloc(a->nip_val.ni_namelist_val, (a->nip_val.ni_namelist_len + 1) * sizeof(ni_name));
305 a->nip_val.ni_namelist_val[a->nip_val.ni_namelist_len] = strdup(b->nip_val.ni_namelist_val[j]);
306 a->nip_val.ni_namelist_len++;
307 }
308 }
309 }
310
311 void
312 ni_proplist_merge(ni_proplist *a, ni_proplist *b)
313 {
314 ni_index wa, wb;
315 int addme;
316
317 if (a == NULL) return;
318 if (b == NULL) return;
319
320 for (wb = 0; wb < b->ni_proplist_len; wb++)
321 {
322 addme = 1;
323 for (wa = 0; (wa < a->ni_proplist_len) && (addme == 1) ; wa++)
324 {
325 if (!strcmp(a->ni_proplist_val[wa].nip_name, b->ni_proplist_val[wb].nip_name)) addme = 0;
326 }
327 if (addme == 1)
328 {
329 a->ni_proplist_val = (ni_property *)realloc(a->ni_proplist_val, (a->ni_proplist_len + 1) * sizeof(ni_property));
330 a->ni_proplist_val[a->ni_proplist_len].nip_name = strdup(b->ni_proplist_val[wb].nip_name);
331 a->ni_proplist_val[a->ni_proplist_len].nip_val.ni_namelist_len = 0;
332 a->ni_proplist_val[a->ni_proplist_len].nip_val.ni_namelist_val = NULL;
333 a->ni_proplist_len++;
334 }
335 }
336
337 for (wb = 0; wb < b->ni_proplist_len; wb++)
338 {
339 for (wa = 0; wa < a->ni_proplist_len; wa++)
340 {
341 if (!strcmp(a->ni_proplist_val[wa].nip_name, b->ni_proplist_val[wb].nip_name))
342 {
343 ni_property_merge(&(a->ni_proplist_val[wa]), &(b->ni_proplist_val[wb]));
344 }
345 }
346 }
347 }
348
349 static void
350 _lu_data_free(void *x)
351 {
352 struct _lu_data_s *t;
353 int i;
354
355 if (x == NULL) return;
356
357 t = (struct _lu_data_s *)x;
358
359 for (i = 0; i < t->icount; i++)
360 {
361 if ((t->idata[i] != NULL) && (t->idata_destructor[i] != NULL))
362 {
363 (*(t->idata_destructor[i]))(t->idata[i]);
364 }
365
366 t->idata[i] = NULL;
367 t->idata_destructor[i] = NULL;
368 }
369
370 if (t->ikey != NULL) free(t->ikey);
371 t->ikey = NULL;
372
373 if (t->idata != NULL) free(t->idata);
374 t->idata = NULL;
375
376 if (t->idata_destructor != NULL) free(t->idata_destructor);
377 t->idata_destructor = NULL;
378
379 free(t);
380 }
381
382 static void
383 _lu_data_init()
384 {
385 pthread_key_create(&_info_key, _lu_data_free);
386 return;
387 }
388
389 static struct _lu_data_s *
390 _lu_data_get()
391 {
392 struct _lu_data_s *libinfo_data;
393
394 /*
395 * Only one thread should create the _info_key
396 */
397 pthread_once(&_info_key_initialized, _lu_data_init);
398
399 /* Check if this thread already created libinfo_data */
400 libinfo_data = pthread_getspecific(_info_key);
401 if (libinfo_data != NULL) return libinfo_data;
402
403 libinfo_data = (struct _lu_data_s *)calloc(1, sizeof(struct _lu_data_s));
404
405 pthread_setspecific(_info_key, libinfo_data);
406 return libinfo_data;
407 }
408
409 void *
410 _lu_data_create_key(unsigned int key, void (*destructor)(void *))
411 {
412 struct _lu_data_s *libinfo_data;
413 unsigned int i, n;
414
415 libinfo_data = _lu_data_get();
416
417 for (i = 0; i < libinfo_data->icount; i++)
418 {
419 if (libinfo_data->ikey[i] == key) return libinfo_data->idata[i];
420 }
421
422 i = libinfo_data->icount;
423 n = i + 1;
424
425 if (i == 0)
426 {
427 libinfo_data->ikey = (unsigned int *)malloc(sizeof(unsigned int));
428 libinfo_data->idata = (void **)malloc(sizeof(void *));
429 libinfo_data->idata_destructor = (void (**)(void *))malloc(sizeof(void (*)(void *)));
430 }
431 else
432 {
433 libinfo_data->ikey = (unsigned int *)realloc(libinfo_data->ikey, n * sizeof(unsigned int));
434 libinfo_data->idata = (void **)realloc(libinfo_data->idata, n * sizeof(void *));
435 libinfo_data->idata_destructor = (void (**)(void *))realloc(libinfo_data->idata_destructor, n * sizeof(void (*)(void *)));
436 }
437
438 libinfo_data->ikey[i] = key;
439 libinfo_data->idata[i] = NULL;
440 libinfo_data->idata_destructor[i] = destructor;
441 libinfo_data->icount++;
442
443 return NULL;
444 }
445
446 static unsigned int
447 _lu_data_index(unsigned int key, struct _lu_data_s *libinfo_data)
448 {
449 unsigned int i;
450
451 if (libinfo_data == NULL) return (unsigned int)-1;
452
453 for (i = 0; i < libinfo_data->icount; i++)
454 {
455 if (libinfo_data->ikey[i] == key) return i;
456 }
457
458 return (unsigned int)-1;
459 }
460
461 void
462 _lu_data_set_key(unsigned int key, void *data)
463 {
464 struct _lu_data_s *libinfo_data;
465 unsigned int i;
466
467 libinfo_data = _lu_data_get();
468
469 i = _lu_data_index(key, libinfo_data);
470 if (i == (unsigned int)-1) return;
471
472 libinfo_data->idata[i] = data;
473 }
474
475 void *
476 _lu_data_get_key(unsigned int key)
477 {
478 struct _lu_data_s *libinfo_data;
479 unsigned int i;
480
481 libinfo_data = _lu_data_get();
482
483 i = _lu_data_index(key, libinfo_data);
484 if (i == (unsigned int)-1) return NULL;
485
486 return libinfo_data->idata[i];
487 }
488
489 void
490 _lu_data_free_vm_xdr(struct lu_thread_info *tdata)
491 {
492 if (tdata == NULL) return;
493
494 if (tdata->lu_vm != NULL)
495 {
496 vm_deallocate(mach_task_self(), (vm_address_t)tdata->lu_vm, tdata->lu_vm_length);
497 tdata->lu_vm = NULL;
498 }
499 tdata->lu_vm_length = 0;
500 tdata->lu_vm_cursor = 0;
501
502 if (tdata->lu_xdr != NULL)
503 {
504 xdr_destroy(tdata->lu_xdr);
505 free(tdata->lu_xdr);
506 tdata->lu_xdr = NULL;
507 }
508 }
509
510 int
511 _lu_xdr_attribute(XDR *xdr, char **key, char ***val, unsigned int *count)
512 {
513 unsigned int i, j, len;
514 char **x, *s;
515
516 if (xdr == NULL) return -1;
517 if (key == NULL) return -1;
518 if (val == NULL) return -1;
519 if (count == NULL) return -1;
520
521 *key = NULL;
522 *val = NULL;
523 *count = 0;
524
525 if (!xdr_string(xdr, key, -1)) return -1;
526
527 if (!xdr_int(xdr, &len))
528 {
529 free(*key);
530 *key = NULL;
531 return -1;
532 }
533
534 if (len == 0) return 0;
535 *count = len;
536
537 x = (char **)calloc(len + 1, sizeof(char *));
538 *val = x;
539
540 for (i = 0; i < len; i++)
541 {
542 s = NULL;
543 if (!xdr_string(xdr, &s, -1))
544 {
545 for (j = 0; j < i; j++) free(x[j]);
546 free(x);
547 *val = NULL;
548 free(*key);
549 *key = NULL;
550 *count = 0;
551 return -1;
552 }
553 x[i] = s;
554 }
555
556 x[len] = NULL;
557
558 return 0;
559 }
560
561 kern_return_t
562 _lookup_link(mach_port_t server, lookup_name name, int *procno)
563 {
564 kern_return_t status;
565 security_token_t token;
566 unsigned int n;
567
568 token.val[0] = -1;
569 token.val[1] = -1;
570
571 status = MIG_SERVER_DIED;
572 for (n = 0; (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
573 {
574 status = _lookup_link_secure(server, name, procno, &token);
575 }
576
577 if (status != KERN_SUCCESS)
578 {
579 #ifdef DEBUG
580 syslog(LOG_DEBUG, "pid %u _lookup_link %s status %u", getpid(), name, status);
581 #endif
582 return status;
583 }
584
585 if (token.val[0] != 0)
586 {
587 #ifdef DEBUG
588 syslog(LOG_DEBUG, "pid %u _lookup_link %s auth failure uid=%d", getpid(), name, token.val[0]);
589 #endif
590 return KERN_FAILURE;
591 }
592
593 #ifdef DEBUG
594 syslog(LOG_DEBUG, "pid %u _lookup_link %s = %d", getpid(), name, *procno);
595 #endif
596 return status;
597 }
598
599 kern_return_t
600 _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)
601 {
602 kern_return_t status;
603 security_token_t token;
604 unsigned int n;
605
606 token.val[0] = -1;
607 token.val[1] = -1;
608
609 status = MIG_SERVER_DIED;
610 for (n = 0; (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
611 {
612 status = _lookup_one_secure(server, proc, indata, indataCnt, outdata, outdataCnt, &token);
613 }
614
615 if (status != KERN_SUCCESS)
616 {
617 #ifdef DEBUG
618 syslog(LOG_DEBUG, "pid %u _lookup_one %d status %u", getpid(), proc, status);
619 #endif
620 return status;
621 }
622
623 if (token.val[0] != 0)
624 {
625 #ifdef DEBUG
626 syslog(LOG_DEBUG, "pid %u _lookup_one %d auth failure uid=%d", getpid(), proc, token.val[0]);
627 #endif
628 return KERN_FAILURE;
629 }
630
631 #ifdef DEBUG
632 syslog(LOG_DEBUG, "pid %u _lookup_one %d", getpid(), proc);
633 #endif
634 return status;
635 }
636
637 kern_return_t
638 _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)
639 {
640 kern_return_t status;
641 security_token_t token;
642 unsigned int n;
643
644 token.val[0] = -1;
645 token.val[1] = -1;
646
647 status = MIG_SERVER_DIED;
648 for (n = 0; (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
649 {
650 status = _lookup_all_secure(server, proc, indata, indataCnt, outdata, outdataCnt, &token);
651 }
652
653 if (status != KERN_SUCCESS)
654 {
655 #ifdef DEBUG
656 syslog(LOG_DEBUG, "pid %u _lookup_all %d status %u", getpid(), proc, status);
657 #endif
658 return status;
659 }
660
661 if (token.val[0] != 0)
662 {
663 #ifdef DEBUG
664 syslog(LOG_DEBUG, "pid %u _lookup_all %d auth failure uid=%d", getpid(), proc, token.val[0]);
665 #endif
666 return KERN_FAILURE;
667 }
668
669 #ifdef DEBUG
670 syslog(LOG_DEBUG, "pid %u _lookup_all %d", getpid(), proc);
671 #endif
672 return status;
673 }
674
675 kern_return_t
676 _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)
677 {
678 kern_return_t status;
679 security_token_t token;
680 unsigned int n;
681
682 token.val[0] = -1;
683 token.val[1] = -1;
684
685 status = MIG_SERVER_DIED;
686 for (n = 0; (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
687 {
688 status = _lookup_ooall_secure(server, proc, indata, indataCnt, outdata, outdataCnt, &token);
689 }
690
691 if (status != KERN_SUCCESS)
692 {
693 #ifdef DEBUG
694 syslog(LOG_DEBUG, "pid %u _lookup_ooall %d status %u", getpid(), proc, status);
695 #endif
696 return status;
697 }
698
699 if (token.val[0] != 0)
700 {
701 #ifdef DEBUG
702 syslog(LOG_DEBUG, "pid %u _lookup_ooall %d auth failure uid=%d", getpid(), proc, token.val[0]);
703 #endif
704 return KERN_FAILURE;
705 }
706
707 #ifdef DEBUG
708 syslog(LOG_DEBUG, "pid %u _lookup_ooall %d", getpid(), proc);
709 #endif
710 return status;
711 }