kern_prot.c revision 1.88.10.3 1 /* $NetBSD: kern_prot.c,v 1.88.10.3 2006/03/09 23:48:23 elad 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. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
37 */
38
39 /*
40 * System calls related to processes and protection
41 */
42
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: kern_prot.c,v 1.88.10.3 2006/03/09 23:48:23 elad Exp $");
45
46 #include "opt_compat_43.h"
47
48 #include <sys/param.h>
49 #include <sys/acct.h>
50 #include <sys/systm.h>
51 #include <sys/ucred.h>
52 #include <sys/proc.h>
53 #include <sys/timeb.h>
54 #include <sys/times.h>
55 #include <sys/pool.h>
56 #include <sys/syslog.h>
57 #include <sys/resourcevar.h>
58
59 #include <sys/mount.h>
60 #include <sys/sa.h>
61 #include <sys/syscallargs.h>
62
63 #include <sys/malloc.h>
64
65 POOL_INIT(cred_pool, sizeof(struct ucred), 0, 0, 0, "credpl",
66 &pool_allocator_nointr);
67
68 int sys_getpid(struct lwp *, void *, register_t *);
69 int sys_getpid_with_ppid(struct lwp *, void *, register_t *);
70 int sys_getuid(struct lwp *, void *, register_t *);
71 int sys_getuid_with_euid(struct lwp *, void *, register_t *);
72 int sys_getgid(struct lwp *, void *, register_t *);
73 int sys_getgid_with_egid(struct lwp *, void *, register_t *);
74
75 static int grsortu(gid_t *, int);
76
77 /* ARGSUSED */
78 int
79 sys_getpid(struct lwp *l, void *v, register_t *retval)
80 {
81 struct proc *p = l->l_proc;
82
83 *retval = p->p_pid;
84 return (0);
85 }
86
87 /* ARGSUSED */
88 int
89 sys_getpid_with_ppid(struct lwp *l, void *v, register_t *retval)
90 {
91 struct proc *p = l->l_proc;
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(struct lwp *l, void *v, register_t *retval)
101 {
102 struct proc *p = l->l_proc;
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(struct lwp *l, void *v, register_t *retval)
111 {
112 struct proc *p = l->l_proc;
113
114 *retval = p->p_pgrp->pg_id;
115 return (0);
116 }
117
118 /*
119 * Return the process group ID of the session leader (session ID)
120 * for the specified process.
121 */
122 int
123 sys_getsid(struct lwp *l, void *v, register_t *retval)
124 {
125 struct sys_getsid_args /* {
126 syscalldarg(pid_t) pid;
127 } */ *uap = v;
128 struct proc *p = l->l_proc;
129
130 if (SCARG(uap, pid) == 0)
131 goto found;
132 if ((p = pfind(SCARG(uap, pid))) == 0)
133 return (ESRCH);
134 found:
135 *retval = p->p_session->s_sid;
136 return (0);
137 }
138
139 int
140 sys_getpgid(struct lwp *l, void *v, register_t *retval)
141 {
142 struct sys_getpgid_args /* {
143 syscallarg(pid_t) pid;
144 } */ *uap = v;
145 struct proc *p = l->l_proc;
146
147 if (SCARG(uap, pid) == 0)
148 goto found;
149 if ((p = pfind(SCARG(uap, pid))) == 0)
150 return (ESRCH);
151 found:
152 *retval = p->p_pgid;
153 return (0);
154 }
155
156 /* ARGSUSED */
157 int
158 sys_getuid(struct lwp *l, void *v, register_t *retval)
159 {
160 struct proc *p = l->l_proc;
161
162 *retval = kauth_cred_getuid(p->p_cred);
163 return (0);
164 }
165
166 /* ARGSUSED */
167 int
168 sys_getuid_with_euid(struct lwp *l, void *v, register_t *retval)
169 {
170 struct proc *p = l->l_proc;
171
172 retval[0] = kauth_cred_getuid(p->p_cred);
173 retval[1] = kauth_cred_geteuid(p->p_cred);
174 return (0);
175 }
176
177 /* ARGSUSED */
178 int
179 sys_geteuid(struct lwp *l, void *v, register_t *retval)
180 {
181 struct proc *p = l->l_proc;
182
183 *retval = kauth_cred_geteuid(p->p_cred);
184 return (0);
185 }
186
187 /* ARGSUSED */
188 int
189 sys_getgid(struct lwp *l, void *v, register_t *retval)
190 {
191 struct proc *p = l->l_proc;
192
193 *retval = kauth_cred_getgid(p->p_cred);
194 return (0);
195 }
196
197 /* ARGSUSED */
198 int
199 sys_getgid_with_egid(struct lwp *l, void *v, register_t *retval)
200 {
201 struct proc *p = l->l_proc;
202
203 retval[0] = kauth_cred_getgid(p->p_cred);
204 retval[1] = kauth_cred_getegid(p->p_cred);
205 return (0);
206 }
207
208 /*
209 * Get effective group ID. The "egid" is groups[0], and could be obtained
210 * via getgroups. This syscall exists because it is somewhat painful to do
211 * correctly in a library function.
212 */
213 /* ARGSUSED */
214 int
215 sys_getegid(struct lwp *l, void *v, register_t *retval)
216 {
217 struct proc *p = l->l_proc;
218
219 *retval = kauth_cred_getegid(p->p_cred);
220 return (0);
221 }
222
223 int
224 sys_getgroups(struct lwp *l, void *v, register_t *retval)
225 {
226 struct sys_getgroups_args /* {
227 syscallarg(int) gidsetsize;
228 syscallarg(gid_t *) gidset;
229 } */ *uap = v;
230 struct proc *p = l->l_proc;
231 kauth_cred_t pc = p->p_cred;
232 u_int ngrp;
233 int error;
234 gid_t *grbuf;
235 int i;
236
237 if (SCARG(uap, gidsetsize) == 0) {
238 *retval = kauth_cred_ngroups(pc);
239 return (0);
240 } else if (SCARG(uap, gidsetsize) < 0)
241 return (EINVAL);
242 ngrp = SCARG(uap, gidsetsize);
243 if (ngrp < kauth_cred_ngroups(pc))
244 return (EINVAL);
245 ngrp = kauth_cred_ngroups(pc);
246
247 /* XXX elad - this is ugly */
248 grbuf = malloc(ngrp * sizeof(*grbuf), M_TEMP, M_WAITOK);
249 for (i = 0; i < ngrp; i++)
250 grbuf[i] = kauth_cred_group(pc, i);
251 error = copyout(grbuf, (caddr_t)SCARG(uap, gidset),
252 ngrp * sizeof(gid_t));
253 free(grbuf, M_TEMP);
254 if (error)
255 return (error);
256 *retval = ngrp;
257 return (0);
258 }
259
260 /* ARGSUSED */
261 int
262 sys_setsid(struct lwp *l, void *v, register_t *retval)
263 {
264 struct proc *p = l->l_proc;
265
266 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
267 return (EPERM);
268 } else {
269 (void)enterpgrp(p, p->p_pid, 1);
270 *retval = p->p_pid;
271 return (0);
272 }
273 }
274
275 /*
276 * set process group (setpgid/old setpgrp)
277 *
278 * caller does setpgid(targpid, targpgid)
279 *
280 * pgid must be in valid range (EINVAL)
281 * pid must be caller or child of caller (ESRCH)
282 * if a child
283 * pid must be in same session (EPERM)
284 * pid can't have done an exec (EACCES)
285 * if pgid != pid
286 * there must exist some pid in same session having pgid (EPERM)
287 * pid must not be session leader (EPERM)
288 *
289 * Permission checks now in enterpgrp()
290 */
291 /* ARGSUSED */
292 int
293 sys_setpgid(struct lwp *l, void *v, register_t *retval)
294 {
295 struct sys_setpgid_args /* {
296 syscallarg(int) pid;
297 syscallarg(int) pgid;
298 } */ *uap = v;
299 struct proc *curp = l->l_proc;
300 struct proc *targp; /* target process */
301
302 if (SCARG(uap, pgid) < 0)
303 return EINVAL;
304
305 /* XXX MP - there is a horrid race here with targp exiting! */
306 if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
307 targp = pfind(SCARG(uap, pid));
308 if (targp == NULL)
309 return ESRCH;
310 } else
311 targp = curp;
312
313 if (SCARG(uap, pgid) == 0)
314 SCARG(uap, pgid) = targp->p_pid;
315 return enterpgrp(targp, SCARG(uap, pgid), 0);
316 }
317
318 /*
319 * Set real, effective and saved uids to the requested values.
320 * non-root callers can only ever change uids to values that match
321 * one of the processes current uid values.
322 * This is further restricted by the flags argument.
323 */
324
325 int
326 do_setresuid(struct lwp *l, uid_t r, uid_t e, uid_t sv, u_int flags)
327 {
328 int error;
329 struct proc *p = l->l_proc;
330 kauth_cred_t cred = p->p_cred;
331
332 /* Superuser can do anything it wants to.... */
333 error = generic_authorize(cred, KAUTH_GENERIC_ISSUSER, &p->p_acflag);
334 if (error) {
335 /* Otherwise check new value is one of the allowed
336 existing values. */
337 if (r != -1 && !((flags & ID_R_EQ_R) && r == kauth_cred_getuid(cred))
338 && !((flags & ID_R_EQ_E) && r == kauth_cred_geteuid(cred))
339 && !((flags & ID_R_EQ_S) && r == kauth_cred_getsvuid(cred)))
340 return error;
341 if (e != -1 && !((flags & ID_E_EQ_R) && e == kauth_cred_getuid(cred))
342 && !((flags & ID_E_EQ_E) && e == kauth_cred_geteuid(cred))
343 && !((flags & ID_E_EQ_S) && e == kauth_cred_getsvuid(cred)))
344 return error;
345 if (sv != -1 && !((flags & ID_S_EQ_R) && sv == kauth_cred_getuid(cred))
346 && !((flags & ID_S_EQ_E) && sv == kauth_cred_geteuid(cred))
347 && !((flags & ID_S_EQ_S) && sv == kauth_cred_getsvuid(cred)))
348 return error;
349 }
350
351 /* If nothing has changed, short circuit the request */
352 if ((r == -1 || r == kauth_cred_getuid(cred))
353 && (e == -1 || e == kauth_cred_geteuid(cred))
354 && (sv == -1 || sv == kauth_cred_getsvuid(cred)))
355 /* nothing to do */
356 return 0;
357
358 /* The pcred structure is not actually shared... */
359 if (r != -1 && r != kauth_cred_getuid(cred)) {
360 /* Update count of processes for this user */
361 (void)chgproccnt(kauth_cred_getuid(cred), -1);
362 (void)chgproccnt(r, 1);
363 kauth_cred_setuid(cred, r);
364 }
365 if (sv != -1)
366 kauth_cred_setsvuid(cred, sv);
367 if (e != -1 && e != kauth_cred_geteuid(cred)) {
368 /* Update a clone of the current credentials */
369 cred = kauth_cred_copy(cred);
370 kauth_cred_seteuid(cred, e);
371 p->p_cred = cred;
372 }
373
374 /* Mark process as having changed credentials, stops tracing etc */
375 p_sugid(p);
376 return 0;
377 }
378
379 /*
380 * Set real, effective and saved gids to the requested values.
381 * non-root callers can only ever change gids to values that match
382 * one of the processes current gid values.
383 * This is further restricted by the flags argument.
384 */
385
386 int
387 do_setresgid(struct lwp *l, gid_t r, gid_t e, gid_t sv, u_int flags)
388 {
389 int error;
390 struct proc *p = l->l_proc;
391 kauth_cred_t cred = p->p_cred;
392
393 /* Superuser can do anything it wants to.... */
394 error = generic_authorize(cred, KAUTH_GENERIC_ISSUSER, &p->p_acflag);
395 if (error) {
396 /* Otherwise check new value is one of the allowed
397 existing values. */
398 if (r != -1 && !((flags & ID_R_EQ_R) && r == kauth_cred_getgid(cred))
399 && !((flags & ID_R_EQ_E) && r == kauth_cred_getegid(cred))
400 && !((flags & ID_R_EQ_S) && r == kauth_cred_getsvgid(cred)))
401 return error;
402 if (e != -1 && !((flags & ID_E_EQ_R) && e == kauth_cred_getgid(cred))
403 && !((flags & ID_E_EQ_E) && e == kauth_cred_getegid(cred))
404 && !((flags & ID_E_EQ_S) && e == kauth_cred_getsvgid(cred)))
405 return error;
406 if (sv != -1 && !((flags & ID_S_EQ_R) && sv == kauth_cred_getgid(cred))
407 && !((flags & ID_S_EQ_E) && sv == kauth_cred_getegid(cred))
408 && !((flags & ID_S_EQ_S) && sv == kauth_cred_getsvgid(cred)))
409 return error;
410 }
411
412 /* If nothing has changed, short circuit the request */
413 if ((r == -1 || r == kauth_cred_getgid(cred))
414 && (e == -1 || e == kauth_cred_getegid(cred))
415 && (sv == -1 || sv == kauth_cred_getsvgid(cred)))
416 /* nothing to do */
417 return 0;
418
419 /* The pcred structure is not actually shared... */
420 if (r != -1)
421 kauth_cred_setgid(cred, r);
422 if (sv != -1)
423 kauth_cred_setsvgid(cred, sv);
424 if (e != -1 && e != kauth_cred_getegid(cred)) {
425 /* Update a clone of the current credentials */
426 cred = kauth_cred_copy(cred);
427 kauth_cred_setegid(cred, e);
428 p->p_cred = cred;
429 }
430
431 /* Mark process as having changed credentials, stops tracing etc */
432 p_sugid(p);
433 return 0;
434 }
435
436 /* ARGSUSED */
437 int
438 sys_setuid(struct lwp *l, void *v, register_t *retval)
439 {
440 struct sys_setuid_args /* {
441 syscallarg(uid_t) uid;
442 } */ *uap = v;
443 uid_t uid = SCARG(uap, uid);
444
445 return do_setresuid(l, uid, uid, uid,
446 ID_R_EQ_R | ID_E_EQ_R | ID_S_EQ_R);
447 }
448
449 /* ARGSUSED */
450 int
451 sys_seteuid(struct lwp *l, void *v, register_t *retval)
452 {
453 struct sys_seteuid_args /* {
454 syscallarg(uid_t) euid;
455 } */ *uap = v;
456
457 return do_setresuid(l, -1, SCARG(uap, euid), -1, ID_E_EQ_R | ID_E_EQ_S);
458 }
459
460 int
461 sys_setreuid(struct lwp *l, void *v, register_t *retval)
462 {
463 struct sys_setreuid_args /* {
464 syscallarg(uid_t) ruid;
465 syscallarg(uid_t) euid;
466 } */ *uap = v;
467 struct proc *p = l->l_proc;
468 uid_t ruid, euid, svuid;
469
470 ruid = SCARG(uap, ruid);
471 euid = SCARG(uap, euid);
472 if (ruid == -1)
473 ruid = kauth_cred_getuid(p->p_cred);
474 if (euid == -1)
475 euid = kauth_cred_geteuid(p->p_cred);
476 /* Saved uid is set to the new euid if the ruid changed */
477 svuid = (ruid == kauth_cred_getuid(p->p_cred)) ? -1 : euid;
478
479 return do_setresuid(l, ruid, euid, svuid,
480 ID_R_EQ_R | ID_R_EQ_E |
481 ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S |
482 ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S);
483 }
484
485 /* ARGSUSED */
486 int
487 sys_setgid(struct lwp *l, void *v, register_t *retval)
488 {
489 struct sys_setgid_args /* {
490 syscallarg(gid_t) gid;
491 } */ *uap = v;
492 gid_t gid = SCARG(uap, gid);
493
494 return do_setresgid(l, gid, gid, gid,
495 ID_R_EQ_R | ID_E_EQ_R | ID_S_EQ_R);
496 }
497
498 /* ARGSUSED */
499 int
500 sys_setegid(struct lwp *l, void *v, register_t *retval)
501 {
502 struct sys_setegid_args /* {
503 syscallarg(gid_t) egid;
504 } */ *uap = v;
505
506 return do_setresgid(l, -1, SCARG(uap, egid), -1, ID_E_EQ_R | ID_E_EQ_S);
507 }
508
509 int
510 sys_setregid(struct lwp *l, void *v, register_t *retval)
511 {
512 struct sys_setregid_args /* {
513 syscallarg(gid_t) rgid;
514 syscallarg(gid_t) egid;
515 } */ *uap = v;
516 struct proc *p = l->l_proc;
517 gid_t rgid, egid, svgid;
518
519 rgid = SCARG(uap, rgid);
520 egid = SCARG(uap, egid);
521 if (rgid == -1)
522 rgid = kauth_cred_getgid(p->p_cred);
523 if (egid == -1)
524 egid = kauth_cred_getegid(p->p_cred);
525 /* Saved gid is set to the new egid if the rgid changed */
526 svgid = rgid == kauth_cred_getgid(p->p_cred) ? -1 : egid;
527
528 return do_setresgid(l, rgid, egid, svgid,
529 ID_R_EQ_R | ID_R_EQ_E |
530 ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S |
531 ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S);
532 }
533
534 int
535 sys_issetugid(struct lwp *l, void *v, register_t *retval)
536 {
537 struct proc *p = l->l_proc;
538
539 /*
540 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
541 * we use P_SUGID because we consider changing the owners as
542 * "tainting" as well.
543 * This is significant for procs that start as root and "become"
544 * a user without an exec - programs cannot know *everything*
545 * that libc *might* have put in their data segment.
546 */
547 *retval = (p->p_flag & P_SUGID) != 0;
548 return (0);
549 }
550
551 /*
552 * sort -u for groups.
553 */
554 static int
555 grsortu(gid_t *grp, int ngrp)
556 {
557 const gid_t *src, *end;
558 gid_t *dst;
559 gid_t group;
560 int i, j;
561
562 /* bubble sort */
563 for (i = 0; i < ngrp; i++)
564 for (j = i + 1; j < ngrp; j++)
565 if (grp[i] > grp[j]) {
566 gid_t tmp = grp[i];
567 grp[i] = grp[j];
568 grp[j] = tmp;
569 }
570
571 /* uniq */
572 end = grp + ngrp;
573 src = grp;
574 dst = grp;
575 while (src < end) {
576 group = *src++;
577 while (src < end && *src == group)
578 src++;
579 *dst++ = group;
580 }
581
582 #ifdef DIAGNOSTIC
583 /* zero out the rest of the array */
584 (void)memset(dst, 0, sizeof(*grp) * (end - dst));
585 #endif
586
587 return dst - grp;
588 }
589
590 /* ARGSUSED */
591 int
592 sys_setgroups(struct lwp *l, void *v, register_t *retval)
593 {
594 struct sys_setgroups_args /* {
595 syscallarg(int) gidsetsize;
596 syscallarg(const gid_t *) gidset;
597 } */ *uap = v;
598 struct proc *p = l->l_proc;
599 kauth_cred_t pc = p->p_cred;
600 int ngrp;
601 int error;
602 gid_t grp[NGROUPS];
603 size_t grsize;
604 int do_ngroups, i, j;
605
606 if ((error = generic_authorize(pc, KAUTH_GENERIC_ISSUSER,
607 &p->p_acflag)) != 0)
608 return (error);
609
610 ngrp = SCARG(uap, gidsetsize);
611 if ((u_int)ngrp > NGROUPS)
612 return (EINVAL);
613
614 grsize = ngrp * sizeof(gid_t);
615 error = copyin(SCARG(uap, gidset), grp, grsize);
616 if (error)
617 return (error);
618
619 ngrp = grsortu(grp, ngrp);
620
621 pc = kauth_cred_copy(pc);
622 p->p_cred = pc;
623
624 do_ngroups = kauth_cred_ngroups(pc);
625
626 /* (1) For every group in current group array... */
627 for (i = 0; i < do_ngroups; i++) {
628 int in_new_array;
629
630 /* ...check if it's also in the new array... */
631 in_new_array = 0;
632 for (j = 0; j < ngrp; j++) {
633 if (kauth_cred_group(pc, i) == grp[j])
634 in_new_array = 1;
635 }
636
637 /* ...if not, delete it. */
638 if (!in_new_array) {
639 kauth_cred_delgroup(pc, kauth_cred_group(pc, i));
640 do_ngroups--;
641 }
642 }
643
644 /* (2) For every group in the new group array... */
645 for (i = 0; i < ngrp; i++) {
646 /* ...add it to current group array. */
647 kauth_cred_addgroup(pc, grp[i]);
648 }
649
650 p_sugid(p);
651 return (0);
652 }
653
654 /*
655 * Check if gid is a member of the group set.
656 */
657 int
658 groupmember(gid_t gid, const struct ucred *cred)
659 {
660 const gid_t *gp;
661 const gid_t *egp;
662
663 egp = &(cred->cr_groups[cred->cr_ngroups]);
664 for (gp = cred->cr_groups; gp < egp; gp++)
665 if (*gp == gid)
666 return (1);
667 return (0);
668 }
669
670 /*
671 * Test whether the specified credentials imply "super-user"
672 * privilege; if so, and we have accounting info, set the flag
673 * indicating use of super-powers.
674 * Returns 0 or error.
675 */
676 int
677 suser(const struct ucred *cred, u_short *acflag)
678 {
679
680 if (cred->cr_uid == 0) {
681 if (acflag)
682 *acflag |= ASU;
683 return (0);
684 }
685 return (EPERM);
686 }
687
688 /*
689 * Allocate a zeroed cred structure.
690 */
691 struct ucred *
692 crget(void)
693 {
694 struct ucred *cr;
695
696 cr = pool_get(&cred_pool, PR_WAITOK);
697 memset(cr, 0, sizeof(*cr));
698 simple_lock_init(&cr->cr_lock);
699 cr->cr_ref = 1;
700 return (cr);
701 }
702
703 /*
704 * Free a cred structure.
705 * Throws away space when ref count gets to 0.
706 */
707 void
708 crfree(struct ucred *cr)
709 {
710 int n;
711
712 simple_lock(&cr->cr_lock);
713 n = --cr->cr_ref;
714 simple_unlock(&cr->cr_lock);
715 if (n == 0)
716 pool_put(&cred_pool, cr);
717 }
718
719 /*
720 * Compare cred structures and return 0 if they match
721 */
722 int
723 crcmp(const struct ucred *cr1, const struct uucred *cr2)
724 {
725 /* FIXME: The group lists should be compared element by element,
726 * as the order of groups may be different in the two lists.
727 * Currently this function can return a non-zero value for
728 * equivalent group lists. */
729 return cr1->cr_uid != cr2->cr_uid ||
730 cr1->cr_gid != cr2->cr_gid ||
731 cr1->cr_ngroups != (uint32_t)cr2->cr_ngroups ||
732 memcmp(cr1->cr_groups, cr2->cr_groups,
733 sizeof(cr1->cr_groups[0]) * cr1->cr_ngroups);
734 }
735
736 /*
737 * Copy cred structure to a new one and free the old one.
738 */
739 struct ucred *
740 crcopy(struct ucred *cr)
741 {
742 struct ucred *newcr;
743
744 if (cr->cr_ref == 1)
745 return (cr);
746
747 newcr = crget();
748 memcpy(&newcr->cr_startcopy, &cr->cr_startcopy,
749 sizeof(struct ucred) - offsetof(struct ucred, cr_startcopy));
750 crfree(cr);
751 return (newcr);
752 }
753
754 /*
755 * Dup cred struct to a new held one.
756 */
757 struct ucred *
758 crdup(const struct ucred *cr)
759 {
760 struct ucred *newcr;
761
762 newcr = crget();
763 memcpy(&newcr->cr_startcopy, &cr->cr_startcopy,
764 sizeof(struct ucred) - offsetof(struct ucred, cr_startcopy));
765 return (newcr);
766 }
767
768 /*
769 * convert from userland credentials to kernel one
770 */
771 void
772 crcvt(struct ucred *uc, const struct uucred *uuc)
773 {
774
775 uc->cr_ref = 0;
776 uc->cr_uid = uuc->cr_uid;
777 uc->cr_gid = uuc->cr_gid;
778 uc->cr_ngroups = uuc->cr_ngroups;
779 (void)memcpy(uc->cr_groups, uuc->cr_groups, sizeof(uuc->cr_groups));
780 }
781
782 /*
783 * Get login name, if available.
784 */
785 /* ARGSUSED */
786 int
787 sys___getlogin(struct lwp *l, void *v, register_t *retval)
788 {
789 struct sys___getlogin_args /* {
790 syscallarg(char *) namebuf;
791 syscallarg(size_t) namelen;
792 } */ *uap = v;
793 struct proc *p = l->l_proc;
794
795 if (SCARG(uap, namelen) > sizeof(p->p_pgrp->pg_session->s_login))
796 SCARG(uap, namelen) = sizeof(p->p_pgrp->pg_session->s_login);
797 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
798 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
799 }
800
801 /*
802 * Set login name.
803 */
804 /* ARGSUSED */
805 int
806 sys___setlogin(struct lwp *l, void *v, register_t *retval)
807 {
808 struct sys___setlogin_args /* {
809 syscallarg(const char *) namebuf;
810 } */ *uap = v;
811 struct proc *p = l->l_proc;
812 struct session *s = p->p_pgrp->pg_session;
813 char newname[sizeof s->s_login + 1];
814 int error;
815
816 if ((error = generic_authorize(p->p_cred, KAUTH_GENERIC_ISSUSER,
817 &p->p_acflag)) != 0)
818 return (error);
819 error = copyinstr(SCARG(uap, namebuf), &newname, sizeof newname, NULL);
820 if (error != 0)
821 return (error == ENAMETOOLONG ? EINVAL : error);
822
823 if (s->s_flags & S_LOGIN_SET && p->p_pid != s->s_sid &&
824 strncmp(newname, s->s_login, sizeof s->s_login) != 0)
825 log(LOG_WARNING, "%s (pid %d) changing logname from "
826 "%.*s to %s\n", p->p_comm, p->p_pid,
827 (int)sizeof s->s_login, s->s_login, newname);
828 s->s_flags |= S_LOGIN_SET;
829 strncpy(s->s_login, newname, sizeof s->s_login);
830 return (0);
831 }
832