- register struct a {
- int rgid;
- int egid;
- } *uap;
- register int rgid, egid;
-
- uap = (struct a *)u.u_ap;
- rgid = uap->rgid;
- if (rgid == -1)
- rgid = u.u_rgid;
- if (u.u_rgid != rgid && u.u_gid != rgid && !suser())
- return;
- egid = uap->egid;
- if (egid == -1)
- egid = u.u_gid;
- if (u.u_rgid != egid && u.u_gid != egid && !suser())
- return;
- if (u.u_rgid != rgid) {
- leavegroup(u.u_rgid);
- (void) entergroup(u.u_rgid);
- u.u_rgid = rgid;
- }
- if (u.u_gid != egid) {
- leavegroup(u.u_gid);
- (void) entergroup(egid);
- u.u_gid = egid;
- }
+ register struct pcred *pc = p->p_cred;
+ register gid_t gid;
+ int error;
+
+ gid = SCARG(uap, gid);
+ if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
+ return (error);
+ pc->pc_ucred = crcopy(pc->pc_ucred);
+ pc->pc_ucred->cr_groups[0] = gid;
+ pc->p_rgid = gid;
+ pc->p_svgid = gid; /* ??? */
+ p->p_flag |= P_SUGID;
+ return (0);
+}
+
+/* ARGSUSED */
+int
+setegid(p, uap, retval)
+ struct proc *p;
+ struct setegid_args /* {
+ syscallarg(gid_t) egid;
+ } */ *uap;
+ register_t *retval;
+{
+ register struct pcred *pc = p->p_cred;
+ register gid_t egid;
+ int error;
+
+ egid = SCARG(uap, egid);
+ if (egid != pc->p_rgid && egid != pc->p_svgid &&
+ (error = suser(pc->pc_ucred, &p->p_acflag)))
+ return (error);
+ pc->pc_ucred = crcopy(pc->pc_ucred);
+ pc->pc_ucred->cr_groups[0] = egid;
+ p->p_flag |= P_SUGID;
+ return (0);
+}
+
+/* ARGSUSED */
+int
+setgroups(p, uap, retval)
+ struct proc *p;
+ struct setgroups_args /* {
+ syscallarg(u_int) gidsetsize;
+ syscallarg(gid_t *) gidset;
+ } */ *uap;
+ register_t *retval;
+{
+ register struct pcred *pc = p->p_cred;
+ register u_int ngrp;
+ int error;
+
+ if (error = suser(pc->pc_ucred, &p->p_acflag))
+ return (error);
+ ngrp = SCARG(uap, gidsetsize);
+ if (ngrp < 1 || ngrp > NGROUPS)
+ return (EINVAL);
+ pc->pc_ucred = crcopy(pc->pc_ucred);
+ if (error = copyin((caddr_t)SCARG(uap, gidset),
+ (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))
+ return (error);
+ pc->pc_ucred->cr_ngroups = ngrp;
+ p->p_flag |= P_SUGID;
+ return (0);