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