| 823 | } |
| 824 | |
| 825 | int |
| 826 | kern_setgroups(struct thread *td, u_int ngrp, gid_t *groups) |
| 827 | { |
| 828 | struct proc *p = td->td_proc; |
| 829 | struct ucred *newcred, *oldcred; |
| 830 | int error; |
| 831 | |
| 832 | MPASS(ngrp <= ngroups_max + 1); |
| 833 | AUDIT_ARG_GROUPSET(groups, ngrp); |
| 834 | newcred = crget(); |
| 835 | crextend(newcred, ngrp); |
| 836 | PROC_LOCK(p); |
| 837 | oldcred = crcopysafe(p, newcred); |
| 838 | |
| 839 | #ifdef MAC |
| 840 | error = mac_cred_check_setgroups(oldcred, ngrp, groups); |
| 841 | if (error) |
| 842 | goto fail; |
| 843 | #endif |
| 844 | |
| 845 | error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS); |
| 846 | if (error) |
| 847 | goto fail; |
| 848 | |
| 849 | if (ngrp == 0) { |
| 850 | /* |
| 851 | * setgroups(0, NULL) is a legitimate way of clearing the |
| 852 | * groups vector on non-BSD systems (which generally do not |
| 853 | * have the egid in the groups[0]). We risk security holes |
| 854 | * when running non-BSD software if we do not do the same. |
| 855 | */ |
| 856 | newcred->cr_ngroups = 1; |
| 857 | } else { |
| 858 | crsetgroups_locked(newcred, ngrp, groups); |
| 859 | } |
| 860 | setsugid(p); |
| 861 | proc_set_cred(p, newcred); |
| 862 | PROC_UNLOCK(p); |
| 863 | crfree(oldcred); |
| 864 | return (0); |
| 865 | |
| 866 | fail: |
| 867 | PROC_UNLOCK(p); |
| 868 | crfree(newcred); |
| 869 | return (error); |
| 870 | } |
| 871 | |
| 872 | #ifndef _SYS_SYSPROTO_H_ |
| 873 | struct setreuid_args { |
no test coverage detected