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