Use M_IOBUF instead of M_TEMP for malloc'd buffers.
[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
fde1aeb2 34 * $Id: kern_prot.c,v 1.4 1993/11/25 01:33:04 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;
276 return (0);
277}
278
3c7eb27c
DG
279struct seteuid_args {
280 int euid;
281};
282
15637ed4 283/* ARGSUSED */
4c45483e 284int
15637ed4
RG
285seteuid(p, uap, retval)
286 struct proc *p;
3c7eb27c 287 struct seteuid_args *uap;
15637ed4
RG
288 int *retval;
289{
290 register struct pcred *pc = p->p_cred;
291 register uid_t euid;
292 int error;
293
294 euid = uap->euid;
295 if (euid != pc->p_ruid && euid != pc->p_svuid &&
296 (error = suser(pc->pc_ucred, &p->p_acflag)))
297 return (error);
298 /*
299 * Everything's okay, do it. Copy credentials so other references do
300 * not see our changes.
301 */
302 pc->pc_ucred = crcopy(pc->pc_ucred);
303 pc->pc_ucred->cr_uid = euid;
304 return (0);
305}
306
3c7eb27c
DG
307struct setgid_args {
308 int gid;
309};
310
15637ed4 311/* ARGSUSED */
4c45483e 312int
15637ed4
RG
313setgid(p, uap, retval)
314 struct proc *p;
3c7eb27c 315 struct setgid_args *uap;
15637ed4
RG
316 int *retval;
317{
318 register struct pcred *pc = p->p_cred;
319 register gid_t gid;
320 int error;
321
322 gid = uap->gid;
323 if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
324 return (error);
325 pc->pc_ucred = crcopy(pc->pc_ucred);
326 pc->pc_ucred->cr_groups[0] = gid;
327 pc->p_rgid = gid;
328 pc->p_svgid = gid; /* ??? */
329 return (0);
330}
331
3c7eb27c
DG
332struct setegid_args {
333 int egid;
334};
335
15637ed4 336/* ARGSUSED */
4c45483e 337int
15637ed4
RG
338setegid(p, uap, retval)
339 struct proc *p;
3c7eb27c 340 struct setegid_args *uap;
15637ed4
RG
341 int *retval;
342{
343 register struct pcred *pc = p->p_cred;
344 register gid_t egid;
345 int error;
346
347 egid = uap->egid;
348 if (egid != pc->p_rgid && egid != pc->p_svgid &&
349 (error = suser(pc->pc_ucred, &p->p_acflag)))
350 return (error);
351 pc->pc_ucred = crcopy(pc->pc_ucred);
352 pc->pc_ucred->cr_groups[0] = egid;
353 return (0);
354}
355
356#ifdef COMPAT_43
3c7eb27c
DG
357
358struct osetreuid_args {
359 int ruid;
360 int euid;
361};
362
15637ed4 363/* ARGSUSED */
4c45483e 364int
15637ed4
RG
365osetreuid(p, uap, retval)
366 register struct proc *p;
3c7eb27c 367 struct osetreuid_args *uap;
15637ed4
RG
368 int *retval;
369{
370 register struct pcred *pc = p->p_cred;
371 register uid_t ruid, euid;
372 int error;
373
374 if (uap->ruid == -1)
375 ruid = pc->p_ruid;
376 else
377 ruid = uap->ruid;
378 /*
379 * Allow setting real uid to previous effective, for swapping real and
380 * effective. This should be:
381 *
382 * if (ruid != pc->p_ruid &&
383 * (error = suser(pc->pc_ucred, &p->p_acflag)))
384 */
385 if (ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid /* XXX */ &&
386 (error = suser(pc->pc_ucred, &p->p_acflag)))
387 return (error);
388 if (uap->euid == -1)
389 euid = pc->pc_ucred->cr_uid;
390 else
391 euid = uap->euid;
392 if (euid != pc->pc_ucred->cr_uid && euid != pc->p_ruid &&
393 euid != pc->p_svuid && (error = suser(pc->pc_ucred, &p->p_acflag)))
394 return (error);
395 /*
396 * Everything's okay, do it. Copy credentials so other references do
397 * not see our changes.
398 */
399 pc->pc_ucred = crcopy(pc->pc_ucred);
400 pc->pc_ucred->cr_uid = euid;
401 pc->p_ruid = ruid;
402 return (0);
403}
404
3c7eb27c
DG
405struct osetregid_args {
406 int rgid;
407 int egid;
408};
409
15637ed4 410/* ARGSUSED */
4c45483e 411int
15637ed4
RG
412osetregid(p, uap, retval)
413 register struct proc *p;
3c7eb27c 414 struct osetregid_args *uap;
15637ed4
RG
415 int *retval;
416{
417 register struct pcred *pc = p->p_cred;
418 register gid_t rgid, egid;
419 int error;
420
421 if (uap->rgid == -1)
422 rgid = pc->p_rgid;
423 else
424 rgid = uap->rgid;
425 /*
426 * Allow setting real gid to previous effective, for swapping real and
427 * effective. This didn't really work correctly in 4.[23], but is
428 * preserved so old stuff doesn't fail. This should be:
429 *
430 * if (rgid != pc->p_rgid &&
431 * (error = suser(pc->pc_ucred, &p->p_acflag)))
432 */
433 if (rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_groups[0] /* XXX */ &&
434 (error = suser(pc->pc_ucred, &p->p_acflag)))
435 return (error);
436 if (uap->egid == -1)
437 egid = pc->pc_ucred->cr_groups[0];
438 else
439 egid = uap->egid;
440 if (egid != pc->pc_ucred->cr_groups[0] && egid != pc->p_rgid &&
441 egid != pc->p_svgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
442 return (error);
443 pc->pc_ucred = crcopy(pc->pc_ucred);
444 pc->pc_ucred->cr_groups[0] = egid;
445 pc->p_rgid = rgid;
446 return (0);
447}
448#endif
449
3c7eb27c
DG
450struct setgroups_args {
451 u_int gidsetsize;
452 int *gidset;
453};
454
15637ed4 455/* ARGSUSED */
4c45483e 456int
15637ed4
RG
457setgroups(p, uap, retval)
458 struct proc *p;
3c7eb27c 459 struct setgroups_args *uap;
15637ed4
RG
460 int *retval;
461{
462 register struct pcred *pc = p->p_cred;
463 register gid_t *gp;
464 register u_int ngrp;
465 register int *lp;
466 int error, groups[NGROUPS];
467
468 if (error = suser(pc->pc_ucred, &p->p_acflag))
469 return (error);
470 if ((ngrp = uap->gidsetsize) > NGROUPS)
471 return (EINVAL);
472 if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
473 ngrp * sizeof (groups[0])))
474 return (error);
475 pc->pc_ucred = crcopy(pc->pc_ucred);
476 pc->pc_ucred->cr_ngroups = ngrp;
477 /* convert from int's to gid_t's */
478 for (gp = pc->pc_ucred->cr_groups, lp = groups; ngrp--; )
479 *gp++ = *lp++;
480 return (0);
481}
482
483/*
484 * Check if gid is a member of the group set.
485 */
4c45483e 486int
15637ed4
RG
487groupmember(gid, cred)
488 gid_t gid;
489 register struct ucred *cred;
490{
491 register gid_t *gp;
492 gid_t *egp;
493
494 egp = &(cred->cr_groups[cred->cr_ngroups]);
495 for (gp = cred->cr_groups; gp < egp; gp++)
496 if (*gp == gid)
497 return (1);
498 return (0);
499}
500
501/*
502 * Test whether the specified credentials imply "super-user"
503 * privilege; if so, and we have accounting info, set the flag
504 * indicating use of super-powers.
505 * Returns 0 or error.
506 */
4c45483e 507int
15637ed4
RG
508suser(cred, acflag)
509 struct ucred *cred;
510 u_short *acflag;
511{
512 if (cred->cr_uid == 0) {
513 if (acflag)
514 *acflag |= ASU;
515 return (0);
516 }
517 return (EPERM);
518}
519
520/*
521 * Allocate a zeroed cred structure.
522 */
523struct ucred *
524crget()
525{
526 register struct ucred *cr;
527
528 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
529 bzero((caddr_t)cr, sizeof(*cr));
530 cr->cr_ref = 1;
531 return (cr);
532}
533
534/*
535 * Free a cred structure.
536 * Throws away space when ref count gets to 0.
537 */
4c45483e 538void
15637ed4
RG
539crfree(cr)
540 struct ucred *cr;
541{
4c45483e 542 int s = splimp(); /* ??? XXX FIXME */
15637ed4
RG
543
544 if (--cr->cr_ref != 0) {
545 (void) splx(s);
546 return;
547 }
548 FREE((caddr_t)cr, M_CRED);
549 (void) splx(s);
550}
551
552/*
553 * Copy cred structure to a new one and free the old one.
554 */
555struct ucred *
556crcopy(cr)
557 struct ucred *cr;
558{
559 struct ucred *newcr;
560
561 if (cr->cr_ref == 1)
562 return (cr);
563 newcr = crget();
564 *newcr = *cr;
565 crfree(cr);
566 newcr->cr_ref = 1;
567 return (newcr);
568}
569
570/*
571 * Dup cred struct to a new held one.
572 */
573struct ucred *
574crdup(cr)
575 struct ucred *cr;
576{
577 struct ucred *newcr;
578
579 newcr = crget();
580 *newcr = *cr;
581 newcr->cr_ref = 1;
582 return (newcr);
583}
584
585/*
586 * Get login name, if available.
587 */
3c7eb27c
DG
588
589struct getlogin_args {
590 char *namebuf;
591 u_int namelen;
592};
593
15637ed4 594/* ARGSUSED */
4c45483e 595int
15637ed4
RG
596getlogin(p, uap, retval)
597 struct proc *p;
3c7eb27c 598 struct getlogin_args *uap;
15637ed4
RG
599 int *retval;
600{
601
602 if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
603 uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
604 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
605 (caddr_t) uap->namebuf, uap->namelen));
606}
607
608/*
609 * Set login name.
610 */
3c7eb27c
DG
611
612struct setlogin_args {
613 char *namebuf;
614};
615
15637ed4 616/* ARGSUSED */
4c45483e 617int
15637ed4
RG
618setlogin(p, uap, retval)
619 struct proc *p;
3c7eb27c 620 struct setlogin_args *uap;
15637ed4
RG
621 int *retval;
622{
623 int error;
624
625 if (error = suser(p->p_ucred, &p->p_acflag))
626 return (error);
627 error = copyinstr((caddr_t) uap->namebuf,
628 (caddr_t) p->p_pgrp->pg_session->s_login,
629 sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
630 if (error == ENAMETOOLONG)
631 error = EINVAL;
632 return (error);
633}