+ if (gid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag)))
+ return (error);
+ if (u.u_cred->cr_ref > 1)
+ u.u_cred = crcopy(u.u_cred);
+ p->p_rgid = gid;
+ u.u_cred->cr_groups[0] = gid;
+ p->p_svgid = gid; /* ??? */
+ return (0);
+}
+
+/* ARGSUSED */
+setegid(p, uap, retval)
+ struct proc *p;
+ struct args {
+ int egid;
+ } *uap;
+ int *retval;
+{
+ register gid_t egid;
+ int error;
+
+ egid = uap->egid;
+ if (egid != p->p_rgid && egid != p->p_svgid &&
+ (error = suser(u.u_cred, &u.u_acflag)))
+ return (error);
+ if (u.u_cred->cr_ref > 1)
+ u.u_cred = crcopy(u.u_cred);
+ u.u_cred->cr_groups[0] = egid;
+ return (0);
+}
+
+#ifdef COMPAT_43
+/* ARGSUSED */
+osetreuid(p, uap, retval)
+ register struct proc *p;
+ struct args {
+ int ruid;
+ int euid;
+ } *uap;
+ int *retval;
+{
+ register uid_t ruid, euid;
+ int error;
+
+ if (uap->ruid == -1)
+ (error = suser(u.u_cred, &u.u_acflag)))
+ return (error);
+ if (uap->euid == -1)
+ euid != p->p_svuid && (error = suser(u.u_cred, &u.u_acflag)))
+ return (error);
+ /*
+ * Everything's okay, do it.
+ * Copy credentials so other references do not
+ * see our changes.
+ */
+ if (u.u_cred->cr_ref > 1)
+ u.u_cred = crcopy(u.u_cred);
+ u.u_cred->cr_uid = euid;
+ p->p_uid = euid;
+ p->p_ruid = ruid;
+ return (0);
+}
+
+/* ARGSUSED */
+osetregid(p, uap, retval)
+ struct proc *p;
+ struct args {
+ int rgid;
+ int egid;
+ } *uap;
+ int *retval;
+{
+ register gid_t rgid, egid;
+ int error;
+
+ if (uap->rgid == -1)
+ (error = suser(u.u_cred, &u.u_acflag)))
+ return (error);
+ if (uap->egid == -1)
+ egid != p->p_svgid && (error = suser(u.u_cred, &u.u_acflag)))
+ return (error);
+ if (u.u_cred->cr_ref > 1)
+ u.u_cred = crcopy(u.u_cred);
+ p->p_rgid = rgid;
+ u.u_cred->cr_groups[0] = egid;
+ return (0);
+}
+#endif
+
+/* ARGSUSED */
+setgroups(p, uap, retval)
+ struct proc *p;
+ struct args {
+ u_int gidsetsize;
+ int *gidset;
+ } *uap;
+ int *retval;
+{
+ register gid_t *gp;
+ register int *lp;
+ int error, ngrp, groups[NGROUPS];
+
+ if (error = suser(u.u_cred, &u.u_acflag))
+ return (error);
+ ngrp = uap->gidsetsize;
+ if (ngrp > NGROUPS)
+ return (EINVAL);
+ error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
+ uap->gidsetsize * sizeof (groups[0]));
+ if (error)
+ return (error);
+ gp = u.u_cred->cr_groups;
+ for (lp = groups; lp < &groups[uap->gidsetsize]; )
+ *gp++ = *lp++;
+ u.u_cred->cr_ngroups = ngrp;
+ return (0);
+}
+
+/*
+ * Check if gid is a member of the group set.
+ */
+groupmember(gid, cred)
+ gid_t gid;
+ register struct ucred *cred;
+{
+ register gid_t *gp;
+ gid_t *egp;
+
+ egp = &(cred->cr_groups[cred->cr_ngroups]);
+ for (gp = cred->cr_groups; gp < egp; gp++)
+ if (*gp == gid)
+ return (1);
+ return (0);
+}
+
+/*
+ * Test if the current user is the super user.
+ */
+suser(cred, acflag)
+ struct ucred *cred;
+ short *acflag;
+{
+
+ if (cred->cr_uid == 0) {
+ if (acflag)
+ *acflag |= ASU;
+ return (0);
+ }
+ return (EPERM);
+}
+
+/*
+ * Allocate a zeroed cred structure.
+ */
+struct ucred *
+crget()
+{
+ register struct ucred *cr;
+
+ MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
+ bzero((caddr_t)cr, sizeof(*cr));
+ cr->cr_ref = 1;
+ return (cr);
+}
+
+/*
+ * Free a cred structure.
+ * Throws away space when ref count gets to 0.
+ */
+crfree(cr)
+ struct ucred *cr;
+{
+ int s = splimp();
+
+ if (--cr->cr_ref != 0) {
+ (void) splx(s);
+ return;