xref: /netbsd/sys/kern/kern_prot.c (revision c4a72b64)
1 /*	$NetBSD: kern_prot.c,v 1.69 2002/08/25 21:30:40 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  * (c) UNIX System Laboratories, Inc.
7  * All or some portions of this file are derived from material licensed
8  * to the University of California by American Telephone and Telegraph
9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10  * the permission of UNIX System Laboratories, Inc.
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  *
40  *	@(#)kern_prot.c	8.9 (Berkeley) 2/14/95
41  */
42 
43 /*
44  * System calls related to processes and protection
45  */
46 
47 #include <sys/cdefs.h>
48 __KERNEL_RCSID(0, "$NetBSD: kern_prot.c,v 1.69 2002/08/25 21:30:40 thorpej Exp $");
49 
50 #include "opt_compat_43.h"
51 
52 #include <sys/param.h>
53 #include <sys/acct.h>
54 #include <sys/systm.h>
55 #include <sys/ucred.h>
56 #include <sys/proc.h>
57 #include <sys/timeb.h>
58 #include <sys/times.h>
59 #include <sys/malloc.h>
60 
61 #include <sys/mount.h>
62 #include <sys/syscallargs.h>
63 
64 int	sys_getpid(struct proc *, void *, register_t *);
65 int	sys_getpid_with_ppid(struct proc *, void *, register_t *);
66 int	sys_getuid(struct proc *, void *, register_t *);
67 int	sys_getuid_with_euid(struct proc *, void *, register_t *);
68 int	sys_getgid(struct proc *, void *, register_t *);
69 int	sys_getgid_with_egid(struct proc *, void *, register_t *);
70 
71 /* ARGSUSED */
72 int
73 sys_getpid(p, v, retval)
74 	struct proc *p;
75 	void *v;
76 	register_t *retval;
77 {
78 
79 	*retval = p->p_pid;
80 	return (0);
81 }
82 
83 /* ARGSUSED */
84 int
85 sys_getpid_with_ppid(p, v, retval)
86 	struct proc *p;
87 	void *v;
88 	register_t *retval;
89 {
90 
91 	retval[0] = p->p_pid;
92 	retval[1] = p->p_pptr->p_pid;
93 	return (0);
94 }
95 
96 /* ARGSUSED */
97 int
98 sys_getppid(p, v, retval)
99 	struct proc *p;
100 	void *v;
101 	register_t *retval;
102 {
103 
104 	*retval = p->p_pptr->p_pid;
105 	return (0);
106 }
107 
108 /* Get process group ID; note that POSIX getpgrp takes no parameter */
109 int
110 sys_getpgrp(p, v, retval)
111 	struct proc *p;
112 	void *v;
113 	register_t *retval;
114 {
115 
116 	*retval = p->p_pgrp->pg_id;
117 	return (0);
118 }
119 
120 /*
121  * Return the process group ID of the session leader (session ID)
122  * for the specified process.
123  */
124 int
125 sys_getsid(p, v, retval)
126 	struct proc *p;
127 	void *v;
128 	register_t *retval;
129 {
130 	struct sys_getsid_args /* {
131 		syscalldarg(pid_t) pid;
132 	} */ *uap = v;
133 
134 	if (SCARG(uap, pid) == 0)
135 		goto found;
136 	if ((p = pfind(SCARG(uap, pid))) == 0)
137 		return (ESRCH);
138 found:
139 	*retval = p->p_session->s_sid;
140 	return (0);
141 }
142 
143 int
144 sys_getpgid(p, v, retval)
145 	struct proc *p;
146 	void *v;
147 	register_t *retval;
148 {
149 	struct sys_getpgid_args /* {
150 		syscallarg(pid_t) pid;
151 	} */ *uap = v;
152 
153 	if (SCARG(uap, pid) == 0)
154 		goto found;
155 	if ((p = pfind(SCARG(uap, pid))) == 0)
156 		return (ESRCH);
157 found:
158 	*retval = p->p_pgid;
159 	return (0);
160 }
161 
162 /* ARGSUSED */
163 int
164 sys_getuid(p, v, retval)
165 	struct proc *p;
166 	void *v;
167 	register_t *retval;
168 {
169 
170 	*retval = p->p_cred->p_ruid;
171 	return (0);
172 }
173 
174 /* ARGSUSED */
175 int
176 sys_getuid_with_euid(p, v, retval)
177 	struct proc *p;
178 	void *v;
179 	register_t *retval;
180 {
181 
182 	retval[0] = p->p_cred->p_ruid;
183 	retval[1] = p->p_ucred->cr_uid;
184 	return (0);
185 }
186 
187 /* ARGSUSED */
188 int
189 sys_geteuid(p, v, retval)
190 	struct proc *p;
191 	void *v;
192 	register_t *retval;
193 {
194 
195 	*retval = p->p_ucred->cr_uid;
196 	return (0);
197 }
198 
199 /* ARGSUSED */
200 int
201 sys_getgid(p, v, retval)
202 	struct proc *p;
203 	void *v;
204 	register_t *retval;
205 {
206 
207 	*retval = p->p_cred->p_rgid;
208 	return (0);
209 }
210 
211 /* ARGSUSED */
212 int
213 sys_getgid_with_egid(p, v, retval)
214 	struct proc *p;
215 	void *v;
216 	register_t *retval;
217 {
218 
219 	retval[0] = p->p_cred->p_rgid;
220 	retval[1] = p->p_ucred->cr_gid;
221 	return (0);
222 }
223 
224 /*
225  * Get effective group ID.  The "egid" is groups[0], and could be obtained
226  * via getgroups.  This syscall exists because it is somewhat painful to do
227  * correctly in a library function.
228  */
229 /* ARGSUSED */
230 int
231 sys_getegid(p, v, retval)
232 	struct proc *p;
233 	void *v;
234 	register_t *retval;
235 {
236 
237 	*retval = p->p_ucred->cr_gid;
238 	return (0);
239 }
240 
241 int
242 sys_getgroups(p, v, retval)
243 	struct proc *p;
244 	void *v;
245 	register_t *retval;
246 {
247 	struct sys_getgroups_args /* {
248 		syscallarg(int) gidsetsize;
249 		syscallarg(gid_t *) gidset;
250 	} */ *uap = v;
251 	struct pcred *pc = p->p_cred;
252 	u_int ngrp;
253 	int error;
254 
255 	if (SCARG(uap, gidsetsize) == 0) {
256 		*retval = pc->pc_ucred->cr_ngroups;
257 		return (0);
258 	} else if (SCARG(uap, gidsetsize) < 0)
259 		return (EINVAL);
260 	ngrp = SCARG(uap, gidsetsize);
261 	if (ngrp < pc->pc_ucred->cr_ngroups)
262 		return (EINVAL);
263 	ngrp = pc->pc_ucred->cr_ngroups;
264 	error = copyout((caddr_t)pc->pc_ucred->cr_groups,
265 			(caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t));
266 	if (error)
267 		return (error);
268 	*retval = ngrp;
269 	return (0);
270 }
271 
272 /* ARGSUSED */
273 int
274 sys_setsid(p, v, retval)
275 	struct proc *p;
276 	void *v;
277 	register_t *retval;
278 {
279 
280 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
281 		return (EPERM);
282 	} else {
283 		(void)enterpgrp(p, p->p_pid, 1);
284 		*retval = p->p_pid;
285 		return (0);
286 	}
287 }
288 
289 /*
290  * set process group (setpgid/old setpgrp)
291  *
292  * caller does setpgid(targpid, targpgid)
293  *
294  * pgid must be in valid range (EINVAL)
295  * pid must be caller or child of caller (ESRCH)
296  * if a child
297  *	pid must be in same session (EPERM)
298  *	pid can't have done an exec (EACCES)
299  * if pgid != pid
300  * 	there must exist some pid in same session having pgid (EPERM)
301  * pid must not be session leader (EPERM)
302  */
303 /* ARGSUSED */
304 int
305 sys_setpgid(curp, v, retval)
306 	struct proc *curp;
307 	void *v;
308 	register_t *retval;
309 {
310 	struct sys_setpgid_args /* {
311 		syscallarg(int) pid;
312 		syscallarg(int) pgid;
313 	} */ *uap = v;
314 	struct proc *targp;			/* target process */
315 	struct pgrp *pgrp;			/* target pgrp */
316 
317 	if (SCARG(uap, pgid) < 0)
318 		return (EINVAL);
319 
320 	if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
321 		if ((targp = pfind(SCARG(uap, pid))) == 0
322 		    || !inferior(targp, curp))
323 			return (ESRCH);
324 		if (targp->p_session != curp->p_session)
325 			return (EPERM);
326 		if (targp->p_flag & P_EXEC)
327 			return (EACCES);
328 	} else
329 		targp = curp;
330 	if (SESS_LEADER(targp))
331 		return (EPERM);
332 	if (SCARG(uap, pgid) == 0)
333 		SCARG(uap, pgid) = targp->p_pid;
334 	else if (SCARG(uap, pgid) != targp->p_pid)
335 		if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 ||
336 	            pgrp->pg_session != curp->p_session)
337 			return (EPERM);
338 	return (enterpgrp(targp, SCARG(uap, pgid), 0));
339 }
340 
341 /* ARGSUSED */
342 int
343 sys_setuid(p, v, retval)
344 	struct proc *p;
345 	void *v;
346 	register_t *retval;
347 {
348 	struct sys_setuid_args /* {
349 		syscallarg(uid_t) uid;
350 	} */ *uap = v;
351 	struct pcred *pc = p->p_cred;
352 	uid_t uid;
353 	int error;
354 
355 	uid = SCARG(uap, uid);
356 	if (uid != pc->p_ruid &&
357 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
358 		return (error);
359 	/*
360 	 * Check if we are all set, and this is a no-op.
361 	 */
362 	if (pc->p_ruid == uid && pc->p_svuid == uid &&
363 	    pc->pc_ucred->cr_uid == uid)
364 		return (0);
365 	/*
366 	 * Everything's okay, do it.
367 	 * Transfer proc count to new user.
368 	 * Copy credentials so other references do not see our changes.
369 	 */
370 	(void)chgproccnt(pc->p_ruid, -1);
371 	(void)chgproccnt(uid, 1);
372 	pc->pc_ucred = crcopy(pc->pc_ucred);
373 	pc->pc_ucred->cr_uid = uid;
374 	pc->p_ruid = uid;
375 	pc->p_svuid = uid;
376 	p_sugid(p);
377 	return (0);
378 }
379 
380 /* ARGSUSED */
381 int
382 sys_seteuid(p, v, retval)
383 	struct proc *p;
384 	void *v;
385 	register_t *retval;
386 {
387 	struct sys_seteuid_args /* {
388 		syscallarg(uid_t) euid;
389 	} */ *uap = v;
390 	struct pcred *pc = p->p_cred;
391 	uid_t euid;
392 	int error;
393 
394 	euid = SCARG(uap, euid);
395 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
396 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
397 		return (error);
398 	/*
399 	 * Check if we are all set, and this is a no-op.
400 	 */
401 	if (pc->pc_ucred->cr_uid == euid)
402 		return (0);
403 
404 	/*
405 	 * Everything's okay, do it.  Copy credentials so other references do
406 	 * not see our changes.
407 	 */
408 	pc->pc_ucred = crcopy(pc->pc_ucred);
409 	pc->pc_ucred->cr_uid = euid;
410 	p_sugid(p);
411 	return (0);
412 }
413 
414 int
415 sys_setreuid(p, v, retval)
416 	struct proc *p;
417 	void *v;
418 	register_t *retval;
419 {
420 	struct sys_setreuid_args /* {
421 		syscallarg(uid_t) ruid;
422 		syscallarg(uid_t) euid;
423 	} */ *uap = v;
424 	struct pcred *pc = p->p_cred;
425 	uid_t ruid, euid;
426 	int error, changed = 0;
427 
428 	ruid = SCARG(uap, ruid);
429 	euid = SCARG(uap, euid);
430 
431 	if (ruid != (uid_t)-1 &&
432 	    ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid &&
433 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
434 		return (error);
435 
436 	if (euid != (uid_t)-1 &&
437 	    euid != pc->p_ruid && euid != pc->pc_ucred->cr_uid &&
438 	    euid != pc->p_svuid &&
439 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
440 		return (error);
441 
442 	if (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid) {
443 		pc->pc_ucred = crcopy(pc->pc_ucred);
444 		pc->pc_ucred->cr_uid = euid;
445 		changed++;
446 	}
447 
448 	if (ruid != (uid_t)-1 &&
449 	    (pc->p_ruid != ruid || pc->p_svuid != pc->pc_ucred->cr_uid)) {
450 		(void)chgproccnt(pc->p_ruid, -1);
451 		(void)chgproccnt(ruid, 1);
452 		pc->p_ruid = ruid;
453 		pc->p_svuid = pc->pc_ucred->cr_uid;
454 		changed++;
455 	}
456 
457 	if (changed)
458 		p_sugid(p);
459 	return (0);
460 }
461 
462 /* ARGSUSED */
463 int
464 sys_setgid(p, v, retval)
465 	struct proc *p;
466 	void *v;
467 	register_t *retval;
468 {
469 	struct sys_setgid_args /* {
470 		syscallarg(gid_t) gid;
471 	} */ *uap = v;
472 	struct pcred *pc = p->p_cred;
473 	gid_t gid;
474 	int error;
475 
476 	gid = SCARG(uap, gid);
477 	if (gid != pc->p_rgid &&
478 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
479 		return (error);
480 	/*
481 	 * Check if we are all set, and this is a no-op.
482 	 */
483 	if (pc->pc_ucred->cr_gid == gid && pc->p_rgid == gid &&
484 	    pc->p_svgid == gid)
485 		return (0);
486 
487 	pc->pc_ucred = crcopy(pc->pc_ucred);
488 	pc->pc_ucred->cr_gid = gid;
489 	pc->p_rgid = gid;
490 	pc->p_svgid = gid;
491 	p_sugid(p);
492 	return (0);
493 }
494 
495 /* ARGSUSED */
496 int
497 sys_setegid(p, v, retval)
498 	struct proc *p;
499 	void *v;
500 	register_t *retval;
501 {
502 	struct sys_setegid_args /* {
503 		syscallarg(gid_t) egid;
504 	} */ *uap = v;
505 	struct pcred *pc = p->p_cred;
506 	gid_t egid;
507 	int error;
508 
509 	egid = SCARG(uap, egid);
510 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
511 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
512 		return (error);
513 	/*
514 	 * Check if we are all set, and this is a no-op.
515 	 */
516 	if (pc->pc_ucred->cr_gid == egid)
517 		return (0);
518 
519 	pc->pc_ucred = crcopy(pc->pc_ucred);
520 	pc->pc_ucred->cr_gid = egid;
521 	p_sugid(p);
522 	return (0);
523 }
524 
525 int
526 sys_setregid(p, v, retval)
527 	struct proc *p;
528 	void *v;
529 	register_t *retval;
530 {
531 	struct sys_setregid_args /* {
532 		syscallarg(gid_t) rgid;
533 		syscallarg(gid_t) egid;
534 	} */ *uap = v;
535 	struct pcred *pc = p->p_cred;
536 	gid_t rgid, egid;
537 	int error, changed = 0;
538 
539 	rgid = SCARG(uap, rgid);
540 	egid = SCARG(uap, egid);
541 
542 	if (rgid != (gid_t)-1 &&
543 	    rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_gid &&
544 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
545 		return (error);
546 
547 	if (egid != (gid_t)-1 &&
548 	    egid != pc->p_rgid && egid != pc->pc_ucred->cr_gid &&
549 	    egid != pc->p_svgid &&
550 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
551 		return (error);
552 
553 	if (egid != (gid_t)-1 && pc->pc_ucred->cr_gid != egid) {
554 		pc->pc_ucred = crcopy(pc->pc_ucred);
555 		pc->pc_ucred->cr_gid = egid;
556 		changed++;
557 	}
558 
559 	if (rgid != (gid_t)-1 &&
560 	    (pc->p_rgid != rgid || pc->p_svgid != pc->pc_ucred->cr_gid)) {
561 		pc->p_rgid = rgid;
562 		pc->p_svgid = pc->pc_ucred->cr_gid;
563 		changed++;
564 	}
565 
566 	if (changed)
567 		p_sugid(p);
568 	return (0);
569 }
570 
571 int
572 sys_issetugid(p, v, retval)
573 	struct proc *p;
574 	void *v;
575 	register_t *retval;
576 {
577 	/*
578 	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
579 	 * we use P_SUGID because we consider changing the owners as
580 	 * "tainting" as well.
581 	 * This is significant for procs that start as root and "become"
582 	 * a user without an exec - programs cannot know *everything*
583 	 * that libc *might* have put in their data segment.
584 	 */
585 	*retval = (p->p_flag & P_SUGID) != 0;
586 	return (0);
587 }
588 
589 /* ARGSUSED */
590 int
591 sys_setgroups(p, v, retval)
592 	struct proc *p;
593 	void *v;
594 	register_t *retval;
595 {
596 	struct sys_setgroups_args /* {
597 		syscallarg(int) gidsetsize;
598 		syscallarg(const gid_t *) gidset;
599 	} */ *uap = v;
600 	struct pcred *pc = p->p_cred;
601 	int ngrp;
602 	int error;
603 	gid_t grp[NGROUPS];
604 	size_t grsize;
605 
606 	if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0)
607 		return (error);
608 
609 	ngrp = SCARG(uap, gidsetsize);
610 	if ((u_int)ngrp > NGROUPS)
611 		return (EINVAL);
612 
613 	grsize = ngrp * sizeof(gid_t);
614 	error = copyin(SCARG(uap, gidset), grp, grsize);
615 	if (error)
616 		return (error);
617 	/*
618 	 * Check if this is a no-op.
619 	 */
620 	if (pc->pc_ucred->cr_ngroups == (u_int) ngrp &&
621 	    memcmp(grp, pc->pc_ucred->cr_groups, grsize) == 0)
622 		return (0);
623 
624 	pc->pc_ucred = crcopy(pc->pc_ucred);
625 	(void)memcpy(pc->pc_ucred->cr_groups, grp, grsize);
626 	pc->pc_ucred->cr_ngroups = ngrp;
627 	p_sugid(p);
628 	return (0);
629 }
630 
631 /*
632  * Check if gid is a member of the group set.
633  */
634 int
635 groupmember(gid, cred)
636 	gid_t gid;
637 	struct ucred *cred;
638 {
639 	gid_t *gp;
640 	gid_t *egp;
641 
642 	egp = &(cred->cr_groups[cred->cr_ngroups]);
643 	for (gp = cred->cr_groups; gp < egp; gp++)
644 		if (*gp == gid)
645 			return (1);
646 	return (0);
647 }
648 
649 /*
650  * Test whether the specified credentials imply "super-user"
651  * privilege; if so, and we have accounting info, set the flag
652  * indicating use of super-powers.
653  * Returns 0 or error.
654  */
655 int
656 suser(cred, acflag)
657 	struct ucred *cred;
658 	u_short *acflag;
659 {
660 	if (cred->cr_uid == 0) {
661 		if (acflag)
662 			*acflag |= ASU;
663 		return (0);
664 	}
665 	return (EPERM);
666 }
667 
668 /*
669  * Allocate a zeroed cred structure.
670  */
671 struct ucred *
672 crget()
673 {
674 	struct ucred *cr;
675 
676 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
677 	memset((caddr_t)cr, 0, sizeof(*cr));
678 	cr->cr_ref = 1;
679 	return (cr);
680 }
681 
682 /*
683  * Free a cred structure.
684  * Throws away space when ref count gets to 0.
685  */
686 void
687 crfree(cr)
688 	struct ucred *cr;
689 {
690 
691 	if (--cr->cr_ref == 0)
692 		FREE((caddr_t)cr, M_CRED);
693 }
694 
695 /*
696  * Copy cred structure to a new one and free the old one.
697  */
698 struct ucred *
699 crcopy(cr)
700 	struct ucred *cr;
701 {
702 	struct ucred *newcr;
703 
704 	if (cr->cr_ref == 1)
705 		return (cr);
706 	newcr = crget();
707 	*newcr = *cr;
708 	crfree(cr);
709 	newcr->cr_ref = 1;
710 	return (newcr);
711 }
712 
713 /*
714  * Dup cred struct to a new held one.
715  */
716 struct ucred *
717 crdup(cr)
718 	struct ucred *cr;
719 {
720 	struct ucred *newcr;
721 
722 	newcr = crget();
723 	*newcr = *cr;
724 	newcr->cr_ref = 1;
725 	return (newcr);
726 }
727 
728 /*
729  * convert from userland credentials to kernel one
730  */
731 void
732 crcvt(uc, uuc)
733 	struct ucred *uc;
734 	const struct uucred *uuc;
735 {
736 	uc->cr_ref = 0;
737 	uc->cr_uid = uuc->cr_uid;
738 	uc->cr_gid = uuc->cr_gid;
739 	uc->cr_ngroups = uuc->cr_ngroups;
740 	(void)memcpy(uc->cr_groups, uuc->cr_groups, sizeof(uuc->cr_groups));
741 }
742 
743 /*
744  * Get login name, if available.
745  */
746 /* ARGSUSED */
747 int
748 sys___getlogin(p, v, retval)
749 	struct proc *p;
750 	void *v;
751 	register_t *retval;
752 {
753 	struct sys___getlogin_args /* {
754 		syscallarg(char *) namebuf;
755 		syscallarg(size_t) namelen;
756 	} */ *uap = v;
757 
758 	if (SCARG(uap, namelen) > sizeof(p->p_pgrp->pg_session->s_login))
759 		SCARG(uap, namelen) = sizeof(p->p_pgrp->pg_session->s_login);
760 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
761 	    (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
762 }
763 
764 /*
765  * Set login name.
766  */
767 /* ARGSUSED */
768 int
769 sys_setlogin(p, v, retval)
770 	struct proc *p;
771 	void *v;
772 	register_t *retval;
773 {
774 	struct sys_setlogin_args /* {
775 		syscallarg(const char *) namebuf;
776 	} */ *uap = v;
777 	int error;
778 
779 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
780 		return (error);
781 	error = copyinstr(SCARG(uap, namebuf), p->p_pgrp->pg_session->s_login,
782 	    sizeof(p->p_pgrp->pg_session->s_login) - 1, (size_t *)0);
783 	if (error == ENAMETOOLONG)
784 		error = EINVAL;
785 	return (error);
786 }
787