kern_prot.c revision 1.1.1.3 1 /*
2 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
39 */
40
41 /*
42 * System calls related to processes and protection
43 */
44
45 #include <sys/param.h>
46 #include <sys/acct.h>
47 #include <sys/systm.h>
48 #include <sys/ucred.h>
49 #include <sys/proc.h>
50 #include <sys/timeb.h>
51 #include <sys/times.h>
52 #include <sys/malloc.h>
53
54 #include <sys/mount.h>
55 #include <sys/syscallargs.h>
56
57 /* ARGSUSED */
58 int
59 getpid(p, uap, retval)
60 struct proc *p;
61 void *uap;
62 register_t *retval;
63 {
64
65 *retval = p->p_pid;
66 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
67 retval[1] = p->p_pptr->p_pid;
68 #endif
69 return (0);
70 }
71
72 /* ARGSUSED */
73 int
74 getppid(p, uap, retval)
75 struct proc *p;
76 void *uap;
77 register_t *retval;
78 {
79
80 *retval = p->p_pptr->p_pid;
81 return (0);
82 }
83
84 /* Get process group ID; note that POSIX getpgrp takes no parameter */
85 int
86 getpgrp(p, uap, retval)
87 struct proc *p;
88 void *uap;
89 register_t *retval;
90 {
91
92 *retval = p->p_pgrp->pg_id;
93 return (0);
94 }
95
96 /* ARGSUSED */
97 int
98 getuid(p, uap, retval)
99 struct proc *p;
100 void *uap;
101 register_t *retval;
102 {
103
104 *retval = p->p_cred->p_ruid;
105 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
106 retval[1] = p->p_ucred->cr_uid;
107 #endif
108 return (0);
109 }
110
111 /* ARGSUSED */
112 int
113 geteuid(p, uap, retval)
114 struct proc *p;
115 void *uap;
116 register_t *retval;
117 {
118
119 *retval = p->p_ucred->cr_uid;
120 return (0);
121 }
122
123 /* ARGSUSED */
124 int
125 getgid(p, uap, retval)
126 struct proc *p;
127 void *uap;
128 register_t *retval;
129 {
130
131 *retval = p->p_cred->p_rgid;
132 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
133 retval[1] = p->p_ucred->cr_groups[0];
134 #endif
135 return (0);
136 }
137
138 /*
139 * Get effective group ID. The "egid" is groups[0], and could be obtained
140 * via getgroups. This syscall exists because it is somewhat painful to do
141 * correctly in a library function.
142 */
143 /* ARGSUSED */
144 int
145 getegid(p, uap, retval)
146 struct proc *p;
147 void *uap;
148 register_t *retval;
149 {
150
151 *retval = p->p_ucred->cr_groups[0];
152 return (0);
153 }
154
155 int
156 getgroups(p, uap, retval)
157 struct proc *p;
158 register struct getgroups_args /* {
159 syscallarg(u_int) gidsetsize;
160 syscallarg(gid_t *) gidset;
161 } */ *uap;
162 register_t *retval;
163 {
164 register struct pcred *pc = p->p_cred;
165 register u_int ngrp;
166 int error;
167
168 if ((ngrp = SCARG(uap, gidsetsize)) == 0) {
169 *retval = pc->pc_ucred->cr_ngroups;
170 return (0);
171 }
172 if (ngrp < pc->pc_ucred->cr_ngroups)
173 return (EINVAL);
174 ngrp = pc->pc_ucred->cr_ngroups;
175 if (error = copyout((caddr_t)pc->pc_ucred->cr_groups,
176 (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t)))
177 return (error);
178 *retval = ngrp;
179 return (0);
180 }
181
182 /* ARGSUSED */
183 int
184 setsid(p, uap, retval)
185 register struct proc *p;
186 void *uap;
187 register_t *retval;
188 {
189
190 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
191 return (EPERM);
192 } else {
193 (void)enterpgrp(p, p->p_pid, 1);
194 *retval = p->p_pid;
195 return (0);
196 }
197 }
198
199 /*
200 * set process group (setpgid/old setpgrp)
201 *
202 * caller does setpgid(targpid, targpgid)
203 *
204 * pid must be caller or child of caller (ESRCH)
205 * if a child
206 * pid must be in same session (EPERM)
207 * pid can't have done an exec (EACCES)
208 * if pgid != pid
209 * there must exist some pid in same session having pgid (EPERM)
210 * pid must not be session leader (EPERM)
211 */
212 /* ARGSUSED */
213 int
214 setpgid(curp, uap, retval)
215 struct proc *curp;
216 register struct setpgid_args /* {
217 syscallarg(int) pid;
218 syscallarg(int) pgid;
219 } */ *uap;
220 register_t *retval;
221 {
222 register struct proc *targp; /* target process */
223 register struct pgrp *pgrp; /* target pgrp */
224
225 if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
226 if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp))
227 return (ESRCH);
228 if (targp->p_session != curp->p_session)
229 return (EPERM);
230 if (targp->p_flag & P_EXEC)
231 return (EACCES);
232 } else
233 targp = curp;
234 if (SESS_LEADER(targp))
235 return (EPERM);
236 if (SCARG(uap, pgid) == 0)
237 SCARG(uap, pgid) = targp->p_pid;
238 else if (SCARG(uap, pgid) != targp->p_pid)
239 if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 ||
240 pgrp->pg_session != curp->p_session)
241 return (EPERM);
242 return (enterpgrp(targp, SCARG(uap, pgid), 0));
243 }
244
245 /* ARGSUSED */
246 int
247 setuid(p, uap, retval)
248 struct proc *p;
249 struct setuid_args /* {
250 syscallarg(uid_t) uid;
251 } */ *uap;
252 register_t *retval;
253 {
254 register struct pcred *pc = p->p_cred;
255 register uid_t uid;
256 int error;
257
258 uid = SCARG(uap, uid);
259 if (uid != pc->p_ruid &&
260 (error = suser(pc->pc_ucred, &p->p_acflag)))
261 return (error);
262 /*
263 * Everything's okay, do it.
264 * Transfer proc count to new user.
265 * Copy credentials so other references do not see our changes.
266 */
267 (void)chgproccnt(pc->p_ruid, -1);
268 (void)chgproccnt(uid, 1);
269 pc->pc_ucred = crcopy(pc->pc_ucred);
270 pc->pc_ucred->cr_uid = uid;
271 pc->p_ruid = uid;
272 pc->p_svuid = uid;
273 p->p_flag |= P_SUGID;
274 return (0);
275 }
276
277 /* ARGSUSED */
278 int
279 seteuid(p, uap, retval)
280 struct proc *p;
281 struct seteuid_args /* {
282 syscallarg(uid_t) euid;
283 } */ *uap;
284 register_t *retval;
285 {
286 register struct pcred *pc = p->p_cred;
287 register uid_t euid;
288 int error;
289
290 euid = SCARG(uap, euid);
291 if (euid != pc->p_ruid && euid != pc->p_svuid &&
292 (error = suser(pc->pc_ucred, &p->p_acflag)))
293 return (error);
294 /*
295 * Everything's okay, do it. Copy credentials so other references do
296 * not see our changes.
297 */
298 pc->pc_ucred = crcopy(pc->pc_ucred);
299 pc->pc_ucred->cr_uid = euid;
300 p->p_flag |= P_SUGID;
301 return (0);
302 }
303
304 /* ARGSUSED */
305 int
306 setgid(p, uap, retval)
307 struct proc *p;
308 struct setgid_args /* {
309 syscallarg(gid_t) gid;
310 } */ *uap;
311 register_t *retval;
312 {
313 register struct pcred *pc = p->p_cred;
314 register gid_t gid;
315 int error;
316
317 gid = SCARG(uap, gid);
318 if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
319 return (error);
320 pc->pc_ucred = crcopy(pc->pc_ucred);
321 pc->pc_ucred->cr_groups[0] = gid;
322 pc->p_rgid = gid;
323 pc->p_svgid = gid; /* ??? */
324 p->p_flag |= P_SUGID;
325 return (0);
326 }
327
328 /* ARGSUSED */
329 int
330 setegid(p, uap, retval)
331 struct proc *p;
332 struct setegid_args /* {
333 syscallarg(gid_t) egid;
334 } */ *uap;
335 register_t *retval;
336 {
337 register struct pcred *pc = p->p_cred;
338 register gid_t egid;
339 int error;
340
341 egid = SCARG(uap, egid);
342 if (egid != pc->p_rgid && egid != pc->p_svgid &&
343 (error = suser(pc->pc_ucred, &p->p_acflag)))
344 return (error);
345 pc->pc_ucred = crcopy(pc->pc_ucred);
346 pc->pc_ucred->cr_groups[0] = egid;
347 p->p_flag |= P_SUGID;
348 return (0);
349 }
350
351 /* ARGSUSED */
352 int
353 setgroups(p, uap, retval)
354 struct proc *p;
355 struct setgroups_args /* {
356 syscallarg(u_int) gidsetsize;
357 syscallarg(gid_t *) gidset;
358 } */ *uap;
359 register_t *retval;
360 {
361 register struct pcred *pc = p->p_cred;
362 register u_int ngrp;
363 int error;
364
365 if (error = suser(pc->pc_ucred, &p->p_acflag))
366 return (error);
367 ngrp = SCARG(uap, gidsetsize);
368 if (ngrp < 1 || ngrp > NGROUPS)
369 return (EINVAL);
370 pc->pc_ucred = crcopy(pc->pc_ucred);
371 if (error = copyin((caddr_t)SCARG(uap, gidset),
372 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))
373 return (error);
374 pc->pc_ucred->cr_ngroups = ngrp;
375 p->p_flag |= P_SUGID;
376 return (0);
377 }
378
379 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
380 /* ARGSUSED */
381 int
382 compat_43_setreuid(p, uap, retval)
383 register struct proc *p;
384 struct compat_43_setreuid_args /* {
385 syscallarg(int) ruid;
386 syscallarg(int) euid;
387 } */ *uap;
388 register_t *retval;
389 {
390 register struct pcred *pc = p->p_cred;
391 union {
392 struct setuid_args sa;
393 struct seteuid_args ea;
394 } args;
395
396 /*
397 * If ruid == euid then setreuid is being used to emulate setuid,
398 * just do it.
399 */
400 if (SCARG(uap, ruid) != -1 && SCARG(uap, ruid) == SCARG(uap, euid)) {
401 SCARG(&args.sa, uid) = SCARG(uap, ruid);
402 return (setuid(p, &args.sa, retval));
403 }
404 /*
405 * Otherwise we assume that the intent of setting ruid is to be
406 * able to get back ruid priviledge (i.e. swapping ruid and euid).
407 * So we make sure that we will be able to do so, but do not
408 * actually set the ruid.
409 */
410 if (SCARG(uap, ruid) != (uid_t)-1 && SCARG(uap, ruid) != pc->p_ruid &&
411 SCARG(uap, ruid) != pc->p_svuid)
412 return (EPERM);
413 if (SCARG(uap, euid) == (uid_t)-1)
414 return (0);
415 SCARG(&args.ea, euid) = SCARG(uap, euid);
416 return (seteuid(p, &args.ea, retval));
417 }
418
419 /* ARGSUSED */
420 int
421 compat_43_setregid(p, uap, retval)
422 register struct proc *p;
423 struct compat_43_setregid_args /* {
424 syscallarg(int) rgid;
425 syscallarg(int) egid;
426 } */ *uap;
427 register_t *retval;
428 {
429 register struct pcred *pc = p->p_cred;
430 union {
431 struct setgid_args sa;
432 struct setegid_args ea;
433 } args;
434
435 /*
436 * If rgid == egid then setreuid is being used to emulate setgid,
437 * just do it.
438 */
439 if (SCARG(uap, rgid) != -1 && SCARG(uap, rgid) == SCARG(uap, egid)) {
440 SCARG(&args.sa, gid) = SCARG(uap, rgid);
441 return (setgid(p, &args.sa, retval));
442 }
443 /*
444 * Otherwise we assume that the intent of setting rgid is to be
445 * able to get back rgid priviledge (i.e. swapping rgid and egid).
446 * So we make sure that we will be able to do so, but do not
447 * actually set the rgid.
448 */
449 if (SCARG(uap, rgid) != (gid_t)-1 && SCARG(uap, rgid) != pc->p_rgid &&
450 SCARG(uap, rgid) != pc->p_svgid)
451 return (EPERM);
452 if (SCARG(uap, egid) == (gid_t)-1)
453 return (0);
454 SCARG(&args.ea, egid) = SCARG(uap, egid);
455 return (setegid(p, &args.ea, retval));
456 }
457 #endif /* defined(COMPAT_43) || defined(COMPAT_SUNOS) */
458
459 /*
460 * Check if gid is a member of the group set.
461 */
462 int
463 groupmember(gid, cred)
464 gid_t gid;
465 register struct ucred *cred;
466 {
467 register gid_t *gp;
468 gid_t *egp;
469
470 egp = &(cred->cr_groups[cred->cr_ngroups]);
471 for (gp = cred->cr_groups; gp < egp; gp++)
472 if (*gp == gid)
473 return (1);
474 return (0);
475 }
476
477 /*
478 * Test whether the specified credentials imply "super-user"
479 * privilege; if so, and we have accounting info, set the flag
480 * indicating use of super-powers.
481 * Returns 0 or error.
482 */
483 int
484 suser(cred, acflag)
485 struct ucred *cred;
486 u_short *acflag;
487 {
488 if (cred->cr_uid == 0) {
489 if (acflag)
490 *acflag |= ASU;
491 return (0);
492 }
493 return (EPERM);
494 }
495
496 /*
497 * Allocate a zeroed cred structure.
498 */
499 struct ucred *
500 crget()
501 {
502 register struct ucred *cr;
503
504 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
505 bzero((caddr_t)cr, sizeof(*cr));
506 cr->cr_ref = 1;
507 return (cr);
508 }
509
510 /*
511 * Free a cred structure.
512 * Throws away space when ref count gets to 0.
513 */
514 void
515 crfree(cr)
516 struct ucred *cr;
517 {
518 int s;
519
520 s = splimp(); /* ??? */
521 if (--cr->cr_ref == 0)
522 FREE((caddr_t)cr, M_CRED);
523 (void) splx(s);
524 }
525
526 /*
527 * Copy cred structure to a new one and free the old one.
528 */
529 struct ucred *
530 crcopy(cr)
531 struct ucred *cr;
532 {
533 struct ucred *newcr;
534
535 if (cr->cr_ref == 1)
536 return (cr);
537 newcr = crget();
538 *newcr = *cr;
539 crfree(cr);
540 newcr->cr_ref = 1;
541 return (newcr);
542 }
543
544 /*
545 * Dup cred struct to a new held one.
546 */
547 struct ucred *
548 crdup(cr)
549 struct ucred *cr;
550 {
551 struct ucred *newcr;
552
553 newcr = crget();
554 *newcr = *cr;
555 newcr->cr_ref = 1;
556 return (newcr);
557 }
558
559 /*
560 * Get login name, if available.
561 */
562 /* ARGSUSED */
563 int
564 getlogin(p, uap, retval)
565 struct proc *p;
566 struct getlogin_args /* {
567 syscallarg(char *) namebuf;
568 syscallarg(u_int) namelen;
569 } */ *uap;
570 register_t *retval;
571 {
572
573 if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
574 SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
575 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
576 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
577 }
578
579 /*
580 * Set login name.
581 */
582 /* ARGSUSED */
583 int
584 setlogin(p, uap, retval)
585 struct proc *p;
586 struct setlogin_args /* {
587 syscallarg(char *) namebuf;
588 } */ *uap;
589 register_t *retval;
590 {
591 int error;
592
593 if (error = suser(p->p_ucred, &p->p_acflag))
594 return (error);
595 error = copyinstr((caddr_t) SCARG(uap, namebuf),
596 (caddr_t) p->p_pgrp->pg_session->s_login,
597 sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
598 if (error == ENAMETOOLONG)
599 error = EINVAL;
600 return (error);
601 }
602