kern_prot.c revision 1.34 1 /* $NetBSD: kern_prot.c,v 1.34 1996/05/22 02:22:47 mycroft 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 /* ARGSUSED */
60 int
61 sys_getpid(p, v, retval)
62 struct proc *p;
63 void *v;
64 register_t *retval;
65 {
66
67 *retval = p->p_pid;
68 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \
69 defined(COMPAT_FREEBSD)
70 retval[1] = p->p_pptr->p_pid;
71 #endif
72 return (0);
73 }
74
75 /* ARGSUSED */
76 int
77 sys_getppid(p, v, retval)
78 struct proc *p;
79 void *v;
80 register_t *retval;
81 {
82
83 *retval = p->p_pptr->p_pid;
84 return (0);
85 }
86
87 /* Get process group ID; note that POSIX getpgrp takes no parameter */
88 int
89 sys_getpgrp(p, v, retval)
90 struct proc *p;
91 void *v;
92 register_t *retval;
93 {
94
95 *retval = p->p_pgrp->pg_id;
96 return (0);
97 }
98
99 /* ARGSUSED */
100 int
101 sys_getuid(p, v, retval)
102 struct proc *p;
103 void *v;
104 register_t *retval;
105 {
106
107 *retval = p->p_cred->p_ruid;
108 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \
109 defined(COMPAT_FREEBSD)
110 retval[1] = p->p_ucred->cr_uid;
111 #endif
112 return (0);
113 }
114
115 /* ARGSUSED */
116 int
117 sys_geteuid(p, v, retval)
118 struct proc *p;
119 void *v;
120 register_t *retval;
121 {
122
123 *retval = p->p_ucred->cr_uid;
124 return (0);
125 }
126
127 /* ARGSUSED */
128 int
129 sys_getgid(p, v, retval)
130 struct proc *p;
131 void *v;
132 register_t *retval;
133 {
134
135 *retval = p->p_cred->p_rgid;
136 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_FREEBSD)
137 retval[1] = p->p_ucred->cr_gid;
138 #endif
139 return (0);
140 }
141
142 /*
143 * Get effective group ID. The "egid" is groups[0], and could be obtained
144 * via getgroups. This syscall exists because it is somewhat painful to do
145 * correctly in a library function.
146 */
147 /* ARGSUSED */
148 int
149 sys_getegid(p, v, retval)
150 struct proc *p;
151 void *v;
152 register_t *retval;
153 {
154
155 *retval = p->p_ucred->cr_gid;
156 return (0);
157 }
158
159 int
160 sys_getgroups(p, v, retval)
161 struct proc *p;
162 void *v;
163 register_t *retval;
164 {
165 register struct sys_getgroups_args /* {
166 syscallarg(u_int) gidsetsize;
167 syscallarg(gid_t *) gidset;
168 } */ *uap = v;
169 register struct pcred *pc = p->p_cred;
170 register u_int ngrp;
171 int error;
172
173 if ((ngrp = SCARG(uap, gidsetsize)) == 0) {
174 *retval = pc->pc_ucred->cr_ngroups;
175 return (0);
176 }
177 if (ngrp < pc->pc_ucred->cr_ngroups)
178 return (EINVAL);
179 ngrp = pc->pc_ucred->cr_ngroups;
180 error = copyout((caddr_t)pc->pc_ucred->cr_groups,
181 (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t));
182 if (error)
183 return (error);
184 *retval = ngrp;
185 return (0);
186 }
187
188 /* ARGSUSED */
189 int
190 sys_setsid(p, v, retval)
191 register struct proc *p;
192 void *v;
193 register_t *retval;
194 {
195
196 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
197 return (EPERM);
198 } else {
199 (void)enterpgrp(p, p->p_pid, 1);
200 *retval = p->p_pid;
201 return (0);
202 }
203 }
204
205 /*
206 * set process group (setpgid/old setpgrp)
207 *
208 * caller does setpgid(targpid, targpgid)
209 *
210 * pid must be caller or child of caller (ESRCH)
211 * if a child
212 * pid must be in same session (EPERM)
213 * pid can't have done an exec (EACCES)
214 * if pgid != pid
215 * there must exist some pid in same session having pgid (EPERM)
216 * pid must not be session leader (EPERM)
217 */
218 /* ARGSUSED */
219 int
220 sys_setpgid(curp, v, retval)
221 struct proc *curp;
222 void *v;
223 register_t *retval;
224 {
225 register struct sys_setpgid_args /* {
226 syscallarg(int) pid;
227 syscallarg(int) pgid;
228 } */ *uap = v;
229 register struct proc *targp; /* target process */
230 register struct pgrp *pgrp; /* target pgrp */
231
232 #ifdef COMPAT_09
233 SCARG(uap, pid) = (short) SCARG(uap, pid); /* XXX */
234 SCARG(uap, pgid) = (short) SCARG(uap, pgid); /* XXX */
235 #endif
236
237 if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
238 if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp))
239 return (ESRCH);
240 if (targp->p_session != curp->p_session)
241 return (EPERM);
242 if (targp->p_flag & P_EXEC)
243 return (EACCES);
244 } else
245 targp = curp;
246 if (SESS_LEADER(targp))
247 return (EPERM);
248 if (SCARG(uap, pgid) == 0)
249 SCARG(uap, pgid) = targp->p_pid;
250 else if (SCARG(uap, pgid) != targp->p_pid)
251 if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 ||
252 pgrp->pg_session != curp->p_session)
253 return (EPERM);
254 return (enterpgrp(targp, SCARG(uap, pgid), 0));
255 }
256
257 /* ARGSUSED */
258 int
259 sys_setuid(p, v, retval)
260 struct proc *p;
261 void *v;
262 register_t *retval;
263 {
264 struct sys_setuid_args /* {
265 syscallarg(uid_t) uid;
266 } */ *uap = v;
267 register struct pcred *pc = p->p_cred;
268 register uid_t uid;
269 int error;
270
271 #ifdef COMPAT_09 /* XXX */
272 uid = (u_short)SCARG(uap, uid);
273 #else
274 uid = SCARG(uap, uid);
275 #endif
276 if (uid != pc->p_ruid &&
277 (error = suser(pc->pc_ucred, &p->p_acflag)))
278 return (error);
279 /*
280 * Everything's okay, do it.
281 * Transfer proc count to new user.
282 * Copy credentials so other references do not see our changes.
283 */
284 (void)chgproccnt(pc->p_ruid, -1);
285 (void)chgproccnt(uid, 1);
286 pc->pc_ucred = crcopy(pc->pc_ucred);
287 pc->pc_ucred->cr_uid = uid;
288 pc->p_ruid = uid;
289 pc->p_svuid = uid;
290 p->p_flag |= P_SUGID;
291 return (0);
292 }
293
294 /* ARGSUSED */
295 int
296 sys_seteuid(p, v, retval)
297 struct proc *p;
298 void *v;
299 register_t *retval;
300 {
301 struct sys_seteuid_args /* {
302 syscallarg(uid_t) euid;
303 } */ *uap = v;
304 register struct pcred *pc = p->p_cred;
305 register uid_t euid;
306 int error;
307
308 #ifdef COMPAT_09 /* XXX */
309 euid = (u_short)SCARG(uap, euid);
310 #else
311 euid = SCARG(uap, euid);
312 #endif
313 if (euid != pc->p_ruid && euid != pc->p_svuid &&
314 (error = suser(pc->pc_ucred, &p->p_acflag)))
315 return (error);
316 /*
317 * Everything's okay, do it. Copy credentials so other references do
318 * not see our changes.
319 */
320 pc->pc_ucred = crcopy(pc->pc_ucred);
321 pc->pc_ucred->cr_uid = euid;
322 p->p_flag |= P_SUGID;
323 return (0);
324 }
325
326 /* ARGSUSED */
327 int
328 sys_setgid(p, v, retval)
329 struct proc *p;
330 void *v;
331 register_t *retval;
332 {
333 struct sys_setgid_args /* {
334 syscallarg(gid_t) gid;
335 } */ *uap = v;
336 register struct pcred *pc = p->p_cred;
337 register gid_t gid;
338 int error;
339
340 #ifdef COMPAT_09 /* XXX */
341 gid = (u_short)SCARG(uap, gid);
342 #else
343 gid = SCARG(uap, gid);
344 #endif
345 if (gid != pc->p_rgid &&
346 (error = suser(pc->pc_ucred, &p->p_acflag)))
347 return (error);
348 pc->pc_ucred = crcopy(pc->pc_ucred);
349 pc->pc_ucred->cr_gid = gid;
350 pc->p_rgid = gid;
351 pc->p_svgid = gid;
352 p->p_flag |= P_SUGID;
353 return (0);
354 }
355
356 /* ARGSUSED */
357 int
358 sys_setegid(p, v, retval)
359 struct proc *p;
360 void *v;
361 register_t *retval;
362 {
363 struct sys_setegid_args /* {
364 syscallarg(gid_t) egid;
365 } */ *uap = v;
366 register struct pcred *pc = p->p_cred;
367 register gid_t egid;
368 int error;
369
370 #ifdef COMPAT_09 /* XXX */
371 egid = (u_short)SCARG(uap, egid);
372 #else
373 egid = SCARG(uap, egid);
374 #endif
375 if (egid != pc->p_rgid && egid != pc->p_svgid &&
376 (error = suser(pc->pc_ucred, &p->p_acflag)))
377 return (error);
378 pc->pc_ucred = crcopy(pc->pc_ucred);
379 pc->pc_ucred->cr_gid = egid;
380 p->p_flag |= P_SUGID;
381 return (0);
382 }
383
384 /* ARGSUSED */
385 int
386 sys_setgroups(p, v, retval)
387 struct proc *p;
388 void *v;
389 register_t *retval;
390 {
391 struct sys_setgroups_args /* {
392 syscallarg(u_int) gidsetsize;
393 syscallarg(gid_t *) gidset;
394 } */ *uap = v;
395 register struct pcred *pc = p->p_cred;
396 register u_int ngrp;
397 int error;
398
399 if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0)
400 return (error);
401 ngrp = SCARG(uap, gidsetsize);
402 if (ngrp > NGROUPS)
403 return (EINVAL);
404 pc->pc_ucred = crcopy(pc->pc_ucred);
405 error = copyin((caddr_t)SCARG(uap, gidset),
406 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t));
407 if (error)
408 return (error);
409 pc->pc_ucred->cr_ngroups = ngrp;
410 p->p_flag |= P_SUGID;
411 return (0);
412 }
413
414 /*
415 * Check if gid is a member of the group set.
416 */
417 int
418 groupmember(gid, cred)
419 gid_t gid;
420 register struct ucred *cred;
421 {
422 register gid_t *gp;
423 gid_t *egp;
424
425 egp = &(cred->cr_groups[cred->cr_ngroups]);
426 for (gp = cred->cr_groups; gp < egp; gp++)
427 if (*gp == gid)
428 return (1);
429 return (0);
430 }
431
432 /*
433 * Test whether the specified credentials imply "super-user"
434 * privilege; if so, and we have accounting info, set the flag
435 * indicating use of super-powers.
436 * Returns 0 or error.
437 */
438 int
439 suser(cred, acflag)
440 struct ucred *cred;
441 u_short *acflag;
442 {
443 if (cred->cr_uid == 0) {
444 if (acflag)
445 *acflag |= ASU;
446 return (0);
447 }
448 return (EPERM);
449 }
450
451 /*
452 * Allocate a zeroed cred structure.
453 */
454 struct ucred *
455 crget()
456 {
457 register struct ucred *cr;
458
459 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
460 bzero((caddr_t)cr, sizeof(*cr));
461 cr->cr_ref = 1;
462 return (cr);
463 }
464
465 /*
466 * Free a cred structure.
467 * Throws away space when ref count gets to 0.
468 */
469 void
470 crfree(cr)
471 struct ucred *cr;
472 {
473 int s;
474
475 s = splimp(); /* ??? */
476 if (--cr->cr_ref == 0)
477 FREE((caddr_t)cr, M_CRED);
478 (void) splx(s);
479 }
480
481 /*
482 * Copy cred structure to a new one and free the old one.
483 */
484 struct ucred *
485 crcopy(cr)
486 struct ucred *cr;
487 {
488 struct ucred *newcr;
489
490 if (cr->cr_ref == 1)
491 return (cr);
492 newcr = crget();
493 *newcr = *cr;
494 crfree(cr);
495 newcr->cr_ref = 1;
496 return (newcr);
497 }
498
499 /*
500 * Dup cred struct to a new held one.
501 */
502 struct ucred *
503 crdup(cr)
504 struct ucred *cr;
505 {
506 struct ucred *newcr;
507
508 newcr = crget();
509 *newcr = *cr;
510 newcr->cr_ref = 1;
511 return (newcr);
512 }
513
514 /*
515 * Get login name, if available.
516 */
517 /* ARGSUSED */
518 int
519 sys_getlogin(p, v, retval)
520 struct proc *p;
521 void *v;
522 register_t *retval;
523 {
524 struct sys_getlogin_args /* {
525 syscallarg(char *) namebuf;
526 syscallarg(u_int) namelen;
527 } */ *uap = v;
528
529 if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
530 SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
531 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
532 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
533 }
534
535 /*
536 * Set login name.
537 */
538 /* ARGSUSED */
539 int
540 sys_setlogin(p, v, retval)
541 struct proc *p;
542 void *v;
543 register_t *retval;
544 {
545 struct sys_setlogin_args /* {
546 syscallarg(char *) namebuf;
547 } */ *uap = v;
548 int error;
549
550 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
551 return (error);
552 error = copyinstr((caddr_t) SCARG(uap, namebuf),
553 (caddr_t) p->p_pgrp->pg_session->s_login,
554 sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)0);
555 if (error == ENAMETOOLONG)
556 error = EINVAL;
557 return (error);
558 }
559