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