386BSD 0.1 development
[unix-history] / usr / src / sys.386bsd / kern / kern_prot.c
CommitLineData
1d70dcb0
WJ
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
140getgroups(p, uap, retval)
141 struct proc *p;
142 register struct arg {
143 u_int gidsetsize;
144 int *gidset; /* XXX not yet POSIX */
145 } *uap;
146 int *retval;
147{
148 register struct pcred *pc = p->p_cred;
149 register gid_t *gp;
150 register int *lp;
151 register u_int ngrp;
152 int groups[NGROUPS];
153 int error;
154
155 if ((ngrp = uap->gidsetsize) == 0) {
156 *retval = pc->pc_ucred->cr_ngroups;
157 return (0);
158 }
159 if (ngrp < pc->pc_ucred->cr_ngroups)
160 return (EINVAL);
161 ngrp = pc->pc_ucred->cr_ngroups;
162 for (gp = pc->pc_ucred->cr_groups, lp = groups; lp < &groups[ngrp]; )
163 *lp++ = *gp++;
164 if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset,
165 ngrp * sizeof (groups[0])))
166 return (error);
167 *retval = ngrp;
168 return (0);
169}
170
171/* ARGSUSED */
172setsid(p, uap, retval)
173 register struct proc *p;
174 void *uap;
175 int *retval;
176{
177
178 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
179 return (EPERM);
180 } else {
181 enterpgrp(p, p->p_pid, 1);
182 *retval = p->p_pid;
183 return (0);
184 }
185}
186
187/*
188 * set process group (setpgid/old setpgrp)
189 *
190 * caller does setpgid(targpid, targpgid)
191 *
192 * pid must be caller or child of caller (ESRCH)
193 * if a child
194 * pid must be in same session (EPERM)
195 * pid can't have done an exec (EACCES)
196 * if pgid != pid
197 * there must exist some pid in same session having pgid (EPERM)
198 * pid must not be session leader (EPERM)
199 */
200/* ARGSUSED */
201setpgid(curp, uap, retval)
202 struct proc *curp;
203 register struct args {
204 int pid; /* target process id */
205 int pgid; /* target pgrp id */
206 } *uap;
207 int *retval;
208{
209 register struct proc *targp; /* target process */
210 register struct pgrp *pgrp; /* target pgrp */
211
212 if (uap->pid != 0 && uap->pid != curp->p_pid) {
213 if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
214 return (ESRCH);
215 if (targp->p_session != curp->p_session)
216 return (EPERM);
217 if (targp->p_flag&SEXEC)
218 return (EACCES);
219 } else
220 targp = curp;
221 if (SESS_LEADER(targp))
222 return (EPERM);
223 if (uap->pgid == 0)
224 uap->pgid = targp->p_pid;
225 else if (uap->pgid != targp->p_pid)
226 if ((pgrp = pgfind(uap->pgid)) == 0 ||
227 pgrp->pg_session != curp->p_session)
228 return (EPERM);
229 enterpgrp(targp, uap->pgid, 0);
230 return (0);
231}
232
233/* ARGSUSED */
234setuid(p, uap, retval)
235 struct proc *p;
236 struct args {
237 int uid;
238 } *uap;
239 int *retval;
240{
241 register struct pcred *pc = p->p_cred;
242 register uid_t uid;
243 int error;
244
245 uid = uap->uid;
246 if (uid != pc->p_ruid &&
247 (error = suser(pc->pc_ucred, &p->p_acflag)))
248 return (error);
249 /*
250 * Everything's okay, do it. Copy credentials so other references do
251 * not see our changes.
252 */
253 pc->pc_ucred = crcopy(pc->pc_ucred);
254 pc->pc_ucred->cr_uid = uid;
255 pc->p_ruid = uid;
256 pc->p_svuid = uid;
257 return (0);
258}
259
260/* ARGSUSED */
261seteuid(p, uap, retval)
262 struct proc *p;
263 struct args {
264 int euid;
265 } *uap;
266 int *retval;
267{
268 register struct pcred *pc = p->p_cred;
269 register uid_t euid;
270 int error;
271
272 euid = uap->euid;
273 if (euid != pc->p_ruid && euid != pc->p_svuid &&
274 (error = suser(pc->pc_ucred, &p->p_acflag)))
275 return (error);
276 /*
277 * Everything's okay, do it. Copy credentials so other references do
278 * not see our changes.
279 */
280 pc->pc_ucred = crcopy(pc->pc_ucred);
281 pc->pc_ucred->cr_uid = euid;
282 return (0);
283}
284
285/* ARGSUSED */
286setgid(p, uap, retval)
287 struct proc *p;
288 struct args {
289 int gid;
290 } *uap;
291 int *retval;
292{
293 register struct pcred *pc = p->p_cred;
294 register gid_t gid;
295 int error;
296
297 gid = uap->gid;
298 if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
299 return (error);
300 pc->pc_ucred = crcopy(pc->pc_ucred);
301 pc->pc_ucred->cr_groups[0] = gid;
302 pc->p_rgid = gid;
303 pc->p_svgid = gid; /* ??? */
304 return (0);
305}
306
307/* ARGSUSED */
308setegid(p, uap, retval)
309 struct proc *p;
310 struct args {
311 int egid;
312 } *uap;
313 int *retval;
314{
315 register struct pcred *pc = p->p_cred;
316 register gid_t egid;
317 int error;
318
319 egid = uap->egid;
320 if (egid != pc->p_rgid && egid != pc->p_svgid &&
321 (error = suser(pc->pc_ucred, &p->p_acflag)))
322 return (error);
323 pc->pc_ucred = crcopy(pc->pc_ucred);
324 pc->pc_ucred->cr_groups[0] = egid;
325 return (0);
326}
327
328#ifdef COMPAT_43
329/* ARGSUSED */
330osetreuid(p, uap, retval)
331 register struct proc *p;
332 struct args {
333 int ruid;
334 int euid;
335 } *uap;
336 int *retval;
337{
338 register struct pcred *pc = p->p_cred;
339 register uid_t ruid, euid;
340 int error;
341
342 if (uap->ruid == -1)
343 ruid = pc->p_ruid;
344 else
345 ruid = uap->ruid;
346 /*
347 * Allow setting real uid to previous effective, for swapping real and
348 * effective. This should be:
349 *
350 * if (ruid != pc->p_ruid &&
351 * (error = suser(pc->pc_ucred, &p->p_acflag)))
352 */
353 if (ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid /* XXX */ &&
354 (error = suser(pc->pc_ucred, &p->p_acflag)))
355 return (error);
356 if (uap->euid == -1)
357 euid = pc->pc_ucred->cr_uid;
358 else
359 euid = uap->euid;
360 if (euid != pc->pc_ucred->cr_uid && euid != pc->p_ruid &&
361 euid != pc->p_svuid && (error = suser(pc->pc_ucred, &p->p_acflag)))
362 return (error);
363 /*
364 * Everything's okay, do it. Copy credentials so other references do
365 * not see our changes.
366 */
367 pc->pc_ucred = crcopy(pc->pc_ucred);
368 pc->pc_ucred->cr_uid = euid;
369 pc->p_ruid = ruid;
370 return (0);
371}
372
373/* ARGSUSED */
374osetregid(p, uap, retval)
375 register struct proc *p;
376 struct args {
377 int rgid;
378 int egid;
379 } *uap;
380 int *retval;
381{
382 register struct pcred *pc = p->p_cred;
383 register gid_t rgid, egid;
384 int error;
385
386 if (uap->rgid == -1)
387 rgid = pc->p_rgid;
388 else
389 rgid = uap->rgid;
390 /*
391 * Allow setting real gid to previous effective, for swapping real and
392 * effective. This didn't really work correctly in 4.[23], but is
393 * preserved so old stuff doesn't fail. This should be:
394 *
395 * if (rgid != pc->p_rgid &&
396 * (error = suser(pc->pc_ucred, &p->p_acflag)))
397 */
398 if (rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_groups[0] /* XXX */ &&
399 (error = suser(pc->pc_ucred, &p->p_acflag)))
400 return (error);
401 if (uap->egid == -1)
402 egid = pc->pc_ucred->cr_groups[0];
403 else
404 egid = uap->egid;
405 if (egid != pc->pc_ucred->cr_groups[0] && egid != pc->p_rgid &&
406 egid != pc->p_svgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
407 return (error);
408 pc->pc_ucred = crcopy(pc->pc_ucred);
409 pc->pc_ucred->cr_groups[0] = egid;
410 pc->p_rgid = rgid;
411 return (0);
412}
413#endif
414
415/* ARGSUSED */
416setgroups(p, uap, retval)
417 struct proc *p;
418 struct args {
419 u_int gidsetsize;
420 int *gidset;
421 } *uap;
422 int *retval;
423{
424 register struct pcred *pc = p->p_cred;
425 register gid_t *gp;
426 register u_int ngrp;
427 register int *lp;
428 int error, groups[NGROUPS];
429
430 if (error = suser(pc->pc_ucred, &p->p_acflag))
431 return (error);
432 if ((ngrp = uap->gidsetsize) > NGROUPS)
433 return (EINVAL);
434 if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
435 ngrp * sizeof (groups[0])))
436 return (error);
437 pc->pc_ucred = crcopy(pc->pc_ucred);
438 pc->pc_ucred->cr_ngroups = ngrp;
439 /* convert from int's to gid_t's */
440 for (gp = pc->pc_ucred->cr_groups, lp = groups; ngrp--; )
441 *gp++ = *lp++;
442 return (0);
443}
444
445/*
446 * Check if gid is a member of the group set.
447 */
448groupmember(gid, cred)
449 gid_t gid;
450 register struct ucred *cred;
451{
452 register gid_t *gp;
453 gid_t *egp;
454
455 egp = &(cred->cr_groups[cred->cr_ngroups]);
456 for (gp = cred->cr_groups; gp < egp; gp++)
457 if (*gp == gid)
458 return (1);
459 return (0);
460}
461
462/*
463 * Test whether the specified credentials imply "super-user"
464 * privilege; if so, and we have accounting info, set the flag
465 * indicating use of super-powers.
466 * Returns 0 or error.
467 */
468suser(cred, acflag)
469 struct ucred *cred;
470 u_short *acflag;
471{
472 if (cred->cr_uid == 0) {
473 if (acflag)
474 *acflag |= ASU;
475 return (0);
476 }
477 return (EPERM);
478}
479
480/*
481 * Allocate a zeroed cred structure.
482 */
483struct ucred *
484crget()
485{
486 register struct ucred *cr;
487
488 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
489 bzero((caddr_t)cr, sizeof(*cr));
490 cr->cr_ref = 1;
491 return (cr);
492}
493
494/*
495 * Free a cred structure.
496 * Throws away space when ref count gets to 0.
497 */
498crfree(cr)
499 struct ucred *cr;
500{
501 int s = splimp(); /* ??? */
502
503 if (--cr->cr_ref != 0) {
504 (void) splx(s);
505 return;
506 }
507 FREE((caddr_t)cr, M_CRED);
508 (void) splx(s);
509}
510
511/*
512 * Copy cred structure to a new one and free the old one.
513 */
514struct ucred *
515crcopy(cr)
516 struct ucred *cr;
517{
518 struct ucred *newcr;
519
520 if (cr->cr_ref == 1)
521 return (cr);
522 newcr = crget();
523 *newcr = *cr;
524 crfree(cr);
525 newcr->cr_ref = 1;
526 return (newcr);
527}
528
529/*
530 * Dup cred struct to a new held one.
531 */
532struct ucred *
533crdup(cr)
534 struct ucred *cr;
535{
536 struct ucred *newcr;
537
538 newcr = crget();
539 *newcr = *cr;
540 newcr->cr_ref = 1;
541 return (newcr);
542}
543
544/*
545 * Get login name, if available.
546 */
547/* ARGSUSED */
548getlogin(p, uap, retval)
549 struct proc *p;
550 struct args {
551 char *namebuf;
552 u_int namelen;
553 } *uap;
554 int *retval;
555{
556
557 if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
558 uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
559 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
560 (caddr_t) uap->namebuf, uap->namelen));
561}
562
563/*
564 * Set login name.
565 */
566/* ARGSUSED */
567setlogin(p, uap, retval)
568 struct proc *p;
569 struct args {
570 char *namebuf;
571 } *uap;
572 int *retval;
573{
574 int error;
575
576 if (error = suser(p->p_ucred, &p->p_acflag))
577 return (error);
578 error = copyinstr((caddr_t) uap->namebuf,
579 (caddr_t) p->p_pgrp->pg_session->s_login,
580 sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
581 if (error == ENAMETOOLONG)
582 error = EINVAL;
583 return (error);
584}