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