From d31dd04957f1ca04d2fb85a1de4cdac475b6803c Mon Sep 17 00:00:00 2001 From: Apple Date: Fri, 30 Mar 2012 23:25:31 +0000 Subject: [PATCH] Libinfo-406.17.tar.gz --- Libinfo.xcodeproj/project.pbxproj | 21 +- gen.subproj/gethostbyname.3 | 4 +- gen.subproj/getnetent.3 | 2 +- lookup.subproj/cache_module.c | 6 +- lookup.subproj/ds_module.c | 2535 +++++++-------------- lookup.subproj/file_module.c | 68 +- lookup.subproj/getgrent.3 | 88 +- lookup.subproj/getpwent.3 | 118 +- lookup.subproj/grp.h | 104 + lookup.subproj/libinfo.c | 300 ++- lookup.subproj/mdns_module.c | 6 +- lookup.subproj/pwd.h | 131 ++ lookup.subproj/search_module.c | 100 +- lookup.subproj/si_getaddrinfo.c | 183 +- lookup.subproj/si_module.c | 38 +- lookup.subproj/si_module.h | 15 +- membership.subproj/mbr_check_membership.3 | 66 +- membership.subproj/mbr_uid_to_uuid.3 | 36 +- membership.subproj/membership.c | 882 ++++--- membership.subproj/membership.h | 21 + membership.subproj/membershipPriv.h | 24 +- rpc.subproj/clnt_raw.c | 4 +- rpc.subproj/rpc_prot.c | 2 +- xcodescripts/install_files.sh | 5 + 24 files changed, 2053 insertions(+), 2706 deletions(-) create mode 100644 lookup.subproj/grp.h create mode 100644 lookup.subproj/pwd.h diff --git a/Libinfo.xcodeproj/project.pbxproj b/Libinfo.xcodeproj/project.pbxproj index d633498..112788a 100644 --- a/Libinfo.xcodeproj/project.pbxproj +++ b/Libinfo.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 45; + objectVersion = 46; objects = { /* Begin PBXBuildFile section */ @@ -221,8 +221,6 @@ 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 */ @@ -424,9 +422,9 @@ FC5284BE11478C200058CCB0 /* rcmd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rcmd.c; sourceTree = ""; }; FC5284BF11478C200058CCB0 /* rcmdsh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rcmdsh.c; sourceTree = ""; }; 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 = ""; }; + FCFDBF0A145CC5C100A39A66 /* grp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = grp.h; sourceTree = ""; }; + FCFDBF0B145CC5C100A39A66 /* pwd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pwd.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -529,7 +527,6 @@ children = ( 2D4070B0129354A700FE81ED /* getnameinfo_link.c */, FC5285D1114791B50058CCB0 /* DSlibinfoMIG.defs */, - FC5285D2114791B50058CCB0 /* DSlibinfoMIGAsyncReply.defs */, FC52841811478C200058CCB0 /* aliasdb.h */, FC52841911478C200058CCB0 /* bootparams.5 */, FC52841A11478C200058CCB0 /* bootparams.h */, @@ -544,6 +541,7 @@ FC52842311478C200058CCB0 /* getnameinfo.3 */, FC52842411478C200058CCB0 /* getnetgrent.3 */, FC52842511478C200058CCB0 /* getpwent.3 */, + FCFDBF0A145CC5C100A39A66 /* grp.h */, FC52842611478C200058CCB0 /* ils.c */, FC52842711478C200058CCB0 /* ils.h */, FC52842811478C200058CCB0 /* initgroups.3 */, @@ -555,6 +553,7 @@ 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 */, @@ -570,7 +569,6 @@ FC52843A11478C200058CCB0 /* membership.subproj */ = { isa = PBXGroup; children = ( - FC5285D3114791B50058CCB0 /* DSmemberdMIG.defs */, FC52843C11478C200058CCB0 /* mbr_check_membership.3 */, FC52843D11478C200058CCB0 /* mbr_uid_to_uuid.3 */, FC52843E11478C200058CCB0 /* membership.c */, @@ -768,8 +766,11 @@ /* 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 = ( @@ -1043,8 +1044,6 @@ 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 */, @@ -1076,6 +1075,7 @@ ); 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 = __; @@ -1099,7 +1099,6 @@ 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"; }; diff --git a/gen.subproj/gethostbyname.3 b/gen.subproj/gethostbyname.3 index 8737a10..7c85286 100644 --- a/gen.subproj/gethostbyname.3 +++ b/gen.subproj/gethostbyname.3 @@ -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 diff --git a/gen.subproj/getnetent.3 b/gen.subproj/getnetent.3 index 5e34499..55723c3 100644 --- a/gen.subproj/getnetent.3 +++ b/gen.subproj/getnetent.3 @@ -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 diff --git a/lookup.subproj/cache_module.c b/lookup.subproj/cache_module.c index 6a55ee1..5a39a1b 100644 --- a/lookup.subproj/cache_module.c +++ b/lookup.subproj/cache_module.c @@ -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, diff --git a/lookup.subproj/ds_module.c b/lookup.subproj/ds_module.c index 3c4e3e4..65ff3a8 100644 --- a/lookup.subproj/ds_module.c +++ b/lookup.subproj/ds_module.c @@ -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@ * @@ -21,14 +21,6 @@ * @APPLE_LICENSE_HEADER_END@ */ -#include - -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 @@ -39,8 +31,8 @@ libinfoDSmig_do_Response_async(mach_port_t server, char *reply, mach_msg_type_nu #include #include #include +#include #include -#include "kvbuf.h" #include #include #include @@ -51,90 +43,82 @@ libinfoDSmig_do_Response_async(mach_port_t server, char *reply, mach_msg_type_nu #include #include #include +#include +#include +#include #include #include -#include "DSlibinfoMIG.h" -#include "DSmemberdMIG.h" +#include #ifdef DEBUG #include #endif -#define SOCK_UNSPEC 0 -#define IPPROTO_UNSPEC 0 +#ifdef __i386__ +/* */ +__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)); } diff --git a/lookup.subproj/file_module.c b/lookup.subproj/file_module.c index 7db0b89..bf332f8 100644 --- a/lookup.subproj/file_module.c +++ b/lookup.subproj/file_module.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -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, diff --git a/lookup.subproj/getgrent.3 b/lookup.subproj/getgrent.3 index 2a2920c..adad337 100644 --- a/lookup.subproj/getgrent.3 +++ b/lookup.subproj/getgrent.3 @@ -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 @@ -59,6 +62,10 @@ .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 . diff --git a/lookup.subproj/getpwent.3 b/lookup.subproj/getpwent.3 index 75c99c3..14bf4c1 100644 --- a/lookup.subproj/getpwent.3 +++ b/lookup.subproj/getpwent.3 @@ -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 @@ -60,6 +63,10 @@ .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 @@ -69,12 +76,12 @@ 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 +#include +#include +#include +#include + +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 index 0000000..76a8efc --- /dev/null +++ b/lookup.subproj/grp.h @@ -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 + +__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 +__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_ */ diff --git a/lookup.subproj/libinfo.c b/lookup.subproj/libinfo.c index 0f5f2e2..7a9628e 100644 --- a/lookup.subproj/libinfo.c +++ b/lookup.subproj/libinfo.c @@ -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 #include #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include #include "netdb_async.h" +#include #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 * diff --git a/lookup.subproj/mdns_module.c b/lookup.subproj/mdns_module.c index 7f23aad..27a907f 100644 --- a/lookup.subproj/mdns_module.c +++ b/lookup.subproj/mdns_module.c @@ -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 index 0000000..d58d696 --- /dev/null +++ b/lookup.subproj/pwd.h @@ -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 + +__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 +__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_ */ diff --git a/lookup.subproj/search_module.c b/lookup.subproj/search_module.c index 2b17317..7d4f0ec 100644 --- a/lookup.subproj/search_module.c +++ b/lookup.subproj/search_module.c @@ -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); + } } }); diff --git a/lookup.subproj/si_getaddrinfo.c b/lookup.subproj/si_getaddrinfo.c index f4bdabf..a0bbf51 100644 --- a/lookup.subproj/si_getaddrinfo.c +++ b/lookup.subproj/si_getaddrinfo.c @@ -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); -} diff --git a/lookup.subproj/si_module.c b/lookup.subproj/si_module.c index b0fc587..86c0016 100644 --- a/lookup.subproj/si_module.c +++ b/lookup.subproj/si_module.c @@ -32,7 +32,7 @@ #include #include #include - +#include #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 * diff --git a/lookup.subproj/si_module.h b/lookup.subproj/si_module.h index 37635c0..a87c629 100644 --- a/lookup.subproj/si_module.h +++ b/lookup.subproj/si_module.h @@ -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 #include #include +#include #include #include #include @@ -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); diff --git a/membership.subproj/mbr_check_membership.3 b/membership.subproj/mbr_check_membership.3 index 5f947c3..7467ad8 100644 --- a/membership.subproj/mbr_check_membership.3 +++ b/membership.subproj/mbr_check_membership.3 @@ -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 @@ -26,28 +26,38 @@ .\" 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 diff --git a/membership.subproj/mbr_uid_to_uuid.3 b/membership.subproj/mbr_uid_to_uuid.3 index a778aea..9ca8ec9 100644 --- a/membership.subproj/mbr_uid_to_uuid.3 +++ b/membership.subproj/mbr_uid_to_uuid.3 @@ -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 diff --git a/membership.subproj/membership.c b/membership.subproj/membership.c index b2c980c..80baf4a 100644 --- a/membership.subproj/membership.c +++ b/membership.subproj/membership.c @@ -28,163 +28,277 @@ #include #include #ifdef DS_AVAILABLE -#include "DSmemberdMIG.h" -#endif +#include +#include +#include +#include -#ifdef DS_AVAILABLE -extern mach_port_t _mbr_port; -extern int _ds_running(void); +#ifdef __i386__ +/* */ +__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 diff --git a/membership.subproj/membership.h b/membership.subproj/membership.h index ea72447..193f8dd 100644 --- a/membership.subproj/membership.h +++ b/membership.subproj/membership.h @@ -61,6 +61,27 @@ */ #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 diff --git a/membership.subproj/membershipPriv.h b/membership.subproj/membershipPriv.h index 83abd35..ae54066 100644 --- a/membership.subproj/membershipPriv.h +++ b/membership.subproj/membershipPriv.h @@ -32,6 +32,13 @@ #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_ */ diff --git a/rpc.subproj/clnt_raw.c b/rpc.subproj/clnt_raw.c index 75a44aa..d1b6522 100644 --- a/rpc.subproj/clnt_raw.c +++ b/rpc.subproj/clnt_raw.c @@ -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 */ diff --git a/rpc.subproj/rpc_prot.c b/rpc.subproj/rpc_prot.c index 0299d1d..64532bd 100644 --- a/rpc.subproj/rpc_prot.c +++ b/rpc.subproj/rpc_prot.c @@ -260,7 +260,7 @@ rejected(rjct_stat, error) switch (rjct_stat) { - case RPC_VERSMISMATCH: + case RPC_MISMATCH: error->re_status = RPC_VERSMISMATCH; return; diff --git a/xcodescripts/install_files.sh b/xcodescripts/install_files.sh index 4157e3f..9cae643 100755 --- a/xcodescripts/install_files.sh +++ b/xcodescripts/install_files.sh @@ -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 -- 2.45.2