#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
#include <pthread.h>
#include <errno.h>
#include <notify.h>
#include <syslog.h>
#include <unistd.h>
#ifdef DEBUG
#include <asl.h>
#endif
#include "lu_utils.h"
#include "netdb_async.h"
#include "DSlibinfoMIG.h"
#include "DSlibinfoMIGAsyncReply.h"
#define MAX_LOOKUP_ATTEMPTS 10
#define _LU_MAXLUSTRLEN 256
#define QBUF_SIZE 16384
#define KVBUF_START_SIZE 128
#define LI_MESSAGE_SEND_ID 4241776
#define LI_MESSAGE_REPLY_ID 4241876
#define ILS_MAGIC_SIZE 8
#define ILS_MAGIC "ILSMAGIC"
#define L1_CACHE_NOTIFICATION_KEY_GLOBAL "com.apple.system.DirectoryService.InvalidateCache"
#define L1_CACHE_NOTIFICATION_KEY_GROUP "com.apple.system.DirectoryService.InvalidateCache.group"
#define L1_CACHE_NOTIFICATION_KEY_HOST "com.apple.system.DirectoryService.InvalidateCache.host"
#define L1_CACHE_NOTIFICATION_KEY_SERVICE "com.apple.system.DirectoryService.InvalidateCache.service"
#define L1_CACHE_NOTIFICATION_KEY_USER "com.apple.system.DirectoryService.InvalidateCache.user"
uint32_t gL1CacheEnabled = 1;
static const uint32_t align_32[] = { 0, 1, 2, 0, 4, 0, 0, 0, 4 };
static const uint32_t align_64[] = { 0, 1, 2, 0, 4, 0, 0, 0, 8 };
static pthread_key_t _info_key = 0;
static pthread_once_t _info_key_initialized = PTHREAD_ONCE_INIT;
static pthread_mutex_t _notify_lock = PTHREAD_MUTEX_INITIALIZER;
static int _L1_notify_token[] =
{
-1,
-1,
-1,
-1,
-1
};
struct _li_data_s
{
uint32_t icount;
uint32_t *ikey;
void **idata;
};
typedef struct _li_async_request_s
{
mach_port_t reply_port;
uint32_t retry;
uint32_t proc;
void *context;
void *callback;
char request[MAX_MIG_INLINE_DATA];
mach_msg_type_number_t requestCnt;
char reply[MAX_MIG_INLINE_DATA];
mach_msg_type_number_t replyCnt;
vm_address_t ooreply;
mach_msg_type_number_t ooreplyCnt;
security_token_t token;
struct _li_async_request_s *next;
} _li_async_request_t;
static pthread_mutex_t _li_worklist_lock = PTHREAD_MUTEX_INITIALIZER;
static _li_async_request_t *_li_worklist = NULL;
static kern_return_t
_LI_async_send(_li_async_request_t *r)
{
mach_msg_return_t status;
mach_vm_address_t cb;
if (r == NULL) return KERN_FAILURE;
if (r->retry == 0) return MIG_SERVER_DIED;
r->retry--;
cb = (mach_vm_address_t)(r->callback);
status = libinfoDSmig_Query_async(_ds_port, r->reply_port, r->proc, r->request, r->requestCnt, cb);
if (status == MACH_SEND_INVALID_REPLY)
{
mach_port_mod_refs(mach_task_self(), r->reply_port, MACH_PORT_RIGHT_RECEIVE, -1);
r->reply_port = MACH_PORT_NULL;
}
return status;
}
static _li_async_request_t *
_LI_worklist_remove(mach_port_t p)
{
_li_async_request_t *r, *n;
if (p == MACH_PORT_NULL) return NULL;
if (_li_worklist == NULL) return NULL;
pthread_mutex_lock(&_li_worklist_lock);
if (_li_worklist->reply_port == p)
{
r = _li_worklist;
_li_worklist = r->next;
pthread_mutex_unlock(&_li_worklist_lock);
return r;
}
for (r = _li_worklist; r != NULL; r = r->next)
{
n = r->next;
if (n == NULL) break;
if (n->reply_port == p)
{
r->next = n->next;
pthread_mutex_unlock(&_li_worklist_lock);
return n;
}
}
pthread_mutex_unlock(&_li_worklist_lock);
return NULL;
}
static _li_async_request_t *
_LI_worklist_find(mach_port_t p)
{
_li_async_request_t *r;
if (p == MACH_PORT_NULL) return NULL;
if (_li_worklist == NULL) return NULL;
pthread_mutex_lock(&_li_worklist_lock);
for (r = _li_worklist; r != NULL; r = r->next)
{
if (r->reply_port == p)
{
pthread_mutex_unlock(&_li_worklist_lock);
return r;
}
}
pthread_mutex_unlock(&_li_worklist_lock);
return NULL;
}
static void
_LI_free_request(_li_async_request_t *r)
{
if (r == NULL) return;
if (r->reply_port != MACH_PORT_NULL) mach_port_mod_refs(mach_task_self(), r->reply_port, MACH_PORT_RIGHT_RECEIVE, -1);
r->reply_port = MACH_PORT_NULL;
free(r);
}
__private_extern__ kern_return_t
libinfoDSmig_do_Response_async(mach_port_t server, char *reply, mach_msg_type_number_t replyCnt, vm_offset_t ooreply, mach_msg_type_number_t ooreplyCnt, mach_vm_address_t callbackAddr, security_token_t servertoken)
{
_li_async_request_t *r;
r = _LI_worklist_find(server);
if (r != NULL)
{
r->ooreply = ooreply;
r->ooreplyCnt = ooreplyCnt;
if (replyCnt > 0) memcpy(r->reply, reply, replyCnt);
r->replyCnt = replyCnt;
r->token = servertoken;
}
else if (ooreplyCnt != 0)
{
vm_deallocate(mach_task_self(), ooreply, ooreplyCnt);
}
return KERN_SUCCESS;
}
kern_return_t
LI_async_receive(mach_port_t p, kvarray_t **reply)
{
kern_return_t status;
_li_async_request_t *r;
kvbuf_t *out;
int flags;
flags = MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0);
status = mach_msg_server_once(DSlibinfoMIGAsyncReply_server, 65536, p, flags);
if (status != KERN_SUCCESS) return status;
r = _LI_worklist_remove(p);
if (r == NULL) return KERN_FAILURE;
out = (kvbuf_t *)calloc(1, sizeof(kvbuf_t));
if (out == NULL)
{
if (r->ooreplyCnt > 0) vm_deallocate(mach_task_self(), r->ooreply, r->ooreplyCnt);
return KERN_FAILURE;
}
if (r->ooreplyCnt > 0)
{
out->datalen = r->ooreplyCnt;
out->databuf = malloc(r->ooreplyCnt);
if (out->databuf == NULL)
{
free(out);
*reply = NULL;
vm_deallocate(mach_task_self(), r->ooreply, r->ooreplyCnt);
return KERN_FAILURE;
}
memcpy(out->databuf, (char *)r->ooreply, r->ooreplyCnt);
vm_deallocate(mach_task_self(), r->ooreply, r->ooreplyCnt);
}
else if (r->replyCnt > 0)
{
out->datalen = r->replyCnt;
out->databuf = malloc(r->replyCnt);
if (out->databuf == NULL)
{
free(out);
*reply = NULL;
return KERN_FAILURE;
}
memcpy(out->databuf, r->reply, r->replyCnt);
}
*reply = kvbuf_decode(out);
if (*reply == NULL)
{
free(out->databuf);
free(out);
}
_LI_free_request(r);
return KERN_SUCCESS;
}
static void
_LI_worklist_append(_li_async_request_t *r)
{
_li_async_request_t *p;
if (r == NULL) return;
pthread_mutex_lock(&_li_worklist_lock);
if (_li_worklist == NULL)
{
_li_worklist = r;
pthread_mutex_unlock(&_li_worklist_lock);
return;
}
for (p = _li_worklist; p->next != NULL; p = p->next);
p->next = r;
pthread_mutex_unlock(&_li_worklist_lock);
}
void
LI_async_call_cancel(mach_port_t p, void **context)
{
_li_async_request_t *req;
req = _LI_worklist_remove(p);
if (req != NULL)
{
if (context != NULL) *context = req->context;
_LI_free_request(req);
}
else if (p != MACH_PORT_NULL)
{
mach_port_mod_refs(mach_task_self(), p, MACH_PORT_RIGHT_RECEIVE, -1);
}
}
void
lu_async_call_cancel(mach_port_t p)
{
LI_async_call_cancel(p, NULL);
}
static _li_async_request_t *
_LI_create_request(uint32_t proc, kvbuf_t *query, void *callback, void *context)
{
_li_async_request_t *r;
kern_return_t status;
mach_port_t target;
if (_ds_running() == 0) return NULL;
if (query == NULL) return NULL;
if (query->datalen > MAX_MIG_INLINE_DATA) return NULL;
r = (_li_async_request_t *)calloc(1, sizeof(_li_async_request_t));
if (r == NULL) return NULL;
status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &(r->reply_port));
if (status != KERN_SUCCESS)
{
_LI_free_request(r);
return NULL;
}
target = MACH_PORT_NULL;
mach_port_request_notification(mach_task_self(), r->reply_port, MACH_NOTIFY_NO_SENDERS, 1, r->reply_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &target);
r->retry = MAX_LOOKUP_ATTEMPTS;
r->context = context;
r->callback = callback;
r->proc = proc;
memcpy(r->request, query->databuf, query->datalen);
r->requestCnt = query->datalen;
r->next = NULL;
return r;
}
kern_return_t
LI_async_start(mach_port_t *p, uint32_t proc, kvbuf_t *query, void *callback, void *context)
{
_li_async_request_t *r;
kern_return_t status;
uint32_t retry;
if (p == NULL) return KERN_FAILURE;
*p = MACH_PORT_NULL;
if (_ds_running() == 0) return KERN_FAILURE;
if (_ds_port == MACH_PORT_NULL) return KERN_FAILURE;
r = _LI_create_request(proc, query, callback, context);
if (r == NULL) return KERN_FAILURE;
status = MIG_SERVER_DIED;
for (retry = 0; (status == MIG_SERVER_DIED) && (retry < MAX_LOOKUP_ATTEMPTS); retry++)
{
status = _LI_async_send(r);
}
if (status != KERN_SUCCESS)
{
_LI_free_request(r);
return status;
}
_LI_worklist_append(r);
*p = r->reply_port;
return KERN_SUCCESS;
}
kern_return_t
LI_async_send(mach_port_t *p, uint32_t proc, kvbuf_t *query)
{
return LI_async_start(p, proc, query, NULL, NULL);
}
kern_return_t
LI_async_handle_reply(mach_msg_header_t *msg, kvarray_t **reply, void **callback, void **context)
{
_li_async_request_t *req;
kvbuf_t *out;
kern_return_t status;
uint32_t retry;
mig_reply_error_t *bufReply;
if (msg == NULL) return -1;
if (msg->msgh_id == MACH_NOTIFY_NO_SENDERS)
{
req = _LI_worklist_find(msg->msgh_local_port);
if (req == NULL) return -1;
status = MIG_SERVER_DIED;
for (retry = 0; (status == MIG_SERVER_DIED) && (retry < MAX_LOOKUP_ATTEMPTS); retry++)
{
status = _LI_async_send(req);
}
if (status != KERN_SUCCESS) return -1;
return MIG_REPLY_MISMATCH;
}
mach_msg_size_t reply_alloc = round_page(65536 + MAX_TRAILER_SIZE);
status = vm_allocate(mach_task_self(), (vm_address_t *) &bufReply, reply_alloc, VM_MAKE_TAG(VM_MEMORY_MACH_MSG) | TRUE);
if (status != KERN_SUCCESS) return status;
status = DSlibinfoMIGAsyncReply_server(msg, (mach_msg_header_t *)bufReply);
if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) mach_msg_destroy(&bufReply->Head);
vm_deallocate(mach_task_self(), (vm_address_t) bufReply, reply_alloc);
if (status == FALSE) return KERN_FAILURE;
req = _LI_worklist_remove(msg->msgh_local_port);
if (req == NULL) return KERN_FAILURE;
*callback = req->callback;
*context = req->context;
out = (kvbuf_t *)calloc(1, sizeof(kvbuf_t));
if (out == NULL)
{
if (req->ooreplyCnt > 0) vm_deallocate(mach_task_self(), req->ooreply, req->ooreplyCnt);
return KERN_FAILURE;
}
if (req->ooreplyCnt > 0)
{
out->datalen = req->ooreplyCnt;
out->databuf = malloc(req->ooreplyCnt);
if (out->databuf == NULL)
{
free(out);
*reply = NULL;
vm_deallocate(mach_task_self(), req->ooreply, req->ooreplyCnt);
return KERN_FAILURE;
}
memcpy(out->databuf, (char *)req->ooreply, req->ooreplyCnt);
vm_deallocate(mach_task_self(), req->ooreply, req->ooreplyCnt);
}
else if (req->replyCnt > 0)
{
out->datalen = req->replyCnt;
out->databuf = malloc(req->replyCnt);
if (out->databuf == NULL)
{
free(out);
*reply = NULL;
return KERN_FAILURE;
}
memcpy(out->databuf, req->reply, req->replyCnt);
}
*reply = kvbuf_decode(out);
if (*reply == NULL)
{
free(out->databuf);
free(out);
}
_LI_free_request(req);
return KERN_SUCCESS;
}
static void
_LI_thread_info_free(void *x)
{
struct li_thread_info *tdata;
if (x == NULL) return;
tdata = (struct li_thread_info *)x;
LI_ils_free(tdata->li_entry, tdata->li_entry_size);
LI_data_free_kvarray(tdata);
free(tdata);
}
static void
_LI_data_free(void *x)
{
struct _li_data_s *t;
int i;
if (x == NULL) return;
t = (struct _li_data_s *)x;
for (i = 0; i < t->icount; i++)
{
_LI_thread_info_free(t->idata[i]);
t->idata[i] = NULL;
}
if (t->ikey != NULL) free(t->ikey);
t->ikey = NULL;
if (t->idata != NULL) free(t->idata);
t->idata = NULL;
free(t);
}
static void
_LI_data_init()
{
pthread_key_create(&_info_key, _LI_data_free);
return;
}
static struct _li_data_s *
_LI_data_get()
{
struct _li_data_s *libinfo_data;
pthread_once(&_info_key_initialized, _LI_data_init);
libinfo_data = pthread_getspecific(_info_key);
if (libinfo_data != NULL) return libinfo_data;
libinfo_data = (struct _li_data_s *)calloc(1, sizeof(struct _li_data_s));
if (libinfo_data == NULL) return NULL;
pthread_setspecific(_info_key, libinfo_data);
return libinfo_data;
}
__private_extern__ void *
LI_data_find_key(uint32_t key)
{
struct _li_data_s *libinfo_data;
uint32_t i;
libinfo_data = _LI_data_get();
if (libinfo_data == NULL) return NULL;
for (i = 0; i < libinfo_data->icount; i++)
{
if (libinfo_data->ikey[i] == key) return libinfo_data->idata[i];
}
return NULL;
}
__private_extern__ void *
LI_data_create_key(uint32_t key, size_t esize)
{
struct _li_data_s *libinfo_data;
struct li_thread_info *tdata;
uint32_t i, n;
libinfo_data = _LI_data_get();
if (libinfo_data == NULL) return NULL;
for (i = 0; i < libinfo_data->icount; i++)
{
if (libinfo_data->ikey[i] == key) return libinfo_data->idata[i];
}
i = libinfo_data->icount;
n = i + 1;
if (i == 0)
{
libinfo_data->ikey = (uint32_t *)malloc(sizeof(uint32_t));
libinfo_data->idata = (void **)malloc(sizeof(void *));
}
else
{
libinfo_data->ikey = (uint32_t *)reallocf(libinfo_data->ikey, n * sizeof(uint32_t));
libinfo_data->idata = (void **)reallocf(libinfo_data->idata, n * sizeof(void *));
}
if ((libinfo_data->ikey == NULL) || (libinfo_data->idata == NULL))
{
if (libinfo_data->ikey != NULL) free(libinfo_data->ikey);
libinfo_data->ikey = NULL;
if (libinfo_data->idata != NULL) free(libinfo_data->idata);
libinfo_data->idata = NULL;
return NULL;
}
tdata = (struct li_thread_info *)calloc(1, sizeof(struct li_thread_info));
if (tdata == NULL) return NULL;
tdata->li_entry_size = esize;
libinfo_data->ikey[i] = key;
libinfo_data->idata[i] = tdata;
libinfo_data->icount++;
return tdata;
}
static uint32_t
_LI_data_index(uint32_t key, struct _li_data_s *libinfo_data)
{
uint32_t i;
if (libinfo_data == NULL) return (uint32_t)-1;
for (i = 0; i < libinfo_data->icount; i++)
{
if (libinfo_data->ikey[i] == key) return i;
}
return (uint32_t)-1;
}
void
_LI_data_set_key(uint32_t key, void *data)
{
struct _li_data_s *libinfo_data;
uint32_t i;
libinfo_data = _LI_data_get();
if (libinfo_data == NULL) return;
i = _LI_data_index(key, libinfo_data);
if (i == (uint32_t)-1) return;
libinfo_data->idata[i] = data;
}
void *
_LI_data_get_key(uint32_t key)
{
struct _li_data_s *libinfo_data;
uint32_t i;
libinfo_data = _LI_data_get();
if (libinfo_data == NULL) return NULL;
i = _LI_data_index(key, libinfo_data);
if (i == (uint32_t)-1) return NULL;
return libinfo_data->idata[i];
}
__private_extern__ void
LI_data_free_kvarray(struct li_thread_info *tdata)
{
if (tdata == NULL) return;
if (tdata->li_vm == NULL) return;
kvarray_free((kvarray_t *)tdata->li_vm);
tdata->li_vm = NULL;
}
__private_extern__ void
LI_data_recycle(struct li_thread_info *tdata, void *entry, size_t entrysize)
{
if (tdata == NULL) return;
LI_ils_free(tdata->li_entry, entrysize);
tdata->li_entry = entry;
}
#define KVBUF_CHUNK 256
__private_extern__ kvbuf_t *
kvbuf_query(char *fmt, ...)
{
va_list ap;
char *arg, *f, str[32];
int32_t iarg;
uint32_t uarg;
kvbuf_t *kv;
if (fmt == NULL) return NULL;
kv = kvbuf_new();
if (kv == NULL) return NULL;
kvbuf_add_dict(kv);
va_start(ap, fmt);
for (f = fmt; (*f) != '\0'; f++)
{
if (*f == 'k')
{
arg = va_arg(ap, char *);
kvbuf_add_key(kv, arg);
}
else if (*f == 's')
{
arg = va_arg(ap, char *);
kvbuf_add_val(kv, arg);
}
else if (*f == 'i')
{
iarg = va_arg(ap, int32_t);
snprintf(str, sizeof(str), "%d", iarg);
kvbuf_add_val(kv, str);
}
else if (*f == 'u')
{
uarg = va_arg(ap,uint32_t);
snprintf(str, sizeof(str), "%u", uarg);
kvbuf_add_val(kv, str);
}
}
va_end(ap);
return kv;
}
__private_extern__ kvbuf_t *
kvbuf_query_key_val(const char *key, const char *val)
{
kvbuf_t *kv;
uint32_t x, kl, vl, vc;
char *p;
if (key == NULL) return NULL;
kl = strlen(key) + 1;
vl = 0;
vc = 0;
if (val != NULL)
{
vl = strlen(val) + 1;
vc = 1;
}
kv = (kvbuf_t *)calloc(1, sizeof(kvbuf_t));
if (kv == NULL) return NULL;
kv->_size = (5 * sizeof(uint32_t)) + kl + vl;
kv->datalen = kv->_size;
kv->databuf = calloc(1, kv->_size);
if (kv->databuf == NULL)
{
free(kv);
return NULL;
}
p = kv->databuf;
x = htonl(1);
memcpy(p, &x, sizeof(uint32_t));
p += sizeof(uint32_t);
memcpy(p, &x, sizeof(uint32_t));
p += sizeof(uint32_t);
x = htonl(kl);
memcpy(p, &x, sizeof(uint32_t));
p += sizeof(uint32_t);
memcpy(p, key, kl);
p += kl;
x = htonl(vc);
memcpy(p, &x, sizeof(uint32_t));
p += sizeof(uint32_t);
if (vc > 0)
{
x = htonl(vl);
memcpy(p, &x, sizeof(uint32_t));
p += sizeof(uint32_t);
memcpy(p, val, vl);
}
return kv;
}
__private_extern__ kvbuf_t *
kvbuf_query_key_int(const char *key, int32_t i)
{
char str[32];
snprintf(str, sizeof(str), "%d", i);
return kvbuf_query_key_val(key, str);
}
__private_extern__ kvbuf_t *
kvbuf_query_key_uint(const char *key, uint32_t u)
{
char str[32];
snprintf(str, sizeof(str), "%u", u);
return kvbuf_query_key_val(key, str);
}
kvbuf_t *
kvbuf_new(void)
{
kvbuf_t *kv;
kv = (kvbuf_t *)calloc(1, sizeof(kvbuf_t));
if (kv == NULL) return NULL;
kv->_size = KVBUF_START_SIZE;
kv->databuf = calloc(1, kv->_size);
if (kv->databuf == NULL)
{
free(kv);
return NULL;
}
kv->datalen = sizeof(uint32_t);
kv->_dict = kv->datalen;
return kv;
}
kvbuf_t *
kvbuf_init(char *buffer, uint32_t length)
{
kvbuf_t *kv;
kv = (kvbuf_t *)calloc(1, sizeof(kvbuf_t));
if (kv == NULL) return NULL;
kv->_size = length;
kv->datalen = length;
kv->databuf = calloc(1, length);
if (kv->databuf == NULL)
{
free(kv);
kv = NULL;
}
else
{
memcpy(kv->databuf, buffer, length);
}
return kv;
}
static void
kvbuf_grow(kvbuf_t *kv, uint32_t delta)
{
uint32_t newlen, n;
char *p;
if (kv == NULL) return;
if (delta == 0) return;
if (kv->databuf == NULL) delta += sizeof(uint32_t);
n = (delta + KVBUF_CHUNK - 1) / KVBUF_CHUNK;
newlen = kv->datalen + (n * KVBUF_CHUNK);
if (newlen <= kv->_size) return;
kv->_size = newlen;
if (kv->databuf == NULL)
{
kv->databuf = calloc(1, kv->_size);
if (kv->databuf == NULL)
{
memset(kv, 0, sizeof(kvbuf_t));
return;
}
kv->datalen = sizeof(uint32_t);
kv->_dict = sizeof(uint32_t);
}
else
{
kv->databuf = reallocf(kv->databuf, kv->_size);
if (kv->databuf == NULL)
{
memset(kv, 0, sizeof(kvbuf_t));
return;
}
p = kv->databuf + kv->datalen;
memset(p, 0, kv->_size - kv->datalen);
}
}
void
kvbuf_add_dict(kvbuf_t *kv)
{
char *p;
uint32_t x, dict_count;
if (kv == NULL) return;
kvbuf_grow(kv, sizeof(uint32_t));
if (kv->databuf == NULL) return;
kv->_dict = kv->datalen;
kv->datalen += sizeof(uint32_t);
kv->_key = kv->datalen;
kv->_vlist = 0;
kv->_val = 0;
p = kv->databuf;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
dict_count = ntohl(x);
dict_count++;
x = htonl(dict_count);
memcpy(p, &x, sizeof(uint32_t));
}
void
kvbuf_add_key(kvbuf_t *kv, const char *key)
{
uint32_t kl, x, key_count, delta;
char *p;
if (kv == NULL) return;
if (key == NULL) return;
kl = strlen(key) + 1;
delta = (2 * sizeof(uint32_t)) + kl;
kvbuf_grow(kv, delta);
if (kv->databuf == NULL) return;
p = kv->databuf + kv->_dict;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
key_count = ntohl(x);
if (key_count == 0) kv->_key = kv->_dict + sizeof(uint32_t);
else kv->_key = kv->datalen;
key_count++;
x = htonl(key_count);
memcpy(p, &x, sizeof(uint32_t));
p = kv->databuf + kv->datalen;
x = htonl(kl);
memcpy(p, &x, sizeof(uint32_t));
p += sizeof(uint32_t);
memcpy(p, key, kl);
p += kl;
kv->_vlist = kv->datalen + sizeof(uint32_t) + kl;
x = 0;
memcpy(p, &x, sizeof(uint32_t));
kv->datalen += delta;
kv->_val = kv->datalen;
}
void
kvbuf_add_val_len(kvbuf_t *kv, const char *val, uint32_t len)
{
uint32_t x, val_count, delta;
char *p;
if (kv == NULL) return;
if (val == NULL) return;
if (len == 0) return;
delta = sizeof(uint32_t) + len;
kvbuf_grow(kv, delta);
if (kv->databuf == NULL) return;
p = kv->databuf + kv->_vlist;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
val_count = ntohl(x);
val_count++;
x = htonl(val_count);
memcpy(p, &x, sizeof(uint32_t));
p = kv->databuf + kv->_val;
x = htonl(len);
memcpy(p, &x, sizeof(uint32_t));
p += sizeof(uint32_t);
memcpy(p, val, len);
p += len;
kv->datalen += delta;
kv->_val = kv->datalen;
}
uint32_t
kvbuf_get_len(const char *p)
{
uint32_t x;
x = 0;
memcpy(&x, p - sizeof(uint32_t), sizeof(uint32_t));
return ntohl(x);
}
void
kvbuf_add_val(kvbuf_t *kv, const char *val)
{
if (kv == NULL) return;
if (val == NULL) return;
kvbuf_add_val_len(kv, val, strlen(val) + 1);
}
void
kvbuf_free(kvbuf_t *kv)
{
if (kv == NULL) return;
if (kv->databuf != NULL) free(kv->databuf);
memset(kv, 0, sizeof(kvbuf_t));
free(kv);
}
void
kvbuf_append_kvbuf(kvbuf_t *kv, const kvbuf_t *kv2)
{
uint32_t curr_count, new_count, temp;
if (kv == NULL) return;
if (kv2 == NULL) return;
curr_count = 0;
new_count = 0;
memcpy(&temp, kv->databuf, sizeof(uint32_t));
curr_count = ntohl(temp);
memcpy(&temp, kv2->databuf, sizeof(uint32_t));
new_count = ntohl(temp);
if (new_count == 0) return;
curr_count += new_count;
temp = htonl(curr_count);
memcpy(kv->databuf, &temp, sizeof(uint32_t));
temp = kv2->datalen - sizeof(uint32_t);
kvbuf_grow(kv, temp);
memcpy(kv->databuf + kv->datalen, kv2->databuf + sizeof(uint32_t), temp);
kv->datalen += temp;
}
uint32_t
kvbuf_reset(kvbuf_t *kv)
{
uint32_t x;
if (kv == NULL) return 0;
if (kv->databuf == NULL) return 0;
kv->_dict = 0;
kv->_key = 0;
kv->_vlist = 0;
kv->_val = 0;
if (kv->datalen < sizeof(uint32_t)) return 0;
x = 0;
memcpy(&x, kv->databuf, sizeof(uint32_t));
return ntohl(x);
}
uint32_t
kvbuf_next_dict(kvbuf_t *kv)
{
uint32_t x, k, v, kcount, vcount, kl, vl;
char *p;
if (kv == NULL) return 0;
if (kv->databuf == NULL) return 0;
kv->_key = 0;
kv->_vlist = 0;
kv->_val = 0;
if (kv->_dict == 0)
{
if (kv->datalen < sizeof(uint32_t)) return 0;
kv->_dict = sizeof(uint32_t);
if (kv->datalen < (kv->_dict + sizeof(uint32_t))) return 0;
p = kv->databuf + kv->_dict;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
kcount = ntohl(x);
return kcount;
}
p = kv->databuf + kv->_dict;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_dict += sizeof(uint32_t);
kcount = ntohl(x);
for (k = 0; k < kcount; k++)
{
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_dict += sizeof(uint32_t);
kl = ntohl(x);
p += kl;
kv->_dict += kl;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_dict += sizeof(uint32_t);
vcount = ntohl(x);
for (v = 0; v < vcount; v++)
{
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_dict += sizeof(uint32_t);
vl = ntohl(x);
p += vl;
kv->_dict += vl;
}
}
if (kv->datalen < (kv->_dict + sizeof(uint32_t))) return 0;
p = kv->databuf + kv->_dict;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
kcount = ntohl(x);
return kcount;
}
char *
kvbuf_next_key(kvbuf_t *kv, uint32_t *val_count)
{
uint32_t x, kl, v, vl, vc;
char *p, *out;
if (kv == NULL) return NULL;
if (val_count == NULL) return NULL;
*val_count = 0;
if (kv->databuf == NULL) return NULL;
if (kv->_dict == 0) return NULL;
kv->_vlist = 0;
kv->_val = 0;
if (kv->_key == 0)
{
if (kv->datalen < (kv->_dict + sizeof(uint32_t))) return NULL;
kv->_key = kv->_dict + sizeof(uint32_t);
}
else
{
p = kv->databuf + kv->_key;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
kl = ntohl(x);
if (kv->datalen < (kv->_key + sizeof(uint32_t) + kl)) return NULL;
p += (sizeof(uint32_t) + kl);
kv->_key += (sizeof(uint32_t) + kl);
if (kv->datalen < (kv->_key + sizeof(uint32_t))) return NULL;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
vc = ntohl(x);
p += sizeof(uint32_t);
kv->_key += sizeof(uint32_t);
for (v = 0; v < vc; v++)
{
if (kv->datalen < (kv->_key + sizeof(uint32_t))) return NULL;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
vl = ntohl(x);
if (kv->datalen < (kv->_key + kl)) return NULL;
p += (sizeof(uint32_t) + vl);
kv->_key += (sizeof(uint32_t) + vl);
}
}
if (kv->datalen < (kv->_key + sizeof(uint32_t))) return NULL;
p = kv->databuf + kv->_key;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
kl = ntohl(x);
p += sizeof(uint32_t);
out = p;
kv->_vlist = kv->_key + sizeof(uint32_t) + kl;
if (kv->datalen < (kv->_vlist + sizeof(uint32_t)))
{
kv->_vlist = 0;
return NULL;
}
p = kv->databuf + kv->_vlist;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
*val_count = ntohl(x);
return out;
}
char *
kvbuf_next_val(kvbuf_t *kv)
{
return kvbuf_next_val_len(kv, NULL);
}
char *
kvbuf_next_val_len(kvbuf_t *kv, uint32_t *len)
{
uint32_t x = 0;
uint32_t vltemp = 0;
char *p;
if (kv == NULL) return NULL;
if (kv->databuf == NULL) return NULL;
if (kv->_vlist == 0) return NULL;
if (kv->_val == 0)
{
if (kv->datalen < (kv->_vlist + sizeof(uint32_t))) return NULL;
kv->_val = kv->_vlist + sizeof(uint32_t);
p = kv->databuf + kv->_val;
memcpy(&x, p, sizeof(uint32_t));
vltemp = ntohl(x);
}
else
{
p = kv->databuf + kv->_val;
memcpy(&x, p, sizeof(uint32_t));
vltemp = ntohl(x);
if (kv->datalen < (kv->_val + sizeof(uint32_t) + vltemp)) return NULL;
p += (sizeof(uint32_t) + vltemp);
kv->_val += (sizeof(uint32_t) + vltemp);
}
if (kv->datalen < (kv->_val + sizeof(uint32_t))) return NULL;
if (len != NULL) (*len) = vltemp;
p = kv->databuf + kv->_val + sizeof(uint32_t);
return p;
}
kvarray_t *
kvbuf_decode(kvbuf_t *kv)
{
kvarray_t *a;
uint32_t x, d, k, v;
char *p;
if (kv == NULL) return NULL;
if (kv->databuf == NULL) return NULL;
if (kv->datalen < sizeof(uint32_t)) return NULL;
p = kv->databuf;
kv->_size = kv->datalen;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_size -= sizeof(uint32_t);
x = ntohl(x);
if (x == 0) return NULL;
a = (kvarray_t *)calloc(1, sizeof(kvarray_t));
if (a == NULL) return NULL;
a->count = x;
a->dict = (kvdict_t *)calloc(a->count, sizeof(kvdict_t));
if (a->dict == NULL)
{
free(a);
return NULL;
}
for (d = 0; d < a->count; d++)
{
if (kv->_size < sizeof(uint32_t))
{
kvarray_free(a);
return NULL;
}
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_size -= sizeof(uint32_t);
a->dict[d].kcount = ntohl(x);
if (a->dict[d].kcount > 0)
{
a->dict[d].key = (const char **)calloc(a->dict[d].kcount, sizeof(const char *));
if (a->dict[d].key == NULL)
{
kvarray_free(a);
return NULL;
}
a->dict[d].vcount = (uint32_t *)calloc(a->dict[d].kcount, sizeof(uint32_t));
if (a->dict[d].vcount == NULL)
{
kvarray_free(a);
return NULL;
}
a->dict[d].val = (const char ***)calloc(a->dict[d].kcount, sizeof(char **));
if (a->dict[d].val == NULL)
{
kvarray_free(a);
return NULL;
}
}
for (k = 0; k < a->dict[d].kcount; k++)
{
if (kv->_size < sizeof(uint32_t))
{
kvarray_free(a);
return NULL;
}
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_size -= sizeof(uint32_t);
x = ntohl(x);
if (kv->_size < x)
{
kvarray_free(a);
return NULL;
}
a->dict[d].key[k] = p;
p += x;
kv->_size -= x;
if (kv->_size < sizeof(uint32_t))
{
kvarray_free(a);
return NULL;
}
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_size -= sizeof(uint32_t);
a->dict[d].vcount[k] = ntohl(x);
if (a->dict[d].vcount[k] > 0)
{
a->dict[d].val[k] = (const char **)calloc(a->dict[d].vcount[k] + 1, sizeof(const char *));
if (a->dict[d].val[k] == NULL)
{
kvarray_free(a);
return NULL;
}
}
for (v = 0; v < a->dict[d].vcount[k]; v++)
{
if (kv->_size < sizeof(uint32_t))
{
kvarray_free(a);
return NULL;
}
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_size -= sizeof(uint32_t);
x = ntohl(x);
if (kv->_size < x)
{
kvarray_free(a);
return NULL;
}
a->dict[d].val[k][v] = p;
p += x;
kv->_size -= x;
}
}
}
a->kv = kv;
return a;
}
void
kvarray_free(kvarray_t *a)
{
uint32_t d, k;
if (a == NULL) return;
for (d = 0; d < a->count; d++)
{
for (k = 0; k < a->dict[d].kcount; k++)
{
if (a->dict[d].val == NULL) continue;
if (a->dict[d].val[k] != NULL) free(a->dict[d].val[k]);
}
if (a->dict[d].key != NULL) free(a->dict[d].key);
if (a->dict[d].vcount != NULL) free(a->dict[d].vcount);
if (a->dict[d].val != NULL) free(a->dict[d].val);
}
a->count = 0;
if (a->dict != NULL) free(a->dict);
a->dict = NULL;
if (a->kv != NULL) kvbuf_free(a->kv);
a->kv = NULL;
free(a);
}
kern_return_t
LI_DSLookupGetProcedureNumber(const char *name, int32_t *procno)
{
kern_return_t status;
security_token_t token;
uint32_t n, len;
if (name == NULL) return KERN_FAILURE;
len = strlen(name) + 1;
if (len == 1) return KERN_FAILURE;
token.val[0] = -1;
token.val[1] = -1;
if (_ds_running() == 0) return KERN_FAILURE;
if (_ds_port == MACH_PORT_NULL) return KERN_FAILURE;
status = MIG_SERVER_DIED;
for (n = 0; (_ds_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
{
status = libinfoDSmig_GetProcedureNumber(_ds_port, (char *)name, procno, &token);
if (status == MACH_SEND_INVALID_DEST)
{
mach_port_mod_refs(mach_task_self(), _ds_port, MACH_PORT_RIGHT_SEND, -1);
status = bootstrap_look_up(bootstrap_port, kDSStdMachDSLookupPortName, &_ds_port);
if ((status != BOOTSTRAP_SUCCESS) && (status != BOOTSTRAP_UNKNOWN_SERVICE)) _ds_port = MACH_PORT_NULL;
status = MIG_SERVER_DIED;
}
}
if (status != KERN_SUCCESS)
{
#ifdef DEBUG
asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupGetProcedureNumber %s status %u", name, status);
#endif
return status;
}
if (token.val[0] != 0)
{
#ifdef DEBUG
asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupGetProcedureNumber %s auth failure uid=%d", name, token.val[0]);
#endif
return KERN_FAILURE;
}
#ifdef DEBUG
asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupGetProcedureNumber %s = %d", name, *procno);
#endif
return status;
}
__private_extern__ kern_return_t
LI_DSLookupQuery(int32_t procno, kvbuf_t *request, kvarray_t **reply)
{
kern_return_t status;
security_token_t token;
uint32_t n;
mach_msg_type_number_t illen, oolen;
char ilbuf[MAX_MIG_INLINE_DATA];
vm_offset_t oobuf;
kvbuf_t *out;
if (reply == NULL) return KERN_FAILURE;
if ((request != NULL) && ((request->databuf == NULL) || (request->datalen == 0))) return KERN_FAILURE;
token.val[0] = -1;
token.val[1] = -1;
*reply = NULL;
if (_ds_running() == 0) return KERN_FAILURE;
if (_ds_port == MACH_PORT_NULL) return KERN_FAILURE;
status = MIG_SERVER_DIED;
for (n = 0; (_ds_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
{
illen = 0;
oolen = 0;
oobuf = 0;
if (request != NULL)
{
status = libinfoDSmig_Query(_ds_port, procno, request->databuf, request->datalen, ilbuf, &illen, &oobuf, &oolen, &token);
}
else
{
status = libinfoDSmig_Query(_ds_port, procno, "", 0, ilbuf, &illen, &oobuf, &oolen, &token);
}
if (status == MACH_SEND_INVALID_DEST)
{
mach_port_mod_refs(mach_task_self(), _ds_port, MACH_PORT_RIGHT_SEND, -1);
status = bootstrap_look_up(bootstrap_port, kDSStdMachDSLookupPortName, &_ds_port);
if ((status != BOOTSTRAP_SUCCESS) && (status != BOOTSTRAP_UNKNOWN_SERVICE)) _ds_port = MACH_PORT_NULL;
status = MIG_SERVER_DIED;
}
}
if (status != KERN_SUCCESS)
{
#ifdef DEBUG
asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupQuery %d status %u", procno, status);
#endif
return status;
}
if (token.val[0] != 0)
{
#ifdef DEBUG
asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupQuery %d auth failure uid=%d", procno, token.val[0]);
#endif
if (oolen > 0) vm_deallocate(mach_task_self(), (vm_address_t)oobuf, oolen);
return KERN_FAILURE;
}
out = (kvbuf_t *)calloc(1, sizeof(kvbuf_t));
if (out == NULL)
{
if (oolen > 0) vm_deallocate(mach_task_self(), (vm_address_t)oobuf, oolen);
return KERN_FAILURE;
}
if (oolen > 0)
{
out->datalen = oolen;
out->databuf = malloc(oolen);
if (out->databuf == NULL)
{
free(out);
*reply = NULL;
vm_deallocate(mach_task_self(), (vm_address_t)oobuf, oolen);
return KERN_FAILURE;
}
memcpy(out->databuf, (char *)oobuf, oolen);
vm_deallocate(mach_task_self(), (vm_address_t)oobuf, oolen);
}
else if (illen > 0)
{
out->datalen = illen;
out->databuf = malloc(illen);
if (out->databuf == NULL)
{
free(out);
*reply = NULL;
return KERN_FAILURE;
}
memcpy(out->databuf, ilbuf, illen);
}
*reply = kvbuf_decode(out);
if (*reply == NULL)
{
free(out->databuf);
free(out);
}
#ifdef DEBUG
asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupQuery %d status OK", procno);
#endif
return status;
}
__private_extern__ void *
LI_getent(const char *procname, int *procnum, void *(*extract)(kvarray_t *), int tkey, size_t esize)
{
void *entry;
struct li_thread_info *tdata;
kvarray_t *reply;
kern_return_t status;
tdata = LI_data_create_key(tkey, esize);
if (tdata == NULL) return NULL;
if (tdata->li_vm == NULL)
{
if (*procnum < 0)
{
status = LI_DSLookupGetProcedureNumber(procname, procnum);
if (status != KERN_SUCCESS)
{
LI_data_free_kvarray(tdata);
tdata->li_vm = NULL;
return NULL;
}
}
reply = NULL;
status = LI_DSLookupQuery(*procnum, NULL, &reply);
if (status != KERN_SUCCESS)
{
LI_data_free_kvarray(tdata);
tdata->li_vm = NULL;
return NULL;
}
tdata->li_vm = (char *)reply;
}
entry = extract((kvarray_t *)(tdata->li_vm));
if (entry == NULL)
{
LI_data_free_kvarray(tdata);
tdata->li_vm = NULL;
return NULL;
}
return entry;
}
__private_extern__ void *
LI_getone(const char *procname, int *procnum, void *(*extract)(kvarray_t *), const char *key, const char *val)
{
void *entry;
kvbuf_t *request;
kvarray_t *reply;
kern_return_t status;
if (*procnum < 0)
{
status = LI_DSLookupGetProcedureNumber(procname, procnum);
if (status != KERN_SUCCESS) return NULL;
}
request = kvbuf_query_key_val(key, val);
if (request == NULL) return NULL;
reply = NULL;
status = LI_DSLookupQuery(*procnum, request, &reply);
kvbuf_free(request);
if (status != KERN_SUCCESS) return NULL;
entry = extract(reply);
kvarray_free(reply);
return entry;
}
__private_extern__
int LI_L1_cache_check(int tkey)
{
int check, x;
const char *notify_key;
if (gL1CacheEnabled == 0) return LI_L1_CACHE_DISABLED;
if (_L1_notify_token[0] == -1)
{
pthread_mutex_lock(&_notify_lock);
if (_L1_notify_token[0] == -1) notify_register_check(L1_CACHE_NOTIFICATION_KEY_GLOBAL, &(_L1_notify_token[0]));
pthread_mutex_unlock(&_notify_lock);
}
if (_L1_notify_token[0] == -1) return LI_L1_CACHE_FAILED;
check = 1;
if (notify_check(_L1_notify_token[0], &check) != 0) return LI_L1_CACHE_FAILED;
if (check == 1) return LI_L1_CACHE_STALE;
x = 0;
notify_key = NULL;
switch (tkey)
{
case _li_data_key_group:
{
x = 1;
notify_key = L1_CACHE_NOTIFICATION_KEY_GROUP;
break;
}
case _li_data_key_host:
{
x = 2;
notify_key = L1_CACHE_NOTIFICATION_KEY_HOST;
break;
}
case _li_data_key_service:
{
x = 3;
notify_key = L1_CACHE_NOTIFICATION_KEY_SERVICE;
break;
}
case _li_data_key_user:
{
x = 4;
notify_key = L1_CACHE_NOTIFICATION_KEY_USER;
break;
}
default: break;
}
if ((x != 0) && (notify_key != NULL))
{
if (_L1_notify_token[x] == -1)
{
pthread_mutex_lock(&_notify_lock);
if (_L1_notify_token[x] == -1) notify_register_check(notify_key, &(_L1_notify_token[x]));
pthread_mutex_unlock(&_notify_lock);
}
if (_L1_notify_token[x] == -1) return LI_L1_CACHE_FAILED;
check = 1;
if (notify_check(_L1_notify_token[x], &check) != 0) return LI_L1_CACHE_FAILED;
if (check == 1) return LI_L1_CACHE_STALE;
}
return LI_L1_CACHE_OK;
}
static uint32_t
padsize(size_t curr, size_t item, const uint32_t *align)
{
uint32_t na, diff;
if (item > 8) item = 8;
na = align[item];
if (na == 0) return 0;
diff = curr % na;
if (diff == 0) return 0;
return na - diff;
}
__private_extern__ void *
LI_ils_create(char *fmt, ...)
{
va_list ap;
char *arg, *f;
char **list;
void *hp, *dp, *lp, *ils;
uint8_t u8;
uint16_t u16;
uint32_t u32, i, pad;
uint64_t u64;
unsigned long l;
size_t memsize, hsize, csize, slen, largest;
const uint32_t *align;
if (fmt == NULL) return NULL;
largest = 0;
align = align_32;
if (sizeof(char *) == 8) align = align_64;
memsize = ILS_MAGIC_SIZE;
hsize = 0;
va_start(ap, fmt);
for (f = fmt; (*f) != '\0'; f++)
{
csize = 0;
slen = 0;
if (*f == 's')
{
if (largest < sizeof(char *)) largest = sizeof(char *);
csize = sizeof(char *) + padsize(hsize, sizeof(char *), align);
arg = va_arg(ap, char *);
if (arg != NULL) slen = strlen(arg) + 1;
}
else if (*f == '1')
{
if (largest < 1) largest = 1;
csize = 1;
u8 = va_arg(ap, int);
}
else if (*f == '2')
{
if (largest < 2) largest = 2;
csize = 2 + padsize(hsize, 2, align);
u16 = va_arg(ap, int);
}
else if (*f == '4')
{
if (largest < 4) largest = 4;
csize = 4 + padsize(hsize, 4, align);
u32 = va_arg(ap, uint32_t);
}
else if (*f == '8')
{
if (largest < 8) largest = 8;
csize = 8 + padsize(hsize, 8, align);
u64 = va_arg(ap, uint64_t);
}
else if (*f == 'L')
{
if (largest < sizeof(unsigned long)) largest = sizeof(unsigned long);
csize = sizeof(unsigned long) + padsize(hsize, sizeof(unsigned long), align);
l = va_arg(ap, unsigned long);
}
else if (*f == '*')
{
if (largest < sizeof(char *)) largest = sizeof(char *);
csize = sizeof(char *) + padsize(hsize, sizeof(char *), align);
list = va_arg(ap, char **);
if (list != NULL)
{
for (i = 0; list[i] != NULL; i++)
{
slen += sizeof(char *);
slen += (strlen(list[i]) + 1);
}
slen += sizeof(char *);
}
}
else if (*f == 'a')
{
if (largest < sizeof(char *)) largest = sizeof(char *);
csize = sizeof(char *) + padsize(hsize, sizeof(char *), align);
list = va_arg(ap, char **);
if (list != NULL)
{
for (i = 0; list[i] != NULL; i++)
{
slen += sizeof(char *);
slen += 4;
}
slen += sizeof(char *);
}
}
else if (*f == 'b')
{
if (largest < sizeof(char *)) largest = sizeof(char *);
csize = sizeof(char *) + padsize(hsize, sizeof(char *), align);
list = va_arg(ap, char **);
if (list != NULL)
{
for (i = 0; list[i] != NULL; i++)
{
slen += sizeof(char *);
slen += 8;
}
slen += sizeof(char *);
}
}
else if (*f == 'c')
{
if (largest < sizeof(char *)) largest = sizeof(char *);
csize = sizeof(char *) + padsize(hsize, sizeof(char *), align);
list = va_arg(ap, char **);
if (list != NULL)
{
for (i = 0; list[i] != NULL; i++)
{
slen += sizeof(char *);
slen += 16;
}
slen += sizeof(char *);
}
}
else return NULL;
memsize += csize;
memsize += slen;
hsize += csize;
}
va_end(ap);
pad = padsize(hsize, largest, align);
memsize += pad;
hsize += pad;
ils = malloc(memsize);
if (ils == NULL)
{
errno = ENOMEM;
return NULL;
}
dp = ils + hsize;
memcpy(dp, ILS_MAGIC, ILS_MAGIC_SIZE);
dp += ILS_MAGIC_SIZE;
hp = ils;
hsize = 0;
va_start(ap, fmt);
for (f = fmt; (*f) != '\0'; f++)
{
if (*f == 's')
{
pad = padsize(hsize, sizeof(char *), align);
if (pad != 0)
{
memset(hp, 0, pad);
hp += pad;
hsize += pad;
}
arg = va_arg(ap, char *);
if (arg == NULL)
{
memset(hp, 0, sizeof(char *));
}
else
{
memcpy(hp, &dp, sizeof(char *));
slen = strlen(arg) + 1;
memcpy(dp, arg, slen);
dp += slen;
}
hp += sizeof(char *);
hsize += sizeof(char *);
}
else if (*f == '1')
{
u8 = va_arg(ap, int);
memcpy(hp, &u8, sizeof(uint8_t));
hp += sizeof(uint8_t);
}
else if (*f == '2')
{
pad = padsize(hsize, 2, align);
if (pad != 0)
{
memset(hp, 0, pad);
hp += pad;
hsize += pad;
}
u16 = va_arg(ap, int);
memcpy(hp, &u16, sizeof(uint16_t));
hp += sizeof(uint16_t);
hsize += sizeof(uint16_t);
}
else if (*f == '4')
{
pad = padsize(hsize, 4, align);
if (pad != 0)
{
memset(hp, 0, pad);
hp += pad;
hsize += pad;
}
u32 = va_arg(ap, uint32_t);
memcpy(hp, &u32, sizeof(uint32_t));
hp += sizeof(uint32_t);
hsize += sizeof(uint32_t);
}
else if (*f == '8')
{
pad = padsize(hsize, 8, align);
if (pad != 0)
{
memset(hp, 0, pad);
hp += pad;
hsize += pad;
}
u64 = va_arg(ap, uint64_t);
memcpy(hp, &u64, sizeof(uint64_t));
hp += sizeof(uint64_t);
hsize += sizeof(uint64_t);
}
else if (*f == 'L')
{
pad = padsize(hsize, sizeof(unsigned long), align);
if (pad != 0)
{
memset(hp, 0, pad);
hp += pad;
hsize += pad;
}
l = va_arg(ap, unsigned long);
memcpy(hp, &l, sizeof(unsigned long));
hp += sizeof(unsigned long);
hsize += sizeof(unsigned long);
}
else if (*f == '*')
{
pad = padsize(hsize, sizeof(char *), align);
if (pad != 0)
{
memset(hp, 0, pad);
hp += pad;
hsize += pad;
}
list = va_arg(ap, char **);
if (list == NULL)
{
memset(hp, 0, sizeof(char *));
}
else
{
memcpy(hp, &dp, sizeof(char *));
for (i = 0; list[i] != NULL; i++);
lp = dp;
dp += ((i + 1) * sizeof(char *));
for (i = 0; list[i] != NULL; i++)
{
memcpy(lp, &dp, sizeof(char *));
lp += sizeof(char *);
slen = strlen(list[i]) + 1;
memcpy(dp, list[i], slen);
dp += slen;
}
memset(lp, 0, sizeof(char *));
}
hp += sizeof(char *);
hsize += sizeof(char *);
}
else if (*f == 'a')
{
pad = padsize(hsize, sizeof(char *), align);
if (pad != 0)
{
memset(hp, 0, pad);
hp += pad;
hsize += pad;
}
list = va_arg(ap, char **);
if (list == NULL)
{
memset(hp, 0, sizeof(char *));
}
else
{
memcpy(hp, &dp, sizeof(char *));
for (i = 0; list[i] != NULL; i++);
lp = dp;
dp += ((i + 1) * sizeof(char *));
for (i = 0; list[i] != NULL; i++)
{
memcpy(lp, &dp, sizeof(char *));
lp += sizeof(char *);
slen = 4;
memcpy(dp, list[i], slen);
dp += slen;
}
memset(lp, 0, sizeof(char *));
}
hp += sizeof(char *);
hsize += sizeof(char *);
}
else if (*f == 'b')
{
pad = padsize(hsize, sizeof(char *), align);
if (pad != 0)
{
memset(hp, 0, pad);
hp += pad;
hsize += pad;
}
list = va_arg(ap, char **);
if (list == NULL)
{
memset(hp, 0, sizeof(char *));
}
else
{
memcpy(hp, &dp, sizeof(char *));
for (i = 0; list[i] != NULL; i++);
lp = dp;
dp += ((i + 1) * sizeof(char *));
for (i = 0; list[i] != NULL; i++)
{
memcpy(lp, &dp, sizeof(char *));
lp += sizeof(char *);
slen = 8;
memcpy(dp, list[i], slen);
dp += slen;
}
memset(lp, 0, sizeof(char *));
}
hp += sizeof(char *);
hsize += sizeof(char *);
}
else if (*f == 'c')
{
pad = padsize(hsize, sizeof(char *), align);
if (pad != 0)
{
memset(hp, 0, pad);
hp += pad;
hsize += pad;
}
list = va_arg(ap, char **);
if (list == NULL)
{
memset(hp, 0, sizeof(char *));
}
else
{
memcpy(hp, &dp, sizeof(char *));
for (i = 0; list[i] != NULL; i++);
lp = dp;
dp += ((i + 1) * sizeof(char *));
for (i = 0; list[i] != NULL; i++)
{
memcpy(lp, &dp, sizeof(char *));
lp += sizeof(char *);
slen = 16;
memcpy(dp, list[i], slen);
dp += slen;
}
memset(lp, 0, sizeof(char *));
}
hp += sizeof(char *);
hsize += sizeof(char *);
}
}
va_end(ap);
pad = padsize(hsize, largest, align);
if (pad > 0) memset(hp, 0, pad);
return ils;
}
__private_extern__ int
LI_ils_free(void *ils, size_t len)
{
char *p;
if (ils == NULL) return 0;
p = ils + len;
if (memcmp(p, ILS_MAGIC, ILS_MAGIC_SIZE) != 0) return -1;
free(ils);
return 0;
}
kern_return_t
_lookup_link(mach_port_t server, char *name, int *procno)
{
syslog(LOG_ERR, "RED ALERT! lookupd call %s from pid %u", name, getpid());
return KERN_FAILURE;
}
kern_return_t
_lookup_one(mach_port_t server, int proc, char *indata, mach_msg_type_number_t indataCnt, char *outdata, mach_msg_type_number_t *outdataCnt)
{
return KERN_FAILURE;
}
kern_return_t
_lookup_all(mach_port_t server, int proc, char *indata, mach_msg_type_number_t indataCnt, char **outdata, mach_msg_type_number_t *outdataCnt)
{
return KERN_FAILURE;
}
kern_return_t
_lookup_ooall(mach_port_t server, int proc, char *indata, mach_msg_type_number_t indataCnt, char **outdata, mach_msg_type_number_t *outdataCnt)
{
return KERN_FAILURE;
}