/*
- * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* @APPLE_LICENSE_HEADER_END@
*/
-#include <mach/mach.h>
-
-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)
-{
- return KERN_SUCCESS;
-}
-
#ifdef DS_AVAILABLE
#include <stdio.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/stat.h>
+#include <pthread.h>
#include <ils.h>
-#include "kvbuf.h"
#include <pwd.h>
#include <grp.h>
#include <fstab.h>
#include <si_module.h>
#include <netdb_async.h>
#include <net/if.h>
+#include <xpc/xpc.h>
+#include <xpc/private.h>
+#include <opendirectory/odipc.h>
#include <servers/bootstrap.h>
#include <bootstrap_priv.h>
-#include "DSlibinfoMIG.h"
-#include "DSmemberdMIG.h"
+#include <opendirectory/DSlibinfoMIG_types.h>
#ifdef DEBUG
#include <asl.h>
#endif
-#define SOCK_UNSPEC 0
-#define IPPROTO_UNSPEC 0
+#ifdef __i386__
+/* <rdar://problem/10675978> */
+__attribute__((weak_import))
+void xpc_dictionary_get_audit_token(xpc_object_t xdict, audit_token_t *token);
-#define IPV6_ADDR_LEN 16
-#define IPV4_ADDR_LEN 4
+__attribute__((weak_import))
+xpc_pipe_t xpc_pipe_create(const char *name, uint64_t flags);
-#define WANT_NOTHING 0
-#define WANT_A4_ONLY 1
-#define WANT_A6_ONLY 2
-#define WANT_A6_PLUS_MAPPED_A4 3
-#define WANT_MAPPED_A4_ONLY 4
+__attribute__((weak_import))
+void xpc_pipe_invalidate(xpc_pipe_t pipe);
+
+__attribute__((weak_import))
+int xpc_pipe_routine(xpc_pipe_t pipe, xpc_object_t message, xpc_object_t *reply);
+#endif
-/* ONLY TO BE USED BY getipv6nodebyaddr */
-#define WANT_A6_OR_MAPPED_A4_IF_NO_A6 5
+#define IPV6_ADDR_LEN 16
+#define IPV4_ADDR_LEN 4
-#define MAX_LOOKUP_ATTEMPTS 10
+typedef si_item_t *(*od_extract_t)(si_mod_t *si, xpc_object_t reply, const void *extra, uint64_t valid_global, uint64_t valid_cat);
-#define INET_NTOP_AF_INET_OFFSET 4
-#define INET_NTOP_AF_INET6_OFFSET 8
+/* notify SPI */
+uint32_t notify_peek(int token, uint32_t *val);
-mach_port_t _ds_port;
-mach_port_t _mbr_port;
+typedef struct
+{
+ int notify_token_global;
+ int notify_token_user;
+ int notify_token_group;
+ int notify_token_service;
+} ds_si_private_t;
extern uint32_t gL1CacheEnabled;
+extern int _si_opendirectory_disabled;
static pthread_key_t _ds_serv_cache_key = 0;
+static xpc_pipe_t __od_pipe; /* use accessor only */
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+mach_port_t _ds_port;
static void
-_ds_child(void)
+_od_fork_child(void)
{
+ // re-enable opendirectory interaction since we forked
+ _si_opendirectory_disabled = 0;
+
+ if (__od_pipe != NULL) {
+ xpc_pipe_invalidate(__od_pipe);
+ /* disable release due to 10649340, it will cause a minor leak for each fork without exec */
+ // xpc_release(__od_pipe);
+ __od_pipe = NULL;
+ }
_ds_port = MACH_PORT_NULL;
- _mbr_port = MACH_PORT_NULL;
+ pthread_mutex_unlock(&mutex);
}
-static int _si_opendirectory_disabled;
-
-void
-_si_disable_opendirectory(void)
+static void
+_od_fork_prepare(void)
{
- _si_opendirectory_disabled = 1;
- _ds_port = MACH_PORT_NULL;
- _mbr_port = MACH_PORT_NULL;
+ pthread_mutex_lock(&mutex);
}
-int
-_ds_running(void)
+static void
+_od_fork_parent(void)
{
- kern_return_t status;
- char *od_debug_mode = NULL;
-
- if (_ds_port != MACH_PORT_NULL) return 1;
-
- if (_si_opendirectory_disabled) return 0;
- pthread_atfork(NULL, NULL, _ds_child);
-
- if (!issetugid()) {
- od_debug_mode = getenv("OD_DEBUG_MODE");
- }
-
- if (od_debug_mode) {
- status = bootstrap_look_up(bootstrap_port, kDSStdMachDSLookupPortName "_debug", &_ds_port);
- } else {
- status = bootstrap_look_up2(bootstrap_port, kDSStdMachDSLookupPortName,
- &_ds_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
- }
- if ((status != BOOTSTRAP_SUCCESS) && (status != BOOTSTRAP_UNKNOWN_SERVICE)) _ds_port = MACH_PORT_NULL;
-
- if (od_debug_mode) {
- status = bootstrap_look_up(bootstrap_port, kDSStdMachDSMembershipPortName "_debug", &_mbr_port);
- } else {
- status = bootstrap_look_up2(bootstrap_port, kDSStdMachDSMembershipPortName,
- &_mbr_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
- }
- if ((status != BOOTSTRAP_SUCCESS) && (status != BOOTSTRAP_UNKNOWN_SERVICE)) _mbr_port = MACH_PORT_NULL;
-
- return (_ds_port != MACH_PORT_NULL);
+ pthread_mutex_unlock(&mutex);
}
static void
if (x != NULL) si_item_release(x);
}
-static kern_return_t
-LI_DSLookupGetProcedureNumber(const char *name, int32_t *procno)
+void
+_si_disable_opendirectory(void)
{
- 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;
+ _si_opendirectory_disabled = 1;
+ _ds_port = MACH_PORT_NULL;
+}
- if (_ds_running() == 0) return KERN_FAILURE;
- if (_ds_port == MACH_PORT_NULL) return KERN_FAILURE;
+XPC_RETURNS_RETAINED
+static xpc_pipe_t
+_od_xpc_pipe(bool resetPipe)
+{
+ static dispatch_once_t once;
+ xpc_pipe_t result = NULL;
- 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);
+#ifdef __i386__
+ if (xpc_pipe_create == NULL) {
+ _si_disable_opendirectory();
+ return NULL;
+ }
+#endif
- if (status == MACH_SEND_INVALID_DEST)
- {
- mach_port_mod_refs(mach_task_self(), _ds_port, MACH_PORT_RIGHT_SEND, -1);
- status = bootstrap_look_up2(bootstrap_port, kDSStdMachDSLookupPortName, &_ds_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
- if ((status != BOOTSTRAP_SUCCESS) && (status != BOOTSTRAP_UNKNOWN_SERVICE)) _ds_port = MACH_PORT_NULL;
- status = MIG_SERVER_DIED;
+ dispatch_once(&once, ^(void) {
+ char *rc_xbs;
+
+ /* if this is a build environment we ignore opendirectoryd */
+ rc_xbs = getenv("RC_XBS");
+ if ((issetugid() == 0) && (rc_xbs != NULL) && (strcmp(rc_xbs, "YES") == 0)) {
+ _si_opendirectory_disabled = 1;
+ return;
}
- }
- if (status != KERN_SUCCESS)
- {
-#ifdef DEBUG
- asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupGetProcedureNumber %s status %u", name, status);
-#endif
- return status;
+ pthread_atfork(_od_fork_prepare, _od_fork_parent, _od_fork_child);
+ });
+
+ if (_si_opendirectory_disabled == 1) {
+ return NULL;
}
-
- 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;
+
+ pthread_mutex_lock(&mutex);
+ if (resetPipe) {
+ xpc_release(__od_pipe);
+ __od_pipe = NULL;
}
-
-#ifdef DEBUG
- asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupGetProcedureNumber %s = %d", name, *procno);
-#endif
- return status;
+
+ if (__od_pipe == NULL) {
+ if (!issetugid() && getenv("OD_DEBUG_MODE") != NULL) {
+ __od_pipe = xpc_pipe_create(kODMachLibinfoPortNameDebug, 0);
+ } else {
+ __od_pipe = xpc_pipe_create(kODMachLibinfoPortName, XPC_PIPE_FLAG_PRIVILEGED);
+ }
+ }
+
+ if (__od_pipe != NULL) result = xpc_retain(__od_pipe);
+ pthread_mutex_unlock(&mutex);
+
+ return result;
}
-static kern_return_t
-LI_DSLookupQuery(int32_t procno, kvbuf_t *request, kvarray_t **reply)
+static bool
+_od_running(void)
{
- 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;
+ xpc_pipe_t pipe;
- 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_up2(bootstrap_port, kDSStdMachDSLookupPortName, &_ds_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
- if ((status != BOOTSTRAP_SUCCESS) && (status != BOOTSTRAP_UNKNOWN_SERVICE)) _ds_port = MACH_PORT_NULL;
- status = MIG_SERVER_DIED;
- }
+ pipe = _od_xpc_pipe(false);
+ if (pipe != NULL) {
+ xpc_release(pipe);
}
- if (status != KERN_SUCCESS)
- {
-#ifdef DEBUG
- asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupQuery %d status %u", procno, status);
-#endif
- return status;
+ if (_si_opendirectory_disabled) {
+ return 0;
}
- 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) && (oobuf != 0)) vm_deallocate(mach_task_self(), (vm_address_t)oobuf, oolen);
- return KERN_FAILURE;
- }
+ return (pipe != NULL);
+}
- out = (kvbuf_t *)calloc(1, sizeof(kvbuf_t));
- if (out == NULL)
- {
- if ((oolen > 0) && (oobuf != 0)) vm_deallocate(mach_task_self(), (vm_address_t)oobuf, oolen);
- return KERN_FAILURE;
- }
+static void
+_ds_child(void)
+{
+ _ds_port = MACH_PORT_NULL;
+}
- if ((oolen > 0) && (oobuf != 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;
- }
+int
+_ds_running(void)
+{
+ kern_return_t status;
+ char *od_debug_mode = NULL;
- 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;
- }
+ if (_ds_port != MACH_PORT_NULL) return 1;
+
+ if (_si_opendirectory_disabled) return 0;
+ pthread_atfork(NULL, NULL, _ds_child);
- memcpy(out->databuf, ilbuf, illen);
+ if (!issetugid()) {
+ od_debug_mode = getenv("OD_DEBUG_MODE");
}
- *reply = kvbuf_decode(out);
- if (*reply == NULL)
- {
- /* DS returned no data */
- free(out->databuf);
- free(out);
+ if (od_debug_mode) {
+ status = bootstrap_look_up(bootstrap_port, kDSStdMachDSLookupPortName "_debug", &_ds_port);
+ } else {
+ status = bootstrap_look_up2(bootstrap_port, kDSStdMachDSLookupPortName, &_ds_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
}
+ if ((status != BOOTSTRAP_SUCCESS) && (status != BOOTSTRAP_UNKNOWN_SERVICE)) _ds_port = MACH_PORT_NULL;
-#ifdef DEBUG
- asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupQuery %d status OK", procno);
-#endif
- return status;
+ return (_ds_port != MACH_PORT_NULL);
}
-/* notify SPI */
-uint32_t notify_peek(int token, uint32_t *val);
-
-typedef struct
-{
- int notify_token_global;
- int notify_token_user;
- int notify_token_group;
- int notify_token_host;
- int notify_token_service;
-} ds_si_private_t;
-
-static uid_t
-audit_token_uid(audit_token_t a)
+static bool
+_valid_token(xpc_object_t reply)
{
+ audit_token_t token;
+
/*
* This should really call audit_token_to_au32,
* but that's in libbsm, not in a Libsystem library.
*/
- return (uid_t)a.val[1];
+ xpc_dictionary_get_audit_token(reply, &token);
+
+ return ((uid_t) token.val[1] == 0);
}
static void
-ds_get_validation(si_mod_t *si, uint64_t *a, uint64_t *b, int cat)
+_ds_get_validation(si_mod_t *si, uint64_t *a, uint64_t *b, int cat)
{
ds_si_private_t *pp;
uint32_t peek;
if (cat == CATEGORY_USER) status = notify_peek(pp->notify_token_user, &peek);
else if (cat == CATEGORY_GROUP) status = notify_peek(pp->notify_token_group, &peek);
else if (cat == CATEGORY_GROUPLIST) status = notify_peek(pp->notify_token_group, &peek);
- else if (cat == CATEGORY_HOST_IPV4) status = notify_peek(pp->notify_token_host, &peek);
- else if (cat == CATEGORY_HOST_IPV6) status = notify_peek(pp->notify_token_host, &peek);
else if (cat == CATEGORY_SERVICE) status = notify_peek(pp->notify_token_service, &peek);
if (status == NOTIFY_STATUS_OK) *b = ntohl(peek);
}
}
-static si_list_t *
-ds_list(si_mod_t *si, int cat, const char *procname, int *procnum, void *extra, si_item_t *(*extract)(si_mod_t *, kvarray_t *, void *, uint64_t, uint64_t), kvbuf_t *request)
+XPC_RETURNS_RETAINED
+__private_extern__ xpc_object_t
+_od_rpc_call(const char *procname, xpc_object_t payload, xpc_pipe_t (*get_pipe)(bool))
{
- si_item_t *item;
- si_list_t *list;
- kvarray_t *reply;
- kern_return_t status;
- uint64_t va, vb;
-
- if (*procnum < 0)
- {
- status = LI_DSLookupGetProcedureNumber(procname, procnum);
- if (status != KERN_SUCCESS) return NULL;
+ xpc_object_t result = NULL;
+ xpc_object_t reply;
+ xpc_pipe_t od_pipe;
+ int retries, rc;
+
+ od_pipe = get_pipe(false);
+ if (od_pipe == NULL) return NULL;
+
+ if (payload == NULL) {
+ payload = xpc_dictionary_create(NULL, NULL, 0);
+ }
+
+ // we nest it for backward compatibility so we can do independent submissions
+ xpc_dictionary_set_string(payload, OD_RPC_NAME, procname);
+ xpc_dictionary_set_int64(payload, OD_RPC_VERSION, 2);
+
+ for (retries = 0; od_pipe != NULL && retries < 2; retries++) {
+ rc = xpc_pipe_routine(od_pipe, payload, &reply);
+ switch (rc) {
+ case EPIPE:
+ xpc_release(od_pipe);
+ od_pipe = get_pipe(true);
+ break;
+
+ case EAGAIN:
+ /* just loop and try to send again */
+ break;
+
+ case 0:
+ if (_valid_token(reply) == true) {
+ result = reply;
+ }
+ /* fall through since we got a valid response */
+
+ default:
+ /* release and NULL the pipe it'll break the loop */
+ xpc_release(od_pipe);
+ od_pipe = NULL;
+ break;
+ }
+ }
+
+ if (od_pipe != NULL) {
+ xpc_release(od_pipe);
}
- reply = NULL;
- ds_get_validation(si, &va, &vb, cat);
- status = LI_DSLookupQuery(*procnum, request, &reply);
+ return result;
+}
+
+static si_list_t *
+_ds_list(si_mod_t *si, int cat, const char *procname, const void *extra, od_extract_t extract)
+{
+ __block si_list_t *list;
+ uint64_t va, vb;
+ xpc_object_t reply, result;
- if ((status != KERN_SUCCESS) || (reply == NULL)) return NULL;
+ if (procname == NULL) return NULL;
+ _ds_get_validation(si, &va, &vb, cat);
+
list = NULL;
- while (reply->curr < reply->count)
- {
- item = extract(si, reply, extra, va, vb);
- list = si_list_add(list, item);
- si_item_release(item);
+ reply = _od_rpc_call(procname, NULL, _od_xpc_pipe);
+ if (reply != NULL) {
+ result = xpc_dictionary_get_value(reply, OD_RPC_RESULT);
+ if (result != NULL && xpc_get_type(result) == XPC_TYPE_ARRAY) {
+ xpc_array_apply(result, ^bool(size_t index, xpc_object_t value) {
+ si_item_t *item = extract(si, value, extra, va, vb);
+ list = si_list_add(list, item);
+ si_item_release(item);
+
+ return true;
+ });
+ }
+
+ xpc_release(reply);
}
- kvarray_free(reply);
-
return list;
}
static si_item_t *
-ds_item(si_mod_t *si, int cat, const char *procname, int *procnum, void *extra, si_item_t *(*extract)(si_mod_t *, kvarray_t *, void *, uint64_t, uint64_t), kvbuf_t *request)
+_ds_item(si_mod_t *si, int cat, const char *procname, const void *extra, od_extract_t extract, xpc_object_t payload)
{
- si_item_t *item;
- kvarray_t *reply;
- kern_return_t status;
+ xpc_object_t result;
uint64_t va, vb;
+ si_item_t *item = NULL;
+
+ if (procname == NULL) return NULL;
- if (*procnum < 0)
- {
- status = LI_DSLookupGetProcedureNumber(procname, procnum);
- if (status != KERN_SUCCESS) return NULL;
+ result = _od_rpc_call(procname, payload, _od_xpc_pipe);
+ if (result != NULL) {
+ _ds_get_validation(si, &va, &vb, cat);
+ if (xpc_dictionary_get_int64(result, OD_RPC_ERROR) == 0) {
+ item = extract(si, result, extra, va, vb);
+ }
+
+ xpc_release(result);
}
-
- reply = NULL;
- ds_get_validation(si, &va, &vb, cat);
- status = LI_DSLookupQuery(*procnum, request, &reply);
-
- if ((status != KERN_SUCCESS) || (reply == NULL)) return NULL;
-
- item = extract(si, reply, extra, va, vb);
- kvarray_free(reply);
-
+
return item;
}
-/*
- * Extract the next user entry from a kvarray.
- */
-static si_item_t *
-extract_user(si_mod_t *si, kvarray_t *in, void *ignored, uint64_t valid_global, uint64_t valid_cat)
+static int
+_ds_is_valid(si_mod_t *si, si_item_t *item)
{
- struct passwd tmp;
- uint32_t d, k, kcount;
-
- if (si == NULL) return NULL;
- if (in == NULL) return NULL;
-
- d = in->curr;
- in->curr++;
+ si_mod_t *src;
+ ds_si_private_t *pp;
+ int status;
+ uint32_t oldval, newval;
+
+ if (si == NULL) return 0;
+ if (item == NULL) return 0;
+ if (si->name == NULL) return 0;
+ if (item->src == NULL) return 0;
+
+ pp = (ds_si_private_t *)si->private;
+ if (pp == NULL) return 0;
+
+ src = (si_mod_t *)item->src;
+
+ if (src->name == NULL) return 0;
+ if (string_not_equal(si->name, src->name)) return 0;
+
+ /* check global invalidation */
+ oldval = item->validation_a;
+ newval = -1;
+ status = notify_peek(pp->notify_token_global, &newval);
+ if (status != NOTIFY_STATUS_OK) return 0;
+
+ newval = ntohl(newval);
+ if (oldval != newval) return 0;
+
+ oldval = item->validation_b;
+ newval = -1;
+ if (item->type == CATEGORY_USER) status = notify_peek(pp->notify_token_user, &newval);
+ else if (item->type == CATEGORY_GROUP) status = notify_peek(pp->notify_token_group, &newval);
+ else if (item->type == CATEGORY_SERVICE) status = notify_peek(pp->notify_token_service, &newval);
+ else return 0;
+
+ if (status != NOTIFY_STATUS_OK) return 0;
+
+ newval = ntohl(newval);
+ if (oldval != newval) return 0;
+
+ return 1;
+}
- if (d >= in->count) return NULL;
+static void
+_free_addr_list(char **l)
+{
+ int i;
- memset(&tmp, 0, sizeof(struct passwd));
-
- tmp.pw_uid = -2;
- tmp.pw_gid = -2;
-
- kcount = in->dict[d].kcount;
-
- for (k = 0; k < kcount; k++)
- {
- if (string_equal(in->dict[d].key[k], "pw_name"))
- {
- if (tmp.pw_name != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.pw_name = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "pw_passwd"))
- {
- if (tmp.pw_passwd != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.pw_passwd = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "pw_uid"))
- {
- if (in->dict[d].vcount[k] == 0) continue;
- tmp.pw_uid = atoi(in->dict[d].val[k][0]);
- }
- else if (string_equal(in->dict[d].key[k], "pw_gid"))
- {
- if (in->dict[d].vcount[k] == 0) continue;
- tmp.pw_gid = atoi(in->dict[d].val[k][0]);
- }
- else if (string_equal(in->dict[d].key[k], "pw_change"))
- {
- if (in->dict[d].vcount[k] == 0) continue;
- tmp.pw_change = atol(in->dict[d].val[k][0]);
- }
- else if (string_equal(in->dict[d].key[k], "pw_expire"))
- {
- if (in->dict[d].vcount[k] == 0) continue;
- tmp.pw_expire = atol(in->dict[d].val[k][0]);
- }
- else if (string_equal(in->dict[d].key[k], "pw_class"))
- {
- if (tmp.pw_class != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.pw_class = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "pw_gecos"))
- {
- if (tmp.pw_gecos != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.pw_gecos = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "pw_dir"))
- {
- if (tmp.pw_dir != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.pw_dir = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "pw_shell"))
- {
- if (tmp.pw_shell != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.pw_shell = (char *)in->dict[d].val[k][0];
- }
- }
-
- if (tmp.pw_name == NULL) tmp.pw_name = "";
- if (tmp.pw_passwd == NULL) tmp.pw_passwd = "";
- if (tmp.pw_class == NULL) tmp.pw_class = "";
- if (tmp.pw_gecos == NULL) tmp.pw_gecos = "";
- if (tmp.pw_dir == NULL) tmp.pw_dir = "";
- if (tmp.pw_shell == NULL) tmp.pw_shell = "";
-
- return (si_item_t *)LI_ils_create("L4488ss44LssssL", (unsigned long)si, CATEGORY_USER, 1, valid_global, valid_cat, tmp.pw_name, tmp.pw_passwd, tmp.pw_uid, tmp.pw_gid, tmp.pw_change, tmp.pw_class, tmp.pw_gecos, tmp.pw_dir, tmp.pw_shell, tmp.pw_expire);
-}
-
-static si_item_t *
-extract_group(si_mod_t *si, kvarray_t *in, void *ignored, uint64_t valid_global, uint64_t valid_cat)
-{
- struct group tmp;
- char *empty[1];
- uint32_t d, k, kcount;
-
- if (si == NULL) return NULL;
- if (in == NULL) return NULL;
-
- d = in->curr;
- in->curr++;
-
- if (d >= in->count) return NULL;
-
- empty[0] = NULL;
- memset(&tmp, 0, sizeof(struct group));
-
- tmp.gr_gid = -2;
-
- kcount = in->dict[d].kcount;
-
- for (k = 0; k < kcount; k++)
- {
- if (string_equal(in->dict[d].key[k], "gr_name"))
- {
- if (tmp.gr_name != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.gr_name = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "gr_passwd"))
- {
- if (tmp.gr_passwd != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.gr_passwd = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "gr_gid"))
- {
- if (in->dict[d].vcount[k] == 0) continue;
- tmp.gr_gid = atoi(in->dict[d].val[k][0]);
- }
- else if (string_equal(in->dict[d].key[k], "gr_mem"))
- {
- if (tmp.gr_mem != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.gr_mem = (char **)in->dict[d].val[k];
- }
- }
-
- if (tmp.gr_name == NULL) tmp.gr_name = "";
- if (tmp.gr_passwd == NULL) tmp.gr_passwd = "";
- if (tmp.gr_mem == NULL) tmp.gr_mem = empty;
-
- return (si_item_t *)LI_ils_create("L4488ss4*", (unsigned long)si, CATEGORY_GROUP, 1, valid_global, valid_cat, tmp.gr_name, tmp.gr_passwd, tmp.gr_gid, tmp.gr_mem);
-}
-
-static void
-_free_addr_list(char **l)
-{
- int i;
-
- if (l == NULL) return;
- for (i = 0; l[i] != NULL; i++) free(l[i]);
- free(l);
-}
+ if (l == NULL) return;
+ for (i = 0; l[i] != NULL; i++) free(l[i]);
+ free(l);
+}
/* map ipv4 addresses and append to v6 list */
static int
return 0;
}
-static si_item_t *
-extract_netgroup(si_mod_t *si, kvarray_t *in, void *ignored, uint64_t valid_global, uint64_t valid_cat)
+static xpc_object_t
+_xpc_query_key_string(const char *key, const char *value)
{
- const char *host, *user, *domain;
- uint32_t d, k, kcount;
-
- if (si == NULL) return NULL;
- if (in == NULL) return NULL;
-
- d = in->curr;
- in->curr++;
-
- if (d >= in->count) return NULL;
-
- kcount = in->dict[d].kcount;
+ xpc_object_t payload;
+
+ if (value == NULL) return NULL;
+
+ payload = xpc_dictionary_create(NULL, NULL, 0);
+ if (payload == NULL) return NULL;
+
+ xpc_dictionary_set_string(payload, key, value);
+
+ return payload;
+}
- host = NULL;
- user = NULL;
- domain = NULL;
+static xpc_object_t
+_xpc_query_key_id(const char *key, id_t idValue)
+{
+ xpc_object_t payload;
+
+ payload = xpc_dictionary_create(NULL, NULL, 0);
+ if (payload == NULL) return NULL;
+
+ xpc_dictionary_set_int64(payload, key, idValue);
+
+ return payload;
+}
- for (k = 0; k < kcount; k++)
- {
- if (string_equal(in->dict[d].key[k], "host"))
- {
- if (host != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
+static xpc_object_t
+_xpc_query_key_uuid(const char *key, uuid_t uu)
+{
+ xpc_object_t payload;
+
+ payload = xpc_dictionary_create(NULL, NULL, 0);
+ if (payload == NULL) return NULL;
+
+ xpc_dictionary_set_uuid(payload, key, uu);
+
+ return payload;
+}
- host = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "user"))
- {
- if (user != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
+static xpc_object_t
+_xpc_query_key_int(const char *key, int64_t intValue)
+{
+ xpc_object_t payload;
+
+ payload = xpc_dictionary_create(NULL, NULL, 0);
+ if (payload == NULL) return NULL;
+
+ xpc_dictionary_set_int64(payload, key, intValue);
+
+ return payload;
+}
- user = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "domain"))
- {
- if (domain != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
+#pragma mark -
- domain = (char *)in->dict[d].val[k][0];
- }
+static char **
+_extract_array(xpc_object_t reply, const char *key, unsigned int *len)
+{
+ xpc_object_t xpc_array;
+ char **result;
+
+ xpc_array = xpc_dictionary_get_value(reply, key);
+ if (xpc_array == NULL || xpc_get_type(xpc_array) != XPC_TYPE_ARRAY) {
+ return calloc(1, sizeof(*result));
}
+
+ result = calloc(xpc_array_get_count(xpc_array) + 1, sizeof(*result));
+ if (result == NULL) {
+ return NULL;
+ }
+
+ if (len != NULL) {
+ /* include trailing NULL */
+ (*len) = xpc_array_get_count(xpc_array) + 1;
+ }
+
+ xpc_array_apply(xpc_array, ^_Bool(size_t idx, xpc_object_t value) {
+ result[idx] = (char *) xpc_string_get_string_ptr(value);
+ return true;
+ });
+
+ return result;
+}
- if (host == NULL) host = "";
- if (user == NULL) user = "";
- if (domain == NULL) domain = "";
+static const char *
+_extract_string(xpc_object_t reply, const char *key)
+{
+ xpc_object_t value = xpc_dictionary_get_value(reply, key);
+ xpc_type_t type;
+ const char *result = NULL;
+
+ if (value == NULL) {
+ return "";
+ }
+
+ type = xpc_get_type(value);
+ if (type == XPC_TYPE_STRING) {
+ result = xpc_string_get_string_ptr(value);
+ } else if (type == XPC_TYPE_ARRAY && xpc_array_get_count(value) != 0) {
+ result = xpc_array_get_string(value, 0);
+ }
+
+ if (result == NULL) {
+ result = "";
+ }
+
+ return result;
+}
- return (si_item_t *)LI_ils_create("L4488sss", (unsigned long)si, CATEGORY_ALIAS, 1, valid_global, valid_cat, host, user, domain);
+static uint32_t
+_extract_uint32(xpc_object_t reply, const char *key)
+{
+ xpc_object_t value = xpc_dictionary_get_value(reply, key);
+ xpc_type_t type;
+ uint32_t result;
+
+ if (value == NULL) {
+ return 0;
+ }
+
+ type = xpc_get_type(value);
+ if (type == XPC_TYPE_ARRAY && xpc_array_get_count(value) != 0) {
+ value = xpc_array_get_value(value, 0);
+ type = xpc_get_type(value);
+ }
+
+ if (type == XPC_TYPE_STRING) {
+ result = (int) strtol(xpc_string_get_string_ptr(value), NULL, 10);
+ } else if (type == XPC_TYPE_INT64) {
+ result = (uint32_t) xpc_int64_get_value(value);
+ } else if (type == XPC_TYPE_BOOL) {
+ result = xpc_bool_get_value(value);
+ } else {
+ result = 0;
+ }
+
+ return result;
}
static si_item_t *
-extract_alias(si_mod_t *si, kvarray_t *in, void *ignored, uint64_t valid_global, uint64_t valid_cat)
+_extract_user(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
{
- struct aliasent tmp;
- char *empty[1];
- uint32_t d, k, kcount;
-
+ struct passwd tmp;
+
if (si == NULL) return NULL;
- if (in == NULL) return NULL;
-
- d = in->curr;
- in->curr++;
-
- if (d >= in->count) return NULL;
-
- empty[0] = NULL;
- memset(&tmp, 0, sizeof(struct group));
-
- kcount = in->dict[d].kcount;
-
- for (k = 0; k < kcount; k++)
- {
- if (string_equal(in->dict[d].key[k], "alias_name"))
- {
- if (tmp.alias_name != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.alias_name = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "alias_members"))
- {
- if (tmp.alias_members != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.alias_members_len = in->dict[d].vcount[k];
- tmp.alias_members = (char **)in->dict[d].val[k];
- }
- else if (string_equal(in->dict[d].key[k], "alias_local"))
- {
- if (in->dict[d].vcount[k] == 0) continue;
- tmp.alias_local = atoi(in->dict[d].val[k][0]);
- }
- }
-
- return (si_item_t *)LI_ils_create("L4488s4*4", (unsigned long)si, CATEGORY_ALIAS, 1, valid_global, valid_cat, tmp.alias_name, tmp.alias_members_len, tmp.alias_members, tmp.alias_local);
+ if (reply == NULL) return NULL;
+
+ tmp.pw_name = (char *) _extract_string(reply, "pw_name");
+ tmp.pw_passwd = (char *) _extract_string(reply, "pw_passwd");
+ tmp.pw_uid = (uid_t) _extract_uint32(reply, "pw_uid");
+ tmp.pw_gid = (gid_t) _extract_uint32(reply, "pw_gid");
+ tmp.pw_change = (time_t) _extract_uint32(reply, "pw_change");
+ tmp.pw_expire = (time_t) _extract_uint32(reply, "pw_expire");
+ tmp.pw_class = (char *) _extract_string(reply, "pw_class");
+ tmp.pw_gecos = (char *) _extract_string(reply, "pw_gecos");
+ tmp.pw_dir = (char *) _extract_string(reply, "pw_dir");
+ tmp.pw_shell = (char *) _extract_string(reply, "pw_shell");
+
+ return (si_item_t *)LI_ils_create("L4488ss44LssssL", (unsigned long)si, CATEGORY_USER, 1, valid_global, valid_cat, tmp.pw_name, tmp.pw_passwd, tmp.pw_uid, tmp.pw_gid, tmp.pw_change, tmp.pw_class, tmp.pw_gecos, tmp.pw_dir, tmp.pw_shell, tmp.pw_expire);
}
static si_item_t *
-extract_host(si_mod_t *si, kvarray_t *in, void *extra, uint64_t valid_global, uint64_t valid_cat)
+_extract_group(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
{
- struct hostent tmp;
- si_item_t *out;
- uint32_t i, d, k, kcount, vcount, v4count, v6count, want;
- int status, addr_len;
- int family, addr_count;
- struct in_addr a4;
- struct in6_addr a6;
- char **v4addrs, **v6addrs;
- char *empty[1];
-
- v4addrs = NULL;
- v6addrs = NULL;
- v4count = 0;
- v6count = 0;
- addr_count = 0;
- addr_len = sizeof(void *);
-
+ si_item_t *item;
+ struct group tmp;
+
if (si == NULL) return NULL;
- if (in == NULL) return NULL;
-
- d = in->curr;
- in->curr++;
-
- if (d >= in->count) return NULL;
-
- empty[0] = NULL;
- memset(&tmp, 0, sizeof(struct hostent));
-
- family = AF_INET;
- tmp.h_length = IPV4_ADDR_LEN;
-
- want = WANT_A4_ONLY;
- if (extra != NULL) want = *(uint32_t *)extra;
-
- if (want != WANT_A4_ONLY)
- {
- family = AF_INET6;
- tmp.h_length = IPV6_ADDR_LEN;
- }
-
- tmp.h_addrtype = family;
-
- kcount = in->dict[d].kcount;
-
- for (k = 0; k < kcount; k++)
- {
- if (string_equal(in->dict[d].key[k], "h_name"))
- {
- if (tmp.h_name != NULL) continue;
-
- vcount = in->dict[d].vcount[k];
- if (vcount == 0) continue;
-
- tmp.h_name = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "h_aliases"))
- {
- if (tmp.h_aliases != NULL) continue;
-
- vcount = in->dict[d].vcount[k];
- if (vcount == 0) continue;
-
- tmp.h_aliases = (char **)in->dict[d].val[k];
- }
- else if (string_equal(in->dict[d].key[k], "h_ipv4_addr_list"))
- {
- if (v4addrs != NULL) continue;
-
- v4count = in->dict[d].vcount[k];
- if (v4count == 0) continue;
-
- v4addrs = (char **)calloc(v4count + 1, sizeof(char *));
- if (v4addrs == NULL)
- {
- _free_addr_list(v6addrs);
- return NULL;
- }
-
- for (i = 0; i < v4count; i++)
- {
- v4addrs[i] = calloc(1, IPV4_ADDR_LEN);
- if (v4addrs[i] == NULL)
- {
- _free_addr_list(v4addrs);
- _free_addr_list(v6addrs);
- return NULL;
- }
-
- memset(&a4, 0, sizeof(struct in_addr));
- status = inet_pton(AF_INET, in->dict[d].val[k][i], &a4);
- if (status != 1)
- {
- _free_addr_list(v4addrs);
- _free_addr_list(v6addrs);
- return NULL;
- }
-
- memcpy(v4addrs[i], &a4, IPV4_ADDR_LEN);
- }
- }
- else if (string_equal(in->dict[d].key[k], "h_ipv6_addr_list"))
- {
- if (v6addrs != NULL) continue;
-
- v6count = in->dict[d].vcount[k];
- if (v6count == 0) continue;
-
- v6addrs = (char **)calloc(v6count + 1, sizeof(char *));
- if (v6addrs == NULL)
- {
- _free_addr_list(v4addrs);
- return NULL;
- }
-
- for (i = 0; i < v6count; i++)
- {
- v6addrs[i] = calloc(1, IPV6_ADDR_LEN);
- if (v6addrs[i] == NULL)
- {
- _free_addr_list(v4addrs);
- _free_addr_list(v6addrs);
- return NULL;
- }
-
- memset(&a6, 0, sizeof(struct in6_addr));
- status = inet_pton(AF_INET6, in->dict[d].val[k][i], &a6);
- if (status != 1)
- {
- _free_addr_list(v4addrs);
- _free_addr_list(v6addrs);
- return NULL;
- }
+ if (reply == NULL) return NULL;
+
+ tmp.gr_name = (char *) _extract_string(reply, "gr_name");
+ tmp.gr_passwd = (char *) _extract_string(reply, "gr_passwd");
+ tmp.gr_gid = (gid_t) _extract_uint32(reply, "gr_gid");
+ tmp.gr_mem = _extract_array(reply, "gr_mem", NULL);
- memcpy(v6addrs[i], &(a6.__u6_addr.__u6_addr32[0]), IPV6_ADDR_LEN);
- }
- }
+ item = (si_item_t *) LI_ils_create("L4488ss4*", (unsigned long)si, CATEGORY_GROUP, 1, valid_global, valid_cat, tmp.gr_name, tmp.gr_passwd, tmp.gr_gid, tmp.gr_mem);
+
+ if (tmp.gr_mem != NULL) {
+ free(tmp.gr_mem); /* have to free because it's allocated */
}
+
+ return item;
+}
- if (tmp.h_name == NULL) tmp.h_name = "";
- if (tmp.h_aliases == NULL) tmp.h_aliases = empty;
+static si_item_t *
+_extract_netgroup(si_mod_t *si, xpc_object_t reply, const void *ignored, uint64_t valid_global, uint64_t valid_cat)
+{
+ const char *host, *user, *domain;
- if (want == WANT_A4_ONLY)
- {
- _free_addr_list(v6addrs);
- if (v4addrs == NULL) return NULL;
+ if (si == NULL) return NULL;
+ if (reply == NULL) return NULL;
- tmp.h_addr_list = v4addrs;
- out = (si_item_t *)LI_ils_create("L4488s*44a", (unsigned long)si, CATEGORY_HOST_IPV4, 1, valid_global, valid_cat, tmp.h_name, tmp.h_aliases, tmp.h_addrtype, tmp.h_length, tmp.h_addr_list);
- _free_addr_list(v4addrs);
- return out;
- }
- else if ((want == WANT_A6_ONLY) || ((want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) && (v6count > 0)))
- {
- _free_addr_list(v4addrs);
- if (v6addrs == NULL) return NULL;
+ host = _extract_string(reply, "host");
+ user = _extract_string(reply, "user");
+ domain = _extract_string(reply, "domain");
- tmp.h_addr_list = v6addrs;
- out = (si_item_t *)LI_ils_create("L4488s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, valid_global, valid_cat, tmp.h_name, tmp.h_aliases, tmp.h_addrtype, tmp.h_length, tmp.h_addr_list);
- _free_addr_list(v6addrs);
- return out;
- }
+ return (si_item_t *)LI_ils_create("L4488sss", (unsigned long)si, CATEGORY_NETGROUP, 1, valid_global, valid_cat, host, user, domain);
+}
- /*
- * At this point, want is WANT_A6_PLUS_MAPPED_A4, WANT_MAPPED_A4_ONLY,
- * or WANT_A6_OR_MAPPED_A4_IF_NO_A6. In the last case, there are no ipv6
- * addresses, so that case degenerates into WANT_MAPPED_A4_ONLY.
- */
- if (want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) want = WANT_MAPPED_A4_ONLY;
+static si_item_t *
+_extract_alias(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
+{
+ struct aliasent tmp;
+ si_item_t *item;
- if (want == WANT_MAPPED_A4_ONLY)
- {
- _free_addr_list(v6addrs);
- v6addrs = NULL;
- v6count = 0;
- }
+ if (si == NULL) return NULL;
+ if (reply == NULL) return NULL;
+
+ tmp.alias_name = (char *) _extract_string(reply, "alias_name");
+ tmp.alias_local = _extract_uint32(reply, "alias_local");
+ tmp.alias_members = _extract_array(reply, "alias_members", &tmp.alias_members_len);
- status = _map_v4(&v6addrs, v6count, v4addrs, v4count);
- _free_addr_list(v4addrs);
- if (status != 0)
- {
- _free_addr_list(v6addrs);
- return NULL;
+ item = (si_item_t *)LI_ils_create("L4488s4*4", (unsigned long)si, CATEGORY_ALIAS, 1, valid_global, valid_cat, tmp.alias_name, tmp.alias_members_len, tmp.alias_members, tmp.alias_local);
+
+ if (tmp.alias_members != NULL) {
+ free(tmp.alias_members);
}
-
- if (v6addrs == NULL) return NULL;
-
- tmp.h_addr_list = v6addrs;
- out = (si_item_t *)LI_ils_create("L4488s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, valid_global, valid_cat, tmp.h_name, tmp.h_aliases, tmp.h_addrtype, tmp.h_length, tmp.h_addr_list);
- _free_addr_list(v6addrs);
- return out;
+
+ return item;
}
static si_item_t *
-extract_network(si_mod_t *si, kvarray_t *in, void *ignored, uint64_t valid_global, uint64_t valid_cat)
+_extract_network(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
{
struct netent tmp;
- uint32_t d, k, kcount;
- char *empty[1];
+ si_item_t *item;
if (si == NULL) return NULL;
- if (in == NULL) return NULL;
-
- d = in->curr;
- in->curr++;
-
- if (d >= in->count) return NULL;
+ if (reply == NULL) return NULL;
- empty[0] = NULL;
- memset(&tmp, 0, sizeof(struct netent));
-
- tmp.n_addrtype = AF_INET;
-
- kcount = in->dict[d].kcount;
-
- for (k = 0; k < kcount; k++)
- {
- if (string_equal(in->dict[d].key[k], "n_name"))
- {
- if (tmp.n_name != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.n_name = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "n_net"))
- {
- if (in->dict[d].vcount[k] == 0) continue;
- tmp.n_net = inet_network(in->dict[d].val[k][0]);
- }
- else if (string_equal(in->dict[d].key[k], "n_addrtype"))
- {
- if (in->dict[d].vcount[k] == 0) continue;
- tmp.n_addrtype = atoi(in->dict[d].val[k][0]);
- }
- else if (string_equal(in->dict[d].key[k], "n_aliases"))
- {
- if (tmp.n_aliases != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
+ tmp.n_name = (char *) _extract_string(reply, "n_name");
+ tmp.n_aliases = _extract_array(reply, "n_aliases", NULL);
+ tmp.n_net = _extract_uint32(reply, "n_net");
+ tmp.n_addrtype = AF_INET; /* opendirectoryd doesn't return this value, only AF_INET is supported */
- tmp.n_aliases = (char **)in->dict[d].val[k];
- }
+ item = (si_item_t *)LI_ils_create("L4488s*44", (unsigned long)si, CATEGORY_NETWORK, 1, valid_global, valid_cat, tmp.n_name, tmp.n_aliases, tmp.n_addrtype, tmp.n_net);
+
+ if (tmp.n_aliases != NULL) {
+ free(tmp.n_aliases);
}
-
- if (tmp.n_name == NULL) tmp.n_name = "";
- if (tmp.n_aliases == NULL) tmp.n_aliases = empty;
-
- return (si_item_t *)LI_ils_create("L4488s*44", (unsigned long)si, CATEGORY_NETWORK, 1, valid_global, valid_cat, tmp.n_name, tmp.n_aliases, tmp.n_addrtype, tmp.n_net);
+
+ return item;
}
static si_item_t *
-extract_service(si_mod_t *si, kvarray_t *in, void *ignored, uint64_t valid_global, uint64_t valid_cat)
+_extract_service(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
{
struct servent tmp;
- char *empty[1];
- uint32_t d, k, kcount;
+ si_item_t *item;
if (si == NULL) return NULL;
- if (in == NULL) return NULL;
-
- d = in->curr;
- in->curr++;
-
- if (d >= in->count) return NULL;
-
- empty[0] = NULL;
- memset(&tmp, 0, sizeof(struct servent));
-
- kcount = in->dict[d].kcount;
-
- for (k = 0; k < kcount; k++)
- {
- if (string_equal(in->dict[d].key[k], "s_name"))
- {
- if (tmp.s_name != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.s_name = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "s_aliases"))
- {
- if (tmp.s_aliases != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.s_aliases = (char **)in->dict[d].val[k];
- }
- else if (string_equal(in->dict[d].key[k], "s_port"))
- {
- if (in->dict[d].vcount[k] == 0) continue;
- tmp.s_port = atoi(in->dict[d].val[k][0]);
- }
- else if (string_equal(in->dict[d].key[k], "s_proto"))
- {
- if (tmp.s_proto != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
+ if (reply == NULL) return NULL;
+
+ tmp.s_name = (char *) _extract_string(reply, "s_name");
+ tmp.s_aliases = _extract_array(reply, "s_aliases", NULL);
+ tmp.s_port = (unsigned int) htons(_extract_uint32(reply, "s_port"));
+ tmp.s_proto = (char *) _extract_string(reply, "s_proto");
- tmp.s_proto = (char *)in->dict[d].val[k][0];
- }
+ item = (si_item_t *)LI_ils_create("L4488s*4s", (unsigned long)si, CATEGORY_SERVICE, 1, valid_global, valid_cat, tmp.s_name, tmp.s_aliases, tmp.s_port, tmp.s_proto);
+
+ if (tmp.s_aliases != NULL) {
+ free(tmp.s_aliases);
}
-
- if (tmp.s_name == NULL) tmp.s_name = "";
- if (tmp.s_proto == NULL) tmp.s_proto = "";
- if (tmp.s_aliases == NULL) tmp.s_aliases = empty;
-
- /* strange but correct */
- tmp.s_port = htons(tmp.s_port);
-
- return (si_item_t *)LI_ils_create("L4488s*4s", (unsigned long)si, CATEGORY_SERVICE, 1, valid_global, valid_cat, tmp.s_name, tmp.s_aliases, tmp.s_port, tmp.s_proto);
+
+ return item;
}
static si_item_t *
-extract_protocol(si_mod_t *si, kvarray_t *in, void *ignored, uint64_t valid_global, uint64_t valid_cat)
+_extract_protocol(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
{
struct protoent tmp;
- uint32_t d, k, kcount;
- char *empty[1];
+ si_item_t *item;
if (si == NULL) return NULL;
- if (in == NULL) return NULL;
-
- d = in->curr;
- in->curr++;
-
- if (d >= in->count) return NULL;
-
- empty[0] = NULL;
- memset(&tmp, 0, sizeof(struct protoent));
-
- kcount = in->dict[d].kcount;
-
- for (k = 0; k < kcount; k++)
- {
- if (string_equal(in->dict[d].key[k], "p_name"))
- {
- if (tmp.p_name != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
+ if (reply == NULL) return NULL;
- tmp.p_name = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "p_proto"))
- {
- if (in->dict[d].vcount[k] == 0) continue;
- tmp.p_proto = atoi(in->dict[d].val[k][0]);
- }
- else if (string_equal(in->dict[d].key[k], "p_aliases"))
- {
- if (tmp.p_aliases != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
+ tmp.p_name = (char *) _extract_string(reply, "p_name");
+ tmp.p_proto = (int) _extract_uint32(reply, "p_proto");
+ tmp.p_aliases = _extract_array(reply, "p_aliases", NULL);
- tmp.p_aliases = (char **)in->dict[d].val[k];
- }
+ item = (si_item_t *)LI_ils_create("L4488s*4", (unsigned long)si, CATEGORY_PROTOCOL, 1, valid_global, valid_cat, tmp.p_name, tmp.p_aliases, tmp.p_proto);
+ if (tmp.p_aliases != NULL) {
+ free(tmp.p_aliases);
}
-
- if (tmp.p_name == NULL) tmp.p_name = "";
- if (tmp.p_aliases == NULL) tmp.p_aliases = empty;
-
- return (si_item_t *)LI_ils_create("L4488s*4", (unsigned long)si, CATEGORY_PROTOCOL, 1, valid_global, valid_cat, tmp.p_name, tmp.p_aliases, tmp.p_proto);
+
+ return item;
}
static si_item_t *
-extract_rpc(si_mod_t *si, kvarray_t *in, void *ignored, uint64_t valid_global, uint64_t valid_cat)
+_extract_rpc(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
{
struct rpcent tmp;
- uint32_t d, k, kcount;
- char *empty[1];
+ si_item_t *item;
if (si == NULL) return NULL;
- if (in == NULL) return NULL;
-
- d = in->curr;
- in->curr++;
-
- if (d >= in->count) return NULL;
-
- empty[0] = NULL;
- memset(&tmp, 0, sizeof(struct rpcent));
+ if (reply == NULL) return NULL;
- kcount = in->dict[d].kcount;
+ tmp.r_name = (char *) _extract_string(reply, "r_name");
+ tmp.r_number = (int) _extract_uint32(reply, "r_number");
+ tmp.r_aliases = _extract_array(reply, "r_aliases", NULL);
- for (k = 0; k < kcount; k++)
- {
- if (string_equal(in->dict[d].key[k], "r_name"))
- {
- if (tmp.r_name != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.r_name = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "r_number"))
- {
- if (in->dict[d].vcount[k] == 0) continue;
- tmp.r_number = atoi(in->dict[d].val[k][0]);
- }
- else if (string_equal(in->dict[d].key[k], "r_aliases"))
- {
- if (tmp.r_aliases != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.r_aliases = (char **)in->dict[d].val[k];
- }
+ item = (si_item_t *)LI_ils_create("L4488s*4", (unsigned long)si, CATEGORY_RPC, 1, valid_global, valid_cat, tmp.r_name, tmp.r_aliases, tmp.r_number);
+ if (tmp.r_aliases != NULL) {
+ free(tmp.r_aliases);
}
-
- if (tmp.r_name == NULL) tmp.r_name = "";
- if (tmp.r_aliases == NULL) tmp.r_aliases = empty;
-
- return (si_item_t *)LI_ils_create("L4488s*4", (unsigned long)si, CATEGORY_RPC, 1, valid_global, valid_cat, tmp.r_name, tmp.r_aliases, tmp.r_number);
+
+ return item;
}
static si_item_t *
-extract_fstab(si_mod_t *si, kvarray_t *in, void *extra, uint64_t valid_global, uint64_t valid_cat)
+_extract_fstab(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
{
struct fstab tmp;
- uint32_t d, k, kcount;
- char *file;
if (si == NULL) return NULL;
- if (in == NULL) return NULL;
-
- file = NULL;
- if (extra != NULL) file = (char *)extra;
+ if (reply == NULL) return NULL;
- d = in->curr;
- in->curr++;
-
- if (d >= in->count) return NULL;
-
- memset(&tmp, 0, sizeof(struct fstab));
-
- kcount = in->dict[d].kcount;
-
- for (k = 0; k < kcount; k++)
- {
- if (string_equal(in->dict[d].key[k], "fs_spec"))
- {
- if (tmp.fs_spec != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.fs_spec = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "fs_file"))
- {
- if (tmp.fs_file != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.fs_file = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "fs_vfstype"))
- {
- if (tmp.fs_vfstype != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.fs_vfstype = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "fs_mntops"))
- {
- if (tmp.fs_mntops != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.fs_mntops = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "fs_type"))
- {
- if (tmp.fs_type != NULL) continue;
- if (in->dict[d].vcount[k] == 0) continue;
-
- tmp.fs_type = (char *)in->dict[d].val[k][0];
- }
- else if (string_equal(in->dict[d].key[k], "fs_freq"))
- {
- if (in->dict[d].vcount[k] == 0) continue;
- tmp.fs_freq = atoi(in->dict[d].val[k][0]);
- }
- else if (string_equal(in->dict[d].key[k], "fs_passno"))
- {
- if (in->dict[d].vcount[k] == 0) continue;
- tmp.fs_passno = atoi(in->dict[d].val[k][0]);
- }
- }
-
- if (tmp.fs_spec == NULL) tmp.fs_spec = "";
- if (tmp.fs_file == NULL) tmp.fs_file = "";
- if (tmp.fs_vfstype == NULL) tmp.fs_vfstype = "";
- if (tmp.fs_mntops == NULL) tmp.fs_mntops = "";
- if (tmp.fs_type == NULL) tmp.fs_type = "";
-
- if ((file != NULL) && string_not_equal(file, tmp.fs_file)) return NULL;
+ tmp.fs_file = (char *) _extract_string(reply, "fs_file");
+ if (tmp.fs_file == NULL) return NULL;
+
+ tmp.fs_spec = (char *) _extract_string(reply, "fs_spec");
+ tmp.fs_freq = _extract_uint32(reply, "fs_freq");
+ tmp.fs_passno = _extract_uint32(reply, "fs_passno");
+ tmp.fs_mntops = (char *) _extract_string(reply, "fs_mntops");
+ tmp.fs_type = (char *) _extract_string(reply, "fs_type");
+ tmp.fs_vfstype = (char *) _extract_string(reply, "fs_vfstype");
return (si_item_t *)LI_ils_create("L4488sssss44", (unsigned long)si, CATEGORY_FS, 1, valid_global, valid_cat, tmp.fs_spec, tmp.fs_file, tmp.fs_vfstype, tmp.fs_mntops, tmp.fs_type, tmp.fs_freq, tmp.fs_passno);
}
static si_item_t *
-extract_mac_mac(si_mod_t *si, kvarray_t *in, void *extra, uint64_t valid_global, uint64_t valid_cat)
+_extract_mac_mac(si_mod_t *si, xpc_object_t reply, const void *extra, uint64_t valid_global, uint64_t valid_cat)
{
- uint32_t d, k, kcount;
+ const char *value;
char *cmac;
si_item_t *out;
if (si == NULL) return NULL;
- if (in == NULL) return NULL;
+ if (reply == NULL) return NULL;
if (extra == NULL) return NULL;
- d = in->curr;
- in->curr++;
-
- if (d >= in->count) return NULL;
-
- kcount = in->dict[d].kcount;
-
- cmac = NULL;
- for (k = 0; k < kcount; k++)
- {
- if ((cmac == NULL) && (string_equal(in->dict[d].key[k], "mac")))
- {
- if (in->dict[d].vcount[k] == 0) continue;
- cmac = si_standardize_mac_address(in->dict[d].val[k][0]);
- if (cmac == NULL) return NULL;
- }
- }
-
+ value = _extract_string(reply, "mac");
+ if (value == NULL || value[0] == '\0') return NULL;
+
+ cmac = si_standardize_mac_address(value);
if (cmac == NULL) return NULL;
out = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_MAC, 1, valid_global, valid_cat, extra, cmac);
+
free(cmac);
+
return out;
}
static si_item_t *
-extract_mac_name(si_mod_t *si, kvarray_t *in, void *extra, uint64_t valid_global, uint64_t valid_cat)
+_extract_mac_name(si_mod_t *si, xpc_object_t reply, const void *extra, uint64_t valid_global, uint64_t valid_cat)
{
- uint32_t d, k, kcount;
const char *name;
si_item_t *out;
if (si == NULL) return NULL;
- if (in == NULL) return NULL;
+ if (reply == NULL) return NULL;
if (extra == NULL) return NULL;
- d = in->curr;
- in->curr++;
-
- if (d >= in->count) return NULL;
-
- kcount = in->dict[d].kcount;
-
- name = NULL;
- for (k = 0; k < kcount; k++)
- {
- if ((name == NULL) && (string_equal(in->dict[d].key[k], "name")))
- {
- if (in->dict[d].vcount[k] == 0) continue;
- name = in->dict[d].val[k][0];
- }
- }
-
- if (name == NULL) return NULL;
+ name = _extract_string(reply, "name");
out = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_MAC, 1, valid_global, valid_cat, name, extra);
return out;
}
-static si_item_t *
-ds_user_byname(si_mod_t *si, const char *name)
-{
- static int proc = -1;
- kvbuf_t *request;
- si_item_t *item;
-
- request = kvbuf_query_key_val("login", name);
- if (request == NULL) return NULL;
-
- item = ds_item(si, CATEGORY_USER, "getpwnam", &proc, NULL, extract_user, request);
-
- kvbuf_free(request);
- return item;
-}
-
-static si_item_t *
-ds_user_byuid(si_mod_t *si, uid_t uid)
-{
- static int proc = -1;
- char val[16];
- kvbuf_t *request;
- si_item_t *item;
-
- snprintf(val, sizeof(val), "%d", (int)uid);
- request = kvbuf_query_key_val("uid", val);
- if (request == NULL) return NULL;
-
- item = ds_item(si, CATEGORY_USER, "getpwuid", &proc, NULL, extract_user, request);
-
- kvbuf_free(request);
- return item;
-}
-
-static si_list_t *
-ds_user_all(si_mod_t *si)
-{
- static int proc = -1;
-
- return ds_list(si, CATEGORY_USER, "getpwent", &proc, NULL, extract_user, NULL);
-}
-
-static si_item_t *
-ds_group_byname(si_mod_t *si, const char *name)
-{
- static int proc = -1;
- kvbuf_t *request;
- si_item_t *item;
-
- request = kvbuf_query_key_val("name", name);
- if (request == NULL) return NULL;
-
- item = ds_item(si, CATEGORY_GROUP, "getgrnam", &proc, NULL, extract_group, request);
-
- kvbuf_free(request);
- return item;
-}
-
-static si_item_t *
-ds_group_bygid(si_mod_t *si, gid_t gid)
-{
- static int proc = -1;
- char val[16];
- kvbuf_t *request;
- si_item_t *item;
-
- snprintf(val, sizeof(val), "%d", (int)gid);
- request = kvbuf_query_key_val("gid", val);
- if (request == NULL) return NULL;
-
- item = ds_item(si, CATEGORY_GROUP, "getgrgid", &proc, NULL, extract_group, request);
-
- kvbuf_free(request);
- return item;
-}
-
-static si_list_t *
-ds_group_all(si_mod_t *si)
-{
- static int proc = -1;
-
- return ds_list(si, CATEGORY_GROUP, "getgrent", &proc, NULL, extract_group, NULL);
-}
-
-static si_item_t *
-ds_grouplist(si_mod_t *si, const char *name)
-{
- struct passwd *pw;
- kern_return_t kstatus, ks2;
- uint32_t i, j, count, uid, basegid, gidptrCnt;
- int32_t *gidp;
- gid_t *gidptr;
- audit_token_t token;
- si_item_t *user, *item;
- char **gidlist;
- uint64_t va, vb;
- size_t gidptrsz;
- int n;
-
- if (name == NULL) return NULL;
-
- user = ds_user_byname(si, name);
- if (user == NULL) return NULL;
-
- pw = (struct passwd *)((uintptr_t)user + sizeof(si_item_t));
- uid = pw->pw_uid;
- basegid = pw->pw_gid;
-
- free(user);
-
- count = 0;
- gidptr = NULL;
- gidptrCnt = 0;
- gidptrsz = 0;
- memset(&token, 0, sizeof(audit_token_t));
-
- if (_mbr_port == MACH_PORT_NULL)
- {
- kstatus = bootstrap_look_up2(bootstrap_port, kDSStdMachDSMembershipPortName, &_mbr_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
- }
-
- for (n = 0; n < MAX_LOOKUP_ATTEMPTS; n++)
- {
- kstatus = memberdDSmig_GetAllGroups(_mbr_port, uid, &count, &gidptr, &gidptrCnt, &token);
- if (kstatus != MACH_SEND_INVALID_DEST) break;
-
- mach_port_mod_refs(mach_task_self(), _mbr_port, MACH_PORT_RIGHT_SEND, -1);
-
- ks2 = bootstrap_look_up2(bootstrap_port, kDSStdMachDSMembershipPortName, &_mbr_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
- if ((ks2 != BOOTSTRAP_SUCCESS) && (ks2 != BOOTSTRAP_UNKNOWN_SERVICE))
- {
- _mbr_port = MACH_PORT_NULL;
- break;
- }
- }
-
- if (kstatus != KERN_SUCCESS) return NULL;
- if (gidptr == NULL) return NULL;
-
- /* gidptrCnt is the size, but it was set to number of groups (by DS) in 10.6 and earlier */
- gidptrsz = gidptrCnt;
- if (count == gidptrCnt) gidptrsz = gidptrCnt * sizeof(gid_t);
-
- if ((audit_token_uid(token) != 0) || (count == 0))
- {
- if (gidptr != NULL) vm_deallocate(mach_task_self(), (vm_address_t)gidptr, gidptrsz);
- return NULL;
- }
-
- gidlist = (char **)calloc(count + 1, sizeof(char *));
- if (gidlist == NULL)
- {
- if (gidptr != NULL) vm_deallocate(mach_task_self(), (vm_address_t)gidptr, gidptrsz);
- return NULL;
- }
-
- for (i = 0; i < count; i++)
- {
- gidp = (int32_t *)calloc(1, sizeof(int32_t));
- if (gidp == NULL)
- {
- for (j = 0; j < i; j++) free(gidlist[j]);
- free(gidlist);
- count = 0;
- break;
- }
-
- *gidp = gidptr[i];
- gidlist[i] = (char *)gidp;
- }
-
- if (count == 0)
- {
- if (gidptr != NULL) vm_deallocate(mach_task_self(), (vm_address_t)gidptr, gidptrsz);
- return NULL;
- }
+#pragma mark -
- va = 0;
- vb = 0;
- ds_get_validation(si, &va, &vb, CATEGORY_GROUPLIST);
+static si_item_t *
+ds_user_byname(si_mod_t *si, const char *name)
+{
+ xpc_object_t payload;
+ si_item_t *item;
- item = (si_item_t *)LI_ils_create("L4488s44a", (unsigned long)si, CATEGORY_GROUPLIST, 1, va, vb, name, basegid, count, gidlist);
+ if (!_od_running()) return NULL;
- if (gidptr != NULL) vm_deallocate(mach_task_self(), (vm_address_t)gidptr, gidptrsz);
+ payload = _xpc_query_key_string("name", name);
+ if (payload == NULL) return NULL;
- for (i = 0; i <= count; i++) free(gidlist[i]);
- free(gidlist);
+ item = _ds_item(si, CATEGORY_USER, "getpwnam", NULL, _extract_user, payload);
+ xpc_release(payload);
return item;
}
-static si_list_t *
-ds_netgroup_byname(si_mod_t *si, const char *name)
+static si_item_t *
+ds_user_byuid(si_mod_t *si, uid_t uid)
{
- static int proc = -1;
- kvbuf_t *request;
- si_list_t *list;
+ xpc_object_t payload;
+ si_item_t *item;
- request = kvbuf_query_key_val("netgroup", name);
- if (request == NULL) return NULL;
+ if (!_od_running()) return NULL;
- list = ds_list(si, CATEGORY_NETGROUP, "getnetgrent", &proc, NULL, extract_netgroup, request);
+ payload = _xpc_query_key_id("uid", uid);
+ if (payload == NULL) return NULL;
- kvbuf_free(request);
+ item = _ds_item(si, CATEGORY_USER, "getpwuid", NULL, _extract_user, payload);
- return list;
+ xpc_release(payload);
+ return item;
}
-static int
-check_innetgr(kvarray_t *in)
+static si_item_t *
+ds_user_byuuid(si_mod_t *si, uuid_t uuid)
{
- uint32_t d, k, kcount;
+ xpc_object_t payload;
+ si_item_t *item;
- if (in == NULL) return 0;
+ if (!_od_running()) return NULL;
- d = in->curr;
- if (d >= in->count) return 0;
+ payload = _xpc_query_key_uuid("uuid", uuid);
+ if (payload == NULL) return NULL;
- kcount = in->dict[d].kcount;
+ item = _ds_item(si, CATEGORY_USER, "getpwuuid", NULL, _extract_user, payload);
- for (k = 0; k < kcount; k++)
- {
- if (string_equal(in->dict[d].key[k], "result"))
- {
- if (in->dict[d].vcount[k] == 0) continue;
- return atoi(in->dict[d].val[k][0]);
- }
- }
+ xpc_release(payload);
+ return item;
+}
- return 0;
+static si_list_t *
+ds_user_all(si_mod_t *si)
+{
+ return _ds_list(si, CATEGORY_USER, "getpwent", NULL, _extract_user);
}
-static int
-ds_in_netgroup(si_mod_t *si, const char *group, const char *host, const char *user, const char *domain)
+static si_item_t *
+ds_group_byname(si_mod_t *si, const char *name)
{
- int is_innetgr;
- kvbuf_t *request;
- kvarray_t *reply;
- kern_return_t status;
- static int proc = -1;
+ xpc_object_t payload;
+ si_item_t *item;
- if (proc < 0)
- {
- status = LI_DSLookupGetProcedureNumber("innetgr", &proc);
- if (status != KERN_SUCCESS) return 0;
- }
+ if (!_od_running()) return NULL;
- /* Encode NULL */
- if (group == NULL) group = "";
- if (host == NULL) host = "";
- if (user == NULL) user = "";
- if (domain == NULL) domain = "";
+ payload = _xpc_query_key_string("name", name);
+ if (payload == NULL) return NULL;
- request = kvbuf_query("ksksksks", "netgroup", group, "host", host, "user", user, "domain", domain);
- if (request == NULL) return 0;
+ item = _ds_item(si, CATEGORY_GROUP, "getgrnam", NULL, _extract_group, payload);
- reply = NULL;
- status = LI_DSLookupQuery(proc, request, &reply);
- kvbuf_free(request);
+ xpc_release(payload);
+ return item;
+}
- if ((status != KERN_SUCCESS) || (reply == NULL)) return 0;
+static si_item_t *
+ds_group_bygid(si_mod_t *si, gid_t gid)
+{
+ xpc_object_t payload;
+ si_item_t *item;
- is_innetgr = check_innetgr(reply);
+ if (!_od_running()) return NULL;
+
+ payload = _xpc_query_key_id("gid", gid);
+ if (payload == NULL) return NULL;
- kvarray_free(reply);
+ item = _ds_item(si, CATEGORY_GROUP, "getgrgid", NULL, _extract_group, payload);
- return is_innetgr;
+ xpc_release(payload);
+ return item;
}
static si_item_t *
-ds_alias_byname(si_mod_t *si, const char *name)
+ds_group_byuuid(si_mod_t *si, uuid_t uuid)
{
- static int proc = -1;
- kvbuf_t *request;
+ xpc_object_t payload;
si_item_t *item;
- request = kvbuf_query_key_val("name", name);
- if (request == NULL) return NULL;
+ if (!_od_running()) return NULL;
+
+ payload = _xpc_query_key_uuid("uuid", uuid);
+ if (payload == NULL) return NULL;
- item = ds_item(si, CATEGORY_ALIAS, "alias_getbyname", &proc, NULL, extract_alias, request);
+ item = _ds_item(si, CATEGORY_GROUP, "getgruuid", NULL, _extract_group, payload);
- kvbuf_free(request);
+ xpc_release(payload);
return item;
}
static si_list_t *
-ds_alias_all(si_mod_t *si)
+ds_group_all(si_mod_t *si)
{
- static int proc = -1;
-
- return ds_list(si, CATEGORY_ALIAS, "alias_getent", &proc, NULL, extract_alias, NULL);
+ if (!_od_running()) return NULL;
+ return _ds_list(si, CATEGORY_GROUP, "getgrent", NULL, _extract_group);
}
static si_item_t *
-ds_host_byname(si_mod_t *si, const char *name, int af, const char *ignored, uint32_t *err)
+ds_grouplist(si_mod_t *si, const char *name, uint32_t ngroups)
{
- static int proc = -1;
- kvbuf_t *request;
- si_item_t *item;
- uint32_t want4, want6;
- int cat;
+ xpc_object_t payload, reply;
+ si_item_t *item = NULL;
- if (err != NULL) *err = SI_STATUS_NO_ERROR;
+ if (!_od_running()) return NULL;
+ if (name == NULL) return NULL;
- if (name == NULL)
- {
- *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
- return NULL;
+ payload = xpc_dictionary_create(NULL, NULL, 0);
+ if (payload == NULL) return NULL;
+
+ xpc_dictionary_set_string(payload, "name", name);
+ xpc_dictionary_set_int64(payload, "ngroups", ngroups);
+
+ reply = _od_rpc_call("getgrouplist", payload, _od_xpc_pipe);
+ if (reply != NULL) {
+ size_t gidptrsz;
+ const gid_t *gidptr = xpc_dictionary_get_data(reply, "groups", &gidptrsz);
+ int32_t count;
+ uint64_t va, vb;
+
+ _ds_get_validation(si, &va, &vb, CATEGORY_GROUPLIST);
+
+ /* see what we were sent */
+ count = _extract_uint32(reply, "count");
+ if (count != 0) {
+ item = (si_item_t *)LI_ils_create("L4488s4@", (unsigned long)si, CATEGORY_GROUPLIST, 1, va, vb, name, count,
+ gidptrsz, gidptr);
+ }
+
+ xpc_release(reply);
}
+
+ xpc_release(payload);
+
+ return item;
+}
- want4 = 0;
- want6 = 0;
+static si_list_t *
+ds_netgroup_byname(si_mod_t *si, const char *name)
+{
+ xpc_object_t payload;
+ si_list_t *list = NULL;
+ si_item_t *item;
- cat = CATEGORY_HOST_IPV4;
+ if (!_od_running()) return NULL;
- if (af == AF_INET)
- {
- want4 = 1;
- }
- else if (af == AF_INET6)
- {
- want6 = 1;
- cat = CATEGORY_HOST_IPV6;
- }
- else
- {
- *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
- return NULL;
- }
+ payload = _xpc_query_key_string("netgroup", name);
+ if (payload == NULL) return NULL;
- request = kvbuf_query("kskuku", "name", name, "ipv4", want4, "ipv6", want6);
- if (request == NULL)
- {
- *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
- return NULL;
+ item = _ds_item(si, CATEGORY_NETGROUP, "getnetgrent", NULL, _extract_netgroup, payload);
+ if (item != NULL) {
+ list = si_list_add(list, item);
+ si_item_release(item);
}
- item = ds_item(si, cat, "gethostbyname", &proc, NULL, extract_host, request);
+ xpc_release(payload);
- if ((item == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
-
- kvbuf_free(request);
- return item;
+ return list;
}
-static si_item_t *
-ds_host_byaddr(si_mod_t *si, const void *addr, int af, const char *ignored, uint32_t *err)
+static int
+ds_in_netgroup(si_mod_t *si, const char *group, const char *host, const char *user, const char *domain)
{
- static int proc = -1;
- kvbuf_t *request;
- si_item_t *item;
- struct in_addr addr4;
- struct in6_addr addr6;
- char val[64 + 1 + IF_NAMESIZE];
- int cat;
- uint32_t want;
-
- if (err != NULL) *err = SI_STATUS_NO_ERROR;
-
- cat = CATEGORY_HOST_IPV4;
+ xpc_object_t payload, reply;
+ int is_innetgr;
- memset(&addr4, 0, sizeof(struct in_addr));
- memset(&addr6, 0, sizeof(struct in6_addr));
- memset(val, 0, sizeof(val));
+ if (!_od_running()) return 0;
+
+ payload = xpc_dictionary_create(NULL, NULL, 0);
+ if (payload == NULL) return 0;
+
+ xpc_dictionary_set_string(payload, "netgroup", (group ? group : ""));
+ xpc_dictionary_set_string(payload, "host", (host ? host : ""));
+ xpc_dictionary_set_string(payload, "user", (user ? user : ""));
+ xpc_dictionary_set_string(payload, "domain", (domain ? domain : ""));
+
+ reply = _od_rpc_call("innetgr", payload, _od_xpc_pipe);
+ if (reply != NULL) {
+ is_innetgr = xpc_dictionary_get_bool(reply, OD_RPC_RESULT);
+ xpc_release(reply);
+ } else {
+ is_innetgr = 0;
+ }
- want = WANT_A4_ONLY;
+ xpc_release(payload);
- if (af == AF_INET)
- {
- memcpy(&addr4.s_addr, addr, IPV4_ADDR_LEN);
- if (inet_ntop(af, &addr4, val, sizeof(val)) == NULL)
- {
- *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
- return NULL;
- }
- }
- else if (af == AF_INET6)
- {
- want = WANT_A6_ONLY;
- cat = CATEGORY_HOST_IPV6;
- memcpy(&addr6, addr, IPV6_ADDR_LEN);
- if (inet_ntop(af, &addr6, val, sizeof(val)) == NULL)
- {
- *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
- return NULL;
- }
- }
- else
- {
- *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
- return NULL;
- }
+ return is_innetgr;
+}
- request = kvbuf_query("ksku", "address", val, "family", af);
- if (request == NULL)
- {
- *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
- return NULL;
- }
+static si_item_t *
+ds_alias_byname(si_mod_t *si, const char *name)
+{
+ xpc_object_t payload;
+ si_item_t *item;
- item = ds_item(si, cat, "gethostbyaddr", &proc, &want, extract_host, request);
+ if (!_od_running()) return NULL;
+
+ payload = _xpc_query_key_string("name", name);
+ if (payload == NULL) return NULL;
- if ((item == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
+ item = _ds_item(si, CATEGORY_ALIAS, "alias_getbyname", NULL, _extract_alias, payload);
- kvbuf_free(request);
+ xpc_release(payload);
return item;
}
static si_list_t *
-ds_host_all(si_mod_t *si)
+ds_alias_all(si_mod_t *si)
{
- static int proc = -1;
-
- return ds_list(si, CATEGORY_HOST_IPV4, "gethostent", &proc, NULL, extract_host, NULL);
+ if (!_od_running()) return NULL;
+ return _ds_list(si, CATEGORY_ALIAS, "alias_getent", NULL, _extract_alias);
}
static si_item_t *
ds_network_byname(si_mod_t *si, const char *name)
{
- static int proc = -1;
- kvbuf_t *request;
+ xpc_object_t payload;
si_item_t *item;
- request = kvbuf_query_key_val("name", name);
- if (request == NULL) return NULL;
+ if (!_od_running()) return NULL;
+
+ payload = _xpc_query_key_string("name", name);
+ if (payload == NULL) return NULL;
- item = ds_item(si, CATEGORY_NETWORK, "getnetbyname", &proc, NULL, extract_network, request);
+ item = _ds_item(si, CATEGORY_NETWORK, "getnetbyname", NULL, _extract_network, payload);
- kvbuf_free(request);
+ xpc_release(payload);
return item;
}
static si_item_t *
ds_network_byaddr(si_mod_t *si, uint32_t addr)
{
- static int proc = -1;
unsigned char f1, f2, f3;
char val[64];
- kvbuf_t *request;
+ xpc_object_t payload;
si_item_t *item;
+ if (!_od_running()) return NULL;
+
f1 = addr & 0xff;
addr >>= 8;
f2 = addr & 0xff;
else if (f2 != 0) snprintf(val, sizeof(val), "%u.%u", f2, f1);
else snprintf(val, sizeof(val), "%u", f1);
- request = kvbuf_query_key_val("net", val);
- if (request == NULL) return NULL;
+ payload = _xpc_query_key_string("net", val);
+ if (payload == NULL) return NULL;
- item = ds_item(si, CATEGORY_NETWORK, "getnetbyaddr", &proc, NULL, extract_network, request);
+ item = _ds_item(si, CATEGORY_NETWORK, "getnetbyaddr", NULL, _extract_network, payload);
- kvbuf_free(request);
+ xpc_release(payload);
return item;
}
static si_list_t *
ds_network_all(si_mod_t *si)
{
- static int proc = -1;
-
- return ds_list(si, CATEGORY_NETWORK, "getnetent", &proc, NULL, extract_network, NULL);
+ if (!_od_running()) return NULL;
+ return _ds_list(si, CATEGORY_NETWORK, "getnetent", NULL, _extract_network);
}
static si_item_t *
ds_service_byname(si_mod_t *si, const char *name, const char *proto)
{
- static int proc = -1;
- kvbuf_t *request;
+ xpc_object_t payload;
si_item_t *item;
struct servent *s;
+ if (!_od_running()) return NULL;
if (name == NULL) name = "";
if (proto == NULL) proto = "";
if (string_equal(name, s->s_name)) return si_item_retain(item);
}
- request = kvbuf_query("ksks", "name", name, "proto", proto);
- if (request == NULL) return NULL;
-
- item = ds_item(si, CATEGORY_SERVICE, "getservbyname", &proc, NULL, extract_service, request);
+ payload = xpc_dictionary_create(NULL, NULL, 0);
+ if (payload == NULL) return NULL;
+
+ xpc_dictionary_set_string(payload, "name", name);
+ xpc_dictionary_set_string(payload, "proto", proto);
+
+ item = _ds_item(si, CATEGORY_SERVICE, "getservbyname", NULL, _extract_service, payload);
- kvbuf_free(request);
+ xpc_release(payload);
+
return item;
}
static si_item_t *
ds_service_byport(si_mod_t *si, int port, const char *proto)
{
- static int proc = -1;
- uint16_t sport;
- char val[16];
- kvbuf_t *request;
+ xpc_object_t payload;
si_item_t *item;
- if (proto == NULL) proto = "";
-
- sport = port;
- snprintf(val, sizeof(val), "%d", ntohs(sport));
+ if (!_od_running()) return NULL;
- request = kvbuf_query("ksks", "port", val, "proto", proto);
- if (request == NULL) return NULL;
+ payload = xpc_dictionary_create(NULL, NULL, 0);
+ if (payload == NULL) return NULL;
+
+ /* swap to native order, API passes network order */
+ xpc_dictionary_set_int64(payload, "port", ntohs(port));
+ xpc_dictionary_set_string(payload, "proto", (proto ? proto : ""));
- item = ds_item(si, CATEGORY_SERVICE, "getservbyport", &proc, NULL, extract_service, request);
+ item = _ds_item(si, CATEGORY_SERVICE, "getservbyport", NULL, _extract_service, payload);
- kvbuf_free(request);
+ xpc_release(payload);
+
return item;
}
static si_list_t *
ds_service_all(si_mod_t *si)
{
- static int proc = -1;
-
- return ds_list(si, CATEGORY_SERVICE, "getservent", &proc, NULL, extract_service, NULL);
+ if (!_od_running()) return NULL;
+ return _ds_list(si, CATEGORY_SERVICE, "getservent", NULL, _extract_service);
}
static si_item_t *
ds_protocol_byname(si_mod_t *si, const char *name)
{
- static int proc = -1;
- kvbuf_t *request;
+ xpc_object_t payload;
si_item_t *item;
- request = kvbuf_query_key_val("name", name);
- if (request == NULL) return NULL;
+ if (!_od_running()) return NULL;
- item = ds_item(si, CATEGORY_PROTOCOL, "getprotobyname", &proc, NULL, extract_protocol, request);
+ payload = _xpc_query_key_string("name", name);
+ if (payload == NULL) return NULL;
- kvbuf_free(request);
+ item = _ds_item(si, CATEGORY_PROTOCOL, "getprotobyname", NULL, _extract_protocol, payload);
+
+ xpc_release(payload);
return item;
}
static si_item_t *
ds_protocol_bynumber(si_mod_t *si, int number)
{
- static int proc = -1;
- char val[16];
- kvbuf_t *request;
+ xpc_object_t payload;
si_item_t *item;
- snprintf(val, sizeof(val), "%d", number);
- request = kvbuf_query_key_val("number", val);
- if (request == NULL) return NULL;
+ if (!_od_running()) return NULL;
+
+ payload = _xpc_query_key_int("number", number);
+ if (payload == NULL) return NULL;
- item = ds_item(si, CATEGORY_PROTOCOL, "getprotobynumber", &proc, NULL, extract_protocol, request);
+ item = _ds_item(si, CATEGORY_PROTOCOL, "getprotobynumber", NULL, _extract_protocol, payload);
- kvbuf_free(request);
+ xpc_release(payload);
return item;
}
static si_list_t *
ds_protocol_all(si_mod_t *si)
{
- static int proc = -1;
-
- return ds_list(si, CATEGORY_PROTOCOL, "getprotoent", &proc, NULL, extract_protocol, NULL);
+ return _ds_list(si, CATEGORY_PROTOCOL, "getprotoent", NULL, _extract_protocol);
}
static si_item_t *
ds_rpc_byname(si_mod_t *si, const char *name)
{
- static int proc = -1;
- kvbuf_t *request;
+ xpc_object_t payload;
si_item_t *item;
- request = kvbuf_query_key_val("name", name);
- if (request == NULL) return NULL;
+ if (!_od_running()) return NULL;
+
+ payload = _xpc_query_key_string("name", name);
+ if (payload == NULL) return NULL;
- item = ds_item(si, CATEGORY_RPC, "getrpcbyname", &proc, NULL, extract_rpc, request);
+ item = _ds_item(si, CATEGORY_RPC, "getrpcbyname", NULL, _extract_rpc, payload);
- kvbuf_free(request);
+ xpc_release(payload);
return item;
}
static si_item_t *
ds_rpc_bynumber(si_mod_t *si, int number)
{
- static int proc = -1;
- char val[16];
- kvbuf_t *request;
+ xpc_object_t payload;
si_item_t *item;
- snprintf(val, sizeof(val), "%u", (uint32_t)number);
- request = kvbuf_query_key_val("number", val);
- if (request == NULL) return NULL;
+ if (!_od_running()) return NULL;
- item = ds_item(si, CATEGORY_RPC, "getrpcbynumber", &proc, NULL, extract_rpc, request);
+ payload = _xpc_query_key_int("number", number);
+ if (payload == NULL) return NULL;
- kvbuf_free(request);
+ item = _ds_item(si, CATEGORY_RPC, "getrpcbynumber", NULL, _extract_rpc, payload);
+
+ xpc_release(payload);
return item;
}
static si_list_t *
ds_rpc_all(si_mod_t *si)
{
- static int proc = -1;
-
- return ds_list(si, CATEGORY_RPC, "getrpcent", &proc, NULL, extract_rpc, NULL);
+ return _ds_list(si, CATEGORY_RPC, "getrpcent", NULL, _extract_rpc);
}
static si_item_t *
ds_fs_byspec(si_mod_t *si, const char *name)
{
- static int proc = -1;
- kvbuf_t *request;
+ xpc_object_t payload;
si_item_t *item;
- request = kvbuf_query_key_val("name", name);
- if (request == NULL) return NULL;
+ if (!_od_running()) return NULL;
+
+ payload = _xpc_query_key_string("name", name);
+ if (payload == NULL) return NULL;
- item = ds_item(si, CATEGORY_FS, "getfsbyname", &proc, NULL, extract_fstab, request);
+ item = _ds_item(si, CATEGORY_FS, "getfsbyname", NULL, _extract_fstab, payload);
- kvbuf_free(request);
+ xpc_release(payload);
return item;
}
static si_list_t *
ds_fs_all(si_mod_t *si)
{
- static int proc = -1;
-
- return ds_list(si, CATEGORY_FS, "getfsent", &proc, NULL, extract_fstab, NULL);
+ return _ds_list(si, CATEGORY_FS, "getfsent", NULL, _extract_fstab);
}
static si_item_t *
uint32_t i;
struct fstab *f;
+ if (!_od_running()) return NULL;
if (name == NULL) return NULL;
list = ds_fs_all(si);
static si_item_t *
ds_mac_byname(si_mod_t *si, const char *name)
{
- static int proc = -1;
- kvbuf_t *request;
+ xpc_object_t payload;
si_item_t *item;
- request = kvbuf_query_key_val("name", name);
- if (request == NULL) return NULL;
+ if (!_od_running()) return NULL;
+
+ payload = _xpc_query_key_string("name", name);
+ if (payload == NULL) return NULL;
- item = ds_item(si, CATEGORY_MAC, "getmacbyname", &proc, (void *)name, extract_mac_mac, request);
+ item = _ds_item(si, CATEGORY_MAC, "getmacbyname", name, _extract_mac_mac, payload);
- kvbuf_free(request);
+ xpc_release(payload);
return item;
}
static si_item_t *
ds_mac_bymac(si_mod_t *si, const char *mac)
{
- static int proc = -1;
- kvbuf_t *request;
+ xpc_object_t payload;
si_item_t *item;
char *cmac;
+
+ if (!_od_running()) return NULL;
cmac = si_standardize_mac_address(mac);
if (cmac == NULL) return NULL;
- request = kvbuf_query_key_val("mac", cmac);
- if (request == NULL) return NULL;
-
- item = ds_item(si, CATEGORY_MAC, "gethostbymac", &proc, cmac, extract_mac_name, request);
+ payload = xpc_dictionary_create(NULL, NULL, 0);
+ if (payload == NULL) return NULL;
+
+ payload = _xpc_query_key_string("mac", cmac);
+ item = _ds_item(si, CATEGORY_MAC, "gethostbymac", cmac, _extract_mac_name, payload);
free(cmac);
- kvbuf_free(request);
+ xpc_release(payload);
+
return item;
}
-static si_list_t *
-ds_addrinfo(si_mod_t *si, const void *node, const void *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *ignored, uint32_t *err)
-{
- static int proc = -1;
- si_list_t *list, *out;
- si_item_t *item;
- kvbuf_t *request = NULL;
- kvdict_t *dict;
- kvarray_t *reply = NULL;
- kern_return_t status = 0;
- uint16_t scope = 0;
- int i, k, kcount, d;
- uint32_t port;
-
- struct hostent *h;
- char *h_name = NULL;
- int h_aliases_cnt = 0;
- const char **h_aliases = NULL;
- struct in_addr *a4 = NULL;
- struct in6_addr *a6 = NULL;
- int a4_cnt = 0;
- int a6_cnt = 0;
- struct servent *s;
- const char *s_name = NULL;
- int s_aliases_cnt = 0;
- const char **s_aliases = NULL;
- uint16_t s_port = 0;
- const char *s_proto = NULL;
- const char *protoname;
- int wantv4, wantv6;
-
- int numericserv = ((flags & AI_NUMERICSERV) != 0);
- int numerichost = ((flags & AI_NUMERICHOST) != 0);
-
- wantv4 = 0;
- wantv6 = 0;
-
- if (node != NULL)
- {
- wantv4 = ((family != AF_INET6) || (flags & AI_V4MAPPED));
- wantv6 = (family != AF_INET);
- }
-
- if (err != NULL) *err = SI_STATUS_NO_ERROR;
-
- if (proc < 0)
- {
- status = LI_DSLookupGetProcedureNumber("gethostbyname_service", &proc);
- if (status != KERN_SUCCESS)
- {
- if (err != NULL) *err = SI_STATUS_EAI_SYSTEM;
- return NULL;
- }
- }
-
- /* look up canonical name of numeric host */
- if ((numerichost == 1) && (flags & AI_CANONNAME) && (node != NULL))
- {
- item = si_host_byaddr(si, node, family, NULL, NULL);
- if (item != NULL)
- {
- h = (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
- h_name = strdup(h->h_name);
- si_item_release(item);
- }
- }
-
- if (numericserv == 1)
- {
- s_port = *(int16_t *)serv;
- }
-
- if ((numericserv == 0) || (numerichost == 0))
- {
- request = kvbuf_new();
- if (request != NULL)
- {
- kvbuf_add_dict(request);
-
- if (numerichost == 0)
- {
- kvbuf_add_key(request, "name");
- kvbuf_add_val(request, node);
- kvbuf_add_key(request, "ipv4");
- kvbuf_add_val(request, wantv4 ? "1" : "0");
- kvbuf_add_key(request, "ipv6");
- kvbuf_add_val(request, wantv6 ? "1" : "0");
- }
-
- if (numericserv == 0)
- {
- protoname = NULL;
- if (proto == IPPROTO_UDP) protoname = "udp";
- if (proto == IPPROTO_TCP) protoname = "tcp";
-
- kvbuf_add_key(request, "s_name");
- kvbuf_add_val(request, serv);
- if (protoname != NULL)
- {
- kvbuf_add_key(request, "s_proto");
- kvbuf_add_val(request, protoname);
- }
- }
-
- status = LI_DSLookupQuery(proc, request, &reply);
- kvbuf_free(request);
- }
- else
- {
- if (err != NULL) *err = SI_STATUS_EAI_SYSTEM;
- }
- }
-
- if ((status != KERN_SUCCESS) || (reply == NULL))
- {
- free(h_name);
- return NULL;
- }
-
- for (d = 0; d < reply->count; d++)
- {
- dict = reply->dict + d;
- kcount = dict->kcount;
-
- for (k = 0; k < kcount; k++)
- {
- if (string_equal(dict->key[k], "h_name"))
- {
- if (dict->vcount[k] == 0) continue;
- h_name = strdup(dict->val[k][0]);
- }
- else if (string_equal(dict->key[k], "h_aliases"))
- {
- h_aliases_cnt = dict->vcount[k];
- h_aliases = (const char **)calloc(h_aliases_cnt, sizeof(char *));
- if (h_aliases == NULL) h_aliases_cnt = 0;
-
- for (i = 0; i < h_aliases_cnt; ++i)
- {
- h_aliases[i] = dict->val[k][i];
- }
- }
- else if (wantv4 && (string_equal(dict->key[k], "h_ipv4_addr_list")))
- {
- a4_cnt = dict->vcount[k];
- a4 = calloc(a4_cnt, sizeof(struct in_addr));
- if (a4 == NULL) a4_cnt = 0;
-
- for (i = 0; i < a4_cnt; ++i)
- {
- memset(&a4[i], 0, sizeof(struct in_addr));
- inet_pton(AF_INET, dict->val[k][i], &a4[i]);
- }
- }
- else if (wantv6 && (string_equal(dict->key[k], "h_ipv6_addr_list")))
- {
- a6_cnt = dict->vcount[k];
- a6 = calloc(a6_cnt, sizeof(struct in6_addr));
- if (a6 == NULL) a6_cnt = 0;
-
- for (i = 0; i < a6_cnt; ++i)
- {
- memset(&a6[i], 0, sizeof(struct in6_addr));
- inet_pton(AF_INET6, dict->val[k][i], &a6[i]);
- }
- }
- else if (string_equal(dict->key[k], "s_name"))
- {
- if (dict->vcount[k] == 0) continue;
- s_name = dict->val[k][0];
- }
- else if (string_equal(dict->key[k], "s_port"))
- {
- if (dict->vcount[k] == 0) continue;
- s_port = atoi(dict->val[k][0]);
- }
- else if (string_equal(dict->key[k], "s_aliases"))
- {
- s_aliases_cnt = dict->vcount[k];
- s_aliases = (const char **)calloc(s_aliases_cnt+1, sizeof(char *));
- if (s_aliases == NULL) s_aliases_cnt = 0;
-
- for (i = 0; i < s_aliases_cnt; ++i)
- {
- s_aliases[i] = dict->val[k][i];
- }
- }
- else if (string_equal(dict->key[k], "s_proto"))
- {
- if (dict->vcount[k] == 0) continue;
- s_proto = dict->val[k][0];
- }
- }
- }
-
- kvarray_free(reply);
-
- /* check if we actually got back what we wanted */
- if (((wantv4 || wantv6) && (a4_cnt == 0) && (a6_cnt == 0)) || ((serv != NULL) && (s_port == 0)))
- {
- if (err != NULL) *err = SI_STATUS_EAI_NONAME;
-
- free(h_name);
- free(h_aliases);
- free(s_aliases);
- free(a4);
- free(a6);
-
- return NULL;
- }
-
- /*
- * Cache the service entry regardless of whether there is a host match.
- * This allows later modules to get the service entry quickly.
- * This should really be part of the general cache mechanism, but that's
- * not currently visible outside of the search module.
- */
- if ((s_name != NULL) && (s_port != 0))
- {
- port = htons(s_port);
-
- item = pthread_getspecific(_ds_serv_cache_key);
- if (item != NULL)
- {
- s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
- if ((port != s->s_port) || string_not_equal(s_name, s->s_name))
- {
- si_item_release(item);
- item = NULL;
- }
- }
-
- if (item == NULL)
- {
- item = LI_ils_create("L4488s*4s", (unsigned long)si, CATEGORY_SERVICE, 1, (uint64_t)1, (uint64_t)1, s_name, s_aliases, port, s_proto);
- pthread_setspecific(_ds_serv_cache_key, item);
- }
- }
-
- /* Construct the addrinfo list from the returned addresses (if found). */
- out = NULL;
- for (i = 0; i < a6_cnt; i++)
- {
- list = si_addrinfo_list(si, flags, socktype, proto, NULL, &a6[i], s_port, scope, NULL, h_name);
- out = si_list_concat(out, list);
- si_list_release(list);
- }
-
- for (i = 0; i < a4_cnt; i++)
- {
- list = si_addrinfo_list(si, flags, socktype, proto, &a4[i], NULL, s_port, 0, h_name, NULL);
- out = si_list_concat(out, list);
- si_list_release(list);
- }
-
- free(h_name);
- free(h_aliases);
- free(s_aliases);
- free(a4);
- free(a6);
-
- return out;
-}
-
-static int
-ds_is_valid(si_mod_t *si, si_item_t *item)
-{
- si_mod_t *src;
- ds_si_private_t *pp;
- int status;
- uint32_t oldval, newval;
-
- if (si == NULL) return 0;
- if (item == NULL) return 0;
- if (si->name == NULL) return 0;
- if (item->src == NULL) return 0;
-
- pp = (ds_si_private_t *)si->private;
- if (pp == NULL) return 0;
-
- src = (si_mod_t *)item->src;
-
- if (src->name == NULL) return 0;
- if (string_not_equal(si->name, src->name)) return 0;
-
- /* check global invalidation */
- oldval = item->validation_a;
- newval = -1;
- status = notify_peek(pp->notify_token_global, &newval);
- if (status != NOTIFY_STATUS_OK) return 0;
-
- newval = ntohl(newval);
- if (oldval != newval) return 0;
-
- oldval = item->validation_b;
- newval = -1;
- if (item->type == CATEGORY_USER) status = notify_peek(pp->notify_token_user, &newval);
- else if (item->type == CATEGORY_GROUP) status = notify_peek(pp->notify_token_group, &newval);
- else if (item->type == CATEGORY_HOST_IPV4) status = notify_peek(pp->notify_token_host, &newval);
- else if (item->type == CATEGORY_HOST_IPV6) status = notify_peek(pp->notify_token_host, &newval);
- else if (item->type == CATEGORY_SERVICE) status = notify_peek(pp->notify_token_service, &newval);
- else return 0;
-
- if (status != NOTIFY_STATUS_OK) return 0;
-
- newval = ntohl(newval);
- if (oldval != newval) return 0;
-
- return 1;
-}
+#pragma mark -
si_mod_t *
si_module_static_ds(void)
{
static const struct si_mod_vtable_s ds_vtable =
{
- .sim_is_valid = &ds_is_valid,
+ .sim_is_valid = &_ds_is_valid,
.sim_user_byname = &ds_user_byname,
.sim_user_byuid = &ds_user_byuid,
+ .sim_user_byuuid = &ds_user_byuuid,
.sim_user_all = &ds_user_all,
.sim_group_byname = &ds_group_byname,
.sim_group_bygid = &ds_group_bygid,
+ .sim_group_byuuid = &ds_group_byuuid,
.sim_group_all = &ds_group_all,
.sim_grouplist = &ds_grouplist,
.sim_alias_byname = &ds_alias_byname,
.sim_alias_all = &ds_alias_all,
- .sim_host_byname = &ds_host_byname,
- .sim_host_byaddr = &ds_host_byaddr,
- .sim_host_all = &ds_host_all,
+ /* host lookups not supported */
+ .sim_host_byname = NULL,
+ .sim_host_byaddr = NULL,
+ .sim_host_all = NULL,
.sim_network_byname = &ds_network_byname,
.sim_network_byaddr = &ds_network_byaddr,
pp->notify_token_global = -1;
pp->notify_token_user = -1;
pp->notify_token_group = -1;
- pp->notify_token_host = -1;
pp->notify_token_service = -1;
}
notify_register_check(kNotifyDSCacheInvalidation, &(pp->notify_token_global));
notify_register_check(kNotifyDSCacheInvalidationUser, &(pp->notify_token_user));
notify_register_check(kNotifyDSCacheInvalidationGroup, &(pp->notify_token_group));
- notify_register_check(kNotifyDSCacheInvalidationHost, &(pp->notify_token_host));
notify_register_check(kNotifyDSCacheInvalidationService, &(pp->notify_token_service));
}
#include <servers/bootstrap.h>
#include <libkern/OSByteOrder.h>
#ifdef DS_AVAILABLE
-#include "DSmemberdMIG.h"
-#endif
+#include <xpc/xpc.h>
+#include <xpc/private.h>
+#include <opendirectory/odipc.h>
+#include <pthread.h>
-#ifdef DS_AVAILABLE
-extern mach_port_t _mbr_port;
-extern int _ds_running(void);
+#ifdef __i386__
+/* <rdar://problem/10675978> */
+__attribute__((weak_import))
+xpc_pipe_t xpc_pipe_create(const char *name, uint64_t flags);
+
+__attribute__((weak_import))
+void xpc_pipe_invalidate(xpc_pipe_t pipe);
+
+__attribute__((weak_import))
+int xpc_pipe_routine(xpc_pipe_t pipe, xpc_object_t message, xpc_object_t *reply);
+#endif /* __i386__ */
+#endif /* DS_AVAILABLE */
static const uuid_t _user_compat_prefix = {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd, 0xcc, 0xcc, 0xbb, 0xbb, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00};
static const uuid_t _group_compat_prefix = {0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0x00, 0x00, 0x00, 0x00};
#define COMPAT_PREFIX_LEN (sizeof(uuid_t) - sizeof(id_t))
-#define MAX_LOOKUP_ATTEMPTS 10
+#ifdef DS_AVAILABLE
+
+int _si_opendirectory_disabled;
+static xpc_pipe_t __mbr_pipe; /* use accessor */
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+__private_extern__ xpc_object_t _od_rpc_call(const char *procname, xpc_object_t payload, xpc_pipe_t (*get_pipe)(bool));
+
#endif
-uid_t
-audit_token_uid(audit_token_t a)
+#ifdef DS_AVAILABLE
+static void
+_mbr_fork_child(void)
{
- /*
- * This should really call audit_token_to_au32,
- * but that's in libbsm, not in a Libsystem library.
- */
- return (uid_t)a.val[1];
+ if (__mbr_pipe != NULL) {
+ xpc_pipe_invalidate(__mbr_pipe);
+ /* disable release due to 10649340, it will cause a minor leak for each fork without exec */
+ // xpc_release(__mbr_pipe);
+ __mbr_pipe = NULL;
+ }
+
+ pthread_mutex_unlock(&mutex);
}
+#endif
#ifdef DS_AVAILABLE
-static int
-_mbr_MembershipCall(struct kauth_identity_extlookup *req)
+static void
+_mbr_fork_prepare(void)
{
- audit_token_t token;
- kern_return_t status;
- uint32_t i;
-
- /* call _ds_running() to look up _mbr_port */
- _ds_running();
- if (_mbr_port == MACH_PORT_NULL) return EIO;
-
- memset(&token, 0, sizeof(audit_token_t));
-
- status = MIG_SERVER_DIED;
- for (i = 0; (_mbr_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (i < MAX_LOOKUP_ATTEMPTS); i++)
- {
- status = memberdDSmig_MembershipCall(_mbr_port, req, &token);
- if (status == MACH_SEND_INVALID_DEST)
- {
- mach_port_mod_refs(mach_task_self(), _mbr_port, MACH_PORT_RIGHT_SEND, -1);
- _mbr_port = MACH_PORT_NULL;
- _ds_running();
- status = MIG_SERVER_DIED;
- }
- }
-
- if (status != KERN_SUCCESS) return EIO;
- if (audit_token_uid(token) != 0) return EAUTH;
-
- return 0;
+ pthread_mutex_lock(&mutex);
}
#endif
#ifdef DS_AVAILABLE
-static int
-_mbr_MapName(char *name, int type, guid_t *uu)
+static void
+_mbr_fork_parent(void)
{
- kern_return_t status;
- audit_token_t token;
- uint32_t i;
-
- if (name == NULL) return EINVAL;
- if (strlen(name) > 255) return EINVAL;
-
- /* call _ds_running() to look up _mbr_port */
- _ds_running();
- if (_mbr_port == MACH_PORT_NULL) return EIO;
-
- memset(&token, 0, sizeof(audit_token_t));
-
- status = MIG_SERVER_DIED;
- for (i = 0; (_mbr_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (i < MAX_LOOKUP_ATTEMPTS); i++)
- {
- status = memberdDSmig_MapName(_mbr_port, type, name, uu, &token);
- if (status == KERN_FAILURE) return ENOENT;
-
- if (status == MACH_SEND_INVALID_DEST)
- {
- mach_port_mod_refs(mach_task_self(), _mbr_port, MACH_PORT_RIGHT_SEND, -1);
- _mbr_port = MACH_PORT_NULL;
- _ds_running();
- status = MIG_SERVER_DIED;
- }
- }
-
- if (status != KERN_SUCCESS) return EIO;
- if (audit_token_uid(token) != 0) return EAUTH;
-
- return 0;
+ pthread_mutex_unlock(&mutex);
}
#endif
#ifdef DS_AVAILABLE
-static int
-_mbr_ClearCache()
+XPC_RETURNS_RETAINED
+static xpc_pipe_t
+_mbr_xpc_pipe(bool resetPipe)
{
- kern_return_t status;
- uint32_t i;
+ static dispatch_once_t once;
+ xpc_pipe_t pipe = NULL;
- /* call _ds_running() to look up _mbr_port */
- _ds_running();
- if (_mbr_port == MACH_PORT_NULL) return EIO;
+#ifdef __i386__
+ if (xpc_pipe_create == NULL) {
+ _si_opendirectory_disabled = 1;
+ return NULL;
+ }
+#endif
- status = MIG_SERVER_DIED;
- for (i = 0; (_mbr_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (i < MAX_LOOKUP_ATTEMPTS); i++)
- {
- status = memberdDSmig_ClearCache(_mbr_port);
- if (status == MACH_SEND_INVALID_DEST)
- {
- mach_port_mod_refs(mach_task_self(), _mbr_port, MACH_PORT_RIGHT_SEND, -1);
- _mbr_port = MACH_PORT_NULL;
- _ds_running();
- status = MIG_SERVER_DIED;
+ dispatch_once(&once, ^(void) {
+ char *rc_xbs;
+
+ /* if this is a build environment we ignore opendirectoryd */
+ rc_xbs = getenv("RC_XBS");
+ if (rc_xbs != NULL && strcmp(rc_xbs, "YES") == 0) {
+ _si_opendirectory_disabled = 1;
+ return;
}
+
+ pthread_atfork(_mbr_fork_prepare, _mbr_fork_parent, _mbr_fork_child);
+ });
+
+ if (_si_opendirectory_disabled == 1) {
+ return NULL;
}
-
- if (status != KERN_SUCCESS) return EIO;
-
- return 0;
+
+ pthread_mutex_lock(&mutex);
+ if (resetPipe) {
+ xpc_release(__mbr_pipe);
+ __mbr_pipe = NULL;
+ }
+
+ if (__mbr_pipe == NULL) {
+ if (!issetugid() && getenv("OD_DEBUG_MODE") != NULL) {
+ __mbr_pipe = xpc_pipe_create(kODMachMembershipPortNameDebug, 0);
+ } else {
+ __mbr_pipe = xpc_pipe_create(kODMachMembershipPortName, XPC_PIPE_FLAG_PRIVILEGED);
+ }
+ }
+
+ if (__mbr_pipe != NULL) pipe = xpc_retain(__mbr_pipe);
+ pthread_mutex_unlock(&mutex);
+
+ return pipe;
}
#endif
-#ifdef DS_AVAILABLE
-static int
-_mbr_SetIdentifierTTL(int idType, const void *identifier, size_t identifier_size, unsigned int seconds)
+static bool
+_mbr_od_available(void)
{
- kern_return_t status;
- uint32_t i;
+#if DS_AVAILABLE
+ xpc_pipe_t pipe = _mbr_xpc_pipe(false);
+ if (pipe != NULL) {
+ xpc_release(pipe);
+ return true;
+ }
+#endif
+ return false;
+}
+
+int
+mbr_identifier_translate(int id_type, const void *identifier, size_t identifier_size, int target_type, void **result, int *rec_type)
+{
+#if DS_AVAILABLE
+ xpc_object_t payload, reply;
+#endif
+ id_t tempID;
+ size_t identifier_len;
+ int rc = EIO;
- /* call _ds_running() to look up _mbr_port */
- _ds_running();
- if (_mbr_port == MACH_PORT_NULL) return EIO;
+ if (identifier == NULL || result == NULL || identifier_size == 0) return EIO;
- status = MIG_SERVER_DIED;
- for (i = 0; (_mbr_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (i < MAX_LOOKUP_ATTEMPTS); i++)
- {
- status = memberdDSmig_SetIdentifierTTL(_mbr_port, idType, (identifier_data_t)identifier, identifier_size, seconds);
- if (status == MACH_SEND_INVALID_DEST)
- {
- mach_port_mod_refs(mach_task_self(), _mbr_port, MACH_PORT_RIGHT_SEND, -1);
- _mbr_port = MACH_PORT_NULL;
- _ds_running();
- status = MIG_SERVER_DIED;
+ if (identifier_size == -1) {
+ identifier_size = strlen(identifier);
+ } else {
+ /* 10898647: For types that are known to be strings, send the smallest necessary amount of data. */
+ switch (id_type) {
+ case ID_TYPE_USERNAME:
+ case ID_TYPE_GROUPNAME:
+ case ID_TYPE_GROUP_NFS:
+ case ID_TYPE_USER_NFS:
+ case ID_TYPE_X509_DN:
+ case ID_TYPE_KERBEROS:
+ case ID_TYPE_NAME:
+ identifier_len = strlen(identifier);
+ if (identifier_size > identifier_len) {
+ identifier_size = identifier_len;
+ }
+ break;
+ }
+ }
+
+ switch (target_type) {
+ case ID_TYPE_GID:
+ case ID_TYPE_UID:
+ case ID_TYPE_UID_OR_GID:
+ /* shortcut UUIDs using compatibilty prefixes */
+ if (id_type == ID_TYPE_UUID) {
+ const uint8_t *uu = identifier;
+
+ if (identifier_size != sizeof(uuid_t)) return EINVAL;
+
+ if (memcmp(uu, _user_compat_prefix, COMPAT_PREFIX_LEN) == 0) {
+ id_t *tempRes = malloc(sizeof(*tempRes));
+ memcpy(&tempID, &uu[COMPAT_PREFIX_LEN], sizeof(tempID));
+ (*tempRes) = ntohl(tempID);
+ (*result) = tempRes;
+ if (rec_type != NULL) {
+ (*rec_type) = MBR_REC_TYPE_USER;
+ }
+ return 0;
+ } else if (memcmp(uu, _group_compat_prefix, COMPAT_PREFIX_LEN) == 0) {
+ id_t *tempRes = malloc(sizeof(*tempRes));
+ memcpy(&tempID, &uu[COMPAT_PREFIX_LEN], sizeof(tempID));
+ (*tempRes) = ntohl(tempID);
+ (*result) = tempRes;
+ if (rec_type != NULL) {
+ (*rec_type) = MBR_REC_TYPE_GROUP;
+ }
+ return 0;
+ }
+ }
+ break;
+
+ case ID_TYPE_UUID:
+ /* if this is a UID or GID translation, we shortcut UID/GID 0 */
+ /* or if no OD, we return compatibility UUIDs */
+ switch (id_type) {
+ case ID_TYPE_UID:
+ if (identifier_size != sizeof(tempID)) return EINVAL;
+
+ tempID = *((id_t *) identifier);
+ if ((tempID == 0) || (_mbr_od_available() == false)) {
+ uint8_t *tempUU = malloc(sizeof(uuid_t));
+ uuid_copy(tempUU, _user_compat_prefix);
+ *((id_t *) &tempUU[COMPAT_PREFIX_LEN]) = htonl(tempID);
+ (*result) = tempUU;
+ if (rec_type != NULL) {
+ (*rec_type) = MBR_REC_TYPE_USER;
+ }
+ return 0;
+ }
+ break;
+
+ case ID_TYPE_GID:
+ if (identifier_size != sizeof(tempID)) return EINVAL;
+
+ tempID = *((id_t *) identifier);
+ if ((tempID == 0) || (_mbr_od_available() == false)) {
+ uint8_t *tempUU = malloc(sizeof(uuid_t));
+ uuid_copy(tempUU, _group_compat_prefix);
+ *((id_t *) &tempUU[COMPAT_PREFIX_LEN]) = htonl(tempID);
+ (*result) = tempUU;
+ if (rec_type != NULL) {
+ (*rec_type) = MBR_REC_TYPE_GROUP;
+ }
+ return 0;
+ }
+ break;
+ }
+ break;
+ }
+
+#if DS_AVAILABLE
+ payload = xpc_dictionary_create(NULL, NULL, 0);
+ if (payload == NULL) return EIO;
+
+ xpc_dictionary_set_int64(payload, "requesting", target_type);
+ xpc_dictionary_set_int64(payload, "type", id_type);
+ xpc_dictionary_set_data(payload, "identifier", identifier, identifier_size);
+
+ reply = _od_rpc_call("mbr_identifier_translate", payload, _mbr_xpc_pipe);
+ if (reply != NULL) {
+ const void *reply_id;
+ size_t idLen;
+
+ rc = (int) xpc_dictionary_get_int64(reply, "error");
+ if (rc == 0) {
+ reply_id = xpc_dictionary_get_data(reply, "identifier", &idLen);
+ if (reply_id != NULL) {
+ char *identifier = malloc(idLen);
+
+ memcpy(identifier, reply_id, idLen); // should already be NULL terminated, etc.
+ (*result) = identifier;
+
+ if (rec_type != NULL) {
+ (*rec_type) = (int) xpc_dictionary_get_int64(reply, "rectype");
+ }
+ } else {
+ (*result) = NULL;
+ rc = ENOENT;
+ }
}
+
+ xpc_release(reply);
}
- if (status != KERN_SUCCESS) return EIO;
+ xpc_release(payload);
+#endif
- return 0;
+ return rc;
}
-#endif
int
mbr_uid_to_uuid(uid_t id, uuid_t uu)
int
mbr_uuid_to_id(const uuid_t uu, uid_t *id, int *id_type)
{
-#ifdef DS_AVAILABLE
- struct kauth_identity_extlookup request;
- int status;
- id_t tempID;
-
- if (id == NULL) return EIO;
- if (id_type == NULL) return EIO;
-
- if (!memcmp(uu, _user_compat_prefix, COMPAT_PREFIX_LEN))
- {
- memcpy(&tempID, &uu[COMPAT_PREFIX_LEN], sizeof(tempID));
- *id = ntohl(tempID);
- *id_type = ID_TYPE_UID;
- return 0;
- }
- else if (!memcmp(uu, _group_compat_prefix, COMPAT_PREFIX_LEN))
- {
- memcpy(&tempID, &uu[COMPAT_PREFIX_LEN], sizeof(tempID));
- *id = ntohl(tempID);
- *id_type = ID_TYPE_GID;
- return 0;
- }
-
- request.el_seqno = 1;
- request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_UID | KAUTH_EXTLOOKUP_WANT_GID;
- memcpy(&request.el_uguid, uu, sizeof(guid_t));
- memcpy(&request.el_gguid, uu, sizeof(guid_t));
-
- status = _mbr_MembershipCall(&request);
- if (status != 0) return status;
-
- if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_UID) != 0)
- {
- *id = request.el_uid;
- *id_type = ID_TYPE_UID;
- }
- else if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_GID) != 0)
- {
- *id = request.el_gid;
- *id_type = ID_TYPE_GID;
- }
- else
- {
- return ENOENT;
+ id_t *result;
+ int local_type;
+ int rc;
+
+ rc = mbr_identifier_translate(ID_TYPE_UUID, uu, sizeof(uuid_t), ID_TYPE_UID_OR_GID, (void **) &result, &local_type);
+ if (rc == 0) {
+ switch (local_type) {
+ case MBR_REC_TYPE_GROUP:
+ (*id_type) = ID_TYPE_GID;
+ break;
+
+ case MBR_REC_TYPE_USER:
+ (*id_type) = ID_TYPE_UID;
+ break;
+
+ default:
+ (*id_type) = -1;
+ break;
+ }
+
+ (*id) = (*result);
+ free(result);
}
-
- return 0;
-#else
- return EIO;
-#endif
+
+ return rc;
}
int
mbr_sid_to_uuid(const nt_sid_t *sid, uuid_t uu)
{
#ifdef DS_AVAILABLE
- struct kauth_identity_extlookup request;
- int status;
-
- request.el_seqno = 1;
- request.el_flags = KAUTH_EXTLOOKUP_VALID_GSID | KAUTH_EXTLOOKUP_WANT_GGUID | KAUTH_EXTLOOKUP_VALID_USID | KAUTH_EXTLOOKUP_WANT_UGUID;
- memset(&request.el_gsid, 0, sizeof(ntsid_t));
- memcpy(&request.el_gsid, sid, KAUTH_NTSID_SIZE(sid));
- memset(&request.el_usid, 0, sizeof(ntsid_t));
- memcpy(&request.el_usid, sid, KAUTH_NTSID_SIZE(sid));
-
- status = _mbr_MembershipCall(&request);
- if (status != 0) return status;
-
- if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_GGUID) != 0) memcpy(uu, &request.el_gguid, sizeof(guid_t));
- else if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_UGUID) != 0) memcpy(uu, &request.el_uguid, sizeof(guid_t));
- else return ENOENT;
-
- return 0;
+ return mbr_identifier_to_uuid(ID_TYPE_SID, sid, sizeof(*sid), uu);
#else
return EIO;
#endif
int
mbr_identifier_to_uuid(int id_type, const void *identifier, size_t identifier_size, uuid_t uu)
{
-#ifdef DS_AVAILABLE
- kern_return_t status;
- audit_token_t token;
- vm_offset_t ool = 0;
- mach_msg_type_number_t oolCnt = 0;
- uint32_t i;
- id_t tempID;
-#if __BIG_ENDIAN__
- id_t newID;
-#endif
-
- if (identifier == NULL) return EINVAL;
- if (identifier_size == 0) return EINVAL;
- else if (identifier_size == -1) identifier_size = strlen((char*) identifier) + 1;
-
- /* call _ds_running() to look up _mbr_port */
- _ds_running();
-
- /* if this is a UID or GID translation, we shortcut UID/GID 0 */
- /* if no DS, we return compatibility UUIDs */
- switch (id_type)
- {
- case ID_TYPE_UID:
- {
- if (identifier_size != sizeof(tempID)) return EINVAL;
-
- tempID = *((id_t *) identifier);
- if ((tempID == 0) || (_mbr_port == MACH_PORT_NULL))
- {
- uuid_copy(uu, _user_compat_prefix);
- *((id_t *) &uu[COMPAT_PREFIX_LEN]) = htonl(tempID);
- return 0;
- }
- break;
- }
- case ID_TYPE_GID:
- {
- if (identifier_size != sizeof(tempID)) return EINVAL;
-
- tempID = *((id_t *) identifier);
- if ((tempID == 0) || (_mbr_port == MACH_PORT_NULL))
- {
- uuid_copy(uu, _group_compat_prefix);
- *((id_t *) &uu[COMPAT_PREFIX_LEN]) = htonl(tempID);
- return 0;
- }
- break;
- }
- }
-
- if (_mbr_port == MACH_PORT_NULL) return EIO;
-
- memset(&token, 0, sizeof(audit_token_t));
-
-#if __BIG_ENDIAN__
- switch (id_type)
- {
- case ID_TYPE_UID:
- case ID_TYPE_GID:
- if (identifier_size < sizeof(id_t)) return EINVAL;
- newID = OSSwapInt32(*((id_t *) identifier));
- identifier = &newID;
- break;
- }
-#endif
-
- if (identifier_size > MAX_MIG_INLINE_DATA)
- {
- if (vm_read(mach_task_self(), (vm_offset_t) identifier, identifier_size, &ool, &oolCnt) != 0) return ENOMEM;
- identifier = NULL;
- identifier_size = 0;
- }
-
- status = MIG_SERVER_DIED;
- for (i = 0; (_mbr_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (i < MAX_LOOKUP_ATTEMPTS); i++)
- {
- status = memberdDSmig_MapIdentifier(_mbr_port, id_type, (identifier_data_t) identifier, identifier_size, ool, oolCnt, (guid_t *)uu, &token);
- if (status == KERN_FAILURE) return ENOENT;
-
- if (status == MACH_SEND_INVALID_DEST)
- {
- if (ool != 0) vm_deallocate(mach_task_self(), ool, oolCnt);
-
- mach_port_mod_refs(mach_task_self(), _mbr_port, MACH_PORT_RIGHT_SEND, -1);
- _mbr_port = MACH_PORT_NULL;
- _ds_running();
- status = MIG_SERVER_DIED;
- }
+ uint8_t *result;
+ int rc;
+
+ rc = mbr_identifier_translate(id_type, identifier, identifier_size, ID_TYPE_UUID, (void **) &result, NULL);
+ if (rc == 0) {
+ uuid_copy(uu, result);
+ free(result);
}
-
- if (status != KERN_SUCCESS) return EIO;
- if (audit_token_uid(token) != 0) return EAUTH;
-
- return 0;
-#else
- return EIO;
-#endif
+
+ return rc;
}
int
mbr_uuid_to_sid_type(const uuid_t uu, nt_sid_t *sid, int *id_type)
{
#ifdef DS_AVAILABLE
- struct kauth_identity_extlookup request;
- int status;
-
- request.el_seqno = 1;
- request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_USID | KAUTH_EXTLOOKUP_WANT_GSID;
- memcpy(&request.el_uguid, uu, sizeof(guid_t));
- memcpy(&request.el_gguid, uu, sizeof(guid_t));
-
- status = _mbr_MembershipCall(&request);
- if (status != 0) return status;
-
- if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_USID) != 0)
- {
- *id_type = SID_TYPE_USER;
- memcpy(sid, &request.el_usid, sizeof(nt_sid_t));
- }
- else if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_GSID) != 0)
- {
- *id_type = SID_TYPE_GROUP;
- memcpy(sid, &request.el_gsid, sizeof(nt_sid_t));
- }
- else
- {
- return ENOENT;
+ void *result;
+ int local_type;
+ int rc;
+
+ rc = mbr_identifier_translate(ID_TYPE_UUID, uu, sizeof(uuid_t), ID_TYPE_SID, &result, &local_type);
+ if (rc == 0) {
+ memcpy(sid, result, sizeof(nt_sid_t));
+ if (id_type != NULL) {
+ /* remap ID types */
+ switch (local_type) {
+ case MBR_REC_TYPE_USER:
+ (*id_type) = SID_TYPE_USER;
+ break;
+
+ case MBR_REC_TYPE_GROUP:
+ (*id_type) = SID_TYPE_GROUP;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ free(result);
}
-
- return 0;
+
+ return rc;
#else
return EIO;
#endif
int
mbr_check_membership(const uuid_t user, const uuid_t group, int *ismember)
{
-#ifdef DS_AVAILABLE
- struct kauth_identity_extlookup request;
- int status;
-
- request.el_seqno = 1;
- request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP;
- memcpy(&request.el_uguid, user, sizeof(guid_t));
- memcpy(&request.el_gguid, group, sizeof(guid_t));
-
- status = _mbr_MembershipCall(&request);
- if (status != 0) return status;
- if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) == 0) return ENOENT;
-
- *ismember = ((request.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) != 0);
- return 0;
-#else
- return EIO;
-#endif
+ return mbr_check_membership_ext(ID_TYPE_UUID, user, sizeof(uuid_t), ID_TYPE_UUID, group, 0, ismember);
}
int
mbr_check_membership_refresh(const uuid_t user, uuid_t group, int *ismember)
{
-#ifdef DS_AVAILABLE
- struct kauth_identity_extlookup request;
- int status;
-
- request.el_seqno = 1;
- request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP | (1<<15);
- memcpy(&request.el_uguid, user, sizeof(guid_t));
- memcpy(&request.el_gguid, group, sizeof(guid_t));
+ return mbr_check_membership_ext(ID_TYPE_UUID, user, sizeof(uuid_t), ID_TYPE_UUID, group, 1, ismember);
+}
- status = _mbr_MembershipCall(&request);
- if (status != 0) return status;
- if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) == 0) return ENOENT;
+int
+mbr_check_membership_ext(int userid_type, const void *userid, size_t userid_size, int groupid_type, const void *groupid, int refresh, int *isMember)
+{
+#ifdef DS_AVAILABLE
+ xpc_object_t payload, reply;
+ int rc = 0;
+
+ payload = xpc_dictionary_create(NULL, NULL, 0);
+ if (payload == NULL) return ENOMEM;
- *ismember = ((request.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) != 0);
- return 0;
+ xpc_dictionary_set_int64(payload, "user_idtype", userid_type);
+ xpc_dictionary_set_data(payload, "user_id", userid, userid_size);
+ xpc_dictionary_set_int64(payload, "group_idtype", groupid_type);
+
+ switch (groupid_type) {
+ case ID_TYPE_GROUPNAME:
+ case ID_TYPE_GROUP_NFS:
+ xpc_dictionary_set_data(payload, "group_id", groupid, strlen(groupid));
+ break;
+
+ case ID_TYPE_GID:
+ xpc_dictionary_set_data(payload, "group_id", groupid, sizeof(id_t));
+ break;
+
+ case ID_TYPE_SID:
+ xpc_dictionary_set_data(payload, "group_id", groupid, sizeof(nt_sid_t));
+ break;
+
+ case ID_TYPE_UUID:
+ xpc_dictionary_set_data(payload, "group_id", groupid, sizeof(uuid_t));
+ break;
+
+ default:
+ rc = EINVAL;
+ break;
+ }
+
+ if (rc == 0) {
+ reply = _od_rpc_call("mbr_check_membership", payload, _mbr_xpc_pipe);
+ if (reply != NULL) {
+ rc = (int) xpc_dictionary_get_int64(reply, "error");
+ (*isMember) = xpc_dictionary_get_bool(reply, "ismember");
+ xpc_release(reply);
+ } else {
+ rc = EIO;
+ }
+ }
+
+ xpc_release(payload);
+
+ return rc;
#else
return EIO;
#endif
int
mbr_check_membership_by_id(uuid_t user, gid_t group, int *ismember)
{
-#ifdef DS_AVAILABLE
- struct kauth_identity_extlookup request;
- int status;
-
- request.el_seqno = 1;
- request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP;
- memcpy(&request.el_uguid, user, sizeof(guid_t));
- request.el_gid = group;
-
- status = _mbr_MembershipCall(&request);
- if (status != 0) return status;
- if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) == 0) return ENOENT;
-
- *ismember = ((request.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) != 0);
- return 0;
-#else
- return EIO;
-#endif
+ return mbr_check_membership_ext(ID_TYPE_UUID, user, sizeof(uuid_t), ID_TYPE_GID, &group, 0, ismember);
}
int
mbr_reset_cache()
{
#ifdef DS_AVAILABLE
- return _mbr_ClearCache();
+ _od_rpc_call("mbr_cache_flush", NULL, _mbr_xpc_pipe);
+ return 0;
#else
return EIO;
#endif
int
mbr_user_name_to_uuid(const char *name, uuid_t uu)
{
-#ifdef DS_AVAILABLE
- return _mbr_MapName((char *)name, 1, (guid_t *)uu);
-#else
- return EIO;
-#endif
+ return mbr_identifier_to_uuid(ID_TYPE_USERNAME, name, -1, uu);
}
int
mbr_group_name_to_uuid(const char *name, uuid_t uu)
{
-#ifdef DS_AVAILABLE
- return _mbr_MapName((char *)name, 0, (guid_t *)uu);
-#else
- return EIO;
-#endif
+ return mbr_identifier_to_uuid(ID_TYPE_GROUPNAME, name, -1, uu);
}
int
mbr_check_service_membership(const uuid_t user, const char *servicename, int *ismember)
{
#ifdef DS_AVAILABLE
- char *prefix = "com.apple.access_";
- char *all_services = "com.apple.access_all_services";
- char groupName[256];
- uuid_t group_uu;
- int result;
-
- if (servicename == NULL) return EINVAL;
- if (strlen(servicename) > 255 - strlen(prefix)) return EINVAL;
-
- /* start by checking "all services" */
- result = mbr_group_name_to_uuid(all_services, group_uu);
-
- if (result == EAUTH) return result;
+ xpc_object_t payload, reply;
+ int result = EIO;
- if (result == ENOENT)
- {
- /* all_services group didn't exist, check individual group */
- memcpy(groupName, prefix, strlen(prefix));
- strcpy(groupName + strlen(prefix), servicename);
- result = mbr_group_name_to_uuid(groupName, group_uu);
- }
-
- if (result == 0)
- {
- /* refreshes are driven at a higher level, just check membership */
- result = mbr_check_membership(user, group_uu, ismember);
+ if (ismember == NULL || servicename == NULL) return EINVAL;
+
+ payload = xpc_dictionary_create(NULL, NULL, 0);
+ if (payload == NULL) return EIO;
+
+ xpc_dictionary_set_data(payload, "user_id", user, sizeof(uuid_t));
+ xpc_dictionary_set_int64(payload, "user_idtype", ID_TYPE_UUID);
+ xpc_dictionary_set_string(payload, "service", servicename);
+
+ reply = _od_rpc_call("mbr_check_service_membership", payload, _mbr_xpc_pipe);
+ if (reply != NULL) {
+ result = (int) xpc_dictionary_get_int64(reply, "error");
+ (*ismember) = xpc_dictionary_get_bool(reply, "ismember");
+
+ xpc_release(reply);
+ } else {
+ (*ismember) = 0;
}
+
+ xpc_release(payload);
return result;
#else
#endif
}
-#ifdef DS_AVAILABLE
-static void
-ConvertBytesToHex(char **string, char **data, int numBytes)
-{
- int i;
-
- for (i=0; i < numBytes; i++)
- {
- unsigned char hi = ((**data) >> 4) & 0xf;
- unsigned char low = (**data) & 0xf;
- if (hi < 10)
- **string = '0' + hi;
- else
- **string = 'A' + hi - 10;
-
- (*string)++;
-
- if (low < 10)
- **string = '0' + low;
- else
- **string = 'A' + low - 10;
-
- (*string)++;
- (*data)++;
- }
-}
-#endif
-
int
mbr_uuid_to_string(const uuid_t uu, char *string)
{
-#ifdef DS_AVAILABLE
- char *guid = (char*)uu;
- char *strPtr = string;
- ConvertBytesToHex(&strPtr, &guid, 4);
- *strPtr = '-'; strPtr++;
- ConvertBytesToHex(&strPtr, &guid, 2);
- *strPtr = '-'; strPtr++;
- ConvertBytesToHex(&strPtr, &guid, 2);
- *strPtr = '-'; strPtr++;
- ConvertBytesToHex(&strPtr, &guid, 2);
- *strPtr = '-'; strPtr++;
- ConvertBytesToHex(&strPtr, &guid, 6);
- *strPtr = '\0';
-
+ uuid_unparse_upper(uu, string);
+
return 0;
-#else
- return EIO;
-#endif
}
int
mbr_string_to_uuid(const char *string, uuid_t uu)
{
-#ifdef DS_AVAILABLE
- short dataIndex = 0;
- int isFirstNibble = 1;
-
- if (string == NULL) return EINVAL;
- if (strlen(string) > MBR_UU_STRING_SIZE) return EINVAL;
-
- while (*string != '\0' && dataIndex < 16)
- {
- char nibble;
-
- if (*string >= '0' && *string <= '9')
- nibble = *string - '0';
- else if (*string >= 'A' && *string <= 'F')
- nibble = *string - 'A' + 10;
- else if (*string >= 'a' && *string <= 'f')
- nibble = *string - 'a' + 10;
- else
- {
- if (*string != '-')
- return EINVAL;
- string++;
- continue;
- }
-
- if (isFirstNibble)
- {
- uu[dataIndex] = nibble << 4;
- isFirstNibble = 0;
- }
- else
- {
- uu[dataIndex] |= nibble;
- dataIndex++;
- isFirstNibble = 1;
- }
-
- string++;
- }
-
- if (dataIndex != 16) return EINVAL;
-
- return 0;
-#else
- return EIO;
-#endif
+ return uuid_parse(string, uu);
}
int
mbr_set_identifier_ttl(int id_type, const void *identifier, size_t identifier_size, unsigned int seconds)
{
#ifdef DS_AVAILABLE
- _mbr_SetIdentifierTTL(id_type, identifier, identifier_size, seconds);
- return 0;
+ xpc_object_t payload, reply;
+ int rc = 0;
+
+ payload = xpc_dictionary_create(NULL, NULL, 0);
+ if (payload == NULL) return ENOMEM;
+
+ xpc_dictionary_set_int64(payload, "type", id_type);
+ xpc_dictionary_set_data(payload, "identifier", identifier, identifier_size);
+ xpc_dictionary_set_int64(payload, "ttl", seconds);
+
+ if (rc == 0) {
+ reply = _od_rpc_call("mbr_set_identifier_ttl", payload, _mbr_xpc_pipe);
+ if (reply != NULL) {
+ rc = (int) xpc_dictionary_get_int64(reply, "error");
+ xpc_release(reply);
+ } else {
+ rc = EIO;
+ }
+ }
+
+ xpc_release(payload);
+
+ return rc;
#else
return EIO;
#endif