From John Dyson - fix for bug in kern_physio where buffers would be
[unix-history] / sys / kern / kern_prot.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1982, 1986, 1989, 1990, 1991 Regents of the University
3 * of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
600f7f07 33 * from: @(#)kern_prot.c 7.21 (Berkeley) 5/3/91
67c9e20b 34 * $Id: kern_prot.c,v 1.5 1993/12/19 00:51:29 wollman Exp $
15637ed4
RG
35 */
36
37/*
38 * System calls related to processes and protection
39 */
40
41#include "param.h"
15637ed4 42#include "systm.h"
fde1aeb2 43#include "acct.h"
15637ed4
RG
44#include "ucred.h"
45#include "proc.h"
46#include "timeb.h"
47#include "times.h"
48#include "malloc.h"
49
50/* ARGSUSED */
4c45483e 51int
15637ed4
RG
52getpid(p, uap, retval)
53 struct proc *p;
54 void *uap;
55 int *retval;
56{
57
58 *retval = p->p_pid;
59#ifdef COMPAT_43
60 retval[1] = p->p_pptr->p_pid;
61#endif
62 return (0);
63}
64
65/* ARGSUSED */
4c45483e 66int
15637ed4
RG
67getppid(p, uap, retval)
68 struct proc *p;
69 void *uap;
70 int *retval;
71{
72
73 *retval = p->p_pptr->p_pid;
74 return (0);
75}
76
77/* Get process group ID; note that POSIX getpgrp takes no parameter */
4c45483e 78int
15637ed4
RG
79getpgrp(p, uap, retval)
80 struct proc *p;
81 void *uap;
82 int *retval;
83{
84
85 *retval = p->p_pgrp->pg_id;
86 return (0);
87}
88
89/* ARGSUSED */
4c45483e 90int
15637ed4
RG
91getuid(p, uap, retval)
92 struct proc *p;
93 void *uap;
94 int *retval;
95{
96
97 *retval = p->p_cred->p_ruid;
98#ifdef COMPAT_43
99 retval[1] = p->p_ucred->cr_uid;
100#endif
101 return (0);
102}
103
104/* ARGSUSED */
4c45483e 105int
15637ed4
RG
106geteuid(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 */
4c45483e 117int
15637ed4
RG
118getgid(p, uap, retval)
119 struct proc *p;
120 void *uap;
121 int *retval;
122{
123
124 *retval = p->p_cred->p_rgid;
125#ifdef COMPAT_43
126 retval[1] = p->p_ucred->cr_groups[0];
127#endif
128 return (0);
129}
130
131/*
132 * Get effective group ID. The "egid" is groups[0], and could be obtained
133 * via getgroups. This syscall exists because it is somewhat painful to do
134 * correctly in a library function.
135 */
136/* ARGSUSED */
4c45483e 137int
15637ed4
RG
138getegid(p, uap, retval)
139 struct proc *p;
140 void *uap;
141 int *retval;
142{
143
144 *retval = p->p_ucred->cr_groups[0];
145 return (0);
146}
147
3c7eb27c
DG
148struct getgroups_args {
149 u_int gidsetsize;
150 int *gidset; /* XXX not yet POSIX */
151};
152
4c45483e 153int
15637ed4
RG
154getgroups(p, uap, retval)
155 struct proc *p;
3c7eb27c 156 register struct getgroups_args *uap;
15637ed4
RG
157 int *retval;
158{
159 register struct pcred *pc = p->p_cred;
160 register gid_t *gp;
161 register int *lp;
162 register u_int ngrp;
163 int groups[NGROUPS];
164 int error;
165
166 if ((ngrp = uap->gidsetsize) == 0) {
167 *retval = pc->pc_ucred->cr_ngroups;
168 return (0);
169 }
170 if (ngrp < pc->pc_ucred->cr_ngroups)
171 return (EINVAL);
172 ngrp = pc->pc_ucred->cr_ngroups;
173 for (gp = pc->pc_ucred->cr_groups, lp = groups; lp < &groups[ngrp]; )
174 *lp++ = *gp++;
175 if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset,
176 ngrp * sizeof (groups[0])))
177 return (error);
178 *retval = ngrp;
179 return (0);
180}
181
182/* ARGSUSED */
4c45483e 183int
15637ed4
RG
184setsid(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 */
3c7eb27c
DG
212
213struct setpgid_args {
214 int pid; /* target process id */
215 int pgid; /* target pgrp id */
216};
217
15637ed4 218/* ARGSUSED */
4c45483e 219int
15637ed4
RG
220setpgid(curp, uap, retval)
221 struct proc *curp;
3c7eb27c 222 register struct setpgid_args *uap;
15637ed4
RG
223 int *retval;
224{
225 register struct proc *targp; /* target process */
226 register struct pgrp *pgrp; /* target pgrp */
227
228 if (uap->pid != 0 && uap->pid != curp->p_pid) {
229 if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
230 return (ESRCH);
231 if (targp->p_session != curp->p_session)
232 return (EPERM);
233 if (targp->p_flag&SEXEC)
234 return (EACCES);
235 } else
236 targp = curp;
237 if (SESS_LEADER(targp))
238 return (EPERM);
239 if (uap->pgid == 0)
240 uap->pgid = targp->p_pid;
241 else if (uap->pgid != targp->p_pid)
242 if ((pgrp = pgfind(uap->pgid)) == 0 ||
243 pgrp->pg_session != curp->p_session)
244 return (EPERM);
245 enterpgrp(targp, uap->pgid, 0);
246 return (0);
247}
248
3c7eb27c
DG
249struct setuid_args {
250 int uid;
251};
252
15637ed4 253/* ARGSUSED */
4c45483e 254int
15637ed4
RG
255setuid(p, uap, retval)
256 struct proc *p;
3c7eb27c 257 struct setuid_args *uap;
15637ed4
RG
258 int *retval;
259{
260 register struct pcred *pc = p->p_cred;
261 register uid_t uid;
262 int error;
263
264 uid = uap->uid;
265 if (uid != pc->p_ruid &&
266 (error = suser(pc->pc_ucred, &p->p_acflag)))
267 return (error);
268 /*
269 * Everything's okay, do it. Copy credentials so other references do
270 * not see our changes.
271 */
272 pc->pc_ucred = crcopy(pc->pc_ucred);
273 pc->pc_ucred->cr_uid = uid;
274 pc->p_ruid = uid;
275 pc->p_svuid = uid;
67c9e20b 276 p->p_flag |= SUGID;
15637ed4
RG
277 return (0);
278}
279
3c7eb27c
DG
280struct seteuid_args {
281 int euid;
282};
283
15637ed4 284/* ARGSUSED */
4c45483e 285int
15637ed4
RG
286seteuid(p, uap, retval)
287 struct proc *p;
3c7eb27c 288 struct seteuid_args *uap;
15637ed4
RG
289 int *retval;
290{
291 register struct pcred *pc = p->p_cred;
292 register uid_t euid;
293 int error;
294
295 euid = uap->euid;
296 if (euid != pc->p_ruid && euid != pc->p_svuid &&
297 (error = suser(pc->pc_ucred, &p->p_acflag)))
298 return (error);
299 /*
300 * Everything's okay, do it. Copy credentials so other references do
301 * not see our changes.
302 */
303 pc->pc_ucred = crcopy(pc->pc_ucred);
304 pc->pc_ucred->cr_uid = euid;
67c9e20b 305 p->p_flag |= SUGID;
15637ed4
RG
306 return (0);
307}
308
3c7eb27c
DG
309struct setgid_args {
310 int gid;
311};
312
15637ed4 313/* ARGSUSED */
4c45483e 314int
15637ed4
RG
315setgid(p, uap, retval)
316 struct proc *p;
3c7eb27c 317 struct setgid_args *uap;
15637ed4
RG
318 int *retval;
319{
320 register struct pcred *pc = p->p_cred;
321 register gid_t gid;
322 int error;
323
324 gid = uap->gid;
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;
67c9e20b
GW
330 pc->p_svgid = gid;
331 p->p_flag |= SUGID;
15637ed4
RG
332 return (0);
333}
334
3c7eb27c
DG
335struct setegid_args {
336 int egid;
337};
338
15637ed4 339/* ARGSUSED */
4c45483e 340int
15637ed4
RG
341setegid(p, uap, retval)
342 struct proc *p;
3c7eb27c 343 struct setegid_args *uap;
15637ed4
RG
344 int *retval;
345{
346 register struct pcred *pc = p->p_cred;
347 register gid_t egid;
348 int error;
349
350 egid = uap->egid;
351 if (egid != pc->p_rgid && egid != pc->p_svgid &&
352 (error = suser(pc->pc_ucred, &p->p_acflag)))
353 return (error);
354 pc->pc_ucred = crcopy(pc->pc_ucred);
355 pc->pc_ucred->cr_groups[0] = egid;
67c9e20b 356 p->p_flag |= SUGID;
15637ed4
RG
357 return (0);
358}
359
360#ifdef COMPAT_43
3c7eb27c
DG
361
362struct osetreuid_args {
363 int ruid;
364 int euid;
365};
366
15637ed4 367/* ARGSUSED */
4c45483e 368int
15637ed4
RG
369osetreuid(p, uap, retval)
370 register struct proc *p;
3c7eb27c 371 struct osetreuid_args *uap;
15637ed4
RG
372 int *retval;
373{
374 register struct pcred *pc = p->p_cred;
67c9e20b 375 struct seteuid_args e_args;
15637ed4 376
15637ed4 377 /*
67c9e20b
GW
378 * Most calls to setreuid() are done in order to swap real and
379 * effective uids. In old versions of BSD, this was the only
380 * way to temporarily renounce privileges and be able to get
381 * them back. In the presence of the POSIX saved id, however,
382 * we can do this without modifying the real uid, which could have
383 * opened up a security hole. So, we implement this: when the user
384 * attempts to set its real uid, we just check to make sure
385 * that they will be able to seteuid() back to that id at some
386 * later time, but don't actually change the real uid.
387 * Logic taken from 4.4BSD.
15637ed4 388 */
67c9e20b
GW
389 if(uap->ruid != -1 && uap->ruid != pc->p_ruid
390 && uap->ruid != pc->p_svuid) {
391 return EPERM;
392 }
393
394 if(uap->euid == -1) {
395 return 0;
396 }
397 e_args.euid = uap->euid;
398 return seteuid(p, &e_args, retval);
15637ed4
RG
399}
400
3c7eb27c
DG
401struct osetregid_args {
402 int rgid;
403 int egid;
404};
405
15637ed4 406/* ARGSUSED */
4c45483e 407int
15637ed4
RG
408osetregid(p, uap, retval)
409 register struct proc *p;
3c7eb27c 410 struct osetregid_args *uap;
15637ed4
RG
411 int *retval;
412{
413 register struct pcred *pc = p->p_cred;
67c9e20b 414 struct setegid_args e_args;
15637ed4 415
15637ed4 416 /*
67c9e20b 417 * Same comments as for setreuid() apply here.
15637ed4 418 */
67c9e20b
GW
419 if(uap->rgid != -1
420 && uap->rgid != pc->p_rgid
421 && uap->rgid != pc->p_svgid) {
422 return EPERM;
423 }
424
425 if(uap->egid == -1) {
426 return 0;
427 }
428 e_args.egid = uap->egid;
429 return setegid(p, &e_args, retval);
15637ed4
RG
430}
431#endif
432
3c7eb27c
DG
433struct setgroups_args {
434 u_int gidsetsize;
435 int *gidset;
436};
437
15637ed4 438/* ARGSUSED */
4c45483e 439int
15637ed4
RG
440setgroups(p, uap, retval)
441 struct proc *p;
3c7eb27c 442 struct setgroups_args *uap;
15637ed4
RG
443 int *retval;
444{
445 register struct pcred *pc = p->p_cred;
446 register gid_t *gp;
447 register u_int ngrp;
448 register int *lp;
449 int error, groups[NGROUPS];
450
451 if (error = suser(pc->pc_ucred, &p->p_acflag))
452 return (error);
453 if ((ngrp = uap->gidsetsize) > NGROUPS)
454 return (EINVAL);
455 if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
456 ngrp * sizeof (groups[0])))
457 return (error);
458 pc->pc_ucred = crcopy(pc->pc_ucred);
459 pc->pc_ucred->cr_ngroups = ngrp;
460 /* convert from int's to gid_t's */
461 for (gp = pc->pc_ucred->cr_groups, lp = groups; ngrp--; )
462 *gp++ = *lp++;
463 return (0);
464}
465
466/*
467 * Check if gid is a member of the group set.
468 */
4c45483e 469int
15637ed4
RG
470groupmember(gid, cred)
471 gid_t gid;
472 register struct ucred *cred;
473{
474 register gid_t *gp;
475 gid_t *egp;
476
477 egp = &(cred->cr_groups[cred->cr_ngroups]);
478 for (gp = cred->cr_groups; gp < egp; gp++)
479 if (*gp == gid)
480 return (1);
481 return (0);
482}
483
484/*
485 * Test whether the specified credentials imply "super-user"
486 * privilege; if so, and we have accounting info, set the flag
487 * indicating use of super-powers.
488 * Returns 0 or error.
489 */
4c45483e 490int
15637ed4
RG
491suser(cred, acflag)
492 struct ucred *cred;
493 u_short *acflag;
494{
495 if (cred->cr_uid == 0) {
496 if (acflag)
497 *acflag |= ASU;
498 return (0);
499 }
500 return (EPERM);
501}
502
503/*
504 * Allocate a zeroed cred structure.
505 */
506struct ucred *
507crget()
508{
509 register struct ucred *cr;
510
511 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
512 bzero((caddr_t)cr, sizeof(*cr));
513 cr->cr_ref = 1;
514 return (cr);
515}
516
517/*
518 * Free a cred structure.
519 * Throws away space when ref count gets to 0.
520 */
4c45483e 521void
15637ed4
RG
522crfree(cr)
523 struct ucred *cr;
524{
4c45483e 525 int s = splimp(); /* ??? XXX FIXME */
15637ed4
RG
526
527 if (--cr->cr_ref != 0) {
528 (void) splx(s);
529 return;
530 }
531 FREE((caddr_t)cr, M_CRED);
532 (void) splx(s);
533}
534
535/*
536 * Copy cred structure to a new one and free the old one.
537 */
538struct ucred *
539crcopy(cr)
540 struct ucred *cr;
541{
542 struct ucred *newcr;
543
544 if (cr->cr_ref == 1)
545 return (cr);
546 newcr = crget();
547 *newcr = *cr;
548 crfree(cr);
549 newcr->cr_ref = 1;
550 return (newcr);
551}
552
553/*
554 * Dup cred struct to a new held one.
555 */
556struct ucred *
557crdup(cr)
558 struct ucred *cr;
559{
560 struct ucred *newcr;
561
562 newcr = crget();
563 *newcr = *cr;
564 newcr->cr_ref = 1;
565 return (newcr);
566}
567
568/*
569 * Get login name, if available.
570 */
3c7eb27c
DG
571
572struct getlogin_args {
573 char *namebuf;
574 u_int namelen;
575};
576
15637ed4 577/* ARGSUSED */
4c45483e 578int
15637ed4
RG
579getlogin(p, uap, retval)
580 struct proc *p;
3c7eb27c 581 struct getlogin_args *uap;
15637ed4
RG
582 int *retval;
583{
584
585 if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
586 uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
587 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
588 (caddr_t) uap->namebuf, uap->namelen));
589}
590
591/*
592 * Set login name.
593 */
3c7eb27c
DG
594
595struct setlogin_args {
596 char *namebuf;
597};
598
15637ed4 599/* ARGSUSED */
4c45483e 600int
15637ed4
RG
601setlogin(p, uap, retval)
602 struct proc *p;
3c7eb27c 603 struct setlogin_args *uap;
15637ed4
RG
604 int *retval;
605{
606 int error;
607
608 if (error = suser(p->p_ucred, &p->p_acflag))
609 return (error);
610 error = copyinstr((caddr_t) uap->namebuf,
611 (caddr_t) p->p_pgrp->pg_session->s_login,
612 sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
613 if (error == ENAMETOOLONG)
614 error = EINVAL;
615 return (error);
616}