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