Index: include/pthread_np.h =================================================================== --- include/pthread_np.h +++ include/pthread_np.h @@ -51,6 +51,7 @@ int pthread_attr_setaffinity_np(pthread_attr_t *, size_t, const cpuset_t *); void pthread_get_name_np(pthread_t, char *, size_t); int pthread_getaffinity_np(pthread_t, size_t, cpuset_t *); +int pthread_getcred_np(uid_t *, int *, gid_t *); int pthread_getthreadid_np(void); int pthread_main_np(void); int pthread_multi_np(void); @@ -63,8 +64,10 @@ int pthread_mutex_isowned_np(pthread_mutex_t *mutex); void pthread_resume_all_np(void); int pthread_resume_np(pthread_t); +int pthread_revertcred_np(void); void pthread_set_name_np(pthread_t, const char *); int pthread_setaffinity_np(pthread_t, size_t, const cpuset_t *); +int pthread_setcred_np(uid_t , int , gid_t *); int pthread_single_np(void); void pthread_suspend_all_np(void); int pthread_suspend_np(pthread_t); Index: include/unistd.h =================================================================== --- include/unistd.h +++ include/unistd.h @@ -505,6 +505,7 @@ int execvP(const char *, const char *, char * const *); int feature_present(const char *); char *fflagstostr(u_long); +int getcred(uid_t *, int *, gid_t *); int getdomainname(char *, int); int getentropy(void *, size_t); int getgrouplist(const char *, gid_t, gid_t *, int *); @@ -550,6 +551,7 @@ char *re_comp(const char *); int re_exec(const char *); int reboot(int); +int revertcred(void); int revoke(const char *); pid_t rfork(int); pid_t rfork_thread(int, void *, int (*)(void *), void *); @@ -562,6 +564,7 @@ int select(int, fd_set *, fd_set *, fd_set *, struct timeval *); #endif #endif +int setcred(uid_t, int, const gid_t *); int setdomainname(const char *, int); int setgroups(int, const gid_t *); void sethostid(long); Index: lib/libc/include/namespace.h =================================================================== --- lib/libc/include/namespace.h +++ lib/libc/include/namespace.h @@ -138,6 +138,7 @@ #define pthread_getaffinity_np _pthread_getaffinity_np #define pthread_getconcurrency _pthread_getconcurrency #define pthread_getcpuclockid _pthread_getcpuclockid +#define pthread_getcred_np _pthread_getcred_np #define pthread_getprio _pthread_getprio #define pthread_getschedparam _pthread_getschedparam #define pthread_getspecific _pthread_getspecific @@ -172,6 +173,7 @@ #define pthread_once _pthread_once #define pthread_resume_all_np _pthread_resume_all_np #define pthread_resume_np _pthread_resume_np +#define pthread_revertcred_np _pthread_revertcred_np #define pthread_rwlock_destroy _pthread_rwlock_destroy #define pthread_rwlock_init _pthread_rwlock_init #define pthread_rwlock_rdlock _pthread_rwlock_rdlock @@ -191,6 +193,7 @@ #define pthread_setcancelstate _pthread_setcancelstate #define pthread_setcanceltype _pthread_setcanceltype #define pthread_setconcurrency _pthread_setconcurrency +#define pthread_setcred_np _pthread_setcred_np #define pthread_setprio _pthread_setprio #define pthread_setschedparam _pthread_setschedparam #define pthread_setspecific _pthread_setspecific Index: lib/libc/include/un-namespace.h =================================================================== --- lib/libc/include/un-namespace.h +++ lib/libc/include/un-namespace.h @@ -119,6 +119,7 @@ #undef pthread_getaffinity_np #undef pthread_getconcurrency #undef pthread_getcpuclockid +#undef pthread_getcred_np #undef pthread_getprio #undef pthread_getschedparam #undef pthread_getspecific @@ -153,6 +154,7 @@ #undef pthread_once #undef pthread_resume_all_np #undef pthread_resume_np +#undef pthread_revertcred_np #undef pthread_rwlock_destroy #undef pthread_rwlock_init #undef pthread_rwlock_rdlock @@ -172,6 +174,7 @@ #undef pthread_setcancelstate #undef pthread_setcanceltype #undef pthread_setconcurrency +#undef pthread_setcred_np #undef pthread_setprio #undef pthread_setschedparam #undef pthread_setspecific Index: lib/libc/sys/Makefile.inc =================================================================== --- lib/libc/sys/Makefile.inc +++ lib/libc/sys/Makefile.inc @@ -297,6 +297,7 @@ semget.2 \ semop.2 \ send.2 \ + setcred.2 \ setfib.2 \ sendfile.2 \ setgroups.2 \ @@ -463,6 +464,8 @@ select.2 FD_ZERO.3 MLINKS+=send.2 sendmsg.2 \ send.2 sendto.2 +MLINKS+=setcred.2 getcred.2 \ + setcred.2 revertcred.2 MLINKS+=setpgid.2 setpgrp.2 MLINKS+=setresuid.2 getresgid.2 \ setresuid.2 getresuid.2 \ Index: lib/libc/sys/Symbol.map =================================================================== --- lib/libc/sys/Symbol.map +++ lib/libc/sys/Symbol.map @@ -406,6 +406,9 @@ fhlinkat; fhreadlink; getfhat; + getcred; + setcred; + revertcred; }; FBSDprivate_1.0 { Index: lib/libc/sys/setcred.2 =================================================================== --- /dev/null +++ lib/libc/sys/setcred.2 @@ -0,0 +1,119 @@ +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) 2019 Gandi +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd January 23, 2019 +.Dt SETCRED 2 +.Os +.Sh NAME +.Nm setcred , +.Nm getcred , +.Nm revertcred +.Nd control per-thread user credentials +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.In sys/param.h +.Ft int +.Fn setcred "uid_t uid" "int gidsetlen" "const gid_t *gidset" +.Ft int +.Fn getcred "uid_t *uid" "int *gidsetlen" "const gid_t *gidset" +.Ft int +.Fn revertcred "void" +.Sh Description +The +.Fn setcred +system call sets the real, effective, and saved UIDs and GIDs, +along with supplementary group access list of the current thread. +.Pp +The +.Fa uid +parameter can be any UID. +The +.Fa gidsetlen +parameter indicates the number of entries in the array and must be no more +than NGROUPS. The +.Fa gidset +parameter is an array of GIDs, the first being the primary GID to set. +This call will replace all supplementary groups in the credential. +.Pp +The +.Fn getcred +system call retrieves the real user ID of the calling thread and stores it in +.Fa uid . +It also retrieves the current group access list of the calling thread and +stores it in +.Fa gidset . +The gidsetlen argument indicates the number of entries that may be placed in +gidset. +.Pp +The +.Fn getcred +system call sets this variable to the actual number of groups returned in +gidset, even on error. +.Pp +The +.Fn revertcred +system call reverts the thread's credential, including the real, effective and +saved UIDs and GIDs, to the per-process credential. +.Pp +These system calls may only be called if the process has super-user privileges. +.Sh RETURN VALUES +.Rv -std +.Sh ERRORS +The +.Fn revertcred +system call will only fail if: +.Bl -tag -width Er +.It Bq Er EPERM +The user is not the super user. +.El +.Pp +In addition to the error returned by +.Fn revertcred , +the +.Fn setcred +and +.Fn getcred +system calls may fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value of +.Fa gidsetlen +is not valid. +.It Bq Er ENOENT +The per-thread credential has not yet been explicitly set with +.Fn setcred , +or it has been reverted with +.Fn revertcred . +.It Bq Er ERANGE +The incoming +.Fa gidsetlen +is less than the number of groups in the credential. +.It Bq Er EFAULT +One of the parameters points to an invalid address. +.El Index: lib/libthr/pthread.map =================================================================== --- lib/libthr/pthread.map +++ lib/libthr/pthread.map @@ -325,3 +325,9 @@ FBSD_1.5 { pthread_get_name_np; }; + +FBSD_1.6 { + pthread_getcred_np; + pthread_setcred_np; + pthread_revertcred_np; +}; Index: lib/libthr/thread/Makefile.inc =================================================================== --- lib/libthr/thread/Makefile.inc +++ lib/libthr/thread/Makefile.inc @@ -14,6 +14,7 @@ thr_cond.c \ thr_condattr.c \ thr_create.c \ + thr_cred_np.c \ thr_ctrdtr.c \ thr_detach.c \ thr_equal.c \ Index: lib/libthr/thread/thr_cred_np.c =================================================================== --- /dev/null +++ lib/libthr/thread/thr_cred_np.c @@ -0,0 +1,58 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2018 Gandi + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#include +#include +#include "un-namespace.h" + +__weak_reference(_pthread_getcred_np, pthread_getcred_np); +__weak_reference(_pthread_setcred_np, pthread_setcred_np); +__weak_reference(_pthread_revertcred_np, pthread_revertcred_np); + +int _pthread_getcred_np(uid_t *uid, int *gidsetlen, gid_t *gidset) +{ + + return (getcred(uid, gidsetlen, gidset)); +} + +int _pthread_setcred_np(uid_t uid, int gidsetlen, gid_t *gidset) +{ + + return (setcred(uid, gidsetlen, gidset)); +} + +int _pthread_revertcred_np(void) +{ + + return (revertcred()); +} Index: share/man/man3/Makefile =================================================================== --- share/man/man3/Makefile +++ share/man/man3/Makefile @@ -275,6 +275,7 @@ pthread_rwlock_wrlock.3 \ pthread_schedparam.3 \ pthread_self.3 \ + pthread_setcred_np.3 \ pthread_set_name_np.3 \ pthread_setspecific.3 \ pthread_sigmask.3 \ @@ -339,6 +340,8 @@ PTHREAD_MLINKS+=pthread_rwlock_wrlock.3 pthread_rwlock_trywrlock.3 PTHREAD_MLINKS+=pthread_schedparam.3 pthread_getschedparam.3 \ pthread_schedparam.3 pthread_setschedparam.3 +PTHREAD_MLINKS+=pthread_setcred_np.3 pthread_getcred_np.3 \ + pthread_setcred_np.3 pthread_revertcred_np.3 PTHREAD_MLINKS+=pthread_set_name_np.3 pthread_get_name_np.3 PTHREAD_MLINKS+=pthread_spin_init.3 pthread_spin_destroy.3 \ pthread_spin_lock.3 pthread_spin_trylock.3 \ Index: share/man/man3/pthread_setcred_np.3 =================================================================== --- /dev/null +++ share/man/man3/pthread_setcred_np.3 @@ -0,0 +1,124 @@ +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) 2019 Gandi +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd January 23, 2019 +.Dt pthread_setcred_np 3 +.Os +.Sh NAME +.Nm pthread_setcred_np , +.Nm pthread_getcred_np , +.Nm pthread_revertcred_np +.Nd control per-thread user credentials +.Sh LIBRARY +.Lb libpthread +.Sh SYNOPSIS +.In pthread_np.h +.In sys/param.h +.Ft int +.Fn pthread_setcred_np "uid_t uid" "int gidsetlen" "const gid_t *gidset" +.Ft int +.Fn pthread_getcred_np "uid_t *uid" "int *gidsetlen" "const gid_t *gidset" +.Ft int +.Fn pthread_revertcred_np "void" +.Sh Description +The +.Fn pthread_setcred_np +function sets the real, effective, and saved UIDs and GIDs, +along with supplementary group access list of the current thread. +.Pp +The +.Fa uid +parameter can be any UID. The +.Fa gidsetlen +parameter indicates the number of entries in the array and must be no more +than NGROUPS. The +.Fa gidset +parameter is an array of GIDs, the first being the primary GID to set. +This call will replace all supplementary groups in the credential. +.Pp +The +.Fn pthread_getcred_np +function retrieves the real user ID of the calling thread and stores it in +.Fa uid . +It also retrieves the current group access list of the calling thread and +stores it in +.Fa gidset . +The gidsetlen argument indicates the number of entries that may be placed in +gidset. +.Pp +The +.Fn pthread_getcred_np +sets this variable to the actual number of groups returned in +gidset, even on error. +.Pp +The +.Fn pthread_revertcred_np +function reverts the thread's credential, including the real, effective and +saved UIDs and GIDs, to the per-process credential. +.Pp +These functions may only be called if the process has super-user privileges. +.Sh RETURN VALUES +.Rv -std +.Sh ERRORS +The +.Fn pthread_revertcred_np +function will only fail if: +.Bl -tag -width Er +.It Bq Er EPERM +The user is not the super user. +.El +.Pp +In addition to the error returned by +.Fn pthread_revertcred_np , +the +.Fn pthread_setcred_np +and +.Fn pthread_getcred_np +functions calls may fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value of +.Fa gidsetlen +is not valid. +.It Bq Er ENOENT +The per-thread credential has not yet been explicitly set with +.Fn pthread_setcred_np , +or it has been reverted with +.Fn pthread_revertcred_np . +.It Bq Er ERANGE +The incoming +.Fa gidsetlen +is less than the number of groups in the credential. +.It Bq Er EFAULT +One of the parameters points to an invalid address. +.El +.Sh STANDARDS +These functions are non standard extensions. +.Sh SEE ALSO +.Xr setcred 2 , +.Xr getcred 2 , +.Xr revertcred 2 , Index: sys/bsm/audit_kevents.h =================================================================== --- sys/bsm/audit_kevents.h +++ sys/bsm/audit_kevents.h @@ -644,6 +644,9 @@ #define AUE_SETLOGINCLASS 43238 /* FreeBSD-specific. */ #define AUE_POSIX_FADVISE 43239 /* FreeBSD-specific. */ #define AUE_SCTP_GENERIC_SENDMSG_IOV 43240 /* FreeBSD-specific. */ +#define AUE_GETCRED 43263 /* FreeBSD-specific. */ +#define AUE_SETCRED 43264 /* FreeBSD-specific. */ +#define AUE_REVERTCRED 43265 /* FreeBSD-specific. */ /* * Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the Index: sys/compat/freebsd32/syscalls.master =================================================================== --- sys/compat/freebsd32/syscalls.master +++ sys/compat/freebsd32/syscalls.master @@ -1145,5 +1145,10 @@ const char *to); } 567 AUE_NULL NOPROTO { int fhreadlink( struct fhandle *fhp, char *buf, \ size_t bufsize); } +568 AUE_SETCRED NOPROTO { int setcred( uid_t uid, int gidsetlen, \ + const gid_t *gidset); } +569 AUE_GETCRED NOPROTO { int getcred( uid_t *uid, int *gidsetlen, \ + gid_t *gidset); } +570 AUE_REVERTCRED NOPROTO { int revertcred(void); } ; vim: syntax=off Index: sys/ddb/db_ps.c =================================================================== --- sys/ddb/db_ps.c +++ sys/ddb/db_ps.c @@ -257,7 +257,11 @@ void *wchan; if (all) { - db_printf("%6d ", td->td_tid); + db_printf("%6d ", td->td_tid); + if (TD_IS_SUGID(td)) + db_printf("%5d ", td->td_ucred->cr_ruid); + else + db_printf(" "); switch (td->td_state) { case TDS_RUNNING: snprintf(state, sizeof(state), "Run"); @@ -340,6 +344,7 @@ struct lock_object *lock; bool comma; int delta; + int i; /* Determine which thread to examine. */ if (have_addr) @@ -350,6 +355,15 @@ db_printf("Thread %d at %p:\n", td->td_tid, td); db_printf(" proc (pid %d): %p\n", td->td_proc->p_pid, td->td_proc); + if (TD_IS_SUGID(td)) { + db_printf(" uid: %d gids: ", td->td_ucred->cr_uid); + for (i = 0; i < td->td_ucred->cr_ngroups; i++) { + db_printf("%d", td->td_ucred->cr_groups[i]); + if (i < (td->td_ucred->cr_ngroups - 1)) + db_printf(", "); + } + db_printf("\n"); + } if (td->td_name[0] != '\0') db_printf(" name: %s\n", td->td_name); db_printf(" stack: %p-%p\n", (void *)td->td_kstack, Index: sys/fs/unionfs/union_subr.c =================================================================== --- sys/fs/unionfs/union_subr.c +++ sys/fs/unionfs/union_subr.c @@ -772,7 +772,7 @@ */ chgproccnt(cred->cr_ruidinfo, 1, 0); change_euid(cred, rootinfo); - change_ruid(cred, rootinfo); + change_ruid(cred, rootinfo, 1); change_svuid(cred, (uid_t)0); uifree(rootinfo); cnp->cn_cred = cred; Index: sys/kern/kern_proc.c =================================================================== --- sys/kern/kern_proc.c +++ sys/kern/kern_proc.c @@ -954,7 +954,6 @@ struct thread *td0; struct tty *tp; struct session *sp; - struct ucred *cred; struct sigacts *ps; struct timeval boottime; @@ -974,34 +973,6 @@ kp->ki_vmspace = p->p_vmspace; kp->ki_flag = p->p_flag; kp->ki_flag2 = p->p_flag2; - cred = p->p_ucred; - if (cred) { - kp->ki_uid = cred->cr_uid; - kp->ki_ruid = cred->cr_ruid; - kp->ki_svuid = cred->cr_svuid; - kp->ki_cr_flags = 0; - if (cred->cr_flags & CRED_FLAG_CAPMODE) - kp->ki_cr_flags |= KI_CRF_CAPABILITY_MODE; - /* XXX bde doesn't like KI_NGROUPS */ - if (cred->cr_ngroups > KI_NGROUPS) { - kp->ki_ngroups = KI_NGROUPS; - kp->ki_cr_flags |= KI_CRF_GRP_OVERFLOW; - } else - kp->ki_ngroups = cred->cr_ngroups; - bcopy(cred->cr_groups, kp->ki_groups, - kp->ki_ngroups * sizeof(gid_t)); - kp->ki_rgid = cred->cr_rgid; - kp->ki_svgid = cred->cr_svgid; - /* If jailed(cred), emulate the old P_JAILED flag. */ - if (jailed(cred)) { - kp->ki_flag |= P_JAILED; - /* If inside the jail, use 0 as a jail ID. */ - if (cred->cr_prison != curthread->td_ucred->cr_prison) - kp->ki_jid = cred->cr_prison->pr_id; - } - strlcpy(kp->ki_loginclass, cred->cr_loginclass->lc_name, - sizeof(kp->ki_loginclass)); - } ps = p->p_sigacts; if (ps) { mtx_lock(&ps->ps_mtx); @@ -1107,6 +1078,7 @@ fill_kinfo_thread(struct thread *td, struct kinfo_proc *kp, int preferthread) { struct proc *p; + struct ucred *cred; p = td->td_proc; kp->ki_tdaddr = td; @@ -1115,6 +1087,34 @@ if (preferthread) PROC_STATLOCK(p); thread_lock(td); + cred = td->td_ucred; + if (cred) { + kp->ki_uid = cred->cr_uid; + kp->ki_ruid = cred->cr_ruid; + kp->ki_svuid = cred->cr_svuid; + kp->ki_cr_flags = 0; + if (cred->cr_flags & CRED_FLAG_CAPMODE) + kp->ki_cr_flags |= KI_CRF_CAPABILITY_MODE; + /* XXX bde doesn't like KI_NGROUPS */ + if (cred->cr_ngroups > KI_NGROUPS) { + kp->ki_ngroups = KI_NGROUPS; + kp->ki_cr_flags |= KI_CRF_GRP_OVERFLOW; + } else + kp->ki_ngroups = cred->cr_ngroups; + bcopy(cred->cr_groups, kp->ki_groups, + kp->ki_ngroups * sizeof(gid_t)); + kp->ki_rgid = cred->cr_rgid; + kp->ki_svgid = cred->cr_svgid; + /* If jailed(cred), emulate the old P_JAILED flag. */ + if (jailed(cred)) { + kp->ki_flag |= P_JAILED; + /* If inside the jail, use 0 as a jail ID. */ + if (cred->cr_prison != curthread->td_ucred->cr_prison) + kp->ki_jid = cred->cr_prison->pr_id; + } + strlcpy(kp->ki_loginclass, cred->cr_loginclass->lc_name, + sizeof(kp->ki_loginclass)); + } if (td->td_wmesg != NULL) strlcpy(kp->ki_wmesg, td->td_wmesg, sizeof(kp->ki_wmesg)); else Index: sys/kern/kern_prot.c =================================================================== --- sys/kern/kern_prot.c +++ sys/kern/kern_prot.c @@ -87,6 +87,11 @@ static void crsetgroups_locked(struct ucred *cr, int ngrp, gid_t *groups); +static int kern_setresuid(struct thread *td, + struct ucred *newcred, struct ucred *oldcred, + uid_t ruid, uid_t euid, uid_t suid, + struct uidinfo *euip, struct uidinfo *ruip, + int chgproccnt); #ifndef _SYS_SYSPROTO_H_ struct getpid_args { @@ -219,9 +224,9 @@ sys_getuid(struct thread *td, struct getuid_args *uap) { - td->td_retval[0] = td->td_ucred->cr_ruid; + td->td_retval[0] = td->td_pucred->cr_ruid; #if defined(COMPAT_43) - td->td_retval[1] = td->td_ucred->cr_uid; + td->td_retval[1] = td->td_pucred->cr_uid; #endif return (0); } @@ -236,7 +241,7 @@ sys_geteuid(struct thread *td, struct geteuid_args *uap) { - td->td_retval[0] = td->td_ucred->cr_uid; + td->td_retval[0] = td->td_pucred->cr_uid; return (0); } @@ -250,9 +255,9 @@ sys_getgid(struct thread *td, struct getgid_args *uap) { - td->td_retval[0] = td->td_ucred->cr_rgid; + td->td_retval[0] = td->td_pucred->cr_rgid; #if defined(COMPAT_43) - td->td_retval[1] = td->td_ucred->cr_groups[0]; + td->td_retval[1] = td->td_pucred->cr_groups[0]; #endif return (0); } @@ -272,7 +277,7 @@ sys_getegid(struct thread *td, struct getegid_args *uap) { - td->td_retval[0] = td->td_ucred->cr_groups[0]; + td->td_retval[0] = td->td_pucred->cr_groups[0]; return (0); } @@ -289,7 +294,7 @@ u_int ngrp; int error; - cred = td->td_ucred; + cred = td->td_pucred; ngrp = cred->cr_ngroups; if (uap->gidsetsize == 0) { @@ -538,7 +543,7 @@ * Set the real uid and transfer proc count to new user. */ if (uid != oldcred->cr_ruid) { - change_ruid(newcred, uip); + change_ruid(newcred, uip, 1); setsugid(p); } /* @@ -792,6 +797,8 @@ int sys_setgroups(struct thread *td, struct setgroups_args *uap) { + struct ucred *newcred, *oldcred; + struct proc *p = td->td_proc; gid_t smallgroups[XU_NGROUPS]; gid_t *groups; u_int gidsetsize; @@ -807,37 +814,43 @@ groups = smallgroups; error = copyin(uap->gidset, groups, gidsetsize * sizeof(gid_t)); - if (error == 0) - error = kern_setgroups(td, gidsetsize, groups); + if (error != 0) + goto out; + MPASS(gidsetsize <= ngroups_max + 1); + AUDIT_ARG_GROUPSET(groups, gidsetsize); + + newcred = crget(); + crextend(newcred, gidsetsize); + PROC_LOCK(p); + oldcred = crcopysafe(p, newcred); + error = kern_setgroups(td, newcred, oldcred, gidsetsize, groups); + if (error == 0) + proc_set_cred(p, newcred); + PROC_UNLOCK(p); + crfree(error ? newcred : oldcred); +out: if (gidsetsize > XU_NGROUPS) free(groups, M_TEMP); return (error); } int -kern_setgroups(struct thread *td, u_int ngrp, gid_t *groups) +kern_setgroups(struct thread *td, struct ucred *newcred, struct ucred *oldcred, + u_int ngrp, gid_t *groups) { struct proc *p = td->td_proc; - struct ucred *newcred, *oldcred; int error; - MPASS(ngrp <= ngroups_max + 1); - AUDIT_ARG_GROUPSET(groups, ngrp); - newcred = crget(); - crextend(newcred, ngrp); - PROC_LOCK(p); - oldcred = crcopysafe(p, newcred); - #ifdef MAC error = mac_cred_check_setgroups(oldcred, ngrp, groups); if (error) - goto fail; + goto out; #endif error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS); if (error) - goto fail; + goto out; if (ngrp == 0) { /* @@ -851,14 +864,8 @@ crsetgroups_locked(newcred, ngrp, groups); } setsugid(p); - proc_set_cred(p, newcred); - PROC_UNLOCK(p); - crfree(oldcred); - return (0); -fail: - PROC_UNLOCK(p); - crfree(newcred); +out: return (error); } @@ -906,7 +913,7 @@ setsugid(p); } if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { - change_ruid(newcred, ruip); + change_ruid(newcred, ruip, 1); setsugid(p); } if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && @@ -1030,10 +1037,45 @@ PROC_LOCK(p); oldcred = crcopysafe(p, newcred); + error = kern_setresuid(td, newcred, oldcred, ruid, euid, suid, + euip, ruip, 1); + if (error != 0) + goto fail; + proc_set_cred(p, newcred); +#ifdef RACCT + racct_proc_ucred_changed(p, oldcred, newcred); + crhold(newcred); +#endif + PROC_UNLOCK(p); +#ifdef RCTL + rctl_proc_ucred_changed(p, newcred); + crfree(newcred); +#endif + uifree(ruip); + uifree(euip); + crfree(oldcred); + return (0); + +fail: + PROC_UNLOCK(p); + uifree(ruip); + uifree(euip); + crfree(newcred); + return (error); + +} + +static int __always_inline +kern_setresuid(struct thread *td, struct ucred *newcred, struct ucred *oldcred, + uid_t ruid, uid_t euid, uid_t suid, + struct uidinfo *euip, struct uidinfo *ruip, int chgproccnt) +{ + int error; + #ifdef MAC error = mac_cred_check_setresuid(oldcred, ruid, euid, suid); if (error) - goto fail; + return (error); #endif if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && @@ -1046,42 +1088,22 @@ suid != oldcred->cr_svuid && suid != oldcred->cr_uid)) && (error = priv_check_cred(oldcred, PRIV_CRED_SETRESUID)) != 0) - goto fail; + return (error); if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { change_euid(newcred, euip); - setsugid(p); + setsugid(td->td_proc); } if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { - change_ruid(newcred, ruip); - setsugid(p); + change_ruid(newcred, ruip, chgproccnt); + setsugid(td->td_proc); } if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { change_svuid(newcred, suid); - setsugid(p); + setsugid(td->td_proc); } - proc_set_cred(p, newcred); -#ifdef RACCT - racct_proc_ucred_changed(p, oldcred, newcred); - crhold(newcred); -#endif - PROC_UNLOCK(p); -#ifdef RCTL - rctl_proc_ucred_changed(p, newcred); - crfree(newcred); -#endif - uifree(ruip); - uifree(euip); - crfree(oldcred); - return (0); - -fail: - PROC_UNLOCK(p); - uifree(ruip); - uifree(euip); - crfree(newcred); - return (error); + return (0); } /* @@ -1169,7 +1191,7 @@ struct ucred *cred; int error1 = 0, error2 = 0, error3 = 0; - cred = td->td_ucred; + cred = td->td_pucred; if (uap->ruid) error1 = copyout(&cred->cr_ruid, uap->ruid, sizeof(cred->cr_ruid)); @@ -1196,7 +1218,7 @@ struct ucred *cred; int error1 = 0, error2 = 0, error3 = 0; - cred = td->td_ucred; + cred = td->td_pucred; if (uap->rgid) error1 = copyout(&cred->cr_rgid, uap->rgid, sizeof(cred->cr_rgid)); @@ -2219,15 +2241,16 @@ * duration of the call. */ void -change_ruid(struct ucred *newcred, struct uidinfo *ruip) +change_ruid(struct ucred *newcred, struct uidinfo *ruip, int do_chgproccnt) { - - (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); + if (do_chgproccnt != 0) + (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); newcred->cr_ruid = ruip->ui_uid; uihold(ruip); uifree(newcred->cr_ruidinfo); newcred->cr_ruidinfo = ruip; - (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); + if (do_chgproccnt != 0) + (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); } /*- @@ -2268,3 +2291,118 @@ newcred->cr_svgid = svgid; } + +/* + * Set credentials. + */ +#ifndef _SYS_SYSPROTO_H_ +struct setcred_args { + uid_t uid; + int gidsetlen; + const gid_t *gidset; +}; +#endif +/* ARGSUSED */ +int +sys_setcred(struct thread *td, struct setcred_args *uap) +{ + struct ucred *newcred, *oldcred; + struct uidinfo *uip; + gid_t smallgroups[XU_NGROUPS]; + gid_t *groups; + int gidsetlen; + int error; + + gidsetlen = uap->gidsetlen; + if (gidsetlen > ngroups_max + 1) + return (EINVAL); + AUDIT_ARG_UID(uap->uid); + error = priv_check_cred(td->td_pucred, PRIV_CRED_SETUID); + if (error != 0) + return (error); + oldcred = td->td_ucred; + newcred = crdup(oldcred); + crextend(newcred, gidsetlen); + uip = uifind(uap->uid); + if (gidsetlen > XU_NGROUPS) + groups = malloc(gidsetlen * sizeof(gid_t), M_TEMP, M_WAITOK); + else + groups = smallgroups; + error = copyin(uap->gidset, groups, gidsetlen * sizeof(gid_t)); + if (error != 0) + goto out; + + AUDIT_ARG_GROUPSET(groups, gidsetlen); + PROC_LOCK(td->td_proc); + error = kern_setresuid(td, newcred, td->td_pucred, uap->uid, + uap->uid, uap->uid, uip, uip, 0); + if (error != 0) + goto unlock; + error = kern_setgroups(td, newcred, td->td_pucred, gidsetlen, + groups); + td->td_ucred = newcred; + td->td_pflags |= TDP_SUGID; + +unlock: + PROC_UNLOCK(td->td_proc); +out: + if (gidsetlen > XU_NGROUPS) + free(groups, M_TEMP); + uifree(uip); + crfree(error ? newcred : oldcred); + return (error); +} + +/* + * Get credentials. + */ +#ifndef _SYS_SYSPROTO_H_ +struct getcred_args { + uid_t *uid; + int *gidsetlen; + gid_t *gidset; +}; +#endif +/* ARGSUSED */ +int +sys_getcred(struct thread *td, struct getcred_args *uap) +{ + struct ucred *cred; + int gidsetlen = 0; + int error; + const int zero = 0; + + error = copyin(uap->gidsetlen, &gidsetlen, sizeof(int)); + if (error != 0) + return (error); + error = copyout(&zero, uap->gidsetlen, sizeof(*uap->gidsetlen)); + if (error != 0) + return (error); + if (!TD_IS_SUGID(td)) + return (ENOENT); + cred = td->td_ucred; + error = copyout(&cred->cr_ruid, uap->uid, sizeof(*uap->uid)); + if (gidsetlen < cred->cr_ngroups) + return (ERANGE); + error = copyout(cred->cr_groups, uap->gidset, + cred->cr_ngroups * sizeof(*uap->gidset)); + if (error != 0) + return (error); + error = copyout(&cred->cr_ngroups, uap->gidsetlen, + sizeof(*uap->gidsetlen)); + return (error); +} + +int +sys_revertcred(struct thread *td, struct revertcred_args *uap) +{ + int error; + + error = priv_check_cred(td->td_proc->p_ucred, PRIV_CRED_SETUID); + if (error != 0) + return (error); + td->td_pflags &= ~TDP_SUGID; + crfree(td->td_ucred); + td->td_ucred = crhold(td->td_pucred); + return (0); +} Index: sys/kern/kern_thread.c =================================================================== --- sys/kern/kern_thread.c +++ sys/kern/kern_thread.c @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include #include #include @@ -61,6 +63,8 @@ #endif #include +#include +#include #include #include @@ -82,9 +86,9 @@ "struct thread KBI td_flags"); _Static_assert(offsetof(struct thread, td_pflags) == 0x104, "struct thread KBI td_pflags"); -_Static_assert(offsetof(struct thread, td_frame) == 0x478, +_Static_assert(offsetof(struct thread, td_frame) == 0x480, "struct thread KBI td_frame"); -_Static_assert(offsetof(struct thread, td_emuldata) == 0x530, +_Static_assert(offsetof(struct thread, td_emuldata) == 0x538, "struct thread KBI td_emuldata"); _Static_assert(offsetof(struct proc, p_flag) == 0xb0, "struct proc KBI p_flag"); @@ -453,6 +457,7 @@ { PROC_LOCK_ASSERT(p, MA_OWNED); + newtd->td_pucred = crhold(p->p_ucred); newtd->td_ucred = crhold(p->p_ucred); newtd->td_limit = lim_hold(p->p_limit); newtd->td_cowgen = p->p_cowgen; @@ -463,6 +468,7 @@ { newtd->td_ucred = crhold(td->td_ucred); + newtd->td_pucred = crhold(td->td_pucred); newtd->td_limit = lim_hold(td->td_limit); newtd->td_cowgen = td->td_cowgen; } @@ -473,6 +479,8 @@ if (td->td_ucred != NULL) crfree(td->td_ucred); + if (td->td_pucred != NULL) + crfree(td->td_pucred); if (td->td_limit != NULL) lim_free(td->td_limit); } @@ -481,16 +489,15 @@ thread_cow_update(struct thread *td) { struct proc *p; - struct ucred *oldcred; - struct plimit *oldlimit; + struct ucred *oldcred = NULL; + struct plimit *oldlimit = NULL; + struct ucred *tcred, *pcred; p = td->td_proc; - oldcred = NULL; - oldlimit = NULL; PROC_LOCK(p); - if (td->td_ucred != p->p_ucred) { - oldcred = td->td_ucred; - td->td_ucred = crhold(p->p_ucred); + if (td->td_pucred != p->p_ucred) { + oldcred = td->td_pucred; + td->td_pucred = crhold(p->p_ucred); } if (td->td_limit != p->p_limit) { oldlimit = td->td_limit; @@ -502,6 +509,36 @@ crfree(oldcred); if (oldlimit != NULL) lim_free(oldlimit); + if (td->td_ucred != td->td_pucred) { + if (!TD_IS_SUGID(td)) { + crfree(td->td_ucred); + td->td_ucred = crhold(td->td_pucred); + } else { + tcred = td->td_ucred; + pcred = td->td_pucred; +#ifdef MAC + if (tcred->cr_label != pcred->cr_label) { + mac_cred_label_free(tcred->cr_label); + mac_cred_relabel(tcred, pcred->cr_label); + } +#endif /* MAC */ + if (tcred->cr_loginclass != pcred->cr_loginclass) { + loginclass_free(tcred->cr_loginclass); + loginclass_hold(pcred->cr_loginclass); + tcred->cr_loginclass = pcred->cr_loginclass; + } + if (tcred->cr_prison != pcred->cr_prison) { + prison_free(tcred->cr_prison); + prison_hold(pcred->cr_prison); + tcred->cr_prison = pcred->cr_prison; + } +#ifdef AUDIT + audit_cred_destroy(tcred); + audit_cred_copy(pcred, tcred); +#endif /* AUDIT */ + tcred->cr_flags = pcred->cr_flags; + } + } } /* Index: sys/kern/syscalls.master =================================================================== --- sys/kern/syscalls.master +++ sys/kern/syscalls.master @@ -3167,6 +3167,23 @@ size_t bufsize ); } +568 AUE_GETCRED STD { + int getcred( + _Out_ uid_t *uid, + _Inout_ int *gidsetlen, + _Out_writes_(*gidsetlen) gid_t *gidset + ); + } +569 AUE_SETCRED STD { + int setcred( + uid_t uid, + int gidsetlen, + _In_reads_(gidsetlen) const gid_t *gidset + ); + } +570 AUE_REVERTCRED STD { + int revertcred(void); + } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master Index: sys/security/audit/audit_bsm.c =================================================================== --- sys/security/audit/audit_bsm.c +++ sys/security/audit/audit_bsm.c @@ -1466,6 +1466,29 @@ } break; + case AUE_SETCRED: + if (ARG_IS_VALID(kar, ARG_UID)) { + tok = au_to_arg32(1, "uid", ar->ar_arg_uid); + kau_write(rec, tok); + } + if (ARG_IS_VALID(kar, ARG_GROUPSET)) { + for(ctr = 0; ctr < ar->ar_arg_groups.gidset_size; ctr++) + { + tok = au_to_arg32(1, "gidset", + ar->ar_arg_groups.gidset[ctr]); + kau_write(rec, tok); + } + } + break; + + case AUE_GETCRED: + case AUE_REVERTCRED: + + /* + * Header, subject, and return tokens added at end. + */ + break; + case AUE_SETLOGIN: if (ARG_IS_VALID(kar, ARG_LOGIN)) { tok = au_to_text(ar->ar_arg_login); Index: sys/sys/proc.h =================================================================== --- sys/sys/proc.h +++ sys/sys/proc.h @@ -265,7 +265,8 @@ struct lock_list_entry *td_sleeplocks; /* (k) Held sleep locks. */ int td_intr_nesting_level; /* (k) Interrupt recursion. */ int td_pinned; /* (k) Temporary cpu pin count. */ - struct ucred *td_ucred; /* (k) Reference to credentials. */ + struct ucred *td_pucred; /* (k) Reference to process creds. */ + struct ucred *td_ucred; /* (k) Reference to thread creds. */ struct plimit *td_limit; /* (k) Resource limits. */ int td_slptick; /* (t) Time at sleep. */ int td_blktick; /* (t) Time spent blocked. */ @@ -492,6 +493,7 @@ #define TDP_UIOHELD 0x10000000 /* Current uio has pages held in td_ma */ #define TDP_FORKING 0x20000000 /* Thread is being created through fork() */ #define TDP_EXECVMSPC 0x40000000 /* Execve destroyed old vmspace */ +#define TDP_SUGID 0x80000000 /* Thread is tainted by setcred(2) */ /* * Reasons that the current thread can not be run yet. @@ -514,7 +516,8 @@ #define TD_CAN_RUN(td) ((td)->td_state == TDS_CAN_RUN) #define TD_IS_INHIBITED(td) ((td)->td_state == TDS_INHIBITED) #define TD_ON_UPILOCK(td) ((td)->td_flags & TDF_UPIBLOCKED) -#define TD_IS_IDLETHREAD(td) ((td)->td_flags & TDF_IDLETD) +#define TD_IS_IDLETHREAD(td) ((td)->td_flags & TDF_IDLETD) +#define TD_IS_SUGID(td) ((td)->td_pflags & TDP_SUGID) #define KTDSTATE(td) \ (((td)->td_inhibitors & TDI_SLEEPING) != 0 ? "sleep" : \ Index: sys/sys/syscallsubr.h =================================================================== --- sys/sys/syscallsubr.h +++ sys/sys/syscallsubr.h @@ -238,7 +238,8 @@ fd_set *fd_ex, struct timeval *tvp, int abi_nfdbits); int kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags, struct mbuf *control, enum uio_seg segflg); -int kern_setgroups(struct thread *td, u_int ngrp, gid_t *groups); +int kern_setgroups(struct thread *td, struct ucred *newcred, + struct ucred *oldcred, u_int ngrp, gid_t *groups); int kern_setitimer(struct thread *, u_int, struct itimerval *, struct itimerval *); int kern_setrlimit(struct thread *, u_int, struct rlimit *); Index: sys/sys/ucred.h =================================================================== --- sys/sys/ucred.h +++ sys/sys/ucred.h @@ -62,13 +62,13 @@ struct prison *cr_prison; /* jail(2) */ struct loginclass *cr_loginclass; /* login class */ u_int cr_flags; /* credential flags */ - void *cr_pspare2[2]; /* general use 2 */ + void *cr_pspare2[2]; /* general use 2 */ #define cr_endcopy cr_label struct label *cr_label; /* MAC label */ struct auditinfo_addr cr_audit; /* Audit properties. */ gid_t *cr_groups; /* groups */ int cr_agroups; /* Available groups */ - gid_t cr_smallgroups[XU_NGROUPS]; /* storage for small groups */ + gid_t cr_smallgroups[XU_NGROUPS]; /* storage for small groups */ }; #define NOCRED ((struct ucred *)0) /* no credential available */ #define FSCRED ((struct ucred *)-1) /* filesystem credential */ @@ -101,7 +101,7 @@ void change_egid(struct ucred *newcred, gid_t egid); void change_euid(struct ucred *newcred, struct uidinfo *euip); void change_rgid(struct ucred *newcred, gid_t rgid); -void change_ruid(struct ucred *newcred, struct uidinfo *ruip); +void change_ruid(struct ucred *newcred, struct uidinfo *ruip, int do_chgproccnt); void change_svgid(struct ucred *newcred, gid_t svgid); void change_svuid(struct ucred *newcred, uid_t svuid); void crcopy(struct ucred *dest, struct ucred *src); Index: usr.bin/procstat/procstat_cred.c =================================================================== --- usr.bin/procstat/procstat_cred.c +++ usr.bin/procstat/procstat_cred.c @@ -43,19 +43,53 @@ static const char *get_umask(struct procstat *procstat, struct kinfo_proc *kipp); +static void procstat_emit(struct procstat *procstat, + struct kinfo_proc *kipp); void procstat_cred(struct procstat *procstat, struct kinfo_proc *kipp) { - unsigned int i, ngroups; - gid_t *groups; + struct kinfo_proc *kip; + unsigned int i, count; if ((procstat_opts & PS_OPT_NOHEADER) == 0) - xo_emit("{T:/%5s %-16s %5s %5s %5s %5s %5s %5s %5s %5s %-15s}\n", - "PID", "COMM", "EUID", "RUID", "SVUID", "EGID", "RGID", + xo_emit("{T:/%5s %6s %-16s %5s %5s %5s %5s %5s %5s %5s %5s %-15s}\n", + "PID", "TID", "COMM", "EUID", "RUID", "SVUID", "EGID", "RGID", "SVGID", "UMASK", "FLAGS", "GROUPS"); - xo_emit("{k:process_id/%5d/%d} ", kipp->ki_pid); + kip = procstat_getprocs(procstat, KERN_PROC_PID | KERN_PROC_INC_THREAD, + kipp->ki_pid, &count); + if (kip == NULL) + return; + kinfo_proc_sort(kip, count); + for (i = 0; i < count; i++) { + kipp = &kip[i]; + procstat_emit(procstat, kipp); + } + +} + +static const char * +get_umask(struct procstat *procstat, struct kinfo_proc *kipp) +{ + u_short fd_cmask; + static char umask[4]; + + if (procstat_getumask(procstat, kipp, &fd_cmask) == 0) { + snprintf(umask, 4, "%03o", fd_cmask); + return (umask); + } else { + return ("-"); + } +} + +static void procstat_emit(struct procstat *procstat, struct kinfo_proc *kipp) +{ + unsigned int i, ngroups; + gid_t *groups; + + xo_emit("{d:process_id/%5d/%d} ", kipp->ki_pid); + xo_emit("{dk:thread_id/%6d/%d} ", kipp->ki_tid); xo_emit("{:command/%-16s/%s} ", kipp->ki_comm); xo_emit("{:uid/%5d} ", kipp->ki_uid); xo_emit("{:ruid/%5d} ", kipp->ki_ruid); @@ -89,17 +123,3 @@ xo_close_list("groups"); xo_emit("\n"); } - -static const char * -get_umask(struct procstat *procstat, struct kinfo_proc *kipp) -{ - u_short fd_cmask; - static char umask[4]; - - if (procstat_getumask(procstat, kipp, &fd_cmask) == 0) { - snprintf(umask, 4, "%03o", fd_cmask); - return (umask); - } else { - return ("-"); - } -}