+/* ARGSUSED */
+int
+getegid(p, uap, retval)
+ struct proc *p;
+ void *uap;
+ register_t *retval;
+{
+
+ *retval = p->p_ucred->cr_groups[0];
+ return (0);
+}
+
+int
+getgroups(p, uap, retval)
+ struct proc *p;
+ register struct getgroups_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 ((ngrp = SCARG(uap, gidsetsize)) == 0) {
+ *retval = pc->pc_ucred->cr_ngroups;
+ return (0);
+ }
+ if (ngrp < pc->pc_ucred->cr_ngroups)
+ return (EINVAL);
+ ngrp = pc->pc_ucred->cr_ngroups;
+ if (error = copyout((caddr_t)pc->pc_ucred->cr_groups,
+ (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t)))
+ return (error);
+ *retval = ngrp;
+ return (0);
+}
+
+/* ARGSUSED */
+int
+setsid(p, uap, retval)
+ register struct proc *p;
+ void *uap;
+ register_t *retval;
+{
+
+ if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
+ return (EPERM);
+ } else {
+ (void)enterpgrp(p, p->p_pid, 1);
+ *retval = p->p_pid;
+ return (0);
+ }
+}
+
+/*
+ * set process group (setpgid/old setpgrp)
+ *
+ * caller does setpgid(targpid, targpgid)
+ *
+ * pid must be caller or child of caller (ESRCH)
+ * if a child
+ * pid must be in same session (EPERM)
+ * pid can't have done an exec (EACCES)
+ * if pgid != pid
+ * there must exist some pid in same session having pgid (EPERM)
+ * pid must not be session leader (EPERM)
+ */
+/* ARGSUSED */
+int
+setpgid(curp, uap, retval)
+ struct proc *curp;
+ register struct setpgid_args /* {
+ syscallarg(int) pid;
+ syscallarg(int) pgid;
+ } */ *uap;
+ register_t *retval;
+{
+ register struct proc *targp; /* target process */
+ register struct pgrp *pgrp; /* target pgrp */
+
+ if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
+ if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp))
+ return (ESRCH);
+ if (targp->p_session != curp->p_session)
+ return (EPERM);
+ if (targp->p_flag & P_EXEC)
+ return (EACCES);
+ } else
+ targp = curp;
+ if (SESS_LEADER(targp))
+ return (EPERM);
+ if (SCARG(uap, pgid) == 0)
+ SCARG(uap, pgid) = targp->p_pid;
+ else if (SCARG(uap, pgid) != targp->p_pid)
+ if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 ||
+ pgrp->pg_session != curp->p_session)
+ return (EPERM);
+ return (enterpgrp(targp, SCARG(uap, pgid), 0));
+}
+
+/* ARGSUSED */
+int
+setuid(p, uap, retval)
+ struct proc *p;
+ struct setuid_args /* {
+ syscallarg(uid_t) uid;
+ } */ *uap;
+ register_t *retval;
+{
+ register struct pcred *pc = p->p_cred;
+ register uid_t uid;
+ int error;
+
+ uid = SCARG(uap, uid);
+ if (uid != pc->p_ruid &&
+ (error = suser(pc->pc_ucred, &p->p_acflag)))
+ return (error);
+ /*
+ * Everything's okay, do it.
+ * Transfer proc count to new user.
+ * Copy credentials so other references do not see our changes.
+ */
+ (void)chgproccnt(pc->p_ruid, -1);
+ (void)chgproccnt(uid, 1);
+ pc->pc_ucred = crcopy(pc->pc_ucred);
+ pc->pc_ucred->cr_uid = uid;
+ pc->p_ruid = uid;
+ pc->p_svuid = uid;
+ p->p_flag |= P_SUGID;
+ return (0);
+}
+
+/* ARGSUSED */
+int
+seteuid(p, uap, retval)
+ struct proc *p;
+ struct seteuid_args /* {
+ syscallarg(uid_t) euid;
+ } */ *uap;
+ register_t *retval;
+{
+ register struct pcred *pc = p->p_cred;
+ register uid_t euid;
+ int error;
+
+ euid = SCARG(uap, euid);
+ if (euid != pc->p_ruid && euid != pc->p_svuid &&
+ (error = suser(pc->pc_ucred, &p->p_acflag)))
+ return (error);
+ /*
+ * Everything's okay, do it. Copy credentials so other references do
+ * not see our changes.
+ */
+ pc->pc_ucred = crcopy(pc->pc_ucred);
+ pc->pc_ucred->cr_uid = euid;
+ p->p_flag |= P_SUGID;
+ return (0);
+}