kern_prot.c revision 1.33 1 /* $NetBSD: kern_prot.c,v 1.33 1996/02/09 18:59:42 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 /* 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 && (error = suser(pc->pc_ucred, &p->p_acflag)))
346 return (error);
347 pc->pc_ucred = crcopy(pc->pc_ucred);
348 pc->pc_ucred->cr_gid = gid;
349 pc->p_rgid = gid;
350 pc->p_svgid = gid; /* ??? */
351 p->p_flag |= P_SUGID;
352 return (0);
353 }
354
355 /* ARGSUSED */
356 int
357 sys_setegid(p, v, retval)
358 struct proc *p;
359 void *v;
360 register_t *retval;
361 {
362 struct sys_setegid_args /* {
363 syscallarg(gid_t) egid;
364 } */ *uap = v;
365 register struct pcred *pc = p->p_cred;
366 register gid_t egid;
367 int error;
368
369 #ifdef COMPAT_09 /* XXX */
370 egid = (u_short)SCARG(uap, egid);
371 #else
372 egid = SCARG(uap, egid);
373 #endif
374 if (egid != pc->p_rgid && egid != pc->p_svgid &&
375 (error = suser(pc->pc_ucred, &p->p_acflag)))
376 return (error);
377 pc->pc_ucred = crcopy(pc->pc_ucred);
378 pc->pc_ucred->cr_gid = egid;
379 p->p_flag |= P_SUGID;
380 return (0);
381 }
382
383 /* ARGSUSED */
384 int
385 sys_setgroups(p, v, retval)
386 struct proc *p;
387 void *v;
388 register_t *retval;
389 {
390 struct sys_setgroups_args /* {
391 syscallarg(u_int) gidsetsize;
392 syscallarg(gid_t *) gidset;
393 } */ *uap = v;
394 register struct pcred *pc = p->p_cred;
395 register u_int ngrp;
396 int error;
397
398 if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0)
399 return (error);
400 ngrp = SCARG(uap, gidsetsize);
401 if (ngrp > NGROUPS)
402 return (EINVAL);
403 pc->pc_ucred = crcopy(pc->pc_ucred);
404 error = copyin((caddr_t)SCARG(uap, gidset),
405 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t));
406 if (error)
407 return (error);
408 pc->pc_ucred->cr_ngroups = ngrp;
409 p->p_flag |= P_SUGID;
410 return (0);
411 }
412
413 /*
414 * Check if gid is a member of the group set.
415 */
416 int
417 groupmember(gid, cred)
418 gid_t gid;
419 register struct ucred *cred;
420 {
421 register gid_t *gp;
422 gid_t *egp;
423
424 egp = &(cred->cr_groups[cred->cr_ngroups]);
425 for (gp = cred->cr_groups; gp < egp; gp++)
426 if (*gp == gid)
427 return (1);
428 return (0);
429 }
430
431 /*
432 * Test whether the specified credentials imply "super-user"
433 * privilege; if so, and we have accounting info, set the flag
434 * indicating use of super-powers.
435 * Returns 0 or error.
436 */
437 int
438 suser(cred, acflag)
439 struct ucred *cred;
440 u_short *acflag;
441 {
442 if (cred->cr_uid == 0) {
443 if (acflag)
444 *acflag |= ASU;
445 return (0);
446 }
447 return (EPERM);
448 }
449
450 /*
451 * Allocate a zeroed cred structure.
452 */
453 struct ucred *
454 crget()
455 {
456 register struct ucred *cr;
457
458 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
459 bzero((caddr_t)cr, sizeof(*cr));
460 cr->cr_ref = 1;
461 return (cr);
462 }
463
464 /*
465 * Free a cred structure.
466 * Throws away space when ref count gets to 0.
467 */
468 void
469 crfree(cr)
470 struct ucred *cr;
471 {
472 int s;
473
474 s = splimp(); /* ??? */
475 if (--cr->cr_ref == 0)
476 FREE((caddr_t)cr, M_CRED);
477 (void) splx(s);
478 }
479
480 /*
481 * Copy cred structure to a new one and free the old one.
482 */
483 struct ucred *
484 crcopy(cr)
485 struct ucred *cr;
486 {
487 struct ucred *newcr;
488
489 if (cr->cr_ref == 1)
490 return (cr);
491 newcr = crget();
492 *newcr = *cr;
493 crfree(cr);
494 newcr->cr_ref = 1;
495 return (newcr);
496 }
497
498 /*
499 * Dup cred struct to a new held one.
500 */
501 struct ucred *
502 crdup(cr)
503 struct ucred *cr;
504 {
505 struct ucred *newcr;
506
507 newcr = crget();
508 *newcr = *cr;
509 newcr->cr_ref = 1;
510 return (newcr);
511 }
512
513 /*
514 * Get login name, if available.
515 */
516 /* ARGSUSED */
517 int
518 sys_getlogin(p, v, retval)
519 struct proc *p;
520 void *v;
521 register_t *retval;
522 {
523 struct sys_getlogin_args /* {
524 syscallarg(char *) namebuf;
525 syscallarg(u_int) namelen;
526 } */ *uap = v;
527
528 if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
529 SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
530 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
531 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
532 }
533
534 /*
535 * Set login name.
536 */
537 /* ARGSUSED */
538 int
539 sys_setlogin(p, v, retval)
540 struct proc *p;
541 void *v;
542 register_t *retval;
543 {
544 struct sys_setlogin_args /* {
545 syscallarg(char *) namebuf;
546 } */ *uap = v;
547 int error;
548
549 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
550 return (error);
551 error = copyinstr((caddr_t) SCARG(uap, namebuf),
552 (caddr_t) p->p_pgrp->pg_session->s_login,
553 sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)0);
554 if (error == ENAMETOOLONG)
555 error = EINVAL;
556 return (error);
557 }
558