Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
d5dc47bf | 2 | * Copyright (c) 1982, 1986, 1989, 1990 Regents of the University of California. |
88a39492 | 3 | * All rights reserved. |
da7c5cc6 | 4 | * |
dbf0c423 | 5 | * %sccs.include.redist.c% |
88a39492 | 6 | * |
fca91c15 | 7 | * @(#)kern_prot.c 7.15 (Berkeley) %G% |
da7c5cc6 | 8 | */ |
a05af100 BJ |
9 | |
10 | /* | |
4147b3f6 | 11 | * System calls related to processes and protection |
a05af100 BJ |
12 | */ |
13 | ||
94368568 | 14 | #include "param.h" |
88a39492 | 15 | #include "acct.h" |
94368568 | 16 | #include "systm.h" |
d9c2f47f | 17 | #include "user.h" |
94368568 JB |
18 | #include "proc.h" |
19 | #include "timeb.h" | |
20 | #include "times.h" | |
88a39492 | 21 | #include "malloc.h" |
a05af100 | 22 | |
d5dc47bf MK |
23 | /* ARGSUSED */ |
24 | getpid(p, uap, retval) | |
25 | struct proc *p; | |
26 | void *uap; | |
27 | int *retval; | |
4147b3f6 BJ |
28 | { |
29 | ||
d5dc47bf MK |
30 | *retval = p->p_pid; |
31 | #ifdef COMPAT_43 | |
32 | retval[1] = p->p_ppid; | |
33 | #endif | |
d9c2f47f | 34 | return (0); |
4147b3f6 BJ |
35 | } |
36 | ||
d5dc47bf MK |
37 | /* ARGSUSED */ |
38 | getppid(p, uap, retval) | |
39 | struct proc *p; | |
40 | void *uap; | |
41 | int *retval; | |
4147b3f6 | 42 | { |
d5dc47bf MK |
43 | |
44 | *retval = p->p_ppid; | |
d9c2f47f | 45 | return (0); |
d5dc47bf MK |
46 | } |
47 | ||
48 | getpgrp(p, uap, retval) | |
49 | struct proc *p; | |
50 | struct args { | |
4147b3f6 | 51 | int pid; |
d5dc47bf MK |
52 | } *uap; |
53 | int *retval; | |
54 | { | |
4147b3f6 | 55 | |
d5dc47bf | 56 | if (uap->pid != 0 && (p = pfind(uap->pid)) == 0) |
d9c2f47f | 57 | return (ESRCH); |
d5dc47bf | 58 | *retval = p->p_pgrp->pg_id; |
d9c2f47f | 59 | return (0); |
4147b3f6 BJ |
60 | } |
61 | ||
d5dc47bf MK |
62 | /* ARGSUSED */ |
63 | getuid(p, uap, retval) | |
64 | struct proc *p; | |
65 | void *uap; | |
66 | int *retval; | |
a05af100 BJ |
67 | { |
68 | ||
d5dc47bf MK |
69 | *retval = p->p_ruid; |
70 | #ifdef COMPAT_43 | |
71 | retval[1] = u.u_cred->cr_uid; | |
72 | #endif | |
d9c2f47f | 73 | return (0); |
a05af100 BJ |
74 | } |
75 | ||
d5dc47bf MK |
76 | /* ARGSUSED */ |
77 | geteuid(p, uap, retval) | |
78 | struct proc *p; | |
79 | void *uap; | |
80 | int *retval; | |
4147b3f6 BJ |
81 | { |
82 | ||
d5dc47bf | 83 | *retval = u.u_cred->cr_uid; |
d9c2f47f | 84 | return (0); |
4147b3f6 BJ |
85 | } |
86 | ||
d5dc47bf MK |
87 | /* ARGSUSED */ |
88 | getgid(p, uap, retval) | |
89 | struct proc *p; | |
90 | void *uap; | |
91 | int *retval; | |
92 | { | |
93 | ||
94 | *retval = p->p_rgid; | |
95 | #ifdef COMPAT_43 | |
96 | retval[1] = u.u_cred->cr_groups[0]; | |
97 | #endif | |
d9c2f47f | 98 | return (0); |
d5dc47bf MK |
99 | } |
100 | ||
101 | /* | |
102 | * Get effective group ID. | |
103 | * The "egid" is groups[0], and thus could be obtained via getgroups; | |
104 | * this is somewhat painful to do correctly in a library function, | |
105 | * this the existence of this syscall. | |
106 | */ | |
107 | /* ARGSUSED */ | |
108 | getegid(p, uap, retval) | |
109 | struct proc *p; | |
110 | void *uap; | |
111 | int *retval; | |
4147b3f6 | 112 | { |
d5dc47bf MK |
113 | |
114 | *retval = u.u_cred->cr_groups[0]; | |
d9c2f47f | 115 | return (0); |
d5dc47bf MK |
116 | } |
117 | ||
118 | getgroups(p, uap, retval) | |
119 | struct proc *p; | |
120 | register struct arg { | |
b32450f4 | 121 | u_int gidsetsize; |
d5dc47bf MK |
122 | int *gidset; /* XXX not yet POSIX */ |
123 | } *uap; | |
124 | int *retval; | |
125 | { | |
38b6104c MK |
126 | register gid_t *gp; |
127 | register int *lp; | |
fca91c15 | 128 | register u_int ngrp; |
38b6104c | 129 | int groups[NGROUPS]; |
d5dc47bf | 130 | int error; |
4147b3f6 | 131 | |
fca91c15 | 132 | if ((ngrp = uap->gidsetsize) == 0) { |
d5dc47bf | 133 | *retval = u.u_cred->cr_ngroups; |
d9c2f47f | 134 | return (0); |
197da11b | 135 | } |
fca91c15 | 136 | if (ngrp < u.u_cred->cr_ngroups) |
d9c2f47f | 137 | return (EINVAL); |
fca91c15 MK |
138 | ngrp = u.u_cred->cr_ngroups; |
139 | for (gp = u.u_cred->cr_groups, lp = groups; lp < &groups[ngrp]; ) | |
38b6104c | 140 | *lp++ = *gp++; |
d5dc47bf | 141 | if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset, |
fca91c15 | 142 | ngrp * sizeof (groups[0]))) |
d9c2f47f | 143 | return (error); |
fca91c15 | 144 | *retval = ngrp; |
d9c2f47f | 145 | return (0); |
4147b3f6 BJ |
146 | } |
147 | ||
d5dc47bf MK |
148 | /* ARGSUSED */ |
149 | setsid(p, uap, retval) | |
150 | struct proc *p; | |
151 | void *uap; | |
152 | int *retval; | |
8fe87cbb | 153 | { |
8fe87cbb | 154 | |
d5dc47bf | 155 | if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { |
d9c2f47f | 156 | return (EPERM); |
d5dc47bf | 157 | } else { |
8fe87cbb | 158 | pgmv(p, p->p_pid, 1); |
d5dc47bf | 159 | *retval = p->p_pid; |
d9c2f47f | 160 | return (0); |
8fe87cbb | 161 | } |
8fe87cbb MT |
162 | } |
163 | ||
164 | /* | |
d5dc47bf | 165 | * set process group (setpgrp/setpgid) |
8fe87cbb | 166 | * |
164c0f54 MK |
167 | * caller does setpgrp(pid, pgid) |
168 | * | |
169 | * pid must be caller or child of caller (ESRCH) | |
170 | * if a child | |
171 | * pid must be in same session (EPERM) | |
172 | * pid can't have done an exec (EACCES) | |
173 | * if pgid != pid | |
174 | * there must exist some pid in same session having pgid (EPERM) | |
175 | * pid must not be session leader (EPERM) | |
8fe87cbb | 176 | */ |
d5dc47bf MK |
177 | /* ARGSUSED */ |
178 | setpgrp(cp, uap, retval) | |
179 | struct proc *cp; | |
180 | register struct args { | |
4147b3f6 | 181 | int pid; |
8fe87cbb | 182 | int pgid; |
d5dc47bf MK |
183 | } *uap; |
184 | int *retval; | |
185 | { | |
8fe87cbb MT |
186 | register struct proc *p; |
187 | register struct pgrp *pgrp; | |
4147b3f6 | 188 | |
d5dc47bf MK |
189 | if (uap->pid != 0) { |
190 | if ((p = pfind(uap->pid)) == 0 || !inferior(p)) | |
d9c2f47f | 191 | return (ESRCH); |
d5dc47bf | 192 | if (p->p_session != cp->p_session) |
d9c2f47f | 193 | return (EPERM); |
d5dc47bf | 194 | if (p->p_flag&SEXEC) |
d9c2f47f | 195 | return (EACCES); |
d5dc47bf MK |
196 | } else |
197 | p = cp; | |
198 | if (SESS_LEADER(p)) | |
d9c2f47f | 199 | return (EPERM); |
8fe87cbb MT |
200 | if (uap->pgid == 0) |
201 | uap->pgid = p->p_pid; | |
202 | else if ((uap->pgid != p->p_pid) && | |
203 | (((pgrp = pgfind(uap->pgid)) == 0) || | |
204 | pgrp->pg_mem == NULL || | |
d5dc47bf | 205 | pgrp->pg_session != u.u_procp->p_session)) |
d9c2f47f | 206 | return (EPERM); |
8fe87cbb | 207 | /* |
d5dc47bf | 208 | * done checking, now do it |
8fe87cbb MT |
209 | */ |
210 | pgmv(p, uap->pgid, 0); | |
d9c2f47f | 211 | return (0); |
4147b3f6 BJ |
212 | } |
213 | ||
d5dc47bf MK |
214 | /* ARGSUSED */ |
215 | setuid(p, uap, retval) | |
216 | register struct proc *p; | |
217 | struct args { | |
218 | int uid; | |
219 | } *uap; | |
220 | int *retval; | |
4f083fd7 | 221 | { |
d5dc47bf MK |
222 | register uid_t uid; |
223 | int error; | |
224 | ||
225 | uid = uap->uid; | |
226 | if (uid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag))) | |
d9c2f47f | 227 | return (error); |
d5dc47bf MK |
228 | /* |
229 | * Everything's okay, do it. | |
230 | * Copy credentials so other references do not | |
231 | * see our changes. | |
232 | */ | |
233 | if (u.u_cred->cr_ref > 1) | |
234 | u.u_cred = crcopy(u.u_cred); | |
235 | u.u_cred->cr_uid = uid; | |
236 | p->p_uid = uid; | |
237 | p->p_ruid = uid; | |
238 | p->p_svuid = uid; | |
d9c2f47f | 239 | return (0); |
d5dc47bf MK |
240 | } |
241 | ||
242 | /* ARGSUSED */ | |
243 | seteuid(p, uap, retval) | |
244 | register struct proc *p; | |
245 | struct args { | |
4f083fd7 SL |
246 | int euid; |
247 | } *uap; | |
d5dc47bf MK |
248 | int *retval; |
249 | { | |
250 | register uid_t euid; | |
251 | int error; | |
4f083fd7 | 252 | |
4f083fd7 | 253 | euid = uap->euid; |
d5dc47bf MK |
254 | if (euid != p->p_ruid && euid != p->p_svuid && |
255 | (error = suser(u.u_cred, &u.u_acflag))) | |
d9c2f47f | 256 | return (error); |
4f083fd7 SL |
257 | /* |
258 | * Everything's okay, do it. | |
88a39492 KM |
259 | * Copy credentials so other references do not |
260 | * see our changes. | |
4f083fd7 | 261 | */ |
88a39492 KM |
262 | if (u.u_cred->cr_ref > 1) |
263 | u.u_cred = crcopy(u.u_cred); | |
164c0f54 MK |
264 | u.u_cred->cr_uid = euid; |
265 | p->p_uid = euid; | |
d9c2f47f | 266 | return (0); |
4f083fd7 SL |
267 | } |
268 | ||
d5dc47bf MK |
269 | /* ARGSUSED */ |
270 | setgid(p, uap, retval) | |
271 | struct proc *p; | |
272 | struct args { | |
273 | int gid; | |
274 | } *uap; | |
275 | int *retval; | |
4f083fd7 | 276 | { |
d5dc47bf MK |
277 | register gid_t gid; |
278 | int error; | |
279 | ||
280 | gid = uap->gid; | |
281 | if (gid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag))) | |
d9c2f47f | 282 | return (error); |
d5dc47bf MK |
283 | if (u.u_cred->cr_ref > 1) |
284 | u.u_cred = crcopy(u.u_cred); | |
285 | p->p_rgid = gid; | |
286 | u.u_cred->cr_groups[0] = gid; | |
287 | p->p_svgid = gid; /* ??? */ | |
d9c2f47f | 288 | return (0); |
d5dc47bf MK |
289 | } |
290 | ||
291 | /* ARGSUSED */ | |
292 | setegid(p, uap, retval) | |
293 | struct proc *p; | |
294 | struct args { | |
4f083fd7 SL |
295 | int egid; |
296 | } *uap; | |
d5dc47bf MK |
297 | int *retval; |
298 | { | |
299 | register gid_t egid; | |
300 | int error; | |
4f083fd7 | 301 | |
4f083fd7 | 302 | egid = uap->egid; |
d5dc47bf MK |
303 | if (egid != p->p_rgid && egid != p->p_svgid && |
304 | (error = suser(u.u_cred, &u.u_acflag))) | |
d9c2f47f | 305 | return (error); |
88a39492 KM |
306 | if (u.u_cred->cr_ref > 1) |
307 | u.u_cred = crcopy(u.u_cred); | |
164c0f54 | 308 | u.u_cred->cr_groups[0] = egid; |
d9c2f47f | 309 | return (0); |
d5dc47bf MK |
310 | } |
311 | ||
312 | #ifdef COMPAT_43 | |
313 | /* ARGSUSED */ | |
314 | osetreuid(p, uap, retval) | |
315 | register struct proc *p; | |
316 | struct args { | |
317 | int ruid; | |
318 | int euid; | |
319 | } *uap; | |
320 | int *retval; | |
321 | { | |
322 | register uid_t ruid, euid; | |
323 | int error; | |
324 | ||
325 | if (uap->ruid == -1) | |
326 | (error = suser(u.u_cred, &u.u_acflag))) | |
d9c2f47f | 327 | return (error); |
d5dc47bf MK |
328 | if (uap->euid == -1) |
329 | euid != p->p_svuid && (error = suser(u.u_cred, &u.u_acflag))) | |
d9c2f47f | 330 | return (error); |
d5dc47bf MK |
331 | /* |
332 | * Everything's okay, do it. | |
333 | * Copy credentials so other references do not | |
334 | * see our changes. | |
335 | */ | |
336 | if (u.u_cred->cr_ref > 1) | |
337 | u.u_cred = crcopy(u.u_cred); | |
338 | u.u_cred->cr_uid = euid; | |
339 | p->p_uid = euid; | |
340 | p->p_ruid = ruid; | |
d9c2f47f | 341 | return (0); |
4f083fd7 | 342 | } |
a05af100 | 343 | |
d5dc47bf MK |
344 | /* ARGSUSED */ |
345 | osetregid(p, uap, retval) | |
346 | struct proc *p; | |
347 | struct args { | |
348 | int rgid; | |
349 | int egid; | |
350 | } *uap; | |
351 | int *retval; | |
4147b3f6 | 352 | { |
d5dc47bf MK |
353 | register gid_t rgid, egid; |
354 | int error; | |
355 | ||
356 | if (uap->rgid == -1) | |
357 | (error = suser(u.u_cred, &u.u_acflag))) | |
d9c2f47f | 358 | return (error); |
d5dc47bf MK |
359 | if (uap->egid == -1) |
360 | egid != p->p_svgid && (error = suser(u.u_cred, &u.u_acflag))) | |
d9c2f47f | 361 | return (error); |
d5dc47bf MK |
362 | if (u.u_cred->cr_ref > 1) |
363 | u.u_cred = crcopy(u.u_cred); | |
364 | p->p_rgid = rgid; | |
365 | u.u_cred->cr_groups[0] = egid; | |
d9c2f47f | 366 | return (0); |
d5dc47bf MK |
367 | } |
368 | #endif | |
369 | ||
370 | /* ARGSUSED */ | |
371 | setgroups(p, uap, retval) | |
372 | struct proc *p; | |
373 | struct args { | |
b32450f4 | 374 | u_int gidsetsize; |
4147b3f6 | 375 | int *gidset; |
d5dc47bf MK |
376 | } *uap; |
377 | int *retval; | |
378 | { | |
38b6104c | 379 | register gid_t *gp; |
fca91c15 | 380 | register u_int ngrp; |
38b6104c | 381 | register int *lp; |
446a921a | 382 | int error, groups[NGROUPS]; |
4147b3f6 | 383 | |
d5dc47bf | 384 | if (error = suser(u.u_cred, &u.u_acflag)) |
d9c2f47f | 385 | return (error); |
fca91c15 | 386 | if ((ngrp = uap->gidsetsize) > NGROUPS) |
d9c2f47f | 387 | return (EINVAL); |
446a921a | 388 | if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups, |
fca91c15 | 389 | ngrp * sizeof (groups[0]))) |
d9c2f47f | 390 | return (error); |
fca91c15 | 391 | u.u_cred->cr_ngroups = ngrp; |
446a921a | 392 | /* convert from int's to gid_t's */ |
fca91c15 MK |
393 | for (gp = u.u_cred->cr_groups, lp = groups; ngrp--; ) |
394 | *gp++ = *lp++; | |
d9c2f47f | 395 | return (0); |
4147b3f6 BJ |
396 | } |
397 | ||
f926daf9 | 398 | /* |
88a39492 | 399 | * Check if gid is a member of the group set. |
f926daf9 | 400 | */ |
88a39492 | 401 | groupmember(gid, cred) |
90731a34 | 402 | gid_t gid; |
88a39492 | 403 | register struct ucred *cred; |
197da11b | 404 | { |
38b6104c | 405 | register gid_t *gp; |
88a39492 | 406 | gid_t *egp; |
197da11b | 407 | |
88a39492 KM |
408 | egp = &(cred->cr_groups[cred->cr_ngroups]); |
409 | for (gp = cred->cr_groups; gp < egp; gp++) | |
197da11b | 410 | if (*gp == gid) |
88a39492 KM |
411 | return (1); |
412 | return (0); | |
197da11b BJ |
413 | } |
414 | ||
f926daf9 | 415 | /* |
88a39492 | 416 | * Test if the current user is the super user. |
f926daf9 | 417 | */ |
88a39492 KM |
418 | suser(cred, acflag) |
419 | struct ucred *cred; | |
420 | short *acflag; | |
197da11b | 421 | { |
197da11b | 422 | |
88a39492 KM |
423 | if (cred->cr_uid == 0) { |
424 | if (acflag) | |
425 | *acflag |= ASU; | |
426 | return (0); | |
38b6104c | 427 | } |
88a39492 | 428 | return (EPERM); |
197da11b | 429 | } |
f926daf9 SL |
430 | |
431 | /* | |
88a39492 | 432 | * Allocate a zeroed cred structure. |
f926daf9 | 433 | */ |
88a39492 KM |
434 | struct ucred * |
435 | crget() | |
f926daf9 | 436 | { |
88a39492 | 437 | register struct ucred *cr; |
f926daf9 | 438 | |
88a39492 KM |
439 | MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); |
440 | bzero((caddr_t)cr, sizeof(*cr)); | |
441 | cr->cr_ref = 1; | |
d5dc47bf | 442 | return (cr); |
88a39492 KM |
443 | } |
444 | ||
445 | /* | |
446 | * Free a cred structure. | |
447 | * Throws away space when ref count gets to 0. | |
448 | */ | |
449 | crfree(cr) | |
450 | struct ucred *cr; | |
451 | { | |
d5dc47bf | 452 | int s = splimp(); |
88a39492 KM |
453 | |
454 | if (--cr->cr_ref != 0) { | |
455 | (void) splx(s); | |
456 | return; | |
457 | } | |
458 | FREE((caddr_t)cr, M_CRED); | |
459 | (void) splx(s); | |
460 | } | |
461 | ||
462 | /* | |
463 | * Copy cred structure to a new one and free the old one. | |
464 | */ | |
465 | struct ucred * | |
466 | crcopy(cr) | |
467 | struct ucred *cr; | |
468 | { | |
469 | struct ucred *newcr; | |
470 | ||
471 | newcr = crget(); | |
472 | *newcr = *cr; | |
473 | crfree(cr); | |
474 | newcr->cr_ref = 1; | |
d5dc47bf | 475 | return (newcr); |
88a39492 KM |
476 | } |
477 | ||
478 | /* | |
479 | * Dup cred struct to a new held one. | |
480 | */ | |
481 | struct ucred * | |
482 | crdup(cr) | |
483 | struct ucred *cr; | |
484 | { | |
485 | struct ucred *newcr; | |
486 | ||
487 | newcr = crget(); | |
488 | *newcr = *cr; | |
489 | newcr->cr_ref = 1; | |
d5dc47bf | 490 | return (newcr); |
f926daf9 | 491 | } |
5b6ee178 KF |
492 | |
493 | /* | |
164c0f54 | 494 | * Get login name, if available. |
5b6ee178 | 495 | */ |
d5dc47bf MK |
496 | /* ARGSUSED */ |
497 | getlogin(p, uap, retval) | |
498 | struct proc *p; | |
499 | struct args { | |
5b6ee178 KF |
500 | char *namebuf; |
501 | u_int namelen; | |
d5dc47bf MK |
502 | } *uap; |
503 | int *retval; | |
504 | { | |
5b6ee178 | 505 | |
d5dc47bf MK |
506 | if (uap->namelen > sizeof (p->p_logname)) |
507 | uap->namelen = sizeof (p->p_logname); | |
d9c2f47f | 508 | return (copyout((caddr_t)p->p_logname, (caddr_t)uap->namebuf, |
d5dc47bf | 509 | uap->namelen)); |
5b6ee178 KF |
510 | } |
511 | ||
512 | /* | |
164c0f54 | 513 | * Set login name. |
5b6ee178 | 514 | */ |
d5dc47bf MK |
515 | /* ARGSUSED */ |
516 | setlogin(p, uap, retval) | |
517 | struct proc *p; | |
518 | struct args { | |
5b6ee178 | 519 | char *namebuf; |
d5dc47bf MK |
520 | } *uap; |
521 | int *retval; | |
522 | { | |
164c0f54 | 523 | int error; |
5b6ee178 | 524 | |
d5dc47bf | 525 | if (error = suser(u.u_cred, &u.u_acflag)) |
d9c2f47f | 526 | return (error); |
d5dc47bf MK |
527 | error = copyinstr((caddr_t)uap->namebuf, (caddr_t)p->p_logname, |
528 | sizeof (p->p_logname) - 1, (int *) 0); | |
164c0f54 MK |
529 | if (error == ENOENT) /* name too long */ |
530 | error = EINVAL; | |
d9c2f47f | 531 | return (error); |
5b6ee178 | 532 | } |