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