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