]> git.saurik.com Git - apple/libinfo.git/commitdiff
Libinfo-406.17.tar.gz mac-os-x-108 mac-os-x-1081 mac-os-x-1082 mac-os-x-1083 mac-os-x-1084 mac-os-x-1085 v406.17
authorApple <opensource@apple.com>
Fri, 30 Mar 2012 23:25:31 +0000 (23:25 +0000)
committerApple <opensource@apple.com>
Fri, 30 Mar 2012 23:25:31 +0000 (23:25 +0000)
24 files changed:
Libinfo.xcodeproj/project.pbxproj
gen.subproj/gethostbyname.3
gen.subproj/getnetent.3
lookup.subproj/cache_module.c
lookup.subproj/ds_module.c
lookup.subproj/file_module.c
lookup.subproj/getgrent.3
lookup.subproj/getpwent.3
lookup.subproj/grp.h [new file with mode: 0644]
lookup.subproj/libinfo.c
lookup.subproj/mdns_module.c
lookup.subproj/pwd.h [new file with mode: 0644]
lookup.subproj/search_module.c
lookup.subproj/si_getaddrinfo.c
lookup.subproj/si_module.c
lookup.subproj/si_module.h
membership.subproj/mbr_check_membership.3
membership.subproj/mbr_uid_to_uuid.3
membership.subproj/membership.c
membership.subproj/membership.h
membership.subproj/membershipPriv.h
rpc.subproj/clnt_raw.c
rpc.subproj/rpc_prot.c
xcodescripts/install_files.sh

index d633498c9513d6fb42ac2359f96197f683bd4286..112788ae1b3ef4ce456fb226497a62c2cf2d3e1f 100644 (file)
@@ -3,7 +3,7 @@
        archiveVersion = 1;
        classes = {
        };
-       objectVersion = 45;
+       objectVersion = 46;
        objects = {
 
 /* Begin PBXBuildFile section */
                FC52855D11478C200058CCB0 /* rcmd.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5284BE11478C200058CCB0 /* rcmd.c */; };
                FC52855E11478C200058CCB0 /* rcmdsh.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5284BF11478C200058CCB0 /* rcmdsh.c */; };
                FC5285D4114791B50058CCB0 /* DSlibinfoMIG.defs in Sources */ = {isa = PBXBuildFile; fileRef = FC5285D1114791B50058CCB0 /* DSlibinfoMIG.defs */; };
-               FC5285D5114791B50058CCB0 /* DSlibinfoMIGAsyncReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = FC5285D2114791B50058CCB0 /* DSlibinfoMIGAsyncReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
-               FC5285D6114791B50058CCB0 /* DSmemberdMIG.defs in Sources */ = {isa = PBXBuildFile; fileRef = FC5285D3114791B50058CCB0 /* DSmemberdMIG.defs */; };
                FC5285F7114793400058CCB0 /* ether_addr.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5285F6114793400058CCB0 /* ether_addr.c */; };
 /* End PBXBuildFile section */
 
                FC5284BE11478C200058CCB0 /* rcmd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rcmd.c; sourceTree = "<group>"; };
                FC5284BF11478C200058CCB0 /* rcmdsh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rcmdsh.c; sourceTree = "<group>"; };
                FC5285D1114791B50058CCB0 /* DSlibinfoMIG.defs */ = {isa = PBXFileReference; explicitFileType = sourcecode.mig; fileEncoding = 4; name = DSlibinfoMIG.defs; path = usr/local/include/opendirectory/DSlibinfoMIG.defs; sourceTree = SDKROOT; };
-               FC5285D2114791B50058CCB0 /* DSlibinfoMIGAsyncReply.defs */ = {isa = PBXFileReference; explicitFileType = sourcecode.mig; fileEncoding = 4; name = DSlibinfoMIGAsyncReply.defs; path = usr/local/include/opendirectory/DSlibinfoMIGAsyncReply.defs; sourceTree = SDKROOT; };
-               FC5285D3114791B50058CCB0 /* DSmemberdMIG.defs */ = {isa = PBXFileReference; explicitFileType = sourcecode.mig; fileEncoding = 4; name = DSmemberdMIG.defs; path = usr/local/include/opendirectory/DSmemberdMIG.defs; sourceTree = SDKROOT; };
                FC5285F6114793400058CCB0 /* ether_addr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ether_addr.c; sourceTree = "<group>"; };
+               FCFDBF0A145CC5C100A39A66 /* grp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = grp.h; sourceTree = "<group>"; };
+               FCFDBF0B145CC5C100A39A66 /* pwd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pwd.h; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
                        children = (
                                2D4070B0129354A700FE81ED /* getnameinfo_link.c */,
                                FC5285D1114791B50058CCB0 /* DSlibinfoMIG.defs */,
-                               FC5285D2114791B50058CCB0 /* DSlibinfoMIGAsyncReply.defs */,
                                FC52841811478C200058CCB0 /* aliasdb.h */,
                                FC52841911478C200058CCB0 /* bootparams.5 */,
                                FC52841A11478C200058CCB0 /* bootparams.h */,
                                FC52842311478C200058CCB0 /* getnameinfo.3 */,
                                FC52842411478C200058CCB0 /* getnetgrent.3 */,
                                FC52842511478C200058CCB0 /* getpwent.3 */,
+                               FCFDBF0A145CC5C100A39A66 /* grp.h */,
                                FC52842611478C200058CCB0 /* ils.c */,
                                FC52842711478C200058CCB0 /* ils.h */,
                                FC52842811478C200058CCB0 /* initgroups.3 */,
                                FC52842F11478C200058CCB0 /* netdb.h */,
                                FC52843011478C200058CCB0 /* netdb_async.h */,
                                FC52843111478C200058CCB0 /* printerdb.h */,
+                               FCFDBF0B145CC5C100A39A66 /* pwd.h */,
                                FC52843211478C200058CCB0 /* search_module.c */,
                                FC52843311478C200058CCB0 /* si_data.c */,
                                FC52843411478C200058CCB0 /* si_data.h */,
                FC52843A11478C200058CCB0 /* membership.subproj */ = {
                        isa = PBXGroup;
                        children = (
-                               FC5285D3114791B50058CCB0 /* DSmemberdMIG.defs */,
                                FC52843C11478C200058CCB0 /* mbr_check_membership.3 */,
                                FC52843D11478C200058CCB0 /* mbr_uid_to_uuid.3 */,
                                FC52843E11478C200058CCB0 /* membership.c */,
 /* Begin PBXProject section */
                08FB7793FE84155DC02AAC07 /* Project object */ = {
                        isa = PBXProject;
+                       attributes = {
+                               LastUpgradeCheck = 0440;
+                       };
                        buildConfigurationList = 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "Libinfo" */;
-                       compatibilityVersion = "Xcode 3.1";
+                       compatibilityVersion = "Xcode 3.2";
                        developmentRegion = English;
                        hasScannedForEncodings = 1;
                        knownRegions = (
                                FC52855D11478C200058CCB0 /* rcmd.c in Sources */,
                                FC52855E11478C200058CCB0 /* rcmdsh.c in Sources */,
                                FC5285D4114791B50058CCB0 /* DSlibinfoMIG.defs in Sources */,
-                               FC5285D5114791B50058CCB0 /* DSlibinfoMIGAsyncReply.defs in Sources */,
-                               FC5285D6114791B50058CCB0 /* DSmemberdMIG.defs in Sources */,
                                FC5285F7114793400058CCB0 /* ether_addr.c in Sources */,
                                2D31A0FC128074E700D5A84C /* getifmaddrs.c in Sources */,
                                2D4070B1129354A700FE81ED /* getnameinfo_link.c in Sources */,
                                );
                                INSTALLHDRS_SCRIPT_PHASE = YES;
                                INSTALL_PATH = /usr/lib/system;
+                               ORDER_FILE = "$(SDKROOT)/$(APPLE_INTERNAL_DIR)/OrderFiles/libsystem_info.order";
                                PRODUCT_NAME = info;
                                VERSION_INFO_EXPORT_DECL = static;
                                VERSION_INFO_PREFIX = __;
                                GCC_TREAT_WARNINGS_AS_ERRORS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
-                               PREBINDING = NO;
                                VERSIONING_SYSTEM = "apple-generic";
                                WARNING_LDFLAGS = "-Wall";
                        };
index 8737a10ae12d29ea6bb8cff85c5305ff1dcde948..7c85286ff887fcc18de18bc632055dbd9e51ec6b 100644 (file)
@@ -114,7 +114,7 @@ argument specifies the address family
 etc.) of this address.
 .Pp
 The structure returned contains information obtained from
-.Xr DirectoryService 8 ,
+.Xr mDNSResponder 8 ,
 including records in
 .Pa /etc/hosts .
 .\"The structure returned contains either the information obtained from the name
@@ -305,7 +305,7 @@ for example, a mail-forwarder may be registered for this domain.
 .Xr resolver 3 ,
 .Xr hosts 5 ,
 .Xr hostname 7 ,
-.Xr DirectoryService 8
+.Xr mDNSResponder 8
 .\".Xr named 8
 .Sh CAVEAT
 The
index 5e344999b59591486738725ec9778af4acf132ca..55723c3230383a20b9b9a8cb8242d6f30f68b507 100644 (file)
@@ -73,7 +73,7 @@ following structure describing an internet network.
 .\"`networks' entry in
 .\".Xr nsswitch.conf 5 .
 This structure contains information obtained from
-.Xr DirectoryService 8 ,
+.Xr opendirectoryd 8 ,
 including records in
 .Pa /etc/networks .
 .Pp
index 6a55ee1eb34360234447270dc2f88a404165e162..5a39a1b78a89612f4d7db5aff5e82ce7932e87c8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Apple Inc.  All rights reserved.
+ * Copyright (c) 2008-2011 Apple Inc.  All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -191,7 +191,7 @@ cache_group_all(si_mod_t *si)
 }
 
 static si_item_t *
-cache_grouplist(si_mod_t *si, const char *name)
+cache_grouplist(si_mod_t *si, const char *name, uint32_t count)
 {
        return cache_fetch_item(si, CATEGORY_GROUPLIST, name, 0, SEL_NAME);
 }
@@ -409,10 +409,12 @@ si_module_static_cache(void)
 
                .sim_user_byname = &cache_user_byname,
                .sim_user_byuid = &cache_user_byuid,
+               .sim_user_byuuid = NULL,
                .sim_user_all = &cache_user_all,
 
                .sim_group_byname = &cache_group_byname,
                .sim_group_bygid = &cache_group_bygid,
