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