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 #include <sys/param.h>
30 #include <sys/types.h>
31 #include <sys/sysmacros.h>
32 #include <sys/systm.h>
33 #include <sys/errno.h>
34 #include <sys/file.h>
35 #include <sys/proc.h>
36 #include <sys/session.h>
37 #include <sys/debug.h>
38 
39 /* ARGSUSED */
40 int
setpgrp(int flag,int pid,int pgid)41 setpgrp(int flag, int pid, int pgid)
42 {
43 	proc_t	*p = curproc;
44 	int	retval = 0;
45 	int	sid;
46 
47 	switch (flag) {
48 
49 	case 1: /* setpgrp() */
50 		mutex_enter(&pidlock);
51 		if (p->p_sessp->s_sidp != p->p_pidp && !pgmembers(p->p_pid)) {
52 			mutex_exit(&pidlock);
53 			sess_create();
54 		} else
55 			mutex_exit(&pidlock);
56 		mutex_enter(&p->p_splock);
57 		sid = p->p_sessp->s_sid;
58 		mutex_exit(&p->p_splock);
59 		return (sid);
60 
61 	case 3: /* setsid() */
62 		mutex_enter(&pidlock);
63 		if (p->p_pgidp == p->p_pidp || pgmembers(p->p_pid)) {
64 			mutex_exit(&pidlock);
65 			return (set_errno(EPERM));
66 		}
67 		mutex_exit(&pidlock);
68 		sess_create();
69 		mutex_enter(&p->p_splock);
70 		sid = p->p_sessp->s_sid;
71 		mutex_exit(&p->p_splock);
72 		return (sid);
73 
74 	case 5: /* setpgid() */
75 	{
76 		mutex_enter(&pidlock);
77 		if (pid == 0)
78 			pid = p->p_pid;
79 		else if (pid < 0 || pid >= maxpid) {
80 			mutex_exit(&pidlock);
81 			return (set_errno(EINVAL));
82 		} else if (pid != p->p_pid) {
83 			for (p = p->p_child; /* empty */; p = p->p_sibling) {
84 				if (p == NULL) {
85 					mutex_exit(&pidlock);
86 					return (set_errno(ESRCH));
87 				}
88 				if (p->p_pid == pid)
89 					break;
90 			}
91 			if (p->p_flag & SEXECED) {
92 				mutex_exit(&pidlock);
93 				return (set_errno(EACCES));
94 			}
95 			if (p->p_sessp != ttoproc(curthread)->p_sessp) {
96 				mutex_exit(&pidlock);
97 				return (set_errno(EPERM));
98 			}
99 		}
100 
101 		if (p->p_sessp->s_sid == pid) {
102 			mutex_exit(&pidlock);
103 			return (set_errno(EPERM));
104 		}
105 
106 		if (pgid == 0)
107 			pgid = p->p_pid;
108 		else if (pgid < 0 || pgid >= maxpid) {
109 			mutex_exit(&pidlock);
110 			return (set_errno(EINVAL));
111 		}
112 
113 		if (p->p_pgrp == pgid) {
114 			mutex_exit(&pidlock);
115 			break;
116 		} else if (p->p_pid == pgid) {
117 			/*
118 			 * We need to protect p_pgidp with p_lock because
119 			 * /proc looks at it while holding only p_lock.
120 			 */
121 			mutex_enter(&p->p_lock);
122 			pgexit(p);
123 			pgjoin(p, p->p_pidp);
124 			mutex_exit(&p->p_lock);
125 		} else {
126 			register proc_t *q;
127 
128 			if ((q = pgfind(pgid)) == NULL ||
129 			    q->p_sessp != p->p_sessp) {
130 				mutex_exit(&pidlock);
131 				return (set_errno(EPERM));
132 			}
133 			/*
134 			 * See comment above about p_lock and /proc
135 			 */
136 			mutex_enter(&p->p_lock);
137 			pgexit(p);
138 			pgjoin(p, q->p_pgidp);
139 			mutex_exit(&p->p_lock);
140 		}
141 		mutex_exit(&pidlock);
142 		break;
143 	}
144 
145 	case 0: /* getpgrp() */
146 		mutex_enter(&pidlock);
147 		retval = p->p_pgrp;
148 		mutex_exit(&pidlock);
149 		break;
150 
151 	case 2: /* getsid() */
152 	case 4: /* getpgid() */
153 		if (pid < 0 || pid >= maxpid) {
154 			return (set_errno(EINVAL));
155 		}
156 		mutex_enter(&pidlock);
157 		if (pid != 0 && p->p_pid != pid &&
158 		    ((p = prfind(pid)) == NULL || p->p_stat == SIDL)) {
159 			mutex_exit(&pidlock);
160 			return (set_errno(ESRCH));
161 		}
162 		if (flag == 2)
163 			retval = p->p_sessp->s_sid;
164 		else
165 			retval = p->p_pgrp;
166 		mutex_exit(&pidlock);
167 		break;
168 
169 	}
170 	return (retval);
171 }
172