+               .sim_group_byuuid = NULL,
                .sim_group_all = &cache_group_all,
 
                .sim_grouplist = &cache_grouplist,
index 3c4e3e4940b4ff2b106b3192554fe9e59c614391..65ff3a8c21bdee4717bd785ef15df82e462f466f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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>
@@ -39,8 +31,8 @@ libinfoDSmig_do_Response_async(mach_port_t server, char *reply, mach_msg_type_nu
 #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>
@@ -51,90 +43,82 @@ libinfoDSmig_do_Response_async(mach_port_t server, char *reply, mach_msg_type_nu
 #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
@@ -143,197 +127,128 @@ _ds_serv_cache_free(void *x)
        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;
@@ -360,242 +275,172 @@ ds_get_validation(si_mod_t *si, uint64_t *a, uint64_t *b, int cat)
                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 
@@ -633,1107 +478,636 @@ _map_v4(char ***v6, uint32_t n6, char **v4, uint32_t n4)
        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;
@@ -1744,31 +1118,30 @@ ds_network_byaddr(si_mod_t *si, uint32_t addr)
        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 = "";
 
@@ -1780,152 +1153,149 @@ ds_service_byname(si_mod_t *si, const char *name, const char *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 *
@@ -1936,6 +1306,7 @@ ds_fs_byfile(si_mod_t *si, const char *name)
        uint32_t i;
        struct fstab *f;
 
+       if (!_od_running()) return NULL;
        if (name == NULL) return NULL;
 
        list = ds_fs_all(si);
@@ -1955,364 +1326,61 @@ ds_fs_byfile(si_mod_t *si, const char *name)
 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,
@@ -2323,9 +1391,10 @@ si_module_static_ds(void)
                .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,
@@ -2380,7 +1449,6 @@ si_module_static_ds(void)
                        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;
                }
 
@@ -2398,7 +1466,6 @@ si_module_static_ds(void)
                        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));
                }
 
index 7db0b896bac9ebbb03a6bc0ce933e16dee9c1b24..bf332f85406cbeae407ab8b0eed25e7ca311e6e9 100644 (file)
@@ -30,6 +30,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <notify.h>
+#include <pthread.h>
 #include <arpa/inet.h>
 #include <sys/param.h>
 #include <sys/mount.h>
@@ -132,21 +133,18 @@ _fsi_append_string(char *s, char **l)
        int i, len;
 
        if (s == NULL) return l;
-       if (l == NULL) 
-       {
-               l = (char **)malloc(2 * sizeof(char *));
-               l[0] = s;
-               l[1] = NULL;
-               return l;
+       if (l != NULL) {
+               for (i = 0; l[i] != NULL; i++);
+               len = i;
+       } else {
+               len = 0;
        }
 
-       for (i = 0; l[i] != NULL; i++);
-       len = i + 1; /* count the NULL on the end of the list too! */
-
-       l = (char **)reallocf(l, (len + 1) * sizeof(char *));
+       l = (char **) reallocf(l, (len + 2) * sizeof(char *));
+       if (l == NULL) return NULL;
 
-       l[len - 1] = s;
-       l[len] = NULL;
+       l[len] = s;
+       l[len + 1] = NULL;
        return l;
 }
 
@@ -276,7 +274,7 @@ _fsi_get_validation(si_mod_t *si, int vtype, const char *path, FILE *f, uint64_t
        int status;
 
        if (a != NULL) *a = 0;
-       if (b != NULL) *a = 0;
+       if (b != NULL) *b = 0;
 
        if (si == NULL) return;
        if (path == NULL) return;
@@ -984,8 +982,8 @@ _fsi_get_grouplist(si_mod_t *si, const char *user)
        si_item_t *item;
        FILE *f;
        uint64_t va, vb;
-       int32_t gid, basegid, *gidp;
-       char **gidlist;
+       gid_t gid, basegid;
+       gid_t *gidlist;
        struct passwd *pw;
 
        if (user == NULL) return NULL;
@@ -1000,7 +998,8 @@ _fsi_get_grouplist(si_mod_t *si, const char *user)
        {
                pw = (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
                basegid = pw->pw_gid;
-               free(item);
+               si_item_release(item);
+               item = NULL;
        }
 
        f = fopen(_PATH_GROUP, "r");
@@ -1034,12 +1033,13 @@ _fsi_get_grouplist(si_mod_t *si, const char *user)
                match = 0;
                gid = -2;
 
-               for (i = 0; (i < ntokens) && (match == 0); i++)
+               for (i = 0; i < ntokens; i++)
                {
                        if (string_equal(user, members[i]))
                        {
                                gid = atoi(tokens[2]);
                                match = 1;
+                               break;
                        }
                }
 
@@ -1050,40 +1050,24 @@ _fsi_get_grouplist(si_mod_t *si, const char *user)
 
                if (match == 1)
                {
-                       if (gidcount == 0) gidlist = (char **)calloc(1, sizeof(char *));
-                       else gidlist = (char **)reallocf(gidlist, (gidcount + 1) * sizeof(char *));
-                       gidp = (int32_t *)calloc(1, sizeof(int32_t));
-
+                       gidlist = (gid_t *) reallocf(gidlist, (gidcount + 1) * sizeof(gid_t));
                        if (gidlist == NULL)
                        {
                                gidcount = 0;
                                break;
                        }
 
-                       if (gidp == NULL)
-                       {
-                               for (i = 0; i < gidcount; i++) free(gidlist[i]);
-                               free(gidlist);
-                               gidcount = 0;
-                               break;
-                       }
-
-                       *gidp = gid;
-                       gidlist[gidcount++] = (char *)gidp;
+                       gidlist[gidcount++] = gid;
                }
        }
 
        fclose(f);
 
-       if (gidcount == 0) return NULL;
-
-       gidlist = (char **)reallocf(gidlist, (gidcount + 1) * sizeof(int32_t *));
-       if (gidlist == NULL) return NULL;
-       gidlist[gidcount] = NULL;
-
-       item = (si_item_t *)LI_ils_create("L4488s44a", (unsigned long)si, CATEGORY_GROUPLIST, 1, va, vb, user, basegid, gidcount, gidlist);
+       if (gidcount != 0) {
+               item = (si_item_t *)LI_ils_create("L4488s4@", (unsigned long)si, CATEGORY_GROUPLIST, 1, va, vb, user, gidcount, 
+                                                                                 gidcount * sizeof(gid_t), gidlist);
+       }
 
-       for (i = 0; i <= gidcount; i++) free(gidlist[i]);
        free(gidlist);
 
        return item;
@@ -2030,7 +2014,7 @@ file_group_all(si_mod_t *si)
 }
 
 static si_item_t *
-file_grouplist(si_mod_t *si, const char *name)
+file_grouplist(si_mod_t *si, const char *name, __unused uint32_t ignored)
 {
        return _fsi_get_grouplist(si, name);
 }
