kern_prot.c revision 1.88.10.1 1 /* $NetBSD: kern_prot.c,v 1.88.10.1 2006/03/08 00:53:40 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.1 2006/03/08 00:53:40 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 /* XXX elad cred = kauth_cred_copy(cred); */
370 kauth_cred_seteuid(cred, e);
371 }
372
373 /* Mark process as having changed credentials, stops tracing etc */
374 p_sugid(p);
375 return 0;
376 }
377
378 /*
379 * Set real, effective and saved gids to the requested values.
380 * non-root callers can only ever change gids to values that match
381 * one of the processes current gid values.
382 * This is further restricted by the flags argument.
383 */
384
385 int
386 do_setresgid(struct lwp *l, gid_t r, gid_t e, gid_t sv, u_int flags)
387 {
388 int error;
389 struct proc *p = l->l_proc;
390 kauth_cred_t cred = p->p_cred;
391
392 /* Superuser can do anything it wants to.... */
393 error = generic_authorize(cred, KAUTH_GENERIC_ISSUSER, &p->p_acflag);
394 if (error) {
395 /* Otherwise check new value is one of the allowed
396 existing values. */
397 if (r != -1 && !((flags & ID_R_EQ_R) && r == kauth_cred_getgid(cred))
398 && !((flags & ID_R_EQ_E) && r == kauth_cred_getegid(cred))
399 && !((flags & ID_R_EQ_S) && r == kauth_cred_getsvgid(cred)))
400 return error;
401 if (e != -1 && !((flags & ID_E_EQ_R) && e == kauth_cred_getgid(cred))
402 && !((flags & ID_E_EQ_E) && e == kauth_cred_getegid(cred))
403 && !((flags & ID_E_EQ_S) && e == kauth_cred_getsvgid(cred)))
404 return error;
405 if (sv != -1 && !((flags & ID_S_EQ_R) && sv == kauth_cred_getgid(cred))
406 && !((flags & ID_S_EQ_E) && sv == kauth_cred_getegid(cred))
407 && !((flags & ID_S_EQ_S) && sv == kauth_cred_getsvgid(cred)))
408 return error;
409 }
410
411 /* If nothing has changed, short circuit the request */
412 if ((r == -1 || r == kauth_cred_getgid(cred))
413 && (e == -1 || e == kauth_cred_getegid(cred))
414 && (sv == -1 || sv == kauth_cred_getsvgid(cred)))
415 /* nothing to do */
416 return 0;
417
418 /* The pcred structure is not actually shared... */
419 if (r != -1)
420 kauth_cred_setgid(cred, r);
421 if (sv != -1)
422 kauth_cred_setsvgid(cred, sv);
423 if (e != -1 && e != kauth_cred_getegid(cred)) {
424 /* Update a clone of the current credentials */
425 /* XXX elad cred = kauth_cred_copy(cred); */
426 kauth_cred_setrefcnt(cred, 1);
427 kauth_cred_setegid(cred, e);
428 }
429
430 /* Mark process as having changed credentials, stops tracing etc */
431 p_sugid(p);
432 return 0;
433 }
434
435 /* ARGSUSED */
436 int
437 sys_setuid(struct lwp *l, void *v, register_t *retval)
438 {
439 struct sys_setuid_args /* {
440 syscallarg(uid_t) uid;
441 } */ *uap = v;
442 uid_t uid = SCARG(uap, uid);
443
444 return do_setresuid(l, uid, uid, uid,
445 ID_R_EQ_R | ID_E_EQ_R | ID_S_EQ_R);
446 }
447
448 /* ARGSUSED */
449 int
450 sys_seteuid(struct lwp *l, void *v, register_t *retval)
451 {
452 struct sys_seteuid_args /* {
453 syscallarg(uid_t) euid;
454 } */ *uap = v;
455
456 return do_setresuid(l, -1, SCARG(uap, euid), -1, ID_E_EQ_R | ID_E_EQ_S);
457 }
458
459 int
460 sys_setreuid(struct lwp *l, void *v, register_t *retval)
461 {
462 struct sys_setreuid_args /* {
463 syscallarg(uid_t) ruid;
464 syscallarg(uid_t) euid;
465 } */ *uap = v;
466 struct proc *p = l->l_proc;
467 uid_t ruid, euid, svuid;
468
469 ruid = SCARG(uap, ruid);
470 euid = SCARG(uap, euid);
471 if (ruid == -1)
472 ruid = kauth_cred_getuid(p->p_cred);
473 if (euid == -1)
474 euid = kauth_cred_geteuid(p->p_cred);
475 /* Saved uid is set to the new euid if the ruid changed */
476 svuid = (ruid == kauth_cred_getuid(p->p_cred)) ? -1 : euid;
477
478 return do_setresuid(l, ruid, euid, svuid,
479 ID_R_EQ_R | ID_R_EQ_E |
480 ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S |
481 ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S);
482 }
483
484 /* ARGSUSED */
485 int
486 sys_setgid(struct lwp *l, void *v, register_t *retval)
487 {
488 struct sys_setgid_args /* {
489 syscallarg(gid_t) gid;
490 } */ *uap = v;
491 gid_t gid = SCARG(uap, gid);
492
493 return do_setresgid(l, gid, gid, gid,
494 ID_R_EQ_R | ID_E_EQ_R | ID_S_EQ_R);
495 }
496
497 /* ARGSUSED */
498 int
499 sys_setegid(struct lwp *l, void *v, register_t *retval)
500 {
501 struct sys_setegid_args /* {
502 syscallarg(gid_t) egid;
503 } */ *uap = v;
504
505 return do_setresgid(l, -1, SCARG(uap, egid), -1, ID_E_EQ_R | ID_E_EQ_S);
506 }
507
508 int
509 sys_setregid(struct lwp *l, void *v, register_t *retval)
510 {
511 struct sys_setregid_args /* {
512 syscallarg(gid_t) rgid;
513 syscallarg(gid_t) egid;
514 } */ *uap = v;
515 struct proc *p = l->l_proc;
516 gid_t rgid, egid, svgid;
517
518 rgid = SCARG(uap, rgid);
519 egid = SCARG(uap, egid);
520 if (rgid == -1)
521 rgid = kauth_cred_getgid(p->p_cred);
522 if (egid == -1)
523 egid = kauth_cred_getegid(p->p_cred);
524 /* Saved gid is set to the new egid if the rgid changed */
525 svgid = rgid == kauth_cred_getgid(p->p_cred) ? -1 : egid;
526
527 return do_setresgid(l, rgid, egid, svgid,
528 ID_R_EQ_R | ID_R_EQ_E |
529 ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S |
530 ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S);
531 }
532
533 int
534 sys_issetugid(struct lwp *l, void *v, register_t *retval)
535 {
536 struct proc *p = l->l_proc;
537
538 /*
539 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
540 * we use P_SUGID because we consider changing the owners as
541 * "tainting" as well.
542 * This is significant for procs that start as root and "become"
543 * a user without an exec - programs cannot know *everything*
544 * that libc *might* have put in their data segment.
545 */
546 *retval = (p->p_flag & P_SUGID) != 0;
547 return (0);
548 }
549
550 /*
551 * sort -u for groups.
552 */
553 static int
554 grsortu(gid_t *grp, int ngrp)
555 {
556 const gid_t *src, *end;
557 gid_t *dst;
558 gid_t group;
559 int i, j;
560
561 /* bubble sort */
562 for (i = 0; i < ngrp; i++)
563 for (j = i + 1; j < ngrp; j++)
564 if (grp[i] > grp[j]) {
565 gid_t tmp = grp[i];
566 grp[i] = grp[j];
567 grp[j] = tmp;
568 }
569
570 /* uniq */
571 end = grp + ngrp;
572 src = grp;
573 dst = grp;
574 while (src < end) {
575 group = *src++;
576 while (src < end && *src == group)
577 src++;
578 *dst++ = group;
579 }
580
581 #ifdef DIAGNOSTIC
582 /* zero out the rest of the array */
583 (void)memset(dst, 0, sizeof(*grp) * (end - dst));
584 #endif
585
586 return dst - grp;
587 }
588
589 /* ARGSUSED */
590 int
591 sys_setgroups(struct lwp *l, void *v, register_t *retval)
592 {
593 struct sys_setgroups_args /* {
594 syscallarg(int) gidsetsize;
595 syscallarg(const gid_t *) gidset;
596 } */ *uap = v;
597 struct proc *p = l->l_proc;
598 kauth_cred_t pc = p->p_cred;
599 int ngrp;
600 int error;
601 gid_t grp[NGROUPS];
602 size_t grsize;
603 int do_ngroups, i, j;
604
605 if ((error = generic_authorize(pc, KAUTH_GENERIC_ISSUSER,
606 &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 ngrp = grsortu(grp, ngrp);
619
620 /* XXX elad pc = kauth_cred_copy(pc); */
621 kauth_cred_setrefcnt(pc, 1);
622
623 do_ngroups = kauth_cred_ngroups(pc);
624
625 /* (1) For every group in current group array... */
626 for (i = 0; i < do_ngroups; i++) {
627 int in_new_array;
628
629 /* ...check if it's also in the new array... */
630 in_new_array = 0;
631 for (j = 0; j < ngrp; j++) {
632 if (kauth_cred_group(pc, i) == grp[j])
633 in_new_array = 1;
634 }
635
636 /* ...if not, delete it. */
637 if (!in_new_array) {
638 kauth_cred_delgroup(pc, kauth_cred_group(pc, i));
639 do_ngroups--;
640 }
641 }
642
643 /* (2) For every group in the new group array... */
644 for (i = 0; i < ngrp; i++) {
645 /* ...add it to current group array. */
646 kauth_cred_addgroup(pc, grp[i]);
647 }
648
649 p_sugid(p);
650 return (0);
651 }
652
653 /*
654 * Check if gid is a member of the group set.
655 */
656 int
657 groupmember(gid_t gid, const struct ucred *cred)
658 {
659 const gid_t *gp;
660 const gid_t *egp;
661
662 egp = &(cred->cr_groups[cred->cr_ngroups]);
663 for (gp = cred->cr_groups; gp < egp; gp++)
664 if (*gp == gid)
665 return (1);
666 return (0);
667 }
668
669 /*
670 * Test whether the specified credentials imply "super-user"
671 * privilege; if so, and we have accounting info, set the flag
672 * indicating use of super-powers.
673 * Returns 0 or error.
674 */
675 int
676 suser(const struct ucred *cred, u_short *acflag)
677 {
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(void)
692 {
693 struct ucred *cr;
694
695 cr = pool_get(&cred_pool, PR_WAITOK);
696 memset(cr, 0, sizeof(*cr));
697 simple_lock_init(&cr->cr_lock);
698 cr->cr_ref = 1;
699 return (cr);
700 }
701
702 /*
703 * Free a cred structure.
704 * Throws away space when ref count gets to 0.
705 */
706 void
707 crfree(struct ucred *cr)
708 {
709 int n;
710
711 simple_lock(&cr->cr_lock);
712 n = --cr->cr_ref;
713 simple_unlock(&cr->cr_lock);
714 if (n == 0)
715 pool_put(&cred_pool, cr);
716 }
717
718 /*
719 * Compare cred structures and return 0 if they match
720 */
721 int
722 crcmp(const struct ucred *cr1, const struct uucred *cr2)
723 {
724 /* FIXME: The group lists should be compared element by element,
725 * as the order of groups may be different in the two lists.
726 * Currently this function can return a non-zero value for
727 * equivalent group lists. */
728 return cr1->cr_uid != cr2->cr_uid ||
729 cr1->cr_gid != cr2->cr_gid ||
730 cr1->cr_ngroups != (uint32_t)cr2->cr_ngroups ||
731 memcmp(cr1->cr_groups, cr2->cr_groups,
732 sizeof(cr1->cr_groups[0]) * cr1->cr_ngroups);
733 }
734
735 /*
736 * Copy cred structure to a new one and free the old one.
737 */
738 struct ucred *
739 crcopy(struct ucred *cr)
740 {
741 struct ucred *newcr;
742
743 if (cr->cr_ref == 1)
744 return (cr);
745
746 newcr = crget();
747 memcpy(&newcr->cr_startcopy, &cr->cr_startcopy,
748 sizeof(struct ucred) - offsetof(struct ucred, cr_startcopy));
749 crfree(cr);
750 return (newcr);
751 }
752
753 /*
754 * Dup cred struct to a new held one.
755 */
756 struct ucred *
757 crdup(const struct ucred *cr)
758 {
759 struct ucred *newcr;
760
761 newcr = crget();
762 memcpy(&newcr->cr_startcopy, &cr->cr_startcopy,
763 sizeof(struct ucred) - offsetof(struct ucred, cr_startcopy));
764 return (newcr);
765 }
766
767 /*
768 * convert from userland credentials to kernel one
769 */
770 void
771 crcvt(struct ucred *uc, const struct uucred *uuc)
772 {
773
774 uc->cr_ref = 0;
775 uc->cr_uid = uuc->cr_uid;
776 uc->cr_gid = uuc->cr_gid;
777 uc->cr_ngroups = uuc->cr_ngroups;
778 (void)memcpy(uc->cr_groups, uuc->cr_groups, sizeof(uuc->cr_groups));
779 }
780
781 /*
782 * Get login name, if available.
783 */
784 /* ARGSUSED */
785 int
786 sys___getlogin(struct lwp *l, void *v, register_t *retval)
787 {
788 struct sys___getlogin_args /* {
789 syscallarg(char *) namebuf;
790 syscallarg(size_t) namelen;
791 } */ *uap = v;
792 struct proc *p = l->l_proc;
793
794 if (SCARG(uap, namelen) > sizeof(p->p_pgrp->pg_session->s_login))
795 SCARG(uap, namelen) = sizeof(p->p_pgrp->pg_session->s_login);
796 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
797 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
798 }
799
800 /*
801 * Set login name.
802 */
803 /* ARGSUSED */
804 int
805 sys___setlogin(struct lwp *l, void *v, register_t *retval)
806 {
807 struct sys___setlogin_args /* {
808 syscallarg(const char *) namebuf;
809 } */ *uap = v;
810 struct proc *p = l->l_proc;
811 struct session *s = p->p_pgrp->pg_session;
812 char newname[sizeof s->s_login + 1];
813 int error;
814
815 if ((error = generic_authorize(p->p_cred, KAUTH_GENERIC_ISSUSER,
816 &p->p_acflag)) != 0)
817 return (error);
818 error = copyinstr(SCARG(uap, namebuf), &newname, sizeof newname, NULL);
819 if (error != 0)
820 return (error == ENAMETOOLONG ? EINVAL : error);
821
822 if (s->s_flags & S_LOGIN_SET && p->p_pid != s->s_sid &&
823 strncmp(newname, s->s_login, sizeof s->s_login) != 0)
824 log(LOG_WARNING, "%s (pid %d) changing logname from "
825 "%.*s to %s\n", p->p_comm, p->p_pid,
826 (int)sizeof s->s_login, s->s_login, newname);
827 s->s_flags |= S_LOGIN_SET;
828 strncpy(s->s_login, newname, sizeof s->s_login);
829 return (0);
830 }
831