#include <security/_label.h>
#endif
+#include <IOKit/IOBSD.h>
+
void mach_kauth_cred_uthread_update( void );
#define CRED_DIAGNOSTIC 0
#define KAUTH_COMPLAINT_INTERVAL 1000
int kauth_resolver_timeout_cnt = 0;
+#if DEVELOPMENT || DEBUG
+/* Internal builds get different (less ambiguous) breadcrumbs. */
+#define KAUTH_RESOLVER_FAILED_ERRCODE EOWNERDEAD
+#else
+/* But non-Internal builds get errors that are allowed by standards. */
+#define KAUTH_RESOLVER_FAILED_ERRCODE EIO
+#endif /* DEVELOPMENT || DEBUG */
+
+int kauth_resolver_failed_cnt = 0;
+#define RESOLVER_FAILED_MESSAGE(fmt, args...) \
+do { \
+ if (!(kauth_resolver_failed_cnt++ % 100)) { \
+ printf("%s: " fmt "\n", __PRETTY_FUNCTION__, ##args); \
+ } \
+} while (0)
+
static int kauth_resolver_submit(struct kauth_identity_extlookup *lkp, uint64_t extend_data);
static int kauth_resolver_complete(user_addr_t message);
static int kauth_resolver_getwork(user_addr_t message);
break;
/* woken because the resolver has died? */
if (kauth_resolver_identity == 0) {
- error = EIO;
+ RESOLVER_FAILED_MESSAGE("kauth external resolver died while while waiting for work to complete");
+ error = KAUTH_RESOLVER_FAILED_ERRCODE;
break;
}
/* an error? */
int opcode = uap->opcode;
user_addr_t message = uap->message;
struct kauth_resolver_work *workp;
- struct kauth_cache_sizes sz_arg;
+ struct kauth_cache_sizes sz_arg = {};
int error;
pid_t new_id;
+ if (!IOTaskHasEntitlement(current_task(), IDENTITYSVC_ENTITLEMENT)) {
+ KAUTH_DEBUG("RESOLVER - pid %d not entitled to call identitysvc", current_proc()->p_pid);
+ return(EPERM);
+ }
+
/*
* New server registering itself.
*/
* If this is a wakeup from another thread in the resolver
* deregistering it, error out the request-for-work thread
*/
- if (!kauth_resolver_identity)
- error = EIO;
+ if (!kauth_resolver_identity) {
+ RESOLVER_FAILED_MESSAGE("external resolver died");
+ error = KAUTH_RESOLVER_FAILED_ERRCODE;
+ }
KAUTH_RESOLVER_UNLOCK();
return(error);
}
* If this is a wakeup from another thread in the resolver
* deregistering it, error out the request-for-work thread
*/
- if (!kauth_resolver_identity)
- error = EIO;
+ if (!kauth_resolver_identity) {
+ printf("external resolver died");
+ error = KAUTH_RESOLVER_FAILED_ERRCODE;
+ }
return(error);
}
return kauth_resolver_getwork2(message);
struct kauth_identity_extlookup extl;
struct kauth_resolver_work *workp;
struct kauth_resolver_work *killp;
- int error, result, request_flags;
+ int error, result, want_extend_data;
/*
* Copy in the mesage, including the extension field, since we are
case KAUTH_EXTLOOKUP_FATAL:
/* fatal error means the resolver is dead */
KAUTH_DEBUG("RESOLVER - resolver %d died, waiting for a new one", kauth_resolver_identity);
+ RESOLVER_FAILED_MESSAGE("resolver %d died, waiting for a new one", kauth_resolver_identity);
/*
* Terminate outstanding requests; without an authoritative
* resolver, we are now back on our own authority. Tag the
/* Cause all waiting-for-work threads to return EIO */
wakeup((caddr_t)&kauth_resolver_unsubmitted);
/* and return EIO to the caller */
- error = EIO;
+ error = KAUTH_RESOLVER_FAILED_ERRCODE;
break;
case KAUTH_EXTLOOKUP_BADRQ:
case KAUTH_EXTLOOKUP_FAILURE:
KAUTH_DEBUG("RESOLVER - resolver reported transient failure for request %d", extl.el_seqno);
- result = EIO;
+ RESOLVER_FAILED_MESSAGE("resolver reported transient failure for request %d", extl.el_seqno);
+ result = KAUTH_RESOLVER_FAILED_ERRCODE;
break;
default:
KAUTH_DEBUG("RESOLVER - resolver returned unexpected status %d", extl.el_result);
- result = EIO;
+ RESOLVER_FAILED_MESSAGE("resolver returned unexpected status %d", extl.el_result);
+ result = KAUTH_RESOLVER_FAILED_ERRCODE;
break;
}
/* found it? */
if (workp->kr_seqno == extl.el_seqno) {
/*
- * Take a snapshot of the original request flags.
+ * Do we want extend_data?
*/
- request_flags = workp->kr_work.el_flags;
+ want_extend_data = (workp->kr_work.el_flags & (KAUTH_EXTLOOKUP_WANT_PWNAM|KAUTH_EXTLOOKUP_WANT_GRNAM));
/*
* Get the request of the submitted queue so
* part of a user's address space if they return
* flags that mismatch the original request's flags.
*/
- if ((extl.el_flags & request_flags) & (KAUTH_EXTLOOKUP_VALID_PWNAM|KAUTH_EXTLOOKUP_VALID_GRNAM)) {
+ if (want_extend_data && (extl.el_flags & (KAUTH_EXTLOOKUP_VALID_PWNAM|KAUTH_EXTLOOKUP_VALID_GRNAM))) {
size_t actual; /* notused */
KAUTH_RESOLVER_UNLOCK();
error = copyinstr(extl.el_extend, CAST_DOWN(void *, workp->kr_extend), MAXPATHLEN, &actual);
+ KAUTH_DEBUG("RESOLVER - resolver got name :%*s: len = %d\n", (int)actual,
+ actual ? "null" : (char *)extl.el_extend, actual);
KAUTH_RESOLVER_LOCK();
} else if (extl.el_flags & (KAUTH_EXTLOOKUP_VALID_PWNAM|KAUTH_EXTLOOKUP_VALID_GRNAM)) {
error = EFAULT;
if ((kip->ki_valid & KI_VALID_UID) && (kip->ki_uid == elp->el_uid)) {
if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_SUPGRPS) {
assert(elp->el_sup_grp_cnt <= NGROUPS);
+ if (elp->el_sup_grp_cnt > NGROUPS) {
+ KAUTH_DEBUG("CACHE - invalid sup_grp_cnt provided (%d), truncating to %d",
+ elp->el_sup_grp_cnt, NGROUPS);
+ elp->el_sup_grp_cnt = NGROUPS;
+ }
kip->ki_supgrpcnt = elp->el_sup_grp_cnt;
memcpy(kip->ki_supgrps, elp->el_sup_groups, sizeof(elp->el_sup_groups[0]) * kip->ki_supgrpcnt);
kip->ki_valid |= KI_VALID_GROUPS;
return(kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_GID, guidp, gidp));
}
+/*
+ * kauth_cred_nfs4domain2dsnode
+ *
+ * Description: Fetch dsnode from nfs4domain
+ *
+ * Parameters: nfs4domain Pointer to a string nfs4 domain
+ * dsnode Pointer to buffer for dsnode
+ *
+ * Returns: 0 Success
+ * ENOENT For now just a stub that always fails
+ *
+ * Implicit returns:
+ * *dsnode Modified, if successuful
+ */
+int
+kauth_cred_nfs4domain2dsnode(__unused char *nfs4domain, __unused char *dsnode)
+{
+ return(ENOENT);
+}
+
+/*
+ * kauth_cred_dsnode2nfs4domain
+ *
+ * Description: Fetch nfs4domain from dsnode
+ *
+ * Parameters: nfs4domain Pointer to string dsnode
+ * dsnode Pointer to buffer for nfs4domain
+ *
+ * Returns: 0 Success
+ * ENOENT For now just a stub that always fails
+ *
+ * Implicit returns:
+ * *nfs4domain Modified, if successuful
+ */
+int
+kauth_cred_dsnode2nfs4domain(__unused char *dsnode, __unused char *nfs4domain)
+{
+ return(ENOENT);
+}
/*
* kauth_cred_ntsid2uid
* atomically.
*/
if (to == KI_VALID_PWNAM || to == KI_VALID_GRNAM) {
+ if (dst == NULL)
+ return (EINVAL);
namebuf = dst;
+ *namebuf = '\0';
}
ki.ki_valid = 0;
switch(from) {
default:
return(EINVAL);
}
+ /* If we didn't get what we're asking for. Call the resolver */
+ if (!error && !(to & ki.ki_valid))
+ error = ENOENT;
/* lookup failure or error */
if (error != 0) {
/* any other error is fatal */
* changing access to server file system objects on each
* expiration.
*/
+ if (ki.ki_supgrpcnt > NGROUPS) {
+ panic("kauth data structure corrupted. kauth identity 0x%p with %d groups, greater than max of %d",
+ &ki, ki.ki_supgrpcnt, NGROUPS);
+ }
+
el.el_sup_grp_cnt = ki.ki_supgrpcnt;
memcpy(el.el_sup_groups, ki.ki_supgrps, sizeof (el.el_sup_groups[0]) * ki.ki_supgrpcnt);
/* update cred on proc */
PROC_UPDATE_CREDS_ONPROC(p);
- mac_proc_set_enforce(p, MAC_ALL_ENFORCE);
proc_ucred_unlock(p);
}
break;
p->p_ucred = my_new_cred;
/* update cred on proc */
PROC_UPDATE_CREDS_ONPROC(p);
- mac_proc_set_enforce(p, MAC_ALL_ENFORCE);
proc_ucred_unlock(p);
}
break;
return 0;
}
- MALLOC( cred_listp, debug_ucred *, req->oldlen, M_TEMP, M_WAITOK );
+ MALLOC( cred_listp, debug_ucred *, req->oldlen, M_TEMP, M_WAITOK | M_ZERO);
if ( cred_listp == NULL ) {
return (ENOMEM);
}
return (ENOMEM);
}
- MALLOC( bt_bufp, cred_debug_buffer *, req->oldlen, M_TEMP, M_WAITOK );
+ MALLOC( bt_bufp, cred_debug_buffer *, req->oldlen, M_TEMP, M_WAITOK | M_ZERO);
if ( bt_bufp == NULL ) {
return (ENOMEM);
}