@@ -2040,7 +2024,7 @@ file_netgroup_byname(si_mod_t *si, const char *name)
 {
        si_list_t *list = NULL;
        si_item_t *item;
-       uint64_t va, vb;
+       uint64_t va=0, vb=0;
        file_netgroup_t *n;
        file_si_private_t *pp;
 
@@ -2296,10 +2280,12 @@ si_module_static_file(void)
 
                .sim_user_byname = &file_user_byname,
                .sim_user_byuid = &file_user_byuid,
+               .sim_user_byuuid = NULL,
                .sim_user_all = &file_user_all,
 
                .sim_group_byname = &file_group_byname,
                .sim_group_bygid = &file_group_bygid,
+               .sim_group_byuuid = NULL,
                .sim_group_all = &file_group_all,
 
                .sim_grouplist = &file_grouplist,
index 2a2920c7f90b6963fb656324ccd9fe5ea78733c1..adad337cd965522b023e60a77a0ae8a143b4d3aa 100644 (file)
@@ -28,7 +28,7 @@
 .\"     From: @(#)getgrent.3   8.2 (Berkeley) 4/19/94
 .\" $FreeBSD: src/lib/libc/gen/getgrent.3,v 1.28 2007/01/09 00:27:53 imp Exp $
 .\"
-.Dd April 16, 2003
+.Dd October 26, 2011
 .Dt GETGRENT 3
 .Os
 .Sh NAME
@@ -38,6 +38,8 @@
 .Nm getgrnam_r ,
 .Nm getgrgid ,
 .Nm getgrgid_r ,
+.Nm getgruuid ,
+.Nm getgruuid_r ,
 .Nm setgroupent ,
 .Nm setgrent ,
 .Nm endgrent
@@ -46,6 +48,7 @@
 .Lb libc
 .Sh SYNOPSIS
 .In grp.h
+.In uuid/uuid.h
 .Ft struct group *
 .Fn getgrent void
 .\".Ft int
 .Ft int
 .Fn getgrgid_r "gid_t gid" "struct group *grp" "char *buffer" "size_t bufsize" "struct group **result"
 .Ft int
+.Fn getgruuid "uuid_t uuid"
+.Ft int
+.Fn getgruuid_r "uuid_t uuid" "struct group *grp" "char *buffer" "size_t bufsize" "struct group **result"
+.Ft int
 .Fn setgroupent "int stayopen"
 .Ft void
 .Fn setgrent void
@@ -67,7 +74,7 @@
 .Sh DESCRIPTION
 .\"These functions operate on the group database file
 These functions obtain information from
-.Xr DirectoryService 8 ,
+.Xr opendirectoryd 8 ,
 including records in
 .Pa /etc/group
 which is described
@@ -88,21 +95,35 @@ struct group {
 .Ed
 .Pp
 The functions
-.Fn getgrnam
+.Fn getgrnam ,
+.Fn getgrgid ,
 and
-.Fn getgrgid
+.Fn getgruuid
 search the group database for the given group name pointed to by
-.Fa name
-or the group id pointed to by
+.Fa name ,
+the group id given by
 .Fa gid ,
+or the UUID given by
+.Fa uuid 
 respectively, returning the first one encountered.
 Identical group
-names or group gids may result in undefined behavior.
+names, group gids, or uuids may result in undefined behavior.
+.Pp
+Note that the groups file
+.Pa /etc/group
+does not contain group UUIDs.
+The UUID for a group may be found using
+.Fn mbr_gid_to_uuid .
 .Pp
 On Mac OS X, these routines are thread-safe and return a pointer to a
 thread-specific data structure.  The contents of this data
 structure are automatically released by subsequent calls to
 any of these routines on the same thread, or when the thread exits.
+These routines are therefore unsuitable for use in libraries or frameworks,
+from where they may overwrite the per-thread data that the calling
+application expects to find as a result of its own calls to these
+routines. Library and framework code should use the alternative reentrant 
+variants detailed below.
 .Pp
 The
 .Fn getgrent
@@ -111,17 +132,15 @@ sequentially reads the group database and is intended for programs
 that wish to step through the complete list of groups.
 .Pp
 The functions
-.\".Fn getgrent_r ,
-.\".Fn getgrnam_r ,
-.Fn getgrnam_r
-and
-.Fn getgrgid_r
-are thread-safe versions of
-.\".Fn getgrent ,
-.\".Fn getgrnam ,
-.Fn getgrnam
+.Fn getgrnam_r , 
+.Fn getgrgid_r ,
 and
+.Fn getgruuid_r
+are alternative versions of
+.Fn getgrnam ,
 .Fn getgrgid ,
+and
+.Fn getgruuid
 respectively.
 The caller must provide storage for the results of the search in
 the
@@ -186,11 +205,10 @@ Note that programs must explicitly set
 to zero before calling any of these functions if they need to
 distinguish between a non-existent entry and an error.
 The functions
-.\".Fn getgrent_r ,
-.\".Fn getgrnam_r ,
-.Fn getgrnam_r
+.Fn getgrnam_r ,
+.Fn getgrgid_r ,
 and
-.Fn getgrgid_r
+.Fn getgruuid_r
 return 0 if no error occurred, or an error number to indicate failure.
 It is not an error if a matching entry is not found.
 (Thus, if
@@ -216,13 +234,13 @@ group database file
 .Sh COMPATIBILITY
 The historic function
 .Fn setgrfile ,
-which allowed the specification of alternate password databases, has
+which allowed the specification of alternate group databases, has
 been deprecated and is no longer available.
 .Sh SEE ALSO
 .Xr getpwent 3 ,
 .Xr group 5 ,
-.\".Xr nsswitch.conf 5 ,
-.Xr DirectoryService 8 ,
+.Xr mbr_gid_to_uuid 3, 
+.Xr opendirectory 8 ,
 .Xr yp 8
 .Sh STANDARDS
 The
@@ -265,11 +283,17 @@ and
 .Fn getgrgid_r
 appeared in
 .Fx 5.1 .
+The functions
+.Fn getgruuid
+and
+.Fn getgruuid_r
+appeared in Mac OS X 10.8.
 .Sh BUGS
 The functions
 .Fn getgrent ,
 .Fn getgrnam ,
 .Fn getgrgid ,
+.Fn getgruuid ,
 .Fn setgroupent
 and
 .Fn setgrent
@@ -278,21 +302,3 @@ a pointer to that object.
 Subsequent calls to
 the same function
 will modify the same object.
-.\".Pp
-.\"The functions
-.\".Fn getgrent ,
-.\".Fn getgrent_r ,
-.\".Fn endgrent ,
-.\".Fn setgroupent ,
-.\"and
-.\".Fn setgrent
-.\"are fairly useless in a networked environment and should be
-.\"avoided, if possible.
-.\"The
-.\".Fn getgrent
-.\"and
-.\".Fn getgrent_r
-.\"functions
-.\"make no attempt to suppress duplicate information if multiple
-.\"sources are specified in
-.\".Xr nsswitch.conf 5 .
index 75c99c352388c643ff8a2c7b23c05f8f282c052f..14bf4c10c115559ba51f5f92e9a5eac695504c48 100644 (file)
@@ -28,7 +28,7 @@
 .\"     From: @(#)getpwent.3   8.2 (Berkeley) 12/11/93
 .\" $FreeBSD: src/lib/libc/gen/getpwent.3,v 1.30 2007/01/09 00:27:54 imp Exp $
 .\"
-.Dd April 16, 2003
+.Dd October 26, 2011
 .Dt GETPWENT 3
 .Os
 .Sh NAME
@@ -38,6 +38,8 @@
 .Nm getpwnam_r ,
 .Nm getpwuid ,
 .Nm getpwuid_r ,
+.Nm getpwuuid ,
+.Nm getpwuuid_r ,
 .Nm setpassent ,
 .Nm setpwent ,
 .Nm endpwent
@@ -47,6 +49,7 @@
 .Sh SYNOPSIS
 .In sys/types.h
 .In pwd.h
+.In uuid/uuid.h
 .Ft struct passwd *
 .Fn getpwent void
 .\".Ft int
 .Ft int
 .Fn getpwuid_r "uid_t uid" "struct passwd *pwd" "char *buffer" "size_t bufsize" "struct passwd **result"
 .Ft int
+.Fn getpwuuid "uuid_t uuid"
+.Ft int
+.Fn getpwuuid_r "uuid_t uuid" "struct passwd *pwd" "char *buffer" "size_t bufsize" "struct passwd **result"
+.Ft int
 .Fn setpassent "int stayopen"
 .Ft void
 .Fn setpwent void
 These functions
 .\"operate on the password database file
 obtain information from
-.Xr DirectoryService 8 ,
+.Xr opendirectoryd 8 ,
 including records in
-.Pa /etc/passwd
+.Pa /etc/master.passwd
 which is described
 in
-.Xr passwd 5 .
+.Xr master.passwd 5 .
 Each entry in the database is defined by the structure
 .Vt passwd
 found in the include
@@ -97,16 +104,28 @@ struct passwd {
 .Ed
 .Pp
 The functions
-.Fn getpwnam
+.Fn getpwnam ,
+.Fn getpwuid ,
 and
-.Fn getpwuid
-search the password database for the given login name or user uid,
+.Fn getpwuuid
+search the password database for the given login name, user uid, or user uuid
 respectively, always returning the first one encountered.
 .Pp
+Note that the password file
+.Pa /etc/master.passwd
+does not contain user UUIDs.
+The UUID for a user may be found using
+.Fn mbr_uid_to_uuid .
+.Pp
 On Mac OS X, these routines are thread-safe and return a pointer to a
 thread-specific data structure.  The contents of this data
 structure are automatically released by subsequent calls to
 any of these routines on the same thread, or when the thread exits.
+These routines are therefore unsuitable for use in libraries or frameworks,
+from where they may overwrite the per-thread data that the calling
+application expects to find as a result of its own calls to these
+routines. Library and framework code should use the alternative reentrant 
+variants detailed below.
 .Pp
 The
 .Fn getpwent
@@ -115,30 +134,31 @@ sequentially reads the password database and is intended for programs
 that wish to process the complete list of users.
 .Pp
 The functions
-.\".Fn getpwent_r ,
-.\".Fn getpwnam_r ,
-.Fn getpwnam_r
-and
-.Fn getpwuid_r
-are thread-safe versions of
-.\".Fn getpwent ,
-.\".Fn getpwnam ,
-.Fn getpwnam
+.Fn getpwnam_r ,
+.Fn getpwuid_r ,
 and
+.Fn getpwuuid_r
+are alternative versions of
+.Fn getpwnam ,
 .Fn getpwuid ,
-respectively.
-The caller must provide storage for the results of the search in
-the
-.Fa pwd ,
-.Fa buffer ,
-.Fa bufsize ,
 and
-.Fa result
-arguments.
-When these functions are successful, the
+.Fn getpwuuid
+respectively.
+They store the results of their search in the caller-provided
+.Fa pwd 
+structure, which additionally contains pointers to strings that are 
+stored in the caller-provided 
+.Fa buffer
+of size
+.Fa bufsize .
+(The maximum required
+.Fa bufsize
+can be obtained by passing the _SC_GETPW_R_SIZE_MAX constant to the
+.Xr sysconf 3
+call. See example code below.) When these functions are successful, the
 .Fa pwd
-argument will be filled-in, and a pointer to that argument will be
-stored in
+argument will be filled in, and a pointer to that argument will be
+stored in the caller-provided
 .Fa result .
 If an entry is not found or an error occurs,
 .Fa result
@@ -188,7 +208,7 @@ by returning a structure whose password field points to the string
 .Ql ******** .
 Legacy crypt passwords are still returned for user records created on
 earlier versions of Mac OS X whose
-.Xr DirectoryService 8
+.Xr opendirectoryd 8
 .Dt AuthenticationAuthority
 attribute contains the value
 .Ql ;basic; .
@@ -196,8 +216,9 @@ attribute contains the value
 The functions
 .Fn getpwent ,
 .Fn getpwnam ,
+.Fn getpwuid ,
 and
-.Fn getpwuid
+.Fn getpwuuid
 return a valid pointer to a passwd structure on success
 or
 .Dv NULL
@@ -210,11 +231,10 @@ Note that programs must explicitly set
 to zero before calling any of these functions if they need to
 distinguish between a non-existent entry and an error.
 The functions
-.\".Fn getpwent_r ,
-.\".Fn getpwnam_r ,
-.Fn getpwnam_r
+.Fn getpwnam_r ,
+.Fn getpwuid_r ,
 and
-.Fn getpwuid_r
+.Fn getpwuuid_r
 return 0 if no error occurred, or an error number to indicate failure.
 It is not an error if a matching entry is not found.
 (Thus, if
@@ -232,6 +252,27 @@ and
 .Fn setpwent
 functions
 have no return value.
+.Sh EXAMPLES
+To print the current user's home directory without depending on per-thread storage:
+.Bd -literal -offset indent
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <pwd.h>
+
+int bufsize;
+
+if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1)
+    abort();
+
+char buffer[bufsize];
+struct passwd pwd, *result = NULL;
+if (getpwuid_r(getuid(), &pwd, buffer, bufsize, &result) != 0 || !result)
+    abort();
+
+printf("%s\\n", pwd.pw_dir);
+.Ed
 .Sh FILES
 .Bl -tag -width /etc/master.passwd -compact
 .\".It Pa /etc/pwd.db
@@ -272,7 +313,8 @@ The caller should retry with a larger buffer.
 .Xr passwd 5 ,
 .\".Xr pwd_mkdb 8 ,
 .\".Xr vipw 8 ,
-.Xr DirectoryService 8 ,
+.Xr mbr_uid_to_uuid 3, 
+.Xr opendirectoryd 8 ,
 .Xr yp 8
 .Sh STANDARDS
 The
@@ -308,12 +350,18 @@ and
 .Fn getpwuid_r
 functions appeared in
 .Fx 5.1 .
+The functions
+.Fn getpwuuid
+and
+.Fn getpwuuid_r
+appeared in Mac OS X 10.8.
 .Sh BUGS
 The functions
 .Fn getpwent ,
 .Fn getpwnam ,
-and
 .Fn getpwuid ,
+and
+.Fn getpwuuid ,
 .\"leave their results in an internal static object and return
 leave their results in an internal thread-specific memory and return
 a pointer to that object.
diff --git a/lookup.subproj/grp.h b/lookup.subproj/grp.h
new file mode 100644 (file)
index 0000000..76a8efc
--- /dev/null
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)grp.h       8.2 (Berkeley) 1/21/94
+ */
+/* Portions copyright (c) 2000-2011 Apple Inc. All rights reserved. */ 
+
+#ifndef _GRP_H_
+#define        _GRP_H_
+
+#include <_types.h>
+
+#ifndef _GID_T
+typedef __darwin_gid_t gid_t;          /* [XBD] */
+#define _GID_T
+#endif
+
+/*
+ * Although the definition of size_t is not mandated by [TSF], the function
+ * prototypes defined by [TSF] for the thread reentrant functions include
+ * it as a type for their 4th arguments, so we define it here.
+ */
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef __darwin_size_t        size_t;         /* [???] */
+#endif
+
+#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
+#define        _PATH_GROUP             "/etc/group"
+#endif
+
+struct group {
+       char    *gr_name;               /* [XBD] group name */
+       char    *gr_passwd;             /* [???] group password */
+       gid_t   gr_gid;                 /* [XBD] group id */
+       char    **gr_mem;               /* [XBD] group members */
+};
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+/* [XBD] */
+struct group *getgrgid(gid_t);
+struct group *getgrnam(const char *);
+/* [TSF] */
+int getgrgid_r(gid_t, struct group *, char *, size_t, struct group **);
+int getgrnam_r(const char *, struct group *, char *, size_t, struct group **);
+/* [XSI] */
+struct group *getgrent(void);
+void setgrent(void);
+void endgrent(void);
+__END_DECLS
+
+#if (!defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)) || defined(_DARWIN_C_SOURCE)
+#include <uuid/uuid.h>
+__BEGIN_DECLS
+char *group_from_gid(gid_t, int);
+struct group *getgruuid(uuid_t);
+int getgruuid_r(uuid_t, struct group *, char *, size_t, struct group **);
+__END_DECLS
+#endif
+
+#if !defined(_XOPEN_SOURCE) || defined(_DARWIN_C_SOURCE)
+__BEGIN_DECLS
+void setgrfile(const char *);
+int setgroupent(int);
+__END_DECLS
+#endif
+
+#endif /* !_GRP_H_ */
index 0f5f2e2a7e9f14a9c5d0b9936e48b5cbbe7e3e25..7a9628ebbc198edac63cc0953f2ce13f1f3962ce 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008 Apple Inc.  All rights reserved.
+ * Copyright (c) 2008-2011 Apple Inc.  All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -27,6 +27,7 @@
 #include <string.h>
 #include <errno.h>
 #include <netdb.h>
+#include <asl.h>
 #include <printerdb.h>
 #include <sys/param.h>
 #include <sys/syscall.h>
@@ -38,6 +39,7 @@
 #include <thread_data.h>
 #include <sys/kauth.h>
 #include "netdb_async.h"
+#include <dispatch/dispatch.h>
 
 #define SOCK_UNSPEC 0
 #define IPPROTO_UNSPEC 0
@@ -272,6 +274,24 @@ getpwuid_async_handle_reply(mach_msg_header_t *msg)
        si_async_handle_reply(msg);
 }
 
+struct passwd *
+getpwuuid(uuid_t uuid)
+{
+       si_item_t *item;
+
+#ifdef CALL_TRACE
+       uuid_string_t uuidstr;
+       uuid_unparse_upper(uuid, uuidstr);
+       fprintf(stderr, "-> %s %s\n", __func__, uuidstr);
+#endif
+
+       item = si_user_byuuid(si_search(), uuid);
+       LI_set_thread_item(CATEGORY_USER + 300, item);
+
+       if (item == NULL) return NULL;
+       return (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
+}
+
 void
 setpwent(void)
 {
@@ -425,6 +445,24 @@ getgruid_async_handle_reply(mach_msg_header_t *msg)
        si_async_handle_reply(msg);
 }
 
+struct group *
+getgruuid(uuid_t uuid)
+{
+       si_item_t *item;
+
+#ifdef CALL_TRACE
+       uuid_string_t uuidstr;
+       uuid_unparse_upper(uuid, uuidstr);
+       fprintf(stderr, "-> %s %s\n", __func__, uuidstr);
+#endif
+
+       item = si_group_byuuid(si_search(), uuid);
+       LI_set_thread_item(CATEGORY_GROUP + 300, item);
+
+       if (item == NULL) return NULL;
+       return (struct group *)((uintptr_t)item + sizeof(si_item_t));
+}
+
 void
 setgrent(void)
 {
@@ -557,10 +595,42 @@ endnetgrent(void)
        LI_set_thread_list(CATEGORY_NETGROUP, NULL);
 }
 
+#if DS_AVAILABLE
+static void
+_check_groups(const char *function, int32_t ngroups)
+{
+       static dispatch_once_t once;
+       
+       if (ngroups > 0 && ngroups < NGROUPS_MAX) {
+               return;
+       }
+       
+       /* only log once per process */
+       dispatch_once(&once, ^(void) {
+               const char *proc_name = getprogname();
+               if (strcmp(proc_name, "id") != 0 && strcmp(proc_name, "smbd") != 0 && strcmp(proc_name, "rpcsvchost") != 0) {
+                       aslmsg msg = asl_new(ASL_TYPE_MSG);
+                       char buffer[256];
+                       
+                       snprintf(buffer, sizeof(buffer), "%d", (ngroups == 0 ? INT_MAX : ngroups));
+                       asl_set(msg, "com.apple.message.value", buffer);
+                       
+                       asl_set(msg, "com.apple.message.domain", "com.apple.system.libinfo");
+                       asl_set(msg, "com.apple.message.result", "noop");
+                       asl_set(msg, "com.apple.message.signature", function);
+                       
+                       asl_log(NULL, msg, ASL_LEVEL_NOTICE, "%s called triggering group enumeration", function);
+                       
+                       asl_free(msg);
+               }
+       });
+}
+#endif
+
 /* GROUPLIST */
 
 static int
-getgrouplist_internal(const char *name, int basegid, gid_t *groups, uint32_t *ngroups, int set_thread_data)
+getgrouplist_internal(const char *name, int basegid, gid_t *groups, uint32_t *ngroups)
 {
        int i, j, x, g, add, max;
        si_item_t *item;
@@ -580,34 +650,31 @@ getgrouplist_internal(const char *name, int basegid, gid_t *groups, uint32_t *ng
        if (groups == NULL) return 0;
        if (ngroups == NULL) return 0;
 
-       max = *ngroups;
+       max = (*ngroups);
        *ngroups = 0;
        if (max <= 0) return 0;
 
        groups[0] = basegid;
        *ngroups = 1;
-
-       item = si_grouplist(si_search(), name);
-       if (set_thread_data != 0) LI_set_thread_item(CATEGORY_GROUPLIST, item);
+       
+       item = si_grouplist(si_search(), name, max);
+       LI_set_thread_item(CATEGORY_GROUPLIST, item);
        if (item == NULL) return 0;
 
        gl = (si_grouplist_t *)((uintptr_t)item + sizeof(si_item_t));
 
        x = 1;
 
-       if (gl->gl_basegid != basegid)
-       {
-               if (x >= max) return -1;
-               groups[x] = gl->gl_basegid;
-               x++;
-               *ngroups = x;
-       }
-
        for (i = 0; i < gl->gl_count; i++)
        {
-               g = (int)*(gl->gl_gid[i]);
+               g = gl->gl_gid[i];
                add = 1;
-               for (j = 0; (j < x) && (add == 1); j++) if (groups[j] == g) add = 0;
+               for (j = 0; j < x; j++) {
+                       if (groups[j] == g) {
+                               add = 0;
+                               break;
+                       }
+               }
                if (add == 0) continue;
 
                if (x >= max) return -1;
@@ -622,121 +689,100 @@ getgrouplist_internal(const char *name, int basegid, gid_t *groups, uint32_t *ng
 int
 getgrouplist(const char *name, int basegid, int *groups, int *ngroups)
 {
-       return getgrouplist_internal(name, basegid, (gid_t *)groups, (uint32_t *)ngroups, 1);
-}
+#if DS_AVAILABLE
+       _check_groups("getgrouplist", *ngroups);
+#endif
 
-/* XXX to do: async getgrouplist */
+       return getgrouplist_internal(name, basegid, (gid_t *)groups, (uint32_t *)ngroups);
+}
 
-static int
-merge_gid(gid_t **list, gid_t g, int32_t *count)
+static void
+merge_gid(gid_t *list, gid_t g, int32_t *count)
 {
+       int32_t cnt;
        int i;
 
-       if (list == NULL) return -1;
+       cnt = (*count);
+       for (i = 0; i < cnt; i++) {
+               if (list[i] == g) return;
+       }
 
-       if (*count == 0)
-       {
-               *list = (gid_t *)calloc(1, sizeof(gid_t));
-               if (list == NULL)
-               {
-                       errno = ENOMEM;
-                       return -1;
-               }
+       list[cnt] = g;
+       (*count)++;
+}
 
-               (*list)[(*count)++] = g;
-               return 0;
-       }
+static int32_t
+_getgrouplist_2_internal(const char *name, gid_t basegid, gid_t **groups)
+{
+       int32_t i, count;
+       si_item_t *item;
+       gid_t *gids;
+       si_grouplist_t *gl;
+
+       item = si_grouplist(si_search(), name, INT_MAX);
+       LI_set_thread_item(CATEGORY_GROUPLIST, item);
+       if (item == NULL) return -1;
 
-       for (i = 0; i < *count; i++) if ((*list)[i] == g) return 0;
+       gl = (si_grouplist_t *) ((uintptr_t) item + sizeof(si_item_t));
+       
+       /*
+        * we can allocate enough up-front, we'll only use what we need
+        * we add one to the count that was found in case the basegid is not there
+        */
+       gids = calloc(gl->gl_count + 1, sizeof(gid_t));
 
-       *list = (gid_t *)reallocf(*list, (*count + 1) * sizeof(gid_t));
-       (*list)[(*count)++] = g;
-       return 0;
+       count = 0;
+       merge_gid(gids, basegid, &count);
+       if (gl->gl_gid != NULL) {
+               for (i = 0; i < gl->gl_count; i++) {
+                       merge_gid(gids, gl->gl_gid[i], &count);
+               }
+       }
+       
+       (*groups) = gids;
+       
+       return count;
 }
 
 int32_t
 getgrouplist_2(const char *name, gid_t basegid, gid_t **groups)
 {
-       int32_t i, status, count;
-       gid_t g;
-       si_item_t *item;
-       si_grouplist_t *gl;
-
        /*
         * Passes back a gid_t list containing all the users groups (and basegid).
         * Caller must free the list.
         * Returns the number of gids in the list or -1 on failure.
         */
-
+       
 #ifdef CALL_TRACE
        fprintf(stderr, "-> %s %s %d\n", __func__, name, basegid);
 #endif
-
+       
        if (name == NULL) return 0;
        if (groups == NULL) return 0;
-
-       item = si_grouplist(si_search(), name);
-       LI_set_thread_item(CATEGORY_GROUPLIST, item);
-       if (item == NULL) return -1;
-
-       gl = (si_grouplist_t *)((uintptr_t)item + sizeof(si_item_t));
-
-       count = 0;
-       *groups = NULL;
-
-       status = merge_gid(groups, basegid, &count);
-       if (status != 0) return status;
-
-       status = merge_gid(groups, gl->gl_basegid, &count);
-       if (status != 0) return status;
-
-       for (i = 0; i < gl->gl_count; i++)
-       {
-               g = (gid_t)*(gl->gl_gid[i]);
-               status = merge_gid(groups, g, &count);
-               if (status != 0) return status;
-       }
-
-       return count;
+       
+#if DS_AVAILABLE
+       _check_groups("getgrouplist_2", INT_MAX);
+#endif
+       
+       return _getgrouplist_2_internal(name, basegid, groups);
 }
 
 int32_t
 getgroupcount(const char *name, gid_t basegid)
 {
-       int32_t i, status, count;
-       gid_t g;
-       si_item_t *item;
-       si_grouplist_t *gl;
+       int32_t count;
        gid_t *groups;
 
 #ifdef CALL_TRACE
        fprintf(stderr, "-> %s %s %d\n", __func__, name, basegid);
 #endif
 
-       if (name == NULL) return 0;
-
-       item = si_grouplist(si_search(), name);
-       LI_set_thread_item(CATEGORY_GROUPLIST, item);
-       if (item == NULL) return -1;
-
-       gl = (si_grouplist_t *)((uintptr_t)item + sizeof(si_item_t));
+#if DS_AVAILABLE
+       _check_groups("getgroupcount", INT_MAX);
+#endif
 
-       count = 0;
        groups = NULL;
-
-       status = merge_gid(&groups, basegid, &count);
-       if (status != 0) return status;
-
-       status = merge_gid(&groups, gl->gl_basegid, &count);
-       if (status != 0) return status;
-
-       for (i = 0; i < gl->gl_count; i++)
-       {
-               g = (gid_t)*(gl->gl_gid[i]);
-               status = merge_gid(&groups, g, &count);
-               if (status != 0) return status;
-       }
-
+       count = _getgrouplist_2_internal(name, basegid, &groups);
        if (groups != NULL) free(groups);
 
        return count;
@@ -770,19 +816,19 @@ initgroups(const char *name, int basegid)
        {
                p = (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
                uid = p->pw_uid;
-
                si_item_release(item);
        }
 #endif
 
        ngroups = NGROUPS;
 
-       status = getgrouplist_internal(name, basegid, groups, &ngroups, 0);
        /*
         * Ignore status.
         * A failure either means that user belongs to more than NGROUPS groups 
         * or no groups at all.
         */
+    
+       (void) getgrouplist_internal(name, basegid, groups, &ngroups);
 
        status = __initgroups(ngroups, groups, uid);
        if (status < 0) return -1;
@@ -3046,6 +3092,37 @@ getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize, struct gr
        return 0;
 }
 
+int
+getgruuid_r(uuid_t uuid, struct group *grp, char *buffer, size_t bufsize, struct group **result)
+{
+       si_item_t *item;
+       struct group *g;
+       int status;
+       
+#ifdef CALL_TRACE
+       uuid_string_t uuidstr;
+       uuid_unparse_upper(uuid, uuidstr);
+       fprintf(stderr, "-> %s %s\n", __func__, uuidstr);
+#endif
+
+       if (result != NULL) *result = NULL;
+
+       if ((grp == NULL) || (buffer == NULL) || (result == NULL) || (bufsize == 0)) return ERANGE;
+       
+       item = si_group_byuuid(si_search(), uuid);
+       if (item == NULL) return 0;
+       
+       g = (struct group *)((uintptr_t)item + sizeof(si_item_t));
+       
+       status = copy_group_r(g, grp, buffer, bufsize);
+       si_item_release(item);
+       
+       if (status != 0) return ERANGE;
+       
+       *result = grp;
+       return 0;
+}
+
 int
 getpwnam_r(const char *name, struct passwd *pw, char *buffer, size_t bufsize, struct passwd **result)
 {
@@ -3104,6 +3181,37 @@ getpwuid_r(uid_t uid, struct passwd *pw, char *buffer, size_t bufsize, struct pa
        return 0;
 }
 
+int
+getpwuuid_r(uuid_t uuid, struct passwd *pw, char *buffer, size_t bufsize, struct passwd **result)
+{
+       si_item_t *item;
+       struct passwd *p;
+       int status;
+
+#ifdef CALL_TRACE
+       uuid_string_t uuidstr;
+       uuid_unparse_upper(uuid, uuidstr);
+       fprintf(stderr, "-> %s %s\n", __func__, uuidstr);
+#endif
+
+       if (result != NULL) *result = NULL;
+
+       if ((pw == NULL) || (buffer == NULL) || (result == NULL) || (bufsize == 0)) return ERANGE;
+
+       item = si_user_byuuid(si_search(), uuid);
+       if (item == NULL) return 0;
+
+       p = (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
+
+       status = copy_user_r(p, pw, buffer, bufsize);
+       si_item_release(item);
+
+       if (status != 0) return ERANGE;
+
+       *result = pw;
+       return 0;
+}
+
 /* misc */
 
 char *
index 7f23aadd63f33cc4333171045d481ba6a100a702..27a907f9ea2e1e6b40228b8367db27d8fc27fd7f 100644 (file)
@@ -1515,9 +1515,9 @@ _mdns_search(const char *name, int class, int type, const char *interface, DNSSe
                        extra.tv_sec = SHORT_AAAA_EXTRA;
                        extra.tv_nsec = 0;
 
-                       // if delta is really small, we probably got a result from mDNSResponder's cache
-                       if ((delta.tv_sec == 0) && (delta.tv_nsec <= 200000000)) {
-                               extra.tv_sec = LONG_AAAA_EXTRA;
+                       // if delta is small (<= 20 milliseconds), we probably got a result from mDNSResponder's cache
+                       if ((delta.tv_sec == 0) && (delta.tv_nsec <= 20000000)) {
+                               extra.tv_sec = MEDIUM_AAAA_EXTRA;
                        }
                        else if (n_iface_4 == 0) {
                                extra.tv_sec = LONG_AAAA_EXTRA;
diff --git a/lookup.subproj/pwd.h b/lookup.subproj/pwd.h
new file mode 100644 (file)
index 0000000..d58d696
--- /dev/null
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ * Portions Copyright(C) 1995, Jason Downs.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)pwd.h       8.2 (Berkeley) 1/21/94
+ */
+/* Portions copyright (c) 2000-2011 Apple Inc. All rights reserved. */
+
+#ifndef _PWD_H_
+#define        _PWD_H_
+
+#include <_types.h>
+
+#ifndef _GID_T
+typedef __darwin_gid_t         gid_t;
+#define _GID_T
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef        __darwin_size_t         size_t;
+#endif
+
+#ifndef _UID_T
+typedef __darwin_uid_t         uid_t;
+#define _UID_T
+#endif
+
+#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
+#define        _PATH_PWD               "/etc"
+#define        _PATH_PASSWD            "/etc/passwd"
+#define        _PASSWD                 "passwd"
+#define        _PATH_MASTERPASSWD      "/etc/master.passwd"
+#define        _PATH_MASTERPASSWD_LOCK "/etc/ptmp"
+#define        _MASTERPASSWD           "master.passwd"
+
+#define        _PATH_MP_DB             "/etc/pwd.db"
+#define        _MP_DB                  "pwd.db"
+#define        _PATH_SMP_DB            "/etc/spwd.db"
+#define        _SMP_DB                 "spwd.db"
+
+#define        _PATH_PWD_MKDB          "/usr/sbin/pwd_mkdb"
+
+#define        _PW_KEYBYNAME           '1'     /* stored by name */
+#define        _PW_KEYBYNUM            '2'     /* stored by entry in the "file" */
+#define        _PW_KEYBYUID            '3'     /* stored by uid */
+
+#define        _PASSWORD_EFMT1         '_'     /* extended encryption format */
+
+#define        _PASSWORD_LEN           128     /* max length, not counting NULL */
+
+#define _PASSWORD_NOUID                0x01    /* flag for no specified uid. */
+#define _PASSWORD_NOGID                0x02    /* flag for no specified gid. */
+#define _PASSWORD_NOCHG                0x04    /* flag for no specified change. */
+#define _PASSWORD_NOEXP                0x08    /* flag for no specified expire. */
+
+#define _PASSWORD_WARNDAYS     14      /* days to warn about expiry */
+#define _PASSWORD_CHGNOW       -1      /* special day to force password
+                                        * change at next login */
+#endif
+
+struct passwd {
+       char    *pw_name;               /* user name */
+       char    *pw_passwd;             /* encrypted password */
+       uid_t   pw_uid;                 /* user uid */
+       gid_t   pw_gid;                 /* user gid */
+       __darwin_time_t pw_change;              /* password change time */
+       char    *pw_class;              /* user access class */
+       char    *pw_gecos;              /* Honeywell login info */
+       char    *pw_dir;                /* home directory */
+       char    *pw_shell;              /* default shell */
+       __darwin_time_t pw_expire;              /* account expiration */
+};
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+struct passwd  *getpwuid(uid_t);
+struct passwd  *getpwnam(const char *);
+int             getpwuid_r(uid_t, struct passwd *, char *, size_t, struct passwd **);
+int             getpwnam_r(const char *, struct passwd *, char *, size_t, struct passwd **);
+struct passwd  *getpwent(void);
+void            setpwent(void);
+void            endpwent(void);
+__END_DECLS
+
+#if (!defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)) || defined(_DARWIN_C_SOURCE)
+#include <uuid/uuid.h>
+__BEGIN_DECLS
+int             setpassent(int);
+char           *user_from_uid(uid_t, int);
+struct passwd  *getpwuuid(uuid_t);
+int             getpwuuid_r(uuid_t, struct passwd *, char *, size_t, struct passwd **);
+__END_DECLS
+#endif
+
+#endif /* !_PWD_H_ */
index 2b17317cacf348fc6f6e1455cb1f7875de3c605a..7d4f0ece349d791980d638e5efe84a2286663fc9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Apple Inc.  All rights reserved.
+ * Copyright (c) 2008-2011 Apple Inc.  All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -223,6 +223,37 @@ search_item_bynumber(si_mod_t *si, uint32_t number, int cat, si_item_t *(*call)(
        return NULL;
 }
 
+static si_item_t *
+search_item_byuuid(si_mod_t *si, uuid_t uuid, int cat, si_item_t *(*call)(si_mod_t *, uuid_t))
+{
+       int i;
+       search_si_private_t *pp;
+       si_item_t *item;
+       si_mod_t *src;
+
+       if (si == NULL) return NULL;
+       if (call == NULL) return NULL;
+
+       pp = (search_si_private_t *)si->private;
+       if (pp == NULL) return NULL;
+
+       i = 0;
+
+       while (NULL != (src = search_get_module(pp, cat, &i)))
+       {
+               item = call(src, uuid);
+               if (item != NULL)
+               {
+                       /*
+                        * N.B. item not added to cache, since the data does not
+                        * contain the uuid that was used to find it.
+                        */
+                       return item;
+               }
+       }
+
+       return NULL;
+}
 static si_list_t *
 search_list(si_mod_t *si, int cat, si_list_t *(*call)(si_mod_t *))
 {
@@ -280,6 +311,12 @@ search_user_byuid(si_mod_t *si, uid_t uid)
        return search_item_bynumber(si, (uint32_t)uid, CATEGORY_USER, si_user_byuid);
 }
 
+static si_item_t *
+search_user_byuuid(si_mod_t *si, uuid_t uuid)
+{
+       return search_item_byuuid(si, uuid, CATEGORY_USER, si_user_byuuid);
+}
+
 static si_list_t *
 search_user_all(si_mod_t *si)
 {
@@ -295,7 +332,13 @@ search_group_byname(si_mod_t *si, const char *name)
 static si_item_t *
 search_group_bygid(si_mod_t *si, gid_t gid)
 {
-       return search_item_bynumber(si, (uint32_t)gid, CATEGORY_USER, si_group_bygid);
+       return search_item_bynumber(si, (uint32_t)gid, CATEGORY_GROUP, si_group_bygid);
+}
+
+static si_item_t *
+search_group_byuuid(si_mod_t *si, uuid_t uuid)
+{
+       return search_item_byuuid(si, uuid, CATEGORY_GROUP, si_group_byuuid);
 }
 
 static si_list_t *
@@ -305,9 +348,30 @@ search_group_all(si_mod_t *si)
 }
 
 static si_item_t *
-search_groupist(si_mod_t *si, const char *name)
+search_groupist(si_mod_t *si, const char *name, uint32_t count)
 {
-       return search_item_byname(si, name, CATEGORY_GROUPLIST, si_grouplist);
+       int i;
+       search_si_private_t *pp;
+       si_item_t *item = NULL;
+       si_mod_t *src;
+       
+       if (si == NULL) return NULL;
+       
+       pp = (search_si_private_t *)si->private;
+       if (pp == NULL) return NULL;
+       
+       i = 0;
+       
+       while (NULL != (src = search_get_module(pp, CATEGORY_GROUPLIST, &i))) {
+               if (src == pp->cache) continue;
+               
+               if (src->vtable->sim_grouplist != NULL) {
+                       item = src->vtable->sim_grouplist(si, name, count);
+                       if (item != NULL) break;
+               }
+       }
+       
+       return item;
 }
 
 static si_list_t *
@@ -333,6 +397,7 @@ search_netgroup_byname(si_mod_t *si, const char *name)
        }
 
        i = 0;
+       null_res = 0;
 
        all = NULL;
        while (NULL != (src = search_get_module(pp, cat, &i)))
@@ -368,7 +433,6 @@ search_in_netgroup(si_mod_t *si, const char *group, const char *host, const char
 
        cat = CATEGORY_NETGROUP;
        i = 0;
-       innetgr = 0;
 
        while (NULL != (src = search_get_module(pp, cat, &i)))
        {
@@ -808,10 +872,12 @@ si_module_static_search(void)
 
                .sim_user_byname = &search_user_byname,
                .sim_user_byuid = &search_user_byuid,
+               .sim_user_byuuid = &search_user_byuuid,
                .sim_user_all = &search_user_all,
 
                .sim_group_byname = &search_group_byname,
                .sim_group_bygid = &search_group_bygid,
+               .sim_group_byuuid = &search_group_byuuid,
                .sim_group_all = &search_group_all,
 
                .sim_grouplist = &search_groupist,
@@ -897,20 +963,24 @@ si_module_static_search(void)
                si_module_config_modules_for_category(pp, CATEGORY_DEFAULT, count, modules);
                pp->cache = pp->search_list[CATEGORY_DEFAULT].module[0];
 
-               FILE *conf = fopen(_PATH_SI_CONF, "r");
-               errno = 0;
-               if (conf != NULL)
+               char *check = getenv("SYSINFO_CONF_ENABLE");
+               if ((check != NULL) && (!strcmp(check, "1")))
                {
-                       forever
+                       FILE *conf = fopen(_PATH_SI_CONF, "r");
+                       errno = 0;
+                       if (conf != NULL)
                        {
-                               char *line = _fsi_get_line(conf);
-                               if (line == NULL) break;
+                               forever
+                               {
+                                       char *line = _fsi_get_line(conf);
+                                       if (line == NULL) break;
 
-                               si_module_config_parse_line(pp, line);
-                               free(line);
-                       }
+                                       si_module_config_parse_line(pp, line);
+                                       free(line);
+                               }
 
-                       fclose(conf);
+                               fclose(conf);
+                       }
                }
        });
 
index f4bdabfadc33d6aa1bb2f9a7e3841de7c53f60f6..a0bbf51bfad70d7ac658a727b79a8209afe08209 100644 (file)
@@ -61,8 +61,8 @@ static uint32_t net_v4_count = 0;
 static uint32_t net_v6_count = 0;      // includes 6to4 addresses
 static pthread_mutex_t net_config_mutex = PTHREAD_MUTEX_INITIALIZER;
 
-// forward - temporary until we move this SPI to Libc
-int inet_aton_check(const char *cp, struct in_addr *addr, int strict);
+// Libc SPI
+int _inet_aton_check(const char *cp, struct in_addr *addr, int strict);
 
 typedef struct {
        struct hostent host;
@@ -648,7 +648,7 @@ _gai_numerichost(const char* nodename, uint32_t *family, int flags, struct in_ad
                if (numerichost == 0)
                {
                        /* inet_pton doesn't allow "a", "a.b", or "a.b.c" forms, so we re-check */
-                       numerichost = inet_aton_check(nodename, a4, 1);
+                       numerichost = _inet_aton_check(nodename, a4, 1);
                }
 
                if (numerichost == 1)
@@ -1662,180 +1662,3 @@ si_ipnode_byname(si_mod_t *si, const char *name, int family, int flags, const ch
 
        return item6;
 }
-
-// Temporary until we move this SPI to Libc
-
-/*
- * Copyright (c) 1983, 1990, 1993
- *    The Regents of the University of California.  All rights reserved.
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Portions Copyright (c) 1993 by Digital Equipment Corporation.
- * 
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies, and that
- * the name of Digital Equipment Corporation not be used in advertising or
- * publicity pertaining to distribution of the document or software without
- * specific, written prior permission.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
-
-/*
- * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
- * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*%
- * Check whether "cp" is a valid ascii representation
- * of an Internet address and convert to a binary address.
- * Returns 1 if the address is valid, 0 if not.
- * This replaces inet_addr, the return value from which
- * cannot distinguish between failure and a local broadcast address.
- */
-int
-inet_aton_check(const char *cp, struct in_addr *addr, int strict) {
-       u_long val;
-       int base, n;
-       char c;
-       u_int8_t parts[4];
-       u_int8_t *pp = parts;
-       int digit;
-       
-       c = *cp;
-       for (;;) {
-               /*
-                * Collect number up to ``.''.
-                * Values are specified as for C:
-                * 0x=hex, 0=octal, isdigit=decimal.
-                */
-               if (!isdigit((unsigned char)c))
-                       return (0);
-               val = 0; base = 10; digit = 0;
-               if (c == '0') {
-                       c = *++cp;
-                       if (c == 'x' || c == 'X')
-                               base = 16, c = *++cp;
-                       else {
-                               base = 8;
-                               digit = 1 ;
-                       }
-               }
-               for (;;) {
-                       if (isascii(c) && isdigit((unsigned char)c)) {
-                               if (base == 8 && (c == '8' || c == '9'))
-                                       return (0);
-                               val = (val * base) + (c - '0');
-                               c = *++cp;
-                               digit = 1;
-                       } else if (base == 16 && isascii(c) && 
-                                          isxdigit((unsigned char)c)) {
-                               val = (val << 4) |
-                               (c + 10 - (islower((unsigned char)c) ? 'a' : 'A'));
-                               c = *++cp;
-                               digit = 1;
-                       } else
-                               break;
-               }
-               if (c == '.') {
-                       /*
-                        * Internet format:
-                        *      a.b.c.d
-                        *      a.b.c   (with c treated as 16 bits)
-                        *      a.b     (with b treated as 24 bits)
-                        */
-                       if (pp >= parts + 3 || val > 0xffU)
-                               return (0);
-                       *pp++ = val;
-                       c = *++cp;
-               } else
-                       break;
-       }
-       /*
-        * Check for trailing characters.
-        */
-       if (c != '\0') {
-               if (strict) return (0);
-               if (!isascii(c) || !isspace(c)) return (0);
-       }
-       /*
-        * Did we get a valid digit?
-        */
-       if (!digit)
-               return (0);
-       /*
-        * Concoct the address according to
-        * the number of parts specified.
-        */
-       n = pp - parts + 1;
-       switch (n) {
-               case 1:                         /*%< a -- 32 bits */
-                       break;
-                       
-               case 2:                         /*%< a.b -- 8.24 bits */
-                       if (val > 0xffffffU)
-                               return (0);
-                       val |= parts[0] << 24;
-                       break;
-                       
-               case 3:                         /*%< a.b.c -- 8.8.16 bits */
-                       if (val > 0xffffU)
-                               return (0);
-                       val |= (parts[0] << 24) | (parts[1] << 16);
-                       break;
-                       
-               case 4:                         /*%< a.b.c.d -- 8.8.8.8 bits */
-                       if (val > 0xffU)
-                               return (0);
-                       val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
-                       break;
-       }
-       if (addr != NULL)
-               addr->s_addr = htonl(val);
-       return (1);
-}
index b0fc5870fc5b2e1cf5d62accce57bb520928de46..86c00164fa20c52c68600f657400eec255574f76 100644 (file)
@@ -32,7 +32,7 @@
 #include <pthread.h>
 #include <mach/mach.h>
 #include <dispatch/dispatch.h>
-
+#include <dispatch/private.h>
 #include "si_module.h"
 
 #define PLUGIN_DIR_PATH "/usr/lib/info"
@@ -521,6 +521,14 @@ si_user_byuid(si_mod_t *si, uid_t uid)
        return si->vtable->sim_user_byuid(si, uid);
 }
 
+si_item_t *
+si_user_byuuid(si_mod_t *si, uuid_t uuid)
+{
+       if (si == NULL) return NULL;
+       if (si->vtable->sim_user_byuuid == NULL) return NULL;
+       return si->vtable->sim_user_byuuid(si, uuid);
+}
+
 si_list_t *
 si_user_all(si_mod_t *si)
 {
@@ -545,6 +553,14 @@ si_group_bygid(si_mod_t *si, gid_t gid)
        return si->vtable->sim_group_bygid(si, gid);
 }
 
+si_item_t *
+si_group_byuuid(si_mod_t *si, uuid_t uuid)
+{
+       if (si == NULL) return NULL;
+       if (si->vtable->sim_group_byuuid == NULL) return NULL;
+       return si->vtable->sim_group_byuuid(si, uuid);
+}
+
 si_list_t *
 si_group_all(si_mod_t *si)
 {
@@ -554,11 +570,11 @@ si_group_all(si_mod_t *si)
 }
 
 si_item_t *
-si_grouplist(si_mod_t *si, const char *name)
+si_grouplist(si_mod_t *si, const char *name, uint32_t count)
 {
        if (si == NULL) return NULL;
        if (si->vtable->sim_grouplist == NULL) return NULL;
-       return si->vtable->sim_grouplist(si, name);
+       return si->vtable->sim_grouplist(si, name, count);
 }
 
 si_list_t *
@@ -772,7 +788,7 @@ si_item_call(struct si_mod_s *si, int call, const char *str1, const char *str2,
                case SI_CALL_USER_BYUID: return si_user_byuid(si, (uid_t)num1);
                case SI_CALL_GROUP_BYNAME: return si_group_byname(si, str1);
                case SI_CALL_GROUP_BYGID: return si_group_bygid(si, (gid_t)num1);
-               case SI_CALL_GROUPLIST: return si_grouplist(si, str1);
+               case SI_CALL_GROUPLIST: return si_grouplist(si, str1, (int) num1);
                case SI_CALL_ALIAS_BYNAME: return si_alias_byname(si, str1);
                case SI_CALL_HOST_BYNAME: return si_host_byname(si, str1, num1, str3, err);
                case SI_CALL_HOST_BYADDR: return si_host_byaddr(si, (void *)str1, num1, str3, err);
@@ -986,6 +1002,12 @@ si_async_workunit_release(si_async_workunit_t *r)
        if (r->str2 != NULL) free(r->str2);
        if (r->str3 != NULL) free(r->str3);
 
+       /* release send-once right if it has not been used */
+       if (r->send != MACH_PORT_NULL) mach_port_deallocate(mach_task_self(), r->send);
+
+       /* release receive right */
+       mach_port_mod_refs(mach_task_self(), r->port, MACH_PORT_RIGHT_RECEIVE, -1);
+
        free(r);
 }
 
@@ -1033,6 +1055,7 @@ si_async_launchpad(si_async_workunit_t *r)
 
        msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, MACH_MSGH_BITS_ZERO);
        msg.header.msgh_remote_port = r->send;
+       r->send = MACH_PORT_NULL;
        msg.header.msgh_local_port = MACH_PORT_NULL;
        msg.header.msgh_size = sizeof(mach_msg_empty_send_t);
        msg.header.msgh_id = r->call;
@@ -1101,7 +1124,7 @@ si_async_cancel(mach_port_t p)
 
        /*
         * Test and set the WORKUNIT_CANCELLED flag.
-        * If it was already set, this work item has been executed - too late to cancel.
+        * If it was already set, this work item has been executed - too late to really cancel.
         */
        if (OSAtomicTestAndSetBarrier(WORKUNIT_CANCELLED_BIT_ADDRESS, &(r->flags)) == 1)
        {
@@ -1109,7 +1132,6 @@ si_async_cancel(mach_port_t p)
 #ifdef CALL_TRACE
                fprintf(stderr, "** %s worklist item %p has executed\n", __func__, r);
 #endif
-               return;
        }
 
 #ifdef CALL_TRACE
@@ -1123,8 +1145,6 @@ si_async_cancel(mach_port_t p)
        }
 
        si_async_workunit_release(r);
-
-       mach_port_mod_refs(mach_task_self(), p, MACH_PORT_RIGHT_RECEIVE, -1);
 }
 
 void
@@ -1169,8 +1189,6 @@ si_async_handle_reply(mach_msg_header_t *msg)
        }
 
        si_async_workunit_release(r);
-
-       mach_port_mod_refs(mach_task_self(), reply, MACH_PORT_RIGHT_RECEIVE, -1);
 }
 
 char *
index 37635c097de3a66dd097906bda2946d5856233be..a87c6292b2108a83dfd1779757e4bdf4a18d0fbe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Apple Inc.  All rights reserved.
+ * Copyright (c) 2008-2011 Apple Inc.  All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -30,6 +30,7 @@
 #include <sys/socket.h>
 #include <pwd.h>
 #include <grp.h>
+#include <uuid/uuid.h>
 #include <netdb.h>
 #include <aliasdb.h>
 #include <fstab.h>
@@ -150,9 +151,9 @@ typedef void (*list_async_callback)(si_list_t *, uint32_t, void *);
 typedef struct grouplist_s
 {
        char *gl_user;
-       gid_t gl_basegid;
        int gl_count;
-       gid_t **gl_gid;
+       int gl_gid_siz;
+       gid_t *gl_gid;
 } si_grouplist_t;
 
 typedef struct addrinfo_s
@@ -211,13 +212,15 @@ struct si_mod_vtable_s
 
        si_item_t *(*sim_user_byname)(struct si_mod_s *si, const char *name);
        si_item_t *(*sim_user_byuid)(struct si_mod_s *si, uid_t uid);
+       si_item_t *(*sim_user_byuuid)(struct si_mod_s *si, uuid_t uuid);
        si_list_t *(*sim_user_all)(struct si_mod_s *si);
 
        si_item_t *(*sim_group_byname)(struct si_mod_s *si, const char *name);
        si_item_t *(*sim_group_bygid)(struct si_mod_s *si, gid_t gid);
+       si_item_t *(*sim_group_byuuid)(struct si_mod_s *si, uuid_t uuid);
        si_list_t *(*sim_group_all)(struct si_mod_s *si);
 
-       si_item_t *(*sim_grouplist)(struct si_mod_s *si, const char *name);
+       si_item_t *(*sim_grouplist)(struct si_mod_s *si, const char *name, uint32_t count);
 
        si_list_t *(*sim_netgroup_byname)(struct si_mod_s *si, const char *name);
        int (*sim_in_netgroup)(struct si_mod_s *si, const char *name, const char *host, const char *user, const char *domain);
@@ -296,13 +299,15 @@ int si_item_is_valid(si_item_t *item);
 
 si_item_t *si_user_byname(si_mod_t *si, const char *name);
 si_item_t *si_user_byuid(si_mod_t *si, uid_t uid);
+si_item_t *si_user_byuuid(si_mod_t *si, uuid_t uuid);
 si_list_t *si_user_all(si_mod_t *si);
 
 si_item_t *si_group_byname(si_mod_t *si, const char *name);
 si_item_t *si_group_bygid(si_mod_t *si, gid_t gid);
+si_item_t *si_group_byuuid(si_mod_t *si, uuid_t uuid);
 si_list_t *si_group_all(si_mod_t *si);
 
-si_item_t *si_grouplist(si_mod_t *si, const char *name);
+si_item_t *si_grouplist(si_mod_t *si, const char *name, uint32_t count);
 
 int si_in_netgroup(struct si_mod_s *si, const char *name, const char *host, const char *user, const char *domain);
 si_list_t *si_netgroup_byname(struct si_mod_s *si, const char *name);
index 5f947c3f49b5525dd45415f2bb3ad0eff7ffdb81..7467ad8bc2878487512b1ea3aa320e5a4984ed52 100644 (file)
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2005-2007 Apple Inc
+.\" Copyright (c) 2005-2011 Apple Inc
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
 .\" SUCH DAMAGE.
 .\"
 .\"
-.Dd February 3, 2005
+.Dd November 5, 2011
 .Dt MBR_CHECK_MEMBERSHIP 3
 .Os "Mac OS X"
 .Sh NAME
-.Nm mbr_check_membership
-.Nd check whether a user is a member of a group
+.Nm mbr_check_membership,
+.Nm mbr_check_service_membership
+.Nd check whether a user is a member of a group or service ACL
 .Sh SYNOPSIS
 .In membership.h
 .Ft int
 .Fn mbr_check_membership "uuid_t user" "uuid_t group" "int *ismember"
+.Ft int
+.Fn mbr_check_service_membership "uuid_t user" "const char *service" "int *ismember"
 .Sh DESCRIPTION
 .Fn mbr_check_membership
-tests if a given user is a member of a group, individually or as a member of a nested group.
+tests if a given user is a member of a group (either direct or indirect via a
+nested group).
 .Fa ismember
-is set to 1 if the user is a member of the group, and 0 otherwise.  
+is set to 1 if the user is a member or 0 if not a member of the group.  
+.Fn mbr_check_service_membership
+similarly tests if a given user is a member of a service ACL group.  Service
+ACLs are special groups defined with the prefix "com.apple.access_".  The
+service is then prefixed (e.g., "afp" would check "com.apple.access_afp").
+There is a special group that grants accessto all services called
+"com.apple.access_all_services".
 .Pp
 Users may belong to any number of groups.
 .Fn mbr_check_membership
-should be always be used to check group membership, rather than
-calling
-.Xr getgroups 2 ,
-and checking the returned list of gids.
+should always be used to check group membership, rather than calling
+.Xr getgroups 2
+or
+.Xr getgrouplist 2 .
 The
 .Xr setgroups 2
 and
@@ -65,29 +75,35 @@ uuid is equal to the reserved "everyone" uuid (ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000
 .Fa ismember
 will be set to 1 for any valid user.
 .Pp
-Group membership information is managed by the
-.Xr DirectoryService 8
-daemon.
+Group membership information is managed by
+.Xr opendirectoryd 8 .
 .Sh RETURN VALUES
 .Fn mbr_check_membership
-returns 0 on success.
-It returns EIO if it is unable to communicate with the
-.Xr DirectoryService 8
-daemon.
-ENOENT is returned if
-.Fa user
-cannot be found.
-.Pp
-Note that 
-.Fn mbr_check_membership
 does not test whether
 .Fa group
 exists or not.
 Querying membership for a nonexistent group will result in
 .Fa ismember
-being to 0 and a return value of 0.
+being set to 0.  The function returns 0 on success or one of the following error
+codes on failure:
+.Bl -tag -width Er
+.It Bq Er EIO
+Communication with
+.Xr openditectoryd 8
+failed.
+.It Bq Er ENOENT
+.Fa user
+can not be found.
+.El
+.Pp
+.Fn mbr_check_service_membership
+is identical to
+.Fn mbr_check_membership
+except that ENOENT means no service ACL has been defined.
+.Pp
 .Sh SEE ALSO
+.Xr odutil 1 ,
 .Xr setgroups 2 ,
 .Xr getgroups 2 ,
 .Xr mbr_uid_to_uuid 3 ,
-.Xr DirectoryService 8
+.Xr opendirectoryd 8
index a778aeade6fbb7ff5a2b4aa439028d4f9ac0e04b..9ca8ec9dab5784926da475df257ba8c25e6bff98 100644 (file)
@@ -26,7 +26,7 @@
 .\" SUCH DAMAGE.
 .\"
 .\"
-.Dd August 25, 2010
+.Dd October 10, 2011
 .Dt MBR_UID_TO_UUID 3
 .Os "Mac OS X"
 .Sh NAME
@@ -59,9 +59,8 @@ every user or group can be referenced by a 128 bit uuid.
 Additionally, if the user or group is hosted on a PDC
 or Active Directory server, it will have a 128 bit or larger sid.
 .Pp
-These routines communicate with the
-.Xr DirectoryService 8
-daemon.
+These routines communicate with
+.Xr openditectoryd 8 .
 .Pp
 .Fn mbr_uid_to_uuid
 takes a uid and looks up the associated user account.
@@ -109,23 +108,30 @@ The converted string is terminated with a nul character.
 .Fn mbr_string_to_sid
 converts an external string representation into a sid.
 .Sh RETURN VALUES
-These functions return 0 on success, or EIO if communications with the
-.Xr DirectoryService 8
-daemon fails.
-ENOENT is returned if the mapping can not be performed.
+These functions return 0 on success or one of the following error codes on failure:
+.Bl -tag -width Er
+.It Bq Er EIO
+Communication with
+.Xr openditectoryd 8
+failed.
+.It Bq Er ENOENT
+The mapping can not be performed.
+.It Bq Er EAUTH
+Communication with
+.Xr openditectoryd 8
+failed due to an authentication error.
+.It Bq Er EINVAL
+Invalid arguments were provided.
+.It Bq Er ENOMEM
+Insufficient storage space is available.
+.El
 .Pp
 .Fn mbr_gid_to_uuid
 and
 .Fn mbr_uid_to_uuid
 return 0 (success), even if the user/group does not exist.
-.Pp
-The 
-.Fn mbr_sid_to_string
-and 
-.Fn mbr_string_to_sid
-functions return 0 on success, or an errno value on failure.
 .Sh SEE ALSO
 .Xr getpwuid 3 ,
 .Xr getgrgid 3 ,
 .Xr mbr_check_membership 3 ,
-.Xr DirectoryService 8
\ No newline at end of file
+.Xr openditectoryd 8
index b2c980cece19f1c0bf2cd071d1eb3e73d841c8e5..80baf4afa0373c42ea33110f8d40281595100330 100644 (file)
 #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)
@@ -201,80 +315,38 @@ mbr_gid_to_uuid(gid_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
@@ -283,136 +355,49 @@ mbr_sid_to_uuid(const nt_sid_t *sid, uuid_t uu)
 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
@@ -438,44 +423,66 @@ mbr_uuid_to_sid(const uuid_t uu, nt_sid_t *sid)
 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
@@ -484,31 +491,15 @@ mbr_check_membership_refresh(const uuid_t user, uuid_t group, int *ismember)
 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
@@ -517,54 +508,42 @@ mbr_reset_cache()
 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
@@ -674,114 +653,47 @@ mbr_string_to_sid(const char *string, nt_sid_t *sid)
 #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
index ea724474f43625fb66fc8ac30ec45676872dfdca..193f8dd5561128b9e394017564ed40f89400648b 100644 (file)
 */
 #define ID_TYPE_GROUPNAME              5
 
+/*!
+       @defined        ID_TYPE_UUID
+       @abstract       is of type uuid_t
+       @discussion     is of type uuid_t
+*/
+#define ID_TYPE_UUID                   6
+
+/*!
+    @defined    ID_TYPE_GROUP_NFS
+    @abstract   is a NULL terminated UTF8 string
+    @discussion is a NULL terminated UTF8 string
+*/
+#define ID_TYPE_GROUP_NFS      7
+
+/*!
+    @defined    ID_TYPE_USER_NFS
+    @abstract   is a NULL terminated UTF8 string
+    @discussion is a NULL terminated UTF8 string
+*/
+#define ID_TYPE_USER_NFS               8
+
 /*!
        @defined    ID_TYPE_GSS_EXPORT_NAME
        @abstract       is a gss exported name
index 83abd35b699c8b8b6fa3ee4e3ec3a4d688a8f27c..ae5406690c8a08fbaa486e2e5f5ac7f40816a1ad 100644 (file)
 #define SID_TYPE_USER 0
 #define SID_TYPE_GROUP 1
 
+#define MBR_REC_TYPE_USER 1
+#define MBR_REC_TYPE_GROUP 2
+
+/* only supported by mbr_identifier_translate for target type */
+#define ID_TYPE_UID_OR_GID 30
+#define ID_TYPE_NAME 31
+
 __BEGIN_DECLS
 
 int mbr_reset_cache();
@@ -39,11 +46,24 @@ int mbr_user_name_to_uuid(const char *name, uuid_t uu);
 int mbr_group_name_to_uuid(const char *name, uuid_t uu);
 int mbr_check_membership_by_id(uuid_t user, gid_t group, int *ismember);
 int mbr_check_membership_refresh(const uuid_t user, uuid_t group, int *ismember);
-int mbr_uuid_to_string(const uuid_t uu, char *string);
-int mbr_string_to_uuid(const char *string, uuid_t uu);
+
+/* mbr_uuid_to_string should use uuid_unparse from uuid.h */
+int mbr_uuid_to_string(const uuid_t uu, char *string) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_8, __IPHONE_NA, __IPHONE_NA);
+
+/* mbr_string_to_uuid should use uuid_parse from uuid.h */
+int mbr_string_to_uuid(const char *string, uuid_t uu) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_8, __IPHONE_NA, __IPHONE_NA);
+
 int mbr_uuid_to_sid_type(const uuid_t uu, nt_sid_t *sid, int *id_type);
 int mbr_set_identifier_ttl(int id_type, const void *identifier, size_t identifier_size, unsigned int seconds);
 
+/* new SPI to allow translation from any-to-any type, pass ID_TYPE_UID_OR_GID when translating to a UID */
+int mbr_identifier_translate(int id_type, const void *identifier, size_t identifier_size, int target_type, void **result, int *rec_type);
+
+/* 
+ * groupid_type does not support ID_TYPE_GSS_EXPORT_NAME
+ */
+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);
+
 __END_DECLS
 
 #endif /* !_MEMBERSHIPPRIV_H_ */
index 75a44aa4dd2595ae344d56763dc11d9094910b85..d1b6522e19c0b14ecfb3050ed152492eec2c24c9 100644 (file)
@@ -119,8 +119,6 @@ clntraw_create(prog, vers)
 {
        register struct clntraw_private *clp = clntraw_private;
        struct rpc_msg call_msg;
-       XDR *xdrs = &clp->xdr_stream;
-       CLIENT *client = &clp->client_object;
 
        if (clp == 0) {
                clp = (struct clntraw_private *)calloc(1, sizeof (*clp));
@@ -128,6 +126,8 @@ clntraw_create(prog, vers)
                        return (0);
                clntraw_private = clp;
        }
+       XDR *xdrs = &clp->xdr_stream;
+       CLIENT *client = &clp->client_object;
        /*
         * pre-serialize the staic part of the call msg and stash it away
         */
index 0299d1d2772d90fee097d1fcacfce9ec1aaf0b9c..64532bd4059bdc1fcb7de38273c76f16809d9614 100644 (file)
@@ -260,7 +260,7 @@ rejected(rjct_stat, error)
 
        switch (rjct_stat) {
 
-       case RPC_VERSMISMATCH:
+       case RPC_MISMATCH:
                error->re_status = RPC_VERSMISMATCH;
                return;
 
index 4157e3fc39a691a42da72761245af6c047460e0b..9cae64335693b67ee96f9e213bc24ea1b37fbc50 100755 (executable)
@@ -23,8 +23,10 @@ InstallHeaders /usr/include \
        gen.subproj/ifaddrs.h \
        lookup.subproj/aliasdb.h \
        lookup.subproj/bootparams.h \
+       lookup.subproj/grp.h \
        lookup.subproj/netdb.h \
        lookup.subproj/printerdb.h \
+       lookup.subproj/pwd.h \
        membership.subproj/membership.h \
        membership.subproj/ntsid.h
 
@@ -206,6 +208,9 @@ LinkManPages mbr_uid_to_uuid.3 \
        mbr_gid_to_uuid.3 mbr_sid_to_uuid.3 mbr_uuid_to_id.3 mbr_uuid_to_sid.3 \
        mbr_sid_to_string.3 mbr_string_to_sid.3
 
+LinkManPages mbr_check_membership.3 \
+       mbr_check_service_membership.3
+
 LinkManPages getrpcent.3 \
        getrpcbyname.3 getrpcbynumber.3 endrpcent.3 setrpcent.3