xref: /minix/minix/servers/pm/getset.c (revision 00e393ca)
1 /* This file handles the 6 system calls that get and set uids and gids.
2  * It also handles getpid(), setsid(), and getpgrp().  The code for each
3  * one is so tiny that it hardly seemed worthwhile to make each a separate
4  * function.
5  */
6 
7 #include "pm.h"
8 #include <minix/callnr.h>
9 #include <minix/endpoint.h>
10 #include <limits.h>
11 #include <minix/com.h>
12 #include <signal.h>
13 #include "mproc.h"
14 
15 /*===========================================================================*
16  *				do_get					     *
17  *===========================================================================*/
18 int
19 do_get(void)
20 {
21 /* Handle PM_GETUID, PM_GETGID, PM_GETGROUPS, PM_GETPID, PM_GETPGRP, PM_GETSID,
22  * PM_ISSETUGID.
23  */
24   register struct mproc *rmp = mp;
25   int r;
26   int ngroups;
27 
28   switch(call_nr) {
29 	case PM_GETGROUPS:
30 		ngroups = m_in.m_lc_pm_groups.num;
31 		if (ngroups > NGROUPS_MAX || ngroups < 0)
32 			return(EINVAL);
33 
34 		if (ngroups == 0) {
35 			r = rmp->mp_ngroups;
36 			break;
37 		}
38 
39 		if (ngroups < rmp->mp_ngroups)
40 			/* Asking for less groups than available */
41 			return(EINVAL);
42 
43 		r = sys_datacopy(SELF, (vir_bytes) rmp->mp_sgroups, who_e,
44 			m_in.m_lc_pm_groups.ptr, ngroups * sizeof(gid_t));
45 
46 		if (r != OK)
47 			return(r);
48 
49 		r = rmp->mp_ngroups;
50 		break;
51 	case PM_GETUID:
52 		r = rmp->mp_realuid;
53 		rmp->mp_reply.m_pm_lc_getuid.euid = rmp->mp_effuid;
54 		break;
55 
56 	case PM_GETGID:
57 		r = rmp->mp_realgid;
58 		rmp->mp_reply.m_pm_lc_getgid.egid = rmp->mp_effgid;
59 		break;
60 
61 	case PM_GETPID:
62 		r = mproc[who_p].mp_pid;
63 		rmp->mp_reply.m_pm_lc_getpid.parent_pid = mproc[rmp->mp_parent].mp_pid;
64 		break;
65 
66 	case PM_GETPGRP:
67 		r = rmp->mp_procgrp;
68 		break;
69 
70 	case PM_GETSID:
71 	{
72 		struct mproc *target;
73 		pid_t p = m_in.m_lc_pm_getsid.pid;
74 		target = p ? find_proc(p) : &mproc[who_p];
75 		r = ESRCH;
76 		if(target)
77 			r = target->mp_procgrp;
78 		break;
79 	}
80 	case PM_ISSETUGID:
81 		r = !!(rmp->mp_flags & TAINTED);
82 		break;
83 
84 	default:
85 		r = EINVAL;
86 		break;
87   }
88   return(r);
89 }
90 
91 /*===========================================================================*
92  *				do_set					     *
93  *===========================================================================*/
94 int
95 do_set(void)
96 {
97 /* Handle PM_SETUID, PM_SETEUID, PM_SETGID, PM_SETGROUPS, PM_SETEGID, and
98  * SETSID. These calls have in common that, if successful, they will be
99  * forwarded to VFS as well.
100  */
101   register struct mproc *rmp = mp;
102   message m;
103   int r, i;
104   int ngroups;
105   uid_t uid;
106   gid_t gid;
107 
108   memset(&m, 0, sizeof(m));
109 
110   switch(call_nr) {
111 	case PM_SETUID:
112 		uid = m_in.m_lc_pm_setuid.uid;
113 		/* NetBSD specific semantics: setuid(geteuid()) may fail. */
114 		if (rmp->mp_realuid != uid && rmp->mp_effuid != SUPER_USER)
115 			return(EPERM);
116 		/* BSD semantics: always update all three fields. */
117 		rmp->mp_realuid = uid;
118 		rmp->mp_effuid = uid;
119 		rmp->mp_svuid = uid;
120 
121 		m.m_type = VFS_PM_SETUID;
122 		m.VFS_PM_ENDPT = rmp->mp_endpoint;
123 		m.VFS_PM_EID = rmp->mp_effuid;
124 		m.VFS_PM_RID = rmp->mp_realuid;
125 
126 		break;
127 
128 	case PM_SETEUID:
129 		uid = m_in.m_lc_pm_setuid.uid;
130 		/* BSD semantics: seteuid(geteuid()) may fail. */
131 		if (rmp->mp_realuid != uid && rmp->mp_svuid != uid &&
132 		    rmp->mp_effuid != SUPER_USER)
133 			return(EPERM);
134 		rmp->mp_effuid = uid;
135 
136 		m.m_type = VFS_PM_SETUID;
137 		m.VFS_PM_ENDPT = rmp->mp_endpoint;
138 		m.VFS_PM_EID = rmp->mp_effuid;
139 		m.VFS_PM_RID = rmp->mp_realuid;
140 
141 		break;
142 
143 	case PM_SETGID:
144 		gid = m_in.m_lc_pm_setgid.gid;
145 		if (rmp->mp_realgid != gid && rmp->mp_effuid != SUPER_USER)
146 			return(EPERM);
147 		rmp->mp_realgid = gid;
148 		rmp->mp_effgid = gid;
149 		rmp->mp_svgid = gid;
150 
151 		m.m_type = VFS_PM_SETGID;
152 		m.VFS_PM_ENDPT = rmp->mp_endpoint;
153 		m.VFS_PM_EID = rmp->mp_effgid;
154 		m.VFS_PM_RID = rmp->mp_realgid;
155 
156 		break;
157 
158 	case PM_SETEGID:
159 		gid = m_in.m_lc_pm_setgid.gid;
160 		if (rmp->mp_realgid != gid && rmp->mp_svgid != gid &&
161 		    rmp->mp_effuid != SUPER_USER)
162 			return(EPERM);
163 		rmp->mp_effgid = gid;
164 
165 		m.m_type = VFS_PM_SETGID;
166 		m.VFS_PM_ENDPT = rmp->mp_endpoint;
167 		m.VFS_PM_EID = rmp->mp_effgid;
168 		m.VFS_PM_RID = rmp->mp_realgid;
169 
170 		break;
171 
172 	case PM_SETGROUPS:
173 		if (rmp->mp_effuid != SUPER_USER)
174 			return(EPERM);
175 
176 		ngroups = m_in.m_lc_pm_groups.num;
177 
178 		if (ngroups > NGROUPS_MAX || ngroups < 0)
179 			return(EINVAL);
180 
181 		if (ngroups > 0 && m_in.m_lc_pm_groups.ptr == 0)
182 			return(EFAULT);
183 
184 		r = sys_datacopy(who_e, m_in.m_lc_pm_groups.ptr, SELF,
185 			     (vir_bytes) rmp->mp_sgroups,
186 			     ngroups * sizeof(gid_t));
187 		if (r != OK)
188 			return(r);
189 
190 		for (i = 0; i < ngroups; i++) {
191 			if (rmp->mp_sgroups[i] > GID_MAX)
192 				return(EINVAL);
193 		}
194 		for (i = ngroups; i < NGROUPS_MAX; i++) {
195 			rmp->mp_sgroups[i] = 0;
196 		}
197 		rmp->mp_ngroups = ngroups;
198 
199 		m.m_type = VFS_PM_SETGROUPS;
200 		m.VFS_PM_ENDPT = rmp->mp_endpoint;
201 		m.VFS_PM_GROUP_NO = rmp->mp_ngroups;
202 		m.VFS_PM_GROUP_ADDR = (char *) rmp->mp_sgroups;
203 
204 		break;
205 	case PM_SETSID:
206 		if (rmp->mp_procgrp == rmp->mp_pid) return(EPERM);
207 		rmp->mp_procgrp = rmp->mp_pid;
208 
209 		m.m_type = VFS_PM_SETSID;
210 		m.VFS_PM_ENDPT = rmp->mp_endpoint;
211 
212 		break;
213 
214 	default:
215 		return(EINVAL);
216   }
217 
218   /* Send the request to VFS */
219   tell_vfs(rmp, &m);
220 
221   /* Do not reply until VFS has processed the request */
222   return(SUSPEND);
223 }
224