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