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