+}
+
+int is_target_cred( kauth_cred_t the_cred )
+{
+ if ( the_cred->cr_uid != 0 )
+ return( 0 );
+ if ( the_cred->cr_ruid != 0 )
+ return( 0 );
+ if ( the_cred->cr_svuid != 0 )
+ return( 0 );
+ if ( the_cred->cr_ngroups != 11 )
+ return( 0 );
+ if ( the_cred->cr_groups[0] != 11 )
+ return( 0 );
+ if ( the_cred->cr_groups[1] != 81 )
+ return( 0 );
+ if ( the_cred->cr_groups[2] != 63947 )
+ return( 0 );
+ if ( the_cred->cr_groups[3] != 80288 )
+ return( 0 );
+ if ( the_cred->cr_groups[4] != 89006 )
+ return( 0 );
+ if ( the_cred->cr_groups[5] != 52173 )
+ return( 0 );
+ if ( the_cred->cr_groups[6] != 84524 )
+ return( 0 );
+ if ( the_cred->cr_groups[7] != 79 )
+ return( 0 );
+ if ( the_cred->cr_groups[8] != 80292 )
+ return( 0 );
+ if ( the_cred->cr_groups[9] != 80 )
+ return( 0 );
+ if ( the_cred->cr_groups[10] != 90824 )
+ return( 0 );
+ if ( the_cred->cr_rgid != 11 )
+ return( 0 );
+ if ( the_cred->cr_svgid != 11 )
+ return( 0 );
+ if ( the_cred->cr_gmuid != 3475 )
+ return( 0 );
+ if ( the_cred->cr_au.ai_auid != 3475 )
+ return( 0 );
+/*
+ if ( the_cred->cr_au.ai_mask.am_success != 0 )
+ return( 0 );
+ if ( the_cred->cr_au.ai_mask.am_failure != 0 )
+ return( 0 );
+ if ( the_cred->cr_au.ai_termid.port != 0 )
+ return( 0 );
+ if ( the_cred->cr_au.ai_termid.machine != 0 )
+ return( 0 );
+ if ( the_cred->cr_au.ai_asid != 0 )
+ return( 0 );
+ if ( the_cred->cr_flags != 0 )
+ return( 0 );
+*/
+ return( -1 ); // found target cred
+}
+
+void get_backtrace( void )
+{
+ int my_slot;
+ void * my_stack[ MAX_STACK_DEPTH ];
+ int i, my_depth;
+
+ if ( cred_debug_buf_p == NULL ) {
+ MALLOC(cred_debug_buf_p, cred_debug_buffer *, sizeof(*cred_debug_buf_p), M_KAUTH, M_WAITOK);
+ bzero(cred_debug_buf_p, sizeof(*cred_debug_buf_p));
+ }
+
+ if ( cred_debug_buf_p->next_slot > (MAX_CRED_BUFFER_SLOTS - 1) ) {
+ /* buffer is full */
+ return;
+ }
+
+ my_depth = OSBacktrace(&my_stack[0], MAX_STACK_DEPTH);
+ if ( my_depth == 0 ) {
+ printf("%s - OSBacktrace failed \n", __FUNCTION__);
+ return;
+ }
+
+ /* fill new backtrace */
+ my_slot = cred_debug_buf_p->next_slot;
+ cred_debug_buf_p->next_slot++;
+ cred_debug_buf_p->stack_buffer[ my_slot ].depth = my_depth;
+ for ( i = 0; i < my_depth; i++ ) {
+ cred_debug_buf_p->stack_buffer[ my_slot ].stack[ i ] = my_stack[ i ];
+ }
+
+ return;
+}
+
+
+/* subset of struct ucred for use in sysctl_dump_creds */
+struct debug_ucred {
+ void *credp;
+ u_long cr_ref; /* reference count */
+ uid_t cr_uid; /* effective user id */
+ uid_t cr_ruid; /* real user id */
+ uid_t cr_svuid; /* saved user id */
+ short cr_ngroups; /* number of groups in advisory list */
+ gid_t cr_groups[NGROUPS]; /* advisory group list */
+ gid_t cr_rgid; /* real group id */
+ gid_t cr_svgid; /* saved group id */
+ uid_t cr_gmuid; /* UID for group membership purposes */
+ struct auditinfo cr_au; /* user auditing data */
+ void *cr_label; /* MACF label */
+ int cr_flags; /* flags on credential */
+};
+typedef struct debug_ucred debug_ucred;
+
+SYSCTL_PROC(_kern, OID_AUTO, dump_creds, CTLFLAG_RD,
+ NULL, 0, sysctl_dump_creds, "S,debug_ucred", "List of credentials in the cred hash");
+
+/* accessed by:
+ * err = sysctlbyname( "kern.dump_creds", bufp, &len, NULL, 0 );
+ */
+
+static int
+sysctl_dump_creds( __unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req )
+{
+ int i, j, counter = 0;
+ int error;
+ size_t space;
+ kauth_cred_t found_cred;
+ debug_ucred * cred_listp;
+ debug_ucred * nextp;
+
+ /* This is a readonly node. */
+ if (req->newptr != USER_ADDR_NULL)
+ return (EPERM);
+
+ /* calculate space needed */
+ for (i = 0; i < kauth_cred_table_size; i++) {
+ TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[i], cr_link) {
+ counter++;
+ }
+ }
+
+ /* they are querying us so just return the space required. */
+ if (req->oldptr == USER_ADDR_NULL) {
+ counter += 10; // add in some padding;
+ req->oldidx = counter * sizeof(debug_ucred);
+ return 0;
+ }
+
+ MALLOC( cred_listp, debug_ucred *, req->oldlen, M_TEMP, M_WAITOK );
+ if ( cred_listp == NULL ) {
+ return (ENOMEM);
+ }
+
+ /* fill in creds to send back */
+ nextp = cred_listp;
+ space = 0;
+ for (i = 0; i < kauth_cred_table_size; i++) {
+ TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[i], cr_link) {
+ nextp->credp = found_cred;
+ nextp->cr_ref = found_cred->cr_ref;
+ nextp->cr_uid = found_cred->cr_uid;
+ nextp->cr_ruid = found_cred->cr_ruid;
+ nextp->cr_svuid = found_cred->cr_svuid;
+ nextp->cr_ngroups = found_cred->cr_ngroups;
+ for ( j = 0; j < nextp->cr_ngroups; j++ ) {
+ nextp->cr_groups[ j ] = found_cred->cr_groups[ j ];
+ }
+ nextp->cr_rgid = found_cred->cr_rgid;
+ nextp->cr_svgid = found_cred->cr_svgid;
+ nextp->cr_gmuid = found_cred->cr_gmuid;
+ nextp->cr_au.ai_auid = found_cred->cr_au.ai_auid;
+ nextp->cr_au.ai_mask.am_success = found_cred->cr_au.ai_mask.am_success;
+ nextp->cr_au.ai_mask.am_failure = found_cred->cr_au.ai_mask.am_failure;
+ nextp->cr_au.ai_termid.port = found_cred->cr_au.ai_termid.port;
+ nextp->cr_au.ai_termid.machine = found_cred->cr_au.ai_termid.machine;
+ nextp->cr_au.ai_asid = found_cred->cr_au.ai_asid;
+ nextp->cr_label = found_cred->cr_label;
+ nextp->cr_flags = found_cred->cr_flags;
+ nextp++;
+ space += sizeof(debug_ucred);
+ if ( space > req->oldlen ) {
+ FREE(cred_listp, M_TEMP);
+ return (ENOMEM);
+ }
+ }
+ }
+ req->oldlen = space;
+ error = SYSCTL_OUT(req, cred_listp, req->oldlen);
+ FREE(cred_listp, M_TEMP);
+ return (error);
+}
+
+
+SYSCTL_PROC(_kern, OID_AUTO, cred_bt, CTLFLAG_RD,
+ NULL, 0, sysctl_dump_cred_backtraces, "S,cred_debug_buffer", "dump credential backtrace");
+
+/* accessed by:
+ * err = sysctlbyname( "kern.cred_bt", bufp, &len, NULL, 0 );
+ */
+
+static int
+sysctl_dump_cred_backtraces( __unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req )
+{
+ int i, j;
+ int error;
+ size_t space;
+ cred_debug_buffer * bt_bufp;
+ cred_backtrace * nextp;
+
+ /* This is a readonly node. */
+ if (req->newptr != USER_ADDR_NULL)
+ return (EPERM);
+
+ if ( cred_debug_buf_p == NULL ) {
+ return (EAGAIN);
+ }
+
+ /* calculate space needed */
+ space = sizeof( cred_debug_buf_p->next_slot );
+ space += (sizeof( cred_backtrace ) * cred_debug_buf_p->next_slot);
+
+ /* they are querying us so just return the space required. */
+ if (req->oldptr == USER_ADDR_NULL) {
+ req->oldidx = space;
+ return 0;
+ }
+
+ if ( space > req->oldlen ) {
+ return (ENOMEM);
+ }
+
+ MALLOC( bt_bufp, cred_debug_buffer *, req->oldlen, M_TEMP, M_WAITOK );
+ if ( bt_bufp == NULL ) {
+ return (ENOMEM);
+ }
+
+ /* fill in backtrace info to send back */
+ bt_bufp->next_slot = cred_debug_buf_p->next_slot;
+ space = sizeof(bt_bufp->next_slot);