+ return posix_cred_get(cred)->cr_gid;
+}
+
+
+/*
+ * kauth_cred_getrgid
+ *
+ * Description: Fetch RGID from credential
+ *
+ * Parameters: cred Credential to examine
+ *
+ * Returns: (gid_t) RGID associated with credential
+ */
+gid_t
+kauth_cred_getrgid(kauth_cred_t cred)
+{
+ NULLCRED_CHECK(cred);
+ return posix_cred_get(cred)->cr_rgid;
+}
+
+
+/*
+ * kauth_cred_getsvgid
+ *
+ * Description: Fetch SVGID from credential
+ *
+ * Parameters: cred Credential to examine
+ *
+ * Returns: (gid_t) SVGID associated with credential
+ */
+gid_t
+kauth_cred_getsvgid(kauth_cred_t cred)
+{
+ NULLCRED_CHECK(cred);
+ return posix_cred_get(cred)->cr_svgid;
+}
+
+
+static int kauth_cred_cache_lookup(int from, int to, void *src, void *dst);
+
+#if CONFIG_EXT_RESOLVER == 0
+/*
+ * If there's no resolver, only support a subset of the kauth_cred_x2y() lookups.
+ */
+static __inline int
+kauth_cred_cache_lookup(int from, int to, void *src, void *dst)
+{
+ /* NB: These must match the definitions used by Libinfo's mbr_identifier_translate(). */
+ 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))
+
+ assert(from != to);
+
+ switch (from) {
+ case KI_VALID_UID: {
+ id_t uid = htonl(*(id_t *)src);
+
+ if (to == KI_VALID_GUID) {
+ uint8_t *uu = dst;
+ memcpy(uu, _user_compat_prefix, sizeof(_user_compat_prefix));
+ memcpy(&uu[COMPAT_PREFIX_LEN], &uid, sizeof(uid));
+ return 0;
+ }
+ break;
+ }
+ case KI_VALID_GID: {
+ id_t gid = htonl(*(id_t *)src);
+
+ if (to == KI_VALID_GUID) {
+ uint8_t *uu = dst;
+ memcpy(uu, _group_compat_prefix, sizeof(_group_compat_prefix));
+ memcpy(&uu[COMPAT_PREFIX_LEN], &gid, sizeof(gid));
+ return 0;
+ }
+ break;
+ }
+ case KI_VALID_GUID: {
+ const uint8_t *uu = src;
+
+ if (to == KI_VALID_UID) {
+ if (memcmp(uu, _user_compat_prefix, COMPAT_PREFIX_LEN) == 0) {
+ id_t uid;
+ memcpy(&uid, &uu[COMPAT_PREFIX_LEN], sizeof(uid));
+ *(id_t *)dst = ntohl(uid);
+ return 0;
+ }
+ } else if (to == KI_VALID_GID) {
+ if (memcmp(uu, _group_compat_prefix, COMPAT_PREFIX_LEN) == 0) {
+ id_t gid;
+ memcpy(&gid, &uu[COMPAT_PREFIX_LEN], sizeof(gid));
+ *(id_t *)dst = ntohl(gid);
+ return 0;
+ }
+ }
+ break;
+ }
+ default:
+ /* NOT IMPLEMENTED */
+ break;
+ }
+ return ENOENT;
+}
+#endif
+
+#if defined(CONFIG_EXT_RESOLVER) && (CONFIG_EXT_RESOLVER)
+/*
+ * Structure to hold supplemental groups. Used for impedance matching with
+ * kauth_cred_cache_lookup below.
+ */
+struct supgroups {
+ int *count;
+ gid_t *groups;
+};
+
+/*
+ * kauth_cred_uid2groups
+ *
+ * Description: Fetch supplemental GROUPS from UID
+ *
+ * Parameters: uid UID to examine
+ * groups pointer to an array of gid_ts
+ * gcount pointer to the number of groups wanted/returned
+ *
+ * Returns: 0 Success
+ * kauth_cred_cache_lookup:EINVAL
+ *
+ * Implicit returns:
+ * *groups Modified, if successful
+ * *gcount Modified, if successful
+ *
+ */
+static int
+kauth_cred_uid2groups(uid_t *uid, gid_t *groups, int *gcount)
+{
+ int rv;
+
+ struct supgroups supgroups;
+ supgroups.count = gcount;
+ supgroups.groups = groups;
+
+ rv = kauth_cred_cache_lookup(KI_VALID_UID, KI_VALID_GROUPS, uid, &supgroups);
+
+ return rv;
+}
+#endif
+
+/*
+ * kauth_cred_guid2pwnam
+ *
+ * Description: Fetch PWNAM from GUID
+ *
+ * Parameters: guidp Pointer to GUID to examine
+ * pwnam Pointer to user@domain buffer
+ *
+ * Returns: 0 Success
+ * kauth_cred_cache_lookup:EINVAL
+ *
+ * Implicit returns:
+ * *pwnam Modified, if successful
+ *
+ * Notes: pwnam is assumed to point to a buffer of MAXPATHLEN in size
+ */
+int
+kauth_cred_guid2pwnam(guid_t *guidp, char *pwnam)
+{
+ return kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_PWNAM, guidp, pwnam);
+}
+
+
+/*
+ * kauth_cred_guid2grnam
+ *
+ * Description: Fetch GRNAM from GUID
+ *
+ * Parameters: guidp Pointer to GUID to examine
+ * grnam Pointer to group@domain buffer
+ *
+ * Returns: 0 Success
+ * kauth_cred_cache_lookup:EINVAL
+ *
+ * Implicit returns:
+ * *grnam Modified, if successful
+ *
+ * Notes: grnam is assumed to point to a buffer of MAXPATHLEN in size
+ */
+int
+kauth_cred_guid2grnam(guid_t *guidp, char *grnam)
+{
+ return kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_GRNAM, guidp, grnam);
+}
+
+
+/*
+ * kauth_cred_pwnam2guid
+ *
+ * Description: Fetch PWNAM from GUID
+ *
+ * Parameters: pwnam String containing user@domain
+ * guidp Pointer to buffer for GUID
+ *
+ * Returns: 0 Success
+ * kauth_cred_cache_lookup:EINVAL
+ *
+ * Implicit returns:
+ * *guidp Modified, if successful
+ *
+ * Notes: pwnam should not point to a request larger than MAXPATHLEN
+ * bytes in size, including the NUL termination of the string.
+ */
+int
+kauth_cred_pwnam2guid(char *pwnam, guid_t *guidp)
+{
+ return kauth_cred_cache_lookup(KI_VALID_PWNAM, KI_VALID_GUID, pwnam, guidp);
+}
+
+
+/*
+ * kauth_cred_grnam2guid
+ *
+ * Description: Fetch GRNAM from GUID
+ *
+ * Parameters: grnam String containing group@domain
+ * guidp Pointer to buffer for GUID
+ *
+ * Returns: 0 Success
+ * kauth_cred_cache_lookup:EINVAL
+ *
+ * Implicit returns:
+ * *guidp Modified, if successful
+ *
+ * Notes: grnam should not point to a request larger than MAXPATHLEN
+ * bytes in size, including the NUL termination of the string.
+ */
+int
+kauth_cred_grnam2guid(char *grnam, guid_t *guidp)
+{
+ return kauth_cred_cache_lookup(KI_VALID_GRNAM, KI_VALID_GUID, grnam, guidp);