1 /* $NetBSD: kern_prot.c,v 1.86 2005/08/23 07:58:58 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.86 2005/08/23 07:58:58 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 int i, j, k; 548 static const size_t gs = sizeof(grp[0]); 549 550 /* bubble sort */ 551 for (i = 0; i < ngrp; i++) 552 for (j = i + 1; j < ngrp; j++) 553 if (grp[i] > grp[j]) { 554 gid_t tmp = grp[i]; 555 grp[i] = grp[j]; 556 grp[j] = tmp; 557 } 558 /* uniq */ 559 for (i = 0; i < ngrp; i++) { 560 for (j = i + 1; j < ngrp && grp[i] == grp[j]; j++) 561 continue; 562 k = j - (i + 1); 563 if (k == 0) 564 continue; 565 (void)memcpy(&grp[i + 1], &grp[j], gs * (ngrp - j)); 566 ngrp -= k; 567 #ifdef DIAGNOSTIC 568 /* zero out the rest of the array */ 569 (void)memset(&grp[ngrp], 0, gs * k); 570 #endif 571 } 572 return ngrp; 573 } 574 575 /* ARGSUSED */ 576 int 577 sys_setgroups(struct lwp *l, void *v, register_t *retval) 578 { 579 struct sys_setgroups_args /* { 580 syscallarg(int) gidsetsize; 581 syscallarg(const gid_t *) gidset; 582 } */ *uap = v; 583 struct proc *p = l->l_proc; 584 struct pcred *pc = p->p_cred; 585 int ngrp; 586 int error; 587 gid_t grp[NGROUPS]; 588 size_t grsize; 589 590 if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0) 591 return (error); 592 593 ngrp = SCARG(uap, gidsetsize); 594 if ((u_int)ngrp > NGROUPS) 595 return (EINVAL); 596 597 grsize = ngrp * sizeof(gid_t); 598 error = copyin(SCARG(uap, gidset), grp, grsize); 599 if (error) 600 return (error); 601 602 ngrp = grsortu(grp, ngrp); 603 /* 604 * Check if this is a no-op. 605 */ 606 if (pc->pc_ucred->cr_ngroups == (u_int) ngrp && 607 memcmp(grp, pc->pc_ucred->cr_groups, grsize) == 0) 608 return (0); 609 610 pc->pc_ucred = crcopy(pc->pc_ucred); 611 (void)memcpy(pc->pc_ucred->cr_groups, grp, grsize); 612 pc->pc_ucred->cr_ngroups = ngrp; 613 p_sugid(p); 614 return (0); 615 } 616 617 /* 618 * Check if gid is a member of the group set. 619 */ 620 int 621 groupmember(gid_t gid, const struct ucred *cred) 622 { 623 const gid_t *gp; 624 const gid_t *egp; 625 626 egp = &(cred->cr_groups[cred->cr_ngroups]); 627 for (gp = cred->cr_groups; gp < egp; gp++) 628 if (*gp == gid) 629 return (1); 630 return (0); 631 } 632 633 /* 634 * Test whether the specified credentials imply "super-user" 635 * privilege; if so, and we have accounting info, set the flag 636 * indicating use of super-powers. 637 * Returns 0 or error. 638 */ 639 int 640 suser(const struct ucred *cred, u_short *acflag) 641 { 642 643 if (cred->cr_uid == 0) { 644 if (acflag) 645 *acflag |= ASU; 646 return (0); 647 } 648 return (EPERM); 649 } 650 651 /* 652 * Allocate a zeroed cred structure. 653 */ 654 struct ucred * 655 crget(void) 656 { 657 struct ucred *cr; 658 659 cr = pool_get(&cred_pool, PR_WAITOK); 660 memset(cr, 0, sizeof(*cr)); 661 simple_lock_init(&cr->cr_lock); 662 cr->cr_ref = 1; 663 return (cr); 664 } 665 666 /* 667 * Free a cred structure. 668 * Throws away space when ref count gets to 0. 669 */ 670 void 671 crfree(struct ucred *cr) 672 { 673 int n; 674 675 simple_lock(&cr->cr_lock); 676 n = --cr->cr_ref; 677 simple_unlock(&cr->cr_lock); 678 if (n == 0) 679 pool_put(&cred_pool, cr); 680 } 681 682 /* 683 * Compare cred structures and return 0 if they match 684 */ 685 int 686 crcmp(const struct ucred *cr1, const struct uucred *cr2) 687 { 688 /* FIXME: The group lists should be compared element by element, 689 * as the order of groups may be different in the two lists. 690 * Currently this function can return a non-zero value for 691 * equivalent group lists. */ 692 return cr1->cr_uid != cr2->cr_uid || 693 cr1->cr_gid != cr2->cr_gid || 694 cr1->cr_ngroups != (uint32_t)cr2->cr_ngroups || 695 memcmp(cr1->cr_groups, cr2->cr_groups, 696 sizeof(cr1->cr_groups[0]) * cr1->cr_ngroups); 697 } 698 699 /* 700 * Copy cred structure to a new one and free the old one. 701 */ 702 struct ucred * 703 crcopy(struct ucred *cr) 704 { 705 struct ucred *newcr; 706 707 if (cr->cr_ref == 1) 708 return (cr); 709 710 newcr = crget(); 711 memcpy(&newcr->cr_startcopy, &cr->cr_startcopy, 712 sizeof(struct ucred) - offsetof(struct ucred, cr_startcopy)); 713 crfree(cr); 714 return (newcr); 715 } 716 717 /* 718 * Dup cred struct to a new held one. 719 */ 720 struct ucred * 721 crdup(const struct ucred *cr) 722 { 723 struct ucred *newcr; 724 725 newcr = crget(); 726 memcpy(&newcr->cr_startcopy, &cr->cr_startcopy, 727 sizeof(struct ucred) - offsetof(struct ucred, cr_startcopy)); 728 return (newcr); 729 } 730 731 /* 732 * convert from userland credentials to kernel one 733 */ 734 void 735 crcvt(struct ucred *uc, const struct uucred *uuc) 736 { 737 738 uc->cr_ref = 0; 739 uc->cr_uid = uuc->cr_uid; 740 uc->cr_gid = uuc->cr_gid; 741 uc->cr_ngroups = uuc->cr_ngroups; 742 (void)memcpy(uc->cr_groups, uuc->cr_groups, sizeof(uuc->cr_groups)); 743 } 744 745 /* 746 * Get login name, if available. 747 */ 748 /* ARGSUSED */ 749 int 750 sys___getlogin(struct lwp *l, void *v, register_t *retval) 751 { 752 struct sys___getlogin_args /* { 753 syscallarg(char *) namebuf; 754 syscallarg(size_t) namelen; 755 } */ *uap = v; 756 struct proc *p = l->l_proc; 757 758 if (SCARG(uap, namelen) > sizeof(p->p_pgrp->pg_session->s_login)) 759 SCARG(uap, namelen) = sizeof(p->p_pgrp->pg_session->s_login); 760 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 761 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen))); 762 } 763 764 /* 765 * Set login name. 766 */ 767 /* ARGSUSED */ 768 int 769 sys___setlogin(struct lwp *l, void *v, register_t *retval) 770 { 771 struct sys___setlogin_args /* { 772 syscallarg(const char *) namebuf; 773 } */ *uap = v; 774 struct proc *p = l->l_proc; 775 struct session *s = p->p_pgrp->pg_session; 776 char newname[sizeof s->s_login + 1]; 777 int error; 778 779 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 780 return (error); 781 error = copyinstr(SCARG(uap, namebuf), &newname, sizeof newname, NULL); 782 if (error != 0) 783 return (error == ENAMETOOLONG ? EINVAL : error); 784 785 if (s->s_flags & S_LOGIN_SET && p->p_pid != s->s_sid && 786 strncmp(newname, s->s_login, sizeof s->s_login) != 0) 787 log(LOG_WARNING, "%s (pid %d) changing logname from " 788 "%.*s to %s\n", p->p_comm, p->p_pid, 789 (int)sizeof s->s_login, s->s_login, newname); 790 s->s_flags |= S_LOGIN_SET; 791 strncpy(s->s_login, newname, sizeof s->s_login); 792 return (0); 793 } 794