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