1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved	*/
28 
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* from SVr4.0 1.78 */
31 
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/sysmacros.h>
35 #include <sys/systm.h>
36 #include <sys/errno.h>
37 #include <sys/file.h>
38 #include <sys/proc.h>
39 #include <sys/session.h>
40 #include <sys/debug.h>
41 
42 /* ARGSUSED */
43 int
44 setpgrp(int flag, int pid, int pgid)
45 {
46 	proc_t	*p = curproc;
47 	int	retval = 0;
48 	int	sid;
49 
50 	switch (flag) {
51 
52 	case 1: /* setpgrp() */
53 		mutex_enter(&pidlock);
54 		if (p->p_sessp->s_sidp != p->p_pidp && !pgmembers(p->p_pid)) {
55 			mutex_exit(&pidlock);
56 			sess_create();
57 		} else
58 			mutex_exit(&pidlock);
59 		mutex_enter(&p->p_splock);
60 		sid = p->p_sessp->s_sid;
61 		mutex_exit(&p->p_splock);
62 		return (sid);
63 
64 	case 3: /* setsid() */
65 		mutex_enter(&pidlock);
66 		if (p->p_pgidp == p->p_pidp || pgmembers(p->p_pid)) {
67 			mutex_exit(&pidlock);
68 			return (set_errno(EPERM));
69 		}
70 		mutex_exit(&pidlock);
71 		sess_create();
72 		mutex_enter(&p->p_splock);
73 		sid = p->p_sessp->s_sid;
74 		mutex_exit(&p->p_splock);
75 		return (sid);
76 
77 	case 5: /* setpgid() */
78 	{
79 		mutex_enter(&pidlock);
80 		if (pid == 0)
81 			pid = p->p_pid;
82 		else if (pid < 0 || pid >= maxpid) {
83 			mutex_exit(&pidlock);
84 			return (set_errno(EINVAL));
85 		} else if (pid != p->p_pid) {
86 			for (p = p->p_child; /* empty */; p = p->p_sibling) {
87 				if (p == NULL) {
88 					mutex_exit(&pidlock);
89 					return (set_errno(ESRCH));
90 				}
91 				if (p->p_pid == pid)
92 					break;
93 			}
94 			if (p->p_flag & SEXECED) {
95 				mutex_exit(&pidlock);
96 				return (set_errno(EACCES));
97 			}
98 			if (p->p_sessp != ttoproc(curthread)->p_sessp) {
99 				mutex_exit(&pidlock);
100 				return (set_errno(EPERM));
101 			}
102 		}
103 
104 		if (p->p_sessp->s_sid == pid) {
105 			mutex_exit(&pidlock);
106 			return (set_errno(EPERM));
107 		}
108 
109 		if (pgid == 0)
110 			pgid = p->p_pid;
111 		else if (pgid < 0 || pgid >= maxpid) {
112 			mutex_exit(&pidlock);
113 			return (set_errno(EINVAL));
114 		}
115 
116 		if (p->p_pgrp == pgid) {
117 			mutex_exit(&pidlock);
118 			break;
119 		} else if (p->p_pid == pgid) {
120 			/*
121 			 * We need to protect p_pgidp with p_lock because
122 			 * /proc looks at it while holding only p_lock.
123 			 */
124 			mutex_enter(&p->p_lock);
125 			pgexit(p);
126 			pgjoin(p, p->p_pidp);
127 			mutex_exit(&p->p_lock);
128 		} else {
129 			register proc_t *q;
130 
131 			if ((q = pgfind(pgid)) == NULL ||
132 			    q->p_sessp != p->p_sessp) {
133 				mutex_exit(&pidlock);
134 				return (set_errno(EPERM));
135 			}
136 			/*
137 			 * See comment above about p_lock and /proc
138 			 */
139 			mutex_enter(&p->p_lock);
140 			pgexit(p);
141 			pgjoin(p, q->p_pgidp);
142 			mutex_exit(&p->p_lock);
143 		}
144 		mutex_exit(&pidlock);
145 		break;
146 	}
147 
148 	case 0: /* getpgrp() */
149 		mutex_enter(&pidlock);
150 		retval = p->p_pgrp;
151 		mutex_exit(&pidlock);
152 		break;
153 
154 	case 2: /* getsid() */
155 	case 4: /* getpgid() */
156 		if (pid < 0 || pid >= maxpid) {
157 			return (set_errno(EINVAL));
158 		}
159 		mutex_enter(&pidlock);
160 		if (pid != 0 && p->p_pid != pid &&
161 		    ((p = prfind(pid)) == NULL || p->p_stat == SIDL)) {
162 			mutex_exit(&pidlock);
163 			return (set_errno(ESRCH));
164 		}
165 		if (flag == 2)
166 			retval = p->p_sessp->s_sid;
167 		else
168 			retval = p->p_pgrp;
169 		mutex_exit(&pidlock);
170 		break;
171 
172 	}
173 	return (retval);
174 }
175