kern_prot.c revision 1.14 1 /*
2 * Copyright (c) 1982, 1986, 1989, 1990, 1991 Regents of the University
3 * 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 * from: @(#)kern_prot.c 7.21 (Berkeley) 5/3/91
39 * $Id: kern_prot.c,v 1.14 1994/05/17 04:21:57 cgd Exp $
40 */
41
42 /*
43 * System calls related to processes and protection
44 */
45
46 #include <sys/param.h>
47 #include <sys/acct.h>
48 #include <sys/systm.h>
49 #include <sys/ucred.h>
50 #include <sys/proc.h>
51 #include <sys/timeb.h>
52 #include <sys/times.h>
53 #include <sys/malloc.h>
54
55 /* ARGSUSED */
56 int
57 getpid(p, uap, retval)
58 struct proc *p;
59 void *uap;
60 int *retval;
61 {
62
63 *retval = p->p_pid;
64 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
65 retval[1] = p->p_pptr->p_pid;
66 #endif
67 return (0);
68 }
69
70 /* ARGSUSED */
71 int
72 getppid(p, uap, retval)
73 struct proc *p;
74 void *uap;
75 int *retval;
76 {
77
78 *retval = p->p_pptr->p_pid;
79 return (0);
80 }
81
82 /* Get process group ID; note that POSIX getpgrp takes no parameter */
83 int
84 getpgrp(p, uap, retval)
85 struct proc *p;
86 void *uap;
87 int *retval;
88 {
89
90 *retval = p->p_pgrp->pg_id;
91 return (0);
92 }
93
94 /* ARGSUSED */
95 int
96 getuid(p, uap, retval)
97 struct proc *p;
98 void *uap;
99 int *retval;
100 {
101
102 *retval = p->p_cred->p_ruid;
103 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
104 retval[1] = p->p_ucred->cr_uid;
105 #endif
106 return (0);
107 }
108
109 /* ARGSUSED */
110 int
111 geteuid(p, uap, retval)
112 struct proc *p;
113 void *uap;
114 int *retval;
115 {
116
117 *retval = p->p_ucred->cr_uid;
118 return (0);
119 }
120
121 /* ARGSUSED */
122 int
123 getgid(p, uap, retval)
124 struct proc *p;
125 void *uap;
126 int *retval;
127 {
128
129 *retval = p->p_cred->p_rgid;
130 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
131 retval[1] = p->p_ucred->cr_groups[0];
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 int
143 getegid(p, uap, retval)
144 struct proc *p;
145 void *uap;
146 int *retval;
147 {
148
149 *retval = p->p_ucred->cr_groups[0];
150 return (0);
151 }
152
153 struct getgroups_args {
154 u_int gidsetsize;
155 gid_t *gidset;
156 };
157
158 int
159 getgroups(p, uap, retval)
160 struct proc *p;
161 register struct getgroups_args *uap;
162 int *retval;
163 {
164 register struct pcred *pc = p->p_cred;
165 register u_int ngrp;
166 int error;
167
168 if ((ngrp = 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)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 int *retval;
188 {
189
190 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
191 return (EPERM);
192 } else {
193 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
213 struct setpgid_args {
214 int pid; /* target process id */
215 int pgid; /* target pgrp id */
216 };
217
218 /* ARGSUSED */
219 int
220 setpgid(curp, uap, retval)
221 struct proc *curp;
222 register struct setpgid_args *uap;
223 int *retval;
224 {
225 register struct proc *targp; /* target process */
226 register struct pgrp *pgrp; /* target pgrp */
227
228 #ifdef COMPAT_09
229 uap->pid = (short) uap->pid; /* XXX */
230 uap->pgid = (short) uap->pgid; /* XXX */
231 #endif
232
233 if (uap->pid != 0 && uap->pid != curp->p_pid) {
234 if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
235 return (ESRCH);
236 if (targp->p_session != curp->p_session)
237 return (EPERM);
238 if (targp->p_flag&P_EXEC)
239 return (EACCES);
240 } else
241 targp = curp;
242 if (SESS_LEADER(targp))
243 return (EPERM);
244 if (uap->pgid == 0)
245 uap->pgid = targp->p_pid;
246 else if (uap->pgid != targp->p_pid)
247 if ((pgrp = pgfind(uap->pgid)) == 0 ||
248 pgrp->pg_session != curp->p_session)
249 return (EPERM);
250 enterpgrp(targp, uap->pgid, 0);
251 return (0);
252 }
253
254 struct setuid_args {
255 uid_t uid;
256 };
257
258 /* ARGSUSED */
259 int
260 setuid(p, uap, retval)
261 struct proc *p;
262 struct setuid_args *uap;
263 int *retval;
264 {
265 register struct pcred *pc = p->p_cred;
266 register uid_t uid;
267 int error;
268
269 #ifdef COMPAT_09 /* XXX */
270 uid = (u_short)uap->uid;
271 #else
272 uid = uap->uid;
273 #endif
274 if (uid != pc->p_ruid &&
275 (error = suser(pc->pc_ucred, &p->p_acflag)))
276 return (error);
277 /*
278 * Everything's okay, do it. Copy credentials so other references do
279 * not see our changes.
280 */
281 pc->pc_ucred = crcopy(pc->pc_ucred);
282 pc->pc_ucred->cr_uid = uid;
283 pc->p_ruid = uid;
284 pc->p_svuid = uid;
285 p->p_flag |= P_SUGID;
286 return (0);
287 }
288
289 struct seteuid_args {
290 uid_t euid;
291 };
292
293 /* ARGSUSED */
294 int
295 seteuid(p, uap, retval)
296 struct proc *p;
297 struct seteuid_args *uap;
298 int *retval;
299 {
300 register struct pcred *pc = p->p_cred;
301 register uid_t euid;
302 int error;
303
304 #ifdef COMPAT_09 /* XXX */
305 euid = (u_short)uap->euid;
306 #else
307 euid = uap->euid;
308 #endif
309 if (euid != pc->p_ruid && euid != pc->p_svuid &&
310 (error = suser(pc->pc_ucred, &p->p_acflag)))
311 return (error);
312 /*
313 * Everything's okay, do it. Copy credentials so other references do
314 * not see our changes.
315 */
316 pc->pc_ucred = crcopy(pc->pc_ucred);
317 pc->pc_ucred->cr_uid = euid;
318 p->p_flag |= P_SUGID;
319 return (0);
320 }
321
322 struct setgid_args {
323 gid_t gid;
324 };
325
326 /* ARGSUSED */
327 int
328 setgid(p, uap, retval)
329 struct proc *p;
330 struct setgid_args *uap;
331 int *retval;
332 {
333 register struct pcred *pc = p->p_cred;
334 register gid_t gid;
335 int error;
336
337 #ifdef COMPAT_09 /* XXX */
338 gid = (u_short)uap->gid;
339 #else
340 gid = uap->gid;
341 #endif
342 if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
343 return (error);
344 pc->pc_ucred = crcopy(pc->pc_ucred);
345 pc->pc_ucred->cr_groups[0] = gid;
346 pc->p_rgid = gid;
347 pc->p_svgid = gid; /* ??? */
348 p->p_flag |= P_SUGID;
349 return (0);
350 }
351
352 struct setegid_args {
353 gid_t egid;
354 };
355
356 /* ARGSUSED */
357 int
358 setegid(p, uap, retval)
359 struct proc *p;
360 struct setegid_args *uap;
361 int *retval;
362 {
363 register struct pcred *pc = p->p_cred;
364 register gid_t egid;
365 int error;
366
367 #ifdef COMPAT_09 /* XXX */
368 egid = (u_short)uap->egid;
369 #else
370 egid = uap->egid;
371 #endif
372 if (egid != pc->p_rgid && egid != pc->p_svgid &&
373 (error = suser(pc->pc_ucred, &p->p_acflag)))
374 return (error);
375 pc->pc_ucred = crcopy(pc->pc_ucred);
376 pc->pc_ucred->cr_groups[0] = egid;
377 p->p_flag |= P_SUGID;
378 return (0);
379 }
380
381 #ifdef COMPAT_43
382
383 struct osetreuid_args {
384 uid_t ruid;
385 uid_t euid;
386 };
387
388 /* ARGSUSED */
389 int
390 osetreuid(p, uap, retval)
391 register struct proc *p;
392 struct osetreuid_args *uap;
393 int *retval;
394 {
395 register struct pcred *pc = p->p_cred;
396 struct seteuid_args args;
397
398 /*
399 * we assume that the intent of setting ruid is to be able to get
400 * back ruid priviledge. So we make sure that we will be able to
401 * do so, but do not actually set the ruid.
402 */
403 if (uap->ruid != (uid_t)-1 && uap->ruid != pc->p_ruid &&
404 uap->ruid != pc->p_svuid)
405 return (EPERM);
406 if (uap->euid == (uid_t)-1)
407 return (0);
408 args.euid = uap->euid;
409 return (seteuid(p, &args, retval));
410 }
411
412 struct osetregid_args {
413 gid_t rgid;
414 gid_t egid;
415 };
416
417 /* ARGSUSED */
418 int
419 osetregid(p, uap, retval)
420 register struct proc *p;
421 struct osetregid_args *uap;
422 int *retval;
423 {
424 register struct pcred *pc = p->p_cred;
425 struct setegid_args args;
426
427 /*
428 * we assume that the intent of setting rgid is to be able to get
429 * back rgid priviledge. So we make sure that we will be able to
430 * do so, but do not actually set the rgid.
431 */
432 if (uap->rgid != (gid_t)-1 && uap->rgid != pc->p_rgid &&
433 uap->rgid != pc->p_svgid)
434 return (EPERM);
435 if (uap->egid == (gid_t)-1)
436 return (0);
437 args.egid = uap->egid;
438 return (setegid(p, &args, retval));
439 }
440 #endif
441
442 struct setgroups_args {
443 u_int gidsetsize;
444 gid_t *gidset;
445 };
446
447 /* ARGSUSED */
448 int
449 setgroups(p, uap, retval)
450 struct proc *p;
451 struct setgroups_args *uap;
452 int *retval;
453 {
454 register struct pcred *pc = p->p_cred;
455 register u_int ngrp;
456 int error;
457
458 if (error = suser(pc->pc_ucred, &p->p_acflag))
459 return (error);
460 if ((ngrp = uap->gidsetsize) > NGROUPS)
461 return (EINVAL);
462 pc->pc_ucred = crcopy(pc->pc_ucred);
463 if (error = copyin((caddr_t)uap->gidset,
464 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))
465 return (error);
466 pc->pc_ucred->cr_ngroups = ngrp;
467 p->p_flag |= P_SUGID;
468 return (0);
469 }
470
471 /*
472 * Check if gid is a member of the group set.
473 */
474 int
475 groupmember(gid, cred)
476 gid_t gid;
477 register struct ucred *cred;
478 {
479 register gid_t *gp;
480 gid_t *egp;
481
482 egp = &(cred->cr_groups[cred->cr_ngroups]);
483 for (gp = cred->cr_groups; gp < egp; gp++)
484 if (*gp == gid)
485 return (1);
486 return (0);
487 }
488
489 /*
490 * Test whether the specified credentials imply "super-user"
491 * privilege; if so, and we have accounting info, set the flag
492 * indicating use of super-powers.
493 * Returns 0 or error.
494 */
495 int
496 suser(cred, acflag)
497 struct ucred *cred;
498 u_short *acflag;
499 {
500 if (cred->cr_uid == 0) {
501 if (acflag)
502 *acflag |= ASU;
503 return (0);
504 }
505 return (EPERM);
506 }
507
508 /*
509 * Allocate a zeroed cred structure.
510 */
511 struct ucred *
512 crget()
513 {
514 register struct ucred *cr;
515
516 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
517 bzero((caddr_t)cr, sizeof(*cr));
518 cr->cr_ref = 1;
519 return (cr);
520 }
521
522 /*
523 * Free a cred structure.
524 * Throws away space when ref count gets to 0.
525 */
526 void
527 crfree(cr)
528 struct ucred *cr;
529 {
530 int s = splimp(); /* ??? */
531
532 if (--cr->cr_ref != 0) {
533 (void) splx(s);
534 return;
535 }
536 FREE((caddr_t)cr, M_CRED);
537 (void) splx(s);
538 }
539
540 /*
541 * Copy cred structure to a new one and free the old one.
542 */
543 struct ucred *
544 crcopy(cr)
545 struct ucred *cr;
546 {
547 struct ucred *newcr;
548
549 if (cr->cr_ref == 1)
550 return (cr);
551 newcr = crget();
552 *newcr = *cr;
553 crfree(cr);
554 newcr->cr_ref = 1;
555 return (newcr);
556 }
557
558 /*
559 * Dup cred struct to a new held one.
560 */
561 struct ucred *
562 crdup(cr)
563 struct ucred *cr;
564 {
565 struct ucred *newcr;
566
567 newcr = crget();
568 *newcr = *cr;
569 newcr->cr_ref = 1;
570 return (newcr);
571 }
572
573 /*
574 * Get login name, if available.
575 */
576
577 struct getlogin_args {
578 char *namebuf;
579 u_int namelen;
580 };
581
582 /* ARGSUSED */
583 int
584 getlogin(p, uap, retval)
585 struct proc *p;
586 struct getlogin_args *uap;
587 int *retval;
588 {
589
590 if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
591 uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
592 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
593 (caddr_t) uap->namebuf, uap->namelen));
594 }
595
596 /*
597 * Set login name.
598 */
599
600 struct setlogin_args {
601 char *namebuf;
602 };
603
604 /* ARGSUSED */
605 int
606 setlogin(p, uap, retval)
607 struct proc *p;
608 struct setlogin_args *uap;
609 int *retval;
610 {
611 int error;
612
613 if (error = suser(p->p_ucred, &p->p_acflag))
614 return (error);
615 error = copyinstr((caddr_t) uap->namebuf,
616 (caddr_t) p->p_pgrp->pg_session->s_login,
617 sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
618 if (error == ENAMETOOLONG)
619 error = EINVAL;
620 return (error);
621 }
622