| /* ldap.cc: Helper functions for ldap access to Active Directory. |
| |
| This file is part of Cygwin. |
| |
| This software is a copyrighted work licensed under the terms of the |
| Cygwin license. Please consult the file "CYGWIN_LICENSE" for |
| details. */ |
| |
| #include "winsup.h" |
| #include "ldap.h" |
| #include "cygerrno.h" |
| #include "security.h" |
| #include "path.h" |
| #include "fhandler.h" |
| #include "dtable.h" |
| #include "cygheap.h" |
| #include "registry.h" |
| #include "pinfo.h" |
| #include "lm.h" |
| #include "dsgetdc.h" |
| #include "tls_pbuf.h" |
| #include <sys/param.h> |
| |
| #define CYG_LDAP_ENUM_PAGESIZE 100 /* entries per page */ |
| |
| static PWCHAR rootdse_attr[] = |
| { |
| (PWCHAR) L"defaultNamingContext", |
| (PWCHAR) L"supportedCapabilities", |
| NULL |
| }; |
| |
| static const PCWSTR std_user_attr[] = |
| { |
| L"sAMAccountName", |
| L"objectSid", |
| L"primaryGroupID", |
| L"uidNumber", |
| L"cygwinUnixUid", /* TODO */ |
| /* windows scheme */ |
| L"displayName", |
| L"homeDrive", |
| L"homeDirectory", |
| /* cygwin scheme */ |
| L"cygwinGecos", |
| L"cygwinHome", |
| L"cygwinShell", |
| /* unix scheme */ |
| L"gecos", |
| L"unixHomeDirectory", |
| L"loginShell", |
| /* desc scheme */ |
| L"description" |
| }; |
| |
| static PWCHAR group_attr[] = |
| { |
| (PWCHAR) L"sAMAccountName", |
| (PWCHAR) L"objectSid", |
| (PWCHAR) L"gidNumber", |
| (PWCHAR) L"cygwinUnixGid", /* TODO */ |
| NULL |
| }; |
| |
| PWCHAR tdom_attr[] = |
| { |
| (PWCHAR) L"trustPosixOffset", |
| NULL |
| }; |
| |
| PWCHAR sid_attr[] = |
| { |
| (PWCHAR) L"objectSid", |
| NULL |
| }; |
| |
| PWCHAR rfc2307_uid_attr[] = |
| { |
| (PWCHAR) L"uid", |
| NULL |
| }; |
| |
| PWCHAR rfc2307_gid_attr[] = |
| { |
| (PWCHAR) L"cn", |
| NULL |
| }; |
| |
| /* ================================================================= */ |
| /* Helper method of cygheap_pwdgrp class. It sets the user attribs */ |
| /* from the settings in nsswitch.conf. */ |
| /* ================================================================= */ |
| |
| #define user_attr (cygheap->pg.ldap_user_attr) |
| |
| void |
| cygheap_pwdgrp::init_ldap_user_attr () |
| { |
| ldap_user_attr = (PWCHAR *) |
| ccalloc_abort (HEAP_BUF, sizeof (std_user_attr) / sizeof (*std_user_attr) |
| + 3 * NSS_SCHEME_MAX + 1, sizeof (PWCHAR)); |
| memcpy (ldap_user_attr, std_user_attr, sizeof (std_user_attr)); |
| uint16_t freeattr_idx = sizeof (std_user_attr) / sizeof (*std_user_attr); |
| for (uint16_t idx = 0; idx < NSS_SCHEME_MAX; ++idx) |
| { |
| if (home_scheme[idx].method == NSS_SCHEME_FREEATTR) |
| ldap_user_attr[freeattr_idx++] = home_scheme[idx].attrib; |
| if (shell_scheme[idx].method == NSS_SCHEME_FREEATTR) |
| ldap_user_attr[freeattr_idx++] = shell_scheme[idx].attrib; |
| if (gecos_scheme[idx].method == NSS_SCHEME_FREEATTR) |
| ldap_user_attr[freeattr_idx++] = gecos_scheme[idx].attrib; |
| } |
| } |
| |
| /* ================================================================= */ |
| /* Helper methods. */ |
| /* ================================================================= */ |
| |
| inline int |
| cyg_ldap::map_ldaperr_to_errno (ULONG lerr) |
| { |
| switch (lerr) |
| { |
| case LDAP_SUCCESS: |
| return NO_ERROR; |
| case LDAP_NO_RESULTS_RETURNED: |
| /* LdapMapErrorToWin32 maps LDAP_NO_RESULTS_RETURNED to ERROR_MORE_DATA, |
| which in turn is mapped to EMSGSIZE by geterrno_from_win_error. This |
| is SO wrong, especially considering that LDAP_MORE_RESULTS_TO_RETURN |
| is mapped to ERROR_MORE_DATA as well :-P */ |
| return ENMFILE; |
| default: |
| break; |
| } |
| return geterrno_from_win_error (LdapMapErrorToWin32 (lerr)); |
| } |
| |
| inline int |
| cyg_ldap::wait (cygthread *thr) |
| { |
| if (!thr) |
| return EIO; |
| if (cygwait (*thr, cw_infinite, cw_sig | cw_sig_restart) != WAIT_OBJECT_0) |
| { |
| thr->terminate_thread (); |
| return EIO; |
| } |
| thr->detach (); |
| return 0; |
| } |
| |
| /* ================================================================= */ |
| /* Helper struct and functions for interruptible LDAP initalization. */ |
| /* ================================================================= */ |
| |
| struct cyg_ldap_init { |
| cyg_ldap *that; |
| PCWSTR domain; |
| bool ssl; |
| ULONG ret; |
| }; |
| |
| ULONG |
| cyg_ldap::connect_ssl (PCWSTR domain) |
| { |
| ULONG ret; |
| |
| if (!(lh = ldap_sslinitW ((PWCHAR) domain, LDAP_SSL_PORT, 1))) |
| { |
| debug_printf ("ldap_init(%W) error 0x%02x", domain, LdapGetLastError ()); |
| return LdapGetLastError (); |
| } |
| if ((ret = ldap_bind_s (lh, NULL, NULL, LDAP_AUTH_NEGOTIATE)) != LDAP_SUCCESS) |
| debug_printf ("ldap_bind(%W) 0x%02x", domain, ret); |
| else if ((ret = ldap_search_sW (lh, NULL, LDAP_SCOPE_BASE, |
| (PWCHAR) L"(objectclass=*)", rootdse_attr, |
| 0, &msg)) |
| != LDAP_SUCCESS) |
| debug_printf ("ldap_search(%W, ROOTDSE) error 0x%02x", domain, ret); |
| return ret; |
| } |
| |
| ULONG |
| cyg_ldap::connect_non_ssl (PCWSTR domain) |
| { |
| ULONG ret; |
| |
| if (!(lh = ldap_initW ((PWCHAR) domain, LDAP_PORT))) |
| { |
| debug_printf ("ldap_init(%W) error 0x%02x", domain, LdapGetLastError ()); |
| return LdapGetLastError (); |
| } |
| if ((ret = ldap_set_option (lh, LDAP_OPT_SIGN, LDAP_OPT_ON)) |
| != LDAP_SUCCESS) |
| debug_printf ("ldap_set_option(LDAP_OPT_SIGN) error 0x%02x", ret); |
| if ((ret = ldap_set_option (lh, LDAP_OPT_ENCRYPT, LDAP_OPT_ON)) |
| != LDAP_SUCCESS) |
| debug_printf ("ldap_set_option(LDAP_OPT_ENCRYPT) error 0x%02x", ret); |
| if ((ret = ldap_bind_s (lh, NULL, NULL, LDAP_AUTH_NEGOTIATE)) != LDAP_SUCCESS) |
| debug_printf ("ldap_bind(%W) 0x%02x", domain, ret); |
| else if ((ret = ldap_search_sW (lh, NULL, LDAP_SCOPE_BASE, |
| (PWCHAR) L"(objectclass=*)", rootdse_attr, |
| 0, &msg)) |
| != LDAP_SUCCESS) |
| debug_printf ("ldap_search(%W, ROOTDSE) error 0x%02x", domain, ret); |
| return ret; |
| } |
| |
| static DWORD WINAPI |
| ldap_init_thr (LPVOID param) |
| { |
| cyg_ldap_init *cl = (cyg_ldap_init *) param; |
| cl->ret = cl->ssl ? cl->that->connect_ssl (cl->domain) |
| : cl->that->connect_non_ssl (cl->domain); |
| return 0; |
| } |
| |
| inline int |
| cyg_ldap::connect (PCWSTR domain) |
| { |
| /* FIXME? connect_ssl can take ages even when failing, so we're trying to |
| do everything the non-SSL (but still encrypted) way. */ |
| cyg_ldap_init cl = { this, domain, false, NO_ERROR }; |
| cygthread *thr = new cygthread (ldap_init_thr, &cl, "ldap_init"); |
| return wait (thr) ?: map_ldaperr_to_errno (cl.ret); |
| } |
| |
| /* ================================================================= */ |
| /* Helper struct and functions for interruptible LDAP search. */ |
| /* ================================================================= */ |
| |
| struct cyg_ldap_search { |
| cyg_ldap *that; |
| PWCHAR base; |
| ULONG scope; |
| PWCHAR filter; |
| PWCHAR *attrs; |
| ULONG ret; |
| }; |
| |
| ULONG |
| cyg_ldap::search_s (PWCHAR base, ULONG scope, PWCHAR filter, PWCHAR *attrs) |
| { |
| ULONG ret; |
| |
| if ((ret = ldap_search_sW (lh, base, scope, filter, attrs, 0, &msg)) |
| != LDAP_SUCCESS) |
| debug_printf ("ldap_search_sW(%W,%W) error 0x%02x", base, filter, ret); |
| return ret; |
| } |
| |
| static DWORD WINAPI |
| ldap_search_thr (LPVOID param) |
| { |
| cyg_ldap_search *cl = (cyg_ldap_search *) param; |
| cl->ret = cl->that->search_s (cl->base, cl->scope, cl->filter, cl->attrs); |
| return 0; |
| } |
| |
| inline int |
| cyg_ldap::search (PWCHAR base, ULONG scope, PWCHAR filter, PWCHAR *attrs) |
| { |
| cyg_ldap_search cl = { this, base, scope, filter, attrs, NO_ERROR }; |
| cygthread *thr = new cygthread (ldap_search_thr, &cl, "ldap_search"); |
| return wait (thr) ?: map_ldaperr_to_errno (cl.ret); |
| } |
| |
| /* ================================================================= */ |
| /* Helper struct and functions for interruptible LDAP page search. */ |
| /* ================================================================= */ |
| |
| struct cyg_ldap_next_page { |
| cyg_ldap *that; |
| ULONG ret; |
| }; |
| |
| ULONG |
| cyg_ldap::next_page_s () |
| { |
| ULONG total; |
| ULONG ret; |
| |
| do |
| { |
| ret = ldap_get_next_page_s (lh, srch_id, NULL, CYG_LDAP_ENUM_PAGESIZE, |
| &total, &msg); |
| } |
| while (ret == LDAP_SUCCESS && ldap_count_entries (lh, msg) == 0); |
| if (ret && ret != LDAP_NO_RESULTS_RETURNED) |
| debug_printf ("ldap_result() error 0x%02x", ret); |
| return ret; |
| } |
| |
| static DWORD WINAPI |
| ldap_next_page_thr (LPVOID param) |
| { |
| cyg_ldap_next_page *cl = (cyg_ldap_next_page *) param; |
| cl->ret = cl->that->next_page_s (); |
| return 0; |
| } |
| |
| inline int |
| cyg_ldap::next_page () |
| { |
| cyg_ldap_next_page cl = { this, NO_ERROR }; |
| cygthread *thr = new cygthread (ldap_next_page_thr, &cl, "ldap_next_page"); |
| return wait (thr) ?: map_ldaperr_to_errno (cl.ret); |
| } |
| |
| /* ================================================================= */ |
| /* Public methods. */ |
| /* ================================================================= */ |
| |
| int |
| cyg_ldap::open (PCWSTR domain) |
| { |
| int ret = NO_ERROR; |
| |
| /* Already open? */ |
| if (lh) |
| return NO_ERROR; |
| |
| if ((ret = connect (domain)) != NO_ERROR) |
| goto err; |
| /* Prime `ret' and fetch ROOTDSE search result. */ |
| ret = EIO; |
| if (!(entry = ldap_first_entry (lh, msg))) |
| { |
| debug_printf ("No ROOTDSE entry for %W", domain); |
| goto err; |
| } |
| if (!(val = ldap_get_valuesW (lh, entry, rootdse_attr[0]))) |
| { |
| debug_printf ("No %W value for %W", rootdse_attr[0], domain); |
| goto err; |
| } |
| if (!(def_context = wcsdup (val[0]))) |
| { |
| debug_printf ("wcsdup(%W, %W) %d", domain, rootdse_attr[0], |
| get_errno ()); |
| goto err; |
| } |
| ldap_value_freeW (val); |
| if ((val = ldap_get_valuesW (lh, entry, rootdse_attr[1]))) |
| { |
| for (ULONG idx = 0; idx < ldap_count_valuesW (val); ++idx) |
| if (!wcscmp (val[idx], LDAP_CAP_ACTIVE_DIRECTORY_OID_W)) |
| { |
| isAD = true; |
| break; |
| } |
| } |
| ldap_value_freeW (val); |
| val = NULL; |
| ldap_msgfree (msg); |
| msg = entry = NULL; |
| return NO_ERROR; |
| err: |
| close (); |
| return ret; |
| } |
| |
| void |
| cyg_ldap::close () |
| { |
| if (srch_id != NULL) |
| ldap_search_abandon_page (lh, srch_id); |
| if (lh) |
| ldap_unbind (lh); |
| if (msg) |
| ldap_msgfree (msg); |
| if (val) |
| ldap_value_freeW (val); |
| if (def_context) |
| free (def_context); |
| lh = NULL; |
| msg = entry = NULL; |
| val = NULL; |
| def_context = NULL; |
| srch_id = NULL; |
| last_fetched_sid = NO_SID; |
| } |
| |
| PWCHAR |
| cyg_ldap::get_string_attribute (PCWSTR name) |
| { |
| if (val) |
| ldap_value_freeW (val); |
| val = ldap_get_valuesW (lh, entry, (PWCHAR) name); |
| if (val) |
| return val[0]; |
| return NULL; |
| } |
| |
| uint32_t |
| cyg_ldap::get_num_attribute (PCWSTR name) |
| { |
| PWCHAR ret = get_string_attribute (name); |
| if (ret) |
| return (uint32_t) wcstoul (ret, NULL, 10); |
| return (uint32_t) -1; |
| } |
| |
| #define ACCOUNT_FILTER_START L"(&(|(&(objectCategory=Person)" \ |
| "(objectClass=User))" \ |
| "(objectClass=Group))" \ |
| "(objectSid=" |
| |
| #define ACCOUNT_FILTER_END L"))" |
| |
| bool |
| cyg_ldap::fetch_ad_account (PSID sid, bool group, PCWSTR domain) |
| { |
| WCHAR filter[sizeof (ACCOUNT_FILTER_START) + sizeof (ACCOUNT_FILTER_END) |
| + 3 * SECURITY_MAX_SID_SIZE + 1]; |
| PWCHAR f, base = NULL; |
| LONG len = (LONG) RtlLengthSid (sid); |
| PBYTE s = (PBYTE) sid; |
| static WCHAR hex_wchars[] = L"0123456789abcdef"; |
| tmp_pathbuf tp; |
| |
| if (last_fetched_sid == sid) |
| return true; |
| |
| if (open (NULL) != NO_ERROR) |
| return false; |
| |
| if (msg) |
| { |
| ldap_msgfree (msg); |
| msg = entry = NULL; |
| } |
| if (val) |
| { |
| ldap_value_freeW (val); |
| val = NULL; |
| } |
| f = wcpcpy (filter, ACCOUNT_FILTER_START); |
| while (len-- > 0) |
| { |
| *f++ = L'\\'; |
| *f++ = hex_wchars[*s >> 4]; |
| *f++ = hex_wchars[*s++ & 0xf]; |
| } |
| wcpcpy (f, ACCOUNT_FILTER_END); |
| if (domain) |
| { |
| /* FIXME: This is a hack. The most correct solution is probably to |
| open a connection to the DC of the trusted domain. But this always |
| takes extra time, so we're trying to avoid it. If this results in |
| problems, we know what to do. */ |
| base = tp.w_get (); |
| PWCHAR b = base; |
| for (PWCHAR dotp = (PWCHAR) domain; dotp && *dotp; domain = dotp) |
| { |
| dotp = wcschr (domain, L'.'); |
| if (dotp) |
| *dotp++ = L'\0'; |
| if (b > base) |
| *b++ = L','; |
| b = wcpcpy (b, L"DC="); |
| b = wcpcpy (b, domain); |
| } |
| } |
| else |
| { |
| /* def_context is only valid after open. */ |
| base = def_context; |
| } |
| if (!user_attr) |
| cygheap->pg.init_ldap_user_attr (); |
| attr = group ? group_attr : user_attr; |
| if (search (base, LDAP_SCOPE_SUBTREE, filter, attr) != 0) |
| return false; |
| if (!(entry = ldap_first_entry (lh, msg))) |
| { |
| debug_printf ("No entry for %W in base %W", filter, base); |
| return false; |
| } |
| last_fetched_sid = sid; |
| return true; |
| } |
| |
| int |
| cyg_ldap::enumerate_ad_accounts (PCWSTR domain, bool group) |
| { |
| int ret; |
| tmp_pathbuf tp; |
| PCWSTR filter; |
| |
| close (); |
| if ((ret = open (domain)) != NO_ERROR) |
| return ret; |
| |
| if (!group) |
| filter = L"(&(objectCategory=Person)" |
| "(objectClass=User)" |
| /* 512 == ADS_UF_NORMAL_ACCOUNT |
| Without checking this flag we'd enumerate undesired accounts |
| like, e.g., interdomain trusts. */ |
| "(userAccountControl:" LDAP_MATCHING_RULE_BIT_AND ":=512)" |
| "(objectSid=*))"; |
| else if (!domain) |
| /* From the local domain, we fetch well-known groups. */ |
| filter = L"(&(objectClass=Group)" |
| "(objectSid=*))"; |
| else |
| /* From foreign domains, we don't. */ |
| filter = L"(&(objectClass=Group)" |
| /* 1 == BUILTIN_LOCAL_GROUP */ |
| "(!(groupType:" LDAP_MATCHING_RULE_BIT_AND ":=1))" |
| "(objectSid=*))"; |
| if (!user_attr) |
| cygheap->pg.init_ldap_user_attr (); |
| attr = group ? group_attr : user_attr; |
| srch_id = ldap_search_init_pageW (lh, def_context, LDAP_SCOPE_SUBTREE, |
| (PWCHAR) filter, attr, 0, NULL, NULL, |
| INFINITE, CYG_LDAP_ENUM_PAGESIZE, NULL); |
| if (srch_id == NULL) |
| { |
| debug_printf ("ldap_search_init_pageW(%W,%W) error 0x%02x", |
| def_context, filter, LdapGetLastError ()); |
| return map_ldaperr_to_errno (LdapGetLastError ()); |
| } |
| return NO_ERROR; |
| } |
| |
| int |
| cyg_ldap::next_account (cygsid &sid) |
| { |
| ULONG ret; |
| PLDAP_BERVAL *bval; |
| |
| if (entry) |
| { |
| if ((entry = ldap_next_entry (lh, entry)) |
| && (bval = ldap_get_values_lenW (lh, entry, (PWCHAR) L"objectSid"))) |
| { |
| last_fetched_sid = sid = (PSID) bval[0]->bv_val; |
| ldap_value_free_len (bval); |
| return NO_ERROR; |
| } |
| ldap_msgfree (msg); |
| msg = entry = NULL; |
| } |
| ret = next_page (); |
| if (ret == NO_ERROR) |
| { |
| if ((entry = ldap_first_entry (lh, msg)) |
| && (bval = ldap_get_values_lenW (lh, entry, (PWCHAR) L"objectSid"))) |
| { |
| last_fetched_sid = sid = (PSID) bval[0]->bv_val; |
| ldap_value_free_len (bval); |
| return NO_ERROR; |
| } |
| ret = EIO; |
| } |
| ldap_search_abandon_page (lh, srch_id); |
| srch_id = NULL; |
| return ret; |
| } |
| |
| #define SYSTEM_CONTAINER L"CN=System," |
| |
| #define PSX_OFFSET_FILTER L"(&(objectClass=trustedDomain)(name=%W))" |
| #define PSX_OFFSET_FILTER_FLAT L"(&(objectClass=trustedDomain)(flatName=%W))" |
| |
| /* Return UINT32_MAX on error to allow differing between not being able |
| to fetch a value and a real 0 offset. */ |
| uint32_t |
| cyg_ldap::fetch_posix_offset_for_domain (PCWSTR domain) |
| { |
| WCHAR base[wcslen (def_context) + sizeof (SYSTEM_CONTAINER) / sizeof (WCHAR)]; |
| WCHAR filter[sizeof (PSX_OFFSET_FILTER_FLAT) + wcslen (domain) + 1]; |
| |
| if (msg) |
| { |
| ldap_msgfree (msg); |
| msg = entry = NULL; |
| } |
| if (val) |
| { |
| ldap_value_freeW (val); |
| val = NULL; |
| } |
| /* As base, use system container within default naming context to restrict |
| the search to this container only. */ |
| wcpcpy (wcpcpy (base, SYSTEM_CONTAINER), def_context); |
| /* If domain name has no dot, it's a Netbios name. In that case, filter |
| by flatName rather than by name. */ |
| __small_swprintf (filter, wcschr (domain, L'.') ? PSX_OFFSET_FILTER |
| : PSX_OFFSET_FILTER_FLAT, |
| domain); |
| if (search (base, LDAP_SCOPE_ONELEVEL, filter, attr = tdom_attr) != 0) |
| return UINT32_MAX; |
| if (!(entry = ldap_first_entry (lh, msg))) |
| { |
| debug_printf ("No entry for %W in def_context %W", filter, def_context); |
| return UINT32_MAX; |
| } |
| return get_num_attribute (tdom_attr[0]); |
| } |
| |
| #define UXID_FILTER_GRP L"(&(objectClass=Group)" \ |
| "(gidNumber=%u))" |
| |
| #define UXID_FILTER_USR L"(&(objectCategory=Person)" \ |
| "(objectClass=User)" \ |
| "(uidNumber=%u))" |
| |
| bool |
| cyg_ldap::fetch_unix_sid_from_ad (uint32_t id, cygsid &sid, bool group) |
| { |
| WCHAR filter[MAX (sizeof (UXID_FILTER_GRP), sizeof (UXID_FILTER_USR)) + 16]; |
| PLDAP_BERVAL *bval; |
| |
| if (msg) |
| { |
| ldap_msgfree (msg); |
| msg = entry = NULL; |
| } |
| __small_swprintf (filter, group ? UXID_FILTER_GRP : UXID_FILTER_USR, id); |
| if (search (def_context, LDAP_SCOPE_SUBTREE, filter, sid_attr) != 0) |
| return false; |
| if ((entry = ldap_first_entry (lh, msg)) |
| && (bval = ldap_get_values_lenW (lh, entry, (PWCHAR) L"objectSid"))) |
| { |
| sid = (PSID) bval[0]->bv_val; |
| ldap_value_free_len (bval); |
| return true; |
| } |
| return false; |
| } |
| |
| #define PSXID_FILTER_GRP L"(&(objectClass=posixGroup)" \ |
| "(gidNumber=%u))" |
| |
| #define PSXID_FILTER_USR L"(&(objectClass=posixAccount)" \ |
| "(uidNumber=%u))" |
| |
| PWCHAR |
| cyg_ldap::fetch_unix_name_from_rfc2307 (uint32_t id, bool group) |
| { |
| WCHAR filter[MAX (sizeof (PSXID_FILTER_GRP), sizeof (PSXID_FILTER_USR)) + 16]; |
| |
| if (msg) |
| { |
| ldap_msgfree (msg); |
| msg = entry = NULL; |
| } |
| if (val) |
| { |
| ldap_value_freeW (val); |
| val = NULL; |
| } |
| attr = group ? rfc2307_gid_attr : rfc2307_uid_attr; |
| __small_swprintf (filter, group ? PSXID_FILTER_GRP : PSXID_FILTER_USR, id); |
| if (search (def_context, LDAP_SCOPE_SUBTREE, filter, attr) != 0) |
| return NULL; |
| if (!(entry = ldap_first_entry (lh, msg))) |
| { |
| debug_printf ("No entry for %W in def_context %W", filter, def_context); |
| return NULL; |
| } |
| return get_string_attribute (attr[0]); |
| } |
| |
| uid_t |
| cyg_ldap::remap_uid (uid_t uid) |
| { |
| cygsid user (NO_SID); |
| PWCHAR name; |
| struct passwd *pw; |
| |
| if (isAD) |
| { |
| if (fetch_unix_sid_from_ad (uid, user, false) |
| && user != NO_SID |
| && (pw = internal_getpwsid (user, this))) |
| return pw->pw_uid; |
| } |
| else if ((name = fetch_unix_name_from_rfc2307 (uid, false))) |
| { |
| char *mbname = NULL; |
| sys_wcstombs_alloc (&mbname, HEAP_NOTHEAP, name); |
| if ((pw = internal_getpwnam (mbname))) |
| return pw->pw_uid; |
| } |
| return ILLEGAL_UID; |
| } |
| |
| gid_t |
| cyg_ldap::remap_gid (gid_t gid) |
| { |
| cygsid group (NO_SID); |
| PWCHAR name; |
| struct group *gr; |
| |
| if (isAD) |
| { |
| if (fetch_unix_sid_from_ad (gid, group, true) |
| && group != NO_SID |
| && (gr = internal_getgrsid (group, this))) |
| return gr->gr_gid; |
| } |
| else if ((name = fetch_unix_name_from_rfc2307 (gid, true))) |
| { |
| char *mbname = NULL; |
| sys_wcstombs_alloc (&mbname, HEAP_NOTHEAP, name); |
| if ((gr = internal_getgrnam (mbname))) |
| return gr->gr_gid; |
| } |
| return ILLEGAL_GID; |
| } |