more-or-less working with new proc & user structs
[unix-history] / usr / src / sys / kern / kern_prot.c
CommitLineData
da7c5cc6 1/*
8429d022
MK
2 * Copyright (c) 1982, 1986, 1989, 1990, 1991 Regents of the University
3 * of California. All rights reserved.
da7c5cc6 4 *
dbf0c423 5 * %sccs.include.redist.c%
88a39492 6 *
8429d022 7 * @(#)kern_prot.c 7.19 (Berkeley) %G%
da7c5cc6 8 */
a05af100
BJ
9
10/*
4147b3f6 11 * System calls related to processes and protection
a05af100
BJ
12 */
13
94368568 14#include "param.h"
88a39492 15#include "acct.h"
94368568 16#include "systm.h"
8429d022 17#include "ucred.h"
94368568
JB
18#include "proc.h"
19#include "timeb.h"
20#include "times.h"
88a39492 21#include "malloc.h"
a05af100 22
d5dc47bf
MK
23/* ARGSUSED */
24getpid(p, uap, retval)
25 struct proc *p;
26 void *uap;
27 int *retval;
4147b3f6
BJ
28{
29
d5dc47bf
MK
30 *retval = p->p_pid;
31#ifdef COMPAT_43
8429d022 32 retval[1] = p->p_pptr->p_pid;
d5dc47bf 33#endif
d9c2f47f 34 return (0);
4147b3f6
BJ
35}
36
d5dc47bf
MK
37/* ARGSUSED */
38getppid(p, uap, retval)
39 struct proc *p;
40 void *uap;
41 int *retval;
4147b3f6 42{
d5dc47bf 43
8429d022 44 *retval = p->p_pptr->p_pid;
d9c2f47f 45 return (0);
d5dc47bf
MK
46}
47
8429d022 48/* Get process group ID; note that POSIX getpgrp takes no parameter */
d5dc47bf
MK
49getpgrp(p, uap, retval)
50 struct proc *p;
8429d022 51 void *uap;
d5dc47bf
MK
52 int *retval;
53{
4147b3f6 54
d5dc47bf 55 *retval = p->p_pgrp->pg_id;
d9c2f47f 56 return (0);
4147b3f6
BJ
57}
58
d5dc47bf
MK
59/* ARGSUSED */
60getuid(p, uap, retval)
61 struct proc *p;
62 void *uap;
63 int *retval;
a05af100
BJ
64{
65
8429d022 66 *retval = p->p_cred->p_ruid;
d5dc47bf 67#ifdef COMPAT_43
8429d022 68 retval[1] = p->p_ucred->cr_uid;
d5dc47bf 69#endif
d9c2f47f 70 return (0);
a05af100
BJ
71}
72
d5dc47bf
MK
73/* ARGSUSED */
74geteuid(p, uap, retval)
75 struct proc *p;
76 void *uap;
77 int *retval;
4147b3f6
BJ
78{
79
8429d022 80 *retval = p->p_ucred->cr_uid;
d9c2f47f 81 return (0);
4147b3f6
BJ
82}
83
d5dc47bf
MK
84/* ARGSUSED */
85getgid(p, uap, retval)
86 struct proc *p;
87 void *uap;
88 int *retval;
89{
90
8429d022 91 *retval = p->p_cred->p_rgid;
d5dc47bf 92#ifdef COMPAT_43
8429d022 93 retval[1] = p->p_ucred->cr_groups[0];
d5dc47bf 94#endif
d9c2f47f 95 return (0);
d5dc47bf
MK
96}
97
98/*
0712db82
KB
99 * Get effective group ID. The "egid" is groups[0], and could be obtained
100 * via getgroups. This syscall exists because it is somewhat painful to do
101 * correctly in a library function.
d5dc47bf
MK
102 */
103/* ARGSUSED */
104getegid(p, uap, retval)
105 struct proc *p;
106 void *uap;
107 int *retval;
4147b3f6 108{
8429d022
MK
109
110 *retval = p->p_ucred->cr_groups[0];
d9c2f47f 111 return (0);
d5dc47bf
MK
112}
113
114getgroups(p, uap, retval)
115 struct proc *p;
116 register struct arg {
b32450f4 117 u_int gidsetsize;
d5dc47bf
MK
118 int *gidset; /* XXX not yet POSIX */
119 } *uap;
120 int *retval;
121{
8429d022 122 register struct pcred *pc = p->p_cred;
38b6104c
MK
123 register gid_t *gp;
124 register int *lp;
fca91c15 125 register u_int ngrp;
38b6104c 126 int groups[NGROUPS];
d5dc47bf 127 int error;
4147b3f6 128
fca91c15 129 if ((ngrp = uap->gidsetsize) == 0) {
8429d022 130 *retval = pc->pc_ucred->cr_ngroups;
d9c2f47f 131 return (0);
197da11b 132 }
8429d022 133 if (ngrp < pc->pc_ucred->cr_ngroups)
d9c2f47f 134 return (EINVAL);
8429d022
MK
135 ngrp = pc->pc_ucred->cr_ngroups;
136 for (gp = pc->pc_ucred->cr_groups, lp = groups; lp < &groups[ngrp]; )
38b6104c 137 *lp++ = *gp++;
d5dc47bf 138 if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset,
fca91c15 139 ngrp * sizeof (groups[0])))
d9c2f47f 140 return (error);
fca91c15 141 *retval = ngrp;
d9c2f47f 142 return (0);
4147b3f6
BJ
143}
144
d5dc47bf
MK
145/* ARGSUSED */
146setsid(p, uap, retval)
8429d022 147 register struct proc *p;
d5dc47bf
MK
148 void *uap;
149 int *retval;
8fe87cbb 150{
8fe87cbb 151
d5dc47bf 152 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
d9c2f47f 153 return (EPERM);
d5dc47bf 154 } else {
8429d022 155 enterpgrp(p, p->p_pid, 1);
d5dc47bf 156 *retval = p->p_pid;
d9c2f47f 157 return (0);
8fe87cbb 158 }
8fe87cbb
MT
159}
160
161/*
8429d022 162 * set process group (setpgid/old setpgrp)
8fe87cbb 163 *
8429d022 164 * caller does setpgid(pid, pgid)
164c0f54
MK
165 *
166 * pid must be caller or child of caller (ESRCH)
167 * if a child
168 * pid must be in same session (EPERM)
169 * pid can't have done an exec (EACCES)
170 * if pgid != pid
171 * there must exist some pid in same session having pgid (EPERM)
172 * pid must not be session leader (EPERM)
8fe87cbb 173 */
d5dc47bf 174/* ARGSUSED */
8429d022 175setpgid(cp, uap, retval)
d5dc47bf
MK
176 struct proc *cp;
177 register struct args {
4147b3f6 178 int pid;
8fe87cbb 179 int pgid;
d5dc47bf
MK
180 } *uap;
181 int *retval;
182{
8fe87cbb
MT
183 register struct proc *p;
184 register struct pgrp *pgrp;
4147b3f6 185
d5dc47bf
MK
186 if (uap->pid != 0) {
187 if ((p = pfind(uap->pid)) == 0 || !inferior(p))
d9c2f47f 188 return (ESRCH);
d5dc47bf 189 if (p->p_session != cp->p_session)
d9c2f47f 190 return (EPERM);
d5dc47bf 191 if (p->p_flag&SEXEC)
d9c2f47f 192 return (EACCES);
d5dc47bf
MK
193 } else
194 p = cp;
195 if (SESS_LEADER(p))
d9c2f47f 196 return (EPERM);
8fe87cbb
MT
197 if (uap->pgid == 0)
198 uap->pgid = p->p_pid;
0712db82
KB
199 else if (uap->pgid != p->p_pid)
200 if ((pgrp = pgfind(uap->pgid)) == 0 ||
201 pgrp->pg_mem == NULL ||
202 pgrp->pg_session != cp->p_session)
203 return (EPERM);
8429d022 204 enterpgrp(p, uap->pgid, 0);
d9c2f47f 205 return (0);
4147b3f6
BJ
206}
207
d5dc47bf
MK
208/* ARGSUSED */
209setuid(p, uap, retval)
8429d022 210 struct proc *p;
d5dc47bf
MK
211 struct args {
212 int uid;
213 } *uap;
214 int *retval;
4f083fd7 215{
8429d022 216 register struct pcred *pc = p->p_cred;
d5dc47bf
MK
217 register uid_t uid;
218 int error;
219
220 uid = uap->uid;
8429d022
MK
221 if (uid != pc->p_ruid &&
222 (error = suser(pc->pc_ucred, &p->p_acflag)))
d9c2f47f 223 return (error);
d5dc47bf 224 /*
0712db82
KB
225 * Everything's okay, do it. Copy credentials so other references do
226 * not see our changes.
d5dc47bf 227 */
8429d022
MK
228 pc->pc_ucred = crcopy(pc->pc_ucred);
229 pc->pc_ucred->cr_uid = uid;
230 pc->p_ruid = uid;
231 pc->p_svuid = uid;
d9c2f47f 232 return (0);
d5dc47bf
MK
233}
234
235/* ARGSUSED */
236seteuid(p, uap, retval)
8429d022 237 struct proc *p;
d5dc47bf 238 struct args {
4f083fd7
SL
239 int euid;
240 } *uap;
d5dc47bf
MK
241 int *retval;
242{
8429d022 243 register struct pcred *pc = p->p_cred;
d5dc47bf
MK
244 register uid_t euid;
245 int error;
4f083fd7 246
4f083fd7 247 euid = uap->euid;
8429d022
MK
248 if (euid != pc->p_ruid && euid != pc->p_svuid &&
249 (error = suser(pc->pc_ucred, &p->p_acflag)))
d9c2f47f 250 return (error);
4f083fd7 251 /*
0712db82
KB
252 * Everything's okay, do it. Copy credentials so other references do
253 * not see our changes.
4f083fd7 254 */
8429d022
MK
255 pc->pc_ucred = crcopy(pc->pc_ucred);
256 pc->pc_ucred->cr_uid = euid;
d9c2f47f 257 return (0);
4f083fd7
SL
258}
259
d5dc47bf
MK
260/* ARGSUSED */
261setgid(p, uap, retval)
262 struct proc *p;
263 struct args {
264 int gid;
265 } *uap;
266 int *retval;
4f083fd7 267{
8429d022 268 register struct pcred *pc = p->p_cred;
d5dc47bf
MK
269 register gid_t gid;
270 int error;
271
272 gid = uap->gid;
8429d022 273 if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
d9c2f47f 274 return (error);
8429d022
MK
275 pc->pc_ucred = crcopy(pc->pc_ucred);
276 pc->pc_ucred->cr_groups[0] = gid;
277 pc->p_rgid = gid;
278 pc->p_svgid = gid; /* ??? */
d9c2f47f 279 return (0);
d5dc47bf
MK
280}
281
282/* ARGSUSED */
283setegid(p, uap, retval)
284 struct proc *p;
285 struct args {
4f083fd7
SL
286 int egid;
287 } *uap;
d5dc47bf
MK
288 int *retval;
289{
8429d022 290 register struct pcred *pc = p->p_cred;
d5dc47bf
MK
291 register gid_t egid;
292 int error;
4f083fd7 293
4f083fd7 294 egid = uap->egid;
8429d022
MK
295 if (egid != pc->p_rgid && egid != pc->p_svgid &&
296 (error = suser(pc->pc_ucred, &p->p_acflag)))
d9c2f47f 297 return (error);
8429d022
MK
298 pc->pc_ucred = crcopy(pc->pc_ucred);
299 pc->pc_ucred->cr_groups[0] = egid;
d9c2f47f 300 return (0);
d5dc47bf
MK
301}
302
303#ifdef COMPAT_43
304/* ARGSUSED */
305osetreuid(p, uap, retval)
306 register struct proc *p;
307 struct args {
308 int ruid;
309 int euid;
310 } *uap;
311 int *retval;
312{
8429d022 313 register struct pcred *pc = p->p_cred;
d5dc47bf
MK
314 register uid_t ruid, euid;
315 int error;
316
317 if (uap->ruid == -1)
8429d022
MK
318 if (ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid /* XXX */ &&
319 (error = suser(pc->pc_ucred, &p->p_acflag)))
d9c2f47f 320 return (error);
d5dc47bf 321 if (uap->euid == -1)
8429d022
MK
322 if (euid != pc->pc_ucred->cr_uid && euid != pc->p_ruid &&
323 euid != pc->p_svuid && (error = suser(pc->pc_ucred, &p->p_acflag)))
d9c2f47f 324 return (error);
d5dc47bf 325 /*
0712db82
KB
326 * Everything's okay, do it. Copy credentials so other references do
327 * not see our changes.
d5dc47bf 328 */
8429d022
MK
329 pc->pc_ucred = crcopy(pc->pc_ucred);
330 pc->pc_ucred->cr_uid = euid;
331 pc->p_ruid = ruid;
d9c2f47f 332 return (0);
4f083fd7 333}
a05af100 334
d5dc47bf
MK
335/* ARGSUSED */
336osetregid(p, uap, retval)
8429d022 337 register struct proc *p;
d5dc47bf
MK
338 struct args {
339 int rgid;
340 int egid;
341 } *uap;
342 int *retval;
4147b3f6 343{
8429d022 344 register struct pcred *pc = p->p_cred;
d5dc47bf
MK
345 register gid_t rgid, egid;
346 int error;
347
348 if (uap->rgid == -1)
8429d022
MK
349 if (rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_groups[0] /* XXX */ &&
350 (error = suser(pc->pc_ucred, &p->p_acflag)))
d9c2f47f 351 return (error);
d5dc47bf 352 if (uap->egid == -1)
8429d022
MK
353 if (egid != pc->pc_ucred->cr_groups[0] && egid != pc->p_rgid &&
354 egid != pc->p_svgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
d9c2f47f 355 return (error);
8429d022
MK
356 pc->pc_ucred = crcopy(pc->pc_ucred);
357 pc->pc_ucred->cr_groups[0] = egid;
358 pc->p_rgid = rgid;
d9c2f47f 359 return (0);
d5dc47bf
MK
360}
361#endif
362
363/* ARGSUSED */
364setgroups(p, uap, retval)
365 struct proc *p;
366 struct args {
b32450f4 367 u_int gidsetsize;
4147b3f6 368 int *gidset;
d5dc47bf
MK
369 } *uap;
370 int *retval;
371{
8429d022 372 register struct pcred *pc = p->p_cred;
38b6104c 373 register gid_t *gp;
fca91c15 374 register u_int ngrp;
38b6104c 375 register int *lp;
446a921a 376 int error, groups[NGROUPS];
4147b3f6 377
8429d022 378 if (error = suser(pc->pc_ucred, &p->p_acflag))
d9c2f47f 379 return (error);
fca91c15 380 if ((ngrp = uap->gidsetsize) > NGROUPS)
d9c2f47f 381 return (EINVAL);
446a921a 382 if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
fca91c15 383 ngrp * sizeof (groups[0])))
d9c2f47f 384 return (error);
8429d022
MK
385 pc->pc_ucred = crcopy(pc->pc_ucred);
386 pc->pc_ucred->cr_ngroups = ngrp;
446a921a 387 /* convert from int's to gid_t's */
8429d022 388 for (gp = pc->pc_ucred->cr_groups, lp = groups; ngrp--; )
fca91c15 389 *gp++ = *lp++;
d9c2f47f 390 return (0);
4147b3f6
BJ
391}
392
f926daf9 393/*
88a39492 394 * Check if gid is a member of the group set.
f926daf9 395 */
88a39492 396groupmember(gid, cred)
90731a34 397 gid_t gid;
88a39492 398 register struct ucred *cred;
197da11b 399{
38b6104c 400 register gid_t *gp;
88a39492 401 gid_t *egp;
197da11b 402
88a39492
KM
403 egp = &(cred->cr_groups[cred->cr_ngroups]);
404 for (gp = cred->cr_groups; gp < egp; gp++)
197da11b 405 if (*gp == gid)
88a39492
KM
406 return (1);
407 return (0);
197da11b
BJ
408}
409
f926daf9 410/*
f242743a
MK
411 * Test whether the specified credentials imply "super-user"
412 * privilege; if so, and we have accounting info, set the flag
413 * indicating use of super-powers.
414 * Returns 0 or error.
f926daf9 415 */
88a39492
KM
416suser(cred, acflag)
417 struct ucred *cred;
418 short *acflag;
197da11b 419{
88a39492
KM
420 if (cred->cr_uid == 0) {
421 if (acflag)
422 *acflag |= ASU;
423 return (0);
38b6104c 424 }
88a39492 425 return (EPERM);
197da11b 426}
f926daf9
SL
427
428/*
88a39492 429 * Allocate a zeroed cred structure.
f926daf9 430 */
88a39492
KM
431struct ucred *
432crget()
f926daf9 433{
88a39492 434 register struct ucred *cr;
f926daf9 435
88a39492
KM
436 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
437 bzero((caddr_t)cr, sizeof(*cr));
438 cr->cr_ref = 1;
d5dc47bf 439 return (cr);
88a39492
KM
440}
441
442/*
443 * Free a cred structure.
444 * Throws away space when ref count gets to 0.
445 */
446crfree(cr)
447 struct ucred *cr;
448{
8429d022 449 int s = splimp(); /* ??? */
88a39492
KM
450
451 if (--cr->cr_ref != 0) {
452 (void) splx(s);
453 return;
454 }
455 FREE((caddr_t)cr, M_CRED);
456 (void) splx(s);
457}
458
459/*
460 * Copy cred structure to a new one and free the old one.
461 */
462struct ucred *
463crcopy(cr)
464 struct ucred *cr;
465{
466 struct ucred *newcr;
467
0712db82
KB
468 if (cr->cr_ref == 1)
469 return (cr);
88a39492
KM
470 newcr = crget();
471 *newcr = *cr;
472 crfree(cr);
473 newcr->cr_ref = 1;
d5dc47bf 474 return (newcr);
88a39492
KM
475}
476
477/*
478 * Dup cred struct to a new held one.
479 */
480struct ucred *
481crdup(cr)
482 struct ucred *cr;
483{
484 struct ucred *newcr;
485
486 newcr = crget();
487 *newcr = *cr;
488 newcr->cr_ref = 1;
d5dc47bf 489 return (newcr);
f926daf9 490}
5b6ee178
KF
491
492/*
164c0f54 493 * Get login name, if available.
5b6ee178 494 */
d5dc47bf
MK
495/* ARGSUSED */
496getlogin(p, uap, retval)
497 struct proc *p;
498 struct args {
5b6ee178
KF
499 char *namebuf;
500 u_int namelen;
d5dc47bf
MK
501 } *uap;
502 int *retval;
503{
5b6ee178 504
8429d022
MK
505 if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
506 uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
507 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
508 (caddr_t) uap->namebuf, uap->namelen));
5b6ee178
KF
509}
510
511/*
164c0f54 512 * Set login name.
5b6ee178 513 */
d5dc47bf
MK
514/* ARGSUSED */
515setlogin(p, uap, retval)
516 struct proc *p;
517 struct args {
5b6ee178 518 char *namebuf;
d5dc47bf
MK
519 } *uap;
520 int *retval;
521{
164c0f54 522 int error;
5b6ee178 523
8429d022 524 if (error = suser(p->p_ucred, &p->p_acflag))
d9c2f47f 525 return (error);
8429d022
MK
526 error = copyinstr((caddr_t) uap->namebuf,
527 (caddr_t) p->p_pgrp->pg_session->s_login,
528 sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
529 if (error == ENAMETOOLONG)
164c0f54 530 error = EINVAL;
d9c2f47f 531 return (error);
5b6ee178 532}