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